diff --git a/.changeset/bounded-bedrock-and-priced-calls.md b/.changeset/bounded-bedrock-and-priced-calls.md new file mode 100644 index 0000000..32c1c29 --- /dev/null +++ b/.changeset/bounded-bedrock-and-priced-calls.md @@ -0,0 +1,11 @@ +--- +'@eks-agent/sdk': minor +'@eks-agent/pricing': minor +'@eks-agent/core': minor +--- + +Harden the Bedrock call path and make unpriced traffic observable. + +- `@eks-agent/sdk`: every `BedrockAdapter.messages()` call now carries a bounded request deadline even when the caller passes no `AbortSignal`. New `requestTimeoutMs` option (default 60s); a caller-supplied signal is combined with the deadline rather than replacing it, and a deadline fire classifies as a retryable `Network` error. +- `@eks-agent/pricing`: new `priceModel()` returns `{ costUsd, priced }` so an unknown model id is observable instead of silently metering as `$0`. `estimateCost()` is unchanged and now delegates to `priceModel`. +- `@eks-agent/core`: `CallEvent` gains an optional `unpriced` flag, set by the SDK when a model id has no pricing entry, so cost dashboards can surface unmetered traffic. diff --git a/.github/workflows/security.yaml b/.github/workflows/security.yaml index 7aca05c..b6c37ef 100644 --- a/.github/workflows/security.yaml +++ b/.github/workflows/security.yaml @@ -37,7 +37,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: aquasecurity/trivy-action@master + - uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 with: scan-type: config scan-ref: . @@ -68,7 +68,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: aquasecurity/trivy-action@master + - uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 with: scan-type: fs scan-ref: . @@ -105,7 +105,7 @@ jobs: with: go-version-file: operators/go.mod cache-dependency-path: operators/go.sum - - uses: securego/gosec@master + - uses: securego/gosec@9e6a9843d7a4a6e3e9a8539b02612c8a4aa3f889 # v2.27.1 with: args: -severity medium -fmt sarif -out gosec.sarif ./operators/... - uses: github/codeql-action/upload-sarif@v3 diff --git a/docs/adr/0002-bedrock-only-v1.md b/docs/adr/0002-bedrock-only-v1.md index fe70e84..41caf9f 100644 --- a/docs/adr/0002-bedrock-only-v1.md +++ b/docs/adr/0002-bedrock-only-v1.md @@ -21,5 +21,5 @@ v1 ships only `BedrockAdapter` with per-family submodules (Anthropic, Meta, Mist ## Consequences - The SDK has a thin family of adapters that share `BedrockAdapter` as a base. Adding a model family means adding `buildRequestBody` + `parseResponseBody` for that family's wire shape, nothing more. -- Pricing tables live in `@eks-agent/pricing` and are Bedrock-only. Renovate refresh is weekly. +- Pricing tables live in `@eks-agent/pricing`, are Bedrock-only, and are hand-curated — Renovate bumps the package's deps, not the `PRICES` content. An automated refresh from the AWS Pricing API (`scripts/refresh-pricing.mjs`) is Phase-2 and currently a fail-loud scaffold; until it lands, prices are updated by hand, and a model id missing from the table meters as an unmetered `0` (`priced:false` via `priceModel`) rather than a silent real `$0`. - The error taxonomy in `@eks-agent/core` is provider-agnostic, so the day we add a non-Bedrock adapter, downstream code doesn't change. diff --git a/operators/internal/awsclients/clients.go b/operators/internal/awsclients/clients.go index 667151e..ce23071 100644 --- a/operators/internal/awsclients/clients.go +++ b/operators/internal/awsclients/clients.go @@ -9,8 +9,10 @@ package awsclients import ( "context" "fmt" + "time" "github.com/aws/aws-sdk-go-v2/aws" + awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" awsconfig "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/athena" "github.com/aws/aws-sdk-go-v2/service/bedrock" @@ -38,11 +40,22 @@ type Clients struct { Bedrock Bedrock } +// awsHTTPTimeout bounds every AWS SDK request. controller-runtime does not +// decorate the reconcile context with a per-call deadline, and the SDK's +// default transport sets no overall request timeout — so without this a +// connection that establishes then stalls before responding would pin a +// bounded reconcile worker indefinitely, eventually starving the pool. 30s +// comfortably covers the slowest single control-plane call; the Athena poll +// path bounds its own multi-call loop separately (budget_reconcile.go). +const awsHTTPTimeout = 30 * time.Second + // New builds a Clients backed by the default credential chain (IRSA via // fromContainerCredentials → fromEnv → fromInstanceProfile). Region is // resolved from the same chain unless explicitly passed. func New(ctx context.Context, region string) (*Clients, error) { - opts := []func(*awsconfig.LoadOptions) error{} + opts := []func(*awsconfig.LoadOptions) error{ + awsconfig.WithHTTPClient(awshttp.NewBuildableClient().WithTimeout(awsHTTPTimeout)), + } if region != "" { opts = append(opts, awsconfig.WithRegion(region)) } diff --git a/operators/internal/controller/budget_killswitch_test.go b/operators/internal/controller/budget_killswitch_test.go new file mode 100644 index 0000000..997d0ab --- /dev/null +++ b/operators/internal/controller/budget_killswitch_test.go @@ -0,0 +1,77 @@ +/* +Copyright 2026 stxkxs. + +Licensed under the Apache License, Version 2.0 (the "License"); +*/ + +package controller + +import ( + "context" + "strings" + "testing" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/eventbridge" + ebtypes "github.com/aws/aws-sdk-go-v2/service/eventbridge/types" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + commonv1alpha1 "github.com/nanohype/eks-agent-platform/operators/api/common/v1alpha1" + governancev1alpha1 "github.com/nanohype/eks-agent-platform/operators/api/governance/v1alpha1" +) + +// fakeEventBridge is a minimal in-memory awsclients.EventBridge that returns a +// canned PutEvents result so the partial-failure branch can be asserted. +type fakeEventBridge struct { + out *eventbridge.PutEventsOutput + calls []eventbridge.PutEventsInput +} + +func (f *fakeEventBridge) PutEvents(_ context.Context, params *eventbridge.PutEventsInput, _ ...func(*eventbridge.Options)) (*eventbridge.PutEventsOutput, error) { + f.calls = append(f.calls, *params) + return f.out, nil +} + +func newBudgetPolicy() *governancev1alpha1.BudgetPolicy { + return &governancev1alpha1.BudgetPolicy{ + ObjectMeta: metav1.ObjectMeta{Name: "acme-budget", Namespace: "tenants-acme"}, + Spec: governancev1alpha1.BudgetPolicySpec{ + PlatformRef: commonv1alpha1.LocalRef{Name: "acme"}, + MonthlyUsd: "100.00", + }, + } +} + +func TestFireKillSwitch_SuccessReturnsNil(t *testing.T) { + eb := &fakeEventBridge{out: &eventbridge.PutEventsOutput{FailedEntryCount: 0}} + r := &BudgetReconciler{EventBridge: eb, KillSwitchEventBusName: "killswitch-bus"} + + if err := r.fireKillSwitch(context.Background(), newBudgetPolicy(), "150.00", 150); err != nil { + t.Fatalf("fireKillSwitch on a clean PutEvents must return nil, got %v", err) + } + if len(eb.calls) != 1 { + t.Fatalf("want exactly 1 PutEvents call, got %d", len(eb.calls)) + } + if got := aws.ToString(eb.calls[0].Entries[0].EventBusName); got != "killswitch-bus" { + t.Errorf("event bus = %q, want killswitch-bus", got) + } +} + +func TestFireKillSwitch_PartialFailureIsRetryableError(t *testing.T) { + eb := &fakeEventBridge{out: &eventbridge.PutEventsOutput{ + FailedEntryCount: 1, + Entries: []ebtypes.PutEventsResultEntry{{ + ErrorCode: aws.String("ThrottlingException"), + ErrorMessage: aws.String("rate exceeded"), + }}, + }} + r := &BudgetReconciler{EventBridge: eb, KillSwitchEventBusName: "killswitch-bus"} + + err := r.fireKillSwitch(context.Background(), newBudgetPolicy(), "150.00", 150) + if err == nil { + t.Fatal("FailedEntryCount>0 must surface as an error so the kill-switch is retried, got nil") + } + if !strings.Contains(err.Error(), "ThrottlingException") { + t.Errorf("error must carry the failed entry's ErrorCode, got %q", err.Error()) + } +} diff --git a/operators/internal/controller/labels.go b/operators/internal/controller/labels.go index f7e768a..0a4714b 100644 --- a/operators/internal/controller/labels.go +++ b/operators/internal/controller/labels.go @@ -17,6 +17,9 @@ package controller // prevent. const labelPrefix = "agents.nanohype.dev" +// Exported label keys, one per kind of object the operator labels. Each is the +// single source of truth for both the object's metadata label and any selector +// that matches it. const ( LabelPlatform = labelPrefix + "/platform" LabelTenant = labelPrefix + "/tenant" diff --git a/operators/internal/controller/platform_controller.go b/operators/internal/controller/platform_controller.go index e6b377c..7ff9ae8 100644 --- a/operators/internal/controller/platform_controller.go +++ b/operators/internal/controller/platform_controller.go @@ -9,6 +9,7 @@ package controller import ( "context" "fmt" + "sync" "time" corev1 "k8s.io/api/core/v1" @@ -52,6 +53,14 @@ type PlatformReconciler struct { // AWSCfg carries the SSM-resolved values the KMS + S3 steps need: // DataKMSKeyARN, ArtifactsBucketName, Environment. AWSCfg PlatformAWSConfig + + // bucketPolicyMu serializes the read-modify-write of the SHARED artifacts + // bucket policy across concurrent reconciles. That policy is one document + // holding a statement per tenant; with MaxConcurrentReconciles > 1 two + // Platform reconciles could otherwise interleave Get→mutate→Put and + // silently drop a peer tenant's statement. The operator runs as a single + // leader (leader election), so a process-local mutex is sufficient. + bucketPolicyMu sync.Mutex } // +kubebuilder:rbac:groups=platform.nanohype.dev,resources=platforms,verbs=get;list;watch;update;patch diff --git a/operators/internal/controller/platform_kms_s3.go b/operators/internal/controller/platform_kms_s3.go index bfc37d5..2f3bf89 100644 --- a/operators/internal/controller/platform_kms_s3.go +++ b/operators/internal/controller/platform_kms_s3.go @@ -168,6 +168,12 @@ func (r *PlatformReconciler) ensureBucketPolicy(ctx context.Context, p *platform }, } + // Serialize the shared-bucket-policy read-modify-write so concurrent + // reconciles can't interleave Get→mutate→Put and drop a peer tenant's + // statement (see PlatformReconciler.bucketPolicyMu). + r.bucketPolicyMu.Lock() + defer r.bucketPolicyMu.Unlock() + currentDoc, err := r.fetchBucketPolicy(ctx, bucket) if err != nil { return err @@ -210,6 +216,10 @@ func (r *PlatformReconciler) removeBucketPolicyStatements(ctx context.Context, p } bucket := cfg.ArtifactsBucketName sid := "TenantAccess-" + p.Name + // Same shared-document serialization as ensureBucketPolicy: a finalizer + // teardown must not interleave with a peer tenant's reconcile write. + r.bucketPolicyMu.Lock() + defer r.bucketPolicyMu.Unlock() currentDoc, err := r.fetchBucketPolicy(ctx, bucket) if err != nil { return err diff --git a/operators/internal/controller/platform_kms_s3_reconcile_test.go b/operators/internal/controller/platform_kms_s3_reconcile_test.go new file mode 100644 index 0000000..5bc624c --- /dev/null +++ b/operators/internal/controller/platform_kms_s3_reconcile_test.go @@ -0,0 +1,233 @@ +/* +Copyright 2026 stxkxs. + +Licensed under the Apache License, Version 2.0 (the "License"); +*/ + +package controller + +import ( + "context" + "encoding/json" + "testing" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/kms" + kmstypes "github.com/aws/aws-sdk-go-v2/service/kms/types" + "github.com/aws/aws-sdk-go-v2/service/s3" + smithy "github.com/aws/smithy-go" +) + +// fakeKMS is a minimal in-memory awsclients.KMS. The interface is exactly the +// three methods below, so there is nothing left to panic-guard. +type fakeKMS struct { + grants []kmstypes.GrantListEntry + created []kms.CreateGrantInput + revoked []string + pageBoundary int // if > 0, paginate ListGrants at this size +} + +func (f *fakeKMS) ListGrants(_ context.Context, params *kms.ListGrantsInput, _ ...func(*kms.Options)) (*kms.ListGrantsOutput, error) { + if f.pageBoundary > 0 && len(f.grants) > f.pageBoundary { + if params.Marker == nil { + return &kms.ListGrantsOutput{Grants: f.grants[:f.pageBoundary], Truncated: true, NextMarker: aws.String("page-2")}, nil + } + return &kms.ListGrantsOutput{Grants: f.grants[f.pageBoundary:]}, nil + } + return &kms.ListGrantsOutput{Grants: f.grants}, nil +} + +func (f *fakeKMS) CreateGrant(_ context.Context, params *kms.CreateGrantInput, _ ...func(*kms.Options)) (*kms.CreateGrantOutput, error) { + f.created = append(f.created, *params) + id := "grant-" + aws.ToString(params.Name) + f.grants = append(f.grants, kmstypes.GrantListEntry{Name: params.Name, GrantId: aws.String(id)}) + return &kms.CreateGrantOutput{GrantId: aws.String(id)}, nil +} + +func (f *fakeKMS) RevokeGrant(_ context.Context, params *kms.RevokeGrantInput, _ ...func(*kms.Options)) (*kms.RevokeGrantOutput, error) { + f.revoked = append(f.revoked, aws.ToString(params.GrantId)) + return &kms.RevokeGrantOutput{}, nil +} + +// fakeS3 is a minimal in-memory awsclients.S3 holding one bucket-policy doc. +type fakeS3 struct { + policy *string // nil => GetBucketPolicy returns NoSuchBucketPolicy + puts []string +} + +func (f *fakeS3) GetBucketPolicy(_ context.Context, _ *s3.GetBucketPolicyInput, _ ...func(*s3.Options)) (*s3.GetBucketPolicyOutput, error) { + if f.policy == nil { + return nil, &smithy.GenericAPIError{Code: "NoSuchBucketPolicy", Message: "no policy set"} + } + return &s3.GetBucketPolicyOutput{Policy: f.policy}, nil +} + +func (f *fakeS3) PutBucketPolicy(_ context.Context, params *s3.PutBucketPolicyInput, _ ...func(*s3.Options)) (*s3.PutBucketPolicyOutput, error) { + doc := aws.ToString(params.Policy) + f.policy = aws.String(doc) // persist so re-runs observe prior state + f.puts = append(f.puts, doc) + return &s3.PutBucketPolicyOutput{}, nil +} + +func sidsOf(t *testing.T, raw string) []string { + t.Helper() + var doc map[string]any + if err := json.Unmarshal([]byte(raw), &doc); err != nil { + t.Fatalf("parse policy json: %v", err) + } + stmts, _ := doc["Statement"].([]any) + out := make([]string, 0, len(stmts)) + for _, s := range stmts { + if m, ok := s.(map[string]any); ok { + if sid, ok := m["Sid"].(string); ok { + out = append(out, sid) + } + } + } + return out +} + +func countSid(sids []string, want string) int { + n := 0 + for _, s := range sids { + if s == want { + n++ + } + } + return n +} + +func TestEnsureKmsGrant_CreatesTenantScopedGrant(t *testing.T) { + k := &fakeKMS{} + r := &PlatformReconciler{KMS: k} + cfg := PlatformAWSConfig{DataKMSKeyARN: "arn:aws:kms:us-west-2:123456789012:key/abc"} + role := "arn:aws:iam::123456789012:role/tenant-acme" + + if err := r.ensureKmsGrant(context.Background(), newPlatform("acme", "acme"), role, cfg); err != nil { + t.Fatalf("ensureKmsGrant: %v", err) + } + if len(k.created) != 1 { + t.Fatalf("want exactly 1 CreateGrant, got %d", len(k.created)) + } + got := k.created[0] + if aws.ToString(got.GranteePrincipal) != role { + t.Errorf("grantee = %q, want %q", aws.ToString(got.GranteePrincipal), role) + } + if aws.ToString(got.Name) != "tenant-acme" { + t.Errorf("grant name = %q, want tenant-acme", aws.ToString(got.Name)) + } + // The EncryptionContext is the load-bearing cross-tenant isolation primitive. + if got.Constraints == nil || got.Constraints.EncryptionContextEquals["PlatformId"] != "acme" { + t.Fatalf("EncryptionContextEquals[PlatformId] != acme: %+v", got.Constraints) + } +} + +func TestEnsureKmsGrant_IdempotentWhenGrantExists(t *testing.T) { + k := &fakeKMS{grants: []kmstypes.GrantListEntry{{Name: aws.String("tenant-acme"), GrantId: aws.String("g1")}}} + r := &PlatformReconciler{KMS: k} + cfg := PlatformAWSConfig{DataKMSKeyARN: "arn:aws:kms:us-west-2:123:key/abc"} + + if err := r.ensureKmsGrant(context.Background(), newPlatform("acme", "acme"), "role", cfg); err != nil { + t.Fatalf("ensureKmsGrant: %v", err) + } + if len(k.created) != 0 { + t.Fatalf("an existing grant must short-circuit CreateGrant, got %d creates", len(k.created)) + } +} + +func TestEnsureKmsGrant_FindsGrantOnSecondPage(t *testing.T) { + k := &fakeKMS{ + grants: []kmstypes.GrantListEntry{ + {Name: aws.String("tenant-other"), GrantId: aws.String("g0")}, + {Name: aws.String("tenant-acme"), GrantId: aws.String("g1")}, + }, + pageBoundary: 1, + } + r := &PlatformReconciler{KMS: k} + cfg := PlatformAWSConfig{DataKMSKeyARN: "arn:aws:kms:us-west-2:123:key/abc"} + + if err := r.ensureKmsGrant(context.Background(), newPlatform("acme", "acme"), "role", cfg); err != nil { + t.Fatalf("ensureKmsGrant: %v", err) + } + if len(k.created) != 0 { + t.Fatalf("a grant on page 2 must be found before create, got %d creates", len(k.created)) + } +} + +func TestEnsureBucketPolicy_AddsTenantStatementsToEmptyPolicy(t *testing.T) { + s := &fakeS3{} // nil => NoSuchBucketPolicy => starts from an empty doc + r := &PlatformReconciler{S3: s} + cfg := PlatformAWSConfig{ArtifactsBucketName: "artifacts"} + + if err := r.ensureBucketPolicy(context.Background(), newPlatform("acme", "acme"), "role-arn", cfg); err != nil { + t.Fatalf("ensureBucketPolicy: %v", err) + } + if len(s.puts) != 1 { + t.Fatalf("want 1 PutBucketPolicy, got %d", len(s.puts)) + } + sids := sidsOf(t, s.puts[len(s.puts)-1]) + if countSid(sids, "TenantAccess-acme") != 1 || countSid(sids, "TenantAccess-acme-List") != 1 { + t.Fatalf("expected both tenant statements exactly once, got sids=%v", sids) + } +} + +func TestEnsureBucketPolicy_PreservesForeignReplacesOwn(t *testing.T) { + seed := `{"Version":"2012-10-17","Statement":[` + + `{"Sid":"TenantAccess-other","Effect":"Allow","Principal":{"AWS":"other-role"}},` + + `{"Sid":"TenantAccess-acme","Effect":"Allow","Resource":"stale"}]}` + s := &fakeS3{policy: aws.String(seed)} + r := &PlatformReconciler{S3: s} + cfg := PlatformAWSConfig{ArtifactsBucketName: "artifacts"} + + if err := r.ensureBucketPolicy(context.Background(), newPlatform("acme", "acme"), "role-arn", cfg); err != nil { + t.Fatalf("ensureBucketPolicy: %v", err) + } + sids := sidsOf(t, s.puts[len(s.puts)-1]) + if countSid(sids, "TenantAccess-other") != 1 { + t.Errorf("a peer tenant's statement must survive the merge, sids=%v", sids) + } + if countSid(sids, "TenantAccess-acme") != 1 { + t.Errorf("own statement must be replaced, not duplicated, sids=%v", sids) + } + if countSid(sids, "TenantAccess-acme-List") != 1 { + t.Errorf("own list statement must be present once, sids=%v", sids) + } +} + +func TestEnsureBucketPolicy_IdempotentAcrossRuns(t *testing.T) { + s := &fakeS3{} + r := &PlatformReconciler{S3: s} + cfg := PlatformAWSConfig{ArtifactsBucketName: "artifacts"} + p := newPlatform("acme", "acme") + + for i := 0; i < 3; i++ { + if err := r.ensureBucketPolicy(context.Background(), p, "role-arn", cfg); err != nil { + t.Fatalf("run %d: %v", i, err) + } + } + sids := sidsOf(t, s.puts[len(s.puts)-1]) + if len(sids) != 2 { + t.Fatalf("re-running must not accumulate statements, got sids=%v", sids) + } +} + +func TestRemoveBucketPolicyStatements_DropsOwnKeepsForeign(t *testing.T) { + seed := `{"Version":"2012-10-17","Statement":[` + + `{"Sid":"TenantAccess-other","Effect":"Allow"},` + + `{"Sid":"TenantAccess-acme","Effect":"Allow"},` + + `{"Sid":"TenantAccess-acme-List","Effect":"Allow"}]}` + s := &fakeS3{policy: aws.String(seed)} + r := &PlatformReconciler{S3: s} + cfg := PlatformAWSConfig{ArtifactsBucketName: "artifacts"} + + if err := r.removeBucketPolicyStatements(context.Background(), newPlatform("acme", "acme"), cfg); err != nil { + t.Fatalf("removeBucketPolicyStatements: %v", err) + } + sids := sidsOf(t, s.puts[len(s.puts)-1]) + if countSid(sids, "TenantAccess-acme") != 0 || countSid(sids, "TenantAccess-acme-List") != 0 { + t.Errorf("own statements must be removed on teardown, sids=%v", sids) + } + if countSid(sids, "TenantAccess-other") != 1 { + t.Errorf("a peer tenant's statement must survive teardown, sids=%v", sids) + } +} diff --git a/operators/internal/controller/platform_reconcile.go b/operators/internal/controller/platform_reconcile.go index c8869a6..1033152 100644 --- a/operators/internal/controller/platform_reconcile.go +++ b/operators/internal/controller/platform_reconcile.go @@ -9,10 +9,12 @@ package controller import ( "context" "fmt" + "strings" corev1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" + apimeta "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -316,22 +318,17 @@ func (r *PlatformReconciler) cleanupTenantResources(ctx context.Context, p *plat // isNoKindMatch returns true when the error indicates the cluster doesn't // have the referenced CRD installed (Argo CD AppProject is optional). func isNoKindMatch(err error) bool { - // meta.IsNoMatchError isn't available cleanly via the client package, - // so match by string. Brittle but acceptable for an optional resource. - return err != nil && (containsString(err.Error(), "no matches for kind") || - containsString(err.Error(), "no kind \"")) -} - -func containsString(haystack, needle string) bool { - if len(needle) == 0 { - return true + if err == nil { + return false } - for i := 0; i+len(needle) <= len(haystack); i++ { - if haystack[i:i+len(needle)] == needle { - return true - } + // apimachinery's typed predicate catches the missing-REST-mapping case + // (NoKindMatchError / NoResourceMatchError); the string fallback covers + // the rarer pre-mapping text some client paths surface. + if apimeta.IsNoMatchError(err) { + return true } - return false + return strings.Contains(err.Error(), "no matches for kind") || + strings.Contains(err.Error(), "no kind \"") } // fetchPlatform is a thin wrapper that returns NotFound vs other errors diff --git a/package.json b/package.json index 8c4e931..82aaf28 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@eslint/js": "^10.0.1", "@types/node": "^25.8.0", "@vitest/coverage-v8": "^4.1.6", - "esbuild": "^0.28.0", + "esbuild": "^0.28.1", "eslint": "^10.4.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-import-x": "^4.16.2", @@ -54,13 +54,7 @@ "turbo": "^2.9.14", "typescript": "^6.0.3", "typescript-eslint": "^8.59.3", + "vite": "^8.0.16", "vitest": "^4.1.6" - }, - "pnpm": { - "peerDependencyRules": { - "allowedVersions": { - "typescript": "^6.0.0" - } - } } } diff --git a/packages/core/src/schemas.ts b/packages/core/src/schemas.ts index 25f00fe..8caa3dc 100644 --- a/packages/core/src/schemas.ts +++ b/packages/core/src/schemas.ts @@ -80,6 +80,12 @@ export const CallEvent = z.object({ modelId: z.string(), tokens: TokenUsage, costUsd: z.number().nonnegative(), + /** + * True when modelId had no pricing entry, so costUsd is an unmetered 0 + * rather than a real $0. Lets cost dashboards surface unpriced traffic + * instead of silently undercounting spend. + */ + unpriced: z.boolean().optional(), latencyMs: z.number().nonnegative(), status: z.enum(['ok', 'error']), errorClass: z.string().optional(), diff --git a/packages/pricing/src/index.test.ts b/packages/pricing/src/index.test.ts index 16e0e64..76b6a04 100644 --- a/packages/pricing/src/index.test.ts +++ b/packages/pricing/src/index.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { estimateCost, PRICES } from './index.js'; +import { estimateCost, PRICES, priceModel } from './index.js'; describe('estimateCost', () => { it('prices a Claude 3.5 Sonnet call (US inference profile)', () => { @@ -50,3 +50,31 @@ describe('estimateCost', () => { expect(ids.some((id) => id.startsWith('cohere.'))).toBe(true); }); }); + +describe('priceModel', () => { + it('returns priced:true with the cost for a known model', () => { + const r = priceModel({ + modelId: 'anthropic.claude-3-5-sonnet-20241022-v2:0', + tokens: { inputTokens: 1_000_000, outputTokens: 1_000_000, cacheReadTokens: 0, cacheWriteTokens: 0 }, + }); + expect(r.priced).toBe(true); + expect(r.costUsd).toBeCloseTo(18.0, 4); + }); + + it('flags an unknown model id as priced:false with an unmetered 0', () => { + const r = priceModel({ + modelId: 'unknown.model.id', + tokens: { inputTokens: 5_000_000, outputTokens: 5_000_000, cacheReadTokens: 0, cacheWriteTokens: 0 }, + }); + expect(r.priced).toBe(false); + expect(r.costUsd).toBe(0); + }); + + it('keeps estimateCost in sync with priceModel.costUsd', () => { + const args = { + modelId: 'amazon.nova-pro-v1:0', + tokens: { inputTokens: 2_000_000, outputTokens: 1_000_000, cacheReadTokens: 0, cacheWriteTokens: 0 }, + }; + expect(estimateCost(args)).toBe(priceModel(args).costUsd); + }); +}); diff --git a/packages/pricing/src/index.ts b/packages/pricing/src/index.ts index e92a076..2a02a55 100644 --- a/packages/pricing/src/index.ts +++ b/packages/pricing/src/index.ts @@ -3,10 +3,13 @@ import type { TokenUsage } from '@eks-agent/core'; /** * Bedrock on-demand prices per million tokens. * - * MAINTENANCE: keep this file Renovate-managed (or refreshed weekly via the - * pricing scrape script in scripts/refresh-pricing.mjs). Never hand-edit - * values from memory — Bedrock pricing changes regularly and outdated - * numbers silently undercount spend. + * MAINTENANCE: this table is hand-curated and is NOT Renovate-managed + * (Renovate bumps package deps, not PRICES content). An automated refresh from + * the AWS Pricing API (scripts/refresh-pricing.mjs) is Phase-2 and currently a + * fail-loud scaffold. Until then, update values by hand from the Bedrock + * pricing page — never from memory, since Bedrock pricing changes regularly. A + * model id missing from this table prices as an unmetered 0 (priced:false via + * priceModel), so add new models here before they bill. * * Prices are USD per 1,000,000 tokens. */ @@ -56,7 +59,23 @@ export const PRICES: Record = { 'cohere.command-r-v1:0': { inputPerMillion: 0.5, outputPerMillion: 1.5 }, }; -export function estimateCost({ modelId, tokens }: { modelId: string; tokens: TokenUsage }): number { +export interface PriceResult { + /** Estimated USD cost. 0 when the model id has no entry in PRICES. */ + costUsd: number; + /** + * False when modelId had no PRICES entry — costUsd is then an unmetered 0, + * not a real $0. Lets callers flag unpriced traffic rather than silently + * undercounting spend on a new or mistyped model id. + */ + priced: boolean; +} + +/** + * Price a call, surfacing whether the model id was actually found. Prefer this + * over estimateCost on metering paths so an unpriced model is observable + * instead of silently zeroed. + */ +export function priceModel({ modelId, tokens }: { modelId: string; tokens: TokenUsage }): PriceResult { // Bedrock cross-region inference profile prefixes: us. eu. apac. ap. (and // future regional shorts). Strip any 2–5-char lowercase prefix before lookup // so profile IDs resolve to the base model price. @@ -67,12 +86,21 @@ export function estimateCost({ modelId, tokens }: { modelId: string; tokens: Tok // for static read-only catalogs. // eslint-disable-next-line security/detect-object-injection const price = PRICES[modelId] ?? PRICES[key]; - if (!price) return 0; + if (!price) return { costUsd: 0, priced: false }; const input = (tokens.inputTokens / 1_000_000) * price.inputPerMillion; const output = (tokens.outputTokens / 1_000_000) * price.outputPerMillion; const cacheRead = price.cacheReadPerMillion !== undefined ? (tokens.cacheReadTokens / 1_000_000) * price.cacheReadPerMillion : 0; const cacheWrite = price.cacheWritePerMillion !== undefined ? (tokens.cacheWriteTokens / 1_000_000) * price.cacheWritePerMillion : 0; - return input + output + cacheRead + cacheWrite; + return { costUsd: input + output + cacheRead + cacheWrite, priced: true }; +} + +/** + * Estimate USD cost for a call. Returns 0 for an unknown model id — use + * {@link priceModel} when you need to distinguish a real $0 from an + * unmetered miss. + */ +export function estimateCost(args: { modelId: string; tokens: TokenUsage }): number { + return priceModel(args).costUsd; } diff --git a/packages/sdk/src/adapters/bedrock-base.ts b/packages/sdk/src/adapters/bedrock-base.ts index 3d1a8fc..0eeee01 100644 --- a/packages/sdk/src/adapters/bedrock-base.ts +++ b/packages/sdk/src/adapters/bedrock-base.ts @@ -14,7 +14,7 @@ import { } from '@aws-sdk/client-bedrock-runtime'; import { fromNodeProviderChain } from '@aws-sdk/credential-providers'; import { AgentError, type CallEvent, type ErrorClass, type ModelFamily, type TokenUsage } from '@eks-agent/core'; -import { estimateCost } from '@eks-agent/pricing'; +import { priceModel } from '@eks-agent/pricing'; import type { Message, MessagesParams, MessagesResponse, ProviderAdapter, ProviderId } from '../types.js'; @@ -36,6 +36,14 @@ export interface BedrockAdapterOptions { tenant?: string; /** Optional Workspace ID for finer-grained spend attribution. */ workspace?: string; + /** + * Per-request deadline in ms applied to every InvokeModel call, even when + * the caller passes no AbortSignal. Guards against a stalled Bedrock socket + * hanging the call until the OS TCP timeout. Defaults to 60_000. A caller's + * own params.signal is combined with (not replaced by) this deadline — + * whichever fires first wins. Raise it for legitimately long generations. + */ + requestTimeoutMs?: number; } /** @@ -51,6 +59,7 @@ export abstract class BedrockAdapter implements ProviderAdapter { protected readonly platform: string; protected readonly tenant: string; protected readonly workspace?: string; + protected readonly requestTimeoutMs: number; constructor(opts: BedrockAdapterOptions) { this.client = new BedrockRuntimeClient({ @@ -60,6 +69,7 @@ export abstract class BedrockAdapter implements ProviderAdapter { this.platform = opts.platform ?? ''; this.tenant = opts.tenant ?? ''; if (opts.workspace !== undefined) this.workspace = opts.workspace; + this.requestTimeoutMs = opts.requestTimeoutMs ?? 60_000; } protected abstract buildRequestBody(params: MessagesParams): Record; @@ -85,14 +95,18 @@ export abstract class BedrockAdapter implements ProviderAdapter { : {}), }); - // Thread the caller's AbortSignal through to the AWS SDK send call so - // InvokeModelCommand is cancelled in-flight, not just unwaited. - // exactOptionalPropertyTypes forces a conditional spread rather than - // `{ abortSignal: signal | undefined }`. - const out = await this.client.send(cmd, params.signal ? { abortSignal: params.signal } : {}); + // Every InvokeModel call gets a bounded deadline regardless of caller + // diligence: a default request timeout is always applied, and a + // caller-supplied AbortSignal is combined with it (earliest fire wins) + // so both in-flight cancellation and the safety-net deadline hold. The + // default-deadline fire surfaces as a TimeoutError (classified Network, + // retryable); a caller abort surfaces as AbortError (Cancelled). + const deadline = AbortSignal.timeout(this.requestTimeoutMs); + const abortSignal = params.signal ? AbortSignal.any([params.signal, deadline]) : deadline; + const out = await this.client.send(cmd, { abortSignal }); const body = JSON.parse(new TextDecoder().decode(out.body)) as unknown; const parsed = this.parseResponseBody(body); - const costUsd = estimateCost({ + const { costUsd, priced } = priceModel({ modelId: params.modelId, tokens: parsed.usage, }); @@ -117,6 +131,7 @@ export abstract class BedrockAdapter implements ProviderAdapter { modelId: params.modelId, tokens: parsed.usage, costUsd, + ...(priced ? {} : { unpriced: true }), latencyMs: response.latencyMs, status: 'ok', timestamp: new Date().toISOString(), @@ -156,6 +171,10 @@ export abstract class BedrockAdapter implements ProviderAdapter { if (err && typeof err === 'object' && 'name' in err) { const name = String(err.name); if (name === 'AbortError') return 'Cancelled'; + // The default request-deadline fires as a TimeoutError (vs a caller + // AbortError); a timeout is a transient network condition, so it is + // retryable, not a deliberate cancellation. + if (name === 'TimeoutError') return 'Network'; if (name === 'GuardrailIntervenedException') return 'GuardrailBlock'; } return 'Server'; diff --git a/packages/sdk/src/adapters/bedrock-messages.test.ts b/packages/sdk/src/adapters/bedrock-messages.test.ts new file mode 100644 index 0000000..c122fe4 --- /dev/null +++ b/packages/sdk/src/adapters/bedrock-messages.test.ts @@ -0,0 +1,101 @@ +import { ThrottlingException } from '@aws-sdk/client-bedrock-runtime'; +import { AgentError, type CallEvent } from '@eks-agent/core'; +import { describe, expect, it } from 'vitest'; + +import type { MessagesParams } from '../types.js'; + +import { AnthropicBedrockAdapter } from './anthropic.js'; + +// Inject a fake BedrockRuntimeClient by reassigning the protected `client` +// field from a test subclass — NOT module-mocking @aws-sdk/* (which would be a +// rubric REJECT). This exercises the real messages() orchestration: build → +// send → parse → cost → emitCallEvent, plus the error-wrapping path. +class FakeClientAdapter extends AnthropicBedrockAdapter { + lastOptions: { abortSignal?: AbortSignal } | undefined; + + setSend(fn: () => Promise): void { + this.client = { + send: (_cmd: unknown, opts: { abortSignal?: AbortSignal }) => { + this.lastOptions = opts; + return fn(); + }, + } as unknown as typeof this.client; + } +} + +function anthropicBody(text: string): Uint8Array { + return new TextEncoder().encode( + JSON.stringify({ + content: [{ type: 'text', text }], + stop_reason: 'end_turn', + usage: { input_tokens: 10, output_tokens: 5 }, + }), + ); +} + +const baseParams: MessagesParams = { + modelId: 'anthropic.claude-3-5-sonnet-20241022-v2:0', + modelFamily: 'anthropic', + messages: [{ role: 'user', content: 'hi' }], + maxTokens: 64, + correlationId: 'cid-123', +}; + +describe('BedrockAdapter.messages orchestration', () => { + it('returns a parsed response with cost, latency, and correlationId', async () => { + const adapter = new FakeClientAdapter({ region: 'us-west-2' }); + adapter.setSend(() => Promise.resolve({ body: anthropicBody('pong') })); + + const res = await adapter.messages(baseParams); + + expect(res.text).toBe('pong'); + expect(res.correlationId).toBe('cid-123'); + expect(res.usage.inputTokens).toBe(10); + expect(res.costUsd).toBeGreaterThan(0); + expect(typeof res.latencyMs).toBe('number'); + }); + + it('applies a default request deadline even when the caller passes no signal', async () => { + const adapter = new FakeClientAdapter({ region: 'us-west-2' }); + adapter.setSend(() => Promise.resolve({ body: anthropicBody('x') })); + + await adapter.messages(baseParams); + + expect(adapter.lastOptions?.abortSignal).toBeInstanceOf(AbortSignal); + }); + + it('emits a CallEvent exactly once on success and never on throw', async () => { + const adapter = new FakeClientAdapter({ region: 'us-west-2', platform: 'p', tenant: 't' }); + const events: CallEvent[] = []; + adapter.emitCallEvent = (e) => events.push(e); + + adapter.setSend(() => Promise.resolve({ body: anthropicBody('ok') })); + await adapter.messages(baseParams); + expect(events).toHaveLength(1); + expect(events[0]?.correlationId).toBe('cid-123'); + expect(events[0]?.status).toBe('ok'); + + adapter.setSend(() => Promise.reject(new ThrottlingException({ $metadata: {}, message: 'slow down' }))); + await expect(adapter.messages(baseParams)).rejects.toBeInstanceOf(AgentError); + expect(events).toHaveLength(1); + }); + + it('flags unpriced traffic on the CallEvent for an unknown model id', async () => { + const adapter = new FakeClientAdapter({ region: 'us-west-2' }); + const events: CallEvent[] = []; + adapter.emitCallEvent = (e) => events.push(e); + adapter.setSend(() => Promise.resolve({ body: anthropicBody('x') })); + + await adapter.messages({ ...baseParams, modelId: 'unknown.model.id' }); + + expect(events[0]?.unpriced).toBe(true); + expect(events[0]?.costUsd).toBe(0); + }); + + it('wraps a ThrottlingException as a retryable RateLimit AgentError', async () => { + const adapter = new FakeClientAdapter({ region: 'us-west-2' }); + adapter.setSend(() => Promise.reject(new ThrottlingException({ $metadata: {}, message: 'slow' }))); + + await expect(adapter.messages(baseParams)).rejects.toMatchObject({ class: 'RateLimit', retryable: true }); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a0eef2..eacf66e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,14 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + vite: ^8.0.16 + esbuild: ^0.28.1 + ws: ^8.21.0 + form-data: ^4.0.6 + js-yaml: ^4.2.0 + read-yaml-file: ^2.1.0 + importers: .: @@ -27,8 +35,8 @@ importers: specifier: ^4.1.6 version: 4.1.6(vitest@4.1.6) esbuild: - specifier: ^0.28.0 - version: 0.28.0 + specifier: ^0.28.1 + version: 0.28.1 eslint: specifier: ^10.4.0 version: 10.4.0(jiti@2.6.1) @@ -62,9 +70,12 @@ importers: typescript-eslint: specifier: ^8.59.3 version: 8.59.3(eslint@10.4.0(jiti@2.6.1))(typescript@6.0.3) + vite: + specifier: ^8.0.16 + version: 8.0.16(@types/node@25.8.0)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0) vitest: specifier: ^4.1.6 - version: 4.1.6(@types/node@25.8.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.13(@types/node@25.8.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)) + version: 4.1.6(@types/node@25.8.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.16(@types/node@25.8.0)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)) examples/blank-tenant: {} @@ -91,7 +102,7 @@ importers: version: 6.0.3 vitest: specifier: ^4.1.6 - version: 4.1.6(@types/node@25.8.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.13(@types/node@25.8.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)) + version: 4.1.6(@types/node@25.8.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.16(@types/node@25.8.0)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)) packages/client: dependencies: @@ -107,7 +118,7 @@ importers: version: 6.0.3 vitest: specifier: ^4.1.6 - version: 4.1.6(@types/node@25.8.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.13(@types/node@25.8.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)) + version: 4.1.6(@types/node@25.8.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.16(@types/node@25.8.0)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)) packages/core: dependencies: @@ -120,7 +131,7 @@ importers: version: 6.0.3 vitest: specifier: ^4.1.6 - version: 4.1.6(@types/node@25.8.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.13(@types/node@25.8.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)) + version: 4.1.6(@types/node@25.8.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.16(@types/node@25.8.0)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)) packages/pricing: dependencies: @@ -133,7 +144,7 @@ importers: version: 6.0.3 vitest: specifier: ^4.1.6 - version: 4.1.6(@types/node@25.8.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.13(@types/node@25.8.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)) + version: 4.1.6(@types/node@25.8.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.16(@types/node@25.8.0)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)) packages/sdk: dependencies: @@ -155,7 +166,7 @@ importers: version: 6.0.3 vitest: specifier: ^4.1.6 - version: 4.1.6(@types/node@25.8.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.13(@types/node@25.8.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)) + version: 4.1.6(@types/node@25.8.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.16(@types/node@25.8.0)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)) packages: @@ -442,158 +453,158 @@ packages: '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} - '@esbuild/aix-ppc64@0.28.0': - resolution: {integrity: sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==} + '@esbuild/aix-ppc64@0.28.1': + resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.28.0': - resolution: {integrity: sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==} + '@esbuild/android-arm64@0.28.1': + resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.28.0': - resolution: {integrity: sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==} + '@esbuild/android-arm@0.28.1': + resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.28.0': - resolution: {integrity: sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==} + '@esbuild/android-x64@0.28.1': + resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.28.0': - resolution: {integrity: sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==} + '@esbuild/darwin-arm64@0.28.1': + resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.28.0': - resolution: {integrity: sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==} + '@esbuild/darwin-x64@0.28.1': + resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.28.0': - resolution: {integrity: sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==} + '@esbuild/freebsd-arm64@0.28.1': + resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.28.0': - resolution: {integrity: sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==} + '@esbuild/freebsd-x64@0.28.1': + resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.28.0': - resolution: {integrity: sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==} + '@esbuild/linux-arm64@0.28.1': + resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.28.0': - resolution: {integrity: sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==} + '@esbuild/linux-arm@0.28.1': + resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.28.0': - resolution: {integrity: sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==} + '@esbuild/linux-ia32@0.28.1': + resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.28.0': - resolution: {integrity: sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==} + '@esbuild/linux-loong64@0.28.1': + resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.28.0': - resolution: {integrity: sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==} + '@esbuild/linux-mips64el@0.28.1': + resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.28.0': - resolution: {integrity: sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==} + '@esbuild/linux-ppc64@0.28.1': + resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.28.0': - resolution: {integrity: sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==} + '@esbuild/linux-riscv64@0.28.1': + resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.28.0': - resolution: {integrity: sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==} + '@esbuild/linux-s390x@0.28.1': + resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.28.0': - resolution: {integrity: sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==} + '@esbuild/linux-x64@0.28.1': + resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.28.0': - resolution: {integrity: sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==} + '@esbuild/netbsd-arm64@0.28.1': + resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.28.0': - resolution: {integrity: sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==} + '@esbuild/netbsd-x64@0.28.1': + resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.28.0': - resolution: {integrity: sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==} + '@esbuild/openbsd-arm64@0.28.1': + resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.28.0': - resolution: {integrity: sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==} + '@esbuild/openbsd-x64@0.28.1': + resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.28.0': - resolution: {integrity: sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==} + '@esbuild/openharmony-arm64@0.28.1': + resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.28.0': - resolution: {integrity: sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==} + '@esbuild/sunos-x64@0.28.1': + resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.28.0': - resolution: {integrity: sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==} + '@esbuild/win32-arm64@0.28.1': + resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.28.0': - resolution: {integrity: sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==} + '@esbuild/win32-ia32@0.28.1': + resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.28.0': - resolution: {integrity: sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==} + '@esbuild/win32-x64@0.28.1': + resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -700,8 +711,8 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@napi-rs/wasm-runtime@1.1.4': - resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} + '@napi-rs/wasm-runtime@1.1.5': + resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} peerDependencies: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 @@ -721,109 +732,109 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@oxc-project/types@0.130.0': - resolution: {integrity: sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==} + '@oxc-project/types@0.133.0': + resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} '@package-json/types@0.0.12': resolution: {integrity: sha512-uu43FGU34B5VM9mCNjXCwLaGHYjXdNincqKLaraaCW+7S2+SmiBg1Nv8bPnmschrIfZmfKNY9f3fC376MRrObw==} - '@rolldown/binding-android-arm64@1.0.1': - resolution: {integrity: sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==} + '@rolldown/binding-android-arm64@1.0.3': + resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.1': - resolution: {integrity: sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==} + '@rolldown/binding-darwin-arm64@1.0.3': + resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.1': - resolution: {integrity: sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==} + '@rolldown/binding-darwin-x64@1.0.3': + resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.1': - resolution: {integrity: sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==} + '@rolldown/binding-freebsd-x64@1.0.3': + resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.1': - resolution: {integrity: sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.1': - resolution: {integrity: sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==} + '@rolldown/binding-linux-arm64-gnu@1.0.3': + resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.1': - resolution: {integrity: sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==} + '@rolldown/binding-linux-arm64-musl@1.0.3': + resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.0.1': - resolution: {integrity: sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==} + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.1': - resolution: {integrity: sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==} + '@rolldown/binding-linux-s390x-gnu@1.0.3': + resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.1': - resolution: {integrity: sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==} + '@rolldown/binding-linux-x64-gnu@1.0.3': + resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.1': - resolution: {integrity: sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==} + '@rolldown/binding-linux-x64-musl@1.0.3': + resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.1': - resolution: {integrity: sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==} + '@rolldown/binding-openharmony-arm64@1.0.3': + resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.1': - resolution: {integrity: sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==} + '@rolldown/binding-wasm32-wasi@1.0.3': + resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.1': - resolution: {integrity: sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==} + '@rolldown/binding-win32-arm64-msvc@1.0.3': + resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.1': - resolution: {integrity: sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==} + '@rolldown/binding-win32-x64-msvc@1.0.3': + resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0': - resolution: {integrity: sha512-aKs/3GSWyV0mrhNmt/96/Z3yczC3yvrzYATCiCXQebBsGyYzjNdUphRVLeJQ67ySKVXRfMxt2lm12pmXvbPFQQ==} + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} '@simple-libs/child-process-utils@1.0.2': resolution: {integrity: sha512-/4R8QKnd/8agJynkNdJmNw2MBxuFTRcNFnE5Sg/G+jkSsV8/UBgULMzhizWWW42p8L5H7flImV2ATi79Ove2Tw==} @@ -1116,7 +1127,7 @@ packages: resolution: {integrity: sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==} peerDependencies: msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + vite: ^8.0.16 peerDependenciesMeta: msw: optional: true @@ -1178,9 +1189,6 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} - argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -1435,8 +1443,8 @@ packages: es-toolkit@1.46.1: resolution: {integrity: sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==} - esbuild@0.28.0: - resolution: {integrity: sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==} + esbuild@0.28.1: + resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} engines: {node: '>=18'} hasBin: true @@ -1506,11 +1514,6 @@ packages: resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - esquery@1.7.0: resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} @@ -1604,8 +1607,8 @@ packages: flatted@3.4.2: resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + form-data@4.0.6: + resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} engines: {node: '>= 6'} fs-extra@7.0.1: @@ -1687,6 +1690,10 @@ packages: resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} engines: {node: '>= 0.4'} + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + hpagent@1.2.0: resolution: {integrity: sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==} engines: {node: '>=14'} @@ -1780,7 +1787,7 @@ packages: isomorphic-ws@5.0.0: resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==} peerDependencies: - ws: '*' + ws: ^8.21.0 istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} @@ -1807,12 +1814,8 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@3.14.2: - resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} - hasBin: true - - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + js-yaml@4.2.0: + resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} hasBin: true jsep@1.4.0: @@ -2003,8 +2006,8 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nanoid@3.3.12: - resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + nanoid@3.3.13: + resolution: {integrity: sha512-sPdqC6ByMVVGvF1ynvvMo0/o+oD1VX7DaHhijt1bFgjvBkHBib4t49GoNDhf2NDta4oeUNlaGbSt5K7qjZ955Q==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -2121,12 +2124,8 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} - pify@4.0.1: - resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} - engines: {node: '>=6'} - - postcss@8.5.14: - resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: @@ -2156,9 +2155,9 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - read-yaml-file@1.1.0: - resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} - engines: {node: '>=6'} + read-yaml-file@2.1.0: + resolution: {integrity: sha512-UkRNRIwnhG+y7hpqnycCL/xbTk7+ia9VuVTC0S+zVbwd65DI9eUpRMfsWIGrCWxTU/mi+JW8cHQCrv+zfCbEPQ==} + engines: {node: '>=10.13'} regexp-tree@0.1.27: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} @@ -2193,8 +2192,8 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rolldown@1.0.1: - resolution: {integrity: sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==} + rolldown@1.0.3: + resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -2258,9 +2257,6 @@ packages: spawndamnit@3.0.1: resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} - sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - stable-hash-x@0.2.0: resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==} engines: {node: '>=12.0.0'} @@ -2302,9 +2298,9 @@ packages: resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} - strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} strnum@2.3.0: resolution: {integrity: sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==} @@ -2340,6 +2336,10 @@ packages: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + tinyrainbow@3.1.0: resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} @@ -2401,14 +2401,14 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - vite@8.0.13: - resolution: {integrity: sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==} + vite@8.0.16: + resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 '@vitejs/devtools': ^0.1.18 - esbuild: ^0.27.0 || ^0.28.0 + esbuild: ^0.28.1 jiti: '>=1.21.0' less: ^4.0.0 sass: ^1.70.0 @@ -2460,7 +2460,7 @@ packages: '@vitest/ui': 4.1.6 happy-dom: '*' jsdom: '*' - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + vite: ^8.0.16 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -2516,8 +2516,8 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.20.1: - resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -2950,7 +2950,7 @@ snapshots: '@changesets/parse@0.4.3': dependencies: '@changesets/types': 6.1.0 - js-yaml: 4.1.1 + js-yaml: 4.2.0 '@changesets/pre@2.0.2': dependencies: @@ -3117,82 +3117,82 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.28.0': + '@esbuild/aix-ppc64@0.28.1': optional: true - '@esbuild/android-arm64@0.28.0': + '@esbuild/android-arm64@0.28.1': optional: true - '@esbuild/android-arm@0.28.0': + '@esbuild/android-arm@0.28.1': optional: true - '@esbuild/android-x64@0.28.0': + '@esbuild/android-x64@0.28.1': optional: true - '@esbuild/darwin-arm64@0.28.0': + '@esbuild/darwin-arm64@0.28.1': optional: true - '@esbuild/darwin-x64@0.28.0': + '@esbuild/darwin-x64@0.28.1': optional: true - '@esbuild/freebsd-arm64@0.28.0': + '@esbuild/freebsd-arm64@0.28.1': optional: true - '@esbuild/freebsd-x64@0.28.0': + '@esbuild/freebsd-x64@0.28.1': optional: true - '@esbuild/linux-arm64@0.28.0': + '@esbuild/linux-arm64@0.28.1': optional: true - '@esbuild/linux-arm@0.28.0': + '@esbuild/linux-arm@0.28.1': optional: true - '@esbuild/linux-ia32@0.28.0': + '@esbuild/linux-ia32@0.28.1': optional: true - '@esbuild/linux-loong64@0.28.0': + '@esbuild/linux-loong64@0.28.1': optional: true - '@esbuild/linux-mips64el@0.28.0': + '@esbuild/linux-mips64el@0.28.1': optional: true - '@esbuild/linux-ppc64@0.28.0': + '@esbuild/linux-ppc64@0.28.1': optional: true - '@esbuild/linux-riscv64@0.28.0': + '@esbuild/linux-riscv64@0.28.1': optional: true - '@esbuild/linux-s390x@0.28.0': + '@esbuild/linux-s390x@0.28.1': optional: true - '@esbuild/linux-x64@0.28.0': + '@esbuild/linux-x64@0.28.1': optional: true - '@esbuild/netbsd-arm64@0.28.0': + '@esbuild/netbsd-arm64@0.28.1': optional: true - '@esbuild/netbsd-x64@0.28.0': + '@esbuild/netbsd-x64@0.28.1': optional: true - '@esbuild/openbsd-arm64@0.28.0': + '@esbuild/openbsd-arm64@0.28.1': optional: true - '@esbuild/openbsd-x64@0.28.0': + '@esbuild/openbsd-x64@0.28.1': optional: true - '@esbuild/openharmony-arm64@0.28.0': + '@esbuild/openharmony-arm64@0.28.1': optional: true - '@esbuild/sunos-x64@0.28.0': + '@esbuild/sunos-x64@0.28.1': optional: true - '@esbuild/win32-arm64@0.28.0': + '@esbuild/win32-arm64@0.28.1': optional: true - '@esbuild/win32-ia32@0.28.0': + '@esbuild/win32-ia32@0.28.1': optional: true - '@esbuild/win32-x64@0.28.0': + '@esbuild/win32-x64@0.28.1': optional: true '@eslint-community/eslint-utils@4.9.1(eslint@10.4.0(jiti@2.6.1))': @@ -3275,10 +3275,10 @@ snapshots: '@types/node': 24.12.4 '@types/node-fetch': 2.6.13 '@types/stream-buffers': 3.0.8 - form-data: 4.0.5 + form-data: 4.0.6 hpagent: 1.2.0 - isomorphic-ws: 5.0.0(ws@8.20.1) - js-yaml: 4.1.1 + isomorphic-ws: 5.0.0(ws@8.21.0) + js-yaml: 4.2.0 jsonpath-plus: 10.4.0 node-fetch: 2.7.0 openid-client: 6.8.4 @@ -3286,7 +3286,7 @@ snapshots: socks-proxy-agent: 8.0.5 stream-buffers: 3.0.3 tar-fs: 3.1.2 - ws: 8.20.1 + ws: 8.21.0 transitivePeerDependencies: - bare-abort-controller - bare-buffer @@ -3310,7 +3310,7 @@ snapshots: '@manypkg/find-root': 1.1.0 fs-extra: 8.1.0 globby: 11.1.0 - read-yaml-file: 1.1.0 + read-yaml-file: 2.1.0 '@napi-rs/wasm-runtime@0.2.12': dependencies: @@ -3319,7 +3319,7 @@ snapshots: '@tybys/wasm-util': 0.10.2 optional: true - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 @@ -3340,60 +3340,60 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 - '@oxc-project/types@0.130.0': {} + '@oxc-project/types@0.133.0': {} '@package-json/types@0.0.12': {} - '@rolldown/binding-android-arm64@1.0.1': + '@rolldown/binding-android-arm64@1.0.3': optional: true - '@rolldown/binding-darwin-arm64@1.0.1': + '@rolldown/binding-darwin-arm64@1.0.3': optional: true - '@rolldown/binding-darwin-x64@1.0.1': + '@rolldown/binding-darwin-x64@1.0.3': optional: true - '@rolldown/binding-freebsd-x64@1.0.1': + '@rolldown/binding-freebsd-x64@1.0.3': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.1': + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.1': + '@rolldown/binding-linux-arm64-gnu@1.0.3': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.1': + '@rolldown/binding-linux-arm64-musl@1.0.3': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.1': + '@rolldown/binding-linux-ppc64-gnu@1.0.3': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.1': + '@rolldown/binding-linux-s390x-gnu@1.0.3': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.1': + '@rolldown/binding-linux-x64-gnu@1.0.3': optional: true - '@rolldown/binding-linux-x64-musl@1.0.1': + '@rolldown/binding-linux-x64-musl@1.0.3': optional: true - '@rolldown/binding-openharmony-arm64@1.0.1': + '@rolldown/binding-openharmony-arm64@1.0.3': optional: true - '@rolldown/binding-wasm32-wasi@1.0.1': + '@rolldown/binding-wasm32-wasi@1.0.3': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.1': + '@rolldown/binding-win32-arm64-msvc@1.0.3': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.1': + '@rolldown/binding-win32-x64-msvc@1.0.3': optional: true - '@rolldown/pluginutils@1.0.0': {} + '@rolldown/pluginutils@1.0.1': {} '@simple-libs/child-process-utils@1.0.2': dependencies: @@ -3492,7 +3492,7 @@ snapshots: '@types/node-fetch@2.6.13': dependencies: '@types/node': 25.8.0 - form-data: 4.0.5 + form-data: 4.0.6 '@types/node@12.20.55': {} @@ -3670,7 +3670,7 @@ snapshots: obug: 2.1.1 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.6(@types/node@25.8.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.13(@types/node@25.8.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)) + vitest: 4.1.6(@types/node@25.8.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.16(@types/node@25.8.0)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)) '@vitest/expect@4.1.6': dependencies: @@ -3681,13 +3681,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.6(vite@8.0.13(@types/node@25.8.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.6(vite@8.0.16(@types/node@25.8.0)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0))': dependencies: '@vitest/spy': 4.1.6 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.13(@types/node@25.8.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0) + vite: 8.0.16(@types/node@25.8.0)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0) '@vitest/pretty-format@4.1.6': dependencies: @@ -3747,10 +3747,6 @@ snapshots: ansi-styles@6.2.3: {} - argparse@1.0.10: - dependencies: - sprintf-js: 1.0.3 - argparse@2.0.1: {} array-ify@1.0.0: {} @@ -3886,7 +3882,7 @@ snapshots: dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 - js-yaml: 4.1.1 + js-yaml: 4.2.0 parse-json: 5.2.0 optionalDependencies: typescript: 6.0.3 @@ -3961,34 +3957,34 @@ snapshots: es-toolkit@1.46.1: {} - esbuild@0.28.0: + esbuild@0.28.1: optionalDependencies: - '@esbuild/aix-ppc64': 0.28.0 - '@esbuild/android-arm': 0.28.0 - '@esbuild/android-arm64': 0.28.0 - '@esbuild/android-x64': 0.28.0 - '@esbuild/darwin-arm64': 0.28.0 - '@esbuild/darwin-x64': 0.28.0 - '@esbuild/freebsd-arm64': 0.28.0 - '@esbuild/freebsd-x64': 0.28.0 - '@esbuild/linux-arm': 0.28.0 - '@esbuild/linux-arm64': 0.28.0 - '@esbuild/linux-ia32': 0.28.0 - '@esbuild/linux-loong64': 0.28.0 - '@esbuild/linux-mips64el': 0.28.0 - '@esbuild/linux-ppc64': 0.28.0 - '@esbuild/linux-riscv64': 0.28.0 - '@esbuild/linux-s390x': 0.28.0 - '@esbuild/linux-x64': 0.28.0 - '@esbuild/netbsd-arm64': 0.28.0 - '@esbuild/netbsd-x64': 0.28.0 - '@esbuild/openbsd-arm64': 0.28.0 - '@esbuild/openbsd-x64': 0.28.0 - '@esbuild/openharmony-arm64': 0.28.0 - '@esbuild/sunos-x64': 0.28.0 - '@esbuild/win32-arm64': 0.28.0 - '@esbuild/win32-ia32': 0.28.0 - '@esbuild/win32-x64': 0.28.0 + '@esbuild/aix-ppc64': 0.28.1 + '@esbuild/android-arm': 0.28.1 + '@esbuild/android-arm64': 0.28.1 + '@esbuild/android-x64': 0.28.1 + '@esbuild/darwin-arm64': 0.28.1 + '@esbuild/darwin-x64': 0.28.1 + '@esbuild/freebsd-arm64': 0.28.1 + '@esbuild/freebsd-x64': 0.28.1 + '@esbuild/linux-arm': 0.28.1 + '@esbuild/linux-arm64': 0.28.1 + '@esbuild/linux-ia32': 0.28.1 + '@esbuild/linux-loong64': 0.28.1 + '@esbuild/linux-mips64el': 0.28.1 + '@esbuild/linux-ppc64': 0.28.1 + '@esbuild/linux-riscv64': 0.28.1 + '@esbuild/linux-s390x': 0.28.1 + '@esbuild/linux-x64': 0.28.1 + '@esbuild/netbsd-arm64': 0.28.1 + '@esbuild/netbsd-x64': 0.28.1 + '@esbuild/openbsd-arm64': 0.28.1 + '@esbuild/openbsd-x64': 0.28.1 + '@esbuild/openharmony-arm64': 0.28.1 + '@esbuild/sunos-x64': 0.28.1 + '@esbuild/win32-arm64': 0.28.1 + '@esbuild/win32-ia32': 0.28.1 + '@esbuild/win32-x64': 0.28.1 escalade@3.2.0: {} @@ -4081,8 +4077,6 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 5.0.1 - esprima@4.0.1: {} - esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -4174,12 +4168,12 @@ snapshots: flatted@3.4.2: {} - form-data@4.0.5: + form-data@4.0.6: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 es-set-tostringtag: 2.1.0 - hasown: 2.0.3 + hasown: 2.0.4 mime-types: 2.1.35 fs-extra@7.0.1: @@ -4270,6 +4264,10 @@ snapshots: dependencies: function-bind: 1.1.2 + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + hpagent@1.2.0: {} html-escaper@2.0.2: {} @@ -4327,9 +4325,9 @@ snapshots: isexe@2.0.0: {} - isomorphic-ws@5.0.0(ws@8.20.1): + isomorphic-ws@5.0.0(ws@8.21.0): dependencies: - ws: 8.20.1 + ws: 8.21.0 istanbul-lib-coverage@3.2.2: {} @@ -4352,12 +4350,7 @@ snapshots: js-tokens@4.0.0: {} - js-yaml@3.14.2: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - - js-yaml@4.1.1: + js-yaml@4.2.0: dependencies: argparse: 2.0.1 @@ -4524,7 +4517,7 @@ snapshots: ms@2.1.3: {} - nanoid@3.3.12: {} + nanoid@3.3.13: {} napi-postinstall@0.3.4: {} @@ -4628,11 +4621,9 @@ snapshots: picomatch@4.0.4: {} - pify@4.0.1: {} - - postcss@8.5.14: + postcss@8.5.15: dependencies: - nanoid: 3.3.12 + nanoid: 3.3.13 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -4653,12 +4644,10 @@ snapshots: queue-microtask@1.2.3: {} - read-yaml-file@1.1.0: + read-yaml-file@2.1.0: dependencies: - graceful-fs: 4.2.11 - js-yaml: 3.14.2 - pify: 4.0.1 - strip-bom: 3.0.0 + js-yaml: 4.2.0 + strip-bom: 4.0.0 regexp-tree@0.1.27: {} @@ -4681,26 +4670,26 @@ snapshots: rfdc@1.4.1: {} - rolldown@1.0.1: + rolldown@1.0.3: dependencies: - '@oxc-project/types': 0.130.0 - '@rolldown/pluginutils': 1.0.0 + '@oxc-project/types': 0.133.0 + '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.1 - '@rolldown/binding-darwin-arm64': 1.0.1 - '@rolldown/binding-darwin-x64': 1.0.1 - '@rolldown/binding-freebsd-x64': 1.0.1 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.1 - '@rolldown/binding-linux-arm64-gnu': 1.0.1 - '@rolldown/binding-linux-arm64-musl': 1.0.1 - '@rolldown/binding-linux-ppc64-gnu': 1.0.1 - '@rolldown/binding-linux-s390x-gnu': 1.0.1 - '@rolldown/binding-linux-x64-gnu': 1.0.1 - '@rolldown/binding-linux-x64-musl': 1.0.1 - '@rolldown/binding-openharmony-arm64': 1.0.1 - '@rolldown/binding-wasm32-wasi': 1.0.1 - '@rolldown/binding-win32-arm64-msvc': 1.0.1 - '@rolldown/binding-win32-x64-msvc': 1.0.1 + '@rolldown/binding-android-arm64': 1.0.3 + '@rolldown/binding-darwin-arm64': 1.0.3 + '@rolldown/binding-darwin-x64': 1.0.3 + '@rolldown/binding-freebsd-x64': 1.0.3 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 + '@rolldown/binding-linux-arm64-gnu': 1.0.3 + '@rolldown/binding-linux-arm64-musl': 1.0.3 + '@rolldown/binding-linux-ppc64-gnu': 1.0.3 + '@rolldown/binding-linux-s390x-gnu': 1.0.3 + '@rolldown/binding-linux-x64-gnu': 1.0.3 + '@rolldown/binding-linux-x64-musl': 1.0.3 + '@rolldown/binding-openharmony-arm64': 1.0.3 + '@rolldown/binding-wasm32-wasi': 1.0.3 + '@rolldown/binding-win32-arm64-msvc': 1.0.3 + '@rolldown/binding-win32-x64-msvc': 1.0.3 run-parallel@1.2.0: dependencies: @@ -4758,8 +4747,6 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - sprintf-js@1.0.3: {} - stable-hash-x@0.2.0: {} stackback@0.0.2: {} @@ -4800,7 +4787,7 @@ snapshots: dependencies: ansi-regex: 6.2.2 - strip-bom@3.0.0: {} + strip-bom@4.0.0: {} strnum@2.3.0: {} @@ -4855,6 +4842,11 @@ snapshots: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + tinyrainbow@3.1.0: {} to-regex-range@5.0.1: @@ -4871,7 +4863,7 @@ snapshots: tsx@4.22.0: dependencies: - esbuild: 0.28.0 + esbuild: 0.28.1 optionalDependencies: fsevents: 2.3.3 @@ -4935,25 +4927,25 @@ snapshots: dependencies: punycode: 2.3.1 - vite@8.0.13(@types/node@25.8.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0): + vite@8.0.16(@types/node@25.8.0)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.14 - rolldown: 1.0.1 - tinyglobby: 0.2.16 + postcss: 8.5.15 + rolldown: 1.0.3 + tinyglobby: 0.2.17 optionalDependencies: '@types/node': 25.8.0 - esbuild: 0.28.0 + esbuild: 0.28.1 fsevents: 2.3.3 jiti: 2.6.1 tsx: 4.22.0 yaml: 2.9.0 - vitest@4.1.6(@types/node@25.8.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.13(@types/node@25.8.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)): + vitest@4.1.6(@types/node@25.8.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.16(@types/node@25.8.0)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.6 - '@vitest/mocker': 4.1.6(vite@8.0.13(@types/node@25.8.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)) + '@vitest/mocker': 4.1.6(vite@8.0.16(@types/node@25.8.0)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.6 '@vitest/runner': 4.1.6 '@vitest/snapshot': 4.1.6 @@ -4970,7 +4962,7 @@ snapshots: tinyexec: 1.1.2 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vite: 8.0.13(@types/node@25.8.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0) + vite: 8.0.16(@types/node@25.8.0)(esbuild@0.28.1)(jiti@2.6.1)(tsx@4.22.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 25.8.0 @@ -5010,7 +5002,7 @@ snapshots: wrappy@1.0.2: {} - ws@8.20.1: {} + ws@8.21.0: {} xml-naming@0.1.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 75348c1..468aaa0 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -5,3 +5,19 @@ packages: allowBuilds: esbuild: true unrs-resolver: true + +# Force patched transitive versions to clear known advisories. ws + form-data +# ship at runtime via @kubernetes/client-node inside @eks-agent/client; the +# rest are dev-tree (vitest/tsx, changesets). read-yaml-file is bumped to v2 so +# it pulls js-yaml 4 and the vulnerable js-yaml 3.x line drops out entirely. +overrides: + vite: "^8.0.16" # GHSA-v6wh-96g9-6wx3, GHSA-fx2h-pf6j-xcff + esbuild: "^0.28.1" # GHSA-g7r4-m6w7-qqqr + ws: "^8.21.0" # CVE-2026-48779 (memory-exhaustion DoS) + form-data: "^4.0.6" # CVE-2026-12143 (CRLF header injection) + js-yaml: "^4.2.0" # CVE-2026-53550 (merge-key quadratic DoS) + read-yaml-file: "^2.1.0" + +peerDependencyRules: + allowedVersions: + typescript: "^6.0.0"