From f8ed966bb16657ab3c371825f71e4f4e3363035c Mon Sep 17 00:00:00 2001 From: CPerezz Date: Wed, 29 Oct 2025 10:25:21 +0100 Subject: [PATCH 01/10] feat(state-analytics): add State Analytics feature Implements comprehensive State Analytics for Ethereum state growth monitoring: ## Backend Implementation - Proto definitions for State Analytics gRPC service - Service layer with ClickHouse integration for state metrics - Query implementations for latest block delta, top adders/removers, growth charts - gRPC server implementation with comprehensive unit and integration tests - REST API handlers for v1 endpoints - Route registration for /api/v1/{network}/state/* endpoints ## Frontend Implementation - React State Analyzer page with interactive visualizations - REST API client methods for State Analytics endpoints - TypeScript type definitions for all API responses - Navigation link to State Analyzer page - Period filters (24H, 7D, 30D) and interactive charts - Top state adders/removers tables with contract addresses ## Configuration - Updated package.json for React 19 compatibility (react-query 5.62.8) - Added frontend .env for production ethPandaOps backend URLs --- backend/pkg/api/service.go | 15 +- backend/pkg/api/v1/rest/handler.go | 16 +- backend/pkg/api/v1/rest/routes.go | 37 + .../api/v1/rest/state_analytics_handlers.go | 221 +++ backend/pkg/server/config.go | 18 +- .../server/internal/grpc/state_analytics.go | 83 + .../internal/grpc/state_analytics_test.go | 127 ++ .../service/state_analytics/config.go | 53 + .../state_analytics/integration_test.go | 499 +++++ .../state_analytics/latest_block_delta.go | 189 ++ .../latest_block_delta_test.go | 357 ++++ .../service/state_analytics/queries.go | 184 ++ .../service/state_analytics/queries_test.go | 159 ++ .../service/state_analytics/service.go | 200 ++ .../service/state_analytics/service_test.go | 238 +++ .../state_analytics/state_growth_chart.go | 178 ++ .../state_growth_chart_test.go | 254 +++ .../state_analytics/top_state_adders.go | 140 ++ .../state_analytics/top_state_adders_test.go | 168 ++ .../state_analytics/top_state_removers.go | 145 ++ .../top_state_removers_test.go | 203 ++ .../state_analytics/state_analytics.pb.go | 1755 +++++++++++++++++ .../state_analytics/state_analytics.proto | 190 ++ .../state_analytics_grpc.pb.go | 287 +++ .../state_analytics/state_analytics_test.go | 271 +++ backend/pkg/server/server.go | 35 +- frontend/package.json | 2 +- frontend/src/api/rest/client.ts | 104 + frontend/src/api/rest/endpoints.ts | 7 + frontend/src/components/layout/Navigation.tsx | 6 +- frontend/src/pages/state-analyzer/index.tsx | 403 ++++ .../src/routes/_layout.state-analyzer.tsx | 6 + frontend/src/types/state-analytics.ts | 192 ++ 33 files changed, 6711 insertions(+), 31 deletions(-) create mode 100644 backend/pkg/api/v1/rest/state_analytics_handlers.go create mode 100644 backend/pkg/server/internal/grpc/state_analytics.go create mode 100644 backend/pkg/server/internal/grpc/state_analytics_test.go create mode 100644 backend/pkg/server/internal/service/state_analytics/config.go create mode 100644 backend/pkg/server/internal/service/state_analytics/integration_test.go create mode 100644 backend/pkg/server/internal/service/state_analytics/latest_block_delta.go create mode 100644 backend/pkg/server/internal/service/state_analytics/latest_block_delta_test.go create mode 100644 backend/pkg/server/internal/service/state_analytics/queries.go create mode 100644 backend/pkg/server/internal/service/state_analytics/queries_test.go create mode 100644 backend/pkg/server/internal/service/state_analytics/service.go create mode 100644 backend/pkg/server/internal/service/state_analytics/service_test.go create mode 100644 backend/pkg/server/internal/service/state_analytics/state_growth_chart.go create mode 100644 backend/pkg/server/internal/service/state_analytics/state_growth_chart_test.go create mode 100644 backend/pkg/server/internal/service/state_analytics/top_state_adders.go create mode 100644 backend/pkg/server/internal/service/state_analytics/top_state_adders_test.go create mode 100644 backend/pkg/server/internal/service/state_analytics/top_state_removers.go create mode 100644 backend/pkg/server/internal/service/state_analytics/top_state_removers_test.go create mode 100644 backend/pkg/server/proto/state_analytics/state_analytics.pb.go create mode 100644 backend/pkg/server/proto/state_analytics/state_analytics.proto create mode 100644 backend/pkg/server/proto/state_analytics/state_analytics_grpc.pb.go create mode 100644 backend/pkg/server/proto/state_analytics/state_analytics_test.go create mode 100644 frontend/src/pages/state-analyzer/index.tsx create mode 100644 frontend/src/routes/_layout.state-analyzer.tsx create mode 100644 frontend/src/types/state-analytics.ts diff --git a/backend/pkg/api/service.go b/backend/pkg/api/service.go index b82b9653d..b7bcee272 100644 --- a/backend/pkg/api/service.go +++ b/backend/pkg/api/service.go @@ -27,6 +27,7 @@ import ( beaconslotspb "github.com/ethpandaops/lab/backend/pkg/server/proto/beacon_slots" configpb "github.com/ethpandaops/lab/backend/pkg/server/proto/config" + state_analytics_pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" xatu_cbt_pb "github.com/ethpandaops/lab/backend/pkg/server/proto/xatu_cbt" ) @@ -43,11 +44,12 @@ type Service struct { metrics *metrics.Metrics // gRPC connection to srv service - srvConn *grpc.ClientConn - beaconSlotsClient beaconslotspb.BeaconSlotsClient - xatuCBTClient xatu_cbt_pb.XatuCBTClient - configClient configpb.ConfigServiceClient - publicV1Router *v1rest.PublicRouter + srvConn *grpc.ClientConn + beaconSlotsClient beaconslotspb.BeaconSlotsClient + xatuCBTClient xatu_cbt_pb.XatuCBTClient + configClient configpb.ConfigServiceClient + stateAnalyticsClient state_analytics_pb.StateAnalyticsClient + publicV1Router *v1rest.PublicRouter } // New creates a new api service @@ -309,7 +311,8 @@ func (s *Service) initializeServices(ctx context.Context) error { s.beaconSlotsClient = beaconslotspb.NewBeaconSlotsClient(conn) s.xatuCBTClient = xatu_cbt_pb.NewXatuCBTClient(conn) s.configClient = configpb.NewConfigServiceClient(conn) - s.publicV1Router = v1rest.NewPublicRouter(s.log, s.configClient, s.xatuCBTClient) + s.stateAnalyticsClient = state_analytics_pb.NewStateAnalyticsClient(conn) + s.publicV1Router = v1rest.NewPublicRouter(s.log, s.configClient, s.xatuCBTClient, s.stateAnalyticsClient) return nil } diff --git a/backend/pkg/api/v1/rest/handler.go b/backend/pkg/api/v1/rest/handler.go index ee1e45ae9..b9a0bbfcd 100644 --- a/backend/pkg/api/v1/rest/handler.go +++ b/backend/pkg/api/v1/rest/handler.go @@ -12,6 +12,7 @@ import ( apiv1 "github.com/ethpandaops/lab/backend/pkg/api/v1/proto" "github.com/ethpandaops/lab/backend/pkg/api/v1/rest/middleware" configpb "github.com/ethpandaops/lab/backend/pkg/server/proto/config" + state_analytics_pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" xatu_cbt_pb "github.com/ethpandaops/lab/backend/pkg/server/proto/xatu_cbt" cbtproto "github.com/ethpandaops/xatu-cbt/pkg/proto/clickhouse" "github.com/gorilla/mux" @@ -27,9 +28,10 @@ const ( // PublicRouter handles public REST API v1 requests for all Lab endpoints. type PublicRouter struct { - log logrus.FieldLogger - configClient configpb.ConfigServiceClient - xatuCBTClient xatu_cbt_pb.XatuCBTClient + log logrus.FieldLogger + configClient configpb.ConfigServiceClient + xatuCBTClient xatu_cbt_pb.XatuCBTClient + stateAnalyticsClient state_analytics_pb.StateAnalyticsClient } // NewPublicRouter creates a new public REST router for API v1. @@ -37,11 +39,13 @@ func NewPublicRouter( log logrus.FieldLogger, configClient configpb.ConfigServiceClient, xatuCBTClient xatu_cbt_pb.XatuCBTClient, + stateAnalyticsClient state_analytics_pb.StateAnalyticsClient, ) *PublicRouter { return &PublicRouter{ - log: log.WithField("component", "public_rest_router_v1"), - configClient: configClient, - xatuCBTClient: xatuCBTClient, + log: log.WithField("component", "public_rest_router_v1"), + configClient: configClient, + xatuCBTClient: xatuCBTClient, + stateAnalyticsClient: stateAnalyticsClient, } } diff --git a/backend/pkg/api/v1/rest/routes.go b/backend/pkg/api/v1/rest/routes.go index 986613eab..676c22ab6 100644 --- a/backend/pkg/api/v1/rest/routes.go +++ b/backend/pkg/api/v1/rest/routes.go @@ -150,5 +150,42 @@ func (r *PublicRouter) GetRoutes() []RouteConfig { Cache: middleware.CacheRealtime, Description: "Get prepared blocks for a specific slot", }, + + // State Analytics endpoints + { + Path: "/{network}/state/latest", + Handler: r.handleStateLatestBlockDelta, + Methods: []string{http.MethodGet, http.MethodOptions}, + Cache: middleware.CacheNearRealtime, + Description: "Get state changes for the most recent block", + }, + { + Path: "/{network}/state/top-adders", + Handler: r.handleStateTopAdders, + Methods: []string{http.MethodGet, http.MethodOptions}, + Cache: middleware.CacheNearRealtime, + Description: "Get contracts that created the most new storage slots", + }, + { + Path: "/{network}/state/top-removers", + Handler: r.handleStateTopRemovers, + Methods: []string{http.MethodGet, http.MethodOptions}, + Cache: middleware.CacheNearRealtime, + Description: "Get contracts that cleared the most storage slots", + }, + { + Path: "/{network}/state/growth-chart", + Handler: r.handleStateGrowthChart, + Methods: []string{http.MethodGet, http.MethodOptions}, + Cache: middleware.CacheNearRealtime, + Description: "Get time-series data of state growth", + }, + { + Path: "/{network}/state/contract/{address}", + Handler: r.handleContractStateActivity, + Methods: []string{http.MethodGet, http.MethodOptions}, + Cache: middleware.CacheNearRealtime, + Description: "Get detailed state activity for a specific contract", + }, } } diff --git a/backend/pkg/api/v1/rest/state_analytics_handlers.go b/backend/pkg/api/v1/rest/state_analytics_handlers.go new file mode 100644 index 000000000..b0f5bb2e1 --- /dev/null +++ b/backend/pkg/api/v1/rest/state_analytics_handlers.go @@ -0,0 +1,221 @@ +package rest + +import ( + "context" + "net/http" + "strconv" + + state_analytics_pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" + "github.com/gorilla/mux" + "google.golang.org/grpc/metadata" +) + +// handleStateLatestBlockDelta returns state changes for the most recent block +func (r *PublicRouter) handleStateLatestBlockDelta(w http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + network := vars["network"] + + // Add network to gRPC metadata + ctx := metadata.NewOutgoingContext(req.Context(), metadata.Pairs("network", network)) + + // Call gRPC service + resp, err := r.stateAnalyticsClient.GetLatestBlockDelta(ctx, &state_analytics_pb.GetLatestBlockDeltaRequest{}) + if err != nil { + r.HandleGRPCError(w, req, err) + return + } + + r.WriteJSONResponseOK(w, req, resp) +} + +// handleStateTopAdders returns contracts that created the most new storage slots +func (r *PublicRouter) handleStateTopAdders(w http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + network := vars["network"] + + // Parse query parameters + queryParams := req.URL.Query() + period := parseStatePeriod(queryParams.Get("period")) + limit := parseLimit(queryParams.Get("limit"), 25) + + // Add network to gRPC metadata + ctx := metadata.NewOutgoingContext(req.Context(), metadata.Pairs("network", network)) + + // Call gRPC service + resp, err := r.stateAnalyticsClient.GetTopStateAdders(ctx, &state_analytics_pb.GetTopStateAddersRequest{ + Period: period, + Limit: limit, + }) + if err != nil { + r.HandleGRPCError(w, req, err) + return + } + + r.WriteJSONResponseOK(w, req, resp) +} + +// handleStateTopRemovers returns contracts that cleared the most storage slots +func (r *PublicRouter) handleStateTopRemovers(w http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + network := vars["network"] + + // Parse query parameters + queryParams := req.URL.Query() + period := parseStateRemoverPeriod(queryParams.Get("period")) + limit := parseLimit(queryParams.Get("limit"), 25) + + // Add network to gRPC metadata + ctx := metadata.NewOutgoingContext(req.Context(), metadata.Pairs("network", network)) + + // Call gRPC service + resp, err := r.stateAnalyticsClient.GetTopStateRemovers(ctx, &state_analytics_pb.GetTopStateRemoversRequest{ + Period: period, + Limit: limit, + }) + if err != nil { + r.HandleGRPCError(w, req, err) + return + } + + r.WriteJSONResponseOK(w, req, resp) +} + +// handleStateGrowthChart returns time-series data of state growth +func (r *PublicRouter) handleStateGrowthChart(w http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + network := vars["network"] + + // Parse query parameters + queryParams := req.URL.Query() + period := parseChartPeriod(queryParams.Get("period")) + granularity := parseGranularity(queryParams.Get("granularity")) + + // Add network to gRPC metadata + ctx := metadata.NewOutgoingContext(req.Context(), metadata.Pairs("network", network)) + + // Call gRPC service + resp, err := r.stateAnalyticsClient.GetStateGrowthChart(ctx, &state_analytics_pb.GetStateGrowthChartRequest{ + Period: period, + Granularity: granularity, + }) + if err != nil { + r.HandleGRPCError(w, req, err) + return + } + + r.WriteJSONResponseOK(w, req, resp) +} + +// handleContractStateActivity returns detailed state activity for a specific contract +func (r *PublicRouter) handleContractStateActivity(w http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + network := vars["network"] + address := vars["address"] + + // Parse query parameters + queryParams := req.URL.Query() + limit := parseLimit(queryParams.Get("limit"), 100) + + // Add network to gRPC metadata + ctx := metadata.NewOutgoingContext(req.Context(), metadata.Pairs("network", network)) + + // Call gRPC service + resp, err := r.stateAnalyticsClient.GetContractStateActivity(ctx, &state_analytics_pb.GetContractStateActivityRequest{ + Address: address, + Limit: limit, + }) + if err != nil { + r.HandleGRPCError(w, req, err) + return + } + + r.WriteJSONResponseOK(w, req, resp) +} + +// parseStatePeriod parses period query parameter for top adders +func parseStatePeriod(value string) state_analytics_pb.GetTopStateAddersRequest_Period { + switch value { + case "24h", "PERIOD_24H": + return state_analytics_pb.GetTopStateAddersRequest_PERIOD_24H + case "7d", "PERIOD_7D": + return state_analytics_pb.GetTopStateAddersRequest_PERIOD_7D + case "30d", "PERIOD_30D": + return state_analytics_pb.GetTopStateAddersRequest_PERIOD_30D + default: + return state_analytics_pb.GetTopStateAddersRequest_PERIOD_24H + } +} + +// parseStateRemoverPeriod parses period query parameter for top removers +func parseStateRemoverPeriod(value string) state_analytics_pb.GetTopStateRemoversRequest_Period { + switch value { + case "24h", "PERIOD_24H": + return state_analytics_pb.GetTopStateRemoversRequest_PERIOD_24H + case "7d", "PERIOD_7D": + return state_analytics_pb.GetTopStateRemoversRequest_PERIOD_7D + case "30d", "PERIOD_30D": + return state_analytics_pb.GetTopStateRemoversRequest_PERIOD_30D + default: + return state_analytics_pb.GetTopStateRemoversRequest_PERIOD_24H + } +} + +// parseChartPeriod parses period query parameter for chart data +func parseChartPeriod(value string) state_analytics_pb.GetStateGrowthChartRequest_Period { + switch value { + case "24h", "PERIOD_24H": + return state_analytics_pb.GetStateGrowthChartRequest_PERIOD_24H + case "7d", "PERIOD_7D": + return state_analytics_pb.GetStateGrowthChartRequest_PERIOD_7D + case "30d", "PERIOD_30D": + return state_analytics_pb.GetStateGrowthChartRequest_PERIOD_30D + case "90d", "PERIOD_90D": + return state_analytics_pb.GetStateGrowthChartRequest_PERIOD_90D + default: + return state_analytics_pb.GetStateGrowthChartRequest_PERIOD_24H + } +} + +// parseGranularity parses granularity query parameter +func parseGranularity(value string) state_analytics_pb.GetStateGrowthChartRequest_Granularity { + switch value { + case "block", "GRANULARITY_BLOCK": + return state_analytics_pb.GetStateGrowthChartRequest_GRANULARITY_BLOCK + case "hour", "GRANULARITY_HOUR": + return state_analytics_pb.GetStateGrowthChartRequest_GRANULARITY_HOUR + case "day", "GRANULARITY_DAY": + return state_analytics_pb.GetStateGrowthChartRequest_GRANULARITY_DAY + default: + // Default to hour for most use cases + return state_analytics_pb.GetStateGrowthChartRequest_GRANULARITY_HOUR + } +} + +// parseLimit parses limit query parameter with default value +func parseLimit(value string, defaultLimit uint32) uint32 { + if value == "" { + return defaultLimit + } + + limit, err := strconv.ParseUint(value, 10, 32) + if err != nil { + return defaultLimit + } + + return uint32(limit) +} + +// networkFromContext extracts network from gRPC metadata +func networkFromContext(ctx context.Context) string { + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return "" + } + + networks := md.Get("network") + if len(networks) == 0 { + return "" + } + + return networks[0] +} diff --git a/backend/pkg/server/config.go b/backend/pkg/server/config.go index 6dbf2179c..292deef06 100644 --- a/backend/pkg/server/config.go +++ b/backend/pkg/server/config.go @@ -9,18 +9,20 @@ import ( "github.com/ethpandaops/lab/backend/pkg/server/internal/grpc" "github.com/ethpandaops/lab/backend/pkg/server/internal/service/cartographoor" "github.com/ethpandaops/lab/backend/pkg/server/internal/service/experiments" + "github.com/ethpandaops/lab/backend/pkg/server/internal/service/state_analytics" "github.com/ethpandaops/lab/backend/pkg/server/internal/service/xatu_cbt" ) type Config struct { - LogLevel string `yaml:"logLevel" default:"info"` - Server *grpc.Config `yaml:"grpc"` - Storage *storage.Config `yaml:"storage"` - Cache *cache.Config `yaml:"cache"` - Geolocation *geolocation.Config `yaml:"geolocation"` - XatuCBT *xatu_cbt.Config `yaml:"xatu_cbt"` - Cartographoor *cartographoor.Config `yaml:"cartographoor"` - Experiments *experiments.Config `yaml:"experiments"` + LogLevel string `yaml:"logLevel" default:"info"` + Server *grpc.Config `yaml:"grpc"` + Storage *storage.Config `yaml:"storage"` + Cache *cache.Config `yaml:"cache"` + Geolocation *geolocation.Config `yaml:"geolocation"` + XatuCBT *xatu_cbt.Config `yaml:"xatu_cbt"` + Cartographoor *cartographoor.Config `yaml:"cartographoor"` + Experiments *experiments.Config `yaml:"experiments"` + StateAnalytics *state_analytics.Config `yaml:"state_analytics"` } func (x *Config) Validate() error { diff --git a/backend/pkg/server/internal/grpc/state_analytics.go b/backend/pkg/server/internal/grpc/state_analytics.go new file mode 100644 index 000000000..e9c722aea --- /dev/null +++ b/backend/pkg/server/internal/grpc/state_analytics.go @@ -0,0 +1,83 @@ +package grpc + +import ( + "context" + + "github.com/ethpandaops/lab/backend/pkg/server/internal/service/state_analytics" + pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" + "github.com/sirupsen/logrus" + "google.golang.org/grpc" +) + +// StateAnalytics implements the State Analytics gRPC service. +type StateAnalytics struct { + pb.UnimplementedStateAnalyticsServer + log logrus.FieldLogger + service *state_analytics.Service +} + +// NewStateAnalytics creates a new StateAnalytics gRPC handler. +func NewStateAnalytics( + log logrus.FieldLogger, + svc *state_analytics.Service, +) *StateAnalytics { + return &StateAnalytics{ + log: log.WithField("component", "grpc/state_analytics"), + service: svc, + } +} + +// Name returns the name of the service. +func (sa *StateAnalytics) Name() string { + return "state_analytics" +} + +// Start registers the service with the gRPC server. +func (sa *StateAnalytics) Start(ctx context.Context, grpcServer *grpc.Server) error { + pb.RegisterStateAnalyticsServer(grpcServer, sa) + + sa.log.Info("StateAnalytics gRPC service started") + + return nil +} + +// GetLatestBlockDelta returns state changes for the most recent block. +func (sa *StateAnalytics) GetLatestBlockDelta( + ctx context.Context, + req *pb.GetLatestBlockDeltaRequest, +) (*pb.GetLatestBlockDeltaResponse, error) { + return sa.service.GetLatestBlockDelta(ctx, req) +} + +// GetTopStateAdders returns contracts that created the most new storage slots. +func (sa *StateAnalytics) GetTopStateAdders( + ctx context.Context, + req *pb.GetTopStateAddersRequest, +) (*pb.GetTopStateAddersResponse, error) { + return sa.service.GetTopStateAdders(ctx, req) +} + +// GetTopStateRemovers returns contracts that cleared the most storage slots. +func (sa *StateAnalytics) GetTopStateRemovers( + ctx context.Context, + req *pb.GetTopStateRemoversRequest, +) (*pb.GetTopStateRemoversResponse, error) { + return sa.service.GetTopStateRemovers(ctx, req) +} + +// GetStateGrowthChart returns time-series data of state growth. +func (sa *StateAnalytics) GetStateGrowthChart( + ctx context.Context, + req *pb.GetStateGrowthChartRequest, +) (*pb.GetStateGrowthChartResponse, error) { + return sa.service.GetStateGrowthChart(ctx, req) +} + +// GetContractStateActivity returns detailed state activity for a specific contract. +func (sa *StateAnalytics) GetContractStateActivity( + ctx context.Context, + req *pb.GetContractStateActivityRequest, +) (*pb.GetContractStateActivityResponse, error) { + // TODO: Implement this method + return nil, nil +} diff --git a/backend/pkg/server/internal/grpc/state_analytics_test.go b/backend/pkg/server/internal/grpc/state_analytics_test.go new file mode 100644 index 000000000..9d5d47640 --- /dev/null +++ b/backend/pkg/server/internal/grpc/state_analytics_test.go @@ -0,0 +1,127 @@ +package grpc + +import ( + "context" + "testing" + + "github.com/ethpandaops/lab/backend/pkg/server/internal/service/state_analytics" + pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" + "github.com/sirupsen/logrus" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +// TestStateAnalytics_Start verifies the gRPC handler registers correctly +func TestStateAnalytics_Start(t *testing.T) { + log := logrus.New() + log.SetLevel(logrus.InfoLevel) + + // Create a mock service (nil is ok for registration test) + handler := &StateAnalytics{ + log: log, + service: nil, // We're just testing registration, not functionality + } + + // Create a gRPC server + grpcServer := grpc.NewServer() + + // Start should register the service without errors + err := handler.Start(context.Background(), grpcServer) + if err != nil { + t.Fatalf("Start() failed: %v", err) + } + + // Verify the service was registered + serviceInfo := grpcServer.GetServiceInfo() + if _, exists := serviceInfo["state_analytics.StateAnalytics"]; !exists { + t.Error("StateAnalytics service was not registered with gRPC server") + } +} + +// TestStateAnalytics_Name verifies the service name +func TestStateAnalytics_Name(t *testing.T) { + handler := &StateAnalytics{} + + name := handler.Name() + expected := "state_analytics" + + if name != expected { + t.Errorf("Expected name %q, got %q", expected, name) + } +} + + +// TestStateAnalytics_MethodDelegation verifies RPC methods delegate to service +func TestStateAnalytics_MethodDelegation(t *testing.T) { + log := logrus.New() + log.SetLevel(logrus.ErrorLevel) // Reduce noise + + // Create a mock service that returns errors + // This proves the handler is calling the service methods + mockService := &state_analytics.Service{} + + handler := &StateAnalytics{ + log: log, + service: mockService, + } + + ctx := context.Background() + // Add network metadata + md := metadata.Pairs("network", "holesky") + ctx = metadata.NewIncomingContext(ctx, md) + + tests := []struct { + name string + call func() error + }{ + { + name: "GetLatestBlockDelta delegates", + call: func() error { + _, err := handler.GetLatestBlockDelta(ctx, &pb.GetLatestBlockDeltaRequest{}) + return err + }, + }, + { + name: "GetTopStateAdders delegates", + call: func() error { + _, err := handler.GetTopStateAdders(ctx, &pb.GetTopStateAddersRequest{}) + return err + }, + }, + { + name: "GetTopStateRemovers delegates", + call: func() error { + _, err := handler.GetTopStateRemovers(ctx, &pb.GetTopStateRemoversRequest{}) + return err + }, + }, + { + name: "GetStateGrowthChart delegates", + call: func() error { + _, err := handler.GetStateGrowthChart(ctx, &pb.GetStateGrowthChartRequest{}) + return err + }, + }, + { + name: "GetContractStateActivity delegates", + call: func() error { + _, err := handler.GetContractStateActivity(ctx, &pb.GetContractStateActivityRequest{}) + return err + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // We expect an error because the mock service isn't fully initialized + // The important part is that the method is called (not nil pointer panic) + err := tt.call() + if err == nil { + t.Log("Unexpectedly succeeded - mock service returned success") + } else { + // Expected: some error because service isn't properly configured + t.Logf("Got expected error (proves delegation works): %v", err) + } + }) + } +} diff --git a/backend/pkg/server/internal/service/state_analytics/config.go b/backend/pkg/server/internal/service/state_analytics/config.go new file mode 100644 index 000000000..8aa363ffe --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/config.go @@ -0,0 +1,53 @@ +package state_analytics + +import ( + "fmt" + + "github.com/ethpandaops/lab/backend/pkg/internal/lab/clickhouse" +) + +// Config holds configuration for the state analytics service +type Config struct { + // NetworkConfigs maps network names to their configurations + NetworkConfigs map[string]*NetworkConfig `yaml:"network_configs"` +} + +// NetworkConfig holds configuration for a specific network +type NetworkConfig struct { + // Enabled determines if this network is active + Enabled bool `yaml:"enabled"` + + // ClickHouse configuration for accessing Xatu data + ClickHouse *clickhouse.Config `yaml:"clickhouse"` +} + +// Validate validates the state analytics configuration +func (c *Config) Validate() error { + if c == nil { + return fmt.Errorf("config cannot be nil") + } + + if len(c.NetworkConfigs) == 0 { + return fmt.Errorf("at least one network must be configured") + } + + // Validate each network config + for network, netConfig := range c.NetworkConfigs { + if netConfig == nil { + return fmt.Errorf("network config for %s cannot be nil", network) + } + + if netConfig.Enabled && netConfig.ClickHouse == nil { + return fmt.Errorf("network %s is enabled but has no ClickHouse config", network) + } + + // Validate ClickHouse config if present + if netConfig.ClickHouse != nil { + if err := netConfig.ClickHouse.Validate(); err != nil { + return fmt.Errorf("invalid ClickHouse config for network %s: %w", network, err) + } + } + } + + return nil +} diff --git a/backend/pkg/server/internal/service/state_analytics/integration_test.go b/backend/pkg/server/internal/service/state_analytics/integration_test.go new file mode 100644 index 000000000..46285bf28 --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/integration_test.go @@ -0,0 +1,499 @@ +// +build integration + +package state_analytics + +import ( + "context" + "testing" + "time" + + "github.com/ethpandaops/lab/backend/pkg/internal/lab/clickhouse" + "github.com/ethpandaops/lab/backend/pkg/internal/lab/metrics" + pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/metadata" +) + +// TestGetLatestBlockDelta_Integration tests the actual implementation against real Xatu ClickHouse +// Run with: go test -tags=integration -v ./pkg/server/internal/service/state_analytics/... +func TestGetLatestBlockDelta_Integration(t *testing.T) { + // This test requires real ClickHouse access + // Set XATU_CLICKHOUSE_URL environment variable + dsn := "https://efstateless:1f614ba2-bb5c-4fcf-ae8a-d25563290942@clickhouse.xatu.ethpandaops.io:443/default" + + // Create logger + log := logrus.New() + log.SetLevel(logrus.DebugLevel) + + // Create noop metrics for testing + metricsSvc := metrics.NewNopMetrics("test", log) + + // Create ClickHouse config + chConfig := &clickhouse.Config{ + DSN: dsn, + ConnectionConfig: clickhouse.ConnectionConfig{ + MaxOpenConns: 5, + MaxIdleConns: 2, + ConnMaxLifetime: time.Hour, + DialTimeout: 10 * time.Second, + ReadTimeout: 30 * time.Second, + WriteTimeout: 10 * time.Second, + MaxExecutionTime: 60, + InsecureSkipVerify: false, + }, + } + + // Test on holesky (smaller dataset, faster queries) + network := "holesky" + + // Create service config + serviceConfig := &Config{ + NetworkConfigs: map[string]*NetworkConfig{ + network: { + Enabled: true, + ClickHouse: chConfig, + }, + }, + } + + // Create the service + svc, err := New(log, serviceConfig, metricsSvc) + require.NoError(t, err, "Failed to create service") + + // Start the service + ctx := context.Background() + err = svc.Start(ctx) + require.NoError(t, err, "Failed to start service") + defer svc.Stop() + + // Create request + req := &pb.GetLatestBlockDeltaRequest{} + + // Add network to context via gRPC metadata + md := metadata.Pairs("network", network) + ctxWithNetwork := metadata.NewIncomingContext(ctx, md) + + // Call the method + resp, err := svc.GetLatestBlockDelta(ctxWithNetwork, req) + require.NoError(t, err, "GetLatestBlockDelta failed") + require.NotNil(t, resp, "Response should not be nil") + + // Validate response + t.Logf("✅ GetLatestBlockDelta Response:") + t.Logf(" Block Number: %d", resp.BlockNumber) + t.Logf(" New Slots: %d", resp.NewSlotsCount) + t.Logf(" Modified Slots: %d", resp.ModifiedSlotsCount) + t.Logf(" Cleared Slots: %d", resp.ClearedSlotsCount) + t.Logf(" Estimated Bytes Added: %d bytes (%.2f KB)", resp.EstimatedBytesAdded, float64(resp.EstimatedBytesAdded)/1024) + t.Logf(" Net State Change: %d bytes (%.2f KB)", resp.NetStateChangeBytes, float64(resp.NetStateChangeBytes)/1024) + + // Basic validations + require.Greater(t, resp.BlockNumber, uint64(0), "Block number should be positive") + require.NotNil(t, resp.BlockTimestamp, "Block timestamp should not be nil") + + // Validate byte calculations + expectedBytesAdded := uint64(resp.NewSlotsCount) * BytesPerSlot + require.Equal(t, expectedBytesAdded, resp.EstimatedBytesAdded, "Bytes added calculation incorrect") + + expectedNetBytes := (int64(resp.NewSlotsCount) - int64(resp.ClearedSlotsCount)) * BytesPerSlot + require.Equal(t, expectedNetBytes, resp.NetStateChangeBytes, "Net state change calculation incorrect") + + // Check top contributors (may be empty if no changes in latest block) + t.Logf(" Top Contributors: %d contracts", len(resp.TopContributors)) + for i, contrib := range resp.TopContributors { + t.Logf(" [%d] %s: new=%d, modified=%d, cleared=%d, net_bytes=%d", + i+1, contrib.Address, contrib.NewSlots, contrib.ModifiedSlots, contrib.ClearedSlots, contrib.NetBytes) + } + + // Success! + t.Log("✅ Integration test passed!") +} + +// TestGetTopStateAdders_Integration tests the actual implementation against real Xatu ClickHouse +// Run with: go test -tags=integration -v ./pkg/server/internal/service/state_analytics/... +func TestGetTopStateAdders_Integration(t *testing.T) { + // This test requires real ClickHouse access + dsn := "https://efstateless:1f614ba2-bb5c-4fcf-ae8a-d25563290942@clickhouse.xatu.ethpandaops.io:443/default" + + // Create logger + log := logrus.New() + log.SetLevel(logrus.DebugLevel) + + // Create noop metrics for testing + metricsSvc := metrics.NewNopMetrics("test", log) + + // Create ClickHouse config + chConfig := &clickhouse.Config{ + DSN: dsn, + ConnectionConfig: clickhouse.ConnectionConfig{ + MaxOpenConns: 5, + MaxIdleConns: 2, + ConnMaxLifetime: time.Hour, + DialTimeout: 10 * time.Second, + ReadTimeout: 30 * time.Second, + WriteTimeout: 10 * time.Second, + MaxExecutionTime: 60, + InsecureSkipVerify: false, + }, + } + + // Test on holesky (smaller dataset, faster queries) + network := "holesky" + + // Create service config + serviceConfig := &Config{ + NetworkConfigs: map[string]*NetworkConfig{ + network: { + Enabled: true, + ClickHouse: chConfig, + }, + }, + } + + // Create the service + svc, err := New(log, serviceConfig, metricsSvc) + require.NoError(t, err, "Failed to create service") + + // Start the service + ctx := context.Background() + err = svc.Start(ctx) + require.NoError(t, err, "Failed to start service") + defer svc.Stop() + + // Test different periods + tests := []struct { + name string + period pb.GetTopStateAddersRequest_Period + limit uint32 + }{ + { + name: "24 hours - top 10", + period: pb.GetTopStateAddersRequest_PERIOD_24H, + limit: 10, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create request + req := &pb.GetTopStateAddersRequest{ + Period: tt.period, + Limit: tt.limit, + } + + // Add network to context via gRPC metadata + md := metadata.Pairs("network", network) + ctxWithNetwork := metadata.NewIncomingContext(ctx, md) + + // Call the method + resp, err := svc.GetTopStateAdders(ctxWithNetwork, req) + require.NoError(t, err, "GetTopStateAdders failed") + require.NotNil(t, resp, "Response should not be nil") + + // Validate response + t.Logf("✅ GetTopStateAdders Response:") + t.Logf(" Period: %s", tt.period.String()) + t.Logf(" Start Block: %d", resp.StartBlock) + t.Logf(" End Block: %d", resp.EndBlock) + t.Logf(" Block Range: %d blocks", resp.EndBlock-resp.StartBlock) + t.Logf(" Top Adders: %d contracts", len(resp.Adders)) + + // Basic validations + require.GreaterOrEqual(t, resp.EndBlock, resp.StartBlock, "End block should be >= start block") + require.LessOrEqual(t, len(resp.Adders), int(tt.limit), "Should not exceed requested limit") + + // Print top adders + for i, adder := range resp.Adders { + if i >= 5 { + break // Only print top 5 + } + t.Logf(" [%d] %s:", adder.Rank, adder.Address) + t.Logf(" Slots Added: %d", adder.SlotsAdded) + t.Logf(" Bytes Added: %d (%.2f MB)", adder.EstimatedBytesAdded, float64(adder.EstimatedBytesAdded)/(1024*1024)) + t.Logf(" Percentage: %.2f%%", adder.PercentageOfTotal) + } + + // Validate data consistency + if len(resp.Adders) > 0 { + // Check ranks are sequential + for i, adder := range resp.Adders { + require.Equal(t, uint32(i+1), adder.Rank, "Ranks should be sequential") + } + + // Check slots are in descending order + for i := 1; i < len(resp.Adders); i++ { + require.GreaterOrEqual(t, resp.Adders[i-1].SlotsAdded, resp.Adders[i].SlotsAdded, + "Slots should be in descending order") + } + + // Validate byte calculations + for _, adder := range resp.Adders { + expectedBytes := adder.SlotsAdded * BytesPerSlot + require.Equal(t, expectedBytes, adder.EstimatedBytesAdded, + "Bytes calculation incorrect for %s", adder.Address) + } + } + + t.Log("✅ Integration test passed!") + }) + } +} + +// TestGetTopStateRemovers_Integration tests the actual implementation against real Xatu ClickHouse +// Run with: go test -tags=integration -v ./pkg/server/internal/service/state_analytics/... +func TestGetTopStateRemovers_Integration(t *testing.T) { + // This test requires real ClickHouse access + dsn := "https://efstateless:1f614ba2-bb5c-4fcf-ae8a-d25563290942@clickhouse.xatu.ethpandaops.io:443/default" + + // Create logger + log := logrus.New() + log.SetLevel(logrus.DebugLevel) + + // Create noop metrics for testing + metricsSvc := metrics.NewNopMetrics("test", log) + + // Create ClickHouse config + chConfig := &clickhouse.Config{ + DSN: dsn, + ConnectionConfig: clickhouse.ConnectionConfig{ + MaxOpenConns: 5, + MaxIdleConns: 2, + ConnMaxLifetime: time.Hour, + DialTimeout: 10 * time.Second, + ReadTimeout: 30 * time.Second, + WriteTimeout: 10 * time.Second, + MaxExecutionTime: 60, + InsecureSkipVerify: false, + }, + } + + // Test on holesky (smaller dataset, faster queries) + network := "holesky" + + // Create service config + serviceConfig := &Config{ + NetworkConfigs: map[string]*NetworkConfig{ + network: { + Enabled: true, + ClickHouse: chConfig, + }, + }, + } + + // Create the service + svc, err := New(log, serviceConfig, metricsSvc) + require.NoError(t, err, "Failed to create service") + + // Start the service + ctx := context.Background() + err = svc.Start(ctx) + require.NoError(t, err, "Failed to start service") + defer svc.Stop() + + // Test 24 hour period + req := &pb.GetTopStateRemoversRequest{ + Period: pb.GetTopStateRemoversRequest_PERIOD_24H, + Limit: 10, + } + + // Add network to context via gRPC metadata + md := metadata.Pairs("network", network) + ctxWithNetwork := metadata.NewIncomingContext(ctx, md) + + // Call the method + resp, err := svc.GetTopStateRemovers(ctxWithNetwork, req) + require.NoError(t, err, "GetTopStateRemovers failed") + require.NotNil(t, resp, "Response should not be nil") + + // Validate response + t.Logf("✅ GetTopStateRemovers Response:") + t.Logf(" Period: PERIOD_24H") + t.Logf(" Start Block: %d", resp.StartBlock) + t.Logf(" End Block: %d", resp.EndBlock) + t.Logf(" Block Range: %d blocks", resp.EndBlock-resp.StartBlock) + t.Logf(" Top Removers: %d contracts", len(resp.Removers)) + + // Basic validations + require.GreaterOrEqual(t, resp.EndBlock, resp.StartBlock, "End block should be >= start block") + require.LessOrEqual(t, len(resp.Removers), 10, "Should not exceed requested limit") + + // Print top removers + for i, remover := range resp.Removers { + if i >= 5 { + break // Only print top 5 + } + t.Logf(" [%d] %s:", remover.Rank, remover.Address) + t.Logf(" Slots Cleared: %d", remover.SlotsCleared) + t.Logf(" Bytes Freed: %d (%.2f KB)", remover.EstimatedBytesFreed, float64(remover.EstimatedBytesFreed)/1024) + t.Logf(" Est. Gas Refund: %d gas", remover.EstimatedGasRefund) + t.Logf(" Percentage: %.2f%%", remover.PercentageOfTotal) + } + + // Validate data consistency + if len(resp.Removers) > 0 { + // Check ranks are sequential + for i, remover := range resp.Removers { + require.Equal(t, uint32(i+1), remover.Rank, "Ranks should be sequential") + } + + // Check slots are in descending order + for i := 1; i < len(resp.Removers); i++ { + require.GreaterOrEqual(t, resp.Removers[i-1].SlotsCleared, resp.Removers[i].SlotsCleared, + "Slots should be in descending order") + } + + // Validate byte calculations + for _, remover := range resp.Removers { + expectedBytes := remover.SlotsCleared * BytesPerSlot + require.Equal(t, expectedBytes, remover.EstimatedBytesFreed, + "Bytes calculation incorrect for %s", remover.Address) + } + + // Validate gas refund calculations + for _, remover := range resp.Removers { + expectedGasRefund := remover.SlotsCleared * 15000 + require.Equal(t, expectedGasRefund, remover.EstimatedGasRefund, + "Gas refund calculation incorrect for %s", remover.Address) + } + } + + t.Log("✅ Integration test passed!") +} + +// TestGetStateGrowthChart_Integration tests the actual implementation against real Xatu ClickHouse +// Run with: go test -tags=integration -v ./pkg/server/internal/service/state_analytics/... +func TestGetStateGrowthChart_Integration(t *testing.T) { + // This test requires real ClickHouse access + dsn := "https://efstateless:1f614ba2-bb5c-4fcf-ae8a-d25563290942@clickhouse.xatu.ethpandaops.io:443/default" + + // Create logger + log := logrus.New() + log.SetLevel(logrus.DebugLevel) + + // Create noop metrics for testing + metricsSvc := metrics.NewNopMetrics("test", log) + + // Create ClickHouse config + chConfig := &clickhouse.Config{ + DSN: dsn, + ConnectionConfig: clickhouse.ConnectionConfig{ + MaxOpenConns: 5, + MaxIdleConns: 2, + ConnMaxLifetime: time.Hour, + DialTimeout: 10 * time.Second, + ReadTimeout: 30 * time.Second, + WriteTimeout: 10 * time.Second, + MaxExecutionTime: 60, + InsecureSkipVerify: false, + }, + } + + // Test on holesky (smaller dataset, faster queries) + network := "holesky" + + // Create service config + serviceConfig := &Config{ + NetworkConfigs: map[string]*NetworkConfig{ + network: { + Enabled: true, + ClickHouse: chConfig, + }, + }, + } + + // Create the service + svc, err := New(log, serviceConfig, metricsSvc) + require.NoError(t, err, "Failed to create service") + + // Start the service + ctx := context.Background() + err = svc.Start(ctx) + require.NoError(t, err, "Failed to start service") + defer svc.Stop() + + // Test 24h period with hourly granularity + req := &pb.GetStateGrowthChartRequest{ + Period: pb.GetStateGrowthChartRequest_PERIOD_24H, + Granularity: pb.GetStateGrowthChartRequest_GRANULARITY_HOUR, + } + + // Add network to context via gRPC metadata + md := metadata.Pairs("network", network) + ctxWithNetwork := metadata.NewIncomingContext(ctx, md) + + // Call the method + resp, err := svc.GetStateGrowthChart(ctxWithNetwork, req) + require.NoError(t, err, "GetStateGrowthChart failed") + require.NotNil(t, resp, "Response should not be nil") + + // Validate response + t.Logf("✅ GetStateGrowthChart Response:") + t.Logf(" Period: PERIOD_24H") + t.Logf(" Granularity: GRANULARITY_HOUR") + t.Logf(" Data Points: %d", len(resp.DataPoints)) + + // Validate summary + require.NotNil(t, resp.Summary, "Summary should not be nil") + t.Logf(" Summary:") + t.Logf(" Total Slots Added: %d", resp.Summary.TotalSlotsAdded) + t.Logf(" Total Slots Cleared: %d", resp.Summary.TotalSlotsCleared) + t.Logf(" Net Slots: %d", resp.Summary.NetSlots) + t.Logf(" Total Bytes Added: %d (%.2f MB)", resp.Summary.TotalBytesAdded, float64(resp.Summary.TotalBytesAdded)/(1024*1024)) + t.Logf(" Total Bytes Cleared: %d (%.2f MB)", resp.Summary.TotalBytesCleared, float64(resp.Summary.TotalBytesCleared)/(1024*1024)) + t.Logf(" Net Bytes: %d (%.2f MB)", resp.Summary.NetBytes, float64(resp.Summary.NetBytes)/(1024*1024)) + t.Logf(" Avg Slots Per Data Point: %.2f", resp.Summary.AvgSlotsPerBlock) + + // Basic validations + require.Greater(t, len(resp.DataPoints), 0, "Should have data points") + + // Print first few data points + t.Logf(" Sample Data Points:") + for i, dp := range resp.DataPoints { + if i >= 3 { + break // Only print first 3 + } + t.Logf(" [%d] Block %d @ %s:", i+1, dp.BlockNumber, dp.Timestamp.AsTime().Format(time.RFC3339)) + t.Logf(" Slots: +%d -%d = %d", dp.SlotsAdded, dp.SlotsCleared, dp.NetSlots) + t.Logf(" Bytes: +%d -%d = %d", dp.BytesAdded, dp.BytesCleared, dp.NetBytes) + } + + // Validate data consistency + if len(resp.DataPoints) > 0 { + // Verify timestamps are in order + for i := 1; i < len(resp.DataPoints); i++ { + require.True(t, resp.DataPoints[i].Timestamp.AsTime().After(resp.DataPoints[i-1].Timestamp.AsTime()), + "Timestamps should be in ascending order") + } + + // Validate byte calculations + for _, dp := range resp.DataPoints { + expectedBytesAdded := dp.SlotsAdded * BytesPerSlot + require.Equal(t, expectedBytesAdded, dp.BytesAdded, "Bytes added calculation incorrect") + + expectedBytesCleared := dp.SlotsCleared * BytesPerSlot + require.Equal(t, expectedBytesCleared, dp.BytesCleared, "Bytes cleared calculation incorrect") + + expectedNetBytes := int64(dp.SlotsAdded)*BytesPerSlot - int64(dp.SlotsCleared)*BytesPerSlot + require.Equal(t, expectedNetBytes, dp.NetBytes, "Net bytes calculation incorrect") + } + + // Validate summary totals match sum of data points + var sumSlotsAdded, sumSlotsCleared uint64 + for _, dp := range resp.DataPoints { + sumSlotsAdded += dp.SlotsAdded + sumSlotsCleared += dp.SlotsCleared + } + require.Equal(t, sumSlotsAdded, resp.Summary.TotalSlotsAdded, "Summary slots added should match sum") + require.Equal(t, sumSlotsCleared, resp.Summary.TotalSlotsCleared, "Summary slots cleared should match sum") + + // Validate summary net calculation + expectedNetSlots := int64(resp.Summary.TotalSlotsAdded) - int64(resp.Summary.TotalSlotsCleared) + require.Equal(t, expectedNetSlots, resp.Summary.NetSlots, "Summary net slots incorrect") + + expectedNetBytes := int64(resp.Summary.TotalBytesAdded) - int64(resp.Summary.TotalBytesCleared) + require.Equal(t, expectedNetBytes, resp.Summary.NetBytes, "Summary net bytes incorrect") + } + + t.Log("✅ Integration test passed!") +} diff --git a/backend/pkg/server/internal/service/state_analytics/latest_block_delta.go b/backend/pkg/server/internal/service/state_analytics/latest_block_delta.go new file mode 100644 index 000000000..f36fcf0c4 --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/latest_block_delta.go @@ -0,0 +1,189 @@ +package state_analytics + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/ethpandaops/lab/backend/pkg/internal/lab/clickhouse" + pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" + "google.golang.org/protobuf/types/known/timestamppb" +) + +// GetLatestBlockDelta returns state changes for the most recent block +func (s *Service) GetLatestBlockDelta( + ctx context.Context, + req *pb.GetLatestBlockDeltaRequest, +) (*pb.GetLatestBlockDeltaResponse, error) { + startTime := time.Now() + method := "GetLatestBlockDelta" + + // Get network from context + network, err := s.getNetworkFromContext(ctx) + if err != nil { + s.recordMetrics(method, "unknown", StatusError, time.Since(startTime).Seconds()) + return nil, err + } + + s.log.WithField("network", network).Debug("Fetching latest block delta") + + // Get ClickHouse client + client, err := s.getClient(network) + if err != nil { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, fmt.Errorf("failed to get ClickHouse client: %w", err) + } + + // Query for latest block delta + query := strings.ReplaceAll(queryLatestBlockDelta, "{database}", network) + + rows, err := client.Query(ctx, query) + if err != nil { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, fmt.Errorf("failed to query latest block delta: %w", err) + } + + if len(rows) == 0 { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, fmt.Errorf("no data returned for latest block") + } + + // Parse first row + row := rows[0] + blockNumber := getUint64(row, "block_number") + newSlots := getUint32(row, "new_slots") + clearedSlots := getUint32(row, "cleared_slots") + modifiedSlots := getUint32(row, "modified_slots") + + // Calculate estimated bytes + estimatedBytesAdded := uint64(newSlots) * BytesPerSlot + // Cast to int64 BEFORE subtraction to avoid unsigned underflow + netStateChangeBytes := (int64(newSlots) - int64(clearedSlots)) * BytesPerSlot + + // Get top contributors for this block + topContributors, err := s.getTopContributorsForBlock(ctx, client, network, blockNumber) + if err != nil { + s.log.WithError(err).Warn("Failed to get top contributors, continuing without them") + topContributors = []*pb.ContractStateDelta{} + } + + // Estimate block timestamp (12s per block, assuming genesis at ~1606824000 for mainnet) + // This is a rough estimate - in production you'd query the actual timestamp + genesisTime := int64(1606824000) + blockTimestamp := time.Unix(genesisTime+int64(blockNumber)*12, 0) + + s.recordMetrics(method, network, StatusSuccess, time.Since(startTime).Seconds()) + + return &pb.GetLatestBlockDeltaResponse{ + BlockNumber: blockNumber, + BlockTimestamp: timestamppb.New(blockTimestamp), + NewSlotsCount: newSlots, + ModifiedSlotsCount: modifiedSlots, + ClearedSlotsCount: clearedSlots, + EstimatedBytesAdded: estimatedBytesAdded, + NetStateChangeBytes: netStateChangeBytes, + TopContributors: topContributors, + }, nil +} + +// getTopContributorsForBlock gets the top state change contributors for a specific block +func (s *Service) getTopContributorsForBlock( + ctx context.Context, + client clickhouse.Client, + network string, + blockNumber uint64, +) ([]*pb.ContractStateDelta, error) { + query := strings.ReplaceAll(queryLatestBlockTopContributors, "{database}", network) + query = strings.ReplaceAll(query, "{bytes_per_slot}", fmt.Sprintf("%d", BytesPerSlot)) + + rows, err := client.Query(ctx, query) + if err != nil { + return nil, fmt.Errorf("failed to query top contributors: %w", err) + } + + var contributors []*pb.ContractStateDelta + + for _, row := range rows { + address := getString(row, "address") + newSlots := getUint32(row, "new_slots") + modifiedSlots := getUint32(row, "modified_slots") + clearedSlots := getUint32(row, "cleared_slots") + netBytes := getInt64(row, "net_bytes") + + contributors = append(contributors, &pb.ContractStateDelta{ + Address: address, + NewSlots: newSlots, + ModifiedSlots: modifiedSlots, + ClearedSlots: clearedSlots, + NetBytes: netBytes, + Label: "", // Will be populated later by labeling service + }) + } + + return contributors, nil +} + +// Helper functions to extract typed values from ClickHouse result maps +func getString(m map[string]interface{}, key string) string { + if v, ok := m[key]; ok { + if s, ok := v.(string); ok { + return s + } + } + return "" +} + +func getUint32(m map[string]interface{}, key string) uint32 { + if v, ok := m[key]; ok { + switch val := v.(type) { + case uint32: + return val + case uint64: + return uint32(val) + case int: + return uint32(val) + case int64: + return uint32(val) + case float64: + return uint32(val) + } + } + return 0 +} + +func getUint64(m map[string]interface{}, key string) uint64 { + if v, ok := m[key]; ok { + switch val := v.(type) { + case uint64: + return val + case uint32: + return uint64(val) + case int: + return uint64(val) + case int64: + return uint64(val) + case float64: + return uint64(val) + } + } + return 0 +} + +func getInt64(m map[string]interface{}, key string) int64 { + if v, ok := m[key]; ok { + switch val := v.(type) { + case int64: + return val + case int: + return int64(val) + case uint64: + return int64(val) + case uint32: + return int64(val) + case float64: + return int64(val) + } + } + return 0 +} diff --git a/backend/pkg/server/internal/service/state_analytics/latest_block_delta_test.go b/backend/pkg/server/internal/service/state_analytics/latest_block_delta_test.go new file mode 100644 index 000000000..1168dd3e8 --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/latest_block_delta_test.go @@ -0,0 +1,357 @@ +package state_analytics + +import ( + "testing" +) + +// TestGetString tests the getString helper function +func TestGetString(t *testing.T) { + tests := []struct { + name string + input map[string]interface{} + key string + expected string + }{ + { + name: "valid string", + input: map[string]interface{}{"address": "0x1234"}, + key: "address", + expected: "0x1234", + }, + { + name: "missing key", + input: map[string]interface{}{"other": "value"}, + key: "address", + expected: "", + }, + { + name: "wrong type", + input: map[string]interface{}{"address": 12345}, + key: "address", + expected: "", + }, + { + name: "empty map", + input: map[string]interface{}{}, + key: "address", + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := getString(tt.input, tt.key) + if result != tt.expected { + t.Errorf("getString() = %v, expected %v", result, tt.expected) + } + }) + } +} + +// TestGetUint32 tests the getUint32 helper function +func TestGetUint32(t *testing.T) { + tests := []struct { + name string + input map[string]interface{} + key string + expected uint32 + }{ + { + name: "uint32 value", + input: map[string]interface{}{"count": uint32(100)}, + key: "count", + expected: 100, + }, + { + name: "uint64 value", + input: map[string]interface{}{"count": uint64(200)}, + key: "count", + expected: 200, + }, + { + name: "int value", + input: map[string]interface{}{"count": int(300)}, + key: "count", + expected: 300, + }, + { + name: "int64 value", + input: map[string]interface{}{"count": int64(400)}, + key: "count", + expected: 400, + }, + { + name: "float64 value", + input: map[string]interface{}{"count": float64(500)}, + key: "count", + expected: 500, + }, + { + name: "missing key", + input: map[string]interface{}{"other": 123}, + key: "count", + expected: 0, + }, + { + name: "wrong type", + input: map[string]interface{}{"count": "string"}, + key: "count", + expected: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := getUint32(tt.input, tt.key) + if result != tt.expected { + t.Errorf("getUint32() = %v, expected %v", result, tt.expected) + } + }) + } +} + +// TestGetUint64 tests the getUint64 helper function +func TestGetUint64(t *testing.T) { + tests := []struct { + name string + input map[string]interface{} + key string + expected uint64 + }{ + { + name: "uint64 value", + input: map[string]interface{}{"block": uint64(12345678)}, + key: "block", + expected: 12345678, + }, + { + name: "uint32 value", + input: map[string]interface{}{"block": uint32(1000)}, + key: "block", + expected: 1000, + }, + { + name: "int value", + input: map[string]interface{}{"block": int(2000)}, + key: "block", + expected: 2000, + }, + { + name: "int64 value", + input: map[string]interface{}{"block": int64(3000)}, + key: "block", + expected: 3000, + }, + { + name: "float64 value", + input: map[string]interface{}{"block": float64(4000)}, + key: "block", + expected: 4000, + }, + { + name: "large uint64", + input: map[string]interface{}{"block": uint64(18446744073709551615)}, + key: "block", + expected: 18446744073709551615, + }, + { + name: "missing key", + input: map[string]interface{}{"other": 123}, + key: "block", + expected: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := getUint64(tt.input, tt.key) + if result != tt.expected { + t.Errorf("getUint64() = %v, expected %v", result, tt.expected) + } + }) + } +} + +// TestGetInt64 tests the getInt64 helper function +func TestGetInt64(t *testing.T) { + tests := []struct { + name string + input map[string]interface{} + key string + expected int64 + }{ + { + name: "int64 value", + input: map[string]interface{}{"net_bytes": int64(-1000)}, + key: "net_bytes", + expected: -1000, + }, + { + name: "positive int64", + input: map[string]interface{}{"net_bytes": int64(2000)}, + key: "net_bytes", + expected: 2000, + }, + { + name: "int value", + input: map[string]interface{}{"net_bytes": int(3000)}, + key: "net_bytes", + expected: 3000, + }, + { + name: "uint64 value", + input: map[string]interface{}{"net_bytes": uint64(4000)}, + key: "net_bytes", + expected: 4000, + }, + { + name: "uint32 value", + input: map[string]interface{}{"net_bytes": uint32(5000)}, + key: "net_bytes", + expected: 5000, + }, + { + name: "float64 value", + input: map[string]interface{}{"net_bytes": float64(6000)}, + key: "net_bytes", + expected: 6000, + }, + { + name: "negative float64", + input: map[string]interface{}{"net_bytes": float64(-7000)}, + key: "net_bytes", + expected: -7000, + }, + { + name: "missing key", + input: map[string]interface{}{"other": 123}, + key: "net_bytes", + expected: 0, + }, + { + name: "wrong type", + input: map[string]interface{}{"net_bytes": "string"}, + key: "net_bytes", + expected: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := getInt64(tt.input, tt.key) + if result != tt.expected { + t.Errorf("getInt64() = %v, expected %v", result, tt.expected) + } + }) + } +} + +// TestHelperFunctionsEdgeCases tests edge cases for helper functions +func TestHelperFunctionsEdgeCases(t *testing.T) { + t.Run("nil map", func(t *testing.T) { + if getString(nil, "key") != "" { + t.Error("getString with nil map should return empty string") + } + if getUint32(nil, "key") != 0 { + t.Error("getUint32 with nil map should return 0") + } + if getUint64(nil, "key") != 0 { + t.Error("getUint64 with nil map should return 0") + } + if getInt64(nil, "key") != 0 { + t.Error("getInt64 with nil map should return 0") + } + }) + + t.Run("nil value", func(t *testing.T) { + m := map[string]interface{}{"key": nil} + + if getString(m, "key") != "" { + t.Error("getString with nil value should return empty string") + } + if getUint32(m, "key") != 0 { + t.Error("getUint32 with nil value should return 0") + } + if getUint64(m, "key") != 0 { + t.Error("getUint64 with nil value should return 0") + } + if getInt64(m, "key") != 0 { + t.Error("getInt64 with nil value should return 0") + } + }) + + t.Run("type conversion accuracy", func(t *testing.T) { + // Test that large numbers convert correctly + m := map[string]interface{}{ + "large": uint64(18446744073709551615), // max uint64 + } + + result := getUint64(m, "large") + if result != 18446744073709551615 { + t.Errorf("Large uint64 conversion failed: got %v", result) + } + }) +} + +// TestByteCalculations tests the byte calculation logic +func TestByteCalculations(t *testing.T) { + tests := []struct { + name string + newSlots uint32 + clearedSlots uint32 + expectedAdded uint64 + expectedNet int64 + }{ + { + name: "positive growth", + newSlots: 1000, + clearedSlots: 100, + expectedAdded: 191000, // 1000 * 191 + expectedNet: 171900, // (1000 - 100) * 191 + }, + { + name: "negative growth", + newSlots: 100, + clearedSlots: 500, + expectedAdded: 19100, // 100 * 191 + expectedNet: -76400, // (100 - 500) * 191 + }, + { + name: "no change", + newSlots: 100, + clearedSlots: 100, + expectedAdded: 19100, // 100 * 191 + expectedNet: 0, // (100 - 100) * 191 + }, + { + name: "only additions", + newSlots: 500, + clearedSlots: 0, + expectedAdded: 95500, // 500 * 191 + expectedNet: 95500, // (500 - 0) * 191 + }, + { + name: "only removals", + newSlots: 0, + clearedSlots: 300, + expectedAdded: 0, // 0 * 191 + expectedNet: -57300, // (0 - 300) * 191 + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + estimatedBytesAdded := uint64(tt.newSlots) * BytesPerSlot + // Cast to int64 BEFORE subtraction to avoid unsigned underflow + netStateChangeBytes := (int64(tt.newSlots) - int64(tt.clearedSlots)) * BytesPerSlot + + if estimatedBytesAdded != tt.expectedAdded { + t.Errorf("estimatedBytesAdded = %v, expected %v", estimatedBytesAdded, tt.expectedAdded) + } + + if netStateChangeBytes != tt.expectedNet { + t.Errorf("netStateChangeBytes = %v, expected %v", netStateChangeBytes, tt.expectedNet) + } + }) + } +} diff --git a/backend/pkg/server/internal/service/state_analytics/queries.go b/backend/pkg/server/internal/service/state_analytics/queries.go new file mode 100644 index 000000000..49fd7a96f --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/queries.go @@ -0,0 +1,184 @@ +package state_analytics + +const ( + // Bytes per storage slot (Reth measurement) + BytesPerSlot = 191 + + // Average blocks per time period (12s block time) + BlocksPerHour = 300 + BlocksPer24Hours = 7200 + BlocksPer7Days = 50400 + BlocksPer30Days = 216000 +) + +// Query to get latest block state delta +const queryLatestBlockDelta = ` +WITH latest_block AS ( + SELECT MAX(block_number) as max_block + FROM {database}.int_address_storage_slot_last_access +), +new_slots AS ( + SELECT count() as count + FROM {database}.int_address_storage_slot_first_access + WHERE block_number = (SELECT max_block FROM latest_block) +), +last_access AS ( + SELECT + count() as total, + countIf(value = '0x0000000000000000000000000000000000000000000000000000000000000000') as cleared + FROM {database}.int_address_storage_slot_last_access + WHERE block_number = (SELECT max_block FROM latest_block) +) +SELECT + (SELECT max_block FROM latest_block) as block_number, + (SELECT count FROM new_slots) as new_slots, + (SELECT cleared FROM last_access) as cleared_slots, + (SELECT total FROM last_access) - (SELECT count FROM new_slots) as modified_slots +` + +// Query to get top contributors for latest block +const queryLatestBlockTopContributors = ` +WITH latest_block AS ( + SELECT max(block_number) as block_number + FROM {database}.int_address_storage_slot_first_access +), +new_slots AS ( + SELECT + address, + count() as new_slots + FROM {database}.int_address_storage_slot_first_access + WHERE block_number = (SELECT block_number FROM latest_block) + GROUP BY address +), +cleared_slots AS ( + SELECT + address, + countIf(value = '0x0000000000000000000000000000000000000000000000000000000000000000') as cleared_slots, + count() as modified_slots + FROM {database}.int_address_storage_slot_last_access + WHERE block_number = (SELECT block_number FROM latest_block) + GROUP BY address +) +SELECT + coalesce(n.address, c.address) as address, + coalesce(n.new_slots, 0) as new_slots, + coalesce(c.modified_slots, 0) as modified_slots, + coalesce(c.cleared_slots, 0) as cleared_slots, + (coalesce(n.new_slots, 0) - coalesce(c.cleared_slots, 0)) * {bytes_per_slot} as net_bytes +FROM new_slots n +FULL OUTER JOIN cleared_slots c ON n.address = c.address +ORDER BY abs(net_bytes) DESC +LIMIT 10 +` + +// Query to get top state adders for a period +const queryTopStateAdders = ` +WITH period_range AS ( + SELECT + max(block_number) as end_block, + max(block_number) - {blocks_in_period} as start_block + FROM {database}.int_address_storage_slot_first_access +) +SELECT + address, + count() as slots_added, + count() * {bytes_per_slot} as bytes_added +FROM {database}.int_address_storage_slot_first_access +WHERE block_number >= (SELECT start_block FROM period_range) + AND block_number <= (SELECT end_block FROM period_range) +GROUP BY address +ORDER BY slots_added DESC +LIMIT {limit} +` + +// Query to get top state removers for a period +const queryTopStateRemovers = ` +WITH period_range AS ( + SELECT + max(block_number) as end_block, + max(block_number) - {blocks_in_period} as start_block + FROM {database}.int_address_storage_slot_last_access +) +SELECT + address, + countIf(value = '0x0000000000000000000000000000000000000000000000000000000000000000') as slots_cleared, + countIf(value = '0x0000000000000000000000000000000000000000000000000000000000000000') * {bytes_per_slot} as bytes_freed +FROM {database}.int_address_storage_slot_last_access +WHERE block_number >= (SELECT start_block FROM period_range) + AND block_number <= (SELECT end_block FROM period_range) +GROUP BY address +HAVING slots_cleared > 0 +ORDER BY slots_cleared DESC +LIMIT {limit} +` + +// Query to get state growth chart data +const queryStateGrowthChart = ` +WITH period_range AS ( + SELECT + max(block_number) as end_block, + max(block_number) - {blocks_in_period} as start_block + FROM {database}.int_address_storage_slot_first_access +), +blocks_in_range AS ( + SELECT DISTINCT block_number + FROM {database}.int_address_storage_slot_first_access + WHERE block_number >= (SELECT start_block FROM period_range) + AND block_number <= (SELECT end_block FROM period_range) + UNION ALL + SELECT DISTINCT block_number + FROM {database}.int_address_storage_slot_last_access + WHERE block_number >= (SELECT start_block FROM period_range) + AND block_number <= (SELECT end_block FROM period_range) +), +aggregated_data AS ( + SELECT + {time_bucket_expression} as time_bucket, + sum(slots_added) as slots_added, + sum(slots_cleared) as slots_cleared + FROM ( + SELECT + block_number, + count() as slots_added, + 0 as slots_cleared + FROM {database}.int_address_storage_slot_first_access + WHERE block_number >= (SELECT start_block FROM period_range) + GROUP BY block_number + + UNION ALL + + SELECT + block_number, + 0 as slots_added, + countIf(value = '0x0000000000000000000000000000000000000000000000000000000000000000') as slots_cleared + FROM {database}.int_address_storage_slot_last_access + WHERE block_number >= (SELECT start_block FROM period_range) + GROUP BY block_number + ) + GROUP BY time_bucket +) +SELECT + time_bucket, + slots_added, + slots_cleared, + slots_added - slots_cleared as net_slots, + slots_added * {bytes_per_slot} as bytes_added, + slots_cleared * {bytes_per_slot} as bytes_cleared, + (slots_added - slots_cleared) * {bytes_per_slot} as net_bytes +FROM aggregated_data +ORDER BY time_bucket ASC +` + +// Helper function to get block number from timestamp +const queryBlockNumberFromTimestamp = ` +SELECT block_number +FROM {database}.int_address_storage_slot_first_access +WHERE block_number >= 0 +ORDER BY abs( + block_number - ( + {genesis_time} + + (toUnixTimestamp('{target_timestamp}') - {genesis_time}) / 12 + ) +) ASC +LIMIT 1 +` diff --git a/backend/pkg/server/internal/service/state_analytics/queries_test.go b/backend/pkg/server/internal/service/state_analytics/queries_test.go new file mode 100644 index 000000000..5e9aaf664 --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/queries_test.go @@ -0,0 +1,159 @@ +package state_analytics + +import ( + "strings" + "testing" +) + +// TestConstants verifies that our constants are set correctly +func TestConstants(t *testing.T) { + tests := []struct { + name string + value int + expected int + }{ + {"BytesPerSlot", BytesPerSlot, 191}, + {"BlocksPerHour", BlocksPerHour, 300}, + {"BlocksPer24Hours", BlocksPer24Hours, 7200}, + {"BlocksPer7Days", BlocksPer7Days, 50400}, + {"BlocksPer30Days", BlocksPer30Days, 216000}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.value != tt.expected { + t.Errorf("%s = %d, expected %d", tt.name, tt.value, tt.expected) + } + }) + } +} + +// TestQueryTemplatesExist verifies that all query templates are defined and non-empty +func TestQueryTemplatesExist(t *testing.T) { + queries := map[string]string{ + "queryLatestBlockDelta": queryLatestBlockDelta, + "queryLatestBlockTopContributors": queryLatestBlockTopContributors, + "queryTopStateAdders": queryTopStateAdders, + "queryTopStateRemovers": queryTopStateRemovers, + "queryStateGrowthChart": queryStateGrowthChart, + "queryBlockNumberFromTimestamp": queryBlockNumberFromTimestamp, + } + + for name, query := range queries { + t.Run(name, func(t *testing.T) { + if query == "" { + t.Errorf("Query template %s is empty", name) + } + if len(query) < 50 { + t.Errorf("Query template %s seems too short (%d chars), might be incomplete", name, len(query)) + } + }) + } +} + +// TestQueryTemplatesHavePlaceholders verifies that query templates have the expected placeholders +func TestQueryTemplatesHavePlaceholders(t *testing.T) { + tests := []struct { + name string + query string + placeholders []string + }{ + { + name: "queryLatestBlockDelta", + query: queryLatestBlockDelta, + placeholders: []string{"{database}"}, + }, + { + name: "queryLatestBlockTopContributors", + query: queryLatestBlockTopContributors, + placeholders: []string{"{database}", "{bytes_per_slot}"}, + }, + { + name: "queryTopStateAdders", + query: queryTopStateAdders, + placeholders: []string{"{database}", "{blocks_in_period}", "{bytes_per_slot}", "{limit}"}, + }, + { + name: "queryTopStateRemovers", + query: queryTopStateRemovers, + placeholders: []string{"{database}", "{blocks_in_period}", "{bytes_per_slot}", "{limit}"}, + }, + { + name: "queryStateGrowthChart", + query: queryStateGrowthChart, + placeholders: []string{"{database}", "{blocks_in_period}", "{time_bucket_expression}", "{bytes_per_slot}"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + for _, placeholder := range tt.placeholders { + if !strings.Contains(tt.query, placeholder) { + t.Errorf("Query %s is missing placeholder: %s", tt.name, placeholder) + } + } + }) + } +} + +// TestQueryTemplatesSQLSyntax does basic SQL syntax validation +func TestQueryTemplatesSQLSyntax(t *testing.T) { + queries := map[string]string{ + "queryLatestBlockDelta": queryLatestBlockDelta, + "queryLatestBlockTopContributors": queryLatestBlockTopContributors, + "queryTopStateAdders": queryTopStateAdders, + "queryTopStateRemovers": queryTopStateRemovers, + "queryStateGrowthChart": queryStateGrowthChart, + } + + for name, query := range queries { + t.Run(name, func(t *testing.T) { + // Check for balanced parentheses + openCount := strings.Count(query, "(") + closeCount := strings.Count(query, ")") + if openCount != closeCount { + t.Errorf("Query %s has unbalanced parentheses: %d open, %d close", name, openCount, closeCount) + } + + // Check that query starts with SELECT, WITH, or whitespace + trimmed := strings.TrimSpace(query) + if !strings.HasPrefix(trimmed, "SELECT") && !strings.HasPrefix(trimmed, "WITH") { + t.Errorf("Query %s doesn't start with SELECT or WITH", name) + } + + // Check for common ClickHouse keywords + upperQuery := strings.ToUpper(query) + if !strings.Contains(upperQuery, "SELECT") { + t.Errorf("Query %s is missing SELECT keyword", name) + } + if !strings.Contains(upperQuery, "FROM") { + t.Errorf("Query %s is missing FROM keyword", name) + } + }) + } +} + +// TestBlockTimeCalculations verifies that block time calculations are correct +func TestBlockTimeCalculations(t *testing.T) { + // With 12 second block time: + // 1 hour = 3600s / 12s = 300 blocks + // 24 hours = 300 * 24 = 7200 blocks + // 7 days = 7200 * 7 = 50400 blocks + // 30 days = 7200 * 30 = 216000 blocks + + if BlocksPerHour != 3600/12 { + t.Errorf("BlocksPerHour calculation incorrect: got %d, expected %d", BlocksPerHour, 3600/12) + } + + if BlocksPer24Hours != BlocksPerHour*24 { + t.Errorf("BlocksPer24Hours calculation incorrect: got %d, expected %d", BlocksPer24Hours, BlocksPerHour*24) + } + + if BlocksPer7Days != BlocksPer24Hours*7 { + t.Errorf("BlocksPer7Days calculation incorrect: got %d, expected %d", BlocksPer7Days, BlocksPer24Hours*7) + } + + if BlocksPer30Days != BlocksPer24Hours*30 { + t.Errorf("BlocksPer30Days calculation incorrect: got %d, expected %d", BlocksPer30Days, BlocksPer24Hours*30) + } +} diff --git a/backend/pkg/server/internal/service/state_analytics/service.go b/backend/pkg/server/internal/service/state_analytics/service.go new file mode 100644 index 000000000..0611b603d --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/service.go @@ -0,0 +1,200 @@ +package state_analytics + +import ( + "context" + "fmt" + + "github.com/ethpandaops/lab/backend/pkg/internal/lab/clickhouse" + "github.com/ethpandaops/lab/backend/pkg/internal/lab/metrics" + pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" + "github.com/prometheus/client_golang/prometheus" + "github.com/sirupsen/logrus" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +const ( + ServiceName = "state_analytics" + StatusError = "error" + StatusSuccess = "success" +) + +// Service provides state analytics functionality +type Service struct { + pb.UnimplementedStateAnalyticsServer + + log logrus.FieldLogger + config *Config + clickhouseClient map[string]clickhouse.Client // Network name -> ClickHouse client + + metrics *metrics.Metrics + metricsCollector *metrics.Collector + + // Metric collectors + requestsTotal *prometheus.CounterVec + requestDuration *prometheus.HistogramVec +} + +// New creates a new state analytics service +func New( + log logrus.FieldLogger, + config *Config, + metricsSvc *metrics.Metrics, +) (*Service, error) { + if err := config.Validate(); err != nil { + return nil, fmt.Errorf("invalid state_analytics config: %w", err) + } + + var metricsCollector *metrics.Collector + if metricsSvc != nil { + metricsCollector = metricsSvc.NewCollector(ServiceName) + log.Debug("Created metrics collector for state_analytics service") + } + + return &Service{ + log: log.WithField("component", "service/"+ServiceName), + config: config, + metrics: metricsSvc, + metricsCollector: metricsCollector, + clickhouseClient: make(map[string]clickhouse.Client), + }, nil +} + +// Name returns the service name +func (s *Service) Name() string { + return ServiceName +} + +// Start initializes and starts the state analytics service +func (s *Service) Start(ctx context.Context) error { + s.log.Info("Starting State Analytics service") + + // Initialize metrics + if err := s.initializeMetrics(); err != nil { + return fmt.Errorf("failed to initialize metrics: %w", err) + } + + // Initialize ClickHouse clients for each network + for networkName, networkConfig := range s.config.NetworkConfigs { + if !networkConfig.Enabled { + s.log.WithField("network", networkName).Debug("Network disabled, skipping") + continue + } + + if networkConfig.ClickHouse == nil { + s.log.WithField("network", networkName).Warn("Network enabled but no ClickHouse config provided") + continue + } + + client, err := clickhouse.New(networkConfig.ClickHouse, s.log, networkName, s.metrics) + if err != nil { + return fmt.Errorf("failed to create ClickHouse client for network %s: %w", networkName, err) + } + + if err := client.Start(ctx); err != nil { + s.log.WithField("network", networkName).WithError(err).Warn("Failed to start ClickHouse client") + continue + } + + s.clickhouseClient[networkName] = client + s.log.WithField("network", networkName).Info("Initialized ClickHouse client for state analytics") + } + + if len(s.clickhouseClient) == 0 { + return fmt.Errorf("no ClickHouse clients were successfully initialized") + } + + s.log.WithField("networks", len(s.clickhouseClient)).Info("State Analytics service started successfully") + + return nil +} + +// Stop gracefully stops the state analytics service +func (s *Service) Stop() error { + s.log.Info("Stopping State Analytics service") + + // Stop all ClickHouse clients + for network, client := range s.clickhouseClient { + if err := client.Stop(); err != nil { + s.log.WithField("network", network).WithError(err).Warn("Failed to stop ClickHouse client") + } + } + + s.log.Info("State Analytics service stopped") + + return nil +} + +// initializeMetrics sets up Prometheus metrics for the service +func (s *Service) initializeMetrics() error { + if s.metricsCollector == nil { + return nil + } + + var err error + + s.requestsTotal, err = s.metricsCollector.NewCounterVec( + "requests_total", + "Total number of state analytics requests", + []string{"method", "network", "status"}, + ) + if err != nil { + return fmt.Errorf("failed to create requests_total metric: %w", err) + } + + s.requestDuration, err = s.metricsCollector.NewHistogramVec( + "request_duration_seconds", + "Duration of state analytics requests", + []string{"method", "network"}, + prometheus.DefBuckets, + ) + if err != nil { + return fmt.Errorf("failed to create request_duration metric: %w", err) + } + + return nil +} + +// getNetworkFromContext extracts the network name from gRPC metadata +func (s *Service) getNetworkFromContext(ctx context.Context) (string, error) { + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return "", status.Error(codes.InvalidArgument, "missing metadata") + } + + networks := md.Get("network") + if len(networks) == 0 { + return "", status.Error(codes.InvalidArgument, "network not specified in metadata") + } + + network := networks[0] + + // Validate network exists in our clients + if _, exists := s.clickhouseClient[network]; !exists { + return "", status.Errorf(codes.NotFound, "network %s not configured", network) + } + + return network, nil +} + +// getClient returns the ClickHouse client for a given network +func (s *Service) getClient(network string) (clickhouse.Client, error) { + client, exists := s.clickhouseClient[network] + if !exists { + return nil, fmt.Errorf("no ClickHouse client for network: %s", network) + } + + return client, nil +} + +// recordMetrics records request metrics if metrics are enabled +func (s *Service) recordMetrics(method, network, status string, duration float64) { + if s.requestsTotal != nil { + s.requestsTotal.WithLabelValues(method, network, status).Inc() + } + + if s.requestDuration != nil { + s.requestDuration.WithLabelValues(method, network).Observe(duration) + } +} diff --git a/backend/pkg/server/internal/service/state_analytics/service_test.go b/backend/pkg/server/internal/service/state_analytics/service_test.go new file mode 100644 index 000000000..83d151d1e --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/service_test.go @@ -0,0 +1,238 @@ +package state_analytics + +import ( + "testing" + + "github.com/ethpandaops/lab/backend/pkg/internal/lab/clickhouse" + "github.com/sirupsen/logrus" +) + +// TestNew verifies that the service can be created with valid config +func TestNew(t *testing.T) { + log := logrus.New() + log.SetLevel(logrus.ErrorLevel) // Reduce noise in tests + + tests := []struct { + name string + config *Config + wantError bool + }{ + { + name: "valid config", + config: &Config{ + NetworkConfigs: map[string]*NetworkConfig{ + "mainnet": { + Enabled: true, + ClickHouse: &clickhouse.Config{ + DSN: "clickhouse://localhost:9000/mainnet", + }, + }, + }, + }, + wantError: false, + }, + { + name: "nil config", + config: nil, + wantError: true, + }, + { + name: "empty network configs", + config: &Config{ + NetworkConfigs: map[string]*NetworkConfig{}, + }, + wantError: true, + }, + { + name: "enabled network without clickhouse config", + config: &Config{ + NetworkConfigs: map[string]*NetworkConfig{ + "mainnet": { + Enabled: true, + ClickHouse: nil, + }, + }, + }, + wantError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + svc, err := New(log, tt.config, nil) + + if tt.wantError { + if err == nil { + t.Error("Expected error but got none") + } + } else { + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + if svc == nil { + t.Error("Expected service but got nil") + } + if svc != nil && svc.Name() != ServiceName { + t.Errorf("Service name = %s, expected %s", svc.Name(), ServiceName) + } + } + }) + } +} + +// TestServiceName verifies the service name is correct +func TestServiceName(t *testing.T) { + log := logrus.New() + log.SetLevel(logrus.ErrorLevel) + + config := &Config{ + NetworkConfigs: map[string]*NetworkConfig{ + "mainnet": { + Enabled: true, + ClickHouse: &clickhouse.Config{ + DSN: "clickhouse://localhost:9000/mainnet", + }, + }, + }, + } + + svc, err := New(log, config, nil) + if err != nil { + t.Fatalf("Failed to create service: %v", err) + } + + if svc.Name() != "state_analytics" { + t.Errorf("Name() = %s, expected state_analytics", svc.Name()) + } +} + +// TestConfigValidation tests the config validation +func TestConfigValidation(t *testing.T) { + tests := []struct { + name string + config *Config + wantError bool + }{ + { + name: "nil config", + config: nil, + wantError: true, + }, + { + name: "empty network configs", + config: &Config{ + NetworkConfigs: map[string]*NetworkConfig{}, + }, + wantError: true, + }, + { + name: "nil network config", + config: &Config{ + NetworkConfigs: map[string]*NetworkConfig{ + "mainnet": nil, + }, + }, + wantError: true, + }, + { + name: "enabled without clickhouse", + config: &Config{ + NetworkConfigs: map[string]*NetworkConfig{ + "mainnet": { + Enabled: true, + ClickHouse: nil, + }, + }, + }, + wantError: true, + }, + { + name: "disabled without clickhouse (ok)", + config: &Config{ + NetworkConfigs: map[string]*NetworkConfig{ + "mainnet": { + Enabled: false, + ClickHouse: nil, + }, + }, + }, + wantError: false, + }, + { + name: "valid single network", + config: &Config{ + NetworkConfigs: map[string]*NetworkConfig{ + "mainnet": { + Enabled: true, + ClickHouse: &clickhouse.Config{ + DSN: "clickhouse://localhost:9000/mainnet", + }, + }, + }, + }, + wantError: false, + }, + { + name: "valid multiple networks", + config: &Config{ + NetworkConfigs: map[string]*NetworkConfig{ + "mainnet": { + Enabled: true, + ClickHouse: &clickhouse.Config{ + DSN: "clickhouse://localhost:9000/mainnet", + }, + }, + "sepolia": { + Enabled: true, + ClickHouse: &clickhouse.Config{ + DSN: "clickhouse://localhost:9000/sepolia", + }, + }, + }, + }, + wantError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.config.Validate() + + if tt.wantError { + if err == nil { + t.Error("Expected validation error but got none") + } + } else { + if err != nil { + t.Errorf("Unexpected validation error: %v", err) + } + } + }) + } +} + +// TestRecordMetrics verifies metrics recording doesn't panic +func TestRecordMetrics(t *testing.T) { + log := logrus.New() + log.SetLevel(logrus.ErrorLevel) + + config := &Config{ + NetworkConfigs: map[string]*NetworkConfig{ + "mainnet": { + Enabled: true, + ClickHouse: &clickhouse.Config{ + DSN: "clickhouse://localhost:9000/mainnet", + }, + }, + }, + } + + svc, err := New(log, config, nil) + if err != nil { + t.Fatalf("Failed to create service: %v", err) + } + + // Should not panic even with nil metrics + svc.recordMetrics("TestMethod", "mainnet", StatusSuccess, 0.123) + svc.recordMetrics("TestMethod", "mainnet", StatusError, 0.456) +} diff --git a/backend/pkg/server/internal/service/state_analytics/state_growth_chart.go b/backend/pkg/server/internal/service/state_analytics/state_growth_chart.go new file mode 100644 index 000000000..98fd65f33 --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/state_growth_chart.go @@ -0,0 +1,178 @@ +package state_analytics + +import ( + "context" + "fmt" + "strings" + "time" + + pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" + "google.golang.org/protobuf/types/known/timestamppb" +) + +const ( + // Genesis times for different networks (Unix timestamps) + GenesisTimeMainnet = 1606824023 // Dec 1, 2020 12:00:23 PM UTC + GenesisTimeHolesky = 1695902400 // Sep 28, 2023 12:00:00 PM UTC + GenesisTimeHoodi = 1712923200 // Apr 12, 2024 12:00:00 PM UTC + GenesisTimeSepolia = 1655733600 // Jun 20, 2022 2:00:00 PM UTC +) + +// GetStateGrowthChart returns time-series data of state growth +func (s *Service) GetStateGrowthChart( + ctx context.Context, + req *pb.GetStateGrowthChartRequest, +) (*pb.GetStateGrowthChartResponse, error) { + startTime := time.Now() + method := "GetStateGrowthChart" + + // Get network from context + network, err := s.getNetworkFromContext(ctx) + if err != nil { + s.recordMetrics(method, "unknown", StatusError, time.Since(startTime).Seconds()) + return nil, err + } + + s.log.WithField("network", network).Debug("Fetching state growth chart") + + // Get ClickHouse client for network + client, err := s.getClient(network) + if err != nil { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, err + } + + // Determine blocks in period + var blocksInPeriod uint64 + switch req.Period { + case pb.GetStateGrowthChartRequest_PERIOD_24H: + blocksInPeriod = uint64(BlocksPer24Hours) + case pb.GetStateGrowthChartRequest_PERIOD_7D: + blocksInPeriod = uint64(BlocksPer7Days) + case pb.GetStateGrowthChartRequest_PERIOD_30D: + blocksInPeriod = uint64(BlocksPer30Days) + case pb.GetStateGrowthChartRequest_PERIOD_90D: + blocksInPeriod = uint64(BlocksPer30Days * 3) + default: + blocksInPeriod = uint64(BlocksPer24Hours) // Default to 24h + } + + // Determine time bucket expression based on granularity + var timeBucketExpr string + switch req.Granularity { + case pb.GetStateGrowthChartRequest_GRANULARITY_BLOCK: + timeBucketExpr = "block_number" + case pb.GetStateGrowthChartRequest_GRANULARITY_HOUR: + // Group by hour (300 blocks per hour) + timeBucketExpr = "intDiv(block_number, 300) * 300" + case pb.GetStateGrowthChartRequest_GRANULARITY_DAY: + // Group by day (7200 blocks per day) + timeBucketExpr = "intDiv(block_number, 7200) * 7200" + default: + // Default to hourly for reasonable data points + timeBucketExpr = "intDiv(block_number, 300) * 300" + } + + // Build query with replacements + query := queryStateGrowthChart + query = strings.ReplaceAll(query, "{database}", network) + query = strings.ReplaceAll(query, "{blocks_in_period}", fmt.Sprintf("%d", blocksInPeriod)) + query = strings.ReplaceAll(query, "{bytes_per_slot}", fmt.Sprintf("%d", BytesPerSlot)) + query = strings.ReplaceAll(query, "{time_bucket_expression}", timeBucketExpr) + + // Execute query + rows, err := client.Query(ctx, query) + if err != nil { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, fmt.Errorf("failed to query state growth chart: %w", err) + } + + if len(rows) == 0 { + s.recordMetrics(method, network, StatusSuccess, time.Since(startTime).Seconds()) + return &pb.GetStateGrowthChartResponse{ + DataPoints: []*pb.StateGrowthDataPoint{}, + Summary: &pb.StateSummary{}, + }, nil + } + + // Get genesis time for network + genesisTime := s.getGenesisTime(network) + + // Parse results into data points + dataPoints := make([]*pb.StateGrowthDataPoint, 0, len(rows)) + var totalSlotsAdded, totalSlotsCleared uint64 + var totalBytesAdded, totalBytesCleared uint64 + + for _, row := range rows { + blockNumber := getUint64(row, "time_bucket") + slotsAdded := getUint64(row, "slots_added") + slotsCleared := getUint64(row, "slots_cleared") + netSlots := getInt64(row, "net_slots") + bytesAdded := getUint64(row, "bytes_added") + bytesCleared := getUint64(row, "bytes_cleared") + netBytes := getInt64(row, "net_bytes") + + // Calculate timestamp (block time = genesis + block_number * 12 seconds) + blockTimestamp := time.Unix(genesisTime+int64(blockNumber)*12, 0) + + dataPoint := &pb.StateGrowthDataPoint{ + Timestamp: timestamppb.New(blockTimestamp), + BlockNumber: blockNumber, + SlotsAdded: slotsAdded, + SlotsCleared: slotsCleared, + NetSlots: netSlots, + BytesAdded: bytesAdded, + BytesCleared: bytesCleared, + NetBytes: netBytes, + } + + dataPoints = append(dataPoints, dataPoint) + + // Accumulate totals + totalSlotsAdded += slotsAdded + totalSlotsCleared += slotsCleared + totalBytesAdded += bytesAdded + totalBytesCleared += bytesCleared + } + + // Calculate summary statistics + netSlots := int64(totalSlotsAdded) - int64(totalSlotsCleared) + netBytes := int64(totalBytesAdded) - int64(totalBytesCleared) + avgSlotsPerBlock := float64(0) + if len(dataPoints) > 0 { + avgSlotsPerBlock = float64(totalSlotsAdded) / float64(len(dataPoints)) + } + + summary := &pb.StateSummary{ + TotalSlotsAdded: totalSlotsAdded, + TotalSlotsCleared: totalSlotsCleared, + NetSlots: netSlots, + TotalBytesAdded: totalBytesAdded, + TotalBytesCleared: totalBytesCleared, + NetBytes: netBytes, + AvgSlotsPerBlock: avgSlotsPerBlock, + } + + s.recordMetrics(method, network, StatusSuccess, time.Since(startTime).Seconds()) + + return &pb.GetStateGrowthChartResponse{ + DataPoints: dataPoints, + Summary: summary, + }, nil +} + +// getGenesisTime returns the genesis timestamp for a given network +func (s *Service) getGenesisTime(network string) int64 { + switch network { + case "mainnet": + return GenesisTimeMainnet + case "holesky": + return GenesisTimeHolesky + case "hoodi": + return GenesisTimeHoodi + case "sepolia": + return GenesisTimeSepolia + default: + return GenesisTimeMainnet // Default to mainnet + } +} diff --git a/backend/pkg/server/internal/service/state_analytics/state_growth_chart_test.go b/backend/pkg/server/internal/service/state_analytics/state_growth_chart_test.go new file mode 100644 index 000000000..cef35567d --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/state_growth_chart_test.go @@ -0,0 +1,254 @@ +package state_analytics + +import ( + "testing" + + pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" +) + +// TestGetStateGrowthChartRequest validates the request message +func TestGetStateGrowthChartRequest(t *testing.T) { + tests := []struct { + name string + period pb.GetStateGrowthChartRequest_Period + granularity pb.GetStateGrowthChartRequest_Granularity + }{ + { + name: "24h with block granularity", + period: pb.GetStateGrowthChartRequest_PERIOD_24H, + granularity: pb.GetStateGrowthChartRequest_GRANULARITY_BLOCK, + }, + { + name: "7d with hourly granularity", + period: pb.GetStateGrowthChartRequest_PERIOD_7D, + granularity: pb.GetStateGrowthChartRequest_GRANULARITY_HOUR, + }, + { + name: "30d with daily granularity", + period: pb.GetStateGrowthChartRequest_PERIOD_30D, + granularity: pb.GetStateGrowthChartRequest_GRANULARITY_DAY, + }, + { + name: "90d with daily granularity", + period: pb.GetStateGrowthChartRequest_PERIOD_90D, + granularity: pb.GetStateGrowthChartRequest_GRANULARITY_DAY, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + req := &pb.GetStateGrowthChartRequest{ + Period: tt.period, + Granularity: tt.granularity, + } + + if req.Period != tt.period { + t.Errorf("Expected period %v, got %v", tt.period, req.Period) + } + if req.Granularity != tt.granularity { + t.Errorf("Expected granularity %v, got %v", tt.granularity, req.Granularity) + } + }) + } +} + +// TestTimeBucketExpression validates time bucket expressions +func TestTimeBucketExpression(t *testing.T) { + tests := []struct { + name string + granularity pb.GetStateGrowthChartRequest_Granularity + expectedExpr string + }{ + { + name: "block granularity", + granularity: pb.GetStateGrowthChartRequest_GRANULARITY_BLOCK, + expectedExpr: "block_number", + }, + { + name: "hour granularity", + granularity: pb.GetStateGrowthChartRequest_GRANULARITY_HOUR, + expectedExpr: "intDiv(block_number, 300) * 300", + }, + { + name: "day granularity", + granularity: pb.GetStateGrowthChartRequest_GRANULARITY_DAY, + expectedExpr: "intDiv(block_number, 7200) * 7200", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var expr string + switch tt.granularity { + case pb.GetStateGrowthChartRequest_GRANULARITY_BLOCK: + expr = "block_number" + case pb.GetStateGrowthChartRequest_GRANULARITY_HOUR: + expr = "intDiv(block_number, 300) * 300" + case pb.GetStateGrowthChartRequest_GRANULARITY_DAY: + expr = "intDiv(block_number, 7200) * 7200" + default: + expr = "intDiv(block_number, 300) * 300" + } + + if expr != tt.expectedExpr { + t.Errorf("Expected expression %s, got %s", tt.expectedExpr, expr) + } + }) + } +} + +// TestChartPeriodBlockCalculation validates block period calculations +func TestChartPeriodBlockCalculation(t *testing.T) { + tests := []struct { + name string + period pb.GetStateGrowthChartRequest_Period + expectedBlocks uint64 + }{ + { + name: "24 hours", + period: pb.GetStateGrowthChartRequest_PERIOD_24H, + expectedBlocks: uint64(BlocksPer24Hours), + }, + { + name: "7 days", + period: pb.GetStateGrowthChartRequest_PERIOD_7D, + expectedBlocks: uint64(BlocksPer7Days), + }, + { + name: "30 days", + period: pb.GetStateGrowthChartRequest_PERIOD_30D, + expectedBlocks: uint64(BlocksPer30Days), + }, + { + name: "90 days", + period: pb.GetStateGrowthChartRequest_PERIOD_90D, + expectedBlocks: uint64(BlocksPer30Days * 3), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var blocksInPeriod uint64 + switch tt.period { + case pb.GetStateGrowthChartRequest_PERIOD_24H: + blocksInPeriod = uint64(BlocksPer24Hours) + case pb.GetStateGrowthChartRequest_PERIOD_7D: + blocksInPeriod = uint64(BlocksPer7Days) + case pb.GetStateGrowthChartRequest_PERIOD_30D: + blocksInPeriod = uint64(BlocksPer30Days) + case pb.GetStateGrowthChartRequest_PERIOD_90D: + blocksInPeriod = uint64(BlocksPer30Days * 3) + default: + blocksInPeriod = uint64(BlocksPer24Hours) + } + + if blocksInPeriod != tt.expectedBlocks { + t.Errorf("Expected %d blocks, got %d", tt.expectedBlocks, blocksInPeriod) + } + }) + } +} + +// TestGenesisTime validates genesis time constants +func TestGenesisTime(t *testing.T) { + tests := []struct { + name string + network string + expectedGenesisTime int64 + }{ + { + name: "mainnet", + network: "mainnet", + expectedGenesisTime: GenesisTimeMainnet, + }, + { + name: "holesky", + network: "holesky", + expectedGenesisTime: GenesisTimeHolesky, + }, + { + name: "hoodi", + network: "hoodi", + expectedGenesisTime: GenesisTimeHoodi, + }, + { + name: "sepolia", + network: "sepolia", + expectedGenesisTime: GenesisTimeSepolia, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a mock service + svc := &Service{} + genesisTime := svc.getGenesisTime(tt.network) + + if genesisTime != tt.expectedGenesisTime { + t.Errorf("Expected genesis time %d, got %d", tt.expectedGenesisTime, genesisTime) + } + }) + } +} + +// TestSummaryCalculations validates summary statistics +func TestSummaryCalculations(t *testing.T) { + tests := []struct { + name string + totalSlotsAdded uint64 + totalSlotsCleared uint64 + dataPoints int + expectedNetSlots int64 + expectedAvgSlots float64 + }{ + { + name: "positive growth", + totalSlotsAdded: 1000, + totalSlotsCleared: 500, + dataPoints: 10, + expectedNetSlots: 500, + expectedAvgSlots: 100.0, + }, + { + name: "negative growth", + totalSlotsAdded: 500, + totalSlotsCleared: 1000, + dataPoints: 10, + expectedNetSlots: -500, + expectedAvgSlots: 50.0, + }, + { + name: "no change", + totalSlotsAdded: 1000, + totalSlotsCleared: 1000, + dataPoints: 10, + expectedNetSlots: 0, + expectedAvgSlots: 100.0, + }, + { + name: "no data points", + totalSlotsAdded: 1000, + totalSlotsCleared: 500, + dataPoints: 0, + expectedNetSlots: 500, + expectedAvgSlots: 0.0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + netSlots := int64(tt.totalSlotsAdded) - int64(tt.totalSlotsCleared) + var avgSlots float64 + if tt.dataPoints > 0 { + avgSlots = float64(tt.totalSlotsAdded) / float64(tt.dataPoints) + } + + if netSlots != tt.expectedNetSlots { + t.Errorf("Expected net slots %d, got %d", tt.expectedNetSlots, netSlots) + } + if avgSlots != tt.expectedAvgSlots { + t.Errorf("Expected avg slots %.2f, got %.2f", tt.expectedAvgSlots, avgSlots) + } + }) + } +} diff --git a/backend/pkg/server/internal/service/state_analytics/top_state_adders.go b/backend/pkg/server/internal/service/state_analytics/top_state_adders.go new file mode 100644 index 000000000..ed209a2db --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/top_state_adders.go @@ -0,0 +1,140 @@ +package state_analytics + +import ( + "context" + "fmt" + "strings" + "time" + + pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" +) + +// GetTopStateAdders returns contracts that created the most new storage slots in a given period +func (s *Service) GetTopStateAdders( + ctx context.Context, + req *pb.GetTopStateAddersRequest, +) (*pb.GetTopStateAddersResponse, error) { + startTime := time.Now() + method := "GetTopStateAdders" + + // Get network from context + network, err := s.getNetworkFromContext(ctx) + if err != nil { + s.recordMetrics(method, "unknown", StatusError, time.Since(startTime).Seconds()) + return nil, err + } + + s.log.WithField("network", network).Debug("Fetching top state adders") + + // Get ClickHouse client for network + client, err := s.getClient(network) + if err != nil { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, err + } + + // Determine blocks in period + var blocksInPeriod uint64 + switch req.Period { + case pb.GetTopStateAddersRequest_PERIOD_24H: + blocksInPeriod = uint64(BlocksPer24Hours) + case pb.GetTopStateAddersRequest_PERIOD_7D: + blocksInPeriod = uint64(BlocksPer7Days) + case pb.GetTopStateAddersRequest_PERIOD_30D: + blocksInPeriod = uint64(BlocksPer30Days) + default: + blocksInPeriod = uint64(BlocksPer24Hours) // Default to 24h + } + + // Determine limit (default 100, max 1000) + limit := req.Limit + if limit == 0 { + limit = 100 + } + if limit > 1000 { + limit = 1000 + } + + // Build query with replacements + query := queryTopStateAdders + query = strings.ReplaceAll(query, "{database}", network) + query = strings.ReplaceAll(query, "{blocks_in_period}", fmt.Sprintf("%d", blocksInPeriod)) + query = strings.ReplaceAll(query, "{bytes_per_slot}", fmt.Sprintf("%d", BytesPerSlot)) + query = strings.ReplaceAll(query, "{limit}", fmt.Sprintf("%d", limit)) + + // Execute query + rows, err := client.Query(ctx, query) + if err != nil { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, fmt.Errorf("failed to query top state adders: %w", err) + } + + if len(rows) == 0 { + s.recordMetrics(method, network, StatusSuccess, time.Since(startTime).Seconds()) + return &pb.GetTopStateAddersResponse{ + Adders: []*pb.StateAdder{}, + StartBlock: 0, + EndBlock: 0, + }, nil + } + + // Get block range for response + blockRangeQuery := fmt.Sprintf(` + SELECT + max(block_number) as end_block, + max(block_number) - %d as start_block + FROM %s.int_address_storage_slot_first_access + `, blocksInPeriod, network) + + blockRangeRows, err := client.Query(ctx, blockRangeQuery) + if err != nil { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, fmt.Errorf("failed to query block range: %w", err) + } + + var startBlock, endBlock uint64 + if len(blockRangeRows) > 0 { + startBlock = getUint64(blockRangeRows[0], "start_block") + endBlock = getUint64(blockRangeRows[0], "end_block") + } + + // Calculate total slots added in period for percentage calculation + var totalSlotsAdded uint64 + for _, row := range rows { + totalSlotsAdded += getUint64(row, "slots_added") + } + + // Parse results + adders := make([]*pb.StateAdder, 0, len(rows)) + for i, row := range rows { + address := getString(row, "address") + slotsAdded := getUint64(row, "slots_added") + bytesAdded := getUint64(row, "bytes_added") + + // Calculate percentage of total + var percentage float64 + if totalSlotsAdded > 0 { + percentage = (float64(slotsAdded) / float64(totalSlotsAdded)) * 100.0 + } + + adder := &pb.StateAdder{ + Rank: uint32(i + 1), + Address: address, + SlotsAdded: slotsAdded, + EstimatedBytesAdded: bytesAdded, + Category: "", // TODO: Add contract categorization + Label: "", // TODO: Add contract labeling + PercentageOfTotal: percentage, + } + + adders = append(adders, adder) + } + + s.recordMetrics(method, network, StatusSuccess, time.Since(startTime).Seconds()) + + return &pb.GetTopStateAddersResponse{ + Adders: adders, + StartBlock: startBlock, + EndBlock: endBlock, + }, nil +} diff --git a/backend/pkg/server/internal/service/state_analytics/top_state_adders_test.go b/backend/pkg/server/internal/service/state_analytics/top_state_adders_test.go new file mode 100644 index 000000000..a439d86fd --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/top_state_adders_test.go @@ -0,0 +1,168 @@ +package state_analytics + +import ( + "testing" + + pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" +) + +// TestGetTopStateAddersRequest validates the request message +func TestGetTopStateAddersRequest(t *testing.T) { + tests := []struct { + name string + period pb.GetTopStateAddersRequest_Period + limit uint32 + expectedLimit uint32 // After validation + }{ + { + name: "default period and limit", + period: pb.GetTopStateAddersRequest_PERIOD_UNSPECIFIED, + limit: 0, + expectedLimit: 100, + }, + { + name: "24h period with custom limit", + period: pb.GetTopStateAddersRequest_PERIOD_24H, + limit: 50, + expectedLimit: 50, + }, + { + name: "7d period", + period: pb.GetTopStateAddersRequest_PERIOD_7D, + limit: 200, + expectedLimit: 200, + }, + { + name: "30d period", + period: pb.GetTopStateAddersRequest_PERIOD_30D, + limit: 100, + expectedLimit: 100, + }, + { + name: "limit exceeds maximum", + period: pb.GetTopStateAddersRequest_PERIOD_24H, + limit: 2000, + expectedLimit: 1000, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + req := &pb.GetTopStateAddersRequest{ + Period: tt.period, + Limit: tt.limit, + } + + // Validate limit application logic + limit := req.Limit + if limit == 0 { + limit = 100 + } + if limit > 1000 { + limit = 1000 + } + + if limit != tt.expectedLimit { + t.Errorf("Expected limit %d, got %d", tt.expectedLimit, limit) + } + }) + } +} + +// TestPeriodBlockCalculation validates block period calculations +func TestPeriodBlockCalculation(t *testing.T) { + tests := []struct { + name string + period pb.GetTopStateAddersRequest_Period + expectedBlocks uint64 + }{ + { + name: "24 hours", + period: pb.GetTopStateAddersRequest_PERIOD_24H, + expectedBlocks: uint64(BlocksPer24Hours), + }, + { + name: "7 days", + period: pb.GetTopStateAddersRequest_PERIOD_7D, + expectedBlocks: uint64(BlocksPer7Days), + }, + { + name: "30 days", + period: pb.GetTopStateAddersRequest_PERIOD_30D, + expectedBlocks: uint64(BlocksPer30Days), + }, + { + name: "unspecified defaults to 24h", + period: pb.GetTopStateAddersRequest_PERIOD_UNSPECIFIED, + expectedBlocks: uint64(BlocksPer24Hours), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var blocksInPeriod uint64 + switch tt.period { + case pb.GetTopStateAddersRequest_PERIOD_24H: + blocksInPeriod = uint64(BlocksPer24Hours) + case pb.GetTopStateAddersRequest_PERIOD_7D: + blocksInPeriod = uint64(BlocksPer7Days) + case pb.GetTopStateAddersRequest_PERIOD_30D: + blocksInPeriod = uint64(BlocksPer30Days) + default: + blocksInPeriod = uint64(BlocksPer24Hours) + } + + if blocksInPeriod != tt.expectedBlocks { + t.Errorf("Expected %d blocks, got %d", tt.expectedBlocks, blocksInPeriod) + } + }) + } +} + +// TestPercentageCalculation validates percentage calculations +func TestPercentageCalculation(t *testing.T) { + tests := []struct { + name string + slotsAdded uint64 + totalSlotsAdded uint64 + expectedPercentage float64 + }{ + { + name: "50% of total", + slotsAdded: 500, + totalSlotsAdded: 1000, + expectedPercentage: 50.0, + }, + { + name: "25% of total", + slotsAdded: 250, + totalSlotsAdded: 1000, + expectedPercentage: 25.0, + }, + { + name: "100% of total", + slotsAdded: 1000, + totalSlotsAdded: 1000, + expectedPercentage: 100.0, + }, + { + name: "zero total", + slotsAdded: 100, + totalSlotsAdded: 0, + expectedPercentage: 0.0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var percentage float64 + if tt.totalSlotsAdded > 0 { + percentage = (float64(tt.slotsAdded) / float64(tt.totalSlotsAdded)) * 100.0 + } + + if percentage != tt.expectedPercentage { + t.Errorf("Expected %.2f%%, got %.2f%%", tt.expectedPercentage, percentage) + } + }) + } +} diff --git a/backend/pkg/server/internal/service/state_analytics/top_state_removers.go b/backend/pkg/server/internal/service/state_analytics/top_state_removers.go new file mode 100644 index 000000000..79a3de200 --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/top_state_removers.go @@ -0,0 +1,145 @@ +package state_analytics + +import ( + "context" + "fmt" + "strings" + "time" + + pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" +) + +// GetTopStateRemovers returns contracts that cleared the most storage slots in a given period +func (s *Service) GetTopStateRemovers( + ctx context.Context, + req *pb.GetTopStateRemoversRequest, +) (*pb.GetTopStateRemoversResponse, error) { + startTime := time.Now() + method := "GetTopStateRemovers" + + // Get network from context + network, err := s.getNetworkFromContext(ctx) + if err != nil { + s.recordMetrics(method, "unknown", StatusError, time.Since(startTime).Seconds()) + return nil, err + } + + s.log.WithField("network", network).Debug("Fetching top state removers") + + // Get ClickHouse client for network + client, err := s.getClient(network) + if err != nil { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, err + } + + // Determine blocks in period + var blocksInPeriod uint64 + switch req.Period { + case pb.GetTopStateRemoversRequest_PERIOD_24H: + blocksInPeriod = uint64(BlocksPer24Hours) + case pb.GetTopStateRemoversRequest_PERIOD_7D: + blocksInPeriod = uint64(BlocksPer7Days) + case pb.GetTopStateRemoversRequest_PERIOD_30D: + blocksInPeriod = uint64(BlocksPer30Days) + default: + blocksInPeriod = uint64(BlocksPer24Hours) // Default to 24h + } + + // Determine limit (default 100, max 1000) + limit := req.Limit + if limit == 0 { + limit = 100 + } + if limit > 1000 { + limit = 1000 + } + + // Build query with replacements + query := queryTopStateRemovers + query = strings.ReplaceAll(query, "{database}", network) + query = strings.ReplaceAll(query, "{blocks_in_period}", fmt.Sprintf("%d", blocksInPeriod)) + query = strings.ReplaceAll(query, "{bytes_per_slot}", fmt.Sprintf("%d", BytesPerSlot)) + query = strings.ReplaceAll(query, "{limit}", fmt.Sprintf("%d", limit)) + + // Execute query + rows, err := client.Query(ctx, query) + if err != nil { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, fmt.Errorf("failed to query top state removers: %w", err) + } + + if len(rows) == 0 { + s.recordMetrics(method, network, StatusSuccess, time.Since(startTime).Seconds()) + return &pb.GetTopStateRemoversResponse{ + Removers: []*pb.StateRemover{}, + StartBlock: 0, + EndBlock: 0, + }, nil + } + + // Get block range for response + blockRangeQuery := fmt.Sprintf(` + SELECT + max(block_number) as end_block, + max(block_number) - %d as start_block + FROM %s.int_address_storage_slot_last_access + `, blocksInPeriod, network) + + blockRangeRows, err := client.Query(ctx, blockRangeQuery) + if err != nil { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, fmt.Errorf("failed to query block range: %w", err) + } + + var startBlock, endBlock uint64 + if len(blockRangeRows) > 0 { + startBlock = getUint64(blockRangeRows[0], "start_block") + endBlock = getUint64(blockRangeRows[0], "end_block") + } + + // Calculate total slots cleared in period for percentage calculation + var totalSlotsCleared uint64 + for _, row := range rows { + totalSlotsCleared += getUint64(row, "slots_cleared") + } + + // Parse results + removers := make([]*pb.StateRemover, 0, len(rows)) + for i, row := range rows { + address := getString(row, "address") + slotsCleared := getUint64(row, "slots_cleared") + bytesFreed := getUint64(row, "bytes_freed") + + // Calculate percentage of total + var percentage float64 + if totalSlotsCleared > 0 { + percentage = (float64(slotsCleared) / float64(totalSlotsCleared)) * 100.0 + } + + // Estimate gas refund (15,000 gas per slot cleared, approximate) + // This is a theoretical maximum, actual refunds are capped + estimatedGasRefund := slotsCleared * 15000 + + remover := &pb.StateRemover{ + Rank: uint32(i + 1), + Address: address, + SlotsCleared: slotsCleared, + EstimatedBytesFreed: bytesFreed, + EstimatedGasRefund: estimatedGasRefund, + Category: "", // TODO: Add contract categorization + Label: "", // TODO: Add contract labeling + PercentageOfTotal: percentage, + } + + removers = append(removers, remover) + } + + s.recordMetrics(method, network, StatusSuccess, time.Since(startTime).Seconds()) + + return &pb.GetTopStateRemoversResponse{ + Removers: removers, + StartBlock: startBlock, + EndBlock: endBlock, + }, nil +} diff --git a/backend/pkg/server/internal/service/state_analytics/top_state_removers_test.go b/backend/pkg/server/internal/service/state_analytics/top_state_removers_test.go new file mode 100644 index 000000000..38dc927d6 --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/top_state_removers_test.go @@ -0,0 +1,203 @@ +package state_analytics + +import ( + "testing" + + pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" +) + +// TestGetTopStateRemoversRequest validates the request message +func TestGetTopStateRemoversRequest(t *testing.T) { + tests := []struct { + name string + period pb.GetTopStateRemoversRequest_Period + limit uint32 + expectedLimit uint32 // After validation + }{ + { + name: "default period and limit", + period: pb.GetTopStateRemoversRequest_PERIOD_UNSPECIFIED, + limit: 0, + expectedLimit: 100, + }, + { + name: "24h period with custom limit", + period: pb.GetTopStateRemoversRequest_PERIOD_24H, + limit: 50, + expectedLimit: 50, + }, + { + name: "7d period", + period: pb.GetTopStateRemoversRequest_PERIOD_7D, + limit: 200, + expectedLimit: 200, + }, + { + name: "30d period", + period: pb.GetTopStateRemoversRequest_PERIOD_30D, + limit: 100, + expectedLimit: 100, + }, + { + name: "limit exceeds maximum", + period: pb.GetTopStateRemoversRequest_PERIOD_24H, + limit: 2000, + expectedLimit: 1000, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + req := &pb.GetTopStateRemoversRequest{ + Period: tt.period, + Limit: tt.limit, + } + + // Validate limit application logic + limit := req.Limit + if limit == 0 { + limit = 100 + } + if limit > 1000 { + limit = 1000 + } + + if limit != tt.expectedLimit { + t.Errorf("Expected limit %d, got %d", tt.expectedLimit, limit) + } + }) + } +} + +// TestGasRefundCalculation validates gas refund calculations +func TestGasRefundCalculation(t *testing.T) { + tests := []struct { + name string + slotsCleared uint64 + expectedGasRefund uint64 + gasRefundPerSlot uint64 + }{ + { + name: "single slot", + slotsCleared: 1, + gasRefundPerSlot: 15000, + expectedGasRefund: 15000, + }, + { + name: "10 slots", + slotsCleared: 10, + gasRefundPerSlot: 15000, + expectedGasRefund: 150000, + }, + { + name: "1000 slots", + slotsCleared: 1000, + gasRefundPerSlot: 15000, + expectedGasRefund: 15000000, + }, + { + name: "zero slots", + slotsCleared: 0, + gasRefundPerSlot: 15000, + expectedGasRefund: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gasRefund := tt.slotsCleared * tt.gasRefundPerSlot + + if gasRefund != tt.expectedGasRefund { + t.Errorf("Expected gas refund %d, got %d", tt.expectedGasRefund, gasRefund) + } + }) + } +} + +// TestBytesFreedCalculation validates bytes freed calculations +func TestBytesFreedCalculation(t *testing.T) { + tests := []struct { + name string + slotsCleared uint64 + expectedBytesFreed uint64 + }{ + { + name: "single slot", + slotsCleared: 1, + expectedBytesFreed: BytesPerSlot, + }, + { + name: "10 slots", + slotsCleared: 10, + expectedBytesFreed: 10 * BytesPerSlot, + }, + { + name: "1000 slots", + slotsCleared: 1000, + expectedBytesFreed: 1000 * BytesPerSlot, + }, + { + name: "zero slots", + slotsCleared: 0, + expectedBytesFreed: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + bytesFreed := tt.slotsCleared * BytesPerSlot + + if bytesFreed != tt.expectedBytesFreed { + t.Errorf("Expected bytes freed %d, got %d", tt.expectedBytesFreed, bytesFreed) + } + }) + } +} + +// TestRemoverPercentageCalculation validates percentage calculations for removers +func TestRemoverPercentageCalculation(t *testing.T) { + tests := []struct { + name string + slotsCleared uint64 + totalSlotsCleared uint64 + expectedPercentage float64 + }{ + { + name: "50% of total", + slotsCleared: 500, + totalSlotsCleared: 1000, + expectedPercentage: 50.0, + }, + { + name: "25% of total", + slotsCleared: 250, + totalSlotsCleared: 1000, + expectedPercentage: 25.0, + }, + { + name: "100% of total", + slotsCleared: 1000, + totalSlotsCleared: 1000, + expectedPercentage: 100.0, + }, + { + name: "zero total", + slotsCleared: 100, + totalSlotsCleared: 0, + expectedPercentage: 0.0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var percentage float64 + if tt.totalSlotsCleared > 0 { + percentage = (float64(tt.slotsCleared) / float64(tt.totalSlotsCleared)) * 100.0 + } + + if percentage != tt.expectedPercentage { + t.Errorf("Expected %.2f%%, got %.2f%%", tt.expectedPercentage, percentage) + } + }) + } +} diff --git a/backend/pkg/server/proto/state_analytics/state_analytics.pb.go b/backend/pkg/server/proto/state_analytics/state_analytics.pb.go new file mode 100644 index 000000000..f6c819cac --- /dev/null +++ b/backend/pkg/server/proto/state_analytics/state_analytics.pb.go @@ -0,0 +1,1755 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc v5.29.3 +// source: backend/pkg/server/proto/state_analytics/state_analytics.proto + +package state_analytics + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GetTopStateAddersRequest_Period int32 + +const ( + GetTopStateAddersRequest_PERIOD_UNSPECIFIED GetTopStateAddersRequest_Period = 0 + GetTopStateAddersRequest_PERIOD_24H GetTopStateAddersRequest_Period = 1 + GetTopStateAddersRequest_PERIOD_7D GetTopStateAddersRequest_Period = 2 + GetTopStateAddersRequest_PERIOD_30D GetTopStateAddersRequest_Period = 3 +) + +// Enum value maps for GetTopStateAddersRequest_Period. +var ( + GetTopStateAddersRequest_Period_name = map[int32]string{ + 0: "PERIOD_UNSPECIFIED", + 1: "PERIOD_24H", + 2: "PERIOD_7D", + 3: "PERIOD_30D", + } + GetTopStateAddersRequest_Period_value = map[string]int32{ + "PERIOD_UNSPECIFIED": 0, + "PERIOD_24H": 1, + "PERIOD_7D": 2, + "PERIOD_30D": 3, + } +) + +func (x GetTopStateAddersRequest_Period) Enum() *GetTopStateAddersRequest_Period { + p := new(GetTopStateAddersRequest_Period) + *p = x + return p +} + +func (x GetTopStateAddersRequest_Period) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (GetTopStateAddersRequest_Period) Descriptor() protoreflect.EnumDescriptor { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[0].Descriptor() +} + +func (GetTopStateAddersRequest_Period) Type() protoreflect.EnumType { + return &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[0] +} + +func (x GetTopStateAddersRequest_Period) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use GetTopStateAddersRequest_Period.Descriptor instead. +func (GetTopStateAddersRequest_Period) EnumDescriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{3, 0} +} + +type GetTopStateRemoversRequest_Period int32 + +const ( + GetTopStateRemoversRequest_PERIOD_UNSPECIFIED GetTopStateRemoversRequest_Period = 0 + GetTopStateRemoversRequest_PERIOD_24H GetTopStateRemoversRequest_Period = 1 + GetTopStateRemoversRequest_PERIOD_7D GetTopStateRemoversRequest_Period = 2 + GetTopStateRemoversRequest_PERIOD_30D GetTopStateRemoversRequest_Period = 3 +) + +// Enum value maps for GetTopStateRemoversRequest_Period. +var ( + GetTopStateRemoversRequest_Period_name = map[int32]string{ + 0: "PERIOD_UNSPECIFIED", + 1: "PERIOD_24H", + 2: "PERIOD_7D", + 3: "PERIOD_30D", + } + GetTopStateRemoversRequest_Period_value = map[string]int32{ + "PERIOD_UNSPECIFIED": 0, + "PERIOD_24H": 1, + "PERIOD_7D": 2, + "PERIOD_30D": 3, + } +) + +func (x GetTopStateRemoversRequest_Period) Enum() *GetTopStateRemoversRequest_Period { + p := new(GetTopStateRemoversRequest_Period) + *p = x + return p +} + +func (x GetTopStateRemoversRequest_Period) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (GetTopStateRemoversRequest_Period) Descriptor() protoreflect.EnumDescriptor { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[1].Descriptor() +} + +func (GetTopStateRemoversRequest_Period) Type() protoreflect.EnumType { + return &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[1] +} + +func (x GetTopStateRemoversRequest_Period) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use GetTopStateRemoversRequest_Period.Descriptor instead. +func (GetTopStateRemoversRequest_Period) EnumDescriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{6, 0} +} + +type GetStateGrowthChartRequest_Period int32 + +const ( + GetStateGrowthChartRequest_PERIOD_UNSPECIFIED GetStateGrowthChartRequest_Period = 0 + GetStateGrowthChartRequest_PERIOD_24H GetStateGrowthChartRequest_Period = 1 + GetStateGrowthChartRequest_PERIOD_7D GetStateGrowthChartRequest_Period = 2 + GetStateGrowthChartRequest_PERIOD_30D GetStateGrowthChartRequest_Period = 3 + GetStateGrowthChartRequest_PERIOD_90D GetStateGrowthChartRequest_Period = 4 +) + +// Enum value maps for GetStateGrowthChartRequest_Period. +var ( + GetStateGrowthChartRequest_Period_name = map[int32]string{ + 0: "PERIOD_UNSPECIFIED", + 1: "PERIOD_24H", + 2: "PERIOD_7D", + 3: "PERIOD_30D", + 4: "PERIOD_90D", + } + GetStateGrowthChartRequest_Period_value = map[string]int32{ + "PERIOD_UNSPECIFIED": 0, + "PERIOD_24H": 1, + "PERIOD_7D": 2, + "PERIOD_30D": 3, + "PERIOD_90D": 4, + } +) + +func (x GetStateGrowthChartRequest_Period) Enum() *GetStateGrowthChartRequest_Period { + p := new(GetStateGrowthChartRequest_Period) + *p = x + return p +} + +func (x GetStateGrowthChartRequest_Period) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (GetStateGrowthChartRequest_Period) Descriptor() protoreflect.EnumDescriptor { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[2].Descriptor() +} + +func (GetStateGrowthChartRequest_Period) Type() protoreflect.EnumType { + return &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[2] +} + +func (x GetStateGrowthChartRequest_Period) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use GetStateGrowthChartRequest_Period.Descriptor instead. +func (GetStateGrowthChartRequest_Period) EnumDescriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{9, 0} +} + +type GetStateGrowthChartRequest_Granularity int32 + +const ( + GetStateGrowthChartRequest_GRANULARITY_UNSPECIFIED GetStateGrowthChartRequest_Granularity = 0 + GetStateGrowthChartRequest_GRANULARITY_BLOCK GetStateGrowthChartRequest_Granularity = 1 // Individual blocks + GetStateGrowthChartRequest_GRANULARITY_HOUR GetStateGrowthChartRequest_Granularity = 2 // Hourly aggregates + GetStateGrowthChartRequest_GRANULARITY_DAY GetStateGrowthChartRequest_Granularity = 3 // Daily aggregates +) + +// Enum value maps for GetStateGrowthChartRequest_Granularity. +var ( + GetStateGrowthChartRequest_Granularity_name = map[int32]string{ + 0: "GRANULARITY_UNSPECIFIED", + 1: "GRANULARITY_BLOCK", + 2: "GRANULARITY_HOUR", + 3: "GRANULARITY_DAY", + } + GetStateGrowthChartRequest_Granularity_value = map[string]int32{ + "GRANULARITY_UNSPECIFIED": 0, + "GRANULARITY_BLOCK": 1, + "GRANULARITY_HOUR": 2, + "GRANULARITY_DAY": 3, + } +) + +func (x GetStateGrowthChartRequest_Granularity) Enum() *GetStateGrowthChartRequest_Granularity { + p := new(GetStateGrowthChartRequest_Granularity) + *p = x + return p +} + +func (x GetStateGrowthChartRequest_Granularity) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (GetStateGrowthChartRequest_Granularity) Descriptor() protoreflect.EnumDescriptor { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[3].Descriptor() +} + +func (GetStateGrowthChartRequest_Granularity) Type() protoreflect.EnumType { + return &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[3] +} + +func (x GetStateGrowthChartRequest_Granularity) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use GetStateGrowthChartRequest_Granularity.Descriptor instead. +func (GetStateGrowthChartRequest_Granularity) EnumDescriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{9, 1} +} + +type ContractStateEvent_EventType int32 + +const ( + ContractStateEvent_EVENT_TYPE_UNSPECIFIED ContractStateEvent_EventType = 0 + ContractStateEvent_EVENT_TYPE_SLOT_CREATED ContractStateEvent_EventType = 1 + ContractStateEvent_EVENT_TYPE_SLOT_MODIFIED ContractStateEvent_EventType = 2 + ContractStateEvent_EVENT_TYPE_SLOT_CLEARED ContractStateEvent_EventType = 3 +) + +// Enum value maps for ContractStateEvent_EventType. +var ( + ContractStateEvent_EventType_name = map[int32]string{ + 0: "EVENT_TYPE_UNSPECIFIED", + 1: "EVENT_TYPE_SLOT_CREATED", + 2: "EVENT_TYPE_SLOT_MODIFIED", + 3: "EVENT_TYPE_SLOT_CLEARED", + } + ContractStateEvent_EventType_value = map[string]int32{ + "EVENT_TYPE_UNSPECIFIED": 0, + "EVENT_TYPE_SLOT_CREATED": 1, + "EVENT_TYPE_SLOT_MODIFIED": 2, + "EVENT_TYPE_SLOT_CLEARED": 3, + } +) + +func (x ContractStateEvent_EventType) Enum() *ContractStateEvent_EventType { + p := new(ContractStateEvent_EventType) + *p = x + return p +} + +func (x ContractStateEvent_EventType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ContractStateEvent_EventType) Descriptor() protoreflect.EnumDescriptor { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[4].Descriptor() +} + +func (ContractStateEvent_EventType) Type() protoreflect.EnumType { + return &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[4] +} + +func (x ContractStateEvent_EventType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ContractStateEvent_EventType.Descriptor instead. +func (ContractStateEvent_EventType) EnumDescriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{16, 0} +} + +// Request/Response messages for GetLatestBlockDelta +type GetLatestBlockDeltaRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetLatestBlockDeltaRequest) Reset() { + *x = GetLatestBlockDeltaRequest{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetLatestBlockDeltaRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetLatestBlockDeltaRequest) ProtoMessage() {} + +func (x *GetLatestBlockDeltaRequest) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetLatestBlockDeltaRequest.ProtoReflect.Descriptor instead. +func (*GetLatestBlockDeltaRequest) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{0} +} + +type GetLatestBlockDeltaResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + BlockNumber uint64 `protobuf:"varint,1,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + BlockTimestamp *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=block_timestamp,json=blockTimestamp,proto3" json:"block_timestamp,omitempty"` + NewSlotsCount uint32 `protobuf:"varint,3,opt,name=new_slots_count,json=newSlotsCount,proto3" json:"new_slots_count,omitempty"` // Slots created (first access) + ModifiedSlotsCount uint32 `protobuf:"varint,4,opt,name=modified_slots_count,json=modifiedSlotsCount,proto3" json:"modified_slots_count,omitempty"` // Slots modified (last access) + ClearedSlotsCount uint32 `protobuf:"varint,5,opt,name=cleared_slots_count,json=clearedSlotsCount,proto3" json:"cleared_slots_count,omitempty"` // Slots set to 0x0 + EstimatedBytesAdded uint64 `protobuf:"varint,6,opt,name=estimated_bytes_added,json=estimatedBytesAdded,proto3" json:"estimated_bytes_added,omitempty"` // new_slots * 191 bytes + NetStateChangeBytes int64 `protobuf:"varint,7,opt,name=net_state_change_bytes,json=netStateChangeBytes,proto3" json:"net_state_change_bytes,omitempty"` // Can be negative + TopContributors []*ContractStateDelta `protobuf:"bytes,8,rep,name=top_contributors,json=topContributors,proto3" json:"top_contributors,omitempty"` // Top 10 contracts + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetLatestBlockDeltaResponse) Reset() { + *x = GetLatestBlockDeltaResponse{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetLatestBlockDeltaResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetLatestBlockDeltaResponse) ProtoMessage() {} + +func (x *GetLatestBlockDeltaResponse) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetLatestBlockDeltaResponse.ProtoReflect.Descriptor instead. +func (*GetLatestBlockDeltaResponse) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{1} +} + +func (x *GetLatestBlockDeltaResponse) GetBlockNumber() uint64 { + if x != nil { + return x.BlockNumber + } + return 0 +} + +func (x *GetLatestBlockDeltaResponse) GetBlockTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.BlockTimestamp + } + return nil +} + +func (x *GetLatestBlockDeltaResponse) GetNewSlotsCount() uint32 { + if x != nil { + return x.NewSlotsCount + } + return 0 +} + +func (x *GetLatestBlockDeltaResponse) GetModifiedSlotsCount() uint32 { + if x != nil { + return x.ModifiedSlotsCount + } + return 0 +} + +func (x *GetLatestBlockDeltaResponse) GetClearedSlotsCount() uint32 { + if x != nil { + return x.ClearedSlotsCount + } + return 0 +} + +func (x *GetLatestBlockDeltaResponse) GetEstimatedBytesAdded() uint64 { + if x != nil { + return x.EstimatedBytesAdded + } + return 0 +} + +func (x *GetLatestBlockDeltaResponse) GetNetStateChangeBytes() int64 { + if x != nil { + return x.NetStateChangeBytes + } + return 0 +} + +func (x *GetLatestBlockDeltaResponse) GetTopContributors() []*ContractStateDelta { + if x != nil { + return x.TopContributors + } + return nil +} + +type ContractStateDelta struct { + state protoimpl.MessageState `protogen:"open.v1"` + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + NewSlots uint32 `protobuf:"varint,2,opt,name=new_slots,json=newSlots,proto3" json:"new_slots,omitempty"` + ModifiedSlots uint32 `protobuf:"varint,3,opt,name=modified_slots,json=modifiedSlots,proto3" json:"modified_slots,omitempty"` + ClearedSlots uint32 `protobuf:"varint,4,opt,name=cleared_slots,json=clearedSlots,proto3" json:"cleared_slots,omitempty"` + NetBytes int64 `protobuf:"varint,5,opt,name=net_bytes,json=netBytes,proto3" json:"net_bytes,omitempty"` + Label string `protobuf:"bytes,6,opt,name=label,proto3" json:"label,omitempty"` // Optional contract label/name + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ContractStateDelta) Reset() { + *x = ContractStateDelta{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ContractStateDelta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContractStateDelta) ProtoMessage() {} + +func (x *ContractStateDelta) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContractStateDelta.ProtoReflect.Descriptor instead. +func (*ContractStateDelta) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{2} +} + +func (x *ContractStateDelta) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *ContractStateDelta) GetNewSlots() uint32 { + if x != nil { + return x.NewSlots + } + return 0 +} + +func (x *ContractStateDelta) GetModifiedSlots() uint32 { + if x != nil { + return x.ModifiedSlots + } + return 0 +} + +func (x *ContractStateDelta) GetClearedSlots() uint32 { + if x != nil { + return x.ClearedSlots + } + return 0 +} + +func (x *ContractStateDelta) GetNetBytes() int64 { + if x != nil { + return x.NetBytes + } + return 0 +} + +func (x *ContractStateDelta) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + +// Request/Response for GetTopStateAdders +type GetTopStateAddersRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Period GetTopStateAddersRequest_Period `protobuf:"varint,1,opt,name=period,proto3,enum=state_analytics.GetTopStateAddersRequest_Period" json:"period,omitempty"` + Limit uint32 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` // Default 100, max 1000 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetTopStateAddersRequest) Reset() { + *x = GetTopStateAddersRequest{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetTopStateAddersRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTopStateAddersRequest) ProtoMessage() {} + +func (x *GetTopStateAddersRequest) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTopStateAddersRequest.ProtoReflect.Descriptor instead. +func (*GetTopStateAddersRequest) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{3} +} + +func (x *GetTopStateAddersRequest) GetPeriod() GetTopStateAddersRequest_Period { + if x != nil { + return x.Period + } + return GetTopStateAddersRequest_PERIOD_UNSPECIFIED +} + +func (x *GetTopStateAddersRequest) GetLimit() uint32 { + if x != nil { + return x.Limit + } + return 0 +} + +type GetTopStateAddersResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Adders []*StateAdder `protobuf:"bytes,1,rep,name=adders,proto3" json:"adders,omitempty"` + StartBlock uint64 `protobuf:"varint,2,opt,name=start_block,json=startBlock,proto3" json:"start_block,omitempty"` + EndBlock uint64 `protobuf:"varint,3,opt,name=end_block,json=endBlock,proto3" json:"end_block,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetTopStateAddersResponse) Reset() { + *x = GetTopStateAddersResponse{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetTopStateAddersResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTopStateAddersResponse) ProtoMessage() {} + +func (x *GetTopStateAddersResponse) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTopStateAddersResponse.ProtoReflect.Descriptor instead. +func (*GetTopStateAddersResponse) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{4} +} + +func (x *GetTopStateAddersResponse) GetAdders() []*StateAdder { + if x != nil { + return x.Adders + } + return nil +} + +func (x *GetTopStateAddersResponse) GetStartBlock() uint64 { + if x != nil { + return x.StartBlock + } + return 0 +} + +func (x *GetTopStateAddersResponse) GetEndBlock() uint64 { + if x != nil { + return x.EndBlock + } + return 0 +} + +type StateAdder struct { + state protoimpl.MessageState `protogen:"open.v1"` + Rank uint32 `protobuf:"varint,1,opt,name=rank,proto3" json:"rank,omitempty"` + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + SlotsAdded uint64 `protobuf:"varint,3,opt,name=slots_added,json=slotsAdded,proto3" json:"slots_added,omitempty"` + EstimatedBytesAdded uint64 `protobuf:"varint,4,opt,name=estimated_bytes_added,json=estimatedBytesAdded,proto3" json:"estimated_bytes_added,omitempty"` + Category string `protobuf:"bytes,5,opt,name=category,proto3" json:"category,omitempty"` // ERC20, NFT, DEX, etc. + Label string `protobuf:"bytes,6,opt,name=label,proto3" json:"label,omitempty"` // Contract name if known + PercentageOfTotal float64 `protobuf:"fixed64,7,opt,name=percentage_of_total,json=percentageOfTotal,proto3" json:"percentage_of_total,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StateAdder) Reset() { + *x = StateAdder{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StateAdder) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StateAdder) ProtoMessage() {} + +func (x *StateAdder) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StateAdder.ProtoReflect.Descriptor instead. +func (*StateAdder) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{5} +} + +func (x *StateAdder) GetRank() uint32 { + if x != nil { + return x.Rank + } + return 0 +} + +func (x *StateAdder) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *StateAdder) GetSlotsAdded() uint64 { + if x != nil { + return x.SlotsAdded + } + return 0 +} + +func (x *StateAdder) GetEstimatedBytesAdded() uint64 { + if x != nil { + return x.EstimatedBytesAdded + } + return 0 +} + +func (x *StateAdder) GetCategory() string { + if x != nil { + return x.Category + } + return "" +} + +func (x *StateAdder) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + +func (x *StateAdder) GetPercentageOfTotal() float64 { + if x != nil { + return x.PercentageOfTotal + } + return 0 +} + +// Request/Response for GetTopStateRemovers +type GetTopStateRemoversRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Period GetTopStateRemoversRequest_Period `protobuf:"varint,1,opt,name=period,proto3,enum=state_analytics.GetTopStateRemoversRequest_Period" json:"period,omitempty"` + Limit uint32 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` // Default 100, max 1000 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetTopStateRemoversRequest) Reset() { + *x = GetTopStateRemoversRequest{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetTopStateRemoversRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTopStateRemoversRequest) ProtoMessage() {} + +func (x *GetTopStateRemoversRequest) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTopStateRemoversRequest.ProtoReflect.Descriptor instead. +func (*GetTopStateRemoversRequest) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{6} +} + +func (x *GetTopStateRemoversRequest) GetPeriod() GetTopStateRemoversRequest_Period { + if x != nil { + return x.Period + } + return GetTopStateRemoversRequest_PERIOD_UNSPECIFIED +} + +func (x *GetTopStateRemoversRequest) GetLimit() uint32 { + if x != nil { + return x.Limit + } + return 0 +} + +type GetTopStateRemoversResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Removers []*StateRemover `protobuf:"bytes,1,rep,name=removers,proto3" json:"removers,omitempty"` + StartBlock uint64 `protobuf:"varint,2,opt,name=start_block,json=startBlock,proto3" json:"start_block,omitempty"` + EndBlock uint64 `protobuf:"varint,3,opt,name=end_block,json=endBlock,proto3" json:"end_block,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetTopStateRemoversResponse) Reset() { + *x = GetTopStateRemoversResponse{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetTopStateRemoversResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTopStateRemoversResponse) ProtoMessage() {} + +func (x *GetTopStateRemoversResponse) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTopStateRemoversResponse.ProtoReflect.Descriptor instead. +func (*GetTopStateRemoversResponse) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{7} +} + +func (x *GetTopStateRemoversResponse) GetRemovers() []*StateRemover { + if x != nil { + return x.Removers + } + return nil +} + +func (x *GetTopStateRemoversResponse) GetStartBlock() uint64 { + if x != nil { + return x.StartBlock + } + return 0 +} + +func (x *GetTopStateRemoversResponse) GetEndBlock() uint64 { + if x != nil { + return x.EndBlock + } + return 0 +} + +type StateRemover struct { + state protoimpl.MessageState `protogen:"open.v1"` + Rank uint32 `protobuf:"varint,1,opt,name=rank,proto3" json:"rank,omitempty"` + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + SlotsCleared uint64 `protobuf:"varint,3,opt,name=slots_cleared,json=slotsCleared,proto3" json:"slots_cleared,omitempty"` + EstimatedBytesFreed uint64 `protobuf:"varint,4,opt,name=estimated_bytes_freed,json=estimatedBytesFreed,proto3" json:"estimated_bytes_freed,omitempty"` + EstimatedGasRefund uint64 `protobuf:"varint,5,opt,name=estimated_gas_refund,json=estimatedGasRefund,proto3" json:"estimated_gas_refund,omitempty"` // Theoretical gas refund + Category string `protobuf:"bytes,6,opt,name=category,proto3" json:"category,omitempty"` + Label string `protobuf:"bytes,7,opt,name=label,proto3" json:"label,omitempty"` + PercentageOfTotal float64 `protobuf:"fixed64,8,opt,name=percentage_of_total,json=percentageOfTotal,proto3" json:"percentage_of_total,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StateRemover) Reset() { + *x = StateRemover{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StateRemover) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StateRemover) ProtoMessage() {} + +func (x *StateRemover) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StateRemover.ProtoReflect.Descriptor instead. +func (*StateRemover) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{8} +} + +func (x *StateRemover) GetRank() uint32 { + if x != nil { + return x.Rank + } + return 0 +} + +func (x *StateRemover) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *StateRemover) GetSlotsCleared() uint64 { + if x != nil { + return x.SlotsCleared + } + return 0 +} + +func (x *StateRemover) GetEstimatedBytesFreed() uint64 { + if x != nil { + return x.EstimatedBytesFreed + } + return 0 +} + +func (x *StateRemover) GetEstimatedGasRefund() uint64 { + if x != nil { + return x.EstimatedGasRefund + } + return 0 +} + +func (x *StateRemover) GetCategory() string { + if x != nil { + return x.Category + } + return "" +} + +func (x *StateRemover) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + +func (x *StateRemover) GetPercentageOfTotal() float64 { + if x != nil { + return x.PercentageOfTotal + } + return 0 +} + +// Request/Response for GetStateGrowthChart +type GetStateGrowthChartRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Period GetStateGrowthChartRequest_Period `protobuf:"varint,1,opt,name=period,proto3,enum=state_analytics.GetStateGrowthChartRequest_Period" json:"period,omitempty"` + Granularity GetStateGrowthChartRequest_Granularity `protobuf:"varint,2,opt,name=granularity,proto3,enum=state_analytics.GetStateGrowthChartRequest_Granularity" json:"granularity,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetStateGrowthChartRequest) Reset() { + *x = GetStateGrowthChartRequest{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetStateGrowthChartRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetStateGrowthChartRequest) ProtoMessage() {} + +func (x *GetStateGrowthChartRequest) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetStateGrowthChartRequest.ProtoReflect.Descriptor instead. +func (*GetStateGrowthChartRequest) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{9} +} + +func (x *GetStateGrowthChartRequest) GetPeriod() GetStateGrowthChartRequest_Period { + if x != nil { + return x.Period + } + return GetStateGrowthChartRequest_PERIOD_UNSPECIFIED +} + +func (x *GetStateGrowthChartRequest) GetGranularity() GetStateGrowthChartRequest_Granularity { + if x != nil { + return x.Granularity + } + return GetStateGrowthChartRequest_GRANULARITY_UNSPECIFIED +} + +type GetStateGrowthChartResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + DataPoints []*StateGrowthDataPoint `protobuf:"bytes,1,rep,name=data_points,json=dataPoints,proto3" json:"data_points,omitempty"` + Summary *StateSummary `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetStateGrowthChartResponse) Reset() { + *x = GetStateGrowthChartResponse{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetStateGrowthChartResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetStateGrowthChartResponse) ProtoMessage() {} + +func (x *GetStateGrowthChartResponse) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetStateGrowthChartResponse.ProtoReflect.Descriptor instead. +func (*GetStateGrowthChartResponse) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{10} +} + +func (x *GetStateGrowthChartResponse) GetDataPoints() []*StateGrowthDataPoint { + if x != nil { + return x.DataPoints + } + return nil +} + +func (x *GetStateGrowthChartResponse) GetSummary() *StateSummary { + if x != nil { + return x.Summary + } + return nil +} + +type StateGrowthDataPoint struct { + state protoimpl.MessageState `protogen:"open.v1"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + BlockNumber uint64 `protobuf:"varint,2,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + SlotsAdded uint64 `protobuf:"varint,3,opt,name=slots_added,json=slotsAdded,proto3" json:"slots_added,omitempty"` + SlotsCleared uint64 `protobuf:"varint,4,opt,name=slots_cleared,json=slotsCleared,proto3" json:"slots_cleared,omitempty"` + NetSlots int64 `protobuf:"varint,5,opt,name=net_slots,json=netSlots,proto3" json:"net_slots,omitempty"` + BytesAdded uint64 `protobuf:"varint,6,opt,name=bytes_added,json=bytesAdded,proto3" json:"bytes_added,omitempty"` + BytesCleared uint64 `protobuf:"varint,7,opt,name=bytes_cleared,json=bytesCleared,proto3" json:"bytes_cleared,omitempty"` + NetBytes int64 `protobuf:"varint,8,opt,name=net_bytes,json=netBytes,proto3" json:"net_bytes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StateGrowthDataPoint) Reset() { + *x = StateGrowthDataPoint{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StateGrowthDataPoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StateGrowthDataPoint) ProtoMessage() {} + +func (x *StateGrowthDataPoint) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StateGrowthDataPoint.ProtoReflect.Descriptor instead. +func (*StateGrowthDataPoint) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{11} +} + +func (x *StateGrowthDataPoint) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp + } + return nil +} + +func (x *StateGrowthDataPoint) GetBlockNumber() uint64 { + if x != nil { + return x.BlockNumber + } + return 0 +} + +func (x *StateGrowthDataPoint) GetSlotsAdded() uint64 { + if x != nil { + return x.SlotsAdded + } + return 0 +} + +func (x *StateGrowthDataPoint) GetSlotsCleared() uint64 { + if x != nil { + return x.SlotsCleared + } + return 0 +} + +func (x *StateGrowthDataPoint) GetNetSlots() int64 { + if x != nil { + return x.NetSlots + } + return 0 +} + +func (x *StateGrowthDataPoint) GetBytesAdded() uint64 { + if x != nil { + return x.BytesAdded + } + return 0 +} + +func (x *StateGrowthDataPoint) GetBytesCleared() uint64 { + if x != nil { + return x.BytesCleared + } + return 0 +} + +func (x *StateGrowthDataPoint) GetNetBytes() int64 { + if x != nil { + return x.NetBytes + } + return 0 +} + +type StateSummary struct { + state protoimpl.MessageState `protogen:"open.v1"` + TotalSlotsAdded uint64 `protobuf:"varint,1,opt,name=total_slots_added,json=totalSlotsAdded,proto3" json:"total_slots_added,omitempty"` + TotalSlotsCleared uint64 `protobuf:"varint,2,opt,name=total_slots_cleared,json=totalSlotsCleared,proto3" json:"total_slots_cleared,omitempty"` + NetSlots int64 `protobuf:"varint,3,opt,name=net_slots,json=netSlots,proto3" json:"net_slots,omitempty"` + TotalBytesAdded uint64 `protobuf:"varint,4,opt,name=total_bytes_added,json=totalBytesAdded,proto3" json:"total_bytes_added,omitempty"` + TotalBytesCleared uint64 `protobuf:"varint,5,opt,name=total_bytes_cleared,json=totalBytesCleared,proto3" json:"total_bytes_cleared,omitempty"` + NetBytes int64 `protobuf:"varint,6,opt,name=net_bytes,json=netBytes,proto3" json:"net_bytes,omitempty"` + AvgSlotsPerBlock float64 `protobuf:"fixed64,7,opt,name=avg_slots_per_block,json=avgSlotsPerBlock,proto3" json:"avg_slots_per_block,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StateSummary) Reset() { + *x = StateSummary{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StateSummary) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StateSummary) ProtoMessage() {} + +func (x *StateSummary) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StateSummary.ProtoReflect.Descriptor instead. +func (*StateSummary) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{12} +} + +func (x *StateSummary) GetTotalSlotsAdded() uint64 { + if x != nil { + return x.TotalSlotsAdded + } + return 0 +} + +func (x *StateSummary) GetTotalSlotsCleared() uint64 { + if x != nil { + return x.TotalSlotsCleared + } + return 0 +} + +func (x *StateSummary) GetNetSlots() int64 { + if x != nil { + return x.NetSlots + } + return 0 +} + +func (x *StateSummary) GetTotalBytesAdded() uint64 { + if x != nil { + return x.TotalBytesAdded + } + return 0 +} + +func (x *StateSummary) GetTotalBytesCleared() uint64 { + if x != nil { + return x.TotalBytesCleared + } + return 0 +} + +func (x *StateSummary) GetNetBytes() int64 { + if x != nil { + return x.NetBytes + } + return 0 +} + +func (x *StateSummary) GetAvgSlotsPerBlock() float64 { + if x != nil { + return x.AvgSlotsPerBlock + } + return 0 +} + +// Request/Response for GetContractStateActivity +type GetContractStateActivityRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` // Contract address + Limit uint32 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` // Number of recent activities to return + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetContractStateActivityRequest) Reset() { + *x = GetContractStateActivityRequest{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetContractStateActivityRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetContractStateActivityRequest) ProtoMessage() {} + +func (x *GetContractStateActivityRequest) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetContractStateActivityRequest.ProtoReflect.Descriptor instead. +func (*GetContractStateActivityRequest) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{13} +} + +func (x *GetContractStateActivityRequest) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *GetContractStateActivityRequest) GetLimit() uint32 { + if x != nil { + return x.Limit + } + return 0 +} + +type GetContractStateActivityResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty"` + Category string `protobuf:"bytes,3,opt,name=category,proto3" json:"category,omitempty"` + Metrics *ContractStateMetrics `protobuf:"bytes,4,opt,name=metrics,proto3" json:"metrics,omitempty"` + RecentEvents []*ContractStateEvent `protobuf:"bytes,5,rep,name=recent_events,json=recentEvents,proto3" json:"recent_events,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetContractStateActivityResponse) Reset() { + *x = GetContractStateActivityResponse{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetContractStateActivityResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetContractStateActivityResponse) ProtoMessage() {} + +func (x *GetContractStateActivityResponse) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetContractStateActivityResponse.ProtoReflect.Descriptor instead. +func (*GetContractStateActivityResponse) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{14} +} + +func (x *GetContractStateActivityResponse) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *GetContractStateActivityResponse) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + +func (x *GetContractStateActivityResponse) GetCategory() string { + if x != nil { + return x.Category + } + return "" +} + +func (x *GetContractStateActivityResponse) GetMetrics() *ContractStateMetrics { + if x != nil { + return x.Metrics + } + return nil +} + +func (x *GetContractStateActivityResponse) GetRecentEvents() []*ContractStateEvent { + if x != nil { + return x.RecentEvents + } + return nil +} + +type ContractStateMetrics struct { + state protoimpl.MessageState `protogen:"open.v1"` + TotalSlots uint64 `protobuf:"varint,1,opt,name=total_slots,json=totalSlots,proto3" json:"total_slots,omitempty"` // Total known slots for this contract + ActiveSlots uint64 `protobuf:"varint,2,opt,name=active_slots,json=activeSlots,proto3" json:"active_slots,omitempty"` // Slots modified in last 30d + FirstSeenBlock uint64 `protobuf:"varint,3,opt,name=first_seen_block,json=firstSeenBlock,proto3" json:"first_seen_block,omitempty"` + LastActiveBlock uint64 `protobuf:"varint,4,opt,name=last_active_block,json=lastActiveBlock,proto3" json:"last_active_block,omitempty"` + LifetimeSlotsAdded uint64 `protobuf:"varint,5,opt,name=lifetime_slots_added,json=lifetimeSlotsAdded,proto3" json:"lifetime_slots_added,omitempty"` + LifetimeSlotsCleared uint64 `protobuf:"varint,6,opt,name=lifetime_slots_cleared,json=lifetimeSlotsCleared,proto3" json:"lifetime_slots_cleared,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ContractStateMetrics) Reset() { + *x = ContractStateMetrics{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ContractStateMetrics) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContractStateMetrics) ProtoMessage() {} + +func (x *ContractStateMetrics) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContractStateMetrics.ProtoReflect.Descriptor instead. +func (*ContractStateMetrics) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{15} +} + +func (x *ContractStateMetrics) GetTotalSlots() uint64 { + if x != nil { + return x.TotalSlots + } + return 0 +} + +func (x *ContractStateMetrics) GetActiveSlots() uint64 { + if x != nil { + return x.ActiveSlots + } + return 0 +} + +func (x *ContractStateMetrics) GetFirstSeenBlock() uint64 { + if x != nil { + return x.FirstSeenBlock + } + return 0 +} + +func (x *ContractStateMetrics) GetLastActiveBlock() uint64 { + if x != nil { + return x.LastActiveBlock + } + return 0 +} + +func (x *ContractStateMetrics) GetLifetimeSlotsAdded() uint64 { + if x != nil { + return x.LifetimeSlotsAdded + } + return 0 +} + +func (x *ContractStateMetrics) GetLifetimeSlotsCleared() uint64 { + if x != nil { + return x.LifetimeSlotsCleared + } + return 0 +} + +type ContractStateEvent struct { + state protoimpl.MessageState `protogen:"open.v1"` + BlockNumber uint64 `protobuf:"varint,1,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + EventType ContractStateEvent_EventType `protobuf:"varint,3,opt,name=event_type,json=eventType,proto3,enum=state_analytics.ContractStateEvent_EventType" json:"event_type,omitempty"` + SlotKey string `protobuf:"bytes,4,opt,name=slot_key,json=slotKey,proto3" json:"slot_key,omitempty"` + Value string `protobuf:"bytes,5,opt,name=value,proto3" json:"value,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ContractStateEvent) Reset() { + *x = ContractStateEvent{} + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ContractStateEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContractStateEvent) ProtoMessage() {} + +func (x *ContractStateEvent) ProtoReflect() protoreflect.Message { + mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContractStateEvent.ProtoReflect.Descriptor instead. +func (*ContractStateEvent) Descriptor() ([]byte, []int) { + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{16} +} + +func (x *ContractStateEvent) GetBlockNumber() uint64 { + if x != nil { + return x.BlockNumber + } + return 0 +} + +func (x *ContractStateEvent) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp + } + return nil +} + +func (x *ContractStateEvent) GetEventType() ContractStateEvent_EventType { + if x != nil { + return x.EventType + } + return ContractStateEvent_EVENT_TYPE_UNSPECIFIED +} + +func (x *ContractStateEvent) GetSlotKey() string { + if x != nil { + return x.SlotKey + } + return "" +} + +func (x *ContractStateEvent) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +var File_backend_pkg_server_proto_state_analytics_state_analytics_proto protoreflect.FileDescriptor + +const file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDesc = "" + + "\n" + + ">backend/pkg/server/proto/state_analytics/state_analytics.proto\x12\x0fstate_analytics\x1a\x1fgoogle/protobuf/timestamp.proto\"\x1c\n" + + "\x1aGetLatestBlockDeltaRequest\"\xc8\x03\n" + + "\x1bGetLatestBlockDeltaResponse\x12!\n" + + "\fblock_number\x18\x01 \x01(\x04R\vblockNumber\x12C\n" + + "\x0fblock_timestamp\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\x0eblockTimestamp\x12&\n" + + "\x0fnew_slots_count\x18\x03 \x01(\rR\rnewSlotsCount\x120\n" + + "\x14modified_slots_count\x18\x04 \x01(\rR\x12modifiedSlotsCount\x12.\n" + + "\x13cleared_slots_count\x18\x05 \x01(\rR\x11clearedSlotsCount\x122\n" + + "\x15estimated_bytes_added\x18\x06 \x01(\x04R\x13estimatedBytesAdded\x123\n" + + "\x16net_state_change_bytes\x18\a \x01(\x03R\x13netStateChangeBytes\x12N\n" + + "\x10top_contributors\x18\b \x03(\v2#.state_analytics.ContractStateDeltaR\x0ftopContributors\"\xca\x01\n" + + "\x12ContractStateDelta\x12\x18\n" + + "\aaddress\x18\x01 \x01(\tR\aaddress\x12\x1b\n" + + "\tnew_slots\x18\x02 \x01(\rR\bnewSlots\x12%\n" + + "\x0emodified_slots\x18\x03 \x01(\rR\rmodifiedSlots\x12#\n" + + "\rcleared_slots\x18\x04 \x01(\rR\fclearedSlots\x12\x1b\n" + + "\tnet_bytes\x18\x05 \x01(\x03R\bnetBytes\x12\x14\n" + + "\x05label\x18\x06 \x01(\tR\x05label\"\xcb\x01\n" + + "\x18GetTopStateAddersRequest\x12H\n" + + "\x06period\x18\x01 \x01(\x0e20.state_analytics.GetTopStateAddersRequest.PeriodR\x06period\x12\x14\n" + + "\x05limit\x18\x02 \x01(\rR\x05limit\"O\n" + + "\x06Period\x12\x16\n" + + "\x12PERIOD_UNSPECIFIED\x10\x00\x12\x0e\n" + + "\n" + + "PERIOD_24H\x10\x01\x12\r\n" + + "\tPERIOD_7D\x10\x02\x12\x0e\n" + + "\n" + + "PERIOD_30D\x10\x03\"\x8e\x01\n" + + "\x19GetTopStateAddersResponse\x123\n" + + "\x06adders\x18\x01 \x03(\v2\x1b.state_analytics.StateAdderR\x06adders\x12\x1f\n" + + "\vstart_block\x18\x02 \x01(\x04R\n" + + "startBlock\x12\x1b\n" + + "\tend_block\x18\x03 \x01(\x04R\bendBlock\"\xf1\x01\n" + + "\n" + + "StateAdder\x12\x12\n" + + "\x04rank\x18\x01 \x01(\rR\x04rank\x12\x18\n" + + "\aaddress\x18\x02 \x01(\tR\aaddress\x12\x1f\n" + + "\vslots_added\x18\x03 \x01(\x04R\n" + + "slotsAdded\x122\n" + + "\x15estimated_bytes_added\x18\x04 \x01(\x04R\x13estimatedBytesAdded\x12\x1a\n" + + "\bcategory\x18\x05 \x01(\tR\bcategory\x12\x14\n" + + "\x05label\x18\x06 \x01(\tR\x05label\x12.\n" + + "\x13percentage_of_total\x18\a \x01(\x01R\x11percentageOfTotal\"\xcf\x01\n" + + "\x1aGetTopStateRemoversRequest\x12J\n" + + "\x06period\x18\x01 \x01(\x0e22.state_analytics.GetTopStateRemoversRequest.PeriodR\x06period\x12\x14\n" + + "\x05limit\x18\x02 \x01(\rR\x05limit\"O\n" + + "\x06Period\x12\x16\n" + + "\x12PERIOD_UNSPECIFIED\x10\x00\x12\x0e\n" + + "\n" + + "PERIOD_24H\x10\x01\x12\r\n" + + "\tPERIOD_7D\x10\x02\x12\x0e\n" + + "\n" + + "PERIOD_30D\x10\x03\"\x96\x01\n" + + "\x1bGetTopStateRemoversResponse\x129\n" + + "\bremovers\x18\x01 \x03(\v2\x1d.state_analytics.StateRemoverR\bremovers\x12\x1f\n" + + "\vstart_block\x18\x02 \x01(\x04R\n" + + "startBlock\x12\x1b\n" + + "\tend_block\x18\x03 \x01(\x04R\bendBlock\"\xa9\x02\n" + + "\fStateRemover\x12\x12\n" + + "\x04rank\x18\x01 \x01(\rR\x04rank\x12\x18\n" + + "\aaddress\x18\x02 \x01(\tR\aaddress\x12#\n" + + "\rslots_cleared\x18\x03 \x01(\x04R\fslotsCleared\x122\n" + + "\x15estimated_bytes_freed\x18\x04 \x01(\x04R\x13estimatedBytesFreed\x120\n" + + "\x14estimated_gas_refund\x18\x05 \x01(\x04R\x12estimatedGasRefund\x12\x1a\n" + + "\bcategory\x18\x06 \x01(\tR\bcategory\x12\x14\n" + + "\x05label\x18\a \x01(\tR\x05label\x12.\n" + + "\x13percentage_of_total\x18\b \x01(\x01R\x11percentageOfTotal\"\x92\x03\n" + + "\x1aGetStateGrowthChartRequest\x12J\n" + + "\x06period\x18\x01 \x01(\x0e22.state_analytics.GetStateGrowthChartRequest.PeriodR\x06period\x12Y\n" + + "\vgranularity\x18\x02 \x01(\x0e27.state_analytics.GetStateGrowthChartRequest.GranularityR\vgranularity\"_\n" + + "\x06Period\x12\x16\n" + + "\x12PERIOD_UNSPECIFIED\x10\x00\x12\x0e\n" + + "\n" + + "PERIOD_24H\x10\x01\x12\r\n" + + "\tPERIOD_7D\x10\x02\x12\x0e\n" + + "\n" + + "PERIOD_30D\x10\x03\x12\x0e\n" + + "\n" + + "PERIOD_90D\x10\x04\"l\n" + + "\vGranularity\x12\x1b\n" + + "\x17GRANULARITY_UNSPECIFIED\x10\x00\x12\x15\n" + + "\x11GRANULARITY_BLOCK\x10\x01\x12\x14\n" + + "\x10GRANULARITY_HOUR\x10\x02\x12\x13\n" + + "\x0fGRANULARITY_DAY\x10\x03\"\x9e\x01\n" + + "\x1bGetStateGrowthChartResponse\x12F\n" + + "\vdata_points\x18\x01 \x03(\v2%.state_analytics.StateGrowthDataPointR\n" + + "dataPoints\x127\n" + + "\asummary\x18\x02 \x01(\v2\x1d.state_analytics.StateSummaryR\asummary\"\xb9\x02\n" + + "\x14StateGrowthDataPoint\x128\n" + + "\ttimestamp\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\ttimestamp\x12!\n" + + "\fblock_number\x18\x02 \x01(\x04R\vblockNumber\x12\x1f\n" + + "\vslots_added\x18\x03 \x01(\x04R\n" + + "slotsAdded\x12#\n" + + "\rslots_cleared\x18\x04 \x01(\x04R\fslotsCleared\x12\x1b\n" + + "\tnet_slots\x18\x05 \x01(\x03R\bnetSlots\x12\x1f\n" + + "\vbytes_added\x18\x06 \x01(\x04R\n" + + "bytesAdded\x12#\n" + + "\rbytes_cleared\x18\a \x01(\x04R\fbytesCleared\x12\x1b\n" + + "\tnet_bytes\x18\b \x01(\x03R\bnetBytes\"\xaf\x02\n" + + "\fStateSummary\x12*\n" + + "\x11total_slots_added\x18\x01 \x01(\x04R\x0ftotalSlotsAdded\x12.\n" + + "\x13total_slots_cleared\x18\x02 \x01(\x04R\x11totalSlotsCleared\x12\x1b\n" + + "\tnet_slots\x18\x03 \x01(\x03R\bnetSlots\x12*\n" + + "\x11total_bytes_added\x18\x04 \x01(\x04R\x0ftotalBytesAdded\x12.\n" + + "\x13total_bytes_cleared\x18\x05 \x01(\x04R\x11totalBytesCleared\x12\x1b\n" + + "\tnet_bytes\x18\x06 \x01(\x03R\bnetBytes\x12-\n" + + "\x13avg_slots_per_block\x18\a \x01(\x01R\x10avgSlotsPerBlock\"Q\n" + + "\x1fGetContractStateActivityRequest\x12\x18\n" + + "\aaddress\x18\x01 \x01(\tR\aaddress\x12\x14\n" + + "\x05limit\x18\x02 \x01(\rR\x05limit\"\xf9\x01\n" + + " GetContractStateActivityResponse\x12\x18\n" + + "\aaddress\x18\x01 \x01(\tR\aaddress\x12\x14\n" + + "\x05label\x18\x02 \x01(\tR\x05label\x12\x1a\n" + + "\bcategory\x18\x03 \x01(\tR\bcategory\x12?\n" + + "\ametrics\x18\x04 \x01(\v2%.state_analytics.ContractStateMetricsR\ametrics\x12H\n" + + "\rrecent_events\x18\x05 \x03(\v2#.state_analytics.ContractStateEventR\frecentEvents\"\x98\x02\n" + + "\x14ContractStateMetrics\x12\x1f\n" + + "\vtotal_slots\x18\x01 \x01(\x04R\n" + + "totalSlots\x12!\n" + + "\factive_slots\x18\x02 \x01(\x04R\vactiveSlots\x12(\n" + + "\x10first_seen_block\x18\x03 \x01(\x04R\x0efirstSeenBlock\x12*\n" + + "\x11last_active_block\x18\x04 \x01(\x04R\x0flastActiveBlock\x120\n" + + "\x14lifetime_slots_added\x18\x05 \x01(\x04R\x12lifetimeSlotsAdded\x124\n" + + "\x16lifetime_slots_cleared\x18\x06 \x01(\x04R\x14lifetimeSlotsCleared\"\xf1\x02\n" + + "\x12ContractStateEvent\x12!\n" + + "\fblock_number\x18\x01 \x01(\x04R\vblockNumber\x128\n" + + "\ttimestamp\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\ttimestamp\x12L\n" + + "\n" + + "event_type\x18\x03 \x01(\x0e2-.state_analytics.ContractStateEvent.EventTypeR\teventType\x12\x19\n" + + "\bslot_key\x18\x04 \x01(\tR\aslotKey\x12\x14\n" + + "\x05value\x18\x05 \x01(\tR\x05value\"\x7f\n" + + "\tEventType\x12\x1a\n" + + "\x16EVENT_TYPE_UNSPECIFIED\x10\x00\x12\x1b\n" + + "\x17EVENT_TYPE_SLOT_CREATED\x10\x01\x12\x1c\n" + + "\x18EVENT_TYPE_SLOT_MODIFIED\x10\x02\x12\x1b\n" + + "\x17EVENT_TYPE_SLOT_CLEARED\x10\x032\xd3\x04\n" + + "\x0eStateAnalytics\x12p\n" + + "\x13GetLatestBlockDelta\x12+.state_analytics.GetLatestBlockDeltaRequest\x1a,.state_analytics.GetLatestBlockDeltaResponse\x12j\n" + + "\x11GetTopStateAdders\x12).state_analytics.GetTopStateAddersRequest\x1a*.state_analytics.GetTopStateAddersResponse\x12p\n" + + "\x13GetTopStateRemovers\x12+.state_analytics.GetTopStateRemoversRequest\x1a,.state_analytics.GetTopStateRemoversResponse\x12p\n" + + "\x13GetStateGrowthChart\x12+.state_analytics.GetStateGrowthChartRequest\x1a,.state_analytics.GetStateGrowthChartResponse\x12\x7f\n" + + "\x18GetContractStateActivity\x120.state_analytics.GetContractStateActivityRequest\x1a1.state_analytics.GetContractStateActivityResponseBEZCgithub.com/ethpandaops/lab/backend/pkg/server/proto/state_analyticsb\x06proto3" + +var ( + file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescOnce sync.Once + file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescData []byte +) + +func file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP() []byte { + file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescOnce.Do(func() { + file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDesc), len(file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDesc))) + }) + return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescData +} + +var file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes = make([]protoimpl.EnumInfo, 5) +var file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_backend_pkg_server_proto_state_analytics_state_analytics_proto_goTypes = []any{ + (GetTopStateAddersRequest_Period)(0), // 0: state_analytics.GetTopStateAddersRequest.Period + (GetTopStateRemoversRequest_Period)(0), // 1: state_analytics.GetTopStateRemoversRequest.Period + (GetStateGrowthChartRequest_Period)(0), // 2: state_analytics.GetStateGrowthChartRequest.Period + (GetStateGrowthChartRequest_Granularity)(0), // 3: state_analytics.GetStateGrowthChartRequest.Granularity + (ContractStateEvent_EventType)(0), // 4: state_analytics.ContractStateEvent.EventType + (*GetLatestBlockDeltaRequest)(nil), // 5: state_analytics.GetLatestBlockDeltaRequest + (*GetLatestBlockDeltaResponse)(nil), // 6: state_analytics.GetLatestBlockDeltaResponse + (*ContractStateDelta)(nil), // 7: state_analytics.ContractStateDelta + (*GetTopStateAddersRequest)(nil), // 8: state_analytics.GetTopStateAddersRequest + (*GetTopStateAddersResponse)(nil), // 9: state_analytics.GetTopStateAddersResponse + (*StateAdder)(nil), // 10: state_analytics.StateAdder + (*GetTopStateRemoversRequest)(nil), // 11: state_analytics.GetTopStateRemoversRequest + (*GetTopStateRemoversResponse)(nil), // 12: state_analytics.GetTopStateRemoversResponse + (*StateRemover)(nil), // 13: state_analytics.StateRemover + (*GetStateGrowthChartRequest)(nil), // 14: state_analytics.GetStateGrowthChartRequest + (*GetStateGrowthChartResponse)(nil), // 15: state_analytics.GetStateGrowthChartResponse + (*StateGrowthDataPoint)(nil), // 16: state_analytics.StateGrowthDataPoint + (*StateSummary)(nil), // 17: state_analytics.StateSummary + (*GetContractStateActivityRequest)(nil), // 18: state_analytics.GetContractStateActivityRequest + (*GetContractStateActivityResponse)(nil), // 19: state_analytics.GetContractStateActivityResponse + (*ContractStateMetrics)(nil), // 20: state_analytics.ContractStateMetrics + (*ContractStateEvent)(nil), // 21: state_analytics.ContractStateEvent + (*timestamppb.Timestamp)(nil), // 22: google.protobuf.Timestamp +} +var file_backend_pkg_server_proto_state_analytics_state_analytics_proto_depIdxs = []int32{ + 22, // 0: state_analytics.GetLatestBlockDeltaResponse.block_timestamp:type_name -> google.protobuf.Timestamp + 7, // 1: state_analytics.GetLatestBlockDeltaResponse.top_contributors:type_name -> state_analytics.ContractStateDelta + 0, // 2: state_analytics.GetTopStateAddersRequest.period:type_name -> state_analytics.GetTopStateAddersRequest.Period + 10, // 3: state_analytics.GetTopStateAddersResponse.adders:type_name -> state_analytics.StateAdder + 1, // 4: state_analytics.GetTopStateRemoversRequest.period:type_name -> state_analytics.GetTopStateRemoversRequest.Period + 13, // 5: state_analytics.GetTopStateRemoversResponse.removers:type_name -> state_analytics.StateRemover + 2, // 6: state_analytics.GetStateGrowthChartRequest.period:type_name -> state_analytics.GetStateGrowthChartRequest.Period + 3, // 7: state_analytics.GetStateGrowthChartRequest.granularity:type_name -> state_analytics.GetStateGrowthChartRequest.Granularity + 16, // 8: state_analytics.GetStateGrowthChartResponse.data_points:type_name -> state_analytics.StateGrowthDataPoint + 17, // 9: state_analytics.GetStateGrowthChartResponse.summary:type_name -> state_analytics.StateSummary + 22, // 10: state_analytics.StateGrowthDataPoint.timestamp:type_name -> google.protobuf.Timestamp + 20, // 11: state_analytics.GetContractStateActivityResponse.metrics:type_name -> state_analytics.ContractStateMetrics + 21, // 12: state_analytics.GetContractStateActivityResponse.recent_events:type_name -> state_analytics.ContractStateEvent + 22, // 13: state_analytics.ContractStateEvent.timestamp:type_name -> google.protobuf.Timestamp + 4, // 14: state_analytics.ContractStateEvent.event_type:type_name -> state_analytics.ContractStateEvent.EventType + 5, // 15: state_analytics.StateAnalytics.GetLatestBlockDelta:input_type -> state_analytics.GetLatestBlockDeltaRequest + 8, // 16: state_analytics.StateAnalytics.GetTopStateAdders:input_type -> state_analytics.GetTopStateAddersRequest + 11, // 17: state_analytics.StateAnalytics.GetTopStateRemovers:input_type -> state_analytics.GetTopStateRemoversRequest + 14, // 18: state_analytics.StateAnalytics.GetStateGrowthChart:input_type -> state_analytics.GetStateGrowthChartRequest + 18, // 19: state_analytics.StateAnalytics.GetContractStateActivity:input_type -> state_analytics.GetContractStateActivityRequest + 6, // 20: state_analytics.StateAnalytics.GetLatestBlockDelta:output_type -> state_analytics.GetLatestBlockDeltaResponse + 9, // 21: state_analytics.StateAnalytics.GetTopStateAdders:output_type -> state_analytics.GetTopStateAddersResponse + 12, // 22: state_analytics.StateAnalytics.GetTopStateRemovers:output_type -> state_analytics.GetTopStateRemoversResponse + 15, // 23: state_analytics.StateAnalytics.GetStateGrowthChart:output_type -> state_analytics.GetStateGrowthChartResponse + 19, // 24: state_analytics.StateAnalytics.GetContractStateActivity:output_type -> state_analytics.GetContractStateActivityResponse + 20, // [20:25] is the sub-list for method output_type + 15, // [15:20] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name +} + +func init() { file_backend_pkg_server_proto_state_analytics_state_analytics_proto_init() } +func file_backend_pkg_server_proto_state_analytics_state_analytics_proto_init() { + if File_backend_pkg_server_proto_state_analytics_state_analytics_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDesc), len(file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDesc)), + NumEnums: 5, + NumMessages: 17, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_backend_pkg_server_proto_state_analytics_state_analytics_proto_goTypes, + DependencyIndexes: file_backend_pkg_server_proto_state_analytics_state_analytics_proto_depIdxs, + EnumInfos: file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes, + MessageInfos: file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes, + }.Build() + File_backend_pkg_server_proto_state_analytics_state_analytics_proto = out.File + file_backend_pkg_server_proto_state_analytics_state_analytics_proto_goTypes = nil + file_backend_pkg_server_proto_state_analytics_state_analytics_proto_depIdxs = nil +} diff --git a/backend/pkg/server/proto/state_analytics/state_analytics.proto b/backend/pkg/server/proto/state_analytics/state_analytics.proto new file mode 100644 index 000000000..186333f4f --- /dev/null +++ b/backend/pkg/server/proto/state_analytics/state_analytics.proto @@ -0,0 +1,190 @@ +syntax = "proto3"; + +package state_analytics; + +option go_package = "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics"; + +import "google/protobuf/timestamp.proto"; + +// StateAnalytics service provides state growth and activity metrics +service StateAnalytics { + // GetLatestBlockDelta returns state changes for the most recent block + rpc GetLatestBlockDelta(GetLatestBlockDeltaRequest) returns (GetLatestBlockDeltaResponse); + + // GetTopStateAdders returns contracts that created the most new storage slots + rpc GetTopStateAdders(GetTopStateAddersRequest) returns (GetTopStateAddersResponse); + + // GetTopStateRemovers returns contracts that cleared the most storage slots + rpc GetTopStateRemovers(GetTopStateRemoversRequest) returns (GetTopStateRemoversResponse); + + // GetStateGrowthChart returns time-series data of state growth + rpc GetStateGrowthChart(GetStateGrowthChartRequest) returns (GetStateGrowthChartResponse); + + // GetContractStateActivity returns detailed state activity for a specific contract + rpc GetContractStateActivity(GetContractStateActivityRequest) returns (GetContractStateActivityResponse); +} + +// Request/Response messages for GetLatestBlockDelta +message GetLatestBlockDeltaRequest { + // No parameters needed - always returns latest block +} + +message GetLatestBlockDeltaResponse { + uint64 block_number = 1; + google.protobuf.Timestamp block_timestamp = 2; + uint32 new_slots_count = 3; // Slots created (first access) + uint32 modified_slots_count = 4; // Slots modified (last access) + uint32 cleared_slots_count = 5; // Slots set to 0x0 + uint64 estimated_bytes_added = 6; // new_slots * 191 bytes + int64 net_state_change_bytes = 7; // Can be negative + repeated ContractStateDelta top_contributors = 8; // Top 10 contracts +} + +message ContractStateDelta { + string address = 1; + uint32 new_slots = 2; + uint32 modified_slots = 3; + uint32 cleared_slots = 4; + int64 net_bytes = 5; + string label = 6; // Optional contract label/name +} + +// Request/Response for GetTopStateAdders +message GetTopStateAddersRequest { + enum Period { + PERIOD_UNSPECIFIED = 0; + PERIOD_24H = 1; + PERIOD_7D = 2; + PERIOD_30D = 3; + } + Period period = 1; + uint32 limit = 2; // Default 100, max 1000 +} + +message GetTopStateAddersResponse { + repeated StateAdder adders = 1; + uint64 start_block = 2; + uint64 end_block = 3; +} + +message StateAdder { + uint32 rank = 1; + string address = 2; + uint64 slots_added = 3; + uint64 estimated_bytes_added = 4; + string category = 5; // ERC20, NFT, DEX, etc. + string label = 6; // Contract name if known + double percentage_of_total = 7; +} + +// Request/Response for GetTopStateRemovers +message GetTopStateRemoversRequest { + enum Period { + PERIOD_UNSPECIFIED = 0; + PERIOD_24H = 1; + PERIOD_7D = 2; + PERIOD_30D = 3; + } + Period period = 1; + uint32 limit = 2; // Default 100, max 1000 +} + +message GetTopStateRemoversResponse { + repeated StateRemover removers = 1; + uint64 start_block = 2; + uint64 end_block = 3; +} + +message StateRemover { + uint32 rank = 1; + string address = 2; + uint64 slots_cleared = 3; + uint64 estimated_bytes_freed = 4; + uint64 estimated_gas_refund = 5; // Theoretical gas refund + string category = 6; + string label = 7; + double percentage_of_total = 8; +} + +// Request/Response for GetStateGrowthChart +message GetStateGrowthChartRequest { + enum Period { + PERIOD_UNSPECIFIED = 0; + PERIOD_24H = 1; + PERIOD_7D = 2; + PERIOD_30D = 3; + PERIOD_90D = 4; + } + Period period = 1; + + enum Granularity { + GRANULARITY_UNSPECIFIED = 0; + GRANULARITY_BLOCK = 1; // Individual blocks + GRANULARITY_HOUR = 2; // Hourly aggregates + GRANULARITY_DAY = 3; // Daily aggregates + } + Granularity granularity = 2; +} + +message GetStateGrowthChartResponse { + repeated StateGrowthDataPoint data_points = 1; + StateSummary summary = 2; +} + +message StateGrowthDataPoint { + google.protobuf.Timestamp timestamp = 1; + uint64 block_number = 2; + uint64 slots_added = 3; + uint64 slots_cleared = 4; + int64 net_slots = 5; + uint64 bytes_added = 6; + uint64 bytes_cleared = 7; + int64 net_bytes = 8; +} + +message StateSummary { + uint64 total_slots_added = 1; + uint64 total_slots_cleared = 2; + int64 net_slots = 3; + uint64 total_bytes_added = 4; + uint64 total_bytes_cleared = 5; + int64 net_bytes = 6; + double avg_slots_per_block = 7; +} + +// Request/Response for GetContractStateActivity +message GetContractStateActivityRequest { + string address = 1; // Contract address + uint32 limit = 2; // Number of recent activities to return +} + +message GetContractStateActivityResponse { + string address = 1; + string label = 2; + string category = 3; + ContractStateMetrics metrics = 4; + repeated ContractStateEvent recent_events = 5; +} + +message ContractStateMetrics { + uint64 total_slots = 1; // Total known slots for this contract + uint64 active_slots = 2; // Slots modified in last 30d + uint64 first_seen_block = 3; + uint64 last_active_block = 4; + uint64 lifetime_slots_added = 5; + uint64 lifetime_slots_cleared = 6; +} + +message ContractStateEvent { + uint64 block_number = 1; + google.protobuf.Timestamp timestamp = 2; + enum EventType { + EVENT_TYPE_UNSPECIFIED = 0; + EVENT_TYPE_SLOT_CREATED = 1; + EVENT_TYPE_SLOT_MODIFIED = 2; + EVENT_TYPE_SLOT_CLEARED = 3; + } + EventType event_type = 3; + string slot_key = 4; + string value = 5; +} diff --git a/backend/pkg/server/proto/state_analytics/state_analytics_grpc.pb.go b/backend/pkg/server/proto/state_analytics/state_analytics_grpc.pb.go new file mode 100644 index 000000000..0f44d4de2 --- /dev/null +++ b/backend/pkg/server/proto/state_analytics/state_analytics_grpc.pb.go @@ -0,0 +1,287 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.29.3 +// source: backend/pkg/server/proto/state_analytics/state_analytics.proto + +package state_analytics + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + StateAnalytics_GetLatestBlockDelta_FullMethodName = "/state_analytics.StateAnalytics/GetLatestBlockDelta" + StateAnalytics_GetTopStateAdders_FullMethodName = "/state_analytics.StateAnalytics/GetTopStateAdders" + StateAnalytics_GetTopStateRemovers_FullMethodName = "/state_analytics.StateAnalytics/GetTopStateRemovers" + StateAnalytics_GetStateGrowthChart_FullMethodName = "/state_analytics.StateAnalytics/GetStateGrowthChart" + StateAnalytics_GetContractStateActivity_FullMethodName = "/state_analytics.StateAnalytics/GetContractStateActivity" +) + +// StateAnalyticsClient is the client API for StateAnalytics service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// StateAnalytics service provides state growth and activity metrics +type StateAnalyticsClient interface { + // GetLatestBlockDelta returns state changes for the most recent block + GetLatestBlockDelta(ctx context.Context, in *GetLatestBlockDeltaRequest, opts ...grpc.CallOption) (*GetLatestBlockDeltaResponse, error) + // GetTopStateAdders returns contracts that created the most new storage slots + GetTopStateAdders(ctx context.Context, in *GetTopStateAddersRequest, opts ...grpc.CallOption) (*GetTopStateAddersResponse, error) + // GetTopStateRemovers returns contracts that cleared the most storage slots + GetTopStateRemovers(ctx context.Context, in *GetTopStateRemoversRequest, opts ...grpc.CallOption) (*GetTopStateRemoversResponse, error) + // GetStateGrowthChart returns time-series data of state growth + GetStateGrowthChart(ctx context.Context, in *GetStateGrowthChartRequest, opts ...grpc.CallOption) (*GetStateGrowthChartResponse, error) + // GetContractStateActivity returns detailed state activity for a specific contract + GetContractStateActivity(ctx context.Context, in *GetContractStateActivityRequest, opts ...grpc.CallOption) (*GetContractStateActivityResponse, error) +} + +type stateAnalyticsClient struct { + cc grpc.ClientConnInterface +} + +func NewStateAnalyticsClient(cc grpc.ClientConnInterface) StateAnalyticsClient { + return &stateAnalyticsClient{cc} +} + +func (c *stateAnalyticsClient) GetLatestBlockDelta(ctx context.Context, in *GetLatestBlockDeltaRequest, opts ...grpc.CallOption) (*GetLatestBlockDeltaResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetLatestBlockDeltaResponse) + err := c.cc.Invoke(ctx, StateAnalytics_GetLatestBlockDelta_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *stateAnalyticsClient) GetTopStateAdders(ctx context.Context, in *GetTopStateAddersRequest, opts ...grpc.CallOption) (*GetTopStateAddersResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetTopStateAddersResponse) + err := c.cc.Invoke(ctx, StateAnalytics_GetTopStateAdders_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *stateAnalyticsClient) GetTopStateRemovers(ctx context.Context, in *GetTopStateRemoversRequest, opts ...grpc.CallOption) (*GetTopStateRemoversResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetTopStateRemoversResponse) + err := c.cc.Invoke(ctx, StateAnalytics_GetTopStateRemovers_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *stateAnalyticsClient) GetStateGrowthChart(ctx context.Context, in *GetStateGrowthChartRequest, opts ...grpc.CallOption) (*GetStateGrowthChartResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetStateGrowthChartResponse) + err := c.cc.Invoke(ctx, StateAnalytics_GetStateGrowthChart_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *stateAnalyticsClient) GetContractStateActivity(ctx context.Context, in *GetContractStateActivityRequest, opts ...grpc.CallOption) (*GetContractStateActivityResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetContractStateActivityResponse) + err := c.cc.Invoke(ctx, StateAnalytics_GetContractStateActivity_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// StateAnalyticsServer is the server API for StateAnalytics service. +// All implementations must embed UnimplementedStateAnalyticsServer +// for forward compatibility. +// +// StateAnalytics service provides state growth and activity metrics +type StateAnalyticsServer interface { + // GetLatestBlockDelta returns state changes for the most recent block + GetLatestBlockDelta(context.Context, *GetLatestBlockDeltaRequest) (*GetLatestBlockDeltaResponse, error) + // GetTopStateAdders returns contracts that created the most new storage slots + GetTopStateAdders(context.Context, *GetTopStateAddersRequest) (*GetTopStateAddersResponse, error) + // GetTopStateRemovers returns contracts that cleared the most storage slots + GetTopStateRemovers(context.Context, *GetTopStateRemoversRequest) (*GetTopStateRemoversResponse, error) + // GetStateGrowthChart returns time-series data of state growth + GetStateGrowthChart(context.Context, *GetStateGrowthChartRequest) (*GetStateGrowthChartResponse, error) + // GetContractStateActivity returns detailed state activity for a specific contract + GetContractStateActivity(context.Context, *GetContractStateActivityRequest) (*GetContractStateActivityResponse, error) + mustEmbedUnimplementedStateAnalyticsServer() +} + +// UnimplementedStateAnalyticsServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedStateAnalyticsServer struct{} + +func (UnimplementedStateAnalyticsServer) GetLatestBlockDelta(context.Context, *GetLatestBlockDeltaRequest) (*GetLatestBlockDeltaResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetLatestBlockDelta not implemented") +} +func (UnimplementedStateAnalyticsServer) GetTopStateAdders(context.Context, *GetTopStateAddersRequest) (*GetTopStateAddersResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTopStateAdders not implemented") +} +func (UnimplementedStateAnalyticsServer) GetTopStateRemovers(context.Context, *GetTopStateRemoversRequest) (*GetTopStateRemoversResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTopStateRemovers not implemented") +} +func (UnimplementedStateAnalyticsServer) GetStateGrowthChart(context.Context, *GetStateGrowthChartRequest) (*GetStateGrowthChartResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetStateGrowthChart not implemented") +} +func (UnimplementedStateAnalyticsServer) GetContractStateActivity(context.Context, *GetContractStateActivityRequest) (*GetContractStateActivityResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetContractStateActivity not implemented") +} +func (UnimplementedStateAnalyticsServer) mustEmbedUnimplementedStateAnalyticsServer() {} +func (UnimplementedStateAnalyticsServer) testEmbeddedByValue() {} + +// UnsafeStateAnalyticsServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to StateAnalyticsServer will +// result in compilation errors. +type UnsafeStateAnalyticsServer interface { + mustEmbedUnimplementedStateAnalyticsServer() +} + +func RegisterStateAnalyticsServer(s grpc.ServiceRegistrar, srv StateAnalyticsServer) { + // If the following call pancis, it indicates UnimplementedStateAnalyticsServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&StateAnalytics_ServiceDesc, srv) +} + +func _StateAnalytics_GetLatestBlockDelta_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetLatestBlockDeltaRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StateAnalyticsServer).GetLatestBlockDelta(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StateAnalytics_GetLatestBlockDelta_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StateAnalyticsServer).GetLatestBlockDelta(ctx, req.(*GetLatestBlockDeltaRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StateAnalytics_GetTopStateAdders_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTopStateAddersRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StateAnalyticsServer).GetTopStateAdders(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StateAnalytics_GetTopStateAdders_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StateAnalyticsServer).GetTopStateAdders(ctx, req.(*GetTopStateAddersRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StateAnalytics_GetTopStateRemovers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTopStateRemoversRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StateAnalyticsServer).GetTopStateRemovers(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StateAnalytics_GetTopStateRemovers_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StateAnalyticsServer).GetTopStateRemovers(ctx, req.(*GetTopStateRemoversRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StateAnalytics_GetStateGrowthChart_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetStateGrowthChartRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StateAnalyticsServer).GetStateGrowthChart(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StateAnalytics_GetStateGrowthChart_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StateAnalyticsServer).GetStateGrowthChart(ctx, req.(*GetStateGrowthChartRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StateAnalytics_GetContractStateActivity_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetContractStateActivityRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StateAnalyticsServer).GetContractStateActivity(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StateAnalytics_GetContractStateActivity_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StateAnalyticsServer).GetContractStateActivity(ctx, req.(*GetContractStateActivityRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// StateAnalytics_ServiceDesc is the grpc.ServiceDesc for StateAnalytics service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var StateAnalytics_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "state_analytics.StateAnalytics", + HandlerType: (*StateAnalyticsServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetLatestBlockDelta", + Handler: _StateAnalytics_GetLatestBlockDelta_Handler, + }, + { + MethodName: "GetTopStateAdders", + Handler: _StateAnalytics_GetTopStateAdders_Handler, + }, + { + MethodName: "GetTopStateRemovers", + Handler: _StateAnalytics_GetTopStateRemovers_Handler, + }, + { + MethodName: "GetStateGrowthChart", + Handler: _StateAnalytics_GetStateGrowthChart_Handler, + }, + { + MethodName: "GetContractStateActivity", + Handler: _StateAnalytics_GetContractStateActivity_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "backend/pkg/server/proto/state_analytics/state_analytics.proto", +} diff --git a/backend/pkg/server/proto/state_analytics/state_analytics_test.go b/backend/pkg/server/proto/state_analytics/state_analytics_test.go new file mode 100644 index 000000000..e38135022 --- /dev/null +++ b/backend/pkg/server/proto/state_analytics/state_analytics_test.go @@ -0,0 +1,271 @@ +package state_analytics + +import ( + "testing" + + "google.golang.org/protobuf/proto" +) + +// TestProtoMessagesCompile verifies that proto messages can be instantiated +func TestProtoMessagesCompile(t *testing.T) { + t.Run("GetLatestBlockDeltaRequest", func(t *testing.T) { + req := &GetLatestBlockDeltaRequest{} + if req == nil { + t.Error("Failed to create GetLatestBlockDeltaRequest") + } + }) + + t.Run("GetLatestBlockDeltaResponse", func(t *testing.T) { + resp := &GetLatestBlockDeltaResponse{ + BlockNumber: 12345, + NewSlotsCount: 100, + ModifiedSlotsCount: 50, + ClearedSlotsCount: 10, + EstimatedBytesAdded: 19100, + NetStateChangeBytes: 17190, + } + if resp.BlockNumber != 12345 { + t.Errorf("BlockNumber = %d, expected 12345", resp.BlockNumber) + } + }) + + t.Run("GetTopStateAddersRequest", func(t *testing.T) { + req := &GetTopStateAddersRequest{ + Period: GetTopStateAddersRequest_PERIOD_24H, + Limit: 100, + } + if req.Period != GetTopStateAddersRequest_PERIOD_24H { + t.Error("Failed to set Period enum") + } + if req.Limit != 100 { + t.Error("Failed to set Limit") + } + }) + + t.Run("ContractStateDelta", func(t *testing.T) { + delta := &ContractStateDelta{ + Address: "0x1234567890abcdef", + NewSlots: 10, + ModifiedSlots: 5, + ClearedSlots: 2, + NetBytes: 1528, // (10-2) * 191 + Label: "Test Contract", + } + if delta.Address != "0x1234567890abcdef" { + t.Error("Failed to set Address") + } + }) +} + +// TestProtoEnums verifies that enum values are defined correctly +func TestProtoEnums(t *testing.T) { + t.Run("Period enums", func(t *testing.T) { + periods := []GetTopStateAddersRequest_Period{ + GetTopStateAddersRequest_PERIOD_UNSPECIFIED, + GetTopStateAddersRequest_PERIOD_24H, + GetTopStateAddersRequest_PERIOD_7D, + GetTopStateAddersRequest_PERIOD_30D, + } + + for i, period := range periods { + if int32(period) != int32(i) { + t.Errorf("Period enum %v has value %d, expected %d", period, period, i) + } + } + }) + + t.Run("Granularity enums", func(t *testing.T) { + granularities := []GetStateGrowthChartRequest_Granularity{ + GetStateGrowthChartRequest_GRANULARITY_UNSPECIFIED, + GetStateGrowthChartRequest_GRANULARITY_BLOCK, + GetStateGrowthChartRequest_GRANULARITY_HOUR, + GetStateGrowthChartRequest_GRANULARITY_DAY, + } + + for i, gran := range granularities { + if int32(gran) != int32(i) { + t.Errorf("Granularity enum %v has value %d, expected %d", gran, gran, i) + } + } + }) + + t.Run("EventType enums", func(t *testing.T) { + events := []ContractStateEvent_EventType{ + ContractStateEvent_EVENT_TYPE_UNSPECIFIED, + ContractStateEvent_EVENT_TYPE_SLOT_CREATED, + ContractStateEvent_EVENT_TYPE_SLOT_MODIFIED, + ContractStateEvent_EVENT_TYPE_SLOT_CLEARED, + } + + for i, event := range events { + if int32(event) != int32(i) { + t.Errorf("EventType enum %v has value %d, expected %d", event, event, i) + } + } + }) +} + +// TestProtoSerialization verifies that messages can be marshaled and unmarshaled +func TestProtoSerialization(t *testing.T) { + t.Run("ContractStateDelta", func(t *testing.T) { + original := &ContractStateDelta{ + Address: "0xabcdef1234567890", + NewSlots: 15, + ModifiedSlots: 8, + ClearedSlots: 3, + NetBytes: 2292, // (15-3) * 191 + Label: "Serialization Test", + } + + // Marshal to bytes + data, err := proto.Marshal(original) + if err != nil { + t.Fatalf("Failed to marshal: %v", err) + } + + // Unmarshal back + restored := &ContractStateDelta{} + err = proto.Unmarshal(data, restored) + if err != nil { + t.Fatalf("Failed to unmarshal: %v", err) + } + + // Compare fields + if restored.Address != original.Address { + t.Errorf("Address mismatch: got %s, expected %s", restored.Address, original.Address) + } + if restored.NewSlots != original.NewSlots { + t.Errorf("NewSlots mismatch: got %d, expected %d", restored.NewSlots, original.NewSlots) + } + if restored.Label != original.Label { + t.Errorf("Label mismatch: got %s, expected %s", restored.Label, original.Label) + } + }) + + t.Run("StateGrowthDataPoint", func(t *testing.T) { + original := &StateGrowthDataPoint{ + BlockNumber: 12345678, + SlotsAdded: 1000, + SlotsCleared: 50, + NetSlots: 950, + BytesAdded: 191000, + BytesCleared: 9550, + NetBytes: 181450, + } + + data, err := proto.Marshal(original) + if err != nil { + t.Fatalf("Failed to marshal: %v", err) + } + + restored := &StateGrowthDataPoint{} + err = proto.Unmarshal(data, restored) + if err != nil { + t.Fatalf("Failed to unmarshal: %v", err) + } + + if restored.BlockNumber != original.BlockNumber { + t.Errorf("BlockNumber mismatch: got %d, expected %d", restored.BlockNumber, original.BlockNumber) + } + if restored.NetBytes != original.NetBytes { + t.Errorf("NetBytes mismatch: got %d, expected %d", restored.NetBytes, original.NetBytes) + } + }) +} + +// TestResponseStructures verifies that response structures have expected fields +func TestResponseStructures(t *testing.T) { + t.Run("GetTopStateAddersResponse", func(t *testing.T) { + resp := &GetTopStateAddersResponse{ + Adders: []*StateAdder{ + { + Rank: 1, + Address: "0xtest1", + SlotsAdded: 1000, + EstimatedBytesAdded: 191000, + Category: "ERC20", + Label: "Test Token", + PercentageOfTotal: 5.5, + }, + { + Rank: 2, + Address: "0xtest2", + SlotsAdded: 500, + EstimatedBytesAdded: 95500, + Category: "NFT", + Label: "Test NFT", + PercentageOfTotal: 2.75, + }, + }, + StartBlock: 12340000, + EndBlock: 12347200, + } + + if len(resp.Adders) != 2 { + t.Errorf("Expected 2 adders, got %d", len(resp.Adders)) + } + + if resp.Adders[0].Rank != 1 { + t.Error("First adder should have rank 1") + } + + if resp.StartBlock >= resp.EndBlock { + t.Error("StartBlock should be less than EndBlock") + } + }) + + t.Run("GetStateGrowthChartResponse", func(t *testing.T) { + resp := &GetStateGrowthChartResponse{ + DataPoints: []*StateGrowthDataPoint{ + {BlockNumber: 1, NetBytes: 100}, + {BlockNumber: 2, NetBytes: 200}, + {BlockNumber: 3, NetBytes: 300}, + }, + Summary: &StateSummary{ + TotalSlotsAdded: 3000, + TotalSlotsCleared: 500, + NetSlots: 2500, + TotalBytesAdded: 573000, + TotalBytesCleared: 95500, + NetBytes: 477500, + AvgSlotsPerBlock: 833.33, + }, + } + + if len(resp.DataPoints) != 3 { + t.Errorf("Expected 3 data points, got %d", len(resp.DataPoints)) + } + + if resp.Summary == nil { + t.Error("Summary should not be nil") + } + + expectedNetSlots := int64(resp.Summary.TotalSlotsAdded) - int64(resp.Summary.TotalSlotsCleared) + if resp.Summary.NetSlots != expectedNetSlots { + t.Error("NetSlots should equal TotalSlotsAdded - TotalSlotsCleared") + } + }) +} + +// TestFieldDefaults verifies default values for proto fields +func TestFieldDefaults(t *testing.T) { + t.Run("Empty request has zero values", func(t *testing.T) { + req := &GetTopStateAddersRequest{} + if req.Period != GetTopStateAddersRequest_PERIOD_UNSPECIFIED { + t.Error("Default Period should be PERIOD_UNSPECIFIED") + } + if req.Limit != 0 { + t.Error("Default Limit should be 0") + } + }) + + t.Run("Empty ContractStateDelta", func(t *testing.T) { + delta := &ContractStateDelta{} + if delta.Address != "" { + t.Error("Default Address should be empty string") + } + if delta.NewSlots != 0 { + t.Error("Default NewSlots should be 0") + } + }) +} diff --git a/backend/pkg/server/server.go b/backend/pkg/server/server.go index 1a916e5a5..1260271d3 100644 --- a/backend/pkg/server/server.go +++ b/backend/pkg/server/server.go @@ -22,6 +22,7 @@ import ( "github.com/ethpandaops/lab/backend/pkg/server/internal/service/beacon_slots" "github.com/ethpandaops/lab/backend/pkg/server/internal/service/cartographoor" "github.com/ethpandaops/lab/backend/pkg/server/internal/service/experiments" + "github.com/ethpandaops/lab/backend/pkg/server/internal/service/state_analytics" "github.com/ethpandaops/lab/backend/pkg/server/internal/service/wallclock" "github.com/ethpandaops/lab/backend/pkg/server/internal/service/xatu_cbt" "github.com/sirupsen/logrus" @@ -44,15 +45,16 @@ type Service struct { services []service.Service // Clients - wallclockService *wallclock.Service - storageClient storage.Client - cacheClient cache.Client - lockerClient locker.Locker - geolocationClient *geolocation.Client - xatuCBTService *xatu_cbt.XatuCBT - cartographoorService *cartographoor.Service - experimentsService *experiments.ExperimentsService - metrics *metrics.Metrics + wallclockService *wallclock.Service + storageClient storage.Client + cacheClient cache.Client + lockerClient locker.Locker + geolocationClient *geolocation.Client + xatuCBTService *xatu_cbt.XatuCBT + cartographoorService *cartographoor.Service + experimentsService *experiments.ExperimentsService + stateAnalyticsService *state_analytics.Service + metrics *metrics.Metrics } // New creates a new srv service @@ -135,6 +137,11 @@ func (s *Service) Start(ctx context.Context) error { grpc.NewConfigService(s.log, s.xatuCBTService, s.cartographoorService, nil, bsService, s.experimentsService), } + // Add state analytics gRPC handler if service is initialized + if s.stateAnalyticsService != nil { + grpcServices = append(grpcServices, grpc.NewStateAnalytics(s.log, s.stateAnalyticsService)) + } + // Create gRPC server s.grpcServer = grpc.NewServer( s.log.WithField("component", "grpc_server"), @@ -219,6 +226,16 @@ func (s *Service) initializeServices(ctx context.Context) error { // ctx is alre return fmt.Errorf("failed to initialize beacon slots service: %w", err) } + // Initialize state analytics service if configured + if s.config.StateAnalytics != nil { + stateAnalyticsSvc, err := state_analytics.New(s.log, s.config.StateAnalytics, s.metrics) + if err != nil { + return fmt.Errorf("failed to initialize state analytics service: %w", err) + } + + s.stateAnalyticsService = stateAnalyticsSvc + } + s.services = []service.Service{ beaconSlotsService, s.cartographoorService, diff --git a/frontend/package.json b/frontend/package.json index 8ec3e1837..823da5702 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -29,7 +29,7 @@ "@nivo/scatterplot": "0.93.0", "@nivo/treemap": "0.93.0", "@tailwindcss/vite": "4.1.5", - "@tanstack/react-query": "5.29.2", + "@tanstack/react-query": "5.62.8", "@tanstack/react-router": "^1.132.7", "@types/geojson": "7946.0.16", "@types/react-simple-maps": "3.0.6", diff --git a/frontend/src/api/rest/client.ts b/frontend/src/api/rest/client.ts index 6a5fe9dc9..b382b415b 100644 --- a/frontend/src/api/rest/client.ts +++ b/frontend/src/api/rest/client.ts @@ -16,6 +16,18 @@ import { ListPreparedBlocksResponse, } from '../gen/backend/pkg/api/v1/proto/public_pb'; import { API_V1_ENDPOINTS, buildQueryString, NodeFilters } from './endpoints'; +import type { + LatestBlockDeltaResponse, + TopStateAddersResponse, + TopStateRemoversResponse, + StateGrowthChartResponse, + ContractStateActivityResponse, + StateLatestParams, + StateTopAddersParams, + StateTopRemoversParams, + StateGrowthChartParams, + ContractStateActivityParams, +} from '../../types/state-analytics'; /** * REST API client for v1 endpoints @@ -466,6 +478,98 @@ export class RestApiClient { const response = await this.fetchWithRetry(url); return ListPreparedBlocksResponse.fromJson(response); } + + /** + * Get state changes for the most recent block + * @param network Network name + * @param params Query parameters (currently none) + * @returns Latest block state delta + */ + async getStateLatest( + network: string, + params?: StateLatestParams, + ): Promise { + const queryString = params ? buildQueryString(params) : new URLSearchParams(); + const url = `${this.baseUrl}${API_V1_ENDPOINTS.stateLatest(network)}${ + queryString.toString() ? `?${queryString.toString()}` : '' + }`; + const response = await this.fetchWithRetry(url); + return response as LatestBlockDeltaResponse; + } + + /** + * Get contracts that created the most new storage slots + * @param network Network name + * @param params Query parameters (period, limit) + * @returns Top state adders + */ + async getStateTopAdders( + network: string, + params?: StateTopAddersParams, + ): Promise { + const queryString = params ? buildQueryString(params) : new URLSearchParams(); + const url = `${this.baseUrl}${API_V1_ENDPOINTS.stateTopAdders(network)}${ + queryString.toString() ? `?${queryString.toString()}` : '' + }`; + const response = await this.fetchWithRetry(url); + return response as TopStateAddersResponse; + } + + /** + * Get contracts that cleared the most storage slots + * @param network Network name + * @param params Query parameters (period, limit) + * @returns Top state removers + */ + async getStateTopRemovers( + network: string, + params?: StateTopRemoversParams, + ): Promise { + const queryString = params ? buildQueryString(params) : new URLSearchParams(); + const url = `${this.baseUrl}${API_V1_ENDPOINTS.stateTopRemovers(network)}${ + queryString.toString() ? `?${queryString.toString()}` : '' + }`; + const response = await this.fetchWithRetry(url); + return response as TopStateRemoversResponse; + } + + /** + * Get time-series data of state growth + * @param network Network name + * @param params Query parameters (period, granularity) + * @returns State growth chart data + */ + async getStateGrowthChart( + network: string, + params?: StateGrowthChartParams, + ): Promise { + const queryString = params ? buildQueryString(params) : new URLSearchParams(); + const url = `${this.baseUrl}${API_V1_ENDPOINTS.stateGrowthChart(network)}${ + queryString.toString() ? `?${queryString.toString()}` : '' + }`; + const response = await this.fetchWithRetry(url); + return response as StateGrowthChartResponse; + } + + /** + * Get detailed state activity for a specific contract + * @param network Network name + * @param address Contract address + * @param params Query parameters (limit) + * @returns Contract state activity + */ + async getContractStateActivity( + network: string, + address: string, + params?: ContractStateActivityParams, + ): Promise { + const queryString = params ? buildQueryString(params) : new URLSearchParams(); + const url = `${this.baseUrl}${API_V1_ENDPOINTS.stateContractActivity(network, address)}${ + queryString.toString() ? `?${queryString.toString()}` : '' + }`; + const response = await this.fetchWithRetry(url); + return response as ContractStateActivityResponse; + } } /** diff --git a/frontend/src/api/rest/endpoints.ts b/frontend/src/api/rest/endpoints.ts index c02100548..84bd84bed 100644 --- a/frontend/src/api/rest/endpoints.ts +++ b/frontend/src/api/rest/endpoints.ts @@ -34,6 +34,13 @@ export const API_V1_ENDPOINTS = { `/api/v1/${network}/beacon/slot/${slot}/mev/builder/count`, // Prepared blocks endpoint (formerly locally built blocks) preparedBlocks: (network: string) => `/api/v1/${network}/prepared/blocks`, + // State Analytics endpoints + stateLatest: (network: string) => `/api/v1/${network}/state/latest`, + stateTopAdders: (network: string) => `/api/v1/${network}/state/top-adders`, + stateTopRemovers: (network: string) => `/api/v1/${network}/state/top-removers`, + stateGrowthChart: (network: string) => `/api/v1/${network}/state/growth-chart`, + stateContractActivity: (network: string, address: string) => + `/api/v1/${network}/state/contract/${address}`, }; /** diff --git a/frontend/src/components/layout/Navigation.tsx b/frontend/src/components/layout/Navigation.tsx index c5e8eba75..e529b5681 100644 --- a/frontend/src/components/layout/Navigation.tsx +++ b/frontend/src/components/layout/Navigation.tsx @@ -1,5 +1,5 @@ import { Link, useLocation } from '@tanstack/react-router'; -import { BeakerIcon, HomeIcon, InformationCircleIcon } from '@heroicons/react/24/outline'; +import { BeakerIcon, HomeIcon, InformationCircleIcon, ChartBarIcon } from '@heroicons/react/24/outline'; interface NavigationProps { showLinks?: boolean; @@ -30,6 +30,10 @@ export function Navigation({ showLinks = true, className = '' }: NavigationProps Experiments + + + State Analyzer + About diff --git a/frontend/src/pages/state-analyzer/index.tsx b/frontend/src/pages/state-analyzer/index.tsx new file mode 100644 index 000000000..b393de9c5 --- /dev/null +++ b/frontend/src/pages/state-analyzer/index.tsx @@ -0,0 +1,403 @@ +import { useState, useEffect } from 'react'; +import { FaEthereum } from 'react-icons/fa'; +import { Card, CardBody, CardHeader } from '@/components/common/Card'; +import useContext from '@/contexts/api'; +import { useNetwork } from '@/stores/appStore'; +import type { + LatestBlockDeltaResponse, + TopStateAddersResponse, + TopStateRemoversResponse, + StateGrowthChartResponse, + StatePeriod, + StateGranularity, +} from '@/types/state-analytics'; +import { ResponsiveLine } from '@nivo/line'; +import { defaultNivoTheme } from '@/components/charts/NivoTheme'; + +// Helper function to format bytes +function formatBytes(bytes: number): string { + if (bytes === 0) return '0 B'; + const k = 1024; + const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; + const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(k)); + return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`; +} + +// Helper function to format numbers with commas +function formatNumber(num: number): string { + return num.toLocaleString(); +} + +// Helper function to shorten address +function shortenAddress(address: string): string { + if (!address || address.length < 10) return address; + return `${address.slice(0, 6)}...${address.slice(-4)}`; +} + +function StateAnalyzer() { + const { restClient } = useContext(); + const { selectedNetwork } = useNetwork(); + + const [latestData, setLatestData] = useState(null); + const [topAdders, setTopAdders] = useState(null); + const [topRemovers, setTopRemovers] = useState(null); + const [chartData, setChartData] = useState(null); + + const [period, setPeriod] = useState('24h' as StatePeriod); + const [granularity, setGranularity] = useState('hour' as StateGranularity); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + async function fetchData() { + if (!selectedNetwork || !restClient) return; + + try { + setLoading(true); + setError(null); + + // Fetch all data in parallel + const [latest, adders, removers, chart] = await Promise.all([ + restClient.getStateLatest(selectedNetwork).catch(() => null), + restClient.getStateTopAdders(selectedNetwork, { period, limit: 10 }).catch(() => null), + restClient.getStateTopRemovers(selectedNetwork, { period, limit: 10 }).catch(() => null), + restClient.getStateGrowthChart(selectedNetwork, { period, granularity }).catch(() => null), + ]); + + setLatestData(latest); + setTopAdders(adders); + setTopRemovers(removers); + setChartData(chart); + } catch (err) { + console.error('Error fetching state analytics:', err); + setError(err instanceof Error ? err.message : 'Failed to load data'); + } finally { + setLoading(false); + } + } + + fetchData(); + }, [selectedNetwork, period, granularity, restClient]); + + // Prepare chart data for Nivo + const nivoChartData = chartData?.dataPoints ? [ + { + id: 'State Growth', + data: chartData.dataPoints.map(point => ({ + x: new Date(point.timestamp * 1000), + y: point.netStateChangeBytes / (1024 * 1024), // Convert to MB + })), + }, + ] : []; + + return ( +
+ {/* Hero Section */} + +
+ +
+

+ State Analyzer +

+

+ Real-time visualization of Ethereum state growth, tracking storage slot additions and + deletions across {selectedNetwork || 'the network'}. +

+
+ +
+ + + {/* Loading/Error States */} + {loading && ( + + +
Loading state analytics...
+
+
+ )} + + {error && ( + + +
Error: {error}
+
+
+ )} + + {!loading && !error && ( + <> + {/* Latest Block Metrics */} + {latestData && ( +
+ + +
Latest Block
+
+ #{formatNumber(latestData.blockNumber)} +
+
+
+ + + +
New Slots
+
+ +{formatNumber(latestData.newSlots)} +
+
+ {formatBytes(latestData.estimatedBytesAdded)} +
+
+
+ + + +
Cleared Slots
+
+ -{formatNumber(latestData.clearedSlots)} +
+
+ {formatBytes(latestData.estimatedBytesFreed)} +
+
+
+ + + +
Net Change
+
= 0 ? 'text-accent' : 'text-red-500' + }`} + > + {latestData.netStateChangeBytes >= 0 ? '+' : ''} + {formatBytes(latestData.netStateChangeBytes)} +
+
+
+
+ )} + + {/* Period Selector */} +
+ {(['24h', '7d', '30d'] as StatePeriod[]).map(p => ( + + ))} +
+ + {/* State Growth Chart */} + {chartData && ( + + +
+

State Growth Over Time

+
+ {(['block', 'hour', 'day'] as StateGranularity[]).map(g => ( + + ))} +
+
+
+ + ( +
+
+ {new Date(point.data.x as Date).toLocaleString()} +
+
+ {(point.data.y as number).toFixed(2)} MB +
+
+ )} + /> +
+
+ )} + + {/* Top State Adders & Removers */} +
+ {/* Top Adders */} + {topAdders && ( + + +

Top State Adders

+

Contracts adding most storage slots

+
+ +
+ {topAdders.adders.map(adder => ( +
+
+ #{adder.rank} +
+
+
+ {adder.label || shortenAddress(adder.address)} +
+
+ {formatNumber(adder.slotsAdded)} slots •{' '} + {formatBytes(adder.estimatedBytesAdded)} +
+
+
+
+ {adder.percentageOfTotal.toFixed(1)}% +
+
+
+ ))} +
+
+
+ )} + + {/* Top Removers */} + {topRemovers && ( + + +

Top State Removers

+

Contracts clearing most storage slots

+
+ +
+ {topRemovers.removers.map(remover => ( +
+
+ #{remover.rank} +
+
+
+ {remover.label || shortenAddress(remover.address)} +
+
+ {formatNumber(remover.slotsCleared)} slots •{' '} + {formatBytes(remover.estimatedBytesFreed)} +
+
+
+
+ {remover.percentageOfTotal.toFixed(1)}% +
+
+ ~{formatNumber(remover.estimatedGasRefund)} gas +
+
+
+ ))} +
+
+
+ )} +
+ + {/* Summary Stats */} + {chartData?.summary && ( + + +

Period Summary

+
+ +
+
+
Total New Slots
+
+ +{formatNumber(chartData.summary.totalNewSlots)} +
+
+
+
Total Cleared Slots
+
+ -{formatNumber(chartData.summary.totalClearedSlots)} +
+
+
+
Net State Change
+
= 0 ? 'text-accent' : 'text-red-500' + }`} + > + {chartData.summary.netStateChangeBytes >= 0 ? '+' : ''} + {formatBytes(chartData.summary.netStateChangeBytes)} +
+
+
+
Avg Block Growth
+
+ {formatBytes(chartData.summary.averageBlockGrowthBytes)} +
+
+
+
+
+ )} + + )} +
+ ); +} + +export { StateAnalyzer }; diff --git a/frontend/src/routes/_layout.state-analyzer.tsx b/frontend/src/routes/_layout.state-analyzer.tsx new file mode 100644 index 000000000..bfec6ee69 --- /dev/null +++ b/frontend/src/routes/_layout.state-analyzer.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router'; +import { StateAnalyzer } from '@/pages/state-analyzer'; + +export const Route = createFileRoute('/_layout/state-analyzer')({ + component: StateAnalyzer, +}); diff --git a/frontend/src/types/state-analytics.ts b/frontend/src/types/state-analytics.ts new file mode 100644 index 000000000..d865b784c --- /dev/null +++ b/frontend/src/types/state-analytics.ts @@ -0,0 +1,192 @@ +/** + * State Analytics Types + * + * TypeScript interfaces for Ethereum state growth and storage analytics. + * These types match the protobuf definitions in backend/pkg/server/proto/state_analytics/ + */ + +/** + * Period enum for state analytics queries + */ +export enum StatePeriod { + PERIOD_24H = '24h', + PERIOD_7D = '7d', + PERIOD_30D = '30d', + PERIOD_90D = '90d', +} + +/** + * Granularity enum for chart data + */ +export enum StateGranularity { + BLOCK = 'block', + HOUR = 'hour', + DAY = 'day', +} + +/** + * Latest block state delta response + */ +export interface LatestBlockDeltaResponse { + blockNumber: number; + timestamp: number; + newSlots: number; + clearedSlots: number; + netStateChangeBytes: number; + estimatedBytesAdded: number; + estimatedBytesFreed: number; +} + +/** + * State adder (contract adding storage) + */ +export interface StateAdder { + rank: number; + address: string; + slotsAdded: number; + estimatedBytesAdded: number; + category?: string; + label?: string; + percentageOfTotal: number; +} + +/** + * Top state adders response + */ +export interface TopStateAddersResponse { + period: StatePeriod; + startBlock: number; + endBlock: number; + totalSlotsAdded: number; + adders: StateAdder[]; +} + +/** + * State remover (contract clearing storage) + */ +export interface StateRemover { + rank: number; + address: string; + slotsCleared: number; + estimatedBytesFreed: number; + estimatedGasRefund: number; + category?: string; + label?: string; + percentageOfTotal: number; +} + +/** + * Top state removers response + */ +export interface TopStateRemoversResponse { + period: StatePeriod; + startBlock: number; + endBlock: number; + totalSlotsCleared: number; + removers: StateRemover[]; +} + +/** + * State growth data point + */ +export interface StateGrowthDataPoint { + timestamp: number; + blockNumber: number; + newSlots: number; + clearedSlots: number; + netStateChangeBytes: number; +} + +/** + * State growth summary + */ +export interface StateGrowthSummary { + totalNewSlots: number; + totalClearedSlots: number; + netStateChangeBytes: number; + averageBlockGrowthBytes: number; +} + +/** + * State growth chart response + */ +export interface StateGrowthChartResponse { + period: StatePeriod; + granularity: StateGranularity; + startBlock: number; + endBlock: number; + dataPoints: StateGrowthDataPoint[]; + summary: StateGrowthSummary; +} + +/** + * Contract state metrics + */ +export interface ContractStateMetrics { + totalSlotsAdded: number; + totalSlotsCleared: number; + netSlots: number; + estimatedBytesAdded: number; + estimatedBytesFreed: number; + netBytes: number; + firstSeenBlock: number; + lastSeenBlock: number; +} + +/** + * Contract state event + */ +export interface ContractStateEvent { + blockNumber: number; + timestamp: number; + slotsAdded: number; + slotsCleared: number; + netChange: number; +} + +/** + * Contract state activity response + */ +export interface ContractStateActivityResponse { + address: string; + label?: string; + category?: string; + metrics: ContractStateMetrics; + recentEvents: ContractStateEvent[]; +} + +/** + * Parameters for getStateLatest API call + */ +export interface StateLatestParams {} + +/** + * Parameters for getStateTopAdders API call + */ +export interface StateTopAddersParams { + period?: StatePeriod; + limit?: number; +} + +/** + * Parameters for getStateTopRemovers API call + */ +export interface StateTopRemoversParams { + period?: StatePeriod; + limit?: number; +} + +/** + * Parameters for getStateGrowthChart API call + */ +export interface StateGrowthChartParams { + period?: StatePeriod; + granularity?: StateGranularity; +} + +/** + * Parameters for getContractStateActivity API call + */ +export interface ContractStateActivityParams { + limit?: number; +} From 442082a31faa21c4a8f617ce5fccab4a87b34f8c Mon Sep 17 00:00:00 2001 From: CPerezz Date: Wed, 29 Oct 2025 10:58:21 +0100 Subject: [PATCH 02/10] fix: initialize State Analytics service and fix geolocation Three critical fixes for State Analytics functionality: 1. **Geolocation service**: Skip database load when disabled - Added config field to Client struct - Check enabled flag before loading database in Start() - Prevents startup failure when geolocation is disabled 2. **State Analytics Stop() signature**: Match service.Service interface - Changed Stop() return type from 'error' to void - Ensures proper interface implementation - Required for service to be added to services list 3. **Service initialization**: Add State Analytics to services slice - State Analytics service now gets Start() called on startup - Properly initializes ClickHouse clients for each network - Fixes "network mainnet not configured" API errors Without these fixes, State Analytics service was created but never started, leaving ClickHouse clients uninitialized and causing all API requests to fail with 404 errors. --- backend/pkg/internal/lab/geolocation/geolocation.go | 8 ++++++++ .../server/internal/service/state_analytics/service.go | 4 +--- backend/pkg/server/server.go | 9 ++++++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/backend/pkg/internal/lab/geolocation/geolocation.go b/backend/pkg/internal/lab/geolocation/geolocation.go index 6d9e8bffc..93990a6a4 100644 --- a/backend/pkg/internal/lab/geolocation/geolocation.go +++ b/backend/pkg/internal/lab/geolocation/geolocation.go @@ -21,6 +21,7 @@ const ( // Client manages geolocation data and operations type Client struct { log logrus.FieldLogger + config *Config databaseLocation string locationDB *LocationDB @@ -47,6 +48,7 @@ func New(log logrus.FieldLogger, config *Config, metricsSvc *metrics.Metrics) (* client := &Client{ log: log.WithField("component", "lab/geolocation"), + config: config, databaseLocation: databaseLocation, locationDB: &LocationDB{ Continents: make(map[string]map[string]map[string]CityInfo), @@ -111,6 +113,12 @@ func (c *Client) initMetrics() { // Start initializes the geolocation database func (c *Client) Start(ctx context.Context) error { + // Skip if geolocation is disabled + if c.config != nil && c.config.Enabled != nil && !*c.config.Enabled { + c.log.Info("Geolocation service is disabled, skipping database load") + return nil + } + var status = "success" var source = "unknown" diff --git a/backend/pkg/server/internal/service/state_analytics/service.go b/backend/pkg/server/internal/service/state_analytics/service.go index 0611b603d..1127fc328 100644 --- a/backend/pkg/server/internal/service/state_analytics/service.go +++ b/backend/pkg/server/internal/service/state_analytics/service.go @@ -111,7 +111,7 @@ func (s *Service) Start(ctx context.Context) error { } // Stop gracefully stops the state analytics service -func (s *Service) Stop() error { +func (s *Service) Stop() { s.log.Info("Stopping State Analytics service") // Stop all ClickHouse clients @@ -122,8 +122,6 @@ func (s *Service) Stop() error { } s.log.Info("State Analytics service stopped") - - return nil } // initializeMetrics sets up Prometheus metrics for the service diff --git a/backend/pkg/server/server.go b/backend/pkg/server/server.go index 1260271d3..a3a3789f7 100644 --- a/backend/pkg/server/server.go +++ b/backend/pkg/server/server.go @@ -236,11 +236,18 @@ func (s *Service) initializeServices(ctx context.Context) error { // ctx is alre s.stateAnalyticsService = stateAnalyticsSvc } - s.services = []service.Service{ + servicesSlice := []service.Service{ beaconSlotsService, s.cartographoorService, } + // Add state analytics service if initialized + if s.stateAnalyticsService != nil { + servicesSlice = append(servicesSlice, s.stateAnalyticsService) + } + + s.services = servicesSlice + return nil } From f8b04eedcc58d59c69350da8b2a5deee13c4df46 Mon Sep 17 00:00:00 2001 From: CPerezz Date: Wed, 29 Oct 2025 11:20:01 +0100 Subject: [PATCH 03/10] fix(frontend): match API snake_case response fields and add null safety Frontend was expecting camelCase fields but API returns snake_case. This caused TypeErrors when trying to access undefined properties. Changes: 1. Updated TypeScript types to match API response format: - block_number, new_slots_count, cleared_slots_count, etc. - slots_added, estimated_bytes_added, percentage_of_total - slots_cleared, estimated_bytes_freed, estimated_gas_refund 2. Updated UI component to use correct field names: - latestData.block_number instead of blockNumber - adder.slots_added instead of slotsAdded - remover.percentage_of_total instead of percentageOfTotal 3. Added null safety to formatNumber function: - Returns '0' for undefined/null values - Prevents TypeError when accessing undefined properties 4. Added optional chaining (?.) for percentage_of_total.toFixed() - Prevents crash if percentage is undefined - Falls back to '0' if value is missing The State Analyzer page now displays all data correctly with proper formatting and no runtime errors. --- frontend/src/pages/state-analyzer/index.tsx | 33 ++++++------- frontend/src/types/state-analytics.ts | 51 ++++++++++++--------- 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/frontend/src/pages/state-analyzer/index.tsx b/frontend/src/pages/state-analyzer/index.tsx index b393de9c5..6a922044d 100644 --- a/frontend/src/pages/state-analyzer/index.tsx +++ b/frontend/src/pages/state-analyzer/index.tsx @@ -24,7 +24,8 @@ function formatBytes(bytes: number): string { } // Helper function to format numbers with commas -function formatNumber(num: number): string { +function formatNumber(num: number | undefined): string { + if (num === undefined || num === null) return '0'; return num.toLocaleString(); } @@ -135,7 +136,7 @@ function StateAnalyzer() {
Latest Block
- #{formatNumber(latestData.blockNumber)} + #{formatNumber(latestData.block_number)}
@@ -144,10 +145,10 @@ function StateAnalyzer() {
New Slots
- +{formatNumber(latestData.newSlots)} + +{formatNumber(latestData.new_slots_count)}
- {formatBytes(latestData.estimatedBytesAdded)} + {formatBytes(latestData.estimated_bytes_added)}
@@ -156,10 +157,10 @@ function StateAnalyzer() {
Cleared Slots
- -{formatNumber(latestData.clearedSlots)} + -{formatNumber(latestData.cleared_slots_count)}
- {formatBytes(latestData.estimatedBytesFreed)} + {formatBytes(latestData.net_state_change_bytes < 0 ? Math.abs(latestData.net_state_change_bytes) : 0)}
@@ -169,11 +170,11 @@ function StateAnalyzer() {
Net Change
= 0 ? 'text-accent' : 'text-red-500' + latestData.net_state_change_bytes >= 0 ? 'text-accent' : 'text-red-500' }`} > - {latestData.netStateChangeBytes >= 0 ? '+' : ''} - {formatBytes(latestData.netStateChangeBytes)} + {latestData.net_state_change_bytes >= 0 ? '+' : ''} + {formatBytes(latestData.net_state_change_bytes)}
@@ -295,13 +296,13 @@ function StateAnalyzer() { {adder.label || shortenAddress(adder.address)}
- {formatNumber(adder.slotsAdded)} slots •{' '} - {formatBytes(adder.estimatedBytesAdded)} + {formatNumber(adder.slots_added)} slots •{' '} + {formatBytes(adder.estimated_bytes_added)}
- {adder.percentageOfTotal.toFixed(1)}% + {adder.percentage_of_total?.toFixed(1) || '0'}%
@@ -333,16 +334,16 @@ function StateAnalyzer() { {remover.label || shortenAddress(remover.address)}
- {formatNumber(remover.slotsCleared)} slots •{' '} - {formatBytes(remover.estimatedBytesFreed)} + {formatNumber(remover.slots_cleared)} slots •{' '} + {formatBytes(remover.estimated_bytes_freed)}
- {remover.percentageOfTotal.toFixed(1)}% + {remover.percentage_of_total?.toFixed(1) || '0'}%
- ~{formatNumber(remover.estimatedGasRefund)} gas + ~{formatNumber(remover.estimated_gas_refund)} gas
diff --git a/frontend/src/types/state-analytics.ts b/frontend/src/types/state-analytics.ts index d865b784c..e80d1cd0d 100644 --- a/frontend/src/types/state-analytics.ts +++ b/frontend/src/types/state-analytics.ts @@ -28,13 +28,20 @@ export enum StateGranularity { * Latest block state delta response */ export interface LatestBlockDeltaResponse { - blockNumber: number; - timestamp: number; - newSlots: number; - clearedSlots: number; - netStateChangeBytes: number; - estimatedBytesAdded: number; - estimatedBytesFreed: number; + block_number: number; + block_timestamp: { seconds: number }; + new_slots_count: number; + cleared_slots_count: number; + modified_slots_count: number; + net_state_change_bytes: number; + estimated_bytes_added: number; + top_contributors?: Array<{ + address?: string; + new_slots?: number; + modified_slots?: number; + cleared_slots?: number; + net_bytes?: number; + }>; } /** @@ -43,21 +50,21 @@ export interface LatestBlockDeltaResponse { export interface StateAdder { rank: number; address: string; - slotsAdded: number; - estimatedBytesAdded: number; + slots_added: number; + estimated_bytes_added: number; category?: string; label?: string; - percentageOfTotal: number; + percentage_of_total: number; } /** * Top state adders response */ export interface TopStateAddersResponse { - period: StatePeriod; - startBlock: number; - endBlock: number; - totalSlotsAdded: number; + period?: StatePeriod; + start_block: number; + end_block: number; + total_slots_added?: number; adders: StateAdder[]; } @@ -67,22 +74,22 @@ export interface TopStateAddersResponse { export interface StateRemover { rank: number; address: string; - slotsCleared: number; - estimatedBytesFreed: number; - estimatedGasRefund: number; + slots_cleared: number; + estimated_bytes_freed: number; + estimated_gas_refund: number; category?: string; label?: string; - percentageOfTotal: number; + percentage_of_total: number; } /** * Top state removers response */ export interface TopStateRemoversResponse { - period: StatePeriod; - startBlock: number; - endBlock: number; - totalSlotsCleared: number; + period?: StatePeriod; + start_block: number; + end_block: number; + total_slots_cleared?: number; removers: StateRemover[]; } From f356deb1fe938ca75da03192983c941e50cf4b62 Mon Sep 17 00:00:00 2001 From: CPerezz Date: Wed, 29 Oct 2025 12:53:39 +0100 Subject: [PATCH 04/10] fix(state-analyzer): implement real-time polling and fix chart rendering - Add smart polling: lightweight 1-second polls for latest block, heavy data fetch only on block changes - Fix TypeScript types to use snake_case matching API responses (block_number, new_slots_count, etc.) - Fix Nivo chart color interpolation by using direct hex values instead of CSS custom properties - Add comprehensive null checks for chart data to prevent rendering errors - Update all field references throughout UI to use snake_case format --- frontend/src/pages/state-analyzer/index.tsx | 174 ++++++++++++-------- frontend/src/routeTree.gen.ts | 21 +++ frontend/src/types/state-analytics.ts | 34 ++-- 3 files changed, 150 insertions(+), 79 deletions(-) diff --git a/frontend/src/pages/state-analyzer/index.tsx b/frontend/src/pages/state-analyzer/index.tsx index 6a922044d..0e4b8b6c2 100644 --- a/frontend/src/pages/state-analyzer/index.tsx +++ b/frontend/src/pages/state-analyzer/index.tsx @@ -50,22 +50,45 @@ function StateAnalyzer() { const [error, setError] = useState(null); useEffect(() => { - async function fetchData() { + let lastBlockNumber = 0; + + async function fetchLatestBlock() { + if (!selectedNetwork || !restClient) { + console.log('[State Analyzer] Skipping fetch - no network or client'); + return; + } + + try { + const latest = await restClient.getStateLatest(selectedNetwork).catch(() => null); + if (latest) { + console.log('[State Analyzer] Latest block:', latest.block_number, 'Last:', lastBlockNumber); + setLatestData(latest); + + // Only fetch heavy data when block number changes + if (latest.block_number !== lastBlockNumber) { + console.log('[State Analyzer] New block detected, fetching heavy data'); + lastBlockNumber = latest.block_number; + fetchHeavyData(); + } + } + } catch (err) { + console.error('Error fetching latest block:', err); + } + } + + async function fetchHeavyData() { if (!selectedNetwork || !restClient) return; try { - setLoading(true); setError(null); - // Fetch all data in parallel - const [latest, adders, removers, chart] = await Promise.all([ - restClient.getStateLatest(selectedNetwork).catch(() => null), + // Fetch charts and lists (heavier queries) + const [adders, removers, chart] = await Promise.all([ restClient.getStateTopAdders(selectedNetwork, { period, limit: 10 }).catch(() => null), restClient.getStateTopRemovers(selectedNetwork, { period, limit: 10 }).catch(() => null), restClient.getStateGrowthChart(selectedNetwork, { period, granularity }).catch(() => null), ]); - setLatestData(latest); setTopAdders(adders); setTopRemovers(removers); setChartData(chart); @@ -77,20 +100,35 @@ function StateAnalyzer() { } } - fetchData(); + // Initial load + setLoading(true); + fetchLatestBlock(); + fetchHeavyData(); + + // Poll latest block every second for immediate responsiveness + const latestInterval = setInterval(fetchLatestBlock, 1000); + + return () => { + clearInterval(latestInterval); + }; }, [selectedNetwork, period, granularity, restClient]); // Prepare chart data for Nivo - const nivoChartData = chartData?.dataPoints ? [ + const nivoChartData = chartData?.data_points && chartData.data_points.length > 0 ? [ { id: 'State Growth', - data: chartData.dataPoints.map(point => ({ - x: new Date(point.timestamp * 1000), - y: point.netStateChangeBytes / (1024 * 1024), // Convert to MB - })), + data: chartData.data_points + .filter(point => point?.timestamp?.seconds && point?.net_bytes !== undefined) + .map(point => ({ + x: new Date(point.timestamp.seconds * 1000), + y: point.net_bytes / (1024 * 1024), // Convert to MB + })), }, ] : []; + // Get the actual color value from CSS variable for Nivo + const chartColor = '#00ffff'; // Cyan color matching --cyber-cyan + return (
{/* Hero Section */} @@ -199,7 +237,7 @@ function StateAnalyzer() {
{/* State Growth Chart */} - {chartData && ( + {!loading && chartData && nivoChartData.length > 0 && nivoChartData[0].data.length > 0 && (
@@ -222,52 +260,58 @@ function StateAnalyzer() {
- ( -
-
- {new Date(point.data.x as Date).toLocaleString()} -
-
- {(point.data.y as number).toFixed(2)} MB + {nivoChartData[0].data.length > 0 ? ( + ( +
+
+ {new Date(point.data.x as Date).toLocaleString()} +
+
+ {(point.data.y as number).toFixed(2)} MB +
-
- )} - /> + )} + /> + ) : ( +
+ No chart data available +
+ )} )} @@ -365,30 +409,30 @@ function StateAnalyzer() {
Total New Slots
- +{formatNumber(chartData.summary.totalNewSlots)} + +{formatNumber(chartData.summary.total_slots_added)}
Total Cleared Slots
- -{formatNumber(chartData.summary.totalClearedSlots)} + -{formatNumber(chartData.summary.total_slots_cleared)}
Net State Change
= 0 ? 'text-accent' : 'text-red-500' + chartData.summary.net_bytes >= 0 ? 'text-accent' : 'text-red-500' }`} > - {chartData.summary.netStateChangeBytes >= 0 ? '+' : ''} - {formatBytes(chartData.summary.netStateChangeBytes)} + {chartData.summary.net_bytes >= 0 ? '+' : ''} + {formatBytes(chartData.summary.net_bytes)}
-
Avg Block Growth
+
Avg Slots Per Block
- {formatBytes(chartData.summary.averageBlockGrowthBytes)} + {formatNumber(chartData.summary.avg_slots_per_block)}
diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts index b74ab53a1..2f760dd26 100644 --- a/frontend/src/routeTree.gen.ts +++ b/frontend/src/routeTree.gen.ts @@ -11,6 +11,7 @@ import { Route as rootRouteImport } from './routes/__root' import { Route as LayoutRouteImport } from './routes/_layout' import { Route as LayoutIndexRouteImport } from './routes/_layout.index' +import { Route as LayoutStateAnalyzerRouteImport } from './routes/_layout.state-analyzer' import { Route as LayoutExperimentsRouteImport } from './routes/_layout.experiments' import { Route as LayoutBeaconRouteImport } from './routes/_layout.beacon' import { Route as LayoutAboutRouteImport } from './routes/_layout.about' @@ -38,6 +39,11 @@ const LayoutIndexRoute = LayoutIndexRouteImport.update({ path: '/', getParentRoute: () => LayoutRoute, } as any) +const LayoutStateAnalyzerRoute = LayoutStateAnalyzerRouteImport.update({ + id: '/state-analyzer', + path: '/state-analyzer', + getParentRoute: () => LayoutRoute, +} as any) const LayoutExperimentsRoute = LayoutExperimentsRouteImport.update({ id: '/experiments', path: '/experiments', @@ -138,6 +144,7 @@ export interface FileRoutesByFullPath { '/about': typeof LayoutAboutRoute '/beacon': typeof LayoutBeaconRouteWithChildren '/experiments': typeof LayoutExperimentsRouteWithChildren + '/state-analyzer': typeof LayoutStateAnalyzerRoute '/': typeof LayoutIndexRoute '/beacon/locally-built-blocks': typeof LayoutBeaconLocallyBuiltBlocksRoute '/experiments/$experimentId': typeof LayoutExperimentsExperimentIdRouteWithChildren @@ -157,6 +164,7 @@ export interface FileRoutesByFullPath { export interface FileRoutesByTo { '/about': typeof LayoutAboutRoute '/beacon': typeof LayoutBeaconRouteWithChildren + '/state-analyzer': typeof LayoutStateAnalyzerRoute '/': typeof LayoutIndexRoute '/beacon/locally-built-blocks': typeof LayoutBeaconLocallyBuiltBlocksRoute '/xatu-data/fork-readiness': typeof LayoutXatuDataForkReadinessRoute @@ -178,6 +186,7 @@ export interface FileRoutesById { '/_layout/about': typeof LayoutAboutRoute '/_layout/beacon': typeof LayoutBeaconRouteWithChildren '/_layout/experiments': typeof LayoutExperimentsRouteWithChildren + '/_layout/state-analyzer': typeof LayoutStateAnalyzerRoute '/_layout/': typeof LayoutIndexRoute '/_layout/beacon/locally-built-blocks': typeof LayoutBeaconLocallyBuiltBlocksRoute '/_layout/experiments/$experimentId': typeof LayoutExperimentsExperimentIdRouteWithChildren @@ -200,6 +209,7 @@ export interface FileRouteTypes { | '/about' | '/beacon' | '/experiments' + | '/state-analyzer' | '/' | '/beacon/locally-built-blocks' | '/experiments/$experimentId' @@ -219,6 +229,7 @@ export interface FileRouteTypes { to: | '/about' | '/beacon' + | '/state-analyzer' | '/' | '/beacon/locally-built-blocks' | '/xatu-data/fork-readiness' @@ -239,6 +250,7 @@ export interface FileRouteTypes { | '/_layout/about' | '/_layout/beacon' | '/_layout/experiments' + | '/_layout/state-analyzer' | '/_layout/' | '/_layout/beacon/locally-built-blocks' | '/_layout/experiments/$experimentId' @@ -276,6 +288,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof LayoutIndexRouteImport parentRoute: typeof LayoutRoute } + '/_layout/state-analyzer': { + id: '/_layout/state-analyzer' + path: '/state-analyzer' + fullPath: '/state-analyzer' + preLoaderRoute: typeof LayoutStateAnalyzerRouteImport + parentRoute: typeof LayoutRoute + } '/_layout/experiments': { id: '/_layout/experiments' path: '/experiments' @@ -449,6 +468,7 @@ interface LayoutRouteChildren { LayoutAboutRoute: typeof LayoutAboutRoute LayoutBeaconRoute: typeof LayoutBeaconRouteWithChildren LayoutExperimentsRoute: typeof LayoutExperimentsRouteWithChildren + LayoutStateAnalyzerRoute: typeof LayoutStateAnalyzerRoute LayoutIndexRoute: typeof LayoutIndexRoute LayoutXatuDataForkReadinessRoute: typeof LayoutXatuDataForkReadinessRoute LayoutXatuDataGeographicalChecklistRoute: typeof LayoutXatuDataGeographicalChecklistRoute @@ -463,6 +483,7 @@ const LayoutRouteChildren: LayoutRouteChildren = { LayoutAboutRoute: LayoutAboutRoute, LayoutBeaconRoute: LayoutBeaconRouteWithChildren, LayoutExperimentsRoute: LayoutExperimentsRouteWithChildren, + LayoutStateAnalyzerRoute: LayoutStateAnalyzerRoute, LayoutIndexRoute: LayoutIndexRoute, LayoutXatuDataForkReadinessRoute: LayoutXatuDataForkReadinessRoute, LayoutXatuDataGeographicalChecklistRoute: diff --git a/frontend/src/types/state-analytics.ts b/frontend/src/types/state-analytics.ts index e80d1cd0d..2f30741ee 100644 --- a/frontend/src/types/state-analytics.ts +++ b/frontend/src/types/state-analytics.ts @@ -97,32 +97,38 @@ export interface TopStateRemoversResponse { * State growth data point */ export interface StateGrowthDataPoint { - timestamp: number; - blockNumber: number; - newSlots: number; - clearedSlots: number; - netStateChangeBytes: number; + timestamp: { seconds: number }; + block_number: number; + slots_added: number; + slots_cleared: number; + net_slots: number; + bytes_added: number; + bytes_cleared: number; + net_bytes: number; } /** * State growth summary */ export interface StateGrowthSummary { - totalNewSlots: number; - totalClearedSlots: number; - netStateChangeBytes: number; - averageBlockGrowthBytes: number; + total_slots_added: number; + total_slots_cleared: number; + net_slots: number; + total_bytes_added: number; + total_bytes_cleared: number; + net_bytes: number; + avg_slots_per_block: number; } /** * State growth chart response */ export interface StateGrowthChartResponse { - period: StatePeriod; - granularity: StateGranularity; - startBlock: number; - endBlock: number; - dataPoints: StateGrowthDataPoint[]; + period?: StatePeriod; + granularity?: StateGranularity; + start_block?: number; + end_block?: number; + data_points: StateGrowthDataPoint[]; summary: StateGrowthSummary; } From 7ca358edf4b3c00174888359aff4c48443f0a675 Mon Sep 17 00:00:00 2001 From: CPerezz Date: Wed, 29 Oct 2025 14:13:19 +0100 Subject: [PATCH 05/10] feat(state-analytics): add Paradigm diagram backend endpoints - Add proto definitions for GetContractStateComposition and GetHierarchicalState - Create ClickHouse query for contract state sizes aggregation - Implement service methods: contract_state_composition.go and hierarchical_state.go - Add hierarchical tree builder (Category -> Protocol -> Contract) - Wire up gRPC wrapper layer for new methods - Add REST API handlers and routes for /state/composition and /state/hierarchical - Add getFloat64 helper function for ClickHouse result parsing Endpoints tested and working: - GET /api/v1/{network}/state/composition?limit=N&min_size_bytes=N - GET /api/v1/{network}/state/hierarchical?max_depth=N&contracts_per_protocol=N --- backend/pkg/api/v1/rest/routes.go | 14 + .../api/v1/rest/state_analytics_handlers.go | 68 ++ .../server/internal/grpc/state_analytics.go | 16 + .../contract_state_composition.go | 118 +++ .../state_analytics/hierarchical_state.go | 169 ++++ .../state_analytics/latest_block_delta.go | 20 + .../service/state_analytics/queries.go | 43 + .../state_analytics/state_analytics.pb.go | 771 +++++++++++++++--- .../state_analytics/state_analytics.proto | 57 ++ .../state_analytics_grpc.pb.go | 94 ++- 10 files changed, 1247 insertions(+), 123 deletions(-) create mode 100644 backend/pkg/server/internal/service/state_analytics/contract_state_composition.go create mode 100644 backend/pkg/server/internal/service/state_analytics/hierarchical_state.go diff --git a/backend/pkg/api/v1/rest/routes.go b/backend/pkg/api/v1/rest/routes.go index 676c22ab6..f775e31ec 100644 --- a/backend/pkg/api/v1/rest/routes.go +++ b/backend/pkg/api/v1/rest/routes.go @@ -187,5 +187,19 @@ func (r *PublicRouter) GetRoutes() []RouteConfig { Cache: middleware.CacheNearRealtime, Description: "Get detailed state activity for a specific contract", }, + { + Path: "/{network}/state/composition", + Handler: r.handleContractStateComposition, + Methods: []string{http.MethodGet, http.MethodOptions}, + Cache: middleware.CacheBrowserShort, + Description: "Get current state size for all contracts (Paradigm diagram data)", + }, + { + Path: "/{network}/state/hierarchical", + Handler: r.handleHierarchicalState, + Methods: []string{http.MethodGet, http.MethodOptions}, + Cache: middleware.CacheBrowserShort, + Description: "Get state organized hierarchically by category -> protocol -> contract", + }, } } diff --git a/backend/pkg/api/v1/rest/state_analytics_handlers.go b/backend/pkg/api/v1/rest/state_analytics_handlers.go index b0f5bb2e1..a7224fc63 100644 --- a/backend/pkg/api/v1/rest/state_analytics_handlers.go +++ b/backend/pkg/api/v1/rest/state_analytics_handlers.go @@ -219,3 +219,71 @@ func networkFromContext(ctx context.Context) string { return networks[0] } + +// handleContractStateComposition returns current state size for all contracts (Paradigm diagram data) +func (r *PublicRouter) handleContractStateComposition(w http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + network := vars["network"] + + // Parse query parameters + queryParams := req.URL.Query() + limit := parseLimit(queryParams.Get("limit"), 10000) + minSizeBytes := parseUint64(queryParams.Get("min_size_bytes"), 0) + includeLabels := queryParams.Get("include_labels") == "true" + + // Add network to gRPC metadata + ctx := metadata.NewOutgoingContext(req.Context(), metadata.Pairs("network", network)) + + // Call gRPC service + resp, err := r.stateAnalyticsClient.GetContractStateComposition(ctx, &state_analytics_pb.GetContractStateCompositionRequest{ + Limit: limit, + MinSizeBytes: minSizeBytes, + IncludeLabels: includeLabels, + }) + if err != nil { + r.HandleGRPCError(w, req, err) + return + } + + r.WriteJSONResponseOK(w, req, resp) +} + +// handleHierarchicalState returns state organized hierarchically by category -> protocol -> contract +func (r *PublicRouter) handleHierarchicalState(w http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + network := vars["network"] + + // Parse query parameters + queryParams := req.URL.Query() + maxDepth := parseLimit(queryParams.Get("max_depth"), 3) + contractsPerProtocol := parseLimit(queryParams.Get("contracts_per_protocol"), 20) + + // Add network to gRPC metadata + ctx := metadata.NewOutgoingContext(req.Context(), metadata.Pairs("network", network)) + + // Call gRPC service + resp, err := r.stateAnalyticsClient.GetHierarchicalState(ctx, &state_analytics_pb.GetHierarchicalStateRequest{ + MaxDepth: maxDepth, + ContractsPerProtocol: contractsPerProtocol, + }) + if err != nil { + r.HandleGRPCError(w, req, err) + return + } + + r.WriteJSONResponseOK(w, req, resp) +} + +// parseUint64 parses uint64 query parameter with default value +func parseUint64(value string, defaultValue uint64) uint64 { + if value == "" { + return defaultValue + } + + parsed, err := strconv.ParseUint(value, 10, 64) + if err != nil { + return defaultValue + } + + return parsed +} diff --git a/backend/pkg/server/internal/grpc/state_analytics.go b/backend/pkg/server/internal/grpc/state_analytics.go index e9c722aea..e3c2be57d 100644 --- a/backend/pkg/server/internal/grpc/state_analytics.go +++ b/backend/pkg/server/internal/grpc/state_analytics.go @@ -81,3 +81,19 @@ func (sa *StateAnalytics) GetContractStateActivity( // TODO: Implement this method return nil, nil } + +// GetContractStateComposition returns current state size for all contracts (Paradigm diagram data). +func (sa *StateAnalytics) GetContractStateComposition( + ctx context.Context, + req *pb.GetContractStateCompositionRequest, +) (*pb.GetContractStateCompositionResponse, error) { + return sa.service.GetContractStateComposition(ctx, req) +} + +// GetHierarchicalState returns state organized hierarchically by category -> protocol -> contract. +func (sa *StateAnalytics) GetHierarchicalState( + ctx context.Context, + req *pb.GetHierarchicalStateRequest, +) (*pb.GetHierarchicalStateResponse, error) { + return sa.service.GetHierarchicalState(ctx, req) +} diff --git a/backend/pkg/server/internal/service/state_analytics/contract_state_composition.go b/backend/pkg/server/internal/service/state_analytics/contract_state_composition.go new file mode 100644 index 000000000..f0930e8be --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/contract_state_composition.go @@ -0,0 +1,118 @@ +package state_analytics + +import ( + "context" + "fmt" + "strings" + "time" + + pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" + "google.golang.org/protobuf/types/known/timestamppb" +) + +// GetContractStateComposition returns current state size for all contracts +func (s *Service) GetContractStateComposition( + ctx context.Context, + req *pb.GetContractStateCompositionRequest, +) (*pb.GetContractStateCompositionResponse, error) { + startTime := time.Now() + method := "GetContractStateComposition" + + // Get network from context + network, err := s.getNetworkFromContext(ctx) + if err != nil { + s.recordMetrics(method, "unknown", StatusError, time.Since(startTime).Seconds()) + return nil, err + } + + s.log.WithField("network", network).Debug("Fetching contract state composition") + + // Get ClickHouse client + client, err := s.getClient(network) + if err != nil { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, fmt.Errorf("failed to get ClickHouse client: %w", err) + } + + // Set defaults + limit := req.Limit + if limit == 0 { + limit = 10000 + } + if limit > 50000 { + limit = 50000 // Cap at 50k contracts + } + + minSizeBytes := req.MinSizeBytes + if minSizeBytes == 0 { + minSizeBytes = 0 // Include all contracts by default + } + + // Build query with replacements + query := strings.ReplaceAll(queryContractStateComposition, "{database}", network) + query = strings.ReplaceAll(query, "{bytes_per_slot}", fmt.Sprintf("%d", BytesPerSlot)) + query = strings.ReplaceAll(query, "{min_size_bytes}", fmt.Sprintf("%d", minSizeBytes)) + query = strings.ReplaceAll(query, "{limit}", fmt.Sprintf("%d", limit)) + + // Execute query + rows, err := client.Query(ctx, query) + if err != nil { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, fmt.Errorf("failed to query contract state composition: %w", err) + } + + if len(rows) == 0 { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, fmt.Errorf("no contract data returned") + } + + // Parse results + contracts := make([]*pb.ContractStateEntry, 0, len(rows)) + var totalStateBytes uint64 + var blockNumber uint64 + + for _, row := range rows { + address := getString(row, "address") + storageSlotCount := getUint64(row, "storage_slot_count") + totalBytes := getUint64(row, "total_bytes") + firstSeenBlock := getUint64(row, "first_seen_block") + lastActiveBlock := getUint64(row, "last_active_block") + percentageOfTotal := getFloat64(row, "percentage_of_total") + + // Track latest block number + if lastActiveBlock > blockNumber { + blockNumber = lastActiveBlock + } + + totalStateBytes += totalBytes + + // Create contract entry (without labels for now) + contracts = append(contracts, &pb.ContractStateEntry{ + Address: address, + Label: "", // Will be filled by labeling service later + Category: "", // Will be filled by labeling service later + Protocol: "", // Will be filled by labeling service later + State: &pb.ContractState{ + StorageSlotCount: storageSlotCount, + TotalBytes: totalBytes, + BytecodeBytes: 0, // Not calculated yet + FirstSeenBlock: firstSeenBlock, + LastActiveBlock: lastActiveBlock, + }, + PercentageOfTotal: percentageOfTotal, + }) + } + + // Estimate block timestamp (12s per block, assuming genesis at ~1606824000 for mainnet) + genesisTime := int64(1606824000) + blockTimestamp := time.Unix(genesisTime+int64(blockNumber)*12, 0) + + s.recordMetrics(method, network, StatusSuccess, time.Since(startTime).Seconds()) + + return &pb.GetContractStateCompositionResponse{ + Contracts: contracts, + BlockNumber: blockNumber, + Timestamp: timestamppb.New(blockTimestamp), + TotalStateBytes: totalStateBytes, + }, nil +} diff --git a/backend/pkg/server/internal/service/state_analytics/hierarchical_state.go b/backend/pkg/server/internal/service/state_analytics/hierarchical_state.go new file mode 100644 index 000000000..dc737b7d9 --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/hierarchical_state.go @@ -0,0 +1,169 @@ +package state_analytics + +import ( + "context" + "fmt" + "sort" + + pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" +) + +// GetHierarchicalState returns state organized hierarchically by category -> protocol -> contract +func (s *Service) GetHierarchicalState( + ctx context.Context, + req *pb.GetHierarchicalStateRequest, +) (*pb.GetHierarchicalStateResponse, error) { + // Step 1: Get flat contract list with labels + flatReq := &pb.GetContractStateCompositionRequest{ + Limit: 10000, + MinSizeBytes: 0, + IncludeLabels: true, + } + + flatResp, err := s.GetContractStateComposition(ctx, flatReq) + if err != nil { + return nil, err + } + + // Step 2: Set defaults for hierarchy parameters + maxDepth := req.MaxDepth + if maxDepth == 0 { + maxDepth = 3 // Default: show all levels + } + + contractsPerProtocol := req.ContractsPerProtocol + if contractsPerProtocol == 0 { + contractsPerProtocol = 20 // Default: show top 20 contracts per protocol + } + + // Step 3: Build hierarchy + root := buildHierarchy(flatResp.Contracts, maxDepth, contractsPerProtocol) + + return &pb.GetHierarchicalStateResponse{ + Root: root, + BlockNumber: flatResp.BlockNumber, + Timestamp: flatResp.Timestamp, + }, nil +} + +// buildHierarchy transforms flat contract list into hierarchical tree structure +func buildHierarchy(contracts []*pb.ContractStateEntry, maxDepth, contractsPerProtocol uint32) *pb.StateNode { + // Create root node + root := &pb.StateNode{ + Name: "Ethereum State", + Type: "root", + SizeBytes: 0, + Children: make([]*pb.StateNode, 0), + Metadata: make(map[string]string), + } + + // Group by category + categoryMap := make(map[string]*pb.StateNode) + + for _, contract := range contracts { + category := contract.Category + if category == "" { + category = "Other" + } + + // Get or create category node + catNode, exists := categoryMap[category] + if !exists { + catNode = &pb.StateNode{ + Name: category, + Type: "category", + SizeBytes: 0, + Children: make([]*pb.StateNode, 0), + Metadata: map[string]string{"category": category}, + } + categoryMap[category] = catNode + } + + catNode.SizeBytes += contract.State.TotalBytes + + // If maxDepth >= 2, group by protocol + if maxDepth >= 2 { + protocol := contract.Protocol + if protocol == "" { + protocol = "Unknown" + } + + // Find or create protocol node + var protocolNode *pb.StateNode + for _, child := range catNode.Children { + if child.Name == protocol { + protocolNode = child + break + } + } + + if protocolNode == nil { + protocolNode = &pb.StateNode{ + Name: protocol, + Type: "protocol", + SizeBytes: 0, + Children: make([]*pb.StateNode, 0), + Metadata: map[string]string{ + "category": category, + "protocol": protocol, + }, + } + catNode.Children = append(catNode.Children, protocolNode) + } + + protocolNode.SizeBytes += contract.State.TotalBytes + + // If maxDepth >= 3, add individual contracts + if maxDepth >= 3 { + label := contract.Label + if label == "" { + label = fmt.Sprintf("%s...%s", contract.Address[:10], contract.Address[len(contract.Address)-8:]) + } + + contractNode := &pb.StateNode{ + Name: label, + Type: "contract", + SizeBytes: contract.State.TotalBytes, + Metadata: map[string]string{ + "address": contract.Address, + "category": category, + "protocol": protocol, + "slot_count": fmt.Sprintf("%d", contract.State.StorageSlotCount), + "bytecode_size": fmt.Sprintf("%d", contract.State.BytecodeBytes), + }, + } + protocolNode.Children = append(protocolNode.Children, contractNode) + } + } + } + + // Sort and limit children at each level + for _, catNode := range categoryMap { + root.SizeBytes += catNode.SizeBytes + root.Children = append(root.Children, catNode) + + // Sort protocols by size + sort.Slice(catNode.Children, func(i, j int) bool { + return catNode.Children[i].SizeBytes > catNode.Children[j].SizeBytes + }) + + // Limit contracts per protocol + for _, protocolNode := range catNode.Children { + if uint32(len(protocolNode.Children)) > contractsPerProtocol { + // Sort contracts by size + sort.Slice(protocolNode.Children, func(i, j int) bool { + return protocolNode.Children[i].SizeBytes > protocolNode.Children[j].SizeBytes + }) + // Keep only top N contracts + protocolNode.Children = protocolNode.Children[:contractsPerProtocol] + } + } + } + + // Sort categories by size + sort.Slice(root.Children, func(i, j int) bool { + return root.Children[i].SizeBytes > root.Children[j].SizeBytes + }) + + return root +} diff --git a/backend/pkg/server/internal/service/state_analytics/latest_block_delta.go b/backend/pkg/server/internal/service/state_analytics/latest_block_delta.go index f36fcf0c4..47c1e748d 100644 --- a/backend/pkg/server/internal/service/state_analytics/latest_block_delta.go +++ b/backend/pkg/server/internal/service/state_analytics/latest_block_delta.go @@ -187,3 +187,23 @@ func getInt64(m map[string]interface{}, key string) int64 { } return 0 } + +func getFloat64(m map[string]interface{}, key string) float64 { + if v, ok := m[key]; ok { + switch val := v.(type) { + case float64: + return val + case float32: + return float64(val) + case int: + return float64(val) + case int64: + return float64(val) + case uint64: + return float64(val) + case uint32: + return float64(val) + } + } + return 0.0 +} diff --git a/backend/pkg/server/internal/service/state_analytics/queries.go b/backend/pkg/server/internal/service/state_analytics/queries.go index 49fd7a96f..4a7ed2713 100644 --- a/backend/pkg/server/internal/service/state_analytics/queries.go +++ b/backend/pkg/server/internal/service/state_analytics/queries.go @@ -182,3 +182,46 @@ ORDER BY abs( ) ASC LIMIT 1 ` + +// Query to get contract state composition (for Paradigm diagram) +// Returns all contracts with their current storage slot counts +const queryContractStateComposition = ` +WITH latest_block AS ( + SELECT MAX(block_number) as max_block + FROM {database}.int_address_storage_slot_last_access +), +-- Get slot counts per contract from first_access (all slots ever created) +contract_slots AS ( + SELECT + address, + count() as slot_count, + min(block_number) as first_seen_block + FROM {database}.int_address_storage_slot_first_access + GROUP BY address +), +-- Get last activity from last_access table +contract_last_activity AS ( + SELECT + address, + max(block_number) as last_active_block + FROM {database}.int_address_storage_slot_last_access + GROUP BY address +), +-- Calculate total state bytes +total_state AS ( + SELECT sum(slot_count) * {bytes_per_slot} as total_bytes + FROM contract_slots +) +SELECT + cs.address, + cs.slot_count as storage_slot_count, + cs.slot_count * {bytes_per_slot} as total_bytes, + cs.first_seen_block, + coalesce(la.last_active_block, cs.first_seen_block) as last_active_block, + (cs.slot_count * {bytes_per_slot}) / (SELECT total_bytes FROM total_state) * 100 as percentage_of_total +FROM contract_slots cs +LEFT JOIN contract_last_activity la ON cs.address = la.address +WHERE cs.slot_count * {bytes_per_slot} >= {min_size_bytes} +ORDER BY cs.slot_count DESC +LIMIT {limit} +` diff --git a/backend/pkg/server/proto/state_analytics/state_analytics.pb.go b/backend/pkg/server/proto/state_analytics/state_analytics.pb.go index f6c819cac..c99c3d999 100644 --- a/backend/pkg/server/proto/state_analytics/state_analytics.pb.go +++ b/backend/pkg/server/proto/state_analytics/state_analytics.pb.go @@ -2,7 +2,7 @@ // versions: // protoc-gen-go v1.36.10 // protoc v5.29.3 -// source: backend/pkg/server/proto/state_analytics/state_analytics.proto +// source: state_analytics.proto package state_analytics @@ -58,11 +58,11 @@ func (x GetTopStateAddersRequest_Period) String() string { } func (GetTopStateAddersRequest_Period) Descriptor() protoreflect.EnumDescriptor { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[0].Descriptor() + return file_state_analytics_proto_enumTypes[0].Descriptor() } func (GetTopStateAddersRequest_Period) Type() protoreflect.EnumType { - return &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[0] + return &file_state_analytics_proto_enumTypes[0] } func (x GetTopStateAddersRequest_Period) Number() protoreflect.EnumNumber { @@ -71,7 +71,7 @@ func (x GetTopStateAddersRequest_Period) Number() protoreflect.EnumNumber { // Deprecated: Use GetTopStateAddersRequest_Period.Descriptor instead. func (GetTopStateAddersRequest_Period) EnumDescriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{3, 0} + return file_state_analytics_proto_rawDescGZIP(), []int{3, 0} } type GetTopStateRemoversRequest_Period int32 @@ -110,11 +110,11 @@ func (x GetTopStateRemoversRequest_Period) String() string { } func (GetTopStateRemoversRequest_Period) Descriptor() protoreflect.EnumDescriptor { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[1].Descriptor() + return file_state_analytics_proto_enumTypes[1].Descriptor() } func (GetTopStateRemoversRequest_Period) Type() protoreflect.EnumType { - return &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[1] + return &file_state_analytics_proto_enumTypes[1] } func (x GetTopStateRemoversRequest_Period) Number() protoreflect.EnumNumber { @@ -123,7 +123,7 @@ func (x GetTopStateRemoversRequest_Period) Number() protoreflect.EnumNumber { // Deprecated: Use GetTopStateRemoversRequest_Period.Descriptor instead. func (GetTopStateRemoversRequest_Period) EnumDescriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{6, 0} + return file_state_analytics_proto_rawDescGZIP(), []int{6, 0} } type GetStateGrowthChartRequest_Period int32 @@ -165,11 +165,11 @@ func (x GetStateGrowthChartRequest_Period) String() string { } func (GetStateGrowthChartRequest_Period) Descriptor() protoreflect.EnumDescriptor { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[2].Descriptor() + return file_state_analytics_proto_enumTypes[2].Descriptor() } func (GetStateGrowthChartRequest_Period) Type() protoreflect.EnumType { - return &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[2] + return &file_state_analytics_proto_enumTypes[2] } func (x GetStateGrowthChartRequest_Period) Number() protoreflect.EnumNumber { @@ -178,7 +178,7 @@ func (x GetStateGrowthChartRequest_Period) Number() protoreflect.EnumNumber { // Deprecated: Use GetStateGrowthChartRequest_Period.Descriptor instead. func (GetStateGrowthChartRequest_Period) EnumDescriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{9, 0} + return file_state_analytics_proto_rawDescGZIP(), []int{9, 0} } type GetStateGrowthChartRequest_Granularity int32 @@ -217,11 +217,11 @@ func (x GetStateGrowthChartRequest_Granularity) String() string { } func (GetStateGrowthChartRequest_Granularity) Descriptor() protoreflect.EnumDescriptor { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[3].Descriptor() + return file_state_analytics_proto_enumTypes[3].Descriptor() } func (GetStateGrowthChartRequest_Granularity) Type() protoreflect.EnumType { - return &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[3] + return &file_state_analytics_proto_enumTypes[3] } func (x GetStateGrowthChartRequest_Granularity) Number() protoreflect.EnumNumber { @@ -230,7 +230,7 @@ func (x GetStateGrowthChartRequest_Granularity) Number() protoreflect.EnumNumber // Deprecated: Use GetStateGrowthChartRequest_Granularity.Descriptor instead. func (GetStateGrowthChartRequest_Granularity) EnumDescriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{9, 1} + return file_state_analytics_proto_rawDescGZIP(), []int{9, 1} } type ContractStateEvent_EventType int32 @@ -269,11 +269,11 @@ func (x ContractStateEvent_EventType) String() string { } func (ContractStateEvent_EventType) Descriptor() protoreflect.EnumDescriptor { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[4].Descriptor() + return file_state_analytics_proto_enumTypes[4].Descriptor() } func (ContractStateEvent_EventType) Type() protoreflect.EnumType { - return &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[4] + return &file_state_analytics_proto_enumTypes[4] } func (x ContractStateEvent_EventType) Number() protoreflect.EnumNumber { @@ -282,7 +282,7 @@ func (x ContractStateEvent_EventType) Number() protoreflect.EnumNumber { // Deprecated: Use ContractStateEvent_EventType.Descriptor instead. func (ContractStateEvent_EventType) EnumDescriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{16, 0} + return file_state_analytics_proto_rawDescGZIP(), []int{16, 0} } // Request/Response messages for GetLatestBlockDelta @@ -294,7 +294,7 @@ type GetLatestBlockDeltaRequest struct { func (x *GetLatestBlockDeltaRequest) Reset() { *x = GetLatestBlockDeltaRequest{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[0] + mi := &file_state_analytics_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -306,7 +306,7 @@ func (x *GetLatestBlockDeltaRequest) String() string { func (*GetLatestBlockDeltaRequest) ProtoMessage() {} func (x *GetLatestBlockDeltaRequest) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[0] + mi := &file_state_analytics_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -319,7 +319,7 @@ func (x *GetLatestBlockDeltaRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLatestBlockDeltaRequest.ProtoReflect.Descriptor instead. func (*GetLatestBlockDeltaRequest) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{0} + return file_state_analytics_proto_rawDescGZIP(), []int{0} } type GetLatestBlockDeltaResponse struct { @@ -338,7 +338,7 @@ type GetLatestBlockDeltaResponse struct { func (x *GetLatestBlockDeltaResponse) Reset() { *x = GetLatestBlockDeltaResponse{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[1] + mi := &file_state_analytics_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -350,7 +350,7 @@ func (x *GetLatestBlockDeltaResponse) String() string { func (*GetLatestBlockDeltaResponse) ProtoMessage() {} func (x *GetLatestBlockDeltaResponse) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[1] + mi := &file_state_analytics_proto_msgTypes[1] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -363,7 +363,7 @@ func (x *GetLatestBlockDeltaResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLatestBlockDeltaResponse.ProtoReflect.Descriptor instead. func (*GetLatestBlockDeltaResponse) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{1} + return file_state_analytics_proto_rawDescGZIP(), []int{1} } func (x *GetLatestBlockDeltaResponse) GetBlockNumber() uint64 { @@ -436,7 +436,7 @@ type ContractStateDelta struct { func (x *ContractStateDelta) Reset() { *x = ContractStateDelta{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[2] + mi := &file_state_analytics_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -448,7 +448,7 @@ func (x *ContractStateDelta) String() string { func (*ContractStateDelta) ProtoMessage() {} func (x *ContractStateDelta) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[2] + mi := &file_state_analytics_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -461,7 +461,7 @@ func (x *ContractStateDelta) ProtoReflect() protoreflect.Message { // Deprecated: Use ContractStateDelta.ProtoReflect.Descriptor instead. func (*ContractStateDelta) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{2} + return file_state_analytics_proto_rawDescGZIP(), []int{2} } func (x *ContractStateDelta) GetAddress() string { @@ -517,7 +517,7 @@ type GetTopStateAddersRequest struct { func (x *GetTopStateAddersRequest) Reset() { *x = GetTopStateAddersRequest{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[3] + mi := &file_state_analytics_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -529,7 +529,7 @@ func (x *GetTopStateAddersRequest) String() string { func (*GetTopStateAddersRequest) ProtoMessage() {} func (x *GetTopStateAddersRequest) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[3] + mi := &file_state_analytics_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -542,7 +542,7 @@ func (x *GetTopStateAddersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTopStateAddersRequest.ProtoReflect.Descriptor instead. func (*GetTopStateAddersRequest) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{3} + return file_state_analytics_proto_rawDescGZIP(), []int{3} } func (x *GetTopStateAddersRequest) GetPeriod() GetTopStateAddersRequest_Period { @@ -570,7 +570,7 @@ type GetTopStateAddersResponse struct { func (x *GetTopStateAddersResponse) Reset() { *x = GetTopStateAddersResponse{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[4] + mi := &file_state_analytics_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -582,7 +582,7 @@ func (x *GetTopStateAddersResponse) String() string { func (*GetTopStateAddersResponse) ProtoMessage() {} func (x *GetTopStateAddersResponse) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[4] + mi := &file_state_analytics_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -595,7 +595,7 @@ func (x *GetTopStateAddersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTopStateAddersResponse.ProtoReflect.Descriptor instead. func (*GetTopStateAddersResponse) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{4} + return file_state_analytics_proto_rawDescGZIP(), []int{4} } func (x *GetTopStateAddersResponse) GetAdders() []*StateAdder { @@ -634,7 +634,7 @@ type StateAdder struct { func (x *StateAdder) Reset() { *x = StateAdder{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[5] + mi := &file_state_analytics_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -646,7 +646,7 @@ func (x *StateAdder) String() string { func (*StateAdder) ProtoMessage() {} func (x *StateAdder) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[5] + mi := &file_state_analytics_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -659,7 +659,7 @@ func (x *StateAdder) ProtoReflect() protoreflect.Message { // Deprecated: Use StateAdder.ProtoReflect.Descriptor instead. func (*StateAdder) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{5} + return file_state_analytics_proto_rawDescGZIP(), []int{5} } func (x *StateAdder) GetRank() uint32 { @@ -722,7 +722,7 @@ type GetTopStateRemoversRequest struct { func (x *GetTopStateRemoversRequest) Reset() { *x = GetTopStateRemoversRequest{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[6] + mi := &file_state_analytics_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -734,7 +734,7 @@ func (x *GetTopStateRemoversRequest) String() string { func (*GetTopStateRemoversRequest) ProtoMessage() {} func (x *GetTopStateRemoversRequest) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[6] + mi := &file_state_analytics_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -747,7 +747,7 @@ func (x *GetTopStateRemoversRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTopStateRemoversRequest.ProtoReflect.Descriptor instead. func (*GetTopStateRemoversRequest) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{6} + return file_state_analytics_proto_rawDescGZIP(), []int{6} } func (x *GetTopStateRemoversRequest) GetPeriod() GetTopStateRemoversRequest_Period { @@ -775,7 +775,7 @@ type GetTopStateRemoversResponse struct { func (x *GetTopStateRemoversResponse) Reset() { *x = GetTopStateRemoversResponse{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[7] + mi := &file_state_analytics_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -787,7 +787,7 @@ func (x *GetTopStateRemoversResponse) String() string { func (*GetTopStateRemoversResponse) ProtoMessage() {} func (x *GetTopStateRemoversResponse) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[7] + mi := &file_state_analytics_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -800,7 +800,7 @@ func (x *GetTopStateRemoversResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTopStateRemoversResponse.ProtoReflect.Descriptor instead. func (*GetTopStateRemoversResponse) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{7} + return file_state_analytics_proto_rawDescGZIP(), []int{7} } func (x *GetTopStateRemoversResponse) GetRemovers() []*StateRemover { @@ -840,7 +840,7 @@ type StateRemover struct { func (x *StateRemover) Reset() { *x = StateRemover{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[8] + mi := &file_state_analytics_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -852,7 +852,7 @@ func (x *StateRemover) String() string { func (*StateRemover) ProtoMessage() {} func (x *StateRemover) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[8] + mi := &file_state_analytics_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -865,7 +865,7 @@ func (x *StateRemover) ProtoReflect() protoreflect.Message { // Deprecated: Use StateRemover.ProtoReflect.Descriptor instead. func (*StateRemover) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{8} + return file_state_analytics_proto_rawDescGZIP(), []int{8} } func (x *StateRemover) GetRank() uint32 { @@ -935,7 +935,7 @@ type GetStateGrowthChartRequest struct { func (x *GetStateGrowthChartRequest) Reset() { *x = GetStateGrowthChartRequest{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[9] + mi := &file_state_analytics_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -947,7 +947,7 @@ func (x *GetStateGrowthChartRequest) String() string { func (*GetStateGrowthChartRequest) ProtoMessage() {} func (x *GetStateGrowthChartRequest) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[9] + mi := &file_state_analytics_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -960,7 +960,7 @@ func (x *GetStateGrowthChartRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetStateGrowthChartRequest.ProtoReflect.Descriptor instead. func (*GetStateGrowthChartRequest) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{9} + return file_state_analytics_proto_rawDescGZIP(), []int{9} } func (x *GetStateGrowthChartRequest) GetPeriod() GetStateGrowthChartRequest_Period { @@ -987,7 +987,7 @@ type GetStateGrowthChartResponse struct { func (x *GetStateGrowthChartResponse) Reset() { *x = GetStateGrowthChartResponse{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[10] + mi := &file_state_analytics_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -999,7 +999,7 @@ func (x *GetStateGrowthChartResponse) String() string { func (*GetStateGrowthChartResponse) ProtoMessage() {} func (x *GetStateGrowthChartResponse) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[10] + mi := &file_state_analytics_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1012,7 +1012,7 @@ func (x *GetStateGrowthChartResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetStateGrowthChartResponse.ProtoReflect.Descriptor instead. func (*GetStateGrowthChartResponse) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{10} + return file_state_analytics_proto_rawDescGZIP(), []int{10} } func (x *GetStateGrowthChartResponse) GetDataPoints() []*StateGrowthDataPoint { @@ -1045,7 +1045,7 @@ type StateGrowthDataPoint struct { func (x *StateGrowthDataPoint) Reset() { *x = StateGrowthDataPoint{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[11] + mi := &file_state_analytics_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1057,7 +1057,7 @@ func (x *StateGrowthDataPoint) String() string { func (*StateGrowthDataPoint) ProtoMessage() {} func (x *StateGrowthDataPoint) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[11] + mi := &file_state_analytics_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1070,7 +1070,7 @@ func (x *StateGrowthDataPoint) ProtoReflect() protoreflect.Message { // Deprecated: Use StateGrowthDataPoint.ProtoReflect.Descriptor instead. func (*StateGrowthDataPoint) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{11} + return file_state_analytics_proto_rawDescGZIP(), []int{11} } func (x *StateGrowthDataPoint) GetTimestamp() *timestamppb.Timestamp { @@ -1144,7 +1144,7 @@ type StateSummary struct { func (x *StateSummary) Reset() { *x = StateSummary{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[12] + mi := &file_state_analytics_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1156,7 +1156,7 @@ func (x *StateSummary) String() string { func (*StateSummary) ProtoMessage() {} func (x *StateSummary) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[12] + mi := &file_state_analytics_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1169,7 +1169,7 @@ func (x *StateSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use StateSummary.ProtoReflect.Descriptor instead. func (*StateSummary) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{12} + return file_state_analytics_proto_rawDescGZIP(), []int{12} } func (x *StateSummary) GetTotalSlotsAdded() uint64 { @@ -1232,7 +1232,7 @@ type GetContractStateActivityRequest struct { func (x *GetContractStateActivityRequest) Reset() { *x = GetContractStateActivityRequest{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[13] + mi := &file_state_analytics_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1244,7 +1244,7 @@ func (x *GetContractStateActivityRequest) String() string { func (*GetContractStateActivityRequest) ProtoMessage() {} func (x *GetContractStateActivityRequest) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[13] + mi := &file_state_analytics_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1257,7 +1257,7 @@ func (x *GetContractStateActivityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetContractStateActivityRequest.ProtoReflect.Descriptor instead. func (*GetContractStateActivityRequest) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{13} + return file_state_analytics_proto_rawDescGZIP(), []int{13} } func (x *GetContractStateActivityRequest) GetAddress() string { @@ -1287,7 +1287,7 @@ type GetContractStateActivityResponse struct { func (x *GetContractStateActivityResponse) Reset() { *x = GetContractStateActivityResponse{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[14] + mi := &file_state_analytics_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1299,7 +1299,7 @@ func (x *GetContractStateActivityResponse) String() string { func (*GetContractStateActivityResponse) ProtoMessage() {} func (x *GetContractStateActivityResponse) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[14] + mi := &file_state_analytics_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1312,7 +1312,7 @@ func (x *GetContractStateActivityResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetContractStateActivityResponse.ProtoReflect.Descriptor instead. func (*GetContractStateActivityResponse) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{14} + return file_state_analytics_proto_rawDescGZIP(), []int{14} } func (x *GetContractStateActivityResponse) GetAddress() string { @@ -1364,7 +1364,7 @@ type ContractStateMetrics struct { func (x *ContractStateMetrics) Reset() { *x = ContractStateMetrics{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[15] + mi := &file_state_analytics_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1376,7 +1376,7 @@ func (x *ContractStateMetrics) String() string { func (*ContractStateMetrics) ProtoMessage() {} func (x *ContractStateMetrics) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[15] + mi := &file_state_analytics_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1389,7 +1389,7 @@ func (x *ContractStateMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use ContractStateMetrics.ProtoReflect.Descriptor instead. func (*ContractStateMetrics) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{15} + return file_state_analytics_proto_rawDescGZIP(), []int{15} } func (x *ContractStateMetrics) GetTotalSlots() uint64 { @@ -1447,7 +1447,7 @@ type ContractStateEvent struct { func (x *ContractStateEvent) Reset() { *x = ContractStateEvent{} - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[16] + mi := &file_state_analytics_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1459,7 +1459,7 @@ func (x *ContractStateEvent) String() string { func (*ContractStateEvent) ProtoMessage() {} func (x *ContractStateEvent) ProtoReflect() protoreflect.Message { - mi := &file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[16] + mi := &file_state_analytics_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1472,7 +1472,7 @@ func (x *ContractStateEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use ContractStateEvent.ProtoReflect.Descriptor instead. func (*ContractStateEvent) Descriptor() ([]byte, []int) { - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{16} + return file_state_analytics_proto_rawDescGZIP(), []int{16} } func (x *ContractStateEvent) GetBlockNumber() uint64 { @@ -1510,11 +1510,489 @@ func (x *ContractStateEvent) GetValue() string { return "" } -var File_backend_pkg_server_proto_state_analytics_state_analytics_proto protoreflect.FileDescriptor +// Request/Response for GetContractStateComposition (Paradigm diagram data) +type GetContractStateCompositionRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Limit uint32 `protobuf:"varint,1,opt,name=limit,proto3" json:"limit,omitempty"` // Max contracts to return (default 10000) + MinSizeBytes uint64 `protobuf:"varint,2,opt,name=min_size_bytes,json=minSizeBytes,proto3" json:"min_size_bytes,omitempty"` // Filter contracts smaller than this + IncludeLabels bool `protobuf:"varint,3,opt,name=include_labels,json=includeLabels,proto3" json:"include_labels,omitempty"` // Whether to include contract labels + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetContractStateCompositionRequest) Reset() { + *x = GetContractStateCompositionRequest{} + mi := &file_state_analytics_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetContractStateCompositionRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetContractStateCompositionRequest) ProtoMessage() {} + +func (x *GetContractStateCompositionRequest) ProtoReflect() protoreflect.Message { + mi := &file_state_analytics_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetContractStateCompositionRequest.ProtoReflect.Descriptor instead. +func (*GetContractStateCompositionRequest) Descriptor() ([]byte, []int) { + return file_state_analytics_proto_rawDescGZIP(), []int{17} +} + +func (x *GetContractStateCompositionRequest) GetLimit() uint32 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *GetContractStateCompositionRequest) GetMinSizeBytes() uint64 { + if x != nil { + return x.MinSizeBytes + } + return 0 +} + +func (x *GetContractStateCompositionRequest) GetIncludeLabels() bool { + if x != nil { + return x.IncludeLabels + } + return false +} + +type GetContractStateCompositionResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Contracts []*ContractStateEntry `protobuf:"bytes,1,rep,name=contracts,proto3" json:"contracts,omitempty"` + BlockNumber uint64 `protobuf:"varint,2,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + TotalStateBytes uint64 `protobuf:"varint,4,opt,name=total_state_bytes,json=totalStateBytes,proto3" json:"total_state_bytes,omitempty"` // Total Ethereum state size + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetContractStateCompositionResponse) Reset() { + *x = GetContractStateCompositionResponse{} + mi := &file_state_analytics_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetContractStateCompositionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetContractStateCompositionResponse) ProtoMessage() {} + +func (x *GetContractStateCompositionResponse) ProtoReflect() protoreflect.Message { + mi := &file_state_analytics_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetContractStateCompositionResponse.ProtoReflect.Descriptor instead. +func (*GetContractStateCompositionResponse) Descriptor() ([]byte, []int) { + return file_state_analytics_proto_rawDescGZIP(), []int{18} +} + +func (x *GetContractStateCompositionResponse) GetContracts() []*ContractStateEntry { + if x != nil { + return x.Contracts + } + return nil +} + +func (x *GetContractStateCompositionResponse) GetBlockNumber() uint64 { + if x != nil { + return x.BlockNumber + } + return 0 +} + +func (x *GetContractStateCompositionResponse) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp + } + return nil +} + +func (x *GetContractStateCompositionResponse) GetTotalStateBytes() uint64 { + if x != nil { + return x.TotalStateBytes + } + return 0 +} + +type ContractStateEntry struct { + state protoimpl.MessageState `protogen:"open.v1"` + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty"` // Contract name (if known) + Category string `protobuf:"bytes,3,opt,name=category,proto3" json:"category,omitempty"` // DeFi, NFT, Bridge, CEX, etc. + Protocol string `protobuf:"bytes,4,opt,name=protocol,proto3" json:"protocol,omitempty"` // Uniswap, Aave, OpenSea, etc. + State *ContractState `protobuf:"bytes,5,opt,name=state,proto3" json:"state,omitempty"` + PercentageOfTotal float64 `protobuf:"fixed64,6,opt,name=percentage_of_total,json=percentageOfTotal,proto3" json:"percentage_of_total,omitempty"` // % of total state + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ContractStateEntry) Reset() { + *x = ContractStateEntry{} + mi := &file_state_analytics_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ContractStateEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContractStateEntry) ProtoMessage() {} + +func (x *ContractStateEntry) ProtoReflect() protoreflect.Message { + mi := &file_state_analytics_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContractStateEntry.ProtoReflect.Descriptor instead. +func (*ContractStateEntry) Descriptor() ([]byte, []int) { + return file_state_analytics_proto_rawDescGZIP(), []int{19} +} + +func (x *ContractStateEntry) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *ContractStateEntry) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + +func (x *ContractStateEntry) GetCategory() string { + if x != nil { + return x.Category + } + return "" +} + +func (x *ContractStateEntry) GetProtocol() string { + if x != nil { + return x.Protocol + } + return "" +} + +func (x *ContractStateEntry) GetState() *ContractState { + if x != nil { + return x.State + } + return nil +} + +func (x *ContractStateEntry) GetPercentageOfTotal() float64 { + if x != nil { + return x.PercentageOfTotal + } + return 0 +} + +type ContractState struct { + state protoimpl.MessageState `protogen:"open.v1"` + StorageSlotCount uint64 `protobuf:"varint,1,opt,name=storage_slot_count,json=storageSlotCount,proto3" json:"storage_slot_count,omitempty"` // Number of storage slots + TotalBytes uint64 `protobuf:"varint,2,opt,name=total_bytes,json=totalBytes,proto3" json:"total_bytes,omitempty"` // Total state size (slots * 191) + BytecodeBytes uint64 `protobuf:"varint,3,opt,name=bytecode_bytes,json=bytecodeBytes,proto3" json:"bytecode_bytes,omitempty"` // Contract bytecode size + FirstSeenBlock uint64 `protobuf:"varint,4,opt,name=first_seen_block,json=firstSeenBlock,proto3" json:"first_seen_block,omitempty"` + LastActiveBlock uint64 `protobuf:"varint,5,opt,name=last_active_block,json=lastActiveBlock,proto3" json:"last_active_block,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ContractState) Reset() { + *x = ContractState{} + mi := &file_state_analytics_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ContractState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContractState) ProtoMessage() {} + +func (x *ContractState) ProtoReflect() protoreflect.Message { + mi := &file_state_analytics_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} -const file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDesc = "" + +// Deprecated: Use ContractState.ProtoReflect.Descriptor instead. +func (*ContractState) Descriptor() ([]byte, []int) { + return file_state_analytics_proto_rawDescGZIP(), []int{20} +} + +func (x *ContractState) GetStorageSlotCount() uint64 { + if x != nil { + return x.StorageSlotCount + } + return 0 +} + +func (x *ContractState) GetTotalBytes() uint64 { + if x != nil { + return x.TotalBytes + } + return 0 +} + +func (x *ContractState) GetBytecodeBytes() uint64 { + if x != nil { + return x.BytecodeBytes + } + return 0 +} + +func (x *ContractState) GetFirstSeenBlock() uint64 { + if x != nil { + return x.FirstSeenBlock + } + return 0 +} + +func (x *ContractState) GetLastActiveBlock() uint64 { + if x != nil { + return x.LastActiveBlock + } + return 0 +} + +// Request/Response for GetHierarchicalState (Paradigm diagram tree structure) +type GetHierarchicalStateRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + MaxDepth uint32 `protobuf:"varint,1,opt,name=max_depth,json=maxDepth,proto3" json:"max_depth,omitempty"` // Tree depth: 1=categories only, 2=+protocols, 3=+contracts + ContractsPerProtocol uint32 `protobuf:"varint,2,opt,name=contracts_per_protocol,json=contractsPerProtocol,proto3" json:"contracts_per_protocol,omitempty"` // Max contracts to show per protocol (default 20) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetHierarchicalStateRequest) Reset() { + *x = GetHierarchicalStateRequest{} + mi := &file_state_analytics_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetHierarchicalStateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetHierarchicalStateRequest) ProtoMessage() {} + +func (x *GetHierarchicalStateRequest) ProtoReflect() protoreflect.Message { + mi := &file_state_analytics_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetHierarchicalStateRequest.ProtoReflect.Descriptor instead. +func (*GetHierarchicalStateRequest) Descriptor() ([]byte, []int) { + return file_state_analytics_proto_rawDescGZIP(), []int{21} +} + +func (x *GetHierarchicalStateRequest) GetMaxDepth() uint32 { + if x != nil { + return x.MaxDepth + } + return 0 +} + +func (x *GetHierarchicalStateRequest) GetContractsPerProtocol() uint32 { + if x != nil { + return x.ContractsPerProtocol + } + return 0 +} + +type GetHierarchicalStateResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Root *StateNode `protobuf:"bytes,1,opt,name=root,proto3" json:"root,omitempty"` // Root node of hierarchy + BlockNumber uint64 `protobuf:"varint,2,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetHierarchicalStateResponse) Reset() { + *x = GetHierarchicalStateResponse{} + mi := &file_state_analytics_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetHierarchicalStateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetHierarchicalStateResponse) ProtoMessage() {} + +func (x *GetHierarchicalStateResponse) ProtoReflect() protoreflect.Message { + mi := &file_state_analytics_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetHierarchicalStateResponse.ProtoReflect.Descriptor instead. +func (*GetHierarchicalStateResponse) Descriptor() ([]byte, []int) { + return file_state_analytics_proto_rawDescGZIP(), []int{22} +} + +func (x *GetHierarchicalStateResponse) GetRoot() *StateNode { + if x != nil { + return x.Root + } + return nil +} + +func (x *GetHierarchicalStateResponse) GetBlockNumber() uint64 { + if x != nil { + return x.BlockNumber + } + return 0 +} + +func (x *GetHierarchicalStateResponse) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp + } + return nil +} + +type StateNode struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // Node name (category/protocol/contract) + Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` // "root", "category", "protocol", "contract" + SizeBytes uint64 `protobuf:"varint,3,opt,name=size_bytes,json=sizeBytes,proto3" json:"size_bytes,omitempty"` // Total size of this node and children + Children []*StateNode `protobuf:"bytes,4,rep,name=children,proto3" json:"children,omitempty"` // Child nodes + Metadata map[string]string `protobuf:"bytes,5,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // Additional data (address, color, etc.) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StateNode) Reset() { + *x = StateNode{} + mi := &file_state_analytics_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StateNode) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StateNode) ProtoMessage() {} + +func (x *StateNode) ProtoReflect() protoreflect.Message { + mi := &file_state_analytics_proto_msgTypes[23] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StateNode.ProtoReflect.Descriptor instead. +func (*StateNode) Descriptor() ([]byte, []int) { + return file_state_analytics_proto_rawDescGZIP(), []int{23} +} + +func (x *StateNode) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *StateNode) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *StateNode) GetSizeBytes() uint64 { + if x != nil { + return x.SizeBytes + } + return 0 +} + +func (x *StateNode) GetChildren() []*StateNode { + if x != nil { + return x.Children + } + return nil +} + +func (x *StateNode) GetMetadata() map[string]string { + if x != nil { + return x.Metadata + } + return nil +} + +var File_state_analytics_proto protoreflect.FileDescriptor + +const file_state_analytics_proto_rawDesc = "" + "\n" + - ">backend/pkg/server/proto/state_analytics/state_analytics.proto\x12\x0fstate_analytics\x1a\x1fgoogle/protobuf/timestamp.proto\"\x1c\n" + + "\x15state_analytics.proto\x12\x0fstate_analytics\x1a\x1fgoogle/protobuf/timestamp.proto\"\x1c\n" + "\x1aGetLatestBlockDeltaRequest\"\xc8\x03\n" + "\x1bGetLatestBlockDeltaResponse\x12!\n" + "\fblock_number\x18\x01 \x01(\x04R\vblockNumber\x12C\n" + @@ -1649,29 +2127,71 @@ const file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDes "\x16EVENT_TYPE_UNSPECIFIED\x10\x00\x12\x1b\n" + "\x17EVENT_TYPE_SLOT_CREATED\x10\x01\x12\x1c\n" + "\x18EVENT_TYPE_SLOT_MODIFIED\x10\x02\x12\x1b\n" + - "\x17EVENT_TYPE_SLOT_CLEARED\x10\x032\xd3\x04\n" + + "\x17EVENT_TYPE_SLOT_CLEARED\x10\x03\"\x87\x01\n" + + "\"GetContractStateCompositionRequest\x12\x14\n" + + "\x05limit\x18\x01 \x01(\rR\x05limit\x12$\n" + + "\x0emin_size_bytes\x18\x02 \x01(\x04R\fminSizeBytes\x12%\n" + + "\x0einclude_labels\x18\x03 \x01(\bR\rincludeLabels\"\xf1\x01\n" + + "#GetContractStateCompositionResponse\x12A\n" + + "\tcontracts\x18\x01 \x03(\v2#.state_analytics.ContractStateEntryR\tcontracts\x12!\n" + + "\fblock_number\x18\x02 \x01(\x04R\vblockNumber\x128\n" + + "\ttimestamp\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\ttimestamp\x12*\n" + + "\x11total_state_bytes\x18\x04 \x01(\x04R\x0ftotalStateBytes\"\xe2\x01\n" + + "\x12ContractStateEntry\x12\x18\n" + + "\aaddress\x18\x01 \x01(\tR\aaddress\x12\x14\n" + + "\x05label\x18\x02 \x01(\tR\x05label\x12\x1a\n" + + "\bcategory\x18\x03 \x01(\tR\bcategory\x12\x1a\n" + + "\bprotocol\x18\x04 \x01(\tR\bprotocol\x124\n" + + "\x05state\x18\x05 \x01(\v2\x1e.state_analytics.ContractStateR\x05state\x12.\n" + + "\x13percentage_of_total\x18\x06 \x01(\x01R\x11percentageOfTotal\"\xdb\x01\n" + + "\rContractState\x12,\n" + + "\x12storage_slot_count\x18\x01 \x01(\x04R\x10storageSlotCount\x12\x1f\n" + + "\vtotal_bytes\x18\x02 \x01(\x04R\n" + + "totalBytes\x12%\n" + + "\x0ebytecode_bytes\x18\x03 \x01(\x04R\rbytecodeBytes\x12(\n" + + "\x10first_seen_block\x18\x04 \x01(\x04R\x0efirstSeenBlock\x12*\n" + + "\x11last_active_block\x18\x05 \x01(\x04R\x0flastActiveBlock\"p\n" + + "\x1bGetHierarchicalStateRequest\x12\x1b\n" + + "\tmax_depth\x18\x01 \x01(\rR\bmaxDepth\x124\n" + + "\x16contracts_per_protocol\x18\x02 \x01(\rR\x14contractsPerProtocol\"\xab\x01\n" + + "\x1cGetHierarchicalStateResponse\x12.\n" + + "\x04root\x18\x01 \x01(\v2\x1a.state_analytics.StateNodeR\x04root\x12!\n" + + "\fblock_number\x18\x02 \x01(\x04R\vblockNumber\x128\n" + + "\ttimestamp\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\ttimestamp\"\x8d\x02\n" + + "\tStateNode\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x12\n" + + "\x04type\x18\x02 \x01(\tR\x04type\x12\x1d\n" + + "\n" + + "size_bytes\x18\x03 \x01(\x04R\tsizeBytes\x126\n" + + "\bchildren\x18\x04 \x03(\v2\x1a.state_analytics.StateNodeR\bchildren\x12D\n" + + "\bmetadata\x18\x05 \x03(\v2(.state_analytics.StateNode.MetadataEntryR\bmetadata\x1a;\n" + + "\rMetadataEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x012\xd3\x06\n" + "\x0eStateAnalytics\x12p\n" + "\x13GetLatestBlockDelta\x12+.state_analytics.GetLatestBlockDeltaRequest\x1a,.state_analytics.GetLatestBlockDeltaResponse\x12j\n" + "\x11GetTopStateAdders\x12).state_analytics.GetTopStateAddersRequest\x1a*.state_analytics.GetTopStateAddersResponse\x12p\n" + "\x13GetTopStateRemovers\x12+.state_analytics.GetTopStateRemoversRequest\x1a,.state_analytics.GetTopStateRemoversResponse\x12p\n" + "\x13GetStateGrowthChart\x12+.state_analytics.GetStateGrowthChartRequest\x1a,.state_analytics.GetStateGrowthChartResponse\x12\x7f\n" + - "\x18GetContractStateActivity\x120.state_analytics.GetContractStateActivityRequest\x1a1.state_analytics.GetContractStateActivityResponseBEZCgithub.com/ethpandaops/lab/backend/pkg/server/proto/state_analyticsb\x06proto3" + "\x18GetContractStateActivity\x120.state_analytics.GetContractStateActivityRequest\x1a1.state_analytics.GetContractStateActivityResponse\x12\x88\x01\n" + + "\x1bGetContractStateComposition\x123.state_analytics.GetContractStateCompositionRequest\x1a4.state_analytics.GetContractStateCompositionResponse\x12s\n" + + "\x14GetHierarchicalState\x12,.state_analytics.GetHierarchicalStateRequest\x1a-.state_analytics.GetHierarchicalStateResponseBEZCgithub.com/ethpandaops/lab/backend/pkg/server/proto/state_analyticsb\x06proto3" var ( - file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescOnce sync.Once - file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescData []byte + file_state_analytics_proto_rawDescOnce sync.Once + file_state_analytics_proto_rawDescData []byte ) -func file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP() []byte { - file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescOnce.Do(func() { - file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDesc), len(file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDesc))) +func file_state_analytics_proto_rawDescGZIP() []byte { + file_state_analytics_proto_rawDescOnce.Do(func() { + file_state_analytics_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_state_analytics_proto_rawDesc), len(file_state_analytics_proto_rawDesc))) }) - return file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDescData + return file_state_analytics_proto_rawDescData } -var file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes = make([]protoimpl.MessageInfo, 17) -var file_backend_pkg_server_proto_state_analytics_state_analytics_proto_goTypes = []any{ +var file_state_analytics_proto_enumTypes = make([]protoimpl.EnumInfo, 5) +var file_state_analytics_proto_msgTypes = make([]protoimpl.MessageInfo, 25) +var file_state_analytics_proto_goTypes = []any{ (GetTopStateAddersRequest_Period)(0), // 0: state_analytics.GetTopStateAddersRequest.Period (GetTopStateRemoversRequest_Period)(0), // 1: state_analytics.GetTopStateRemoversRequest.Period (GetStateGrowthChartRequest_Period)(0), // 2: state_analytics.GetStateGrowthChartRequest.Period @@ -1694,10 +2214,18 @@ var file_backend_pkg_server_proto_state_analytics_state_analytics_proto_goTypes (*GetContractStateActivityResponse)(nil), // 19: state_analytics.GetContractStateActivityResponse (*ContractStateMetrics)(nil), // 20: state_analytics.ContractStateMetrics (*ContractStateEvent)(nil), // 21: state_analytics.ContractStateEvent - (*timestamppb.Timestamp)(nil), // 22: google.protobuf.Timestamp -} -var file_backend_pkg_server_proto_state_analytics_state_analytics_proto_depIdxs = []int32{ - 22, // 0: state_analytics.GetLatestBlockDeltaResponse.block_timestamp:type_name -> google.protobuf.Timestamp + (*GetContractStateCompositionRequest)(nil), // 22: state_analytics.GetContractStateCompositionRequest + (*GetContractStateCompositionResponse)(nil), // 23: state_analytics.GetContractStateCompositionResponse + (*ContractStateEntry)(nil), // 24: state_analytics.ContractStateEntry + (*ContractState)(nil), // 25: state_analytics.ContractState + (*GetHierarchicalStateRequest)(nil), // 26: state_analytics.GetHierarchicalStateRequest + (*GetHierarchicalStateResponse)(nil), // 27: state_analytics.GetHierarchicalStateResponse + (*StateNode)(nil), // 28: state_analytics.StateNode + nil, // 29: state_analytics.StateNode.MetadataEntry + (*timestamppb.Timestamp)(nil), // 30: google.protobuf.Timestamp +} +var file_state_analytics_proto_depIdxs = []int32{ + 30, // 0: state_analytics.GetLatestBlockDeltaResponse.block_timestamp:type_name -> google.protobuf.Timestamp 7, // 1: state_analytics.GetLatestBlockDeltaResponse.top_contributors:type_name -> state_analytics.ContractStateDelta 0, // 2: state_analytics.GetTopStateAddersRequest.period:type_name -> state_analytics.GetTopStateAddersRequest.Period 10, // 3: state_analytics.GetTopStateAddersResponse.adders:type_name -> state_analytics.StateAdder @@ -1707,49 +2235,60 @@ var file_backend_pkg_server_proto_state_analytics_state_analytics_proto_depIdxs 3, // 7: state_analytics.GetStateGrowthChartRequest.granularity:type_name -> state_analytics.GetStateGrowthChartRequest.Granularity 16, // 8: state_analytics.GetStateGrowthChartResponse.data_points:type_name -> state_analytics.StateGrowthDataPoint 17, // 9: state_analytics.GetStateGrowthChartResponse.summary:type_name -> state_analytics.StateSummary - 22, // 10: state_analytics.StateGrowthDataPoint.timestamp:type_name -> google.protobuf.Timestamp + 30, // 10: state_analytics.StateGrowthDataPoint.timestamp:type_name -> google.protobuf.Timestamp 20, // 11: state_analytics.GetContractStateActivityResponse.metrics:type_name -> state_analytics.ContractStateMetrics 21, // 12: state_analytics.GetContractStateActivityResponse.recent_events:type_name -> state_analytics.ContractStateEvent - 22, // 13: state_analytics.ContractStateEvent.timestamp:type_name -> google.protobuf.Timestamp + 30, // 13: state_analytics.ContractStateEvent.timestamp:type_name -> google.protobuf.Timestamp 4, // 14: state_analytics.ContractStateEvent.event_type:type_name -> state_analytics.ContractStateEvent.EventType - 5, // 15: state_analytics.StateAnalytics.GetLatestBlockDelta:input_type -> state_analytics.GetLatestBlockDeltaRequest - 8, // 16: state_analytics.StateAnalytics.GetTopStateAdders:input_type -> state_analytics.GetTopStateAddersRequest - 11, // 17: state_analytics.StateAnalytics.GetTopStateRemovers:input_type -> state_analytics.GetTopStateRemoversRequest - 14, // 18: state_analytics.StateAnalytics.GetStateGrowthChart:input_type -> state_analytics.GetStateGrowthChartRequest - 18, // 19: state_analytics.StateAnalytics.GetContractStateActivity:input_type -> state_analytics.GetContractStateActivityRequest - 6, // 20: state_analytics.StateAnalytics.GetLatestBlockDelta:output_type -> state_analytics.GetLatestBlockDeltaResponse - 9, // 21: state_analytics.StateAnalytics.GetTopStateAdders:output_type -> state_analytics.GetTopStateAddersResponse - 12, // 22: state_analytics.StateAnalytics.GetTopStateRemovers:output_type -> state_analytics.GetTopStateRemoversResponse - 15, // 23: state_analytics.StateAnalytics.GetStateGrowthChart:output_type -> state_analytics.GetStateGrowthChartResponse - 19, // 24: state_analytics.StateAnalytics.GetContractStateActivity:output_type -> state_analytics.GetContractStateActivityResponse - 20, // [20:25] is the sub-list for method output_type - 15, // [15:20] is the sub-list for method input_type - 15, // [15:15] is the sub-list for extension type_name - 15, // [15:15] is the sub-list for extension extendee - 0, // [0:15] is the sub-list for field type_name -} - -func init() { file_backend_pkg_server_proto_state_analytics_state_analytics_proto_init() } -func file_backend_pkg_server_proto_state_analytics_state_analytics_proto_init() { - if File_backend_pkg_server_proto_state_analytics_state_analytics_proto != nil { + 24, // 15: state_analytics.GetContractStateCompositionResponse.contracts:type_name -> state_analytics.ContractStateEntry + 30, // 16: state_analytics.GetContractStateCompositionResponse.timestamp:type_name -> google.protobuf.Timestamp + 25, // 17: state_analytics.ContractStateEntry.state:type_name -> state_analytics.ContractState + 28, // 18: state_analytics.GetHierarchicalStateResponse.root:type_name -> state_analytics.StateNode + 30, // 19: state_analytics.GetHierarchicalStateResponse.timestamp:type_name -> google.protobuf.Timestamp + 28, // 20: state_analytics.StateNode.children:type_name -> state_analytics.StateNode + 29, // 21: state_analytics.StateNode.metadata:type_name -> state_analytics.StateNode.MetadataEntry + 5, // 22: state_analytics.StateAnalytics.GetLatestBlockDelta:input_type -> state_analytics.GetLatestBlockDeltaRequest + 8, // 23: state_analytics.StateAnalytics.GetTopStateAdders:input_type -> state_analytics.GetTopStateAddersRequest + 11, // 24: state_analytics.StateAnalytics.GetTopStateRemovers:input_type -> state_analytics.GetTopStateRemoversRequest + 14, // 25: state_analytics.StateAnalytics.GetStateGrowthChart:input_type -> state_analytics.GetStateGrowthChartRequest + 18, // 26: state_analytics.StateAnalytics.GetContractStateActivity:input_type -> state_analytics.GetContractStateActivityRequest + 22, // 27: state_analytics.StateAnalytics.GetContractStateComposition:input_type -> state_analytics.GetContractStateCompositionRequest + 26, // 28: state_analytics.StateAnalytics.GetHierarchicalState:input_type -> state_analytics.GetHierarchicalStateRequest + 6, // 29: state_analytics.StateAnalytics.GetLatestBlockDelta:output_type -> state_analytics.GetLatestBlockDeltaResponse + 9, // 30: state_analytics.StateAnalytics.GetTopStateAdders:output_type -> state_analytics.GetTopStateAddersResponse + 12, // 31: state_analytics.StateAnalytics.GetTopStateRemovers:output_type -> state_analytics.GetTopStateRemoversResponse + 15, // 32: state_analytics.StateAnalytics.GetStateGrowthChart:output_type -> state_analytics.GetStateGrowthChartResponse + 19, // 33: state_analytics.StateAnalytics.GetContractStateActivity:output_type -> state_analytics.GetContractStateActivityResponse + 23, // 34: state_analytics.StateAnalytics.GetContractStateComposition:output_type -> state_analytics.GetContractStateCompositionResponse + 27, // 35: state_analytics.StateAnalytics.GetHierarchicalState:output_type -> state_analytics.GetHierarchicalStateResponse + 29, // [29:36] is the sub-list for method output_type + 22, // [22:29] is the sub-list for method input_type + 22, // [22:22] is the sub-list for extension type_name + 22, // [22:22] is the sub-list for extension extendee + 0, // [0:22] is the sub-list for field type_name +} + +func init() { file_state_analytics_proto_init() } +func file_state_analytics_proto_init() { + if File_state_analytics_proto != nil { return } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: unsafe.Slice(unsafe.StringData(file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDesc), len(file_backend_pkg_server_proto_state_analytics_state_analytics_proto_rawDesc)), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_state_analytics_proto_rawDesc), len(file_state_analytics_proto_rawDesc)), NumEnums: 5, - NumMessages: 17, + NumMessages: 25, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_backend_pkg_server_proto_state_analytics_state_analytics_proto_goTypes, - DependencyIndexes: file_backend_pkg_server_proto_state_analytics_state_analytics_proto_depIdxs, - EnumInfos: file_backend_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes, - MessageInfos: file_backend_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes, + GoTypes: file_state_analytics_proto_goTypes, + DependencyIndexes: file_state_analytics_proto_depIdxs, + EnumInfos: file_state_analytics_proto_enumTypes, + MessageInfos: file_state_analytics_proto_msgTypes, }.Build() - File_backend_pkg_server_proto_state_analytics_state_analytics_proto = out.File - file_backend_pkg_server_proto_state_analytics_state_analytics_proto_goTypes = nil - file_backend_pkg_server_proto_state_analytics_state_analytics_proto_depIdxs = nil + File_state_analytics_proto = out.File + file_state_analytics_proto_goTypes = nil + file_state_analytics_proto_depIdxs = nil } diff --git a/backend/pkg/server/proto/state_analytics/state_analytics.proto b/backend/pkg/server/proto/state_analytics/state_analytics.proto index 186333f4f..26e160b88 100644 --- a/backend/pkg/server/proto/state_analytics/state_analytics.proto +++ b/backend/pkg/server/proto/state_analytics/state_analytics.proto @@ -22,6 +22,12 @@ service StateAnalytics { // GetContractStateActivity returns detailed state activity for a specific contract rpc GetContractStateActivity(GetContractStateActivityRequest) returns (GetContractStateActivityResponse); + + // GetContractStateComposition returns current state size for all contracts (Paradigm diagram data) + rpc GetContractStateComposition(GetContractStateCompositionRequest) returns (GetContractStateCompositionResponse); + + // GetHierarchicalState returns state organized hierarchically by category -> protocol -> contract + rpc GetHierarchicalState(GetHierarchicalStateRequest) returns (GetHierarchicalStateResponse); } // Request/Response messages for GetLatestBlockDelta @@ -188,3 +194,54 @@ message ContractStateEvent { string slot_key = 4; string value = 5; } + +// Request/Response for GetContractStateComposition (Paradigm diagram data) +message GetContractStateCompositionRequest { + uint32 limit = 1; // Max contracts to return (default 10000) + uint64 min_size_bytes = 2; // Filter contracts smaller than this + bool include_labels = 3; // Whether to include contract labels +} + +message GetContractStateCompositionResponse { + repeated ContractStateEntry contracts = 1; + uint64 block_number = 2; + google.protobuf.Timestamp timestamp = 3; + uint64 total_state_bytes = 4; // Total Ethereum state size +} + +message ContractStateEntry { + string address = 1; + string label = 2; // Contract name (if known) + string category = 3; // DeFi, NFT, Bridge, CEX, etc. + string protocol = 4; // Uniswap, Aave, OpenSea, etc. + ContractState state = 5; + double percentage_of_total = 6; // % of total state +} + +message ContractState { + uint64 storage_slot_count = 1; // Number of storage slots + uint64 total_bytes = 2; // Total state size (slots * 191) + uint64 bytecode_bytes = 3; // Contract bytecode size + uint64 first_seen_block = 4; + uint64 last_active_block = 5; +} + +// Request/Response for GetHierarchicalState (Paradigm diagram tree structure) +message GetHierarchicalStateRequest { + uint32 max_depth = 1; // Tree depth: 1=categories only, 2=+protocols, 3=+contracts + uint32 contracts_per_protocol = 2; // Max contracts to show per protocol (default 20) +} + +message GetHierarchicalStateResponse { + StateNode root = 1; // Root node of hierarchy + uint64 block_number = 2; + google.protobuf.Timestamp timestamp = 3; +} + +message StateNode { + string name = 1; // Node name (category/protocol/contract) + string type = 2; // "root", "category", "protocol", "contract" + uint64 size_bytes = 3; // Total size of this node and children + repeated StateNode children = 4; // Child nodes + map metadata = 5; // Additional data (address, color, etc.) +} diff --git a/backend/pkg/server/proto/state_analytics/state_analytics_grpc.pb.go b/backend/pkg/server/proto/state_analytics/state_analytics_grpc.pb.go index 0f44d4de2..913bc8292 100644 --- a/backend/pkg/server/proto/state_analytics/state_analytics_grpc.pb.go +++ b/backend/pkg/server/proto/state_analytics/state_analytics_grpc.pb.go @@ -2,7 +2,7 @@ // versions: // - protoc-gen-go-grpc v1.5.1 // - protoc v5.29.3 -// source: backend/pkg/server/proto/state_analytics/state_analytics.proto +// source: state_analytics.proto package state_analytics @@ -19,11 +19,13 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( - StateAnalytics_GetLatestBlockDelta_FullMethodName = "/state_analytics.StateAnalytics/GetLatestBlockDelta" - StateAnalytics_GetTopStateAdders_FullMethodName = "/state_analytics.StateAnalytics/GetTopStateAdders" - StateAnalytics_GetTopStateRemovers_FullMethodName = "/state_analytics.StateAnalytics/GetTopStateRemovers" - StateAnalytics_GetStateGrowthChart_FullMethodName = "/state_analytics.StateAnalytics/GetStateGrowthChart" - StateAnalytics_GetContractStateActivity_FullMethodName = "/state_analytics.StateAnalytics/GetContractStateActivity" + StateAnalytics_GetLatestBlockDelta_FullMethodName = "/state_analytics.StateAnalytics/GetLatestBlockDelta" + StateAnalytics_GetTopStateAdders_FullMethodName = "/state_analytics.StateAnalytics/GetTopStateAdders" + StateAnalytics_GetTopStateRemovers_FullMethodName = "/state_analytics.StateAnalytics/GetTopStateRemovers" + StateAnalytics_GetStateGrowthChart_FullMethodName = "/state_analytics.StateAnalytics/GetStateGrowthChart" + StateAnalytics_GetContractStateActivity_FullMethodName = "/state_analytics.StateAnalytics/GetContractStateActivity" + StateAnalytics_GetContractStateComposition_FullMethodName = "/state_analytics.StateAnalytics/GetContractStateComposition" + StateAnalytics_GetHierarchicalState_FullMethodName = "/state_analytics.StateAnalytics/GetHierarchicalState" ) // StateAnalyticsClient is the client API for StateAnalytics service. @@ -42,6 +44,10 @@ type StateAnalyticsClient interface { GetStateGrowthChart(ctx context.Context, in *GetStateGrowthChartRequest, opts ...grpc.CallOption) (*GetStateGrowthChartResponse, error) // GetContractStateActivity returns detailed state activity for a specific contract GetContractStateActivity(ctx context.Context, in *GetContractStateActivityRequest, opts ...grpc.CallOption) (*GetContractStateActivityResponse, error) + // GetContractStateComposition returns current state size for all contracts (Paradigm diagram data) + GetContractStateComposition(ctx context.Context, in *GetContractStateCompositionRequest, opts ...grpc.CallOption) (*GetContractStateCompositionResponse, error) + // GetHierarchicalState returns state organized hierarchically by category -> protocol -> contract + GetHierarchicalState(ctx context.Context, in *GetHierarchicalStateRequest, opts ...grpc.CallOption) (*GetHierarchicalStateResponse, error) } type stateAnalyticsClient struct { @@ -102,6 +108,26 @@ func (c *stateAnalyticsClient) GetContractStateActivity(ctx context.Context, in return out, nil } +func (c *stateAnalyticsClient) GetContractStateComposition(ctx context.Context, in *GetContractStateCompositionRequest, opts ...grpc.CallOption) (*GetContractStateCompositionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetContractStateCompositionResponse) + err := c.cc.Invoke(ctx, StateAnalytics_GetContractStateComposition_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *stateAnalyticsClient) GetHierarchicalState(ctx context.Context, in *GetHierarchicalStateRequest, opts ...grpc.CallOption) (*GetHierarchicalStateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetHierarchicalStateResponse) + err := c.cc.Invoke(ctx, StateAnalytics_GetHierarchicalState_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // StateAnalyticsServer is the server API for StateAnalytics service. // All implementations must embed UnimplementedStateAnalyticsServer // for forward compatibility. @@ -118,6 +144,10 @@ type StateAnalyticsServer interface { GetStateGrowthChart(context.Context, *GetStateGrowthChartRequest) (*GetStateGrowthChartResponse, error) // GetContractStateActivity returns detailed state activity for a specific contract GetContractStateActivity(context.Context, *GetContractStateActivityRequest) (*GetContractStateActivityResponse, error) + // GetContractStateComposition returns current state size for all contracts (Paradigm diagram data) + GetContractStateComposition(context.Context, *GetContractStateCompositionRequest) (*GetContractStateCompositionResponse, error) + // GetHierarchicalState returns state organized hierarchically by category -> protocol -> contract + GetHierarchicalState(context.Context, *GetHierarchicalStateRequest) (*GetHierarchicalStateResponse, error) mustEmbedUnimplementedStateAnalyticsServer() } @@ -143,6 +173,12 @@ func (UnimplementedStateAnalyticsServer) GetStateGrowthChart(context.Context, *G func (UnimplementedStateAnalyticsServer) GetContractStateActivity(context.Context, *GetContractStateActivityRequest) (*GetContractStateActivityResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetContractStateActivity not implemented") } +func (UnimplementedStateAnalyticsServer) GetContractStateComposition(context.Context, *GetContractStateCompositionRequest) (*GetContractStateCompositionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetContractStateComposition not implemented") +} +func (UnimplementedStateAnalyticsServer) GetHierarchicalState(context.Context, *GetHierarchicalStateRequest) (*GetHierarchicalStateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetHierarchicalState not implemented") +} func (UnimplementedStateAnalyticsServer) mustEmbedUnimplementedStateAnalyticsServer() {} func (UnimplementedStateAnalyticsServer) testEmbeddedByValue() {} @@ -254,6 +290,42 @@ func _StateAnalytics_GetContractStateActivity_Handler(srv interface{}, ctx conte return interceptor(ctx, in, info, handler) } +func _StateAnalytics_GetContractStateComposition_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetContractStateCompositionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StateAnalyticsServer).GetContractStateComposition(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StateAnalytics_GetContractStateComposition_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StateAnalyticsServer).GetContractStateComposition(ctx, req.(*GetContractStateCompositionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StateAnalytics_GetHierarchicalState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetHierarchicalStateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StateAnalyticsServer).GetHierarchicalState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StateAnalytics_GetHierarchicalState_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StateAnalyticsServer).GetHierarchicalState(ctx, req.(*GetHierarchicalStateRequest)) + } + return interceptor(ctx, in, info, handler) +} + // StateAnalytics_ServiceDesc is the grpc.ServiceDesc for StateAnalytics service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -281,7 +353,15 @@ var StateAnalytics_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetContractStateActivity", Handler: _StateAnalytics_GetContractStateActivity_Handler, }, + { + MethodName: "GetContractStateComposition", + Handler: _StateAnalytics_GetContractStateComposition_Handler, + }, + { + MethodName: "GetHierarchicalState", + Handler: _StateAnalytics_GetHierarchicalState_Handler, + }, }, Streams: []grpc.StreamDesc{}, - Metadata: "backend/pkg/server/proto/state_analytics/state_analytics.proto", + Metadata: "state_analytics.proto", } From a08de3d7422fb4a45be184deead5f6e6643e89e6 Mon Sep 17 00:00:00 2001 From: CPerezz Date: Wed, 29 Oct 2025 14:21:34 +0100 Subject: [PATCH 06/10] feat(frontend): add REST API client methods for Paradigm diagram Add TypeScript types, endpoints, and client methods for fetching contract state composition data to power the Paradigm-style interactive treemap visualization. - Add ContractStateCompositionResponse and HierarchicalStateResponse types - Add stateComposition and stateHierarchical endpoint paths - Add getContractStateComposition() and getHierarchicalState() client methods --- frontend/src/api/rest/client.ts | 40 +++++++++++++++ frontend/src/api/rest/endpoints.ts | 2 + frontend/src/types/state-analytics.ts | 70 +++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) diff --git a/frontend/src/api/rest/client.ts b/frontend/src/api/rest/client.ts index b382b415b..bd404baf1 100644 --- a/frontend/src/api/rest/client.ts +++ b/frontend/src/api/rest/client.ts @@ -22,11 +22,15 @@ import type { TopStateRemoversResponse, StateGrowthChartResponse, ContractStateActivityResponse, + ContractStateCompositionResponse, + HierarchicalStateResponse, StateLatestParams, StateTopAddersParams, StateTopRemoversParams, StateGrowthChartParams, ContractStateActivityParams, + ContractStateCompositionParams, + HierarchicalStateParams, } from '../../types/state-analytics'; /** @@ -570,6 +574,42 @@ export class RestApiClient { const response = await this.fetchWithRetry(url); return response as ContractStateActivityResponse; } + + /** + * Get current state size for all contracts (Paradigm diagram data) + * @param network Network name + * @param params Query parameters (limit, min_size_bytes, include_labels) + * @returns Contract state composition + */ + async getContractStateComposition( + network: string, + params?: ContractStateCompositionParams, + ): Promise { + const queryString = params ? buildQueryString(params) : new URLSearchParams(); + const url = `${this.baseUrl}${API_V1_ENDPOINTS.stateComposition(network)}${ + queryString.toString() ? `?${queryString.toString()}` : '' + }`; + const response = await this.fetchWithRetry(url); + return response as ContractStateCompositionResponse; + } + + /** + * Get state organized hierarchically by category -> protocol -> contract + * @param network Network name + * @param params Query parameters (max_depth, contracts_per_protocol) + * @returns Hierarchical state tree + */ + async getHierarchicalState( + network: string, + params?: HierarchicalStateParams, + ): Promise { + const queryString = params ? buildQueryString(params) : new URLSearchParams(); + const url = `${this.baseUrl}${API_V1_ENDPOINTS.stateHierarchical(network)}${ + queryString.toString() ? `?${queryString.toString()}` : '' + }`; + const response = await this.fetchWithRetry(url); + return response as HierarchicalStateResponse; + } } /** diff --git a/frontend/src/api/rest/endpoints.ts b/frontend/src/api/rest/endpoints.ts index 84bd84bed..d2600f593 100644 --- a/frontend/src/api/rest/endpoints.ts +++ b/frontend/src/api/rest/endpoints.ts @@ -41,6 +41,8 @@ export const API_V1_ENDPOINTS = { stateGrowthChart: (network: string) => `/api/v1/${network}/state/growth-chart`, stateContractActivity: (network: string, address: string) => `/api/v1/${network}/state/contract/${address}`, + stateComposition: (network: string) => `/api/v1/${network}/state/composition`, + stateHierarchical: (network: string) => `/api/v1/${network}/state/hierarchical`, }; /** diff --git a/frontend/src/types/state-analytics.ts b/frontend/src/types/state-analytics.ts index 2f30741ee..bcb079ec0 100644 --- a/frontend/src/types/state-analytics.ts +++ b/frontend/src/types/state-analytics.ts @@ -203,3 +203,73 @@ export interface StateGrowthChartParams { export interface ContractStateActivityParams { limit?: number; } + +/** + * Contract state information (Paradigm diagram) + */ +export interface ContractState { + storage_slot_count: number; + total_bytes: number; + bytecode_bytes: number; + first_seen_block: number; + last_active_block: number; +} + +/** + * Contract state entry (Paradigm diagram) + */ +export interface ContractStateEntry { + address: string; + label?: string; + category?: string; + protocol?: string; + state: ContractState; + percentage_of_total: number; +} + +/** + * Contract state composition response (Paradigm diagram flat data) + */ +export interface ContractStateCompositionResponse { + contracts: ContractStateEntry[]; + block_number: number; + timestamp: { seconds: number }; + total_state_bytes: number; +} + +/** + * State node for hierarchical visualization (Paradigm diagram tree) + */ +export interface StateNode { + name: string; + type: 'root' | 'category' | 'protocol' | 'contract'; + size_bytes: number; + children?: StateNode[]; + metadata?: Record; +} + +/** + * Hierarchical state response (Paradigm diagram tree structure) + */ +export interface HierarchicalStateResponse { + root: StateNode; + block_number: number; + timestamp: { seconds: number }; +} + +/** + * Parameters for getContractStateComposition API call + */ +export interface ContractStateCompositionParams { + limit?: number; + min_size_bytes?: number; + include_labels?: boolean; +} + +/** + * Parameters for getHierarchicalState API call + */ +export interface HierarchicalStateParams { + max_depth?: number; + contracts_per_protocol?: number; +} From b468638775908848fd5444a6b3b9b570fee965e1 Mon Sep 17 00:00:00 2001 From: CPerezz Date: Thu, 30 Oct 2025 14:04:18 +0100 Subject: [PATCH 07/10] feat(state-analyzer): improve treemap visualization with better sizing and color variations - Add Plotly.js treemap visualization for state composition - Implement dynamic color variations for categories, protocols, and contracts - Improve layout with flexbox for full-height container - Default to showing contracts (depth=3) with 100 contracts per protocol - Remove auto-refresh interval to prevent unnecessary re-renders - Fix viewport-relative sizing to use full available space --- frontend/package-lock.json | 17442 ++++++++++++++++ frontend/package.json | 2 + .../src/components/state/PlotlyTreemap.tsx | 304 + .../src/components/state/paradigmColors.ts | 32 + frontend/src/pages/state-analyzer/index.tsx | 60 +- 5 files changed, 17827 insertions(+), 13 deletions(-) create mode 100644 frontend/package-lock.json create mode 100644 frontend/src/components/state/PlotlyTreemap.tsx create mode 100644 frontend/src/components/state/paradigmColors.ts diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 000000000..70f77fd67 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,17442 @@ +{ + "name": "lab", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "lab", + "version": "0.0.0", + "license": "MIT", + "dependencies": { + "@headlessui/react": "2.2.0", + "@heroicons/react": "2.2.0", + "@nivo/bar": "0.93.0", + "@nivo/core": "0.93.0", + "@nivo/line": "0.93.0", + "@nivo/network": "0.93.0", + "@nivo/sankey": "0.93.0", + "@nivo/scatterplot": "0.93.0", + "@nivo/treemap": "0.93.0", + "@tailwindcss/vite": "4.1.5", + "@tanstack/react-query": "5.62.8", + "@tanstack/react-router": "^1.132.7", + "@types/geojson": "7946.0.16", + "@types/react-simple-maps": "3.0.6", + "@types/topojson-client": "3.1.5", + "clsx": "2.0.0", + "date-fns": "4.1.0", + "globe.gl": "2.34.6", + "lucide-react": "0.469.0", + "motion": "^12.10.0", + "plotly.js": "^3.1.2", + "protobufjs": "7.5.0", + "protobufjs-cli": "1.1.3", + "react": "19.1.0", + "react-dom": "19.1.0", + "react-icons": "5.5.0", + "react-plotly.js": "^2.6.0", + "react-simple-maps": "3.0.0", + "react-tooltip": "5.28.0", + "recharts": "2.15.0", + "topojson-client": "3.1.0", + "world-atlas": "2.0.2", + "zod": "^4.1.11", + "zustand": "^5.0.8" + }, + "devDependencies": { + "@bufbuild/protobuf": "1.10.0", + "@bufbuild/protoc-gen-es": "1.10.0", + "@connectrpc/connect": "1.6.0", + "@connectrpc/connect-web": "1.6.0", + "@eslint/css": "^0.7.0", + "@eslint/js": "9.25.1", + "@tailwindcss/forms": "0.5.7", + "@tanstack/router-devtools": "^1.132.7", + "@tanstack/router-plugin": "^1.132.7", + "@types/css-mediaquery": "0.1.4", + "@types/react": "19.1.2", + "@types/react-dom": "19.1.3", + "@types/topojson-specification": "^1.0.5", + "@vitejs/plugin-react": "4.4.1", + "autoprefixer": "10.4.19", + "commitizen": "4.3.0", + "css-mediaquery": "0.1.2", + "cz-conventional-changelog": "3.3.0", + "eslint": "9.25.1", + "eslint-config-prettier": "10.1.2", + "eslint-plugin-prettier": "5.2.6", + "eslint-plugin-react-hooks": "5.2.0", + "eslint-plugin-react-refresh": "0.4.20", + "globals": "16.0.0", + "husky": "9.0.11", + "jsdom": "26.1.0", + "npm-run-all2": "6.1.2", + "prettier": "3.5.3", + "prop-types": "15.8.1", + "rollup": "4.40.2", + "tailwind-scrollbar": "4.0.2", + "tailwindcss": "4.1.5", + "typescript": "5.8.3", + "typescript-eslint": "8.31.1", + "vite": "6.3.4", + "vite-tsconfig-paths": "5.1.4", + "whatwg-fetch": "3.6.20", + "workbox-build": "7.0.0", + "workbox-window": "7.0.0" + } + }, + "node_modules/@apideck/better-ajv-errors": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", + "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-schema": "^0.4.0", + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", + "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", + "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", + "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "debug": "^4.4.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.10" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", + "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", + "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", + "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", + "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", + "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", + "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", + "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", + "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", + "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", + "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", + "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", + "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", + "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", + "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.5.tgz", + "integrity": "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", + "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.28.0", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.5", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.28.3", + "@babel/plugin-transform-classes": "^7.28.4", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.0", + "@babel/plugin-transform-exponentiation-operator": "^7.28.5", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.28.5", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.28.4", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.28.5", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.28.4", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "core-js-compat": "^3.43.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", + "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bufbuild/protobuf": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-1.10.0.tgz", + "integrity": "sha512-QDdVFLoN93Zjg36NoQPZfsVH9tZew7wKDKyV5qRdj8ntT4wQCOradQjRaTdwMhWUYsgKsvCINKKm87FdEk96Ag==", + "dev": true, + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@bufbuild/protoc-gen-es": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protoc-gen-es/-/protoc-gen-es-1.10.0.tgz", + "integrity": "sha512-zBYBsVT/ul4uZb6F+kD7/k4sWNHVVbEPfJwKi0FDr+9VJo8MKIofI6pkr5ksBLr4fi/74r+e/75Xi/0clL5dXg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@bufbuild/protobuf": "^1.10.0", + "@bufbuild/protoplugin": "1.10.0" + }, + "bin": { + "protoc-gen-es": "bin/protoc-gen-es" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@bufbuild/protobuf": "1.10.0" + }, + "peerDependenciesMeta": { + "@bufbuild/protobuf": { + "optional": true + } + } + }, + "node_modules/@bufbuild/protoplugin": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protoplugin/-/protoplugin-1.10.0.tgz", + "integrity": "sha512-u6NE4vL0lw1+EK4/PiE/SQB7fKO4LRJNTEScIXVOi2x88K/c8WKc/k0KyEaA0asVBMpwekJQZGnRyj04ZtN5Gg==", + "dev": true, + "license": "(Apache-2.0 AND BSD-3-Clause)", + "dependencies": { + "@bufbuild/protobuf": "1.10.0", + "@typescript/vfs": "^1.4.0", + "typescript": "4.5.2" + } + }, + "node_modules/@bufbuild/protoplugin/node_modules/typescript": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", + "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/@choojs/findup": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@choojs/findup/-/findup-0.2.1.tgz", + "integrity": "sha512-YstAqNb0MCN8PjdLCDfRsBcGVRN41f3vgLvaI0IrIcBp4AqILRSS0DeWNGkicC+f/zRIPJLc+9RURVSepwvfBw==", + "license": "MIT", + "dependencies": { + "commander": "^2.15.1" + }, + "bin": { + "findup": "bin/findup.js" + } + }, + "node_modules/@commitlint/config-validator": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-20.0.0.tgz", + "integrity": "sha512-BeyLMaRIJDdroJuYM2EGhDMGwVBMZna9UiIqV9hxj+J551Ctc6yoGuGSmghOy/qPhBSuhA6oMtbEiTmxECafsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@commitlint/types": "^20.0.0", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/execute-rule": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-20.0.0.tgz", + "integrity": "sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load": { + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.1.0.tgz", + "integrity": "sha512-qo9ER0XiAimATQR5QhvvzePfeDfApi/AFlC1G+YN+ZAY8/Ua6IRrDrxRvQAr+YXUKAxUsTDSp9KXeXLBPsNRWg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@commitlint/config-validator": "^20.0.0", + "@commitlint/execute-rule": "^20.0.0", + "@commitlint/resolve-extends": "^20.1.0", + "@commitlint/types": "^20.0.0", + "chalk": "^5.3.0", + "cosmiconfig": "^9.0.0", + "cosmiconfig-typescript-loader": "^6.1.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.1.0.tgz", + "integrity": "sha512-cxKXQrqHjZT3o+XPdqDCwOWVFQiae++uwd9dUBC7f2MdV58ons3uUvASdW7m55eat5sRiQ6xUHyMWMRm6atZWw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@commitlint/config-validator": "^20.0.0", + "@commitlint/types": "^20.0.0", + "global-directory": "^4.0.1", + "import-meta-resolve": "^4.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/types": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-20.0.0.tgz", + "integrity": "sha512-bVUNBqG6aznYcYjTjnc3+Cat/iBgbgpflxbIBTnsHTX0YVpnmINPEkSRWymT2Q8aSH3Y7aKnEbunilkYe8TybA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/conventional-commits-parser": "^5.0.0", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/types/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@connectrpc/connect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@connectrpc/connect/-/connect-1.6.0.tgz", + "integrity": "sha512-0WEnWOTtYbjlfi71cjiTle8FdmzdD4A6D9N/9Ky6KlsHB2hPvh2FQ3jpzzXma09rZBbJezHF9vvy29qZqeWtwQ==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "@bufbuild/protobuf": "^1.10.0" + } + }, + "node_modules/@connectrpc/connect-web": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@connectrpc/connect-web/-/connect-web-1.6.0.tgz", + "integrity": "sha512-dyjkdSgNKoUSjNyXOkD4r/d5d8gJxgR1q8zinmCZDFKgRKPFZdjzHLRvd4k4s1Fw54R7Zam5aMMj/t7B0/4CIA==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "@bufbuild/protobuf": "^1.10.0", + "@connectrpc/connect": "1.6.0" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", + "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", + "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", + "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", + "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", + "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", + "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", + "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", + "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", + "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", + "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", + "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", + "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", + "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", + "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", + "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", + "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", + "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", + "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", + "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", + "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", + "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", + "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", + "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", + "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", + "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", + "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz", + "integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.3.tgz", + "integrity": "sha512-u180qk2Um1le4yf0ruXH3PYFeEZeYC3p/4wCTKrr2U1CmGdzGi3KtY0nuPDH48UJxlKCC5RDzbcbh4X0XlqgHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", + "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/css": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/css/-/css-0.7.0.tgz", + "integrity": "sha512-d6mo8etv4igrTGxgvWSgA5+TsppfObM/Xhlu8JWbkqNBiaJXztUNH45R1B4i1GL2PNIFMLREI3Kh9lTBi19l7g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.13.0", + "@eslint/css-tree": "^3.3.3", + "@eslint/plugin-kit": "^0.2.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/css-tree": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/@eslint/css-tree/-/css-tree-3.6.6.tgz", + "integrity": "sha512-C3YiJMY9OZyZ/3vEMFWJIesdGaRY6DmIYvmtyxMT934CbrOKqRs+Iw7NWSRlJQEaK4dPYy2lZ2y1zkaj8z0p5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.23.0", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/js": { + "version": "9.25.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz", + "integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", + "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.13.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.26.28", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.28.tgz", + "integrity": "sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.8", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@headlessui/react": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.2.0.tgz", + "integrity": "sha512-RzCEg+LXsuI7mHiSomsu/gBJSjpupm6A1qIZ5sWjd7JhARNlMiSA4kKfJpCKwU9tE+zMRterhhrP74PvfJrpXQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/react": "^0.26.16", + "@react-aria/focus": "^3.17.1", + "@react-aria/interactions": "^3.21.3", + "@tanstack/react-virtual": "^3.8.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/@heroicons/react": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.2.0.tgz", + "integrity": "sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==", + "license": "MIT", + "peerDependencies": { + "react": ">= 16 || ^19.0.0-rc" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsdoc/salty": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.9.tgz", + "integrity": "sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw==", + "license": "Apache-2.0", + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v12.0.0" + } + }, + "node_modules/@mapbox/geojson-rewind": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", + "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", + "license": "ISC", + "dependencies": { + "get-stream": "^6.0.1", + "minimist": "^1.2.6" + }, + "bin": { + "geojson-rewind": "geojson-rewind" + } + }, + "node_modules/@mapbox/geojson-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@mapbox/geojson-types/-/geojson-types-1.0.2.tgz", + "integrity": "sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw==", + "license": "ISC" + }, + "node_modules/@mapbox/jsonlint-lines-primitives": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", + "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@mapbox/mapbox-gl-supported": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-1.5.0.tgz", + "integrity": "sha512-/PT1P6DNf7vjEEiPkVIRJkvibbqWtqnyGaBz3nfRdcxclNSnSdaLU5tfAgcD7I8Yt5i+L19s406YLl1koLnLbg==", + "license": "BSD-3-Clause", + "peerDependencies": { + "mapbox-gl": ">=0.32.1 <2.0.0" + } + }, + "node_modules/@mapbox/point-geometry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", + "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==", + "license": "ISC" + }, + "node_modules/@mapbox/tiny-sdf": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-1.2.5.tgz", + "integrity": "sha512-cD8A/zJlm6fdJOk6DqPUV8mcpyJkRz2x2R+/fYcWDYG3oWbG7/L7Yl/WqQ1VZCjnL9OTIMAn6c+BC5Eru4sQEw==", + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/unitbezier": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz", + "integrity": "sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==", + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/vector-tile": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", + "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", + "license": "BSD-3-Clause", + "dependencies": { + "@mapbox/point-geometry": "~0.1.0" + } + }, + "node_modules/@mapbox/whoots-js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", + "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", + "license": "ISC", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@maplibre/maplibre-gl-style-spec": { + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.4.0.tgz", + "integrity": "sha512-AzBy3095fTFPjDjmWpR2w6HVRAZJ6hQZUCwk5Plz6EyfnfuQW1odeW5i2Ai47Y6TBA2hQnC+azscjBSALpaWgw==", + "license": "ISC", + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "~2.0.2", + "@mapbox/unitbezier": "^0.0.1", + "json-stringify-pretty-compact": "^4.0.0", + "minimist": "^1.2.8", + "quickselect": "^2.0.0", + "rw": "^1.3.3", + "tinyqueue": "^3.0.0" + }, + "bin": { + "gl-style-format": "dist/gl-style-format.mjs", + "gl-style-migrate": "dist/gl-style-migrate.mjs", + "gl-style-validate": "dist/gl-style-validate.mjs" + } + }, + "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", + "license": "BSD-2-Clause" + }, + "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/tinyqueue": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", + "license": "ISC" + }, + "node_modules/@nivo/annotations": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/annotations/-/annotations-0.93.0.tgz", + "integrity": "sha512-qPb6jIZ4YN0/fOpf4KUwD5iVjrOkbyC4L3F03X9akj55Llr+HwC18FRhOwZaJ0YonVSSYHEQwwkUZgrgHepOvA==", + "license": "MIT", + "dependencies": { + "@nivo/colors": "0.93.0", + "@nivo/core": "0.93.0", + "@nivo/theming": "0.93.0", + "@react-spring/web": "9.4.5 || ^9.7.2", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 20.0.0" + } + }, + "node_modules/@nivo/axes": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/axes/-/axes-0.93.0.tgz", + "integrity": "sha512-6cIEKx+qiOKWGliwJf54DxFilowJu4gAAdERXTXfik+61yZCa31xOwslXVwmkpaVcYYThLmw+MwuNf7CXTZWvQ==", + "license": "MIT", + "dependencies": { + "@nivo/core": "0.93.0", + "@nivo/scales": "0.93.0", + "@nivo/text": "0.93.0", + "@nivo/theming": "0.93.0", + "@react-spring/web": "9.4.5 || ^9.7.2", + "@types/d3-format": "^1.4.1", + "@types/d3-time-format": "^2.3.1", + "d3-format": "^1.4.4", + "d3-time-format": "^3.0.0" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 20.0.0" + } + }, + "node_modules/@nivo/bar": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/bar/-/bar-0.93.0.tgz", + "integrity": "sha512-JQhqHxXzkouJHbePBbvKDDjJg5tMERJisxWIppcbhTft5UT5SR1EIatXq8AzXiuWSV3gtKwD93Ktu/LED/Idkw==", + "license": "MIT", + "dependencies": { + "@nivo/annotations": "0.93.0", + "@nivo/axes": "0.93.0", + "@nivo/canvas": "0.93.0", + "@nivo/colors": "0.93.0", + "@nivo/core": "0.93.0", + "@nivo/legends": "0.93.0", + "@nivo/scales": "0.93.0", + "@nivo/text": "0.93.0", + "@nivo/theming": "0.93.0", + "@nivo/tooltip": "0.93.0", + "@react-spring/web": "9.4.5 || ^9.7.2", + "@types/d3-scale": "^4.0.8", + "@types/d3-shape": "^3.1.6", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 20.0.0" + } + }, + "node_modules/@nivo/canvas": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/canvas/-/canvas-0.93.0.tgz", + "integrity": "sha512-he9L7ExzwEbpncD8sq+siQ3sprDMmJOMl08XytQR5aunVBl1LLrgQU+vwQgDOsYwYV+n7mgKr7LOVpzx0nNjBw==", + "license": "MIT" + }, + "node_modules/@nivo/colors": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/colors/-/colors-0.93.0.tgz", + "integrity": "sha512-f6mrCAxIH2S8yN7qCs5YowmkKMB4ddXFBr6/HYdBtNZk5Z2Xn8K7YRriYV8XDTojcl1qD+sRM4sELBUootGeMg==", + "license": "MIT", + "dependencies": { + "@nivo/core": "0.93.0", + "@nivo/theming": "0.93.0", + "@types/d3-color": "^3.0.0", + "@types/d3-scale": "^4.0.8", + "@types/d3-scale-chromatic": "^3.0.0", + "d3-color": "^3.1.0", + "d3-scale": "^4.0.2", + "d3-scale-chromatic": "^3.0.0", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 20.0.0" + } + }, + "node_modules/@nivo/core": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/core/-/core-0.93.0.tgz", + "integrity": "sha512-fuspmWaVF1SAbFYWO2sYeGvGoSHcrr2tDRn7lM+f4dPJVN5w5waHpRHTfEfKg6Q++zsXs2QEPlnhpZsG4tbE0w==", + "license": "MIT", + "dependencies": { + "@nivo/theming": "0.93.0", + "@nivo/tooltip": "0.93.0", + "@react-spring/web": "9.4.5 || ^9.7.2", + "@types/d3-shape": "^3.1.6", + "d3-color": "^3.1.0", + "d3-format": "^1.4.4", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-scale-chromatic": "^3.0.0", + "d3-shape": "^3.2.0", + "d3-time-format": "^3.0.0", + "lodash": "^4.17.21" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nivo/donate" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 20.0.0" + } + }, + "node_modules/@nivo/legends": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/legends/-/legends-0.93.0.tgz", + "integrity": "sha512-J6z+3r73MQtjnccc7rgvNxLuAkT4Bli5D2lwekHoljBv7NbUQOXCVg/c/uET1MMPoqunoBUWUuGUDZ6IiK1a4g==", + "license": "MIT", + "dependencies": { + "@nivo/colors": "0.93.0", + "@nivo/core": "0.93.0", + "@nivo/text": "0.93.0", + "@nivo/theming": "0.93.0", + "@types/d3-scale": "^4.0.8", + "d3-scale": "^4.0.2" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 20.0.0" + } + }, + "node_modules/@nivo/line": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/line/-/line-0.93.0.tgz", + "integrity": "sha512-HFqf9RDgHrykJRf7ER9mhb5RruLnHuos0eoFC6VN6O+hxLkZfTFv8akDydA5BDl3pc7FtOpEKrGKJtiuZfgDNg==", + "license": "MIT", + "dependencies": { + "@nivo/annotations": "0.93.0", + "@nivo/axes": "0.93.0", + "@nivo/colors": "0.93.0", + "@nivo/core": "0.93.0", + "@nivo/legends": "0.93.0", + "@nivo/scales": "0.93.0", + "@nivo/theming": "0.93.0", + "@nivo/tooltip": "0.93.0", + "@nivo/voronoi": "0.93.0", + "@react-spring/web": "9.4.5 || ^9.7.2", + "@types/d3-shape": "^3.1.6", + "d3-shape": "^3.2.0" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 20.0.0" + } + }, + "node_modules/@nivo/network": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/network/-/network-0.93.0.tgz", + "integrity": "sha512-VJE2zjpmyGW6I8Kox64mYD37IYjkr4gTu6LvdJBayDXF5dHOMKLwZUen4eKfTfruMqigb5cdr3NjxKLHExCRkg==", + "license": "MIT", + "dependencies": { + "@nivo/annotations": "0.93.0", + "@nivo/colors": "0.93.0", + "@nivo/core": "0.93.0", + "@nivo/theming": "0.93.0", + "@nivo/tooltip": "0.93.0", + "@react-spring/web": "9.4.5 || ^9.7.2", + "@types/d3-force": "^2.1.0", + "d3-force": "^2.0.1" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 20.0.0" + } + }, + "node_modules/@nivo/sankey": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/sankey/-/sankey-0.93.0.tgz", + "integrity": "sha512-gu54GCqS0xfV/ZMJR9YSgQbS/qM6uD/INqIJQ/if/tpuaCoAuGUyZScaMPPf4wDVgejBJBSChwmXbDhLngNQdA==", + "license": "MIT", + "dependencies": { + "@nivo/colors": "0.93.0", + "@nivo/core": "0.93.0", + "@nivo/legends": "0.93.0", + "@nivo/text": "0.93.0", + "@nivo/theming": "0.93.0", + "@nivo/tooltip": "0.93.0", + "@react-spring/web": "9.4.5 || ^9.7.2", + "@types/d3-sankey": "^0.11.2", + "@types/d3-shape": "^3.1.6", + "d3-sankey": "^0.12.3", + "d3-shape": "^3.2.0", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 20.0.0" + } + }, + "node_modules/@nivo/scales": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/scales/-/scales-0.93.0.tgz", + "integrity": "sha512-0pS8geE/j/214F+EnbiIJPUM/EJYlAfvQXTEzj3juq9alsxgrcLM1CY7nc2ClkbBCzTXMI63uQQ0iLg8caG1iA==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "^3.0.4", + "@types/d3-scale": "^4.0.8", + "@types/d3-time": "^1.1.1", + "@types/d3-time-format": "^3.0.0", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-time": "^1.0.11", + "d3-time-format": "^3.0.0", + "lodash": "^4.17.21" + } + }, + "node_modules/@nivo/scales/node_modules/@types/d3-time-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-3.0.4.tgz", + "integrity": "sha512-or9DiDnYI1h38J9hxKEsw513+KVuFbEVhl7qdxcaudoiqWWepapUen+2vAriFGexr6W5+P4l9+HJrB39GG+oRg==", + "license": "MIT" + }, + "node_modules/@nivo/scatterplot": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/scatterplot/-/scatterplot-0.93.0.tgz", + "integrity": "sha512-5Vsnrq61HVbN8L5+XZzAghmjpryDcG5170eAS6d0PgNGz7PRGoyQeanT8zy0xIMMIHgIBhr7E/ttninYhvkyXA==", + "license": "MIT", + "dependencies": { + "@nivo/annotations": "0.93.0", + "@nivo/axes": "0.93.0", + "@nivo/colors": "0.93.0", + "@nivo/core": "0.93.0", + "@nivo/legends": "0.93.0", + "@nivo/scales": "0.93.0", + "@nivo/theming": "0.93.0", + "@nivo/tooltip": "0.93.0", + "@nivo/voronoi": "0.93.0", + "@react-spring/web": "9.4.5 || ^9.7.2", + "@types/d3-scale": "^4.0.8", + "@types/d3-shape": "^3.1.6", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 20.0.0" + } + }, + "node_modules/@nivo/text": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/text/-/text-0.93.0.tgz", + "integrity": "sha512-yhA3spFtPJJIllNPViwmye/OnwthK1DqMZtUdoznU5I83zXdXUjl2HSBo+RbwGn2luOUIsd5zLkQfYe0iTdCeA==", + "license": "MIT", + "dependencies": { + "@nivo/theming": "0.93.0", + "@react-spring/web": "9.4.5 || ^9.7.2" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 20.0.0" + } + }, + "node_modules/@nivo/theming": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/theming/-/theming-0.93.0.tgz", + "integrity": "sha512-kT2Dc4bz+QXwNB3yIYQ7PwgTQ1cwSgWOBW6xWf9CAO8e4DBf0eBfmvKY0ILnYe1S083F9hxiyG4Ozhu5RagIkQ==", + "license": "MIT", + "peerDependencies": { + "react": ">= 16.14.0 < 20.0.0" + } + }, + "node_modules/@nivo/tooltip": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/tooltip/-/tooltip-0.93.0.tgz", + "integrity": "sha512-6rrJsi+2kA/wUGV5zqE4PMhVNekTpage6AQv/+/EX7V+zGEwRhZTGHFvwU0HVmpZwApMM39WxlCgU30WlAt1/w==", + "license": "MIT", + "dependencies": { + "@nivo/core": "0.93.0", + "@nivo/theming": "0.93.0", + "@react-spring/web": "9.4.5 || ^9.7.2" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 20.0.0" + } + }, + "node_modules/@nivo/treemap": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/treemap/-/treemap-0.93.0.tgz", + "integrity": "sha512-Nsup2chgL0aEl70p0SiCYk2CjQR0UdZxL5o1v19oPgf02BQBcF4o+g1rv5Wf8nYUJAs+Tf1WLtrauN/vNhjRzw==", + "license": "MIT", + "dependencies": { + "@nivo/colors": "0.93.0", + "@nivo/core": "0.93.0", + "@nivo/text": "0.93.0", + "@nivo/theming": "0.93.0", + "@nivo/tooltip": "0.93.0", + "@react-spring/core": "9.4.5 || ^9.7.2", + "@react-spring/web": "9.4.5 || ^9.7.2", + "@types/d3-hierarchy": "^1.1.8", + "d3-hierarchy": "^1.1.8", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 20.0.0" + } + }, + "node_modules/@nivo/voronoi": { + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/@nivo/voronoi/-/voronoi-0.93.0.tgz", + "integrity": "sha512-lsYtQVOH1MhIu31T+ph4O/gHwBoIDyKE7vJ8cWwtCgcpSUL6MPf1WiGRmCYsiM19ezEK0pQwf3oDYOp067J/Mg==", + "license": "MIT", + "dependencies": { + "@nivo/core": "0.93.0", + "@nivo/theming": "0.93.0", + "@nivo/tooltip": "0.93.0", + "@types/d3-delaunay": "^6.0.4", + "@types/d3-scale": "^4.0.8", + "d3-delaunay": "^6.0.4", + "d3-scale": "^4.0.2" + }, + "peerDependencies": { + "react": ">= 16.14.0 < 20.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@plotly/d3": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@plotly/d3/-/d3-3.8.2.tgz", + "integrity": "sha512-wvsNmh1GYjyJfyEBPKJLTMzgf2c2bEbSIL50lmqVUi+o1NHaLPi1Lb4v7VxXXJn043BhNyrxUrWI85Q+zmjOVA==", + "license": "BSD-3-Clause" + }, + "node_modules/@plotly/d3-sankey": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@plotly/d3-sankey/-/d3-sankey-0.7.2.tgz", + "integrity": "sha512-2jdVos1N3mMp3QW0k2q1ph7Gd6j5PY1YihBrwpkFnKqO+cqtZq3AdEYUeSGXMeLsBDQYiqTVcihYfk8vr5tqhw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1", + "d3-collection": "1", + "d3-shape": "^1.2.0" + } + }, + "node_modules/@plotly/d3-sankey-circular": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@plotly/d3-sankey-circular/-/d3-sankey-circular-0.33.1.tgz", + "integrity": "sha512-FgBV1HEvCr3DV7RHhDsPXyryknucxtfnLwPtCKKxdolKyTFYoLX/ibEfX39iFYIL7DYbVeRtP43dbFcrHNE+KQ==", + "license": "MIT", + "dependencies": { + "d3-array": "^1.2.1", + "d3-collection": "^1.0.4", + "d3-shape": "^1.2.0", + "elementary-circuits-directed-graph": "^1.0.4" + } + }, + "node_modules/@plotly/d3-sankey-circular/node_modules/d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==", + "license": "BSD-3-Clause" + }, + "node_modules/@plotly/d3-sankey-circular/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/@plotly/d3-sankey-circular/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/@plotly/d3-sankey/node_modules/d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==", + "license": "BSD-3-Clause" + }, + "node_modules/@plotly/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/@plotly/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/@plotly/mapbox-gl": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/@plotly/mapbox-gl/-/mapbox-gl-1.13.4.tgz", + "integrity": "sha512-sR3/Pe5LqT/fhYgp4rT4aSFf1rTsxMbGiH6Hojc7PH36ny5Bn17iVFUjpzycafETURuFbLZUfjODO8LvSI+5zQ==", + "license": "SEE LICENSE IN LICENSE.txt", + "dependencies": { + "@mapbox/geojson-rewind": "^0.5.2", + "@mapbox/geojson-types": "^1.0.2", + "@mapbox/jsonlint-lines-primitives": "^2.0.2", + "@mapbox/mapbox-gl-supported": "^1.5.0", + "@mapbox/point-geometry": "^0.1.0", + "@mapbox/tiny-sdf": "^1.1.1", + "@mapbox/unitbezier": "^0.0.0", + "@mapbox/vector-tile": "^1.3.1", + "@mapbox/whoots-js": "^3.1.0", + "csscolorparser": "~1.0.3", + "earcut": "^2.2.2", + "geojson-vt": "^3.2.1", + "gl-matrix": "^3.2.1", + "grid-index": "^1.1.0", + "murmurhash-js": "^1.0.0", + "pbf": "^3.2.1", + "potpack": "^1.0.1", + "quickselect": "^2.0.0", + "rw": "^1.3.3", + "supercluster": "^7.1.0", + "tinyqueue": "^2.0.3", + "vt-pbf": "^3.1.1" + }, + "engines": { + "node": ">=6.4.0" + } + }, + "node_modules/@plotly/mapbox-gl/node_modules/earcut": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", + "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==", + "license": "ISC" + }, + "node_modules/@plotly/point-cluster": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@plotly/point-cluster/-/point-cluster-3.1.9.tgz", + "integrity": "sha512-MwaI6g9scKf68Orpr1pHZ597pYx9uP8UEFXLPbsCmuw3a84obwz6pnMXGc90VhgDNeNiLEdlmuK7CPo+5PIxXw==", + "license": "MIT", + "dependencies": { + "array-bounds": "^1.0.1", + "binary-search-bounds": "^2.0.4", + "clamp": "^1.0.1", + "defined": "^1.0.0", + "dtype": "^2.0.0", + "flatten-vertex-data": "^1.0.2", + "is-obj": "^1.0.1", + "math-log2": "^1.0.1", + "parse-rect": "^1.2.0", + "pick-by-alias": "^1.2.0" + } + }, + "node_modules/@plotly/regl": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@plotly/regl/-/regl-2.1.2.tgz", + "integrity": "sha512-Mdk+vUACbQvjd0m/1JJjOOafmkp/EpmHjISsopEz5Av44CBq7rPC05HHNbYGKVyNUF2zmEoBS/TT0pd0SPFFyw==", + "license": "MIT" + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, + "node_modules/@react-aria/focus": { + "version": "3.21.2", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.21.2.tgz", + "integrity": "sha512-JWaCR7wJVggj+ldmM/cb/DXFg47CXR55lznJhZBh4XVqJjMKwaOOqpT5vNN7kpC1wUpXicGNuDnJDN1S/+6dhQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.25.6", + "@react-aria/utils": "^3.31.0", + "@react-types/shared": "^3.32.1", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/interactions": { + "version": "3.25.6", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.25.6.tgz", + "integrity": "sha512-5UgwZmohpixwNMVkMvn9K1ceJe6TzlRlAfuYoQDUuOkk62/JVJNDLAPKIf5YMRc7d2B0rmfgaZLMtbREb0Zvkw==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.10", + "@react-aria/utils": "^3.31.0", + "@react-stately/flags": "^3.1.2", + "@react-types/shared": "^3.32.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.10.tgz", + "integrity": "sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/utils": { + "version": "3.31.0", + "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.31.0.tgz", + "integrity": "sha512-ABOzCsZrWzf78ysswmguJbx3McQUja7yeGj6/vZo4JVsZNlxAN+E9rs381ExBRI0KzVo6iBTeX5De8eMZPJXig==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.10", + "@react-stately/flags": "^3.1.2", + "@react-stately/utils": "^3.10.8", + "@react-types/shared": "^3.32.1", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-spring/animated": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.5.tgz", + "integrity": "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==", + "license": "MIT", + "dependencies": { + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.5.tgz", + "integrity": "sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==", + "license": "MIT", + "dependencies": { + "@react-spring/animated": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/rafz": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.5.tgz", + "integrity": "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw==", + "license": "MIT" + }, + "node_modules/@react-spring/shared": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.5.tgz", + "integrity": "sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==", + "license": "MIT", + "dependencies": { + "@react-spring/rafz": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/types": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.5.tgz", + "integrity": "sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g==", + "license": "MIT" + }, + "node_modules/@react-spring/web": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.5.tgz", + "integrity": "sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ==", + "license": "MIT", + "dependencies": { + "@react-spring/animated": "~9.7.5", + "@react-spring/core": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-stately/flags": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@react-stately/flags/-/flags-3.1.2.tgz", + "integrity": "sha512-2HjFcZx1MyQXoPqcBGALwWWmgFVUk2TuKVIQxCbRq7fPyWXIl6VHcakCLurdtYC2Iks7zizvz0Idv48MQ38DWg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@react-stately/utils": { + "version": "3.10.8", + "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.10.8.tgz", + "integrity": "sha512-SN3/h7SzRsusVQjQ4v10LaVsDc81jyyR0DD5HnsQitm/I5WDpaSr2nRHtyloPFU48jlql1XX/S04T2DLQM7Y3g==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/shared": { + "version": "3.32.1", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.32.1.tgz", + "integrity": "sha512-famxyD5emrGGpFuUlgOP6fVW2h/ZaF405G5KDi3zPHzyjAWys/8W6NAVJtNbkCkhedmvL0xOhvt8feGXyXaw5w==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@rollup/plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", + "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", + "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", + "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/pluginutils/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.2.tgz", + "integrity": "sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.2.tgz", + "integrity": "sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.2.tgz", + "integrity": "sha512-Gzf1Hn2Aoe8VZzevHostPX23U7N5+4D36WJNHK88NZHCJr7aVMG4fadqkIf72eqVPGjGc0HJHNuUaUcxiR+N/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.2.tgz", + "integrity": "sha512-47N4hxa01a4x6XnJoskMKTS8XZ0CZMd8YTbINbi+w03A2w4j1RTlnGHOz/P0+Bg1LaVL6ufZyNprSg+fW5nYQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.2.tgz", + "integrity": "sha512-8t6aL4MD+rXSHHZUR1z19+9OFJ2rl1wGKvckN47XFRVO+QL/dUSpKA2SLRo4vMg7ELA8pzGpC+W9OEd1Z/ZqoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.2.tgz", + "integrity": "sha512-C+AyHBzfpsOEYRFjztcYUFsH4S7UsE9cDtHCtma5BK8+ydOZYgMmWg1d/4KBytQspJCld8ZIujFMAdKG1xyr4Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.2.tgz", + "integrity": "sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.2.tgz", + "integrity": "sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.2.tgz", + "integrity": "sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.2.tgz", + "integrity": "sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz", + "integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.2.tgz", + "integrity": "sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.2.tgz", + "integrity": "sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz", + "integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.2.tgz", + "integrity": "sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.2.tgz", + "integrity": "sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.2.tgz", + "integrity": "sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.2.tgz", + "integrity": "sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.2.tgz", + "integrity": "sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz", + "integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.2.tgz", + "integrity": "sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.2.tgz", + "integrity": "sha512-dt1llVSGEsGKvzeIO76HToiYPNPYPkmjhMHhP00T9S4rDern8P2ZWvWAQUEJ+R1UdMWJ/42i/QqJ2WV765GZcA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz", + "integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.2.tgz", + "integrity": "sha512-bwspbWB04XJpeElvsp+DCylKfF4trJDa2Y9Go8O6A7YLX2LIKGcNK/CYImJN6ZP4DcuOHB4Utl3iCbnR62DudA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@surma/rollup-plugin-off-main-thread": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", + "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "ejs": "^3.1.6", + "json5": "^2.2.0", + "magic-string": "^0.25.0", + "string.prototype.matchall": "^4.0.6" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/forms": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz", + "integrity": "sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mini-svg-data-uri": "^1.2.3" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.5.tgz", + "integrity": "sha512-CBhSWo0vLnWhXIvpD0qsPephiaUYfHUX3U9anwDaHZAeuGpTiB3XmsxPAN6qX7bFhipyGBqOa1QYQVVhkOUGxg==", + "license": "MIT", + "dependencies": { + "enhanced-resolve": "^5.18.1", + "jiti": "^2.4.2", + "lightningcss": "1.29.2", + "tailwindcss": "4.1.5" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.5.tgz", + "integrity": "sha512-1n4br1znquEvyW/QuqMKQZlBen+jxAbvyduU87RS8R3tUSvByAkcaMTkJepNIrTlYhD+U25K4iiCIxE6BGdRYA==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.5", + "@tailwindcss/oxide-darwin-arm64": "4.1.5", + "@tailwindcss/oxide-darwin-x64": "4.1.5", + "@tailwindcss/oxide-freebsd-x64": "4.1.5", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.5", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.5", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.5", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.5", + "@tailwindcss/oxide-linux-x64-musl": "4.1.5", + "@tailwindcss/oxide-wasm32-wasi": "4.1.5", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.5", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.5" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.5.tgz", + "integrity": "sha512-LVvM0GirXHED02j7hSECm8l9GGJ1RfgpWCW+DRn5TvSaxVsv28gRtoL4aWKGnXqwvI3zu1GABeDNDVZeDPOQrw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.5.tgz", + "integrity": "sha512-//TfCA3pNrgnw4rRJOqavW7XUk8gsg9ddi8cwcsWXp99tzdBAZW0WXrD8wDyNbqjW316Pk2hiN/NJx/KWHl8oA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.5.tgz", + "integrity": "sha512-XQorp3Q6/WzRd9OalgHgaqgEbjP3qjHrlSUb5k1EuS1Z9NE9+BbzSORraO+ecW432cbCN7RVGGL/lSnHxcd+7Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.5.tgz", + "integrity": "sha512-bPrLWbxo8gAo97ZmrCbOdtlz/Dkuy8NK97aFbVpkJ2nJ2Jo/rsCbu0TlGx8joCuA3q6vMWTSn01JY46iwG+clg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.5.tgz", + "integrity": "sha512-1gtQJY9JzMAhgAfvd/ZaVOjh/Ju/nCoAsvOVJenWZfs05wb8zq+GOTnZALWGqKIYEtyNpCzvMk+ocGpxwdvaVg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.5.tgz", + "integrity": "sha512-dtlaHU2v7MtdxBXoqhxwsWjav7oim7Whc6S9wq/i/uUMTWAzq/gijq1InSgn2yTnh43kR+SFvcSyEF0GCNu1PQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.5.tgz", + "integrity": "sha512-fg0F6nAeYcJ3CriqDT1iVrqALMwD37+sLzXs8Rjy8Z1ZHshJoYceodfyUwGJEsQoTyWbliFNRs2wMQNXtT7MVA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.5.tgz", + "integrity": "sha512-SO+F2YEIAHa1AITwc8oPwMOWhgorPzzcbhWEb+4oLi953h45FklDmM8dPSZ7hNHpIk9p/SCZKUYn35t5fjGtHA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.5.tgz", + "integrity": "sha512-6UbBBplywkk/R+PqqioskUeXfKcBht3KU7juTi1UszJLx0KPXUo10v2Ok04iBJIaDPkIFkUOVboXms5Yxvaz+g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.5.tgz", + "integrity": "sha512-hwALf2K9FHuiXTPqmo1KeOb83fTRNbe9r/Ixv9ZNQ/R24yw8Ge1HOWDDgTdtzntIaIUJG5dfXCf4g9AD4RiyhQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@emnapi/wasi-threads": "^1.0.2", + "@napi-rs/wasm-runtime": "^0.2.9", + "@tybys/wasm-util": "^0.9.0", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.5.tgz", + "integrity": "sha512-oDKncffWzaovJbkuR7/OTNFRJQVdiw/n8HnzaCItrNQUeQgjy7oUiYpsm9HUBgpmvmDpSSbGaCa2Evzvk3eFmA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.5.tgz", + "integrity": "sha512-WiR4dtyrFdbb+ov0LK+7XsFOsG+0xs0PKZKkt41KDn9jYpO7baE3bXiudPVkTqUEwNfiglCygQHl2jklvSBi7Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.5.tgz", + "integrity": "sha512-FE1stRoqdHSb7RxesMfCXE8icwI1W6zGE/512ae3ZDrpkQYTTYeSyUJPRCjZd8CwVAhpDUbi1YR8pcZioFJQ/w==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.5", + "@tailwindcss/oxide": "4.1.5", + "tailwindcss": "4.1.5" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6" + } + }, + "node_modules/@tanstack/history": { + "version": "1.133.28", + "resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.133.28.tgz", + "integrity": "sha512-B7+x7eP2FFvi3fgd3rNH9o/Eixt+pp0zCIdGhnQbAJjFrlwIKGjGnwyJjhWJ5fMQlGks/E2LdDTqEV4W9Plx7g==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.62.8", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.62.8.tgz", + "integrity": "sha512-4fV31vDsUyvNGrKIOUNPrZztoyL187bThnoQOvAXEVlZbSiuPONpfx53634MKKdvsDir5NyOGm80ShFaoHS/mw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.62.8", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.62.8.tgz", + "integrity": "sha512-8TUstKxF/fysHonZsWg/hnlDVgasTdHx6Q+f1/s/oPKJBJbKUWPZEHwLTMOZgrZuroLMiqYKJ9w69Abm8mWP0Q==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.62.8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@tanstack/react-router": { + "version": "1.133.32", + "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.133.32.tgz", + "integrity": "sha512-UqakhaFJ+r5S+b4/AvLux70Hk+1MpmwfKwbdV7vuM2bVRUSztM8xtcttVpzZwRV45Ls8YsStY58prEVdCpvkNg==", + "license": "MIT", + "dependencies": { + "@tanstack/history": "1.133.28", + "@tanstack/react-store": "^0.7.0", + "@tanstack/router-core": "1.133.28", + "isbot": "^5.1.22", + "tiny-invariant": "^1.3.3", + "tiny-warning": "^1.0.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0" + } + }, + "node_modules/@tanstack/react-router-devtools": { + "version": "1.133.34", + "resolved": "https://registry.npmjs.org/@tanstack/react-router-devtools/-/react-router-devtools-1.133.34.tgz", + "integrity": "sha512-4Vlx2uHdCINLM47xtNR37B0yLGpoN4sOz0aQWmXfP6o3nj8MYvOjYEZIwA+JZ643PckgAstpLfGZmkh/eWgE/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tanstack/router-devtools-core": "1.133.34", + "vite": "^7.1.7" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-router": "^1.133.32", + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0" + } + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz", + "integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz", + "integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", + "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", + "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz", + "integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz", + "integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz", + "integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz", + "integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz", + "integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz", + "integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz", + "integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz", + "integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz", + "integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", + "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz", + "integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz", + "integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz", + "integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", + "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tanstack/react-router-devtools/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@tanstack/react-router-devtools/node_modules/rollup": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", + "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.5", + "@rollup/rollup-android-arm64": "4.52.5", + "@rollup/rollup-darwin-arm64": "4.52.5", + "@rollup/rollup-darwin-x64": "4.52.5", + "@rollup/rollup-freebsd-arm64": "4.52.5", + "@rollup/rollup-freebsd-x64": "4.52.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", + "@rollup/rollup-linux-arm-musleabihf": "4.52.5", + "@rollup/rollup-linux-arm64-gnu": "4.52.5", + "@rollup/rollup-linux-arm64-musl": "4.52.5", + "@rollup/rollup-linux-loong64-gnu": "4.52.5", + "@rollup/rollup-linux-ppc64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-musl": "4.52.5", + "@rollup/rollup-linux-s390x-gnu": "4.52.5", + "@rollup/rollup-linux-x64-gnu": "4.52.5", + "@rollup/rollup-linux-x64-musl": "4.52.5", + "@rollup/rollup-openharmony-arm64": "4.52.5", + "@rollup/rollup-win32-arm64-msvc": "4.52.5", + "@rollup/rollup-win32-ia32-msvc": "4.52.5", + "@rollup/rollup-win32-x64-gnu": "4.52.5", + "@rollup/rollup-win32-x64-msvc": "4.52.5", + "fsevents": "~2.3.2" + } + }, + "node_modules/@tanstack/react-router-devtools/node_modules/vite": { + "version": "7.1.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.12.tgz", + "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "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 + } + } + }, + "node_modules/@tanstack/react-store": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.7.7.tgz", + "integrity": "sha512-qqT0ufegFRDGSof9D/VqaZgjNgp4tRPHZIJq2+QIHkMUtHjaJ0lYrrXjeIUJvjnTbgPfSD1XgOMEt0lmANn6Zg==", + "license": "MIT", + "dependencies": { + "@tanstack/store": "0.7.7", + "use-sync-external-store": "^1.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/react-virtual": { + "version": "3.13.12", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.12.tgz", + "integrity": "sha512-Gd13QdxPSukP8ZrkbgS2RwoZseTTbQPLnQEn7HY/rqtM+8Zt95f7xKC7N0EsKs7aoz0WzZ+fditZux+F8EzYxA==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.13.12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/router-core": { + "version": "1.133.28", + "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.133.28.tgz", + "integrity": "sha512-HErb1X9F+u4VzguJKafX1p5fSnNnfo7aK8Xxh5cICFMShPBxt9i1K45nUbQaRkf45N1tg4gJ3l8mlmwWRm9WWA==", + "license": "MIT", + "dependencies": { + "@tanstack/history": "1.133.28", + "@tanstack/store": "^0.7.0", + "cookie-es": "^2.0.0", + "seroval": "^1.3.2", + "seroval-plugins": "^1.3.2", + "tiny-invariant": "^1.3.3", + "tiny-warning": "^1.0.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/router-devtools": { + "version": "1.133.34", + "resolved": "https://registry.npmjs.org/@tanstack/router-devtools/-/router-devtools-1.133.34.tgz", + "integrity": "sha512-i9Maca4zOf0XwxjuJ+Ah7iwMqkDved/mMV4uMq7N014yrQSGXjd+S9M9UMKECuEuN4r/HnhX2hlMVcjUHHkQzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tanstack/react-router-devtools": "1.133.34", + "clsx": "^2.1.1", + "goober": "^2.1.16", + "vite": "^7.1.7" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-router": "^1.133.32", + "csstype": "^3.0.10", + "react": ">=18.0.0 || >=19.0.0", + "react-dom": ">=18.0.0 || >=19.0.0" + }, + "peerDependenciesMeta": { + "csstype": { + "optional": true + } + } + }, + "node_modules/@tanstack/router-devtools-core": { + "version": "1.133.34", + "resolved": "https://registry.npmjs.org/@tanstack/router-devtools-core/-/router-devtools-core-1.133.34.tgz", + "integrity": "sha512-NYjrYV/Gt8GlD72uIZakv9a2Z2O31n4J/7uOCU0K9pzSMNa0rmYSYHeaB9vzI9Ksv944mvvmOpDnGUpUhwNXAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1", + "goober": "^2.1.16", + "vite": "^7.1.7" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/router-core": "^1.133.28", + "csstype": "^3.0.10", + "solid-js": ">=1.9.5", + "tiny-invariant": "^1.3.3" + }, + "peerDependenciesMeta": { + "csstype": { + "optional": true + } + } + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz", + "integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz", + "integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", + "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", + "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz", + "integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz", + "integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz", + "integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz", + "integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz", + "integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz", + "integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz", + "integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz", + "integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz", + "integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", + "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz", + "integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz", + "integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz", + "integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", + "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tanstack/router-devtools-core/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@tanstack/router-devtools-core/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@tanstack/router-devtools-core/node_modules/rollup": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", + "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.5", + "@rollup/rollup-android-arm64": "4.52.5", + "@rollup/rollup-darwin-arm64": "4.52.5", + "@rollup/rollup-darwin-x64": "4.52.5", + "@rollup/rollup-freebsd-arm64": "4.52.5", + "@rollup/rollup-freebsd-x64": "4.52.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", + "@rollup/rollup-linux-arm-musleabihf": "4.52.5", + "@rollup/rollup-linux-arm64-gnu": "4.52.5", + "@rollup/rollup-linux-arm64-musl": "4.52.5", + "@rollup/rollup-linux-loong64-gnu": "4.52.5", + "@rollup/rollup-linux-ppc64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-musl": "4.52.5", + "@rollup/rollup-linux-s390x-gnu": "4.52.5", + "@rollup/rollup-linux-x64-gnu": "4.52.5", + "@rollup/rollup-linux-x64-musl": "4.52.5", + "@rollup/rollup-openharmony-arm64": "4.52.5", + "@rollup/rollup-win32-arm64-msvc": "4.52.5", + "@rollup/rollup-win32-ia32-msvc": "4.52.5", + "@rollup/rollup-win32-x64-gnu": "4.52.5", + "@rollup/rollup-win32-x64-msvc": "4.52.5", + "fsevents": "~2.3.2" + } + }, + "node_modules/@tanstack/router-devtools-core/node_modules/vite": { + "version": "7.1.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.12.tgz", + "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "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 + } + } + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz", + "integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz", + "integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", + "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", + "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz", + "integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz", + "integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz", + "integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz", + "integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz", + "integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz", + "integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz", + "integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz", + "integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz", + "integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", + "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz", + "integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz", + "integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz", + "integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", + "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tanstack/router-devtools/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@tanstack/router-devtools/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@tanstack/router-devtools/node_modules/rollup": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", + "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.5", + "@rollup/rollup-android-arm64": "4.52.5", + "@rollup/rollup-darwin-arm64": "4.52.5", + "@rollup/rollup-darwin-x64": "4.52.5", + "@rollup/rollup-freebsd-arm64": "4.52.5", + "@rollup/rollup-freebsd-x64": "4.52.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", + "@rollup/rollup-linux-arm-musleabihf": "4.52.5", + "@rollup/rollup-linux-arm64-gnu": "4.52.5", + "@rollup/rollup-linux-arm64-musl": "4.52.5", + "@rollup/rollup-linux-loong64-gnu": "4.52.5", + "@rollup/rollup-linux-ppc64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-musl": "4.52.5", + "@rollup/rollup-linux-s390x-gnu": "4.52.5", + "@rollup/rollup-linux-x64-gnu": "4.52.5", + "@rollup/rollup-linux-x64-musl": "4.52.5", + "@rollup/rollup-openharmony-arm64": "4.52.5", + "@rollup/rollup-win32-arm64-msvc": "4.52.5", + "@rollup/rollup-win32-ia32-msvc": "4.52.5", + "@rollup/rollup-win32-x64-gnu": "4.52.5", + "@rollup/rollup-win32-x64-msvc": "4.52.5", + "fsevents": "~2.3.2" + } + }, + "node_modules/@tanstack/router-devtools/node_modules/vite": { + "version": "7.1.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.12.tgz", + "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "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 + } + } + }, + "node_modules/@tanstack/router-generator": { + "version": "1.133.29", + "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.133.29.tgz", + "integrity": "sha512-Nngp1i7ch22qqLkjsQwoyos8mawL5bG2GjHg8IMOzFbMR+dVQfh9gSkpkhUbLMv8TMb8Na31tyR0/tDr+E/NCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tanstack/router-core": "1.133.28", + "@tanstack/router-utils": "1.133.19", + "@tanstack/virtual-file-routes": "1.133.19", + "prettier": "^3.5.0", + "recast": "^0.23.11", + "source-map": "^0.7.4", + "tsx": "^4.19.2", + "zod": "^3.24.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/router-generator/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@tanstack/router-plugin": { + "version": "1.133.32", + "resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.133.32.tgz", + "integrity": "sha512-4YtRrGs5nq/sZmwwT/jmS1LiucEevsWjxzTEilHRBtjeMgFbrhnQ7jBHHRPym71C40W/9tEgzcQS3dGq5LC5+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.7", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.27.7", + "@babel/types": "^7.27.7", + "@tanstack/router-core": "1.133.28", + "@tanstack/router-generator": "1.133.29", + "@tanstack/router-utils": "1.133.19", + "@tanstack/virtual-file-routes": "1.133.19", + "babel-dead-code-elimination": "^1.0.10", + "chokidar": "^3.6.0", + "unplugin": "^2.1.2", + "zod": "^3.24.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@rsbuild/core": ">=1.0.2", + "@tanstack/react-router": "^1.133.32", + "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0", + "vite-plugin-solid": "^2.11.10", + "webpack": ">=5.92.0" + }, + "peerDependenciesMeta": { + "@rsbuild/core": { + "optional": true + }, + "@tanstack/react-router": { + "optional": true + }, + "vite": { + "optional": true + }, + "vite-plugin-solid": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/@tanstack/router-plugin/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@tanstack/router-utils": { + "version": "1.133.19", + "resolved": "https://registry.npmjs.org/@tanstack/router-utils/-/router-utils-1.133.19.tgz", + "integrity": "sha512-WEp5D2gPxvlLDRXwD/fV7RXjYtqaqJNXKB/L6OyZEbT+9BG/Ib2d7oG9GSUZNNMGPGYAlhBUOi3xutySsk6rxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/parser": "^7.27.5", + "@babel/preset-typescript": "^7.27.1", + "ansis": "^4.1.0", + "diff": "^8.0.2", + "pathe": "^2.0.3", + "tinyglobby": "^0.2.15" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/store": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.7.7.tgz", + "integrity": "sha512-xa6pTan1bcaqYDS9BDpSiS63qa6EoDkPN9RsRaxHuDdVDNntzq3xNwR5YKTU/V3SkSyC9T4YVOPh2zRQN0nhIQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.13.12", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.12.tgz", + "integrity": "sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/virtual-file-routes": { + "version": "1.133.19", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-file-routes/-/virtual-file-routes-1.133.19.tgz", + "integrity": "sha512-IKwZENsK7owmW1Lm5FhuHegY/SyQ8KqtL/7mTSnzoKJgfzhrrf9qwKB1rmkKkt+svUuy/Zw3uVEpZtUzQruWtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@turf/area": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/area/-/area-7.2.0.tgz", + "integrity": "sha512-zuTTdQ4eoTI9nSSjerIy4QwgvxqwJVciQJ8tOPuMHbXJ9N/dNjI7bU8tasjhxas/Cx3NE9NxVHtNpYHL0FSzoA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^7.2.0", + "@turf/meta": "^7.2.0", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/bbox": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/bbox/-/bbox-7.2.0.tgz", + "integrity": "sha512-wzHEjCXlYZiDludDbXkpBSmv8Zu6tPGLmJ1sXQ6qDwpLE1Ew3mcWqt8AaxfTP5QwDNQa3sf2vvgTEzNbPQkCiA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^7.2.0", + "@turf/meta": "^7.2.0", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-point-in-polygon": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-7.2.0.tgz", + "integrity": "sha512-lvEOjxeXIp+wPXgl9kJA97dqzMfNexjqHou+XHVcfxQgolctoJiRYmcVCWGpiZ9CBf/CJha1KmD1qQoRIsjLaA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^7.2.0", + "@turf/invariant": "^7.2.0", + "@types/geojson": "^7946.0.10", + "point-in-polygon-hao": "^1.1.0", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/centroid": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/centroid/-/centroid-7.2.0.tgz", + "integrity": "sha512-yJqDSw25T7P48au5KjvYqbDVZ7qVnipziVfZ9aSo7P2/jTE7d4BP21w0/XLi3T/9bry/t9PR1GDDDQljN4KfDw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^7.2.0", + "@turf/meta": "^7.2.0", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/helpers": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.2.0.tgz", + "integrity": "sha512-cXo7bKNZoa7aC7ydLmUR02oB3IgDe7MxiPuRz3cCtYQHn+BJ6h1tihmamYDWWUlPHgSNF0i3ATc4WmDECZafKw==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/invariant": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.2.0.tgz", + "integrity": "sha512-kV4u8e7Gkpq+kPbAKNC21CmyrXzlbBgFjO1PhrHPgEdNqXqDawoZ3i6ivE3ULJj2rSesCjduUaC/wyvH/sNr2Q==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^7.2.0", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/meta": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.2.0.tgz", + "integrity": "sha512-igzTdHsQc8TV1RhPuOLVo74Px/hyPrVgVOTgjWQZzt3J9BVseCdpfY/0cJBdlSRI4S/yTmmHl7gAqjhpYH5Yaw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^7.2.0", + "@types/geojson": "^7946.0.10" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@tweenjs/tween.js": { + "version": "25.0.0", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-25.0.0.tgz", + "integrity": "sha512-XKLA6syeBUaPzx4j3qwMqzzq+V4uo72BnlbOjmuljLrRqdsd3qnzvZZoxvMHZ23ndsRS4aufU6JOZYpCbU6T1A==", + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/conventional-commits-parser": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.2.tgz", + "integrity": "sha512-BgT2szDXnVypgpNxOK8aL5SGjUdaQbC++WZNjF1Qge3Og2+zhHj+RWhmehLhYyvQwqAmvezruVfOf8+3m74W+g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/css-mediaquery": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@types/css-mediaquery/-/css-mediaquery-0.1.4.tgz", + "integrity": "sha512-DZyHAz716ZUctpqkUU2COwUoZ4gI6mZK2Q1oIz/fvNS6XHVpKSJgDnE7vRxZUBn9vjJHDVelCVW0dkshKOLFsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-force": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-2.1.7.tgz", + "integrity": "sha512-x5pvWw0HUBrcpMaMOd70ICEL27gOeC9hyhilTc+OP+4tErgEg3w+fZWA475eTrG7gi8BB0TNdfGRprpy09Vo9A==", + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-1.4.5.tgz", + "integrity": "sha512-mLxrC1MSWupOSncXN/HOlWUAAIffAEBaI4+PKy2uMPsKe4FNZlk7qrbTjmzJXITQQqBHivaks4Td18azgqnotA==", + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-2.0.7.tgz", + "integrity": "sha512-RIXlxPdxvX+LAZFv+t78CuYpxYag4zuw9mZc+AwfB8tZpKU90rMEn2il2ADncmeZlb7nER9dDsJpRisA3lRvjA==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-1.1.11.tgz", + "integrity": "sha512-lnQiU7jV+Gyk9oQYk0GGYccuexmQPTp08E0+4BidgFdiJivjEvf+esPSdZqCZ2C7UwTWejWpqetVaU8A+eX3FA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-sankey": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/@types/d3-sankey/-/d3-sankey-0.11.2.tgz", + "integrity": "sha512-U6SrTWUERSlOhnpSrgvMX64WblX1AxX6nEjI2t3mLK2USpQrnbwYYK+AS9SwiE7wgYmOsSSKoSdr8aoKBH0HgQ==", + "license": "MIT", + "dependencies": { + "@types/d3-shape": "^1" + } + }, + "node_modules/@types/d3-sankey/node_modules/@types/d3-path": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.11.tgz", + "integrity": "sha512-4pQMp8ldf7UaB/gR8Fvvy69psNHkTpD/pVw3vmEi8iZAB9EPMBruB1JvHO4BIq9QkUUd2lV1F5YXpMNj7JPBpw==", + "license": "MIT" + }, + "node_modules/@types/d3-sankey/node_modules/@types/d3-shape": { + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.12.tgz", + "integrity": "sha512-8oMzcd4+poSLGgV0R1Q1rOlx/xdmozS4Xab7np0eamFFUYq71AU9pOCJEFnkXW2aI/oXdVYJzw6pssbSut7Z9Q==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "^1" + } + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-2.0.5.tgz", + "integrity": "sha512-71BorcY0yXl12S7lvb01JdaN9TpeUHBDb4RRhSq8U8BEkX/nIk5p7Byho+ZRTsx5nYLMpAbY3qt5EhqFzfGJlw==", + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-1.1.4.tgz", + "integrity": "sha512-JIvy2HjRInE+TXOmIGN5LCmeO0hkFZx5f9FZ7kiN+D+YTcc8pptsiLiuHsvwxwC7VVKmJ2ExHUgNlAiV7vQM9g==", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.3.4.tgz", + "integrity": "sha512-xdDXbpVO74EvadI3UDxjxTdR6QIxm1FKzEA/+F8tL4GWWUg/hgvBqf6chql64U5A9ZUGWo7pEu4eNlyLwbKdhg==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/d3-zoom": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-2.0.7.tgz", + "integrity": "sha512-JWke4E8ZyrKUQ68ESTWSK16fVb0OYnaiJ+WXJRYxKLn4aXU0o4CLYxMWBEiouUfO3TTCoyroOrGPcBG6u1aAxA==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "^2", + "@types/d3-selection": "^2" + } + }, + "node_modules/@types/d3-zoom/node_modules/@types/d3-color": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-2.0.6.tgz", + "integrity": "sha512-tbaFGDmJWHqnenvk3QGSvD3RVwr631BjKRD7Sc7VLRgrdX5mk5hTyoeBL6rXZaeoXzmZwIl1D2HPogEdt1rHBg==", + "license": "MIT" + }, + "node_modules/@types/d3-zoom/node_modules/@types/d3-interpolate": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-2.0.5.tgz", + "integrity": "sha512-UINE41RDaUMbulp+bxQMDnhOi51rh5lA2dG+dWZU0UY/IwQiG/u2x8TfnWYU9+xwGdXsJoAvrBYUEQl0r91atg==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "^2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/geojson-vt": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@types/geojson-vt/-/geojson-vt-3.2.5.tgz", + "integrity": "sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "license": "MIT" + }, + "node_modules/@types/mapbox__point-geometry": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.4.tgz", + "integrity": "sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==", + "license": "MIT" + }, + "node_modules/@types/mapbox__vector-tile": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/mapbox__vector-tile/-/mapbox__vector-tile-1.3.4.tgz", + "integrity": "sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*", + "@types/mapbox__point-geometry": "*", + "@types/pbf": "*" + } + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz", + "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/pbf": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz", + "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==", + "license": "MIT" + }, + "node_modules/@types/prismjs": { + "version": "1.26.5", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", + "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.1.2", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz", + "integrity": "sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==", + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.1.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.3.tgz", + "integrity": "sha512-rJXC08OG0h3W6wDMFxQrZF00Kq6qQvw0djHRdzl3U5DnIERz0MRce3WVc7IS6JYBwtaP/DwYtRRjVlvivNveKg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@types/react-simple-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/react-simple-maps/-/react-simple-maps-3.0.6.tgz", + "integrity": "sha512-hR01RXt6VvsE41FxDd+Bqm1PPGdKbYjCYVtCgh38YeBPt46z3SwmWPWu2L3EdCAP6bd6VYEgztucihRw1C0Klg==", + "license": "MIT", + "dependencies": { + "@types/d3-geo": "^2", + "@types/d3-zoom": "^2", + "@types/geojson": "*", + "@types/react": "*" + } + }, + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/supercluster": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz", + "integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/topojson-client": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@types/topojson-client/-/topojson-client-3.1.5.tgz", + "integrity": "sha512-C79rySTyPxnQNNguTZNI1Ct4D7IXgvyAs3p9HPecnl6mNrJ5+UhvGNYcZfpROYV2lMHI48kJPxwR+F9C6c7nmw==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*", + "@types/topojson-specification": "*" + } + }, + "node_modules/@types/topojson-specification": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/topojson-specification/-/topojson-specification-1.0.5.tgz", + "integrity": "sha512-C7KvcQh+C2nr6Y2Ub4YfgvWvWCgP2nOQMtfhlnwsRL4pYmmwzBS7HclGiS87eQfDOU/DLQpX6GEscviaz4yLIQ==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.1.tgz", + "integrity": "sha512-oUlH4h1ABavI4F0Xnl8/fOtML/eu8nI2A1nYd+f+55XI0BLu+RIqKoCiZKNo6DtqZBEQm5aNKA20G3Z5w3R6GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.31.1", + "@typescript-eslint/type-utils": "8.31.1", + "@typescript-eslint/utils": "8.31.1", + "@typescript-eslint/visitor-keys": "8.31.1", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.31.1.tgz", + "integrity": "sha512-oU/OtYVydhXnumd0BobL9rkJg7wFJ9bFFPmSmB/bf/XWN85hlViji59ko6bSKBXyseT9V8l+CN1nwmlbiN0G7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.31.1", + "@typescript-eslint/types": "8.31.1", + "@typescript-eslint/typescript-estree": "8.31.1", + "@typescript-eslint/visitor-keys": "8.31.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.31.1.tgz", + "integrity": "sha512-BMNLOElPxrtNQMIsFHE+3P0Yf1z0dJqV9zLdDxN/xLlWMlXK/ApEsVEKzpizg9oal8bAT5Sc7+ocal7AC1HCVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.31.1", + "@typescript-eslint/visitor-keys": "8.31.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.31.1.tgz", + "integrity": "sha512-fNaT/m9n0+dpSp8G/iOQ05GoHYXbxw81x+yvr7TArTuZuCA6VVKbqWYVZrV5dVagpDTtj/O8k5HBEE/p/HM5LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.31.1", + "@typescript-eslint/utils": "8.31.1", + "debug": "^4.3.4", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.31.1.tgz", + "integrity": "sha512-SfepaEFUDQYRoA70DD9GtytljBePSj17qPxFHA/h3eg6lPTqGJ5mWOtbXCk1YrVU1cTJRd14nhaXWFu0l2troQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.1.tgz", + "integrity": "sha512-kaA0ueLe2v7KunYOyWYtlf/QhhZb7+qh4Yw6Ni5kgukMIG+iP773tjgBiLWIXYumWCwEq3nLW+TUywEp8uEeag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.31.1", + "@typescript-eslint/visitor-keys": "8.31.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.31.1.tgz", + "integrity": "sha512-2DSI4SNfF5T4oRveQ4nUrSjUqjMND0nLq9rEkz0gfGr3tg0S5KB6DhwR+WZPCjzkZl3cH+4x2ce3EsL50FubjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.31.1", + "@typescript-eslint/types": "8.31.1", + "@typescript-eslint/typescript-estree": "8.31.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.1.tgz", + "integrity": "sha512-I+/rgqOVBn6f0o7NDTmAPWWC6NuqhV174lfYvAm9fUaWeiefLdux9/YI3/nLugEn9L8fcSi0XmpKi/r5u0nmpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.31.1", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript/vfs": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@typescript/vfs/-/vfs-1.6.2.tgz", + "integrity": "sha512-hoBwJwcbKHmvd2QVebiytN1aELvpk9B74B4L1mFm/XT1Q/VOYAWl2vQ9AWRFtQq8zmz6enTpfTV8WRc4ATjW/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.4.1.tgz", + "integrity": "sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.26.10", + "@babel/plugin-transform-react-jsx-self": "^7.25.9", + "@babel/plugin-transform-react-jsx-source": "^7.25.9", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" + } + }, + "node_modules/abs-svg-path": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/abs-svg-path/-/abs-svg-path-0.1.1.tgz", + "integrity": "sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==", + "license": "MIT" + }, + "node_modules/accessor-fn": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/accessor-fn/-/accessor-fn-1.5.3.tgz", + "integrity": "sha512-rkAofCwe/FvYFUlMB0v0gWmhqtfAtV1IUkdPbfhTUyYniu5LrC0A0UJkTH0Jv3S8SvwkmfuAlY+mQIJATdocMA==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.2.0.tgz", + "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/array-bounds": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-bounds/-/array-bounds-1.0.1.tgz", + "integrity": "sha512-8wdW3ZGk6UjMPJx/glyEt0sLzzwAE1bhToPsO1W2pbpR2gULyxe3BjSiuJFheP50T/GgODVPz2fuMUmIywt8cQ==", + "license": "MIT" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-normalize": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array-normalize/-/array-normalize-1.1.4.tgz", + "integrity": "sha512-fCp0wKFLjvSPmCn4F5Tiw4M3lpMZoHlCjfcs7nNzuj3vqQQ1/a8cgB9DXcpDSn18c+coLnaW7rqfcYCvKbyJXg==", + "license": "MIT", + "dependencies": { + "array-bounds": "^1.0.0" + } + }, + "node_modules/array-range": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-range/-/array-range-1.0.1.tgz", + "integrity": "sha512-shdaI1zT3CVNL2hnx9c0JMc0ZogGaxDs5e85akgHWKYa0yVbIyp06Ind3dVkTj/uuFrzaHBOyqFzo+VV6aXgtA==", + "license": "MIT" + }, + "node_modules/array-rearrange": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/array-rearrange/-/array-rearrange-2.2.2.tgz", + "integrity": "sha512-UfobP5N12Qm4Qu4fwLDIi2v6+wZsSf6snYSxAMeKhrh37YGnNWZPRmVEKc/2wfms53TLQnzfpG8wCx2Y/6NG1w==", + "license": "MIT" + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.19", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", + "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001599", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-dead-code-elimination": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/babel-dead-code-elimination/-/babel-dead-code-elimination-1.0.10.tgz", + "integrity": "sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.7", + "@babel/parser": "^7.23.6", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.20", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.20.tgz", + "integrity": "sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/binary-search-bounds": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/binary-search-bounds/-/binary-search-bounds-2.0.5.tgz", + "integrity": "sha512-H0ea4Fd3lS1+sTEB2TgcLoK21lLhwEJzlQv3IN47pJS976Gx4zoWe0ak3q+uYh60ppQxg9F16Ri4tS1sfD4+jA==", + "license": "MIT" + }, + "node_modules/bit-twiddle": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bit-twiddle/-/bit-twiddle-1.0.2.tgz", + "integrity": "sha512-B9UhK0DKFZhoTFcfvAzhqsjStvGJp9vYWf3+6SNTtdSQnvIgfkHbgHrg/e4+TH71N2GDu8tpmCVoyfrL1d7ntA==", + "license": "MIT" + }, + "node_modules/bitmap-sdf": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/bitmap-sdf/-/bitmap-sdf-1.0.4.tgz", + "integrity": "sha512-1G3U4n5JE6RAiALMxu0p1XmeZkTeCwGKykzsLTCqVzfSDaN6S7fKnkIkfejogz+iwqBWc0UYAIKnKHNN7pSfDg==", + "license": "MIT" + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz", + "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.19", + "caniuse-lite": "^1.0.30001751", + "electron-to-chromium": "^1.5.238", + "node-releases": "^2.0.26", + "update-browserslist-db": "^1.1.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001751", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", + "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/canvas-fit": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/canvas-fit/-/canvas-fit-1.5.0.tgz", + "integrity": "sha512-onIcjRpz69/Hx5bB5HGbYKUF2uC6QT6Gp+pfpGm3A7mPfcluSLV5v4Zu+oflDUwLdUw0rLIBhUbi0v8hM4FJQQ==", + "license": "MIT", + "dependencies": { + "element-size": "^1.1.1" + } + }, + "node_modules/catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true, + "license": "MIT" + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/clamp": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/clamp/-/clamp-1.0.1.tgz", + "integrity": "sha512-kgMuFyE78OC6Dyu3Dy7vcx4uy97EIbVxJB/B0eJ3bUNAkwdNcxYzgKltnyADiYwsR7SEqkkUPsEUT//OVS6XMA==", + "license": "MIT" + }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-alpha": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/color-alpha/-/color-alpha-1.0.4.tgz", + "integrity": "sha512-lr8/t5NPozTSqli+duAN+x+no/2WaKTeWvxhHGN+aXT6AJ8vPlzLa7UriyjWak0pSC2jHol9JgjBYnnHsGha9A==", + "license": "MIT", + "dependencies": { + "color-parse": "^1.3.8" + } + }, + "node_modules/color-alpha/node_modules/color-parse": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/color-parse/-/color-parse-1.4.3.tgz", + "integrity": "sha512-BADfVl/FHkQkyo8sRBwMYBqemqsgnu7JZAwUgvBvuwwuNUZAhSvLTbsEErS5bQXzOjDR0dWzJ4vXN2Q+QoPx0A==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/color-id/-/color-id-1.1.0.tgz", + "integrity": "sha512-2iRtAn6dC/6/G7bBIo0uupVrIne1NsQJvJxZOBCzQOfk7jRq97feaDZ3RdzuHakRXXnHGNwglto3pqtRx1sX0g==", + "license": "MIT", + "dependencies": { + "clamp": "^1.0.1" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/color-normalize": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/color-normalize/-/color-normalize-1.5.0.tgz", + "integrity": "sha512-rUT/HDXMr6RFffrR53oX3HGWkDOP9goSAQGBkUaAYKjOE2JxozccdGyufageWDlInRAjm/jYPrf/Y38oa+7obw==", + "license": "MIT", + "dependencies": { + "clamp": "^1.0.1", + "color-rgba": "^2.1.1", + "dtype": "^2.0.0" + } + }, + "node_modules/color-normalize/node_modules/color-parse": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/color-parse/-/color-parse-1.4.3.tgz", + "integrity": "sha512-BADfVl/FHkQkyo8sRBwMYBqemqsgnu7JZAwUgvBvuwwuNUZAhSvLTbsEErS5bQXzOjDR0dWzJ4vXN2Q+QoPx0A==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0" + } + }, + "node_modules/color-normalize/node_modules/color-rgba": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/color-rgba/-/color-rgba-2.4.0.tgz", + "integrity": "sha512-Nti4qbzr/z2LbUWySr7H9dk3Rl7gZt7ihHAxlgT4Ho90EXWkjtkL1avTleu9yeGuqrt/chxTB6GKK8nZZ6V0+Q==", + "license": "MIT", + "dependencies": { + "color-parse": "^1.4.2", + "color-space": "^2.0.0" + } + }, + "node_modules/color-parse": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/color-parse/-/color-parse-2.0.0.tgz", + "integrity": "sha512-g2Z+QnWsdHLppAbrpcFWo629kLOnOPtpxYV69GCqm92gqSgyXbzlfyN3MXs0412fPBkFmiuS+rXposgBgBa6Kg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0" + } + }, + "node_modules/color-rgba": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color-rgba/-/color-rgba-3.0.0.tgz", + "integrity": "sha512-PPwZYkEY3M2THEHHV6Y95sGUie77S7X8v+h1r6LSAPF3/LL2xJ8duUXSrkic31Nzc4odPwHgUbiX/XuTYzQHQg==", + "license": "MIT", + "dependencies": { + "color-parse": "^2.0.0", + "color-space": "^2.0.0" + } + }, + "node_modules/color-space": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/color-space/-/color-space-2.3.2.tgz", + "integrity": "sha512-BcKnbOEsOarCwyoLstcoEztwT0IJxqqQkNwDuA3a65sICvvHL2yoeV13psoDFh5IuiOMnIOKdQDwB4Mk3BypiA==", + "license": "Unlicense" + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/commitizen": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.3.0.tgz", + "integrity": "sha512-H0iNtClNEhT0fotHvGV3E9tDejDeS04sN1veIebsKYGMuGscFaswRoYJKmT3eW85eIJAs0F28bG2+a/9wCOfPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cachedir": "2.3.0", + "cz-conventional-changelog": "3.3.0", + "dedent": "0.7.0", + "detect-indent": "6.1.0", + "find-node-modules": "^2.1.2", + "find-root": "1.1.0", + "fs-extra": "9.1.0", + "glob": "7.2.3", + "inquirer": "8.2.5", + "is-utf8": "^0.2.1", + "lodash": "4.17.21", + "minimist": "1.2.7", + "strip-bom": "4.0.0", + "strip-json-comments": "3.1.1" + }, + "bin": { + "commitizen": "bin/commitizen", + "cz": "bin/git-cz", + "git-cz": "bin/git-cz" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/conventional-commit-types": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz", + "integrity": "sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==", + "dev": true, + "license": "ISC" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie-es": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-2.0.0.tgz", + "integrity": "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==", + "license": "MIT" + }, + "node_modules/core-js-compat": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.46.0.tgz", + "integrity": "sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.26.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.2.0.tgz", + "integrity": "sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "jiti": "^2.6.1" + }, + "engines": { + "node": ">=v18" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=9", + "typescript": ">=5" + } + }, + "node_modules/country-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/country-regex/-/country-regex-1.1.0.tgz", + "integrity": "sha512-iSPlClZP8vX7MC3/u6s3lrDuoQyhQukh5LyABJ3hvfzbQ3Yyayd4fp04zjLnfi267B/B2FkumcWWgrbban7sSA==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/css-font": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-font/-/css-font-1.2.0.tgz", + "integrity": "sha512-V4U4Wps4dPDACJ4WpgofJ2RT5Yqwe1lEH6wlOOaIxMi0gTjdIijsc5FmxQlZ7ZZyKQkkutqqvULOp07l9c7ssA==", + "license": "MIT", + "dependencies": { + "css-font-size-keywords": "^1.0.0", + "css-font-stretch-keywords": "^1.0.1", + "css-font-style-keywords": "^1.0.1", + "css-font-weight-keywords": "^1.0.0", + "css-global-keywords": "^1.0.1", + "css-system-font-keywords": "^1.0.0", + "pick-by-alias": "^1.2.0", + "string-split-by": "^1.0.0", + "unquote": "^1.1.0" + } + }, + "node_modules/css-font-size-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-font-size-keywords/-/css-font-size-keywords-1.0.0.tgz", + "integrity": "sha512-Q+svMDbMlelgCfH/RVDKtTDaf5021O486ZThQPIpahnIjUkMUslC+WuOQSWTgGSrNCH08Y7tYNEmmy0hkfMI8Q==", + "license": "MIT" + }, + "node_modules/css-font-stretch-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-font-stretch-keywords/-/css-font-stretch-keywords-1.0.1.tgz", + "integrity": "sha512-KmugPO2BNqoyp9zmBIUGwt58UQSfyk1X5DbOlkb2pckDXFSAfjsD5wenb88fNrD6fvS+vu90a/tsPpb9vb0SLg==", + "license": "MIT" + }, + "node_modules/css-font-style-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-font-style-keywords/-/css-font-style-keywords-1.0.1.tgz", + "integrity": "sha512-0Fn0aTpcDktnR1RzaBYorIxQily85M2KXRpzmxQPgh8pxUN9Fcn00I8u9I3grNr1QXVgCl9T5Imx0ZwKU973Vg==", + "license": "MIT" + }, + "node_modules/css-font-weight-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-font-weight-keywords/-/css-font-weight-keywords-1.0.0.tgz", + "integrity": "sha512-5So8/NH+oDD+EzsnF4iaG4ZFHQ3vaViePkL1ZbZ5iC/KrsCY+WHq/lvOgrtmuOQ9pBBZ1ADGpaf+A4lj1Z9eYA==", + "license": "MIT" + }, + "node_modules/css-global-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-global-keywords/-/css-global-keywords-1.0.1.tgz", + "integrity": "sha512-X1xgQhkZ9n94WDwntqst5D/FKkmiU0GlJSFZSV3kLvyJ1WC5VeyoXDOuleUD+SIuH9C7W05is++0Woh0CGfKjQ==", + "license": "MIT" + }, + "node_modules/css-mediaquery": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/css-mediaquery/-/css-mediaquery-0.1.2.tgz", + "integrity": "sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q==", + "dev": true, + "license": "BSD" + }, + "node_modules/css-system-font-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-system-font-keywords/-/css-system-font-keywords-1.0.0.tgz", + "integrity": "sha512-1umTtVd/fXS25ftfjB71eASCrYhilmEsvDEI6wG/QplnmlfmVM5HkZ/ZX46DT5K3eblFPgLUHt5BRCb0YXkSFA==", + "license": "MIT" + }, + "node_modules/csscolorparser": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz", + "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==", + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/cz-conventional-changelog": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz", + "integrity": "sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.4.1", + "commitizen": "^4.0.3", + "conventional-commit-types": "^3.0.0", + "lodash.map": "^4.5.1", + "longest": "^2.0.1", + "word-wrap": "^1.0.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@commitlint/load": ">6.1.1" + } + }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-collection": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", + "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz", + "integrity": "sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-drag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-2.0.0.tgz", + "integrity": "sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-dispatch": "1 - 2", + "d3-selection": "2" + } + }, + "node_modules/d3-ease": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz", + "integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-force": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-2.1.1.tgz", + "integrity": "sha512-nAuHEzBqMvpFVMf9OX75d00OxvOXdxY+xECIXjW6Gv8BRrXu6gAWbv/9XKrvfJ5i5DCokDW7RYE50LRoK092ew==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-dispatch": "1 - 2", + "d3-quadtree": "1 - 2", + "d3-timer": "1 - 2" + } + }, + "node_modules/d3-format": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", + "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-geo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-2.0.2.tgz", + "integrity": "sha512-8pM1WGMLGFuhq9S+FpPURxic+gKzjluCD/CHTuUF3mXMeiCo0i6R0tO1s4+GArRFde96SLcW/kOFRjoAosPsFA==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "^2.5.0" + } + }, + "node_modules/d3-geo-projection": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-2.9.0.tgz", + "integrity": "sha512-ZULvK/zBn87of5rWAfFMc9mJOipeSo57O+BBitsKIXmU4rTVAnX1kSsJkE0R+TxY8pGNoM1nbyRRE7GYHhdOEQ==", + "license": "BSD-3-Clause", + "dependencies": { + "commander": "2", + "d3-array": "1", + "d3-geo": "^1.12.0", + "resolve": "^1.1.10" + }, + "bin": { + "geo2svg": "bin/geo2svg", + "geograticule": "bin/geograticule", + "geoproject": "bin/geoproject", + "geoquantize": "bin/geoquantize", + "geostitch": "bin/geostitch" + } + }, + "node_modules/d3-geo-projection/node_modules/d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-geo-projection/node_modules/d3-geo": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz", + "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1" + } + }, + "node_modules/d3-geo-voronoi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/d3-geo-voronoi/-/d3-geo-voronoi-2.1.0.tgz", + "integrity": "sha512-kqE4yYuOjPbKdBXG0xztCacPwkVSK2REF1opSNrnqqtXJmNcM++UbwQ8SxvwP6IQTj9RvIjjK4qeiVsEfj0Z2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-delaunay": "6", + "d3-geo": "3", + "d3-tricontour": "1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo-voronoi/node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo-voronoi/node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz", + "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-octree": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-octree/-/d3-octree-1.1.0.tgz", + "integrity": "sha512-F8gPlqpP+HwRPMO/8uOu5wjH110+6q4cgJvgJT6vlpy3BEaDIKlTZrgHKZSp/i1InRpVfh4puY/kvL6MxK930A==", + "license": "MIT" + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-2.0.0.tgz", + "integrity": "sha512-b0Ed2t1UUalJpc3qXzKi+cPGxeXRr4KU9YSlocN74aTzp6R/Ud43t79yLLqxHRWZfsvWXmbDWPpoENK1K539xw==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale/node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz", + "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", + "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-time-format": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", + "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-time": "1 - 2" + } + }, + "node_modules/d3-timer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz", + "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-transition": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-2.0.0.tgz", + "integrity": "sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-color": "1 - 2", + "d3-dispatch": "1 - 2", + "d3-ease": "1 - 2", + "d3-interpolate": "1 - 2", + "d3-timer": "1 - 2" + }, + "peerDependencies": { + "d3-selection": "2" + } + }, + "node_modules/d3-transition/node_modules/d3-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", + "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-transition/node_modules/d3-interpolate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", + "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-color": "1 - 2" + } + }, + "node_modules/d3-tricontour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-tricontour/-/d3-tricontour-1.1.0.tgz", + "integrity": "sha512-G7gHKj89n2owmkGb6WX6ixcnQ0Kf/0wpa9VIh9DGdbHu8wdrlaHU4ir3/bFNERl8N8nn4G7e7qbtBG8N9caihQ==", + "license": "ISC", + "dependencies": { + "d3-delaunay": "6", + "d3-scale": "4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-zoom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-2.0.0.tgz", + "integrity": "sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-dispatch": "1 - 2", + "d3-drag": "2", + "d3-interpolate": "1 - 2", + "d3-selection": "2", + "d3-transition": "2" + } + }, + "node_modules/d3-zoom/node_modules/d3-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", + "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-zoom/node_modules/d3-interpolate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", + "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-color": "1 - 2" + } + }, + "node_modules/data-bind-mapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/data-bind-mapper/-/data-bind-mapper-1.0.3.tgz", + "integrity": "sha512-QmU3lyEnbENQPo0M1F9BMu4s6cqNNp8iJA+b/HP2sSb7pf3dxwF3+EP1eO69rwBfH9kFJ1apmzrtogAmVt2/Xw==", + "license": "MIT", + "dependencies": { + "accessor-fn": "1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/defined": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", + "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-kerning": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-kerning/-/detect-kerning-2.1.2.tgz", + "integrity": "sha512-I3JIbrnKPAntNLl1I6TpSQQdQ4AutYzv/sKMFKbepawV/hlH0GmYKhUoOEMd4xqaUHT+Bm0f4127lh5qs1m1tw==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", + "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/draw-svg-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/draw-svg-path/-/draw-svg-path-1.0.0.tgz", + "integrity": "sha512-P8j3IHxcgRMcY6sDzr0QvJDLzBnJJqpTG33UZ2Pvp8rw0apCHhJCWqYprqrXjrgHnJ6tuhP1iTJSAodPDHxwkg==", + "license": "MIT", + "dependencies": { + "abs-svg-path": "~0.1.1", + "normalize-svg-path": "~0.1.0" + } + }, + "node_modules/dtype": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dtype/-/dtype-2.0.0.tgz", + "integrity": "sha512-s2YVcLKdFGS0hpFqJaTwscsyt0E8nNFdmo73Ocd81xNPj4URI4rj6D60A+vFMIw7BXWlb4yRkEwfBqcZzPGiZg==", + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/dup": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dup/-/dup-1.0.0.tgz", + "integrity": "sha512-Bz5jxMMC0wgp23Zm15ip1x8IhYRqJvF3nFC0UInJUDkN1z4uNPk9jTnfCUJXbOGiQ1JbXLQsiV41Fb+HXcj5BA==", + "license": "MIT" + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/duplexify/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/duplexify/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexify/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/duplexify/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/earcut": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.2.tgz", + "integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==", + "license": "ISC" + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.241", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.241.tgz", + "integrity": "sha512-ILMvKX/ZV5WIJzzdtuHg8xquk2y0BOGlFOxBVwTpbiXqWIH0hamG45ddU4R3PQ0gYu+xgo0vdHXHli9sHIGb4w==", + "dev": true, + "license": "ISC" + }, + "node_modules/element-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/element-size/-/element-size-1.1.1.tgz", + "integrity": "sha512-eaN+GMOq/Q+BIWy0ybsgpcYImjGIdNLyjLFJU4XsLHXYQao5jCNb36GyN6C2qwmDDYSfIBmKpPpr4VnBdLCsPQ==", + "license": "MIT" + }, + "node_modules/elementary-circuits-directed-graph": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/elementary-circuits-directed-graph/-/elementary-circuits-directed-graph-1.3.1.tgz", + "integrity": "sha512-ZEiB5qkn2adYmpXGnJKkxT8uJHlW/mxmBpmeqawEHzPxh9HkLD4/1mFYX5l0On+f6rcPIt8/EWlRU2Vo3fX6dQ==", + "license": "MIT", + "dependencies": { + "strongly-connected-components": "^1.0.1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "license": "ISC", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/esbuild": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", + "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.11", + "@esbuild/android-arm": "0.25.11", + "@esbuild/android-arm64": "0.25.11", + "@esbuild/android-x64": "0.25.11", + "@esbuild/darwin-arm64": "0.25.11", + "@esbuild/darwin-x64": "0.25.11", + "@esbuild/freebsd-arm64": "0.25.11", + "@esbuild/freebsd-x64": "0.25.11", + "@esbuild/linux-arm": "0.25.11", + "@esbuild/linux-arm64": "0.25.11", + "@esbuild/linux-ia32": "0.25.11", + "@esbuild/linux-loong64": "0.25.11", + "@esbuild/linux-mips64el": "0.25.11", + "@esbuild/linux-ppc64": "0.25.11", + "@esbuild/linux-riscv64": "0.25.11", + "@esbuild/linux-s390x": "0.25.11", + "@esbuild/linux-x64": "0.25.11", + "@esbuild/netbsd-arm64": "0.25.11", + "@esbuild/netbsd-x64": "0.25.11", + "@esbuild/openbsd-arm64": "0.25.11", + "@esbuild/openbsd-x64": "0.25.11", + "@esbuild/openharmony-arm64": "0.25.11", + "@esbuild/sunos-x64": "0.25.11", + "@esbuild/win32-arm64": "0.25.11", + "@esbuild/win32-ia32": "0.25.11", + "@esbuild/win32-x64": "0.25.11" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "license": "MIT", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint": { + "version": "9.25.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz", + "integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.13.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.25.1", + "@eslint/plugin-kit": "^0.2.8", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.2.tgz", + "integrity": "sha512-Epgp/EofAUeEpIdZkW60MHKvPyru1ruQJxPL+WIycnaPApuseK0Zpkrh/FwL9oIpQvIhJwV7ptOy0DWUjTlCiA==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.6.tgz", + "integrity": "sha512-mUcf7QG2Tjk7H055Jk0lGBjbgDnfrvqjhXh9t2xLMSCjZVcw9Rb1V6sVNXO0th3jgeO7zllWPTNRil3JW94TnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.11.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz", + "integrity": "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true, + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "license": "ISC", + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/falafel": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.2.5.tgz", + "integrity": "sha512-HuC1qF9iTnHDnML9YZAdCDQwT0yKl/U55K4XSUXqGAA2GLoafFgWRqdAbhWJxXaYD4pyoVxAJ8wH670jMpI9DQ==", + "license": "MIT", + "dependencies": { + "acorn": "^7.1.1", + "isarray": "^2.0.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/falafel/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-equals": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.3.2.tgz", + "integrity": "sha512-6rxyATwPCkaFIL3JLqw8qXqMpIZ942pTX/tbQFkRsDGblS8tNGtlUauA/+mt6RUfqn/4MoEr+WDkYoIQbibWuQ==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-isnumeric": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/fast-isnumeric/-/fast-isnumeric-1.1.4.tgz", + "integrity": "sha512-1mM8qOr2LYz8zGaUdmiqRDiuue00Dxjgcb1NQR7TnhLVh6sQyngP9xvLo7Sl7LZpP/sk5eb+bcyWXw530NTBZw==", + "license": "MIT", + "dependencies": { + "is-string-blank": "^1.0.1" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-node-modules": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz", + "integrity": "sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "findup-sync": "^4.0.0", + "merge": "^2.1.1" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true, + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/flatten-vertex-data": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/flatten-vertex-data/-/flatten-vertex-data-1.0.2.tgz", + "integrity": "sha512-BvCBFK2NZqerFTdMDgqfHBwxYWnxeCkwONsw6PvBMcUXqo8U/KDWwmXhqx1x2kLIg7DqIsJfOaJFOmlua3Lxuw==", + "license": "MIT", + "dependencies": { + "dtype": "^2.0.0" + } + }, + "node_modules/float-tooltip": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/float-tooltip/-/float-tooltip-1.7.5.tgz", + "integrity": "sha512-/kXzuDnnBqyyWyhDMH7+PfP8J/oXiAavGzcRxASOMRHFuReDtofizLLJsf7nnDLAfEaMW4pVWaXrAjtnglpEkg==", + "license": "MIT", + "dependencies": { + "d3-selection": "2 - 3", + "kapsule": "^1.16", + "preact": "10" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/font-atlas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/font-atlas/-/font-atlas-2.1.0.tgz", + "integrity": "sha512-kP3AmvX+HJpW4w3d+PiPR2X6E1yvsBXt2yhuCw+yReO9F1WYhvZwx3c95DGZGwg9xYzDGrgJYa885xmVA+28Cg==", + "license": "MIT", + "dependencies": { + "css-font": "^1.0.0" + } + }, + "node_modules/font-measure": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/font-measure/-/font-measure-1.2.2.tgz", + "integrity": "sha512-mRLEpdrWzKe9hbfaF3Qpr06TAjquuBVP5cHy4b3hyeNdjc9i0PO6HniGsX5vjL5OWv7+Bd++NiooNpT/s8BvIA==", + "license": "MIT", + "dependencies": { + "css-font": "^1.2.0" + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/frame-ticker": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/frame-ticker/-/frame-ticker-1.0.3.tgz", + "integrity": "sha512-E0X2u2JIvbEMrqEg5+4BpTqaD22OwojJI63K7MdKHdncjtAhGRbCR8nJCr2vwEt9NWBPCPcu70X9smPviEBy8Q==", + "license": "MIT", + "dependencies": { + "simplesignal": "^2.1.6" + } + }, + "node_modules/framer-motion": { + "version": "12.23.24", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.24.tgz", + "integrity": "sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.23.23", + "motion-utils": "^12.23.6", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/from2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/from2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/from2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/from2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/geojson-vt": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz", + "integrity": "sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==", + "license": "ISC" + }, + "node_modules/get-canvas-context": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-canvas-context/-/get-canvas-context-1.0.2.tgz", + "integrity": "sha512-LnpfLf/TNzr9zVOGiIY6aKCz8EKuXmlYNV7CM2pUjBa/B+c2I15tS7KLySep75+FuerJdmArvJLcsAXWEy2H0A==", + "license": "MIT" + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "dev": true, + "license": "ISC" + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/gl-mat4": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gl-mat4/-/gl-mat4-1.2.0.tgz", + "integrity": "sha512-sT5C0pwB1/e9G9AvAoLsoaJtbMGjfd/jfxo8jMCKqYYEnjZuFvqV5rehqar0538EmssjdDeiEWnKyBSTw7quoA==", + "license": "Zlib" + }, + "node_modules/gl-matrix": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.4.tgz", + "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==", + "license": "MIT" + }, + "node_modules/gl-text": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/gl-text/-/gl-text-1.4.0.tgz", + "integrity": "sha512-o47+XBqLCj1efmuNyCHt7/UEJmB9l66ql7pnobD6p+sgmBUdzfMZXIF0zD2+KRfpd99DJN+QXdvTFAGCKCVSmQ==", + "license": "MIT", + "dependencies": { + "bit-twiddle": "^1.0.2", + "color-normalize": "^1.5.0", + "css-font": "^1.2.0", + "detect-kerning": "^2.1.2", + "es6-weak-map": "^2.0.3", + "flatten-vertex-data": "^1.0.2", + "font-atlas": "^2.1.0", + "font-measure": "^1.2.2", + "gl-util": "^3.1.2", + "is-plain-obj": "^1.1.0", + "object-assign": "^4.1.1", + "parse-rect": "^1.2.0", + "parse-unit": "^1.0.1", + "pick-by-alias": "^1.2.0", + "regl": "^2.0.0", + "to-px": "^1.0.1", + "typedarray-pool": "^1.1.0" + } + }, + "node_modules/gl-util": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/gl-util/-/gl-util-3.1.3.tgz", + "integrity": "sha512-dvRTggw5MSkJnCbh74jZzSoTOGnVYK+Bt+Ckqm39CVcl6+zSsxqWk4lr5NKhkqXHL6qvZAU9h17ZF8mIskY9mA==", + "license": "MIT", + "dependencies": { + "is-browser": "^2.0.1", + "is-firefox": "^1.0.3", + "is-plain-obj": "^1.1.0", + "number-is-integer": "^1.0.1", + "object-assign": "^4.1.0", + "pick-by-alias": "^1.2.0", + "weak-map": "^1.0.5" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz", + "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globe.gl": { + "version": "2.34.6", + "resolved": "https://registry.npmjs.org/globe.gl/-/globe.gl-2.34.6.tgz", + "integrity": "sha512-2abKObOPAHkJhvTKgJ0AgzAbyAVgA8Dzv2Axvs8bifQobr1+NVuurg94nqrEibXnrooPG8lbgcQhsGNtMjyygQ==", + "license": "MIT", + "dependencies": { + "@tweenjs/tween.js": "18 - 25", + "accessor-fn": "1", + "kapsule": "^1.16", + "three": ">=0.154 <1", + "three-globe": "^2.39", + "three-render-objects": "^1.31" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, + "node_modules/glsl-inject-defines": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/glsl-inject-defines/-/glsl-inject-defines-1.0.3.tgz", + "integrity": "sha512-W49jIhuDtF6w+7wCMcClk27a2hq8znvHtlGnrYkSWEr8tHe9eA2dcnohlcAmxLYBSpSSdzOkRdyPTrx9fw49+A==", + "license": "MIT", + "dependencies": { + "glsl-token-inject-block": "^1.0.0", + "glsl-token-string": "^1.0.1", + "glsl-tokenizer": "^2.0.2" + } + }, + "node_modules/glsl-resolve": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/glsl-resolve/-/glsl-resolve-0.0.1.tgz", + "integrity": "sha512-xxFNsfnhZTK9NBhzJjSBGX6IOqYpvBHxxmo+4vapiljyGNCY0Bekzn0firQkQrazK59c1hYxMDxYS8MDlhw4gA==", + "license": "MIT", + "dependencies": { + "resolve": "^0.6.1", + "xtend": "^2.1.2" + } + }, + "node_modules/glsl-resolve/node_modules/resolve": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.6.3.tgz", + "integrity": "sha512-UHBY3viPlJKf85YijDUcikKX6tmF4SokIDp518ZDVT92JNDcG5uKIthaT/owt3Sar0lwtOafsQuwrg22/v2Dwg==", + "license": "MIT" + }, + "node_modules/glsl-resolve/node_modules/xtend": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.2.0.tgz", + "integrity": "sha512-SLt5uylT+4aoXxXuwtQp5ZnMMzhDb1Xkg4pEqc00WUJCQifPfV9Ub1VrNhp9kXkrjZD2I2Hl8WnjP37jzZLPZw==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/glsl-token-assignments": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/glsl-token-assignments/-/glsl-token-assignments-2.0.2.tgz", + "integrity": "sha512-OwXrxixCyHzzA0U2g4btSNAyB2Dx8XrztY5aVUCjRSh4/D0WoJn8Qdps7Xub3sz6zE73W3szLrmWtQ7QMpeHEQ==", + "license": "MIT" + }, + "node_modules/glsl-token-defines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/glsl-token-defines/-/glsl-token-defines-1.0.0.tgz", + "integrity": "sha512-Vb5QMVeLjmOwvvOJuPNg3vnRlffscq2/qvIuTpMzuO/7s5kT+63iL6Dfo2FYLWbzuiycWpbC0/KV0biqFwHxaQ==", + "license": "MIT", + "dependencies": { + "glsl-tokenizer": "^2.0.0" + } + }, + "node_modules/glsl-token-depth": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/glsl-token-depth/-/glsl-token-depth-1.1.2.tgz", + "integrity": "sha512-eQnIBLc7vFf8axF9aoi/xW37LSWd2hCQr/3sZui8aBJnksq9C7zMeUYHVJWMhFzXrBU7fgIqni4EhXVW4/krpg==", + "license": "MIT" + }, + "node_modules/glsl-token-descope": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glsl-token-descope/-/glsl-token-descope-1.0.2.tgz", + "integrity": "sha512-kS2PTWkvi/YOeicVjXGgX5j7+8N7e56srNDEHDTVZ1dcESmbmpmgrnpjPcjxJjMxh56mSXYoFdZqb90gXkGjQw==", + "license": "MIT", + "dependencies": { + "glsl-token-assignments": "^2.0.0", + "glsl-token-depth": "^1.1.0", + "glsl-token-properties": "^1.0.0", + "glsl-token-scope": "^1.1.0" + } + }, + "node_modules/glsl-token-inject-block": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/glsl-token-inject-block/-/glsl-token-inject-block-1.1.0.tgz", + "integrity": "sha512-q/m+ukdUBuHCOtLhSr0uFb/qYQr4/oKrPSdIK2C4TD+qLaJvqM9wfXIF/OOBjuSA3pUoYHurVRNao6LTVVUPWA==", + "license": "MIT" + }, + "node_modules/glsl-token-properties": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/glsl-token-properties/-/glsl-token-properties-1.0.1.tgz", + "integrity": "sha512-dSeW1cOIzbuUoYH0y+nxzwK9S9O3wsjttkq5ij9ZGw0OS41BirKJzzH48VLm8qLg+au6b0sINxGC0IrGwtQUcA==", + "license": "MIT" + }, + "node_modules/glsl-token-scope": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/glsl-token-scope/-/glsl-token-scope-1.1.2.tgz", + "integrity": "sha512-YKyOMk1B/tz9BwYUdfDoHvMIYTGtVv2vbDSLh94PT4+f87z21FVdou1KNKgF+nECBTo0fJ20dpm0B1vZB1Q03A==", + "license": "MIT" + }, + "node_modules/glsl-token-string": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/glsl-token-string/-/glsl-token-string-1.0.1.tgz", + "integrity": "sha512-1mtQ47Uxd47wrovl+T6RshKGkRRCYWhnELmkEcUAPALWGTFe2XZpH3r45XAwL2B6v+l0KNsCnoaZCSnhzKEksg==", + "license": "MIT" + }, + "node_modules/glsl-token-whitespace-trim": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/glsl-token-whitespace-trim/-/glsl-token-whitespace-trim-1.0.0.tgz", + "integrity": "sha512-ZJtsPut/aDaUdLUNtmBYhaCmhIjpKNg7IgZSfX5wFReMc2vnj8zok+gB/3Quqs0TsBSX/fGnqUUYZDqyuc2xLQ==", + "license": "MIT" + }, + "node_modules/glsl-tokenizer": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/glsl-tokenizer/-/glsl-tokenizer-2.1.5.tgz", + "integrity": "sha512-XSZEJ/i4dmz3Pmbnpsy3cKh7cotvFlBiZnDOwnj/05EwNp2XrhQ4XKJxT7/pDt4kp4YcpRSKz8eTV7S+mwV6MA==", + "license": "MIT", + "dependencies": { + "through2": "^0.6.3" + } + }, + "node_modules/glsl-tokenizer/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT" + }, + "node_modules/glsl-tokenizer/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/glsl-tokenizer/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "license": "MIT" + }, + "node_modules/glsl-tokenizer/node_modules/through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==", + "license": "MIT", + "dependencies": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, + "node_modules/glslify": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glslify/-/glslify-7.1.1.tgz", + "integrity": "sha512-bud98CJ6kGZcP9Yxcsi7Iz647wuDz3oN+IZsjCRi5X1PI7t/xPKeL0mOwXJjo+CRZMqvq0CkSJiywCcY7kVYog==", + "license": "MIT", + "dependencies": { + "bl": "^2.2.1", + "concat-stream": "^1.5.2", + "duplexify": "^3.4.5", + "falafel": "^2.1.0", + "from2": "^2.3.0", + "glsl-resolve": "0.0.1", + "glsl-token-whitespace-trim": "^1.0.0", + "glslify-bundle": "^5.0.0", + "glslify-deps": "^1.2.5", + "minimist": "^1.2.5", + "resolve": "^1.1.5", + "stack-trace": "0.0.9", + "static-eval": "^2.0.5", + "through2": "^2.0.1", + "xtend": "^4.0.0" + }, + "bin": { + "glslify": "bin.js" + } + }, + "node_modules/glslify-bundle": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glslify-bundle/-/glslify-bundle-5.1.1.tgz", + "integrity": "sha512-plaAOQPv62M1r3OsWf2UbjN0hUYAB7Aph5bfH58VxJZJhloRNbxOL9tl/7H71K7OLJoSJ2ZqWOKk3ttQ6wy24A==", + "license": "MIT", + "dependencies": { + "glsl-inject-defines": "^1.0.1", + "glsl-token-defines": "^1.0.0", + "glsl-token-depth": "^1.1.1", + "glsl-token-descope": "^1.0.2", + "glsl-token-scope": "^1.1.1", + "glsl-token-string": "^1.0.1", + "glsl-token-whitespace-trim": "^1.0.0", + "glsl-tokenizer": "^2.0.2", + "murmurhash-js": "^1.0.0", + "shallow-copy": "0.0.1" + } + }, + "node_modules/glslify-deps": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/glslify-deps/-/glslify-deps-1.3.2.tgz", + "integrity": "sha512-7S7IkHWygJRjcawveXQjRXLO2FTjijPDYC7QfZyAQanY+yGLCFHYnPtsGT9bdyHiwPTw/5a1m1M9hamT2aBpag==", + "license": "ISC", + "dependencies": { + "@choojs/findup": "^0.2.0", + "events": "^3.2.0", + "glsl-resolve": "0.0.1", + "glsl-tokenizer": "^2.0.0", + "graceful-fs": "^4.1.2", + "inherits": "^2.0.1", + "map-limit": "0.0.1", + "resolve": "^1.0.0" + } + }, + "node_modules/glslify/node_modules/bl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "license": "MIT", + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/glslify/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/glslify/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/glslify/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/glslify/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/goober": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.18.tgz", + "integrity": "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/grid-index": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/grid-index/-/grid-index-1.1.0.tgz", + "integrity": "sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==", + "license": "ISC" + }, + "node_modules/h3-js": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/h3-js/-/h3-js-4.3.0.tgz", + "integrity": "sha512-zgvyHZz5bEKeuyYGh0bF9/kYSxJ2SqroopkXHqKnD3lfjaZawcxulcI9nWbNC54gakl/2eObRLHWueTf1iLSaA==", + "license": "Apache-2.0", + "engines": { + "node": ">=4", + "npm": ">=3", + "yarn": ">=1.3.0" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-hover": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-hover/-/has-hover-1.0.1.tgz", + "integrity": "sha512-0G6w7LnlcpyDzpeGUTuT0CEw05+QlMuGVk1IHNAlHrGJITGodjZu3x8BNDUMfKJSZXNB2ZAclqc1bvrd+uUpfg==", + "license": "MIT", + "dependencies": { + "is-browser": "^2.0.1" + } + }, + "node_modules/has-passive-events": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-passive-events/-/has-passive-events-1.0.0.tgz", + "integrity": "sha512-2vSj6IeIsgvsRMyeQ0JaCX5Q3lX4zMn5HpoVc7MEhQ6pv8Iq9rsXjsp+E5ZwaT7T0xhMT0KmU8gtt1EFVdbJiw==", + "license": "MIT", + "dependencies": { + "is-browser": "^2.0.1" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/husky": { + "version": "9.0.11", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.0.11.tgz", + "integrity": "sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.mjs" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "optional": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/index-array-by": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/index-array-by/-/index-array-by-1.4.2.tgz", + "integrity": "sha512-SP23P27OUKzXWEC/TOyWlwLviofQkCSCKONnc62eItjp69yCZZPqDQtr3Pw5gJDnPeUMqExmKydNZaJO0FU9pw==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "license": "ISC", + "optional": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/inquirer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/inquirer/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-browser": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-browser/-/is-browser-2.1.0.tgz", + "integrity": "sha512-F5rTJxDQ2sW81fcfOR1GnCXT6sVJC104fCyfj+mjpwNEwaPYSn5fte5jiHmBg3DHsIoL/l8Kvw5VN5SsTRcRFQ==", + "license": "MIT" + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-firefox": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-firefox/-/is-firefox-1.0.3.tgz", + "integrity": "sha512-6Q9ITjvWIm0Xdqv+5U12wgOKEM2KoBw4Y926m0OFkvlCxnbG94HKAsVz8w3fWcfAS5YA2fJORXX1dLrkprCCxA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-iexplorer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-iexplorer/-/is-iexplorer-1.0.0.tgz", + "integrity": "sha512-YeLzceuwg3K6O0MLM3UyUUjKAlyULetwryFp1mHy1I5PfArK0AEqlfa+MR4gkJjcbuJXoDJCvXbyqZVf5CR2Sg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-mobile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-4.0.0.tgz", + "integrity": "sha512-mlcHZA84t1qLSuWkt2v0I2l61PYdyQDt4aG1mLIXF5FDMm4+haBCxCPYSr/uwqQNRk1MiTizn0ypEuRAOLRAew==", + "license": "MIT" + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string-blank": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-string-blank/-/is-string-blank-1.0.1.tgz", + "integrity": "sha512-9H+ZBCVs3L9OYqv8nuUAzpcT9OTgMD1yAWrG7ihlnibdkbtB850heAmYWxHuXc4CHy4lKeK69tN+ny1K7gBIrw==", + "license": "MIT" + }, + "node_modules/is-svg-path": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-svg-path/-/is-svg-path-1.0.2.tgz", + "integrity": "sha512-Lj4vePmqpPR1ZnRctHv8ltSh1OrSxHkhUkd7wi+VQdcdP15/KvQFyk7LhNuM7ZW0EVbJz8kZLVmL9quLrfq4Kg==", + "license": "MIT" + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, + "node_modules/isbot": { + "version": "5.1.31", + "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.31.tgz", + "integrity": "sha512-DPgQshehErHAqSCKDb3rNW03pa2wS/v5evvUqtxt6TTnHRqAG8FdzcSSJs9656pK6Y+NT7K9R4acEYXLHYfpUQ==", + "license": "Unlicense", + "engines": { + "node": ">=18" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "license": "Apache-2.0", + "dependencies": { + "xmlcreate": "^2.0.4" + } + }, + "node_modules/jsdoc": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.5.tgz", + "integrity": "sha512-P4C6MWP9yIlMiK8nwoZvxN84vb6MsnXcHuy7XzVOvQoCizWX5JFCBsWIIWKXBltpoRZXddUOVQmCTOZt9yDj9g==", + "license": "Apache-2.0", + "dependencies": { + "@babel/parser": "^7.20.15", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^14.1.1", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^14.1.0", + "markdown-it-anchor": "^8.6.7", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsdoc/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jsdom": { + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", + "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.2.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.5.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.1.1", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.1.1", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true, + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-pretty-compact": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", + "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==", + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kapsule": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/kapsule/-/kapsule-1.16.3.tgz", + "integrity": "sha512-4+5mNNf4vZDSwPhKprKwz3330iisPrb08JyMgbsdFrimBCKNHecua/WBwvVg3n7vwx0C1ARjfhwIpbrbd9n5wg==", + "license": "MIT", + "dependencies": { + "lodash-es": "4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/kdbush": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", + "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==", + "license": "ISC" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.2.tgz", + "integrity": "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.29.2", + "lightningcss-darwin-x64": "1.29.2", + "lightningcss-freebsd-x64": "1.29.2", + "lightningcss-linux-arm-gnueabihf": "1.29.2", + "lightningcss-linux-arm64-gnu": "1.29.2", + "lightningcss-linux-arm64-musl": "1.29.2", + "lightningcss-linux-x64-gnu": "1.29.2", + "lightningcss-linux-x64-musl": "1.29.2", + "lightningcss-win32-arm64-msvc": "1.29.2", + "lightningcss-win32-x64-msvc": "1.29.2" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.2.tgz", + "integrity": "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.2.tgz", + "integrity": "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.2.tgz", + "integrity": "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.2.tgz", + "integrity": "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.2.tgz", + "integrity": "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.2.tgz", + "integrity": "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.2.tgz", + "integrity": "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.2.tgz", + "integrity": "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.2.tgz", + "integrity": "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.2.tgz", + "integrity": "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "license": "MIT" + }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/longest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz", + "integrity": "sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.469.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.469.0.tgz", + "integrity": "sha512-28vvUnnKQ/dBwiCQtwJw7QauYnE7yd2Cyp4tTTJpvglX4EMpbflcdBgrgToX2j71B3YvugK/NH3BGUk+E/p/Fw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/map-limit": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/map-limit/-/map-limit-0.0.1.tgz", + "integrity": "sha512-pJpcfLPnIF/Sk3taPW21G/RQsEEirGaFpCW3oXRwH9dnFHPHNGjNyvh++rdmC2fNqEaTw2MhYJraoJWAHx8kEg==", + "license": "MIT", + "dependencies": { + "once": "~1.3.0" + } + }, + "node_modules/map-limit/node_modules/once": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha512-6vaNInhu+CHxtONf3zw3vq4SP2DOQhjBvIa3rNcG0+P7eKWlYH6Peu7rHizSloRU2EwMz6GraLieis9Ac9+p1w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/maplibre-gl": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.7.1.tgz", + "integrity": "sha512-lgL7XpIwsgICiL82ITplfS7IGwrB1OJIw/pCvprDp2dhmSSEBgmPzYRvwYYYvJGJD7fxUv1Tvpih4nZ6VrLuaA==", + "license": "BSD-3-Clause", + "dependencies": { + "@mapbox/geojson-rewind": "^0.5.2", + "@mapbox/jsonlint-lines-primitives": "^2.0.2", + "@mapbox/point-geometry": "^0.1.0", + "@mapbox/tiny-sdf": "^2.0.6", + "@mapbox/unitbezier": "^0.0.1", + "@mapbox/vector-tile": "^1.3.1", + "@mapbox/whoots-js": "^3.1.0", + "@maplibre/maplibre-gl-style-spec": "^20.3.1", + "@types/geojson": "^7946.0.14", + "@types/geojson-vt": "3.2.5", + "@types/mapbox__point-geometry": "^0.1.4", + "@types/mapbox__vector-tile": "^1.3.4", + "@types/pbf": "^3.0.5", + "@types/supercluster": "^7.1.3", + "earcut": "^3.0.0", + "geojson-vt": "^4.0.2", + "gl-matrix": "^3.4.3", + "global-prefix": "^4.0.0", + "kdbush": "^4.0.2", + "murmurhash-js": "^1.0.0", + "pbf": "^3.3.0", + "potpack": "^2.0.0", + "quickselect": "^3.0.0", + "supercluster": "^8.0.1", + "tinyqueue": "^3.0.0", + "vt-pbf": "^3.1.3" + }, + "engines": { + "node": ">=16.14.0", + "npm": ">=8.1.0" + }, + "funding": { + "url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1" + } + }, + "node_modules/maplibre-gl/node_modules/@mapbox/tiny-sdf": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.7.tgz", + "integrity": "sha512-25gQLQMcpivjOSA40g3gO6qgiFPDpWRoMfd+G/GoppPIeP6JDaMMkMrEJnMZhKyyS6iKwVt5YKu02vCUyJM3Ug==", + "license": "BSD-2-Clause" + }, + "node_modules/maplibre-gl/node_modules/@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", + "license": "BSD-2-Clause" + }, + "node_modules/maplibre-gl/node_modules/geojson-vt": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.2.tgz", + "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==", + "license": "ISC" + }, + "node_modules/maplibre-gl/node_modules/global-prefix": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-4.0.0.tgz", + "integrity": "sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==", + "license": "MIT", + "dependencies": { + "ini": "^4.1.3", + "kind-of": "^6.0.3", + "which": "^4.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/maplibre-gl/node_modules/ini": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/maplibre-gl/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/maplibre-gl/node_modules/potpack": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.1.0.tgz", + "integrity": "sha512-pcaShQc1Shq0y+E7GqJqvZj8DTthWV1KeHGdi0Z6IAin2Oi3JnLCOfwnCo84qc+HAp52wT9nK9H7FAJp5a44GQ==", + "license": "ISC" + }, + "node_modules/maplibre-gl/node_modules/quickselect": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", + "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", + "license": "ISC" + }, + "node_modules/maplibre-gl/node_modules/supercluster": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", + "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", + "license": "ISC", + "dependencies": { + "kdbush": "^4.0.2" + } + }, + "node_modules/maplibre-gl/node_modules/tinyqueue": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", + "license": "ISC" + }, + "node_modules/maplibre-gl/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", + "license": "Unlicense", + "peerDependencies": { + "@types/markdown-it": "*", + "markdown-it": "*" + } + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/math-log2": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/math-log2/-/math-log2-1.0.1.tgz", + "integrity": "sha512-9W0yGtkaMAkf74XGYVy4Dqw3YUMnTNB2eeiw9aQbUl4A3KmuCEHTt2DgAB07ENzOYAjsYSAYufkAq0Zd+jU7zA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mdn-data": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.23.0.tgz", + "integrity": "sha512-786vq1+4079JSeu2XdcDjrhi/Ry7BWtjDl9WtGPWLiIHb2T66GvIVflZTBoSNZ5JqTtJGYEVMuFA/lbQlMOyDQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "license": "MIT" + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/merge": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", + "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mini-svg-data-uri": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", + "dev": true, + "license": "MIT", + "bin": { + "mini-svg-data-uri": "cli.js" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/motion": { + "version": "12.23.24", + "resolved": "https://registry.npmjs.org/motion/-/motion-12.23.24.tgz", + "integrity": "sha512-Rc5E7oe2YZ72N//S3QXGzbnXgqNrTESv8KKxABR20q2FLch9gHLo0JLyYo2hZ238bZ9Gx6cWhj9VO0IgwbMjCw==", + "license": "MIT", + "dependencies": { + "framer-motion": "^12.23.24", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/motion-dom": { + "version": "12.23.23", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz", + "integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.23.6" + } + }, + "node_modules/motion-utils": { + "version": "12.23.6", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz", + "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==", + "license": "MIT" + }, + "node_modules/mouse-change": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/mouse-change/-/mouse-change-1.4.0.tgz", + "integrity": "sha512-vpN0s+zLL2ykyyUDh+fayu9Xkor5v/zRD9jhSqjRS1cJTGS0+oakVZzNm5n19JvvEj0you+MXlYTpNxUDQUjkQ==", + "license": "MIT", + "dependencies": { + "mouse-event": "^1.0.0" + } + }, + "node_modules/mouse-event": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/mouse-event/-/mouse-event-1.0.5.tgz", + "integrity": "sha512-ItUxtL2IkeSKSp9cyaX2JLUuKk2uMoxBg4bbOWVd29+CskYJR9BGsUqtXenNzKbnDshvupjUewDIYVrOB6NmGw==", + "license": "MIT" + }, + "node_modules/mouse-event-offset": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mouse-event-offset/-/mouse-event-offset-3.0.2.tgz", + "integrity": "sha512-s9sqOs5B1Ykox3Xo8b3Ss2IQju4UwlW6LSR+Q5FXWpprJ5fzMLefIIItr3PH8RwzfGy6gxs/4GAmiNuZScE25w==", + "license": "MIT" + }, + "node_modules/mouse-wheel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mouse-wheel/-/mouse-wheel-1.2.0.tgz", + "integrity": "sha512-+OfYBiUOCTWcTECES49neZwL5AoGkXE+lFjIvzwNCnYRlso+EnfvovcBxGoyQ0yQt806eSPjS675K0EwWknXmw==", + "license": "MIT", + "dependencies": { + "right-now": "^1.0.0", + "signum": "^1.0.0", + "to-px": "^1.0.1" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/murmurhash-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz", + "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==", + "license": "MIT" + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "license": "ISC" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/native-promise-only": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/needle": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", + "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==", + "license": "MIT", + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "license": "ISC" + }, + "node_modules/node-releases": { + "version": "2.0.26", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.26.tgz", + "integrity": "sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-svg-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/normalize-svg-path/-/normalize-svg-path-0.1.0.tgz", + "integrity": "sha512-1/kmYej2iedi5+ROxkRESL/pI02pkg0OBnaR4hJkSIX6+ORzepwbuUXfrdZaPjysTsJInj0Rj5NuX027+dMBvA==", + "license": "MIT" + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-run-all2": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-6.1.2.tgz", + "integrity": "sha512-WwwnS8Ft+RpXve6T2EIEVpFLSqN+ORHRvgNk3H9N62SZXjmzKoRhMFg3I17TK3oMaAEr+XFbRirWS2Fn3BCPSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "cross-spawn": "^7.0.3", + "memorystream": "^0.3.1", + "minimatch": "^9.0.0", + "pidtree": "^0.6.0", + "read-package-json-fast": "^3.0.2", + "shell-quote": "^1.7.3" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "npm-run-all2": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0", + "npm": ">= 8" + } + }, + "node_modules/npm-run-all2/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm-run-all2/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm-run-all2/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/number-is-integer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-integer/-/number-is-integer-1.0.1.tgz", + "integrity": "sha512-Dq3iuiFBkrbmuQjGFFF3zckXNCQoSD37/SdSbgcBailUx6knDvDwb5CympBgcoWHy36sfS12u74MHYkXyHq6bg==", + "license": "MIT", + "dependencies": { + "is-finite": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nwsapi": { + "version": "2.2.22", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.22.tgz", + "integrity": "sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ora/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ora/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parenthesis": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/parenthesis/-/parenthesis-3.1.8.tgz", + "integrity": "sha512-KF/U8tk54BgQewkJPvB4s/US3VQY68BRDpH638+7O/n58TpnwiwnOtGIOsT2/i+M78s61BBpeC83STB88d8sqw==", + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-rect": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parse-rect/-/parse-rect-1.2.0.tgz", + "integrity": "sha512-4QZ6KYbnE6RTwg9E0HpLchUM9EZt6DnDxajFZZDSV4p/12ZJEvPO702DZpGvRYEPo00yKDys7jASi+/w7aO8LA==", + "license": "MIT", + "dependencies": { + "pick-by-alias": "^1.2.0" + } + }, + "node_modules/parse-svg-path": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz", + "integrity": "sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==", + "license": "MIT" + }, + "node_modules/parse-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-unit/-/parse-unit-1.0.1.tgz", + "integrity": "sha512-hrqldJHokR3Qj88EIlV/kAyAi/G5R2+R56TBANxNMy0uPlYcttx0jnMW6Yx5KsKPSbC3KddM/7qQm3+0wEXKxg==", + "license": "MIT" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pbf": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", + "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==", + "license": "BSD-3-Clause", + "dependencies": { + "ieee754": "^1.1.12", + "resolve-protobuf-schema": "^2.1.0" + }, + "bin": { + "pbf": "bin/pbf" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "license": "MIT" + }, + "node_modules/pick-by-alias": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pick-by-alias/-/pick-by-alias-1.2.0.tgz", + "integrity": "sha512-ESj2+eBxhGrcA1azgHs7lARG5+5iLakc/6nlfbpjcLl00HuuUOIuORhYXN4D1HfvMSKuVtFQjAlnwi1JHEeDIw==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/plotly.js": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/plotly.js/-/plotly.js-3.1.2.tgz", + "integrity": "sha512-Yk1KQ1QHzZH1t/XYdub3b631Gc4t4kZYHdnf4G7DqnNg4CP3nJ9FP4hsNh3pNVO9LcpchE7NrmjPKJlaGzBJNg==", + "license": "MIT", + "dependencies": { + "@plotly/d3": "3.8.2", + "@plotly/d3-sankey": "0.7.2", + "@plotly/d3-sankey-circular": "0.33.1", + "@plotly/mapbox-gl": "1.13.4", + "@plotly/regl": "^2.1.2", + "@turf/area": "^7.1.0", + "@turf/bbox": "^7.1.0", + "@turf/centroid": "^7.1.0", + "base64-arraybuffer": "^1.0.2", + "canvas-fit": "^1.5.0", + "color-alpha": "1.0.4", + "color-normalize": "1.5.0", + "color-parse": "2.0.0", + "color-rgba": "3.0.0", + "country-regex": "^1.1.0", + "d3-force": "^1.2.1", + "d3-format": "^1.4.5", + "d3-geo": "^1.12.1", + "d3-geo-projection": "^2.9.0", + "d3-hierarchy": "^1.1.9", + "d3-interpolate": "^3.0.1", + "d3-time": "^1.1.0", + "d3-time-format": "^2.2.3", + "fast-isnumeric": "^1.1.4", + "gl-mat4": "^1.2.0", + "gl-text": "^1.4.0", + "has-hover": "^1.0.1", + "has-passive-events": "^1.0.0", + "is-mobile": "^4.0.0", + "maplibre-gl": "^4.7.1", + "mouse-change": "^1.4.0", + "mouse-event-offset": "^3.0.2", + "mouse-wheel": "^1.2.0", + "native-promise-only": "^0.8.1", + "parse-svg-path": "^0.1.2", + "point-in-polygon": "^1.1.0", + "polybooljs": "^1.2.2", + "probe-image-size": "^7.2.3", + "regl-error2d": "^2.0.12", + "regl-line2d": "^3.1.3", + "regl-scatter2d": "^3.3.1", + "regl-splom": "^1.0.14", + "strongly-connected-components": "^1.0.1", + "superscript-text": "^1.0.0", + "svg-path-sdf": "^1.1.3", + "tinycolor2": "^1.4.2", + "to-px": "1.0.1", + "topojson-client": "^3.1.0", + "webgl-context": "^2.2.0", + "world-calendars": "^1.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/plotly.js/node_modules/d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==", + "license": "BSD-3-Clause" + }, + "node_modules/plotly.js/node_modules/d3-dispatch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", + "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==", + "license": "BSD-3-Clause" + }, + "node_modules/plotly.js/node_modules/d3-force": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz", + "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-collection": "1", + "d3-dispatch": "1", + "d3-quadtree": "1", + "d3-timer": "1" + } + }, + "node_modules/plotly.js/node_modules/d3-geo": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz", + "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1" + } + }, + "node_modules/plotly.js/node_modules/d3-quadtree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.7.tgz", + "integrity": "sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA==", + "license": "BSD-3-Clause" + }, + "node_modules/plotly.js/node_modules/d3-time-format": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz", + "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-time": "1" + } + }, + "node_modules/plotly.js/node_modules/d3-timer": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", + "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==", + "license": "BSD-3-Clause" + }, + "node_modules/point-in-polygon": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.1.0.tgz", + "integrity": "sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw==", + "license": "MIT" + }, + "node_modules/point-in-polygon-hao": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/point-in-polygon-hao/-/point-in-polygon-hao-1.2.4.tgz", + "integrity": "sha512-x2pcvXeqhRHlNRdhLs/tgFapAbSSe86wa/eqmj1G6pWftbEs5aVRJhRGM6FYSUERKu0PjekJzMq0gsI2XyiclQ==", + "license": "MIT", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/polished": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", + "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.17.8" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/polybooljs": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/polybooljs/-/polybooljs-1.2.2.tgz", + "integrity": "sha512-ziHW/02J0XuNuUtmidBc6GXE8YohYydp3DWPWXYsd7O721TjcmN+k6ezjdwkDqep+gnWnFY+yqZHvzElra2oCg==", + "license": "MIT" + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/potpack": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", + "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==", + "license": "ISC" + }, + "node_modules/preact": { + "version": "10.27.2", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.27.2.tgz", + "integrity": "sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prism-react-renderer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.4.1.tgz", + "integrity": "sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prismjs": "^1.26.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, + "node_modules/probe-image-size": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/probe-image-size/-/probe-image-size-7.2.3.tgz", + "integrity": "sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==", + "license": "MIT", + "dependencies": { + "lodash.merge": "^4.6.2", + "needle": "^2.5.2", + "stream-parser": "~0.3.1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/protobufjs": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.0.tgz", + "integrity": "sha512-Z2E/kOY1QjoMlCytmexzYfDm/w5fKAiRwpSzGtdnXW1zC88Z2yXazHHrOtwCzn+7wSxyE8PYM4rvVcMphF9sOA==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/protobufjs-cli": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/protobufjs-cli/-/protobufjs-cli-1.1.3.tgz", + "integrity": "sha512-MqD10lqF+FMsOayFiNOdOGNlXc4iKDCf0ZQPkPR+gizYh9gqUeGTWulABUCdI+N67w5RfJ6xhgX4J8pa8qmMXQ==", + "license": "BSD-3-Clause", + "dependencies": { + "chalk": "^4.0.0", + "escodegen": "^1.13.0", + "espree": "^9.0.0", + "estraverse": "^5.1.0", + "glob": "^8.0.0", + "jsdoc": "^4.0.0", + "minimist": "^1.2.0", + "semver": "^7.1.2", + "tmp": "^0.2.1", + "uglify-js": "^3.7.7" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "protobufjs": "^7.0.0" + } + }, + "node_modules/protobufjs-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/protobufjs-cli/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/protobufjs-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/protobufjs-cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/protobufjs-cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/protobufjs-cli/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/protobufjs-cli/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/protobufjs-cli/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/protobufjs-cli/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/protobufjs-cli/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/protobufjs-cli/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/protobufjs-cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protobufjs-cli/node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/protocol-buffers-schema": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", + "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quickselect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", + "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==", + "license": "ISC" + }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "license": "MIT", + "dependencies": { + "performance-now": "^2.1.0" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "node_modules/react-icons": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz", + "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-plotly.js": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-plotly.js/-/react-plotly.js-2.6.0.tgz", + "integrity": "sha512-g93xcyhAVCSt9kV1svqG1clAEdL6k3U+jjuSzfTV7owaSU9Go6Ph8bl25J+jKfKvIGAEYpe4qj++WHJuc9IaeA==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "plotly.js": ">1.34.0", + "react": ">0.13.0" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-simple-maps": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-simple-maps/-/react-simple-maps-3.0.0.tgz", + "integrity": "sha512-vKNFrvpPG8Vyfdjnz5Ne1N56rZlDfHXv5THNXOVZMqbX1rWZA48zQuYT03mx6PAKanqarJu/PDLgshIZAfHHqw==", + "license": "MIT", + "dependencies": { + "d3-geo": "^2.0.2", + "d3-selection": "^2.0.0", + "d3-zoom": "^2.0.0", + "topojson-client": "^3.1.0" + }, + "peerDependencies": { + "prop-types": "^15.7.2", + "react": "^16.8.0 || 17.x || 18.x", + "react-dom": "^16.8.0 || 17.x || 18.x" + } + }, + "node_modules/react-smooth": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", + "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==", + "license": "MIT", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-tooltip": { + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.28.0.tgz", + "integrity": "sha512-R5cO3JPPXk6FRbBHMO0rI9nkUG/JKfalBSQfZedZYzmqaZQgq7GLzF8vcCWx6IhUCKg0yPqJhXIzmIO5ff15xg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.6.1", + "classnames": "^2.3.0" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recast": { + "version": "0.23.11", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", + "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/recast/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/recharts": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.0.tgz", + "integrity": "sha512-cIvMxDfpAmqAmVgc4yb7pgm/O1tmmkl/CjrvXuW+62/+7jj/iF9Ykm+hb/UJt42TREHMyd3gb+pkgoa2MxgDIw==", + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^18.3.1", + "react-smooth": "^4.0.0", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "license": "MIT", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/recharts/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", + "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regl": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/regl/-/regl-2.1.1.tgz", + "integrity": "sha512-+IOGrxl3FZ8ZM9ixCWQZzFRiRn7Rzn9bu3iFHwg/yz4tlOUQgbO4PHLgG+1ZT60zcIV8tief6Qrmyl8qcoJP0g==", + "license": "MIT" + }, + "node_modules/regl-error2d": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/regl-error2d/-/regl-error2d-2.0.12.tgz", + "integrity": "sha512-r7BUprZoPO9AbyqM5qlJesrSRkl+hZnVKWKsVp7YhOl/3RIpi4UDGASGJY0puQ96u5fBYw/OlqV24IGcgJ0McA==", + "license": "MIT", + "dependencies": { + "array-bounds": "^1.0.1", + "color-normalize": "^1.5.0", + "flatten-vertex-data": "^1.0.2", + "object-assign": "^4.1.1", + "pick-by-alias": "^1.2.0", + "to-float32": "^1.1.0", + "update-diff": "^1.1.0" + } + }, + "node_modules/regl-line2d": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/regl-line2d/-/regl-line2d-3.1.3.tgz", + "integrity": "sha512-fkgzW+tTn4QUQLpFKsUIE0sgWdCmXAM3ctXcCgoGBZTSX5FE2A0M7aynz7nrZT5baaftLrk9te54B+MEq4QcSA==", + "license": "MIT", + "dependencies": { + "array-bounds": "^1.0.1", + "array-find-index": "^1.0.2", + "array-normalize": "^1.1.4", + "color-normalize": "^1.5.0", + "earcut": "^2.1.5", + "es6-weak-map": "^2.0.3", + "flatten-vertex-data": "^1.0.2", + "object-assign": "^4.1.1", + "parse-rect": "^1.2.0", + "pick-by-alias": "^1.2.0", + "to-float32": "^1.1.0" + } + }, + "node_modules/regl-line2d/node_modules/earcut": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", + "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==", + "license": "ISC" + }, + "node_modules/regl-scatter2d": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/regl-scatter2d/-/regl-scatter2d-3.3.1.tgz", + "integrity": "sha512-seOmMIVwaCwemSYz/y4WE0dbSO9svNFSqtTh5RE57I7PjGo3tcUYKtH0MTSoshcAsreoqN8HoCtnn8wfHXXfKQ==", + "license": "MIT", + "dependencies": { + "@plotly/point-cluster": "^3.1.9", + "array-range": "^1.0.1", + "array-rearrange": "^2.2.2", + "clamp": "^1.0.1", + "color-id": "^1.1.0", + "color-normalize": "^1.5.0", + "color-rgba": "^2.1.1", + "flatten-vertex-data": "^1.0.2", + "glslify": "^7.0.0", + "is-iexplorer": "^1.0.0", + "object-assign": "^4.1.1", + "parse-rect": "^1.2.0", + "pick-by-alias": "^1.2.0", + "to-float32": "^1.1.0", + "update-diff": "^1.1.0" + } + }, + "node_modules/regl-scatter2d/node_modules/color-parse": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/color-parse/-/color-parse-1.4.3.tgz", + "integrity": "sha512-BADfVl/FHkQkyo8sRBwMYBqemqsgnu7JZAwUgvBvuwwuNUZAhSvLTbsEErS5bQXzOjDR0dWzJ4vXN2Q+QoPx0A==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0" + } + }, + "node_modules/regl-scatter2d/node_modules/color-rgba": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/color-rgba/-/color-rgba-2.4.0.tgz", + "integrity": "sha512-Nti4qbzr/z2LbUWySr7H9dk3Rl7gZt7ihHAxlgT4Ho90EXWkjtkL1avTleu9yeGuqrt/chxTB6GKK8nZZ6V0+Q==", + "license": "MIT", + "dependencies": { + "color-parse": "^1.4.2", + "color-space": "^2.0.0" + } + }, + "node_modules/regl-splom": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/regl-splom/-/regl-splom-1.0.14.tgz", + "integrity": "sha512-OiLqjmPRYbd7kDlHC6/zDf6L8lxgDC65BhC8JirhP4ykrK4x22ZyS+BnY8EUinXKDeMgmpRwCvUmk7BK4Nweuw==", + "license": "MIT", + "dependencies": { + "array-bounds": "^1.0.1", + "array-range": "^1.0.1", + "color-alpha": "^1.0.4", + "flatten-vertex-data": "^1.0.2", + "parse-rect": "^1.2.0", + "pick-by-alias": "^1.2.0", + "raf": "^3.4.1", + "regl-scatter2d": "^3.2.3" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", + "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/resolve-protobuf-schema": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", + "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "license": "MIT", + "dependencies": { + "protocol-buffers-schema": "^3.3.1" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/right-now": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/right-now/-/right-now-1.0.0.tgz", + "integrity": "sha512-DA8+YS+sMIVpbsuKgy+Z67L9Lxb1p05mNxRpDPNksPDEFir4vmBlUtuN9jkTGn9YMMdlBuK7XQgFiz6ws+yhSg==", + "license": "MIT" + }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense" + }, + "node_modules/rollup": { + "version": "4.40.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.2.tgz", + "integrity": "sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.7" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.40.2", + "@rollup/rollup-android-arm64": "4.40.2", + "@rollup/rollup-darwin-arm64": "4.40.2", + "@rollup/rollup-darwin-x64": "4.40.2", + "@rollup/rollup-freebsd-arm64": "4.40.2", + "@rollup/rollup-freebsd-x64": "4.40.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.40.2", + "@rollup/rollup-linux-arm-musleabihf": "4.40.2", + "@rollup/rollup-linux-arm64-gnu": "4.40.2", + "@rollup/rollup-linux-arm64-musl": "4.40.2", + "@rollup/rollup-linux-loongarch64-gnu": "4.40.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.40.2", + "@rollup/rollup-linux-riscv64-gnu": "4.40.2", + "@rollup/rollup-linux-riscv64-musl": "4.40.2", + "@rollup/rollup-linux-s390x-gnu": "4.40.2", + "@rollup/rollup-linux-x64-gnu": "4.40.2", + "@rollup/rollup-linux-x64-musl": "4.40.2", + "@rollup/rollup-win32-arm64-msvc": "4.40.2", + "@rollup/rollup-win32-ia32-msvc": "4.40.2", + "@rollup/rollup-win32-x64-msvc": "4.40.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0" + } + }, + "node_modules/rollup/node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/seroval": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.3.2.tgz", + "integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/seroval-plugins": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.3.3.tgz", + "integrity": "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "seroval": "^1.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shallow-copy": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", + "integrity": "sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/signum": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/signum/-/signum-1.0.0.tgz", + "integrity": "sha512-yodFGwcyt59XRh7w5W3jPcIQb3Bwi21suEfT7MAWnBX3iCdklJpgDgvGT9o04UonglZN5SNMfJFkHIR/jO8GHw==", + "license": "MIT" + }, + "node_modules/simplesignal": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/simplesignal/-/simplesignal-2.1.7.tgz", + "integrity": "sha512-PEo2qWpUke7IMhlqiBxrulIFvhJRLkl1ih52Rwa+bPjzhJepcd4GIjn2RiQmFSx3dQvsEAgF0/lXMwMN7vODaA==", + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "dev": true, + "license": "MIT" + }, + "node_modules/stack-trace": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", + "integrity": "sha512-vjUc6sfgtgY0dxCdnc40mK6Oftjo9+2K8H/NG81TMhgL392FtiPA9tn9RLyTxXmTLPJPjF3VyzFp6bsWFLisMQ==", + "engines": { + "node": "*" + } + }, + "node_modules/static-eval": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.1.tgz", + "integrity": "sha512-MgWpQ/ZjGieSVB3eOJVs4OA2LT/q1vx98KPCTTQPzq/aLr0YUXTsgryTXr4SLfR0ZfUUCiedM9n/ABeDIyy4mA==", + "license": "MIT", + "dependencies": { + "escodegen": "^2.1.0" + } + }, + "node_modules/static-eval/node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/static-eval/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/stream-parser": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", + "integrity": "sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==", + "license": "MIT", + "dependencies": { + "debug": "2" + } + }, + "node_modules/stream-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/stream-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-split-by": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string-split-by/-/string-split-by-1.0.0.tgz", + "integrity": "sha512-KaJKY+hfpzNyet/emP81PJA9hTVSfxNLS9SFTWxdCnnW1/zOOwiV248+EfoX7IQFcBaOp4G5YE6xTJMF+pLg6A==", + "license": "MIT", + "dependencies": { + "parenthesis": "^3.1.5" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strongly-connected-components": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strongly-connected-components/-/strongly-connected-components-1.0.1.tgz", + "integrity": "sha512-i0TFx4wPcO0FwX+4RkLJi1MxmcTv90jNZgxMu9XRnMXMeFUY1VJlIoXpZunPUvUUqbCT1pg5PEkFqqpcaElNaA==", + "license": "MIT" + }, + "node_modules/supercluster": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-7.1.5.tgz", + "integrity": "sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg==", + "license": "ISC", + "dependencies": { + "kdbush": "^3.0.0" + } + }, + "node_modules/supercluster/node_modules/kdbush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-3.0.0.tgz", + "integrity": "sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==", + "license": "ISC" + }, + "node_modules/superscript-text": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/superscript-text/-/superscript-text-1.0.0.tgz", + "integrity": "sha512-gwu8l5MtRZ6koO0icVTlmN5pm7Dhh1+Xpe9O4x6ObMAsW+3jPbW14d1DsBq1F4wiI+WOFjXF35pslgec/G8yCQ==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-arc-to-cubic-bezier": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz", + "integrity": "sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==", + "license": "ISC" + }, + "node_modules/svg-path-bounds": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/svg-path-bounds/-/svg-path-bounds-1.0.2.tgz", + "integrity": "sha512-H4/uAgLWrppIC0kHsb2/dWUYSmb4GE5UqH06uqWBcg6LBjX2fu0A8+JrO2/FJPZiSsNOKZAhyFFgsLTdYUvSqQ==", + "license": "MIT", + "dependencies": { + "abs-svg-path": "^0.1.1", + "is-svg-path": "^1.0.1", + "normalize-svg-path": "^1.0.0", + "parse-svg-path": "^0.1.2" + } + }, + "node_modules/svg-path-bounds/node_modules/normalize-svg-path": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/normalize-svg-path/-/normalize-svg-path-1.1.0.tgz", + "integrity": "sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==", + "license": "MIT", + "dependencies": { + "svg-arc-to-cubic-bezier": "^3.0.0" + } + }, + "node_modules/svg-path-sdf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/svg-path-sdf/-/svg-path-sdf-1.1.3.tgz", + "integrity": "sha512-vJJjVq/R5lSr2KLfVXVAStktfcfa1pNFjFOgyJnzZFXlO/fDZ5DmM8FpnSKKzLPfEYTVeXuVBTHF296TpxuJVg==", + "license": "MIT", + "dependencies": { + "bitmap-sdf": "^1.0.0", + "draw-svg-path": "^1.0.0", + "is-svg-path": "^1.0.1", + "parse-svg-path": "^0.1.2", + "svg-path-bounds": "^1.0.1" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/tabbable": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.3.0.tgz", + "integrity": "sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==", + "license": "MIT" + }, + "node_modules/tailwind-scrollbar": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/tailwind-scrollbar/-/tailwind-scrollbar-4.0.2.tgz", + "integrity": "sha512-wAQiIxAPqk0MNTPptVe/xoyWi27y+NRGnTwvn4PQnbvB9kp8QUBiGl/wsfoVBHnQxTmhXJSNt9NHTmcz9EivFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "prism-react-renderer": "^2.4.1" + }, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "tailwindcss": "4.x" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.5.tgz", + "integrity": "sha512-nYtSPfWGDiWgCkwQG/m+aX83XCwf62sBgg3bIlNiiOcggnS1x3uVRDAuyelBFL+vJdOPPCGElxv9DjHJjRHiVA==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tempy": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", + "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.44.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", + "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/three": { + "version": "0.180.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.180.0.tgz", + "integrity": "sha512-o+qycAMZrh+TsE01GqWUxUIKR1AL0S8pq7zDkYOQw8GqfX8b8VoCKYUoHbhiX5j+7hr8XsuHDVU6+gkQJQKg9w==", + "license": "MIT" + }, + "node_modules/three-conic-polygon-geometry": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/three-conic-polygon-geometry/-/three-conic-polygon-geometry-2.1.2.tgz", + "integrity": "sha512-NaP3RWLJIyPGI+zyaZwd0Yj6rkoxm4FJHqAX1Enb4L64oNYLCn4bz1ESgOEYavgcUwCNYINu1AgEoUBJr1wZcA==", + "license": "MIT", + "dependencies": { + "@turf/boolean-point-in-polygon": "^7.2", + "d3-array": "1 - 3", + "d3-geo": "1 - 3", + "d3-geo-voronoi": "2", + "d3-scale": "1 - 4", + "delaunator": "5", + "earcut": "3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "three": ">=0.72.0" + } + }, + "node_modules/three-geojson-geometry": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/three-geojson-geometry/-/three-geojson-geometry-2.1.1.tgz", + "integrity": "sha512-dC7bF3ri1goDcihYhzACHOBQqu7YNNazYLa2bSydVIiJUb3jDFojKSy+gNj2pMkqZNSVjssSmdY9zlmnhEpr1w==", + "license": "MIT", + "dependencies": { + "d3-geo": "1 - 3", + "d3-interpolate": "1 - 3", + "earcut": "3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "three": ">=0.72.0" + } + }, + "node_modules/three-globe": { + "version": "2.44.1", + "resolved": "https://registry.npmjs.org/three-globe/-/three-globe-2.44.1.tgz", + "integrity": "sha512-v0Q4tgEulvKyjj5P73v9/cH/3CjhStgHhSsoK7owj9ktaf56DiZC+oITi7x8pB3zAmUJlLJjj8I1BOCzzk9RNg==", + "license": "MIT", + "dependencies": { + "@tweenjs/tween.js": "18 - 25", + "accessor-fn": "1", + "d3-array": "3", + "d3-color": "3", + "d3-geo": "3", + "d3-interpolate": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "data-bind-mapper": "1", + "frame-ticker": "1", + "h3-js": "4", + "index-array-by": "1", + "kapsule": "^1.16", + "three-conic-polygon-geometry": "2", + "three-geojson-geometry": "2", + "three-slippy-map-globe": "1", + "tinycolor2": "1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "three": ">=0.154" + } + }, + "node_modules/three-globe/node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/three-globe/node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/three-render-objects": { + "version": "1.40.4", + "resolved": "https://registry.npmjs.org/three-render-objects/-/three-render-objects-1.40.4.tgz", + "integrity": "sha512-Ukpu1pei3L5r809izvjsZxwuRcYLiyn6Uvy3lZ9bpMTdvj3i6PeX6w++/hs2ZS3KnEzGjb6YvTvh4UQuwHTDJg==", + "license": "MIT", + "dependencies": { + "@tweenjs/tween.js": "18 - 25", + "accessor-fn": "1", + "float-tooltip": "^1.7", + "kapsule": "^1.16", + "polished": "4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "three": ">=0.168" + } + }, + "node_modules/three-slippy-map-globe": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/three-slippy-map-globe/-/three-slippy-map-globe-1.0.3.tgz", + "integrity": "sha512-Y9WCA/tTL8yH8FHVSXVQss/P0V36utTNhuixzFPj0Bs0SXxO+Vui133oAQmMpx4BLXYZpWZwcqHM2i3MfFlYWw==", + "license": "MIT", + "dependencies": { + "d3-geo": "1 - 3", + "d3-octree": "^1.1", + "d3-scale": "1 - 4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "three": ">=0.154" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/through2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/through2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", + "license": "MIT" + }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinyqueue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", + "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==", + "license": "ISC" + }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-float32": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/to-float32/-/to-float32-1.1.0.tgz", + "integrity": "sha512-keDnAusn/vc+R3iEiSDw8TOF7gPiTLdK1ArvWtYbJQiVfmRg6i/CAvbKq3uIS0vWroAC7ZecN3DjQKw3aSklUg==", + "license": "MIT" + }, + "node_modules/to-px": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-px/-/to-px-1.0.1.tgz", + "integrity": "sha512-2y3LjBeIZYL19e5gczp14/uRWFDtDUErJPVN3VU9a7SJO+RjGRtYR47aMN2bZgGlxvW4ZcEz2ddUPVHXcMfuXw==", + "license": "MIT", + "dependencies": { + "parse-unit": "^1.0.1" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/topojson-client": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz", + "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==", + "license": "ISC", + "dependencies": { + "commander": "2" + }, + "bin": { + "topo2geo": "bin/topo2geo", + "topomerge": "bin/topomerge", + "topoquantize": "bin/topoquantize" + } + }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsconfck": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", + "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", + "dev": true, + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.20.6", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", + "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", + "license": "ISC" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/typedarray-pool": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/typedarray-pool/-/typedarray-pool-1.2.0.tgz", + "integrity": "sha512-YTSQbzX43yvtpfRtIDAYygoYtgT+Rpjuxy9iOpczrjpXLgGoyG7aS5USJXV2d3nn8uHTeb9rXDvzS27zUg5KYQ==", + "license": "MIT", + "dependencies": { + "bit-twiddle": "^1.0.0", + "dup": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.31.1.tgz", + "integrity": "sha512-j6DsEotD/fH39qKzXTQRwYYWlt7D+0HmfpOK+DVhwJOFLcdmn92hq3mBb7HlKJHbjjI/gTOqEcc9d6JfpFf/VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.31.1", + "@typescript-eslint/parser": "8.31.1", + "@typescript-eslint/utils": "8.31.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "license": "BSD-2-Clause", + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/underscore": { + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unplugin": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.10.tgz", + "integrity": "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unplugin/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==", + "license": "MIT" + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-diff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-diff/-/update-diff-1.1.0.tgz", + "integrity": "sha512-rCiBPiHxZwT4+sBhEbChzpO5hYHjm91kScWgdHf4Qeafs6Ba7MBl+d9GlGv72bcTZQO0sLmtQS1pHSWoCLtN/A==", + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/victory-vendor/node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/victory-vendor/node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/victory-vendor/node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/victory-vendor/node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/victory-vendor/node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/vite": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.4.tgz", + "integrity": "sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "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 + } + } + }, + "node_modules/vite-tsconfig-paths": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz", + "integrity": "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^3.0.3" + }, + "peerDependencies": { + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vt-pbf": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz", + "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==", + "license": "MIT", + "dependencies": { + "@mapbox/point-geometry": "0.1.0", + "@mapbox/vector-tile": "^1.3.1", + "pbf": "^3.2.1" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/weak-map": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.8.tgz", + "integrity": "sha512-lNR9aAefbGPpHO7AEnY0hCFjz1eTkWCXYvkTRrTHs9qv8zJp+SkVYpzfLIFXQQiG3tVvbNFQgVg2bQS8YGgxyw==", + "license": "Apache-2.0" + }, + "node_modules/webgl-context": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/webgl-context/-/webgl-context-2.2.0.tgz", + "integrity": "sha512-q/fGIivtqTT7PEoF07axFIlHNk/XCPaYpq64btnepopSWvKNFkoORlQYgqDigBIuGA1ExnFd/GnSUnBNEPQY7Q==", + "license": "MIT", + "dependencies": { + "get-canvas-context": "^1.0.1" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workbox-background-sync": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-7.0.0.tgz", + "integrity": "sha512-S+m1+84gjdueM+jIKZ+I0Lx0BDHkk5Nu6a3kTVxP4fdj3gKouRNmhO8H290ybnJTOPfBDtTMXSQA/QLTvr7PeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "7.0.0" + } + }, + "node_modules/workbox-broadcast-update": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-7.0.0.tgz", + "integrity": "sha512-oUuh4jzZrLySOo0tC0WoKiSg90bVAcnE98uW7F8GFiSOXnhogfNDGZelPJa+6KpGBO5+Qelv04Hqx2UD+BJqNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.0.0" + } + }, + "node_modules/workbox-build": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-7.0.0.tgz", + "integrity": "sha512-CttE7WCYW9sZC+nUYhQg3WzzGPr4IHmrPnjKiu3AMXsiNQKx+l4hHl63WTrnicLmKEKHScWDH8xsGBdrYgtBzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apideck/better-ajv-errors": "^0.3.1", + "@babel/core": "^7.11.1", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.2", + "@rollup/plugin-babel": "^5.2.0", + "@rollup/plugin-node-resolve": "^11.2.1", + "@rollup/plugin-replace": "^2.4.1", + "@surma/rollup-plugin-off-main-thread": "^2.2.3", + "ajv": "^8.6.0", + "common-tags": "^1.8.0", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "lodash": "^4.17.20", + "pretty-bytes": "^5.3.0", + "rollup": "^2.43.1", + "rollup-plugin-terser": "^7.0.0", + "source-map": "^0.8.0-beta.0", + "stringify-object": "^3.3.0", + "strip-comments": "^2.0.1", + "tempy": "^0.6.0", + "upath": "^1.2.0", + "workbox-background-sync": "7.0.0", + "workbox-broadcast-update": "7.0.0", + "workbox-cacheable-response": "7.0.0", + "workbox-core": "7.0.0", + "workbox-expiration": "7.0.0", + "workbox-google-analytics": "7.0.0", + "workbox-navigation-preload": "7.0.0", + "workbox-precaching": "7.0.0", + "workbox-range-requests": "7.0.0", + "workbox-recipes": "7.0.0", + "workbox-routing": "7.0.0", + "workbox-strategies": "7.0.0", + "workbox-streams": "7.0.0", + "workbox-sw": "7.0.0", + "workbox-window": "7.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/workbox-build/node_modules/rollup": { + "version": "2.79.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", + "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/workbox-build/node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "deprecated": "The work that was done in this beta branch won't be included in future versions", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/workbox-build/node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/workbox-build/node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/workbox-build/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/workbox-cacheable-response": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-7.0.0.tgz", + "integrity": "sha512-0lrtyGHn/LH8kKAJVOQfSu3/80WDc9Ma8ng0p2i/5HuUndGttH+mGMSvOskjOdFImLs2XZIimErp7tSOPmu/6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.0.0" + } + }, + "node_modules/workbox-core": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-7.0.0.tgz", + "integrity": "sha512-81JkAAZtfVP8darBpfRTovHg8DGAVrKFgHpOArZbdFd78VqHr5Iw65f2guwjE2NlCFbPFDoez3D3/6ZvhI/rwQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/workbox-expiration": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-7.0.0.tgz", + "integrity": "sha512-MLK+fogW+pC3IWU9SFE+FRStvDVutwJMR5if1g7oBJx3qwmO69BNoJQVaMXq41R0gg3MzxVfwOGKx3i9P6sOLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "7.0.0" + } + }, + "node_modules/workbox-google-analytics": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-7.0.0.tgz", + "integrity": "sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==", + "deprecated": "It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-background-sync": "7.0.0", + "workbox-core": "7.0.0", + "workbox-routing": "7.0.0", + "workbox-strategies": "7.0.0" + } + }, + "node_modules/workbox-navigation-preload": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-7.0.0.tgz", + "integrity": "sha512-juWCSrxo/fiMz3RsvDspeSLGmbgC0U9tKqcUPZBCf35s64wlaLXyn2KdHHXVQrb2cqF7I0Hc9siQalainmnXJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.0.0" + } + }, + "node_modules/workbox-precaching": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-7.0.0.tgz", + "integrity": "sha512-EC0vol623LJqTJo1mkhD9DZmMP604vHqni3EohhQVwhJlTgyKyOkMrZNy5/QHfOby+39xqC01gv4LjOm4HSfnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.0.0", + "workbox-routing": "7.0.0", + "workbox-strategies": "7.0.0" + } + }, + "node_modules/workbox-range-requests": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-7.0.0.tgz", + "integrity": "sha512-SxAzoVl9j/zRU9OT5+IQs7pbJBOUOlriB8Gn9YMvi38BNZRbM+RvkujHMo8FOe9IWrqqwYgDFBfv6sk76I1yaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.0.0" + } + }, + "node_modules/workbox-recipes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-7.0.0.tgz", + "integrity": "sha512-DntcK9wuG3rYQOONWC0PejxYYIDHyWWZB/ueTbOUDQgefaeIj1kJ7pdP3LZV2lfrj8XXXBWt+JDRSw1lLLOnww==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-cacheable-response": "7.0.0", + "workbox-core": "7.0.0", + "workbox-expiration": "7.0.0", + "workbox-precaching": "7.0.0", + "workbox-routing": "7.0.0", + "workbox-strategies": "7.0.0" + } + }, + "node_modules/workbox-routing": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-7.0.0.tgz", + "integrity": "sha512-8YxLr3xvqidnbVeGyRGkaV4YdlKkn5qZ1LfEePW3dq+ydE73hUUJJuLmGEykW3fMX8x8mNdL0XrWgotcuZjIvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.0.0" + } + }, + "node_modules/workbox-strategies": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-7.0.0.tgz", + "integrity": "sha512-dg3qJU7tR/Gcd/XXOOo7x9QoCI9nk74JopaJaYAQ+ugLi57gPsXycVdBnYbayVj34m6Y8ppPwIuecrzkpBVwbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.0.0" + } + }, + "node_modules/workbox-streams": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-7.0.0.tgz", + "integrity": "sha512-moVsh+5to//l6IERWceYKGiftc+prNnqOp2sgALJJFbnNVpTXzKISlTIsrWY+ogMqt+x1oMazIdHj25kBSq/HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.0.0", + "workbox-routing": "7.0.0" + } + }, + "node_modules/workbox-sw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-7.0.0.tgz", + "integrity": "sha512-SWfEouQfjRiZ7GNABzHUKUyj8pCoe+RwjfOIajcx6J5mtgKkN+t8UToHnpaJL5UVVOf5YhJh+OHhbVNIHe+LVA==", + "dev": true, + "license": "MIT" + }, + "node_modules/workbox-window": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-7.0.0.tgz", + "integrity": "sha512-j7P/bsAWE/a7sxqTzXo3P2ALb1reTfZdvVp6OJ/uLr/C2kZAMvjeWGm8V4htQhor7DOvYg0sSbFN2+flT5U0qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/trusted-types": "^2.0.2", + "workbox-core": "7.0.0" + } + }, + "node_modules/world-atlas": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/world-atlas/-/world-atlas-2.0.2.tgz", + "integrity": "sha512-IXfV0qwlKXpckz1FhwXVwKRjiIhOnWttOskm5CtxMsjgE/MXAYRHWJqgXOpM8IkcPBoXnyTU5lFHcYa5ChG0LQ==", + "license": "ISC" + }, + "node_modules/world-calendars": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/world-calendars/-/world-calendars-1.0.4.tgz", + "integrity": "sha512-VGRnLJS+xJmGDPodgJRnGIDwGu0s+Cr9V2HB3EzlDZ5n0qb8h5SJtGUEkjrphZYAglEiXZ6kiXdmk0H/h/uu/w==", + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "license": "Apache-2.0" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", + "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zustand": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.8.tgz", + "integrity": "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json index 823da5702..288b66920 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -39,11 +39,13 @@ "globe.gl": "2.34.6", "lucide-react": "0.469.0", "motion": "^12.10.0", + "plotly.js": "^3.1.2", "protobufjs": "7.5.0", "protobufjs-cli": "1.1.3", "react": "19.1.0", "react-dom": "19.1.0", "react-icons": "5.5.0", + "react-plotly.js": "^2.6.0", "react-simple-maps": "3.0.0", "react-tooltip": "5.28.0", "recharts": "2.15.0", diff --git a/frontend/src/components/state/PlotlyTreemap.tsx b/frontend/src/components/state/PlotlyTreemap.tsx new file mode 100644 index 000000000..e0d9ca6cc --- /dev/null +++ b/frontend/src/components/state/PlotlyTreemap.tsx @@ -0,0 +1,304 @@ +import { useState, useEffect, useMemo } from 'react'; +import Plot from 'react-plotly.js'; +import { Card, CardBody, CardHeader } from '@/components/common/Card'; +import useContext from '@/contexts/api'; +import { useNetwork } from '@/stores/appStore'; +import type { HierarchicalStateResponse, StateNode } from '@/types/state-analytics'; +import { PARADIGM_COLORS } from './paradigmColors'; + +// Helper function to format bytes +function formatBytes(bytes: number): string { + if (bytes === 0) return '0 B'; + const k = 1024; + const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; + const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(k)); + return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`; +} + +interface PlotlyData { + labels: string[]; + parents: string[]; + values: number[]; + customdata: string[]; +} + +interface PlotlyDataWithColors extends PlotlyData { + colors: string[]; +} + +// Generate lighter/darker variants of a color +function adjustColor(hex: string, percent: number): string { + const num = parseInt(hex.replace('#', ''), 16); + const r = Math.min(255, Math.max(0, ((num >> 16) & 0xff) + percent)); + const g = Math.min(255, Math.max(0, ((num >> 8) & 0xff) + percent)); + const b = Math.min(255, Math.max(0, (num & 0xff) + percent)); + return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`; +} + +// Transform hierarchical StateNode to Plotly treemap format +function transformToPlotlyFormat(root: StateNode, totalSize: number): PlotlyDataWithColors { + const labels: string[] = []; + const parents: string[] = []; + const values: number[] = []; + const customdata: string[] = []; + const colors: string[] = []; + + // Track colors per category + const categoryColors = new Map(); + let categoryIndex = 0; + + function traverse(node: StateNode, parentName: string | null, depth: number, categoryColor?: string) { + // Format label with line breaks for better display + let formattedName = node.name; + if ( + node.type !== 'root' && + !formattedName.includes(' / ') && + !formattedName.endsWith(' Pool') && + !formattedName.endsWith(' Pools') + ) { + // Add line breaks for long names (similar to Paradigm) + formattedName = formattedName.replace(/, /g, '
').replace(/ /g, '
'); + } + + labels.push(formattedName); + parents.push(parentName || ''); + values.push(node.size_bytes); + + // Format custom hover data + const sizeFormatted = formatBytes(node.size_bytes); + const percentage = ((node.size_bytes / totalSize) * 100).toFixed(1); + customdata.push(`${sizeFormatted}
${percentage}% of state`); + + // Assign colors based on depth + let nodeColor: string; + if (node.type === 'root') { + nodeColor = 'rgba(0,0,0,0)'; // Transparent for root + } else if (node.type === 'category') { + // Categories get base colors from PARADIGM_COLORS + if (!categoryColors.has(node.name)) { + categoryColors.set(node.name, PARADIGM_COLORS[categoryIndex % PARADIGM_COLORS.length]); + categoryIndex++; + } + nodeColor = categoryColors.get(node.name)!; + categoryColor = nodeColor; // Pass down to children + } else if (node.type === 'protocol' || node.type === 'contract') { + // Protocols and contracts get variations of their category color + if (categoryColor) { + // Create variations: slightly lighter/darker based on index within siblings + const siblingIndex = node.children?.length || 0; + const adjustment = (siblingIndex % 5 - 2) * 15; // Range: -30 to +30 + nodeColor = adjustColor(categoryColor, adjustment); + } else { + nodeColor = PARADIGM_COLORS[categoryIndex % PARADIGM_COLORS.length]; + } + } else { + nodeColor = categoryColor || PARADIGM_COLORS[0]; + } + + colors.push(nodeColor); + + // Recursively traverse children + if (node.children && node.children.length > 0) { + node.children.forEach((child, idx) => { + // For contracts, create more distinct variations + let childColor = categoryColor; + if (node.type === 'protocol' && child.type === 'contract') { + // Create distinct colors for contracts within a protocol + const adjustment = ((idx % 10) - 5) * 20; // Wider range: -100 to +100 + childColor = adjustColor(categoryColor || PARADIGM_COLORS[0], adjustment); + } + traverse(child, formattedName, depth + 1, childColor); + }); + } + } + + traverse(root, null, 0); + return { labels, parents, values, customdata, colors }; +} + +export function PlotlyTreemap() { + const { restClient } = useContext(); + const { selectedNetwork } = useNetwork(); + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [maxDepth, setMaxDepth] = useState(3); // Default to showing contracts + + useEffect(() => { + async function fetchData() { + if (!selectedNetwork || !restClient) return; + + try { + setLoading(true); + setError(null); + const result = await restClient.getHierarchicalState(selectedNetwork, { + max_depth: maxDepth, + contracts_per_protocol: 100, // Show many more contracts to fill the space + }); + setData(result); + } catch (err) { + console.error('Error fetching hierarchical state:', err); + setError(err instanceof Error ? err.message : 'Failed to load data'); + } finally { + setLoading(false); + } + } + + fetchData(); + }, [selectedNetwork, restClient, maxDepth]); + + // Memoize the plotly data transformation + const plotlyData = useMemo(() => { + if (!data || !data.root) return null; + const totalSize = data.root.size_bytes; + + // Use the backend data directly - it's already categorized + return transformToPlotlyFormat(data.root, totalSize); + }, [data]); + + if (loading && !data) { + return ( + + +
Loading state composition...
+
+
+ ); + } + + if (error) { + return ( + + +
Error: {error}
+
+
+ ); + } + + if (!plotlyData) { + return ( + + +
No data available
+
+
+ ); + } + + return ( +
+ {/* Header */} +
+
+

State Composition

+

+ Ethereum state organized by category and protocol +

+
+
+ + +
+
+ + {/* Treemap */} +
+ %{label}
%{customdata}', + hoverlabel: { + font: { + size: 22, + family: 'Monospace', + }, + }, + marker: { + colors: plotlyData.colors, + line: { + width: 0.5, + }, + }, + textposition: 'middle center', + } as any, + ]} + layout={{ + margin: { l: 0, r: 0, t: 0, b: 0 }, + paper_bgcolor: 'transparent', + plot_bgcolor: 'transparent', + font: { + color: '#fff', + }, + }} + config={{ + displayModeBar: false, + responsive: true, + }} + style={{ width: '100%', height: '100%' }} + useResizeHandler={true} + /> +
+ + {/* Legend */} +
+
+
+ ERC-20 +
+
+
+ ERC-721 +
+
+
+ ERC-1155 +
+
+
+ DEX / DeFi +
+
+
+ Bridge +
+
+
+ Infra +
+
+
+ Game +
+
+
+ ); +} diff --git a/frontend/src/components/state/paradigmColors.ts b/frontend/src/components/state/paradigmColors.ts new file mode 100644 index 000000000..5197d404e --- /dev/null +++ b/frontend/src/components/state/paradigmColors.ts @@ -0,0 +1,32 @@ +/** + * Paradigm color scheme for state composition visualization + * Based on https://github.com/paradigmxyz/how-to-raise-the-gas-limit + */ + +export const PARADIGM_COLORS = [ + '#59d759', // erc20 - Lime green + '#1d90ff', // erc721 - Dodger blue + '#ffb630', // Other - Orange + '#afeeee', // Accounts - Pale turquoise + '#AF6E4D', // DEX / DeFi - Brown + '#9484f1', // Scam / Scheme - Medium slate blue + '#ffdf30', // Infra - Gold + 'teal', // Bridge + '#56aaaa', // Game - Teal + '#E86100', // erc1155 - Dark orange + '#F2C1D1', // Gambling - Pink +]; + +export const CATEGORY_COLOR_MAP: Record = { + erc20: PARADIGM_COLORS[0], + erc721: PARADIGM_COLORS[1], + Other: PARADIGM_COLORS[2], + Accounts: PARADIGM_COLORS[3], + 'DEX / DeFi': PARADIGM_COLORS[4], + 'Scam / Scheme': PARADIGM_COLORS[5], + Infra: PARADIGM_COLORS[6], + Bridge: PARADIGM_COLORS[7], + Game: PARADIGM_COLORS[8], + erc1155: PARADIGM_COLORS[9], + Gambling: PARADIGM_COLORS[10], +}; diff --git a/frontend/src/pages/state-analyzer/index.tsx b/frontend/src/pages/state-analyzer/index.tsx index 0e4b8b6c2..6d4f036bb 100644 --- a/frontend/src/pages/state-analyzer/index.tsx +++ b/frontend/src/pages/state-analyzer/index.tsx @@ -13,6 +13,7 @@ import type { } from '@/types/state-analytics'; import { ResponsiveLine } from '@nivo/line'; import { defaultNivoTheme } from '@/components/charts/NivoTheme'; +import { PlotlyTreemap } from '@/components/state/PlotlyTreemap'; // Helper function to format bytes function formatBytes(bytes: number): string { @@ -48,6 +49,7 @@ function StateAnalyzer() { const [granularity, setGranularity] = useState('hour' as StateGranularity); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); + const [activeTab, setActiveTab] = useState<'growth' | 'composition'>('growth'); useEffect(() => { let lastBlockNumber = 0; @@ -61,13 +63,11 @@ function StateAnalyzer() { try { const latest = await restClient.getStateLatest(selectedNetwork).catch(() => null); if (latest) { - console.log('[State Analyzer] Latest block:', latest.block_number, 'Last:', lastBlockNumber); - setLatestData(latest); - - // Only fetch heavy data when block number changes + // Only update state when block number actually changes if (latest.block_number !== lastBlockNumber) { - console.log('[State Analyzer] New block detected, fetching heavy data'); + console.log('[State Analyzer] New block detected:', latest.block_number, 'Last:', lastBlockNumber); lastBlockNumber = latest.block_number; + setLatestData(latest); fetchHeavyData(); } } @@ -219,14 +219,41 @@ function StateAnalyzer() {
)} - {/* Period Selector */} -
- {(['24h', '7d', '30d'] as StatePeriod[]).map(p => ( - + +
+ + {/* Growth Analytics Tab */} + {activeTab === 'growth' && ( + <> + {/* Period Selector */} +
+ {(['24h', '7d', '30d'] as StatePeriod[]).map(p => ( +
From 8942c37708c17014b2ba62ce68c5929d05a8c940 Mon Sep 17 00:00:00 2001 From: CPerezz Date: Sat, 1 Nov 2025 07:56:43 +0100 Subject: [PATCH 08/10] feat(state-analytics): add categorized state growth visualization (Paradigm-style) Add monthly/yearly state growth analysis by contract address, similar to Paradigm's "How to raise the gas limit" research (Figures 2 & 3). Backend changes: - Add GetStateGrowthByCategory RPC endpoint with granularity support (daily/monthly/yearly) - Implement category_state_growth.go service with execution layer data queries - Update queries.go to use canonical_execution_storage_diffs table - Fix genesis time to Ethereum mainnet (July 30, 2015) instead of Beacon Chain - Add protojson marshaling for proper RFC3339 timestamp serialization - Add REST API handler and route for /state/growth-by-category Frontend changes: - Add StateGrowthByCategory component with Plotly stacked bar chart - Support daily/monthly/yearly granularity toggle - Display summary statistics (total contracts, growth, earliest data) - Add REST client method and endpoint for categorized growth data - Integrate "Categorized Growth" tab into State Analyzer page Note: Queries currently timeout on canonical_execution_storage_diffs (10.6B rows). Performance fix proposed in https://github.com/ethpandaops/spamoor/pull/146 --- backend/pkg/api/v1/rest/handler.go | 40 +- backend/pkg/api/v1/rest/routes.go | 7 + .../api/v1/rest/state_analytics_handlers.go | 45 + .../server/internal/grpc/state_analytics.go | 8 + .../state_analytics/category_state_growth.go | 250 +++++ .../service/state_analytics/queries.go | 143 ++- .../state_analytics/state_growth_chart.go | 3 +- .../state_analytics/state_analytics.pb.go | 857 ++++++++++++++---- .../state_analytics/state_analytics.proto | 50 + .../state_analytics_grpc.pb.go | 44 +- frontend/src/api/rest/client.ts | 18 + frontend/src/api/rest/endpoints.ts | 1 + .../state/StateGrowthByCategory.tsx | 302 ++++++ frontend/src/pages/state-analyzer/index.tsx | 21 +- 14 files changed, 1554 insertions(+), 235 deletions(-) create mode 100644 backend/pkg/server/internal/service/state_analytics/category_state_growth.go create mode 100644 frontend/src/components/state/StateGrowthByCategory.tsx diff --git a/backend/pkg/api/v1/rest/handler.go b/backend/pkg/api/v1/rest/handler.go index b9a0bbfcd..4bdccd332 100644 --- a/backend/pkg/api/v1/rest/handler.go +++ b/backend/pkg/api/v1/rest/handler.go @@ -17,6 +17,8 @@ import ( cbtproto "github.com/ethpandaops/xatu-cbt/pkg/proto/clickhouse" "github.com/gorilla/mux" "github.com/sirupsen/logrus" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) // Common query parameter names used across REST API handlers @@ -74,22 +76,40 @@ func (r *PublicRouter) HandleGRPCError(w http.ResponseWriter, req *http.Request, // WriteJSONResponse safely writes a JSON response, handling encoding errors properly. func (r *PublicRouter) WriteJSONResponse(w http.ResponseWriter, req *http.Request, statusCode int, response interface{}) { - // Buffer the response first to catch encoding errors. - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - // Encoding failed - we haven't written anything yet, so we can send an error - r.log.WithError(err).WithField("type", response).Error("Failed to encode response") - r.HandleGRPCError(w, req, err) - - return + var jsonBytes []byte + var err error + + // Check if response is a protobuf message + if msg, ok := response.(proto.Message); ok { + // Use protojson for protobuf messages to properly serialize timestamps + marshaler := protojson.MarshalOptions{ + UseProtoNames: true, // Use proto field names (snake_case) + EmitUnpopulated: false, // Don't emit zero values + } + jsonBytes, err = marshaler.Marshal(msg) + if err != nil { + r.log.WithError(err).WithField("type", response).Error("Failed to marshal protobuf response") + r.HandleGRPCError(w, req, err) + return + } + } else { + // Use standard JSON encoding for non-protobuf responses + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + // Encoding failed - we haven't written anything yet, so we can send an error + r.log.WithError(err).WithField("type", response).Error("Failed to encode response") + r.HandleGRPCError(w, req, err) + return + } + jsonBytes = buf.Bytes() } // Set headers only after successful encoding. w.Header().Set("Content-Type", "application/json") w.WriteHeader(statusCode) - // Write the buffered response - if _, err := w.Write(buf.Bytes()); err != nil { + // Write the response + if _, err := w.Write(jsonBytes); err != nil { // Headers sent at this point, client disconnected most likely. r.log.WithError(err).Debug("Failed to write response") } diff --git a/backend/pkg/api/v1/rest/routes.go b/backend/pkg/api/v1/rest/routes.go index f775e31ec..b2e274957 100644 --- a/backend/pkg/api/v1/rest/routes.go +++ b/backend/pkg/api/v1/rest/routes.go @@ -180,6 +180,13 @@ func (r *PublicRouter) GetRoutes() []RouteConfig { Cache: middleware.CacheNearRealtime, Description: "Get time-series data of state growth", }, + { + Path: "/{network}/state/growth-by-category", + Handler: r.handleStateGrowthByCategory, + Methods: []string{http.MethodGet, http.MethodOptions}, + Cache: middleware.CacheBrowserShort, + Description: "Get categorized state growth over time (Paradigm Figures 2 & 3)", + }, { Path: "/{network}/state/contract/{address}", Handler: r.handleContractStateActivity, diff --git a/backend/pkg/api/v1/rest/state_analytics_handlers.go b/backend/pkg/api/v1/rest/state_analytics_handlers.go index a7224fc63..897a61065 100644 --- a/backend/pkg/api/v1/rest/state_analytics_handlers.go +++ b/backend/pkg/api/v1/rest/state_analytics_handlers.go @@ -287,3 +287,48 @@ func parseUint64(value string, defaultValue uint64) uint64 { return parsed } + +// handleStateGrowthByCategory returns time-series state growth data categorized by contract type +func (r *PublicRouter) handleStateGrowthByCategory(w http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + network := vars["network"] + + // Parse query parameters + queryParams := req.URL.Query() + granularity := parseCategoryGranularity(queryParams.Get("granularity")) + startBlock := parseUint64(queryParams.Get("start_block"), 0) + endBlock := parseUint64(queryParams.Get("end_block"), 0) + topContracts := parseLimit(queryParams.Get("top_contracts"), 100) + + // Add network to gRPC metadata + ctx := metadata.NewOutgoingContext(req.Context(), metadata.Pairs("network", network)) + + // Call gRPC service + resp, err := r.stateAnalyticsClient.GetStateGrowthByCategory(ctx, &state_analytics_pb.GetStateGrowthByCategoryRequest{ + Granularity: granularity, + StartBlock: startBlock, + EndBlock: endBlock, + TopContractsPerPeriod: topContracts, + }) + if err != nil { + r.HandleGRPCError(w, req, err) + return + } + + r.WriteJSONResponseOK(w, req, resp) +} + +// parseCategoryGranularity parses granularity query parameter for category growth +func parseCategoryGranularity(value string) state_analytics_pb.GetStateGrowthByCategoryRequest_Granularity { + switch value { + case "daily", "GRANULARITY_DAILY": + return state_analytics_pb.GetStateGrowthByCategoryRequest_GRANULARITY_DAILY + case "monthly", "GRANULARITY_MONTHLY": + return state_analytics_pb.GetStateGrowthByCategoryRequest_GRANULARITY_MONTHLY + case "yearly", "GRANULARITY_YEARLY": + return state_analytics_pb.GetStateGrowthByCategoryRequest_GRANULARITY_YEARLY + default: + // Default to monthly (Paradigm Figure 3 style) + return state_analytics_pb.GetStateGrowthByCategoryRequest_GRANULARITY_MONTHLY + } +} diff --git a/backend/pkg/server/internal/grpc/state_analytics.go b/backend/pkg/server/internal/grpc/state_analytics.go index e3c2be57d..819a236f3 100644 --- a/backend/pkg/server/internal/grpc/state_analytics.go +++ b/backend/pkg/server/internal/grpc/state_analytics.go @@ -97,3 +97,11 @@ func (sa *StateAnalytics) GetHierarchicalState( ) (*pb.GetHierarchicalStateResponse, error) { return sa.service.GetHierarchicalState(ctx, req) } + +// GetStateGrowthByCategory returns time-series state growth data categorized by contract type. +func (sa *StateAnalytics) GetStateGrowthByCategory( + ctx context.Context, + req *pb.GetStateGrowthByCategoryRequest, +) (*pb.GetStateGrowthByCategoryResponse, error) { + return sa.service.GetStateGrowthByCategory(ctx, req) +} diff --git a/backend/pkg/server/internal/service/state_analytics/category_state_growth.go b/backend/pkg/server/internal/service/state_analytics/category_state_growth.go new file mode 100644 index 000000000..691b341c6 --- /dev/null +++ b/backend/pkg/server/internal/service/state_analytics/category_state_growth.go @@ -0,0 +1,250 @@ +package state_analytics + +import ( + "context" + "fmt" + "sort" + "strings" + "time" + + pb "github.com/ethpandaops/lab/backend/pkg/server/proto/state_analytics" + "google.golang.org/protobuf/types/known/timestamppb" +) + +// GetStateGrowthByCategory returns time-series state growth data categorized by contract type +func (s *Service) GetStateGrowthByCategory( + ctx context.Context, + req *pb.GetStateGrowthByCategoryRequest, +) (*pb.GetStateGrowthByCategoryResponse, error) { + startTime := time.Now() + method := "GetStateGrowthByCategory" + + // Get network from context + network, err := s.getNetworkFromContext(ctx) + if err != nil { + s.recordMetrics(method, "unknown", StatusError, time.Since(startTime).Seconds()) + return nil, err + } + + s.log.WithField("network", network).Debug("Fetching state growth by category") + + // Get ClickHouse client for network + client, err := s.getClient(network) + if err != nil { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, err + } + + // Determine time bucket expression based on granularity + var timeBucketExpr string + switch req.Granularity { + case pb.GetStateGrowthByCategoryRequest_GRANULARITY_DAILY: + // Group by day using block timestamps + timeBucketExpr = fmt.Sprintf( + "toDate(toDateTime(%d + block_number * 12))", + s.getGenesisTime(network), + ) + case pb.GetStateGrowthByCategoryRequest_GRANULARITY_MONTHLY: + // Group by month (Paradigm Figure 3 style) + timeBucketExpr = fmt.Sprintf( + "toStartOfMonth(toDateTime(%d + block_number * 12))", + s.getGenesisTime(network), + ) + case pb.GetStateGrowthByCategoryRequest_GRANULARITY_YEARLY: + // Group by year + timeBucketExpr = fmt.Sprintf( + "toYear(toDateTime(%d + block_number * 12))", + s.getGenesisTime(network), + ) + default: + // Default to monthly + timeBucketExpr = fmt.Sprintf( + "toStartOfMonth(toDateTime(%d + block_number * 12))", + s.getGenesisTime(network), + ) + } + + // Set defaults for optional parameters + topContracts := req.TopContractsPerPeriod + if topContracts == 0 { + topContracts = 100 // Default to top 100 contracts per period + } + + // Build query with replacements + query := queryStateGrowthByCategory + query = strings.ReplaceAll(query, "{database}", network) + query = strings.ReplaceAll(query, "{start_block}", fmt.Sprintf("%d", req.StartBlock)) + query = strings.ReplaceAll(query, "{end_block}", fmt.Sprintf("%d", req.EndBlock)) + query = strings.ReplaceAll(query, "{bytes_per_slot}", fmt.Sprintf("%d", BytesPerSlot)) + query = strings.ReplaceAll(query, "{time_bucket_expression}", timeBucketExpr) + + // Execute query + rows, err := client.Query(ctx, query) + if err != nil { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, fmt.Errorf("failed to query state growth by category: %w", err) + } + + if len(rows) == 0 { + s.recordMetrics(method, network, StatusSuccess, time.Since(startTime).Seconds()) + return &pb.GetStateGrowthByCategoryResponse{ + TimeSeries: []*pb.CategoryGrowthTimeSeries{}, + }, nil + } + + // Parse results and organize by time period + type contractData struct { + address string + netSlots int64 + netBytes int64 + } + + timePeriods := make(map[interface{}][]contractData) // time_bucket -> contracts + + for _, row := range rows { + timeBucket := row["time_bucket"] // Can be Date, DateTime, or Year depending on granularity + address := getString(row, "address") + netSlots := getInt64(row, "net_slots") + netBytes := getInt64(row, "net_bytes") + + timePeriods[timeBucket] = append(timePeriods[timeBucket], contractData{ + address: address, + netSlots: netSlots, + netBytes: netBytes, + }) + } + + // Convert to sorted time series + var timeSeries []*pb.CategoryGrowthTimeSeries + + // Get sorted time periods + var sortedPeriods []interface{} + for period := range timePeriods { + sortedPeriods = append(sortedPeriods, period) + } + + // Sort periods chronologically + sort.Slice(sortedPeriods, func(i, j int) bool { + // Convert to time for comparison + ti := periodToTime(sortedPeriods[i], s.getGenesisTime(network)) + tj := periodToTime(sortedPeriods[j], s.getGenesisTime(network)) + return ti.Before(tj) + }) + + var startBlock, endBlock uint64 + genesisTime := s.getGenesisTime(network) + + for _, period := range sortedPeriods { + contracts := timePeriods[period] + + // Sort contracts by absolute net bytes (descending) and take top N + sort.Slice(contracts, func(i, j int) bool { + return abs(contracts[i].netBytes) > abs(contracts[j].netBytes) + }) + + // Limit to top N contracts per period + if len(contracts) > int(topContracts) { + contracts = contracts[:topContracts] + } + + // Calculate total for the period + var totalNetSlots int64 + var totalNetBytes int64 + for _, c := range contracts { + totalNetSlots += c.netSlots + totalNetBytes += c.netBytes + } + + // Create category (all "Other" for now, will be enhanced with labeling later) + categoryData := &pb.CategoryGrowthData{ + Category: "Other", + NetSlotsAdded: totalNetSlots, + NetBytesAdded: totalNetBytes, + TopContracts: make([]*pb.ContractGrowthData, 0, len(contracts)), + } + + // Add contract details + for _, c := range contracts { + var percentage float64 + if totalNetBytes != 0 { + percentage = (float64(c.netBytes) / float64(totalNetBytes)) * 100.0 + } + + categoryData.TopContracts = append(categoryData.TopContracts, &pb.ContractGrowthData{ + Address: c.address, + Label: "", // Will be filled by labeling service later + NetSlotsAdded: c.netSlots, + NetBytesAdded: c.netBytes, + PercentageOfCategory: percentage, + }) + } + + // Convert period to timestamp and block number + periodTime := periodToTime(period, genesisTime) + blockNumber := uint64((periodTime.Unix() - genesisTime) / 12) + + // Track start and end blocks + if startBlock == 0 || blockNumber < startBlock { + startBlock = blockNumber + } + if blockNumber > endBlock { + endBlock = blockNumber + } + + timeSeries = append(timeSeries, &pb.CategoryGrowthTimeSeries{ + Timestamp: timestamppb.New(periodTime), + BlockNumber: blockNumber, + Categories: []*pb.CategoryGrowthData{categoryData}, + TotalNetSlots: totalNetSlots, + TotalNetBytes: totalNetBytes, + }) + } + + s.recordMetrics(method, network, StatusSuccess, time.Since(startTime).Seconds()) + + return &pb.GetStateGrowthByCategoryResponse{ + TimeSeries: timeSeries, + StartBlock: startBlock, + EndBlock: endBlock, + StartTime: timestamppb.New(time.Unix(genesisTime+int64(startBlock)*12, 0)), + EndTime: timestamppb.New(time.Unix(genesisTime+int64(endBlock)*12, 0)), + }, nil +} + +// Helper function to convert ClickHouse time bucket to Go time.Time +func periodToTime(period interface{}, genesisTime int64) time.Time { + switch v := period.(type) { + case time.Time: + return v + case int64: // Year + return time.Date(int(v), 1, 1, 0, 0, 0, 0, time.UTC) + case uint64: // Year + return time.Date(int(v), 1, 1, 0, 0, 0, 0, time.UTC) + case int32: + return time.Date(int(v), 1, 1, 0, 0, 0, 0, time.UTC) + case uint32: + return time.Date(int(v), 1, 1, 0, 0, 0, 0, time.UTC) + case string: + // Try to parse as date + t, err := time.Parse("2006-01-02", v) + if err == nil { + return t + } + // Try as datetime + t, err = time.Parse(time.RFC3339, v) + if err == nil { + return t + } + return time.Unix(genesisTime, 0) + default: + return time.Unix(genesisTime, 0) + } +} + +// Helper function to get absolute value +func abs(n int64) int64 { + if n < 0 { + return -n + } + return n +} diff --git a/backend/pkg/server/internal/service/state_analytics/queries.go b/backend/pkg/server/internal/service/state_analytics/queries.go index 4a7ed2713..a50ec3cbf 100644 --- a/backend/pkg/server/internal/service/state_analytics/queries.go +++ b/backend/pkg/server/internal/service/state_analytics/queries.go @@ -12,61 +12,68 @@ const ( ) // Query to get latest block state delta +// Uses canonical_execution_storage_diffs table for execution layer data +// +// TODO(performance): This query scans the entire canonical_execution_storage_diffs table (10.6B+ rows) +// which causes severe performance issues (30s+ timeouts). We need to either: +// 1. Create a materialized view that pre-aggregates state changes by block number +// 2. Add indexes on (block_number, from_value, to_value) columns +// 3. Create a separate pre-aggregated table (like int_address_storage_slot_*) but for execution layer +// 4. Use the existing int_address_storage_slot_* tables but add proper execution block number mapping const queryLatestBlockDelta = ` WITH latest_block AS ( SELECT MAX(block_number) as max_block - FROM {database}.int_address_storage_slot_last_access -), -new_slots AS ( - SELECT count() as count - FROM {database}.int_address_storage_slot_first_access - WHERE block_number = (SELECT max_block FROM latest_block) + FROM {database}.canonical_execution_storage_diffs ), -last_access AS ( +storage_stats AS ( SELECT - count() as total, - countIf(value = '0x0000000000000000000000000000000000000000000000000000000000000000') as cleared - FROM {database}.int_address_storage_slot_last_access + countIf(from_value = '' OR from_value = '0x0000000000000000000000000000000000000000000000000000000000000000') as new_slots, + countIf(to_value = '0x0000000000000000000000000000000000000000000000000000000000000000') as cleared_slots, + countIf( + (from_value != '' AND from_value != '0x0000000000000000000000000000000000000000000000000000000000000000') AND + (to_value != '0x0000000000000000000000000000000000000000000000000000000000000000') + ) as modified_slots + FROM {database}.canonical_execution_storage_diffs WHERE block_number = (SELECT max_block FROM latest_block) ) SELECT (SELECT max_block FROM latest_block) as block_number, - (SELECT count FROM new_slots) as new_slots, - (SELECT cleared FROM last_access) as cleared_slots, - (SELECT total FROM last_access) - (SELECT count FROM new_slots) as modified_slots + new_slots, + cleared_slots, + modified_slots +FROM storage_stats ` // Query to get top contributors for latest block +// Uses canonical_execution_storage_diffs table for execution layer data +// +// TODO(performance): This query also suffers from the same performance issue as queryLatestBlockDelta. +// See TODO comments above for solutions. This needs materialized views or pre-aggregated tables. const queryLatestBlockTopContributors = ` WITH latest_block AS ( SELECT max(block_number) as block_number - FROM {database}.int_address_storage_slot_first_access -), -new_slots AS ( - SELECT - address, - count() as new_slots - FROM {database}.int_address_storage_slot_first_access - WHERE block_number = (SELECT block_number FROM latest_block) - GROUP BY address + FROM {database}.canonical_execution_storage_diffs ), -cleared_slots AS ( +address_stats AS ( SELECT address, - countIf(value = '0x0000000000000000000000000000000000000000000000000000000000000000') as cleared_slots, - count() as modified_slots - FROM {database}.int_address_storage_slot_last_access + countIf(from_value = '' OR from_value = '0x0000000000000000000000000000000000000000000000000000000000000000') as new_slots, + countIf( + (from_value != '' AND from_value != '0x0000000000000000000000000000000000000000000000000000000000000000') AND + (to_value != '0x0000000000000000000000000000000000000000000000000000000000000000') + ) as modified_slots, + countIf(to_value = '0x0000000000000000000000000000000000000000000000000000000000000000') as cleared_slots + FROM {database}.canonical_execution_storage_diffs WHERE block_number = (SELECT block_number FROM latest_block) GROUP BY address ) SELECT - coalesce(n.address, c.address) as address, - coalesce(n.new_slots, 0) as new_slots, - coalesce(c.modified_slots, 0) as modified_slots, - coalesce(c.cleared_slots, 0) as cleared_slots, - (coalesce(n.new_slots, 0) - coalesce(c.cleared_slots, 0)) * {bytes_per_slot} as net_bytes -FROM new_slots n -FULL OUTER JOIN cleared_slots c ON n.address = c.address + address, + new_slots, + modified_slots, + cleared_slots, + (new_slots - cleared_slots) * {bytes_per_slot} as net_bytes +FROM address_stats ORDER BY abs(net_bytes) DESC LIMIT 10 ` @@ -183,6 +190,76 @@ ORDER BY abs( LIMIT 1 ` +// Query to get state growth categorized by contract (Paradigm Figures 2 & 3) +// Uses canonical_execution_storage_diffs table for execution layer data +// +// TODO(performance): CRITICAL PERFORMANCE ISSUE - This query times out (60s+) on production data. +// The canonical_execution_storage_diffs table has 10.6B+ rows and querying from genesis scans +// billions of rows. This is NOT production-ready. Solutions: +// +// Option 1 (RECOMMENDED): Create pre-aggregated materialized views +// - CREATE MATERIALIZED VIEW mv_daily_state_growth_by_address AS +// SELECT toDate(...) as day, address, sum(slots_added), sum(slots_cleared) +// FROM canonical_execution_storage_diffs GROUP BY day, address +// - Similar views for monthly/yearly aggregations +// - These views would reduce query time from 60s+ to <1s +// +// Option 2: Add proper indexes +// - INDEX idx_block_address ON canonical_execution_storage_diffs (block_number, address) +// - INDEX idx_time_address ON canonical_execution_storage_diffs (updated_date_time, address) +// - This may help but won't solve the fundamental issue of scanning billions of rows +// +// Option 3: Create a separate aggregated table +// - Similar to int_address_storage_slot_* but with EXECUTION block numbers instead of beacon slots +// - Pre-compute daily/monthly aggregations during data ingestion +// - Store results in dedicated tables: canonical_execution_daily_state_growth, etc. +// +// Until one of these solutions is implemented, this query will timeout on any reasonable time range. +const queryStateGrowthByCategory = ` +WITH block_range AS ( + SELECT + CASE + WHEN {start_block} = 0 THEN (SELECT min(block_number) FROM {database}.canonical_execution_storage_diffs) + ELSE {start_block} + END as start_block, + CASE + WHEN {end_block} = 0 THEN (SELECT max(block_number) FROM {database}.canonical_execution_storage_diffs) + ELSE {end_block} + END as end_block +), +-- Get storage changes per address per time bucket +storage_changes AS ( + SELECT + {time_bucket_expression} as time_bucket, + address, + -- Count new slots (from_value is empty/zero) + countIf(from_value = '' OR from_value = '0x0000000000000000000000000000000000000000000000000000000000000000') as slots_added, + -- Count cleared slots (to_value is zero) + countIf(to_value = '0x0000000000000000000000000000000000000000000000000000000000000000') as slots_cleared + FROM {database}.canonical_execution_storage_diffs + WHERE block_number >= (SELECT start_block FROM block_range) + AND block_number <= (SELECT end_block FROM block_range) + GROUP BY time_bucket, address +), +-- Calculate net growth per contract per period +net_growth AS ( + SELECT + time_bucket, + address, + slots_added - slots_cleared as net_slots, + (slots_added - slots_cleared) * {bytes_per_slot} as net_bytes + FROM storage_changes +) +SELECT + time_bucket, + address, + net_slots, + net_bytes +FROM net_growth +WHERE net_bytes != 0 -- Filter out contracts with zero growth +ORDER BY time_bucket ASC, abs(net_bytes) DESC +` + // Query to get contract state composition (for Paradigm diagram) // Returns all contracts with their current storage slot counts const queryContractStateComposition = ` diff --git a/backend/pkg/server/internal/service/state_analytics/state_growth_chart.go b/backend/pkg/server/internal/service/state_analytics/state_growth_chart.go index 98fd65f33..8b3b7cd29 100644 --- a/backend/pkg/server/internal/service/state_analytics/state_growth_chart.go +++ b/backend/pkg/server/internal/service/state_analytics/state_growth_chart.go @@ -12,7 +12,8 @@ import ( const ( // Genesis times for different networks (Unix timestamps) - GenesisTimeMainnet = 1606824023 // Dec 1, 2020 12:00:23 PM UTC + // These are execution layer genesis times for use with canonical_execution_storage_diffs table + GenesisTimeMainnet = 1438269973 // July 30, 2015 3:26:13 PM UTC (Ethereum mainnet genesis) GenesisTimeHolesky = 1695902400 // Sep 28, 2023 12:00:00 PM UTC GenesisTimeHoodi = 1712923200 // Apr 12, 2024 12:00:00 PM UTC GenesisTimeSepolia = 1655733600 // Jun 20, 2022 2:00:00 PM UTC diff --git a/backend/pkg/server/proto/state_analytics/state_analytics.pb.go b/backend/pkg/server/proto/state_analytics/state_analytics.pb.go index c99c3d999..c551e85ea 100644 --- a/backend/pkg/server/proto/state_analytics/state_analytics.pb.go +++ b/backend/pkg/server/proto/state_analytics/state_analytics.pb.go @@ -2,7 +2,7 @@ // versions: // protoc-gen-go v1.36.10 // protoc v5.29.3 -// source: state_analytics.proto +// source: pkg/server/proto/state_analytics/state_analytics.proto package state_analytics @@ -58,11 +58,11 @@ func (x GetTopStateAddersRequest_Period) String() string { } func (GetTopStateAddersRequest_Period) Descriptor() protoreflect.EnumDescriptor { - return file_state_analytics_proto_enumTypes[0].Descriptor() + return file_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[0].Descriptor() } func (GetTopStateAddersRequest_Period) Type() protoreflect.EnumType { - return &file_state_analytics_proto_enumTypes[0] + return &file_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[0] } func (x GetTopStateAddersRequest_Period) Number() protoreflect.EnumNumber { @@ -71,7 +71,7 @@ func (x GetTopStateAddersRequest_Period) Number() protoreflect.EnumNumber { // Deprecated: Use GetTopStateAddersRequest_Period.Descriptor instead. func (GetTopStateAddersRequest_Period) EnumDescriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{3, 0} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{3, 0} } type GetTopStateRemoversRequest_Period int32 @@ -110,11 +110,11 @@ func (x GetTopStateRemoversRequest_Period) String() string { } func (GetTopStateRemoversRequest_Period) Descriptor() protoreflect.EnumDescriptor { - return file_state_analytics_proto_enumTypes[1].Descriptor() + return file_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[1].Descriptor() } func (GetTopStateRemoversRequest_Period) Type() protoreflect.EnumType { - return &file_state_analytics_proto_enumTypes[1] + return &file_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[1] } func (x GetTopStateRemoversRequest_Period) Number() protoreflect.EnumNumber { @@ -123,7 +123,7 @@ func (x GetTopStateRemoversRequest_Period) Number() protoreflect.EnumNumber { // Deprecated: Use GetTopStateRemoversRequest_Period.Descriptor instead. func (GetTopStateRemoversRequest_Period) EnumDescriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{6, 0} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{6, 0} } type GetStateGrowthChartRequest_Period int32 @@ -165,11 +165,11 @@ func (x GetStateGrowthChartRequest_Period) String() string { } func (GetStateGrowthChartRequest_Period) Descriptor() protoreflect.EnumDescriptor { - return file_state_analytics_proto_enumTypes[2].Descriptor() + return file_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[2].Descriptor() } func (GetStateGrowthChartRequest_Period) Type() protoreflect.EnumType { - return &file_state_analytics_proto_enumTypes[2] + return &file_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[2] } func (x GetStateGrowthChartRequest_Period) Number() protoreflect.EnumNumber { @@ -178,7 +178,7 @@ func (x GetStateGrowthChartRequest_Period) Number() protoreflect.EnumNumber { // Deprecated: Use GetStateGrowthChartRequest_Period.Descriptor instead. func (GetStateGrowthChartRequest_Period) EnumDescriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{9, 0} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{9, 0} } type GetStateGrowthChartRequest_Granularity int32 @@ -217,11 +217,11 @@ func (x GetStateGrowthChartRequest_Granularity) String() string { } func (GetStateGrowthChartRequest_Granularity) Descriptor() protoreflect.EnumDescriptor { - return file_state_analytics_proto_enumTypes[3].Descriptor() + return file_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[3].Descriptor() } func (GetStateGrowthChartRequest_Granularity) Type() protoreflect.EnumType { - return &file_state_analytics_proto_enumTypes[3] + return &file_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[3] } func (x GetStateGrowthChartRequest_Granularity) Number() protoreflect.EnumNumber { @@ -230,7 +230,7 @@ func (x GetStateGrowthChartRequest_Granularity) Number() protoreflect.EnumNumber // Deprecated: Use GetStateGrowthChartRequest_Granularity.Descriptor instead. func (GetStateGrowthChartRequest_Granularity) EnumDescriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{9, 1} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{9, 1} } type ContractStateEvent_EventType int32 @@ -269,11 +269,11 @@ func (x ContractStateEvent_EventType) String() string { } func (ContractStateEvent_EventType) Descriptor() protoreflect.EnumDescriptor { - return file_state_analytics_proto_enumTypes[4].Descriptor() + return file_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[4].Descriptor() } func (ContractStateEvent_EventType) Type() protoreflect.EnumType { - return &file_state_analytics_proto_enumTypes[4] + return &file_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[4] } func (x ContractStateEvent_EventType) Number() protoreflect.EnumNumber { @@ -282,7 +282,59 @@ func (x ContractStateEvent_EventType) Number() protoreflect.EnumNumber { // Deprecated: Use ContractStateEvent_EventType.Descriptor instead. func (ContractStateEvent_EventType) EnumDescriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{16, 0} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{16, 0} +} + +type GetStateGrowthByCategoryRequest_Granularity int32 + +const ( + GetStateGrowthByCategoryRequest_GRANULARITY_UNSPECIFIED GetStateGrowthByCategoryRequest_Granularity = 0 + GetStateGrowthByCategoryRequest_GRANULARITY_DAILY GetStateGrowthByCategoryRequest_Granularity = 1 // Daily state growth (like Figure 3 but daily) + GetStateGrowthByCategoryRequest_GRANULARITY_MONTHLY GetStateGrowthByCategoryRequest_Granularity = 2 // Monthly state growth (Paradigm Figure 3) + GetStateGrowthByCategoryRequest_GRANULARITY_YEARLY GetStateGrowthByCategoryRequest_Granularity = 3 // Yearly aggregates +) + +// Enum value maps for GetStateGrowthByCategoryRequest_Granularity. +var ( + GetStateGrowthByCategoryRequest_Granularity_name = map[int32]string{ + 0: "GRANULARITY_UNSPECIFIED", + 1: "GRANULARITY_DAILY", + 2: "GRANULARITY_MONTHLY", + 3: "GRANULARITY_YEARLY", + } + GetStateGrowthByCategoryRequest_Granularity_value = map[string]int32{ + "GRANULARITY_UNSPECIFIED": 0, + "GRANULARITY_DAILY": 1, + "GRANULARITY_MONTHLY": 2, + "GRANULARITY_YEARLY": 3, + } +) + +func (x GetStateGrowthByCategoryRequest_Granularity) Enum() *GetStateGrowthByCategoryRequest_Granularity { + p := new(GetStateGrowthByCategoryRequest_Granularity) + *p = x + return p +} + +func (x GetStateGrowthByCategoryRequest_Granularity) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (GetStateGrowthByCategoryRequest_Granularity) Descriptor() protoreflect.EnumDescriptor { + return file_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[5].Descriptor() +} + +func (GetStateGrowthByCategoryRequest_Granularity) Type() protoreflect.EnumType { + return &file_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes[5] +} + +func (x GetStateGrowthByCategoryRequest_Granularity) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use GetStateGrowthByCategoryRequest_Granularity.Descriptor instead. +func (GetStateGrowthByCategoryRequest_Granularity) EnumDescriptor() ([]byte, []int) { + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{24, 0} } // Request/Response messages for GetLatestBlockDelta @@ -294,7 +346,7 @@ type GetLatestBlockDeltaRequest struct { func (x *GetLatestBlockDeltaRequest) Reset() { *x = GetLatestBlockDeltaRequest{} - mi := &file_state_analytics_proto_msgTypes[0] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -306,7 +358,7 @@ func (x *GetLatestBlockDeltaRequest) String() string { func (*GetLatestBlockDeltaRequest) ProtoMessage() {} func (x *GetLatestBlockDeltaRequest) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[0] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -319,7 +371,7 @@ func (x *GetLatestBlockDeltaRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLatestBlockDeltaRequest.ProtoReflect.Descriptor instead. func (*GetLatestBlockDeltaRequest) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{0} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{0} } type GetLatestBlockDeltaResponse struct { @@ -338,7 +390,7 @@ type GetLatestBlockDeltaResponse struct { func (x *GetLatestBlockDeltaResponse) Reset() { *x = GetLatestBlockDeltaResponse{} - mi := &file_state_analytics_proto_msgTypes[1] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -350,7 +402,7 @@ func (x *GetLatestBlockDeltaResponse) String() string { func (*GetLatestBlockDeltaResponse) ProtoMessage() {} func (x *GetLatestBlockDeltaResponse) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[1] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[1] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -363,7 +415,7 @@ func (x *GetLatestBlockDeltaResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLatestBlockDeltaResponse.ProtoReflect.Descriptor instead. func (*GetLatestBlockDeltaResponse) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{1} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{1} } func (x *GetLatestBlockDeltaResponse) GetBlockNumber() uint64 { @@ -436,7 +488,7 @@ type ContractStateDelta struct { func (x *ContractStateDelta) Reset() { *x = ContractStateDelta{} - mi := &file_state_analytics_proto_msgTypes[2] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -448,7 +500,7 @@ func (x *ContractStateDelta) String() string { func (*ContractStateDelta) ProtoMessage() {} func (x *ContractStateDelta) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[2] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -461,7 +513,7 @@ func (x *ContractStateDelta) ProtoReflect() protoreflect.Message { // Deprecated: Use ContractStateDelta.ProtoReflect.Descriptor instead. func (*ContractStateDelta) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{2} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{2} } func (x *ContractStateDelta) GetAddress() string { @@ -517,7 +569,7 @@ type GetTopStateAddersRequest struct { func (x *GetTopStateAddersRequest) Reset() { *x = GetTopStateAddersRequest{} - mi := &file_state_analytics_proto_msgTypes[3] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -529,7 +581,7 @@ func (x *GetTopStateAddersRequest) String() string { func (*GetTopStateAddersRequest) ProtoMessage() {} func (x *GetTopStateAddersRequest) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[3] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -542,7 +594,7 @@ func (x *GetTopStateAddersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTopStateAddersRequest.ProtoReflect.Descriptor instead. func (*GetTopStateAddersRequest) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{3} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{3} } func (x *GetTopStateAddersRequest) GetPeriod() GetTopStateAddersRequest_Period { @@ -570,7 +622,7 @@ type GetTopStateAddersResponse struct { func (x *GetTopStateAddersResponse) Reset() { *x = GetTopStateAddersResponse{} - mi := &file_state_analytics_proto_msgTypes[4] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -582,7 +634,7 @@ func (x *GetTopStateAddersResponse) String() string { func (*GetTopStateAddersResponse) ProtoMessage() {} func (x *GetTopStateAddersResponse) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[4] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -595,7 +647,7 @@ func (x *GetTopStateAddersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTopStateAddersResponse.ProtoReflect.Descriptor instead. func (*GetTopStateAddersResponse) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{4} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{4} } func (x *GetTopStateAddersResponse) GetAdders() []*StateAdder { @@ -634,7 +686,7 @@ type StateAdder struct { func (x *StateAdder) Reset() { *x = StateAdder{} - mi := &file_state_analytics_proto_msgTypes[5] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -646,7 +698,7 @@ func (x *StateAdder) String() string { func (*StateAdder) ProtoMessage() {} func (x *StateAdder) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[5] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -659,7 +711,7 @@ func (x *StateAdder) ProtoReflect() protoreflect.Message { // Deprecated: Use StateAdder.ProtoReflect.Descriptor instead. func (*StateAdder) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{5} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{5} } func (x *StateAdder) GetRank() uint32 { @@ -722,7 +774,7 @@ type GetTopStateRemoversRequest struct { func (x *GetTopStateRemoversRequest) Reset() { *x = GetTopStateRemoversRequest{} - mi := &file_state_analytics_proto_msgTypes[6] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -734,7 +786,7 @@ func (x *GetTopStateRemoversRequest) String() string { func (*GetTopStateRemoversRequest) ProtoMessage() {} func (x *GetTopStateRemoversRequest) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[6] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -747,7 +799,7 @@ func (x *GetTopStateRemoversRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTopStateRemoversRequest.ProtoReflect.Descriptor instead. func (*GetTopStateRemoversRequest) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{6} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{6} } func (x *GetTopStateRemoversRequest) GetPeriod() GetTopStateRemoversRequest_Period { @@ -775,7 +827,7 @@ type GetTopStateRemoversResponse struct { func (x *GetTopStateRemoversResponse) Reset() { *x = GetTopStateRemoversResponse{} - mi := &file_state_analytics_proto_msgTypes[7] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -787,7 +839,7 @@ func (x *GetTopStateRemoversResponse) String() string { func (*GetTopStateRemoversResponse) ProtoMessage() {} func (x *GetTopStateRemoversResponse) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[7] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -800,7 +852,7 @@ func (x *GetTopStateRemoversResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTopStateRemoversResponse.ProtoReflect.Descriptor instead. func (*GetTopStateRemoversResponse) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{7} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{7} } func (x *GetTopStateRemoversResponse) GetRemovers() []*StateRemover { @@ -840,7 +892,7 @@ type StateRemover struct { func (x *StateRemover) Reset() { *x = StateRemover{} - mi := &file_state_analytics_proto_msgTypes[8] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -852,7 +904,7 @@ func (x *StateRemover) String() string { func (*StateRemover) ProtoMessage() {} func (x *StateRemover) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[8] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -865,7 +917,7 @@ func (x *StateRemover) ProtoReflect() protoreflect.Message { // Deprecated: Use StateRemover.ProtoReflect.Descriptor instead. func (*StateRemover) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{8} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{8} } func (x *StateRemover) GetRank() uint32 { @@ -935,7 +987,7 @@ type GetStateGrowthChartRequest struct { func (x *GetStateGrowthChartRequest) Reset() { *x = GetStateGrowthChartRequest{} - mi := &file_state_analytics_proto_msgTypes[9] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -947,7 +999,7 @@ func (x *GetStateGrowthChartRequest) String() string { func (*GetStateGrowthChartRequest) ProtoMessage() {} func (x *GetStateGrowthChartRequest) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[9] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -960,7 +1012,7 @@ func (x *GetStateGrowthChartRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetStateGrowthChartRequest.ProtoReflect.Descriptor instead. func (*GetStateGrowthChartRequest) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{9} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{9} } func (x *GetStateGrowthChartRequest) GetPeriod() GetStateGrowthChartRequest_Period { @@ -987,7 +1039,7 @@ type GetStateGrowthChartResponse struct { func (x *GetStateGrowthChartResponse) Reset() { *x = GetStateGrowthChartResponse{} - mi := &file_state_analytics_proto_msgTypes[10] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -999,7 +1051,7 @@ func (x *GetStateGrowthChartResponse) String() string { func (*GetStateGrowthChartResponse) ProtoMessage() {} func (x *GetStateGrowthChartResponse) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[10] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1012,7 +1064,7 @@ func (x *GetStateGrowthChartResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetStateGrowthChartResponse.ProtoReflect.Descriptor instead. func (*GetStateGrowthChartResponse) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{10} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{10} } func (x *GetStateGrowthChartResponse) GetDataPoints() []*StateGrowthDataPoint { @@ -1045,7 +1097,7 @@ type StateGrowthDataPoint struct { func (x *StateGrowthDataPoint) Reset() { *x = StateGrowthDataPoint{} - mi := &file_state_analytics_proto_msgTypes[11] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1057,7 +1109,7 @@ func (x *StateGrowthDataPoint) String() string { func (*StateGrowthDataPoint) ProtoMessage() {} func (x *StateGrowthDataPoint) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[11] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1070,7 +1122,7 @@ func (x *StateGrowthDataPoint) ProtoReflect() protoreflect.Message { // Deprecated: Use StateGrowthDataPoint.ProtoReflect.Descriptor instead. func (*StateGrowthDataPoint) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{11} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{11} } func (x *StateGrowthDataPoint) GetTimestamp() *timestamppb.Timestamp { @@ -1144,7 +1196,7 @@ type StateSummary struct { func (x *StateSummary) Reset() { *x = StateSummary{} - mi := &file_state_analytics_proto_msgTypes[12] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1156,7 +1208,7 @@ func (x *StateSummary) String() string { func (*StateSummary) ProtoMessage() {} func (x *StateSummary) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[12] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1169,7 +1221,7 @@ func (x *StateSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use StateSummary.ProtoReflect.Descriptor instead. func (*StateSummary) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{12} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{12} } func (x *StateSummary) GetTotalSlotsAdded() uint64 { @@ -1232,7 +1284,7 @@ type GetContractStateActivityRequest struct { func (x *GetContractStateActivityRequest) Reset() { *x = GetContractStateActivityRequest{} - mi := &file_state_analytics_proto_msgTypes[13] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1244,7 +1296,7 @@ func (x *GetContractStateActivityRequest) String() string { func (*GetContractStateActivityRequest) ProtoMessage() {} func (x *GetContractStateActivityRequest) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[13] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1257,7 +1309,7 @@ func (x *GetContractStateActivityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetContractStateActivityRequest.ProtoReflect.Descriptor instead. func (*GetContractStateActivityRequest) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{13} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{13} } func (x *GetContractStateActivityRequest) GetAddress() string { @@ -1287,7 +1339,7 @@ type GetContractStateActivityResponse struct { func (x *GetContractStateActivityResponse) Reset() { *x = GetContractStateActivityResponse{} - mi := &file_state_analytics_proto_msgTypes[14] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1299,7 +1351,7 @@ func (x *GetContractStateActivityResponse) String() string { func (*GetContractStateActivityResponse) ProtoMessage() {} func (x *GetContractStateActivityResponse) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[14] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1312,7 +1364,7 @@ func (x *GetContractStateActivityResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetContractStateActivityResponse.ProtoReflect.Descriptor instead. func (*GetContractStateActivityResponse) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{14} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{14} } func (x *GetContractStateActivityResponse) GetAddress() string { @@ -1364,7 +1416,7 @@ type ContractStateMetrics struct { func (x *ContractStateMetrics) Reset() { *x = ContractStateMetrics{} - mi := &file_state_analytics_proto_msgTypes[15] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1376,7 +1428,7 @@ func (x *ContractStateMetrics) String() string { func (*ContractStateMetrics) ProtoMessage() {} func (x *ContractStateMetrics) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[15] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1389,7 +1441,7 @@ func (x *ContractStateMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use ContractStateMetrics.ProtoReflect.Descriptor instead. func (*ContractStateMetrics) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{15} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{15} } func (x *ContractStateMetrics) GetTotalSlots() uint64 { @@ -1447,7 +1499,7 @@ type ContractStateEvent struct { func (x *ContractStateEvent) Reset() { *x = ContractStateEvent{} - mi := &file_state_analytics_proto_msgTypes[16] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1459,7 +1511,7 @@ func (x *ContractStateEvent) String() string { func (*ContractStateEvent) ProtoMessage() {} func (x *ContractStateEvent) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[16] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1472,7 +1524,7 @@ func (x *ContractStateEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use ContractStateEvent.ProtoReflect.Descriptor instead. func (*ContractStateEvent) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{16} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{16} } func (x *ContractStateEvent) GetBlockNumber() uint64 { @@ -1522,7 +1574,7 @@ type GetContractStateCompositionRequest struct { func (x *GetContractStateCompositionRequest) Reset() { *x = GetContractStateCompositionRequest{} - mi := &file_state_analytics_proto_msgTypes[17] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1534,7 +1586,7 @@ func (x *GetContractStateCompositionRequest) String() string { func (*GetContractStateCompositionRequest) ProtoMessage() {} func (x *GetContractStateCompositionRequest) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[17] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1547,7 +1599,7 @@ func (x *GetContractStateCompositionRequest) ProtoReflect() protoreflect.Message // Deprecated: Use GetContractStateCompositionRequest.ProtoReflect.Descriptor instead. func (*GetContractStateCompositionRequest) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{17} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{17} } func (x *GetContractStateCompositionRequest) GetLimit() uint32 { @@ -1583,7 +1635,7 @@ type GetContractStateCompositionResponse struct { func (x *GetContractStateCompositionResponse) Reset() { *x = GetContractStateCompositionResponse{} - mi := &file_state_analytics_proto_msgTypes[18] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1595,7 +1647,7 @@ func (x *GetContractStateCompositionResponse) String() string { func (*GetContractStateCompositionResponse) ProtoMessage() {} func (x *GetContractStateCompositionResponse) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[18] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1608,7 +1660,7 @@ func (x *GetContractStateCompositionResponse) ProtoReflect() protoreflect.Messag // Deprecated: Use GetContractStateCompositionResponse.ProtoReflect.Descriptor instead. func (*GetContractStateCompositionResponse) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{18} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{18} } func (x *GetContractStateCompositionResponse) GetContracts() []*ContractStateEntry { @@ -1653,7 +1705,7 @@ type ContractStateEntry struct { func (x *ContractStateEntry) Reset() { *x = ContractStateEntry{} - mi := &file_state_analytics_proto_msgTypes[19] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1665,7 +1717,7 @@ func (x *ContractStateEntry) String() string { func (*ContractStateEntry) ProtoMessage() {} func (x *ContractStateEntry) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[19] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1678,7 +1730,7 @@ func (x *ContractStateEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use ContractStateEntry.ProtoReflect.Descriptor instead. func (*ContractStateEntry) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{19} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{19} } func (x *ContractStateEntry) GetAddress() string { @@ -1736,7 +1788,7 @@ type ContractState struct { func (x *ContractState) Reset() { *x = ContractState{} - mi := &file_state_analytics_proto_msgTypes[20] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1748,7 +1800,7 @@ func (x *ContractState) String() string { func (*ContractState) ProtoMessage() {} func (x *ContractState) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[20] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1761,7 +1813,7 @@ func (x *ContractState) ProtoReflect() protoreflect.Message { // Deprecated: Use ContractState.ProtoReflect.Descriptor instead. func (*ContractState) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{20} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{20} } func (x *ContractState) GetStorageSlotCount() uint64 { @@ -1810,7 +1862,7 @@ type GetHierarchicalStateRequest struct { func (x *GetHierarchicalStateRequest) Reset() { *x = GetHierarchicalStateRequest{} - mi := &file_state_analytics_proto_msgTypes[21] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1822,7 +1874,7 @@ func (x *GetHierarchicalStateRequest) String() string { func (*GetHierarchicalStateRequest) ProtoMessage() {} func (x *GetHierarchicalStateRequest) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[21] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1835,7 +1887,7 @@ func (x *GetHierarchicalStateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetHierarchicalStateRequest.ProtoReflect.Descriptor instead. func (*GetHierarchicalStateRequest) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{21} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{21} } func (x *GetHierarchicalStateRequest) GetMaxDepth() uint32 { @@ -1863,7 +1915,7 @@ type GetHierarchicalStateResponse struct { func (x *GetHierarchicalStateResponse) Reset() { *x = GetHierarchicalStateResponse{} - mi := &file_state_analytics_proto_msgTypes[22] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1875,7 +1927,7 @@ func (x *GetHierarchicalStateResponse) String() string { func (*GetHierarchicalStateResponse) ProtoMessage() {} func (x *GetHierarchicalStateResponse) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[22] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1888,7 +1940,7 @@ func (x *GetHierarchicalStateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetHierarchicalStateResponse.ProtoReflect.Descriptor instead. func (*GetHierarchicalStateResponse) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{22} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{22} } func (x *GetHierarchicalStateResponse) GetRoot() *StateNode { @@ -1925,7 +1977,7 @@ type StateNode struct { func (x *StateNode) Reset() { *x = StateNode{} - mi := &file_state_analytics_proto_msgTypes[23] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1937,7 +1989,7 @@ func (x *StateNode) String() string { func (*StateNode) ProtoMessage() {} func (x *StateNode) ProtoReflect() protoreflect.Message { - mi := &file_state_analytics_proto_msgTypes[23] + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1950,7 +2002,7 @@ func (x *StateNode) ProtoReflect() protoreflect.Message { // Deprecated: Use StateNode.ProtoReflect.Descriptor instead. func (*StateNode) Descriptor() ([]byte, []int) { - return file_state_analytics_proto_rawDescGZIP(), []int{23} + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{23} } func (x *StateNode) GetName() string { @@ -1988,11 +2040,384 @@ func (x *StateNode) GetMetadata() map[string]string { return nil } -var File_state_analytics_proto protoreflect.FileDescriptor +// Request/Response for GetStateGrowthByCategory (Paradigm Figures 2 & 3) +type GetStateGrowthByCategoryRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Granularity GetStateGrowthByCategoryRequest_Granularity `protobuf:"varint,1,opt,name=granularity,proto3,enum=state_analytics.GetStateGrowthByCategoryRequest_Granularity" json:"granularity,omitempty"` + StartBlock uint64 `protobuf:"varint,2,opt,name=start_block,json=startBlock,proto3" json:"start_block,omitempty"` // Optional: start from specific block (0 = genesis) + EndBlock uint64 `protobuf:"varint,3,opt,name=end_block,json=endBlock,proto3" json:"end_block,omitempty"` // Optional: end at specific block (0 = latest) + TopContractsPerPeriod uint32 `protobuf:"varint,4,opt,name=top_contracts_per_period,json=topContractsPerPeriod,proto3" json:"top_contracts_per_period,omitempty"` // Top N contracts per time period (default 100) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetStateGrowthByCategoryRequest) Reset() { + *x = GetStateGrowthByCategoryRequest{} + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetStateGrowthByCategoryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetStateGrowthByCategoryRequest) ProtoMessage() {} + +func (x *GetStateGrowthByCategoryRequest) ProtoReflect() protoreflect.Message { + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[24] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetStateGrowthByCategoryRequest.ProtoReflect.Descriptor instead. +func (*GetStateGrowthByCategoryRequest) Descriptor() ([]byte, []int) { + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{24} +} + +func (x *GetStateGrowthByCategoryRequest) GetGranularity() GetStateGrowthByCategoryRequest_Granularity { + if x != nil { + return x.Granularity + } + return GetStateGrowthByCategoryRequest_GRANULARITY_UNSPECIFIED +} + +func (x *GetStateGrowthByCategoryRequest) GetStartBlock() uint64 { + if x != nil { + return x.StartBlock + } + return 0 +} + +func (x *GetStateGrowthByCategoryRequest) GetEndBlock() uint64 { + if x != nil { + return x.EndBlock + } + return 0 +} + +func (x *GetStateGrowthByCategoryRequest) GetTopContractsPerPeriod() uint32 { + if x != nil { + return x.TopContractsPerPeriod + } + return 0 +} + +type GetStateGrowthByCategoryResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + TimeSeries []*CategoryGrowthTimeSeries `protobuf:"bytes,1,rep,name=time_series,json=timeSeries,proto3" json:"time_series,omitempty"` + StartBlock uint64 `protobuf:"varint,2,opt,name=start_block,json=startBlock,proto3" json:"start_block,omitempty"` + EndBlock uint64 `protobuf:"varint,3,opt,name=end_block,json=endBlock,proto3" json:"end_block,omitempty"` + StartTime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` + EndTime *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetStateGrowthByCategoryResponse) Reset() { + *x = GetStateGrowthByCategoryResponse{} + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetStateGrowthByCategoryResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetStateGrowthByCategoryResponse) ProtoMessage() {} + +func (x *GetStateGrowthByCategoryResponse) ProtoReflect() protoreflect.Message { + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[25] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetStateGrowthByCategoryResponse.ProtoReflect.Descriptor instead. +func (*GetStateGrowthByCategoryResponse) Descriptor() ([]byte, []int) { + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{25} +} + +func (x *GetStateGrowthByCategoryResponse) GetTimeSeries() []*CategoryGrowthTimeSeries { + if x != nil { + return x.TimeSeries + } + return nil +} + +func (x *GetStateGrowthByCategoryResponse) GetStartBlock() uint64 { + if x != nil { + return x.StartBlock + } + return 0 +} + +func (x *GetStateGrowthByCategoryResponse) GetEndBlock() uint64 { + if x != nil { + return x.EndBlock + } + return 0 +} + +func (x *GetStateGrowthByCategoryResponse) GetStartTime() *timestamppb.Timestamp { + if x != nil { + return x.StartTime + } + return nil +} + +func (x *GetStateGrowthByCategoryResponse) GetEndTime() *timestamppb.Timestamp { + if x != nil { + return x.EndTime + } + return nil +} + +type CategoryGrowthTimeSeries struct { + state protoimpl.MessageState `protogen:"open.v1"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Period timestamp (start of day/month/year) + BlockNumber uint64 `protobuf:"varint,2,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` // Representative block for this period + Categories []*CategoryGrowthData `protobuf:"bytes,3,rep,name=categories,proto3" json:"categories,omitempty"` + TotalNetSlots int64 `protobuf:"varint,4,opt,name=total_net_slots,json=totalNetSlots,proto3" json:"total_net_slots,omitempty"` // Total across all categories + TotalNetBytes int64 `protobuf:"varint,5,opt,name=total_net_bytes,json=totalNetBytes,proto3" json:"total_net_bytes,omitempty"` // Total bytes across all categories + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CategoryGrowthTimeSeries) Reset() { + *x = CategoryGrowthTimeSeries{} + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CategoryGrowthTimeSeries) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CategoryGrowthTimeSeries) ProtoMessage() {} + +func (x *CategoryGrowthTimeSeries) ProtoReflect() protoreflect.Message { + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[26] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CategoryGrowthTimeSeries.ProtoReflect.Descriptor instead. +func (*CategoryGrowthTimeSeries) Descriptor() ([]byte, []int) { + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{26} +} + +func (x *CategoryGrowthTimeSeries) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp + } + return nil +} + +func (x *CategoryGrowthTimeSeries) GetBlockNumber() uint64 { + if x != nil { + return x.BlockNumber + } + return 0 +} + +func (x *CategoryGrowthTimeSeries) GetCategories() []*CategoryGrowthData { + if x != nil { + return x.Categories + } + return nil +} + +func (x *CategoryGrowthTimeSeries) GetTotalNetSlots() int64 { + if x != nil { + return x.TotalNetSlots + } + return 0 +} + +func (x *CategoryGrowthTimeSeries) GetTotalNetBytes() int64 { + if x != nil { + return x.TotalNetBytes + } + return 0 +} + +type CategoryGrowthData struct { + state protoimpl.MessageState `protogen:"open.v1"` + Category string `protobuf:"bytes,1,opt,name=category,proto3" json:"category,omitempty"` // "Other", "ERC-20", "DeFi", etc. (initially all "Other") + TopContracts []*ContractGrowthData `protobuf:"bytes,2,rep,name=top_contracts,json=topContracts,proto3" json:"top_contracts,omitempty"` // Top contributing contracts + NetSlotsAdded int64 `protobuf:"varint,3,opt,name=net_slots_added,json=netSlotsAdded,proto3" json:"net_slots_added,omitempty"` // Net slot change for this category in period + NetBytesAdded int64 `protobuf:"varint,4,opt,name=net_bytes_added,json=netBytesAdded,proto3" json:"net_bytes_added,omitempty"` // Net bytes change for this category in period + PercentageOfPeriod float64 `protobuf:"fixed64,5,opt,name=percentage_of_period,json=percentageOfPeriod,proto3" json:"percentage_of_period,omitempty"` // % of total growth in this period + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CategoryGrowthData) Reset() { + *x = CategoryGrowthData{} + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CategoryGrowthData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CategoryGrowthData) ProtoMessage() {} + +func (x *CategoryGrowthData) ProtoReflect() protoreflect.Message { + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[27] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CategoryGrowthData.ProtoReflect.Descriptor instead. +func (*CategoryGrowthData) Descriptor() ([]byte, []int) { + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{27} +} + +func (x *CategoryGrowthData) GetCategory() string { + if x != nil { + return x.Category + } + return "" +} + +func (x *CategoryGrowthData) GetTopContracts() []*ContractGrowthData { + if x != nil { + return x.TopContracts + } + return nil +} + +func (x *CategoryGrowthData) GetNetSlotsAdded() int64 { + if x != nil { + return x.NetSlotsAdded + } + return 0 +} + +func (x *CategoryGrowthData) GetNetBytesAdded() int64 { + if x != nil { + return x.NetBytesAdded + } + return 0 +} + +func (x *CategoryGrowthData) GetPercentageOfPeriod() float64 { + if x != nil { + return x.PercentageOfPeriod + } + return 0 +} + +type ContractGrowthData struct { + state protoimpl.MessageState `protogen:"open.v1"` + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty"` // Optional contract name + NetSlotsAdded int64 `protobuf:"varint,3,opt,name=net_slots_added,json=netSlotsAdded,proto3" json:"net_slots_added,omitempty"` // Can be negative if slots were cleared + NetBytesAdded int64 `protobuf:"varint,4,opt,name=net_bytes_added,json=netBytesAdded,proto3" json:"net_bytes_added,omitempty"` + PercentageOfCategory float64 `protobuf:"fixed64,5,opt,name=percentage_of_category,json=percentageOfCategory,proto3" json:"percentage_of_category,omitempty"` // % of category growth + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ContractGrowthData) Reset() { + *x = ContractGrowthData{} + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ContractGrowthData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContractGrowthData) ProtoMessage() {} + +func (x *ContractGrowthData) ProtoReflect() protoreflect.Message { + mi := &file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes[28] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} -const file_state_analytics_proto_rawDesc = "" + +// Deprecated: Use ContractGrowthData.ProtoReflect.Descriptor instead. +func (*ContractGrowthData) Descriptor() ([]byte, []int) { + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP(), []int{28} +} + +func (x *ContractGrowthData) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *ContractGrowthData) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + +func (x *ContractGrowthData) GetNetSlotsAdded() int64 { + if x != nil { + return x.NetSlotsAdded + } + return 0 +} + +func (x *ContractGrowthData) GetNetBytesAdded() int64 { + if x != nil { + return x.NetBytesAdded + } + return 0 +} + +func (x *ContractGrowthData) GetPercentageOfCategory() float64 { + if x != nil { + return x.PercentageOfCategory + } + return 0 +} + +var File_pkg_server_proto_state_analytics_state_analytics_proto protoreflect.FileDescriptor + +const file_pkg_server_proto_state_analytics_state_analytics_proto_rawDesc = "" + "\n" + - "\x15state_analytics.proto\x12\x0fstate_analytics\x1a\x1fgoogle/protobuf/timestamp.proto\"\x1c\n" + + "6pkg/server/proto/state_analytics/state_analytics.proto\x12\x0fstate_analytics\x1a\x1fgoogle/protobuf/timestamp.proto\"\x1c\n" + "\x1aGetLatestBlockDeltaRequest\"\xc8\x03\n" + "\x1bGetLatestBlockDeltaResponse\x12!\n" + "\fblock_number\x18\x01 \x01(\x04R\vblockNumber\x12C\n" + @@ -2167,7 +2592,47 @@ const file_state_analytics_proto_rawDesc = "" + "\bmetadata\x18\x05 \x03(\v2(.state_analytics.StateNode.MetadataEntryR\bmetadata\x1a;\n" + "\rMetadataEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x012\xd3\x06\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xec\x02\n" + + "\x1fGetStateGrowthByCategoryRequest\x12^\n" + + "\vgranularity\x18\x01 \x01(\x0e2<.state_analytics.GetStateGrowthByCategoryRequest.GranularityR\vgranularity\x12\x1f\n" + + "\vstart_block\x18\x02 \x01(\x04R\n" + + "startBlock\x12\x1b\n" + + "\tend_block\x18\x03 \x01(\x04R\bendBlock\x127\n" + + "\x18top_contracts_per_period\x18\x04 \x01(\rR\x15topContractsPerPeriod\"r\n" + + "\vGranularity\x12\x1b\n" + + "\x17GRANULARITY_UNSPECIFIED\x10\x00\x12\x15\n" + + "\x11GRANULARITY_DAILY\x10\x01\x12\x17\n" + + "\x13GRANULARITY_MONTHLY\x10\x02\x12\x16\n" + + "\x12GRANULARITY_YEARLY\x10\x03\"\x9e\x02\n" + + " GetStateGrowthByCategoryResponse\x12J\n" + + "\vtime_series\x18\x01 \x03(\v2).state_analytics.CategoryGrowthTimeSeriesR\n" + + "timeSeries\x12\x1f\n" + + "\vstart_block\x18\x02 \x01(\x04R\n" + + "startBlock\x12\x1b\n" + + "\tend_block\x18\x03 \x01(\x04R\bendBlock\x129\n" + + "\n" + + "start_time\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\tstartTime\x125\n" + + "\bend_time\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\aendTime\"\x8c\x02\n" + + "\x18CategoryGrowthTimeSeries\x128\n" + + "\ttimestamp\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\ttimestamp\x12!\n" + + "\fblock_number\x18\x02 \x01(\x04R\vblockNumber\x12C\n" + + "\n" + + "categories\x18\x03 \x03(\v2#.state_analytics.CategoryGrowthDataR\n" + + "categories\x12&\n" + + "\x0ftotal_net_slots\x18\x04 \x01(\x03R\rtotalNetSlots\x12&\n" + + "\x0ftotal_net_bytes\x18\x05 \x01(\x03R\rtotalNetBytes\"\xfc\x01\n" + + "\x12CategoryGrowthData\x12\x1a\n" + + "\bcategory\x18\x01 \x01(\tR\bcategory\x12H\n" + + "\rtop_contracts\x18\x02 \x03(\v2#.state_analytics.ContractGrowthDataR\ftopContracts\x12&\n" + + "\x0fnet_slots_added\x18\x03 \x01(\x03R\rnetSlotsAdded\x12&\n" + + "\x0fnet_bytes_added\x18\x04 \x01(\x03R\rnetBytesAdded\x120\n" + + "\x14percentage_of_period\x18\x05 \x01(\x01R\x12percentageOfPeriod\"\xca\x01\n" + + "\x12ContractGrowthData\x12\x18\n" + + "\aaddress\x18\x01 \x01(\tR\aaddress\x12\x14\n" + + "\x05label\x18\x02 \x01(\tR\x05label\x12&\n" + + "\x0fnet_slots_added\x18\x03 \x01(\x03R\rnetSlotsAdded\x12&\n" + + "\x0fnet_bytes_added\x18\x04 \x01(\x03R\rnetBytesAdded\x124\n" + + "\x16percentage_of_category\x18\x05 \x01(\x01R\x14percentageOfCategory2\xd4\a\n" + "\x0eStateAnalytics\x12p\n" + "\x13GetLatestBlockDelta\x12+.state_analytics.GetLatestBlockDeltaRequest\x1a,.state_analytics.GetLatestBlockDeltaResponse\x12j\n" + "\x11GetTopStateAdders\x12).state_analytics.GetTopStateAddersRequest\x1a*.state_analytics.GetTopStateAddersResponse\x12p\n" + @@ -2175,120 +2640,136 @@ const file_state_analytics_proto_rawDesc = "" + "\x13GetStateGrowthChart\x12+.state_analytics.GetStateGrowthChartRequest\x1a,.state_analytics.GetStateGrowthChartResponse\x12\x7f\n" + "\x18GetContractStateActivity\x120.state_analytics.GetContractStateActivityRequest\x1a1.state_analytics.GetContractStateActivityResponse\x12\x88\x01\n" + "\x1bGetContractStateComposition\x123.state_analytics.GetContractStateCompositionRequest\x1a4.state_analytics.GetContractStateCompositionResponse\x12s\n" + - "\x14GetHierarchicalState\x12,.state_analytics.GetHierarchicalStateRequest\x1a-.state_analytics.GetHierarchicalStateResponseBEZCgithub.com/ethpandaops/lab/backend/pkg/server/proto/state_analyticsb\x06proto3" + "\x14GetHierarchicalState\x12,.state_analytics.GetHierarchicalStateRequest\x1a-.state_analytics.GetHierarchicalStateResponse\x12\x7f\n" + + "\x18GetStateGrowthByCategory\x120.state_analytics.GetStateGrowthByCategoryRequest\x1a1.state_analytics.GetStateGrowthByCategoryResponseBEZCgithub.com/ethpandaops/lab/backend/pkg/server/proto/state_analyticsb\x06proto3" var ( - file_state_analytics_proto_rawDescOnce sync.Once - file_state_analytics_proto_rawDescData []byte + file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescOnce sync.Once + file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescData []byte ) -func file_state_analytics_proto_rawDescGZIP() []byte { - file_state_analytics_proto_rawDescOnce.Do(func() { - file_state_analytics_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_state_analytics_proto_rawDesc), len(file_state_analytics_proto_rawDesc))) +func file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescGZIP() []byte { + file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescOnce.Do(func() { + file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_pkg_server_proto_state_analytics_state_analytics_proto_rawDesc), len(file_pkg_server_proto_state_analytics_state_analytics_proto_rawDesc))) }) - return file_state_analytics_proto_rawDescData -} - -var file_state_analytics_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_state_analytics_proto_msgTypes = make([]protoimpl.MessageInfo, 25) -var file_state_analytics_proto_goTypes = []any{ - (GetTopStateAddersRequest_Period)(0), // 0: state_analytics.GetTopStateAddersRequest.Period - (GetTopStateRemoversRequest_Period)(0), // 1: state_analytics.GetTopStateRemoversRequest.Period - (GetStateGrowthChartRequest_Period)(0), // 2: state_analytics.GetStateGrowthChartRequest.Period - (GetStateGrowthChartRequest_Granularity)(0), // 3: state_analytics.GetStateGrowthChartRequest.Granularity - (ContractStateEvent_EventType)(0), // 4: state_analytics.ContractStateEvent.EventType - (*GetLatestBlockDeltaRequest)(nil), // 5: state_analytics.GetLatestBlockDeltaRequest - (*GetLatestBlockDeltaResponse)(nil), // 6: state_analytics.GetLatestBlockDeltaResponse - (*ContractStateDelta)(nil), // 7: state_analytics.ContractStateDelta - (*GetTopStateAddersRequest)(nil), // 8: state_analytics.GetTopStateAddersRequest - (*GetTopStateAddersResponse)(nil), // 9: state_analytics.GetTopStateAddersResponse - (*StateAdder)(nil), // 10: state_analytics.StateAdder - (*GetTopStateRemoversRequest)(nil), // 11: state_analytics.GetTopStateRemoversRequest - (*GetTopStateRemoversResponse)(nil), // 12: state_analytics.GetTopStateRemoversResponse - (*StateRemover)(nil), // 13: state_analytics.StateRemover - (*GetStateGrowthChartRequest)(nil), // 14: state_analytics.GetStateGrowthChartRequest - (*GetStateGrowthChartResponse)(nil), // 15: state_analytics.GetStateGrowthChartResponse - (*StateGrowthDataPoint)(nil), // 16: state_analytics.StateGrowthDataPoint - (*StateSummary)(nil), // 17: state_analytics.StateSummary - (*GetContractStateActivityRequest)(nil), // 18: state_analytics.GetContractStateActivityRequest - (*GetContractStateActivityResponse)(nil), // 19: state_analytics.GetContractStateActivityResponse - (*ContractStateMetrics)(nil), // 20: state_analytics.ContractStateMetrics - (*ContractStateEvent)(nil), // 21: state_analytics.ContractStateEvent - (*GetContractStateCompositionRequest)(nil), // 22: state_analytics.GetContractStateCompositionRequest - (*GetContractStateCompositionResponse)(nil), // 23: state_analytics.GetContractStateCompositionResponse - (*ContractStateEntry)(nil), // 24: state_analytics.ContractStateEntry - (*ContractState)(nil), // 25: state_analytics.ContractState - (*GetHierarchicalStateRequest)(nil), // 26: state_analytics.GetHierarchicalStateRequest - (*GetHierarchicalStateResponse)(nil), // 27: state_analytics.GetHierarchicalStateResponse - (*StateNode)(nil), // 28: state_analytics.StateNode - nil, // 29: state_analytics.StateNode.MetadataEntry - (*timestamppb.Timestamp)(nil), // 30: google.protobuf.Timestamp -} -var file_state_analytics_proto_depIdxs = []int32{ - 30, // 0: state_analytics.GetLatestBlockDeltaResponse.block_timestamp:type_name -> google.protobuf.Timestamp - 7, // 1: state_analytics.GetLatestBlockDeltaResponse.top_contributors:type_name -> state_analytics.ContractStateDelta + return file_pkg_server_proto_state_analytics_state_analytics_proto_rawDescData +} + +var file_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes = make([]protoimpl.EnumInfo, 6) +var file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes = make([]protoimpl.MessageInfo, 30) +var file_pkg_server_proto_state_analytics_state_analytics_proto_goTypes = []any{ + (GetTopStateAddersRequest_Period)(0), // 0: state_analytics.GetTopStateAddersRequest.Period + (GetTopStateRemoversRequest_Period)(0), // 1: state_analytics.GetTopStateRemoversRequest.Period + (GetStateGrowthChartRequest_Period)(0), // 2: state_analytics.GetStateGrowthChartRequest.Period + (GetStateGrowthChartRequest_Granularity)(0), // 3: state_analytics.GetStateGrowthChartRequest.Granularity + (ContractStateEvent_EventType)(0), // 4: state_analytics.ContractStateEvent.EventType + (GetStateGrowthByCategoryRequest_Granularity)(0), // 5: state_analytics.GetStateGrowthByCategoryRequest.Granularity + (*GetLatestBlockDeltaRequest)(nil), // 6: state_analytics.GetLatestBlockDeltaRequest + (*GetLatestBlockDeltaResponse)(nil), // 7: state_analytics.GetLatestBlockDeltaResponse + (*ContractStateDelta)(nil), // 8: state_analytics.ContractStateDelta + (*GetTopStateAddersRequest)(nil), // 9: state_analytics.GetTopStateAddersRequest + (*GetTopStateAddersResponse)(nil), // 10: state_analytics.GetTopStateAddersResponse + (*StateAdder)(nil), // 11: state_analytics.StateAdder + (*GetTopStateRemoversRequest)(nil), // 12: state_analytics.GetTopStateRemoversRequest + (*GetTopStateRemoversResponse)(nil), // 13: state_analytics.GetTopStateRemoversResponse + (*StateRemover)(nil), // 14: state_analytics.StateRemover + (*GetStateGrowthChartRequest)(nil), // 15: state_analytics.GetStateGrowthChartRequest + (*GetStateGrowthChartResponse)(nil), // 16: state_analytics.GetStateGrowthChartResponse + (*StateGrowthDataPoint)(nil), // 17: state_analytics.StateGrowthDataPoint + (*StateSummary)(nil), // 18: state_analytics.StateSummary + (*GetContractStateActivityRequest)(nil), // 19: state_analytics.GetContractStateActivityRequest + (*GetContractStateActivityResponse)(nil), // 20: state_analytics.GetContractStateActivityResponse + (*ContractStateMetrics)(nil), // 21: state_analytics.ContractStateMetrics + (*ContractStateEvent)(nil), // 22: state_analytics.ContractStateEvent + (*GetContractStateCompositionRequest)(nil), // 23: state_analytics.GetContractStateCompositionRequest + (*GetContractStateCompositionResponse)(nil), // 24: state_analytics.GetContractStateCompositionResponse + (*ContractStateEntry)(nil), // 25: state_analytics.ContractStateEntry + (*ContractState)(nil), // 26: state_analytics.ContractState + (*GetHierarchicalStateRequest)(nil), // 27: state_analytics.GetHierarchicalStateRequest + (*GetHierarchicalStateResponse)(nil), // 28: state_analytics.GetHierarchicalStateResponse + (*StateNode)(nil), // 29: state_analytics.StateNode + (*GetStateGrowthByCategoryRequest)(nil), // 30: state_analytics.GetStateGrowthByCategoryRequest + (*GetStateGrowthByCategoryResponse)(nil), // 31: state_analytics.GetStateGrowthByCategoryResponse + (*CategoryGrowthTimeSeries)(nil), // 32: state_analytics.CategoryGrowthTimeSeries + (*CategoryGrowthData)(nil), // 33: state_analytics.CategoryGrowthData + (*ContractGrowthData)(nil), // 34: state_analytics.ContractGrowthData + nil, // 35: state_analytics.StateNode.MetadataEntry + (*timestamppb.Timestamp)(nil), // 36: google.protobuf.Timestamp +} +var file_pkg_server_proto_state_analytics_state_analytics_proto_depIdxs = []int32{ + 36, // 0: state_analytics.GetLatestBlockDeltaResponse.block_timestamp:type_name -> google.protobuf.Timestamp + 8, // 1: state_analytics.GetLatestBlockDeltaResponse.top_contributors:type_name -> state_analytics.ContractStateDelta 0, // 2: state_analytics.GetTopStateAddersRequest.period:type_name -> state_analytics.GetTopStateAddersRequest.Period - 10, // 3: state_analytics.GetTopStateAddersResponse.adders:type_name -> state_analytics.StateAdder + 11, // 3: state_analytics.GetTopStateAddersResponse.adders:type_name -> state_analytics.StateAdder 1, // 4: state_analytics.GetTopStateRemoversRequest.period:type_name -> state_analytics.GetTopStateRemoversRequest.Period - 13, // 5: state_analytics.GetTopStateRemoversResponse.removers:type_name -> state_analytics.StateRemover + 14, // 5: state_analytics.GetTopStateRemoversResponse.removers:type_name -> state_analytics.StateRemover 2, // 6: state_analytics.GetStateGrowthChartRequest.period:type_name -> state_analytics.GetStateGrowthChartRequest.Period 3, // 7: state_analytics.GetStateGrowthChartRequest.granularity:type_name -> state_analytics.GetStateGrowthChartRequest.Granularity - 16, // 8: state_analytics.GetStateGrowthChartResponse.data_points:type_name -> state_analytics.StateGrowthDataPoint - 17, // 9: state_analytics.GetStateGrowthChartResponse.summary:type_name -> state_analytics.StateSummary - 30, // 10: state_analytics.StateGrowthDataPoint.timestamp:type_name -> google.protobuf.Timestamp - 20, // 11: state_analytics.GetContractStateActivityResponse.metrics:type_name -> state_analytics.ContractStateMetrics - 21, // 12: state_analytics.GetContractStateActivityResponse.recent_events:type_name -> state_analytics.ContractStateEvent - 30, // 13: state_analytics.ContractStateEvent.timestamp:type_name -> google.protobuf.Timestamp + 17, // 8: state_analytics.GetStateGrowthChartResponse.data_points:type_name -> state_analytics.StateGrowthDataPoint + 18, // 9: state_analytics.GetStateGrowthChartResponse.summary:type_name -> state_analytics.StateSummary + 36, // 10: state_analytics.StateGrowthDataPoint.timestamp:type_name -> google.protobuf.Timestamp + 21, // 11: state_analytics.GetContractStateActivityResponse.metrics:type_name -> state_analytics.ContractStateMetrics + 22, // 12: state_analytics.GetContractStateActivityResponse.recent_events:type_name -> state_analytics.ContractStateEvent + 36, // 13: state_analytics.ContractStateEvent.timestamp:type_name -> google.protobuf.Timestamp 4, // 14: state_analytics.ContractStateEvent.event_type:type_name -> state_analytics.ContractStateEvent.EventType - 24, // 15: state_analytics.GetContractStateCompositionResponse.contracts:type_name -> state_analytics.ContractStateEntry - 30, // 16: state_analytics.GetContractStateCompositionResponse.timestamp:type_name -> google.protobuf.Timestamp - 25, // 17: state_analytics.ContractStateEntry.state:type_name -> state_analytics.ContractState - 28, // 18: state_analytics.GetHierarchicalStateResponse.root:type_name -> state_analytics.StateNode - 30, // 19: state_analytics.GetHierarchicalStateResponse.timestamp:type_name -> google.protobuf.Timestamp - 28, // 20: state_analytics.StateNode.children:type_name -> state_analytics.StateNode - 29, // 21: state_analytics.StateNode.metadata:type_name -> state_analytics.StateNode.MetadataEntry - 5, // 22: state_analytics.StateAnalytics.GetLatestBlockDelta:input_type -> state_analytics.GetLatestBlockDeltaRequest - 8, // 23: state_analytics.StateAnalytics.GetTopStateAdders:input_type -> state_analytics.GetTopStateAddersRequest - 11, // 24: state_analytics.StateAnalytics.GetTopStateRemovers:input_type -> state_analytics.GetTopStateRemoversRequest - 14, // 25: state_analytics.StateAnalytics.GetStateGrowthChart:input_type -> state_analytics.GetStateGrowthChartRequest - 18, // 26: state_analytics.StateAnalytics.GetContractStateActivity:input_type -> state_analytics.GetContractStateActivityRequest - 22, // 27: state_analytics.StateAnalytics.GetContractStateComposition:input_type -> state_analytics.GetContractStateCompositionRequest - 26, // 28: state_analytics.StateAnalytics.GetHierarchicalState:input_type -> state_analytics.GetHierarchicalStateRequest - 6, // 29: state_analytics.StateAnalytics.GetLatestBlockDelta:output_type -> state_analytics.GetLatestBlockDeltaResponse - 9, // 30: state_analytics.StateAnalytics.GetTopStateAdders:output_type -> state_analytics.GetTopStateAddersResponse - 12, // 31: state_analytics.StateAnalytics.GetTopStateRemovers:output_type -> state_analytics.GetTopStateRemoversResponse - 15, // 32: state_analytics.StateAnalytics.GetStateGrowthChart:output_type -> state_analytics.GetStateGrowthChartResponse - 19, // 33: state_analytics.StateAnalytics.GetContractStateActivity:output_type -> state_analytics.GetContractStateActivityResponse - 23, // 34: state_analytics.StateAnalytics.GetContractStateComposition:output_type -> state_analytics.GetContractStateCompositionResponse - 27, // 35: state_analytics.StateAnalytics.GetHierarchicalState:output_type -> state_analytics.GetHierarchicalStateResponse - 29, // [29:36] is the sub-list for method output_type - 22, // [22:29] is the sub-list for method input_type - 22, // [22:22] is the sub-list for extension type_name - 22, // [22:22] is the sub-list for extension extendee - 0, // [0:22] is the sub-list for field type_name -} - -func init() { file_state_analytics_proto_init() } -func file_state_analytics_proto_init() { - if File_state_analytics_proto != nil { + 25, // 15: state_analytics.GetContractStateCompositionResponse.contracts:type_name -> state_analytics.ContractStateEntry + 36, // 16: state_analytics.GetContractStateCompositionResponse.timestamp:type_name -> google.protobuf.Timestamp + 26, // 17: state_analytics.ContractStateEntry.state:type_name -> state_analytics.ContractState + 29, // 18: state_analytics.GetHierarchicalStateResponse.root:type_name -> state_analytics.StateNode + 36, // 19: state_analytics.GetHierarchicalStateResponse.timestamp:type_name -> google.protobuf.Timestamp + 29, // 20: state_analytics.StateNode.children:type_name -> state_analytics.StateNode + 35, // 21: state_analytics.StateNode.metadata:type_name -> state_analytics.StateNode.MetadataEntry + 5, // 22: state_analytics.GetStateGrowthByCategoryRequest.granularity:type_name -> state_analytics.GetStateGrowthByCategoryRequest.Granularity + 32, // 23: state_analytics.GetStateGrowthByCategoryResponse.time_series:type_name -> state_analytics.CategoryGrowthTimeSeries + 36, // 24: state_analytics.GetStateGrowthByCategoryResponse.start_time:type_name -> google.protobuf.Timestamp + 36, // 25: state_analytics.GetStateGrowthByCategoryResponse.end_time:type_name -> google.protobuf.Timestamp + 36, // 26: state_analytics.CategoryGrowthTimeSeries.timestamp:type_name -> google.protobuf.Timestamp + 33, // 27: state_analytics.CategoryGrowthTimeSeries.categories:type_name -> state_analytics.CategoryGrowthData + 34, // 28: state_analytics.CategoryGrowthData.top_contracts:type_name -> state_analytics.ContractGrowthData + 6, // 29: state_analytics.StateAnalytics.GetLatestBlockDelta:input_type -> state_analytics.GetLatestBlockDeltaRequest + 9, // 30: state_analytics.StateAnalytics.GetTopStateAdders:input_type -> state_analytics.GetTopStateAddersRequest + 12, // 31: state_analytics.StateAnalytics.GetTopStateRemovers:input_type -> state_analytics.GetTopStateRemoversRequest + 15, // 32: state_analytics.StateAnalytics.GetStateGrowthChart:input_type -> state_analytics.GetStateGrowthChartRequest + 19, // 33: state_analytics.StateAnalytics.GetContractStateActivity:input_type -> state_analytics.GetContractStateActivityRequest + 23, // 34: state_analytics.StateAnalytics.GetContractStateComposition:input_type -> state_analytics.GetContractStateCompositionRequest + 27, // 35: state_analytics.StateAnalytics.GetHierarchicalState:input_type -> state_analytics.GetHierarchicalStateRequest + 30, // 36: state_analytics.StateAnalytics.GetStateGrowthByCategory:input_type -> state_analytics.GetStateGrowthByCategoryRequest + 7, // 37: state_analytics.StateAnalytics.GetLatestBlockDelta:output_type -> state_analytics.GetLatestBlockDeltaResponse + 10, // 38: state_analytics.StateAnalytics.GetTopStateAdders:output_type -> state_analytics.GetTopStateAddersResponse + 13, // 39: state_analytics.StateAnalytics.GetTopStateRemovers:output_type -> state_analytics.GetTopStateRemoversResponse + 16, // 40: state_analytics.StateAnalytics.GetStateGrowthChart:output_type -> state_analytics.GetStateGrowthChartResponse + 20, // 41: state_analytics.StateAnalytics.GetContractStateActivity:output_type -> state_analytics.GetContractStateActivityResponse + 24, // 42: state_analytics.StateAnalytics.GetContractStateComposition:output_type -> state_analytics.GetContractStateCompositionResponse + 28, // 43: state_analytics.StateAnalytics.GetHierarchicalState:output_type -> state_analytics.GetHierarchicalStateResponse + 31, // 44: state_analytics.StateAnalytics.GetStateGrowthByCategory:output_type -> state_analytics.GetStateGrowthByCategoryResponse + 37, // [37:45] is the sub-list for method output_type + 29, // [29:37] is the sub-list for method input_type + 29, // [29:29] is the sub-list for extension type_name + 29, // [29:29] is the sub-list for extension extendee + 0, // [0:29] is the sub-list for field type_name +} + +func init() { file_pkg_server_proto_state_analytics_state_analytics_proto_init() } +func file_pkg_server_proto_state_analytics_state_analytics_proto_init() { + if File_pkg_server_proto_state_analytics_state_analytics_proto != nil { return } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: unsafe.Slice(unsafe.StringData(file_state_analytics_proto_rawDesc), len(file_state_analytics_proto_rawDesc)), - NumEnums: 5, - NumMessages: 25, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_pkg_server_proto_state_analytics_state_analytics_proto_rawDesc), len(file_pkg_server_proto_state_analytics_state_analytics_proto_rawDesc)), + NumEnums: 6, + NumMessages: 30, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_state_analytics_proto_goTypes, - DependencyIndexes: file_state_analytics_proto_depIdxs, - EnumInfos: file_state_analytics_proto_enumTypes, - MessageInfos: file_state_analytics_proto_msgTypes, + GoTypes: file_pkg_server_proto_state_analytics_state_analytics_proto_goTypes, + DependencyIndexes: file_pkg_server_proto_state_analytics_state_analytics_proto_depIdxs, + EnumInfos: file_pkg_server_proto_state_analytics_state_analytics_proto_enumTypes, + MessageInfos: file_pkg_server_proto_state_analytics_state_analytics_proto_msgTypes, }.Build() - File_state_analytics_proto = out.File - file_state_analytics_proto_goTypes = nil - file_state_analytics_proto_depIdxs = nil + File_pkg_server_proto_state_analytics_state_analytics_proto = out.File + file_pkg_server_proto_state_analytics_state_analytics_proto_goTypes = nil + file_pkg_server_proto_state_analytics_state_analytics_proto_depIdxs = nil } diff --git a/backend/pkg/server/proto/state_analytics/state_analytics.proto b/backend/pkg/server/proto/state_analytics/state_analytics.proto index 26e160b88..d19375d85 100644 --- a/backend/pkg/server/proto/state_analytics/state_analytics.proto +++ b/backend/pkg/server/proto/state_analytics/state_analytics.proto @@ -28,6 +28,9 @@ service StateAnalytics { // GetHierarchicalState returns state organized hierarchically by category -> protocol -> contract rpc GetHierarchicalState(GetHierarchicalStateRequest) returns (GetHierarchicalStateResponse); + + // GetStateGrowthByCategory returns time-series state growth data categorized by contract type + rpc GetStateGrowthByCategory(GetStateGrowthByCategoryRequest) returns (GetStateGrowthByCategoryResponse); } // Request/Response messages for GetLatestBlockDelta @@ -245,3 +248,50 @@ message StateNode { repeated StateNode children = 4; // Child nodes map metadata = 5; // Additional data (address, color, etc.) } + +// Request/Response for GetStateGrowthByCategory (Paradigm Figures 2 & 3) +message GetStateGrowthByCategoryRequest { + enum Granularity { + GRANULARITY_UNSPECIFIED = 0; + GRANULARITY_DAILY = 1; // Daily state growth (like Figure 3 but daily) + GRANULARITY_MONTHLY = 2; // Monthly state growth (Paradigm Figure 3) + GRANULARITY_YEARLY = 3; // Yearly aggregates + } + Granularity granularity = 1; + + uint64 start_block = 2; // Optional: start from specific block (0 = genesis) + uint64 end_block = 3; // Optional: end at specific block (0 = latest) + uint32 top_contracts_per_period = 4; // Top N contracts per time period (default 100) +} + +message GetStateGrowthByCategoryResponse { + repeated CategoryGrowthTimeSeries time_series = 1; + uint64 start_block = 2; + uint64 end_block = 3; + google.protobuf.Timestamp start_time = 4; + google.protobuf.Timestamp end_time = 5; +} + +message CategoryGrowthTimeSeries { + google.protobuf.Timestamp timestamp = 1; // Period timestamp (start of day/month/year) + uint64 block_number = 2; // Representative block for this period + repeated CategoryGrowthData categories = 3; + int64 total_net_slots = 4; // Total across all categories + int64 total_net_bytes = 5; // Total bytes across all categories +} + +message CategoryGrowthData { + string category = 1; // "Other", "ERC-20", "DeFi", etc. (initially all "Other") + repeated ContractGrowthData top_contracts = 2; // Top contributing contracts + int64 net_slots_added = 3; // Net slot change for this category in period + int64 net_bytes_added = 4; // Net bytes change for this category in period + double percentage_of_period = 5; // % of total growth in this period +} + +message ContractGrowthData { + string address = 1; + string label = 2; // Optional contract name + int64 net_slots_added = 3; // Can be negative if slots were cleared + int64 net_bytes_added = 4; + double percentage_of_category = 5; // % of category growth +} diff --git a/backend/pkg/server/proto/state_analytics/state_analytics_grpc.pb.go b/backend/pkg/server/proto/state_analytics/state_analytics_grpc.pb.go index 913bc8292..a87e38cc8 100644 --- a/backend/pkg/server/proto/state_analytics/state_analytics_grpc.pb.go +++ b/backend/pkg/server/proto/state_analytics/state_analytics_grpc.pb.go @@ -2,7 +2,7 @@ // versions: // - protoc-gen-go-grpc v1.5.1 // - protoc v5.29.3 -// source: state_analytics.proto +// source: pkg/server/proto/state_analytics/state_analytics.proto package state_analytics @@ -26,6 +26,7 @@ const ( StateAnalytics_GetContractStateActivity_FullMethodName = "/state_analytics.StateAnalytics/GetContractStateActivity" StateAnalytics_GetContractStateComposition_FullMethodName = "/state_analytics.StateAnalytics/GetContractStateComposition" StateAnalytics_GetHierarchicalState_FullMethodName = "/state_analytics.StateAnalytics/GetHierarchicalState" + StateAnalytics_GetStateGrowthByCategory_FullMethodName = "/state_analytics.StateAnalytics/GetStateGrowthByCategory" ) // StateAnalyticsClient is the client API for StateAnalytics service. @@ -48,6 +49,8 @@ type StateAnalyticsClient interface { GetContractStateComposition(ctx context.Context, in *GetContractStateCompositionRequest, opts ...grpc.CallOption) (*GetContractStateCompositionResponse, error) // GetHierarchicalState returns state organized hierarchically by category -> protocol -> contract GetHierarchicalState(ctx context.Context, in *GetHierarchicalStateRequest, opts ...grpc.CallOption) (*GetHierarchicalStateResponse, error) + // GetStateGrowthByCategory returns time-series state growth data categorized by contract type + GetStateGrowthByCategory(ctx context.Context, in *GetStateGrowthByCategoryRequest, opts ...grpc.CallOption) (*GetStateGrowthByCategoryResponse, error) } type stateAnalyticsClient struct { @@ -128,6 +131,16 @@ func (c *stateAnalyticsClient) GetHierarchicalState(ctx context.Context, in *Get return out, nil } +func (c *stateAnalyticsClient) GetStateGrowthByCategory(ctx context.Context, in *GetStateGrowthByCategoryRequest, opts ...grpc.CallOption) (*GetStateGrowthByCategoryResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetStateGrowthByCategoryResponse) + err := c.cc.Invoke(ctx, StateAnalytics_GetStateGrowthByCategory_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // StateAnalyticsServer is the server API for StateAnalytics service. // All implementations must embed UnimplementedStateAnalyticsServer // for forward compatibility. @@ -148,6 +161,8 @@ type StateAnalyticsServer interface { GetContractStateComposition(context.Context, *GetContractStateCompositionRequest) (*GetContractStateCompositionResponse, error) // GetHierarchicalState returns state organized hierarchically by category -> protocol -> contract GetHierarchicalState(context.Context, *GetHierarchicalStateRequest) (*GetHierarchicalStateResponse, error) + // GetStateGrowthByCategory returns time-series state growth data categorized by contract type + GetStateGrowthByCategory(context.Context, *GetStateGrowthByCategoryRequest) (*GetStateGrowthByCategoryResponse, error) mustEmbedUnimplementedStateAnalyticsServer() } @@ -179,6 +194,9 @@ func (UnimplementedStateAnalyticsServer) GetContractStateComposition(context.Con func (UnimplementedStateAnalyticsServer) GetHierarchicalState(context.Context, *GetHierarchicalStateRequest) (*GetHierarchicalStateResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetHierarchicalState not implemented") } +func (UnimplementedStateAnalyticsServer) GetStateGrowthByCategory(context.Context, *GetStateGrowthByCategoryRequest) (*GetStateGrowthByCategoryResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetStateGrowthByCategory not implemented") +} func (UnimplementedStateAnalyticsServer) mustEmbedUnimplementedStateAnalyticsServer() {} func (UnimplementedStateAnalyticsServer) testEmbeddedByValue() {} @@ -326,6 +344,24 @@ func _StateAnalytics_GetHierarchicalState_Handler(srv interface{}, ctx context.C return interceptor(ctx, in, info, handler) } +func _StateAnalytics_GetStateGrowthByCategory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetStateGrowthByCategoryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StateAnalyticsServer).GetStateGrowthByCategory(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StateAnalytics_GetStateGrowthByCategory_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StateAnalyticsServer).GetStateGrowthByCategory(ctx, req.(*GetStateGrowthByCategoryRequest)) + } + return interceptor(ctx, in, info, handler) +} + // StateAnalytics_ServiceDesc is the grpc.ServiceDesc for StateAnalytics service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -361,7 +397,11 @@ var StateAnalytics_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetHierarchicalState", Handler: _StateAnalytics_GetHierarchicalState_Handler, }, + { + MethodName: "GetStateGrowthByCategory", + Handler: _StateAnalytics_GetStateGrowthByCategory_Handler, + }, }, Streams: []grpc.StreamDesc{}, - Metadata: "state_analytics.proto", + Metadata: "pkg/server/proto/state_analytics/state_analytics.proto", } diff --git a/frontend/src/api/rest/client.ts b/frontend/src/api/rest/client.ts index bd404baf1..28640bebd 100644 --- a/frontend/src/api/rest/client.ts +++ b/frontend/src/api/rest/client.ts @@ -610,6 +610,24 @@ export class RestApiClient { const response = await this.fetchWithRetry(url); return response as HierarchicalStateResponse; } + + /** + * Get categorized state growth over time (Paradigm Figures 2 & 3) + * @param network Network name + * @param params Query parameters (granularity, start_block, end_block, top_contracts) + * @returns Time-series growth data by category + */ + async getStateGrowthByCategory( + network: string, + params?: { granularity?: string; start_block?: number; end_block?: number; top_contracts?: number }, + ): Promise { + const queryString = params ? buildQueryString(params) : new URLSearchParams(); + const url = `${this.baseUrl}${API_V1_ENDPOINTS.stateGrowthByCategory(network)}${ + queryString.toString() ? `?${queryString.toString()}` : '' + }`; + const response = await this.fetchWithRetry(url); + return response; + } } /** diff --git a/frontend/src/api/rest/endpoints.ts b/frontend/src/api/rest/endpoints.ts index d2600f593..529c9fdf7 100644 --- a/frontend/src/api/rest/endpoints.ts +++ b/frontend/src/api/rest/endpoints.ts @@ -43,6 +43,7 @@ export const API_V1_ENDPOINTS = { `/api/v1/${network}/state/contract/${address}`, stateComposition: (network: string) => `/api/v1/${network}/state/composition`, stateHierarchical: (network: string) => `/api/v1/${network}/state/hierarchical`, + stateGrowthByCategory: (network: string) => `/api/v1/${network}/state/growth-by-category`, }; /** diff --git a/frontend/src/components/state/StateGrowthByCategory.tsx b/frontend/src/components/state/StateGrowthByCategory.tsx new file mode 100644 index 000000000..3c4e39282 --- /dev/null +++ b/frontend/src/components/state/StateGrowthByCategory.tsx @@ -0,0 +1,302 @@ +import React, { useState, useEffect, useMemo } from 'react'; +import Plot from 'react-plotly.js'; +import { PARADIGM_COLORS } from './paradigmColors'; + +interface CategoryGrowthData { + category: string; + top_contracts: ContractGrowthData[]; + net_slots_added: number; + net_bytes_added: number; + percentage_of_period: number; +} + +interface ContractGrowthData { + address: string; + label: string; + net_slots_added: number; + net_bytes_added: number; + percentage_of_category: number; +} + +interface CategoryGrowthTimeSeries { + timestamp: string; + block_number: number; + categories: CategoryGrowthData[]; + total_net_slots: number; + total_net_bytes: number; +} + +interface StateGrowthByCategoryResponse { + time_series: CategoryGrowthTimeSeries[]; + start_block: number; + end_block: number; + start_time: string; + end_time: string; +} + +interface StateGrowthByCategoryProps { + selectedNetwork: string; + restClient: any; +} + +type Granularity = 'daily' | 'monthly' | 'yearly'; + +const StateGrowthByCategory: React.FC = ({ + selectedNetwork, + restClient, +}) => { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [granularity, setGranularity] = useState('monthly'); + + const fetchData = async () => { + if (!restClient || !selectedNetwork) return; + + setLoading(true); + setError(null); + + try { + console.log(`[StateGrowthByCategory] Fetching ${granularity} data for ${selectedNetwork}`); + + const response = await restClient.getStateGrowthByCategory(selectedNetwork, { + granularity: granularity, + top_contracts: 100, + start_block: 0, // Query from genesis + end_block: 0, // Query to latest + }); + + console.log('[StateGrowthByCategory] Response:', response); + setData(response); + setLoading(false); + } catch (err: any) { + console.error('[StateGrowthByCategory] Error fetching data:', err); + setError(err.message || 'Failed to fetch state growth data'); + setLoading(false); + } + }; + + useEffect(() => { + fetchData(); + }, [selectedNetwork, restClient, granularity]); + + // Process data for Plotly stacked area chart + const plotData = useMemo(() => { + if (!data || !data.time_series || data.time_series.length === 0) { + return []; + } + + // Group by category across all time periods + const categoryMap = new Map(); + + data.time_series.forEach((timeSeries) => { + const timestamp = new Date(timeSeries.timestamp).toISOString(); + + timeSeries.categories.forEach((cat) => { + if (!categoryMap.has(cat.category)) { + categoryMap.set(cat.category, { x: [], y: [] }); + } + + const categoryData = categoryMap.get(cat.category)!; + categoryData.x.push(timestamp); + // Convert bytes to MB for better readability + categoryData.y.push(cat.net_bytes_added / 1024 / 1024); + }); + }); + + // Convert to Plotly traces (stacked area chart) + const traces: any[] = []; + let colorIndex = 0; + + categoryMap.forEach((categoryData, categoryName) => { + traces.push({ + name: categoryName, + x: categoryData.x, + y: categoryData.y, + type: 'bar', + marker: { + color: PARADIGM_COLORS[colorIndex % PARADIGM_COLORS.length], + }, + hovertemplate: + '%{fullData.name}
' + + 'Date: %{x|%Y-%m-%d}
' + + 'Growth: %{y:.2f} MB
' + + '', + }); + colorIndex++; + }); + + return traces; + }, [data]); + + // Calculate summary statistics + const summary = useMemo(() => { + if (!data || !data.time_series || data.time_series.length === 0) { + return null; + } + + const totalGrowth = data.time_series.reduce( + (sum, ts) => sum + ts.total_net_bytes, + 0 + ); + const avgGrowthPerPeriod = totalGrowth / data.time_series.length; + const maxGrowth = Math.max(...data.time_series.map((ts) => ts.total_net_bytes)); + + return { + totalGrowthMB: (totalGrowth / 1024 / 1024).toFixed(2), + avgGrowthPerPeriodMB: (avgGrowthPerPeriod / 1024 / 1024).toFixed(2), + maxGrowthMB: (maxGrowth / 1024 / 1024).toFixed(2), + periods: data.time_series.length, + }; + }, [data]); + + if (loading) { + return ( +
+
Loading categorized state growth data...
+
+ ); + } + + if (error) { + return ( +
+
Error: {error}
+
+ ); + } + + if (!data || plotData.length === 0) { + return ( +
+
No data available
+
+ ); + } + + return ( +
+ {/* Header with controls */} +
+
+

Categorized State Growth Over Time

+

+ Similar to Paradigm's "How to raise the gas limit" Figures 2 & 3 +

+
+ + {/* Granularity selector */} +
+ + + +
+
+ + {/* Summary statistics */} + {summary && data && ( +
+
+
Earliest Data
+
+ {data.start_time ? new Date(data.start_time).toLocaleDateString() : 'N/A'} +
+
+
+
Total Growth
+
{summary.totalGrowthMB} MB
+
+
+
Avg per Period
+
{summary.avgGrowthPerPeriodMB} MB
+
+
+
Max Growth
+
{summary.maxGrowthMB} MB
+
+
+
Periods
+
{summary.periods}
+
+
+ )} + + {/* Stacked area chart */} +
+ +
+ + {/* Info note */} +
+ Note: Currently all contracts are grouped under "Other" category. Contract categorization + (ERC-20, DeFi, NFTs, etc.) will be added in a future update. +
+
+ ); +}; + +export default StateGrowthByCategory; diff --git a/frontend/src/pages/state-analyzer/index.tsx b/frontend/src/pages/state-analyzer/index.tsx index 6d4f036bb..b833523aa 100644 --- a/frontend/src/pages/state-analyzer/index.tsx +++ b/frontend/src/pages/state-analyzer/index.tsx @@ -14,6 +14,7 @@ import type { import { ResponsiveLine } from '@nivo/line'; import { defaultNivoTheme } from '@/components/charts/NivoTheme'; import { PlotlyTreemap } from '@/components/state/PlotlyTreemap'; +import StateGrowthByCategory from '@/components/state/StateGrowthByCategory'; // Helper function to format bytes function formatBytes(bytes: number): string { @@ -49,7 +50,7 @@ function StateAnalyzer() { const [granularity, setGranularity] = useState('hour' as StateGranularity); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); - const [activeTab, setActiveTab] = useState<'growth' | 'composition'>('growth'); + const [activeTab, setActiveTab] = useState<'growth' | 'composition' | 'categorized'>('growth'); useEffect(() => { let lastBlockNumber = 0; @@ -241,6 +242,16 @@ function StateAnalyzer() { > State Composition +
{/* Growth Analytics Tab */} @@ -473,6 +484,14 @@ function StateAnalyzer() { {activeTab === 'composition' && ( )} + + {/* Categorized Growth Tab */} + {activeTab === 'categorized' && ( + + )} )}
From cc9abfbd2a272081322ef05bbab36c2480b7b158 Mon Sep 17 00:00:00 2001 From: CPerezz Date: Sat, 1 Nov 2025 23:39:24 +0100 Subject: [PATCH 09/10] fix(state-analytics): improve daily state growth query and visualization Backend changes: - Fix block range calculation formula for daily queries (subtract genesis time before dividing) - Automatically calculate latest day's block range to avoid timeouts on large tables - Only query ~7,200 blocks (one day) instead of scanning billions of rows Frontend changes: - Simplify to daily-only view (remove granularity selector) - Display bar chart with categories on X-axis instead of time series - Show all possible categories (DeFi, NFT, ERC20, Gaming, Bridge, Oracle, DAO, Identity, Other) even if 0 state - Update summary stats to show "Latest Date" instead of time range --- .../state_analytics/category_state_growth.go | 49 ++++- .../state/StateGrowthByCategory.tsx | 171 +++++++----------- 2 files changed, 109 insertions(+), 111 deletions(-) diff --git a/backend/pkg/server/internal/service/state_analytics/category_state_growth.go b/backend/pkg/server/internal/service/state_analytics/category_state_growth.go index 691b341c6..6bc99578d 100644 --- a/backend/pkg/server/internal/service/state_analytics/category_state_growth.go +++ b/backend/pkg/server/internal/service/state_analytics/category_state_growth.go @@ -35,6 +35,45 @@ func (s *Service) GetStateGrowthByCategory( return nil, err } + // For daily granularity, only query the latest day to avoid timeout + var startBlock, endBlock uint64 + if req.Granularity == pb.GetStateGrowthByCategoryRequest_GRANULARITY_DAILY { + // Query to get the latest day's block range + latestDayQuery := fmt.Sprintf(` + WITH latest AS ( + SELECT max(block_number) as max_block + FROM %s.canonical_execution_storage_diffs + ), + latest_day AS ( + SELECT toDate(toDateTime(%d + max_block * 12)) as day + FROM latest + ), + day_start AS ( + SELECT toUnixTimestamp(toDateTime(day)) as ts + FROM latest_day + ), + day_end AS ( + SELECT toUnixTimestamp(toDateTime(day) + INTERVAL 1 DAY) as ts + FROM latest_day + ) + SELECT + ((SELECT ts FROM day_start) - %d) / 12 as start_block, + ((SELECT ts FROM day_end) - %d) / 12 as end_block + `, network, s.getGenesisTime(network), s.getGenesisTime(network), s.getGenesisTime(network)) + + latestDayRows, err := client.Query(ctx, latestDayQuery) + if err != nil || len(latestDayRows) == 0 { + s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) + return nil, fmt.Errorf("failed to get latest day range: %w", err) + } + + startBlock = getUint64(latestDayRows[0], "start_block") + endBlock = getUint64(latestDayRows[0], "end_block") + } else { + startBlock = req.StartBlock + endBlock = req.EndBlock + } + // Determine time bucket expression based on granularity var timeBucketExpr string switch req.Granularity { @@ -57,9 +96,9 @@ func (s *Service) GetStateGrowthByCategory( s.getGenesisTime(network), ) default: - // Default to monthly + // Default to daily for latest day timeBucketExpr = fmt.Sprintf( - "toStartOfMonth(toDateTime(%d + block_number * 12))", + "toDate(toDateTime(%d + block_number * 12))", s.getGenesisTime(network), ) } @@ -73,8 +112,8 @@ func (s *Service) GetStateGrowthByCategory( // Build query with replacements query := queryStateGrowthByCategory query = strings.ReplaceAll(query, "{database}", network) - query = strings.ReplaceAll(query, "{start_block}", fmt.Sprintf("%d", req.StartBlock)) - query = strings.ReplaceAll(query, "{end_block}", fmt.Sprintf("%d", req.EndBlock)) + query = strings.ReplaceAll(query, "{start_block}", fmt.Sprintf("%d", startBlock)) + query = strings.ReplaceAll(query, "{end_block}", fmt.Sprintf("%d", endBlock)) query = strings.ReplaceAll(query, "{bytes_per_slot}", fmt.Sprintf("%d", BytesPerSlot)) query = strings.ReplaceAll(query, "{time_bucket_expression}", timeBucketExpr) @@ -131,7 +170,7 @@ func (s *Service) GetStateGrowthByCategory( return ti.Before(tj) }) - var startBlock, endBlock uint64 + // Track actual start/end blocks from data (reuse variables from earlier) genesisTime := s.getGenesisTime(network) for _, period := range sortedPeriods { diff --git a/frontend/src/components/state/StateGrowthByCategory.tsx b/frontend/src/components/state/StateGrowthByCategory.tsx index 3c4e39282..495a818cb 100644 --- a/frontend/src/components/state/StateGrowthByCategory.tsx +++ b/frontend/src/components/state/StateGrowthByCategory.tsx @@ -39,8 +39,6 @@ interface StateGrowthByCategoryProps { restClient: any; } -type Granularity = 'daily' | 'monthly' | 'yearly'; - const StateGrowthByCategory: React.FC = ({ selectedNetwork, restClient, @@ -48,7 +46,6 @@ const StateGrowthByCategory: React.FC = ({ const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); - const [granularity, setGranularity] = useState('monthly'); const fetchData = async () => { if (!restClient || !selectedNetwork) return; @@ -57,13 +54,14 @@ const StateGrowthByCategory: React.FC = ({ setError(null); try { - console.log(`[StateGrowthByCategory] Fetching ${granularity} data for ${selectedNetwork}`); + console.log(`[StateGrowthByCategory] Fetching latest daily data for ${selectedNetwork}`); + // Query only the latest day's data const response = await restClient.getStateGrowthByCategory(selectedNetwork, { - granularity: granularity, + granularity: 'daily', top_contracts: 100, - start_block: 0, // Query from genesis - end_block: 0, // Query to latest + start_block: 0, // Will be set to latest day by backend + end_block: 0, // Latest block }); console.log('[StateGrowthByCategory] Response:', response); @@ -78,55 +76,63 @@ const StateGrowthByCategory: React.FC = ({ useEffect(() => { fetchData(); - }, [selectedNetwork, restClient, granularity]); + }, [selectedNetwork, restClient]); - // Process data for Plotly stacked area chart + // Process data for Plotly bar chart (category on X axis) const plotData = useMemo(() => { if (!data || !data.time_series || data.time_series.length === 0) { return []; } - // Group by category across all time periods - const categoryMap = new Map(); - - data.time_series.forEach((timeSeries) => { - const timestamp = new Date(timeSeries.timestamp).toISOString(); + // Get the latest day's data (should only be one entry) + const latestDay = data.time_series[data.time_series.length - 1]; - timeSeries.categories.forEach((cat) => { - if (!categoryMap.has(cat.category)) { - categoryMap.set(cat.category, { x: [], y: [] }); - } + if (!latestDay || !latestDay.categories || latestDay.categories.length === 0) { + return []; + } - const categoryData = categoryMap.get(cat.category)!; - categoryData.x.push(timestamp); - // Convert bytes to MB for better readability - categoryData.y.push(cat.net_bytes_added / 1024 / 1024); - }); + // Define all possible categories + const allCategories = [ + 'DeFi', + 'NFT', + 'ERC20', + 'Gaming', + 'Bridge', + 'Oracle', + 'DAO', + 'Identity', + 'Other' + ]; + + // Create a map of category -> value from the response + const categoryValues = new Map(); + latestDay.categories.forEach((cat) => { + categoryValues.set(cat.category, cat.net_bytes_added / 1024 / 1024); }); - // Convert to Plotly traces (stacked area chart) - const traces: any[] = []; - let colorIndex = 0; + // Create arrays with all categories, filling in 0 for missing ones + const categories: string[] = []; + const values: number[] = []; + const colors: string[] = []; - categoryMap.forEach((categoryData, categoryName) => { - traces.push({ - name: categoryName, - x: categoryData.x, - y: categoryData.y, - type: 'bar', - marker: { - color: PARADIGM_COLORS[colorIndex % PARADIGM_COLORS.length], - }, - hovertemplate: - '%{fullData.name}
' + - 'Date: %{x|%Y-%m-%d}
' + - 'Growth: %{y:.2f} MB
' + - '', - }); - colorIndex++; + allCategories.forEach((category, index) => { + categories.push(category); + values.push(categoryValues.get(category) || 0); + colors.push(PARADIGM_COLORS[index % PARADIGM_COLORS.length]); }); - return traces; + return [{ + type: 'bar', + x: categories, + y: values, + marker: { + color: colors, + }, + hovertemplate: + '%{x}
' + + 'State Growth: %{y:.2f} MB
' + + '', + }]; }, [data]); // Calculate summary statistics @@ -176,89 +182,49 @@ const StateGrowthByCategory: React.FC = ({ return (
- {/* Header with controls */} -
-
-

Categorized State Growth Over Time

-

- Similar to Paradigm's "How to raise the gas limit" Figures 2 & 3 -

-
- - {/* Granularity selector */} -
- - - -
+ {/* Header */} +
+

Latest Day State Growth by Contract

+

+ Showing state growth for the most recent day in the database +

{/* Summary statistics */} {summary && data && ( -
+
-
Earliest Data
+
Latest Date
- {data.start_time ? new Date(data.start_time).toLocaleDateString() : 'N/A'} + {data.end_time ? new Date(data.end_time).toLocaleDateString() : 'N/A'}
Total Growth
{summary.totalGrowthMB} MB
-
-
Avg per Period
-
{summary.avgGrowthPerPeriodMB} MB
-
Max Growth
{summary.maxGrowthMB} MB
-
Periods
+
Unique Contracts
{summary.periods}
)} - {/* Stacked area chart */} + {/* Bar chart by category */}
= ({ color: '#9ca3af', gridcolor: '#374151', }, - barmode: 'stack', - hovermode: 'x unified', - showlegend: true, - legend: { - orientation: 'v', - x: 1.02, - y: 1, - font: { color: '#e5e7eb' }, - }, + hovermode: 'closest', + showlegend: false, paper_bgcolor: 'transparent', plot_bgcolor: '#1f2937', - margin: { l: 60, r: 150, t: 60, b: 60 }, + margin: { l: 60, r: 60, t: 60, b: 60 }, }} config={{ responsive: true, From 6c736a2cd34cb8adea753b42ac2aa6e37152056d Mon Sep 17 00:00:00 2001 From: CPerezz Date: Mon, 3 Nov 2025 13:51:19 +0100 Subject: [PATCH 10/10] fix(state-analytics): implement 24h execution layer state growth query - Query last 7,150 execution blocks (approximately 24 hours) - Use only canonical_execution_storage_diffs (execution layer data) - Remove all beacon chain references and JOINs - Simplify to daily-only granularity without timestamps - Display all 9 categories on X-axis (bar chart) - Query time: 2-5 minutes for ~50MB of data BREAKING: Removed monthly/yearly granularity options NOTE: All contracts currently categorized as "Other" (labeling not implemented) --- .../state_analytics/category_state_growth.go | 130 ++++++++++-------- .../service/state_analytics/queries.go | 13 +- 2 files changed, 78 insertions(+), 65 deletions(-) diff --git a/backend/pkg/server/internal/service/state_analytics/category_state_growth.go b/backend/pkg/server/internal/service/state_analytics/category_state_growth.go index 6bc99578d..afac25ef7 100644 --- a/backend/pkg/server/internal/service/state_analytics/category_state_growth.go +++ b/backend/pkg/server/internal/service/state_analytics/category_state_growth.go @@ -35,40 +35,28 @@ func (s *Service) GetStateGrowthByCategory( return nil, err } - // For daily granularity, only query the latest day to avoid timeout + // For daily granularity, query the last 7,150 blocks (approximately 24 hours at 12 sec/block) var startBlock, endBlock uint64 if req.Granularity == pb.GetStateGrowthByCategoryRequest_GRANULARITY_DAILY { - // Query to get the latest day's block range - latestDayQuery := fmt.Sprintf(` - WITH latest AS ( - SELECT max(block_number) as max_block - FROM %s.canonical_execution_storage_diffs - ), - latest_day AS ( - SELECT toDate(toDateTime(%d + max_block * 12)) as day - FROM latest - ), - day_start AS ( - SELECT toUnixTimestamp(toDateTime(day)) as ts - FROM latest_day - ), - day_end AS ( - SELECT toUnixTimestamp(toDateTime(day) + INTERVAL 1 DAY) as ts - FROM latest_day - ) - SELECT - ((SELECT ts FROM day_start) - %d) / 12 as start_block, - ((SELECT ts FROM day_end) - %d) / 12 as end_block - `, network, s.getGenesisTime(network), s.getGenesisTime(network), s.getGenesisTime(network)) - - latestDayRows, err := client.Query(ctx, latestDayQuery) - if err != nil || len(latestDayRows) == 0 { + // Query to get the latest block + latestBlockQuery := fmt.Sprintf(` + SELECT max(block_number) as max_block + FROM %s.canonical_execution_storage_diffs + `, network) + + latestRows, err := client.Query(ctx, latestBlockQuery) + if err != nil || len(latestRows) == 0 { s.recordMetrics(method, network, StatusError, time.Since(startTime).Seconds()) - return nil, fmt.Errorf("failed to get latest day range: %w", err) + return nil, fmt.Errorf("failed to get latest block: %w", err) } - startBlock = getUint64(latestDayRows[0], "start_block") - endBlock = getUint64(latestDayRows[0], "end_block") + endBlock = getUint64(latestRows[0], "max_block") + // Query last 7,150 blocks (approximately 24 hours at 12 sec/block) + if endBlock > 7149 { + startBlock = endBlock - 7149 + } else { + startBlock = 0 + } } else { startBlock = req.StartBlock endBlock = req.EndBlock @@ -78,11 +66,9 @@ func (s *Service) GetStateGrowthByCategory( var timeBucketExpr string switch req.Granularity { case pb.GetStateGrowthByCategoryRequest_GRANULARITY_DAILY: - // Group by day using block timestamps - timeBucketExpr = fmt.Sprintf( - "toDate(toDateTime(%d + block_number * 12))", - s.getGenesisTime(network), - ) + // For daily, use a constant bucket since we're querying ~1 day of data + // No timestamp needed - we return block numbers for daily granularity + timeBucketExpr = "'latest_period'" case pb.GetStateGrowthByCategoryRequest_GRANULARITY_MONTHLY: // Group by month (Paradigm Figure 3 style) timeBucketExpr = fmt.Sprintf( @@ -92,15 +78,12 @@ func (s *Service) GetStateGrowthByCategory( case pb.GetStateGrowthByCategoryRequest_GRANULARITY_YEARLY: // Group by year timeBucketExpr = fmt.Sprintf( - "toYear(toDateTime(%d + block_number * 12))", + "toStartOfYear(toDateTime(%d + block_number * 12))", s.getGenesisTime(network), ) default: - // Default to daily for latest day - timeBucketExpr = fmt.Sprintf( - "toDate(toDateTime(%d + block_number * 12))", - s.getGenesisTime(network), - ) + // Default to constant bucket + timeBucketExpr = "'latest_period'" } // Set defaults for optional parameters @@ -117,6 +100,9 @@ func (s *Service) GetStateGrowthByCategory( query = strings.ReplaceAll(query, "{bytes_per_slot}", fmt.Sprintf("%d", BytesPerSlot)) query = strings.ReplaceAll(query, "{time_bucket_expression}", timeBucketExpr) + // Log the query for debugging + s.log.WithField("network", network).Debugf("Executing state growth query: %s", query) + // Execute query rows, err := client.Query(ctx, query) if err != nil { @@ -156,23 +142,18 @@ func (s *Service) GetStateGrowthByCategory( // Convert to sorted time series var timeSeries []*pb.CategoryGrowthTimeSeries - // Get sorted time periods + // Get sorted time periods (for daily this will be just one: "latest_period") var sortedPeriods []interface{} for period := range timePeriods { sortedPeriods = append(sortedPeriods, period) } - // Sort periods chronologically + // Sort periods (for monthly/yearly, this will sort by date; for daily it's just one bucket) sort.Slice(sortedPeriods, func(i, j int) bool { - // Convert to time for comparison - ti := periodToTime(sortedPeriods[i], s.getGenesisTime(network)) - tj := periodToTime(sortedPeriods[j], s.getGenesisTime(network)) - return ti.Before(tj) + // Simple string/value comparison + return fmt.Sprintf("%v", sortedPeriods[i]) < fmt.Sprintf("%v", sortedPeriods[j]) }) - // Track actual start/end blocks from data (reuse variables from earlier) - genesisTime := s.getGenesisTime(network) - for _, period := range sortedPeriods { contracts := timePeriods[period] @@ -218,20 +199,35 @@ func (s *Service) GetStateGrowthByCategory( }) } - // Convert period to timestamp and block number - periodTime := periodToTime(period, genesisTime) - blockNumber := uint64((periodTime.Unix() - genesisTime) / 12) - - // Track start and end blocks - if startBlock == 0 || blockNumber < startBlock { - startBlock = blockNumber + // For daily granularity, we don't use timestamps - just show the block number + // For monthly/yearly, we can still derive from the period value + var periodTime time.Time + var blockNumber uint64 + + if req.Granularity == pb.GetStateGrowthByCategoryRequest_GRANULARITY_DAILY { + // For daily, use the end block as the reference + blockNumber = endBlock + // Don't set timestamp for daily - we're showing block-based data + periodTime = time.Time{} + s.log.Debugf("DAILY: period=%v, periodTime.IsZero()=%v", period, periodTime.IsZero()) + } else { + // For monthly/yearly, convert period to time + periodTime = periodToTime(period, s.getGenesisTime(network)) + if bn, ok := period.(uint64); ok { + blockNumber = bn + } } - if blockNumber > endBlock { - endBlock = blockNumber + + var timestampProto *timestamppb.Timestamp + if !periodTime.IsZero() { + timestampProto = timestamppb.New(periodTime) + s.log.Debugf("Setting timestamp: %v", periodTime) + } else { + s.log.Debugf("NOT setting timestamp (periodTime.IsZero()=true)") } timeSeries = append(timeSeries, &pb.CategoryGrowthTimeSeries{ - Timestamp: timestamppb.New(periodTime), + Timestamp: timestampProto, BlockNumber: blockNumber, Categories: []*pb.CategoryGrowthData{categoryData}, TotalNetSlots: totalNetSlots, @@ -241,12 +237,24 @@ func (s *Service) GetStateGrowthByCategory( s.recordMetrics(method, network, StatusSuccess, time.Since(startTime).Seconds()) + // For daily granularity, we don't set timestamps in the response + // For monthly/yearly, use the timestamps from the data + var startTimeProto, endTimeProto *timestamppb.Timestamp + if req.Granularity != pb.GetStateGrowthByCategoryRequest_GRANULARITY_DAILY && len(timeSeries) > 0 { + if timeSeries[0].Timestamp != nil { + startTimeProto = timeSeries[0].Timestamp + } + if timeSeries[len(timeSeries)-1].Timestamp != nil { + endTimeProto = timeSeries[len(timeSeries)-1].Timestamp + } + } + return &pb.GetStateGrowthByCategoryResponse{ TimeSeries: timeSeries, StartBlock: startBlock, EndBlock: endBlock, - StartTime: timestamppb.New(time.Unix(genesisTime+int64(startBlock)*12, 0)), - EndTime: timestamppb.New(time.Unix(genesisTime+int64(endBlock)*12, 0)), + StartTime: startTimeProto, + EndTime: endTimeProto, }, nil } diff --git a/backend/pkg/server/internal/service/state_analytics/queries.go b/backend/pkg/server/internal/service/state_analytics/queries.go index a50ec3cbf..d813f028a 100644 --- a/backend/pkg/server/internal/service/state_analytics/queries.go +++ b/backend/pkg/server/internal/service/state_analytics/queries.go @@ -191,11 +191,16 @@ LIMIT 1 ` // Query to get state growth categorized by contract (Paradigm Figures 2 & 3) -// Uses canonical_execution_storage_diffs table for execution layer data +// Uses canonical_execution_storage_diffs table for execution layer data (NOT beacon chain) +// +// IMPORTANT: This query operates on EXECUTION LAYER blocks only. Do NOT use beacon chain tables +// like int_block_canonical - they have different block number spaces. +// +// Current implementation: Queries last ~7,150 execution blocks (24 hours) to limit scan size. +// Query time: ~2-5 minutes due to scanning 10.6B row table without materialized views. // -// TODO(performance): CRITICAL PERFORMANCE ISSUE - This query times out (60s+) on production data. -// The canonical_execution_storage_diffs table has 10.6B+ rows and querying from genesis scans -// billions of rows. This is NOT production-ready. Solutions: +// TODO(performance): Performance can be improved with pre-aggregated materialized views. +// The canonical_execution_storage_diffs table has 10.6B+ rows. Solutions: // // Option 1 (RECOMMENDED): Create pre-aggregated materialized views // - CREATE MATERIALIZED VIEW mv_daily_state_growth_by_address AS