diff --git a/Taskfile.yml b/Taskfile.yml index 63f0682b8f..fb3bbc389c 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -12,7 +12,23 @@ tasks: deps: [down, build] cmds: - docker compose -f ./deployment/docker-compose.yaml up -d + + seed: + cmds: + - task: migrate-db + - task: migrate-clickhouse + + migrate-clickhouse: + env: + GOOSE_DRIVER: clickhouse + GOOSE_DBSTRING: "tcp://127.0.0.1:9000" + GOOSE_MIGRATION_DIR: ./apps/agent/pkg/clickhouse/schema + cmds: + - goose up + + + migrate-db: env: DRIZZLE_DATABASE_URL: "mysql://unkey:password@localhost:3306/unkey" dir: internal/db diff --git a/apps/agent/Dockerfile b/apps/agent/Dockerfile index 891955d01e..e38250d7f0 100644 --- a/apps/agent/Dockerfile +++ b/apps/agent/Dockerfile @@ -16,7 +16,6 @@ COPY --from=builder /go/src/github.com/unkeyed/unkey/apps/agent/bin/unkey . COPY --from=builder /go/src/github.com/unkeyed/unkey/apps/agent/config.production.json . COPY --from=builder /go/src/github.com/unkeyed/unkey/apps/agent/config.staging.json . COPY --from=builder /go/src/github.com/unkeyed/unkey/apps/agent/config.docker.json . +COPY --from=builder /go/src/github.com/unkeyed/unkey/apps/agent/pkg/openapi/openapi.json ./pkg/openapi/openapi.json CMD [ "/usr/local/bin/unkey", "agent"] - - diff --git a/apps/agent/Taskfile.yml b/apps/agent/Taskfile.yml index ea1fcaf096..efe4fe5372 100644 --- a/apps/agent/Taskfile.yml +++ b/apps/agent/Taskfile.yml @@ -10,8 +10,8 @@ tasks: - go vet ./... test: cmds: - - go test -cover -json -failfast ./... | tparse -all -progress - + - go test -cover -json -failfast ./... | tparse -all -progress + build: cmds: - go build -o unkey ./cmd/main.go @@ -20,7 +20,19 @@ tasks: cmds: - go install github.com/amit-davidson/Chronos/cmd/chronos - ~/go/bin/chronos --file=./cmd/main.go --mod={{.TASKFILE_DIR}} - + lint: cmds: - - golangci-lint run \ No newline at end of file + - golangci-lint run + + migrate: + cmds: + - goose -dir=./pkg/clickhouse/schema clickhouse "tcp://127.0.0.1:9000" up + + generate: + cmds: + - go get github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen + - mkdir -p ./pkg/openapi + - go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=./pkg/openapi/config.yaml ./pkg/openapi/openapi.json + + - buf generate diff --git a/apps/agent/cmd/agent/agent.go b/apps/agent/cmd/agent/agent.go index 902cbc52bd..7fbee38488 100644 --- a/apps/agent/cmd/agent/agent.go +++ b/apps/agent/cmd/agent/agent.go @@ -14,13 +14,7 @@ import ( "github.com/Southclaws/fault" "github.com/Southclaws/fault/fmsg" "github.com/unkeyed/unkey/apps/agent/pkg/api" - v1Liveness "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_liveness" - v1RatelimitCommitLease "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_ratelimit_commitLease" - v1RatelimitMultiRatelimit "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_ratelimit_multiRatelimit" - v1RatelimitRatelimit "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_ratelimit_ratelimit" - v1VaultDecrypt "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_vault_decrypt" - v1VaultEncrypt "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_vault_encrypt" - v1VaultEncryptBulk "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_vault_encrypt_bulk" + "github.com/unkeyed/unkey/apps/agent/pkg/clickhouse" "github.com/unkeyed/unkey/apps/agent/pkg/cluster" "github.com/unkeyed/unkey/apps/agent/pkg/config" "github.com/unkeyed/unkey/apps/agent/pkg/connect" @@ -133,69 +127,40 @@ func run(c *cli.Context) error { setupHeartbeat(cfg, logger) } - srv := api.New(api.Config{ - NodeId: cfg.NodeId, - Logger: logger, - Metrics: m, - }) - - v1Liveness.Register(srv.HumaAPI(), srv.Services()) - - connectSrv, err := connect.New(connect.Config{Logger: logger, Image: cfg.Image, Metrics: m}) - if err != nil { - return err - } - - if cfg.Services.Vault != nil { - s3, err := storage.NewS3(storage.S3Config{ - S3URL: cfg.Services.Vault.S3Url, - S3Bucket: cfg.Services.Vault.S3Bucket, - S3AccessKeyId: cfg.Services.Vault.S3AccessKeyId, - S3AccessKeySecret: cfg.Services.Vault.S3AccessKeySecret, - Logger: logger, + var ch clickhouse.Bufferer = clickhouse.NewNoop() + if cfg.Clickhouse != nil { + ch, err = clickhouse.New(clickhouse.Config{ + URL: cfg.Clickhouse.Url, + Logger: logger.With().Str("pkg", "clickhouse").Logger(), }) if err != nil { - return fmt.Errorf("failed to create s3 storage: %w", err) - } - s3 = storageMiddleware.WithTracing("s3", s3) - srv.Vault, err = vault.New(vault.Config{ - Logger: logger, - Metrics: m, - Storage: s3, - MasterKeys: strings.Split(cfg.Services.Vault.MasterKeys, ","), - }) - if err != nil { - return fmt.Errorf("failed to create vault: %w", err) - } - - if err != nil { - return fmt.Errorf("failed to create vault service: %w", err) + return err } - - v1VaultEncrypt.Register(srv.HumaAPI(), srv.Services(), srv.BearerAuthFromSecret(cfg.Services.Vault.AuthToken)) - v1VaultEncryptBulk.Register(srv.HumaAPI(), srv.Services(), srv.BearerAuthFromSecret(cfg.Services.Vault.AuthToken)) - v1VaultDecrypt.Register(srv.HumaAPI(), srv.Services(), srv.BearerAuthFromSecret(cfg.Services.Vault.AuthToken)) - logger.Info().Msg("started vault service") } - if cfg.Services.EventRouter != nil { - er, err := eventrouter.New(eventrouter.Config{ - Logger: logger, - Metrics: m, - BatchSize: cfg.Services.EventRouter.Tinybird.BatchSize, - BufferSize: cfg.Services.EventRouter.Tinybird.BufferSize, - FlushInterval: time.Duration(cfg.Services.EventRouter.Tinybird.FlushInterval) * time.Second, - Tinybird: tinybird.New("https://api.tinybird.co", cfg.Services.EventRouter.Tinybird.Token), - AuthToken: cfg.Services.EventRouter.AuthToken, - }) - if err != nil { - return err - } - srv.WithEventRouter(er) - if err != nil { - return fmt.Errorf("failed to add event router service: %w", err) + s3, err := storage.NewS3(storage.S3Config{ + S3URL: cfg.Services.Vault.S3Url, + S3Bucket: cfg.Services.Vault.S3Bucket, + S3AccessKeyId: cfg.Services.Vault.S3AccessKeyId, + S3AccessKeySecret: cfg.Services.Vault.S3AccessKeySecret, + Logger: logger, + }) + if err != nil { + return fmt.Errorf("failed to create s3 storage: %w", err) + } + s3 = storageMiddleware.WithTracing("s3", s3) + v, err := vault.New(vault.Config{ + Logger: logger, + Metrics: m, + Storage: s3, + MasterKeys: strings.Split(cfg.Services.Vault.MasterKeys, ","), + }) + if err != nil { + return fmt.Errorf("failed to create vault: %w", err) + } - } + if err != nil { + return fmt.Errorf("failed to create vault service: %w", err) } var clus cluster.Cluster @@ -255,39 +220,65 @@ func run(c *cli.Context) error { } }() - err = connectSrv.AddService(connect.NewClusterServer(clus, logger)) - if err != nil { - return fmt.Errorf("failed to add cluster service: %w", err) + } - } + rl, err := ratelimit.New(ratelimit.Config{ + Logger: logger, + Metrics: m, + Cluster: clus, + }) + if err != nil { + logger.Fatal().Err(err).Msg("failed to create service") } - if cfg.Services.Ratelimit != nil { - rl, err := ratelimit.New(ratelimit.Config{ - Logger: logger, - Metrics: m, - Cluster: clus, + srv, err := api.New(api.Config{ + NodeId: cfg.NodeId, + Logger: logger, + Ratelimit: rl, + Metrics: m, + Clickhouse: ch, + AuthToken: cfg.Cluster.AuthToken, + Vault: v, + }) + if err != nil { + return err + } + + if cfg.Services.EventRouter != nil { + er, err := eventrouter.New(eventrouter.Config{ + Logger: logger, + Metrics: m, + BatchSize: cfg.Services.EventRouter.Tinybird.BatchSize, + BufferSize: cfg.Services.EventRouter.Tinybird.BufferSize, + FlushInterval: time.Duration(cfg.Services.EventRouter.Tinybird.FlushInterval) * time.Second, + Tinybird: tinybird.New("https://api.tinybird.co", cfg.Services.EventRouter.Tinybird.Token), + AuthToken: cfg.AuthToken, }) if err != nil { - logger.Fatal().Err(err).Msg("failed to create service") + return err } - - srv.Ratelimit = ratelimit.WithTracing(rl) - - v1RatelimitRatelimit.Register(srv.HumaAPI(), srv.Services(), srv.BearerAuthFromSecret(cfg.Services.Ratelimit.AuthToken)) - v1RatelimitMultiRatelimit.Register(srv.HumaAPI(), srv.Services(), srv.BearerAuthFromSecret(cfg.Services.Ratelimit.AuthToken)) - v1RatelimitCommitLease.Register(srv.HumaAPI(), srv.Services(), srv.BearerAuthFromSecret(cfg.Services.Ratelimit.AuthToken)) - - err = connectSrv.AddService(connect.NewRatelimitServer(rl, logger, cfg.Services.Ratelimit.AuthToken)) + srv.WithEventRouter(er) if err != nil { - return fmt.Errorf("failed to add ratelimit service: %w", err) + return fmt.Errorf("failed to add event router service: %w", err) + } - logger.Info().Msg("started ratelimit service") } - if cfg.Pprof != nil { - connectSrv.EnablePprof(cfg.Pprof.Username, cfg.Pprof.Password) + connectSrv, err := connect.New(connect.Config{Logger: logger, Image: cfg.Image, Metrics: m}) + if err != nil { + return err + } + + err = connectSrv.AddService(connect.NewClusterServer(clus, logger)) + if err != nil { + return fmt.Errorf("failed to add cluster service: %w", err) + + } + err = connectSrv.AddService(connect.NewRatelimitServer(rl, logger, cfg.AuthToken)) + if err != nil { + return fmt.Errorf("failed to add ratelimit service: %w", err) } + logger.Info().Msg("started ratelimit service") go func() { err := connectSrv.Listen(fmt.Sprintf(":%s", cfg.RpcPort)) diff --git a/apps/agent/cmd/main.go b/apps/agent/cmd/main.go index 871a1e4828..78171086cd 100644 --- a/apps/agent/cmd/main.go +++ b/apps/agent/cmd/main.go @@ -26,7 +26,14 @@ func main() { fmt.Println() fmt.Println() - fmt.Println(chain) + for _, e := range chain { + fmt.Printf(" - ") + if e.Location != "" { + fmt.Printf("%s\n", e.Location) + fmt.Printf(" > ") + } + fmt.Printf("%s\n", e.Message) + } fmt.Println() os.Exit(1) } diff --git a/apps/agent/config.docker.json b/apps/agent/config.docker.json index 24d08937c0..9f1655fb0b 100644 --- a/apps/agent/config.docker.json +++ b/apps/agent/config.docker.json @@ -6,6 +6,7 @@ "username": "admin", "password": "admin" }, + "authToken": "${AUTH_TOKEN}", "nodeId": "${NODE_ID}", "logging": {}, "cluster": { @@ -19,11 +20,7 @@ } }, "services": { - "ratelimit": { - "authToken": "${AUTH_TOKEN}" - }, "eventRouter": { - "authToken": "${AUTH_TOKEN}", "tinybird": { "token": "${TINYBIRD_TOKEN}", "batchSize": 1000, @@ -36,12 +33,14 @@ "s3Bucket": "${VAULT_S3_BUCKET}", "s3AccessKeyId": "${VAULT_S3_ACCESS_KEY_ID}", "s3AccessKeySecret": "${VAULT_S3_ACCESS_KEY_SECRET}", - "masterKeys": "${VAULT_MASTER_KEYS}", - "authToken": "${AUTH_TOKEN}" + "masterKeys": "${VAULT_MASTER_KEYS}" } }, "prometheus": { "path": "/metrics", "port": 2112 + }, + "clickhouse": { + "url": "${CLICKHOUSE_URL}" } } diff --git a/apps/agent/config.production.json b/apps/agent/config.production.json index 39662ea010..ea4aade134 100644 --- a/apps/agent/config.production.json +++ b/apps/agent/config.production.json @@ -10,6 +10,7 @@ "port": "${PORT}", "rpcPort": "${RPC_PORT}", "region": "fly::${FLY_REGION}", + "authToken": "${AUTH_TOKEN}", "logging": { "axiom": { "dataset": "agent", @@ -29,11 +30,7 @@ } }, "services": { - "ratelimit": { - "authToken": "${AUTH_TOKEN}" - }, "eventRouter": { - "authToken": "${AUTH_TOKEN}", "tinybird": { "token": "${TINYBIRD_TOKEN}", "batchSize": 1000, @@ -46,8 +43,7 @@ "s3Bucket": "${VAULT_S3_BUCKET}", "s3AccessKeyId": "${VAULT_S3_ACCESS_KEY_ID}", "s3AccessKeySecret": "${VAULT_S3_ACCESS_KEY_SECRET}", - "masterKeys": "${VAULT_MASTER_KEYS}", - "authToken": "${AUTH_TOKEN}" + "masterKeys": "${VAULT_MASTER_KEYS}" } }, "cluster": { diff --git a/apps/agent/config.staging.json b/apps/agent/config.staging.json index 355c7a6427..15b0683710 100644 --- a/apps/agent/config.staging.json +++ b/apps/agent/config.staging.json @@ -10,12 +10,9 @@ "port": "${PORT}", "rpcPort": "${RPC_PORT}", "region": "fly::${FLY_REGION}", + "authToken": "${AUTH_TOKEN}", "services": { - "ratelimit": { - "authToken": "${AUTH_TOKEN}" - }, "eventRouter": { - "authToken": "${AUTH_TOKEN}", "tinybird": { "token": "${TINYBIRD_TOKEN}", "batchSize": 1000, @@ -28,8 +25,7 @@ "s3Bucket": "${VAULT_S3_BUCKET}", "s3AccessKeyId": "${VAULT_S3_ACCESS_KEY_ID}", "s3AccessKeySecret": "${VAULT_S3_ACCESS_KEY_SECRET}", - "masterKeys": "${VAULT_MASTER_KEYS}", - "authToken": "${AUTH_TOKEN}" + "masterKeys": "${VAULT_MASTER_KEYS}" } }, "cluster": { diff --git a/apps/agent/gen/openapi/gen.go b/apps/agent/gen/openapi/gen.go new file mode 100644 index 0000000000..61ba7ada85 --- /dev/null +++ b/apps/agent/gen/openapi/gen.go @@ -0,0 +1,284 @@ +// Package openapi provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT. +package openapi + +// BaseError defines model for BaseError. +type BaseError struct { + // Detail A human-readable explanation specific to this occurrence of the problem. + Detail string `json:"detail"` + + // Instance A URI reference that identifies the specific occurrence of the problem. + Instance string `json:"instance"` + + // RequestId A unique id for this request. Please always provide this to support. + RequestId string `json:"requestId"` + + // Status HTTP status code + Status int `json:"status"` + + // Title A short, human-readable summary of the problem type. This value should not change between occurrences of the error. + Title string `json:"title"` + + // Type A URI reference to human-readable documentation for the error. + Type string `json:"type"` +} + +// Encrypted defines model for Encrypted. +type Encrypted struct { + Encrypted string `json:"encrypted"` + KeyId string `json:"keyId"` +} + +// Item defines model for Item. +type Item struct { + // Cost The cost of the request. + Cost *int64 `json:"cost,omitempty"` + + // Duration The duration in milliseconds for the rate limit window. + Duration int64 `json:"duration"` + + // Identifier The identifier for the rate limit. + Identifier string `json:"identifier"` + + // Limit The maximum number of requests allowed. + Limit int64 `json:"limit"` +} + +// Lease defines model for Lease. +type Lease struct { + // Cost How much to lease. + Cost int64 `json:"cost"` + + // Timeout The time in milliseconds when the lease will expire. If you do not commit the lease by this time, it will be commited as is. + Timeout int64 `json:"timeout"` +} + +// SingleRatelimitResponse defines model for SingleRatelimitResponse. +type SingleRatelimitResponse struct { + // Current The current number of requests made in the current window. + Current int64 `json:"current"` + + // Limit The maximum number of requests allowed. + Limit int64 `json:"limit"` + + // Remaining The number of requests remaining in the current window. + Remaining int64 `json:"remaining"` + + // Reset The time in milliseconds when the rate limit will reset. + Reset int64 `json:"reset"` + + // Success Whether the request passed the ratelimit. If false, the request must be blocked. + Success bool `json:"success"` +} + +// V0EventsRequestBody NDJSON payload of events +type V0EventsRequestBody = string + +// V0EventsResponseBody defines model for V0EventsResponseBody. +type V0EventsResponseBody struct { + // Schema A URL to the JSON Schema for this object. + Schema *string `json:"$schema,omitempty"` + + // QuarantinedRows The number of rows that were quarantined + QuarantinedRows int `json:"quarantined_rows"` + + // SuccessfulRows The number of rows that were successfully processed + SuccessfulRows int `json:"successful_rows"` +} + +// V1DecryptRequestBody defines model for V1DecryptRequestBody. +type V1DecryptRequestBody struct { + // Schema A URL to the JSON Schema for this object. + Schema *string `json:"$schema,omitempty"` + + // Encrypted The encrypted base64 string. + Encrypted string `json:"encrypted"` + + // Keyring The keyring to use for encryption. + Keyring string `json:"keyring"` +} + +// V1DecryptResponseBody defines model for V1DecryptResponseBody. +type V1DecryptResponseBody struct { + // Schema A URL to the JSON Schema for this object. + Schema *string `json:"$schema,omitempty"` + + // Plaintext The plaintext value. + Plaintext string `json:"plaintext"` +} + +// V1EncryptBulkRequestBody defines model for V1EncryptBulkRequestBody. +type V1EncryptBulkRequestBody struct { + // Schema A URL to the JSON Schema for this object. + Schema *string `json:"$schema,omitempty"` + Data []string `json:"data"` + Keyring string `json:"keyring"` +} + +// V1EncryptBulkResponseBody defines model for V1EncryptBulkResponseBody. +type V1EncryptBulkResponseBody struct { + // Schema A URL to the JSON Schema for this object. + Schema *string `json:"$schema,omitempty"` + Encrypted []Encrypted `json:"encrypted"` +} + +// V1EncryptRequestBody defines model for V1EncryptRequestBody. +type V1EncryptRequestBody struct { + // Schema A URL to the JSON Schema for this object. + Schema *string `json:"$schema,omitempty"` + + // Data The data to encrypt. + Data string `json:"data"` + + // Keyring The keyring to use for encryption. + Keyring string `json:"keyring"` +} + +// V1EncryptResponseBody defines model for V1EncryptResponseBody. +type V1EncryptResponseBody struct { + // Schema A URL to the JSON Schema for this object. + Schema *string `json:"$schema,omitempty"` + + // Encrypted The encrypted data as base64 encoded string. + Encrypted string `json:"encrypted"` + + // KeyId The ID of the key used for encryption. + KeyId string `json:"keyId"` +} + +// V1LivenessResponseBody defines model for V1LivenessResponseBody. +type V1LivenessResponseBody struct { + // Schema A URL to the JSON Schema for this object. + Schema *string `json:"$schema,omitempty"` + + // Message Whether we're alive or not + Message string `json:"message"` +} + +// V1RatelimitCommitLeaseRequestBody defines model for V1RatelimitCommitLeaseRequestBody. +type V1RatelimitCommitLeaseRequestBody struct { + // Schema A URL to the JSON Schema for this object. + Schema *string `json:"$schema,omitempty"` + + // Cost The actual cost of the request. + Cost int64 `json:"cost"` + + // Lease The lease you received from the ratelimit response. + Lease string `json:"lease"` +} + +// V1RatelimitMultiRatelimitRequestBody defines model for V1RatelimitMultiRatelimitRequestBody. +type V1RatelimitMultiRatelimitRequestBody struct { + // Schema A URL to the JSON Schema for this object. + Schema *string `json:"$schema,omitempty"` + + // Ratelimits The rate limits to check. + Ratelimits []Item `json:"ratelimits"` +} + +// V1RatelimitMultiRatelimitResponseBody defines model for V1RatelimitMultiRatelimitResponseBody. +type V1RatelimitMultiRatelimitResponseBody struct { + // Schema A URL to the JSON Schema for this object. + Schema *string `json:"$schema,omitempty"` + + // Ratelimits The rate limits that were checked. + Ratelimits []SingleRatelimitResponse `json:"ratelimits"` +} + +// V1RatelimitRatelimitRequestBody defines model for V1RatelimitRatelimitRequestBody. +type V1RatelimitRatelimitRequestBody struct { + // Schema A URL to the JSON Schema for this object. + Schema *string `json:"$schema,omitempty"` + + // Cost The cost of the request. Defaults to 1 if not provided. + Cost *int64 `json:"cost,omitempty"` + + // Duration The duration in milliseconds for the rate limit window. + Duration int64 `json:"duration"` + + // Identifier The identifier for the rate limit. + Identifier string `json:"identifier"` + Lease *Lease `json:"lease,omitempty"` + + // Limit The maximum number of requests allowed. + Limit int64 `json:"limit"` +} + +// V1RatelimitRatelimitResponseBody defines model for V1RatelimitRatelimitResponseBody. +type V1RatelimitRatelimitResponseBody struct { + // Schema A URL to the JSON Schema for this object. + Schema *string `json:"$schema,omitempty"` + + // Current The current number of requests made in the current window. + Current int64 `json:"current"` + + // Lease The lease to use when committing the request. + Lease string `json:"lease"` + + // Limit The maximum number of requests allowed. + Limit int64 `json:"limit"` + + // Remaining The number of requests remaining in the current window. + Remaining int64 `json:"remaining"` + + // Reset The time in milliseconds when the rate limit will reset. + Reset int64 `json:"reset"` + + // Success Whether the request passed the ratelimit. If false, the request must be blocked. + Success bool `json:"success"` +} + +// ValidationError defines model for ValidationError. +type ValidationError struct { + // Detail A human-readable explanation specific to this occurrence of the problem. + Detail string `json:"detail"` + + // Errors Optional list of individual error details + Errors []ValidationErrorDetail `json:"errors"` + + // Instance A URI reference that identifies the specific occurrence of the problem. + Instance string `json:"instance"` + + // RequestId A unique id for this request. Please always provide this to support. + RequestId string `json:"requestId"` + + // Status HTTP status code + Status int `json:"status"` + + // Title A short, human-readable summary of the problem type. This value should not change between occurrences of the error. + Title string `json:"title"` + + // Type A URI reference to human-readable documentation for the error. + Type string `json:"type"` +} + +// ValidationErrorDetail defines model for ValidationErrorDetail. +type ValidationErrorDetail struct { + // Fix A human-readable message describing how to fix the error. + Fix *string `json:"fix,omitempty"` + + // Location Where the error occurred, e.g. 'body.items[3].tags' or 'path.thing-id' + Location string `json:"location"` + + // Message Error message text + Message string `json:"message"` +} + +// RatelimitV1MultiRatelimitJSONRequestBody defines body for RatelimitV1MultiRatelimit for application/json ContentType. +type RatelimitV1MultiRatelimitJSONRequestBody = V1RatelimitMultiRatelimitRequestBody + +// RatelimitV1RatelimitJSONRequestBody defines body for RatelimitV1Ratelimit for application/json ContentType. +type RatelimitV1RatelimitJSONRequestBody = V1RatelimitRatelimitRequestBody + +// V1RatelimitCommitLeaseJSONRequestBody defines body for V1RatelimitCommitLease for application/json ContentType. +type V1RatelimitCommitLeaseJSONRequestBody = V1RatelimitCommitLeaseRequestBody + +// VaultV1DecryptJSONRequestBody defines body for VaultV1Decrypt for application/json ContentType. +type VaultV1DecryptJSONRequestBody = V1DecryptRequestBody + +// VaultV1EncryptJSONRequestBody defines body for VaultV1Encrypt for application/json ContentType. +type VaultV1EncryptJSONRequestBody = V1EncryptRequestBody + +// VaultV1EncryptBulkJSONRequestBody defines body for VaultV1EncryptBulk for application/json ContentType. +type VaultV1EncryptBulkJSONRequestBody = V1EncryptBulkRequestBody diff --git a/apps/agent/go.mod b/apps/agent/go.mod index fb7a0cedf1..dddfa1c91f 100644 --- a/apps/agent/go.mod +++ b/apps/agent/go.mod @@ -5,6 +5,7 @@ go 1.22.3 require ( connectrpc.com/connect v1.16.2 connectrpc.com/otelconnect v0.7.1 + github.com/ClickHouse/clickhouse-go/v2 v2.28.1 github.com/Southclaws/fault v0.8.1 github.com/aws/aws-sdk-go-v2 v1.30.4 github.com/aws/aws-sdk-go-v2/config v1.27.31 @@ -13,12 +14,13 @@ require ( github.com/axiomhq/axiom-go v0.20.2 github.com/btcsuite/btcutil v1.0.2 github.com/danielgtaylor/huma v1.14.2 - github.com/danielgtaylor/huma/v2 v2.22.1 github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b github.com/google/uuid v1.6.0 github.com/grafana/pyroscope-go v1.1.2 github.com/hashicorp/serf v0.10.1 github.com/maypok86/otter v1.2.2 + github.com/pb33f/libopenapi v0.16.5 + github.com/pb33f/libopenapi-validator v0.1.0 github.com/prometheus/client_golang v1.20.2 github.com/redis/go-redis/v9 v9.6.1 github.com/rs/zerolog v1.33.0 @@ -42,10 +44,12 @@ require ( github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect github.com/AlecAivazis/survey/v2 v2.3.7 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/ClickHouse/ch-go v0.62.0 // indirect github.com/Masterminds/semver/v3 v3.3.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Microsoft/hcsshim v0.12.6 // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect + github.com/andybalholm/brotli v1.1.0 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 // indirect @@ -61,8 +65,10 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 // indirect github.com/aws/smithy-go v1.20.4 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/buger/goterm v1.0.4 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/compose-spec/compose-go/v2 v2.1.6 // indirect @@ -92,6 +98,7 @@ require ( github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dolthub/maphash v0.1.0 // indirect + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05 // indirect @@ -100,12 +107,16 @@ require ( github.com/fvbommel/sortorder v1.1.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/gammazero/deque v0.2.1 // indirect + github.com/getkin/kin-openapi v0.124.0 // indirect + github.com/go-faster/city v1.0.1 // indirect + github.com/go-faster/errors v0.7.1 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-sql-driver/mysql v1.4.0 // indirect github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/gofrs/flock v0.12.1 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -141,6 +152,7 @@ require ( github.com/in-toto/in-toto-golang v0.9.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/influxdata/tdigest v0.0.1 // indirect + github.com/invopop/yaml v0.2.0 // indirect github.com/jonboulle/clockwork v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -172,12 +184,17 @@ require ( github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/oapi-codegen/oapi-codegen/v2 v2.3.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/paulmach/orb v0.11.1 // indirect github.com/pelletier/go-toml v1.9.5 // indirect + github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect @@ -188,12 +205,15 @@ require ( github.com/rivo/uniseg v0.4.7 // indirect github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect + github.com/segmentio/asm v1.2.0 // indirect github.com/serialx/hashring v0.0.0-20200727003509-22c0c7ab6b1b // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect github.com/shirou/gopsutil/v3 v3.24.5 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/spf13/pflag v1.0.5 // indirect @@ -206,6 +226,8 @@ require ( github.com/tonistiigi/go-csvvalue v0.0.0-20240814133006-030d3b2625d0 // indirect github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect github.com/tonistiigi/vt100 v0.0.0-20240514184818-90bafcd6abab // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect diff --git a/apps/agent/go.sum b/apps/agent/go.sum index d7c4f787fe..0a547a6cc8 100644 --- a/apps/agent/go.sum +++ b/apps/agent/go.sum @@ -64,10 +64,12 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/ClickHouse/ch-go v0.62.0 h1:eXH0hytXeCEEZHgMvOX9IiW7wqBb4w1MJMp9rArbkrc= +github.com/ClickHouse/ch-go v0.62.0/go.mod h1:uzso52/PD9+gZj7tL6XAo8/EYDrx7CIwNF4c6PnO6S0= +github.com/ClickHouse/clickhouse-go/v2 v2.28.1 h1:tpdOxWZlZ4IYiFWpIteU57JVdWVbSI5OwflofAdhFno= +github.com/ClickHouse/clickhouse-go/v2 v2.28.1/go.mod h1:0U915l9qynE508ehh3ea9+UMGc7gZlAV+9W6pUZd7kk= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Jeffail/gabs/v2 v2.6.1/go.mod h1:xCn81vdHKxFUuWWAaD5jCTQDNPBMh5pPs9IJ+NcziBI= -github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= -github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= @@ -92,6 +94,8 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 h1:aM1rlcoLz8y5B2r4tTLMiVTrMtpfY0O8EScKJxaSaEc= github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -106,12 +110,8 @@ github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDag github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 h1:70PVAiL15/aBMh5LThwgXdSQorVr91L127ttckI9QQU= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4/go.mod h1:/MQxMqci8tlqDH+pjmoLu1i0tbWCUP1hhyMRuFxpQCw= -github.com/aws/aws-sdk-go-v2/config v1.27.28 h1:OTxWGW/91C61QlneCtnD62NLb4W616/NM1jA8LhJqbg= -github.com/aws/aws-sdk-go-v2/config v1.27.28/go.mod h1:uzVRVtJSU5EFv6Fu82AoVFKozJi2ZCY6WRCXj06rbvs= github.com/aws/aws-sdk-go-v2/config v1.27.31 h1:kxBoRsjhT3pq0cKthgj6RU6bXTm/2SgdoUMyrVw0rAI= github.com/aws/aws-sdk-go-v2/config v1.27.31/go.mod h1:z04nZdSWFPaDwK3DdJOG2r+scLQzMYuJeW0CujEm9FM= -github.com/aws/aws-sdk-go-v2/credentials v1.17.28 h1:m8+AHY/ND8CMHJnPoH7PJIRakWGa4gbfbxuY9TGTUXM= -github.com/aws/aws-sdk-go-v2/credentials v1.17.28/go.mod h1:6TF7dSc78ehD1SL6KpRIPKMA1GyyWflIkjqg+qmf4+c= github.com/aws/aws-sdk-go-v2/credentials v1.17.30 h1:aau/oYFtibVovr2rDt8FHlU17BTicFEMAi29V1U+L5Q= github.com/aws/aws-sdk-go-v2/credentials v1.17.30/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE= @@ -132,22 +132,20 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 h1:tJ5RnkHC github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18/go.mod h1:++NHzT+nAF7ZPrHPsA+ENvsXkOO8wEu+C6RXltAG4/c= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16 h1:jg16PhLPUiHIj8zYIW6bqzeQSuHVEiWnGA0Brz5Xv2I= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16/go.mod h1:Uyk1zE1VVdsHSU7096h/rwnXDzOzYQVl+FNPhPw7ShY= -github.com/aws/aws-sdk-go-v2/service/s3 v1.60.0 h1:2QXGJvG19QwqXUvgcdoCOZPyLuvZf8LiXPCN4P53TdI= -github.com/aws/aws-sdk-go-v2/service/s3 v1.60.0/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI= github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0 h1:Wb544Wh+xfSXqJ/j3R4aX9wrKUoZsJNmilBYZb3mKQ4= github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI= github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 h1:zCsFCKvbj25i7p1u94imVoO447I/sFv8qq+lGJhRN0c= github.com/aws/aws-sdk-go-v2/service/sso v1.22.5/go.mod h1:ZeDX1SnKsVlejeuz41GiajjZpRSWR7/42q/EyA/QEiM= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 h1:SKvPgvdvmiTWoi0GAJ7AsJfOz3ngVkD/ERbs5pUnHNI= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5/go.mod h1:20sz31hv/WsPa3HhU3hfrIet2kxM4Pe0r20eBZ20Tac= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.4 h1:iAckBT2OeEK/kBDyN/jDtpEExhjeeA/Im2q4X0rJZT8= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.4/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 h1:OMsEmCyz2i89XwRwPouAJvhj81wINh+4UK+k/0Yo/q8= github.com/aws/aws-sdk-go-v2/service/sts v1.30.5/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/axiomhq/axiom-go v0.20.2 h1:RKelFJr8Pei0xIoBaVteGGvn2pkaaMLrWiHLWu8d0Mc= github.com/axiomhq/axiom-go v0.20.2/go.mod h1:TWHIoBDv/IJNKgyo2EQeOwH4svi+cTePSihPVWZC1/8= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20150223135152-b965b613227f/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -177,6 +175,8 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/buger/goterm v1.0.4 h1:Z9YvGmOih81P0FbVtEYTFF6YsSgxSUKEhf/f9bTMXbY= github.com/buger/goterm v1.0.4/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQtB8tE= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0 h1:s7+5BfS4WFJoVF9pnB8kBk03S7pZXRdKamnV0FOl5Sc= github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ= @@ -187,7 +187,6 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -220,8 +219,6 @@ github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGD github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0= github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro= github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= -github.com/containerd/containerd v1.7.20 h1:Sl6jQYk3TRavaU83h66QMbI2Nqg9Jm6qzwX57Vsn1SQ= -github.com/containerd/containerd v1.7.20/go.mod h1:52GsS5CwquuqPuLncsXwG0t2CiUce+KsNHJZQJvAgR0= github.com/containerd/containerd v1.7.21 h1:USGXRK1eOC/SX0L195YgxTHb0a00anxajOzgfN0qrCA= github.com/containerd/containerd v1.7.21/go.mod h1:e3Jz1rYRUZ2Lt51YrH9Rz0zPyJBOlSvB3ghr2jbVD8g= github.com/containerd/containerd/api v1.7.19 h1:VWbJL+8Ap4Ju2mx9c9qS1uFSB1OVYr5JJrW2yT5vFoA= @@ -243,7 +240,6 @@ github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk= github.com/containerd/ttrpc v1.2.5 h1:IFckT1EFQoFBMG4c3sMdT8EP3/aKfumK1msY+Ze4oLU= github.com/containerd/ttrpc v1.2.5/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o= -github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY= github.com/containerd/typeurl/v2 v2.2.0 h1:6NBDbQzr7I5LHgp34xAXYF5DOTQDn05X58lsPEmzLso= github.com/containerd/typeurl/v2 v2.2.0/go.mod h1:8XOOxnyatxSWuG8OfsZXVnAF4iZfedjS/8UHSPJnX4g= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -261,8 +257,6 @@ github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr github.com/danielgtaylor/casing v0.0.0-20210126043903-4e55e6373ac3/go.mod h1:eFdYmNxcuLDrRNW0efVoxSaApmvGXfHZ9k2CT/RSUF0= github.com/danielgtaylor/huma v1.14.2 h1:Ftqdchm9dVItD+ZAy4gmSgA8oYrvqRgVHCshZbuzS8Q= github.com/danielgtaylor/huma v1.14.2/go.mod h1:I/19C1eNQd7ojMIQvynPe3lbuD5KfQEinH+ivIqjqmg= -github.com/danielgtaylor/huma/v2 v2.22.1 h1:fXhyjGSj5u5VeI+laa+e+7OxiQsP9RC55/tWZZvI4YA= -github.com/danielgtaylor/huma/v2 v2.22.1/go.mod h1:2NZmGf/A+SstJYQlq0Xp4nsTDCmPvKS2w9vI8c9sf1A= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -277,8 +271,6 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/buildx v0.16.2 h1:SPcyEiiCZEntJQ+V0lJI8ZudUrki2v1qUqmC/NqxDDs= github.com/docker/buildx v0.16.2/go.mod h1:by+CuE4Q+2NvECkIhNcWe89jjbHADCrDlzS9MRgbv2k= -github.com/docker/cli v27.1.2+incompatible h1:nYviRv5Y+YAKx3dFrTvS1ErkyVVunKOhoweCTE1BsnI= -github.com/docker/cli v27.1.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v27.2.0+incompatible h1:yHD1QEB1/0vr5eBNpu8tncu8gWxg8EydFPOSKHzXSMM= github.com/docker/cli v27.2.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli-docs-tool v0.8.0 h1:YcDWl7rQJC3lJ7WVZRwSs3bc9nka97QLWfyJQli8yJU= @@ -288,8 +280,6 @@ github.com/docker/compose/v2 v2.29.2/go.mod h1:U+yqqZqYPhILehkmmir+Yh7ZhCfkKqAva github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v27.1.2+incompatible h1:AhGzR1xaQIy53qCkxARaFluI00WPGtXn0AJuoQsVYTY= -github.com/docker/docker v27.1.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v27.2.0+incompatible h1:Rk9nIVdfH3+Vz4cyI/uhbINhEZ/oLmc+CBXmH6fbNk4= github.com/docker/docker v27.2.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= @@ -310,6 +300,9 @@ github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ= github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4= +github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58= +github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w= +github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q= github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 h1:XBBHcIb256gUJtLmY22n99HaZTz+r2Z51xUPi01m3wg= github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203/go.mod h1:E1jcSv8FaEny+OP/5k9UxZVw9YFWGj7eI4KR/iOBqCg= @@ -340,6 +333,7 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/fsnotify/fsevents v0.2.0 h1:BRlvlqjvNTfogHfeBOFvSC9N0Ddy+wzQCQukyoD7o/c= github.com/fsnotify/fsevents v0.2.0/go.mod h1:B3eEk39i4hz8y1zaWS/wPrAP4O6wkIl7HQwKBr1qH/w= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= @@ -350,11 +344,14 @@ github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/gammazero/deque v0.2.1 h1:qSdsbG6pgp6nL7A0+K/B7s12mcCY/5l5SIUpMOl+dC0= github.com/gammazero/deque v0.2.1/go.mod h1:LFroj8x4cMYCukHJDbxFCkT+r9AndaJnFMuZDV34tuU= +github.com/getkin/kin-openapi v0.124.0 h1:VSFNMB9C9rTKBnQ/fpyDU8ytMTr4dWI9QovSKj9kz/M= +github.com/getkin/kin-openapi v0.124.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= -github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= -github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw= +github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw= +github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg= +github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -380,9 +377,12 @@ github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvSc github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/go-sql-driver/mysql v1.3.0 h1:pgwjLi/dvffoP9aabwkT3AKpXQM93QARkjFhDDqC1UE= github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w= @@ -432,6 +432,7 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac h1:Q0Jsdxl5jbxouNs1TQYt0gxesYMU4VXRbsTlgDloZ50= github.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac/go.mod h1:P32wAyui1PQ58Oce/KYkOqQv8cVw1zAapXOl+dRFGbc= @@ -449,8 +450,6 @@ github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b h1:fbskpz/cPqWH8VqkQ7LJ github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b/go.mod h1:Z4GIJBJO3Wa4gD4vbwQxXXZ+WHmW6E9ixmNrwvs0iZs= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93 h1:jc2UWq7CbdszqeH6qu1ougXMIUBfSy8Pbh/anURYbGI= @@ -493,6 +492,7 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -521,7 +521,6 @@ github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZ github.com/graphql-go/graphql v0.7.9/go.mod h1:k6yrAYQaSP59DC5UVxbgxESlmVyojThKdORUqGDGmrI= github.com/graphql-go/graphql v0.8.0/go.mod h1:nKiHzRM0qopJEwCITUuIsxk9PlVlwIiiI8pnJEhordQ= github.com/graphql-go/handler v0.2.3/go.mod h1:leLF6RpV5uZMN1CdImAxuiayrYYhOk33bZciaUGaXeU= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= @@ -592,6 +591,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY= github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= +github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY= +github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8 h1:CZkYfurY6KGhVtlalI4QwQ6T0Cu6iuY3e0x5RLu96WE= @@ -619,6 +620,7 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:C github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -727,6 +729,9 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -735,19 +740,30 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oapi-codegen/oapi-codegen/v2 v2.3.0 h1:rICjNsHbPP1LttefanBPnwsSwl09SqhCO7Ee623qR84= +github.com/oapi-codegen/oapi-codegen/v2 v2.3.0/go.mod h1:4k+cJeSq5ntkwlcpQSxLxICCxQzCL772o30PxdibRt4= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= +github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= -github.com/onsi/ginkgo/v2 v2.20.0 h1:PE84V2mHqoT1sglvHc8ZdQtPcwmvvt29WLEEO3xmdZw= -github.com/onsi/ginkgo/v2 v2.20.0/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= -github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -764,11 +780,22 @@ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYr github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU= +github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU= +github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY= +github.com/pb33f/libopenapi v0.16.5 h1:jqb/N5nc2zuSUSWDgCXi2vKGxMQfTsWHgtmPWSKQGqc= +github.com/pb33f/libopenapi v0.16.5/go.mod h1:PEXNwvtT4KNdjrwudp5OYnD1ryqK6uJ68aMNyWvoMuc= +github.com/pb33f/libopenapi-validator v0.1.0 h1:3XvtjtsMwPDM3qsC7ITrwVAzCLvOxKZLVKBukVBSRmY= +github.com/pb33f/libopenapi-validator v0.1.0/go.mod h1:Cwdf0GUmnUrbw1LBpcGV1Wx5q/LC9akREV4Jc6/yJDc= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= +github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= +github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= +github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -800,8 +827,6 @@ github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7q github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY= github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -827,18 +852,22 @@ github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529/go.mod h1:qe5TWALJ8/a1 github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= -github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= -github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/secure-systems-lab/go-securesystemslib v0.8.0 h1:mr5An6X45Kb2nddcFlbmfHkLguCE9laoZCUzEEpIZXA= github.com/secure-systems-lab/go-securesystemslib v0.8.0/go.mod h1:UH2VZVuJfCYR8WgMlCU1uFsOUU+KeyrTWcSS73NBOzU= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/serialx/hashring v0.0.0-20200727003509-22c0c7ab6b1b h1:h+3JX2VoWTFuyQEo87pStk/a99dzIO1mM9KxIyLPGTU= github.com/serialx/hashring v0.0.0-20200727003509-22c0c7ab6b1b/go.mod h1:/yeG0My1xr/u+HZrFQ1tOQQQQrOawfyMUH13ai5brBc= github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI= @@ -849,6 +878,8 @@ github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFt github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= @@ -912,6 +943,7 @@ github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= @@ -935,13 +967,19 @@ github.com/tsenart/vegeta/v12 v12.12.0/go.mod h1:gpdfR++WHV9/RZh4oux0f6lNPhsOH8p github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/unkeyed/unkey-go v0.8.8 h1:NtWI5Ix9nuERVVwP+1Bs4GAr7aHDcDR+/ArD84PgCn8= github.com/unkeyed/unkey-go v0.8.8/go.mod h1:X8PHynf0QviDvYFWXePSFIGZydm3bRCqOIk7k1nNHuk= -github.com/urfave/cli v1.22.15 h1:nuqt+pdC/KqswQKhETJjo7pvn/k4xMUxgW6liI7XpnM= github.com/urfave/cli/v2 v2.27.4 h1:o1owoI+02Eb+K107p27wEX9Bb8eqIoZCfLXloLUSWJ8= github.com/urfave/cli/v2 v2.27.4/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ= github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts= github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk= +github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= +github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -951,6 +989,7 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -962,6 +1001,7 @@ github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= +go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -971,48 +1011,28 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.53.0 h1:IVtyPth4Rs5P8wIf0mP2KVKFNTJ4paX9qQ4Hkh5gFdc= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.53.0/go.mod h1:ImRBLMJv177/pwiLZ7tU7HDGNdBv7rS0HQ99eN/zBl8= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.54.0 h1:U9ge/19g8pkNXL+0eqeWgiJAd8nSmmvbvwehqyxU/Lc= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.54.0/go.mod h1:dmNhUi0Tl5v/3e0QNp7/3KLMvAPoHh4lMbZU319UkM0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 h1:U2guen0GhqH8o/G2un8f/aG/y++OuW6MyCo6hT9prXk= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0/go.mod h1:yeGZANgEcpdx/WK0IvvRFC+2oLiMS2u4L/0Rj2M2Qr0= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.29.0 h1:k6fQVDQexDE+3jG2SfCQjnHS7OamcP73YMoxEVq5B6k= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.29.0/go.mod h1:t4BrYLHU450Zo9fnydWlIuswB1bm7rM8havDpWOJeDo= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0 h1:aLmmtjRke7LPDQ3lvpFz+kNEH43faFhzW7v8BFIEydg= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0/go.mod h1:TC1pyCt6G9Sjb4bQpShH+P5R53pO6ZuGnHuuln9xMeE= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.29.0 h1:xvhQxJ/C9+RTnAj5DpTg7LSM1vbbMTiXt7e9hsfqHNw= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.29.0/go.mod h1:Fcvs2Bz1jkDM+Wf5/ozBGmi3tQ/c9zPKLnsipnfhGAo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 h1:j9+03ymgYhPKmeXGk5Zu+cIZOlVzd9Zv7QIiyItjFBU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0/go.mod h1:Y5+XiUG4Emn1hTfciPzGPJaSI+RpDts6BnCIir0SLqk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 h1:JAv0Jwtl01UFiyWZEMiJZBiTlv5A50zNs8lsthXqIio= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0/go.mod h1:QNKLmUEAq2QUbPQUfvw4fmv0bgbK7UlOSFCnXyfvSNc= go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= -go.opentelemetry.io/otel/sdk/metric v1.28.0 h1:OkuaKgKrgAbYrrY0t92c+cC+2F6hsFNnCQArXCKlg08= -go.opentelemetry.io/otel/sdk/metric v1.28.0/go.mod h1:cWPjykihLAPvXKi4iZc1dpER3Jdq2Z0YLse3moQUCpg= go.opentelemetry.io/otel/sdk/metric v1.29.0 h1:K2CfmJohnRgvZ9UAj2/FhIf/okdWcNdBwe1m8xFXiSY= go.opentelemetry.io/otel/sdk/metric v1.29.0/go.mod h1:6zZLdCl2fkauYoZIOn/soQIDSWFmNSRcICarHfuhNJQ= go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= @@ -1048,6 +1068,7 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1061,8 +1082,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= -golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA= golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= @@ -1121,6 +1140,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -1135,8 +1155,11 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= @@ -1189,10 +1212,12 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1219,6 +1244,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1245,6 +1271,7 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1325,6 +1352,7 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -1383,6 +1411,8 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1446,16 +1476,10 @@ google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20240820151423-278611b39280 h1:oKt8r1ZvaPqBe3oeGTdyx1iNjuBS+VJcc9QdU1CD3d8= -google.golang.org/genproto v0.0.0-20240820151423-278611b39280/go.mod h1:wxEc5TmU9JSLs1rSqG4z1YzeSNigp/9yIojIPuZVvKQ= google.golang.org/genproto v0.0.0-20240827150818-7e3bb234dfed h1:4C4dbrVFtfIp3GXJdMX1Sj25mahfn5DywOo65/2ISQ8= google.golang.org/genproto v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:ICjniACoWvcDz8c8bOsHVKuuSGDJy1z5M4G0DM3HzTc= -google.golang.org/genproto/googleapis/api v0.0.0-20240820151423-278611b39280 h1:YDFM9oOjiFhaMAVgbDxfxW+66nRrsvzQzJ51wp3OxC0= -google.golang.org/genproto/googleapis/api v0.0.0-20240820151423-278611b39280/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g= google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed h1:3RgNmBoI9MZhsj3QxC+AP/qQhNwpCLOvYDYYsFrhFt0= google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240820151423-278611b39280 h1:XQMA2e105XNlEZ8NRF0HqnUOZzP14sUSsgL09kpdNnU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240820151423-278611b39280/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed h1:J6izYgfBXAI3xTKLgxzTmUltdYaLsuBxFCgDHWJ/eXg= google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -1486,8 +1510,6 @@ google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= @@ -1529,6 +1551,7 @@ gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.1 h1:d4KQkxAaAiRY2h5Zqis161Pv91A37uZyJOx73duwUwM= gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.1/go.mod h1:WbjuEoo1oadwzQ4apSDU+JTvmllEHtsNHS6y7vFc7iw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1536,10 +1559,13 @@ gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= @@ -1559,12 +1585,8 @@ k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8= k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20240816214639-573285566f34 h1:/amS69DLm09mtbFtN3+LyygSFohnYGMseF8iv+2zulg= -k8s.io/kube-openapi v0.0.0-20240816214639-573285566f34/go.mod h1:G0W3eI9gG219NHRq3h5uQaRBl4pj4ZpwzRP5ti8y770= k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 h1:GKE9U8BH16uynoxQii0auTjmmmuZ3O0LFMN6S0lPPhI= k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20240821151609-f90d01438635 h1:2wThSvJoW/Ncn9TmQEYXRnevZXi2duqHWf5OX9S3zjI= k8s.io/utils v0.0.0-20240821151609-f90d01438635/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= diff --git a/apps/agent/integration/cluster/docker/ratelimits_test.go b/apps/agent/integration/cluster/docker/ratelimits_test.go index ba9928e15d..79fa56599d 100644 --- a/apps/agent/integration/cluster/docker/ratelimits_test.go +++ b/apps/agent/integration/cluster/docker/ratelimits_test.go @@ -10,7 +10,7 @@ import ( "time" "github.com/stretchr/testify/require" - v1RatelimitRatelimit "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_ratelimit_ratelimit" + "github.com/unkeyed/unkey/apps/agent/gen/openapi" "github.com/unkeyed/unkey/apps/agent/pkg/uid" @@ -88,12 +88,13 @@ func TestRatelimitsAccuracy(t *testing.T) { for _, tc := range testCases { t.Run(fmt.Sprintf("[%d/%s] attacked with %s over %s", tc.limit, tc.duration, tc.rate.String(), tc.testDuration), func(t *testing.T) { t.Parallel() - request := v1RatelimitRatelimit.V1RatelimitRatelimitRequest{} - request.Body.Identifier = uid.New("test") - request.Body.Limit = tc.limit - request.Body.Duration = tc.duration.Milliseconds() + request := openapi.V1RatelimitRatelimitRequestBody{ + Identifier: uid.New("test"), + Limit: tc.limit, + Duration: tc.duration.Milliseconds(), + } - b, err := json.Marshal(request.Body) + b, err := json.Marshal(request) require.NoError(t, err) target := vegeta.Target{ @@ -115,14 +116,14 @@ func TestRatelimitsAccuracy(t *testing.T) { for res := range attacker.Attack(vegeta.NewStaticTargeter(target), tc.rate, tc.testDuration, "v1.ratelimit.Ratelimit") { total++ - body := v1RatelimitRatelimit.V1RatelimitRatelimitResponse{} - err := json.Unmarshal(res.Body, &body.Body) + body := openapi.V1RatelimitRatelimitResponseBody{} + err := json.Unmarshal(res.Body, &body) if err != nil { errors++ continue } - if body.Body.Success { + if body.Success { passed++ } else { rejected++ diff --git a/apps/agent/pkg/api/agent_auth.go b/apps/agent/pkg/api/agent_auth.go index 1275243713..d3f1e8c7c5 100644 --- a/apps/agent/pkg/api/agent_auth.go +++ b/apps/agent/pkg/api/agent_auth.go @@ -5,34 +5,38 @@ import ( "net/http" "strings" - "github.com/danielgtaylor/huma/v2" + "github.com/unkeyed/unkey/apps/agent/pkg/api/routes" ) -func (s *Server) BearerAuthFromSecret(secret string) func(huma.Context, func(huma.Context)) { - +func newBearerAuthMiddleware(secret string) routes.Middeware { secretB := []byte(secret) - return func(ctx huma.Context, next func(huma.Context)) { + return func(next http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { - authorizationHeader := ctx.Header("Authorization") - if authorizationHeader == "" { - huma.WriteErr(s.api, ctx, http.StatusUnauthorized, "Authorization header is required") - return - } + authorizationHeader := r.Header.Get("Authorization") + if authorizationHeader == "" { + w.WriteHeader(401) + w.Write([]byte("Authorization header is required")) + return + } - token := strings.TrimPrefix(authorizationHeader, "Bearer ") - if token == "" { - huma.WriteErr(s.api, ctx, http.StatusUnauthorized, "Bearer token is required") - return - } + token := strings.TrimPrefix(authorizationHeader, "Bearer ") + if token == "" { + w.WriteHeader(401) + w.Write([]byte("Bearer token is required")) + return - if subtle.ConstantTimeCompare([]byte(token), secretB) != 1 { - huma.WriteErr(s.api, ctx, http.StatusUnauthorized, "Invalid bearer token") + } - return - } + if subtle.ConstantTimeCompare([]byte(token), secretB) != 1 { + w.WriteHeader(401) + w.Write([]byte("Bearer token is invalid")) + return + } - next(ctx) + next(w, r) + } } } diff --git a/apps/agent/pkg/api/ctxutil/context.go b/apps/agent/pkg/api/ctxutil/context.go new file mode 100644 index 0000000000..a0deb97f2e --- /dev/null +++ b/apps/agent/pkg/api/ctxutil/context.go @@ -0,0 +1,25 @@ +package ctxutil + +import "context" + +const ( + request_id string = "request_id" +) + +// getValue returns the value for the given key from the context or its zero value if it doesn't exist. +func getValue[T any](ctx context.Context, key string) T { + val, ok := ctx.Value(key).(T) + if !ok { + var t T + return t + } + return val +} + +func GetRequestId(ctx context.Context) string { + return getValue[string](ctx, request_id) +} + +func SetRequestId(ctx context.Context, requestId string) context.Context { + return context.WithValue(ctx, request_id, requestId) +} diff --git a/apps/agent/pkg/api/errors/internal_server_error.go b/apps/agent/pkg/api/errors/internal_server_error.go new file mode 100644 index 0000000000..d63281cf09 --- /dev/null +++ b/apps/agent/pkg/api/errors/internal_server_error.go @@ -0,0 +1,24 @@ +package errors + +import ( + "context" + "net/http" + + "github.com/Southclaws/fault/fmsg" + "github.com/unkeyed/unkey/apps/agent/gen/openapi" + "github.com/unkeyed/unkey/apps/agent/pkg/api/ctxutil" +) + +// HandleError takes in any unforseen error and returns a BaseError to be sent to the client +func HandleError(ctx context.Context, err error) openapi.BaseError { + + return openapi.BaseError{ + Title: "Internal Server Error", + Detail: fmsg.GetIssue(err), + Instance: "https://errors.unkey.com/todo", + Status: http.StatusInternalServerError, + RequestId: ctxutil.GetRequestId(ctx), + Type: "TODO docs link", + } + +} diff --git a/apps/agent/pkg/api/errors/validation_error.go b/apps/agent/pkg/api/errors/validation_error.go new file mode 100644 index 0000000000..0c44abd289 --- /dev/null +++ b/apps/agent/pkg/api/errors/validation_error.go @@ -0,0 +1,32 @@ +package errors + +import ( + "context" + "net/http" + + "github.com/Southclaws/fault/fmsg" + "github.com/unkeyed/unkey/apps/agent/gen/openapi" + "github.com/unkeyed/unkey/apps/agent/pkg/api/ctxutil" +) + +func HandleValidationError(ctx context.Context, err error) openapi.ValidationError { + + issues := fmsg.GetIssues(err) + details := make([]openapi.ValidationErrorDetail, len(issues)) + for i, issue := range issues { + details[i] = openapi.ValidationErrorDetail{ + Message: issue, + } + } + + return openapi.ValidationError{ + Title: "Internal Server Error", + Detail: "An internal server error occurred", + Errors: details, + Instance: "https://errors.unkey.com/todo", + Status: http.StatusBadRequest, + RequestId: ctxutil.GetRequestId(ctx), + Type: "TODO docs link", + } + +} diff --git a/apps/agent/pkg/api/interface.go b/apps/agent/pkg/api/interface.go new file mode 100644 index 0000000000..7c129ff55e --- /dev/null +++ b/apps/agent/pkg/api/interface.go @@ -0,0 +1,7 @@ +package api + +import "github.com/unkeyed/unkey/apps/agent/pkg/clickhouse/schema" + +type EventBuffer interface { + BufferApiRequest(schema.ApiRequestV1) +} diff --git a/apps/agent/pkg/api/mw_logging.go b/apps/agent/pkg/api/mw_logging.go new file mode 100644 index 0000000000..6738238ae3 --- /dev/null +++ b/apps/agent/pkg/api/mw_logging.go @@ -0,0 +1,93 @@ +package api + +import ( + "bytes" + "fmt" + "io" + "net/http" + "strings" + "time" + + "github.com/unkeyed/unkey/apps/agent/pkg/api/ctxutil" + "github.com/unkeyed/unkey/apps/agent/pkg/clickhouse" + "github.com/unkeyed/unkey/apps/agent/pkg/clickhouse/schema" + "github.com/unkeyed/unkey/apps/agent/pkg/logging" +) + +type responseWriterInterceptor struct { + w http.ResponseWriter + body *bytes.Buffer + statusCode int +} + +// Pass through +func (w *responseWriterInterceptor) Header() http.Header { + return w.w.Header() +} + +// Capture and pass through +func (w *responseWriterInterceptor) Write(b []byte) (int, error) { + w.body.Write(b) + return w.w.Write(b) +} + +// Capture and pass through +func (w *responseWriterInterceptor) WriteHeader(statusCode int) { + w.statusCode = statusCode + w.w.WriteHeader(statusCode) +} +func withLogging(next http.Handler, ch clickhouse.Bufferer, logger logging.Logger) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + ctx := r.Context() + wi := &responseWriterInterceptor{w: w, body: &bytes.Buffer{}} + + errorMessage := "" + // r2 is a clone of r, so we can read the body twice + r2 := r.Clone(ctx) + defer r2.Body.Close() + requestBody, err := io.ReadAll(r2.Body) + if err != nil { + logger.Error().Err(err).Msg("error reading r2 body") + errorMessage = err.Error() + requestBody = []byte("unable to read request body") + } + + next.ServeHTTP(wi, r) + serviceLatency := time.Since(start) + + logger.Info(). + Str("method", r.Method). + Str("path", r.URL.Path). + Int("status", wi.statusCode). + Str("latency", serviceLatency.String()). + Msg("request") + + requestHeaders := []string{} + for k, vv := range r.Header { + if strings.ToLower(k) == "authorization" { + vv = []string{""} + } + requestHeaders = append(requestHeaders, fmt.Sprintf("%s: %s", k, strings.Join(vv, ","))) + } + + responseHeaders := []string{} + for k, vv := range wi.Header() { + responseHeaders = append(responseHeaders, fmt.Sprintf("%s: %s", k, strings.Join(vv, ","))) + } + + ch.BufferApiRequest(schema.ApiRequestV1{ + RequestID: ctxutil.GetRequestId(ctx), + Time: start.UnixMilli(), + Host: r.Host, + Method: r.Method, + Path: r.URL.Path, + RequestHeaders: requestHeaders, + RequestBody: string(requestBody), + ResponseStatus: wi.statusCode, + ResponseHeaders: responseHeaders, + ResponseBody: wi.body.String(), + Error: errorMessage, + }) + }) +} diff --git a/apps/agent/pkg/api/mw_metrics.go b/apps/agent/pkg/api/mw_metrics.go new file mode 100644 index 0000000000..67e070a511 --- /dev/null +++ b/apps/agent/pkg/api/mw_metrics.go @@ -0,0 +1,48 @@ +package api + +import ( + "fmt" + "net/http" + "time" + + "github.com/unkeyed/unkey/apps/agent/pkg/prometheus" +) + +type responseWriterStatusInterceptor struct { + w http.ResponseWriter + statusCode int +} + +// Pass through +func (w *responseWriterStatusInterceptor) Header() http.Header { + return w.w.Header() +} + +// Pass through +func (w *responseWriterStatusInterceptor) Write(b []byte) (int, error) { + return w.w.Write(b) +} + +// Capture and pass through +func (w *responseWriterStatusInterceptor) WriteHeader(statusCode int) { + w.statusCode = statusCode + w.w.WriteHeader(statusCode) +} + +func withMetrics(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + wi := &responseWriterStatusInterceptor{w: w} + + start := time.Now() + next.ServeHTTP(wi, r) + serviceLatency := time.Since(start) + + prometheus.HTTPRequests.With(map[string]string{ + "method": r.Method, + "path": r.URL.Path, + "status": fmt.Sprintf("%d", wi.statusCode), + }).Inc() + + prometheus.ServiceLatency.WithLabelValues(r.URL.Path).Observe(serviceLatency.Seconds()) + }) +} diff --git a/apps/agent/pkg/api/mw_request_id.go b/apps/agent/pkg/api/mw_request_id.go new file mode 100644 index 0000000000..f31ad1015c --- /dev/null +++ b/apps/agent/pkg/api/mw_request_id.go @@ -0,0 +1,16 @@ +package api + +import ( + "net/http" + + "github.com/unkeyed/unkey/apps/agent/pkg/api/ctxutil" + "github.com/unkeyed/unkey/apps/agent/pkg/uid" +) + +func withRequestId(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + ctx = ctxutil.SetRequestId(ctx, uid.New(uid.Request())) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} diff --git a/apps/agent/pkg/api/mw_tracing.go b/apps/agent/pkg/api/mw_tracing.go new file mode 100644 index 0000000000..eb3bfcb2c0 --- /dev/null +++ b/apps/agent/pkg/api/mw_tracing.go @@ -0,0 +1,18 @@ +package api + +import ( + "net/http" + + "github.com/unkeyed/unkey/apps/agent/pkg/tracing" +) + +func withTracing(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + ctx, span := tracing.Start(ctx, tracing.NewSpanName("api", r.URL.Path)) + defer span.End() + r = r.WithContext(ctx) + + next.ServeHTTP(w, r) + }) +} diff --git a/apps/agent/pkg/api/register_routes.go b/apps/agent/pkg/api/register_routes.go new file mode 100644 index 0000000000..6654a6d667 --- /dev/null +++ b/apps/agent/pkg/api/register_routes.go @@ -0,0 +1,56 @@ +package api + +import ( + "github.com/unkeyed/unkey/apps/agent/pkg/api/routes" + notFound "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/not_found" + v1Liveness "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_liveness" + v1RatelimitCommitLease "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_ratelimit_commitLease" + v1RatelimitMultiRatelimit "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_ratelimit_multiRatelimit" + v1RatelimitRatelimit "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_ratelimit_ratelimit" + v1VaultDecrypt "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_vault_decrypt" + v1VaultEncrypt "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_vault_encrypt" + v1VaultEncryptBulk "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_vault_encrypt_bulk" +) + +func (s *Server) RegisterRoutes() { + svc := routes.Services{ + Logger: s.logger, + Metrics: s.metrics, + Vault: s.vault, + Ratelimit: s.ratelimit, + OpenApiValidator: s.validator, + Sender: routes.NewJsonSender(s.logger), + } + + s.logger.Info().Interface("svc", svc).Msg("Registering routes") + + staticBearerAuth := newBearerAuthMiddleware(s.authToken) + + v1Liveness.New(svc).Register(s.mux) + + v1RatelimitCommitLease.New(svc). + WithMiddleware(staticBearerAuth). + Register(s.mux) + + v1RatelimitMultiRatelimit.New(svc). + WithMiddleware(staticBearerAuth). + Register(s.mux) + + v1RatelimitRatelimit.New(svc). + WithMiddleware(staticBearerAuth). + Register(s.mux) + + v1VaultDecrypt.New(svc). + WithMiddleware(staticBearerAuth). + Register(s.mux) + + v1VaultEncrypt.New(svc). + WithMiddleware(staticBearerAuth). + Register(s.mux) + + v1VaultEncryptBulk.New(svc). + WithMiddleware(staticBearerAuth). + Register(s.mux) + + notFound.New(svc).Register(s.mux) +} diff --git a/apps/agent/pkg/api/routes/not_found/handler.go b/apps/agent/pkg/api/routes/not_found/handler.go new file mode 100644 index 0000000000..37945d5a1a --- /dev/null +++ b/apps/agent/pkg/api/routes/not_found/handler.go @@ -0,0 +1,26 @@ +package notFound + +import ( + "net/http" + + "github.com/unkeyed/unkey/apps/agent/gen/openapi" + "github.com/unkeyed/unkey/apps/agent/pkg/api/ctxutil" + "github.com/unkeyed/unkey/apps/agent/pkg/api/routes" +) + +// This is a hack, because / matches everything, so we need to make sure this is the last route +func New(svc routes.Services) *routes.Route { + return routes.NewRoute("", "/", + func(w http.ResponseWriter, r *http.Request) { + + svc.Sender.Send(r.Context(), w, 200, openapi.BaseError{ + Title: "Not Found", + Detail: "This route does not exist", + Instance: "https://errors.unkey.com/todo", + Status: http.StatusNotFound, + RequestId: ctxutil.GetRequestId(r.Context()), + Type: "TODO docs link", + }) + }, + ) +} diff --git a/apps/agent/pkg/api/routes/route.go b/apps/agent/pkg/api/routes/route.go new file mode 100644 index 0000000000..968f234364 --- /dev/null +++ b/apps/agent/pkg/api/routes/route.go @@ -0,0 +1,41 @@ +package routes + +import ( + "fmt" + "net/http" +) + +type Route struct { + method string + path string + handler http.HandlerFunc +} + +func NewRoute(method string, path string, handler http.HandlerFunc) *Route { + return &Route{ + method: method, + path: path, + handler: handler, + } +} + +type Middeware func(http.HandlerFunc) http.HandlerFunc + +func (r *Route) WithMiddleware(mws ...Middeware) *Route { + for _, mw := range mws { + r.handler = mw(r.handler) + } + return r +} + +func (r *Route) Register(mux *http.ServeMux) { + mux.HandleFunc(fmt.Sprintf("%s %s", r.method, r.path), r.handler) +} + +func (r *Route) Method() string { + return r.method +} + +func (r *Route) Path() string { + return r.path +} diff --git a/apps/agent/pkg/api/routes/sender.go b/apps/agent/pkg/api/routes/sender.go new file mode 100644 index 0000000000..8ab0c43fc1 --- /dev/null +++ b/apps/agent/pkg/api/routes/sender.go @@ -0,0 +1,62 @@ +package routes + +import ( + "context" + "encoding/json" + "net/http" + + "github.com/unkeyed/unkey/apps/agent/gen/openapi" + "github.com/unkeyed/unkey/apps/agent/pkg/api/ctxutil" + "github.com/unkeyed/unkey/apps/agent/pkg/logging" +) + +type Sender interface { + + // Send marshals the body and sends it as a response with the given status code. + // If marshalling fails, it will return a 500 response with the error message. + Send(ctx context.Context, w http.ResponseWriter, status int, body any) +} + +type JsonSender struct { + logger logging.Logger +} + +func NewJsonSender(logger logging.Logger) Sender { + return &JsonSender{logger: logger} +} + +// Send returns a JSON response with the given status code and body. +// If marshalling fails, it will return a 500 response with the error message. +func (r *JsonSender) Send(ctx context.Context, w http.ResponseWriter, status int, body any) { + if body == nil { + return + } + + b, err := json.Marshal(body) + if err != nil { + r.logger.Error().Err(err).Interface("body", body).Msg("failed to marshal response body") + w.WriteHeader(http.StatusInternalServerError) + + error := openapi.BaseError{ + Title: "Internal Server Error", + Detail: "failed to marshal response body", + Instance: "https://errors.unkey.com/todo", + Status: http.StatusInternalServerError, + RequestId: ctxutil.GetRequestId(ctx), + Type: "TODO docs link", + } + + b, err = json.Marshal(error) + if err != nil { + w.Write([]byte("failed to marshal response body")) + return + } + w.Write(b) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(status) + w.Write(b) + +} diff --git a/apps/agent/pkg/api/routes/services.go b/apps/agent/pkg/api/routes/services.go index 321d9eb6e0..0f8c85af5f 100644 --- a/apps/agent/pkg/api/routes/services.go +++ b/apps/agent/pkg/api/routes/services.go @@ -1,6 +1,7 @@ package routes import ( + "github.com/unkeyed/unkey/apps/agent/pkg/api/validation" "github.com/unkeyed/unkey/apps/agent/pkg/logging" "github.com/unkeyed/unkey/apps/agent/pkg/metrics" "github.com/unkeyed/unkey/apps/agent/services/ratelimit" @@ -8,8 +9,10 @@ import ( ) type Services struct { - Logger logging.Logger - Metrics metrics.Metrics - Vault *vault.Service - Ratelimit ratelimit.Service + Logger logging.Logger + Metrics metrics.Metrics + Vault *vault.Service + Ratelimit ratelimit.Service + OpenApiValidator validation.OpenAPIValidator + Sender Sender } diff --git a/apps/agent/pkg/api/routes/v1_liveness/handler.go b/apps/agent/pkg/api/routes/v1_liveness/handler.go index e64469acf2..82304a447b 100644 --- a/apps/agent/pkg/api/routes/v1_liveness/handler.go +++ b/apps/agent/pkg/api/routes/v1_liveness/handler.go @@ -1,36 +1,21 @@ -package handler +package v1Liveness import ( - "context" + "net/http" - "github.com/danielgtaylor/huma/v2" + "github.com/unkeyed/unkey/apps/agent/gen/openapi" "github.com/unkeyed/unkey/apps/agent/pkg/api/routes" ) -type v1LivenessRequest struct { - // Empty -} -type v1LivenessResponse struct { - Body struct { - Message string `json:"message" example:"OK" doc:"Whether we're alive or not"` - } -} - -func Register(api huma.API, svc routes.Services, middlewares ...func(ctx huma.Context, next func(huma.Context))) { - huma.Register(api, huma.Operation{ - Tags: []string{"liveness"}, - OperationID: "liveness", - Method: "GET", - Path: "/v1/liveness", - Summary: "Liveness check", - Description: "This endpoint checks if the service is alive.", - Errors: []int{500}, - }, func(ctx context.Context, req *v1LivenessRequest) (*v1LivenessResponse, error) { - res := &v1LivenessResponse{} - res.Body.Message = "OK" - svc.Logger.Info().Interface("response", res).Msg("incoming liveness check") - return res, nil +func New(svc routes.Services) *routes.Route { + return routes.NewRoute("GET", "/v1/liveness", + func(w http.ResponseWriter, r *http.Request) { - }) + svc.Logger.Debug().Msg("incoming liveness check") + svc.Sender.Send(r.Context(), w, 200, openapi.V1LivenessResponseBody{ + Message: "OK", + }) + }, + ) } diff --git a/apps/agent/pkg/api/routes/v1_liveness/handler_test.go b/apps/agent/pkg/api/routes/v1_liveness/handler_test.go index 9c2a30ed83..2ec47ff64d 100644 --- a/apps/agent/pkg/api/routes/v1_liveness/handler_test.go +++ b/apps/agent/pkg/api/routes/v1_liveness/handler_test.go @@ -1,21 +1,19 @@ -package handler_test +package v1Liveness_test import ( "testing" - "github.com/danielgtaylor/huma/v2/humatest" "github.com/stretchr/testify/require" - "github.com/unkeyed/unkey/apps/agent/pkg/api/routes" + "github.com/unkeyed/unkey/apps/agent/gen/openapi" v1Liveness "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_liveness" + "github.com/unkeyed/unkey/apps/agent/pkg/api/testutil" ) func TestLiveness(t *testing.T) { - _, api := humatest.New(t) - v1Liveness.Register(api, routes.Services{}) + h := testutil.NewHarness(t) + route := h.SetupRoute(v1Liveness.New) + res := testutil.CallRoute[any, openapi.V1LivenessResponseBody](t, route, nil, nil) - resp := api.Get("/v1/liveness") - - require.Equal(t, 200, resp.Code) - require.JSONEq(t, `{"message":"OK"}`, resp.Body.String()) + require.Equal(t, 200, res.Status) } diff --git a/apps/agent/pkg/api/routes/v1_ratelimit_commitLease/handler.go b/apps/agent/pkg/api/routes/v1_ratelimit_commitLease/handler.go index 0fffb94e9d..fdf3865e28 100644 --- a/apps/agent/pkg/api/routes/v1_ratelimit_commitLease/handler.go +++ b/apps/agent/pkg/api/routes/v1_ratelimit_commitLease/handler.go @@ -1,56 +1,48 @@ -package handler +package v1RatelimitCommitLease import ( - "context" + "net/http" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" "github.com/btcsuite/btcutil/base58" - "github.com/danielgtaylor/huma/v2" + "github.com/unkeyed/unkey/apps/agent/gen/openapi" ratelimitv1 "github.com/unkeyed/unkey/apps/agent/gen/proto/ratelimit/v1" + "github.com/unkeyed/unkey/apps/agent/pkg/api/errors" "github.com/unkeyed/unkey/apps/agent/pkg/api/routes" - "github.com/unkeyed/unkey/apps/agent/pkg/tracing" "google.golang.org/protobuf/proto" ) -type V1RatelimitCommitLeaseRequest struct { - Body struct { - Lease string `json:"lease" required:"true" doc:"The lease you received from the ratelimit response."` - Cost int64 `json:"cost" required:"true" doc:"The actual cost of the request."` - } `required:"true" contentType:"application/json"` -} - -type V1RatelimitCommitLeaseResponse struct { - // empty, we'll just ack this -} - -func Register(api huma.API, svc routes.Services, middlewares ...func(ctx huma.Context, next func(huma.Context))) { - huma.Register(api, huma.Operation{ - Tags: []string{"ratelimit"}, - OperationID: "v1.ratelimit.commitLease", - Method: "POST", - Path: "/v1/ratelimit.commitLease", - Middlewares: middlewares, - }, func(ctx context.Context, req *V1RatelimitCommitLeaseRequest) (*V1RatelimitCommitLeaseResponse, error) { - - ctx, span := tracing.Start(ctx, tracing.NewSpanName("ratelimit", "commitLease")) - defer span.End() - - b := base58.Decode(req.Body.Lease) - lease := &ratelimitv1.Lease{} - err := proto.Unmarshal(b, lease) - if err != nil { - return nil, huma.Error400BadRequest("invalid lease", err) - } - - _, err = svc.Ratelimit.CommitLease(ctx, &ratelimitv1.CommitLeaseRequest{ - Lease: lease, - Cost: req.Body.Cost, +func New(svc routes.Services) *routes.Route { + return routes.NewRoute("POST", "/ratelimit.v1.RatelimitService/CommitLease", + func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + req := &openapi.V1RatelimitCommitLeaseRequestBody{} + errorResponse, valid := svc.OpenApiValidator.Body(r, req) + if !valid { + svc.Sender.Send(ctx, w, 400, errorResponse) + return + } + + b := base58.Decode(req.Lease) + lease := &ratelimitv1.Lease{} + err := proto.Unmarshal(b, lease) + if err != nil { + errors.HandleValidationError(ctx, fault.Wrap(err, fmsg.WithDesc("invalid_lease", "The lease is not valid."))) + return + } + + _, err = svc.Ratelimit.CommitLease(ctx, &ratelimitv1.CommitLeaseRequest{ + Lease: lease, + Cost: req.Cost, + }) + if err != nil { + errors.HandleError(ctx, fault.Wrap(err, fmsg.With("failed to commit lease"))) + return + + } + + svc.Sender.Send(ctx, w, 204, nil) }) - if err != nil { - return nil, huma.Error500InternalServerError("unable to ratelimit", err) - } - - response := V1RatelimitCommitLeaseResponse{} - - return &response, nil - }) } diff --git a/apps/agent/pkg/api/routes/v1_ratelimit_commitLease/handler_test.go b/apps/agent/pkg/api/routes/v1_ratelimit_commitLease/handler_test.go index 896338b9e3..0c022170c6 100644 --- a/apps/agent/pkg/api/routes/v1_ratelimit_commitLease/handler_test.go +++ b/apps/agent/pkg/api/routes/v1_ratelimit_commitLease/handler_test.go @@ -1,10 +1,11 @@ -package handler_test +package v1RatelimitCommitLease_test import ( "testing" "time" "github.com/stretchr/testify/require" + "github.com/unkeyed/unkey/apps/agent/gen/openapi" v1RatelimitCommitLease "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_ratelimit_commitLease" v1RatelimitRatelimit "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_ratelimit_ratelimit" "github.com/unkeyed/unkey/apps/agent/pkg/api/testutil" @@ -15,39 +16,38 @@ import ( func TestCommitLease(t *testing.T) { t.Skip() h := testutil.NewHarness(t) - - h.Register(v1RatelimitRatelimit.Register) - h.Register(v1RatelimitCommitLease.Register) - - ratelimitReq := v1RatelimitRatelimit.V1RatelimitRatelimitRequest{} - ratelimitReq.Body.Identifier = uid.New("test") - ratelimitReq.Body.Limit = 100 - ratelimitReq.Body.Duration = time.Minute.Milliseconds() - ratelimitReq.Body.Cost = util.Pointer[int64](0) - ratelimitReq.Body.Lease = &v1RatelimitRatelimit.Lease{ - Cost: 10, - Timeout: 10 * time.Second.Milliseconds(), + ratelimitRoute := h.SetupRoute(v1RatelimitRatelimit.New) + commitLeaseRoute := h.SetupRoute(v1RatelimitCommitLease.New) + + req := openapi.V1RatelimitRatelimitRequestBody{ + + Identifier: uid.New("test"), + Limit: 100, + Duration: time.Minute.Milliseconds(), + Cost: util.Pointer[int64](0), + Lease: &openapi.Lease{ + Cost: 10, + Timeout: 10 * time.Second.Milliseconds(), + }, } - res := h.Api().Post("/ratelimit.v1.RatelimitService/Ratelimit", ratelimitReq.Body) + res := testutil.CallRoute[openapi.V1RatelimitRatelimitRequestBody, openapi.V1RatelimitRatelimitResponseBody](t, ratelimitRoute, nil, req) - responseBody := v1RatelimitRatelimit.V1RatelimitRatelimitResponse{} - testutil.UnmarshalBody(t, res, &responseBody.Body) + require.Equal(t, 200, res.Status) + require.Equal(t, int64(100), res.Body.Limit) + require.Equal(t, int64(90), res.Body.Remaining) + require.Equal(t, true, res.Body.Success) + require.Equal(t, int64(10), res.Body.Current) + require.NotNil(t, res.Body.Lease) - t.Logf("responseBody: %+v", responseBody) - require.Equal(t, 200, res.Code) - require.Equal(t, int64(100), responseBody.Body.Limit) - require.Equal(t, int64(90), responseBody.Body.Remaining) - require.Equal(t, true, responseBody.Body.Success) - require.Equal(t, int64(10), responseBody.Body.Current) - require.NotNil(t, responseBody.Body.Lease) + commitReq := openapi.V1RatelimitCommitLeaseRequestBody{ - commitReq := v1RatelimitCommitLease.V1RatelimitCommitLeaseRequest{} - commitReq.Body.Cost = 5 - commitReq.Body.Lease = *responseBody.Body.Lease + Cost: 5, + Lease: res.Body.Lease, + } - commitRes := h.Api().Post("/v1/ratelimit.commitLease", commitReq.Body) + commitRes := testutil.CallRoute[openapi.V1RatelimitCommitLeaseRequestBody, any](t, commitLeaseRoute, nil, commitReq) - require.Equal(t, 204, commitRes.Code) + require.Equal(t, 204, commitRes.Status) } diff --git a/apps/agent/pkg/api/routes/v1_ratelimit_multiRatelimit/handler.go b/apps/agent/pkg/api/routes/v1_ratelimit_multiRatelimit/handler.go index 3d511cbb53..066a07a468 100644 --- a/apps/agent/pkg/api/routes/v1_ratelimit_multiRatelimit/handler.go +++ b/apps/agent/pkg/api/routes/v1_ratelimit_multiRatelimit/handler.go @@ -1,78 +1,47 @@ package v1RatelimitMultiRatelimit import ( - "context" + "net/http" - "github.com/danielgtaylor/huma/v2" + "github.com/unkeyed/unkey/apps/agent/gen/openapi" ratelimitv1 "github.com/unkeyed/unkey/apps/agent/gen/proto/ratelimit/v1" + "github.com/unkeyed/unkey/apps/agent/pkg/api/errors" "github.com/unkeyed/unkey/apps/agent/pkg/api/routes" - "github.com/unkeyed/unkey/apps/agent/pkg/tracing" ) -type v1RatelimitMultiRatelimitRequest struct { - Body struct { - Ratelimits []struct { - Identifier string `json:"identifier" required:"true" doc:"The identifier for the rate limit."` - Limit int64 `json:"limit" required:"true" doc:"The maximum number of requests allowed."` - Duration int64 `json:"duration" required:"true" doc:"The duration in milliseconds for the rate limit window."` - Cost int64 `json:"cost" required:"false" default:"1" doc:"The cost of the request."` - } `json:"ratelimits" required:"true" doc:"The rate limits to check."` - } -} - -// singleRatelimitResponse is the response for a single ratelimit request. -// This struct is used for the response body of the ratelimit endpoint and the multiRatelimit endpoint. -type singleRatelimitResponse struct { - Limit int64 `json:"limit" doc:"The maximum number of requests allowed."` - Remaining int64 `json:"remaining" doc:"The number of requests remaining in the current window."` - Reset int64 `json:"reset" doc:"The time in milliseconds when the rate limit will reset."` - Success bool `json:"success" doc:"Whether the request passed the ratelimit. If false, the request must be blocked."` - Current int64 `json:"current" doc:"The current number of requests made in the current window."` -} -type v1RatelimitRatelimitResponse struct { - Body singleRatelimitResponse -} - -type v1RatelimitMultiRatelimitResponse struct { - Body struct { - Ratelimits []singleRatelimitResponse `json:"ratelimits" doc:"The rate limits that were checked."` - } -} - -func Register(api huma.API, svc routes.Services, middlewares ...func(ctx huma.Context, next func(huma.Context))) { - huma.Register(api, huma.Operation{ - Tags: []string{"ratelimit"}, - OperationID: "ratelimit.v1.multiRatelimit", - Method: "POST", - Path: "/ratelimit.v1.RatelimitService/MultiRatelimit", - Middlewares: middlewares, - }, func(ctx context.Context, req *v1RatelimitMultiRatelimitRequest) (*v1RatelimitMultiRatelimitResponse, error) { - - ctx, span := tracing.Start(ctx, tracing.NewSpanName("ratelimit", "Ratelimit")) - defer span.End() - - // Default cost is 1 if not provided - - ratelimits := make([]*ratelimitv1.RatelimitRequest, len(req.Body.Ratelimits)) - for i, r := range req.Body.Ratelimits { +func New(svc routes.Services) *routes.Route { + return routes.NewRoute("POST", "/ratelimit.v1.RatelimitService/MultiRatelimit", func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + req := &openapi.V1RatelimitMultiRatelimitRequestBody{} + res := &openapi.V1RatelimitMultiRatelimitResponseBody{} + errorResponse, valid := svc.OpenApiValidator.Body(r, req) + if !valid { + svc.Sender.Send(ctx, w, 400, errorResponse) + return + } + ratelimits := make([]*ratelimitv1.RatelimitRequest, len(req.Ratelimits)) + for i, r := range req.Ratelimits { + cost := int64(1) + if r.Cost != nil { + cost = *r.Cost + } ratelimits[i] = &ratelimitv1.RatelimitRequest{ Identifier: r.Identifier, Limit: r.Limit, Duration: r.Duration, - Cost: r.Cost, + Cost: cost, } } - - res, err := svc.Ratelimit.MultiRatelimit(ctx, &ratelimitv1.RatelimitMultiRequest{Ratelimits: ratelimits}) + svcRes, err := svc.Ratelimit.MultiRatelimit(ctx, &ratelimitv1.RatelimitMultiRequest{}) if err != nil { - return nil, huma.Error500InternalServerError("unable to ratelimit", err) - } + errors.HandleError(ctx, err) + return - response := v1RatelimitMultiRatelimitResponse{} - response.Body.Ratelimits = make([]singleRatelimitResponse, len(res.Ratelimits)) - for i, r := range res.Ratelimits { - response.Body.Ratelimits[i] = singleRatelimitResponse{ + } + res.Ratelimits = make([]openapi.SingleRatelimitResponse, len(res.Ratelimits)) + for i, r := range svcRes.Ratelimits { + res.Ratelimits[i] = openapi.SingleRatelimitResponse{ Current: r.Current, Limit: r.Limit, Remaining: r.Remaining, @@ -81,6 +50,6 @@ func Register(api huma.API, svc routes.Services, middlewares ...func(ctx huma.Co } } - return &response, nil + svc.Sender.Send(ctx, w, 200, res) }) } diff --git a/apps/agent/pkg/api/routes/v1_ratelimit_ratelimit/handler.go b/apps/agent/pkg/api/routes/v1_ratelimit_ratelimit/handler.go index 304c7ee126..eb3fa105e8 100644 --- a/apps/agent/pkg/api/routes/v1_ratelimit_ratelimit/handler.go +++ b/apps/agent/pkg/api/routes/v1_ratelimit_ratelimit/handler.go @@ -1,103 +1,69 @@ -package handler +package v1RatelimitRatelimit import ( - "context" + "net/http" "github.com/btcsuite/btcutil/base58" - "github.com/danielgtaylor/huma/v2" + "github.com/unkeyed/unkey/apps/agent/gen/openapi" ratelimitv1 "github.com/unkeyed/unkey/apps/agent/gen/proto/ratelimit/v1" + "github.com/unkeyed/unkey/apps/agent/pkg/api/errors" "github.com/unkeyed/unkey/apps/agent/pkg/api/routes" - "github.com/unkeyed/unkey/apps/agent/pkg/tracing" "github.com/unkeyed/unkey/apps/agent/pkg/util" "google.golang.org/protobuf/proto" ) -type Lease struct { - Cost int64 `json:"cost" required:"true" doc:"How much to lease."` - Timeout int64 `json:"timeout" required:"true" doc:"The time in milliseconds when the lease will expire. If you do not commit the lease by this time, it will be commited as is."` -} - -type V1RatelimitRatelimitRequest struct { - Body struct { - Identifier string `json:"identifier" required:"true" doc:"The identifier for the rate limit."` - Limit int64 `json:"limit" required:"true" doc:"The maximum number of requests allowed."` - Duration int64 `json:"duration" required:"true" doc:"The duration in milliseconds for the rate limit window."` - Cost *int64 `json:"cost" required:"false" doc:"The cost of the request. Defaults to 1 if not provided."` - Lease *Lease `json:"lease" required:"false" doc:"Reserve an amount of tokens with the option to commit and update later."` - } `required:"true" contentType:"application/json"` -} +func New(svc routes.Services) *routes.Route { + return routes.NewRoute("POST", "/ratelimit.v1.RatelimitService/Ratelimit", func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() -func (req *V1RatelimitRatelimitRequest) Resolve(ctx huma.Context) []error { - // Set the default cost if not provided and no lease is provided - if req.Body.Cost == nil { - if req.Body.Lease != nil { - req.Body.Cost = util.Pointer[int64](0) - } else { - req.Body.Cost = util.Pointer[int64](1) + req := &openapi.V1RatelimitRatelimitRequestBody{} + errorResponse, valid := svc.OpenApiValidator.Body(r, req) + if !valid { + svc.Sender.Send(ctx, w, 400, errorResponse) + return } - } - return nil -} - -var _ huma.Resolver = (*V1RatelimitRatelimitRequest)(nil) -type V1RatelimitRatelimitResponse struct { - Body struct { - Limit int64 `json:"limit" doc:"The maximum number of requests allowed."` - Remaining int64 `json:"remaining" doc:"The number of requests remaining in the current window."` - Reset int64 `json:"reset" doc:"The time in milliseconds when the rate limit will reset."` - Success bool `json:"success" doc:"Whether the request passed the ratelimit. If false, the request must be blocked."` - Current int64 `json:"current" doc:"The current number of requests made in the current window."` - Lease *string `json:"lease" doc:"The lease to use when committing the request."` - } -} - -func Register(api huma.API, svc routes.Services, middlewares ...func(ctx huma.Context, next func(huma.Context))) { - huma.Register(api, huma.Operation{ - Tags: []string{"ratelimit"}, - OperationID: "ratelimit.v1.ratelimit", - Method: "POST", - Path: "/ratelimit.v1.RatelimitService/Ratelimit", - Middlewares: middlewares, - }, func(ctx context.Context, req *V1RatelimitRatelimitRequest) (*V1RatelimitRatelimitResponse, error) { - - ctx, span := tracing.Start(ctx, tracing.NewSpanName("ratelimit", "Ratelimit")) - defer span.End() + if req.Cost == nil { + req.Cost = util.Pointer[int64](1) + } var lease *ratelimitv1.LeaseRequest = nil - if req.Body.Lease != nil { + if req.Lease != nil { lease = &ratelimitv1.LeaseRequest{ - Cost: req.Body.Lease.Cost, - Timeout: req.Body.Lease.Timeout, + Cost: req.Lease.Cost, + Timeout: req.Lease.Timeout, } } res, err := svc.Ratelimit.Ratelimit(ctx, &ratelimitv1.RatelimitRequest{ - Identifier: req.Body.Identifier, - Limit: req.Body.Limit, - Duration: req.Body.Duration, - Cost: *req.Body.Cost, + Identifier: req.Identifier, + Limit: req.Limit, + Duration: req.Duration, + Cost: *req.Cost, Lease: lease, }) if err != nil { - return nil, huma.Error500InternalServerError("unable to ratelimit", err) + errors.HandleError(ctx, err) + return } - response := V1RatelimitRatelimitResponse{} - response.Body.Limit = res.Limit - response.Body.Remaining = res.Remaining - response.Body.Reset = res.Reset_ - response.Body.Success = res.Success - response.Body.Current = res.Current + response := openapi.V1RatelimitRatelimitResponseBody{ + Limit: res.Limit, + Remaining: res.Remaining, + Reset: res.Reset_, + Success: res.Success, + Current: res.Current, + } if res.Lease != nil { b, err := proto.Marshal(res.Lease) if err != nil { - return nil, huma.Error500InternalServerError("unable to marshal lease", err) + errors.HandleError(ctx, err) + return } - response.Body.Lease = util.Pointer(base58.Encode(b)) + response.Lease = base58.Encode(b) } - return &response, nil + svc.Sender.Send(ctx, w, 200, response) }) } diff --git a/apps/agent/pkg/api/routes/v1_ratelimit_ratelimit/handler_test.go b/apps/agent/pkg/api/routes/v1_ratelimit_ratelimit/handler_test.go index d88510f97f..56f07682ce 100644 --- a/apps/agent/pkg/api/routes/v1_ratelimit_ratelimit/handler_test.go +++ b/apps/agent/pkg/api/routes/v1_ratelimit_ratelimit/handler_test.go @@ -1,11 +1,11 @@ -package handler_test +package v1RatelimitRatelimit_test import ( - "encoding/json" "testing" "time" "github.com/stretchr/testify/require" + "github.com/unkeyed/unkey/apps/agent/gen/openapi" v1RatelimitRatelimit "github.com/unkeyed/unkey/apps/agent/pkg/api/routes/v1_ratelimit_ratelimit" "github.com/unkeyed/unkey/apps/agent/pkg/api/testutil" "github.com/unkeyed/unkey/apps/agent/pkg/uid" @@ -13,51 +13,44 @@ import ( func TestRatelimit(t *testing.T) { h := testutil.NewHarness(t) - h.Register(v1RatelimitRatelimit.Register) + route := h.SetupRoute(v1RatelimitRatelimit.New) - req := v1RatelimitRatelimit.V1RatelimitRatelimitRequest{} - req.Body.Identifier = uid.New("test") - req.Body.Limit = 10 - req.Body.Duration = 1000 - - resp := h.Api().Post("/ratelimit.v1.RatelimitService/Ratelimit", req.Body) + req := openapi.V1RatelimitRatelimitRequestBody{ + Identifier: uid.New("test"), + Limit: 10, + Duration: 1000, + } - respBody := v1RatelimitRatelimit.V1RatelimitRatelimitResponse{} - err := json.Unmarshal(resp.Body.Bytes(), &respBody.Body) - require.NoError(t, err) + resp := testutil.CallRoute[openapi.V1RatelimitRatelimitRequestBody, openapi.V1RatelimitRatelimitResponseBody](t, route, nil, req) - require.Equal(t, 200, resp.Code) - require.Equal(t, int64(10), respBody.Body.Limit) - require.Equal(t, int64(9), respBody.Body.Remaining) - require.Equal(t, true, respBody.Body.Success) - require.Equal(t, int64(1), respBody.Body.Current) + require.Equal(t, 200, resp.Status) + require.Equal(t, int64(10), resp.Body.Limit) + require.Equal(t, int64(9), resp.Body.Remaining) + require.Equal(t, true, resp.Body.Success) + require.Equal(t, int64(1), resp.Body.Current) } func TestRatelimitWithLease(t *testing.T) { t.Skip() h := testutil.NewHarness(t) + route := h.SetupRoute(v1RatelimitRatelimit.New) - h.Register(v1RatelimitRatelimit.Register) + req := openapi.V1RatelimitRatelimitRequestBody{ - req := v1RatelimitRatelimit.V1RatelimitRatelimitRequest{} - req.Body.Identifier = uid.New("test") - req.Body.Limit = 100 - req.Body.Duration = time.Minute.Milliseconds() - req.Body.Lease = &v1RatelimitRatelimit.Lease{ - Cost: 10, - Timeout: 10 * time.Second.Milliseconds(), + Identifier: uid.New("test"), + Limit: 100, + Duration: time.Minute.Milliseconds(), + Lease: &openapi.Lease{ + Cost: 10, + Timeout: 10 * time.Second.Milliseconds(), + }, } - - resp := h.Api().Post("/ratelimit.v1.RatelimitService/Ratelimit", req.Body) - - respBody := v1RatelimitRatelimit.V1RatelimitRatelimitResponse{} - err := json.Unmarshal(resp.Body.Bytes(), &respBody.Body) - require.NoError(t, err) - - require.Equal(t, 200, resp.Code) - require.Equal(t, int64(100), respBody.Body.Limit) - require.Equal(t, int64(90), respBody.Body.Remaining) - require.Equal(t, true, respBody.Body.Success) - require.Equal(t, int64(10), respBody.Body.Current) - require.NotNil(t, respBody.Body.Lease) + resp := testutil.CallRoute[openapi.V1RatelimitRatelimitRequestBody, openapi.V1RatelimitRatelimitResponseBody](t, route, nil, req) + + require.Equal(t, 200, resp.Status) + require.Equal(t, int64(100), resp.Body.Limit) + require.Equal(t, int64(90), resp.Body.Remaining) + require.Equal(t, true, resp.Body.Success) + require.Equal(t, int64(10), resp.Body.Current) + require.NotNil(t, resp.Body.Lease) } diff --git a/apps/agent/pkg/api/routes/v1_vault_decrypt/handler.go b/apps/agent/pkg/api/routes/v1_vault_decrypt/handler.go index fb17a2091f..b4f34b2b10 100644 --- a/apps/agent/pkg/api/routes/v1_vault_decrypt/handler.go +++ b/apps/agent/pkg/api/routes/v1_vault_decrypt/handler.go @@ -1,50 +1,35 @@ -package handler +package v1VaultDecrypt import ( - "context" + "net/http" - "github.com/danielgtaylor/huma/v2" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" + "github.com/unkeyed/unkey/apps/agent/gen/openapi" vaultv1 "github.com/unkeyed/unkey/apps/agent/gen/proto/vault/v1" + "github.com/unkeyed/unkey/apps/agent/pkg/api/errors" "github.com/unkeyed/unkey/apps/agent/pkg/api/routes" - "github.com/unkeyed/unkey/apps/agent/pkg/tracing" ) -type v1DecryptRequest struct { - Body struct { - Keyring string `json:"keyring" required:"true" doc:"The keyring to use for encryption."` - Encrypted string `json:"encrypted" required:"true" minLength:"1" doc:"The encrypted base64 string."` - } -} - -type v1DecryptResponse struct { - Body struct { - Plaintext string `json:"plaintext" required:"true" doc:"The plaintext value."` - } -} - -func Register(api huma.API, svc routes.Services, middlewares ...func(ctx huma.Context, next func(huma.Context))) { - huma.Register(api, huma.Operation{ - Tags: []string{"vault"}, - OperationID: "vault.v1.decrypt", - Method: "POST", - Path: "/vault.v1.VaultService/Decrypt", - Middlewares: middlewares, - }, func(ctx context.Context, req *v1DecryptRequest) (*v1DecryptResponse, error) { - - ctx, span := tracing.Start(ctx, tracing.NewSpanName("vault", "Decrypt")) - defer span.End() - +func New(svc routes.Services) *routes.Route { + return routes.NewRoute("POST", "/vault.v1.VaultService/Decrypt", func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + req := &openapi.V1DecryptRequestBody{} + errorResponse, valid := svc.OpenApiValidator.Body(r, req) + if !valid { + svc.Sender.Send(ctx, w, 400, errorResponse) + return + } res, err := svc.Vault.Decrypt(ctx, &vaultv1.DecryptRequest{ - Keyring: req.Body.Keyring, - Encrypted: req.Body.Encrypted, + Keyring: req.Keyring, + Encrypted: req.Encrypted, }) if err != nil { - return nil, huma.Error500InternalServerError("unable to decrypt", err) + errors.HandleError(ctx, fault.Wrap(err, fmsg.With("failed to decrypt"))) } - response := v1DecryptResponse{} - response.Body.Plaintext = res.Plaintext - - return &response, nil + svc.Sender.Send(ctx, w, 200, openapi.V1DecryptResponseBody{ + Plaintext: res.Plaintext, + }) }) } diff --git a/apps/agent/pkg/api/routes/v1_vault_encrypt/handler.go b/apps/agent/pkg/api/routes/v1_vault_encrypt/handler.go index cfd46d91b7..694a9b64bf 100644 --- a/apps/agent/pkg/api/routes/v1_vault_encrypt/handler.go +++ b/apps/agent/pkg/api/routes/v1_vault_encrypt/handler.go @@ -1,52 +1,36 @@ -package handler +package v1VaultEncrypt import ( - "context" + "net/http" - "github.com/danielgtaylor/huma/v2" + "github.com/unkeyed/unkey/apps/agent/gen/openapi" vaultv1 "github.com/unkeyed/unkey/apps/agent/gen/proto/vault/v1" + "github.com/unkeyed/unkey/apps/agent/pkg/api/errors" "github.com/unkeyed/unkey/apps/agent/pkg/api/routes" - "github.com/unkeyed/unkey/apps/agent/pkg/tracing" ) -type v1EncryptRequest struct { - Body struct { - Keyring string `json:"keyring" required:"true" doc:"The keyring to use for encryption."` - Data string `json:"data" required:"true" minLength:"1" doc:"The data to encrypt."` - } -} - -type v1EncryptResponse struct { - Body struct { - Encrypted string `json:"encrypted" required:"true" doc:"The encrypted data as base64 encoded string."` - KeyID string `json:"keyId" required:"true" doc:"The ID of the key used for encryption."` - } -} - -func Register(api huma.API, svc routes.Services, middlewares ...func(ctx huma.Context, next func(huma.Context))) { - huma.Register(api, huma.Operation{ - Tags: []string{"vault"}, - OperationID: "vault.v1.encrypt", - Method: "POST", - Path: "/vault.v1.VaultService/Encrypt", - Middlewares: middlewares, - }, func(ctx context.Context, req *v1EncryptRequest) (*v1EncryptResponse, error) { - - ctx, span := tracing.Start(ctx, tracing.NewSpanName("vault", "Encrypt")) - defer span.End() - - res, err := svc.Vault.Encrypt(ctx, &vaultv1.EncryptRequest{ - Keyring: req.Body.Keyring, - Data: req.Body.Data, +func New(svc routes.Services) *routes.Route { + return routes.NewRoute("POST", "/vault.v1.VaultService/Encrypt", + func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + req := &openapi.V1EncryptRequestBody{} + errorResponse, valid := svc.OpenApiValidator.Body(r, req) + if !valid { + svc.Sender.Send(ctx, w, 400, errorResponse) + return + } + res, err := svc.Vault.Encrypt(ctx, &vaultv1.EncryptRequest{ + Keyring: req.Keyring, + Data: req.Data, + }) + if err != nil { + errors.HandleError(ctx, err) + return + } + + svc.Sender.Send(ctx, w, 200, openapi.V1EncryptResponseBody{ + Encrypted: res.Encrypted, + KeyId: res.KeyId, + }) }) - if err != nil { - return nil, huma.Error500InternalServerError("unable to encrypt", err) - } - - response := v1EncryptResponse{} - response.Body.Encrypted = res.Encrypted - response.Body.KeyID = res.KeyId - - return &response, nil - }) } diff --git a/apps/agent/pkg/api/routes/v1_vault_encrypt_bulk/handler.go b/apps/agent/pkg/api/routes/v1_vault_encrypt_bulk/handler.go index 8d81d127c3..1159d10ebe 100644 --- a/apps/agent/pkg/api/routes/v1_vault_encrypt_bulk/handler.go +++ b/apps/agent/pkg/api/routes/v1_vault_encrypt_bulk/handler.go @@ -1,62 +1,45 @@ package v1VaultEncryptBulk import ( - "context" + "net/http" - "github.com/danielgtaylor/huma/v2" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" + "github.com/unkeyed/unkey/apps/agent/gen/openapi" vaultv1 "github.com/unkeyed/unkey/apps/agent/gen/proto/vault/v1" + "github.com/unkeyed/unkey/apps/agent/pkg/api/errors" "github.com/unkeyed/unkey/apps/agent/pkg/api/routes" - "github.com/unkeyed/unkey/apps/agent/pkg/tracing" ) -type v1EncryptBulkRequest struct { - Body struct { - Keyring string `json:"keyring" required:"true"` - Data []string `json:"data" required:"true" minItems:"1" maxItems:"1000"` - } -} - -type encrypted struct { - Encrypted string `json:"encrypted" required:"true"` - KeyID string `json:"keyId" required:"true"` -} - -type v1EncryptBulkResponse struct { - Body struct { - Encrypted []encrypted `json:"encrypted"` - } -} - -func Register(api huma.API, svc routes.Services, middlewares ...func(ctx huma.Context, next func(huma.Context))) { - huma.Register(api, huma.Operation{ - Tags: []string{"vault"}, - OperationID: "vault.v1.encryptBulk", - Method: "POST", - Path: "/vault.v1.VaultService/EncryptBulk", - Middlewares: middlewares, - }, func(ctx context.Context, req *v1EncryptBulkRequest) (*v1EncryptBulkResponse, error) { - - ctx, span := tracing.Start(ctx, tracing.NewSpanName("vault", "EncryptBulk")) - defer span.End() - +type Request = openapi.V1EncryptBulkRequestBody +type Response = openapi.V1EncryptBulkResponseBody + +func New(svc routes.Services) *routes.Route { + return routes.NewRoute("POST", "/vault.v1.VaultService/EncryptBulk", func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + req := Request{} + errorResponse, valid := svc.OpenApiValidator.Body(r, &req) + if !valid { + svc.Sender.Send(ctx, w, 400, errorResponse) + return + } res, err := svc.Vault.EncryptBulk(ctx, &vaultv1.EncryptBulkRequest{ - Keyring: req.Body.Keyring, - Data: req.Body.Data, + Keyring: req.Keyring, + Data: req.Data, }) if err != nil { - return nil, huma.Error500InternalServerError("unable to encrypt", err) + errors.HandleError(ctx, fault.Wrap(err, fmsg.With("failed to encrypt"))) + return } - response := v1EncryptBulkResponse{} - - response.Body.Encrypted = make([]encrypted, len(res.Encrypted)) + encrypted := make([]openapi.Encrypted, len(res.Encrypted)) for i, e := range res.Encrypted { - response.Body.Encrypted[i] = encrypted{ + encrypted[i] = openapi.Encrypted{ Encrypted: e.Encrypted, - KeyID: e.KeyId, + KeyId: e.KeyId, } } - return &response, nil + svc.Sender.Send(ctx, w, 200, Response{Encrypted: encrypted}) }) } diff --git a/apps/agent/pkg/api/server.go b/apps/agent/pkg/api/server.go index b717a7fbc0..3f3d016a75 100644 --- a/apps/agent/pkg/api/server.go +++ b/apps/agent/pkg/api/server.go @@ -1,19 +1,13 @@ package api import ( - "context" - "fmt" "net/http" "sync" "time" - "github.com/danielgtaylor/huma/v2" - "github.com/danielgtaylor/huma/v2/adapters/humago" - "github.com/unkeyed/unkey/apps/agent/pkg/api/routes" + "github.com/unkeyed/unkey/apps/agent/pkg/api/validation" "github.com/unkeyed/unkey/apps/agent/pkg/logging" "github.com/unkeyed/unkey/apps/agent/pkg/metrics" - "github.com/unkeyed/unkey/apps/agent/pkg/prometheus" - "github.com/unkeyed/unkey/apps/agent/pkg/tracing" "github.com/unkeyed/unkey/apps/agent/services/eventrouter" "github.com/unkeyed/unkey/apps/agent/services/ratelimit" "github.com/unkeyed/unkey/apps/agent/services/vault" @@ -24,82 +18,89 @@ type Server struct { logger logging.Logger metrics metrics.Metrics isListening bool - api huma.API mux *http.ServeMux srv *http.Server // The bearer token required for inter service communication authToken string - Vault *vault.Service - Ratelimit ratelimit.Service + vault *vault.Service + ratelimit ratelimit.Service + + clickhouse EventBuffer + validator validation.OpenAPIValidator } type Config struct { - NodeId string - Logger logging.Logger - Metrics metrics.Metrics + NodeId string + Logger logging.Logger + Metrics metrics.Metrics + Ratelimit ratelimit.Service + Clickhouse EventBuffer + Vault *vault.Service + AuthToken string } -func New(config Config) *Server { - mux := http.NewServeMux() +func New(config Config) (*Server, error) { - humaConfig := huma.DefaultConfig("Unkey API", "1.0.0") - humaConfig.Servers = []*huma.Server{ - {URL: "https://api.unkey.dev"}, + mux := http.NewServeMux() + srv := &http.Server{ + Handler: mux, + // See https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/ + // + // > # http.ListenAndServe is doing it wrong + // > Incidentally, this means that the package-level convenience functions that bypass http.Server + // > like http.ListenAndServe, http.ListenAndServeTLS and http.Serve are unfit for public Internet + // > Servers. + // > + // > Those functions leave the Timeouts to their default off value, with no way of enabling them, + // > so if you use them you'll soon be leaking connections and run out of file descriptors. I've + // > made this mistake at least half a dozen times. + // > + // > Instead, create a http.Server instance with ReadTimeout and WriteTimeout and use its + // > corresponding methods, like in the example a few paragraphs above. + ReadTimeout: 10 * time.Second, + WriteTimeout: 20 * time.Second, } s := &Server{ logger: config.Logger, metrics: config.Metrics, + ratelimit: config.Ratelimit, + vault: config.Vault, isListening: false, - api: humago.New(mux, humaConfig), mux: mux, + srv: srv, + clickhouse: config.Clickhouse, + authToken: config.AuthToken, } + // validationMiddleware, err := s.createOpenApiValidationMiddleware("./pkg/openapi/openapi.json") + // if err != nil { + // return nil, fault.Wrap(err, fmsg.With("openapi spec encountered an error")) + // } + // s.app.Use( + // createLoggerMiddleware(s.logger), + // createMetricsMiddleware(), + // // validationMiddleware, + // ) + // s.app.Use(tracingMiddleware) + v, err := validation.New("./pkg/openapi/openapi.json") + if err != nil { + return nil, err + } + s.validator = v - s.api.UseMiddleware(func(hCtx huma.Context, next func(huma.Context)) { - start := time.Now() - - ctx, span := tracing.Start(hCtx.Context(), "api.request") - defer span.End() - - hCtx.AppendHeader("x-node-id", config.NodeId) - - next(huma.WithContext(hCtx, ctx)) - serviceLatency := time.Since(start) - prometheus.HTTPRequests.With(map[string]string{ - "method": hCtx.Method(), - "path": hCtx.URL().Path, - "status": fmt.Sprintf("%d", hCtx.Status()), - }).Inc() - - prometheus.ServiceLatency.WithLabelValues(hCtx.URL().Path).Observe(serviceLatency.Seconds()) - - }) - - return s -} - -func (s *Server) HumaAPI() huma.API { - return s.api -} + s.srv.Handler = withMetrics(withTracing(withRequestId(s.mux))) -func (s *Server) Services() routes.Services { - return routes.Services{ - Logger: s.logger, - Metrics: s.metrics, - Vault: s.Vault, - Ratelimit: s.Ratelimit, - } + return s, nil } func (s *Server) WithEventRouter(svc *eventrouter.Service) { s.Lock() defer s.Unlock() - route, handler := svc.CreateHandler() - - s.mux.Handle(route, handler) + pattern, handlerFunc := svc.CreateHandler() + s.mux.HandleFunc(pattern, handlerFunc) } // Calling this function multiple times will have no effect. @@ -112,34 +113,17 @@ func (s *Server) Listen(addr string) error { } s.isListening = true s.Unlock() - s.srv = &http.Server{Addr: addr, Handler: s.mux} - - // See https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/ - // - // > # http.ListenAndServe is doing it wrong - // > Incidentally, this means that the package-level convenience functions that bypass http.Server - // > like http.ListenAndServe, http.ListenAndServeTLS and http.Serve are unfit for public Internet - // > Servers. - // > - // > Those functions leave the Timeouts to their default off value, with no way of enabling them, - // > so if you use them you'll soon be leaking connections and run out of file descriptors. I've - // > made this mistake at least half a dozen times. - // > - // > Instead, create a http.Server instance with ReadTimeout and WriteTimeout and use its - // > corresponding methods, like in the example a few paragraphs above. - s.srv.ReadTimeout = 10 * time.Second - s.srv.WriteTimeout = 20 * time.Second + s.RegisterRoutes() + + s.srv.Addr = addr s.logger.Info().Str("addr", addr).Msg("listening") return s.srv.ListenAndServe() - } func (s *Server) Shutdown() error { s.Lock() defer s.Unlock() - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - return s.srv.Shutdown(ctx) + return s.srv.Close() } diff --git a/apps/agent/pkg/api/testutil/harness.go b/apps/agent/pkg/api/testutil/harness.go index 1b2ef3e907..be97e61792 100644 --- a/apps/agent/pkg/api/testutil/harness.go +++ b/apps/agent/pkg/api/testutil/harness.go @@ -1,13 +1,13 @@ package testutil import ( + "bytes" "encoding/json" "fmt" + "net/http" "net/http/httptest" "testing" - "github.com/danielgtaylor/huma/v2" - "github.com/danielgtaylor/huma/v2/humatest" "github.com/stretchr/testify/require" "github.com/unkeyed/unkey/apps/agent/pkg/api/routes" "github.com/unkeyed/unkey/apps/agent/pkg/cluster" @@ -27,11 +27,11 @@ type Harness struct { ratelimit ratelimit.Service - api humatest.TestAPI + mux *http.ServeMux } func NewHarness(t *testing.T) *Harness { - _, api := humatest.New(t) + mux := http.NewServeMux() p := port.New() nodeId := uid.New("test") @@ -43,7 +43,7 @@ func NewHarness(t *testing.T) *Harness { t: t, logger: logging.NewNoopLogger(), metrics: metrics.NewNoop(), - api: api, + mux: mux, } memb, err := membership.New(membership.Config{ @@ -72,17 +72,21 @@ func NewHarness(t *testing.T) *Harness { return &h } -func (h *Harness) Register(register func(api huma.API, svc routes.Services, middlewares ...func(ctx huma.Context, next func(huma.Context)))) { - register(h.api, routes.Services{ +func (h *Harness) Register(route *routes.Route) { + + route.Register(h.mux) + +} + +func (h *Harness) SetupRoute(constructor func(svc routes.Services) *routes.Route) *routes.Route { + route := constructor(routes.Services{ Logger: h.logger, Metrics: h.metrics, - Vault: nil, Ratelimit: h.ratelimit, + Vault: nil, }) -} - -func (h *Harness) Api() humatest.TestAPI { - return h.api + h.Register(route) + return route } // Post is a helper function to make a POST request to the API. @@ -93,3 +97,37 @@ func UnmarshalBody[Body any](t *testing.T, r *httptest.ResponseRecorder, body *B require.NoError(t, err) } + +type TestResponse[TBody any] struct { + Status int + Headers http.Header + Body TBody +} + +func CallRoute[Req any, Res any](t *testing.T, route *routes.Route, headers http.Header, req Req) TestResponse[Res] { + t.Helper() + mux := http.NewServeMux() + route.Register(mux) + + rr := httptest.NewRecorder() + + body := new(bytes.Buffer) + err := json.NewEncoder(body).Encode(req) + require.NoError(t, err) + + httpReq := httptest.NewRequest(route.Method(), route.Path(), body) + httpReq.Header = headers + + mux.ServeHTTP(rr, httpReq) + require.NoError(t, err) + + var res Res + err = json.NewDecoder(rr.Body).Decode(&res) + require.NoError(t, err) + + return TestResponse[Res]{ + Status: rr.Code, + Headers: rr.Header(), + Body: res, + } +} diff --git a/apps/agent/pkg/api/validation/validator.go b/apps/agent/pkg/api/validation/validator.go new file mode 100644 index 0000000000..bf3834f3c6 --- /dev/null +++ b/apps/agent/pkg/api/validation/validator.go @@ -0,0 +1,133 @@ +package validation + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "os" + + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" + "github.com/pb33f/libopenapi" + validator "github.com/pb33f/libopenapi-validator" + "github.com/unkeyed/unkey/apps/agent/gen/openapi" + "github.com/unkeyed/unkey/apps/agent/pkg/api/ctxutil" + "github.com/unkeyed/unkey/apps/agent/pkg/util" +) + +type OpenAPIValidator interface { + Body(r *http.Request, dest any) (openapi.ValidationError, bool) +} + +type Validator struct { + validator validator.Validator +} + +func New(specPath string) (*Validator, error) { + b, err := os.ReadFile(specPath) + if err != nil { + return nil, fault.Wrap(err, fmsg.With("failed to read spec file")) + } + document, err := libopenapi.NewDocument(b) + if err != nil { + return nil, fault.Wrap(err, fmsg.With("failed to create OpenAPI document")) + } + + v, errors := validator.NewValidator(document) + if len(errors) > 0 { + messages := make([]fault.Wrapper, len(errors)) + for i, e := range errors { + messages[i] = fmsg.With(e.Error()) + } + return nil, fault.New("failed to create validator", messages...) + } + return &Validator{ + validator: v, + }, nil +} + +// Body reads the request body and validates it against the OpenAPI spec +// The body is closed after reading. +// Returns a ValidationError if the body is invalid that should be marshalled and returned to the client. +// The second return value is a boolean that is true if the body is valid. +func (v *Validator) Body(r *http.Request, dest any) (openapi.ValidationError, bool) { + + bodyBytes, err := io.ReadAll(r.Body) + r.Body.Close() + if err != nil { + return openapi.ValidationError{ + Title: "Bad Request", + Detail: "Failed to read request body", + Errors: []openapi.ValidationErrorDetail{{ + Location: "body", + Message: err.Error(), + }}, + Instance: "https://errors.unkey.com/todo", + Status: http.StatusBadRequest, + RequestId: ctxutil.GetRequestId(r.Context()), + }, false + } + r.Body = io.NopCloser(bytes.NewReader(bodyBytes)) + + if err != nil { + return openapi.ValidationError{ + Title: "Bad Request", + Detail: "Failed to create new request", + Errors: []openapi.ValidationErrorDetail{{ + Location: "body", + Message: err.Error(), + }}, + Instance: "https://errors.unkey.com/todo", + Status: http.StatusBadRequest, + RequestId: ctxutil.GetRequestId(r.Context()), + }, false + } + + valid, errors := v.validator.ValidateHttpRequest(r) + if !valid { + valErr := openapi.ValidationError{ + Title: "Bad Request", + Detail: "One or more fields failed validation", + Instance: "https://errors.unkey.com/todo", + Status: http.StatusBadRequest, + RequestId: ctxutil.GetRequestId(r.Context()), + Type: "TODO docs link", + Errors: []openapi.ValidationErrorDetail{}, + } + for _, e := range errors { + fmt.Printf("valerr: %+v\n", e) + + for _, schemaValidationError := range e.SchemaValidationErrors { + valErr.Errors = append(valErr.Errors, openapi.ValidationErrorDetail{ + Location: schemaValidationError.Location, + Message: schemaValidationError.Reason, + }) + } + } + return valErr, false + } + + err = json.Unmarshal(bodyBytes, dest) + + if err != nil { + return openapi.ValidationError{ + Title: "Bad Request", + Detail: "Failed to parse request body as JSON", + Errors: []openapi.ValidationErrorDetail{{ + Location: "body", + Message: err.Error(), + Fix: util.Pointer("Ensure the request body is valid JSON"), + }}, + Instance: "https://errors.unkey.com/todo", + Status: http.StatusBadRequest, + RequestId: ctxutil.GetRequestId(r.Context()), + Type: "TODO docs link", + }, false + } + fmt.Printf("body %+v\n", dest) + + return openapi.ValidationError{}, true + +} diff --git a/apps/agent/pkg/clickhouse/client.go b/apps/agent/pkg/clickhouse/client.go new file mode 100644 index 0000000000..bddc0d6e09 --- /dev/null +++ b/apps/agent/pkg/clickhouse/client.go @@ -0,0 +1,88 @@ +package clickhouse + +import ( + "context" + "time" + + ch "github.com/ClickHouse/clickhouse-go/v2" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" + "github.com/unkeyed/unkey/apps/agent/pkg/batch" + "github.com/unkeyed/unkey/apps/agent/pkg/clickhouse/schema" + "github.com/unkeyed/unkey/apps/agent/pkg/logging" + "github.com/unkeyed/unkey/apps/agent/pkg/util" +) + +type Clickhouse struct { + conn ch.Conn + logger logging.Logger + + requests *batch.BatchProcessor[schema.ApiRequestV1] +} + +type Config struct { + URL string + Logger logging.Logger +} + +func New(config Config) (*Clickhouse, error) { + + opts, err := ch.ParseDSN(config.URL) + if err != nil { + return nil, fault.Wrap(err, fmsg.With("parsing clickhouse DSN failed")) + } + + // opts.TLS = &tls.Config{} + opts.Debug = true + opts.Debugf = func(format string, v ...any) { + config.Logger.Debug().Msgf(format, v...) + } + config.Logger.Info().Interface("opts", opts.Addr).Msg("connecting to clickhouse") + conn, err := ch.Open(opts) + if err != nil { + return nil, fault.Wrap(err, fmsg.With("opening clickhouse failed")) + } + + err = util.Retry(func() error { + return conn.Ping(context.Background()) + }, 10, func(n int) time.Duration { + return time.Duration(n) * time.Second + }) + if err != nil { + return nil, fault.Wrap(err, fmsg.With("pinging clickhouse failed")) + } + c := &Clickhouse{ + conn: conn, + logger: config.Logger, + + requests: batch.New[schema.ApiRequestV1](batch.Config[schema.ApiRequestV1]{ + BatchSize: 1000, + BufferSize: 100000, + FlushInterval: time.Second, + Consumers: 4, + Flush: func(ctx context.Context, rows []schema.ApiRequestV1) { + table := "api_requests__v1" + err := flush(ctx, conn, table, rows) + if err != nil { + config.Logger.Error().Err(err).Str("table", table).Msg("failed to flush batch") + } + }, + }), + } + + // err = c.conn.Ping(context.Background()) + // if err != nil { + // return nil, fault.Wrap(err, fmsg.With("pinging clickhouse failed")) + // } + return c, nil +} + +func (c *Clickhouse) Shutdown(ctx context.Context) error { + c.requests.Close() + return c.conn.Close() +} + +func (c *Clickhouse) BufferApiRequest(req schema.ApiRequestV1) { + c.logger.Info().Msg("buffering api request") + c.requests.Buffer(req) +} diff --git a/apps/agent/pkg/clickhouse/flush.go b/apps/agent/pkg/clickhouse/flush.go new file mode 100644 index 0000000000..f0d3e30166 --- /dev/null +++ b/apps/agent/pkg/clickhouse/flush.go @@ -0,0 +1,29 @@ +package clickhouse + +import ( + "context" + "fmt" + + ch "github.com/ClickHouse/clickhouse-go/v2" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" +) + +func flush[T any](ctx context.Context, conn ch.Conn, table string, rows []T) error { + batch, err := conn.PrepareBatch(ctx, fmt.Sprintf("INSERT INTO %s", table)) + if err != nil { + return fault.Wrap(err, fmsg.With("preparing batch failed")) + } + for _, row := range rows { + fmt.Printf("row: %+v\n", row) + err := batch.AppendStruct(&row) + if err != nil { + return fault.Wrap(err, fmsg.With("appending struct to batch failed")) + } + } + err = batch.Send() + if err != nil { + return fault.Wrap(err, fmsg.With("committing batch failed")) + } + return nil +} diff --git a/apps/agent/pkg/clickhouse/interface.go b/apps/agent/pkg/clickhouse/interface.go new file mode 100644 index 0000000000..f47700d195 --- /dev/null +++ b/apps/agent/pkg/clickhouse/interface.go @@ -0,0 +1,9 @@ +package clickhouse + +import ( + "github.com/unkeyed/unkey/apps/agent/pkg/clickhouse/schema" +) + +type Bufferer interface { + BufferApiRequest(schema.ApiRequestV1) +} diff --git a/apps/agent/pkg/clickhouse/noop.go b/apps/agent/pkg/clickhouse/noop.go new file mode 100644 index 0000000000..da12194053 --- /dev/null +++ b/apps/agent/pkg/clickhouse/noop.go @@ -0,0 +1,17 @@ +package clickhouse + +import ( + "github.com/unkeyed/unkey/apps/agent/pkg/clickhouse/schema" +) + +type noop struct{} + +var _ Bufferer = &noop{} + +func (n *noop) BufferApiRequest(schema.ApiRequestV1) { + return +} + +func NewNoop() *noop { + return &noop{} +} diff --git a/apps/agent/pkg/clickhouse/schema/001_create_requests_table.sql b/apps/agent/pkg/clickhouse/schema/001_create_requests_table.sql new file mode 100644 index 0000000000..27bf5cd91d --- /dev/null +++ b/apps/agent/pkg/clickhouse/schema/001_create_requests_table.sql @@ -0,0 +1,22 @@ +-- +goose up +CREATE TABLE default.api_requests__v1( + request_id String, + -- unix milli + time Int64, + host String, + method LowCardinality(String), + path String, + -- "Key: Value" pairs + request_headers Array(String), + request_body String, + + response_status Int, + -- "Key: Value" pairs + response_headers Array(String), + response_body String, + -- internal err.Error() string, empty if no error + error String + +) +ENGINE = MergeTree() +PRIMARY KEY (request_id); diff --git a/apps/agent/pkg/clickhouse/schema/requests.go b/apps/agent/pkg/clickhouse/schema/requests.go new file mode 100644 index 0000000000..2147074d13 --- /dev/null +++ b/apps/agent/pkg/clickhouse/schema/requests.go @@ -0,0 +1,15 @@ +package schema + +type ApiRequestV1 struct { + RequestID string `ch:"request_id"` + Time int64 `ch:"time"` + Host string `ch:"host"` + Method string `ch:"method"` + Path string `ch:"path"` + RequestHeaders []string `ch:"request_headers"` + RequestBody string `ch:"request_body"` + ResponseStatus int `ch:"response_status"` + ResponseHeaders []string `ch:"response_headers"` + ResponseBody string `ch:"response_body"` + Error string `ch:"error"` +} diff --git a/apps/agent/pkg/config/agent.go b/apps/agent/pkg/config/agent.go index 1b839e0c7c..e5ee09c23e 100644 --- a/apps/agent/pkg/config/agent.go +++ b/apps/agent/pkg/config/agent.go @@ -1,14 +1,11 @@ package config type Agent struct { - Platform string `json:"platform,omitempty" description:"The platform this agent is running on"` - NodeId string `json:"nodeId,omitempty" description:"A unique node id"` - Image string `json:"image,omitempty" description:"The image this agent is running"` - Pprof *struct { - Username string `json:"username,omitempty" description:"The username to use for pprof"` - Password string `json:"password,omitempty" description:"The password to use for pprof"` - } `json:"pprof,omitempty" description:"Enable pprof"` - Logging *struct { + Platform string `json:"platform,omitempty" description:"The platform this agent is running on"` + NodeId string `json:"nodeId,omitempty" description:"A unique node id"` + Image string `json:"image,omitempty" description:"The image this agent is running"` + AuthToken string `json:"authToken" minLength:"1" description:"The token to use for http authentication"` + Logging *struct { Axiom *struct { Dataset string `json:"dataset" minLength:"1" description:"The dataset to send logs to"` Token string `json:"token" minLength:"1" description:"The token to use for authentication"` @@ -39,26 +36,21 @@ type Agent struct { } `json:"heartbeat,omitempty" description:"Send heartbeat to a URL"` Services struct { - Ratelimit *struct { - AuthToken string `json:"authToken" minLength:"1" description:"The token to use for http authentication"` - } `json:"ratelimit,omitempty" description:"Rate limit requests"` EventRouter *struct { - AuthToken string `json:"authToken" minLength:"1" description:"The token to use for http authentication"` - Tinybird *struct { + Tinybird *struct { Token string `json:"token" minLength:"1" description:"The token to use for tinybird authentication"` FlushInterval int `json:"flushInterval" min:"1" description:"Interval in seconds to flush events"` BufferSize int `json:"bufferSize" min:"1" description:"Size of the buffer"` BatchSize int `json:"batchSize" min:"1" description:"Size of the batch"` } `json:"tinybird,omitempty" description:"Send events to tinybird"` } `json:"eventRouter,omitempty" description:"Route events"` - Vault *struct { + Vault struct { S3Bucket string `json:"s3Bucket" minLength:"1" description:"The bucket to store secrets in"` S3Url string `json:"s3Url" minLength:"1" description:"The url to store secrets in"` S3AccessKeyId string `json:"s3AccessKeyId" minLength:"1" description:"The access key id to use for s3"` S3AccessKeySecret string `json:"s3AccessKeySecret" minLength:"1" description:"The access key secret to use for s3"` MasterKeys string `json:"masterKeys" minLength:"1" description:"The master keys to use for encryption, comma separated"` - AuthToken string `json:"authToken" minLength:"1" description:"The token to use for http authentication"` - } `json:"vault,omitempty" description:"Store secrets"` + } `json:"vault" description:"Store secrets"` } `json:"services"` Cluster *struct { @@ -85,4 +77,7 @@ type Agent struct { User string `json:"user" minLength:"1"` Password string `json:"password" minLength:"1"` } `json:"pyroscope,omitempty"` + Clickhouse *struct { + Url string `json:"url" minLength:"1"` + } `json:"clickhouse,omitempty"` } diff --git a/apps/agent/pkg/openapi/config.yaml b/apps/agent/pkg/openapi/config.yaml new file mode 100644 index 0000000000..855596b3ad --- /dev/null +++ b/apps/agent/pkg/openapi/config.yaml @@ -0,0 +1,6 @@ +package: openapi +output: ./gen/openapi/gen.go +generate: + models: true +output-options: + nullable-type: true diff --git a/apps/agent/pkg/openapi/openapi.json b/apps/agent/pkg/openapi/openapi.json new file mode 100644 index 0000000000..05b01e58e4 --- /dev/null +++ b/apps/agent/pkg/openapi/openapi.json @@ -0,0 +1,898 @@ +{ + "components": { + "schemas": { + "V0EventsRequestBody": { + "type": "string", + "description": "NDJSON payload of events" + }, + "V0EventsResponseBody": { + "type": "object", + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "example": "https://api.unkey.dev/schemas/V0EventsResponseBody.json", + "format": "uri", + "readOnly": true, + "type": "string" + }, + "successful_rows": { + "type": "integer", + "description": "The number of rows that were successfully processed" + }, + "quarantined_rows": { + "type": "integer", + "description": "The number of rows that were quarantined" + } + }, + "required": ["successful_rows", "quarantined_rows"] + }, + "Encrypted": { + "additionalProperties": false, + "properties": { + "encrypted": { + "type": "string" + }, + "keyId": { + "type": "string" + } + }, + "required": ["encrypted", "keyId"], + "type": "object" + }, + "ValidationErrorDetail": { + "additionalProperties": false, + "properties": { + "location": { + "description": "Where the error occurred, e.g. 'body.items[3].tags' or 'path.thing-id'", + "type": "string" + }, + "message": { + "description": "Error message text", + "type": "string" + }, + "fix": { + "description": "A human-readable message describing how to fix the error.", + "type": "string" + } + }, + "type": "object", + "required": ["message", "location"] + }, + "ValidationError": { + "additionalProperties": false, + "properties": { + "requestId": { + "description": "A unique id for this request. Please always provide this to support.", + "example": "req_123", + "type": "string" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.", + "example": "Property foo is required but is missing.", + "type": "string" + }, + "errors": { + "description": "Optional list of individual error details", + "items": { + "$ref": "#/components/schemas/ValidationErrorDetail" + }, + "type": ["array"] + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem.", + "example": "https://example.com/error-log/abc123", + "format": "uri", + "type": "string" + }, + "status": { + "description": "HTTP status code", + "example": 400, + "format": "int", + "type": "integer" + }, + "title": { + "description": "A short, human-readable summary of the problem type. This value should not change between occurrences of the error.", + "example": "Bad Request", + "type": "string" + }, + "type": { + "default": "about:blank", + "description": "A URI reference to human-readable documentation for the error.", + "example": "https://example.com/errors/example", + "format": "uri", + "type": "string" + } + }, + "type": "object", + "required": ["requestId", "detail", "instance", "status", "title", "type", "errors"] + }, + "BaseError": { + "additionalProperties": false, + "properties": { + "requestId": { + "description": "A unique id for this request. Please always provide this to support.", + "example": "req_123", + "type": "string" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.", + "example": "Property foo is required but is missing.", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem.", + "example": "https://example.com/error-log/abc123", + "format": "uri", + "type": "string" + }, + "status": { + "description": "HTTP status code", + "example": 400, + "format": "int", + "type": "integer" + }, + "title": { + "description": "A short, human-readable summary of the problem type. This value should not change between occurrences of the error.", + "example": "Bad Request", + "type": "string" + }, + "type": { + "default": "about:blank", + "description": "A URI reference to human-readable documentation for the error.", + "example": "https://example.com/errors/example", + "format": "uri", + "type": "string" + } + }, + "type": "object", + "required": ["requestId", "detail", "instance", "status", "title", "type", "errors"] + }, + "Item": { + "additionalProperties": false, + "properties": { + "cost": { + "default": 1, + "description": "The cost of the request.", + "format": "int64", + "type": "integer" + }, + "duration": { + "description": "The duration in milliseconds for the rate limit window.", + "format": "int64", + "type": "integer" + }, + "identifier": { + "description": "The identifier for the rate limit.", + "type": "string" + }, + "limit": { + "description": "The maximum number of requests allowed.", + "format": "int64", + "type": "integer" + } + }, + "required": ["identifier", "limit", "duration"], + "type": "object" + }, + "Lease": { + "additionalProperties": false, + "properties": { + "cost": { + "description": "How much to lease.", + "format": "int64", + "type": "integer" + }, + "timeout": { + "description": "The time in milliseconds when the lease will expire. If you do not commit the lease by this time, it will be commited as is.", + "format": "int64", + "type": "integer" + } + }, + "required": ["cost", "timeout"], + "type": "object" + }, + "SingleRatelimitResponse": { + "additionalProperties": false, + "properties": { + "current": { + "description": "The current number of requests made in the current window.", + "format": "int64", + "type": "integer" + }, + "limit": { + "description": "The maximum number of requests allowed.", + "format": "int64", + "type": "integer" + }, + "remaining": { + "description": "The number of requests remaining in the current window.", + "format": "int64", + "type": "integer" + }, + "reset": { + "description": "The time in milliseconds when the rate limit will reset.", + "format": "int64", + "type": "integer" + }, + "success": { + "description": "Whether the request passed the ratelimit. If false, the request must be blocked.", + "type": "boolean" + } + }, + "required": ["limit", "remaining", "reset", "success", "current"], + "type": "object" + }, + "V1DecryptRequestBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "example": "https://api.unkey.dev/schemas/V1DecryptRequestBody.json", + "format": "uri", + "readOnly": true, + "type": "string" + }, + "encrypted": { + "description": "The encrypted base64 string.", + "minLength": 1, + "type": "string" + }, + "keyring": { + "description": "The keyring to use for encryption.", + "type": "string" + } + }, + "required": ["keyring", "encrypted"], + "type": "object" + }, + "V1DecryptResponseBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "example": "https://api.unkey.dev/schemas/V1DecryptResponseBody.json", + "format": "uri", + "readOnly": true, + "type": "string" + }, + "plaintext": { + "description": "The plaintext value.", + "type": "string" + } + }, + "required": ["plaintext"], + "type": "object" + }, + "V1EncryptBulkRequestBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "example": "https://api.unkey.dev/schemas/V1EncryptBulkRequestBody.json", + "format": "uri", + "readOnly": true, + "type": "string" + }, + "data": { + "items": { + "type": "string" + }, + "maxItems": 1000, + "minItems": 1, + "type": ["array"] + }, + "keyring": { + "type": "string" + } + }, + "required": ["keyring", "data"], + "type": "object" + }, + "V1EncryptBulkResponseBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "example": "https://api.unkey.dev/schemas/V1EncryptBulkResponseBody.json", + "format": "uri", + "readOnly": true, + "type": "string" + }, + "encrypted": { + "items": { + "$ref": "#/components/schemas/Encrypted" + }, + "type": ["array"] + } + }, + "required": ["encrypted"], + "type": "object" + }, + "V1EncryptRequestBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "example": "https://api.unkey.dev/schemas/V1EncryptRequestBody.json", + "format": "uri", + "readOnly": true, + "type": "string" + }, + "data": { + "description": "The data to encrypt.", + "minLength": 1, + "type": "string" + }, + "keyring": { + "description": "The keyring to use for encryption.", + "type": "string" + } + }, + "required": ["keyring", "data"], + "type": "object" + }, + "V1EncryptResponseBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "example": "https://api.unkey.dev/schemas/V1EncryptResponseBody.json", + "format": "uri", + "readOnly": true, + "type": "string" + }, + "encrypted": { + "description": "The encrypted data as base64 encoded string.", + "type": "string" + }, + "keyId": { + "description": "The ID of the key used for encryption.", + "type": "string" + } + }, + "required": ["encrypted", "keyId"], + "type": "object" + }, + "V1LivenessResponseBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "example": "https://api.unkey.dev/schemas/V1LivenessResponseBody.json", + "format": "uri", + "readOnly": true, + "type": "string" + }, + "message": { + "description": "Whether we're alive or not", + "example": "OK", + "type": "string" + } + }, + "required": ["message"], + "type": "object" + }, + "V1RatelimitCommitLeaseRequestBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "example": "https://api.unkey.dev/schemas/V1RatelimitCommitLeaseRequestBody.json", + "format": "uri", + "readOnly": true, + "type": "string" + }, + "cost": { + "description": "The actual cost of the request.", + "format": "int64", + "type": "integer" + }, + "lease": { + "description": "The lease you received from the ratelimit response.", + "type": "string" + } + }, + "required": ["lease", "cost"], + "type": "object" + }, + "V1RatelimitMultiRatelimitRequestBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "example": "https://api.unkey.dev/schemas/V1RatelimitMultiRatelimitRequestBody.json", + "format": "uri", + "readOnly": true, + "type": "string" + }, + "ratelimits": { + "description": "The rate limits to check.", + "items": { + "$ref": "#/components/schemas/Item" + }, + "type": ["array"] + } + }, + "required": ["ratelimits"], + "type": "object" + }, + "V1RatelimitMultiRatelimitResponseBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "example": "https://api.unkey.dev/schemas/V1RatelimitMultiRatelimitResponseBody.json", + "format": "uri", + "readOnly": true, + "type": "string" + }, + "ratelimits": { + "description": "The rate limits that were checked.", + "items": { + "$ref": "#/components/schemas/SingleRatelimitResponse" + }, + "type": ["array"] + } + }, + "required": ["ratelimits"], + "type": "object" + }, + "V1RatelimitRatelimitRequestBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "example": "https://api.unkey.dev/schemas/V1RatelimitRatelimitRequestBody.json", + "format": "uri", + "readOnly": true, + "type": "string" + }, + "cost": { + "description": "The cost of the request. Defaults to 1 if not provided.", + "format": "int64", + "type": "integer", + "default": 1 + }, + "duration": { + "description": "The duration in milliseconds for the rate limit window.", + "format": "int64", + "type": "integer" + }, + "identifier": { + "description": "The identifier for the rate limit.", + "type": "string" + }, + "lease": { + "$ref": "#/components/schemas/Lease", + "description": "Reserve an amount of tokens with the option to commit and update later." + }, + "limit": { + "description": "The maximum number of requests allowed.", + "format": "int64", + "type": "integer" + } + }, + "required": ["identifier", "limit", "duration"], + "type": "object" + }, + "V1RatelimitRatelimitResponseBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "example": "https://api.unkey.dev/schemas/V1RatelimitRatelimitResponseBody.json", + "format": "uri", + "readOnly": true, + "type": "string" + }, + "current": { + "description": "The current number of requests made in the current window.", + "format": "int64", + "type": "integer" + }, + "lease": { + "description": "The lease to use when committing the request.", + "type": ["string"] + }, + "limit": { + "description": "The maximum number of requests allowed.", + "format": "int64", + "type": "integer" + }, + "remaining": { + "description": "The number of requests remaining in the current window.", + "format": "int64", + "type": "integer" + }, + "reset": { + "description": "The time in milliseconds when the rate limit will reset.", + "format": "int64", + "type": "integer" + }, + "success": { + "description": "Whether the request passed the ratelimit. If false, the request must be blocked.", + "type": "boolean" + } + }, + "required": ["limit", "remaining", "reset", "success", "current", "lease"], + "type": "object" + } + } + }, + "info": { + "title": "Unkey API", + "version": "1.0.0" + }, + "openapi": "3.0.0", + "paths": { + "/v0/events": { + "post": { + "operationId": "v0.events.create", + "summary": "Create events", + "description": "Accept NDJSON payload of events and process them", + "requestBody": { + "content": { + "application/x-ndjson": { + "schema": { + "$ref": "#/components/schemas/V0EventsRequestBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V0EventsResponseBody" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + }, + "500": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/BaseError" + } + } + }, + "description": "Error" + } + }, + "tags": ["events"] + } + }, + "/ratelimit.v1.RatelimitService/MultiRatelimit": { + "post": { + "operationId": "ratelimit.v1.multiRatelimit", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V1RatelimitMultiRatelimitRequestBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V1RatelimitMultiRatelimitResponseBody" + } + } + }, + "description": "OK" + }, + "400": { + "description": "Bad request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + }, + "500": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/BaseError" + } + } + }, + "description": "Error" + } + }, + "tags": ["ratelimit"] + } + }, + "/ratelimit.v1.RatelimitService/Ratelimit": { + "post": { + "operationId": "ratelimit.v1.ratelimit", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V1RatelimitRatelimitRequestBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V1RatelimitRatelimitResponseBody" + } + } + }, + "description": "OK" + }, + "400": { + "description": "Bad request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + }, + "500": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/BaseError" + } + } + }, + "description": "Error" + } + }, + "tags": ["ratelimit"] + } + }, + "/v1/liveness": { + "get": { + "description": "This endpoint checks if the service is alive.", + "operationId": "liveness", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V1LivenessResponseBody" + } + } + }, + "description": "OK" + }, + "500": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/BaseError" + } + } + }, + "description": "Internal Server Error" + } + }, + "summary": "Liveness check", + "tags": ["liveness"] + } + }, + "/v1/ratelimit.commitLease": { + "post": { + "operationId": "v1.ratelimit.commitLease", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V1RatelimitCommitLeaseRequestBody" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + }, + "500": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/BaseError" + } + } + }, + "description": "Error" + } + }, + "tags": ["ratelimit"] + } + }, + "/vault.v1.VaultService/Decrypt": { + "post": { + "operationId": "vault.v1.decrypt", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V1DecryptRequestBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V1DecryptResponseBody" + } + } + }, + "description": "OK" + }, + "400": { + "description": "Bad request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + }, + "500": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/BaseError" + } + } + }, + "description": "Error" + } + }, + "tags": ["vault"] + } + }, + "/vault.v1.VaultService/Encrypt": { + "post": { + "operationId": "vault.v1.encrypt", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V1EncryptRequestBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V1EncryptResponseBody" + } + } + }, + "description": "OK" + }, + "400": { + "description": "Bad request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + }, + "500": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/BaseError" + } + } + }, + "description": "Error" + } + }, + "tags": ["vault"] + } + }, + "/vault.v1.VaultService/EncryptBulk": { + "post": { + "operationId": "vault.v1.encryptBulk", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V1EncryptBulkRequestBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V1EncryptBulkResponseBody" + } + } + }, + "description": "OK" + }, + "400": { + "description": "Bad request", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + }, + "500": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/BaseError" + } + } + }, + "description": "Error" + } + }, + "tags": ["vault"] + } + } + }, + "servers": [ + { + "url": "https://api.unkey.dev" + }, + { + "url": "http://localhost" + } + ] +} diff --git a/apps/agent/pkg/tinybird/tinybird.go b/apps/agent/pkg/tinybird/tinybird.go index 76d6f516ee..a8b11a38d4 100644 --- a/apps/agent/pkg/tinybird/tinybird.go +++ b/apps/agent/pkg/tinybird/tinybird.go @@ -7,6 +7,8 @@ import ( "io" "net/http" "strings" + + "github.com/unkeyed/unkey/apps/agent/gen/openapi" ) type Client struct { @@ -51,7 +53,7 @@ func (c *Client) Ingest(datasource string, rows []any) error { } - res := Response{} + res := openapi.V0EventsResponseBody{} resBody, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("error reading response body: %w", err) @@ -67,8 +69,3 @@ func (c *Client) Ingest(datasource string, rows []any) error { return nil } - -type Response struct { - SuccessfulRows int `json:"successful_rows"` - QuarantinedRows int `json:"quarantined_rows"` -} diff --git a/apps/agent/pkg/uid/uid.go b/apps/agent/pkg/uid/uid.go index d6c9975cc2..a79831fc80 100644 --- a/apps/agent/pkg/uid/uid.go +++ b/apps/agent/pkg/uid/uid.go @@ -9,7 +9,8 @@ import ( type Prefix string const ( - NodePrefix Prefix = "node" + RequestPrefix Prefix = "req" + NodePrefix Prefix = "node" ) // New Returns a new random base58 encoded uuid. @@ -25,3 +26,7 @@ func New(prefix string) string { func Node() string { return New(string(NodePrefix)) } + +func Request() string { + return New(string(RequestPrefix)) +} diff --git a/apps/agent/schema.json b/apps/agent/schema.json index d2ea739598..e8974390d0 100644 --- a/apps/agent/schema.json +++ b/apps/agent/schema.json @@ -5,6 +5,28 @@ "type": "string", "description": "Make jsonschema happy" }, + "authToken": { + "type": "string", + "description": "The token to use for http authentication", + "minLength": 1 + }, + "clickhouse": { + "type": "object", + "properties": { + "addr": { + "type": "string", + "minLength": 1 + }, + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + }, + "additionalProperties": false, + "required": ["addr", "username", "password"] + }, "cluster": { "type": "object", "properties": { @@ -142,20 +164,23 @@ "description": "Port to listen on", "default": "8080" }, - "pprof": { + "prometheus": { "type": "object", - "description": "Enable pprof", "properties": { - "password": { + "path": { "type": "string", - "description": "The password to use for pprof" + "description": "The path where prometheus scrapes metrics", + "default": "/metrics" }, - "username": { - "type": "string", - "description": "The username to use for pprof" + "port": { + "type": "integer", + "description": "The port where prometheus scrapes metrics", + "format": "int32", + "default": 2112 } }, - "additionalProperties": false + "additionalProperties": false, + "required": ["path", "port"] }, "pyroscope": { "type": "object", @@ -180,6 +205,11 @@ "type": "string", "description": "The region this agent is running in" }, + "rpcPort": { + "type": "string", + "description": "Port to listen on for RPC requests", + "default": "9090" + }, "services": { "type": "object", "properties": { @@ -187,11 +217,6 @@ "type": "object", "description": "Route events", "properties": { - "authToken": { - "type": "string", - "description": "The token to use for http authentication", - "minLength": 1 - }, "tinybird": { "type": "object", "description": "Send events to tinybird", @@ -221,31 +246,12 @@ "required": ["token", "flushInterval", "bufferSize", "batchSize"] } }, - "additionalProperties": false, - "required": ["authToken"] - }, - "ratelimit": { - "type": "object", - "description": "Rate limit requests", - "properties": { - "authToken": { - "type": "string", - "description": "The token to use for http authentication", - "minLength": 1 - } - }, - "additionalProperties": false, - "required": ["authToken"] + "additionalProperties": false }, "vault": { "type": "object", "description": "Store secrets", "properties": { - "authToken": { - "type": "string", - "description": "The token to use for http authentication", - "minLength": 1 - }, "masterKeys": { "type": "string", "description": "The master keys to use for encryption, comma separated", @@ -273,14 +279,7 @@ } }, "additionalProperties": false, - "required": [ - "s3Bucket", - "s3Url", - "s3AccessKeyId", - "s3AccessKeySecret", - "masterKeys", - "authToken" - ] + "required": ["s3Bucket", "s3Url", "s3AccessKeyId", "s3AccessKeySecret", "masterKeys"] } }, "additionalProperties": false @@ -311,5 +310,5 @@ } }, "additionalProperties": true, - "required": ["services"] + "required": ["authToken", "services"] } diff --git a/apps/agent/services/eventrouter/service.go b/apps/agent/services/eventrouter/service.go index 03b48c32f7..1b802caae3 100644 --- a/apps/agent/services/eventrouter/service.go +++ b/apps/agent/services/eventrouter/service.go @@ -7,6 +7,7 @@ import ( "net/http" "time" + "github.com/unkeyed/unkey/apps/agent/gen/openapi" "github.com/unkeyed/unkey/apps/agent/pkg/auth" "github.com/unkeyed/unkey/apps/agent/pkg/batch" "github.com/unkeyed/unkey/apps/agent/pkg/logging" @@ -81,11 +82,10 @@ func New(config Config) (*Service, error) { }, nil } -func (s *Service) CreateHandler() (string, http.Handler) { - return "/v0/events", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Body != nil { - defer r.Body.Close() - } +func (s *Service) CreateHandler() (string, http.HandlerFunc) { + return "POST /v0/events", func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + s.logger.Info().Msg("Received events") ctx, span := tracing.Start(r.Context(), tracing.NewSpanName("eventrouter", "v0/events")) defer span.End() @@ -93,13 +93,15 @@ func (s *Service) CreateHandler() (string, http.Handler) { err := auth.Authorize(ctx, s.authToken, r.Header.Get("Authorization")) if err != nil { s.logger.Warn().Err(err).Msg("failed to authorize request") - http.Error(w, "Unauthorized", http.StatusUnauthorized) + w.WriteHeader(403) + w.Write([]byte("Unauthorized")) return } datasource := r.URL.Query().Get("name") if datasource == "" { - http.Error(w, "missing ?name=", http.StatusBadRequest) + w.WriteHeader(400) + w.Write([]byte("missing ?name= parameter")) return } @@ -115,31 +117,34 @@ func (s *Service) CreateHandler() (string, http.Handler) { break } s.logger.Err(err).Msg("Error decoding row") - http.Error(w, err.Error(), http.StatusBadRequest) - break + w.WriteHeader(400) + w.Write([]byte("Error decoding row")) + return + } rows = append(rows, v) } + s.logger.Info().Int("rows", len(rows)).Msg("Received events") + s.logger.Info().Int("rows", len(rows)).Msg("Received events") for _, row := range rows { s.batcher.Buffer(event{datasource, row}) } - response := tinybird.Response{ + response := openapi.V0EventsResponseBody{ SuccessfulRows: len(rows), QuarantinedRows: 0, } - responseBody, err := json.Marshal(response) + + b, err := json.Marshal(response) if err != nil { s.logger.Err(err).Msg("Error marshalling response") - http.Error(w, err.Error(), http.StatusInternalServerError) + w.WriteHeader(500) + w.Write([]byte("Error marshalling response")) return } - w.Header().Set("Content-Type", "application/json") - _, err = w.Write(responseBody) - if err != nil { - s.logger.Err(err).Msg("Error writing response") - } + w.Header().Add("Content-Type", "application/json") + w.Write(b) - }) + } } diff --git a/apps/api/src/routes/v1_keys_createKey.ts b/apps/api/src/routes/v1_keys_createKey.ts index 491a397b95..006feb7caf 100644 --- a/apps/api/src/routes/v1_keys_createKey.ts +++ b/apps/api/src/routes/v1_keys_createKey.ts @@ -413,21 +413,21 @@ export const registerV1KeysCreateKey = (app: App) => await Promise.all([ roleIds.length > 0 ? db.primary.insert(schema.keysRoles).values( - roleIds.map((roleId) => ({ - keyId: newKey.id, - roleId, - workspaceId: authorizedWorkspaceId, - })), - ) + roleIds.map((roleId) => ({ + keyId: newKey.id, + roleId, + workspaceId: authorizedWorkspaceId, + })), + ) : Promise.resolve(), permissionIds.length > 0 ? db.primary.insert(schema.keysPermissions).values( - permissionIds.map((permissionId) => ({ - keyId: newKey.id, - permissionId, - workspaceId: authorizedWorkspaceId, - })), - ) + permissionIds.map((permissionId) => ({ + keyId: newKey.id, + permissionId, + workspaceId: authorizedWorkspaceId, + })), + ) : Promise.resolve(), ]); diff --git a/apps/api/src/routes/v1_keys_verifyKey.multilimit.test.ts b/apps/api/src/routes/v1_keys_verifyKey.multilimit.test.ts index b3b43be246..2958598040 100644 --- a/apps/api/src/routes/v1_keys_verifyKey.multilimit.test.ts +++ b/apps/api/src/routes/v1_keys_verifyKey.multilimit.test.ts @@ -48,6 +48,7 @@ describe("without identities", () => { }, }); + console.info(res); expect(res.status, `expected 200, received: ${JSON.stringify(res, null, 2)}`).toBe(200); expect(res.body.valid).toBe(true); expect(res.body.code).toBe("VALID"); diff --git a/deployment/config/clickhouse/etc/clickhouse-keeper/keeper_config.xml/keeper_config.xml b/deployment/config/clickhouse/etc/clickhouse-keeper/keeper_config.xml/keeper_config.xml new file mode 100644 index 0000000000..e0c97dde0d --- /dev/null +++ b/deployment/config/clickhouse/etc/clickhouse-keeper/keeper_config.xml/keeper_config.xml @@ -0,0 +1,28 @@ + + + information + /var/log/clickhouse-keeper/clickhouse-keeper.log + /var/log/clickhouse-keeper/clickhouse-keeper.err.log + 1000M + 3 + + 0.0.0.0 + + 9181 + 1 + /var/lib/clickhouse/coordination/log + /var/lib/clickhouse/coordination/snapshots + + 10000 + 30000 + information + + + + 1 + clickhouse-keeper + 9234 + + + + diff --git a/deployment/config/clickhouse/etc/clickhouse-server/config.d/config.xml b/deployment/config/clickhouse/etc/clickhouse-server/config.d/config.xml new file mode 100644 index 0000000000..6914a238c6 --- /dev/null +++ b/deployment/config/clickhouse/etc/clickhouse-server/config.d/config.xml @@ -0,0 +1,30 @@ + + + debug + /var/log/clickhouse-server/clickhouse-server.log + /var/log/clickhouse-server/clickhouse-server.err.log + 1000M + 3 + + ch-1S_1K + 0.0.0.0 + 8123 + 9000 + + + users.xml + + + /var/lib/clickhouse/access/ + + + + /clickhouse/task_queue/ddl + + + + clickhouse-keeper + 9181 + + + diff --git a/deployment/config/clickhouse/etc/clickhouse-server/users.d/users.xml b/deployment/config/clickhouse/etc/clickhouse-server/users.d/users.xml new file mode 100644 index 0000000000..0f32c646e8 --- /dev/null +++ b/deployment/config/clickhouse/etc/clickhouse-server/users.d/users.xml @@ -0,0 +1,37 @@ + + + + + 10000000000 + 0 + in_order + 1 + + + + + 1 + default + + ::/0 + + default + 1 + 1 + 1 + 1 + + + + + + 3600 + 0 + 0 + 0 + 0 + 0 + + + + diff --git a/deployment/docker-compose.yaml b/deployment/docker-compose.yaml index fef1af798f..c2a6dad020 100644 --- a/deployment/docker-compose.yaml +++ b/deployment/docker-compose.yaml @@ -43,6 +43,7 @@ services: dockerfile: ./Dockerfile depends_on: - s3 + - clickhouse environment: PORT: 8080 SERF_PORT: 9090 @@ -54,6 +55,8 @@ services: VAULT_S3_ACCESS_KEY_SECRET: "minio_root_password" VAULT_MASTER_KEYS: "Ch9rZWtfMmdqMFBJdVhac1NSa0ZhNE5mOWlLSnBHenFPENTt7an5MRogENt9Si6wms4pQ2XIvqNSIgNpaBenJmXgcInhu6Nfv2U=" TINYBIRD_TOKEN: "I can't wait until we use clickhouse for local development" + CLICKHOUSE_URL: "clickhouse://default:@clickhouse:9000" + agent_lb: container_name: agent_lb @@ -64,37 +67,18 @@ services: - agent ports: - 8080:8080 - # api_lb: - # container_name: api_kb - # image: nginx:latest - # volumes: - # - ./nginx.api.conf:/etc/nginx/nginx.conf:ro - # depends_on: - # - api - # ports: - # - 8787:8787 - # clickhouse: - # image: clickhouse/clickhouse-server:latest - # user: '101:101' - # container_name: clickhouse - # hostname: clickhouse - # volumes: - # - clickhouse:/etc/clickhouse-server - # ports: - # - '127.0.0.1:8123:8123' - # - '127.0.0.1:9000:9000' - # depends_on: - # - clickhouse-keeper - # clickhouse-keeper: - # image: clickhouse/clickhouse-keeper:latest - # user: '101:101' - # container_name: clickhouse-keeper - # hostname: clickhouse-keeper - # volumes: - # - clickhouse-keeper:/etc/clickhouse-keeper - # ports: - # - '127.0.0.1:9181:9181' < + + clickhouse: + image: bitnami/clickhouse:latest + container_name: clickhouse + environment: + - ALLOW_EMPTY_PASSWORD=yes + ports: + - '8123:8123' + - '9000:9000' + volumes: + - clickhouse:/bitnami/clickhouse s3: container_name: s3 @@ -145,6 +129,7 @@ services: volumes: mysql: + grafana: clickhouse: clickhouse-keeper: s3: diff --git a/fly b/fly new file mode 100644 index 0000000000..858ec76f97 --- /dev/null +++ b/fly @@ -0,0 +1,3 @@ + +BEFORE +registry.fly.io/unkey-production-agent:deployment-01J6EVNG81KD7M8ZMZX3D8KFHG diff --git a/packages/cache/src/swr.test.ts b/packages/cache/src/swr.test.ts index 46e8699def..d7e5aad6e3 100644 --- a/packages/cache/src/swr.test.ts +++ b/packages/cache/src/swr.test.ts @@ -79,3 +79,28 @@ describe("with stale data", () => { expect(res).toEqual({ val: "fresh_data" }); }); }); + +describe("with fresh=0", () => { + test("revalidates every time", async () => { + const memoryStore = new MemoryStore({ persistentMap: new Map() }); + const cache = new SwrCache( + new DefaultStatefulContext(), + memoryStore, + 0, + 800000, + ); + + let revalidated = 0; + for (let i = 0; i < 100; i++) { + const res = await cache.swr(namespace, key, async () => { + revalidated++; + return i; + }); + if (i > 1) { + expect(res.val).toEqual(i - 2); + } + } + + expect(revalidated).toBe(100); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a7297bd686..8e78997d97 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1223,7 +1223,7 @@ importers: devDependencies: checkly: specifier: latest - version: 4.7.0(@types/node@20.14.9)(typescript@5.5.3) + version: 4.8.1(@types/node@20.14.9)(typescript@5.5.3) ts-node: specifier: 10.9.1 version: 10.9.1(@types/node@20.14.9)(typescript@5.5.3) @@ -2084,7 +2084,7 @@ packages: '@antv/g6-core': 0.8.24 '@antv/g6-element': 0.8.24(@antv/g6@4.8.24) '@antv/g6-plugin': 0.8.24(@antv/g6@4.8.24) - '@antv/hierarchy': 0.6.12 + '@antv/hierarchy': 0.6.13 '@antv/layout': 0.3.25(dagre@0.8.5) '@antv/matrix-util': 3.1.0-beta.3 '@antv/path-util': 2.0.15 @@ -2128,8 +2128,8 @@ packages: resolution: {integrity: sha512-hhJOMThec51nU4Fe5p/viLlNIL71uDEgYFzKPajWjr2715SFG1HAgiP6AVylIeqBcAZ04u3Lw7usjl/TuI5RuQ==} dev: false - /@antv/hierarchy@0.6.12: - resolution: {integrity: sha512-WvWT9WYtm2SvYunm1HtzrHazvOozeP4cPFDhJWsnLzmTGMX/tNhsoCD3O+DDB3aeDY8fyM+wfZDvLv7+/4lIeA==} + /@antv/hierarchy@0.6.13: + resolution: {integrity: sha512-gBC0bYXyBVrprWyR0hqINNYfeovxdIcKBAR7x6DfNyN1Gc3hGaSo0wif6Lrv/aWVHz17FeQlVsf8rgEx343FHg==} dev: false /@antv/layout@0.1.31: @@ -2276,14 +2276,14 @@ packages: dependencies: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.24.7 - '@babel/generator': 7.25.5 + '@babel/generator': 7.25.6 '@babel/helper-compilation-targets': 7.25.2 '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) - '@babel/helpers': 7.25.0 - '@babel/parser': 7.25.4 + '@babel/helpers': 7.25.6 + '@babel/parser': 7.25.6 '@babel/template': 7.25.0 - '@babel/traverse': 7.25.4 - '@babel/types': 7.25.4 + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 convert-source-map: 2.0.0 debug: 4.3.6(supports-color@8.1.1) gensync: 1.0.0-beta.2 @@ -2292,11 +2292,11 @@ packages: transitivePeerDependencies: - supports-color - /@babel/generator@7.25.5: - resolution: {integrity: sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==} + /@babel/generator@7.25.6: + resolution: {integrity: sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.25.4 + '@babel/types': 7.25.6 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 @@ -2315,8 +2315,8 @@ packages: resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/traverse': 7.25.4 - '@babel/types': 7.25.4 + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 transitivePeerDependencies: - supports-color @@ -2330,7 +2330,7 @@ packages: '@babel/helper-module-imports': 7.24.7 '@babel/helper-simple-access': 7.24.7 '@babel/helper-validator-identifier': 7.24.7 - '@babel/traverse': 7.25.4 + '@babel/traverse': 7.25.6 transitivePeerDependencies: - supports-color @@ -2338,8 +2338,8 @@ packages: resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/traverse': 7.25.4 - '@babel/types': 7.25.4 + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 transitivePeerDependencies: - supports-color @@ -2355,12 +2355,12 @@ packages: resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==} engines: {node: '>=6.9.0'} - /@babel/helpers@7.25.0: - resolution: {integrity: sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==} + /@babel/helpers@7.25.6: + resolution: {integrity: sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.25.0 - '@babel/types': 7.25.4 + '@babel/types': 7.25.6 /@babel/highlight@7.24.7: resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} @@ -2376,18 +2376,18 @@ packages: engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.25.4 + '@babel/types': 7.25.6 dev: false - /@babel/parser@7.25.4: - resolution: {integrity: sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==} + /@babel/parser@7.25.6: + resolution: {integrity: sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.25.4 + '@babel/types': 7.25.6 - /@babel/runtime@7.25.4: - resolution: {integrity: sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w==} + /@babel/runtime@7.25.6: + resolution: {integrity: sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 @@ -2397,25 +2397,25 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.24.7 - '@babel/parser': 7.25.4 - '@babel/types': 7.25.4 + '@babel/parser': 7.25.6 + '@babel/types': 7.25.6 - /@babel/traverse@7.25.4: - resolution: {integrity: sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==} + /@babel/traverse@7.25.6: + resolution: {integrity: sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.24.7 - '@babel/generator': 7.25.5 - '@babel/parser': 7.25.4 + '@babel/generator': 7.25.6 + '@babel/parser': 7.25.6 '@babel/template': 7.25.0 - '@babel/types': 7.25.4 + '@babel/types': 7.25.6 debug: 4.3.6(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color - /@babel/types@7.25.4: - resolution: {integrity: sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==} + /@babel/types@7.25.6: + resolution: {integrity: sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-string-parser': 7.24.8 @@ -2536,7 +2536,7 @@ packages: /@changesets/apply-release-plan@7.0.4: resolution: {integrity: sha512-HLFwhKWayKinWAul0Vj+76jVx1Pc2v55MGPVjZ924Y/ROeSsBMFutv9heHmCUj48lJyRfOTJG5+ar+29FUky/A==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@changesets/config': 3.0.2 '@changesets/get-version-range-type': 0.4.0 '@changesets/git': 3.0.0 @@ -2555,7 +2555,7 @@ packages: /@changesets/assemble-release-plan@6.0.3: resolution: {integrity: sha512-bLNh9/Lgl1VwkjWZTq8JmRqH+hj7/Yzfz0jsQ/zJJ+FTmVqmqPj3szeKOri8O/hEM8JmHW019vh2gTO9iq5Cuw==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@changesets/errors': 0.2.0 '@changesets/get-dependents-graph': 2.1.1 '@changesets/should-skip-package': 0.1.0 @@ -2574,7 +2574,7 @@ packages: resolution: {integrity: sha512-iJ91xlvRnnrJnELTp4eJJEOPjgpF3NOh4qeQehM6Ugiz9gJPRZ2t+TsXun6E3AMN4hScZKjqVXl0TX+C7AB3ZQ==} hasBin: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@changesets/apply-release-plan': 7.0.4 '@changesets/assemble-release-plan': 6.0.3 '@changesets/changelog-git': 0.2.0 @@ -2639,7 +2639,7 @@ packages: /@changesets/get-release-plan@4.0.3: resolution: {integrity: sha512-6PLgvOIwTSdJPTtpdcr3sLtGatT+Jr22+cQwEBJBy6wP0rjB4yJ9lv583J9fVpn1bfQlBkDa8JxbS2g/n9lIyA==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@changesets/assemble-release-plan': 6.0.3 '@changesets/config': 3.0.2 '@changesets/pre': 2.0.0 @@ -2655,7 +2655,7 @@ packages: /@changesets/git@3.0.0: resolution: {integrity: sha512-vvhnZDHe2eiBNRFHEgMiGd2CT+164dfYyrJDhwwxTVD/OW0FUD6G7+4DIx1dNwkwjHyzisxGAU96q0sVNBns0w==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@changesets/errors': 0.2.0 '@changesets/types': 6.0.0 '@manypkg/get-packages': 1.1.3 @@ -2680,7 +2680,7 @@ packages: /@changesets/pre@2.0.0: resolution: {integrity: sha512-HLTNYX/A4jZxc+Sq8D1AMBsv+1qD6rmmJtjsCJa/9MSRybdxh0mjbTvE6JYZQ/ZiQ0mMlDOlGPXTm9KLTU3jyw==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@changesets/errors': 0.2.0 '@changesets/types': 6.0.0 '@manypkg/get-packages': 1.1.3 @@ -2690,7 +2690,7 @@ packages: /@changesets/read@0.6.0: resolution: {integrity: sha512-ZypqX8+/im1Fm98K4YcZtmLKgjs1kDQ5zHpc2U1qdtNBmZZfo/IBiG162RoP0CUF05tvp2y4IspH11PLnPxuuw==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@changesets/git': 3.0.0 '@changesets/logger': 0.1.0 '@changesets/parse': 0.4.0 @@ -2703,7 +2703,7 @@ packages: /@changesets/should-skip-package@0.1.0: resolution: {integrity: sha512-FxG6Mhjw7yFStlSM7Z0Gmg3RiyQ98d/9VpQAZ3Fzr59dCOM9G6ZdYbjiSAt0XtFr9JR5U2tBaJWPjrkGGc618g==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@changesets/types': 6.0.0 '@manypkg/get-packages': 1.1.3 dev: true @@ -2719,7 +2719,7 @@ packages: /@changesets/write@0.3.1: resolution: {integrity: sha512-SyGtMXzH3qFqlHKcvFY2eX+6b0NGiFcNav8AFsYwy5l8hejOeoeTDemu5Yjmke2V5jpzY+pBvM0vCCQ3gdZpfw==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@changesets/types': 6.0.0 fs-extra: 7.0.1 human-id: 1.0.2 @@ -3244,7 +3244,7 @@ packages: resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} dependencies: '@esbuild-kit/core-utils': 3.3.2 - get-tsconfig: 4.7.6 + get-tsconfig: 4.8.0 dev: true /@esbuild-plugins/node-globals-polyfill@0.2.3(esbuild@0.17.19): @@ -5032,7 +5032,7 @@ packages: '@inquirer/figures': 1.0.5 '@inquirer/type': 1.5.2 '@types/mute-stream': 0.0.4 - '@types/node': 22.5.1 + '@types/node': 22.5.2 '@types/wrap-ansi': 3.0.0 ansi-escapes: 4.3.2 cli-spinners: 2.9.2 @@ -5240,7 +5240,7 @@ packages: /@manypkg/find-root@1.1.0: resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@types/node': 12.20.55 find-up: 4.1.0 fs-extra: 8.1.0 @@ -5249,7 +5249,7 @@ packages: /@manypkg/get-packages@1.1.3: resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@changesets/types': 4.1.0 '@manypkg/find-root': 1.1.0 fs-extra: 8.1.0 @@ -5330,7 +5330,7 @@ packages: react: '>=16' dependencies: '@types/mdx': 2.0.13 - '@types/react': 18.3.4 + '@types/react': 18.3.5 react: 18.3.1 /@million/lint@0.0.73: @@ -5339,20 +5339,20 @@ packages: dependencies: '@babel/core': 7.25.2 '@babel/helper-module-imports': 7.24.7 - '@babel/types': 7.25.4 + '@babel/types': 7.25.6 '@radix-ui/react-dialog': 1.1.1(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-tooltip': 1.1.2(react-dom@18.3.1)(react@18.3.1) '@rollup/pluginutils': 5.1.0 cmdk: 0.2.1(react-dom@18.3.1)(react@18.3.1) esbuild: 0.20.2 - escalade: 3.1.2 + escalade: 3.2.0 isomorphic-fetch: 3.0.0 posthog-node: 3.6.3 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-draggable: 4.4.6(react-dom@18.3.1)(react@18.3.1) react-reconciler: 0.29.2(react@18.3.1) - unplugin: 1.12.2 + unplugin: 1.12.3 zustand: 4.5.5(@types/react@18.2.79)(react@18.3.1) transitivePeerDependencies: - '@types/react' @@ -5488,7 +5488,7 @@ packages: resolution: {integrity: sha512-qYJF8dyLIOLVfS9qhZctfBulgqgxabP5Xlp/5gAd7mFX5op8ghEFGQMvvfcGSU3/uBzSM88qBVUOHOq4zz5YPw==} engines: {node: '>=18.0.0'} dependencies: - axios: 1.7.5 + axios: 1.7.7 openapi-types: 12.1.3 transitivePeerDependencies: - debug @@ -5562,7 +5562,7 @@ packages: dependencies: '@apidevtools/swagger-parser': 10.1.0(openapi-types@12.1.3) '@mintlify/common': 1.0.118(react-dom@18.3.1)(react@18.3.1) - axios: 1.7.5 + axios: 1.7.7 cheerio: 0.22.0 fs-extra: 11.2.0 node-html-markdown: 1.3.0 @@ -6080,35 +6080,24 @@ packages: - typescript dev: true - /@oclif/core@3.27.0: - resolution: {integrity: sha512-Fg93aNFvXzBq5L7ztVHFP2nYwWU1oTCq48G0TjF/qC1UN36KWa2H5Hsm72kERd5x/sjy2M2Tn4kDEorUlpXOlw==} + /@oclif/core@4.0.19: + resolution: {integrity: sha512-VXnsYNVfmucXp5BdOA/OcWi8F/h2h8ofW1GxQDdspodnmnUgALEpqrxXBl5NFuA+iEihtAJeXzX260ICHYDaBg==} engines: {node: '>=18.0.0'} dependencies: - '@types/cli-progress': 3.11.6 ansi-escapes: 4.3.2 - ansi-styles: 4.3.0 - cardinal: 2.1.1 - chalk: 4.1.2 + ansis: 3.3.2 clean-stack: 3.0.1 - cli-progress: 3.12.0 - color: 4.2.3 + cli-spinners: 2.9.2 debug: 4.3.6(supports-color@8.1.1) ejs: 3.1.10 get-package-type: 0.1.0 globby: 11.1.0 - hyperlinker: 1.0.0 indent-string: 4.0.0 is-wsl: 2.2.0 - js-yaml: 3.14.1 + lilconfig: 3.1.2 minimatch: 9.0.5 - natural-orderby: 2.0.3 - object-treeify: 1.1.33 - password-prompt: 1.1.3 - slice-ansi: 4.0.0 string-width: 4.2.3 - strip-ansi: 6.0.1 supports-color: 8.1.1 - supports-hyperlinks: 2.3.0 widest-line: 3.1.0 wordwrap: 1.0.0 wrap-ansi: 7.0.0 @@ -6140,18 +6129,20 @@ packages: - typescript dev: true - /@oclif/plugin-plugins@4.1.12: - resolution: {integrity: sha512-lYNoqoQJz+p4AOMZ9N5k7OkLk/HZJSdaybJ4rWfDZ76pQ7AcrLEPtREi2wLfcwcrzKoBMsrwBoMTf3PnmpW7ZQ==} + /@oclif/plugin-plugins@5.4.4: + resolution: {integrity: sha512-p30fo3JPtbOqTJOX9A/8qKV/14XWt8xFgG/goVfIkuKBAO+cdY78ag8pYatlpzsYzJhO27X1MFn0WkkPWo36Ww==} engines: {node: '>=18.0.0'} dependencies: - '@oclif/core': 3.27.0 - chalk: 5.3.0 + '@oclif/core': 4.0.19 + ansis: 3.3.2 debug: 4.3.6(supports-color@8.1.1) - npm: 10.2.3 - npm-run-path: 4.0.1 + npm: 10.8.3 + npm-package-arg: 11.0.3 + npm-run-path: 5.3.0 + object-treeify: 4.0.1 semver: 7.6.3 - shelljs: 0.8.5 validate-npm-package-name: 5.0.1 + which: 4.0.0 yarn: 1.22.22 transitivePeerDependencies: - supports-color @@ -7031,20 +7022,20 @@ packages: /@probe.gl/env@3.6.0: resolution: {integrity: sha512-4tTZYUg/8BICC3Yyb9rOeoKeijKbZHRXBEKObrfPmX4sQmYB15ZOUpoVBhAyJkOYVAM8EkPci6Uw5dLCwx2BEQ==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 dev: false /@probe.gl/log@3.6.0: resolution: {integrity: sha512-hjpyenpEvOdowgZ1qMeCJxfRD4JkKdlXz0RC14m42Un62NtOT+GpWyKA4LssT0+xyLULCByRAtG2fzZorpIAcA==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@probe.gl/env': 3.6.0 dev: false /@probe.gl/stats@3.6.0: resolution: {integrity: sha512-JdALQXB44OP4kUBN/UrQgzbJe4qokbVF4Y8lkIA8iVCFnjVowWIgkD/z/0QO65yELT54tTrtepw1jScjKB+rhQ==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 dev: false /@protobufjs/aspromise@1.1.2: @@ -7120,18 +7111,18 @@ packages: /@radix-ui/number@1.0.1: resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 dev: false /@radix-ui/primitive@1.0.0: resolution: {integrity: sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 /@radix-ui/primitive@1.0.1: resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 dev: false /@radix-ui/primitive@1.1.0: @@ -7206,7 +7197,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@radix-ui/react-context': 1.0.1(@types/react@18.2.79)(react@18.3.1) @@ -7232,7 +7223,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) '@types/react': 18.2.79 '@types/react-dom': 18.2.25 @@ -7240,7 +7231,7 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-arrow@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-arrow@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==} peerDependencies: '@types/react': '*' @@ -7253,9 +7244,9 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -7292,7 +7283,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-context': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.79)(react@18.3.1) @@ -7316,7 +7307,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@radix-ui/react-context': 1.0.1(@types/react@18.2.79)(react@18.3.1) @@ -7344,7 +7335,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@radix-ui/react-context': 1.0.1(@types/react@18.2.79)(react@18.3.1) @@ -7359,7 +7350,7 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-collapsible@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-collapsible@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==} peerDependencies: '@types/react': '*' @@ -7372,16 +7363,16 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-context': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-id': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@types/react': 18.3.4 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-id': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -7454,7 +7445,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@radix-ui/react-context': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) @@ -7465,7 +7456,7 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-collection@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-collection@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==} peerDependencies: '@types/react': '*' @@ -7478,12 +7469,12 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-context': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-slot': 1.0.2(@types/react@18.3.4)(react@18.3.1) - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.0.2(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -7540,7 +7531,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 react: 18.3.1 /@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.79)(react@18.3.1): @@ -7552,7 +7543,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@types/react': 18.2.79 react: 18.3.1 dev: false @@ -7566,12 +7557,12 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@types/react': 18.3.2 react: 18.3.1 dev: false - /@radix-ui/react-compose-refs@1.0.1(@types/react@18.3.4)(react@18.3.1): + /@radix-ui/react-compose-refs@1.0.1(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} peerDependencies: '@types/react': '*' @@ -7580,8 +7571,8 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@types/react': 18.3.5 react: 18.3.1 dev: false @@ -7615,7 +7606,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 react: 18.3.1 /@radix-ui/react-context@1.0.1(@types/react@18.2.79)(react@18.3.1): @@ -7627,12 +7618,12 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@types/react': 18.2.79 react: 18.3.1 dev: false - /@radix-ui/react-context@1.0.1(@types/react@18.3.4)(react@18.3.1): + /@radix-ui/react-context@1.0.1(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} peerDependencies: '@types/react': '*' @@ -7641,8 +7632,8 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@types/react': 18.3.5 react: 18.3.1 dev: false @@ -7677,7 +7668,7 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.0 '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) '@radix-ui/react-context': 1.0.0(react@18.3.1) @@ -7704,7 +7695,7 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.0 '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) '@radix-ui/react-context': 1.0.0(react@18.3.1) @@ -7738,7 +7729,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@radix-ui/react-context': 1.0.1(@types/react@18.2.79)(react@18.3.1) @@ -7799,12 +7790,12 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@types/react': 18.2.79 react: 18.3.1 dev: false - /@radix-ui/react-direction@1.0.1(@types/react@18.3.4)(react@18.3.1): + /@radix-ui/react-direction@1.0.1(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} peerDependencies: '@types/react': '*' @@ -7813,8 +7804,8 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@types/react': 18.3.5 react: 18.3.1 dev: false @@ -7850,7 +7841,7 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.0 '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) '@radix-ui/react-primitive': 1.0.0(react-dom@18.3.1)(react@18.3.1) @@ -7859,7 +7850,7 @@ packages: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - /@radix-ui/react-dismissable-layer@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-dismissable-layer@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-7UpBa/RKMoHJYjie1gkF1DlK8l1fdU/VKDpoS3rCCo8YBJR294GwcEHyxHw72yvphJ7ld0AXEcSLAzY2F/WyCg==} peerDependencies: '@types/react': '*' @@ -7872,13 +7863,13 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.3.4)(react@18.3.1) - '@types/react': 18.3.4 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -7897,7 +7888,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) @@ -7909,7 +7900,7 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==} peerDependencies: '@types/react': '*' @@ -7922,13 +7913,13 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.3.4)(react@18.3.1) - '@types/react': 18.3.4 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -7993,7 +7984,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@radix-ui/react-context': 1.0.1(@types/react@18.2.79)(react@18.3.1) @@ -8012,7 +8003,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 react: 18.3.1 /@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.79)(react@18.3.1): @@ -8024,12 +8015,12 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@types/react': 18.2.79 react: 18.3.1 dev: false - /@radix-ui/react-focus-guards@1.0.1(@types/react@18.3.4)(react@18.3.1): + /@radix-ui/react-focus-guards@1.0.1(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} peerDependencies: '@types/react': '*' @@ -8038,8 +8029,8 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@types/react': 18.3.5 react: 18.3.1 dev: false @@ -8061,7 +8052,7 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) '@radix-ui/react-primitive': 1.0.0(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1) @@ -8081,7 +8072,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.79)(react@18.3.1) @@ -8091,7 +8082,7 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==} peerDependencies: '@types/react': '*' @@ -8104,11 +8095,11 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -8147,7 +8138,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-use-layout-effect': 1.0.0(react@18.3.1) react: 18.3.1 @@ -8160,13 +8151,13 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@types/react': 18.2.79 react: 18.3.1 dev: false - /@radix-ui/react-id@1.0.1(@types/react@18.3.4)(react@18.3.1): + /@radix-ui/react-id@1.0.1(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} peerDependencies: '@types/react': '*' @@ -8175,9 +8166,9 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 react: 18.3.1 dev: false @@ -8221,7 +8212,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) '@types/react': 18.2.79 '@types/react-dom': 18.2.25 @@ -8242,7 +8233,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.2)(react-dom@18.3.1)(react@18.3.1) '@types/react': 18.3.2 '@types/react-dom': 18.3.0 @@ -8263,7 +8254,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) @@ -8301,7 +8292,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@radix-ui/react-context': 1.0.1(@types/react@18.2.79)(react@18.3.1) @@ -8323,7 +8314,7 @@ packages: react-remove-scroll: 2.5.5(@types/react@18.2.79)(react@18.3.1) dev: false - /@radix-ui/react-popover@1.0.7(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-popover@1.0.7(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-shtvVnlsxT6faMnK/a7n0wptwBD23xc1Z5mdrtKLwVEfsEMXodS0r5s0/g5P0hX//EKYZS2sxUjqfzlg52ZSnQ==} peerDependencies: '@types/react': '*' @@ -8336,29 +8327,29 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-context': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-id': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-slot': 1.0.2(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@types/react': 18.3.4 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-id': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.0.2(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 aria-hidden: 1.2.4 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.5.5(@types/react@18.3.4)(react@18.3.1) + react-remove-scroll: 2.5.5(@types/react@18.3.5)(react@18.3.1) dev: false - /@radix-ui/react-popper@1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-popper@1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg==} peerDependencies: '@types/react': '*' @@ -8371,18 +8362,18 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@floating-ui/react-dom': 2.1.1(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-context': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-use-rect': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-use-size': 1.0.1(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-rect': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-size': 1.0.1(@types/react@18.3.5)(react@18.3.1) '@radix-ui/rect': 1.0.1 - '@types/react': 18.3.4 + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -8401,7 +8392,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@floating-ui/react-dom': 2.1.1(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) @@ -8418,7 +8409,7 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-popper@1.1.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-popper@1.1.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==} peerDependencies: '@types/react': '*' @@ -8431,18 +8422,18 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@floating-ui/react-dom': 2.1.1(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-context': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-use-rect': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-use-size': 1.0.1(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-rect': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-size': 1.0.1(@types/react@18.3.5)(react@18.3.1) '@radix-ui/rect': 1.0.1 - '@types/react': 18.3.4 + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -8481,12 +8472,12 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-primitive': 1.0.0(react-dom@18.3.1)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - /@radix-ui/react-portal@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-portal@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-xLYZeHrWoPmA5mEKEfZZevoVRK/Q43GfzRXkWV6qawIWWK8t6ifIiLQdd7rmQ4Vk1bmI21XhqF9BN3jWf+phpA==} peerDependencies: '@types/react': '*' @@ -8499,9 +8490,9 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -8520,7 +8511,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) '@types/react': 18.2.79 '@types/react-dom': 18.2.25 @@ -8528,7 +8519,7 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-portal@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-portal@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==} peerDependencies: '@types/react': '*' @@ -8541,9 +8532,9 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -8595,7 +8586,7 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.0.0(react@18.3.1) react: 18.3.1 @@ -8614,7 +8605,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@types/react': 18.2.79 @@ -8623,7 +8614,7 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-presence@1.0.1(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-presence@1.0.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} peerDependencies: '@types/react': '*' @@ -8636,10 +8627,10 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -8692,7 +8683,7 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-slot': 1.0.0(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -8710,7 +8701,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-slot': 1.0.2(@types/react@18.2.79)(react@18.3.1) '@types/react': 18.2.79 '@types/react-dom': 18.2.25 @@ -8731,7 +8722,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-slot': 1.0.2(@types/react@18.3.2)(react@18.3.1) '@types/react': 18.3.2 '@types/react-dom': 18.3.0 @@ -8739,7 +8730,7 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} peerDependencies: '@types/react': '*' @@ -8752,9 +8743,9 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@radix-ui/react-slot': 1.0.2(@types/react@18.3.4)(react@18.3.1) - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@radix-ui/react-slot': 1.0.2(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -8831,7 +8822,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-context': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) '@types/react': 18.2.79 @@ -8853,7 +8844,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) @@ -8869,7 +8860,7 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==} peerDependencies: '@types/react': '*' @@ -8882,17 +8873,17 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-context': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-direction': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-id': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@types/react': 18.3.4 + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-direction': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-id': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -8967,7 +8958,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/number': 1.0.1 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) @@ -8996,7 +8987,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/number': 1.0.1 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) @@ -9037,7 +9028,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) '@types/react': 18.2.79 '@types/react-dom': 18.2.25 @@ -9058,7 +9049,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/number': 1.0.1 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) @@ -9081,7 +9072,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) react: 18.3.1 @@ -9094,7 +9085,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@types/react': 18.2.79 react: 18.3.1 @@ -9109,13 +9100,13 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.2)(react@18.3.1) '@types/react': 18.3.2 react: 18.3.1 dev: false - /@radix-ui/react-slot@1.0.2(@types/react@18.3.4)(react@18.3.1): + /@radix-ui/react-slot@1.0.2(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} peerDependencies: '@types/react': '*' @@ -9124,9 +9115,9 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 react: 18.3.1 dev: false @@ -9170,7 +9161,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@radix-ui/react-context': 1.0.1(@types/react@18.2.79)(react@18.3.1) @@ -9269,7 +9260,7 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-toggle-group@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-toggle-group@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==} peerDependencies: '@types/react': '*' @@ -9282,21 +9273,21 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-context': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-direction': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-toggle': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@types/react': 18.3.4 + '@radix-ui/react-context': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-direction': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-toggle': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-toggle@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-toggle@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==} peerDependencies: '@types/react': '*' @@ -9309,17 +9300,17 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@types/react': 18.3.4 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-tooltip@1.0.6(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-tooltip@1.0.6(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-DmNFOiwEc2UDigsYj6clJENma58OelxD24O4IODoZ+3sQc3Zb+L8w1EP+y9laTuKCLAysPw4fD6/v0j4KNV8rg==} peerDependencies: '@types/react': '*' @@ -9332,20 +9323,20 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-context': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-id': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-popper': 1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-portal': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-slot': 1.0.2(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.3.4 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-id': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-popper': 1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-portal': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.0.2(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -9364,7 +9355,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@radix-ui/react-context': 1.0.1(@types/react@18.2.79)(react@18.3.1) @@ -9417,7 +9408,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 react: 18.3.1 /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.79)(react@18.3.1): @@ -9429,12 +9420,12 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@types/react': 18.2.79 react: 18.3.1 dev: false - /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.3.4)(react@18.3.1): + /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} peerDependencies: '@types/react': '*' @@ -9443,8 +9434,8 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@types/react': 18.3.5 react: 18.3.1 dev: false @@ -9478,7 +9469,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1) react: 18.3.1 @@ -9491,13 +9482,13 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@types/react': 18.2.79 react: 18.3.1 dev: false - /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.3.4)(react@18.3.1): + /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} peerDependencies: '@types/react': '*' @@ -9506,9 +9497,9 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 react: 18.3.1 dev: false @@ -9544,7 +9535,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1) react: 18.3.1 @@ -9557,13 +9548,13 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@types/react': 18.2.79 react: 18.3.1 dev: false - /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.3.4)(react@18.3.1): + /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} peerDependencies: '@types/react': '*' @@ -9572,9 +9563,9 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 react: 18.3.1 dev: false @@ -9596,7 +9587,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 react: 18.3.1 /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.79)(react@18.3.1): @@ -9608,12 +9599,12 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@types/react': 18.2.79 react: 18.3.1 dev: false - /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.3.4)(react@18.3.1): + /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} peerDependencies: '@types/react': '*' @@ -9622,8 +9613,8 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@types/react': 18.3.5 react: 18.3.1 dev: false @@ -9661,7 +9652,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@types/react': 18.2.79 react: 18.3.1 dev: false @@ -9675,13 +9666,13 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/rect': 1.0.1 '@types/react': 18.2.79 react: 18.3.1 dev: false - /@radix-ui/react-use-rect@1.0.1(@types/react@18.3.4)(react@18.3.1): + /@radix-ui/react-use-rect@1.0.1(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} peerDependencies: '@types/react': '*' @@ -9690,9 +9681,9 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/rect': 1.0.1 - '@types/react': 18.3.4 + '@types/react': 18.3.5 react: 18.3.1 dev: false @@ -9718,13 +9709,13 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.79)(react@18.3.1) '@types/react': 18.2.79 react: 18.3.1 dev: false - /@radix-ui/react-use-size@1.0.1(@types/react@18.3.4)(react@18.3.1): + /@radix-ui/react-use-size@1.0.1(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} peerDependencies: '@types/react': '*' @@ -9733,9 +9724,9 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.4)(react@18.3.1) - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 react: 18.3.1 dev: false @@ -9765,7 +9756,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) '@types/react': 18.2.79 '@types/react-dom': 18.2.25 @@ -9773,7 +9764,7 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} peerDependencies: '@types/react': '*' @@ -9786,9 +9777,9 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.25.4 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.3.4 + '@babel/runtime': 7.25.6 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -9835,7 +9826,7 @@ packages: /@radix-ui/rect@1.0.1: resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 dev: false /@radix-ui/rect@1.1.0: @@ -9887,7 +9878,7 @@ packages: react: 18.3.1 dev: false - /@react-email/components@0.0.16(@types/react@18.3.4)(react@18.3.1): + /@react-email/components@0.0.16(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-1WATpMSH03cRvhfNjGl/Up3seZJOzN9KLzlk3Q9g/cqNhZEJ7HYxoZM4AQKAI0V3ttXzzxKv8Oj+AZQLHDiICA==} engines: {node: '>=18.0.0'} peerDependencies: @@ -9901,7 +9892,7 @@ packages: '@react-email/container': 0.0.11(react@18.3.1) '@react-email/font': 0.0.5(react@18.3.1) '@react-email/head': 0.0.7(react@18.3.1) - '@react-email/heading': 0.0.11(@types/react@18.3.4)(react@18.3.1) + '@react-email/heading': 0.0.11(@types/react@18.3.5)(react@18.3.1) '@react-email/hr': 0.0.7(react@18.3.1) '@react-email/html': 0.0.7(react@18.3.1) '@react-email/img': 0.0.7(react@18.3.1) @@ -9956,13 +9947,13 @@ packages: - '@types/react' dev: false - /@react-email/heading@0.0.11(@types/react@18.3.4)(react@18.3.1): + /@react-email/heading@0.0.11(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-EF5ZtRCxhHPw3m+8iibKKg0RAvAeHj1AP68sjU7s6+J+kvRgllr/E972Wi5Y8UvcIGossCvpX1WrSMDzeB4puA==} engines: {node: '>=18.0.0'} peerDependencies: react: 18.2.0 dependencies: - '@radix-ui/react-slot': 1.0.2(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-slot': 1.0.2(@types/react@18.3.5)(react@18.3.1) react: 18.3.1 transitivePeerDependencies: - '@types/react' @@ -10220,128 +10211,128 @@ packages: picomatch: 2.3.1 dev: true - /@rollup/rollup-android-arm-eabi@4.21.1: - resolution: {integrity: sha512-2thheikVEuU7ZxFXubPDOtspKn1x0yqaYQwvALVtEcvFhMifPADBrgRPyHV0TF3b+9BgvgjgagVyvA/UqPZHmg==} + /@rollup/rollup-android-arm-eabi@4.21.2: + resolution: {integrity: sha512-fSuPrt0ZO8uXeS+xP3b+yYTCBUd05MoSp2N/MFOgjhhUhMmchXlpTQrTpI8T+YAwAQuK7MafsCOxW7VrPMrJcg==} cpu: [arm] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-android-arm64@4.21.1: - resolution: {integrity: sha512-t1lLYn4V9WgnIFHXy1d2Di/7gyzBWS8G5pQSXdZqfrdCGTwi1VasRMSS81DTYb+avDs/Zz4A6dzERki5oRYz1g==} + /@rollup/rollup-android-arm64@4.21.2: + resolution: {integrity: sha512-xGU5ZQmPlsjQS6tzTTGwMsnKUtu0WVbl0hYpTPauvbRAnmIvpInhJtgjj3mcuJpEiuUw4v1s4BimkdfDWlh7gA==} cpu: [arm64] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-arm64@4.21.1: - resolution: {integrity: sha512-AH/wNWSEEHvs6t4iJ3RANxW5ZCK3fUnmf0gyMxWCesY1AlUj8jY7GC+rQE4wd3gwmZ9XDOpL0kcFnCjtN7FXlA==} + /@rollup/rollup-darwin-arm64@4.21.2: + resolution: {integrity: sha512-99AhQ3/ZMxU7jw34Sq8brzXqWH/bMnf7ZVhvLk9QU2cOepbQSVTns6qoErJmSiAvU3InRqC2RRZ5ovh1KN0d0Q==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-x64@4.21.1: - resolution: {integrity: sha512-dO0BIz/+5ZdkLZrVgQrDdW7m2RkrLwYTh2YMFG9IpBtlC1x1NPNSXkfczhZieOlOLEqgXOFH3wYHB7PmBtf+Bg==} + /@rollup/rollup-darwin-x64@4.21.2: + resolution: {integrity: sha512-ZbRaUvw2iN/y37x6dY50D8m2BnDbBjlnMPotDi/qITMJ4sIxNY33HArjikDyakhSv0+ybdUxhWxE6kTI4oX26w==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.21.1: - resolution: {integrity: sha512-sWWgdQ1fq+XKrlda8PsMCfut8caFwZBmhYeoehJ05FdI0YZXk6ZyUjWLrIgbR/VgiGycrFKMMgp7eJ69HOF2pQ==} + /@rollup/rollup-linux-arm-gnueabihf@4.21.2: + resolution: {integrity: sha512-ztRJJMiE8nnU1YFcdbd9BcH6bGWG1z+jP+IPW2oDUAPxPjo9dverIOyXz76m6IPA6udEL12reYeLojzW2cYL7w==} cpu: [arm] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm-musleabihf@4.21.1: - resolution: {integrity: sha512-9OIiSuj5EsYQlmwhmFRA0LRO0dRRjdCVZA3hnmZe1rEwRk11Jy3ECGGq3a7RrVEZ0/pCsYWx8jG3IvcrJ6RCew==} + /@rollup/rollup-linux-arm-musleabihf@4.21.2: + resolution: {integrity: sha512-flOcGHDZajGKYpLV0JNc0VFH361M7rnV1ee+NTeC/BQQ1/0pllYcFmxpagltANYt8FYf9+kL6RSk80Ziwyhr7w==} cpu: [arm] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-gnu@4.21.1: - resolution: {integrity: sha512-0kuAkRK4MeIUbzQYu63NrJmfoUVicajoRAL1bpwdYIYRcs57iyIV9NLcuyDyDXE2GiZCL4uhKSYAnyWpjZkWow==} + /@rollup/rollup-linux-arm64-gnu@4.21.2: + resolution: {integrity: sha512-69CF19Kp3TdMopyteO/LJbWufOzqqXzkrv4L2sP8kfMaAQ6iwky7NoXTp7bD6/irKgknDKM0P9E/1l5XxVQAhw==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-musl@4.21.1: - resolution: {integrity: sha512-/6dYC9fZtfEY0vozpc5bx1RP4VrtEOhNQGb0HwvYNwXD1BBbwQ5cKIbUVVU7G2d5WRE90NfB922elN8ASXAJEA==} + /@rollup/rollup-linux-arm64-musl@4.21.2: + resolution: {integrity: sha512-48pD/fJkTiHAZTnZwR0VzHrao70/4MlzJrq0ZsILjLW/Ab/1XlVUStYyGt7tdyIiVSlGZbnliqmult/QGA2O2w==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-powerpc64le-gnu@4.21.1: - resolution: {integrity: sha512-ltUWy+sHeAh3YZ91NUsV4Xg3uBXAlscQe8ZOXRCVAKLsivGuJsrkawYPUEyCV3DYa9urgJugMLn8Z3Z/6CeyRQ==} + /@rollup/rollup-linux-powerpc64le-gnu@4.21.2: + resolution: {integrity: sha512-cZdyuInj0ofc7mAQpKcPR2a2iu4YM4FQfuUzCVA2u4HI95lCwzjoPtdWjdpDKyHxI0UO82bLDoOaLfpZ/wviyQ==} cpu: [ppc64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-riscv64-gnu@4.21.1: - resolution: {integrity: sha512-BggMndzI7Tlv4/abrgLwa/dxNEMn2gC61DCLrTzw8LkpSKel4o+O+gtjbnkevZ18SKkeN3ihRGPuBxjaetWzWg==} + /@rollup/rollup-linux-riscv64-gnu@4.21.2: + resolution: {integrity: sha512-RL56JMT6NwQ0lXIQmMIWr1SW28z4E4pOhRRNqwWZeXpRlykRIlEpSWdsgNWJbYBEWD84eocjSGDu/XxbYeCmwg==} cpu: [riscv64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-s390x-gnu@4.21.1: - resolution: {integrity: sha512-z/9rtlGd/OMv+gb1mNSjElasMf9yXusAxnRDrBaYB+eS1shFm6/4/xDH1SAISO5729fFKUkJ88TkGPRUh8WSAA==} + /@rollup/rollup-linux-s390x-gnu@4.21.2: + resolution: {integrity: sha512-PMxkrWS9z38bCr3rWvDFVGD6sFeZJw4iQlhrup7ReGmfn7Oukrr/zweLhYX6v2/8J6Cep9IEA/SmjXjCmSbrMQ==} cpu: [s390x] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-gnu@4.21.1: - resolution: {integrity: sha512-kXQVcWqDcDKw0S2E0TmhlTLlUgAmMVqPrJZR+KpH/1ZaZhLSl23GZpQVmawBQGVhyP5WXIsIQ/zqbDBBYmxm5w==} + /@rollup/rollup-linux-x64-gnu@4.21.2: + resolution: {integrity: sha512-B90tYAUoLhU22olrafY3JQCFLnT3NglazdwkHyxNDYF/zAxJt5fJUB/yBoWFoIQ7SQj+KLe3iL4BhOMa9fzgpw==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-musl@4.21.1: - resolution: {integrity: sha512-CbFv/WMQsSdl+bpX6rVbzR4kAjSSBuDgCqb1l4J68UYsQNalz5wOqLGYj4ZI0thGpyX5kc+LLZ9CL+kpqDovZA==} + /@rollup/rollup-linux-x64-musl@4.21.2: + resolution: {integrity: sha512-7twFizNXudESmC9oneLGIUmoHiiLppz/Xs5uJQ4ShvE6234K0VB1/aJYU3f/4g7PhssLGKBVCC37uRkkOi8wjg==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-arm64-msvc@4.21.1: - resolution: {integrity: sha512-3Q3brDgA86gHXWHklrwdREKIrIbxC0ZgU8lwpj0eEKGBQH+31uPqr0P2v11pn0tSIxHvcdOWxa4j+YvLNx1i6g==} + /@rollup/rollup-win32-arm64-msvc@4.21.2: + resolution: {integrity: sha512-9rRero0E7qTeYf6+rFh3AErTNU1VCQg2mn7CQcI44vNUWM9Ze7MSRS/9RFuSsox+vstRt97+x3sOhEey024FRQ==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-ia32-msvc@4.21.1: - resolution: {integrity: sha512-tNg+jJcKR3Uwe4L0/wY3Ro0H+u3nrb04+tcq1GSYzBEmKLeOQF2emk1whxlzNqb6MMrQ2JOcQEpuuiPLyRcSIw==} + /@rollup/rollup-win32-ia32-msvc@4.21.2: + resolution: {integrity: sha512-5rA4vjlqgrpbFVVHX3qkrCo/fZTj1q0Xxpg+Z7yIo3J2AilW7t2+n6Q8Jrx+4MrYpAnjttTYF8rr7bP46BPzRw==} cpu: [ia32] os: [win32] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-x64-msvc@4.21.1: - resolution: {integrity: sha512-xGiIH95H1zU7naUyTKEyOA/I0aexNMUdO9qRv0bLKN3qu25bBdrxZHqA3PTJ24YNN/GdMzG4xkDcd/GvjuhfLg==} + /@rollup/rollup-win32-x64-msvc@4.21.2: + resolution: {integrity: sha512-6UUxd0+SKomjdzuAcp+HAmxw1FlGBnl1v2yEPSabtx4lBfdXHDVsW7+lQkgz9cNFJGY3AWR7+V8P5BqkD9L9nA==} cpu: [x64] os: [win32] requiresBuild: true @@ -10365,27 +10356,32 @@ packages: '@types/hast': 3.0.4 dev: false - /@shikijs/core@1.14.1: - resolution: {integrity: sha512-KyHIIpKNaT20FtFPFjCQB5WVSTpLR/n+jQXhWHWVUMm9MaOaG9BGOG0MSyt7yA4+Lm+4c9rTc03tt3nYzeYSfw==} + /@shikijs/core@1.16.1: + resolution: {integrity: sha512-aI0hBtw+a6KsJp2jcD4YuQqKpeCbURMZbhHVozDknJpm+KJqeMRkEnfBC8BaKE/5XC+uofPgCLsa/TkTk0Ba0w==} dependencies: + '@shikijs/vscode-textmate': 9.2.0 '@types/hast': 3.0.4 dev: false - /@shikijs/rehype@1.14.1: - resolution: {integrity: sha512-52L8RZ8eJ4t7jWk5jAl5fh5whAmseL5TJezZuWogC6GH5X0JZhWxPxk2+Dg3tH/Ga3447HdzAzEVGkJmXX3o3A==} + /@shikijs/rehype@1.16.1: + resolution: {integrity: sha512-6GM4yvvs4iz9JYaKWww/02tkOK3nBkmK1j2IcRd8y4/LKnDrv2Nm/TeNohYkZG8CjX8UQfLlBQB5nCXD2OMSgg==} dependencies: - '@shikijs/transformers': 1.14.1 + '@shikijs/transformers': 1.16.1 '@types/hast': 3.0.4 hast-util-to-string: 3.0.0 - shiki: 1.14.1 + shiki: 1.16.1 unified: 11.0.5 unist-util-visit: 5.0.0 dev: false - /@shikijs/transformers@1.14.1: - resolution: {integrity: sha512-JJqL8QBVCJh3L61jqqEXgFq1cTycwjcGj7aSmqOEsbxnETM9hRlaB74QuXvY/fVJNjbNt8nvWo0VwAXKvMSLRg==} + /@shikijs/transformers@1.16.1: + resolution: {integrity: sha512-mfbe4YMov+1eyIBU3F6BtaPmLgDkRQaVse8xsBlKTVAcNF3cbZMRCyUz2N6gJOMKLJiv9T5gapBPbRxrDMuoxA==} dependencies: - shiki: 1.14.1 + shiki: 1.16.1 + dev: false + + /@shikijs/vscode-textmate@9.2.0: + resolution: {integrity: sha512-5FinaOp6Vdh/dl4/yaOTh0ZeKch+rYS8DUb38V3GMKYVkdqzxw53lViRKUYkVILRiVQT7dcPC7VvAKOR73zVtQ==} dev: false /@shuding/opentype.js@1.4.0-beta.0: @@ -10433,8 +10429,8 @@ packages: '@types/node': 20.14.9 dev: false - /@slack/types@2.12.0: - resolution: {integrity: sha512-yFewzUomYZ2BYaGJidPuIgjoYj5wqPDmi7DLSaGIkf+rCi4YZ2Z3DaiYIbz7qb/PL2NmamWjCvB7e9ArI5HkKg==} + /@slack/types@2.13.0: + resolution: {integrity: sha512-OAQVtKYIgBVNRmgIoiTjorGPTlgfcfstU3XYYCBA+czlB9aGcKb9MQc+6Jovi4gq3S98yP/GPBZsJSI/2mHKDQ==} engines: {node: '>= 12.13.0', npm: '>= 6.12.0'} dev: false @@ -10443,10 +10439,10 @@ packages: engines: {node: '>= 12.13.0', npm: '>= 6.12.0'} dependencies: '@slack/logger': 3.0.0 - '@slack/types': 2.12.0 + '@slack/types': 2.13.0 '@types/is-stream': 1.1.0 '@types/node': 20.14.9 - axios: 1.7.5 + axios: 1.7.7 eventemitter3: 3.1.2 form-data: 2.5.1 is-electron: 2.2.2 @@ -10809,7 +10805,7 @@ packages: get-caller-file: 2.0.5 git-remote-origin-url: 4.0.0 git-repo-info: 2.1.1 - msw: 2.3.5(typescript@5.5.3) + msw: 2.4.1(typescript@5.5.3) slug: 6.1.0 terminal-link: 3.0.0 ulid: 2.3.0 @@ -10818,6 +10814,7 @@ packages: zod: 3.22.3 transitivePeerDependencies: - bufferutil + - graphql - supports-color - typescript - utf-8-validate @@ -10847,6 +10844,7 @@ packages: transitivePeerDependencies: - bufferutil - debug + - graphql - supports-color - typescript - utf-8-validate @@ -11213,7 +11211,7 @@ packages: /@types/fslightbox-react@1.7.7: resolution: {integrity: sha512-pp9Y7/+L4NFlMp+PdESx66EG0/m70aqg81FNlLP08dGWvRRSvNJFv08Jc91IEQkbh/C1PpokCekNCWZqpWxiyQ==} dependencies: - '@types/react': 18.3.4 + '@types/react': 18.3.5 dev: true /@types/geojson@7946.0.14: @@ -11330,8 +11328,8 @@ packages: resolution: {integrity: sha512-vmYJF0REqDyyU0gviezF/KHq/fYaUbFhkcNbQCuPGFQj6VTbXuHZoxs/Y7mutWe73C8AC6l9fFu8mSYiBAqkGA==} dev: false - /@types/node@18.19.47: - resolution: {integrity: sha512-1f7dB3BL/bpd9tnDJrrHb66Y+cVrhxSOTGorRNdHwYTUlTay3HuTDPKo9a/4vX9pMQkhYBcAbL4jQdNlhCFP9A==} + /@types/node@18.19.48: + resolution: {integrity: sha512-7WevbG4ekUcRQSZzOwxWgi5dZmTak7FaxXDoW7xVxPBmKx1rTzfmRLkeCgJzcbBnOV2dkhAPc8cCeT6agocpjg==} dependencies: undici-types: 5.26.5 dev: false @@ -11341,8 +11339,8 @@ packages: dependencies: undici-types: 5.26.5 - /@types/node@22.5.1: - resolution: {integrity: sha512-KkHsxej0j9IW1KKOOAA/XBA0z08UFSrRQHErzEfA3Vgq57eXIMYboIlHJuYIfd+lwCQjtKqUu3UnmKbtUc9yRw==} + /@types/node@22.5.2: + resolution: {integrity: sha512-acJsPTEqYqulZS/Yp/S3GgeE6GZ0qYODUR8aVr/DkhHQ8l9nd4j5x1/ZJy9/gHrRlFMqkO6i0I3E27Alu4jjPg==} dependencies: undici-types: 6.19.8 @@ -11371,7 +11369,7 @@ packages: /@types/react-dom@18.2.25: resolution: {integrity: sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==} dependencies: - '@types/react': 18.3.4 + '@types/react': 18.3.5 /@types/react-dom@18.3.0: resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} @@ -11381,7 +11379,7 @@ packages: /@types/react-syntax-highlighter@15.5.13: resolution: {integrity: sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==} dependencies: - '@types/react': 18.3.4 + '@types/react': 18.3.5 dev: true /@types/react@18.2.79: @@ -11396,8 +11394,8 @@ packages: '@types/prop-types': 15.7.12 csstype: 3.1.3 - /@types/react@18.3.4: - resolution: {integrity: sha512-J7W30FTdfCxDDjmfRM+/JqLHBIyl7xUIp9kwK637FGmY7+mkSFSe6L4jpZzhj5QMfLssSDP4/i75AKkrdC7/Jw==} + /@types/react@18.3.5: + resolution: {integrity: sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==} dependencies: '@types/prop-types': 15.7.12 csstype: 3.1.3 @@ -11570,7 +11568,7 @@ packages: peerDependencies: react: ^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0 dependencies: - '@types/react': 18.3.4 + '@types/react': 18.3.5 '@visx/group': 3.3.0(react@18.3.1) '@visx/point': 3.3.0 '@visx/scale': 3.5.0 @@ -11587,7 +11585,7 @@ packages: react: ^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0 react-dom: ^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0 dependencies: - '@types/react': 18.3.4 + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 prop-types: 15.8.1 react: 18.3.1 @@ -11604,7 +11602,7 @@ packages: /@visx/event@3.3.0: resolution: {integrity: sha512-fKalbNgNz2ooVOTXhvcOx5IlEQDgVfX66rI7bgZhBxI2/scy+5rWcXJXpwkheRF68SMx9R93SjKW6tmiD0h+jA==} dependencies: - '@types/react': 18.3.4 + '@types/react': 18.3.5 '@visx/point': 3.3.0 dev: false @@ -11613,7 +11611,7 @@ packages: peerDependencies: react: ^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0 dependencies: - '@types/react': 18.3.4 + '@types/react': 18.3.5 prop-types: 15.8.1 react: 18.3.1 dev: false @@ -11623,7 +11621,7 @@ packages: peerDependencies: react: ^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0 dependencies: - '@types/react': 18.3.4 + '@types/react': 18.3.5 classnames: 2.5.1 prop-types: 15.8.1 react: 18.3.1 @@ -11639,7 +11637,7 @@ packages: react: ^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0 dependencies: '@types/lodash': 4.17.7 - '@types/react': 18.3.4 + '@types/react': 18.3.5 lodash: 4.17.21 prop-types: 15.8.1 react: 18.3.1 @@ -11659,7 +11657,7 @@ packages: '@types/d3-path': 1.0.11 '@types/d3-shape': 1.3.12 '@types/lodash': 4.17.7 - '@types/react': 18.3.4 + '@types/react': 18.3.5 '@visx/curve': 3.3.0 '@visx/group': 3.3.0(react@18.3.1) '@visx/scale': 3.5.0 @@ -11677,7 +11675,7 @@ packages: react: ^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0 dependencies: '@types/lodash': 4.17.7 - '@types/react': 18.3.4 + '@types/react': 18.3.5 classnames: 2.5.1 lodash: 4.17.21 prop-types: 15.8.1 @@ -11691,7 +11689,7 @@ packages: react: ^16.8.0-0 || ^17.0.0-0 || ^18.0.0-0 react-dom: ^16.8.0-0 || ^17.0.0-0 || ^18.0.0-0 dependencies: - '@types/react': 18.3.4 + '@types/react': 18.3.5 '@visx/bounds': 3.3.0(react-dom@18.3.1)(react@18.3.1) classnames: 2.5.1 prop-types: 15.8.1 @@ -11884,7 +11882,7 @@ packages: /@vue/compiler-core@3.4.38: resolution: {integrity: sha512-8IQOTCWnLFqfHzOGm9+P8OPSEDukgg3Huc92qSG49if/xI2SAwLHQO2qaPQbjCWPBcQoO1WYfXfTACUrWV3c5A==} dependencies: - '@babel/parser': 7.25.4 + '@babel/parser': 7.25.6 '@vue/shared': 3.4.38 entities: 4.5.0 estree-walker: 2.0.2 @@ -11901,14 +11899,14 @@ packages: /@vue/compiler-sfc@3.4.38: resolution: {integrity: sha512-s5QfZ+9PzPh3T5H4hsQDJtI8x7zdJaew/dCGgqZ2630XdzaZ3AD8xGZfBqpT8oaD/p2eedd+pL8tD5vvt5ZYJQ==} dependencies: - '@babel/parser': 7.25.4 + '@babel/parser': 7.25.6 '@vue/compiler-core': 3.4.38 '@vue/compiler-dom': 3.4.38 '@vue/compiler-ssr': 3.4.38 '@vue/shared': 3.4.38 estree-walker: 2.0.2 magic-string: 0.30.11 - postcss: 8.4.41 + postcss: 8.4.44 source-map-js: 1.2.0 dev: false @@ -12357,6 +12355,11 @@ packages: resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==} dev: true + /ansis@3.3.2: + resolution: {integrity: sha512-cFthbBlt+Oi0i9Pv/j6YdVWJh54CtjGACaMPCIrEV4Ha7HWsIjXDwseYV79TIL0B4+KfSwD5S70PeQDkPUd1rA==} + engines: {node: '>=15'} + dev: true + /any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -12489,11 +12492,6 @@ packages: tslib: 2.7.0 dev: true - /astral-regex@2.0.0: - resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} - engines: {node: '>=8'} - dev: true - /astring@1.9.0: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true @@ -12533,7 +12531,7 @@ packages: postcss: ^8.1.0 dependencies: browserslist: 4.23.3 - caniuse-lite: 1.0.30001653 + caniuse-lite: 1.0.30001655 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.0.1 @@ -12549,7 +12547,7 @@ packages: postcss: ^8.1.0 dependencies: browserslist: 4.23.3 - caniuse-lite: 1.0.30001653 + caniuse-lite: 1.0.30001655 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.0.1 @@ -12562,12 +12560,12 @@ packages: dependencies: possible-typed-array-names: 1.0.0 - /aws-ssl-profiles@1.1.1: - resolution: {integrity: sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ==} + /aws-ssl-profiles@1.1.2: + resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} engines: {node: '>= 6.0.0'} - /axios@1.6.2: - resolution: {integrity: sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==} + /axios@1.7.4: + resolution: {integrity: sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==} dependencies: follow-redirects: 1.15.6 form-data: 4.0.0 @@ -12576,8 +12574,8 @@ packages: - debug dev: true - /axios@1.7.5: - resolution: {integrity: sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==} + /axios@1.7.7: + resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} dependencies: follow-redirects: 1.15.6 form-data: 4.0.0 @@ -12594,7 +12592,7 @@ packages: resolution: {integrity: sha512-fdRxJkQ9MUSEi4jH2DcV3FAPFktk0wefilxrwNyUuWpoWawQGN7G7cB+fOYTtFfI6XNkFgwqJ/D3G18BoJJ/jg==} engines: {node: '>= 10.0.0'} dependencies: - '@babel/types': 7.25.4 + '@babel/types': 7.25.6 dev: false /babylon@6.18.0: @@ -12717,7 +12715,7 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001653 + caniuse-lite: 1.0.30001655 electron-to-chromium: 1.5.13 node-releases: 2.0.18 update-browserslist-db: 1.1.0(browserslist@4.23.3) @@ -12849,8 +12847,8 @@ packages: resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} dev: false - /caniuse-lite@1.0.30001653: - resolution: {integrity: sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==} + /caniuse-lite@1.0.30001655: + resolution: {integrity: sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg==} /capnp-ts@0.7.0: resolution: {integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==} @@ -12957,21 +12955,21 @@ packages: get-func-name: 2.0.2 dev: true - /checkly@4.7.0(@types/node@20.14.9)(typescript@5.5.3): - resolution: {integrity: sha512-OVEn7iUrtTs/YrxmNcWo7jQkH+e5LS0/KhF+MmIi8DbrCc8sCBppO1JyEnjoKcslCkV/Rilad66LShI6V/cqvQ==} + /checkly@4.8.1(@types/node@20.14.9)(typescript@5.5.3): + resolution: {integrity: sha512-LyVxHVOqjZ6k/QXGZQhZgnG7stL5mYfzu+Vl5hkdh2ZKDm/MLk4Q+gRKAyMLOjMN66jrJN1ZM1K3zlLt2/EJcg==} engines: {node: '>=16.0.0'} hasBin: true dependencies: '@oclif/core': 2.8.11(@types/node@20.14.9)(typescript@5.5.3) '@oclif/plugin-help': 5.1.20 '@oclif/plugin-not-found': 2.3.23(@types/node@20.14.9)(typescript@5.5.3) - '@oclif/plugin-plugins': 4.1.12 + '@oclif/plugin-plugins': 5.4.4 '@oclif/plugin-warn-if-update-available': 2.0.24(@types/node@20.14.9)(typescript@5.5.3) '@typescript-eslint/typescript-estree': 6.19.0(typescript@5.5.3) acorn: 8.8.1 acorn-walk: 8.2.0 async-mqtt: 2.6.3 - axios: 1.6.2 + axios: 1.7.4 chalk: 4.1.2 ci-info: 3.8.0 conf: 10.2.0 @@ -15048,8 +15046,8 @@ packages: '@esbuild/win32-x64': 0.21.5 dev: true - /escalade@3.1.2: - resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + /escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} /escape-html@1.0.3: @@ -15913,8 +15911,8 @@ packages: react-dom: '>= 18' dependencies: '@formatjs/intl-localematcher': 0.5.4 - '@shikijs/rehype': 1.14.1 - '@shikijs/transformers': 1.14.1 + '@shikijs/rehype': 1.16.1 + '@shikijs/transformers': 1.16.1 flexsearch: 0.7.21 github-slugger: 2.0.0 negotiator: 0.6.3 @@ -16051,8 +16049,8 @@ packages: es-errors: 1.3.0 get-intrinsic: 1.2.4 - /get-tsconfig@4.7.6: - resolution: {integrity: sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==} + /get-tsconfig@4.8.0: + resolution: {integrity: sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw==} dependencies: resolve-pkg-maps: 1.0.0 dev: true @@ -16557,7 +16555,7 @@ packages: mdast-util-mdxjs-esm: 2.0.1 property-information: 6.5.0 space-separated-tokens: 2.0.2 - style-to-object: 1.0.6 + style-to-object: 1.0.7 unist-util-position: 5.0.0 vfile-message: 4.0.2 transitivePeerDependencies: @@ -16699,6 +16697,13 @@ packages: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} dev: true + /hosted-git-info@7.0.2: + resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} + engines: {node: ^16.14.0 || >=18.0.0} + dependencies: + lru-cache: 10.4.3 + dev: true + /html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} dev: false @@ -16960,6 +16965,7 @@ packages: /interpret@1.4.0: resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} engines: {node: '>= 0.10'} + dev: false /invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} @@ -17351,6 +17357,11 @@ packages: /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + /isexe@3.1.1: + resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} + engines: {node: '>=16'} + dev: true + /isomorphic-fetch@3.0.0: resolution: {integrity: sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==} dependencies: @@ -18434,7 +18445,7 @@ packages: peerDependencies: esbuild: 0.* dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@esbuild-plugins/node-resolve': 0.2.2(esbuild@0.19.12) '@fal-works/esbuild-plugin-global-externals': 2.1.2 '@mdx-js/esbuild': 3.0.1(esbuild@0.19.12) @@ -19502,19 +19513,22 @@ packages: outvariant: 1.4.3 path-to-regexp: 6.2.2 strict-event-emitter: 0.5.1 - type-fest: 4.25.0 + type-fest: 4.26.0 typescript: 5.5.3 yargs: 17.7.2 dev: true - /msw@2.3.5(typescript@5.5.3): - resolution: {integrity: sha512-+GUI4gX5YC5Bv33epBrD+BGdmDvBg2XGruiWnI3GbIbRmMMBeZ5gs3mJ51OWSGHgJKztZ8AtZeYMMNMVrje2/Q==} + /msw@2.4.1(typescript@5.5.3): + resolution: {integrity: sha512-HXcoQPzYTwEmVk+BGIcRa0vLabBT+J20SSSeYh/QfajaK5ceA6dlD4ZZjfz2dqGEq4vRNCPLP6eXsB94KllPFg==} engines: {node: '>=18'} hasBin: true requiresBuild: true peerDependencies: + graphql: '>= 16.8.x' typescript: '>= 4.7.x' peerDependenciesMeta: + graphql: + optional: true typescript: optional: true dependencies: @@ -19527,13 +19541,12 @@ packages: '@types/cookie': 0.6.0 '@types/statuses': 2.0.5 chalk: 4.1.2 - graphql: 16.9.0 headers-polyfill: 4.0.3 is-node-process: 1.2.0 outvariant: 1.4.3 path-to-regexp: 6.2.2 strict-event-emitter: 0.5.1 - type-fest: 4.25.0 + type-fest: 4.26.0 typescript: 5.5.3 yargs: 17.7.2 dev: false @@ -19555,7 +19568,7 @@ packages: resolution: {integrity: sha512-k43gmH9i79rZD4hGPdj7pDuT0UBiFjs4UzXEy1cJrV0QqcSABomoLwvejqdbcXN+Vd7gi999CVM6o9vCPKq29g==} engines: {node: '>= 8.0'} dependencies: - aws-ssl-profiles: 1.1.1 + aws-ssl-profiles: 1.1.2 denque: 2.1.0 generate-function: 2.3.1 iconv-lite: 0.6.3 @@ -19655,7 +19668,7 @@ packages: '@next/env': 14.1.0 '@swc/helpers': 0.5.2 busboy: 1.6.0 - caniuse-lite: 1.0.30001653 + caniuse-lite: 1.0.30001655 graceful-fs: 4.2.11 postcss: 8.4.31 react: 18.3.1 @@ -19695,7 +19708,7 @@ packages: '@opentelemetry/api': 1.4.1 '@swc/helpers': 0.5.2 busboy: 1.6.0 - caniuse-lite: 1.0.30001653 + caniuse-lite: 1.0.30001655 graceful-fs: 4.2.11 postcss: 8.4.31 react: 18.3.1 @@ -19736,7 +19749,7 @@ packages: '@next/env': 14.2.3 '@swc/helpers': 0.5.5 busboy: 1.6.0 - caniuse-lite: 1.0.30001653 + caniuse-lite: 1.0.30001655 graceful-fs: 4.2.11 postcss: 8.4.31 react: 18.3.1 @@ -19779,7 +19792,7 @@ packages: '@opentelemetry/api': 1.4.1 '@swc/helpers': 0.5.5 busboy: 1.6.0 - caniuse-lite: 1.0.30001653 + caniuse-lite: 1.0.30001655 graceful-fs: 4.2.11 postcss: 8.4.31 react: 18.3.1 @@ -19912,6 +19925,16 @@ packages: engines: {node: '>=14.16'} dev: true + /npm-package-arg@11.0.3: + resolution: {integrity: sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==} + engines: {node: ^16.14.0 || >=18.0.0} + dependencies: + hosted-git-info: 7.0.2 + proc-log: 4.2.0 + semver: 7.6.3 + validate-npm-package-name: 5.0.1 + dev: true + /npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} @@ -19930,8 +19953,8 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: false - /npm@10.2.3: - resolution: {integrity: sha512-GbUui/rHTl0mW8HhJSn4A0Xg89yCR3I9otgJT1i0z1QBPOVlgbh6rlcUTpHT8Gut9O1SJjWRUU0nEcAymhG2tQ==} + /npm@10.8.3: + resolution: {integrity: sha512-0IQlyAYvVtQ7uOhDFYZCGK8kkut2nh8cpAdA9E6FvRSJaTgtZRZgNjlC5ZCct//L73ygrpY93CxXpRJDtNqPVg==} engines: {node: ^18.17.0 || >=20.5.0} hasBin: true dev: true @@ -19943,6 +19966,7 @@ packages: - '@npmcli/map-workspaces' - '@npmcli/package-json' - '@npmcli/promise-spawn' + - '@npmcli/redact' - '@npmcli/run-script' - '@sigstore/tuf' - abbrev @@ -19951,8 +19975,6 @@ packages: - chalk - ci-info - cli-columns - - cli-table3 - - columnify - fastest-levenshtein - fs-minipass - glob @@ -19988,7 +20010,6 @@ packages: - npm-profile - npm-registry-fetch - npm-user-validate - - npmlog - p-map - pacote - parse-conflict-json @@ -19998,7 +20019,6 @@ packages: - semver - spdx-expression-parse - ssri - - strip-ansi - supports-color - tar - text-table @@ -20074,6 +20094,11 @@ packages: engines: {node: '>= 10'} dev: true + /object-treeify@4.0.1: + resolution: {integrity: sha512-Y6tg5rHfsefSkfKujv2SwHulInROy/rCL5F4w0QOWxut8AnxYxf0YmNhTh95Zfyxpsudo66uqkux0ACFnyMSgQ==} + engines: {node: '>= 16'} + dev: true + /object-values@1.0.0: resolution: {integrity: sha512-+8hwcz/JnQ9EpLIXzN0Rs7DLsBpJNT/xYehtB/jU93tHYr5BFEO8E+JGQNOSqE7opVzz5cGksKFHt7uUJVLSjQ==} engines: {node: '>=0.10.0'} @@ -20142,7 +20167,7 @@ packages: resolution: {integrity: sha512-kv2hevAWZZ3I/vd2t8znGO2rd8wkowncsfcYpo8i+wU9ML+JEcdqiViANXXjWWGjIhajFNixE6gOY1fEgqILAg==} hasBin: true dependencies: - '@types/node': 18.19.47 + '@types/node': 18.19.48 '@types/node-fetch': 2.6.11 abort-controller: 3.0.0 agentkeepalive: 4.5.0 @@ -20709,8 +20734,8 @@ packages: picocolors: 1.0.1 source-map-js: 1.2.0 - /postcss@8.4.41: - resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==} + /postcss@8.4.44: + resolution: {integrity: sha512-Aweb9unOEpQ3ezu4Q00DPvvM2ZTUitJdNKeP/+uQgr1IBIqu574IaZoURId7BKtWMREwzKa9OgzPzezWGPWFQw==} engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.7 @@ -20728,7 +20753,7 @@ packages: resolution: {integrity: sha512-JB+ei0LkwE+rKHyW5z79Nd1jUaGxU6TvkfjFqY9vQaHxU5aU8dRl0UUaEmZdZbHwjp3WmXCBQQRNyimwbNQfCw==} engines: {node: '>=15.0.0'} dependencies: - axios: 1.7.5 + axios: 1.7.7 rusha: 0.8.14 transitivePeerDependencies: - debug @@ -20819,12 +20844,17 @@ packages: /probe.gl@3.6.0: resolution: {integrity: sha512-19JydJWI7+DtR4feV+pu4Mn1I5TAc0xojuxVgZdXIyfmTLfUaFnk4OloWK1bKbPtkgGKLr2lnbnCXmpZEcEp9g==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 '@probe.gl/env': 3.6.0 '@probe.gl/log': 3.6.0 '@probe.gl/stats': 3.6.0 dev: false + /proc-log@4.2.0: + resolution: {integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: true + /process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} dev: true @@ -21038,10 +21068,10 @@ packages: peerDependencies: react: '>=16' dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 react: 18.3.1 react-syntax-highlighter: 15.5.0(react@18.3.1) - styled-components: 6.1.12(react-dom@18.3.1)(react@18.3.1) + styled-components: 6.1.13(react-dom@18.3.1)(react@18.3.1) tslib: 2.7.0 transitivePeerDependencies: - react-dom @@ -21105,15 +21135,15 @@ packages: dependencies: '@babel/parser': 7.24.1 '@radix-ui/colors': 1.0.1 - '@radix-ui/react-collapsible': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-popover': 1.0.7(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-slot': 1.0.2(@types/react@18.3.4)(react@18.3.1) - '@radix-ui/react-toggle-group': 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-tooltip': 1.0.6(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1) - '@react-email/components': 0.0.16(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-collapsible': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-popover': 1.0.7(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.0.2(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-toggle-group': 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-tooltip': 1.0.6(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@react-email/components': 0.0.16(@types/react@18.3.5)(react@18.3.1) '@react-email/render': 0.0.12 '@swc/core': 1.3.101 - '@types/react': 18.3.4 + '@types/react': 18.3.5 '@types/react-dom': 18.3.0 '@types/webpack': 5.28.5(@swc/core@1.3.101)(esbuild@0.19.11) autoprefixer: 10.4.14(postcss@8.4.35) @@ -21236,7 +21266,7 @@ packages: tslib: 2.7.0 dev: false - /react-remove-scroll-bar@2.3.6(@types/react@18.3.4)(react@18.3.1): + /react-remove-scroll-bar@2.3.6(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} engines: {node: '>=10'} peerDependencies: @@ -21246,9 +21276,9 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.4 + '@types/react': 18.3.5 react: 18.3.1 - react-style-singleton: 2.2.1(@types/react@18.3.4)(react@18.3.1) + react-style-singleton: 2.2.1(@types/react@18.3.5)(react@18.3.1) tslib: 2.7.0 /react-remove-scroll@2.5.10(@types/react@18.2.79)(react@18.3.1): @@ -21300,11 +21330,11 @@ packages: optional: true dependencies: react: 18.3.1 - react-remove-scroll-bar: 2.3.6(@types/react@18.3.4)(react@18.3.1) - react-style-singleton: 2.2.1(@types/react@18.3.4)(react@18.3.1) + react-remove-scroll-bar: 2.3.6(@types/react@18.3.5)(react@18.3.1) + react-style-singleton: 2.2.1(@types/react@18.3.5)(react@18.3.1) tslib: 2.7.0 - use-callback-ref: 1.3.2(@types/react@18.3.4)(react@18.3.1) - use-sidecar: 1.1.2(@types/react@18.3.4)(react@18.3.1) + use-callback-ref: 1.3.2(@types/react@18.3.5)(react@18.3.1) + use-sidecar: 1.1.2(@types/react@18.3.5)(react@18.3.1) dev: true /react-remove-scroll@2.5.5(@types/react@18.2.79)(react@18.3.1): @@ -21326,7 +21356,7 @@ packages: use-sidecar: 1.1.2(@types/react@18.2.79)(react@18.3.1) dev: false - /react-remove-scroll@2.5.5(@types/react@18.3.4)(react@18.3.1): + /react-remove-scroll@2.5.5(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==} engines: {node: '>=10'} peerDependencies: @@ -21336,13 +21366,13 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.4 + '@types/react': 18.3.5 react: 18.3.1 - react-remove-scroll-bar: 2.3.6(@types/react@18.3.4)(react@18.3.1) - react-style-singleton: 2.2.1(@types/react@18.3.4)(react@18.3.1) + react-remove-scroll-bar: 2.3.6(@types/react@18.3.5)(react@18.3.1) + react-style-singleton: 2.2.1(@types/react@18.3.5)(react@18.3.1) tslib: 2.7.0 - use-callback-ref: 1.3.2(@types/react@18.3.4)(react@18.3.1) - use-sidecar: 1.1.2(@types/react@18.3.4)(react@18.3.1) + use-callback-ref: 1.3.2(@types/react@18.3.5)(react@18.3.1) + use-sidecar: 1.1.2(@types/react@18.3.5)(react@18.3.1) dev: false /react-remove-scroll@2.5.7(react@18.3.1): @@ -21356,11 +21386,11 @@ packages: optional: true dependencies: react: 18.3.1 - react-remove-scroll-bar: 2.3.6(@types/react@18.3.4)(react@18.3.1) - react-style-singleton: 2.2.1(@types/react@18.3.4)(react@18.3.1) + react-remove-scroll-bar: 2.3.6(@types/react@18.3.5)(react@18.3.1) + react-style-singleton: 2.2.1(@types/react@18.3.5)(react@18.3.1) tslib: 2.7.0 - use-callback-ref: 1.3.2(@types/react@18.3.4)(react@18.3.1) - use-sidecar: 1.1.2(@types/react@18.3.4)(react@18.3.1) + use-callback-ref: 1.3.2(@types/react@18.3.5)(react@18.3.1) + use-sidecar: 1.1.2(@types/react@18.3.5)(react@18.3.1) dev: true /react-style-singleton@2.2.1(@types/react@18.2.79)(react@18.3.1): @@ -21380,7 +21410,7 @@ packages: tslib: 2.7.0 dev: false - /react-style-singleton@2.2.1(@types/react@18.3.4)(react@18.3.1): + /react-style-singleton@2.2.1(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} engines: {node: '>=10'} peerDependencies: @@ -21390,7 +21420,7 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.4 + '@types/react': 18.3.5 get-nonce: 1.0.1 invariant: 2.2.4 react: 18.3.1 @@ -21401,7 +21431,7 @@ packages: peerDependencies: react: '>= 0.14.0' dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 highlight.js: 10.7.3 lowlight: 1.20.0 prismjs: 1.29.0 @@ -21541,6 +21571,7 @@ packages: engines: {node: '>= 0.10'} dependencies: resolve: 1.22.8 + dev: false /redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} @@ -22047,29 +22078,29 @@ packages: source-map-support: 0.3.3 dev: false - /rollup@4.21.1: - resolution: {integrity: sha512-ZnYyKvscThhgd3M5+Qt3pmhO4jIRR5RGzaSovB6Q7rGNrK5cUncrtLmcTTJVSdcKXyZjW8X8MB0JMSuH9bcAJg==} + /rollup@4.21.2: + resolution: {integrity: sha512-e3TapAgYf9xjdLvKQCkQTnbTKd4a6jwlpQSJJFokHGaX2IVjoEqkIIhiQfqsi0cdwlOD+tQGuOd5AJkc5RngBw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true dependencies: '@types/estree': 1.0.5 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.21.1 - '@rollup/rollup-android-arm64': 4.21.1 - '@rollup/rollup-darwin-arm64': 4.21.1 - '@rollup/rollup-darwin-x64': 4.21.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.21.1 - '@rollup/rollup-linux-arm-musleabihf': 4.21.1 - '@rollup/rollup-linux-arm64-gnu': 4.21.1 - '@rollup/rollup-linux-arm64-musl': 4.21.1 - '@rollup/rollup-linux-powerpc64le-gnu': 4.21.1 - '@rollup/rollup-linux-riscv64-gnu': 4.21.1 - '@rollup/rollup-linux-s390x-gnu': 4.21.1 - '@rollup/rollup-linux-x64-gnu': 4.21.1 - '@rollup/rollup-linux-x64-musl': 4.21.1 - '@rollup/rollup-win32-arm64-msvc': 4.21.1 - '@rollup/rollup-win32-ia32-msvc': 4.21.1 - '@rollup/rollup-win32-x64-msvc': 4.21.1 + '@rollup/rollup-android-arm-eabi': 4.21.2 + '@rollup/rollup-android-arm64': 4.21.2 + '@rollup/rollup-darwin-arm64': 4.21.2 + '@rollup/rollup-darwin-x64': 4.21.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.21.2 + '@rollup/rollup-linux-arm-musleabihf': 4.21.2 + '@rollup/rollup-linux-arm64-gnu': 4.21.2 + '@rollup/rollup-linux-arm64-musl': 4.21.2 + '@rollup/rollup-linux-powerpc64le-gnu': 4.21.2 + '@rollup/rollup-linux-riscv64-gnu': 4.21.2 + '@rollup/rollup-linux-s390x-gnu': 4.21.2 + '@rollup/rollup-linux-x64-gnu': 4.21.2 + '@rollup/rollup-linux-x64-musl': 4.21.2 + '@rollup/rollup-win32-arm64-msvc': 4.21.2 + '@rollup/rollup-win32-ia32-msvc': 4.21.2 + '@rollup/rollup-win32-x64-msvc': 4.21.2 fsevents: 2.3.3 dev: true @@ -22393,6 +22424,7 @@ packages: glob: 7.2.3 interpret: 1.4.0 rechoir: 0.6.2 + dev: false /shiki@0.14.7: resolution: {integrity: sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==} @@ -22410,10 +22442,11 @@ packages: '@types/hast': 3.0.4 dev: false - /shiki@1.14.1: - resolution: {integrity: sha512-FujAN40NEejeXdzPt+3sZ3F2dx1U24BY2XTY01+MG8mbxCiA2XukXdcbyMyLAHJ/1AUUnQd1tZlvIjefWWEJeA==} + /shiki@1.16.1: + resolution: {integrity: sha512-tCJIMaxDVB1mEIJ5TvfZU7kCPB5eo9fli5+21Olc/bmyv+w8kye3JOp+LZRmGkAyT71hrkefQhTiY+o9mBikRQ==} dependencies: - '@shikijs/core': 1.14.1 + '@shikijs/core': 1.16.1 + '@shikijs/vscode-textmate': 9.2.0 '@types/hast': 3.0.4 dev: false @@ -22479,15 +22512,6 @@ packages: engines: {node: '>=8'} dev: true - /slice-ansi@4.0.0: - resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 - dev: true - /slice-ansi@5.0.0: resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} engines: {node: '>=12'} @@ -23000,14 +23024,14 @@ packages: dependencies: inline-style-parser: 0.1.1 - /style-to-object@1.0.6: - resolution: {integrity: sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA==} + /style-to-object@1.0.7: + resolution: {integrity: sha512-uSjr59G5u6fbxUfKbb8GcqMGT3Xs9v5IbPkjb0S16GyOeBLAzSRK0CixBv5YrYvzO6TDLzIS6QCn78tkqWngPw==} dependencies: inline-style-parser: 0.2.3 dev: true - /styled-components@6.1.12(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-n/O4PzRPhbYI0k1vKKayfti3C/IGcPf+DqcrOB7O/ab9x4u/zjqraneT5N45+sIe87cxrCApXM8Bna7NYxwoTA==} + /styled-components@6.1.13(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-M0+N2xSnAtwcVAQeFEsGWFFxXDftHUD7XrKla06QbpUMmbmtFBMMTcKWvFXtWxuD5qQkB8iU5gk6QASlx2ZRMw==} engines: {node: '>= 16'} peerDependencies: react: '>= 16.8.0' @@ -23192,13 +23216,13 @@ packages: /tailwind-merge@2.2.0: resolution: {integrity: sha512-SqqhhaL0T06SW59+JVNfAqKdqLs0497esifRrZ7jOaefP3o64fdFNDMrAQWZFMxTLJPiHVjRLUywT8uFz1xNWQ==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 dev: false /tailwind-merge@2.3.0: resolution: {integrity: sha512-vkYrLpIP+lgR0tQCG6AP7zZXCTLc1Lnv/CCRT3BqJ9CZ3ui2++GPaGb1x/ILsINIMSYqqvrpqjUFsMNLlW99EA==} dependencies: - '@babel/runtime': 7.25.4 + '@babel/runtime': 7.25.6 dev: false /tailwind-scrollbar@3.1.0(tailwindcss@3.4.3): @@ -23672,7 +23696,7 @@ packages: joycon: 3.1.1 postcss-load-config: 4.0.2(postcss@8.4.38)(ts-node@10.9.2) resolve-from: 5.0.0 - rollup: 4.21.1 + rollup: 4.21.2 source-map: 0.8.0-beta.0 sucrase: 3.35.0 tree-kill: 1.2.2 @@ -23688,7 +23712,7 @@ packages: hasBin: true dependencies: esbuild: 0.21.5 - get-tsconfig: 4.7.6 + get-tsconfig: 4.8.0 optionalDependencies: fsevents: 2.3.3 dev: true @@ -23827,8 +23851,8 @@ packages: engines: {node: '>=12.20'} dev: false - /type-fest@4.25.0: - resolution: {integrity: sha512-bRkIGlXsnGBRBQRAY56UXBm//9qH4bmJfFvq83gSz41N282df+fjy8ofcEgc1sM8geNt5cl6mC2g9Fht1cs8Aw==} + /type-fest@4.26.0: + resolution: {integrity: sha512-OduNjVJsFbifKb57UqZ2EMP1i4u64Xwow3NYXUtBbD4vIwJdQd4+xl8YDou1dlm4DVrtwT/7Ky8z8WyCULVfxw==} engines: {node: '>=16'} /type-is@1.6.18: @@ -24160,12 +24184,11 @@ packages: engines: {node: '>= 0.8'} dev: true - /unplugin@1.12.2: - resolution: {integrity: sha512-bEqQxeC7rxtxPZ3M5V4Djcc4lQqKPgGe3mAWZvxcSmX5jhGxll19NliaRzQSQPrk4xJZSGniK3puLWpRuZN7VQ==} + /unplugin@1.12.3: + resolution: {integrity: sha512-my8DH0/T/Kx33KO+6QXAqdeMYgyy0GktlOpdQjpagfHKw5DrD0ctPr7SHUyOT3g4ZVpzCQGt/qcpuoKJ/pniHA==} engines: {node: '>=14.0.0'} dependencies: acorn: 8.12.1 - chokidar: 3.6.0 webpack-sources: 3.2.3 webpack-virtual-modules: 0.6.2 dev: true @@ -24177,7 +24200,7 @@ packages: browserslist: '>= 4.21.0' dependencies: browserslist: 4.23.3 - escalade: 3.1.2 + escalade: 3.2.0 picocolors: 1.0.1 /uri-js@4.4.1: @@ -24208,7 +24231,7 @@ packages: tslib: 2.7.0 dev: false - /use-callback-ref@1.3.2(@types/react@18.3.4)(react@18.3.1): + /use-callback-ref@1.3.2(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==} engines: {node: '>=10'} peerDependencies: @@ -24218,7 +24241,7 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.4 + '@types/react': 18.3.5 react: 18.3.1 tslib: 2.7.0 @@ -24238,7 +24261,7 @@ packages: tslib: 2.7.0 dev: false - /use-sidecar@1.1.2(@types/react@18.3.4)(react@18.3.1): + /use-sidecar@1.1.2(@types/react@18.3.5)(react@18.3.1): resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} engines: {node: '>=10'} peerDependencies: @@ -24248,7 +24271,7 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.3.4 + '@types/react': 18.3.5 detect-node-es: 1.1.0 react: 18.3.1 tslib: 2.7.0 @@ -24490,8 +24513,8 @@ packages: dependencies: '@types/node': 20.14.9 esbuild: 0.21.5 - postcss: 8.4.41 - rollup: 4.21.1 + postcss: 8.4.44 + rollup: 4.21.2 optionalDependencies: fsevents: 2.3.3 dev: true @@ -24872,6 +24895,14 @@ packages: dependencies: isexe: 2.0.0 + /which@4.0.0: + resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} + engines: {node: ^16.13.0 || >=18.0.0} + hasBin: true + dependencies: + isexe: 3.1.1 + dev: true + /why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} @@ -25192,7 +25223,7 @@ packages: engines: {node: '>=12'} dependencies: cliui: 8.0.1 - escalade: 3.1.2 + escalade: 3.2.0 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -25205,7 +25236,7 @@ packages: engines: {node: '>=12'} dependencies: cliui: 8.0.1 - escalade: 3.1.2 + escalade: 3.2.0 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3