From 9074f5e20623efaff2b26db173ff7bb9c61a82a1 Mon Sep 17 00:00:00 2001 From: Andreas Thomas Date: Fri, 15 Sep 2023 22:21:40 +0200 Subject: [PATCH] metrics (#251) * style: fmt * feat: metrics package --- apps/agent/cmd/agent/main.go | 27 +- apps/agent/pkg/analytics/interface.go | 13 +- apps/agent/pkg/cache/cache.go | 22 +- apps/agent/pkg/cache/middleware/logging.go | 37 -- apps/agent/pkg/cache/middleware/metrics.go | 40 ++ apps/agent/pkg/database/middleware_logging.go | 154 ------ apps/agent/pkg/database/middleware_metrics.go | 206 +++++++ apps/agent/pkg/events/kafka/kafka.go | 101 ++-- apps/agent/pkg/metrics/axiom.go | 77 +++ apps/agent/pkg/metrics/convert.go | 31 ++ apps/agent/pkg/metrics/interface.go | 59 ++ apps/agent/pkg/metrics/noop.go | 18 + apps/web/pages/api/v1/clerk/webhooks.ts | 6 +- pnpm-lock.yaml | 505 +++++++++++++++--- 14 files changed, 947 insertions(+), 349 deletions(-) delete mode 100644 apps/agent/pkg/cache/middleware/logging.go create mode 100644 apps/agent/pkg/cache/middleware/metrics.go delete mode 100644 apps/agent/pkg/database/middleware_logging.go create mode 100644 apps/agent/pkg/database/middleware_metrics.go create mode 100644 apps/agent/pkg/metrics/axiom.go create mode 100644 apps/agent/pkg/metrics/convert.go create mode 100644 apps/agent/pkg/metrics/interface.go create mode 100644 apps/agent/pkg/metrics/noop.go diff --git a/apps/agent/cmd/agent/main.go b/apps/agent/cmd/agent/main.go index 86049c78eb..7ffe45d35f 100644 --- a/apps/agent/cmd/agent/main.go +++ b/apps/agent/cmd/agent/main.go @@ -16,6 +16,7 @@ import ( "github.com/unkeyed/unkey/apps/agent/pkg/env" "github.com/unkeyed/unkey/apps/agent/pkg/events" "github.com/unkeyed/unkey/apps/agent/pkg/logging" + metricsPkg "github.com/unkeyed/unkey/apps/agent/pkg/metrics" "github.com/unkeyed/unkey/apps/agent/pkg/ratelimit" "github.com/unkeyed/unkey/apps/agent/pkg/services/workspaces" @@ -74,6 +75,20 @@ var AgentCmd = &cobra.Command{ logger = logger.With(zap.String("allocId", allocId)) } + metrics := metricsPkg.NewNoop() + if runtimeConfig.enableAxiom { + realMetrics, err := metricsPkg.New(metricsPkg.Config{ + AxiomOrgId: e.String("AXIOM_ORG_ID"), + AxiomToken: e.String("AXIOM_TOKEN"), + Logger: logger.With(zap.String("pkg", "metrics")), + Region: region, + }) + if err != nil { + logger.Fatal("unable to start metrics", zap.Error(err)) + } + metrics = realMetrics + } + // Setup Axiom tracer := tracing.NewNoop() @@ -108,7 +123,7 @@ var AgentCmd = &cobra.Command{ ReplicaAsia: e.String("DATABASE_DSN_ASIA", ""), FlyRegion: region, }, - database.WithLogging(logger), + database.WithMetrics(metrics), database.WithTracing(tracer), ) if err != nil { @@ -177,10 +192,11 @@ var AgentCmd = &cobra.Command{ } return key, found }, - Logger: logger.With(zap.String("cacheType", "key")), + Logger: logger.With(zap.String("cacheType", "key")), + Metrics: metrics, }) keyCache = cacheMiddleware.WithTracing[entities.Key](keyCache, tracer) - keyCache = cacheMiddleware.WithLogging[entities.Key](keyCache, logger.With(zap.String("cacheType", "key"))) + keyCache = cacheMiddleware.WithMetrics[entities.Key](keyCache, metrics, "key") apiCache := cache.New[entities.Api](cache.Config[entities.Api]{ Fresh: time.Minute * 5, @@ -194,10 +210,11 @@ var AgentCmd = &cobra.Command{ } return key, found }, - Logger: logger.With(zap.String("cacheType", "api")), + Logger: logger.With(zap.String("cacheType", "api")), + Metrics: metrics, }) apiCache = cacheMiddleware.WithTracing[entities.Api](apiCache, tracer) - apiCache = cacheMiddleware.WithLogging[entities.Api](apiCache, logger.With(zap.String("cacheType", "api"))) + apiCache = cacheMiddleware.WithMetrics[entities.Api](apiCache, metrics, "api") eventBus.OnKeyEvent(func(ctx context.Context, e events.KeyEvent) error { diff --git a/apps/agent/pkg/analytics/interface.go b/apps/agent/pkg/analytics/interface.go index 502948bd04..123b6065b7 100644 --- a/apps/agent/pkg/analytics/interface.go +++ b/apps/agent/pkg/analytics/interface.go @@ -16,12 +16,12 @@ type KeyVerificationV1Event struct { } type KeyVerificationEvent struct { - ApiId string `json:"apiId"` - WorkspaceId string `json:"workspaceId"` - KeyId string `json:"keyId"` - Ratelimited bool `json:"ratelimited"` - UsageExceeded bool `json:"usageExceeded"` - Time int64 `json:"time"` + ApiId string `json:"apiId"` + WorkspaceId string `json:"workspaceId"` + KeyId string `json:"keyId"` + Ratelimited bool `json:"ratelimited"` + UsageExceeded bool `json:"usageExceeded"` + Time int64 `json:"time"` EdgeRegion string `json:"edgeRegion"` Region string `json:"region"` @@ -30,7 +30,6 @@ type KeyVerificationEvent struct { // custom field the user may provide, like a URL or some id RequestedResource string `json:"requestedResource"` - } type ValueAtTime struct { diff --git a/apps/agent/pkg/cache/cache.go b/apps/agent/pkg/cache/cache.go index 9bd9a08b95..85146375dc 100644 --- a/apps/agent/pkg/cache/cache.go +++ b/apps/agent/pkg/cache/cache.go @@ -7,6 +7,7 @@ import ( "sync" "time" + "github.com/unkeyed/unkey/apps/agent/pkg/metrics" "go.uber.org/zap" ) @@ -33,6 +34,7 @@ type cache[T any] struct { logger *zap.Logger maxSize int lru *list.List + metrics metrics.Metrics } type Config[T any] struct { @@ -51,6 +53,8 @@ type Config[T any] struct { // Start evicting the least recently used entry when the cache grows to MaxSize MaxSize int + + Metrics metrics.Metrics } func New[T any](config Config[T]) Cache[T] { @@ -64,6 +68,7 @@ func New[T any](config Config[T]) Cache[T] { logger: config.Logger.With(zap.String("pkg", "cache")), maxSize: config.MaxSize, lru: list.New(), + metrics: config.Metrics, } go c.runEviction() @@ -77,14 +82,15 @@ func (c *cache[T]) runReporting() { c.RLock() size := len(c.data) utilization := float64(size) / math.Max(1, float64(c.maxSize)) - c.logger.Info( - "report.cache.health", - zap.Int("cacheSize", size), - zap.Int("cacheMaxSize", c.maxSize), - zap.Int("lruSize", c.lru.Len()), - zap.Int("refreshQueueSize", len(c.refreshC)), - zap.Float64("utilization", utilization), - ) + + c.metrics.ReportCacheHealth(metrics.CacheHealthReport{ + CacheSize: size, + CacheMaxSize: c.maxSize, + LruSize: c.lru.Len(), + RefreshQueueSize: len(c.refreshC), + Utilization: utilization, + }) + if size != c.lru.Len() { c.logger.Error( "cache skew detected", diff --git a/apps/agent/pkg/cache/middleware/logging.go b/apps/agent/pkg/cache/middleware/logging.go deleted file mode 100644 index f5a34fdae7..0000000000 --- a/apps/agent/pkg/cache/middleware/logging.go +++ /dev/null @@ -1,37 +0,0 @@ -package middleware - -import ( - "context" - "time" - - "github.com/unkeyed/unkey/apps/agent/pkg/cache" - "go.uber.org/zap" -) - -type loggingMiddleware[T any] struct { - next cache.Cache[T] - logger *zap.Logger -} - -func WithLogging[T any](c cache.Cache[T], l *zap.Logger) cache.Cache[T] { - return &loggingMiddleware[T]{next: c, logger: l} -} - -func (mw *loggingMiddleware[T]) Get(ctx context.Context, key string) (T, bool) { - start := time.Now() - value, hit := mw.next.Get(ctx, key) - mw.logger.Info("cache.get", zap.String("key", key), zap.Bool("hit", hit), zap.Int64("latency", time.Since(start).Milliseconds())) - return value, hit -} -func (mw *loggingMiddleware[T]) Set(ctx context.Context, key string, value T) { - mw.logger.Info("cache.set", zap.String("key", key)) - - mw.next.Set(ctx, key, value) - -} -func (mw *loggingMiddleware[T]) Remove(ctx context.Context, key string) { - mw.logger.Info("cache.remove", zap.String("key", key)) - - mw.next.Remove(ctx, key) - -} diff --git a/apps/agent/pkg/cache/middleware/metrics.go b/apps/agent/pkg/cache/middleware/metrics.go new file mode 100644 index 0000000000..05751fa683 --- /dev/null +++ b/apps/agent/pkg/cache/middleware/metrics.go @@ -0,0 +1,40 @@ +package middleware + +import ( + "context" + "time" + + "github.com/unkeyed/unkey/apps/agent/pkg/cache" + "github.com/unkeyed/unkey/apps/agent/pkg/metrics" +) + +type metricsMiddleware[T any] struct { + next cache.Cache[T] + metrics metrics.Metrics + resource string +} + +func WithMetrics[T any](c cache.Cache[T], m metrics.Metrics, resource string) cache.Cache[T] { + return &metricsMiddleware[T]{next: c, metrics: m, resource: resource} +} + +func (mw *metricsMiddleware[T]) Get(ctx context.Context, key string) (T, bool) { + start := time.Now() + value, hit := mw.next.Get(ctx, key) + mw.metrics.ReportCacheHit(metrics.CacheHitReport{ + Key: key, + Hit: hit, + Resource: mw.resource, + Latency: time.Since(start).Milliseconds(), + }) + return value, hit +} +func (mw *metricsMiddleware[T]) Set(ctx context.Context, key string, value T) { + mw.next.Set(ctx, key, value) + +} +func (mw *metricsMiddleware[T]) Remove(ctx context.Context, key string) { + + mw.next.Remove(ctx, key) + +} diff --git a/apps/agent/pkg/database/middleware_logging.go b/apps/agent/pkg/database/middleware_logging.go deleted file mode 100644 index 80563d073d..0000000000 --- a/apps/agent/pkg/database/middleware_logging.go +++ /dev/null @@ -1,154 +0,0 @@ -package database - -import ( - "context" - "time" - - "github.com/unkeyed/unkey/apps/agent/pkg/entities" - "github.com/unkeyed/unkey/apps/agent/pkg/logging" - "go.uber.org/zap" -) - -func WithLogging(logger logging.Logger) Middleware { - - return func(db Database) Database { - return &loggingMiddleware{next: db, logger: logger.With(zap.String("pkg", "database"))} - } -} - -type loggingMiddleware struct { - next Database - logger logging.Logger -} - -func (mw *loggingMiddleware) InsertWorkspace(ctx context.Context, newWorkspace entities.Workspace) (err error) { - start := time.Now() - - err = mw.next.InsertWorkspace(ctx, newWorkspace) - mw.logger.Info("mw.database", zap.String("method", "InsertWorkspace"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return err - -} -func (mw *loggingMiddleware) InsertApi(ctx context.Context, api entities.Api) (err error) { - start := time.Now() - err = mw.next.InsertApi(ctx, api) - mw.logger.Info("mw.database", zap.String("method", "InsertApi"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return err -} -func (mw *loggingMiddleware) FindApi(ctx context.Context, apiId string) (api entities.Api, found bool, err error) { - start := time.Now() - - api, found, err = mw.next.FindApi(ctx, apiId) - mw.logger.Info("mw.database", zap.String("method", "FindApi"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return api, found, err -} -func (mw *loggingMiddleware) FindApiByKeyAuthId(ctx context.Context, keyAuthId string) (api entities.Api, found bool, err error) { - start := time.Now() - - api, found, err = mw.next.FindApiByKeyAuthId(ctx, keyAuthId) - mw.logger.Info("mw.database", zap.String("method", "FindApiByKeyAuthId"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return api, found, err -} -func (mw *loggingMiddleware) CreateKey(ctx context.Context, newKey entities.Key) (err error) { - start := time.Now() - - err = mw.next.CreateKey(ctx, newKey) - mw.logger.Info("mw.database", zap.String("method", "CreateKey"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return err -} -func (mw *loggingMiddleware) FindKeyById(ctx context.Context, keyId string) (key entities.Key, found bool, err error) { - start := time.Now() - - key, found, err = mw.next.FindKeyById(ctx, keyId) - mw.logger.Info("mw.database", zap.String("method", "FindKeyById"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return key, found, err -} -func (mw *loggingMiddleware) FindKeyByHash(ctx context.Context, hash string) (key entities.Key, found bool, err error) { - start := time.Now() - - key, found, err = mw.next.FindKeyByHash(ctx, hash) - mw.logger.Info("mw.database", zap.String("method", "FindKeyByHash"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return key, found, err -} -func (mw *loggingMiddleware) UpdateKey(ctx context.Context, key entities.Key) (err error) { - start := time.Now() - - err = mw.next.UpdateKey(ctx, key) - mw.logger.Info("mw.database", zap.String("method", "UpdateKey"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return err -} -func (mw *loggingMiddleware) DeleteKey(ctx context.Context, keyId string) (err error) { - start := time.Now() - - err = mw.next.DeleteKey(ctx, keyId) - mw.logger.Info("mw.database", zap.String("method", "DeleteKey"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return err -} -func (mw *loggingMiddleware) DecrementRemainingKeyUsage(ctx context.Context, keyId string) (key entities.Key, err error) { - start := time.Now() - - key, err = mw.next.DecrementRemainingKeyUsage(ctx, keyId) - mw.logger.Info("mw.database", zap.String("method", "DecrementRemainingKeyUsage"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return key, err -} -func (mw *loggingMiddleware) CountKeys(ctx context.Context, keyAuthId string) (count int64, err error) { - start := time.Now() - - count, err = mw.next.CountKeys(ctx, keyAuthId) - mw.logger.Info("mw.database", zap.String("method", "CountKeys"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return count, err -} -func (mw *loggingMiddleware) ListKeys(ctx context.Context, keyAuthId string, ownerId string, limit int, offset int) ([]entities.Key, error) { - start := time.Now() - - keys, err := mw.next.ListKeys(ctx, keyAuthId, ownerId, limit, offset) - mw.logger.Info("mw.database", zap.String("method", "ListKeys"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return keys, err -} - -func (mw *loggingMiddleware) ListAllApis(ctx context.Context, limit int, offset int) ([]entities.Api, error) { - start := time.Now() - - apis, err := mw.next.ListAllApis(ctx, limit, offset) - mw.logger.Info("mw.database", zap.String("method", "ListAllApis"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return apis, err -} -func (mw *loggingMiddleware) CreateKeyAuth(ctx context.Context, newKeyAuth entities.KeyAuth) error { - start := time.Now() - - err := mw.next.CreateKeyAuth(ctx, newKeyAuth) - mw.logger.Info("mw.database", zap.String("method", "CreateKeyAuth"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return err -} - -func (mw *loggingMiddleware) FindKeyAuth(ctx context.Context, keyAuthId string) (keyAuth entities.KeyAuth, found bool, err error) { - start := time.Now() - - keyAuth, found, err = mw.next.FindKeyAuth(ctx, keyAuthId) - mw.logger.Info("mw.database", zap.String("method", "FindKeyAuth"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return keyAuth, found, err -} - -func (mw *loggingMiddleware) UpdateWorkspace(ctx context.Context, workspace entities.Workspace) (err error) { - start := time.Now() - - err = mw.next.UpdateWorkspace(ctx, workspace) - mw.logger.Info("mw.database", zap.String("method", "UpdateWorkspace"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return err -} - -func (mw *loggingMiddleware) FindWorkspace(ctx context.Context, workspaceId string) (workspace entities.Workspace, found bool, err error) { - start := time.Now() - - workspace, found, err = mw.next.FindWorkspace(ctx, workspaceId) - mw.logger.Info("mw.database", zap.String("method", "FindWorkspace"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return workspace, found, err -} - -func (mw *loggingMiddleware) Close() error { - start := time.Now() - - err := mw.next.Close() - mw.logger.Info("mw.database", zap.String("method", "Close"), zap.Error(err), zap.Int64("latency", time.Since(start).Milliseconds())) - return err -} diff --git a/apps/agent/pkg/database/middleware_metrics.go b/apps/agent/pkg/database/middleware_metrics.go new file mode 100644 index 0000000000..99b6bf39a2 --- /dev/null +++ b/apps/agent/pkg/database/middleware_metrics.go @@ -0,0 +1,206 @@ +package database + +import ( + "context" + "time" + + "github.com/unkeyed/unkey/apps/agent/pkg/entities" + "github.com/unkeyed/unkey/apps/agent/pkg/metrics" +) + +func WithMetrics(m metrics.Metrics) Middleware { + + return func(db Database) Database { + return &metricsMiddleware{next: db, metrics: m} + } +} + +type metricsMiddleware struct { + next Database + metrics metrics.Metrics +} + +func (mw *metricsMiddleware) InsertWorkspace(ctx context.Context, newWorkspace entities.Workspace) error { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "InsertWorkspace", + Latency: time.Since(start).Milliseconds(), + }) + }() + return mw.next.InsertWorkspace(ctx, newWorkspace) + +} +func (mw *metricsMiddleware) InsertApi(ctx context.Context, api entities.Api) (err error) { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "InsertApi", + Latency: time.Since(start).Milliseconds(), + }) + }() + return mw.next.InsertApi(ctx, api) +} +func (mw *metricsMiddleware) FindApi(ctx context.Context, apiId string) (api entities.Api, found bool, err error) { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "FindApi", + Latency: time.Since(start).Milliseconds(), + }) + }() + return mw.next.FindApi(ctx, apiId) + +} +func (mw *metricsMiddleware) FindApiByKeyAuthId(ctx context.Context, keyAuthId string) (entities.Api, bool, error) { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "FindApiByKeyAuthId", + Latency: time.Since(start).Milliseconds(), + }) + }() + + return mw.next.FindApiByKeyAuthId(ctx, keyAuthId) + +} +func (mw *metricsMiddleware) CreateKey(ctx context.Context, newKey entities.Key) (err error) { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "CreateKey", + Latency: time.Since(start).Milliseconds(), + }) + }() + return mw.next.CreateKey(ctx, newKey) + +} +func (mw *metricsMiddleware) FindKeyById(ctx context.Context, keyId string) (key entities.Key, found bool, err error) { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "FindKeyById", + Latency: time.Since(start).Milliseconds(), + }) + }() + return mw.next.FindKeyById(ctx, keyId) +} +func (mw *metricsMiddleware) FindKeyByHash(ctx context.Context, hash string) (key entities.Key, found bool, err error) { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "FindKeyByHash", + Latency: time.Since(start).Milliseconds(), + }) + }() + return mw.next.FindKeyByHash(ctx, hash) +} +func (mw *metricsMiddleware) UpdateKey(ctx context.Context, key entities.Key) (err error) { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "UpdateKey", + Latency: time.Since(start).Milliseconds(), + }) + }() + return mw.next.UpdateKey(ctx, key) +} +func (mw *metricsMiddleware) DeleteKey(ctx context.Context, keyId string) (err error) { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "DeleteKey", + Latency: time.Since(start).Milliseconds(), + }) + }() + return mw.next.DeleteKey(ctx, keyId) + +} +func (mw *metricsMiddleware) DecrementRemainingKeyUsage(ctx context.Context, keyId string) (key entities.Key, err error) { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "DecrementRemainingKeyUsage", + Latency: time.Since(start).Milliseconds(), + }) + }() + return mw.next.DecrementRemainingKeyUsage(ctx, keyId) +} +func (mw *metricsMiddleware) CountKeys(ctx context.Context, keyAuthId string) (count int64, err error) { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "CountKeys", + Latency: time.Since(start).Milliseconds(), + }) + }() + return mw.next.CountKeys(ctx, keyAuthId) +} +func (mw *metricsMiddleware) ListKeys(ctx context.Context, keyAuthId string, ownerId string, limit int, offset int) ([]entities.Key, error) { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "ListKeys", + Latency: time.Since(start).Milliseconds(), + }) + }() + return mw.next.ListKeys(ctx, keyAuthId, ownerId, limit, offset) +} + +func (mw *metricsMiddleware) ListAllApis(ctx context.Context, limit int, offset int) ([]entities.Api, error) { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "ListAllApis", + Latency: time.Since(start).Milliseconds(), + }) + }() + return mw.next.ListAllApis(ctx, limit, offset) +} +func (mw *metricsMiddleware) CreateKeyAuth(ctx context.Context, newKeyAuth entities.KeyAuth) error { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "CreateKeyAuth", + Latency: time.Since(start).Milliseconds(), + }) + }() + return mw.next.CreateKeyAuth(ctx, newKeyAuth) +} + +func (mw *metricsMiddleware) FindKeyAuth(ctx context.Context, keyAuthId string) (keyAuth entities.KeyAuth, found bool, err error) { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "FindKeyAuth", + Latency: time.Since(start).Milliseconds(), + }) + }() + return mw.next.FindKeyAuth(ctx, keyAuthId) +} + +func (mw *metricsMiddleware) UpdateWorkspace(ctx context.Context, workspace entities.Workspace) (err error) { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "UpdateWorkspace", + Latency: time.Since(start).Milliseconds(), + }) + }() + return mw.next.UpdateWorkspace(ctx, workspace) +} + +func (mw *metricsMiddleware) FindWorkspace(ctx context.Context, workspaceId string) (workspace entities.Workspace, found bool, err error) { + start := time.Now() + defer func() { + mw.metrics.ReportDatabaseLatency(metrics.DatabaseLatencyReport{ + Query: "FindWorkspace", + Latency: time.Since(start).Milliseconds(), + }) + }() + return mw.next.FindWorkspace(ctx, workspaceId) +} + +func (mw *metricsMiddleware) Close() error { + return mw.next.Close() +} diff --git a/apps/agent/pkg/events/kafka/kafka.go b/apps/agent/pkg/events/kafka/kafka.go index 1be0773a8f..673e51fd82 100644 --- a/apps/agent/pkg/events/kafka/kafka.go +++ b/apps/agent/pkg/events/kafka/kafka.go @@ -6,6 +6,7 @@ import ( "encoding/json" "errors" "fmt" + "io" "sync" "time" @@ -25,10 +26,8 @@ type Kafka struct { callbackLock sync.RWMutex onKeyEvent []func(ctx context.Context, e events.KeyEvent) error - shutdownLock sync.RWMutex - shutdown bool - shutdownC chan struct{} - logger *zap.Logger + stopC chan struct{} + logger *zap.Logger // Events are first written to this channel and then flushed to kafka // This allows much cleaner code for users of this package @@ -76,9 +75,7 @@ func New(config Config) (*Kafka, error) { }), onKeyEvent: make([]func(ctx context.Context, e events.KeyEvent) error, 0), - shutdownLock: sync.RWMutex{}, - shutdown: false, - shutdownC: make(chan struct{}), + stopC: make(chan struct{}), keyEventBuffer: make(chan events.KeyEvent, 1024), } @@ -103,10 +100,7 @@ func (k *Kafka) Close() error { defer k.logger.Info("stopped") k.Lock() defer k.Unlock() - k.shutdownLock.Lock() - k.shutdown = true - k.shutdownC <- struct{}{} - k.shutdownLock.Unlock() + close(k.stopC) k.logger.Info("stopping reader") err := k.keyChangedReader.Close() @@ -128,7 +122,7 @@ func (k *Kafka) Start() { go func() { for { select { - case <-k.shutdownC: + case <-k.stopC: return case e := <-k.keyEventBuffer: value, err := json.Marshal(e) @@ -148,51 +142,54 @@ func (k *Kafka) Start() { }() go func() { for { - k.shutdownLock.RLock() - shutdown := k.shutdown - k.shutdownLock.RUnlock() - if shutdown { + select { + case <-k.stopC: return + default: + k.handleNextMessage(context.Background()) } - ctx, cancel := context.WithTimeout(context.Background(), time.Second*15) - defer cancel() - m, err := k.keyChangedReader.FetchMessage(ctx) - if err != nil { - if errors.Is(err, context.DeadlineExceeded) { - continue - } - k.logger.Error("unable to fetch message", zap.Error(err)) - continue - } + } + }() +} - if len(m.Value) == 0 { - k.logger.Warn("message is empty", zap.String("topic", m.Topic)) - continue - } - e := events.KeyEvent{} - err = json.Unmarshal(m.Value, &e) - if err != nil { - k.logger.Error("unable to unmarshal message", zap.Error(err), zap.String("value", string(m.Value))) - continue - } - k.callbackLock.RLock() - for _, handler := range k.onKeyEvent { - err := handler(ctx, e) - if err != nil { - k.logger.Error("unable to handle message", zap.Error(err)) - k.callbackLock.RUnlock() - continue - } - } - k.callbackLock.RUnlock() +func (k *Kafka) handleNextMessage(ctx context.Context) { - err = k.keyChangedReader.CommitMessages(ctx, m) - if err != nil { - k.logger.Error("unable to commit message", zap.Error(err)) - continue - } + m, err := k.keyChangedReader.FetchMessage(ctx) + if err != nil { + if errors.Is(err, io.EOF) { + // The method returns io.EOF to indicate that the reader has been closed. + return + } + + k.logger.Error("unable to fetch message", zap.Error(err)) + return + } + if len(m.Value) == 0 { + k.logger.Warn("message is empty", zap.String("topic", m.Topic)) + return + } + e := events.KeyEvent{} + err = json.Unmarshal(m.Value, &e) + if err != nil { + k.logger.Error("unable to unmarshal message", zap.Error(err), zap.String("value", string(m.Value))) + return + } + k.callbackLock.RLock() + defer k.callbackLock.RUnlock() + for _, handler := range k.onKeyEvent { + err := handler(ctx, e) + if err != nil { + k.logger.Error("unable to handle message", zap.Error(err)) + continue } - }() + } + + err = k.keyChangedReader.CommitMessages(ctx, m) + if err != nil { + k.logger.Error("unable to commit message", zap.Error(err)) + return + } + } diff --git a/apps/agent/pkg/metrics/axiom.go b/apps/agent/pkg/metrics/axiom.go new file mode 100644 index 0000000000..d986eca400 --- /dev/null +++ b/apps/agent/pkg/metrics/axiom.go @@ -0,0 +1,77 @@ +package metrics + +import ( + "context" + "fmt" + "time" + + ax "github.com/axiomhq/axiom-go/axiom" + "github.com/unkeyed/unkey/apps/agent/pkg/logging" + "go.uber.org/zap" +) + +type axiom struct { + eventsC chan ax.Event + region string +} + +type Config struct { + AxiomToken string + AxiomOrgId string + Region string + Logger logging.Logger +} + +func New(config Config) (Metrics, error) { + + client, err := ax.NewClient( + ax.SetPersonalTokenConfig(config.AxiomToken, config.AxiomOrgId), + ) + if err != nil { + return nil, fmt.Errorf("unable to create axiom client") + } + a := &axiom{ + region: config.Region, + eventsC: make(chan ax.Event), + } + + go func() { + _, err := client.IngestChannel(context.Background(), "metrics", a.eventsC) + if err != nil { + config.Logger.Error("unable to ingest to axiom", zap.Error(err)) + } + }() + + return a, nil +} + +func (m *axiom) Close() { + close(m.eventsC) +} + +func (m *axiom) report(metric metricId, r any) { + e := toMap(r) + e["metric"] = metric + e["_time"] = time.Now().UnixMilli() + e["region"] = m.region + m.eventsC <- e +} + +func (m *axiom) ReportHttpRequest(r HttpRequestReport) { + m.report(httpRequest, r) +} + +func (m *axiom) ReportCacheHealth(r CacheHealthReport) { + m.report(cacheHealth, r) +} +func (m *axiom) ReportKeyVerification(r KeyVerificationReport) { + m.report(keyVerifying, r) +} + +func (m *axiom) ReportDatabaseLatency(r DatabaseLatencyReport) { + m.report(databaseLatency, r) +} + +func (m *axiom) ReportCacheHit(r CacheHitReport) { + m.report(cacheHit, r) +} diff --git a/apps/agent/pkg/metrics/convert.go b/apps/agent/pkg/metrics/convert.go new file mode 100644 index 0000000000..d067eed6fb --- /dev/null +++ b/apps/agent/pkg/metrics/convert.go @@ -0,0 +1,31 @@ +package metrics + +import ( + "reflect" +) + +func toMap(s any) map[string]any { + obj := map[string]any{} + if s == nil { + return obj + } + v := reflect.TypeOf(s) + reflectValue := reflect.ValueOf(s) + reflectValue = reflect.Indirect(reflectValue) + + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + for i := 0; i < v.NumField(); i++ { + tag := v.Field(i).Tag.Get("json") + field := reflectValue.Field(i).Interface() + if tag != "" && tag != "-" { + if v.Field(i).Type.Kind() == reflect.Struct { + obj[tag] = toMap(field) + } else { + obj[tag] = field + } + } + } + return obj +} diff --git a/apps/agent/pkg/metrics/interface.go b/apps/agent/pkg/metrics/interface.go new file mode 100644 index 0000000000..6450403767 --- /dev/null +++ b/apps/agent/pkg/metrics/interface.go @@ -0,0 +1,59 @@ +package metrics + +type Metrics interface { + ReportHttpRequest(HttpRequestReport) + ReportKeyVerification(KeyVerificationReport) + ReportCacheHealth(CacheHealthReport) + ReportDatabaseLatency(DatabaseLatencyReport) + ReportCacheHit(CacheHitReport) + Close() +} + +type metricId string + +const ( + httpRequest metricId = "metric.http.request" + keyVerifying metricId = "metric.key.verification" + cacheHealth metricId = "metric.cache.health" + databaseLatency metricId = "metric.database.latency" + cacheHit metricId = "metric.cache.hit" +) + +type HttpRequestReport struct { + Path string `json:"path"` + Method string `json:"method"` + Status int `json:"status"` + Error string `json:"error"` + ServiceLatency int64 `json:"serviceLatency"` + EdgeRegion string `json:"edgeRegion"` + TraceId string `json:"traceId"` +} + +type KeyVerificationReport struct { + KeyId string `json:"keyId"` + ApiId string `json:"apiId"` + KeyAuthId string `json:"keyAuthId"` + WorkspaceId string `json:"workspaceId"` + + TraceId string `json:"traceId"` +} + +type CacheHitReport struct { + Key string `json:"key"` + Hit bool `json:"hit"` + Resource string `json:"resource"` + Latency int64 `json:"latency"` +} + +type CacheHealthReport struct { + CacheSize int `json:"cacheSize"` + CacheMaxSize int `json:"cacheMaxSize"` + LruSize int `json:"lruSize"` + RefreshQueueSize int `json:"refreshQueueSize"` + Utilization float64 `json:"utilization"` +} + +type DatabaseLatencyReport struct { + Query string `json:"query"` + Latency int64 `json:"latency"` +} diff --git a/apps/agent/pkg/metrics/noop.go b/apps/agent/pkg/metrics/noop.go new file mode 100644 index 0000000000..54043468cc --- /dev/null +++ b/apps/agent/pkg/metrics/noop.go @@ -0,0 +1,18 @@ +package metrics + +type noop struct { +} + +func NewNoop() Metrics { + return &noop{} + +} + +func (n *noop) Close() {} + +func (n *noop) ReportHttpRequest(r HttpRequestReport) {} + +func (n *noop) ReportCacheHealth(r CacheHealthReport) {} +func (n *noop) ReportKeyVerification(r KeyVerificationReport) {} +func (n *noop) ReportDatabaseLatency(r DatabaseLatencyReport) {} +func (n *noop) ReportCacheHit(r CacheHitReport) {} diff --git a/apps/web/pages/api/v1/clerk/webhooks.ts b/apps/web/pages/api/v1/clerk/webhooks.ts index ee6dc79c7f..7ad013e7a7 100644 --- a/apps/web/pages/api/v1/clerk/webhooks.ts +++ b/apps/web/pages/api/v1/clerk/webhooks.ts @@ -44,12 +44,14 @@ export default async function handler( }); if (loopsResponse.status < 200 || loopsResponse.status >= 300) { - return res.status(400).json({ error: "Loops API Error ", jsonResponse: await loopsResponse.json() }); + return res + .status(500) + .json({ error: "Loops API Error ", jsonResponse: await loopsResponse.json() }); } return res.status(200).json({}); } catch (err) { return res.status(400).json({ - error: (err as Error).message + error: (err as Error).message, }); } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3995063c0e..c6d26f3c91 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,13 +25,13 @@ importers: version: 2.26.2 checkly: specifier: ^4.1.0 - version: 4.1.0(@types/node@20.5.7)(typescript@5.2.2) + version: 4.1.0(@types/node@20.6.1)(typescript@5.2.2) cz-conventional-changelog: specifier: ^3.3.0 version: 3.3.0 ts-node: specifier: ^10.9.1 - version: 10.9.1(@types/node@20.5.7)(typescript@5.2.2) + version: 10.9.1(@types/node@20.6.1)(typescript@5.2.2) turbo: specifier: ^1.10.13 version: 1.10.13 @@ -54,7 +54,7 @@ importers: version: 4.23.3(next@13.4.19)(react-dom@18.2.0)(react@18.2.0) '@hono/zod-validator': specifier: ^0.1.8 - version: 0.1.8(hono@3.5.6)(zod@3.22.2) + version: 0.1.8(hono@3.6.1)(zod@3.22.2) '@hookform/resolvers': specifier: ^3.3.1 version: 3.3.1(react-hook-form@7.45.4) @@ -225,7 +225,7 @@ importers: version: 0.2.0(@types/react@18.2.21)(react-dom@18.2.0)(react@18.2.0) contentlayer: specifier: ^0.3.4 - version: 0.3.4(esbuild@0.19.2) + version: 0.3.4(esbuild@0.19.3) drizzle-orm: specifier: ^0.28.5 version: 0.28.5(@opentelemetry/api@1.4.1)(@planetscale/database@1.11.0) @@ -261,7 +261,7 @@ importers: version: 13.4.19(@opentelemetry/api@1.4.1)(react-dom@18.2.0)(react@18.2.0) next-contentlayer: specifier: ^0.3.4 - version: 0.3.4(contentlayer@0.3.4)(esbuild@0.19.2)(next@13.4.19)(react-dom@18.2.0)(react@18.2.0) + version: 0.3.4(contentlayer@0.3.4)(esbuild@0.19.3)(next@13.4.19)(react-dom@18.2.0)(react@18.2.0) next-themes: specifier: ^0.2.1 version: 0.2.1(next@13.4.19)(react-dom@18.2.0)(react@18.2.0) @@ -370,7 +370,7 @@ importers: version: 10.4.15(postcss@8.4.29) next: specifier: 13.4.19 - version: 13.4.19(@opentelemetry/api@1.4.1)(react-dom@18.2.0)(react@18.2.0) + version: 13.4.19(react-dom@18.2.0)(react@18.2.0) postcss: specifier: 8.4.29 version: 8.4.29 @@ -454,7 +454,7 @@ importers: version: 20.5.7 next: specifier: ^13.4.19 - version: 13.4.19(@opentelemetry/api@1.4.1)(react-dom@18.2.0)(react@18.2.0) + version: 13.4.19(react-dom@18.2.0)(react@18.2.0) tsup: specifier: ^7.2.0 version: 7.2.0(ts-node@10.9.1)(typescript@5.2.2) @@ -482,7 +482,7 @@ importers: version: 0.8.2(nuxt@3.7.0)(rollup@3.28.1)(vite@4.4.9) '@nuxt/module-builder': specifier: ^0.5.1 - version: 0.5.1(@nuxt/kit@3.7.0)(nuxi@3.7.3)(typescript@5.2.2) + version: 0.5.1(@nuxt/kit@3.7.0)(nuxi@3.8.4)(typescript@5.2.2) '@nuxt/schema': specifier: ^3.7.0 version: 3.7.0(rollup@3.28.1) @@ -1123,6 +1123,13 @@ packages: dependencies: regenerator-runtime: 0.14.0 + /@babel/runtime@7.22.15: + resolution: {integrity: sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.0 + dev: false + /@babel/standalone@7.22.14: resolution: {integrity: sha512-i61lDNe0nRm44nZj05g+1HNb0EVfDGaTI6PkoeUMUSel3GTG6T1OM3BdjZIXghnnFB8bSWbmfS1lkBQgNUdu5w==} engines: {node: '>=6.9.0'} @@ -1565,10 +1572,10 @@ packages: dev: true optional: true - /@contentlayer/cli@0.3.4(esbuild@0.19.2): + /@contentlayer/cli@0.3.4(esbuild@0.19.3): resolution: {integrity: sha512-vNDwgLuhYNu+m70NZ3XK9kexKNguuxPXg7Yvzj3B34cEilQjjzSrcTY/i+AIQm9V7uT5GGshx9ukzPf+SmoszQ==} dependencies: - '@contentlayer/core': 0.3.4(esbuild@0.19.2) + '@contentlayer/core': 0.3.4(esbuild@0.19.3) '@contentlayer/utils': 0.3.4 clipanion: 3.2.1(typanion@3.14.0) typanion: 3.14.0 @@ -1579,10 +1586,10 @@ packages: - supports-color dev: false - /@contentlayer/client@0.3.4(esbuild@0.19.2): + /@contentlayer/client@0.3.4(esbuild@0.19.3): resolution: {integrity: sha512-QSlLyc3y4PtdC5lFw0L4wTZUH8BQnv2nk37hNCsPAqGf+dRO7TLAzdc+2/mVIRgK+vSH+pSOzjLsQpFxxXRTZA==} dependencies: - '@contentlayer/core': 0.3.4(esbuild@0.19.2) + '@contentlayer/core': 0.3.4(esbuild@0.19.3) transitivePeerDependencies: - '@effect-ts/otel-node' - esbuild @@ -1590,7 +1597,7 @@ packages: - supports-color dev: false - /@contentlayer/core@0.3.4(esbuild@0.19.2): + /@contentlayer/core@0.3.4(esbuild@0.19.3): resolution: {integrity: sha512-o68oBLwfYZ+2vtgfk1lgHxOl3LoxvRNiUfeQ8IWFWy/L4wnIkKIqLZX01zlRE5IzYM+ZMMN5V0cKQlO7DsyR9g==} peerDependencies: esbuild: 0.17.x || 0.18.x @@ -1604,9 +1611,9 @@ packages: '@contentlayer/utils': 0.3.4 camel-case: 4.1.2 comment-json: 4.2.3 - esbuild: 0.19.2 + esbuild: 0.19.3 gray-matter: 4.0.3 - mdx-bundler: 9.2.1(esbuild@0.19.2) + mdx-bundler: 9.2.1(esbuild@0.19.3) rehype-stringify: 9.0.4 remark-frontmatter: 4.0.1 remark-parse: 10.0.2 @@ -1619,10 +1626,10 @@ packages: - supports-color dev: false - /@contentlayer/source-files@0.3.4(esbuild@0.19.2): + /@contentlayer/source-files@0.3.4(esbuild@0.19.3): resolution: {integrity: sha512-4njyn0OFPu7WY4tAjMxiJgWOKeiHuBOGdQ36EYE03iij/pPPRbiWbL+cmLccYXUFEW58mDwpqROZZm6pnxjRDQ==} dependencies: - '@contentlayer/core': 0.3.4(esbuild@0.19.2) + '@contentlayer/core': 0.3.4(esbuild@0.19.3) '@contentlayer/utils': 0.3.4 chokidar: 3.5.3 fast-glob: 3.3.1 @@ -1640,11 +1647,11 @@ packages: - supports-color dev: false - /@contentlayer/source-remote-files@0.3.4(esbuild@0.19.2): + /@contentlayer/source-remote-files@0.3.4(esbuild@0.19.3): resolution: {integrity: sha512-cyiv4sNUySZvR0uAKlM+kSAELzNd2h2QT1R2e41dRKbwOUVxeLfmGiLugr0aVac6Q3xYcD99dbHyR1xWPV+w9w==} dependencies: - '@contentlayer/core': 0.3.4(esbuild@0.19.2) - '@contentlayer/source-files': 0.3.4(esbuild@0.19.2) + '@contentlayer/core': 0.3.4(esbuild@0.19.3) + '@contentlayer/source-files': 0.3.4(esbuild@0.19.3) '@contentlayer/utils': 0.3.4 transitivePeerDependencies: - '@effect-ts/otel-node' @@ -1792,16 +1799,16 @@ packages: get-tsconfig: 4.7.0 dev: true - /@esbuild-plugins/node-resolve@0.1.4(esbuild@0.19.2): + /@esbuild-plugins/node-resolve@0.1.4(esbuild@0.19.3): resolution: {integrity: sha512-haFQ0qhxEpqtWWY0kx1Y5oE3sMyO1PcoSiWEPrAw6tm/ZOOLXjSs6Q+v1v9eyuVF0nNt50YEvrcrvENmyoMv5g==} peerDependencies: esbuild: '*' dependencies: '@types/resolve': 1.20.2 debug: 4.3.4(supports-color@8.1.1) - esbuild: 0.19.2 + esbuild: 0.19.3 escape-string-regexp: 4.0.0 - resolve: 1.22.4 + resolve: 1.22.5 transitivePeerDependencies: - supports-color dev: false @@ -1821,6 +1828,16 @@ packages: cpu: [arm64] os: [android] requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64@0.19.3: + resolution: {integrity: sha512-w+Akc0vv5leog550kjJV9Ru+MXMR2VuMrui3C61mnysim0gkFCPOUTAfzTP0qX+HpN9Syu3YA3p1hf3EPqObRw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false optional: true /@esbuild/android-arm@0.18.20: @@ -1838,6 +1855,16 @@ packages: cpu: [arm] os: [android] requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.19.3: + resolution: {integrity: sha512-Lemgw4io4VZl9GHJmjiBGzQ7ONXRfRPHcUEerndjwiSkbxzrpq0Uggku5MxxrXdwJ+pTj1qyw4jwTu7hkPsgIA==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: false optional: true /@esbuild/android-x64@0.18.20: @@ -1855,6 +1882,16 @@ packages: cpu: [x64] os: [android] requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.19.3: + resolution: {integrity: sha512-FKQJKkK5MXcBHoNZMDNUAg1+WcZlV/cuXrWCoGF/TvdRiYS4znA0m5Il5idUwfxrE20bG/vU1Cr5e1AD6IEIjQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: false optional: true /@esbuild/darwin-arm64@0.18.20: @@ -1872,6 +1909,16 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.19.3: + resolution: {integrity: sha512-kw7e3FXU+VsJSSSl2nMKvACYlwtvZB8RUIeVShIEY6PVnuZ3c9+L9lWB2nWeeKWNNYDdtL19foCQ0ZyUL7nqGw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false optional: true /@esbuild/darwin-x64@0.18.20: @@ -1889,6 +1936,16 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.19.3: + resolution: {integrity: sha512-tPfZiwF9rO0jW6Jh9ipi58N5ZLoSjdxXeSrAYypy4psA2Yl1dAMhM71KxVfmjZhJmxRjSnb29YlRXXhh3GqzYw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false optional: true /@esbuild/freebsd-arm64@0.18.20: @@ -1906,6 +1963,16 @@ packages: cpu: [arm64] os: [freebsd] requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.19.3: + resolution: {integrity: sha512-ERDyjOgYeKe0Vrlr1iLrqTByB026YLPzTytDTz1DRCYM+JI92Dw2dbpRHYmdqn6VBnQ9Bor6J8ZlNwdZdxjlSg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: false optional: true /@esbuild/freebsd-x64@0.18.20: @@ -1923,6 +1990,16 @@ packages: cpu: [x64] os: [freebsd] requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.19.3: + resolution: {integrity: sha512-nXesBZ2Ad1qL+Rm3crN7NmEVJ5uvfLFPLJev3x1j3feCQXfAhoYrojC681RhpdOph8NsvKBBwpYZHR7W0ifTTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false optional: true /@esbuild/linux-arm64@0.18.20: @@ -1940,6 +2017,16 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.19.3: + resolution: {integrity: sha512-qXvYKmXj8GcJgWq3aGvxL/JG1ZM3UR272SdPU4QSTzD0eymrM7leiZH77pvY3UetCy0k1xuXZ+VPvoJNdtrsWQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false optional: true /@esbuild/linux-arm@0.18.20: @@ -1957,6 +2044,16 @@ packages: cpu: [arm] os: [linux] requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.19.3: + resolution: {integrity: sha512-zr48Cg/8zkzZCzDHNxXO/89bf9e+r4HtzNUPoz4GmgAkF1gFAFmfgOdCbR8zMbzFDGb1FqBBhdXUpcTQRYS1cQ==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false optional: true /@esbuild/linux-ia32@0.18.20: @@ -1974,6 +2071,16 @@ packages: cpu: [ia32] os: [linux] requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.19.3: + resolution: {integrity: sha512-7XlCKCA0nWcbvYpusARWkFjRQNWNGlt45S+Q18UeS///K6Aw8bB2FKYe9mhVWy/XLShvCweOLZPrnMswIaDXQA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: false optional: true /@esbuild/linux-loong64@0.18.20: @@ -1991,6 +2098,16 @@ packages: cpu: [loong64] os: [linux] requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.19.3: + resolution: {integrity: sha512-qGTgjweER5xqweiWtUIDl9OKz338EQqCwbS9c2Bh5jgEH19xQ1yhgGPNesugmDFq+UUSDtWgZ264st26b3de8A==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: false optional: true /@esbuild/linux-mips64el@0.18.20: @@ -2008,6 +2125,16 @@ packages: cpu: [mips64el] os: [linux] requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.19.3: + resolution: {integrity: sha512-gy1bFskwEyxVMFRNYSvBauDIWNggD6pyxUksc0MV9UOBD138dKTzr8XnM2R4mBsHwVzeuIH8X5JhmNs2Pzrx+A==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: false optional: true /@esbuild/linux-ppc64@0.18.20: @@ -2025,6 +2152,16 @@ packages: cpu: [ppc64] os: [linux] requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.19.3: + resolution: {integrity: sha512-UrYLFu62x1MmmIe85rpR3qou92wB9lEXluwMB/STDzPF9k8mi/9UvNsG07Tt9AqwPQXluMQ6bZbTzYt01+Ue5g==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: false optional: true /@esbuild/linux-riscv64@0.18.20: @@ -2042,6 +2179,16 @@ packages: cpu: [riscv64] os: [linux] requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.19.3: + resolution: {integrity: sha512-9E73TfyMCbE+1AwFOg3glnzZ5fBAFK4aawssvuMgCRqCYzE0ylVxxzjEfut8xjmKkR320BEoMui4o/t9KA96gA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false optional: true /@esbuild/linux-s390x@0.18.20: @@ -2059,6 +2206,16 @@ packages: cpu: [s390x] os: [linux] requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.19.3: + resolution: {integrity: sha512-LlmsbuBdm1/D66TJ3HW6URY8wO6IlYHf+ChOUz8SUAjVTuaisfuwCOAgcxo3Zsu3BZGxmI7yt//yGOxV+lHcEA==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false optional: true /@esbuild/linux-x64@0.18.20: @@ -2076,6 +2233,16 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.19.3: + resolution: {integrity: sha512-ogV0+GwEmvwg/8ZbsyfkYGaLACBQWDvO0Kkh8LKBGKj9Ru8VM39zssrnu9Sxn1wbapA2qNS6BiLdwJZGouyCwQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false optional: true /@esbuild/netbsd-x64@0.18.20: @@ -2093,6 +2260,16 @@ packages: cpu: [x64] os: [netbsd] requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.19.3: + resolution: {integrity: sha512-o1jLNe4uzQv2DKXMlmEzf66Wd8MoIhLNO2nlQBHLtWyh2MitDG7sMpfCO3NTcoTMuqHjfufgUQDFRI5C+xsXQw==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: false optional: true /@esbuild/openbsd-x64@0.18.20: @@ -2110,6 +2287,16 @@ packages: cpu: [x64] os: [openbsd] requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.19.3: + resolution: {integrity: sha512-AZJCnr5CZgZOdhouLcfRdnk9Zv6HbaBxjcyhq0StNcvAdVZJSKIdOiPB9az2zc06ywl0ePYJz60CjdKsQacp5Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: false optional: true /@esbuild/sunos-x64@0.18.20: @@ -2127,6 +2314,16 @@ packages: cpu: [x64] os: [sunos] requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.19.3: + resolution: {integrity: sha512-Acsujgeqg9InR4glTRvLKGZ+1HMtDm94ehTIHKhJjFpgVzZG9/pIcWW/HA/DoMfEyXmANLDuDZ2sNrWcjq1lxw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: false optional: true /@esbuild/win32-arm64@0.18.20: @@ -2144,6 +2341,16 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.19.3: + resolution: {integrity: sha512-FSrAfjVVy7TifFgYgliiJOyYynhQmqgPj15pzLyJk8BUsnlWNwP/IAy6GAiB1LqtoivowRgidZsfpoYLZH586A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false optional: true /@esbuild/win32-ia32@0.18.20: @@ -2161,6 +2368,16 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.19.3: + resolution: {integrity: sha512-xTScXYi12xLOWZ/sc5RBmMN99BcXp/eEf7scUC0oeiRoiT5Vvo9AycuqCp+xdpDyAU+LkrCqEpUS9fCSZF8J3Q==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false optional: true /@esbuild/win32-x64@0.18.20: @@ -2178,6 +2395,16 @@ packages: cpu: [x64] os: [win32] requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.19.3: + resolution: {integrity: sha512-FbUN+0ZRXsypPyWE2IwIkVjDkDnJoMJARWOcFZn4KPPli+QnKqF0z1anvfaYe3ev5HFCpRDLLBDHyOALLppWHw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false optional: true /@eslint-community/eslint-utils@4.4.0(eslint@8.48.0): @@ -2278,13 +2505,13 @@ packages: '@hapi/hoek': 9.3.0 dev: true - /@hono/zod-validator@0.1.8(hono@3.5.6)(zod@3.22.2): + /@hono/zod-validator@0.1.8(hono@3.6.1)(zod@3.22.2): resolution: {integrity: sha512-/Kd/p/dUVKM7/1TY3jafTV+ngwEh3fOLmXCJQKb9esWsCom5WOJaNmZYv8jeRhyipu1xBvmN5jceRA3Ev3rmQw==} peerDependencies: hono: 3.* zod: ^3.19.1 dependencies: - hono: 3.5.6 + hono: 3.6.1 zod: 3.22.2 dev: false @@ -2454,13 +2681,13 @@ packages: - supports-color dev: true - /@mdx-js/esbuild@2.3.0(esbuild@0.19.2): + /@mdx-js/esbuild@2.3.0(esbuild@0.19.3): resolution: {integrity: sha512-r/vsqsM0E+U4Wr0DK+0EfmABE/eg+8ITW4DjvYdh3ve/tK2safaqHArNnaqbOk1DjYGrhxtoXoGaM3BY8fGBTA==} peerDependencies: esbuild: '>=0.11.0' dependencies: '@mdx-js/mdx': 2.3.0 - esbuild: 0.19.2 + esbuild: 0.19.3 node-fetch: 3.3.2 vfile: 5.3.7 transitivePeerDependencies: @@ -2474,7 +2701,7 @@ packages: dependencies: '@mdx-js/mdx': 2.3.0 source-map: 0.7.4 - webpack: 5.88.2(esbuild@0.19.2) + webpack: 5.88.2(esbuild@0.19.3) transitivePeerDependencies: - supports-color dev: false @@ -2838,7 +3065,7 @@ packages: - rollup - supports-color - /@nuxt/module-builder@0.5.1(@nuxt/kit@3.7.0)(nuxi@3.7.3)(typescript@5.2.2): + /@nuxt/module-builder@0.5.1(@nuxt/kit@3.7.0)(nuxi@3.8.4)(typescript@5.2.2): resolution: {integrity: sha512-O39UrOFbNgL27urwDqeMgXeYiNIUvp73nsmtt7jm9JDcMVIWykuUzyBPYtHif7gq5ElzIjjmDw9zdRGgyMzo+w==} hasBin: true peerDependencies: @@ -2849,7 +3076,7 @@ packages: consola: 3.2.3 mlly: 1.4.1 mri: 1.2.0 - nuxi: 3.7.3 + nuxi: 3.8.4 pathe: 1.1.1 unbuild: 2.0.0(typescript@5.2.2) transitivePeerDependencies: @@ -3048,7 +3275,7 @@ packages: wrap-ansi: 7.0.0 dev: true - /@oclif/core@2.8.11(@types/node@20.5.7)(typescript@5.2.2): + /@oclif/core@2.8.11(@types/node@20.6.1)(typescript@5.2.2): resolution: {integrity: sha512-9wYW6KRSWfB/D+tqeyl/jxmEz/xPXkFJGVWfKaptqHz6FPWNJREjAM945MuJL2Y8NRhMe+ScRlZ3WpdToX5aVQ==} engines: {node: '>=14.0.0'} dependencies: @@ -3076,7 +3303,7 @@ packages: strip-ansi: 6.0.1 supports-color: 8.1.1 supports-hyperlinks: 2.3.0 - ts-node: 10.9.1(@types/node@20.5.7)(typescript@5.2.2) + ts-node: 10.9.1(@types/node@20.6.1)(typescript@5.2.2) tslib: 2.6.2 widest-line: 3.1.0 wordwrap: 1.0.0 @@ -3099,12 +3326,12 @@ packages: '@oclif/core': 1.26.2 dev: true - /@oclif/plugin-not-found@2.3.23(@types/node@20.5.7)(typescript@5.2.2): + /@oclif/plugin-not-found@2.3.23(@types/node@20.6.1)(typescript@5.2.2): resolution: {integrity: sha512-UZM8aolxXvqwH8WcmJxRNASDWgMoSQm/pgCdkc1AGCRevYc8+LBSO+U6nLWq+Dx8H/dn9RyIv5oiUIOGkKDlZA==} engines: {node: '>=12.0.0'} dependencies: '@oclif/color': 1.0.11 - '@oclif/core': 2.8.11(@types/node@20.5.7)(typescript@5.2.2) + '@oclif/core': 2.8.11(@types/node@20.6.1)(typescript@5.2.2) fast-levenshtein: 3.0.0 lodash: 4.17.21 transitivePeerDependencies: @@ -3114,12 +3341,12 @@ packages: - typescript dev: true - /@oclif/plugin-plugins@2.3.0(@types/node@20.5.7)(typescript@5.2.2): + /@oclif/plugin-plugins@2.3.0(@types/node@20.6.1)(typescript@5.2.2): resolution: {integrity: sha512-VmlLLYE4LCXX2RGNv4ht8AqG9OADvLIE4Kxhm18h5RZ9cMee7U6nrHQeW455lh/idnWC2XT7bHgJBv2kgYxSiQ==} engines: {node: '>=12.0.0'} dependencies: '@oclif/color': 1.0.11 - '@oclif/core': 2.8.11(@types/node@20.5.7)(typescript@5.2.2) + '@oclif/core': 2.8.11(@types/node@20.6.1)(typescript@5.2.2) chalk: 4.1.2 debug: 4.3.4(supports-color@8.1.1) fs-extra: 9.1.0 @@ -3137,11 +3364,11 @@ packages: - typescript dev: true - /@oclif/plugin-warn-if-update-available@2.0.24(@types/node@20.5.7)(typescript@5.2.2): + /@oclif/plugin-warn-if-update-available@2.0.24(@types/node@20.6.1)(typescript@5.2.2): resolution: {integrity: sha512-Rq8/EZ8wQawvPWS6W59Zhf/zSz/umLc3q75I1ybi7pul6YMNwf/E1eDVHytSUEQ6yQV+p3cCs034IItz4CVdjw==} engines: {node: '>=12.0.0'} dependencies: - '@oclif/core': 2.8.11(@types/node@20.5.7)(typescript@5.2.2) + '@oclif/core': 2.8.11(@types/node@20.6.1)(typescript@5.2.2) chalk: 4.1.2 debug: 4.3.4(supports-color@8.1.1) fs-extra: 9.1.0 @@ -3171,6 +3398,7 @@ packages: /@opentelemetry/api@1.4.1: resolution: {integrity: sha512-O2yRJce1GOc6PAy3QxFM4NzFiWzvScDC1/5ihYBL6BUEVdq0XMWN01sppE+H6bBXbaFYipjwFLEWLg5PaSOThA==} engines: {node: '>=8.0.0'} + dev: false /@opentelemetry/context-async-hooks@1.13.0(@opentelemetry/api@1.4.1): resolution: {integrity: sha512-pS5fU4lrRjOIPZQqA2V1SUM9QUFXbO+8flubAiy6ntLjnAjJJUdRFOUOxK6v86ZHI2p2S8A0vD0BTu95FZYvjA==} @@ -5028,7 +5256,7 @@ packages: deepmerge: 4.3.1 is-builtin-module: 3.2.1 is-module: 1.0.0 - resolve: 1.22.4 + resolve: 1.22.5 rollup: 3.28.1 dev: true @@ -5197,7 +5425,7 @@ packages: rollup: 2.78.0 stacktrace-parser: 0.1.10 tslib: 2.6.2 - webpack: 5.88.2(esbuild@0.19.2) + webpack: 5.88.2(esbuild@0.19.3) transitivePeerDependencies: - encoding - supports-color @@ -5641,6 +5869,9 @@ packages: /@types/node@20.5.7: resolution: {integrity: sha512-dP7f3LdZIysZnmvP3ANJYTSwg+wLLl8p7RqniVlV7j+oXSXAbt9h0WIBFmJy5inWZoX9wZN6eXx+YXd9Rh3RBA==} + /@types/node@20.6.1: + resolution: {integrity: sha512-4LcJvuXQlv4lTHnxwyHQZ3uR9Zw2j7m1C9DfuwoTFQQP4Pmu04O6IfLYgMmHoOCt0nosItLLZAH+sOrRE0Bo8g==} + /@types/normalize-package-data@2.4.1: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} dev: true @@ -6694,7 +6925,7 @@ packages: postcss: ^8.1.0 dependencies: browserslist: 4.21.10 - caniuse-lite: 1.0.30001525 + caniuse-lite: 1.0.30001534 fraction.js: 4.3.6 normalize-range: 0.1.2 picocolors: 1.0.0 @@ -7036,7 +7267,7 @@ packages: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} dependencies: browserslist: 4.21.10 - caniuse-lite: 1.0.30001525 + caniuse-lite: 1.0.30001534 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 dev: true @@ -7044,6 +7275,9 @@ packages: /caniuse-lite@1.0.30001525: resolution: {integrity: sha512-/3z+wB4icFt3r0USMwxujAqRvaD/B7rvGTsKhbhSQErVrJvkZCLhgNLJxU8MevahQVH6hCU9FsHdNUFbiwmE7Q==} + /caniuse-lite@1.0.30001534: + resolution: {integrity: sha512-vlPVrhsCS7XaSh2VvWluIQEzVhefrUQcEsQWSS5A5V+dM07uv1qHeQzAOTGIMy9i3e9bH15+muvI/UHojVgS/Q==} + /cardinal@2.1.1: resolution: {integrity: sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==} hasBin: true @@ -7140,16 +7374,16 @@ packages: resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} dev: true - /checkly@4.1.0(@types/node@20.5.7)(typescript@5.2.2): + /checkly@4.1.0(@types/node@20.6.1)(typescript@5.2.2): resolution: {integrity: sha512-5hcYaEMokj0CX4ue/HMCSfsL6lvOzBPabSj+lRPDLL1sLnGNb2bqJhiDVe3TNsqvR06bEFuuuuZMeX+gyQHhyg==} engines: {node: '>=16.0.0'} hasBin: true dependencies: - '@oclif/core': 2.8.11(@types/node@20.5.7)(typescript@5.2.2) + '@oclif/core': 2.8.11(@types/node@20.6.1)(typescript@5.2.2) '@oclif/plugin-help': 5.1.20 - '@oclif/plugin-not-found': 2.3.23(@types/node@20.5.7)(typescript@5.2.2) - '@oclif/plugin-plugins': 2.3.0(@types/node@20.5.7)(typescript@5.2.2) - '@oclif/plugin-warn-if-update-available': 2.0.24(@types/node@20.5.7)(typescript@5.2.2) + '@oclif/plugin-not-found': 2.3.23(@types/node@20.6.1)(typescript@5.2.2) + '@oclif/plugin-plugins': 2.3.0(@types/node@20.6.1)(typescript@5.2.2) + '@oclif/plugin-warn-if-update-available': 2.0.24(@types/node@20.6.1)(typescript@5.2.2) '@typescript-eslint/typescript-estree': 5.46.1(typescript@5.2.2) acorn: 8.8.1 acorn-walk: 8.2.0 @@ -7513,17 +7747,17 @@ packages: engines: {node: '>= 0.6'} dev: true - /contentlayer@0.3.4(esbuild@0.19.2): + /contentlayer@0.3.4(esbuild@0.19.3): resolution: {integrity: sha512-FYDdTUFaN4yqep0waswrhcXjmMJnPD5iXDTtxcUCGdklfuIrXM2xLx51xl748cHmGA6IsC+27YZFxU6Ym13QIA==} engines: {node: '>=14.18'} hasBin: true requiresBuild: true dependencies: - '@contentlayer/cli': 0.3.4(esbuild@0.19.2) - '@contentlayer/client': 0.3.4(esbuild@0.19.2) - '@contentlayer/core': 0.3.4(esbuild@0.19.2) - '@contentlayer/source-files': 0.3.4(esbuild@0.19.2) - '@contentlayer/source-remote-files': 0.3.4(esbuild@0.19.2) + '@contentlayer/cli': 0.3.4(esbuild@0.19.3) + '@contentlayer/client': 0.3.4(esbuild@0.19.3) + '@contentlayer/core': 0.3.4(esbuild@0.19.3) + '@contentlayer/source-files': 0.3.4(esbuild@0.19.3) + '@contentlayer/source-remote-files': 0.3.4(esbuild@0.19.3) '@contentlayer/utils': 0.3.4 transitivePeerDependencies: - '@effect-ts/otel-node' @@ -7864,7 +8098,7 @@ packages: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} engines: {node: '>=0.11'} dependencies: - '@babel/runtime': 7.22.11 + '@babel/runtime': 7.22.15 dev: false /debounce-fn@4.0.0: @@ -8582,8 +8816,8 @@ packages: safe-array-concat: 1.0.0 dev: false - /es-module-lexer@1.3.0: - resolution: {integrity: sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==} + /es-module-lexer@1.3.1: + resolution: {integrity: sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==} dev: false /es-set-tostringtag@2.0.1: @@ -8718,6 +8952,37 @@ packages: '@esbuild/win32-arm64': 0.19.2 '@esbuild/win32-ia32': 0.19.2 '@esbuild/win32-x64': 0.19.2 + dev: true + + /esbuild@0.19.3: + resolution: {integrity: sha512-UlJ1qUUA2jL2nNib1JTSkifQTcYTroFqRjwCFW4QYEKEsixXD5Tik9xML7zh2gTxkYTBKGHNH9y7txMwVyPbjw==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.19.3 + '@esbuild/android-arm64': 0.19.3 + '@esbuild/android-x64': 0.19.3 + '@esbuild/darwin-arm64': 0.19.3 + '@esbuild/darwin-x64': 0.19.3 + '@esbuild/freebsd-arm64': 0.19.3 + '@esbuild/freebsd-x64': 0.19.3 + '@esbuild/linux-arm': 0.19.3 + '@esbuild/linux-arm64': 0.19.3 + '@esbuild/linux-ia32': 0.19.3 + '@esbuild/linux-loong64': 0.19.3 + '@esbuild/linux-mips64el': 0.19.3 + '@esbuild/linux-ppc64': 0.19.3 + '@esbuild/linux-riscv64': 0.19.3 + '@esbuild/linux-s390x': 0.19.3 + '@esbuild/linux-x64': 0.19.3 + '@esbuild/netbsd-x64': 0.19.3 + '@esbuild/openbsd-x64': 0.19.3 + '@esbuild/sunos-x64': 0.19.3 + '@esbuild/win32-arm64': 0.19.3 + '@esbuild/win32-ia32': 0.19.3 + '@esbuild/win32-x64': 0.19.3 + dev: false /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} @@ -8768,7 +9033,7 @@ packages: dependencies: debug: 3.2.7 is-core-module: 2.13.0 - resolve: 1.22.4 + resolve: 1.22.5 transitivePeerDependencies: - supports-color dev: false @@ -10135,8 +10400,8 @@ packages: parse-passwd: 1.0.0 dev: true - /hono@3.5.6: - resolution: {integrity: sha512-ycTOpIZJ6yLbjzoE+ojsesC7G7ZXfGSoCIDyvqmzlHc5Mk4Aj48Ed9R5g7gw3v7rOkS81pjcYIvWef/karq1iA==} + /hono@3.6.1: + resolution: {integrity: sha512-FaWXh0MSc2Hv2IrGI4vFvZEK69NHfggEgHUlNMXp2zrpKh23j7wS0Ku316Do9CFAl07OBNozBelcvruiBT8crQ==} engines: {node: '>=16.0.0'} dev: false @@ -10839,7 +11104,7 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 20.5.7 + '@types/node': 20.6.1 merge-stream: 2.0.0 supports-color: 8.1.1 dev: false @@ -10848,6 +11113,10 @@ packages: resolution: {integrity: sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w==} hasBin: true + /jiti@1.20.0: + resolution: {integrity: sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==} + hasBin: true + /joi@17.10.1: resolution: {integrity: sha512-vIiDxQKmRidUVp8KngT8MZSOcmRVm2zV7jbMjNYWuHcJWI0bUck3nRTGQjhpPlQenIQIBC5Vp9AhcnHbWQqafw==} dependencies: @@ -11667,17 +11936,17 @@ packages: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} dev: true - /mdx-bundler@9.2.1(esbuild@0.19.2): + /mdx-bundler@9.2.1(esbuild@0.19.3): resolution: {integrity: sha512-hWEEip1KU9MCNqeH2rqwzAZ1pdqPPbfkx9OTJjADqGPQz4t9BO85fhI7AP9gVYrpmfArf9/xJZUN0yBErg/G/Q==} engines: {node: '>=14', npm: '>=6'} peerDependencies: esbuild: 0.* dependencies: '@babel/runtime': 7.22.11 - '@esbuild-plugins/node-resolve': 0.1.4(esbuild@0.19.2) + '@esbuild-plugins/node-resolve': 0.1.4(esbuild@0.19.3) '@fal-works/esbuild-plugin-global-externals': 2.1.2 - '@mdx-js/esbuild': 2.3.0(esbuild@0.19.2) - esbuild: 0.19.2 + '@mdx-js/esbuild': 2.3.0(esbuild@0.19.3) + esbuild: 0.19.3 gray-matter: 4.0.3 remark-frontmatter: 4.0.1 remark-mdx-frontmatter: 1.1.1 @@ -12294,7 +12563,7 @@ packages: esbuild: 0.18.20 fs-extra: 11.1.1 globby: 13.2.2 - jiti: 1.19.3 + jiti: 1.20.0 mlly: 1.4.1 mri: 1.2.0 pathe: 1.1.1 @@ -12428,7 +12697,7 @@ packages: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} dev: false - /next-contentlayer@0.3.4(contentlayer@0.3.4)(esbuild@0.19.2)(next@13.4.19)(react-dom@18.2.0)(react@18.2.0): + /next-contentlayer@0.3.4(contentlayer@0.3.4)(esbuild@0.19.3)(next@13.4.19)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-UtUCwgAl159KwfhNaOwyiI7Lg6sdioyKMeh+E7jxx0CJ29JuXGxBEYmCI6+72NxFGIFZKx8lvttbbQhbnYWYSw==} peerDependencies: contentlayer: 0.3.4 @@ -12436,9 +12705,9 @@ packages: react: '*' react-dom: '*' dependencies: - '@contentlayer/core': 0.3.4(esbuild@0.19.2) + '@contentlayer/core': 0.3.4(esbuild@0.19.3) '@contentlayer/utils': 0.3.4 - contentlayer: 0.3.4(esbuild@0.19.2) + contentlayer: 0.3.4(esbuild@0.19.3) next: 13.4.19(@opentelemetry/api@1.4.1)(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -12504,6 +12773,46 @@ packages: transitivePeerDependencies: - '@babel/core' - babel-plugin-macros + dev: false + + /next@13.4.19(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-HuPSzzAbJ1T4BD8e0bs6B9C1kWQ6gv8ykZoRWs5AQoiIuqbGHHdQO7Ljuvg05Q0Z24E2ABozHe6FxDvI6HfyAw==} + engines: {node: '>=16.8.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + react: ^18.2.0 + react-dom: ^18.2.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + sass: + optional: true + dependencies: + '@next/env': 13.4.19 + '@swc/helpers': 0.5.1 + busboy: 1.6.0 + caniuse-lite: 1.0.30001534 + postcss: 8.4.14 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + styled-jsx: 5.1.1(react@18.2.0) + watchpack: 2.4.0 + zod: 3.21.4 + optionalDependencies: + '@next/swc-darwin-arm64': 13.4.19 + '@next/swc-darwin-x64': 13.4.19 + '@next/swc-linux-arm64-gnu': 13.4.19 + '@next/swc-linux-arm64-musl': 13.4.19 + '@next/swc-linux-x64-gnu': 13.4.19 + '@next/swc-linux-x64-musl': 13.4.19 + '@next/swc-win32-arm64-msvc': 13.4.19 + '@next/swc-win32-ia32-msvc': 13.4.19 + '@next/swc-win32-x64-msvc': 13.4.19 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros /nitropack@2.6.2: resolution: {integrity: sha512-gzbxLIhCoQrK+NrgW5Szuo6zzFEU/bqoohimyJ8IkETI3MXlYtLphlW/UVE8pv8UQ0IJ2HzxFpZ7Ldd0+bQ35A==} @@ -12683,7 +12992,7 @@ packages: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.4 + resolve: 1.22.5 semver: 5.7.2 validate-npm-package-license: 3.0.4 dev: true @@ -12822,6 +13131,14 @@ packages: fsevents: 2.3.3 dev: true + /nuxi@3.8.4: + resolution: {integrity: sha512-YQAH2msfL1PeaDuk880jQAJdtF1hpuYaTQ7j8Ombl+SyyamcB9VTx0gbkNyZj7wmJQYxfiV6a42nlGQ7cJDO+g==} + engines: {node: ^14.18.0 || >=16.10.0} + hasBin: true + optionalDependencies: + fsevents: 2.3.3 + dev: true + /nuxt@3.7.0(@types/node@20.5.7)(rollup@3.28.1)(typescript@5.2.2): resolution: {integrity: sha512-y0/xHYqwuJt20r26xezjpr74FLWR144dMpwSxZ/O2XXUrQUnyO7vHm3fEY4vi+miKbf343YMH5B78GXAELO/Vw==} engines: {node: ^14.18.0 || >=16.10.0} @@ -13585,7 +13902,7 @@ packages: dependencies: lilconfig: 2.1.0 postcss: 8.4.29 - ts-node: 10.9.1(@types/node@20.5.7)(typescript@5.2.2) + ts-node: 10.9.1(@types/node@20.6.1)(typescript@5.2.2) yaml: 2.3.2 /postcss-merge-longhand@6.0.0(postcss@8.4.29): @@ -14480,6 +14797,14 @@ packages: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + /resolve@1.22.5: + resolution: {integrity: sha512-qWhv7PF1V95QPvRoUGHxOtnAlEvlXBylMZcjUR9pAumMmveFtcHJRXGIr+TkjfNJVQypqv2qcDiiars2y1PsSg==} + hasBin: true + dependencies: + is-core-module: 2.13.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + /resolve@2.0.0-next.4: resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} hasBin: true @@ -15398,7 +15723,7 @@ packages: fast-glob: 3.3.1 glob-parent: 6.0.2 is-glob: 4.0.3 - jiti: 1.19.3 + jiti: 1.20.0 lilconfig: 2.1.0 micromatch: 4.0.5 normalize-path: 3.0.0 @@ -15410,7 +15735,7 @@ packages: postcss-load-config: 4.0.1(postcss@8.4.29)(ts-node@10.9.1) postcss-nested: 6.0.1(postcss@8.4.29) postcss-selector-parser: 6.0.13 - resolve: 1.22.4 + resolve: 1.22.5 sucrase: 3.34.0 transitivePeerDependencies: - ts-node @@ -15439,7 +15764,7 @@ packages: is-regex: 1.1.4 minimist: 1.2.8 object-inspect: 1.12.3 - resolve: 1.22.4 + resolve: 1.22.5 resumer: 0.0.0 string.prototype.trim: 1.2.7 through: 2.3.8 @@ -15485,7 +15810,7 @@ packages: engines: {node: '>=8'} dev: true - /terser-webpack-plugin@5.3.9(esbuild@0.19.2)(webpack@5.88.2): + /terser-webpack-plugin@5.3.9(esbuild@0.19.3)(webpack@5.88.2): resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==} engines: {node: '>= 10.13.0'} peerDependencies: @@ -15502,12 +15827,12 @@ packages: optional: true dependencies: '@jridgewell/trace-mapping': 0.3.19 - esbuild: 0.19.2 + esbuild: 0.19.3 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.1 - terser: 5.19.3 - webpack: 5.88.2(esbuild@0.19.2) + terser: 5.19.4 + webpack: 5.88.2(esbuild@0.19.3) dev: false /terser@5.19.3: @@ -15519,6 +15844,18 @@ packages: acorn: 8.10.0 commander: 2.20.3 source-map-support: 0.5.21 + dev: true + + /terser@5.19.4: + resolution: {integrity: sha512-6p1DjHeuluwxDXcuT9VR8p64klWJKo1ILiy19s6C9+0Bh2+NWTX6nD9EPppiER4ICkHDVB1RkVpin/YW2nQn/g==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.5 + acorn: 8.10.0 + commander: 2.20.3 + source-map-support: 0.5.21 + dev: false /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -15694,7 +16031,7 @@ packages: dev: true optional: true - /ts-node@10.9.1(@types/node@20.5.7)(typescript@5.2.2): + /ts-node@10.9.1(@types/node@20.6.1)(typescript@5.2.2): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -15713,7 +16050,7 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.5.7 + '@types/node': 20.6.1 acorn: 8.8.1 acorn-walk: 8.2.0 arg: 4.1.3 @@ -16069,7 +16406,7 @@ packages: esbuild: 0.19.2 globby: 13.2.2 hookable: 5.5.3 - jiti: 1.19.3 + jiti: 1.20.0 magic-string: 0.30.3 mkdist: 1.3.0(typescript@5.2.2) mlly: 1.4.1 @@ -16378,7 +16715,7 @@ packages: '@babel/standalone': 7.22.14 '@babel/types': 7.22.11 defu: 6.1.2 - jiti: 1.19.3 + jiti: 1.20.0 mri: 1.2.0 scule: 1.0.0 transitivePeerDependencies: @@ -16904,7 +17241,7 @@ packages: /webpack-virtual-modules@0.5.0: resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==} - /webpack@5.88.2(esbuild@0.19.2): + /webpack@5.88.2(esbuild@0.19.3): resolution: {integrity: sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==} engines: {node: '>=10.13.0'} hasBin: true @@ -16924,7 +17261,7 @@ packages: browserslist: 4.21.10 chrome-trace-event: 1.0.3 enhanced-resolve: 5.15.0 - es-module-lexer: 1.3.0 + es-module-lexer: 1.3.1 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -16935,7 +17272,7 @@ packages: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.9(esbuild@0.19.2)(webpack@5.88.2) + terser-webpack-plugin: 5.3.9(esbuild@0.19.3)(webpack@5.88.2) watchpack: 2.4.0 webpack-sources: 3.2.3 transitivePeerDependencies: