From 3de1d6d7c57fb2b2323aa464c205dcf3b4aa21ae Mon Sep 17 00:00:00 2001 From: joshsiv-mulga Date: Wed, 3 Jun 2026 11:04:51 +1000 Subject: [PATCH 01/73] fix(microvm): build initramfs device nodes via fakeroot, drop sudo mknod sudo mknod created real /dev/console and /dev/null char-device nodes on the host under $CHROOT_DIR. Real device nodes on the host filesystem are a footgun: a stale-image cleanup, tmp reaper, or an empty $CHROOT_DIR (which would redirect the recursive /dev removal at the host root) could clobber host /dev/null and force a reboot, breaking CI servers. Write the two static nodes the kernel needs into the cpio archive inside a fakeroot session instead. mknod/cpio see faked device entries and emit real char-device records into the archive, while the host filesystem never gets an actual node. init mounts devtmpfs over /dev at runtime for everything else. Also guard $CHROOT_DIR against empty/unexpected values before any destructive removal, and add fakeroot to the required-tools check. --- scripts/build-microvm-image.sh | 40 +++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/scripts/build-microvm-image.sh b/scripts/build-microvm-image.sh index 5804cdf1e..b70d846ed 100755 --- a/scripts/build-microvm-image.sh +++ b/scripts/build-microvm-image.sh @@ -26,7 +26,11 @@ echo "[build-microvm-image] build dir: $BUILD_DIR" mkdir -p "$BUILD_DIR" # --- Verify non-negotiable tools --- -for tool in cpio gzip find; do +# fakeroot is mandatory: device nodes are written into the cpio archive inside a +# faked-root environment so no real device node is ever created on the host +# filesystem (which previously required sudo mknod and risked clobbering host +# /dev/null on cleanup). +for tool in cpio gzip find fakeroot; do if ! command -v "$tool" >/dev/null 2>&1; then echo "ERROR: required tool not found: $tool" >&2 exit 1 @@ -35,6 +39,13 @@ done # --- Create chroot --- CHROOT_DIR=$(mktemp -d) +# Guard: every destructive op below targets "$CHROOT_DIR/...". An empty or +# unexpected value would aim rm -rf at the host (e.g. /dev). Refuse anything that +# is not a freshly-created temp dir. +case "${CHROOT_DIR:?mktemp -d returned empty}" in + /tmp/*|/var/tmp/*|"${TMPDIR:-/nonexistent}"/*) ;; + *) echo "ERROR: refusing to use unexpected CHROOT_DIR: $CHROOT_DIR" >&2; exit 1 ;; +esac CONTAINER_TOOL="" CONTAINER_CID="" cleanup() { @@ -93,16 +104,14 @@ else $CONTAINER_TOOL export "$CONTAINER_CID" | tar -x -C "$CHROOT_DIR" fi -# --- Fix /dev device nodes --- +# --- /dev: empty mountpoint only --- # tar extraction without root silently creates 0-byte regular files for device -# nodes (mknod requires CAP_MKNOD). The kernel opens /dev/console to wire -# init's stdio to the serial console; a regular file there causes all init -# output to be silently discarded. Recreate the two nodes needed before -# devtmpfs mounts (which provides the rest at runtime). -rm -rf "$CHROOT_DIR/dev" +# nodes. Drop them and leave an empty /dev mountpoint. The two static nodes the +# kernel needs (/dev/console to wire init's stdio, /dev/null) are written into +# the cpio archive under fakeroot at pack time — NOT created on the host. init +# mounts devtmpfs over /dev as its first action for everything else at runtime. +rm -rf "${CHROOT_DIR:?}/dev" mkdir "$CHROOT_DIR/dev" -sudo mknod -m 600 "$CHROOT_DIR/dev/console" c 5 1 -sudo mknod -m 666 "$CHROOT_DIR/dev/null" c 1 3 # --- Place init script --- echo "[build-microvm-image] installing init.sh as /init..." @@ -238,10 +247,15 @@ rm -rf "$CHROOT_DIR/boot" # --- Build initramfs --- INITRAMFS_OUT="$BUILD_DIR/initramfs.cpio.gz" echo "[build-microvm-image] building initramfs: $INITRAMFS_OUT" -( - cd "$CHROOT_DIR" - find . | cpio --quiet -o -H newc | gzip -9 > "$INITRAMFS_OUT" -) +# Create the static device nodes and pack the archive inside a single fakeroot +# session: mknod/cpio see faked device entries and write real char-device +# records into the cpio, while the host filesystem never gets an actual node. +fakeroot sh -c ' + cd "$1" || exit 1 + mknod -m 600 dev/console c 5 1 + mknod -m 666 dev/null c 1 3 + find . | cpio --quiet -o -H newc | gzip -9 > "$2" +' _ "$CHROOT_DIR" "$INITRAMFS_OUT" # --- Log artifact sizes --- echo "" From de5ee4339a64e80b26acdae10a37631a5c09f7e8 Mon Sep 17 00:00:00 2001 From: Josh Siviour Date: Wed, 3 Jun 2026 15:06:35 +1000 Subject: [PATCH 02/73] fix(elbv2): render fixed-response listener defaults + DescribeTags listener-rules (#278) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shared-ingress ALBs use a fixed-response default action (HTTP 404) with host-header rules forwarding to per-app target groups. Two gaps broke this: - The HAProxy generator read DefaultActions[0].TargetGroupArn unconditionally, so a fixed-response default (empty ARN) rendered `default_backend bk_`, a dangling reference that made HAProxy fail to start — the listener never bound :80 and the LB served no traffic. Store and render the fixed-response config as a synthetic backend (`http-request return status N ...`), with status, content-type, and body validated before interpolation. - ListenerAction dropped the fixed-response config on create/modify, so DescribeListeners read back an empty action and tofu saw a perpetual diff. Preserve it through CreateListener/ModifyListener and the SDK conversion. - DescribeTags returned InvalidParameterValue for listener-rule ARNs; resolve the rule and return an (untagged) descriptor instead. Adds generator tests for the fixed-response default (with host-header rules) and unsafe-body rejection, plus DescribeTags listener-rule coverage. --- spinifex/handlers/elbv2/haproxy.go | 94 +++++++++++++++++++- spinifex/handlers/elbv2/haproxy_test.go | 85 ++++++++++++++++++ spinifex/handlers/elbv2/service_impl.go | 94 ++++++++++++++------ spinifex/handlers/elbv2/service_impl_test.go | 49 ++++++++++ spinifex/handlers/elbv2/types.go | 14 ++- 5 files changed, 304 insertions(+), 32 deletions(-) diff --git a/spinifex/handlers/elbv2/haproxy.go b/spinifex/handlers/elbv2/haproxy.go index 92c487c82..865b9915e 100644 --- a/spinifex/handlers/elbv2/haproxy.go +++ b/spinifex/handlers/elbv2/haproxy.go @@ -6,6 +6,7 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "strconv" "strings" "sync" @@ -44,12 +45,16 @@ frontend {{.Name}} {{end}} {{range .Backends}} backend {{.Name}} +{{- if .FixedResponse}} + http-request return status {{.FixedResponse.StatusCode}}{{if .FixedResponse.ContentType}} content-type "{{.FixedResponse.ContentType}}"{{end}}{{if .FixedResponse.Body}} string "{{.FixedResponse.Body}}"{{end}} +{{- else}} balance roundrobin{{if .HealthCheckPath}} option httpchk GET {{.HealthCheckPath}} http-check expect status {{.HealthCheckMatcher}}{{end}} {{- range .Servers}} server {{.Name}} {{.Addr}}:{{.Port}} check inter {{.CheckInterval}}s fall {{.Fall}} rise {{.Rise}} {{- end}} +{{- end}} {{end}} ` @@ -123,7 +128,8 @@ type HAProxyACL struct { Expr string } -// HAProxyBackend represents a target group backend. +// HAProxyBackend represents a target group backend, or a synthetic backend that +// emits a fixed response (when FixedResponse is set, the server fields are unused). type HAProxyBackend struct { Name string HealthCheckPath string @@ -131,6 +137,15 @@ type HAProxyBackend struct { TCPCheck bool HTTPCheck bool Servers []HAProxyServer + FixedResponse *HAProxyFixedResponse +} + +// HAProxyFixedResponse renders an `http-request return` directive for a +// fixed-response listener default action. All fields are validated before use. +type HAProxyFixedResponse struct { + StatusCode string + ContentType string + Body string } // HAProxyServer represents a single target server. @@ -238,13 +253,43 @@ func buildHAProxyConfig(lb *LoadBalancerRecord, listeners []*ListenerRecord, tgB backendAdded[backendName] = struct{}{} } + addFixedResponseBackend := func(name string, fr *FixedResponseAction) { + if _, ok := backendAdded[name]; ok { + return + } + hf := &HAProxyFixedResponse{StatusCode: "503"} + if fr != nil { + if validHTTPStatusCode(fr.StatusCode) { + hf.StatusCode = fr.StatusCode + } + if validContentType(fr.ContentType) { + hf.ContentType = fr.ContentType + } + if validFixedResponseBody(fr.MessageBody) { + hf.Body = fr.MessageBody + } + } + cfg.Backends = append(cfg.Backends, HAProxyBackend{Name: name, FixedResponse: hf}) + backendAdded[name] = struct{}{} + } + for _, l := range listeners { if len(l.DefaultActions) == 0 { continue } - tgArn := l.DefaultActions[0].TargetGroupArn - defaultBackendName := sanitizeName("bk", tgArn) + da := l.DefaultActions[0] + isForwardDefault := da.Type == ActionTypeForward && da.TargetGroupArn != "" + + var defaultBackendName string + if isForwardDefault { + defaultBackendName = sanitizeName("bk", da.TargetGroupArn) + } else { + // fixed-response (or any non-forward default, e.g. the shared-ingress + // 404): synthesize a backend that returns the canned reply so HAProxy + // has a valid default_backend instead of a dangling reference. + defaultBackendName = sanitizeName("bkdefault", l.ListenerArn) + } frontend := HAProxyFrontend{ Name: sanitizeName("ft", l.ListenerArn), @@ -270,7 +315,11 @@ func buildHAProxyConfig(lb *LoadBalancerRecord, listeners []*ListenerRecord, tgB } cfg.Frontends = append(cfg.Frontends, frontend) - addBackend(tgArn) + if isForwardDefault { + addBackend(da.TargetGroupArn) + } else { + addFixedResponseBackend(defaultBackendName, da.FixedResponse) + } } return cfg, nil @@ -395,6 +444,43 @@ func wildcardMatch(v string) (flag, literal string) { } } +// contentTypeRegex matches a conservative MIME type (type/subtype) for the +// fixed-response content-type header rendered into the HAProxy config. +var contentTypeRegex = regexp.MustCompile(`^[a-zA-Z0-9!#$&^_.+-]+/[a-zA-Z0-9!#$&^_.+-]+$`) + +// validHTTPStatusCode accepts a 3-digit 2xx–5xx HTTP status. +func validHTTPStatusCode(s string) bool { + if len(s) != 3 || s[0] < '2' || s[0] > '5' { + return false + } + for _, r := range s { + if r < '0' || r > '9' { + return false + } + } + return true +} + +// validContentType accepts a conservative type/subtype MIME string. +func validContentType(s string) bool { + return contentTypeRegex.MatchString(s) +} + +// validFixedResponseBody rejects bytes that would terminate the quoted HAProxy +// string or inject a directive. Spaces are allowed (the body renders inside +// double quotes). +func validFixedResponseBody(s string) bool { + if s == "" { + return false + } + for _, r := range s { + if r == '\n' || r == '\r' || r == '"' || r == '\\' || r == '#' { + return false + } + } + return true +} + // validateRenderSafe rejects bytes that could break ACL parsing or inject new // directives. Mirrors the write-time validators in service_impl_rules.go; // duplicated here so a future migration that bypasses the API cannot leak a diff --git a/spinifex/handlers/elbv2/haproxy_test.go b/spinifex/handlers/elbv2/haproxy_test.go index 4adaed7b4..2c89d2480 100644 --- a/spinifex/handlers/elbv2/haproxy_test.go +++ b/spinifex/handlers/elbv2/haproxy_test.go @@ -163,6 +163,91 @@ func TestGenerateHAProxyConfig_SharedTargetGroup(t *testing.T) { assert.Equal(t, 1, strings.Count(config, "balance roundrobin")) } +// TestGenerateHAProxyConfig_FixedResponseDefault mirrors the shared-ingress +// shape: a listener whose default action is fixed-response (no target group), +// with host-header rules forwarding to per-app target groups. The generator +// must synthesize a default backend instead of emitting a dangling +// `default_backend bk_`, which makes HAProxy fail to start. +func TestGenerateHAProxyConfig_FixedResponseDefault(t *testing.T) { + lb := &LoadBalancerRecord{LoadBalancerID: "lb-ingress"} + listenerArn := "arn:aws:elasticloadbalancing:ap-southeast-2:1:listener/app/wd-ingress/lb-ingress/lst-616760baf6a3031c3" + appTG := "arn:aws:elasticloadbalancing:ap-southeast-2:1:targetgroup/wd-identity/tg-app1" + + listeners := []*ListenerRecord{ + { + ListenerArn: listenerArn, + Port: 80, + Protocol: ProtocolHTTP, + DefaultActions: []ListenerAction{ + {Type: ActionTypeFixedResponse, FixedResponse: &FixedResponseAction{ + StatusCode: "404", + ContentType: "text/plain", + MessageBody: "no route", + }}, + }, + }, + } + + rulesByListener := map[string][]*RuleRecord{ + listenerArn: { + { + RuleID: "rule1", + ListenerArn: listenerArn, + Priority: 1, + Conditions: []RuleCondition{{Field: RuleFieldHostHeader, Values: []string{"identity.toc.spinifex.local"}}}, + Actions: []ListenerAction{{Type: ActionTypeForward, TargetGroupArn: appTG}}, + }, + }, + } + + tgByArn := map[string]*TargetGroupRecord{ + appTG: { + TargetGroupArn: appTG, + HealthCheck: DefaultHealthCheck(), + Targets: []Target{{Id: "i-app1", Port: 8080, PrivateIP: "10.42.0.9", HealthState: TargetHealthHealthy}}, + }, + } + + config, err := GenerateHAProxyConfig(lb, listeners, tgByArn, rulesByListener, "10.42.0.13") + require.NoError(t, err) + + // No dangling default backend. + assert.NotContains(t, config, "default_backend bk_\n") + // Synthetic default backend named off the listener ARN, returning the fixed response. + assert.Contains(t, config, "default_backend bkdefault_lst-616760baf6a3031c3") + assert.Contains(t, config, "backend bkdefault_lst-616760baf6a3031c3") + assert.Contains(t, config, `http-request return status 404 content-type "text/plain" string "no route"`) + // Host-header rule still routes to the app backend. + assert.Contains(t, config, "use_backend bk_tg-app1 if") + assert.Contains(t, config, "10.42.0.9:8080") +} + +// TestGenerateHAProxyConfig_FixedResponseRejectsUnsafeBody falls back to a bare +// status when the body or content-type contains injection bytes. +func TestGenerateHAProxyConfig_FixedResponseRejectsUnsafeBody(t *testing.T) { + lb := &LoadBalancerRecord{LoadBalancerID: "lb-evil"} + listeners := []*ListenerRecord{ + { + ListenerArn: "arn:lst-evil", + Port: 80, + DefaultActions: []ListenerAction{ + {Type: ActionTypeFixedResponse, FixedResponse: &FixedResponseAction{ + StatusCode: "200", + ContentType: "text/plain", + MessageBody: "evil\"\n acl x always_true", + }}, + }, + }, + } + + config, err := GenerateHAProxyConfig(lb, listeners, nil, nil, "0.0.0.0") + require.NoError(t, err) + + assert.Contains(t, config, "http-request return status 200") + assert.NotContains(t, config, "always_true") + assert.NotContains(t, config, `string "evil`) +} + func TestGenerateHAProxyConfig_NoListeners(t *testing.T) { lb := &LoadBalancerRecord{LoadBalancerID: "lb-empty"} config, err := GenerateHAProxyConfig(lb, nil, nil, nil, "0.0.0.0") diff --git a/spinifex/handlers/elbv2/service_impl.go b/spinifex/handlers/elbv2/service_impl.go index 8491c62a4..7bb7f796a 100644 --- a/spinifex/handlers/elbv2/service_impl.go +++ b/spinifex/handlers/elbv2/service_impl.go @@ -777,13 +777,15 @@ const ( elbv2ResourceLoadBalancer = "loadbalancer" elbv2ResourceTargetGroup = "targetgroup" elbv2ResourceListener = "listener" + elbv2ResourceListenerRule = "listener-rule" ) // elbv2ResourceTypeFromArn extracts the resource type from an ELBv2 ARN. // ELBv2 ARNs have the form // "arn:aws:elasticloadbalancing:{region}:{account}:{type}/...". Returns one -// of "loadbalancer", "targetgroup", "listener" — anything else yields -// ErrorInvalidParameterValue so callers can surface a proper API error. +// of "loadbalancer", "targetgroup", "listener", "listener-rule" — anything +// else yields ErrorInvalidParameterValue so callers can surface a proper API +// error. func elbv2ResourceTypeFromArn(arn string) (string, error) { parts := strings.SplitN(arn, ":", 6) if len(parts) < 6 || parts[0] != "arn" || parts[2] != "elasticloadbalancing" { @@ -796,7 +798,7 @@ func elbv2ResourceTypeFromArn(arn string) (string, error) { } resourceType := resourceSegment[:slash] switch resourceType { - case elbv2ResourceLoadBalancer, elbv2ResourceTargetGroup, elbv2ResourceListener: + case elbv2ResourceLoadBalancer, elbv2ResourceTargetGroup, elbv2ResourceListener, elbv2ResourceListenerRule: return resourceType, nil default: return "", errors.New(awserrors.ErrorInvalidParameterValue) @@ -1626,6 +1628,34 @@ func (s *ELBv2ServiceImpl) DescribeTargetHealth(input *elbv2.DescribeTargetHealt // --- Listener operations --- +// listenerActionFromSDK converts an SDK listener action into the stored form, +// preserving fixed-response config so HAProxy generation and tofu read-back see +// the full action (a forward-only conversion drops the fixed-response default +// and produces a dangling backend + perpetual plan diff). +func listenerActionFromSDK(a *elbv2.Action) ListenerAction { + action := ListenerAction{} + if a.Type != nil { + action.Type = *a.Type + } + if a.TargetGroupArn != nil { + action.TargetGroupArn = *a.TargetGroupArn + } + if a.FixedResponseConfig != nil { + fr := &FixedResponseAction{} + if a.FixedResponseConfig.StatusCode != nil { + fr.StatusCode = *a.FixedResponseConfig.StatusCode + } + if a.FixedResponseConfig.ContentType != nil { + fr.ContentType = *a.FixedResponseConfig.ContentType + } + if a.FixedResponseConfig.MessageBody != nil { + fr.MessageBody = *a.FixedResponseConfig.MessageBody + } + action.FixedResponse = fr + } + return action +} + func (s *ELBv2ServiceImpl) CreateListener(input *elbv2.CreateListenerInput, accountID string) (*elbv2.CreateListenerOutput, error) { if input.LoadBalancerArn == nil || *input.LoadBalancerArn == "" { return nil, errors.New(awserrors.ErrorMissingParameter) @@ -1705,14 +1735,7 @@ func (s *ELBv2ServiceImpl) CreateListener(input *elbv2.CreateListenerInput, acco var actions []ListenerAction for _, a := range input.DefaultActions { - action := ListenerAction{} - if a.Type != nil { - action.Type = *a.Type - } - if a.TargetGroupArn != nil { - action.TargetGroupArn = *a.TargetGroupArn - } - actions = append(actions, action) + actions = append(actions, listenerActionFromSDK(a)) } record := &ListenerRecord{ @@ -1857,13 +1880,7 @@ func (s *ELBv2ServiceImpl) ModifyListener(input *elbv2.ModifyListenerInput, acco if len(input.DefaultActions) > 0 { var actions []ListenerAction for _, a := range input.DefaultActions { - action := ListenerAction{} - if a.Type != nil { - action.Type = *a.Type - } - if a.TargetGroupArn != nil { - action.TargetGroupArn = *a.TargetGroupArn - } + action := listenerActionFromSDK(a) if action.Type == ActionTypeForward && action.TargetGroupArn != "" { tg, tgErr := s.store.GetTargetGroupByArn(action.TargetGroupArn) if tgErr != nil { @@ -1957,11 +1974,12 @@ func (s *ELBv2ServiceImpl) DescribeListeners(input *elbv2.DescribeListenersInput // --- Tag operations --- // DescribeTags returns tags for one or more ELBv2 resources (load balancers, -// target groups, listeners). Tag data is read from the existing record stores -// — Spinifex doesn't have a separate tag KV. Listeners currently never store -// tags, so they always return an empty Tags slice (matches AWS behaviour for -// untagged resources). Cross-account or unknown ARNs return the per-resource -// not-found error so existence isn't leaked across accounts. +// target groups, listeners, listener rules). Tag data is read from the existing +// record stores — Spinifex doesn't have a separate tag KV. Listeners and rules +// currently never store tags, so they always return an empty Tags slice +// (matches AWS behaviour for untagged resources). Cross-account or unknown ARNs +// return the per-resource not-found error so existence isn't leaked across +// accounts. func (s *ELBv2ServiceImpl) DescribeTags(input *elbv2.DescribeTagsInput, accountID string) (*elbv2.DescribeTagsOutput, error) { if input == nil || len(input.ResourceArns) == 0 { return nil, errors.New(awserrors.ErrorMissingParameter) @@ -2022,6 +2040,18 @@ func (s *ELBv2ServiceImpl) DescribeTags(input *elbv2.DescribeTagsInput, accountI ownerAccount = l.AccountID // Listeners don't store tags yet — leave map nil. } + case elbv2ResourceListenerRule: + notFoundError = awserrors.ErrorELBv2RuleNotFound + r, rErr := s.store.GetRuleByArn(arn) + if rErr != nil { + slog.Error("DescribeTags: failed to get rule", "arn", arn, "err", rErr) + return nil, errors.New(awserrors.ErrorServerInternal) + } + if r != nil { + found = true + ownerAccount = r.AccountID + // Rules don't store tags yet — leave map nil. + } } if !found || ownerAccount != accountID { @@ -2357,9 +2387,21 @@ func (s *ELBv2ServiceImpl) listenerRecordToSDK(r *ListenerRecord) *elbv2.Listene } for _, a := range r.DefaultActions { - action := &elbv2.Action{ - Type: aws.String(a.Type), - TargetGroupArn: aws.String(a.TargetGroupArn), + action := &elbv2.Action{Type: aws.String(a.Type)} + if a.TargetGroupArn != "" { + action.TargetGroupArn = aws.String(a.TargetGroupArn) + } + if a.FixedResponse != nil { + fr := &elbv2.FixedResponseActionConfig{ + StatusCode: aws.String(a.FixedResponse.StatusCode), + } + if a.FixedResponse.ContentType != "" { + fr.ContentType = aws.String(a.FixedResponse.ContentType) + } + if a.FixedResponse.MessageBody != "" { + fr.MessageBody = aws.String(a.FixedResponse.MessageBody) + } + action.FixedResponseConfig = fr } listener.DefaultActions = append(listener.DefaultActions, action) } diff --git a/spinifex/handlers/elbv2/service_impl_test.go b/spinifex/handlers/elbv2/service_impl_test.go index 3a9f08118..968b86a65 100644 --- a/spinifex/handlers/elbv2/service_impl_test.go +++ b/spinifex/handlers/elbv2/service_impl_test.go @@ -2980,6 +2980,55 @@ func TestDescribeTags_Listener_NoTags(t *testing.T) { assert.Empty(t, out.TagDescriptions[0].Tags) } +func TestDescribeTags_ListenerRule_NoTags(t *testing.T) { + svc := setupTestService(t) + lbOut, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("tags-rule-lb")}, testAccountID) + tgOut, _ := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tags-rule-tg")}, testAccountID) + lstOut, err := svc.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: lbOut.LoadBalancers[0].LoadBalancerArn, + Protocol: aws.String("HTTP"), + Port: aws.Int64(80), + DefaultActions: []*elbv2.Action{ + {Type: aws.String("forward"), TargetGroupArn: tgOut.TargetGroups[0].TargetGroupArn}, + }, + }, testAccountID) + require.NoError(t, err) + + ruleOut, err := svc.CreateRule(&elbv2.CreateRuleInput{ + ListenerArn: lstOut.Listeners[0].ListenerArn, + Priority: aws.Int64(10), + Conditions: []*elbv2.RuleCondition{ + {Field: aws.String("host-header"), Values: aws.StringSlice([]string{"app.example.com"})}, + }, + Actions: []*elbv2.Action{ + {Type: aws.String("forward"), TargetGroupArn: tgOut.TargetGroups[0].TargetGroupArn}, + }, + }, testAccountID) + require.NoError(t, err) + + // Rules don't store tags yet — must still return a TagDescription (with an + // empty Tags slice), not an error. This is the case the Terraform AWS + // provider hits during post-create refresh of aws_lb_listener_rule. + out, err := svc.DescribeTags(&elbv2.DescribeTagsInput{ + ResourceArns: []*string{ruleOut.Rules[0].RuleArn}, + }, testAccountID) + require.NoError(t, err) + require.Len(t, out.TagDescriptions, 1) + assert.Equal(t, *ruleOut.Rules[0].RuleArn, *out.TagDescriptions[0].ResourceArn) + assert.Empty(t, out.TagDescriptions[0].Tags) +} + +func TestDescribeTags_RuleNotFound(t *testing.T) { + svc := setupTestService(t) + _, err := svc.DescribeTags(&elbv2.DescribeTagsInput{ + ResourceArns: []*string{ + aws.String("arn:aws:elasticloadbalancing:us-east-1:123456789012:listener-rule/app/missing/lb-x/lst-y/rule-deadbeef"), + }, + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorELBv2RuleNotFound) +} + func TestDescribeTags_MultipleArns(t *testing.T) { svc := setupTestService(t) lbOut, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{ diff --git a/spinifex/handlers/elbv2/types.go b/spinifex/handlers/elbv2/types.go index f0ef8daa3..21fe3ae0f 100644 --- a/spinifex/handlers/elbv2/types.go +++ b/spinifex/handlers/elbv2/types.go @@ -34,7 +34,8 @@ const ( ProtocolTCPUDP = "TCP_UDP" // Listener action types - ActionTypeForward = "forward" + ActionTypeForward = "forward" + ActionTypeFixedResponse = "fixed-response" // Rule condition fields RuleFieldHostHeader = "host-header" @@ -196,8 +197,17 @@ type ListenerRecord struct { // ListenerAction defines a listener's default action. type ListenerAction struct { - Type string `json:"type"` // "forward" + Type string `json:"type"` // "forward" or "fixed-response" TargetGroupArn string `json:"target_group_arn"` + // FixedResponse is populated when Type == "fixed-response" (no target group). + FixedResponse *FixedResponseAction `json:"fixed_response,omitempty"` +} + +// FixedResponseAction holds the canned reply for a "fixed-response" action. +type FixedResponseAction struct { + StatusCode string `json:"status_code"` + ContentType string `json:"content_type,omitempty"` + MessageBody string `json:"message_body,omitempty"` } // RuleRecord represents a stored listener rule. From b3f72512399ff147a27f153270763b61dacc2cd2 Mon Sep 17 00:00:00 2001 From: Josh Siviour Date: Wed, 3 Jun 2026 20:17:55 +1000 Subject: [PATCH 03/73] refactor: migrate lbagent signing to predastore/auth.SignReq (#281) agent.go signed gateway requests with aws-sdk-go v1's v4.Signer. Switch to predastore/auth.SignReq (a thin wrapper over aws-sdk-go-v2's v4.Signer) so the monorepo runs a single signer version and drops the last direct dependency on aws-sdk-go v1's signer subpackage. - Replace the *v4.Signer field with the raw access/secret keys. - signedPost computes the hex SHA-256 payload hash and calls auth.SignReq. - Add TestSignedPost_ProducesVerifiableSignature: the signed request parses and verifies server-side via auth.ParseReq/Verify with a matching body hash. --- spinifex/lbagent/agent.go | 21 +++++++------- spinifex/lbagent/agent_test.go | 53 ++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/spinifex/lbagent/agent.go b/spinifex/lbagent/agent.go index 4fffb401b..f2e409643 100644 --- a/spinifex/lbagent/agent.go +++ b/spinifex/lbagent/agent.go @@ -5,7 +5,9 @@ package lbagent import ( "bytes" + "crypto/sha256" "crypto/tls" + "encoding/hex" "encoding/xml" "fmt" "io" @@ -20,8 +22,7 @@ import ( "syscall" "time" - "github.com/aws/aws-sdk-go/aws/credentials" - v4 "github.com/aws/aws-sdk-go/aws/signer/v4" + "github.com/mulgadc/predastore/auth" "github.com/mulgadc/spinifex/internal/tlsconfig" ) @@ -43,8 +44,9 @@ type Agent struct { pidPath string socketPath string // HAProxy stats socket - signer *v4.Signer - client *http.Client + accessKey string + secretKey string + client *http.Client localConfigHash string stopCh chan struct{} @@ -70,9 +72,6 @@ func New(lbID, gatewayURL, accessKey, secretKey, region string) (*Agent, error) return nil, fmt.Errorf("region is required") } - creds := credentials.NewStaticCredentials(accessKey, secretKey, "") - signer := v4.NewSigner(creds) - // Use system CA trust store (CA cert injected via cloud-init ca_certs). client := &http.Client{ Timeout: 10 * time.Second, @@ -93,7 +92,8 @@ func New(lbID, gatewayURL, accessKey, secretKey, region string) (*Agent, error) configPath: DefaultConfigPath, pidPath: DefaultPIDPath, socketPath: fmt.Sprintf("/tmp/spinifex-haproxy/lb-%s.sock", lbID), - signer: signer, + accessKey: accessKey, + secretKey: secretKey, client: client, stopCh: make(chan struct{}), reloadFn: reloadHAProxy, @@ -238,8 +238,9 @@ func (a *Agent) signedPost(params url.Values) ([]byte, error) { } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - _, err = a.signer.Sign(req, bytes.NewReader([]byte(body)), "elasticloadbalancing", a.region, time.Now()) - if err != nil { + sum := sha256.Sum256([]byte(body)) + payloadHash := hex.EncodeToString(sum[:]) + if err := auth.SignReq(req, a.accessKey, a.secretKey, payloadHash, "elasticloadbalancing", a.region); err != nil { return nil, fmt.Errorf("sign request: %w", err) } diff --git a/spinifex/lbagent/agent_test.go b/spinifex/lbagent/agent_test.go index 54540087e..2129acb7c 100644 --- a/spinifex/lbagent/agent_test.go +++ b/spinifex/lbagent/agent_test.go @@ -1,14 +1,20 @@ package lbagent import ( + "crypto/sha256" + "encoding/hex" "fmt" + "io" "net/http" "net/http/httptest" + "net/url" "os" "path/filepath" "sync/atomic" "testing" "time" + + "github.com/mulgadc/predastore/auth" ) func TestNew(t *testing.T) { @@ -68,6 +74,53 @@ func TestNew_SocketPath(t *testing.T) { } } +// TestSignedPost_ProducesVerifiableSignature confirms the migrated signing path +// (predastore/auth.SignReq over aws-sdk-go-v2) produces a request the gateway's +// SigV4 verifier accepts, including a body-hash that matches X-Amz-Content-Sha256. +func TestSignedPost_ProducesVerifiableSignature(t *testing.T) { + const ( + accessKey = "AKIAIOSFODNN7EXAMPLE" + secretKey = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + region = "us-east-1" + ) + + var parsed bool + var verifyErr error + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + body, _ := io.ReadAll(r.Body) + sum := sha256.Sum256(body) + req, err := auth.ParseReq(r) + if err != nil { + verifyErr = err + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + parsed = true + verifyErr = req.Verify(secretKey, "elasticloadbalancing", region, + auth.WithBodyHash(hex.EncodeToString(sum[:]))) + fmt.Fprint(w, "ok") + })) + defer srv.Close() + + agent, err := New("lb-sig", srv.URL, accessKey, secretKey, region) + if err != nil { + t.Fatalf("New: %v", err) + } + + if _, err := agent.signedPost(url.Values{ + "Action": {"LBAgentHeartbeat"}, + "LoadBalancerId": {"lb-sig"}, + }); err != nil { + t.Fatalf("signedPost: %v", err) + } + if !parsed { + t.Fatal("gateway did not parse a SigV4 Authorization header") + } + if verifyErr != nil { + t.Fatalf("signed request failed server-side verification: %v", verifyErr) + } +} + // fakeGateway returns a test server that responds to LBAgentHeartbeat and GetLBConfig. func fakeGateway(t *testing.T, configHash, configText, status string) *httptest.Server { t.Helper() From 7b9eb9cc4e5ee2a456f2be5e472cda0dc1bf7f05 Mon Sep 17 00:00:00 2001 From: Josh Siviour Date: Wed, 3 Jun 2026 21:49:25 +1000 Subject: [PATCH 04/73] feat(elbv2): tag/SG/IP-type setters, ip targets, redirect actions, delete-cascade hardening (#282) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(elbv2): make resource deletes idempotent on absent DeleteLoadBalancer, DeleteTargetGroup, DeleteListener and DeleteRule returned a NotFound error when the target was already gone. Real AWS ELBv2 deletes are idempotent (success on absent), so terraform-provider-aws fails a destroy step on retry. Return an empty success output instead, mirroring the KV store which already tolerates absent keys. Adds TestRLC1_ELBv2DeleteIdempotentOnAbsent enforcing the contract across the ELBv2 delete surface; converts the three _NotFound delete tests to assert idempotent success. Refs mulga-siv-172 (idempotency clause; cascade-composition clause stays open). * feat: ELBv2 AddTags/RemoveTags, SetSecurityGroups, SetIpAddressType - O(1) GetListenerByArn via ARN-parse short-ID lookup + ARN equality check - persist tags on listeners/rules; seed at create time - AddTags/RemoveTags across LB, target group, listener, rule resources - SetSecurityGroups (ALB only) reattaches SGs to each ENI via live port update - SetIpAddressType (ipv4-only, idempotent) - wire all four ops through gateway, NATS client, and daemon handlers - frontend: editable Tags tab on LB/TG detail, Security groups tab on LB detail * feat(elbv2): redirect listener/rule actions - add redirect action type; parse/store/read-back RedirectActionConfig - validate status code + render-safe fields (strip AWS #{...} placeholders) - accept redirect and fixed-response on listener rules (not just defaults) - HAProxy: http-request redirect scheme (HTTP->HTTPS fast path) or rebuilt location with placeholder->fetch translation; synthetic per-rule backends * refactor: dedupe ELBv2 attribute handlers and harden store lookups Collapse the four near-identical Modify/Describe attribute handlers (target group and load balancer mirror pairs) onto generic helpers in both the service impl and the gateway, and table-drive the mirror-pair tests over a TG/LB kind. - service_impl_attributes.go: generic attrResource/modifyResourceAttributes/ describeResourceAttributes plus sdkAttrsIn/sdkAttrsOut; folds in nil-input guards, explicit empty-accountID rejection, fresh-string output, and a no-op skip-persist for unchanged Modify calls. - gateway/elbv2/attributes.go: generic attributeOp + shared validateAttrArn, replacing four per-endpoint files. - types.go: default attribute sets are now package-level maps cloned on access instead of rebuilt per Describe; document the access_logs empty-string defaults. - store.go: drop the stale 'linear scan' docstring and log ARN mismatches on GetLoadBalancerByArn/GetTargetGroupByArn instead of silently returning nil. Adds cross-account isolation, wrong-account no-mutation, and empty-string-clear coverage. * feat: support ip target type in ELBv2 RegisterTargets RegisterTargets resolved every target ID through an instance ENI lookup, so ip-type target groups silently no-op'd with an empty PrivateIP and never received traffic. - types.go: add TargetTypeInstance/TargetTypeIP constants. - CreateTargetGroup: default to instance; reject target types other than instance/ip with InvalidParameterValue. - RegisterTargets: resolve PrivateIP per target type via resolveRegisteredTargetIP — ip targets use the supplied IP directly (validated with net.ParseIP), instance targets keep the ENI lookup and reject IP-shaped IDs. * fix: cascade rule deletion in ELBv2 DeleteLoadBalancer DeleteLoadBalancer deleted listeners via store.DeleteListener directly, which bypasses the rule cascade in the DeleteListener handler. Orphan rules survived LB teardown and pinned their target groups as ResourceInUse, leaving the TG permanently undeletable and breaking tofu destroy on multinode. Extract deleteListenerCascade (rules then listener record) and call it from both DeleteListener and the DeleteLoadBalancer cleanup loop. Regression: TestDeleteLoadBalancer_CascadesRuleDeletion. * fix: harden ELBv2 delete lifecycle against orphaned cascades - DeleteLoadBalancer: fail-fast on listener-list/cascade error and run the rule cascade before backing-artifact teardown, so a transient failure leaves the record intact for retry instead of orphaning rules. - DeleteTargetGroup: in-use scan skips listeners/rules whose owning load balancer no longer exists, so a partial-teardown orphan can't pin a target group as ResourceInUse permanently. - DeleteRule: propagate the listener lookup error instead of discarding it, so a failed HAProxy reload is no longer reported as success. - Add lifecycle invariants for no-orphan completeness, no store-bypass cascade, and target-group deletability after LB teardown. - Drop plan/bead references from comments. * test: add NATS e2e round-trips for new ELBv2 ops Cover the client→NATS→handler marshalling path that unit tests skip: tags lifecycle (AddTags/DescribeTags/RemoveTags), target-group and load-balancer attribute round-trips, redirect-action default listener, ip target-type registration, and SetSecurityGroups/SetIpAddressType. * fix(elbv2): correct misleading InvalidConfigurationRequest message The error code is shared by five unrelated conditions (dualstack rejection in SetIpAddressType, cross-listener rule moves, unsupported rule action types, and the two genuine NLB security-group cases), but its canonical message claimed security groups were unsupported on network load balancers. Callers hitting it from SetIpAddressType or the rule paths got a message about security groups and NLBs that did not match their request. Neutralize to a generic, condition-agnostic message. The AWS error code is unchanged. * style(ui): oxfmt security-groups-editor test --- spinifex/awserrors/awserrors.go | 2 +- spinifex/daemon/daemon.go | 4 + spinifex/daemon/daemon_handlers_elbv2.go | 16 + spinifex/gateway/elbv2.go | 12 + spinifex/gateway/elbv2/AddTags.go | 29 + .../elbv2/DescribeLoadBalancerAttributes.go | 37 - .../elbv2/DescribeTargetGroupAttributes.go | 37 - .../elbv2/ModifyLoadBalancerAttributes.go | 40 - .../elbv2/ModifyTargetGroupAttributes.go | 40 - spinifex/gateway/elbv2/RemoveTags.go | 29 + spinifex/gateway/elbv2/SetIpAddressType.go | 31 + spinifex/gateway/elbv2/SetSecurityGroups.go | 31 + spinifex/gateway/elbv2/attributes.go | 106 ++ spinifex/gateway/elbv2_test.go | 4 + spinifex/handlers/elbv2/haproxy.go | 217 ++- spinifex/handlers/elbv2/haproxy_test.go | 153 ++ .../elbv2/lifecycle_invariants_test.go | 187 +++ spinifex/handlers/elbv2/service.go | 4 + spinifex/handlers/elbv2/service_impl.go | 491 +++---- .../handlers/elbv2/service_impl_attributes.go | 265 ++++ .../elbv2/service_impl_health_test.go | 2 +- .../handlers/elbv2/service_impl_lb_network.go | 109 ++ .../elbv2/service_impl_lb_network_test.go | 136 ++ spinifex/handlers/elbv2/service_impl_rules.go | 72 +- .../elbv2/service_impl_rules_extra_test.go | 27 +- .../handlers/elbv2/service_impl_rules_test.go | 105 +- spinifex/handlers/elbv2/service_impl_tags.go | 185 +++ .../handlers/elbv2/service_impl_tags_test.go | 200 +++ spinifex/handlers/elbv2/service_impl_test.go | 1263 +++++++++-------- .../handlers/elbv2/service_impl_vpc_test.go | 2 +- spinifex/handlers/elbv2/service_nats.go | 16 + .../handlers/elbv2/service_nats_e2e_test.go | 203 +++ spinifex/handlers/elbv2/store.go | 42 +- spinifex/handlers/elbv2/store_test.go | 10 + spinifex/handlers/elbv2/types.go | 135 +- .../elbv2/security-groups-editor.test.tsx | 114 ++ .../elbv2/security-groups-editor.tsx | 127 ++ .../src/components/elbv2/tags-editor.test.tsx | 128 ++ .../src/components/elbv2/tags-editor.tsx | 170 +++ .../frontend/src/mutations/elbv2.ts | 73 + .../-components/load-balancer-detail-page.tsx | 67 +- .../describe-load-balancers/$id.test.tsx | 6 + .../-components/target-group-detail-page.tsx | 35 +- 43 files changed, 3799 insertions(+), 1163 deletions(-) create mode 100644 spinifex/gateway/elbv2/AddTags.go delete mode 100644 spinifex/gateway/elbv2/DescribeLoadBalancerAttributes.go delete mode 100644 spinifex/gateway/elbv2/DescribeTargetGroupAttributes.go delete mode 100644 spinifex/gateway/elbv2/ModifyLoadBalancerAttributes.go delete mode 100644 spinifex/gateway/elbv2/ModifyTargetGroupAttributes.go create mode 100644 spinifex/gateway/elbv2/RemoveTags.go create mode 100644 spinifex/gateway/elbv2/SetIpAddressType.go create mode 100644 spinifex/gateway/elbv2/SetSecurityGroups.go create mode 100644 spinifex/gateway/elbv2/attributes.go create mode 100644 spinifex/handlers/elbv2/lifecycle_invariants_test.go create mode 100644 spinifex/handlers/elbv2/service_impl_attributes.go create mode 100644 spinifex/handlers/elbv2/service_impl_lb_network.go create mode 100644 spinifex/handlers/elbv2/service_impl_lb_network_test.go create mode 100644 spinifex/handlers/elbv2/service_impl_tags.go create mode 100644 spinifex/handlers/elbv2/service_impl_tags_test.go create mode 100644 spinifex/services/spinifexui/frontend/src/components/elbv2/security-groups-editor.test.tsx create mode 100644 spinifex/services/spinifexui/frontend/src/components/elbv2/security-groups-editor.tsx create mode 100644 spinifex/services/spinifexui/frontend/src/components/elbv2/tags-editor.test.tsx create mode 100644 spinifex/services/spinifexui/frontend/src/components/elbv2/tags-editor.tsx diff --git a/spinifex/awserrors/awserrors.go b/spinifex/awserrors/awserrors.go index 68e9853d0..9d982e7f8 100644 --- a/spinifex/awserrors/awserrors.go +++ b/spinifex/awserrors/awserrors.go @@ -937,7 +937,7 @@ var ErrorLookup = map[string]ErrorMessage{ ErrorELBv2InvalidScheme: {HTTPCode: 400, Message: "The specified scheme is not valid. Specify 'internet-facing' or 'internal'."}, ErrorELBv2SubnetNotFound: {HTTPCode: 400, Message: "The specified subnet does not exist."}, ErrorELBv2AvailabilityZoneNotSupported: {HTTPCode: 400, Message: "The specified Availability Zone is not supported."}, - ErrorELBv2InvalidConfigurationRequest: {HTTPCode: 400, Message: "Security groups are not supported for load balancers with type 'network'."}, + ErrorELBv2InvalidConfigurationRequest: {HTTPCode: 400, Message: "The requested configuration change is not valid."}, ErrorELBv2RuleNotFound: {HTTPCode: 400, Message: "One or more rules not found."}, ErrorELBv2PriorityInUse: {HTTPCode: 400, Message: "The specified priority is in use."}, ErrorELBv2TooManyRules: {HTTPCode: 400, Message: "You've reached the limit on the number of rules per load balancer."}, diff --git a/spinifex/daemon/daemon.go b/spinifex/daemon/daemon.go index 5ffe47b71..6fd535d65 100644 --- a/spinifex/daemon/daemon.go +++ b/spinifex/daemon/daemon.go @@ -840,12 +840,16 @@ func (d *Daemon) subscribeAll() error { natsSub{"elbv2.DescribeRules", d.handleELBv2DescribeRules, "spinifex-workers"}, natsSub{"elbv2.SetRulePriorities", d.handleELBv2SetRulePriorities, "spinifex-workers"}, natsSub{"elbv2.DescribeTags", d.handleELBv2DescribeTags, "spinifex-workers"}, + natsSub{"elbv2.AddTags", d.handleELBv2AddTags, "spinifex-workers"}, + natsSub{"elbv2.RemoveTags", d.handleELBv2RemoveTags, "spinifex-workers"}, natsSub{"elbv2.LBAgentHeartbeat", d.handleELBv2LBAgentHeartbeat, "spinifex-workers"}, natsSub{"elbv2.GetLBConfig", d.handleELBv2GetLBConfig, "spinifex-workers"}, natsSub{"elbv2.ModifyTargetGroupAttributes", d.handleELBv2ModifyTargetGroupAttributes, "spinifex-workers"}, natsSub{"elbv2.DescribeTargetGroupAttributes", d.handleELBv2DescribeTargetGroupAttributes, "spinifex-workers"}, natsSub{"elbv2.ModifyLoadBalancerAttributes", d.handleELBv2ModifyLoadBalancerAttributes, "spinifex-workers"}, natsSub{"elbv2.DescribeLoadBalancerAttributes", d.handleELBv2DescribeLoadBalancerAttributes, "spinifex-workers"}, + natsSub{"elbv2.SetSecurityGroups", d.handleELBv2SetSecurityGroups, "spinifex-workers"}, + natsSub{"elbv2.SetIpAddressType", d.handleELBv2SetIpAddressType, "spinifex-workers"}, ) } diff --git a/spinifex/daemon/daemon_handlers_elbv2.go b/spinifex/daemon/daemon_handlers_elbv2.go index df70be1df..17deb4a8c 100644 --- a/spinifex/daemon/daemon_handlers_elbv2.go +++ b/spinifex/daemon/daemon_handlers_elbv2.go @@ -82,6 +82,14 @@ func (d *Daemon) handleELBv2DescribeTags(msg *nats.Msg) { handleNATSRequest(msg, d.elbv2Service.DescribeTags) } +func (d *Daemon) handleELBv2AddTags(msg *nats.Msg) { + handleNATSRequest(msg, d.elbv2Service.AddTags) +} + +func (d *Daemon) handleELBv2RemoveTags(msg *nats.Msg) { + handleNATSRequest(msg, d.elbv2Service.RemoveTags) +} + func (d *Daemon) handleELBv2LBAgentHeartbeat(msg *nats.Msg) { handleNATSRequest(msg, d.elbv2Service.LBAgentHeartbeat) } @@ -105,3 +113,11 @@ func (d *Daemon) handleELBv2ModifyLoadBalancerAttributes(msg *nats.Msg) { func (d *Daemon) handleELBv2DescribeLoadBalancerAttributes(msg *nats.Msg) { handleNATSRequest(msg, d.elbv2Service.DescribeLoadBalancerAttributes) } + +func (d *Daemon) handleELBv2SetSecurityGroups(msg *nats.Msg) { + handleNATSRequest(msg, d.elbv2Service.SetSecurityGroups) +} + +func (d *Daemon) handleELBv2SetIpAddressType(msg *nats.Msg) { + handleNATSRequest(msg, d.elbv2Service.SetIpAddressType) +} diff --git a/spinifex/gateway/elbv2.go b/spinifex/gateway/elbv2.go index 4bdf0a3e7..e4d3fc4c3 100644 --- a/spinifex/gateway/elbv2.go +++ b/spinifex/gateway/elbv2.go @@ -99,6 +99,12 @@ var elbv2Actions = map[string]ELBv2Handler{ "DescribeTags": elbv2Handler(func(input *elbv2.DescribeTagsInput, gw *GatewayConfig, accountID string) (any, error) { return gateway_elbv2.DescribeTags(input, gw.NATSConn, accountID) }), + "AddTags": elbv2Handler(func(input *elbv2.AddTagsInput, gw *GatewayConfig, accountID string) (any, error) { + return gateway_elbv2.AddTags(input, gw.NATSConn, accountID) + }), + "RemoveTags": elbv2Handler(func(input *elbv2.RemoveTagsInput, gw *GatewayConfig, accountID string) (any, error) { + return gateway_elbv2.RemoveTags(input, gw.NATSConn, accountID) + }), "LBAgentHeartbeat": elbv2Handler(func(input *handlers_elbv2.LBAgentHeartbeatInput, gw *GatewayConfig, accountID string) (any, error) { return gateway_elbv2.LBAgentHeartbeat(input, gw.NATSConn, accountID) }), @@ -120,6 +126,12 @@ var elbv2Actions = map[string]ELBv2Handler{ "DescribeLoadBalancerAttributes": elbv2Handler(func(input *elbv2.DescribeLoadBalancerAttributesInput, gw *GatewayConfig, accountID string) (any, error) { return gateway_elbv2.DescribeLoadBalancerAttributes(input, gw.NATSConn, accountID) }), + "SetSecurityGroups": elbv2Handler(func(input *elbv2.SetSecurityGroupsInput, gw *GatewayConfig, accountID string) (any, error) { + return gateway_elbv2.SetSecurityGroups(input, gw.NATSConn, accountID) + }), + "SetIpAddressType": elbv2Handler(func(input *elbv2.SetIpAddressTypeInput, gw *GatewayConfig, accountID string) (any, error) { + return gateway_elbv2.SetIpAddressType(input, gw.NATSConn, accountID) + }), "DescribeListenerAttributes": elbv2Handler(func(input *gateway_elbv2.DescribeListenerAttributesInput, gw *GatewayConfig, accountID string) (any, error) { return gateway_elbv2.DescribeListenerAttributes(input, accountID) }), diff --git a/spinifex/gateway/elbv2/AddTags.go b/spinifex/gateway/elbv2/AddTags.go new file mode 100644 index 000000000..c58b24d73 --- /dev/null +++ b/spinifex/gateway/elbv2/AddTags.go @@ -0,0 +1,29 @@ +package gateway_elbv2 + +import ( + "errors" + + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/awserrors" + handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2" + "github.com/nats-io/nats.go" +) + +// AddTags handles the ELBv2 AddTags API call. It adds or overwrites the given +// tags on each ELBv2 resource (load balancer, target group, listener, listener +// rule) named in ResourceArns. +func AddTags(input *elbv2.AddTagsInput, natsConn *nats.Conn, accountID string) (elbv2.AddTagsOutput, error) { + var output elbv2.AddTagsOutput + + if input == nil || len(input.ResourceArns) == 0 || len(input.Tags) == 0 { + return output, errors.New(awserrors.ErrorMissingParameter) + } + + svc := handlers_elbv2.NewNATSELBv2Service(natsConn) + result, err := svc.AddTags(input, accountID) + if err != nil { + return output, err + } + + return *result, nil +} diff --git a/spinifex/gateway/elbv2/DescribeLoadBalancerAttributes.go b/spinifex/gateway/elbv2/DescribeLoadBalancerAttributes.go deleted file mode 100644 index 0ed9a930f..000000000 --- a/spinifex/gateway/elbv2/DescribeLoadBalancerAttributes.go +++ /dev/null @@ -1,37 +0,0 @@ -package gateway_elbv2 - -import ( - "errors" - - "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/mulgadc/spinifex/spinifex/awserrors" - handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2" - "github.com/nats-io/nats.go" -) - -func ValidateDescribeLoadBalancerAttributesInput(input *elbv2.DescribeLoadBalancerAttributesInput) error { - if input == nil { - return errors.New(awserrors.ErrorInvalidParameterValue) - } - if input.LoadBalancerArn == nil || *input.LoadBalancerArn == "" { - return errors.New(awserrors.ErrorMissingParameter) - } - return nil -} - -// DescribeLoadBalancerAttributes handles the ELBv2 DescribeLoadBalancerAttributes API call. -func DescribeLoadBalancerAttributes(input *elbv2.DescribeLoadBalancerAttributesInput, natsConn *nats.Conn, accountID string) (elbv2.DescribeLoadBalancerAttributesOutput, error) { - var output elbv2.DescribeLoadBalancerAttributesOutput - - if err := ValidateDescribeLoadBalancerAttributesInput(input); err != nil { - return output, err - } - - svc := handlers_elbv2.NewNATSELBv2Service(natsConn) - result, err := svc.DescribeLoadBalancerAttributes(input, accountID) - if err != nil { - return output, err - } - - return *result, nil -} diff --git a/spinifex/gateway/elbv2/DescribeTargetGroupAttributes.go b/spinifex/gateway/elbv2/DescribeTargetGroupAttributes.go deleted file mode 100644 index 2402be09d..000000000 --- a/spinifex/gateway/elbv2/DescribeTargetGroupAttributes.go +++ /dev/null @@ -1,37 +0,0 @@ -package gateway_elbv2 - -import ( - "errors" - - "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/mulgadc/spinifex/spinifex/awserrors" - handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2" - "github.com/nats-io/nats.go" -) - -func ValidateDescribeTargetGroupAttributesInput(input *elbv2.DescribeTargetGroupAttributesInput) error { - if input == nil { - return errors.New(awserrors.ErrorInvalidParameterValue) - } - if input.TargetGroupArn == nil || *input.TargetGroupArn == "" { - return errors.New(awserrors.ErrorMissingParameter) - } - return nil -} - -// DescribeTargetGroupAttributes handles the ELBv2 DescribeTargetGroupAttributes API call. -func DescribeTargetGroupAttributes(input *elbv2.DescribeTargetGroupAttributesInput, natsConn *nats.Conn, accountID string) (elbv2.DescribeTargetGroupAttributesOutput, error) { - var output elbv2.DescribeTargetGroupAttributesOutput - - if err := ValidateDescribeTargetGroupAttributesInput(input); err != nil { - return output, err - } - - svc := handlers_elbv2.NewNATSELBv2Service(natsConn) - result, err := svc.DescribeTargetGroupAttributes(input, accountID) - if err != nil { - return output, err - } - - return *result, nil -} diff --git a/spinifex/gateway/elbv2/ModifyLoadBalancerAttributes.go b/spinifex/gateway/elbv2/ModifyLoadBalancerAttributes.go deleted file mode 100644 index 0e57ca24e..000000000 --- a/spinifex/gateway/elbv2/ModifyLoadBalancerAttributes.go +++ /dev/null @@ -1,40 +0,0 @@ -package gateway_elbv2 - -import ( - "errors" - - "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/mulgadc/spinifex/spinifex/awserrors" - handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2" - "github.com/nats-io/nats.go" -) - -func ValidateModifyLoadBalancerAttributesInput(input *elbv2.ModifyLoadBalancerAttributesInput) error { - if input == nil { - return errors.New(awserrors.ErrorInvalidParameterValue) - } - if input.LoadBalancerArn == nil || *input.LoadBalancerArn == "" { - return errors.New(awserrors.ErrorMissingParameter) - } - if len(input.Attributes) == 0 { - return errors.New(awserrors.ErrorMissingParameter) - } - return nil -} - -// ModifyLoadBalancerAttributes handles the ELBv2 ModifyLoadBalancerAttributes API call. -func ModifyLoadBalancerAttributes(input *elbv2.ModifyLoadBalancerAttributesInput, natsConn *nats.Conn, accountID string) (elbv2.ModifyLoadBalancerAttributesOutput, error) { - var output elbv2.ModifyLoadBalancerAttributesOutput - - if err := ValidateModifyLoadBalancerAttributesInput(input); err != nil { - return output, err - } - - svc := handlers_elbv2.NewNATSELBv2Service(natsConn) - result, err := svc.ModifyLoadBalancerAttributes(input, accountID) - if err != nil { - return output, err - } - - return *result, nil -} diff --git a/spinifex/gateway/elbv2/ModifyTargetGroupAttributes.go b/spinifex/gateway/elbv2/ModifyTargetGroupAttributes.go deleted file mode 100644 index f759608db..000000000 --- a/spinifex/gateway/elbv2/ModifyTargetGroupAttributes.go +++ /dev/null @@ -1,40 +0,0 @@ -package gateway_elbv2 - -import ( - "errors" - - "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/mulgadc/spinifex/spinifex/awserrors" - handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2" - "github.com/nats-io/nats.go" -) - -func ValidateModifyTargetGroupAttributesInput(input *elbv2.ModifyTargetGroupAttributesInput) error { - if input == nil { - return errors.New(awserrors.ErrorInvalidParameterValue) - } - if input.TargetGroupArn == nil || *input.TargetGroupArn == "" { - return errors.New(awserrors.ErrorMissingParameter) - } - if len(input.Attributes) == 0 { - return errors.New(awserrors.ErrorMissingParameter) - } - return nil -} - -// ModifyTargetGroupAttributes handles the ELBv2 ModifyTargetGroupAttributes API call. -func ModifyTargetGroupAttributes(input *elbv2.ModifyTargetGroupAttributesInput, natsConn *nats.Conn, accountID string) (elbv2.ModifyTargetGroupAttributesOutput, error) { - var output elbv2.ModifyTargetGroupAttributesOutput - - if err := ValidateModifyTargetGroupAttributesInput(input); err != nil { - return output, err - } - - svc := handlers_elbv2.NewNATSELBv2Service(natsConn) - result, err := svc.ModifyTargetGroupAttributes(input, accountID) - if err != nil { - return output, err - } - - return *result, nil -} diff --git a/spinifex/gateway/elbv2/RemoveTags.go b/spinifex/gateway/elbv2/RemoveTags.go new file mode 100644 index 000000000..e40ac1b0d --- /dev/null +++ b/spinifex/gateway/elbv2/RemoveTags.go @@ -0,0 +1,29 @@ +package gateway_elbv2 + +import ( + "errors" + + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/awserrors" + handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2" + "github.com/nats-io/nats.go" +) + +// RemoveTags handles the ELBv2 RemoveTags API call. It removes the given tag +// keys from each ELBv2 resource (load balancer, target group, listener, +// listener rule) named in ResourceArns. Removal is idempotent. +func RemoveTags(input *elbv2.RemoveTagsInput, natsConn *nats.Conn, accountID string) (elbv2.RemoveTagsOutput, error) { + var output elbv2.RemoveTagsOutput + + if input == nil || len(input.ResourceArns) == 0 || len(input.TagKeys) == 0 { + return output, errors.New(awserrors.ErrorMissingParameter) + } + + svc := handlers_elbv2.NewNATSELBv2Service(natsConn) + result, err := svc.RemoveTags(input, accountID) + if err != nil { + return output, err + } + + return *result, nil +} diff --git a/spinifex/gateway/elbv2/SetIpAddressType.go b/spinifex/gateway/elbv2/SetIpAddressType.go new file mode 100644 index 000000000..87f7a2bd8 --- /dev/null +++ b/spinifex/gateway/elbv2/SetIpAddressType.go @@ -0,0 +1,31 @@ +package gateway_elbv2 + +import ( + "errors" + + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/awserrors" + handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2" + "github.com/nats-io/nats.go" +) + +// SetIpAddressType handles the ELBv2 SetIpAddressType API call. It sets the IP +// address type of the load balancer. +func SetIpAddressType(input *elbv2.SetIpAddressTypeInput, natsConn *nats.Conn, accountID string) (elbv2.SetIpAddressTypeOutput, error) { + var output elbv2.SetIpAddressTypeOutput + + if input == nil || input.LoadBalancerArn == nil || *input.LoadBalancerArn == "" { + return output, errors.New(awserrors.ErrorMissingParameter) + } + if input.IpAddressType == nil || *input.IpAddressType == "" { + return output, errors.New(awserrors.ErrorMissingParameter) + } + + svc := handlers_elbv2.NewNATSELBv2Service(natsConn) + result, err := svc.SetIpAddressType(input, accountID) + if err != nil { + return output, err + } + + return *result, nil +} diff --git a/spinifex/gateway/elbv2/SetSecurityGroups.go b/spinifex/gateway/elbv2/SetSecurityGroups.go new file mode 100644 index 000000000..893f32e2c --- /dev/null +++ b/spinifex/gateway/elbv2/SetSecurityGroups.go @@ -0,0 +1,31 @@ +package gateway_elbv2 + +import ( + "errors" + + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/awserrors" + handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2" + "github.com/nats-io/nats.go" +) + +// SetSecurityGroups handles the ELBv2 SetSecurityGroups API call. It replaces +// the security groups associated with the load balancer. +func SetSecurityGroups(input *elbv2.SetSecurityGroupsInput, natsConn *nats.Conn, accountID string) (elbv2.SetSecurityGroupsOutput, error) { + var output elbv2.SetSecurityGroupsOutput + + if input == nil || input.LoadBalancerArn == nil || *input.LoadBalancerArn == "" { + return output, errors.New(awserrors.ErrorMissingParameter) + } + if len(input.SecurityGroups) == 0 { + return output, errors.New(awserrors.ErrorMissingParameter) + } + + svc := handlers_elbv2.NewNATSELBv2Service(natsConn) + result, err := svc.SetSecurityGroups(input, accountID) + if err != nil { + return output, err + } + + return *result, nil +} diff --git a/spinifex/gateway/elbv2/attributes.go b/spinifex/gateway/elbv2/attributes.go new file mode 100644 index 000000000..bd245d3cb --- /dev/null +++ b/spinifex/gateway/elbv2/attributes.go @@ -0,0 +1,106 @@ +package gateway_elbv2 + +import ( + "errors" + + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/awserrors" + handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2" + "github.com/nats-io/nats.go" +) + +// validateAttrArn rejects a nil or empty resource ARN, shared by every +// attribute Modify/Describe validator. +func validateAttrArn(arn *string) error { + if arn == nil || *arn == "" { + return errors.New(awserrors.ErrorMissingParameter) + } + return nil +} + +// attributeOp validates an attribute request and dispatches it to its NATS +// service call, returning a zero output on any error. Shared by all four +// Modify/Describe attribute handlers. +func attributeOp[I, O any](input *I, validate func(*I) error, call func(*I) (*O, error)) (O, error) { + var output O + if err := validate(input); err != nil { + return output, err + } + result, err := call(input) + if err != nil { + return output, err + } + return *result, nil +} + +func ValidateModifyTargetGroupAttributesInput(input *elbv2.ModifyTargetGroupAttributesInput) error { + if input == nil { + return errors.New(awserrors.ErrorInvalidParameterValue) + } + if err := validateAttrArn(input.TargetGroupArn); err != nil { + return err + } + if len(input.Attributes) == 0 { + return errors.New(awserrors.ErrorMissingParameter) + } + return nil +} + +func ValidateDescribeTargetGroupAttributesInput(input *elbv2.DescribeTargetGroupAttributesInput) error { + if input == nil { + return errors.New(awserrors.ErrorInvalidParameterValue) + } + return validateAttrArn(input.TargetGroupArn) +} + +func ValidateModifyLoadBalancerAttributesInput(input *elbv2.ModifyLoadBalancerAttributesInput) error { + if input == nil { + return errors.New(awserrors.ErrorInvalidParameterValue) + } + if err := validateAttrArn(input.LoadBalancerArn); err != nil { + return err + } + if len(input.Attributes) == 0 { + return errors.New(awserrors.ErrorMissingParameter) + } + return nil +} + +func ValidateDescribeLoadBalancerAttributesInput(input *elbv2.DescribeLoadBalancerAttributesInput) error { + if input == nil { + return errors.New(awserrors.ErrorInvalidParameterValue) + } + return validateAttrArn(input.LoadBalancerArn) +} + +func ModifyTargetGroupAttributes(input *elbv2.ModifyTargetGroupAttributesInput, natsConn *nats.Conn, accountID string) (elbv2.ModifyTargetGroupAttributesOutput, error) { + svc := handlers_elbv2.NewNATSELBv2Service(natsConn) + return attributeOp(input, ValidateModifyTargetGroupAttributesInput, + func(i *elbv2.ModifyTargetGroupAttributesInput) (*elbv2.ModifyTargetGroupAttributesOutput, error) { + return svc.ModifyTargetGroupAttributes(i, accountID) + }) +} + +func DescribeTargetGroupAttributes(input *elbv2.DescribeTargetGroupAttributesInput, natsConn *nats.Conn, accountID string) (elbv2.DescribeTargetGroupAttributesOutput, error) { + svc := handlers_elbv2.NewNATSELBv2Service(natsConn) + return attributeOp(input, ValidateDescribeTargetGroupAttributesInput, + func(i *elbv2.DescribeTargetGroupAttributesInput) (*elbv2.DescribeTargetGroupAttributesOutput, error) { + return svc.DescribeTargetGroupAttributes(i, accountID) + }) +} + +func ModifyLoadBalancerAttributes(input *elbv2.ModifyLoadBalancerAttributesInput, natsConn *nats.Conn, accountID string) (elbv2.ModifyLoadBalancerAttributesOutput, error) { + svc := handlers_elbv2.NewNATSELBv2Service(natsConn) + return attributeOp(input, ValidateModifyLoadBalancerAttributesInput, + func(i *elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + return svc.ModifyLoadBalancerAttributes(i, accountID) + }) +} + +func DescribeLoadBalancerAttributes(input *elbv2.DescribeLoadBalancerAttributesInput, natsConn *nats.Conn, accountID string) (elbv2.DescribeLoadBalancerAttributesOutput, error) { + svc := handlers_elbv2.NewNATSELBv2Service(natsConn) + return attributeOp(input, ValidateDescribeLoadBalancerAttributesInput, + func(i *elbv2.DescribeLoadBalancerAttributesInput) (*elbv2.DescribeLoadBalancerAttributesOutput, error) { + return svc.DescribeLoadBalancerAttributes(i, accountID) + }) +} diff --git a/spinifex/gateway/elbv2_test.go b/spinifex/gateway/elbv2_test.go index ad81cab0f..dacb82bc6 100644 --- a/spinifex/gateway/elbv2_test.go +++ b/spinifex/gateway/elbv2_test.go @@ -52,6 +52,10 @@ func TestELBv2ActionsMap_AllActionsRegistered(t *testing.T) { "ModifyListener", "DescribeListeners", "DescribeTags", + "AddTags", + "RemoveTags", + "SetSecurityGroups", + "SetIpAddressType", "LBAgentHeartbeat", "GetLBConfig", "ModifyTargetGroupAttributes", diff --git a/spinifex/handlers/elbv2/haproxy.go b/spinifex/handlers/elbv2/haproxy.go index 865b9915e..0b87950f9 100644 --- a/spinifex/handlers/elbv2/haproxy.go +++ b/spinifex/handlers/elbv2/haproxy.go @@ -45,7 +45,9 @@ frontend {{.Name}} {{end}} {{range .Backends}} backend {{.Name}} -{{- if .FixedResponse}} +{{- if .Redirect}} + http-request redirect {{if .Redirect.Scheme}}scheme {{.Redirect.Scheme}}{{else}}location {{.Redirect.Location}}{{end}} code {{.Redirect.Code}} +{{- else if .FixedResponse}} http-request return status {{.FixedResponse.StatusCode}}{{if .FixedResponse.ContentType}} content-type "{{.FixedResponse.ContentType}}"{{end}}{{if .FixedResponse.Body}} string "{{.FixedResponse.Body}}"{{end}} {{- else}} balance roundrobin{{if .HealthCheckPath}} @@ -129,7 +131,8 @@ type HAProxyACL struct { } // HAProxyBackend represents a target group backend, or a synthetic backend that -// emits a fixed response (when FixedResponse is set, the server fields are unused). +// emits a fixed response or a redirect (when FixedResponse / Redirect is set, +// the server fields are unused). type HAProxyBackend struct { Name string HealthCheckPath string @@ -138,6 +141,7 @@ type HAProxyBackend struct { HTTPCheck bool Servers []HAProxyServer FixedResponse *HAProxyFixedResponse + Redirect *HAProxyRedirect } // HAProxyFixedResponse renders an `http-request return` directive for a @@ -148,6 +152,15 @@ type HAProxyFixedResponse struct { Body string } +// HAProxyRedirect renders an `http-request redirect` directive. Exactly one of +// Scheme (the scheme-only fast path, e.g. HTTP→HTTPS) or Location (a full +// rebuilt URL with HAProxy log-format fetches) is set. +type HAProxyRedirect struct { + Scheme string + Location string + Code string +} + // HAProxyServer represents a single target server. type HAProxyServer struct { Name string @@ -273,6 +286,14 @@ func buildHAProxyConfig(lb *LoadBalancerRecord, listeners []*ListenerRecord, tgB backendAdded[name] = struct{}{} } + addRedirectBackend := func(name string, rd *HAProxyRedirect) { + if _, ok := backendAdded[name]; ok { + return + } + cfg.Backends = append(cfg.Backends, HAProxyBackend{Name: name, Redirect: rd}) + backendAdded[name] = struct{}{} + } + for _, l := range listeners { if len(l.DefaultActions) == 0 { continue @@ -285,9 +306,9 @@ func buildHAProxyConfig(lb *LoadBalancerRecord, listeners []*ListenerRecord, tgB if isForwardDefault { defaultBackendName = sanitizeName("bk", da.TargetGroupArn) } else { - // fixed-response (or any non-forward default, e.g. the shared-ingress - // 404): synthesize a backend that returns the canned reply so HAProxy - // has a valid default_backend instead of a dangling reference. + // redirect / fixed-response (or any non-forward default, e.g. the + // shared-ingress 404): synthesize a backend so HAProxy has a valid + // default_backend instead of a dangling reference. defaultBackendName = sanitizeName("bkdefault", l.ListenerArn) } @@ -299,25 +320,30 @@ func buildHAProxyConfig(lb *LoadBalancerRecord, listeners []*ListenerRecord, tgB } if !isTCP { - rules := rulesByListener[l.ListenerArn] - for _, r := range rules { - rule, err := buildHAProxyRule(r) + for _, r := range rulesByListener[l.ListenerArn] { + backendName, err := registerRuleBackend(r, l, addBackend, addFixedResponseBackend, addRedirectBackend) + if err != nil { + return HAProxyConfig{}, err + } + rule, err := buildHAProxyRule(r, backendName) if err != nil { return HAProxyConfig{}, err } frontend.Rules = append(frontend.Rules, rule) - for _, a := range r.Actions { - if a.Type == ActionTypeForward && a.TargetGroupArn != "" { - addBackend(a.TargetGroupArn) - } - } } } cfg.Frontends = append(cfg.Frontends, frontend) - if isForwardDefault { + switch { + case isForwardDefault: addBackend(da.TargetGroupArn) - } else { + case da.Type == ActionTypeRedirect: + rd, err := buildRedirect(da.Redirect, l) + if err != nil { + return HAProxyConfig{}, err + } + addRedirectBackend(defaultBackendName, rd) + default: addFixedResponseBackend(defaultBackendName, da.FixedResponse) } } @@ -325,15 +351,50 @@ func buildHAProxyConfig(lb *LoadBalancerRecord, listeners []*ListenerRecord, tgB return cfg, nil } -// buildHAProxyRule converts a RuleRecord into the rendered ACL+use_backend -// shape. Returns an error if any condition value fails the defence-in-depth -// re-validation (HAProxy meta-character rejection). -func buildHAProxyRule(r *RuleRecord) (HAProxyRule, error) { - if len(r.Actions) == 0 || r.Actions[0].Type != ActionTypeForward { - return HAProxyRule{}, fmt.Errorf("rule %s has no forward action", r.RuleID) +// registerRuleBackend resolves the HAProxy backend a rule's single action +// routes to, registering a synthetic backend for redirect / fixed-response +// rule actions, and returns its name. +func registerRuleBackend( + r *RuleRecord, + l *ListenerRecord, + addBackend func(string), + addFixedResponseBackend func(string, *FixedResponseAction), + addRedirectBackend func(string, *HAProxyRedirect), +) (string, error) { + if len(r.Actions) == 0 { + return "", fmt.Errorf("rule %s has no action", r.RuleID) } + a := r.Actions[0] + switch a.Type { + case ActionTypeForward: + if a.TargetGroupArn == "" { + return "", fmt.Errorf("rule %s forward action has no target group", r.RuleID) + } + addBackend(a.TargetGroupArn) + return sanitizeName("bk", a.TargetGroupArn), nil + case ActionTypeFixedResponse: + name := sanitizeName("bkrule", r.RuleID) + addFixedResponseBackend(name, a.FixedResponse) + return name, nil + case ActionTypeRedirect: + rd, err := buildRedirect(a.Redirect, l) + if err != nil { + return "", err + } + name := sanitizeName("bkrule", r.RuleID) + addRedirectBackend(name, rd) + return name, nil + default: + return "", fmt.Errorf("rule %s has unsupported action %q", r.RuleID, a.Type) + } +} - rule := HAProxyRule{Backend: sanitizeName("bk", r.Actions[0].TargetGroupArn)} +// buildHAProxyRule converts a RuleRecord's conditions into the rendered +// ACL+use_backend shape, routing to backendName (already resolved/registered +// by registerRuleBackend). Returns an error if any condition value fails the +// defence-in-depth re-validation (HAProxy meta-character rejection). +func buildHAProxyRule(r *RuleRecord, backendName string) (HAProxyRule, error) { + rule := HAProxyRule{Backend: backendName} for ci, c := range r.Conditions { aclName := fmt.Sprintf("r%s_c%d", sanitizeACLToken(r.RuleID), ci) @@ -481,6 +542,118 @@ func validFixedResponseBody(s string) bool { return true } +// buildRedirect translates a stored RedirectAction into an HAProxy redirect +// directive in the context of listener l (which resolves the `#{protocol}` and +// `#{port}` placeholders). The common scheme-only redirect (e.g. HTTP→HTTPS +// with every other field left at its AWS default) renders as `redirect scheme` +// so HAProxy preserves host/path/query; anything else rebuilds a `location`. +func buildRedirect(rd *RedirectAction, l *ListenerRecord) (*HAProxyRedirect, error) { + if rd == nil { + return nil, fmt.Errorf("redirect action missing config") + } + + var code string + switch rd.StatusCode { + case "HTTP_301": + code = "301" + case "HTTP_302": + code = "302" + default: + return nil, fmt.Errorf("redirect has invalid status code %q", rd.StatusCode) + } + + for _, f := range []string{rd.Protocol, rd.Host, rd.Port, rd.Path, rd.Query} { + if !validRedirectField(f) { + return nil, fmt.Errorf("redirect field contains forbidden characters") + } + } + + defaultHost := rd.Host == "" || rd.Host == "#{host}" + defaultPort := rd.Port == "" || rd.Port == "#{port}" + defaultPath := rd.Path == "" || rd.Path == "#{path}" || rd.Path == "/#{path}" + defaultQuery := rd.Query == "" || rd.Query == "#{query}" + explicitScheme := rd.Protocol == ProtocolHTTP || rd.Protocol == ProtocolHTTPS + + if explicitScheme && defaultHost && defaultPort && defaultPath && defaultQuery { + return &HAProxyRedirect{Scheme: strings.ToLower(rd.Protocol), Code: code}, nil + } + + scheme := redirectScheme(rd.Protocol, l) + host := redirectPlaceholders(orDefault(rd.Host, "#{host}"), l) + + port := "" + if rd.Port != "" && rd.Port != "#{port}" { + port = ":" + redirectPlaceholders(rd.Port, l) + } + + path := "%[path]" + if !defaultPath { + path = redirectPlaceholders(rd.Path, l) + } + + query := "" + if !defaultQuery { + query = "?" + redirectPlaceholders(rd.Query, l) + } else if rd.Query == "#{query}" { + query = "?%[query]" + } + + return &HAProxyRedirect{Location: scheme + "://" + host + port + path + query, Code: code}, nil +} + +func orDefault(s, def string) string { + if s == "" { + return def + } + return s +} + +// redirectScheme resolves the redirect scheme literal, mapping the `#{protocol}` +// placeholder (or an empty protocol) to the listener's own protocol. +func redirectScheme(proto string, l *ListenerRecord) string { + switch proto { + case ProtocolHTTP, ProtocolHTTPS: + return strings.ToLower(proto) + default: + return strings.ToLower(l.Protocol) + } +} + +// redirectPlaceholders substitutes the AWS redirect placeholders with HAProxy +// log-format fetches. `#{protocol}` and `#{port}` resolve from the listener. +func redirectPlaceholders(s string, l *ListenerRecord) string { + r := strings.NewReplacer( + "#{protocol}", strings.ToLower(l.Protocol), + "#{host}", "%[req.hdr(host)]", + "#{port}", strconv.FormatInt(l.Port, 10), + "#{path}", "%[path]", + "#{query}", "%[query]", + ) + return r.Replace(s) +} + +// validRedirectField rejects bytes that would break the HAProxy redirect +// directive. The known `#{...}` placeholders are stripped first, so any +// remaining `#`, `%`, bracket, quote, backslash, whitespace, or control byte +// (which would indicate an unknown placeholder or an injection attempt) fails. +func validRedirectField(s string) bool { + known := []string{"#{protocol}", "#{host}", "#{port}", "#{path}", "#{query}"} + tmp := s + for _, k := range known { + tmp = strings.ReplaceAll(tmp, k, "") + } + for _, r := range tmp { + if r < 0x20 || r == 0x7f { + return false + } + switch r { + case ' ', '"', '#', '%', '[', ']', '\\': + return false + } + } + return true +} + // validateRenderSafe rejects bytes that could break ACL parsing or inject new // directives. Mirrors the write-time validators in service_impl_rules.go; // duplicated here so a future migration that bypasses the API cannot leak a diff --git a/spinifex/handlers/elbv2/haproxy_test.go b/spinifex/handlers/elbv2/haproxy_test.go index 2c89d2480..2f325d135 100644 --- a/spinifex/handlers/elbv2/haproxy_test.go +++ b/spinifex/handlers/elbv2/haproxy_test.go @@ -248,6 +248,159 @@ func TestGenerateHAProxyConfig_FixedResponseRejectsUnsafeBody(t *testing.T) { assert.NotContains(t, config, `string "evil`) } +// TestGenerateHAProxyConfig_RedirectSchemeDefault renders the canonical +// HTTP→HTTPS redirect (scheme-only change, all other fields default) as a +// `redirect scheme https` directive so HAProxy preserves host/path/query. +func TestGenerateHAProxyConfig_RedirectSchemeDefault(t *testing.T) { + lb := &LoadBalancerRecord{LoadBalancerID: "lb-redir"} + listenerArn := "arn:aws:elasticloadbalancing:ap-southeast-2:1:listener/app/r/lb-redir/lst-aa" + listeners := []*ListenerRecord{ + { + ListenerArn: listenerArn, + Port: 80, + Protocol: ProtocolHTTP, + DefaultActions: []ListenerAction{ + {Type: ActionTypeRedirect, Redirect: &RedirectAction{ + Protocol: "HTTPS", + Host: "#{host}", + Path: "/#{path}", + Query: "#{query}", + StatusCode: "HTTP_301", + }}, + }, + }, + } + + config, err := GenerateHAProxyConfig(lb, listeners, nil, nil, "0.0.0.0") + require.NoError(t, err) + + assert.Contains(t, config, "default_backend bkdefault_lst-aa") + assert.Contains(t, config, "http-request redirect scheme https code 301") + assert.NotContains(t, config, "location") +} + +// TestGenerateHAProxyConfig_RedirectLocation renders a redirect that changes +// the host as a rebuilt `location` with HAProxy placeholders preserved. +func TestGenerateHAProxyConfig_RedirectLocation(t *testing.T) { + lb := &LoadBalancerRecord{LoadBalancerID: "lb-redir2"} + listenerArn := "arn:aws:elasticloadbalancing:ap-southeast-2:1:listener/app/r/lb-redir2/lst-bb" + listeners := []*ListenerRecord{ + { + ListenerArn: listenerArn, + Port: 80, + Protocol: ProtocolHTTP, + DefaultActions: []ListenerAction{ + {Type: ActionTypeRedirect, Redirect: &RedirectAction{ + Protocol: "HTTPS", + Host: "www.example.com", + Path: "/#{path}", + Query: "#{query}", + StatusCode: "HTTP_302", + }}, + }, + }, + } + + config, err := GenerateHAProxyConfig(lb, listeners, nil, nil, "0.0.0.0") + require.NoError(t, err) + + assert.Contains(t, config, "http-request redirect location https://www.example.com%[path]?%[query] code 302") +} + +// TestGenerateHAProxyConfig_RedirectCustomAll exercises the location form with +// a placeholder protocol (resolved from the listener), an explicit port, and a +// custom literal path + query. +func TestGenerateHAProxyConfig_RedirectCustomAll(t *testing.T) { + lb := &LoadBalancerRecord{LoadBalancerID: "lb-redir3"} + listenerArn := "arn:aws:elasticloadbalancing:ap-southeast-2:1:listener/app/r/lb-redir3/lst-dd" + listeners := []*ListenerRecord{ + { + ListenerArn: listenerArn, + Port: 80, + Protocol: ProtocolHTTPS, + DefaultActions: []ListenerAction{ + {Type: ActionTypeRedirect, Redirect: &RedirectAction{ + Protocol: "#{protocol}", + Host: "alt.example.com", + Port: "8443", + Path: "/moved", + Query: "ref=1", + StatusCode: "HTTP_302", + }}, + }, + }, + } + + config, err := GenerateHAProxyConfig(lb, listeners, nil, nil, "0.0.0.0") + require.NoError(t, err) + + assert.Contains(t, config, "http-request redirect location https://alt.example.com:8443/moved?ref=1 code 302") +} + +// TestGenerateHAProxyConfig_RedirectRule renders a per-rule redirect action via +// a synthetic backend reached by use_backend. +func TestGenerateHAProxyConfig_RedirectRule(t *testing.T) { + lb := &LoadBalancerRecord{LoadBalancerID: "lb-rr"} + listenerArn := "arn:aws:elasticloadbalancing:ap-southeast-2:1:listener/app/r/lb-rr/lst-cc" + appTG := "arn:aws:elasticloadbalancing:ap-southeast-2:1:targetgroup/app/tg-app" + listeners := []*ListenerRecord{ + { + ListenerArn: listenerArn, + Port: 80, + Protocol: ProtocolHTTP, + DefaultActions: []ListenerAction{ + {Type: ActionTypeForward, TargetGroupArn: appTG}, + }, + }, + } + rulesByListener := map[string][]*RuleRecord{ + listenerArn: { + { + RuleID: "ruleR", + ListenerArn: listenerArn, + Priority: 1, + Conditions: []RuleCondition{{Field: RuleFieldPathPattern, Values: []string{"/old/*"}}}, + Actions: []ListenerAction{{Type: ActionTypeRedirect, Redirect: &RedirectAction{ + Protocol: "HTTPS", + StatusCode: "HTTP_301", + }}}, + }, + }, + } + tgByArn := map[string]*TargetGroupRecord{ + appTG: {TargetGroupArn: appTG, HealthCheck: DefaultHealthCheck()}, + } + + config, err := GenerateHAProxyConfig(lb, listeners, tgByArn, rulesByListener, "0.0.0.0") + require.NoError(t, err) + + assert.Contains(t, config, "use_backend bkrule_ruleR if") + assert.Contains(t, config, "backend bkrule_ruleR") + assert.Contains(t, config, "http-request redirect scheme https code 301") +} + +// TestGenerateHAProxyConfig_RedirectRejectsInjection fails the render when a +// redirect field carries HAProxy meta-characters that survived to the store. +func TestGenerateHAProxyConfig_RedirectRejectsInjection(t *testing.T) { + lb := &LoadBalancerRecord{LoadBalancerID: "lb-evil2"} + listeners := []*ListenerRecord{ + { + ListenerArn: "arn:lst-evil2", + Port: 80, + Protocol: ProtocolHTTP, + DefaultActions: []ListenerAction{ + {Type: ActionTypeRedirect, Redirect: &RedirectAction{ + Host: "evil\"\n acl x always_true", + StatusCode: "HTTP_301", + }}, + }, + }, + } + + _, err := GenerateHAProxyConfig(lb, listeners, nil, nil, "0.0.0.0") + require.Error(t, err) +} + func TestGenerateHAProxyConfig_NoListeners(t *testing.T) { lb := &LoadBalancerRecord{LoadBalancerID: "lb-empty"} config, err := GenerateHAProxyConfig(lb, nil, nil, nil, "0.0.0.0") diff --git a/spinifex/handlers/elbv2/lifecycle_invariants_test.go b/spinifex/handlers/elbv2/lifecycle_invariants_test.go new file mode 100644 index 000000000..b2ac8b6e6 --- /dev/null +++ b/spinifex/handlers/elbv2/lifecycle_invariants_test.go @@ -0,0 +1,187 @@ +package handlers_elbv2 + +import ( + "os" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestRLC1_ELBv2DeleteIdempotentOnAbsent enforces Common Resource Lifecycle +// Contract rule #1 (idempotent delete) across the ELBv2 surface: deleting an +// absent resource is success, not a NotFound error. This mirrors AWS ELBv2 +// delete semantics and is required for tofu destroy to converge on retry. +// +// Every ELBv2 delete endpoint MUST have a case here. When a new delete +// endpoint lands, add it; a missing case is an idempotency gap. +func TestRLC1_ELBv2DeleteIdempotentOnAbsent(t *testing.T) { + const arnBase = "arn:aws:elasticloadbalancing:us-east-1:123456789012:" + + cases := []struct { + name string + call func(svc *ELBv2ServiceImpl) (any, error) + }{ + {"DeleteLoadBalancer", func(svc *ELBv2ServiceImpl) (any, error) { + return svc.DeleteLoadBalancer(&elbv2.DeleteLoadBalancerInput{ + LoadBalancerArn: aws.String(arnBase + "loadbalancer/app/absent/0000000000000000"), + }, testAccountID) + }}, + {"DeleteTargetGroup", func(svc *ELBv2ServiceImpl) (any, error) { + return svc.DeleteTargetGroup(&elbv2.DeleteTargetGroupInput{ + TargetGroupArn: aws.String(arnBase + "targetgroup/absent/0000000000000000"), + }, testAccountID) + }}, + {"DeleteListener", func(svc *ELBv2ServiceImpl) (any, error) { + return svc.DeleteListener(&elbv2.DeleteListenerInput{ + ListenerArn: aws.String(arnBase + "listener/app/absent/0000000000000000/1111111111111111"), + }, testAccountID) + }}, + {"DeleteRule", func(svc *ELBv2ServiceImpl) (any, error) { + return svc.DeleteRule(&elbv2.DeleteRuleInput{ + RuleArn: aws.String(arnBase + "listener-rule/app/absent/0000000000000000/1111111111111111/2222222222222222"), + }, testAccountID) + }}, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + svc := setupTestService(t) + out, err := tc.call(svc) + require.NoErrorf(t, err, "%s on an absent resource must return success (RLC rule #1)", tc.name) + assert.NotNilf(t, out, "%s must return a non-nil output on absent", tc.name) + }) + } +} + +// TestRLC2_ELBv2NoOrphanAfterDeleteLB enforces ADR-0002 §5 no-orphan +// completeness: after DeleteLoadBalancer, no listener or rule owned by that LB +// may survive in the store. Uses two listeners (each with a rule) so a +// single-listener cascade can't pass by accident. +func TestRLC2_ELBv2NoOrphanAfterDeleteLB(t *testing.T) { + svc := setupTestService(t) + + lbOut, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("rlc2-lb")}, testAccountID) + require.NoError(t, err) + lbArn := lbOut.LoadBalancers[0].LoadBalancerArn + + tgOut, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("rlc2-tg")}, testAccountID) + require.NoError(t, err) + tgArn := tgOut.TargetGroups[0].TargetGroupArn + + for i, port := range []int64{80, 8080} { + lst, err := svc.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: lbArn, + Protocol: aws.String("HTTP"), + Port: aws.Int64(port), + DefaultActions: []*elbv2.Action{{Type: aws.String("forward"), TargetGroupArn: tgArn}}, + }, testAccountID) + require.NoError(t, err) + + _, err = svc.CreateRule(&elbv2.CreateRuleInput{ + ListenerArn: lst.Listeners[0].ListenerArn, + Priority: aws.Int64(int64(10 + i)), + Conditions: []*elbv2.RuleCondition{{Field: aws.String("path-pattern"), Values: aws.StringSlice([]string{"/api/*"})}}, + Actions: []*elbv2.Action{{Type: aws.String("forward"), TargetGroupArn: tgArn}}, + }, testAccountID) + require.NoError(t, err) + } + + _, err = svc.DeleteLoadBalancer(&elbv2.DeleteLoadBalancerInput{LoadBalancerArn: lbArn}, testAccountID) + require.NoError(t, err) + + listeners, err := svc.store.ListListenersByLB(*lbArn) + require.NoError(t, err) + require.Emptyf(t, listeners, "ADR-0002 §5 no-orphan completeness: no listener owned by a deleted LB may remain") + + rules, err := svc.store.ListRules() + require.NoError(t, err) + require.Emptyf(t, rules, "ADR-0002 §5 no-orphan completeness: no rule owned by a deleted LB may remain") +} + +// TestRLC3_ELBv2DeleteLBDoesNotBypassListenerCascade enforces ADR-0002 §5 no +// store-bypass cascade: DeleteLoadBalancer must tear listeners (and their +// rules) down through the shared deleteListenerCascade helper, never by +// calling store.DeleteListener directly — a direct store delete orphans the +// listener's rules. The store field is a concrete type with no injection seam, +// so the contract is enforced structurally against the source rather than with +// a runtime spy. +func TestRLC3_ELBv2DeleteLBDoesNotBypassListenerCascade(t *testing.T) { + src, err := os.ReadFile("service_impl.go") + require.NoError(t, err) + + body := stripComments(deleteLBFuncBody(t, string(src))) + assert.Containsf(t, body, "deleteListenerCascade", + "ADR-0002 §5 no store-bypass cascade: DeleteLoadBalancer must route listener teardown through deleteListenerCascade") + assert.NotContainsf(t, body, "s.store.DeleteListener(", + "ADR-0002 §5 no store-bypass cascade: DeleteLoadBalancer must not call store.DeleteListener directly") +} + +// deleteLBFuncBody returns the source text of the DeleteLoadBalancer method, +// from its signature up to the start of the next top-level func. +func deleteLBFuncBody(t *testing.T, src string) string { + t.Helper() + const sig = "func (s *ELBv2ServiceImpl) DeleteLoadBalancer(" + start := strings.Index(src, sig) + require.GreaterOrEqual(t, start, 0, "DeleteLoadBalancer not found in service_impl.go") + rest := src[start+len(sig):] + if before, _, found := strings.Cut(rest, "\nfunc "); found { + return before + } + return rest +} + +// stripComments removes // line comments so source-guard assertions match real +// code, not the prose that documents it. +func stripComments(src string) string { + var b strings.Builder + for line := range strings.SplitSeq(src, "\n") { + if i := strings.Index(line, "//"); i >= 0 { + line = line[:i] + } + b.WriteString(line) + b.WriteByte('\n') + } + return b.String() +} + +// TestRLC4_ELBv2TGDeletableAfterLBTeardown enforces ADR-0002 §5 TG deletability +// after LB teardown: create LB+listener+rule→TG, delete the LB, then the target +// group must delete successfully rather than staying pinned as ResourceInUse by +// an orphaned rule or stale listener default action. +func TestRLC4_ELBv2TGDeletableAfterLBTeardown(t *testing.T) { + svc := setupTestService(t) + + lbOut, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("rlc4-lb")}, testAccountID) + require.NoError(t, err) + lbArn := lbOut.LoadBalancers[0].LoadBalancerArn + + tgOut, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("rlc4-tg")}, testAccountID) + require.NoError(t, err) + tgArn := tgOut.TargetGroups[0].TargetGroupArn + + lst, err := svc.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: lbArn, + Protocol: aws.String("HTTP"), + Port: aws.Int64(80), + DefaultActions: []*elbv2.Action{{Type: aws.String("forward"), TargetGroupArn: tgArn}}, + }, testAccountID) + require.NoError(t, err) + + _, err = svc.CreateRule(&elbv2.CreateRuleInput{ + ListenerArn: lst.Listeners[0].ListenerArn, + Priority: aws.Int64(10), + Conditions: []*elbv2.RuleCondition{{Field: aws.String("path-pattern"), Values: aws.StringSlice([]string{"/api/*"})}}, + Actions: []*elbv2.Action{{Type: aws.String("forward"), TargetGroupArn: tgArn}}, + }, testAccountID) + require.NoError(t, err) + + _, err = svc.DeleteLoadBalancer(&elbv2.DeleteLoadBalancerInput{LoadBalancerArn: lbArn}, testAccountID) + require.NoError(t, err) + + _, err = svc.DeleteTargetGroup(&elbv2.DeleteTargetGroupInput{TargetGroupArn: tgArn}, testAccountID) + require.NoErrorf(t, err, "ADR-0002 §5 TG deletability after LB teardown: target group must not stay pinned as ResourceInUse") +} diff --git a/spinifex/handlers/elbv2/service.go b/spinifex/handlers/elbv2/service.go index 4a6276c46..b2784d9ba 100644 --- a/spinifex/handlers/elbv2/service.go +++ b/spinifex/handlers/elbv2/service.go @@ -9,6 +9,8 @@ type ELBv2Service interface { DescribeLoadBalancers(input *elbv2.DescribeLoadBalancersInput, accountID string) (*elbv2.DescribeLoadBalancersOutput, error) ModifyLoadBalancerAttributes(input *elbv2.ModifyLoadBalancerAttributesInput, accountID string) (*elbv2.ModifyLoadBalancerAttributesOutput, error) DescribeLoadBalancerAttributes(input *elbv2.DescribeLoadBalancerAttributesInput, accountID string) (*elbv2.DescribeLoadBalancerAttributesOutput, error) + SetSecurityGroups(input *elbv2.SetSecurityGroupsInput, accountID string) (*elbv2.SetSecurityGroupsOutput, error) + SetIpAddressType(input *elbv2.SetIpAddressTypeInput, accountID string) (*elbv2.SetIpAddressTypeOutput, error) CreateTargetGroup(input *elbv2.CreateTargetGroupInput, accountID string) (*elbv2.CreateTargetGroupOutput, error) ModifyTargetGroup(input *elbv2.ModifyTargetGroupInput, accountID string) (*elbv2.ModifyTargetGroupOutput, error) @@ -33,6 +35,8 @@ type ELBv2Service interface { SetRulePriorities(input *elbv2.SetRulePrioritiesInput, accountID string) (*elbv2.SetRulePrioritiesOutput, error) DescribeTags(input *elbv2.DescribeTagsInput, accountID string) (*elbv2.DescribeTagsOutput, error) + AddTags(input *elbv2.AddTagsInput, accountID string) (*elbv2.AddTagsOutput, error) + RemoveTags(input *elbv2.RemoveTagsInput, accountID string) (*elbv2.RemoveTagsOutput, error) LBAgentHeartbeat(input *LBAgentHeartbeatInput, accountID string) (*LBAgentHeartbeatOutput, error) GetLBConfig(input *GetLBConfigInput, accountID string) (*GetLBConfigOutput, error) diff --git a/spinifex/handlers/elbv2/service_impl.go b/spinifex/handlers/elbv2/service_impl.go index 7bb7f796a..4d2492bfb 100644 --- a/spinifex/handlers/elbv2/service_impl.go +++ b/spinifex/handlers/elbv2/service_impl.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "log/slog" - "maps" "net" "regexp" "slices" @@ -183,8 +182,6 @@ func (s *ELBv2ServiceImpl) Close() { // heartbeat re-converges. Acceptable trade-off — heartbeats arrive within // one health-check interval (default 5-30s) and round-robin transiently // excluding a backend is safer than serving traffic to a dead one. -// -// Refs mulga-siv-119. func (s *ELBv2ServiceImpl) ResetTargetHealthOnStartup(ctx context.Context) error { if s == nil || s.store == nil { return nil @@ -762,6 +759,28 @@ func (s *ELBv2ServiceImpl) resolveTargetIP(instanceID, accountID string) string return "" } +// resolveRegisteredTargetIP returns the private IP to route to for a target +// being registered, based on the target group's target type. For ip targets the +// supplied ID is the IP itself; for instance targets it is resolved via the +// instance's primary ENI. Returns an error when the ID's shape does not match +// the target type. +func (s *ELBv2ServiceImpl) resolveRegisteredTargetIP(targetType, id, accountID string) (string, error) { + switch targetType { + case TargetTypeIP: + if net.ParseIP(id) == nil { + slog.Warn("RegisterTargets: ip target id is not a valid IP", "id", id) + return "", errors.New(awserrors.ErrorInvalidParameterValue) + } + return id, nil + default: // instance + if net.ParseIP(id) != nil { + slog.Warn("RegisterTargets: instance target group given an IP address", "id", id) + return "", errors.New(awserrors.ErrorInvalidParameterValue) + } + return s.resolveTargetIP(id, accountID), nil + } +} + // buildTGArn constructs a target group ARN from components. func buildTGArn(region, accountID, name, tgID string) string { return fmt.Sprintf("arn:aws:elasticloadbalancing:%s:%s:targetgroup/%s/%s", region, accountID, name, tgID) @@ -1078,7 +1097,27 @@ func (s *ELBv2ServiceImpl) DeleteLoadBalancer(input *elbv2.DeleteLoadBalancerInp return nil, errors.New(awserrors.ErrorServerInternal) } if lb == nil || lb.AccountID != accountID { - return nil, errors.New(awserrors.ErrorELBv2LoadBalancerNotFound) + // Idempotent: AWS ELBv2 delete returns success on an absent (or + // not-owned) load balancer, so tofu destroy retries converge. + return &elbv2.DeleteLoadBalancerOutput{}, nil + } + + // Delete all listeners (and their rules) for this LB before tearing down + // backing artifacts. Cascade through the shared helper, not + // store.DeleteListener directly, so rules don't survive and pin their + // target groups as ResourceInUse after the LB is gone. A list or cascade + // failure aborts the delete with the record intact, so tofu retries + // converge instead of leaving orphaned rules behind. + listeners, err := s.store.ListListenersByLB(lb.LoadBalancerArn) + if err != nil { + slog.Error("DeleteLoadBalancer: failed to list listeners for cascade", "lbArn", lb.LoadBalancerArn, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } + for _, l := range listeners { + if err := s.deleteListenerCascade(l); err != nil { + slog.Error("DeleteLoadBalancer: failed to cascade listener delete", "listenerID", l.ListenerID, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } } // Terminate ALB VM in background (VM termination also cleans up tap device). @@ -1093,17 +1132,6 @@ func (s *ELBv2ServiceImpl) DeleteLoadBalancer(input *elbv2.DeleteLoadBalancerInp }() } - // Delete all listeners for this LB - listeners, err := s.store.ListListenersByLB(lb.LoadBalancerArn) - if err != nil { - slog.Warn("Failed to list listeners for cleanup", "lbArn", lb.LoadBalancerArn, "err", err) - } - for _, l := range listeners { - if err := s.store.DeleteListener(l.ListenerID); err != nil { - slog.Warn("Failed to delete listener during LB cleanup", "listenerID", l.ListenerID, "err", err) - } - } - // Delete system-managed ENIs. Detach first to clear in-use status. if s.VPCService != nil { for _, eniID := range lb.ENIs { @@ -1210,10 +1238,14 @@ func (s *ELBv2ServiceImpl) CreateTargetGroup(input *elbv2.CreateTargetGroupInput return nil, errors.New(awserrors.ErrorELBv2DuplicateTargetGroup) } - targetType := "instance" + targetType := TargetTypeInstance if input.TargetType != nil && *input.TargetType != "" { targetType = *input.TargetType } + if targetType != TargetTypeInstance && targetType != TargetTypeIP { + slog.Warn("CreateTargetGroup: unsupported target type", "targetType", targetType) + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } // Use NLB health check defaults for NLB protocols. var hc HealthCheckConfig @@ -1366,16 +1398,37 @@ func (s *ELBv2ServiceImpl) DeleteTargetGroup(input *elbv2.DeleteTargetGroupInput return nil, errors.New(awserrors.ErrorServerInternal) } if tg == nil || tg.AccountID != accountID { - return nil, errors.New(awserrors.ErrorELBv2TargetGroupNotFound) + // Idempotent: AWS ELBv2 delete returns success on an absent (or + // not-owned) target group, so tofu destroy retries converge. + return &elbv2.DeleteTargetGroupOutput{}, nil } - // Check if any listener references this target group + // Only a *live* listener or rule pins the target group. A listener (or + // rule) whose owning load balancer no longer exists is treated as already + // torn down, not a live reference, so an orphan left by a partial teardown + // can never pin this target group as ResourceInUse permanently. + lbs, err := s.store.ListLoadBalancers() + if err != nil { + slog.Error("DeleteTargetGroup: failed to list load balancers for in-use check", "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } + liveLB := make(map[string]bool, len(lbs)) + for _, lb := range lbs { + liveLB[lb.LoadBalancerArn] = true + } + + // Check if any live listener references this target group. listeners, err := s.store.ListListeners() if err != nil { slog.Error("DeleteTargetGroup: failed to list listeners for in-use check", "err", err) return nil, errors.New(awserrors.ErrorServerInternal) } + liveListener := make(map[string]bool, len(listeners)) for _, l := range listeners { + if !liveLB[l.LoadBalancerArn] { + continue + } + liveListener[l.ListenerArn] = true for _, action := range l.DefaultActions { if action.TargetGroupArn == tg.TargetGroupArn { return nil, errors.New(awserrors.ErrorELBv2TargetGroupInUse) @@ -1383,13 +1436,16 @@ func (s *ELBv2ServiceImpl) DeleteTargetGroup(input *elbv2.DeleteTargetGroupInput } } - // Block deletion when a rule still forwards to the target group. + // Block deletion when a live rule still forwards to the target group. allRules, err := s.store.ListRules() if err != nil { slog.Error("DeleteTargetGroup: failed to list rules for in-use check", "err", err) return nil, errors.New(awserrors.ErrorServerInternal) } for _, r := range allRules { + if !liveListener[r.ListenerArn] { + continue + } for _, action := range r.Actions { if action.TargetGroupArn == tg.TargetGroupArn { return nil, errors.New(awserrors.ErrorELBv2TargetGroupInUse) @@ -1498,8 +1554,11 @@ func (s *ELBv2ServiceImpl) RegisterTargets(input *elbv2.RegisterTargetsInput, ac continue // Already registered } - // Resolve instance ID → private IP via ENI lookup - privateIP := s.resolveTargetIP(*td.Id, accountID) + // Resolve target ID → private IP (instance ENI lookup, or raw IP for ip-type TGs) + privateIP, err := s.resolveRegisteredTargetIP(tg.TargetType, *td.Id, accountID) + if err != nil { + return nil, err + } tg.Targets = append(tg.Targets, Target{ Id: *td.Id, @@ -1653,9 +1712,66 @@ func listenerActionFromSDK(a *elbv2.Action) ListenerAction { } action.FixedResponse = fr } + if a.RedirectConfig != nil { + rd := &RedirectAction{} + if a.RedirectConfig.Protocol != nil { + rd.Protocol = *a.RedirectConfig.Protocol + } + if a.RedirectConfig.Host != nil { + rd.Host = *a.RedirectConfig.Host + } + if a.RedirectConfig.Port != nil { + rd.Port = *a.RedirectConfig.Port + } + if a.RedirectConfig.Path != nil { + rd.Path = *a.RedirectConfig.Path + } + if a.RedirectConfig.Query != nil { + rd.Query = *a.RedirectConfig.Query + } + if a.RedirectConfig.StatusCode != nil { + rd.StatusCode = *a.RedirectConfig.StatusCode + } + action.Redirect = rd + } return action } +// validateListenerAction enforces the per-type action contract for listener +// default actions and rule actions. Forward actions are validated against the +// target group elsewhere; this covers redirect (status code + render-safe +// fields) so invalid input fails at the API instead of being silently +// defaulted by the renderer. +func validateListenerAction(a ListenerAction) error { + if a.Type == ActionTypeRedirect { + if a.Redirect == nil { + return errors.New(awserrors.ErrorMissingParameter) + } + return validateRedirectAction(a.Redirect) + } + return nil +} + +// validateRedirectAction rejects an unsupported status code or any field that +// would break the HAProxy redirect directive once the known AWS placeholders +// are stripped. +func validateRedirectAction(rd *RedirectAction) error { + if rd == nil { + return errors.New(awserrors.ErrorMissingParameter) + } + switch rd.StatusCode { + case "HTTP_301", "HTTP_302": + default: + return errors.New(awserrors.ErrorInvalidParameterValue) + } + for _, f := range []string{rd.Protocol, rd.Host, rd.Port, rd.Path, rd.Query} { + if !validRedirectField(f) { + return errors.New(awserrors.ErrorInvalidParameterValue) + } + } + return nil +} + func (s *ELBv2ServiceImpl) CreateListener(input *elbv2.CreateListenerInput, accountID string) (*elbv2.CreateListenerOutput, error) { if input.LoadBalancerArn == nil || *input.LoadBalancerArn == "" { return nil, errors.New(awserrors.ErrorMissingParameter) @@ -1735,7 +1851,18 @@ func (s *ELBv2ServiceImpl) CreateListener(input *elbv2.CreateListenerInput, acco var actions []ListenerAction for _, a := range input.DefaultActions { - actions = append(actions, listenerActionFromSDK(a)) + action := listenerActionFromSDK(a) + if err := validateListenerAction(action); err != nil { + return nil, err + } + actions = append(actions, action) + } + + tags := make(map[string]string) + for _, tag := range input.Tags { + if tag.Key != nil && tag.Value != nil { + tags[*tag.Key] = *tag.Value + } } record := &ListenerRecord{ @@ -1747,6 +1874,7 @@ func (s *ELBv2ServiceImpl) CreateListener(input *elbv2.CreateListenerInput, acco DefaultActions: actions, AccountID: accountID, CreatedAt: time.Now().UTC(), + Tags: tags, } if err := s.store.PutListener(record); err != nil { @@ -1767,6 +1895,25 @@ func (s *ELBv2ServiceImpl) CreateListener(input *elbv2.CreateListenerInput, acco }, nil } +// deleteListenerCascade removes a listener and all of its rules. Shared by +// DeleteListener and DeleteLoadBalancer so LB teardown never bypasses the rule +// cascade and leaves orphan rules that pin a target group as ResourceInUse. +func (s *ELBv2ServiceImpl) deleteListenerCascade(listener *ListenerRecord) error { + rules, err := s.store.ListRulesByListener(listener.ListenerArn) + if err != nil { + return fmt.Errorf("list rules for listener %s: %w", listener.ListenerArn, err) + } + for _, r := range rules { + if err := s.store.DeleteRule(r.RuleID); err != nil { + return fmt.Errorf("delete rule %s: %w", r.RuleID, err) + } + } + if err := s.store.DeleteListener(listener.ListenerID); err != nil { + return fmt.Errorf("delete listener %s: %w", listener.ListenerID, err) + } + return nil +} + func (s *ELBv2ServiceImpl) DeleteListener(input *elbv2.DeleteListenerInput, accountID string) (*elbv2.DeleteListenerOutput, error) { if input.ListenerArn == nil || *input.ListenerArn == "" { return nil, errors.New(awserrors.ErrorMissingParameter) @@ -1778,24 +1925,14 @@ func (s *ELBv2ServiceImpl) DeleteListener(input *elbv2.DeleteListenerInput, acco return nil, errors.New(awserrors.ErrorServerInternal) } if listener == nil || listener.AccountID != accountID { - return nil, errors.New(awserrors.ErrorELBv2ListenerNotFound) + // Idempotent: AWS ELBv2 delete returns success on an absent (or + // not-owned) listener, so tofu destroy retries converge. + return &elbv2.DeleteListenerOutput{}, nil } // Cascade-delete rules so a recreated listener doesn't inherit orphans. - rules, ruleErr := s.store.ListRulesByListener(listener.ListenerArn) - if ruleErr != nil { - slog.Error("DeleteListener: failed to list rules", "listenerArn", listener.ListenerArn, "err", ruleErr) - return nil, errors.New(awserrors.ErrorServerInternal) - } - for _, r := range rules { - if err := s.store.DeleteRule(r.RuleID); err != nil { - slog.Error("DeleteListener: failed to delete rule", "ruleId", r.RuleID, "err", err) - return nil, errors.New(awserrors.ErrorServerInternal) - } - } - - if err := s.store.DeleteListener(listener.ListenerID); err != nil { - slog.Error("DeleteListener: failed to delete record", "listenerId", listener.ListenerID, "err", err) + if err := s.deleteListenerCascade(listener); err != nil { + slog.Error("DeleteListener: failed to cascade-delete listener", "listenerArn", listener.ListenerArn, "err", err) return nil, errors.New(awserrors.ErrorServerInternal) } @@ -1881,6 +2018,9 @@ func (s *ELBv2ServiceImpl) ModifyListener(input *elbv2.ModifyListenerInput, acco var actions []ListenerAction for _, a := range input.DefaultActions { action := listenerActionFromSDK(a) + if err := validateListenerAction(action); err != nil { + return nil, err + } if action.Type == ActionTypeForward && action.TargetGroupArn != "" { tg, tgErr := s.store.GetTargetGroupByArn(action.TargetGroupArn) if tgErr != nil { @@ -1975,10 +2115,9 @@ func (s *ELBv2ServiceImpl) DescribeListeners(input *elbv2.DescribeListenersInput // DescribeTags returns tags for one or more ELBv2 resources (load balancers, // target groups, listeners, listener rules). Tag data is read from the existing -// record stores — Spinifex doesn't have a separate tag KV. Listeners and rules -// currently never store tags, so they always return an empty Tags slice -// (matches AWS behaviour for untagged resources). Cross-account or unknown ARNs -// return the per-resource not-found error so existence isn't leaked across +// record stores — Spinifex doesn't have a separate tag KV. Untagged resources +// return an empty Tags slice (matches AWS behaviour). Cross-account or unknown +// ARNs return the per-resource not-found error so existence isn't leaked across // accounts. func (s *ELBv2ServiceImpl) DescribeTags(input *elbv2.DescribeTagsInput, accountID string) (*elbv2.DescribeTagsOutput, error) { if input == nil || len(input.ResourceArns) == 0 { @@ -2037,8 +2176,8 @@ func (s *ELBv2ServiceImpl) DescribeTags(input *elbv2.DescribeTagsInput, accountI } if l != nil { found = true + tags = l.Tags ownerAccount = l.AccountID - // Listeners don't store tags yet — leave map nil. } case elbv2ResourceListenerRule: notFoundError = awserrors.ErrorELBv2RuleNotFound @@ -2049,8 +2188,8 @@ func (s *ELBv2ServiceImpl) DescribeTags(input *elbv2.DescribeTagsInput, accountI } if r != nil { found = true + tags = r.Tags ownerAccount = r.AccountID - // Rules don't store tags yet — leave map nil. } } @@ -2088,210 +2227,6 @@ func tagsMapToSDK(tags map[string]string) []*elbv2.Tag { return out } -// --- SDK type conversion helpers --- - -func (s *ELBv2ServiceImpl) ModifyTargetGroupAttributes(input *elbv2.ModifyTargetGroupAttributesInput, accountID string) (*elbv2.ModifyTargetGroupAttributesOutput, error) { - if input.TargetGroupArn == nil || *input.TargetGroupArn == "" { - return nil, errors.New(awserrors.ErrorMissingParameter) - } - - tg, err := s.store.GetTargetGroupByArn(*input.TargetGroupArn) - if err != nil { - slog.Error("ModifyTargetGroupAttributes: failed to get TG", "arn", *input.TargetGroupArn, "err", err) - return nil, errors.New(awserrors.ErrorServerInternal) - } - if tg == nil || tg.AccountID != accountID { - return nil, errors.New(awserrors.ErrorELBv2TargetGroupNotFound) - } - - knownTGAttrs := DefaultTargetGroupAttributes() - var submitted []*elbv2.TargetGroupAttribute - dirty := false - for _, attr := range input.Attributes { - if attr == nil { - slog.Warn("ModifyTargetGroupAttributes: skipping nil attribute element", "arn", *input.TargetGroupArn) - continue - } - if attr.Key == nil || attr.Value == nil { - slog.Warn("ModifyTargetGroupAttributes: skipping attribute with nil Key or Value", "arn", *input.TargetGroupArn) - continue - } - if _, ok := knownTGAttrs[*attr.Key]; !ok { - slog.Warn("ModifyTargetGroupAttributes: rejecting unknown attribute key", "arn", *input.TargetGroupArn, "key", *attr.Key) - return nil, errors.New(awserrors.ErrorValidationError) - } - submitted = append(submitted, &elbv2.TargetGroupAttribute{ - Key: attr.Key, - Value: attr.Value, - }) - existing, exists := tg.Attributes[*attr.Key] - if exists && existing == *attr.Value { - continue // value already matches stored — no mutation needed - } - if tg.Attributes == nil { - tg.Attributes = make(map[string]string) - } - tg.Attributes[*attr.Key] = *attr.Value - dirty = true - } - - // If the caller sent attributes but every single one was rejected by the - // nil guard above, surface that as an error instead of silently returning - // a successful empty response — otherwise the caller thinks the write - // landed when nothing was actually applied. - if len(input.Attributes) > 0 && len(submitted) == 0 { - slog.Warn("ModifyTargetGroupAttributes: all submitted attributes were invalid", "arn", *input.TargetGroupArn, "submitted_count", len(input.Attributes)) - return nil, errors.New(awserrors.ErrorInvalidParameterValue) - } - - // Skip the NATS/KV write when nothing changed. Terraform re-applies the same - // attribute set on every drift check, so this kills ~all Modify traffic - // during steady state and narrows the read-modify-write race window. - if dirty { - if err := s.store.PutTargetGroup(tg); err != nil { - slog.Error("ModifyTargetGroupAttributes: failed to persist TG", "arn", *input.TargetGroupArn, "err", err) - return nil, errors.New(awserrors.ErrorServerInternal) - } - } - - return &elbv2.ModifyTargetGroupAttributesOutput{ - Attributes: submitted, - }, nil -} - -func (s *ELBv2ServiceImpl) DescribeTargetGroupAttributes(input *elbv2.DescribeTargetGroupAttributesInput, accountID string) (*elbv2.DescribeTargetGroupAttributesOutput, error) { - if input.TargetGroupArn == nil || *input.TargetGroupArn == "" { - return nil, errors.New(awserrors.ErrorMissingParameter) - } - - tg, err := s.store.GetTargetGroupByArn(*input.TargetGroupArn) - if err != nil { - slog.Error("DescribeTargetGroupAttributes: failed to get TG", "arn", *input.TargetGroupArn, "err", err) - return nil, errors.New(awserrors.ErrorServerInternal) - } - if tg == nil || tg.AccountID != accountID { - return nil, errors.New(awserrors.ErrorELBv2TargetGroupNotFound) - } - - merged := DefaultTargetGroupAttributes() - maps.Copy(merged, tg.Attributes) - - // Sort keys for deterministic output — Terraform diffs and snapshot tests - // depend on stable attribute ordering. - keys := slices.Sorted(maps.Keys(merged)) - attrs := make([]*elbv2.TargetGroupAttribute, 0, len(keys)) - for _, k := range keys { - attrs = append(attrs, &elbv2.TargetGroupAttribute{ - Key: aws.String(k), - Value: aws.String(merged[k]), - }) - } - - return &elbv2.DescribeTargetGroupAttributesOutput{ - Attributes: attrs, - }, nil -} - -func (s *ELBv2ServiceImpl) ModifyLoadBalancerAttributes(input *elbv2.ModifyLoadBalancerAttributesInput, accountID string) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { - if input.LoadBalancerArn == nil || *input.LoadBalancerArn == "" { - return nil, errors.New(awserrors.ErrorMissingParameter) - } - - lb, err := s.store.GetLoadBalancerByArn(*input.LoadBalancerArn) - if err != nil { - slog.Error("ModifyLoadBalancerAttributes: failed to get LB", "arn", *input.LoadBalancerArn, "err", err) - return nil, errors.New(awserrors.ErrorServerInternal) - } - if lb == nil || lb.AccountID != accountID { - return nil, errors.New(awserrors.ErrorELBv2LoadBalancerNotFound) - } - - knownLBAttrs := DefaultLoadBalancerAttributes(lb.Type) - var submitted []*elbv2.LoadBalancerAttribute - dirty := false - for _, attr := range input.Attributes { - if attr == nil { - slog.Warn("ModifyLoadBalancerAttributes: skipping nil attribute element", "arn", *input.LoadBalancerArn) - continue - } - if attr.Key == nil || attr.Value == nil { - slog.Warn("ModifyLoadBalancerAttributes: skipping attribute with nil Key or Value", "arn", *input.LoadBalancerArn) - continue - } - if _, ok := knownLBAttrs[*attr.Key]; !ok { - slog.Warn("ModifyLoadBalancerAttributes: rejecting unknown attribute key", "arn", *input.LoadBalancerArn, "key", *attr.Key, "lbType", lb.Type) - return nil, errors.New(awserrors.ErrorValidationError) - } - submitted = append(submitted, &elbv2.LoadBalancerAttribute{ - Key: attr.Key, - Value: attr.Value, - }) - existing, exists := lb.Attributes[*attr.Key] - if exists && existing == *attr.Value { - continue - } - if lb.Attributes == nil { - lb.Attributes = make(map[string]string) - } - lb.Attributes[*attr.Key] = *attr.Value - dirty = true - } - - // If the caller sent attributes but every single one was rejected by the - // nil guard above, surface that as an error instead of silently returning - // a successful empty response. - if len(input.Attributes) > 0 && len(submitted) == 0 { - slog.Warn("ModifyLoadBalancerAttributes: all submitted attributes were invalid", "arn", *input.LoadBalancerArn, "submitted_count", len(input.Attributes)) - return nil, errors.New(awserrors.ErrorInvalidParameterValue) - } - - // Skip the NATS/KV write when nothing changed. See - // ModifyTargetGroupAttributes for the Terraform-drift-check motivation. - if dirty { - if err := s.store.PutLoadBalancer(lb); err != nil { - slog.Error("ModifyLoadBalancerAttributes: failed to persist LB", "arn", *input.LoadBalancerArn, "err", err) - return nil, errors.New(awserrors.ErrorServerInternal) - } - } - - return &elbv2.ModifyLoadBalancerAttributesOutput{ - Attributes: submitted, - }, nil -} - -func (s *ELBv2ServiceImpl) DescribeLoadBalancerAttributes(input *elbv2.DescribeLoadBalancerAttributesInput, accountID string) (*elbv2.DescribeLoadBalancerAttributesOutput, error) { - if input.LoadBalancerArn == nil || *input.LoadBalancerArn == "" { - return nil, errors.New(awserrors.ErrorMissingParameter) - } - - lb, err := s.store.GetLoadBalancerByArn(*input.LoadBalancerArn) - if err != nil { - slog.Error("DescribeLoadBalancerAttributes: failed to get LB", "arn", *input.LoadBalancerArn, "err", err) - return nil, errors.New(awserrors.ErrorServerInternal) - } - if lb == nil || lb.AccountID != accountID { - return nil, errors.New(awserrors.ErrorELBv2LoadBalancerNotFound) - } - - merged := DefaultLoadBalancerAttributes(lb.Type) - maps.Copy(merged, lb.Attributes) - - // Sort keys for deterministic output — Terraform diffs and snapshot tests - // depend on stable attribute ordering. - keys := slices.Sorted(maps.Keys(merged)) - attrs := make([]*elbv2.LoadBalancerAttribute, 0, len(keys)) - for _, k := range keys { - attrs = append(attrs, &elbv2.LoadBalancerAttribute{ - Key: aws.String(k), - Value: aws.String(merged[k]), - }) - } - - return &elbv2.DescribeLoadBalancerAttributesOutput{ - Attributes: attrs, - }, nil -} - func (s *ELBv2ServiceImpl) lbRecordToSDK(r *LoadBalancerRecord) *elbv2.LoadBalancer { lb := &elbv2.LoadBalancer{ LoadBalancerArn: aws.String(r.LoadBalancerArn), @@ -2387,24 +2322,52 @@ func (s *ELBv2ServiceImpl) listenerRecordToSDK(r *ListenerRecord) *elbv2.Listene } for _, a := range r.DefaultActions { - action := &elbv2.Action{Type: aws.String(a.Type)} - if a.TargetGroupArn != "" { - action.TargetGroupArn = aws.String(a.TargetGroupArn) - } - if a.FixedResponse != nil { - fr := &elbv2.FixedResponseActionConfig{ - StatusCode: aws.String(a.FixedResponse.StatusCode), - } - if a.FixedResponse.ContentType != "" { - fr.ContentType = aws.String(a.FixedResponse.ContentType) - } - if a.FixedResponse.MessageBody != "" { - fr.MessageBody = aws.String(a.FixedResponse.MessageBody) - } - action.FixedResponseConfig = fr - } - listener.DefaultActions = append(listener.DefaultActions, action) + listener.DefaultActions = append(listener.DefaultActions, listenerActionToSDK(a)) } return listener } + +// listenerActionToSDK converts a stored action into the AWS SDK shape, +// preserving forward / fixed-response / redirect detail so DescribeListeners +// and DescribeRules round-trip cleanly. Shared by listeners and rules. +func listenerActionToSDK(a ListenerAction) *elbv2.Action { + action := &elbv2.Action{Type: aws.String(a.Type)} + if a.TargetGroupArn != "" { + action.TargetGroupArn = aws.String(a.TargetGroupArn) + } + if a.FixedResponse != nil { + fr := &elbv2.FixedResponseActionConfig{ + StatusCode: aws.String(a.FixedResponse.StatusCode), + } + if a.FixedResponse.ContentType != "" { + fr.ContentType = aws.String(a.FixedResponse.ContentType) + } + if a.FixedResponse.MessageBody != "" { + fr.MessageBody = aws.String(a.FixedResponse.MessageBody) + } + action.FixedResponseConfig = fr + } + if a.Redirect != nil { + rd := &elbv2.RedirectActionConfig{ + StatusCode: aws.String(a.Redirect.StatusCode), + } + if a.Redirect.Protocol != "" { + rd.Protocol = aws.String(a.Redirect.Protocol) + } + if a.Redirect.Host != "" { + rd.Host = aws.String(a.Redirect.Host) + } + if a.Redirect.Port != "" { + rd.Port = aws.String(a.Redirect.Port) + } + if a.Redirect.Path != "" { + rd.Path = aws.String(a.Redirect.Path) + } + if a.Redirect.Query != "" { + rd.Query = aws.String(a.Redirect.Query) + } + action.RedirectConfig = rd + } + return action +} diff --git a/spinifex/handlers/elbv2/service_impl_attributes.go b/spinifex/handlers/elbv2/service_impl_attributes.go new file mode 100644 index 000000000..362c469e5 --- /dev/null +++ b/spinifex/handlers/elbv2/service_impl_attributes.go @@ -0,0 +1,265 @@ +package handlers_elbv2 + +import ( + "errors" + "log/slog" + "maps" + "slices" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/awserrors" +) + +// attrPair is the internal key/value shape the generic attribute handlers work +// in, decoupled from the two near-identical SDK attribute types +// (*elbv2.TargetGroupAttribute and *elbv2.LoadBalancerAttribute). +type attrPair struct { + Key string + Value string +} + +// attrResource bundles the per-resource-type plumbing the generic Modify/ +// Describe attribute handlers need, so the target-group and load-balancer +// paths share one implementation. +type attrResource[R any] struct { + arn string + accountID string + opName string // slog prefix / error context + notFound string // awserrors code returned for missing/cross-account + fetch func(string) (*R, error) + save func(*R) error + accountIDOf func(*R) string + defaults func(*R) map[string]string + attrsOf func(*R) map[string]string + setAttrs func(*R, map[string]string) +} + +// load fetches and authorises the record. An empty accountID is rejected +// explicitly so a direct NATS/internal caller cannot match a record whose +// AccountID is also empty. +func (r attrResource[R]) load() (*R, error) { + rec, err := r.fetch(r.arn) + if err != nil { + slog.Error(r.opName+": failed to load record", "arn", r.arn, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } + if rec == nil || r.accountID == "" || r.accountIDOf(rec) != r.accountID { + return nil, errors.New(r.notFound) + } + return rec, nil +} + +// modifyResourceAttributes validates and merges submitted attributes into the +// record, persisting only when something actually changed. rawCount is the +// number of attributes the caller submitted before nil filtering, used to +// distinguish "nothing sent" from "everything sent was invalid". +func modifyResourceAttributes[R any](res attrResource[R], pairs []attrPair, rawCount int) ([]attrPair, error) { + if res.arn == "" { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + rec, err := res.load() + if err != nil { + return nil, err + } + + known := res.defaults(rec) + attrs := res.attrsOf(rec) + submitted := make([]attrPair, 0, len(pairs)) + dirty := false + for _, p := range pairs { + if _, ok := known[p.Key]; !ok { + slog.Warn(res.opName+": rejecting unknown attribute key", "arn", res.arn, "key", p.Key) + return nil, errors.New(awserrors.ErrorValidationError) + } + submitted = append(submitted, p) + if existing, ok := attrs[p.Key]; ok && existing == p.Value { + continue // value already matches stored — no mutation needed + } + if attrs == nil { + attrs = make(map[string]string) + } + attrs[p.Key] = p.Value + dirty = true + } + + // Caller sent attributes but every one was dropped by nil filtering: surface + // an error rather than a successful empty response the caller misreads as a + // landed write. + if rawCount > 0 && len(submitted) == 0 { + slog.Warn(res.opName+": all submitted attributes were invalid", "arn", res.arn, "submitted_count", rawCount) + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + + // Skip the NATS/KV write when nothing changed. Terraform re-applies the same + // attribute set on every drift check, so this kills ~all Modify traffic + // during steady state and narrows the read-modify-write race window. + if dirty { + res.setAttrs(rec, attrs) + if err := res.save(rec); err != nil { + slog.Error(res.opName+": failed to persist", "arn", res.arn, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } + } + + return submitted, nil +} + +// describeResourceAttributes returns the record's attributes merged over the +// per-type defaults, sorted by key for deterministic output (Terraform diffs +// and snapshot tests depend on stable ordering). +func describeResourceAttributes[R any](res attrResource[R]) ([]attrPair, error) { + if res.arn == "" { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + rec, err := res.load() + if err != nil { + return nil, err + } + + merged := res.defaults(rec) + maps.Copy(merged, res.attrsOf(rec)) + + keys := slices.Sorted(maps.Keys(merged)) + out := make([]attrPair, 0, len(keys)) + for _, k := range keys { + out = append(out, attrPair{Key: k, Value: merged[k]}) + } + return out, nil +} + +// sdkAttrsIn converts an SDK attribute slice into internal pairs, dropping nil +// elements and elements with a nil Key/Value. Returns the cleaned pairs and the +// raw submitted count. +func sdkAttrsIn[A any](in []A, keyVal func(A) (*string, *string), arn, opName string) ([]attrPair, int) { + out := make([]attrPair, 0, len(in)) + for _, a := range in { + k, v := keyVal(a) + if k == nil || v == nil { + slog.Warn(opName+": skipping invalid attribute element", "arn", arn) + continue + } + out = append(out, attrPair{Key: *k, Value: *v}) + } + return out, len(in) +} + +// sdkAttrsOut converts internal pairs back into a fresh SDK attribute slice via +// mk. Fresh strings are allocated (never aliasing caller input). Returns nil for +// an empty set to match AWS for resources with no submitted attributes. +func sdkAttrsOut[A any](pairs []attrPair, mk func(key, value string) A) []A { + if len(pairs) == 0 { + return nil + } + out := make([]A, 0, len(pairs)) + for _, p := range pairs { + out = append(out, mk(p.Key, p.Value)) + } + return out +} + +func (s *ELBv2ServiceImpl) tgAttrResource(arn, accountID, opName string) attrResource[TargetGroupRecord] { + return attrResource[TargetGroupRecord]{ + arn: arn, + accountID: accountID, + opName: opName, + notFound: awserrors.ErrorELBv2TargetGroupNotFound, + fetch: s.store.GetTargetGroupByArn, + save: s.store.PutTargetGroup, + accountIDOf: func(r *TargetGroupRecord) string { return r.AccountID }, + defaults: func(*TargetGroupRecord) map[string]string { return DefaultTargetGroupAttributes() }, + attrsOf: func(r *TargetGroupRecord) map[string]string { return r.Attributes }, + setAttrs: func(r *TargetGroupRecord, m map[string]string) { r.Attributes = m }, + } +} + +func (s *ELBv2ServiceImpl) lbAttrResource(arn, accountID, opName string) attrResource[LoadBalancerRecord] { + return attrResource[LoadBalancerRecord]{ + arn: arn, + accountID: accountID, + opName: opName, + notFound: awserrors.ErrorELBv2LoadBalancerNotFound, + fetch: s.store.GetLoadBalancerByArn, + save: s.store.PutLoadBalancer, + accountIDOf: func(r *LoadBalancerRecord) string { return r.AccountID }, + defaults: func(r *LoadBalancerRecord) map[string]string { return DefaultLoadBalancerAttributes(r.Type) }, + attrsOf: func(r *LoadBalancerRecord) map[string]string { return r.Attributes }, + setAttrs: func(r *LoadBalancerRecord, m map[string]string) { r.Attributes = m }, + } +} + +func tgAttrKeyVal(a *elbv2.TargetGroupAttribute) (*string, *string) { + if a == nil { + return nil, nil + } + return a.Key, a.Value +} + +func lbAttrKeyVal(a *elbv2.LoadBalancerAttribute) (*string, *string) { + if a == nil { + return nil, nil + } + return a.Key, a.Value +} + +func mkTGAttr(key, value string) *elbv2.TargetGroupAttribute { + return &elbv2.TargetGroupAttribute{Key: aws.String(key), Value: aws.String(value)} +} + +func mkLBAttr(key, value string) *elbv2.LoadBalancerAttribute { + return &elbv2.LoadBalancerAttribute{Key: aws.String(key), Value: aws.String(value)} +} + +func (s *ELBv2ServiceImpl) ModifyTargetGroupAttributes(input *elbv2.ModifyTargetGroupAttributesInput, accountID string) (*elbv2.ModifyTargetGroupAttributesOutput, error) { + if input == nil { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + const op = "ModifyTargetGroupAttributes" + arn := aws.StringValue(input.TargetGroupArn) + pairs, raw := sdkAttrsIn(input.Attributes, tgAttrKeyVal, arn, op) + submitted, err := modifyResourceAttributes(s.tgAttrResource(arn, accountID, op), pairs, raw) + if err != nil { + return nil, err + } + return &elbv2.ModifyTargetGroupAttributesOutput{Attributes: sdkAttrsOut(submitted, mkTGAttr)}, nil +} + +func (s *ELBv2ServiceImpl) DescribeTargetGroupAttributes(input *elbv2.DescribeTargetGroupAttributesInput, accountID string) (*elbv2.DescribeTargetGroupAttributesOutput, error) { + if input == nil { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + const op = "DescribeTargetGroupAttributes" + arn := aws.StringValue(input.TargetGroupArn) + pairs, err := describeResourceAttributes(s.tgAttrResource(arn, accountID, op)) + if err != nil { + return nil, err + } + return &elbv2.DescribeTargetGroupAttributesOutput{Attributes: sdkAttrsOut(pairs, mkTGAttr)}, nil +} + +func (s *ELBv2ServiceImpl) ModifyLoadBalancerAttributes(input *elbv2.ModifyLoadBalancerAttributesInput, accountID string) (*elbv2.ModifyLoadBalancerAttributesOutput, error) { + if input == nil { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + const op = "ModifyLoadBalancerAttributes" + arn := aws.StringValue(input.LoadBalancerArn) + pairs, raw := sdkAttrsIn(input.Attributes, lbAttrKeyVal, arn, op) + submitted, err := modifyResourceAttributes(s.lbAttrResource(arn, accountID, op), pairs, raw) + if err != nil { + return nil, err + } + return &elbv2.ModifyLoadBalancerAttributesOutput{Attributes: sdkAttrsOut(submitted, mkLBAttr)}, nil +} + +func (s *ELBv2ServiceImpl) DescribeLoadBalancerAttributes(input *elbv2.DescribeLoadBalancerAttributesInput, accountID string) (*elbv2.DescribeLoadBalancerAttributesOutput, error) { + if input == nil { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + const op = "DescribeLoadBalancerAttributes" + arn := aws.StringValue(input.LoadBalancerArn) + pairs, err := describeResourceAttributes(s.lbAttrResource(arn, accountID, op)) + if err != nil { + return nil, err + } + return &elbv2.DescribeLoadBalancerAttributesOutput{Attributes: sdkAttrsOut(pairs, mkLBAttr)}, nil +} diff --git a/spinifex/handlers/elbv2/service_impl_health_test.go b/spinifex/handlers/elbv2/service_impl_health_test.go index 1ea659b14..19553fe75 100644 --- a/spinifex/handlers/elbv2/service_impl_health_test.go +++ b/spinifex/handlers/elbv2/service_impl_health_test.go @@ -164,7 +164,7 @@ func TestRegisterTargets_MultipleInstances(t *testing.T) { // TestResetTargetHealthOnStartup_TransitionsAllNonDrainingToInitial verifies // that the startup reset rewrites every non-draining target's HealthState // back to "initial" so a daemon restart can't surface stale "healthy" claims -// before the lb-agent has posted a fresh report. Refs mulga-siv-119. +// before the lb-agent has posted a fresh report. func TestResetTargetHealthOnStartup_TransitionsAllNonDrainingToInitial(t *testing.T) { store := setupTestNATS(t) svc := &ELBv2ServiceImpl{store: store} diff --git a/spinifex/handlers/elbv2/service_impl_lb_network.go b/spinifex/handlers/elbv2/service_impl_lb_network.go new file mode 100644 index 000000000..85d648fe4 --- /dev/null +++ b/spinifex/handlers/elbv2/service_impl_lb_network.go @@ -0,0 +1,109 @@ +package handlers_elbv2 + +import ( + "errors" + "log/slog" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/awserrors" +) + +// SetIpAddressType sets the load balancer's IP address type. Spinifex ALBs are +// IPv4-only, so the only accepted value is "ipv4"; dualstack variants are +// rejected with InvalidConfigurationRequest. The call is idempotent. +func (s *ELBv2ServiceImpl) SetIpAddressType(input *elbv2.SetIpAddressTypeInput, accountID string) (*elbv2.SetIpAddressTypeOutput, error) { + if input == nil || input.LoadBalancerArn == nil || *input.LoadBalancerArn == "" { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + if input.IpAddressType == nil || *input.IpAddressType == "" { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + if *input.IpAddressType != IPAddressTypeIPv4 { + return nil, errors.New(awserrors.ErrorELBv2InvalidConfigurationRequest) + } + + lb, err := s.store.GetLoadBalancerByArn(*input.LoadBalancerArn) + if err != nil { + slog.Error("SetIpAddressType: failed to get LB", "arn", *input.LoadBalancerArn, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } + if lb == nil || lb.AccountID != accountID { + return nil, errors.New(awserrors.ErrorELBv2LoadBalancerNotFound) + } + + if lb.IPAddressType != IPAddressTypeIPv4 { + lb.IPAddressType = IPAddressTypeIPv4 + if err := s.store.PutLoadBalancer(lb); err != nil { + slog.Error("SetIpAddressType: failed to persist LB", "arn", *input.LoadBalancerArn, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } + } + + return &elbv2.SetIpAddressTypeOutput{ + IpAddressType: aws.String(lb.IPAddressType), + }, nil +} + +// SetSecurityGroups replaces the security groups associated with an +// (application) load balancer. The new groups are re-attached to every ENI the +// ALB spans via ModifyNetworkInterfaceAttribute, which validates them against +// the ENI's VPC and pushes the change to the live data-plane port before the +// record is persisted. +func (s *ELBv2ServiceImpl) SetSecurityGroups(input *elbv2.SetSecurityGroupsInput, accountID string) (*elbv2.SetSecurityGroupsOutput, error) { + if input == nil || input.LoadBalancerArn == nil || *input.LoadBalancerArn == "" { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + if len(input.SecurityGroups) == 0 { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + + lb, err := s.store.GetLoadBalancerByArn(*input.LoadBalancerArn) + if err != nil { + slog.Error("SetSecurityGroups: failed to get LB", "arn", *input.LoadBalancerArn, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } + if lb == nil || lb.AccountID != accountID { + return nil, errors.New(awserrors.ErrorELBv2LoadBalancerNotFound) + } + + // NLBs do not support security groups (mirrors CreateLoadBalancer). + if lb.Type == LoadBalancerTypeNetwork { + return nil, errors.New(awserrors.ErrorELBv2InvalidConfigurationRequest) + } + + sgs := make([]string, 0, len(input.SecurityGroups)) + for _, sg := range input.SecurityGroups { + if sg == nil || *sg == "" { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + sgs = append(sgs, *sg) + } + + // Re-attach the new groups to each ALB ENI. This validates the groups + // against the ENI's VPC and fires the live port-SG update; a failure here + // (e.g. unknown SG) aborts before the record is persisted. All ENIs share + // the LB's VPC and groups, so a successful first apply implies the rest. + if s.VPCService != nil { + for _, eniID := range lb.ENIs { + if _, err := s.VPCService.ModifyNetworkInterfaceAttribute(&ec2.ModifyNetworkInterfaceAttributeInput{ + NetworkInterfaceId: aws.String(eniID), + Groups: aws.StringSlice(sgs), + }, accountID); err != nil { + slog.Error("SetSecurityGroups: failed to update ENI groups", "arn", *input.LoadBalancerArn, "eni", eniID, "err", err) + return nil, err + } + } + } + + lb.SecurityGroups = sgs + if err := s.store.PutLoadBalancer(lb); err != nil { + slog.Error("SetSecurityGroups: failed to persist LB", "arn", *input.LoadBalancerArn, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } + + return &elbv2.SetSecurityGroupsOutput{ + SecurityGroupIds: aws.StringSlice(sgs), + }, nil +} diff --git a/spinifex/handlers/elbv2/service_impl_lb_network_test.go b/spinifex/handlers/elbv2/service_impl_lb_network_test.go new file mode 100644 index 000000000..ad6906a5a --- /dev/null +++ b/spinifex/handlers/elbv2/service_impl_lb_network_test.go @@ -0,0 +1,136 @@ +package handlers_elbv2 + +import ( + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/awserrors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func createLBArn(t *testing.T, svc *ELBv2ServiceImpl, name string) string { + t.Helper() + out, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{ + Name: aws.String(name), + }, testAccountID) + require.NoError(t, err) + require.Len(t, out.LoadBalancers, 1) + return *out.LoadBalancers[0].LoadBalancerArn +} + +func describeLB(t *testing.T, svc *ELBv2ServiceImpl, arn string) *elbv2.LoadBalancer { + t.Helper() + out, err := svc.DescribeLoadBalancers(&elbv2.DescribeLoadBalancersInput{ + LoadBalancerArns: []*string{aws.String(arn)}, + }, testAccountID) + require.NoError(t, err) + require.Len(t, out.LoadBalancers, 1) + return out.LoadBalancers[0] +} + +func TestSetIpAddressType_IPv4Idempotent(t *testing.T) { + svc := setupTestService(t) + arn := createLBArn(t, svc, "ipt-lb") + + out, err := svc.SetIpAddressType(&elbv2.SetIpAddressTypeInput{ + LoadBalancerArn: aws.String(arn), + IpAddressType: aws.String("ipv4"), + }, testAccountID) + require.NoError(t, err) + assert.Equal(t, "ipv4", *out.IpAddressType) + assert.Equal(t, "ipv4", *describeLB(t, svc, arn).IpAddressType) +} + +func TestSetIpAddressType_DualstackRejected(t *testing.T) { + svc := setupTestService(t) + arn := createLBArn(t, svc, "ipt-ds") + + _, err := svc.SetIpAddressType(&elbv2.SetIpAddressTypeInput{ + LoadBalancerArn: aws.String(arn), + IpAddressType: aws.String("dualstack"), + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorELBv2InvalidConfigurationRequest) +} + +func TestSetIpAddressType_MissingParams(t *testing.T) { + svc := setupTestService(t) + arn := createLBArn(t, svc, "ipt-mp") + + _, err := svc.SetIpAddressType(&elbv2.SetIpAddressTypeInput{ + LoadBalancerArn: aws.String(arn), + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorMissingParameter) + + _, err = svc.SetIpAddressType(&elbv2.SetIpAddressTypeInput{ + IpAddressType: aws.String("ipv4"), + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorMissingParameter) +} + +func TestSetIpAddressType_NotFound(t *testing.T) { + svc := setupTestService(t) + _, err := svc.SetIpAddressType(&elbv2.SetIpAddressTypeInput{ + LoadBalancerArn: aws.String("arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/missing/lb-deadbeef"), + IpAddressType: aws.String("ipv4"), + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorELBv2LoadBalancerNotFound) +} + +func TestSetSecurityGroups_UpdatesRecord(t *testing.T) { + svc := setupTestService(t) + arn := createLBArn(t, svc, "sg-lb") + + out, err := svc.SetSecurityGroups(&elbv2.SetSecurityGroupsInput{ + LoadBalancerArn: aws.String(arn), + SecurityGroups: aws.StringSlice([]string{"sg-aaa", "sg-bbb"}), + }, testAccountID) + require.NoError(t, err) + assert.Equal(t, []string{"sg-aaa", "sg-bbb"}, aws.StringValueSlice(out.SecurityGroupIds)) + assert.Equal(t, []string{"sg-aaa", "sg-bbb"}, aws.StringValueSlice(describeLB(t, svc, arn).SecurityGroups)) +} + +func TestSetSecurityGroups_EmptyRejected(t *testing.T) { + svc := setupTestService(t) + arn := createLBArn(t, svc, "sg-empty") + + _, err := svc.SetSecurityGroups(&elbv2.SetSecurityGroupsInput{ + LoadBalancerArn: aws.String(arn), + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorMissingParameter) +} + +func TestSetSecurityGroups_NLBRejected(t *testing.T) { + svc := setupTestService(t) + out, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{ + Name: aws.String("sg-nlb"), + Type: aws.String("network"), + }, testAccountID) + require.NoError(t, err) + arn := *out.LoadBalancers[0].LoadBalancerArn + + _, err = svc.SetSecurityGroups(&elbv2.SetSecurityGroupsInput{ + LoadBalancerArn: aws.String(arn), + SecurityGroups: aws.StringSlice([]string{"sg-aaa"}), + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorELBv2InvalidConfigurationRequest) +} + +func TestSetSecurityGroups_CrossAccount(t *testing.T) { + svc := setupTestService(t) + arn := createLBArn(t, svc, "sg-xacct") + + _, err := svc.SetSecurityGroups(&elbv2.SetSecurityGroupsInput{ + LoadBalancerArn: aws.String(arn), + SecurityGroups: aws.StringSlice([]string{"sg-aaa"}), + }, "999999999999") + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorELBv2LoadBalancerNotFound) +} diff --git a/spinifex/handlers/elbv2/service_impl_rules.go b/spinifex/handlers/elbv2/service_impl_rules.go index 476dc8d51..56ec4e0da 100644 --- a/spinifex/handlers/elbv2/service_impl_rules.go +++ b/spinifex/handlers/elbv2/service_impl_rules.go @@ -86,6 +86,13 @@ func (s *ELBv2ServiceImpl) CreateRule(input *elbv2.CreateRuleInput, accountID st return nil, errors.New(awserrors.ErrorServerInternal) } + tags := make(map[string]string) + for _, tag := range input.Tags { + if tag.Key != nil && tag.Value != nil { + tags[*tag.Key] = *tag.Value + } + } + record := &RuleRecord{ RuleArn: ruleArn, RuleID: ruleID, @@ -95,6 +102,7 @@ func (s *ELBv2ServiceImpl) CreateRule(input *elbv2.CreateRuleInput, accountID st Actions: actions, AccountID: accountID, CreatedAt: time.Now().UTC(), + Tags: tags, } if err := s.store.PutRule(record); err != nil { @@ -176,10 +184,16 @@ func (s *ELBv2ServiceImpl) DeleteRule(input *elbv2.DeleteRuleInput, accountID st return nil, errors.New(awserrors.ErrorServerInternal) } if rule == nil || rule.AccountID != accountID { - return nil, errors.New(awserrors.ErrorELBv2RuleNotFound) + // Idempotent: AWS ELBv2 delete returns success on an absent (or + // not-owned) rule, so tofu destroy retries converge. + return &elbv2.DeleteRuleOutput{}, nil } - listener, _ := s.store.GetListenerByArn(rule.ListenerArn) + listener, err := s.store.GetListenerByArn(rule.ListenerArn) + if err != nil { + slog.Error("DeleteRule: failed to get listener for reload", "listenerArn", rule.ListenerArn, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } if err := s.store.DeleteRule(rule.RuleID); err != nil { slog.Error("DeleteRule: failed to delete", "ruleId", rule.RuleID, "err", err) @@ -549,25 +563,35 @@ func (s *ELBv2ServiceImpl) validateAndConvertRuleActions(in []*elbv2.Action, lis if a == nil || a.Type == nil { return nil, errors.New(awserrors.ErrorMissingParameter) } - if *a.Type != ActionTypeForward { - // redirect / fixed-response / authenticate-* deferred to mulga-951. + action := listenerActionFromSDK(a) + switch action.Type { + case ActionTypeForward: + if action.TargetGroupArn == "" { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + tg, err := s.store.GetTargetGroupByArn(action.TargetGroupArn) + if err != nil { + slog.Error("rule action: failed to get target group", "arn", action.TargetGroupArn, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } + if tg == nil { + return nil, errors.New(awserrors.ErrorELBv2TargetGroupNotFound) + } + if !isCompatibleProtocol(listenerProto, tg.Protocol) { + return nil, errors.New(awserrors.ErrorELBv2IncompatibleProtocols) + } + case ActionTypeRedirect: + if err := validateRedirectAction(action.Redirect); err != nil { + return nil, err + } + case ActionTypeFixedResponse: + if action.FixedResponse == nil { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + default: return nil, errors.New(awserrors.ErrorELBv2InvalidConfigurationRequest) } - if a.TargetGroupArn == nil || *a.TargetGroupArn == "" { - return nil, errors.New(awserrors.ErrorMissingParameter) - } - tg, err := s.store.GetTargetGroupByArn(*a.TargetGroupArn) - if err != nil { - slog.Error("rule action: failed to get target group", "arn", *a.TargetGroupArn, "err", err) - return nil, errors.New(awserrors.ErrorServerInternal) - } - if tg == nil { - return nil, errors.New(awserrors.ErrorELBv2TargetGroupNotFound) - } - if !isCompatibleProtocol(listenerProto, tg.Protocol) { - return nil, errors.New(awserrors.ErrorELBv2IncompatibleProtocols) - } - out = append(out, ListenerAction{Type: *a.Type, TargetGroupArn: *a.TargetGroupArn}) + out = append(out, action) } return out, nil } @@ -596,10 +620,7 @@ func ruleRecordToSDK(r *RuleRecord) *elbv2.Rule { rule.Conditions = append(rule.Conditions, ruleConditionToSDK(c)) } for _, a := range r.Actions { - rule.Actions = append(rule.Actions, &elbv2.Action{ - Type: aws.String(a.Type), - TargetGroupArn: aws.String(a.TargetGroupArn), - }) + rule.Actions = append(rule.Actions, listenerActionToSDK(a)) } return rule } @@ -647,10 +668,7 @@ func defaultRuleFromListener(l *ListenerRecord) *elbv2.Rule { IsDefault: aws.Bool(true), } for _, a := range l.DefaultActions { - rule.Actions = append(rule.Actions, &elbv2.Action{ - Type: aws.String(a.Type), - TargetGroupArn: aws.String(a.TargetGroupArn), - }) + rule.Actions = append(rule.Actions, listenerActionToSDK(a)) } return rule } diff --git a/spinifex/handlers/elbv2/service_impl_rules_extra_test.go b/spinifex/handlers/elbv2/service_impl_rules_extra_test.go index 3a1ba79ae..1f8c03f21 100644 --- a/spinifex/handlers/elbv2/service_impl_rules_extra_test.go +++ b/spinifex/handlers/elbv2/service_impl_rules_extra_test.go @@ -87,9 +87,10 @@ func TestDeleteRule_InputValidation(t *testing.T) { require.Error(t, err) assert.Contains(t, err.Error(), "MissingParameter") - _, err = env.svc.DeleteRule(&elbv2.DeleteRuleInput{RuleArn: aws.String("arn:none")}, testAccountID) - require.Error(t, err) - assert.Contains(t, err.Error(), "RuleNotFound") + // AWS ELBv2 delete is idempotent: absent rule -> success, not NotFound. + out, err := env.svc.DeleteRule(&elbv2.DeleteRuleInput{RuleArn: aws.String("arn:none")}, testAccountID) + require.NoError(t, err) + assert.NotNil(t, out) } func TestDescribeRules_InputValidation(t *testing.T) { @@ -377,11 +378,23 @@ func TestHAProxyRender_UnsupportedField(t *testing.T) { require.Error(t, err) } -func TestBuildHAProxyRule_RejectsNonForward(t *testing.T) { - _, err := buildHAProxyRule(&RuleRecord{ +func TestBuildHAProxyRule_RoutesToBackend(t *testing.T) { + rule, err := buildHAProxyRule(&RuleRecord{ + RuleID: "r1", + Conditions: []RuleCondition{{Field: RuleFieldPathPattern, Values: []string{"/a"}}}, + }, "bk_target") + require.NoError(t, err) + assert.Equal(t, "bk_target", rule.Backend) +} + +func TestRegisterRuleBackend_RejectsUnknownAction(t *testing.T) { + noopBackend := func(string) {} + noopFixed := func(string, *FixedResponseAction) {} + noopRedirect := func(string, *HAProxyRedirect) {} + _, err := registerRuleBackend(&RuleRecord{ RuleID: "r1", - Actions: []ListenerAction{{Type: "redirect"}}, - }) + Actions: []ListenerAction{{Type: "authenticate-cognito"}}, + }, &ListenerRecord{Protocol: ProtocolHTTP}, noopBackend, noopFixed, noopRedirect) require.Error(t, err) } diff --git a/spinifex/handlers/elbv2/service_impl_rules_test.go b/spinifex/handlers/elbv2/service_impl_rules_test.go index 384d5951f..4bc334d7a 100644 --- a/spinifex/handlers/elbv2/service_impl_rules_test.go +++ b/spinifex/handlers/elbv2/service_impl_rules_test.go @@ -70,6 +70,46 @@ func TestCreateRule_PathPattern(t *testing.T) { assert.Contains(t, *out.Rules[0].RuleArn, ":listener-rule/") } +// TestDeleteLoadBalancer_CascadesRuleDeletion is a regression guard: +// DeleteLoadBalancer must cascade through listener rule deletion. Previously it +// called store.DeleteListener directly, bypassing the rule cascade, so a rule's +// target group stayed pinned as ResourceInUse and was permanently undeletable. +func TestDeleteLoadBalancer_CascadesRuleDeletion(t *testing.T) { + env := newRuleTestEnv(t, "del-cascade") + + // Rule on the listener forwards to the alt TG. + _, err := env.svc.CreateRule(&elbv2.CreateRuleInput{ + ListenerArn: aws.String(env.listenerArn), + Priority: aws.Int64(10), + Conditions: []*elbv2.RuleCondition{{Field: aws.String("path-pattern"), Values: aws.StringSlice([]string{"/api/*"})}}, + Actions: []*elbv2.Action{{Type: aws.String("forward"), TargetGroupArn: aws.String(env.tgAltArn)}}, + }, testAccountID) + require.NoError(t, err) + + // Tear down the LB. + _, err = env.svc.DeleteLoadBalancer(&elbv2.DeleteLoadBalancerInput{ + LoadBalancerArn: aws.String(env.lbArn), + }, testAccountID) + require.NoError(t, err) + + // LB deletion must cascade rule deletion — no rule may survive. + rules, err := env.svc.store.ListRules() + require.NoError(t, err) + assert.Empty(t, rules, "LB deletion must cascade rule deletion") + + // Both target groups must now be deletable: neither an orphan rule nor a + // stale listener default action may pin them as ResourceInUse. + _, err = env.svc.DeleteTargetGroup(&elbv2.DeleteTargetGroupInput{ + TargetGroupArn: aws.String(env.tgAltArn), + }, testAccountID) + require.NoError(t, err, "rule target group must not be pinned after LB deletion") + + _, err = env.svc.DeleteTargetGroup(&elbv2.DeleteTargetGroupInput{ + TargetGroupArn: aws.String(env.tgArn), + }, testAccountID) + require.NoError(t, err, "listener default-action target group must not be pinned after LB deletion") +} + func TestCreateRule_PriorityInUse(t *testing.T) { env := newRuleTestEnv(t, "cr-pri") @@ -107,14 +147,75 @@ func TestCreateRule_InvalidPriority(t *testing.T) { } } -func TestCreateRule_RejectsRedirect(t *testing.T) { +func TestCreateRule_RedirectAction(t *testing.T) { + env := newRuleTestEnv(t, "cr-redir") + + out, err := env.svc.CreateRule(&elbv2.CreateRuleInput{ + ListenerArn: aws.String(env.listenerArn), + Priority: aws.Int64(1), + Conditions: []*elbv2.RuleCondition{{Field: aws.String("path-pattern"), Values: aws.StringSlice([]string{"/old/*"})}}, + Actions: []*elbv2.Action{{ + Type: aws.String("redirect"), + RedirectConfig: &elbv2.RedirectActionConfig{ + Protocol: aws.String("HTTPS"), + StatusCode: aws.String("HTTP_301"), + }, + }}, + }, testAccountID) + require.NoError(t, err) + require.Len(t, out.Rules, 1) + require.Len(t, out.Rules[0].Actions, 1) + assert.Equal(t, "redirect", *out.Rules[0].Actions[0].Type) + require.NotNil(t, out.Rules[0].Actions[0].RedirectConfig) + assert.Equal(t, "HTTP_301", *out.Rules[0].Actions[0].RedirectConfig.StatusCode) +} + +func TestCreateRule_FixedResponseAction(t *testing.T) { + env := newRuleTestEnv(t, "cr-fixed") + + out, err := env.svc.CreateRule(&elbv2.CreateRuleInput{ + ListenerArn: aws.String(env.listenerArn), + Priority: aws.Int64(1), + Conditions: []*elbv2.RuleCondition{{Field: aws.String("path-pattern"), Values: aws.StringSlice([]string{"/down"})}}, + Actions: []*elbv2.Action{{ + Type: aws.String("fixed-response"), + FixedResponseConfig: &elbv2.FixedResponseActionConfig{ + StatusCode: aws.String("503"), + ContentType: aws.String("text/plain"), + MessageBody: aws.String("maintenance"), + }, + }}, + }, testAccountID) + require.NoError(t, err) + require.Len(t, out.Rules, 1) + assert.Equal(t, "fixed-response", *out.Rules[0].Actions[0].Type) + require.NotNil(t, out.Rules[0].Actions[0].FixedResponseConfig) +} + +func TestCreateRule_RejectsBadRedirectStatus(t *testing.T) { + env := newRuleTestEnv(t, "cr-badredir") + + _, err := env.svc.CreateRule(&elbv2.CreateRuleInput{ + ListenerArn: aws.String(env.listenerArn), + Priority: aws.Int64(1), + Conditions: []*elbv2.RuleCondition{{Field: aws.String("path-pattern"), Values: aws.StringSlice([]string{"/a"})}}, + Actions: []*elbv2.Action{{ + Type: aws.String("redirect"), + RedirectConfig: &elbv2.RedirectActionConfig{StatusCode: aws.String("HTTP_418")}, + }}, + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), "InvalidParameterValue") +} + +func TestCreateRule_RejectsUnknownAction(t *testing.T) { env := newRuleTestEnv(t, "cr-rej") _, err := env.svc.CreateRule(&elbv2.CreateRuleInput{ ListenerArn: aws.String(env.listenerArn), Priority: aws.Int64(1), Conditions: []*elbv2.RuleCondition{{Field: aws.String("path-pattern"), Values: aws.StringSlice([]string{"/a"})}}, - Actions: []*elbv2.Action{{Type: aws.String("redirect")}}, + Actions: []*elbv2.Action{{Type: aws.String("authenticate-cognito")}}, }, testAccountID) require.Error(t, err) assert.Contains(t, err.Error(), "InvalidConfigurationRequest") diff --git a/spinifex/handlers/elbv2/service_impl_tags.go b/spinifex/handlers/elbv2/service_impl_tags.go new file mode 100644 index 000000000..5238397d2 --- /dev/null +++ b/spinifex/handlers/elbv2/service_impl_tags.go @@ -0,0 +1,185 @@ +package handlers_elbv2 + +import ( + "errors" + "log/slog" + "maps" + + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/awserrors" +) + +// taggable bundles a resource's current tags with a persist closure so the +// AddTags/RemoveTags mutation logic is identical across resource types. +type taggable struct { + tags map[string]string + owner string + save func(map[string]string) error +} + +// resolveTaggable loads the ELBv2 resource named by arn and returns a handle for +// reading and persisting its tags. found is false when the resource doesn't +// exist; notFoundError carries the per-type API error for that case. Store +// failures are logged and returned as ErrorServerInternal. +func (s *ELBv2ServiceImpl) resolveTaggable(arn string) (h taggable, notFoundError string, found bool, err error) { + resourceType, terr := elbv2ResourceTypeFromArn(arn) + if terr != nil { + return taggable{}, "", false, terr + } + + switch resourceType { + case elbv2ResourceLoadBalancer: + notFoundError = awserrors.ErrorELBv2LoadBalancerNotFound + lb, e := s.store.GetLoadBalancerByArn(arn) + if e != nil { + slog.Error("resolveTaggable: failed to get LB", "arn", arn, "err", e) + return taggable{}, notFoundError, false, errors.New(awserrors.ErrorServerInternal) + } + if lb != nil { + found = true + h = taggable{tags: lb.Tags, owner: lb.AccountID, save: func(t map[string]string) error { + lb.Tags = t + return s.store.PutLoadBalancer(lb) + }} + } + case elbv2ResourceTargetGroup: + notFoundError = awserrors.ErrorELBv2TargetGroupNotFound + tg, e := s.store.GetTargetGroupByArn(arn) + if e != nil { + slog.Error("resolveTaggable: failed to get target group", "arn", arn, "err", e) + return taggable{}, notFoundError, false, errors.New(awserrors.ErrorServerInternal) + } + if tg != nil { + found = true + h = taggable{tags: tg.Tags, owner: tg.AccountID, save: func(t map[string]string) error { + tg.Tags = t + return s.store.PutTargetGroup(tg) + }} + } + case elbv2ResourceListener: + notFoundError = awserrors.ErrorELBv2ListenerNotFound + l, e := s.store.GetListenerByArn(arn) + if e != nil { + slog.Error("resolveTaggable: failed to get listener", "arn", arn, "err", e) + return taggable{}, notFoundError, false, errors.New(awserrors.ErrorServerInternal) + } + if l != nil { + found = true + h = taggable{tags: l.Tags, owner: l.AccountID, save: func(t map[string]string) error { + l.Tags = t + return s.store.PutListener(l) + }} + } + case elbv2ResourceListenerRule: + notFoundError = awserrors.ErrorELBv2RuleNotFound + r, e := s.store.GetRuleByArn(arn) + if e != nil { + slog.Error("resolveTaggable: failed to get rule", "arn", arn, "err", e) + return taggable{}, notFoundError, false, errors.New(awserrors.ErrorServerInternal) + } + if r != nil { + found = true + h = taggable{tags: r.Tags, owner: r.AccountID, save: func(t map[string]string) error { + r.Tags = t + return s.store.PutRule(r) + }} + } + } + + return h, notFoundError, found, nil +} + +// AddTags adds or overwrites tags on one or more ELBv2 resources. Tags are +// validated up-front so a malformed key can't leave a partial apply spanning +// the ResourceArns. Cross-account or unknown ARNs yield the per-resource +// not-found error. +func (s *ELBv2ServiceImpl) AddTags(input *elbv2.AddTagsInput, accountID string) (*elbv2.AddTagsOutput, error) { + if input == nil || len(input.ResourceArns) == 0 || len(input.Tags) == 0 { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + + newTags := make(map[string]string, len(input.Tags)) + for _, t := range input.Tags { + if t == nil || t.Key == nil || *t.Key == "" { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + v := "" + if t.Value != nil { + v = *t.Value + } + newTags[*t.Key] = v + } + + for _, arnPtr := range input.ResourceArns { + if arnPtr == nil || *arnPtr == "" { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + arn := *arnPtr + + h, notFoundError, found, err := s.resolveTaggable(arn) + if err != nil { + return nil, err + } + if !found || h.owner != accountID { + return nil, errors.New(notFoundError) + } + + merged := h.tags + if merged == nil { + merged = make(map[string]string, len(newTags)) + } + maps.Copy(merged, newTags) + if err := h.save(merged); err != nil { + slog.Error("AddTags: failed to persist", "arn", arn, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } + } + + return &elbv2.AddTagsOutput{}, nil +} + +// RemoveTags removes the named tag keys from one or more ELBv2 resources. +// Removal is idempotent — keys absent from a resource are silently ignored, +// matching AWS. Cross-account or unknown ARNs yield the per-resource not-found +// error. +func (s *ELBv2ServiceImpl) RemoveTags(input *elbv2.RemoveTagsInput, accountID string) (*elbv2.RemoveTagsOutput, error) { + if input == nil || len(input.ResourceArns) == 0 || len(input.TagKeys) == 0 { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + + keys := make([]string, 0, len(input.TagKeys)) + for _, k := range input.TagKeys { + if k == nil || *k == "" { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + keys = append(keys, *k) + } + + for _, arnPtr := range input.ResourceArns { + if arnPtr == nil || *arnPtr == "" { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + arn := *arnPtr + + h, notFoundError, found, err := s.resolveTaggable(arn) + if err != nil { + return nil, err + } + if !found || h.owner != accountID { + return nil, errors.New(notFoundError) + } + + if len(h.tags) == 0 { + continue + } + for _, k := range keys { + delete(h.tags, k) + } + if err := h.save(h.tags); err != nil { + slog.Error("RemoveTags: failed to persist", "arn", arn, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } + } + + return &elbv2.RemoveTagsOutput{}, nil +} diff --git a/spinifex/handlers/elbv2/service_impl_tags_test.go b/spinifex/handlers/elbv2/service_impl_tags_test.go new file mode 100644 index 000000000..bd54509e6 --- /dev/null +++ b/spinifex/handlers/elbv2/service_impl_tags_test.go @@ -0,0 +1,200 @@ +package handlers_elbv2 + +import ( + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/awserrors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// tagsFor is a small helper that reads back a resource's tags via DescribeTags +// as a plain map for assertions. +func tagsFor(t *testing.T, svc *ELBv2ServiceImpl, arn string) map[string]string { + t.Helper() + out, err := svc.DescribeTags(&elbv2.DescribeTagsInput{ResourceArns: []*string{aws.String(arn)}}, testAccountID) + require.NoError(t, err) + require.Len(t, out.TagDescriptions, 1) + m := make(map[string]string) + for _, tag := range out.TagDescriptions[0].Tags { + m[*tag.Key] = *tag.Value + } + return m +} + +func TestAddTags_LoadBalancer(t *testing.T) { + svc := setupTestService(t) + lbOut, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{ + Name: aws.String("addtags-lb"), + Tags: []*elbv2.Tag{{Key: aws.String("Env"), Value: aws.String("dev")}}, + }, testAccountID) + require.NoError(t, err) + arn := *lbOut.LoadBalancers[0].LoadBalancerArn + + _, err = svc.AddTags(&elbv2.AddTagsInput{ + ResourceArns: []*string{aws.String(arn)}, + Tags: []*elbv2.Tag{ + {Key: aws.String("App"), Value: aws.String("nginx")}, + {Key: aws.String("Env"), Value: aws.String("prod")}, // overwrite + }, + }, testAccountID) + require.NoError(t, err) + + assert.Equal(t, map[string]string{"App": "nginx", "Env": "prod"}, tagsFor(t, svc, arn)) +} + +func TestAddTags_Listener(t *testing.T) { + svc := setupTestService(t) + lbOut, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("addtags-lst-lb")}, testAccountID) + tgOut, _ := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("addtags-lst-tg")}, testAccountID) + lstOut, err := svc.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: lbOut.LoadBalancers[0].LoadBalancerArn, + Protocol: aws.String("HTTP"), + Port: aws.Int64(80), + DefaultActions: []*elbv2.Action{ + {Type: aws.String("forward"), TargetGroupArn: tgOut.TargetGroups[0].TargetGroupArn}, + }, + }, testAccountID) + require.NoError(t, err) + arn := *lstOut.Listeners[0].ListenerArn + + _, err = svc.AddTags(&elbv2.AddTagsInput{ + ResourceArns: []*string{aws.String(arn)}, + Tags: []*elbv2.Tag{{Key: aws.String("team"), Value: aws.String("platform")}}, + }, testAccountID) + require.NoError(t, err) + + assert.Equal(t, map[string]string{"team": "platform"}, tagsFor(t, svc, arn)) +} + +func TestAddTags_CreateTimeTagsPreserved(t *testing.T) { + svc := setupTestService(t) + lbOut, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("addtags-tg-lb")}, testAccountID) + tgOut, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{ + Name: aws.String("addtags-tg"), + Tags: []*elbv2.Tag{{Key: aws.String("owner"), Value: aws.String("alice")}}, + }, testAccountID) + require.NoError(t, err) + _ = lbOut + arn := *tgOut.TargetGroups[0].TargetGroupArn + + _, err = svc.AddTags(&elbv2.AddTagsInput{ + ResourceArns: []*string{aws.String(arn)}, + Tags: []*elbv2.Tag{{Key: aws.String("cost-center"), Value: aws.String("42")}}, + }, testAccountID) + require.NoError(t, err) + + assert.Equal(t, map[string]string{"owner": "alice", "cost-center": "42"}, tagsFor(t, svc, arn)) +} + +func TestAddTags_NotFound(t *testing.T) { + svc := setupTestService(t) + _, err := svc.AddTags(&elbv2.AddTagsInput{ + ResourceArns: []*string{aws.String("arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/missing/lb-deadbeef")}, + Tags: []*elbv2.Tag{{Key: aws.String("k"), Value: aws.String("v")}}, + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorELBv2LoadBalancerNotFound) +} + +func TestAddTags_CrossAccount(t *testing.T) { + svc := setupTestService(t) + lbOut, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("addtags-xacct")}, testAccountID) + arn := *lbOut.LoadBalancers[0].LoadBalancerArn + + _, err := svc.AddTags(&elbv2.AddTagsInput{ + ResourceArns: []*string{aws.String(arn)}, + Tags: []*elbv2.Tag{{Key: aws.String("k"), Value: aws.String("v")}}, + }, "999999999999") + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorELBv2LoadBalancerNotFound) + + // Owner's tags untouched. + assert.Empty(t, tagsFor(t, svc, arn)) +} + +func TestAddTags_MissingParams(t *testing.T) { + svc := setupTestService(t) + lbOut, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("addtags-mp")}, testAccountID) + arn := lbOut.LoadBalancers[0].LoadBalancerArn + + _, err := svc.AddTags(&elbv2.AddTagsInput{ResourceArns: []*string{arn}}, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorMissingParameter) + + _, err = svc.AddTags(&elbv2.AddTagsInput{Tags: []*elbv2.Tag{{Key: aws.String("k"), Value: aws.String("v")}}}, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorMissingParameter) +} + +func TestAddTags_EmptyKeyRejected(t *testing.T) { + svc := setupTestService(t) + lbOut, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("addtags-ek")}, testAccountID) + arn := lbOut.LoadBalancers[0].LoadBalancerArn + + _, err := svc.AddTags(&elbv2.AddTagsInput{ + ResourceArns: []*string{arn}, + Tags: []*elbv2.Tag{{Key: aws.String(""), Value: aws.String("v")}}, + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorInvalidParameterValue) +} + +func TestRemoveTags_LoadBalancer(t *testing.T) { + svc := setupTestService(t) + lbOut, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{ + Name: aws.String("rmtags-lb"), + Tags: []*elbv2.Tag{ + {Key: aws.String("App"), Value: aws.String("nginx")}, + {Key: aws.String("Env"), Value: aws.String("prod")}, + }, + }, testAccountID) + arn := *lbOut.LoadBalancers[0].LoadBalancerArn + + _, err := svc.RemoveTags(&elbv2.RemoveTagsInput{ + ResourceArns: []*string{aws.String(arn)}, + TagKeys: []*string{aws.String("Env")}, + }, testAccountID) + require.NoError(t, err) + + assert.Equal(t, map[string]string{"App": "nginx"}, tagsFor(t, svc, arn)) +} + +func TestRemoveTags_Idempotent(t *testing.T) { + svc := setupTestService(t) + lbOut, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{ + Name: aws.String("rmtags-idem"), + Tags: []*elbv2.Tag{{Key: aws.String("App"), Value: aws.String("nginx")}}, + }, testAccountID) + arn := *lbOut.LoadBalancers[0].LoadBalancerArn + + // Removing an absent key is a no-op, not an error. + _, err := svc.RemoveTags(&elbv2.RemoveTagsInput{ + ResourceArns: []*string{aws.String(arn)}, + TagKeys: []*string{aws.String("DoesNotExist")}, + }, testAccountID) + require.NoError(t, err) + assert.Equal(t, map[string]string{"App": "nginx"}, tagsFor(t, svc, arn)) +} + +func TestRemoveTags_NotFound(t *testing.T) { + svc := setupTestService(t) + _, err := svc.RemoveTags(&elbv2.RemoveTagsInput{ + ResourceArns: []*string{aws.String("arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/missing/tg-deadbeef")}, + TagKeys: []*string{aws.String("k")}, + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorELBv2TargetGroupNotFound) +} + +func TestRemoveTags_MissingParams(t *testing.T) { + svc := setupTestService(t) + lbOut, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("rmtags-mp")}, testAccountID) + arn := lbOut.LoadBalancers[0].LoadBalancerArn + + _, err := svc.RemoveTags(&elbv2.RemoveTagsInput{ResourceArns: []*string{arn}}, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorMissingParameter) +} diff --git a/spinifex/handlers/elbv2/service_impl_test.go b/spinifex/handlers/elbv2/service_impl_test.go index 968b86a65..3ffbbe7cf 100644 --- a/spinifex/handlers/elbv2/service_impl_test.go +++ b/spinifex/handlers/elbv2/service_impl_test.go @@ -142,7 +142,7 @@ func TestCreateLoadBalancer_NetworkType_RejectsSecurityGroups(t *testing.T) { assert.Contains(t, err.Error(), "InvalidConfigurationRequest") } -func TestCreateLoadBalancer_CrossZoneAttributes(t *testing.T) { +func TestCreateLoadBalancer_NLBCrossZoneAttribute(t *testing.T) { svc := setupTestService(t) // NLB: no stored attributes, Describe should return default cross-zone=false. @@ -164,6 +164,10 @@ func TestCreateLoadBalancer_CrossZoneAttributes(t *testing.T) { nlbAttrs[*a.Key] = *a.Value } assert.Equal(t, "false", nlbAttrs["load_balancing.cross_zone.enabled"]) +} + +func TestCreateLoadBalancer_ALBCrossZoneAttribute(t *testing.T) { + svc := setupTestService(t) // ALB: no stored attributes either, Describe should return default cross-zone=true. albOut, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{ @@ -229,15 +233,16 @@ func TestDeleteLoadBalancer(t *testing.T) { assert.Empty(t, desc.LoadBalancers) } -func TestDeleteLoadBalancer_NotFound(t *testing.T) { +func TestDeleteLoadBalancer_IdempotentOnAbsent(t *testing.T) { svc := setupTestService(t) - _, err := svc.DeleteLoadBalancer(&elbv2.DeleteLoadBalancerInput{ + out, err := svc.DeleteLoadBalancer(&elbv2.DeleteLoadBalancerInput{ LoadBalancerArn: aws.String("arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/nope/xyz"), }, testAccountID) - assert.Error(t, err) - assert.Contains(t, err.Error(), "LoadBalancerNotFound") + // AWS ELBv2 delete is idempotent: absent LB -> success, not NotFound. + require.NoError(t, err) + assert.NotNil(t, out) } func TestDeleteLoadBalancer_CleansUpListeners(t *testing.T) { @@ -696,14 +701,15 @@ func TestDeleteTargetGroup_InUse(t *testing.T) { assert.Contains(t, err.Error(), "ResourceInUse") } -func TestDeleteTargetGroup_NotFound(t *testing.T) { +func TestDeleteTargetGroup_IdempotentOnAbsent(t *testing.T) { svc := setupTestService(t) - _, err := svc.DeleteTargetGroup(&elbv2.DeleteTargetGroupInput{ + out, err := svc.DeleteTargetGroup(&elbv2.DeleteTargetGroupInput{ TargetGroupArn: aws.String("arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/nope/xyz"), }, testAccountID) - assert.Error(t, err) - assert.Contains(t, err.Error(), "TargetGroupNotFound") + // AWS ELBv2 delete is idempotent: absent TG -> success, not NotFound. + require.NoError(t, err) + assert.NotNil(t, out) } func TestDescribeTargetGroups_FilterByLBArn(t *testing.T) { @@ -763,6 +769,93 @@ func TestRegisterTargets(t *testing.T) { assert.Equal(t, int64(8080), *health.TargetHealthDescriptions[1].Target.Port) } +func TestRegisterTargets_IPType(t *testing.T) { + svc := setupTestService(t) + + tgOut, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{ + Name: aws.String("ip-tg"), + Port: aws.Int64(80), + TargetType: aws.String("ip"), + }, testAccountID) + require.NoError(t, err) + tgArn := tgOut.TargetGroups[0].TargetGroupArn + assert.Equal(t, "ip", *tgOut.TargetGroups[0].TargetType) + + _, err = svc.RegisterTargets(&elbv2.RegisterTargetsInput{ + TargetGroupArn: tgArn, + Targets: []*elbv2.TargetDescription{ + {Id: aws.String("10.0.1.20")}, + {Id: aws.String("10.0.1.21"), Port: aws.Int64(8080)}, + }, + }, testAccountID) + require.NoError(t, err) + + // ip targets must carry the supplied IP as PrivateIP, not an empty + // ENI-resolution result — otherwise HAProxy/health-check silently drop them. + tg, err := svc.store.GetTargetGroupByArn(*tgArn) + require.NoError(t, err) + require.Len(t, tg.Targets, 2) + ipByID := make(map[string]string) + for _, target := range tg.Targets { + ipByID[target.Id] = target.PrivateIP + } + assert.Equal(t, "10.0.1.20", ipByID["10.0.1.20"]) + assert.Equal(t, "10.0.1.21", ipByID["10.0.1.21"]) + + health, err := svc.DescribeTargetHealth(&elbv2.DescribeTargetHealthInput{ + TargetGroupArn: tgArn, + }, testAccountID) + require.NoError(t, err) + require.Len(t, health.TargetHealthDescriptions, 2) +} + +func TestRegisterTargets_IPType_RejectsNonIP(t *testing.T) { + svc := setupTestService(t) + tgOut, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{ + Name: aws.String("ip-tg-bad"), + TargetType: aws.String("ip"), + }, testAccountID) + require.NoError(t, err) + + _, err = svc.RegisterTargets(&elbv2.RegisterTargetsInput{ + TargetGroupArn: tgOut.TargetGroups[0].TargetGroupArn, + Targets: []*elbv2.TargetDescription{{Id: aws.String("i-notanip")}}, + }, testAccountID) + assert.EqualError(t, err, awserrors.ErrorInvalidParameterValue) +} + +func TestRegisterTargets_InstanceType_RejectsIP(t *testing.T) { + svc := setupTestService(t) + tgOut, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{ + Name: aws.String("inst-tg-badid"), + }, testAccountID) + require.NoError(t, err) + + _, err = svc.RegisterTargets(&elbv2.RegisterTargetsInput{ + TargetGroupArn: tgOut.TargetGroups[0].TargetGroupArn, + Targets: []*elbv2.TargetDescription{{Id: aws.String("10.0.0.5")}}, + }, testAccountID) + assert.EqualError(t, err, awserrors.ErrorInvalidParameterValue) +} + +func TestCreateTargetGroup_RejectsUnsupportedTargetType(t *testing.T) { + svc := setupTestService(t) + _, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{ + Name: aws.String("lambda-tg"), + TargetType: aws.String("lambda"), + }, testAccountID) + assert.EqualError(t, err, awserrors.ErrorInvalidParameterValue) +} + +func TestCreateTargetGroup_DefaultsToInstanceType(t *testing.T) { + svc := setupTestService(t) + tgOut, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{ + Name: aws.String("default-tt"), + }, testAccountID) + require.NoError(t, err) + assert.Equal(t, "instance", *tgOut.TargetGroups[0].TargetType) +} + func TestRegisterTargets_Idempotent(t *testing.T) { svc := setupTestService(t) @@ -865,6 +958,127 @@ func TestCreateListener(t *testing.T) { assert.Equal(t, "forward", *l.DefaultActions[0].Type) } +func TestCreateListener_RedirectDefault(t *testing.T) { + svc := setupTestService(t) + + lbOut, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("redir-lb")}, testAccountID) + + out, err := svc.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: lbOut.LoadBalancers[0].LoadBalancerArn, + Protocol: aws.String("HTTP"), + Port: aws.Int64(80), + DefaultActions: []*elbv2.Action{{ + Type: aws.String("redirect"), + RedirectConfig: &elbv2.RedirectActionConfig{ + Protocol: aws.String("HTTPS"), + Port: aws.String("443"), + StatusCode: aws.String("HTTP_301"), + }, + }}, + }, testAccountID) + require.NoError(t, err) + require.Len(t, out.Listeners, 1) + require.Len(t, out.Listeners[0].DefaultActions, 1) + a := out.Listeners[0].DefaultActions[0] + assert.Equal(t, "redirect", *a.Type) + require.NotNil(t, a.RedirectConfig) + assert.Equal(t, "HTTPS", *a.RedirectConfig.Protocol) + assert.Equal(t, "HTTP_301", *a.RedirectConfig.StatusCode) +} + +func TestCreateListener_RedirectFullFields(t *testing.T) { + svc := setupTestService(t) + + lbOut, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("redirfull-lb")}, testAccountID) + + out, err := svc.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: lbOut.LoadBalancers[0].LoadBalancerArn, + Protocol: aws.String("HTTP"), + Port: aws.Int64(80), + DefaultActions: []*elbv2.Action{{ + Type: aws.String("redirect"), + RedirectConfig: &elbv2.RedirectActionConfig{ + Protocol: aws.String("HTTPS"), + Host: aws.String("new.example.com"), + Port: aws.String("8443"), + Path: aws.String("/moved"), + Query: aws.String("ref=1"), + StatusCode: aws.String("HTTP_302"), + }, + }}, + }, testAccountID) + require.NoError(t, err) + + rc := out.Listeners[0].DefaultActions[0].RedirectConfig + require.NotNil(t, rc) + assert.Equal(t, "new.example.com", *rc.Host) + assert.Equal(t, "8443", *rc.Port) + assert.Equal(t, "/moved", *rc.Path) + assert.Equal(t, "ref=1", *rc.Query) + assert.Equal(t, "HTTP_302", *rc.StatusCode) + + // Read back through Describe to exercise the stored→SDK path. + desc, err := svc.DescribeListeners(&elbv2.DescribeListenersInput{ + LoadBalancerArn: lbOut.LoadBalancers[0].LoadBalancerArn, + }, testAccountID) + require.NoError(t, err) + require.Len(t, desc.Listeners, 1) + assert.Equal(t, "new.example.com", *desc.Listeners[0].DefaultActions[0].RedirectConfig.Host) +} + +func TestModifyListener_ToRedirect(t *testing.T) { + svc := setupTestService(t) + + lbOut, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("mod-redir-lb")}, testAccountID) + tgOut, _ := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("mod-redir-tg")}, testAccountID) + + lstOut, err := svc.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: lbOut.LoadBalancers[0].LoadBalancerArn, + Protocol: aws.String("HTTP"), + Port: aws.Int64(80), + DefaultActions: []*elbv2.Action{{Type: aws.String("forward"), TargetGroupArn: tgOut.TargetGroups[0].TargetGroupArn}}, + }, testAccountID) + require.NoError(t, err) + + out, err := svc.ModifyListener(&elbv2.ModifyListenerInput{ + ListenerArn: lstOut.Listeners[0].ListenerArn, + DefaultActions: []*elbv2.Action{{ + Type: aws.String("redirect"), + RedirectConfig: &elbv2.RedirectActionConfig{Protocol: aws.String("HTTPS"), StatusCode: aws.String("HTTP_301")}, + }}, + }, testAccountID) + require.NoError(t, err) + assert.Equal(t, "redirect", *out.Listeners[0].DefaultActions[0].Type) + + // A bad redirect on modify is rejected. + _, err = svc.ModifyListener(&elbv2.ModifyListenerInput{ + ListenerArn: lstOut.Listeners[0].ListenerArn, + DefaultActions: []*elbv2.Action{{ + Type: aws.String("redirect"), + RedirectConfig: &elbv2.RedirectActionConfig{StatusCode: aws.String("HTTP_999")}, + }}, + }, testAccountID) + require.Error(t, err) +} + +func TestCreateListener_RejectsBadRedirect(t *testing.T) { + svc := setupTestService(t) + + lbOut, _ := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("badredir-lb")}, testAccountID) + + _, err := svc.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: lbOut.LoadBalancers[0].LoadBalancerArn, + Protocol: aws.String("HTTP"), + Port: aws.Int64(80), + DefaultActions: []*elbv2.Action{{ + Type: aws.String("redirect"), + RedirectConfig: &elbv2.RedirectActionConfig{StatusCode: aws.String("HTTP_500")}, + }}, + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), "InvalidParameterValue") +} + func TestCreateListener_DuplicatePort(t *testing.T) { svc := setupTestService(t) @@ -924,14 +1138,15 @@ func TestDeleteListener(t *testing.T) { assert.Empty(t, desc.Listeners) } -func TestDeleteListener_NotFound(t *testing.T) { +func TestDeleteListener_IdempotentOnAbsent(t *testing.T) { svc := setupTestService(t) - _, err := svc.DeleteListener(&elbv2.DeleteListenerInput{ + out, err := svc.DeleteListener(&elbv2.DeleteListenerInput{ ListenerArn: aws.String("arn:nonexistent"), }, testAccountID) - assert.Error(t, err) - assert.Contains(t, err.Error(), "ListenerNotFound") + // AWS ELBv2 delete is idempotent: absent listener -> success, not NotFound. + require.NoError(t, err) + assert.NotNil(t, out) } func TestModifyListener_Port(t *testing.T) { @@ -2181,7 +2396,11 @@ func TestDescribeLoadBalancerAttributes_ALBDefaults(t *testing.T) { for _, a := range out.Attributes { attrMap[*a.Key] = *a.Value } - // ALB default cross-zone is true — comes from the per-type default, not seeding. + // Every default key/value must round-trip through Describe, not just + // cross-zone. ALB default cross-zone is true — from the per-type default. + for k, v := range defaults { + assert.Equal(t, v, attrMap[k], "default mismatch for key %s", k) + } assert.Equal(t, "true", attrMap["load_balancing.cross_zone.enabled"]) } @@ -2273,8 +2492,8 @@ func TestDefaultLoadBalancerAttributes_NLBCoversExpectedKeys(t *testing.T) { } // TestModifyLoadBalancerAttributes_AcceptsConnectionLogsKey is a regression -// guard for mulga-931: terraform sends connection_logs.s3.enabled on every -// aws_lb apply and the handler must accept it. +// guard: terraform sends connection_logs.s3.enabled on every aws_lb apply and +// the handler must accept it. func TestModifyLoadBalancerAttributes_AcceptsConnectionLogsKey(t *testing.T) { svc := setupTestService(t) lbOut, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{ @@ -2295,70 +2514,33 @@ func TestModifyLoadBalancerAttributes_AcceptsConnectionLogsKey(t *testing.T) { require.NoError(t, err, "terraform-sent attribute keys must be accepted") } -func TestModifyDescribeTargetGroupAttributes_RoundTrip(t *testing.T) { +// TestModifyLoadBalancerAttributes_EmptyStringClears verifies that a non-nil +// empty-string Value is treated as a real value, not skipped as invalid. AWS +// uses "" to clear access_logs.s3.bucket, so the handler must persist it. +func TestModifyLoadBalancerAttributes_EmptyStringClears(t *testing.T) { svc := setupTestService(t) - tgOut, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-attr-rt")}, testAccountID) + lbOut, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("alb-clear")}, testAccountID) require.NoError(t, err) - arn := tgOut.TargetGroups[0].TargetGroupArn + arn := lbOut.LoadBalancers[0].LoadBalancerArn - modOut, err := svc.ModifyTargetGroupAttributes(&elbv2.ModifyTargetGroupAttributesInput{ - TargetGroupArn: arn, - Attributes: []*elbv2.TargetGroupAttribute{ - {Key: aws.String("deregistration_delay.timeout_seconds"), Value: aws.String("60")}, - {Key: aws.String("stickiness.enabled"), Value: aws.String("true")}, + // Set a bucket, then clear it with an empty string. + _, err = svc.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{ + LoadBalancerArn: arn, + Attributes: []*elbv2.LoadBalancerAttribute{ + {Key: aws.String("access_logs.s3.bucket"), Value: aws.String("my-logs")}, }, }, testAccountID) require.NoError(t, err) - // Assert the exact echoed key/value pairs, not just the length — a regression - // that pointed at the wrong source or dropped Value would pass a length check. - require.Len(t, modOut.Attributes, 2) - modMap := make(map[string]string, len(modOut.Attributes)) - for _, a := range modOut.Attributes { - require.NotNil(t, a.Key) - require.NotNil(t, a.Value) - modMap[*a.Key] = *a.Value - } - assert.Equal(t, "60", modMap["deregistration_delay.timeout_seconds"]) - assert.Equal(t, "true", modMap["stickiness.enabled"]) - - descOut, err := svc.DescribeTargetGroupAttributes(&elbv2.DescribeTargetGroupAttributesInput{ - TargetGroupArn: arn, - }, testAccountID) - require.NoError(t, err) - attrMap := make(map[string]string) - for _, a := range descOut.Attributes { - attrMap[*a.Key] = *a.Value - } - assert.Equal(t, "60", attrMap["deregistration_delay.timeout_seconds"]) - assert.Equal(t, "true", attrMap["stickiness.enabled"]) - // Unmodified defaults should still be present - assert.Equal(t, "lb_cookie", attrMap["stickiness.type"]) -} - -func TestModifyDescribeLoadBalancerAttributes_RoundTrip(t *testing.T) { - svc := setupTestService(t) - lbOut, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-attr-rt")}, testAccountID) - require.NoError(t, err) - arn := lbOut.LoadBalancers[0].LoadBalancerArn modOut, err := svc.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{ LoadBalancerArn: arn, Attributes: []*elbv2.LoadBalancerAttribute{ - {Key: aws.String("idle_timeout.timeout_seconds"), Value: aws.String("120")}, - {Key: aws.String("deletion_protection.enabled"), Value: aws.String("true")}, + {Key: aws.String("access_logs.s3.bucket"), Value: aws.String("")}, }, }, testAccountID) require.NoError(t, err) - // Assert the exact echoed key/value pairs, not just the length. - require.Len(t, modOut.Attributes, 2) - modMap := make(map[string]string, len(modOut.Attributes)) - for _, a := range modOut.Attributes { - require.NotNil(t, a.Key) - require.NotNil(t, a.Value) - modMap[*a.Key] = *a.Value - } - assert.Equal(t, "120", modMap["idle_timeout.timeout_seconds"]) - assert.Equal(t, "true", modMap["deletion_protection.enabled"]) + require.Len(t, modOut.Attributes, 1, "empty-string Value must be echoed, not skipped") + assert.Equal(t, "", *modOut.Attributes[0].Value) descOut, err := svc.DescribeLoadBalancerAttributes(&elbv2.DescribeLoadBalancerAttributesInput{ LoadBalancerArn: arn, @@ -2368,560 +2550,455 @@ func TestModifyDescribeLoadBalancerAttributes_RoundTrip(t *testing.T) { for _, a := range descOut.Attributes { attrMap[*a.Key] = *a.Value } - assert.Equal(t, "120", attrMap["idle_timeout.timeout_seconds"]) - assert.Equal(t, "true", attrMap["deletion_protection.enabled"]) - // Unmodified defaults should still be present - assert.Equal(t, "true", attrMap["routing.http2.enabled"]) + assert.Equal(t, "", attrMap["access_logs.s3.bucket"], "empty-string clear must persist") } -func TestModifyTargetGroupAttributes_NotFound(t *testing.T) { - svc := setupTestService(t) - _, err := svc.ModifyTargetGroupAttributes(&elbv2.ModifyTargetGroupAttributesInput{ - TargetGroupArn: aws.String("arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/missing/tg-missing"), - Attributes: []*elbv2.TargetGroupAttribute{ - {Key: aws.String("stickiness.enabled"), Value: aws.String("true")}, - }, - }, testAccountID) - assert.EqualError(t, err, awserrors.ErrorELBv2TargetGroupNotFound) +// --- Attribute mirror-pair tests (table-driven over TG/LB) --- +// +// ModifyTargetGroupAttributes/ModifyLoadBalancerAttributes (and their Describe +// counterparts) are mirror pairs differing only by record type, store methods, +// default set and not-found error. The behavioural tests below run once per +// kind via t.Run instead of being hand-copied per resource. + +// rawAttr models one submitted SDK attribute, including the invalid shapes a +// handler must skip: a nil slice element, a nil Key, or a nil Value. +type rawAttr struct { + nilElem bool + key *string + val *string } -func TestDescribeTargetGroupAttributes_NotFound(t *testing.T) { - svc := setupTestService(t) - _, err := svc.DescribeTargetGroupAttributes(&elbv2.DescribeTargetGroupAttributesInput{ - TargetGroupArn: aws.String("arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/missing/tg-missing"), - }, testAccountID) - assert.EqualError(t, err, awserrors.ErrorELBv2TargetGroupNotFound) -} +func kvAttr(k, v string) rawAttr { return rawAttr{key: aws.String(k), val: aws.String(v)} } -func TestModifyLoadBalancerAttributes_NotFound(t *testing.T) { - svc := setupTestService(t) - _, err := svc.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{ - LoadBalancerArn: aws.String("arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/missing/lb-missing"), - Attributes: []*elbv2.LoadBalancerAttribute{ - {Key: aws.String("idle_timeout.timeout_seconds"), Value: aws.String("30")}, - }, - }, testAccountID) - assert.EqualError(t, err, awserrors.ErrorELBv2LoadBalancerNotFound) -} - -func TestDescribeLoadBalancerAttributes_NotFound(t *testing.T) { - svc := setupTestService(t) - _, err := svc.DescribeLoadBalancerAttributes(&elbv2.DescribeLoadBalancerAttributesInput{ - LoadBalancerArn: aws.String("arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/missing/lb-missing"), - }, testAccountID) - assert.EqualError(t, err, awserrors.ErrorELBv2LoadBalancerNotFound) -} - -func TestModifyTargetGroupAttributes_MissingArn(t *testing.T) { - svc := setupTestService(t) - _, err := svc.ModifyTargetGroupAttributes(&elbv2.ModifyTargetGroupAttributesInput{ - Attributes: []*elbv2.TargetGroupAttribute{ - {Key: aws.String("stickiness.enabled"), Value: aws.String("true")}, - }, - }, testAccountID) - assert.EqualError(t, err, awserrors.ErrorMissingParameter) -} - -func TestDescribeTargetGroupAttributes_MissingArn(t *testing.T) { - svc := setupTestService(t) - _, err := svc.DescribeTargetGroupAttributes(&elbv2.DescribeTargetGroupAttributesInput{}, testAccountID) - assert.EqualError(t, err, awserrors.ErrorMissingParameter) -} - -func TestModifyLoadBalancerAttributes_MissingArn(t *testing.T) { - svc := setupTestService(t) - _, err := svc.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{ - Attributes: []*elbv2.LoadBalancerAttribute{ - {Key: aws.String("idle_timeout.timeout_seconds"), Value: aws.String("30")}, - }, - }, testAccountID) - assert.EqualError(t, err, awserrors.ErrorMissingParameter) -} - -func TestDescribeLoadBalancerAttributes_MissingArn(t *testing.T) { - svc := setupTestService(t) - _, err := svc.DescribeLoadBalancerAttributes(&elbv2.DescribeLoadBalancerAttributesInput{}, testAccountID) - assert.EqualError(t, err, awserrors.ErrorMissingParameter) -} - -func TestModifyTargetGroupAttributes_WrongAccount(t *testing.T) { - svc := setupTestService(t) - tgOut, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-attr-wrong-acct")}, testAccountID) - require.NoError(t, err) - - _, err = svc.ModifyTargetGroupAttributes(&elbv2.ModifyTargetGroupAttributesInput{ - TargetGroupArn: tgOut.TargetGroups[0].TargetGroupArn, - Attributes: []*elbv2.TargetGroupAttribute{ - {Key: aws.String("stickiness.enabled"), Value: aws.String("true")}, - }, - }, "999999999999") - assert.EqualError(t, err, awserrors.ErrorELBv2TargetGroupNotFound) -} - -func TestDescribeTargetGroupAttributes_WrongAccount(t *testing.T) { - svc := setupTestService(t) - tgOut, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-desc-attr-wrong-acct")}, testAccountID) - require.NoError(t, err) - - _, err = svc.DescribeTargetGroupAttributes(&elbv2.DescribeTargetGroupAttributesInput{ - TargetGroupArn: tgOut.TargetGroups[0].TargetGroupArn, - }, "999999999999") - assert.EqualError(t, err, awserrors.ErrorELBv2TargetGroupNotFound) -} - -func TestModifyLoadBalancerAttributes_WrongAccount(t *testing.T) { - svc := setupTestService(t) - lbOut, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-attr-wrong-acct")}, testAccountID) - require.NoError(t, err) - - _, err = svc.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{ - LoadBalancerArn: lbOut.LoadBalancers[0].LoadBalancerArn, - Attributes: []*elbv2.LoadBalancerAttribute{ - {Key: aws.String("idle_timeout.timeout_seconds"), Value: aws.String("30")}, - }, - }, "999999999999") - assert.EqualError(t, err, awserrors.ErrorELBv2LoadBalancerNotFound) -} - -func TestDescribeLoadBalancerAttributes_WrongAccount(t *testing.T) { - svc := setupTestService(t) - lbOut, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-desc-attr-wrong-acct")}, testAccountID) - require.NoError(t, err) - - _, err = svc.DescribeLoadBalancerAttributes(&elbv2.DescribeLoadBalancerAttributesInput{ - LoadBalancerArn: lbOut.LoadBalancers[0].LoadBalancerArn, - }, "999999999999") - assert.EqualError(t, err, awserrors.ErrorELBv2LoadBalancerNotFound) -} - -// TestModifyTargetGroupAttributes_SkipsInvalidEntries verifies that nil slice -// elements, nil Keys, and nil Values are skipped (with a warning) rather than -// panicking or being silently dropped. Valid attributes in the same call must -// still be applied. -func TestModifyTargetGroupAttributes_SkipsInvalidEntries(t *testing.T) { - svc := setupTestService(t) - tgOut, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-attr-skip")}, testAccountID) - require.NoError(t, err) - arn := tgOut.TargetGroups[0].TargetGroupArn - - modOut, err := svc.ModifyTargetGroupAttributes(&elbv2.ModifyTargetGroupAttributesInput{ - TargetGroupArn: arn, - Attributes: []*elbv2.TargetGroupAttribute{ - nil, // nil element must not panic - {Key: nil, Value: aws.String("v")}, - {Key: aws.String("k"), Value: nil}, - {Key: aws.String("stickiness.enabled"), Value: aws.String("true")}, - }, - }, testAccountID) - require.NoError(t, err) - // Only the one valid attribute should be returned. - require.Len(t, modOut.Attributes, 1) - assert.Equal(t, "stickiness.enabled", *modOut.Attributes[0].Key) - assert.Equal(t, "true", *modOut.Attributes[0].Value) - - // The valid attribute should have been persisted. - descOut, err := svc.DescribeTargetGroupAttributes(&elbv2.DescribeTargetGroupAttributesInput{ - TargetGroupArn: arn, - }, testAccountID) - require.NoError(t, err) - attrMap := make(map[string]string) - for _, a := range descOut.Attributes { - attrMap[*a.Key] = *a.Value +func kvAttrs(kv ...[2]string) []rawAttr { + out := make([]rawAttr, len(kv)) + for i, p := range kv { + out[i] = kvAttr(p[0], p[1]) } - assert.Equal(t, "true", attrMap["stickiness.enabled"]) + return out } -// TestModifyLoadBalancerAttributes_SkipsInvalidEntries mirrors the TG case for -// the LB handler: nil elements and nil Key/Value fields must be skipped, not -// panic or swallow valid attributes in the same request. -func TestModifyLoadBalancerAttributes_SkipsInvalidEntries(t *testing.T) { - svc := setupTestService(t) - lbOut, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-attr-skip")}, testAccountID) - require.NoError(t, err) - arn := lbOut.LoadBalancers[0].LoadBalancerArn +type echoPair struct{ Key, Val string } - modOut, err := svc.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{ - LoadBalancerArn: arn, - Attributes: []*elbv2.LoadBalancerAttribute{ - nil, // nil element must not panic - {Key: nil, Value: aws.String("v")}, - {Key: aws.String("k"), Value: nil}, - {Key: aws.String("idle_timeout.timeout_seconds"), Value: aws.String("75")}, - }, - }, testAccountID) - require.NoError(t, err) - require.Len(t, modOut.Attributes, 1) - assert.Equal(t, "idle_timeout.timeout_seconds", *modOut.Attributes[0].Key) - assert.Equal(t, "75", *modOut.Attributes[0].Value) - - descOut, err := svc.DescribeLoadBalancerAttributes(&elbv2.DescribeLoadBalancerAttributesInput{ - LoadBalancerArn: arn, - }, testAccountID) - require.NoError(t, err) - attrMap := make(map[string]string) - for _, a := range descOut.Attributes { - attrMap[*a.Key] = *a.Value +func echoMap(pairs []echoPair) map[string]string { + m := make(map[string]string, len(pairs)) + for _, p := range pairs { + m[p.Key] = p.Val } - assert.Equal(t, "75", attrMap["idle_timeout.timeout_seconds"]) + return m } -// TestModifyTargetGroupAttributes_AllInvalidReturnsError guards against the -// silent-success case where every submitted attribute trips the nil guard and -// the handler returned 200 OK with an empty response body — the caller would -// think the write landed when nothing was actually applied. -func TestModifyTargetGroupAttributes_AllInvalidReturnsError(t *testing.T) { - svc := setupTestService(t) - tgOut, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-all-invalid")}, testAccountID) - require.NoError(t, err) - - _, err = svc.ModifyTargetGroupAttributes(&elbv2.ModifyTargetGroupAttributesInput{ - TargetGroupArn: tgOut.TargetGroups[0].TargetGroupArn, - Attributes: []*elbv2.TargetGroupAttribute{ - nil, - {Key: nil, Value: aws.String("v")}, - {Key: aws.String("k"), Value: nil}, - }, - }, testAccountID) - assert.EqualError(t, err, awserrors.ErrorInvalidParameterValue) -} - -// TestModifyLoadBalancerAttributes_AllInvalidReturnsError mirrors the TG case. -func TestModifyLoadBalancerAttributes_AllInvalidReturnsError(t *testing.T) { - svc := setupTestService(t) - lbOut, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-all-invalid")}, testAccountID) - require.NoError(t, err) - - _, err = svc.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{ - LoadBalancerArn: lbOut.LoadBalancers[0].LoadBalancerArn, - Attributes: []*elbv2.LoadBalancerAttribute{ - nil, - {Key: nil, Value: aws.String("v")}, - {Key: aws.String("k"), Value: nil}, - }, - }, testAccountID) - assert.EqualError(t, err, awserrors.ErrorInvalidParameterValue) -} - -// TestModifyTargetGroupAttributes_SequentialMerge verifies that successive -// Modify calls accumulate keys instead of replacing the entire attribute map. -// A future refactor that did `tg.Attributes = newMap` would pass every other -// test (single-call round-trip covers the happy path) but silently wipe -// previous attributes on every subsequent Modify — the most likely real-world -// ALB/TG bug. -func TestModifyTargetGroupAttributes_SequentialMerge(t *testing.T) { - svc := setupTestService(t) - tgOut, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-seq-merge")}, testAccountID) - require.NoError(t, err) - arn := tgOut.TargetGroups[0].TargetGroupArn - - // Call 1: set deregistration_delay.timeout_seconds. - _, err = svc.ModifyTargetGroupAttributes(&elbv2.ModifyTargetGroupAttributesInput{ - TargetGroupArn: arn, - Attributes: []*elbv2.TargetGroupAttribute{ - {Key: aws.String("deregistration_delay.timeout_seconds"), Value: aws.String("45")}, - }, - }, testAccountID) - require.NoError(t, err) - - // Call 2: set a different key; must not wipe the first one. - _, err = svc.ModifyTargetGroupAttributes(&elbv2.ModifyTargetGroupAttributesInput{ - TargetGroupArn: arn, - Attributes: []*elbv2.TargetGroupAttribute{ - {Key: aws.String("stickiness.enabled"), Value: aws.String("true")}, - }, - }, testAccountID) - require.NoError(t, err) - - descOut, err := svc.DescribeTargetGroupAttributes(&elbv2.DescribeTargetGroupAttributesInput{ - TargetGroupArn: arn, - }, testAccountID) - require.NoError(t, err) - attrMap := make(map[string]string) - for _, a := range descOut.Attributes { - attrMap[*a.Key] = *a.Value +// attrArnPtr returns nil for an empty ARN so the MissingArn cases exercise the +// real "no ARN supplied" path rather than an empty-string ARN. +func attrArnPtr(arn string) *string { + if arn == "" { + return nil } - assert.Equal(t, "45", attrMap["deregistration_delay.timeout_seconds"], "first-call key must survive second Modify") - assert.Equal(t, "true", attrMap["stickiness.enabled"], "second-call key must be present") - - // Call 3: overwrite the same key with a new value. - _, err = svc.ModifyTargetGroupAttributes(&elbv2.ModifyTargetGroupAttributesInput{ - TargetGroupArn: arn, - Attributes: []*elbv2.TargetGroupAttribute{ - {Key: aws.String("stickiness.enabled"), Value: aws.String("false")}, - }, - }, testAccountID) - require.NoError(t, err) - - descOut, err = svc.DescribeTargetGroupAttributes(&elbv2.DescribeTargetGroupAttributesInput{ - TargetGroupArn: arn, - }, testAccountID) - require.NoError(t, err) - attrMap = make(map[string]string) - for _, a := range descOut.Attributes { - attrMap[*a.Key] = *a.Value - } - assert.Equal(t, "false", attrMap["stickiness.enabled"], "same-key overwrite must replace the value") - assert.Equal(t, "45", attrMap["deregistration_delay.timeout_seconds"], "unrelated key must still survive") + return aws.String(arn) } -// TestModifyLoadBalancerAttributes_SequentialMerge mirrors the TG case. -func TestModifyLoadBalancerAttributes_SequentialMerge(t *testing.T) { - svc := setupTestService(t) - lbOut, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-seq-merge")}, testAccountID) - require.NoError(t, err) - arn := lbOut.LoadBalancers[0].LoadBalancerArn +// attrKind bundles everything the table-driven attribute tests need to drive +// one resource type (target group or load balancer). +type attrKind struct { + name string + notFound string + missingArn string - _, err = svc.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{ - LoadBalancerArn: arn, - Attributes: []*elbv2.LoadBalancerAttribute{ - {Key: aws.String("idle_timeout.timeout_seconds"), Value: aws.String("120")}, - }, - }, testAccountID) - require.NoError(t, err) + keyA, valA, valA2 string // primary key, value, and an overwrite value + keyB, valB string // secondary key/value + defaultKey string // a default present after create + defaultVal string + unknownKey string // a key the handler must reject - _, err = svc.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{ - LoadBalancerArn: arn, - Attributes: []*elbv2.LoadBalancerAttribute{ - {Key: aws.String("deletion_protection.enabled"), Value: aws.String("true")}, - }, - }, testAccountID) - require.NoError(t, err) - - descOut, err := svc.DescribeLoadBalancerAttributes(&elbv2.DescribeLoadBalancerAttributesInput{ - LoadBalancerArn: arn, - }, testAccountID) - require.NoError(t, err) - attrMap := make(map[string]string) - for _, a := range descOut.Attributes { - attrMap[*a.Key] = *a.Value - } - assert.Equal(t, "120", attrMap["idle_timeout.timeout_seconds"], "first-call key must survive second Modify") - assert.Equal(t, "true", attrMap["deletion_protection.enabled"], "second-call key must be present") - - // Same-key overwrite. - _, err = svc.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{ - LoadBalancerArn: arn, - Attributes: []*elbv2.LoadBalancerAttribute{ - {Key: aws.String("idle_timeout.timeout_seconds"), Value: aws.String("90")}, - }, - }, testAccountID) - require.NoError(t, err) - - descOut, err = svc.DescribeLoadBalancerAttributes(&elbv2.DescribeLoadBalancerAttributesInput{ - LoadBalancerArn: arn, - }, testAccountID) - require.NoError(t, err) - attrMap = make(map[string]string) - for _, a := range descOut.Attributes { - attrMap[*a.Key] = *a.Value - } - assert.Equal(t, "90", attrMap["idle_timeout.timeout_seconds"], "same-key overwrite must replace the value") - assert.Equal(t, "true", attrMap["deletion_protection.enabled"], "unrelated key must still survive") + create func(t *testing.T, svc *ELBv2ServiceImpl, name string) string + modify func(svc *ELBv2ServiceImpl, arn, accountID string, attrs []rawAttr) ([]echoPair, error) + describe func(svc *ELBv2ServiceImpl, arn, accountID string) ([]echoPair, error) + revision func(t *testing.T, svc *ELBv2ServiceImpl, arn string) uint64 } -// TestModifyTargetGroupAttributes_NoopSkipsPersist verifies that a -// re-submission of the same attribute values does not bump the underlying KV -// revision — Terraform's drift check hits Modify on every apply, so the -// steady-state path must be a no-op at the storage layer. -func TestModifyTargetGroupAttributes_NoopSkipsPersist(t *testing.T) { - svc := setupTestService(t) - tgOut, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-noop")}, testAccountID) - require.NoError(t, err) - tgArn := tgOut.TargetGroups[0].TargetGroupArn - - // First modify — must hit the store. - _, err = svc.ModifyTargetGroupAttributes(&elbv2.ModifyTargetGroupAttributesInput{ - TargetGroupArn: tgArn, - Attributes: []*elbv2.TargetGroupAttribute{ - {Key: aws.String("stickiness.enabled"), Value: aws.String("true")}, +func attrKinds() []attrKind { + return []attrKind{ + { + name: "TargetGroup", + notFound: awserrors.ErrorELBv2TargetGroupNotFound, + missingArn: "arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/missing/tg-missing", + keyA: "deregistration_delay.timeout_seconds", valA: "45", valA2: "30", + keyB: "stickiness.enabled", valB: "true", + defaultKey: "stickiness.type", defaultVal: "lb_cookie", + unknownKey: "stickness.enabled", // typo of "stickiness" + create: func(t *testing.T, svc *ELBv2ServiceImpl, name string) string { + out, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String(name)}, testAccountID) + require.NoError(t, err) + return *out.TargetGroups[0].TargetGroupArn + }, + modify: func(svc *ELBv2ServiceImpl, arn, accountID string, attrs []rawAttr) ([]echoPair, error) { + sdk := make([]*elbv2.TargetGroupAttribute, len(attrs)) + for i, a := range attrs { + if a.nilElem { + continue + } + sdk[i] = &elbv2.TargetGroupAttribute{Key: a.key, Value: a.val} + } + out, err := svc.ModifyTargetGroupAttributes(&elbv2.ModifyTargetGroupAttributesInput{ + TargetGroupArn: attrArnPtr(arn), Attributes: sdk, + }, accountID) + if err != nil { + return nil, err + } + pairs := make([]echoPair, len(out.Attributes)) + for i, a := range out.Attributes { + pairs[i] = echoPair{*a.Key, *a.Value} + } + return pairs, nil + }, + describe: func(svc *ELBv2ServiceImpl, arn, accountID string) ([]echoPair, error) { + out, err := svc.DescribeTargetGroupAttributes(&elbv2.DescribeTargetGroupAttributesInput{ + TargetGroupArn: attrArnPtr(arn), + }, accountID) + if err != nil { + return nil, err + } + pairs := make([]echoPair, len(out.Attributes)) + for i, a := range out.Attributes { + pairs[i] = echoPair{*a.Key, *a.Value} + } + return pairs, nil + }, + revision: func(t *testing.T, svc *ELBv2ServiceImpl, arn string) uint64 { + tg, err := svc.store.GetTargetGroupByArn(arn) + require.NoError(t, err) + entry, err := svc.store.kv.Get(KeyPrefixTG + tg.TargetGroupID) + require.NoError(t, err) + return entry.Revision() + }, }, - }, testAccountID) - require.NoError(t, err) - - // Capture KV revision after the first write. - tg, err := svc.store.GetTargetGroupByArn(*tgArn) - require.NoError(t, err) - entry, err := svc.store.kv.Get(KeyPrefixTG + tg.TargetGroupID) - require.NoError(t, err) - revBefore := entry.Revision() - - // Second modify with identical values — must skip the Put. - modOut, err := svc.ModifyTargetGroupAttributes(&elbv2.ModifyTargetGroupAttributesInput{ - TargetGroupArn: tgArn, - Attributes: []*elbv2.TargetGroupAttribute{ - {Key: aws.String("stickiness.enabled"), Value: aws.String("true")}, + { + name: "LoadBalancer", + notFound: awserrors.ErrorELBv2LoadBalancerNotFound, + missingArn: "arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/missing/lb-missing", + keyA: "idle_timeout.timeout_seconds", valA: "120", valA2: "90", + keyB: "deletion_protection.enabled", valB: "true", + defaultKey: "routing.http2.enabled", defaultVal: "true", + unknownKey: "stickiness.enabled", // valid TG key — cross-product mistake + create: func(t *testing.T, svc *ELBv2ServiceImpl, name string) string { + out, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String(name)}, testAccountID) + require.NoError(t, err) + return *out.LoadBalancers[0].LoadBalancerArn + }, + modify: func(svc *ELBv2ServiceImpl, arn, accountID string, attrs []rawAttr) ([]echoPair, error) { + sdk := make([]*elbv2.LoadBalancerAttribute, len(attrs)) + for i, a := range attrs { + if a.nilElem { + continue + } + sdk[i] = &elbv2.LoadBalancerAttribute{Key: a.key, Value: a.val} + } + out, err := svc.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{ + LoadBalancerArn: attrArnPtr(arn), Attributes: sdk, + }, accountID) + if err != nil { + return nil, err + } + pairs := make([]echoPair, len(out.Attributes)) + for i, a := range out.Attributes { + pairs[i] = echoPair{*a.Key, *a.Value} + } + return pairs, nil + }, + describe: func(svc *ELBv2ServiceImpl, arn, accountID string) ([]echoPair, error) { + out, err := svc.DescribeLoadBalancerAttributes(&elbv2.DescribeLoadBalancerAttributesInput{ + LoadBalancerArn: attrArnPtr(arn), + }, accountID) + if err != nil { + return nil, err + } + pairs := make([]echoPair, len(out.Attributes)) + for i, a := range out.Attributes { + pairs[i] = echoPair{*a.Key, *a.Value} + } + return pairs, nil + }, + revision: func(t *testing.T, svc *ELBv2ServiceImpl, arn string) uint64 { + lb, err := svc.store.GetLoadBalancerByArn(arn) + require.NoError(t, err) + entry, err := svc.store.kv.Get(KeyPrefixLB + lb.LoadBalancerID) + require.NoError(t, err) + return entry.Revision() + }, }, - }, testAccountID) - require.NoError(t, err) - require.Len(t, modOut.Attributes, 1) - - entry, err = svc.store.kv.Get(KeyPrefixTG + tg.TargetGroupID) - require.NoError(t, err) - assert.Equal(t, revBefore, entry.Revision(), "identical modify must not increment KV revision") - - // Empty attribute list is also a no-op. - _, err = svc.ModifyTargetGroupAttributes(&elbv2.ModifyTargetGroupAttributesInput{ - TargetGroupArn: tgArn, - }, testAccountID) - require.NoError(t, err) - entry, err = svc.store.kv.Get(KeyPrefixTG + tg.TargetGroupID) - require.NoError(t, err) - assert.Equal(t, revBefore, entry.Revision(), "empty modify must not increment KV revision") -} - -// TestModifyLoadBalancerAttributes_NoopSkipsPersist mirrors the TG case. -func TestModifyLoadBalancerAttributes_NoopSkipsPersist(t *testing.T) { - svc := setupTestService(t) - lbOut, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-noop")}, testAccountID) - require.NoError(t, err) - lbArn := lbOut.LoadBalancers[0].LoadBalancerArn - - _, err = svc.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{ - LoadBalancerArn: lbArn, - Attributes: []*elbv2.LoadBalancerAttribute{ - {Key: aws.String("idle_timeout.timeout_seconds"), Value: aws.String("75")}, - }, - }, testAccountID) - require.NoError(t, err) - - lb, err := svc.store.GetLoadBalancerByArn(*lbArn) - require.NoError(t, err) - entry, err := svc.store.kv.Get(KeyPrefixLB + lb.LoadBalancerID) - require.NoError(t, err) - revBefore := entry.Revision() - - _, err = svc.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{ - LoadBalancerArn: lbArn, - Attributes: []*elbv2.LoadBalancerAttribute{ - {Key: aws.String("idle_timeout.timeout_seconds"), Value: aws.String("75")}, - }, - }, testAccountID) - require.NoError(t, err) - - entry, err = svc.store.kv.Get(KeyPrefixLB + lb.LoadBalancerID) - require.NoError(t, err) - assert.Equal(t, revBefore, entry.Revision(), "identical modify must not increment KV revision") -} - -// TestModifyTargetGroupAttributes_RejectsUnknownKey guards against silently -// persisting typo'd or cross-product attribute keys. AWS rejects unknown keys -// with ValidationError; we must match that so Terraform surfaces the typo at -// plan time instead of letting it drift into KV forever. -func TestModifyTargetGroupAttributes_RejectsUnknownKey(t *testing.T) { - svc := setupTestService(t) - tgOut, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-unknown-key")}, testAccountID) - require.NoError(t, err) - - _, err = svc.ModifyTargetGroupAttributes(&elbv2.ModifyTargetGroupAttributesInput{ - TargetGroupArn: tgOut.TargetGroups[0].TargetGroupArn, - Attributes: []*elbv2.TargetGroupAttribute{ - {Key: aws.String("stickness.enabled"), Value: aws.String("true")}, // typo of "stickiness" - }, - }, testAccountID) - assert.EqualError(t, err, awserrors.ErrorValidationError) - - // The rejected key must not have been persisted. - descOut, err := svc.DescribeTargetGroupAttributes(&elbv2.DescribeTargetGroupAttributesInput{ - TargetGroupArn: tgOut.TargetGroups[0].TargetGroupArn, - }, testAccountID) - require.NoError(t, err) - for _, a := range descOut.Attributes { - assert.NotEqual(t, "stickness.enabled", *a.Key, "unknown key must not appear in Describe") } } -// TestModifyLoadBalancerAttributes_RejectsUnknownKey mirrors the TG case. -func TestModifyLoadBalancerAttributes_RejectsUnknownKey(t *testing.T) { - svc := setupTestService(t) - lbOut, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-unknown-key")}, testAccountID) - require.NoError(t, err) +func TestAttributeRoundTrip(t *testing.T) { + for _, k := range attrKinds() { + t.Run(k.name, func(t *testing.T) { + svc := setupTestService(t) + arn := k.create(t, svc, "attr-rt") - _, err = svc.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{ - LoadBalancerArn: lbOut.LoadBalancers[0].LoadBalancerArn, - Attributes: []*elbv2.LoadBalancerAttribute{ - // Valid TG attribute key sent to LB handler — common cross-product mistake. - {Key: aws.String("stickiness.enabled"), Value: aws.String("true")}, - }, - }, testAccountID) - assert.EqualError(t, err, awserrors.ErrorValidationError) -} + // Assert the exact echoed key/value pairs, not just the length — a + // regression that pointed at the wrong source or dropped Value would + // pass a length check. + echoed, err := k.modify(svc, arn, testAccountID, kvAttrs([2]string{k.keyA, k.valA}, [2]string{k.keyB, k.valB})) + require.NoError(t, err) + require.Len(t, echoed, 2) + em := echoMap(echoed) + assert.Equal(t, k.valA, em[k.keyA]) + assert.Equal(t, k.valB, em[k.keyB]) -// TestDescribeTargetGroupAttributes_SortedOrder verifies that attributes are -// returned in a stable, sorted-by-key order. Go map iteration is randomised, -// so without explicit sorting Terraform would see spurious plan diffs between -// back-to-back describe calls. -func TestDescribeTargetGroupAttributes_SortedOrder(t *testing.T) { - svc := setupTestService(t) - tgOut, err := svc.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("tg-attr-sorted")}, testAccountID) - require.NoError(t, err) - arn := tgOut.TargetGroups[0].TargetGroupArn - - // Modify a few attributes to ensure the merged map contains both defaults - // and overrides. - _, err = svc.ModifyTargetGroupAttributes(&elbv2.ModifyTargetGroupAttributesInput{ - TargetGroupArn: arn, - Attributes: []*elbv2.TargetGroupAttribute{ - {Key: aws.String("stickiness.enabled"), Value: aws.String("true")}, - {Key: aws.String("deregistration_delay.timeout_seconds"), Value: aws.String("45")}, - }, - }, testAccountID) - require.NoError(t, err) - - // Call Describe multiple times; each result must be identical and sorted. - var firstKeys []string - for i := range 5 { - descOut, err := svc.DescribeTargetGroupAttributes(&elbv2.DescribeTargetGroupAttributesInput{ - TargetGroupArn: arn, - }, testAccountID) - require.NoError(t, err) - - keys := make([]string, len(descOut.Attributes)) - for j, a := range descOut.Attributes { - keys[j] = *a.Key - } - assert.True(t, sort.StringsAreSorted(keys), "attributes must be sorted by key, got %v", keys) - if i == 0 { - firstKeys = keys - } else { - assert.Equal(t, firstKeys, keys, "attribute order must be stable across calls") - } + desc, err := k.describe(svc, arn, testAccountID) + require.NoError(t, err) + dm := echoMap(desc) + assert.Equal(t, k.valA, dm[k.keyA]) + assert.Equal(t, k.valB, dm[k.keyB]) + // Unmodified defaults should still be present. + assert.Equal(t, k.defaultVal, dm[k.defaultKey]) + }) } } -// TestDescribeLoadBalancerAttributes_SortedOrder mirrors the TG test: LB -// describe responses must be sorted and stable across repeated calls. -func TestDescribeLoadBalancerAttributes_SortedOrder(t *testing.T) { - svc := setupTestService(t) - lbOut, err := svc.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("lb-attr-sorted")}, testAccountID) - require.NoError(t, err) - arn := lbOut.LoadBalancers[0].LoadBalancerArn +func TestAttributeNotFound(t *testing.T) { + for _, k := range attrKinds() { + t.Run(k.name, func(t *testing.T) { + svc := setupTestService(t) - _, err = svc.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{ - LoadBalancerArn: arn, - Attributes: []*elbv2.LoadBalancerAttribute{ - {Key: aws.String("idle_timeout.timeout_seconds"), Value: aws.String("90")}, - {Key: aws.String("deletion_protection.enabled"), Value: aws.String("true")}, - }, - }, testAccountID) - require.NoError(t, err) + _, err := k.modify(svc, k.missingArn, testAccountID, kvAttrs([2]string{k.keyB, k.valB})) + assert.EqualError(t, err, k.notFound) - var firstKeys []string - for i := range 5 { - descOut, err := svc.DescribeLoadBalancerAttributes(&elbv2.DescribeLoadBalancerAttributesInput{ - LoadBalancerArn: arn, - }, testAccountID) - require.NoError(t, err) + _, err = k.describe(svc, k.missingArn, testAccountID) + assert.EqualError(t, err, k.notFound) + }) + } +} - keys := make([]string, len(descOut.Attributes)) - for j, a := range descOut.Attributes { - keys[j] = *a.Key - } - assert.True(t, sort.StringsAreSorted(keys), "attributes must be sorted by key, got %v", keys) - if i == 0 { - firstKeys = keys - } else { - assert.Equal(t, firstKeys, keys, "attribute order must be stable across calls") - } +func TestAttributeMissingArn(t *testing.T) { + for _, k := range attrKinds() { + t.Run(k.name, func(t *testing.T) { + svc := setupTestService(t) + + _, err := k.modify(svc, "", testAccountID, kvAttrs([2]string{k.keyB, k.valB})) + assert.EqualError(t, err, awserrors.ErrorMissingParameter) + + _, err = k.describe(svc, "", testAccountID) + assert.EqualError(t, err, awserrors.ErrorMissingParameter) + }) + } +} + +func TestAttributeWrongAccount(t *testing.T) { + for _, k := range attrKinds() { + t.Run(k.name, func(t *testing.T) { + svc := setupTestService(t) + arn := k.create(t, svc, "attr-wrong-acct") + + _, err := k.modify(svc, arn, "999999999999", kvAttrs([2]string{k.keyB, k.valB})) + assert.EqualError(t, err, k.notFound) + + _, err = k.describe(svc, arn, "999999999999") + assert.EqualError(t, err, k.notFound) + + // The rejected modify must not have mutated the record — read back as + // the real owner and confirm keyB is still at its default, not valB. + desc, err := k.describe(svc, arn, testAccountID) + require.NoError(t, err) + assert.NotEqual(t, k.valB, echoMap(desc)[k.keyB], "wrong-account modify must not mutate the record") + }) + } +} + +// TestAttributeCrossAccountIsolation verifies that two accounts each holding a +// resource never see each other's attributes: a Modify by account A must not be +// visible to a Describe by account B, even for similarly-named resources. +func TestAttributeCrossAccountIsolation(t *testing.T) { + const accountB = "222222222222" + for _, k := range attrKinds() { + t.Run(k.name, func(t *testing.T) { + svcA := setupTestService(t) + arnA := k.create(t, svcA, "attr-iso") + + // Account A sets keyB. + _, err := k.modify(svcA, arnA, testAccountID, kvAttrs([2]string{k.keyB, k.valB})) + require.NoError(t, err) + + // Account B cannot see or describe A's resource at all. + _, err = k.describe(svcA, arnA, accountB) + assert.EqualError(t, err, k.notFound) + _, err = k.modify(svcA, arnA, accountB, kvAttrs([2]string{k.keyB, "false"})) + assert.EqualError(t, err, k.notFound) + + // A's value is untouched. + desc, err := k.describe(svcA, arnA, testAccountID) + require.NoError(t, err) + assert.Equal(t, k.valB, echoMap(desc)[k.keyB]) + }) + } +} + +// TestAttributeSkipsInvalidEntries verifies that nil slice elements, nil Keys, +// and nil Values are skipped (with a warning) rather than panicking or being +// silently dropped. Valid attributes in the same call must still be applied. +func TestAttributeSkipsInvalidEntries(t *testing.T) { + for _, k := range attrKinds() { + t.Run(k.name, func(t *testing.T) { + svc := setupTestService(t) + arn := k.create(t, svc, "attr-skip") + + echoed, err := k.modify(svc, arn, testAccountID, []rawAttr{ + {nilElem: true}, // nil element must not panic + {key: nil, val: aws.String("v")}, + {key: aws.String("k"), val: nil}, + kvAttr(k.keyB, k.valB), + }) + require.NoError(t, err) + // Only the one valid attribute should be returned. + require.Len(t, echoed, 1) + assert.Equal(t, k.keyB, echoed[0].Key) + assert.Equal(t, k.valB, echoed[0].Val) + + // The valid attribute should have been persisted. + desc, err := k.describe(svc, arn, testAccountID) + require.NoError(t, err) + assert.Equal(t, k.valB, echoMap(desc)[k.keyB]) + }) + } +} + +// TestAttributeAllInvalidReturnsError guards against the silent-success case +// where every submitted attribute trips the nil guard and the handler returns +// 200 OK with an empty body — the caller would think the write landed when +// nothing was applied. +func TestAttributeAllInvalidReturnsError(t *testing.T) { + for _, k := range attrKinds() { + t.Run(k.name, func(t *testing.T) { + svc := setupTestService(t) + arn := k.create(t, svc, "attr-all-invalid") + + _, err := k.modify(svc, arn, testAccountID, []rawAttr{ + {nilElem: true}, + {key: nil, val: aws.String("v")}, + {key: aws.String("k"), val: nil}, + }) + assert.EqualError(t, err, awserrors.ErrorInvalidParameterValue) + }) + } +} + +// TestAttributeSequentialMerge verifies that successive Modify calls accumulate +// keys instead of replacing the entire attribute map. A refactor that did +// `rec.Attributes = newMap` would pass every other test (single-call round-trip +// covers the happy path) but silently wipe previous attributes on every +// subsequent Modify — the most likely real-world bug. +func TestAttributeSequentialMerge(t *testing.T) { + for _, k := range attrKinds() { + t.Run(k.name, func(t *testing.T) { + svc := setupTestService(t) + arn := k.create(t, svc, "attr-seq-merge") + + // Call 1: set keyA. + _, err := k.modify(svc, arn, testAccountID, kvAttrs([2]string{k.keyA, k.valA})) + require.NoError(t, err) + // Call 2: set a different key; must not wipe the first. + _, err = k.modify(svc, arn, testAccountID, kvAttrs([2]string{k.keyB, k.valB})) + require.NoError(t, err) + + desc, err := k.describe(svc, arn, testAccountID) + require.NoError(t, err) + dm := echoMap(desc) + assert.Equal(t, k.valA, dm[k.keyA], "first-call key must survive second Modify") + assert.Equal(t, k.valB, dm[k.keyB], "second-call key must be present") + + // Call 3: overwrite keyA with a new value. + _, err = k.modify(svc, arn, testAccountID, kvAttrs([2]string{k.keyA, k.valA2})) + require.NoError(t, err) + + desc, err = k.describe(svc, arn, testAccountID) + require.NoError(t, err) + dm = echoMap(desc) + assert.Equal(t, k.valA2, dm[k.keyA], "same-key overwrite must replace the value") + assert.Equal(t, k.valB, dm[k.keyB], "unrelated key must still survive") + }) + } +} + +// TestAttributeNoopSkipsPersist verifies that re-submitting identical values +// does not bump the KV revision — Terraform's drift check hits Modify on every +// apply, so the steady-state path must be a storage-layer no-op. +func TestAttributeNoopSkipsPersist(t *testing.T) { + for _, k := range attrKinds() { + t.Run(k.name, func(t *testing.T) { + svc := setupTestService(t) + arn := k.create(t, svc, "attr-noop") + + // First modify — must hit the store. + _, err := k.modify(svc, arn, testAccountID, kvAttrs([2]string{k.keyA, k.valA})) + require.NoError(t, err) + revBefore := k.revision(t, svc, arn) + + // Second modify with identical values — must skip the Put. + echoed, err := k.modify(svc, arn, testAccountID, kvAttrs([2]string{k.keyA, k.valA})) + require.NoError(t, err) + require.Len(t, echoed, 1) + assert.Equal(t, revBefore, k.revision(t, svc, arn), "identical modify must not increment KV revision") + + // Empty attribute list is also a no-op. + _, err = k.modify(svc, arn, testAccountID, nil) + require.NoError(t, err) + assert.Equal(t, revBefore, k.revision(t, svc, arn), "empty modify must not increment KV revision") + }) + } +} + +// TestAttributeRejectsUnknownKey guards against silently persisting typo'd or +// cross-product attribute keys. AWS rejects unknown keys with ValidationError; +// we match that so Terraform surfaces the typo at plan time instead of letting +// it drift into KV forever. +func TestAttributeRejectsUnknownKey(t *testing.T) { + for _, k := range attrKinds() { + t.Run(k.name, func(t *testing.T) { + svc := setupTestService(t) + arn := k.create(t, svc, "attr-unknown-key") + + _, err := k.modify(svc, arn, testAccountID, kvAttrs([2]string{k.unknownKey, "true"})) + assert.EqualError(t, err, awserrors.ErrorValidationError) + + // The rejected key must not have been persisted. + desc, err := k.describe(svc, arn, testAccountID) + require.NoError(t, err) + _, present := echoMap(desc)[k.unknownKey] + assert.False(t, present, "unknown key must not appear in Describe") + }) + } +} + +// TestAttributeSortedOrder verifies attributes are returned in a stable, +// sorted-by-key order. Go map iteration is randomised, so without explicit +// sorting Terraform would see spurious plan diffs between describe calls. +func TestAttributeSortedOrder(t *testing.T) { + for _, k := range attrKinds() { + t.Run(k.name, func(t *testing.T) { + svc := setupTestService(t) + arn := k.create(t, svc, "attr-sorted") + + // Modify a couple of attributes so the merged map mixes defaults and + // overrides. + _, err := k.modify(svc, arn, testAccountID, kvAttrs([2]string{k.keyA, k.valA}, [2]string{k.keyB, k.valB})) + require.NoError(t, err) + + var firstKeys []string + for i := range 5 { + desc, err := k.describe(svc, arn, testAccountID) + require.NoError(t, err) + keys := make([]string, len(desc)) + for j, p := range desc { + keys[j] = p.Key + } + assert.True(t, sort.StringsAreSorted(keys), "attributes must be sorted by key, got %v", keys) + if i == 0 { + firstKeys = keys + } else { + assert.Equal(t, firstKeys, keys, "attribute order must be stable across calls") + } + } + }) } } @@ -2968,9 +3045,9 @@ func TestDescribeTags_Listener_NoTags(t *testing.T) { }, testAccountID) require.NoError(t, err) - // Listeners don't store tags yet — must still return a TagDescription - // (with an empty Tags slice), not an error. This is the case the - // Terraform AWS provider hits during post-create refresh. + // Listener created without tags must still return a TagDescription (with an + // empty Tags slice), not an error. This is the case the Terraform AWS + // provider hits during post-create refresh. out, err := svc.DescribeTags(&elbv2.DescribeTagsInput{ ResourceArns: []*string{lstOut.Listeners[0].ListenerArn}, }, testAccountID) @@ -3006,7 +3083,7 @@ func TestDescribeTags_ListenerRule_NoTags(t *testing.T) { }, testAccountID) require.NoError(t, err) - // Rules don't store tags yet — must still return a TagDescription (with an + // Rule created without tags must still return a TagDescription (with an // empty Tags slice), not an error. This is the case the Terraform AWS // provider hits during post-create refresh of aws_lb_listener_rule. out, err := svc.DescribeTags(&elbv2.DescribeTagsInput{ diff --git a/spinifex/handlers/elbv2/service_impl_vpc_test.go b/spinifex/handlers/elbv2/service_impl_vpc_test.go index 652f12227..2e316ed50 100644 --- a/spinifex/handlers/elbv2/service_impl_vpc_test.go +++ b/spinifex/handlers/elbv2/service_impl_vpc_test.go @@ -139,7 +139,7 @@ func TestCreateLoadBalancer_MultipleSubnets(t *testing.T) { // TestCreateLoadBalancer_MultiSubnet_AllENIsPassedToLauncher verifies that // every subnet's ENI is threaded through to SystemInstanceInput, not just -// the first one. Regression guard for mulga-929. +// the first one. func TestCreateLoadBalancer_MultiSubnet_AllENIsPassedToLauncher(t *testing.T) { svc, vpcSvc := setupTestServiceWithVPC(t) diff --git a/spinifex/handlers/elbv2/service_nats.go b/spinifex/handlers/elbv2/service_nats.go index 605ac2fbf..00797d140 100644 --- a/spinifex/handlers/elbv2/service_nats.go +++ b/spinifex/handlers/elbv2/service_nats.go @@ -111,6 +111,14 @@ func (s *NATSELBv2Service) DescribeTags(input *elbv2.DescribeTagsInput, accountI return utils.NATSRequest[elbv2.DescribeTagsOutput](s.natsConn, "elbv2.DescribeTags", input, defaultTimeout, accountID) } +func (s *NATSELBv2Service) AddTags(input *elbv2.AddTagsInput, accountID string) (*elbv2.AddTagsOutput, error) { + return utils.NATSRequest[elbv2.AddTagsOutput](s.natsConn, "elbv2.AddTags", input, defaultTimeout, accountID) +} + +func (s *NATSELBv2Service) RemoveTags(input *elbv2.RemoveTagsInput, accountID string) (*elbv2.RemoveTagsOutput, error) { + return utils.NATSRequest[elbv2.RemoveTagsOutput](s.natsConn, "elbv2.RemoveTags", input, defaultTimeout, accountID) +} + func (s *NATSELBv2Service) ModifyTargetGroupAttributes(input *elbv2.ModifyTargetGroupAttributesInput, accountID string) (*elbv2.ModifyTargetGroupAttributesOutput, error) { return utils.NATSRequest[elbv2.ModifyTargetGroupAttributesOutput](s.natsConn, "elbv2.ModifyTargetGroupAttributes", input, defaultTimeout, accountID) } @@ -127,6 +135,14 @@ func (s *NATSELBv2Service) DescribeLoadBalancerAttributes(input *elbv2.DescribeL return utils.NATSRequest[elbv2.DescribeLoadBalancerAttributesOutput](s.natsConn, "elbv2.DescribeLoadBalancerAttributes", input, defaultTimeout, accountID) } +func (s *NATSELBv2Service) SetSecurityGroups(input *elbv2.SetSecurityGroupsInput, accountID string) (*elbv2.SetSecurityGroupsOutput, error) { + return utils.NATSRequest[elbv2.SetSecurityGroupsOutput](s.natsConn, "elbv2.SetSecurityGroups", input, defaultTimeout, accountID) +} + +func (s *NATSELBv2Service) SetIpAddressType(input *elbv2.SetIpAddressTypeInput, accountID string) (*elbv2.SetIpAddressTypeOutput, error) { + return utils.NATSRequest[elbv2.SetIpAddressTypeOutput](s.natsConn, "elbv2.SetIpAddressType", input, defaultTimeout, accountID) +} + func (s *NATSELBv2Service) LBAgentHeartbeat(input *LBAgentHeartbeatInput, accountID string) (*LBAgentHeartbeatOutput, error) { return utils.NATSRequest[LBAgentHeartbeatOutput](s.natsConn, "elbv2.LBAgentHeartbeat", input, defaultTimeout, accountID) } diff --git a/spinifex/handlers/elbv2/service_nats_e2e_test.go b/spinifex/handlers/elbv2/service_nats_e2e_test.go index 243772e79..604f1ae3c 100644 --- a/spinifex/handlers/elbv2/service_nats_e2e_test.go +++ b/spinifex/handlers/elbv2/service_nats_e2e_test.go @@ -38,6 +38,20 @@ func setupNATSELBv2Test(t *testing.T) (ELBv2Service, *ELBv2ServiceImpl) { "elbv2.DeleteListener": func(msg *nats.Msg) { handleNATSMsg(msg, backend.DeleteListener) }, "elbv2.ModifyListener": func(msg *nats.Msg) { handleNATSMsg(msg, backend.ModifyListener) }, "elbv2.DescribeListeners": func(msg *nats.Msg) { handleNATSMsg(msg, backend.DescribeListeners) }, + "elbv2.CreateRule": func(msg *nats.Msg) { handleNATSMsg(msg, backend.CreateRule) }, + "elbv2.DescribeRules": func(msg *nats.Msg) { handleNATSMsg(msg, backend.DescribeRules) }, + "elbv2.AddTags": func(msg *nats.Msg) { handleNATSMsg(msg, backend.AddTags) }, + "elbv2.RemoveTags": func(msg *nats.Msg) { handleNATSMsg(msg, backend.RemoveTags) }, + "elbv2.DescribeTags": func(msg *nats.Msg) { handleNATSMsg(msg, backend.DescribeTags) }, + "elbv2.SetSecurityGroups": func(msg *nats.Msg) { handleNATSMsg(msg, backend.SetSecurityGroups) }, + "elbv2.SetIpAddressType": func(msg *nats.Msg) { handleNATSMsg(msg, backend.SetIpAddressType) }, + + "elbv2.ModifyTargetGroupAttributes": func(msg *nats.Msg) { handleNATSMsg(msg, backend.ModifyTargetGroupAttributes) }, + "elbv2.DescribeTargetGroupAttributes": func(msg *nats.Msg) { handleNATSMsg(msg, backend.DescribeTargetGroupAttributes) }, + "elbv2.ModifyLoadBalancerAttributes": func(msg *nats.Msg) { handleNATSMsg(msg, backend.ModifyLoadBalancerAttributes) }, + "elbv2.DescribeLoadBalancerAttributes": func(msg *nats.Msg) { + handleNATSMsg(msg, backend.DescribeLoadBalancerAttributes) + }, } for topic, handler := range topics { @@ -281,3 +295,192 @@ func TestNATSE2E_TargetGroupInUseProtection(t *testing.T) { }, testAccountID) require.Error(t, err) } + +func TestNATSE2E_TagsLifecycle(t *testing.T) { + client, _ := setupNATSELBv2Test(t) + + lbOut, err := client.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("e2e-tags-lb")}, testAccountID) + require.NoError(t, err) + lbArn := lbOut.LoadBalancers[0].LoadBalancerArn + + _, err = client.AddTags(&elbv2.AddTagsInput{ + ResourceArns: []*string{lbArn}, + Tags: []*elbv2.Tag{ + {Key: aws.String("App"), Value: aws.String("nginx")}, + {Key: aws.String("Env"), Value: aws.String("prod")}, + }, + }, testAccountID) + require.NoError(t, err) + + desc, err := client.DescribeTags(&elbv2.DescribeTagsInput{ResourceArns: []*string{lbArn}}, testAccountID) + require.NoError(t, err) + require.Len(t, desc.TagDescriptions, 1) + got := map[string]string{} + for _, tag := range desc.TagDescriptions[0].Tags { + got[*tag.Key] = *tag.Value + } + assert.Equal(t, map[string]string{"App": "nginx", "Env": "prod"}, got) + + _, err = client.RemoveTags(&elbv2.RemoveTagsInput{ + ResourceArns: []*string{lbArn}, + TagKeys: []*string{aws.String("Env")}, + }, testAccountID) + require.NoError(t, err) + + desc2, err := client.DescribeTags(&elbv2.DescribeTagsInput{ResourceArns: []*string{lbArn}}, testAccountID) + require.NoError(t, err) + require.Len(t, desc2.TagDescriptions, 1) + got2 := map[string]string{} + for _, tag := range desc2.TagDescriptions[0].Tags { + got2[*tag.Key] = *tag.Value + } + assert.Equal(t, map[string]string{"App": "nginx"}, got2) +} + +func TestNATSE2E_AttributeRoundTrip(t *testing.T) { + client, _ := setupNATSELBv2Test(t) + + tgOut, err := client.CreateTargetGroup(&elbv2.CreateTargetGroupInput{Name: aws.String("e2e-attr-tg")}, testAccountID) + require.NoError(t, err) + tgArn := tgOut.TargetGroups[0].TargetGroupArn + + _, err = client.ModifyTargetGroupAttributes(&elbv2.ModifyTargetGroupAttributesInput{ + TargetGroupArn: tgArn, + Attributes: []*elbv2.TargetGroupAttribute{ + {Key: aws.String("deregistration_delay.timeout_seconds"), Value: aws.String("120")}, + }, + }, testAccountID) + require.NoError(t, err) + + tgAttrs, err := client.DescribeTargetGroupAttributes(&elbv2.DescribeTargetGroupAttributesInput{TargetGroupArn: tgArn}, testAccountID) + require.NoError(t, err) + tgGot := map[string]string{} + for _, a := range tgAttrs.Attributes { + tgGot[*a.Key] = *a.Value + } + assert.Equal(t, "120", tgGot["deregistration_delay.timeout_seconds"]) + + lbOut, err := client.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("e2e-attr-lb")}, testAccountID) + require.NoError(t, err) + lbArn := lbOut.LoadBalancers[0].LoadBalancerArn + + _, err = client.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{ + LoadBalancerArn: lbArn, + Attributes: []*elbv2.LoadBalancerAttribute{ + {Key: aws.String("deletion_protection.enabled"), Value: aws.String("true")}, + }, + }, testAccountID) + require.NoError(t, err) + + lbAttrs, err := client.DescribeLoadBalancerAttributes(&elbv2.DescribeLoadBalancerAttributesInput{LoadBalancerArn: lbArn}, testAccountID) + require.NoError(t, err) + lbGot := map[string]string{} + for _, a := range lbAttrs.Attributes { + lbGot[*a.Key] = *a.Value + } + assert.Equal(t, "true", lbGot["deletion_protection.enabled"]) +} + +func TestNATSE2E_RedirectListener(t *testing.T) { + client, _ := setupNATSELBv2Test(t) + + lbOut, err := client.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{Name: aws.String("e2e-redir-lb")}, testAccountID) + require.NoError(t, err) + lbArn := lbOut.LoadBalancers[0].LoadBalancerArn + + _, err = client.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: lbArn, + Protocol: aws.String("HTTP"), + Port: aws.Int64(80), + DefaultActions: []*elbv2.Action{{ + Type: aws.String("redirect"), + RedirectConfig: &elbv2.RedirectActionConfig{ + Protocol: aws.String("HTTPS"), + Port: aws.String("443"), + StatusCode: aws.String("HTTP_301"), + }, + }}, + }, testAccountID) + require.NoError(t, err) + + desc, err := client.DescribeListeners(&elbv2.DescribeListenersInput{LoadBalancerArn: lbArn}, testAccountID) + require.NoError(t, err) + require.Len(t, desc.Listeners, 1) + require.Len(t, desc.Listeners[0].DefaultActions, 1) + action := desc.Listeners[0].DefaultActions[0] + assert.Equal(t, "redirect", *action.Type) + require.NotNil(t, action.RedirectConfig, "redirect action config must survive the NATS round-trip") + assert.Equal(t, "HTTP_301", *action.RedirectConfig.StatusCode) + assert.Equal(t, "HTTPS", *action.RedirectConfig.Protocol) +} + +func TestNATSE2E_IPTargetType(t *testing.T) { + client, _ := setupNATSELBv2Test(t) + + tgOut, err := client.CreateTargetGroup(&elbv2.CreateTargetGroupInput{ + Name: aws.String("e2e-ip-tg"), + TargetType: aws.String("ip"), + }, testAccountID) + require.NoError(t, err) + require.Equal(t, "ip", *tgOut.TargetGroups[0].TargetType) + tgArn := tgOut.TargetGroups[0].TargetGroupArn + + _, err = client.RegisterTargets(&elbv2.RegisterTargetsInput{ + TargetGroupArn: tgArn, + Targets: []*elbv2.TargetDescription{ + {Id: aws.String("10.0.1.20")}, + {Id: aws.String("10.0.1.21"), Port: aws.Int64(8080)}, + }, + }, testAccountID) + require.NoError(t, err) + + health, err := client.DescribeTargetHealth(&elbv2.DescribeTargetHealthInput{TargetGroupArn: tgArn}, testAccountID) + require.NoError(t, err) + require.Len(t, health.TargetHealthDescriptions, 2) + + // A non-IP id must be rejected for an ip target group, end-to-end. + _, err = client.RegisterTargets(&elbv2.RegisterTargetsInput{ + TargetGroupArn: tgArn, + Targets: []*elbv2.TargetDescription{{Id: aws.String("i-notanip")}}, + }, testAccountID) + require.Error(t, err) +} + +func TestNATSE2E_SetSecurityGroupsAndIpAddressType(t *testing.T) { + client, _ := setupNATSELBv2Test(t) + + lbOut, err := client.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{ + Name: aws.String("e2e-net-lb"), + SecurityGroups: []*string{aws.String("sg-aaa")}, + }, testAccountID) + require.NoError(t, err) + lbArn := lbOut.LoadBalancers[0].LoadBalancerArn + + _, err = client.SetSecurityGroups(&elbv2.SetSecurityGroupsInput{ + LoadBalancerArn: lbArn, + SecurityGroups: []*string{aws.String("sg-bbb"), aws.String("sg-ccc")}, + }, testAccountID) + require.NoError(t, err) + + // Spinifex ALBs are IPv4-only; "ipv4" is the only accepted value. + _, err = client.SetIpAddressType(&elbv2.SetIpAddressTypeInput{ + LoadBalancerArn: lbArn, + IpAddressType: aws.String("ipv4"), + }, testAccountID) + require.NoError(t, err) + + // A dualstack request must be rejected end-to-end. + _, err = client.SetIpAddressType(&elbv2.SetIpAddressTypeInput{ + LoadBalancerArn: lbArn, + IpAddressType: aws.String("dualstack"), + }, testAccountID) + require.Error(t, err) + + desc, err := client.DescribeLoadBalancers(&elbv2.DescribeLoadBalancersInput{ + LoadBalancerArns: []*string{lbArn}, + }, testAccountID) + require.NoError(t, err) + require.Len(t, desc.LoadBalancers, 1) + assert.ElementsMatch(t, []string{"sg-bbb", "sg-ccc"}, aws.StringValueSlice(desc.LoadBalancers[0].SecurityGroups)) + assert.Equal(t, "ipv4", *desc.LoadBalancers[0].IpAddressType) +} diff --git a/spinifex/handlers/elbv2/store.go b/spinifex/handlers/elbv2/store.go index e852dce01..e2c04c012 100644 --- a/spinifex/handlers/elbv2/store.go +++ b/spinifex/handlers/elbv2/store.go @@ -92,9 +92,9 @@ func (s *Store) ListLoadBalancers() ([]*LoadBalancerRecord, error) { } // GetLoadBalancerByArn finds a load balancer by its ARN via a direct KV lookup -// on the short ID embedded in the ARN's final path segment. Falls back to a -// linear scan only if the ARN can't be parsed. Terraform hits Describe*Attributes -// on every plan/refresh so this must be O(1), not O(n). +// on the short ID embedded in the ARN's final path segment. Returns (nil, nil) +// if the ARN can't be parsed or no record matches. Terraform hits +// Describe*Attributes on every plan/refresh so this must be O(1), not O(n). func (s *Store) GetLoadBalancerByArn(arn string) (*LoadBalancerRecord, error) { // ELBv2 LB ARN: arn:aws:elasticloadbalancing:{region}:{account}:loadbalancer/{app,net}/{name}/{lbID} idx := strings.LastIndex(arn, "/") @@ -106,11 +106,16 @@ func (s *Store) GetLoadBalancerByArn(arn string) (*LoadBalancerRecord, error) { if err != nil { return nil, err } + if lb == nil { + return nil, nil + } // Defence-in-depth: ensure the record actually belongs to this ARN. // Short IDs are random hex, so collisions are effectively impossible, but // a mismatch here would indicate KV corruption and must not be silently // served as a successful lookup. - if lb == nil || lb.LoadBalancerArn != arn { + if lb.LoadBalancerArn != arn { + slog.Error("load balancer KV record ARN mismatch", + "requested_arn", arn, "stored_arn", lb.LoadBalancerArn, "lb_id", lbID) return nil, nil } return lb, nil @@ -187,7 +192,12 @@ func (s *Store) GetTargetGroupByArn(arn string) (*TargetGroupRecord, error) { if err != nil { return nil, err } - if tg == nil || tg.TargetGroupArn != arn { + if tg == nil { + return nil, nil + } + if tg.TargetGroupArn != arn { + slog.Error("target group KV record ARN mismatch", + "requested_arn", arn, "stored_arn", tg.TargetGroupArn, "tg_id", tgID) return nil, nil } return tg, nil @@ -322,18 +332,26 @@ func (s *Store) ListListenersByLB(lbArn string) ([]*ListenerRecord, error) { return result, nil } -// GetListenerByArn finds a listener by its ARN. +// GetListenerByArn finds a listener by its ARN via a direct KV lookup on the +// short ID embedded in the ARN's final path segment. See GetLoadBalancerByArn +// for the motivation — Terraform calls DescribeTags on every aws_lb_listener +// on every plan, and DescribeTags can carry many ARNs per call, so this must +// be O(1) per ARN, not an O(n) listener-KV scan. func (s *Store) GetListenerByArn(arn string) (*ListenerRecord, error) { - listeners, err := s.ListListeners() + // ELBv2 listener ARN: arn:aws:elasticloadbalancing:{region}:{account}:listener/{app,net}/{name}/{lbID}/{listenerID} + idx := strings.LastIndex(arn, "/") + if idx < 0 || idx == len(arn)-1 { + return nil, nil + } + listenerID := arn[idx+1:] + l, err := s.GetListener(listenerID) if err != nil { return nil, err } - for _, l := range listeners { - if l.ListenerArn == arn { - return l, nil - } + if l == nil || l.ListenerArn != arn { + return nil, nil } - return nil, nil + return l, nil } // --- Rule CRUD --- diff --git a/spinifex/handlers/elbv2/store_test.go b/spinifex/handlers/elbv2/store_test.go index ab9d4bf86..6c1285c90 100644 --- a/spinifex/handlers/elbv2/store_test.go +++ b/spinifex/handlers/elbv2/store_test.go @@ -350,6 +350,16 @@ func TestGetListenerByArn(t *testing.T) { require.NoError(t, err) require.NotNil(t, got) assert.Equal(t, l.ListenerID, got.ListenerID) + + got, err = store.GetListenerByArn("arn:nonexistent") + require.NoError(t, err) + assert.Nil(t, got) + + // ARN that parses to a real listener ID but a different ARN must not match + // (defence-in-depth against the parse trick serving a wrong record). + got, err = store.GetListenerByArn("arn:aws:elasticloadbalancing:us-east-1:" + testAccountID + ":listener/app/other/lbX/" + l.ListenerID) + require.NoError(t, err) + assert.Nil(t, got) } // --- Cross-resource isolation: shared IDs across record types must not collide --- diff --git a/spinifex/handlers/elbv2/types.go b/spinifex/handlers/elbv2/types.go index 21fe3ae0f..c9137b169 100644 --- a/spinifex/handlers/elbv2/types.go +++ b/spinifex/handlers/elbv2/types.go @@ -1,6 +1,9 @@ package handlers_elbv2 -import "time" +import ( + "maps" + "time" +) const ( // LoadBalancer types @@ -16,6 +19,10 @@ const ( StateActive = "active" StateFailed = "failed" + // Target group target types (v1 supports instance and ip) + TargetTypeInstance = "instance" + TargetTypeIP = "ip" + // Target health states TargetHealthInitial = "initial" TargetHealthHealthy = "healthy" @@ -36,6 +43,7 @@ const ( // Listener action types ActionTypeForward = "forward" ActionTypeFixedResponse = "fixed-response" + ActionTypeRedirect = "redirect" // Rule condition fields RuleFieldHostHeader = "host-header" @@ -53,7 +61,7 @@ const ( MaxRulesPerListener = 100 MaxConditionsPerRule = 5 MaxValuesPerCondition = 5 - MaxActionsPerRule = 1 // forward only; mulga-951 may bump + MaxActionsPerRule = 1 // single terminal action: forward, redirect, or fixed-response MaxConditionValueLen = 128 MaxHTTPHeaderNameLen = 40 @@ -123,7 +131,7 @@ type TargetGroupRecord struct { Protocol string `json:"protocol"` // "HTTP" or "HTTPS" Port int64 `json:"port"` // Default target port VpcId string `json:"vpc_id"` - TargetType string `json:"target_type"` // "instance" for v1 + TargetType string `json:"target_type"` // TargetTypeInstance or TargetTypeIP HealthCheck HealthCheckConfig `json:"health_check"` Targets []Target `json:"targets"` Attributes map[string]string `json:"attributes,omitempty"` @@ -176,11 +184,11 @@ func DefaultNLBHealthCheck() HealthCheckConfig { // Target represents a registered target in a target group. type Target struct { - Id string `json:"id"` // Instance ID (e.g. i-xxxxx) + Id string `json:"id"` // Instance ID (i-xxxxx) or IP for ip-type TGs Port int64 `json:"port"` // Override port (0 = use TG default) HealthState string `json:"health_state"` // "initial", "healthy", "unhealthy", "draining" HealthDesc string `json:"health_desc"` // Reason for current state - PrivateIP string `json:"private_ip"` // Resolved from instance ENI + PrivateIP string `json:"private_ip"` // Instance ENI IP, or the target IP for ip-type TGs } // ListenerRecord represents a stored Listener. @@ -193,14 +201,18 @@ type ListenerRecord struct { DefaultActions []ListenerAction `json:"default_actions"` AccountID string `json:"account_id"` CreatedAt time.Time `json:"created_at"` + + Tags map[string]string `json:"tags,omitempty"` } -// ListenerAction defines a listener's default action. +// ListenerAction defines a listener default action or a rule action. type ListenerAction struct { - Type string `json:"type"` // "forward" or "fixed-response" + Type string `json:"type"` // "forward", "redirect", or "fixed-response" TargetGroupArn string `json:"target_group_arn"` // FixedResponse is populated when Type == "fixed-response" (no target group). FixedResponse *FixedResponseAction `json:"fixed_response,omitempty"` + // Redirect is populated when Type == "redirect". + Redirect *RedirectAction `json:"redirect,omitempty"` } // FixedResponseAction holds the canned reply for a "fixed-response" action. @@ -210,6 +222,18 @@ type FixedResponseAction struct { MessageBody string `json:"message_body,omitempty"` } +// RedirectAction holds the target for a "redirect" action. Fields mirror the +// AWS RedirectActionConfig and may contain the `#{protocol}`, `#{host}`, +// `#{port}`, `#{path}`, and `#{query}` placeholders. +type RedirectAction struct { + Protocol string `json:"protocol,omitempty"` + Host string `json:"host,omitempty"` + Port string `json:"port,omitempty"` + Path string `json:"path,omitempty"` + Query string `json:"query,omitempty"` + StatusCode string `json:"status_code"` // "HTTP_301" or "HTTP_302" +} + // RuleRecord represents a stored listener rule. type RuleRecord struct { RuleArn string `json:"rule_arn"` @@ -220,6 +244,8 @@ type RuleRecord struct { Actions []ListenerAction `json:"actions"` AccountID string `json:"account_id"` CreatedAt time.Time `json:"created_at"` + + Tags map[string]string `json:"tags,omitempty"` } // RuleCondition is one routing predicate on a rule. Only the field block @@ -250,50 +276,71 @@ type RuleQueryStringKV struct { // provider sends every attribute it knows about, and any key missing here // gets rejected with ValidationError, surfacing as "UnknownError" in tofu. func DefaultLoadBalancerAttributes(lbType string) map[string]string { - // Common to all load balancer types. - attrs := map[string]string{ - "deletion_protection.enabled": "false", - "load_balancing.cross_zone.enabled": "false", - } - switch lbType { case LoadBalancerTypeApplication: - // ALB-specific attributes. Defaults match real AWS values as of the - // aws-sdk-go 1.55 elbv2 API documentation. - attrs["load_balancing.cross_zone.enabled"] = "true" - attrs["access_logs.s3.enabled"] = "false" - attrs["access_logs.s3.bucket"] = "" - attrs["access_logs.s3.prefix"] = "" - attrs["connection_logs.s3.enabled"] = "false" - attrs["connection_logs.s3.bucket"] = "" - attrs["connection_logs.s3.prefix"] = "" - attrs["idle_timeout.timeout_seconds"] = "60" - attrs["client_keep_alive.seconds"] = "3600" - attrs["routing.http.desync_mitigation_mode"] = "defensive" - attrs["routing.http.drop_invalid_header_fields.enabled"] = "false" - attrs["routing.http.preserve_host_header.enabled"] = "false" - attrs["routing.http.x_amzn_tls_version_and_cipher_suite.enabled"] = "false" - attrs["routing.http.xff_client_port.enabled"] = "false" - attrs["routing.http.xff_header_processing.mode"] = "append" - attrs["routing.http2.enabled"] = "true" - attrs["waf.fail_open.enabled"] = "false" - attrs["zonal_shift.config.enabled"] = "false" + return maps.Clone(albAttributeDefaults) case LoadBalancerTypeNetwork: - // NLB-specific attributes. - attrs["access_logs.s3.enabled"] = "false" - attrs["access_logs.s3.bucket"] = "" - attrs["access_logs.s3.prefix"] = "" - attrs["dns_record.client_routing_policy"] = "any_availability_zone" - attrs["ipv6.deny_all_igw_traffic"] = "false" - attrs["zonal_shift.config.enabled"] = "false" + return maps.Clone(nlbAttributeDefaults) + default: + return maps.Clone(lbBaseAttributeDefaults) } - - return attrs } // DefaultTargetGroupAttributes returns the default attribute set for target groups. func DefaultTargetGroupAttributes() map[string]string { - return map[string]string{ + return maps.Clone(targetGroupAttributeDefaults) +} + +// Default attribute sets are package-level so Describe calls clone a prebuilt +// map instead of rebuilding it on every request. Callers receive a clone, never +// the shared map, so mutation cannot leak back into the defaults. +// +// access_logs.s3.bucket / .prefix (and the connection_logs equivalents) default +// to empty strings: that matches real AWS, where logging is disabled by default +// and the bucket/prefix are unset until the operator opts in. Terraform sends +// these empty strings on every apply, so they must be present as known keys. +var ( + // Common to all load balancer types; also the fallback for unknown types. + lbBaseAttributeDefaults = map[string]string{ + "deletion_protection.enabled": "false", + "load_balancing.cross_zone.enabled": "false", + } + + // ALB defaults match real AWS values as of the aws-sdk-go 1.55 elbv2 API. + albAttributeDefaults = map[string]string{ + "deletion_protection.enabled": "false", + "load_balancing.cross_zone.enabled": "true", + "access_logs.s3.enabled": "false", + "access_logs.s3.bucket": "", + "access_logs.s3.prefix": "", + "connection_logs.s3.enabled": "false", + "connection_logs.s3.bucket": "", + "connection_logs.s3.prefix": "", + "idle_timeout.timeout_seconds": "60", + "client_keep_alive.seconds": "3600", + "routing.http.desync_mitigation_mode": "defensive", + "routing.http.drop_invalid_header_fields.enabled": "false", + "routing.http.preserve_host_header.enabled": "false", + "routing.http.x_amzn_tls_version_and_cipher_suite.enabled": "false", + "routing.http.xff_client_port.enabled": "false", + "routing.http.xff_header_processing.mode": "append", + "routing.http2.enabled": "true", + "waf.fail_open.enabled": "false", + "zonal_shift.config.enabled": "false", + } + + nlbAttributeDefaults = map[string]string{ + "deletion_protection.enabled": "false", + "load_balancing.cross_zone.enabled": "false", + "access_logs.s3.enabled": "false", + "access_logs.s3.bucket": "", + "access_logs.s3.prefix": "", + "dns_record.client_routing_policy": "any_availability_zone", + "ipv6.deny_all_igw_traffic": "false", + "zonal_shift.config.enabled": "false", + } + + targetGroupAttributeDefaults = map[string]string{ "deregistration_delay.timeout_seconds": "300", "stickiness.enabled": "false", "stickiness.type": "lb_cookie", @@ -302,4 +349,4 @@ func DefaultTargetGroupAttributes() map[string]string { "load_balancing.algorithm.type": "round_robin", "slow_start.duration_seconds": "0", } -} +) diff --git a/spinifex/services/spinifexui/frontend/src/components/elbv2/security-groups-editor.test.tsx b/spinifex/services/spinifexui/frontend/src/components/elbv2/security-groups-editor.test.tsx new file mode 100644 index 000000000..4b2a45c7e --- /dev/null +++ b/spinifex/services/spinifexui/frontend/src/components/elbv2/security-groups-editor.test.tsx @@ -0,0 +1,114 @@ +import type { SecurityGroup } from "@aws-sdk/client-ec2" +import { render, screen } from "@testing-library/react" +import userEvent from "@testing-library/user-event" +import { describe, expect, it, vi } from "vitest" + +import { SecurityGroupsEditor } from "./security-groups-editor" + +const AVAILABLE: SecurityGroup[] = [ + { GroupId: "sg-1", GroupName: "default", VpcId: "vpc-a" }, + { GroupId: "sg-2", GroupName: "web", VpcId: "vpc-a" }, + { GroupId: "sg-3", GroupName: "db", VpcId: "vpc-a" }, +] + +describe("SecurityGroupsEditor", () => { + it("seeds selection from current and disables Save with no changes", () => { + render( + {}} + />, + ) + + expect(screen.getByLabelText("Security group sg-1 (default)")).toBeChecked() + expect(screen.getByLabelText("Security group sg-2 (web)")).not.toBeChecked() + expect(screen.getByText("No changes")).toBeInTheDocument() + expect(screen.getByRole("button", { name: /save changes/i })).toBeDisabled() + }) + + it("submits the new selection set", async () => { + const user = userEvent.setup() + const onSubmit = vi.fn() + render( + , + ) + + await user.click(screen.getByLabelText("Security group sg-2 (web)")) + await user.click(screen.getByRole("button", { name: /save changes/i })) + + expect(onSubmit).toHaveBeenCalledWith(["sg-1", "sg-2"]) + }) + + it("blocks submit when no security group is selected", async () => { + const user = userEvent.setup() + const onSubmit = vi.fn() + render( + , + ) + + await user.click(screen.getByLabelText("Security group sg-1 (default)")) + + expect(screen.getByText(/at least one security group/i)).toBeInTheDocument() + expect(screen.getByRole("button", { name: /save changes/i })).toBeDisabled() + expect(onSubmit).not.toHaveBeenCalled() + }) + + it("Reset reverts selection back to initial", async () => { + const user = userEvent.setup() + render( + {}} + />, + ) + + await user.click(screen.getByLabelText("Security group sg-2 (web)")) + expect(screen.getByText("Unsaved changes")).toBeInTheDocument() + + await user.click(screen.getByRole("button", { name: /reset/i })) + + expect(screen.getByLabelText("Security group sg-2 (web)")).not.toBeChecked() + expect(screen.getByText("No changes")).toBeInTheDocument() + }) + + it("shows an empty state when the VPC has no security groups", () => { + render( + {}} + />, + ) + expect( + screen.getByText("No security groups in this VPC."), + ).toBeInTheDocument() + }) + + it("renders an error banner when the mutation fails", () => { + render( + {}} + />, + ) + expect(screen.getByRole("alert")).toHaveTextContent("boom") + }) +}) diff --git a/spinifex/services/spinifexui/frontend/src/components/elbv2/security-groups-editor.tsx b/spinifex/services/spinifexui/frontend/src/components/elbv2/security-groups-editor.tsx new file mode 100644 index 000000000..f8725bd3a --- /dev/null +++ b/spinifex/services/spinifexui/frontend/src/components/elbv2/security-groups-editor.tsx @@ -0,0 +1,127 @@ +import type { SecurityGroup } from "@aws-sdk/client-ec2" +import { useMemo, useState } from "react" + +import { Button } from "@/components/ui/button" + +interface SecurityGroupsEditorProps { + // Security groups in the load balancer's VPC, selectable for attachment. + available: SecurityGroup[] + // Currently attached security group IDs. + current: string[] + onSubmit: (securityGroupIds: string[]) => void + isPending: boolean + error?: Error | null + isSuccess?: boolean +} + +function sameSet(a: string[], b: string[]): boolean { + if (a.length !== b.length) { + return false + } + const setB = new Set(b) + return a.every((id) => setB.has(id)) +} + +export function SecurityGroupsEditor({ + available, + current, + onSubmit, + isPending, + error, + isSuccess, +}: SecurityGroupsEditorProps) { + const initial = useMemo(() => [...current], [current]) + const [selected, setSelected] = useState(initial) + + const toggle = (id: string) => { + setSelected((prev) => + prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id], + ) + } + const handleReset = () => setSelected(initial) + + const dirty = !sameSet(selected, initial) + // AWS requires at least one security group on an ALB. + const isEmpty = selected.length === 0 + + return ( +
{ + e.preventDefault() + if (!dirty || isEmpty) { + return + } + onSubmit(selected) + }} + > + {error && ( +
+ {error.message || "Failed to update security groups"} +
+ )} + {isSuccess && !dirty && ( +
+ Security groups updated. +
+ )} +
+
+ {available.length === 0 ? ( +

+ No security groups in this VPC. +

+ ) : ( + available.map((sg) => ( + + )) + )} + {isEmpty && ( +

+ At least one security group is required. +

+ )} +
+
+ + {dirty ? "Unsaved changes" : "No changes"} + + + +
+
+
+ ) +} diff --git a/spinifex/services/spinifexui/frontend/src/components/elbv2/tags-editor.test.tsx b/spinifex/services/spinifexui/frontend/src/components/elbv2/tags-editor.test.tsx new file mode 100644 index 000000000..da6a78849 --- /dev/null +++ b/spinifex/services/spinifexui/frontend/src/components/elbv2/tags-editor.test.tsx @@ -0,0 +1,128 @@ +import type { Tag } from "@aws-sdk/client-elastic-load-balancing-v2" +import { render, screen } from "@testing-library/react" +import userEvent from "@testing-library/user-event" +import { describe, expect, it, vi } from "vitest" + +import { TagsEditor } from "./tags-editor" + +function at(arr: T[], i: number): T { + const v = arr[i] + if (v === undefined) { + throw new Error(`expected an element at index ${i}`) + } + return v +} + +const INITIAL: Tag[] = [ + { Key: "env", Value: "prod" }, + { Key: "team", Value: "platform" }, +] + +describe("TagsEditor", () => { + it("seeds rows from tags and disables Save with no changes", () => { + render( {}} tags={INITIAL} />) + + const keys = screen.getAllByLabelText("Tag key") + expect(keys[0]).toHaveValue("env") + expect(keys[1]).toHaveValue("team") + expect(screen.getByText("No changes")).toBeInTheDocument() + expect(screen.getByRole("button", { name: /save changes/i })).toBeDisabled() + }) + + it("submits the full desired tag set after an edit", async () => { + const user = userEvent.setup() + const onSubmit = vi.fn() + render() + + const value = at(screen.getAllByLabelText("Tag value"), 0) + await user.clear(value) + await user.type(value, "staging") + + await user.click(screen.getByRole("button", { name: /save changes/i })) + + expect(onSubmit).toHaveBeenCalledWith([ + { key: "env", value: "staging" }, + { key: "team", value: "platform" }, + ]) + }) + + it("adds and removes tag rows", async () => { + const user = userEvent.setup() + const onSubmit = vi.fn() + render() + + await user.click(screen.getByRole("button", { name: /add tag/i })) + await user.type(at(screen.getAllByLabelText("Tag key"), 2), "owner") + await user.type(at(screen.getAllByLabelText("Tag value"), 2), "alice") + + await user.click( + at(screen.getAllByRole("button", { name: /remove tag/i }), 1), + ) + + await user.click(screen.getByRole("button", { name: /save changes/i })) + + expect(onSubmit).toHaveBeenCalledWith([ + { key: "env", value: "prod" }, + { key: "owner", value: "alice" }, + ]) + }) + + it("blocks submit on a duplicate key", async () => { + const user = userEvent.setup() + const onSubmit = vi.fn() + render() + + const key = at(screen.getAllByLabelText("Tag key"), 1) + await user.clear(key) + await user.type(key, "env") + + expect(screen.getByText(/keys must be unique/i)).toBeInTheDocument() + expect(screen.getByRole("button", { name: /save changes/i })).toBeDisabled() + expect(onSubmit).not.toHaveBeenCalled() + }) + + it("blocks submit on a value without a key", async () => { + const user = userEvent.setup() + const onSubmit = vi.fn() + render() + + await user.click(screen.getByRole("button", { name: /add tag/i })) + await user.type(at(screen.getAllByLabelText("Tag value"), 0), "orphan") + + expect(screen.getByText(/needs a key/i)).toBeInTheDocument() + expect(screen.getByRole("button", { name: /save changes/i })).toBeDisabled() + expect(onSubmit).not.toHaveBeenCalled() + }) + + it("Reset reverts edits back to initial", async () => { + const user = userEvent.setup() + render( {}} tags={INITIAL} />) + + const value = at(screen.getAllByLabelText("Tag value"), 0) + await user.clear(value) + await user.type(value, "dev") + expect(screen.getByText("Unsaved changes")).toBeInTheDocument() + + await user.click(screen.getByRole("button", { name: /reset/i })) + + expect(at(screen.getAllByLabelText("Tag value"), 0)).toHaveValue("prod") + expect(screen.getByText("No changes")).toBeInTheDocument() + }) + + it("renders the Save button in pending state", () => { + render( {}} tags={INITIAL} />) + expect(screen.getByRole("button", { name: /saving/i })).toBeDisabled() + }) + + it("renders an error banner when the mutation fails", () => { + render( + {}} + tags={INITIAL} + />, + ) + expect(screen.getByRole("alert")).toHaveTextContent("boom") + }) +}) diff --git a/spinifex/services/spinifexui/frontend/src/components/elbv2/tags-editor.tsx b/spinifex/services/spinifexui/frontend/src/components/elbv2/tags-editor.tsx new file mode 100644 index 000000000..3dbe38b28 --- /dev/null +++ b/spinifex/services/spinifexui/frontend/src/components/elbv2/tags-editor.tsx @@ -0,0 +1,170 @@ +import type { Tag } from "@aws-sdk/client-elastic-load-balancing-v2" +import { Plus, Trash2 } from "lucide-react" +import { useMemo, useState } from "react" + +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" + +interface TagRow { + // Stable id so React keys survive key/value edits and row removal. + id: number + key: string + value: string +} + +interface TagsEditorProps { + tags: Tag[] + onSubmit: (tags: { key: string; value: string }[]) => void + isPending: boolean + error?: Error | null + isSuccess?: boolean +} + +function buildInitialRows(tags: Tag[]): TagRow[] { + return tags.map((t, i) => ({ id: i, key: t.Key ?? "", value: t.Value ?? "" })) +} + +function normalize(rows: TagRow[]): { key: string; value: string }[] { + return rows + .map((r) => ({ key: r.key.trim(), value: r.value })) + .filter((r) => r.key.length > 0) +} + +export function TagsEditor({ + tags, + onSubmit, + isPending, + error, + isSuccess, +}: TagsEditorProps) { + const initialRows = useMemo(() => buildInitialRows(tags), [tags]) + + const [rows, setRows] = useState(initialRows) + const [nextId, setNextId] = useState(initialRows.length) + + const setRow = (id: number, patch: Partial) => { + setRows((prev) => prev.map((r) => (r.id === id ? { ...r, ...patch } : r))) + } + const addRow = () => { + setRows((prev) => [...prev, { id: nextId, key: "", value: "" }]) + setNextId((n) => n + 1) + } + const removeRow = (id: number) => { + setRows((prev) => prev.filter((r) => r.id !== id)) + } + const handleReset = () => { + setRows(initialRows) + } + + // A row with a value but no key is incomplete; duplicate keys are ambiguous. + const hasBlankKey = rows.some( + (r) => r.key.trim().length === 0 && r.value.length > 0, + ) + const normalized = normalize(rows) + const keys = normalized.map((r) => r.key) + const hasDuplicate = new Set(keys).size !== keys.length + const hasError = hasBlankKey || hasDuplicate + + const dirty = + JSON.stringify(normalized) !== JSON.stringify(normalize(initialRows)) + + return ( +
{ + e.preventDefault() + if (hasError || !dirty) { + return + } + onSubmit(normalized) + }} + > + {error && ( +
+ {error.message || "Failed to save tags"} +
+ )} + {isSuccess && !dirty && ( +
+ Tags saved. +
+ )} +
+
+ {rows.length === 0 && ( +

No tags.

+ )} + {rows.map((row) => ( +
+ setRow(row.id, { key: e.target.value })} + placeholder="Key" + value={row.key} + /> + setRow(row.id, { value: e.target.value })} + placeholder="Value" + value={row.value} + /> + +
+ ))} +
+ +
+ {hasBlankKey && ( +

+ Every tag with a value needs a key. +

+ )} + {hasDuplicate && ( +

Tag keys must be unique.

+ )} +
+
+ + {dirty ? "Unsaved changes" : "No changes"} + + + +
+
+
+ ) +} diff --git a/spinifex/services/spinifexui/frontend/src/mutations/elbv2.ts b/spinifex/services/spinifexui/frontend/src/mutations/elbv2.ts index 2f1ec077b..16c2fbfb1 100644 --- a/spinifex/services/spinifexui/frontend/src/mutations/elbv2.ts +++ b/spinifex/services/spinifexui/frontend/src/mutations/elbv2.ts @@ -4,6 +4,7 @@ import { type RulePriorityPair, type Tag, type TargetDescription, + AddTagsCommand, CreateListenerCommand, CreateLoadBalancerCommand, CreateRuleCommand, @@ -18,7 +19,9 @@ import { ModifyRuleCommand, ModifyTargetGroupAttributesCommand, RegisterTargetsCommand, + RemoveTagsCommand, SetRulePrioritiesCommand, + SetSecurityGroupsCommand, } from "@aws-sdk/client-elastic-load-balancing-v2" import { useMutation, useQueryClient } from "@tanstack/react-query" @@ -76,6 +79,76 @@ export function useModifyLoadBalancerAttributes() { }) } +export interface UpdateTagsParams { + // ARN of any taggable ELBv2 resource (load balancer, target group, listener, + // listener rule). + resourceArn: string + // Desired final tag set after the edit. + tags: { key: string; value: string }[] + // Tag keys present before the edit, used to compute removals. + initialKeys: string[] +} + +// useUpdateTags reconciles a resource's tags to the desired set by diffing +// against the prior keys: it overwrites the final tags via AddTags and deletes +// any dropped keys via RemoveTags. Either call is skipped when it has no work. +export function useUpdateTags() { + const queryClient = useQueryClient() + return useMutation({ + mutationFn: async (params: UpdateTagsParams) => { + const finalKeys = new Set(params.tags.map((t) => t.key)) + const toRemove = params.initialKeys.filter((k) => !finalKeys.has(k)) + const client = getElbv2Client() + + if (params.tags.length > 0) { + await client.send( + new AddTagsCommand({ + ResourceArns: [params.resourceArn], + Tags: params.tags.map((t) => ({ Key: t.key, Value: t.value })), + }), + ) + } + if (toRemove.length > 0) { + await client.send( + new RemoveTagsCommand({ + ResourceArns: [params.resourceArn], + TagKeys: toRemove, + }), + ) + } + }, + onSuccess: () => { + void queryClient.invalidateQueries({ queryKey: ["elbv2", "tags"] }) + }, + }) +} + +export interface SetSecurityGroupsParams { + loadBalancerArn: string + securityGroupIds: string[] +} + +// useSetSecurityGroups replaces the security groups associated with a load +// balancer (SetSecurityGroups). The new set takes effect on the live data plane +// server-side; the LB query is invalidated so the detail page reflects it. +export function useSetSecurityGroups() { + const queryClient = useQueryClient() + return useMutation({ + mutationFn: async (params: SetSecurityGroupsParams) => { + const command = new SetSecurityGroupsCommand({ + LoadBalancerArn: params.loadBalancerArn, + SecurityGroups: params.securityGroupIds, + }) + return await getElbv2Client().send(command) + }, + onSuccess: (_data, variables) => { + void queryClient.invalidateQueries({ + queryKey: ["elbv2", "loadBalancers", variables.loadBalancerArn], + }) + }, + }) +} + export function useCreateTargetGroup() { const queryClient = useQueryClient() return useMutation({ diff --git a/spinifex/services/spinifexui/frontend/src/routes/_auth/ec2/(load-balancers)/-components/load-balancer-detail-page.tsx b/spinifex/services/spinifexui/frontend/src/routes/_auth/ec2/(load-balancers)/-components/load-balancer-detail-page.tsx index 59f2e8f56..ca2067cbd 100644 --- a/spinifex/services/spinifexui/frontend/src/routes/_auth/ec2/(load-balancers)/-components/load-balancer-detail-page.tsx +++ b/spinifex/services/spinifexui/frontend/src/routes/_auth/ec2/(load-balancers)/-components/load-balancer-detail-page.tsx @@ -1,5 +1,4 @@ import type { Subnet } from "@aws-sdk/client-ec2" -import type { Tag } from "@aws-sdk/client-elastic-load-balancing-v2" import { useSuspenseQuery } from "@tanstack/react-query" import { useNavigate } from "@tanstack/react-router" import { Trash2 } from "lucide-react" @@ -14,6 +13,8 @@ import { AttributesEditor, } from "@/components/elbv2/attributes-editor" import { ListenersTab } from "@/components/elbv2/listeners-tab" +import { SecurityGroupsEditor } from "@/components/elbv2/security-groups-editor" +import { TagsEditor } from "@/components/elbv2/tags-editor" import { ErrorBanner } from "@/components/error-banner" import { PageHeading } from "@/components/page-heading" import { StateBadge } from "@/components/state-badge" @@ -23,8 +24,13 @@ import { formatDateTime, getNameTag } from "@/lib/utils" import { useDeleteLoadBalancer, useModifyLoadBalancerAttributes, + useSetSecurityGroups, + useUpdateTags, } from "@/mutations/elbv2" -import { ec2SubnetsQueryOptions } from "@/queries/ec2" +import { + ec2SecurityGroupsQueryOptions, + ec2SubnetsQueryOptions, +} from "@/queries/ec2" import { elbv2LoadBalancerAttributesQueryOptions, elbv2LoadBalancerQueryOptions, @@ -43,9 +49,12 @@ export function LoadBalancerDetailPage({ arn }: Props) { ) const { data: tagsData } = useSuspenseQuery(elbv2TagsQueryOptions([arn])) const { data: subnetsData } = useSuspenseQuery(ec2SubnetsQueryOptions) + const { data: sgsData } = useSuspenseQuery(ec2SecurityGroupsQueryOptions) const deleteMutation = useDeleteLoadBalancer() const modifyAttrsMutation = useModifyLoadBalancerAttributes() + const updateTagsMutation = useUpdateTags() + const setSecurityGroupsMutation = useSetSecurityGroups() const [showDeleteDialog, setShowDeleteDialog] = useState(false) const lb = lbData.LoadBalancers?.[0] @@ -84,6 +93,12 @@ export function LoadBalancerDetailPage({ arn }: Props) { const attributes = attrsData.Attributes ?? [] const lbTags = tagsData?.TagDescriptions?.find((td) => td.ResourceArn === arn)?.Tags ?? [] + const currentSecurityGroups = (lb.SecurityGroups ?? []).filter( + (id): id is string => id !== undefined, + ) + const vpcSecurityGroups = (sgsData.SecurityGroups ?? []).filter( + (sg) => sg.VpcId === lb.VpcId, + ) return ( <> @@ -121,6 +136,7 @@ export function LoadBalancerDetailPage({ arn }: Props) { Overview Listeners + Security groups Attributes Tags @@ -179,6 +195,22 @@ export function LoadBalancerDetailPage({ arn }: Props) { + + + setSecurityGroupsMutation.mutate({ + loadBalancerArn: arn, + securityGroupIds, + }) + } + /> + + - {lbTags.length > 0 ? ( - - Tags - - {lbTags.map((tag: Tag) => ( - - ))} - - - ) : ( -

No tags.

- )} + + updateTagsMutation.mutate({ + resourceArn: arn, + tags, + initialKeys: lbTags + .map((t) => t.Key ?? "") + .filter((k) => k.length > 0), + }) + } + tags={lbTags} + />
diff --git a/spinifex/services/spinifexui/frontend/src/routes/_auth/ec2/(load-balancers)/describe-load-balancers/$id.test.tsx b/spinifex/services/spinifexui/frontend/src/routes/_auth/ec2/(load-balancers)/describe-load-balancers/$id.test.tsx index cd0ebc56c..b10763eaf 100644 --- a/spinifex/services/spinifexui/frontend/src/routes/_auth/ec2/(load-balancers)/describe-load-balancers/$id.test.tsx +++ b/spinifex/services/spinifexui/frontend/src/routes/_auth/ec2/(load-balancers)/describe-load-balancers/$id.test.tsx @@ -105,6 +105,11 @@ describe("load-balancer detail route", () => { qc.setQueryData(["ec2", "subnets"], { Subnets: [{ SubnetId: "subnet-a", CidrBlock: "10.0.1.0/24", Tags: [] }], }) + qc.setQueryData(["ec2", "securityGroups"], { + SecurityGroups: [ + { GroupId: "sg-1", GroupName: "default", VpcId: "vpc-aaa" }, + ], + }) return qc } @@ -126,6 +131,7 @@ describe("load-balancer detail route", () => { }) qc.setQueryData(["elbv2", "tags", LB_ARN], { TagDescriptions: [] }) qc.setQueryData(["ec2", "subnets"], { Subnets: [] }) + qc.setQueryData(["ec2", "securityGroups"], { SecurityGroups: [] }) renderWithClient(, qc) diff --git a/spinifex/services/spinifexui/frontend/src/routes/_auth/ec2/(target-groups)/-components/target-group-detail-page.tsx b/spinifex/services/spinifexui/frontend/src/routes/_auth/ec2/(target-groups)/-components/target-group-detail-page.tsx index 6d3c8dd7b..da1fbcdf9 100644 --- a/spinifex/services/spinifexui/frontend/src/routes/_auth/ec2/(target-groups)/-components/target-group-detail-page.tsx +++ b/spinifex/services/spinifexui/frontend/src/routes/_auth/ec2/(target-groups)/-components/target-group-detail-page.tsx @@ -1,4 +1,3 @@ -import type { Tag } from "@aws-sdk/client-elastic-load-balancing-v2" import { useSuspenseQuery } from "@tanstack/react-query" import { useNavigate } from "@tanstack/react-router" import { Trash2 } from "lucide-react" @@ -12,6 +11,7 @@ import { AttributesEditor, targetGroupAttributeSpecs, } from "@/components/elbv2/attributes-editor" +import { TagsEditor } from "@/components/elbv2/tags-editor" import { TargetsTab } from "@/components/elbv2/targets-tab" import { ErrorBanner } from "@/components/error-banner" import { PageHeading } from "@/components/page-heading" @@ -20,6 +20,7 @@ import { Tabs, TabsList, TabsPanel, TabsTab } from "@/components/ui/tabs" import { useDeleteTargetGroup, useModifyTargetGroupAttributes, + useUpdateTags, } from "@/mutations/elbv2" import { elbv2TagsQueryOptions, @@ -41,6 +42,7 @@ export function TargetGroupDetailPage({ arn }: Props) { const deleteMutation = useDeleteTargetGroup() const modifyAttrsMutation = useModifyTargetGroupAttributes() + const updateTagsMutation = useUpdateTags() const [showDeleteDialog, setShowDeleteDialog] = useState(false) const [activeTab, setActiveTab] = useState("overview") @@ -195,22 +197,21 @@ export function TargetGroupDetailPage({ arn }: Props) {
- {tgTags.length > 0 ? ( - - Tags - - {tgTags.map((tag: Tag) => ( - - ))} - - - ) : ( -

No tags.

- )} + + updateTagsMutation.mutate({ + resourceArn: arn, + tags, + initialKeys: tgTags + .map((t) => t.Key ?? "") + .filter((k) => k.length > 0), + }) + } + tags={tgTags} + />
From bbff004b456a6c714ac0aac2c80eda589d317d96 Mon Sep 17 00:00:00 2001 From: Josh Siviour Date: Wed, 3 Jun 2026 22:29:31 +1000 Subject: [PATCH 05/73] =?UTF-8?q?feat(eks):=206b=20create-cluster=20?= =?UTF-8?q?=E2=86=92=20ACTIVE=20(single-node=20SQLite=20+=20mgmt-IP=20NLB?= =?UTF-8?q?=20stop-gap)=20(#280)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(eks): cluster_state KV helpers — ClusterMeta + status CAS + prefix sweep Stage 1 of Sprint 6b CreateCluster lifecycle. Introduces the first read/write helpers against the eks-account-{accountID} bucket so later stages (oidc keypair, NLB wiring, cluster reconciler) can persist state without re-inventing CAS/sweep logic. - ClusterMeta struct holds the DescribeCluster source of truth (status, endpoint, OIDC issuer, CA, VPC config, control-plane VM + ENI, NLB ARN). - ClusterStatus enum mirrors the AWS EKS string set verbatim. - PutClusterMeta is unconditional (CreateCluster path); GetClusterMeta returns ErrClusterNotFound on key absence so the service boundary can map to ResourceNotFoundException. - SetClusterStatus is revision-checked with bounded CAS retries so the reconciler and CreateCluster body cannot wedge each other. - DeleteClusterPrefix sweeps every clusters/{name}/* key; called from DeleteCluster after the OIDC private key is zeroized. Tests cover round-trip, missing/corrupt blob, idempotent status set, DELETING transition from every prior state, concurrent revision bump recovery, sibling-cluster preservation, empty-bucket no-op. Plan: docs/development/feature/eks-6b-create-cluster.md * feat(eks): per-cluster ECDSA-P256 OIDC keypair generation + zeroize Stage 2 of Sprint 6b. Lays the at-rest primitives the CreateCluster body will call before launching the K3s server VM. Pure crypto helpers — no daemon, no launcher, no NATS bus. - GenerateClusterOIDCKeypair mints an ECDSA-P256 keypair per cluster (matches eks-v1.md Q8), PEM-marshals the private as PKCS8, envelope-encrypts it via handlers_iam.EncryptSecret (AES-256-GCM, AwsGW masterKey), writes the ciphertext to OIDCSigningKeyKey, and publishes the public JWKS document to OIDCJWKSKey. Returns the JWKS bytes so CreateCluster can hand them straight to user-data without a follow-up KV read. - JWKS shape mirrors what handlers_sts.JWKS already decodes for IRSA verification (RFC 7517 EC P-256, kid = base64url SHA-256 of SPKI DER, alg ES256, use sig). Types are defined locally to avoid a handlers_eks → handlers_sts → handlers_eks import cycle; JSON wire compat is the contract. - LoadClusterOIDCPrivateKey is the recovery-path read for future stages (reconciler restart, restore-snapshot tooling). Validates PKCS8 parses to an ECDSA P-256 *PrivateKey and rejects anything else. - ZeroizeClusterOIDCKey overwrites the encrypted blob with zeros of the same length, then deletes. DeleteCluster calls this *first* so a crash mid-teardown leaves no recoverable key material. Idempotent on missing key — supports retry semantics. Tests cover JWKS shape (RFC 7517 EC P-256 with 32-byte SEC1 coordinates), per-cluster key uniqueness, round-trip private-key decrypt matches JWKS public, wrong-master-key fails, missing-key ErrClusterNotFound mapping, zeroize idempotency, JWKS survives zeroize (carries no secret material), padCoord left-pad correctness. Plan: docs/development/feature/eks-6b-create-cluster.md * feat(eks): cluster SG + NLB ensure/delete helpers Stage 3 of Sprint 6b CreateCluster lifecycle. Adds the customer-account SG provisioning + per-cluster NLB plumbing the CreateCluster body will call between OIDC keypair (Stage 2) and K3s VM launch (Stage 4). Pure interface-call helpers — no daemon, no KV, no NATS bus. - EnsureClusterSGs creates (or returns) eks-cluster-{name}-control-plane-sg and eks-cluster-{name}-nodegroup-sg in the customer VPC, tagged spinifex:managed-by=eks + spinifex:eks-cluster= + spinifex:eks-role. Idempotent on group-name + vpc-id pair. DeleteClusterSGs is best-effort with continue-on-error sweep. - EnsureClusterNLB provisions the eks- NLB (internal scheme), the eks--cp target group (TCP, port 6443, target-type ip per eks-v1.md Q13), and the TCP :443 forward listener. Returns ClusterNLB {LoadBalancerArn, TargetGroupArn, ListenerArn, DNSName} so CreateCluster can persist every ARN in ClusterMeta. Idempotent on cluster name; resource-name length validated against the AWS 32-char cap so a too-long cluster name fails with a clear error instead of a generic InvalidParameterValue downstream. - RegisterClusterTarget + DeregisterClusterTarget bind the K3s server VM ENI IP to the TG on :6443. Stage 4 calls Register once the VM has its ENI IP; DeleteCluster calls Deregister before VM termination. - DeleteClusterNLB tears down NLB + TG. DeleteLoadBalancer already cascades listener cleanup inside the ELBv2 impl. LB sweep error takes precedence so DeleteCluster surfaces the more visible failure first while the TG sweep still runs. Narrow sgProvisioner + nlbProvisioner interfaces in-package give tests hand-rolled recorder fakes; the production VPCService + ELBv2Service satisfy them structurally so no adapter is needed at Stage 6 wire-up. Tests cover fresh-creates with right names/tags/ports, idempotent reuse, mixed-existence (control-plane exists, nodegroup created), name-too-long rejection, empty-inputs rejection, missing-resource no-op on delete, and first-error-surfaced sweep continuation on delete. Plan: docs/development/feature/eks-6b-create-cluster.md * feat(ec2): RunInstances honors pre-created NetworkInterfaceId Closes the AWS-parity gap where RunInstances always auto-created a primary ENI even when the caller specified NetworkInterfaces[0].NetworkInterfaceId. The EKS Sprint 6b CreateCluster launcher (Stage 4) needs to pre-create the K3s server VM's ENI so the ENI can be tagged/owned distinctly from the launcher's instance; the existing path silently created a second ENI and left the caller's unattached. Changes: - ENICreator interface gains GetENI(accountID, eniID) → *ENIInfo. ENIInfo is a translated struct (SubnetID, VpcID, PrivateIp, MAC, Status, SecurityGroupIDs) so handlers/ec2/instance stays free of an import on handlers/ec2/vpc.ENIRecord. - daemon/vpc_adapter.go gains daemonENICreator.GetENI translating VPCServiceImpl.GetENIRecord into ENIInfo. - PrepareRunInstances inspects NetworkInterfaces[0].NetworkInterfaceId after the existing subnet/SG lift block. If non-empty, the loop dispatches to a new attachPreCreatedENI helper: - Looks up the ENI under accountID. - Rejects with InvalidNetworkInterface.InUse if Status == "in-use". - Calls AttachENI to mark the ENI in-use and bind it to the new VM. - Populates instance.ENIId / ENIMac and ec2.Instance network fields (PrivateIp, SubnetId, VpcId, SecurityGroups, NetworkInterfaces[0]). - Skips the auto-create + public-IP-auto-assign paths; the caller is expected to manage public IP out-of-band. - Auto-create path is left untouched for every other code path: callers that pass SubnetId without a NetworkInterfaceId still get a fresh ENI with the existing semantics. Tests cover the four shapes: happy path (auto-create not called, attach called once, instance populated), in-use ENI rejected with the canonical AWS error code, lookup error surfaces verbatim, attach error surfaces verbatim. * feat(eks): K3s control-plane VM launcher with cloud-init user-data LaunchK3sServerVM resolves the eks-server AMI by name, pre-creates the customer-account control-plane ENI in the supplied subnet with the control-plane SG, renders cloud-init user-data (first-boot env, OIDC private key, K3s config.yaml with tls-san + service-account args), then calls RunInstances with NetworkInterfaces[0].NetworkInterfaceId pointing at the pre-created ENI. RunInstances failures roll back the ENI so the caller does not leak a customer-account resource. TerminateK3sServerVM tears the instance and ENI down for DeleteCluster; missing identifiers are a no-op so retries stay safe. ENI + VM both live in the customer account (deviation from plan §7 which specified a SystemAccount-owned VM); cross-account ENI attach is deferred to a follow-up bead. * feat(eks): NATS bootstrap subscriber + cluster reconciler + leader lease NATSBootstrap subscribes to the four single-shot subjects the K3s server VM publishes (k3s-bootstrap-token, k3s-admin-kubeconfig, k3s-oidc-jwks, k3s-ca) on eks.bus.{accountID}.{clusterName}.{kind}. Token and admin kubeconfig are envelope-encrypted via handlers_iam.EncryptSecret and persisted to KV. The published JWKS is cross-checked against the controller-generated keypair by kid and rejected on mismatch. The CA lands on meta.CertificateAuthorityB64 via the new SetClusterCertificateAuthority CAS updater. ClusterReconciler holds a leader lease on spinifex-eks-leader/{accountID}/ {clusterName} (60s TTL, 20s refresh) and drives: - CREATING -> ACTIVE once the four bootstrap KV artifacts are present and NLB /healthz responds 200. - ACTIVE -> probe /healthz on the configured interval, warn on failure. - DELETING / FAILED -> exit (DeleteCluster body owns teardown). Loss of the leader lease (CAS conflict or different holderID) returns ErrReconcilerLeaseLost so the caller can re-acquire from another node. Tested with embedded JetStream + a stub HTTPDoer; race-clean. * feat(eks): OIDC issuer URL builder + reconciler registry ClusterOIDCIssuer renders the {gatewayBaseURL}/oidc/eks/{region}/{accountID}/ {clusterName} URL kube-apiserver advertises as service-account-issuer and that STS / external IRSA validators dereference. Validates URL safety on the path segments so a hostile cluster name cannot inject scheme/path fragments. ReconcilerRegistry tracks per-(accountID, clusterName) reconciler goroutines with idempotent Spawn (drop duplicate spawn calls), Stop (cancel one + wait for release), and StopAll (graceful daemon shutdown). RunClusterReconciler is the production SpawnReconcilerFn: constructs a ClusterReconciler, acquires the leader lease, runs Run in a goroutine. Both helpers consumed by the upcoming service_impl CreateCluster body. * feat(eks): CreateCluster/DescribeCluster/ListClusters/DeleteCluster bodies Wires the EKSServiceImpl orchestration deps (VPC SG/K3s/Subnet, NLB, Instance launcher, AMI resolver, master key, gateway base URL, region, holder ID, reconciler registry) and implements the four lifecycle methods: - CreateCluster: validate → CREATING meta → SGs → NLB → OIDC issuer + keypair → K3s server VM (cloud-init carries OIDC private PEM) → register ENI IP with NLB target group → spawn NATS bootstrap subscriber + per-cluster reconciler via the registry. - DescribeCluster: KV meta read → eks.Cluster shape, with ErrClusterNotFound translated to ResourceNotFoundException at the service boundary. - ListClusters: KV key-prefix scan + sorted maxResults/nextToken pagination. - DeleteCluster: SetClusterStatus DELETING → zeroize OIDC key → stop reconciler via registry → deregister NLB target + delete NLB → terminate K3s VM → delete SGs → delete cluster KV prefix. Daemon wiring: - buildEKSServiceDeps loads MasterKey from BaseDir/config/master.key best-effort, resolves the gateway base URL via the same precedence the LB-agent block applies later, and passes VPCService + ELBv2Service + ImageService directly while adapting InstanceServiceImpl via daemonEKSInstanceLauncher (RunInstances passes through; Terminate- Instances loops vmMgr.Get + StopOrTerminateInstance in-process). - SubnetVPCResolver is satisfied by daemonEKSSubnetResolver wrapping VPCService.GetSubnet. - Startup spawns reconcilers for every persisted CREATING/ACTIVE cluster via SpawnRegisteredReconcilers; shutdown calls eksService.Shutdown so every per-cluster goroutine releases its lease before exit. Test surface: - service_impl_test: TestEKSServiceImpl_ClusterLifecycleShimMode covers the four lifecycle methods when constructed via the back-compat shim (CreateCluster/DeleteCluster → ServerInternal, DescribeCluster → ResourceNotFound on empty bucket, ListClusters → empty list). - daemon_handlers_eks_test: drop the four lifecycle subjects from the NotImplemented routing loop; handler-side coverage now lives in handlers/eks. - awserrors: add ResourceNotFound (404) for the DescribeCluster path. * fix(eks): load master.key from config dir not service data dir eks_deps read master.key from {BaseDir}/config/master.key, but the daemon systemd unit sets SPINIFEX_BASE_DIR=/var/lib/spinifex/spinifex (a per-service data dir). admin init writes master.key to the shared config dir, so the daemon looked in a path that only resolved when a {BaseDir}/config symlink existed — awsgw has one, the daemon's nested data dir does not. Result: MasterKey=nil, depsReadyForOrchestration() false, CreateCluster/DeleteCluster collapse to ServerInternal. master.key is a config artifact written next to spinifex.toml. Read it from filepath.Dir(d.configPath), matching how the daemon already resolves predastore.toml and TLS certs. No symlink or provisioning change needed. * fix(eks): register + resolve eks-server AMI via tag, add import --ami-name CreateCluster's K3s launch failed 'eks: AMI eks-server not found' on every clean install. Two defects: 1. spx admin images import had no way to name a locally-built appliance AMI: --name is a catalog lookup (rejects non-catalog values) and the AMI name was hardcoded to ami-{distro}-{version}-{arch}. build-system-image.sh ran 'import --name $AMI_NAME' for eks-server/eks-agent/GPU images, which all failed 'Image name not found in available images'. 2. The launcher resolved DescribeImages by name=='eks-server', a name the pipeline could never produce. Add --ami-name to override the registered AMI name on --file imports (fixes eks-server, eks-agent, and GPU appliance imports). Resolve the EKS AMI by the spinifex:managed-by=eks tag the pipeline already stamps, newest-wins on multiple matches. Tag-based resolution survives the planned server+agent → single EKS AMI unify untouched (role chosen per-instance at launch). build-system-image.sh now passes --ami-name; Makefile gains import-eks-server-image (IMPORT=1) and dev-install.sh imports the AMI when DEV_INSTALL_EKS=1. * fix(eks): give K3s server VM NATS token + CA so bootstrap can publish The K3s control-plane VM was launched with NATSURL=ConnectedUrl() (loopback, unreachable from the VM) and no auth material, while spinifex NATS requires a shared token over TLS. The VM could not connect to NATS, so it never published its four one-shot bootstrap messages and the cluster stayed in CREATING. Hand the VM the daemon's shared NATS token + CA PEM and a VM-reachable NATS URL (mirrors the ELBv2 LB-agent shared-credential pattern; spinifex has no nkeys hierarchy to scope per-principal creds against). - K3sServerInput: drop dead NATSCredsContent; add NATSToken + NATSCACert, required by validateK3sServerInput. user-data writes SPINIFEX_NATS_TOKEN, SPINIFEX_NATS_CA + the CA file; first-boot.env tightened to 0600. - EKSServiceDeps + CreateCluster: pass NATSURL/NATSToken/NATSCACert. - buildEKSServiceDeps: read CA from config.NATS.CACert; extract resolveGatewayHost(); add resolveNATSURL() (same reachable host, NATS port). - k3s-first-boot.sh: build nats CLI args with --token + --tlsca. * fix(eks): retry transient bootstrap persists, fail cluster on permanent error The NATS bootstrap subscriber tore down on the first persist error and the cluster sat in CREATING forever. Core-NATS delivers a publication once, so a transient KV blip during persist was unrecoverable and a malformed payload (bad JWKS kid, non-base64 CA, empty envelope) silently stranded the cluster. - persistWithRetry rides out transient persist failures in-handler (3 attempts, 200ms backoff) instead of unsubscribing and waiting for a re-publish that never comes. - errBootstrapPermanent classifies validation failures (malformed envelope, empty fields, JWKS kid mismatch, non-base64 CA) as non-retryable so they return immediately. - spawnBootstrap marks the cluster FAILED (with reason) when Run exits with a non-context error, so DescribeCluster surfaces the cause and DeleteCluster can reclaim resources. - MarkClusterFailed transitions to FAILED+StatusReason only from CREATING, so a late bootstrap error cannot clobber a concurrent delete or healthy cluster. - casUpdateMeta extracts the revision-checked RMW loop shared by the meta setters. * fix(eks): resume NATS bootstrap for CREATING clusters on daemon restart SpawnRegisteredReconcilers re-spawned only the reconciler on boot, never the bootstrap subscriber. A daemon restart while a cluster was CREATING (K3s VM still booting) lost the subscriptions; the VM published its four one-shot core-NATS messages to nobody and the cluster hung in CREATING forever. - BootstrapPendingKinds reports which artifacts (token, kubeconfig, CA) are still missing from KV. JWKS is excluded: it persists no artifact and re-waiting on a once-published subject would deadlock — its cross-check is best-effort across a restart. - RunForKinds subscribes to a subject subset (nil = all four); Run delegates to it. subjectHandlers maps each kind to its handler and rejects unknown kinds. - SpawnRegisteredReconcilers resumes bootstrap for CREATING clusters, waiting only on the missing artifacts, so a mid-CREATING restart still drives the cluster to ACTIVE. * fix(eks): DeleteCluster must not wipe KV or report success on teardown failure DeleteCluster ran zeroize, NLB teardown, and VM termination as warn-and-continue then unconditionally swept the per-cluster KV prefix and returned success. A failed NLB or VM teardown leaked billable resources with no owning record (the meta holding their ARNs/IDs was erased) and told the operator the cluster was gone. Zeroize — a stated security guarantee of no recoverable key material — had its failure ignored too. - Zeroize, NLB delete, and VM terminate are now blocking: their failures accumulate (errors.Join) and abort the call before the KV sweep, leaving the cluster DELETING and returning the error so a retry can still reach the ARNs. - KV prefix sweep runs only after NLB + VM teardown confirm. - SG cleanup stays best-effort (plan step 5) — a leaked SG strands no owning record — and target deregister stays best-effort since DeleteClusterNLB tears down the whole NLB + target group. * fix(eks): persist NLB + control-plane ARNs mid-CreateCluster so failures don't leak CreateCluster set meta.NLBArn / target-group / instance / ENI in memory and persisted them only in the final PutClusterMeta, after LaunchK3sServerVM. Any failure between EnsureClusterNLB and that persist left the NLB + target group + listener + backing LB VM created but unrecorded; markFailed did no rollback and DeleteCluster keys teardown off the persisted ARNs, so the resources leaked. - Persist meta immediately after EnsureClusterNLB (records NLB/TG ARNs) and again after LaunchK3sServerVM (records instance + ENI), before the next fallible step. - A failed create now leaves a FAILED meta carrying the resource references, so the DeleteCluster teardown path (165.9) reclaims every NLB/TG/listener/VM. - Tests: NLB-arn-persisted-before-later-failure, failed-create-then-delete reclaims NLB, and a CreateCluster happy path. Shared eksServiceFixture extracted from the delete-cluster fixture. * fix(sts): parse path-based EKS OIDC issuer so IRSA accepts 6b cluster tokens ParseEKSIssuerURL required an `oidc.eks.` host prefix and an exactly-2-segment path (AWS hosted-EKS shape), but ClusterOIDCIssuer emits — and awsgw serves — https://{gateway-host}/oidc/eks/{region}/{accountID}/{clusterName}. Every 6b cluster's iss claim was rejected with "issuer host must start with oidc.eks", so AssumeRoleWithWebIdentity would fail all IRSA tokens once 6e serves them. Reconcile on the path-based shape, which is what is actually reachable on bare-metal/on-prem (no oidc.eks.* vhost or DNS exists). Host trust comes from the IAM OIDC-provider registration (the full issuer string is the registry key) and the JWKS signature check, not a host pattern — so the parser drops the host prefix rule and instead pins accountID/clusterName at fixed positions in a strict 5-segment /oidc/eks/{region}/{accountID}/{clusterName} path. A crafted iss with extra or missing segments still fails closed. Adds a cross-component round-trip test asserting a ClusterOIDCIssuer-built iss parses back to the same (accountID, clusterName). * fix(eks): reclaim FAILED clusters on retry + cluster-scoped exists/not-found errors A failed CreateCluster left a FAILED ClusterMeta that poisoned retries: the preflight returned ErrorELBv2TargetGroupInUse ("The target group is currently in use...") for a cluster-exists condition, and because that maps to a retryable code the SDK's auto-retry surfaced ResourceInUseException instead of the original failure. FAILED clusters were also a dead state — visible to neither a clean recreate nor a clear lifecycle. - Add EKS-specific ResourceInUseException / ResourceNotFoundException codes with cluster-scoped messages; CreateCluster's exists check and DescribeCluster / DeleteCluster not-found now use them instead of the ELBv2 / EC2 codes. - CreateCluster reclaims a FAILED cluster: it purges the prior attempt's recorded resources and clears KV before recreating, so a retry (including the SDK auto-retry) is idempotent rather than blocked. Teardown failure surfaces rather than recreating on top of orphans. - Extract purgeClusterInfra, shared by DeleteCluster and the reclaim path (blocking zeroize/NLB/VM, best-effort SG, KV sweep only after teardown confirms). - FAILED clusters remain observable via Describe (status=FAILED) and List — no state where create blocks but describe/list show nothing. * fix(eks): fail CREATING clusters that exceed create timeout A per-cluster reconciler that never observes a ready control plane (bootstrap artifacts missing or healthz unreachable) previously stayed CREATING forever. Add a configurable create timeout (default 15m): once meta.CreatedAt is older than the deadline and the cluster is still not ready, the reconciler marks it FAILED with a reason, exiting the loop. Within the deadline it stays CREATING. * fix(eks): surface ACTIVE cluster health in describe-cluster The reconciler only slog.Warn'd a failing /healthz probe for an ACTIVE cluster, so describe-cluster kept reporting a dead control plane as healthy. Add HealthIssue + LastHealthProbe to ClusterMeta, write them from the ACTIVE reconcile branch (recording the failure reason, clearing on recovery), and map a non-empty HealthIssue to a ClusterHealth ClusterUnreachable issue in describe-cluster. * test(eks): add plan-mandated CreateCluster/DeleteCluster service cases service_impl_test only covered shim mode. Add the four cases the plan's Testing section requires: CONFIG_MAP auth mode rejected (and API accepted), missing subnetIds rejected, DescribeCluster 404 with full deps wired (past the shim short-circuit), and the DeleteCluster zeroize-before-teardown ordering proven by forcing a teardown failure and asserting the OIDC key is already wiped. * refactor(eks): return OIDC private-key PEM from generator, drop re-read CreateCluster discarded GenerateClusterOIDCKeypair's return then did a second KV get + AES-GCM decrypt via loadOIDCPrivateKeyPEM to re-derive the same PEM the generator already had in hand. Return the plaintext PEM (alongside the JWKS) from the generator and use it directly; remove loadOIDCPrivateKeyPEM and the now -unused crypto/x509 + encoding/pem imports in service_impl. * fix(eks): make CreateCluster/DeleteCluster failures diagnosable Unmet orchestration deps and a missing eks-server AMI both collapsed to a bare ServerInternal with no request-time log, leaving the client a 'contact AWS re:Post' message and zero cause. Enumerate the specific missing deps and log them at ERROR, returning ServiceUnavailable (an operator/config fault, not an unrecoverable internal one). Add an ErrEKSServerAMINotFound sentinel so a missing control-plane AMI is logged and surfaced as ServiceUnavailable too. * fix(eks): serialize REST-JSON responses via jsonutil so the AWS SDK can parse them WriteJSONResponse marshaled aws-sdk-go *Output structs with encoding/json, which ignores their locationName tags and emits Go PascalCase keys. EKS clients parse restjson on the lowercase locationName, so every field of list/describe/create/delete responses was silently dropped (empty endpoint, null identity.oidc.issuer). Marshal via jsonutil.BuildJSON — the same marshaler the SDK uses for restjson bodies — which honors locationName. Adds wire-shape tests asserting lowercase keys present and PascalCase absent. * feat(eks): launch K3s server VM via boot-agnostic system-instance path The EKS K3s control-plane VM launched through the plain tenant RunInstances path, so it had only its VPC ENI and no management-bridge NIC -- no route to the daemon's NATS endpoint. It never published its bootstrap subjects and the cluster stayed CREATING. Generalize LaunchSystemInstance to a boot-agnostic contract supporting both system-instance boot styles: - BootDirect: direct-boot microVM (fw_cfg blobs) -- ELBv2 LB agent - BootAMI: AMI boot + cloud-init seed (q35) -- EKS K3s server VM The launch contract moves to a neutral handlers/sysinstance package so EKS can launch system VMs without an eks->elbv2 dependency; handlers/elbv2 re-exports the types as aliases. The BootAMI branch mirrors the daemon's Prepare -> Insert -> Launch split and allocates the mgmt NIC on the VM record between Insert and Launch, so the cloud-init network-config renders a static mgmt0 interface. The EKS NATSURL is now sourced from the mgmt-bridge IP (the on-link address the VM's mgmt NIC can reach), falling back to the gateway-host resolution when no mgmt bridge exists. Verified: K3s VM now boots from the eks-server AMI under q35 with a mgmt0 NIC (10.15.8.x), reachable from the host over br-mgmt, with NATS on-link at the bridge IP. No AMI rebuild required. * fix(eks): make DeleteCluster K3s teardown idempotent so it can't wedge TerminateK3sServerVM treated every DeleteNetworkInterface error -- and every TerminateSystemInstance error -- as blocking. Because instance terminate is async, the immediate ENI delete races it: the first attempt fails InvalidNetworkInterface.InUse, and once the instance-terminate cascade releases the ENI every retry fails InvalidNetworkInterfaceID.NotFound. Both joined into purgeClusterInfra's teardownErrs gate, which short-circuits before the SG sweep and KV prefix delete -- so once the ENI was gone the cluster was stuck DELETING permanently, leaking its control-plane + nodegroup SGs and KV meta. Classify the teardown errors instead of blanket-propagating: - ENI InvalidNetworkInterfaceID.NotFound / InvalidNetworkInterface.NotFound -> idempotent success (the cascade or a prior retry already deleted it); must not block the downstream SG + KV sweep. - ENI InvalidNetworkInterface.InUse (VM still terminating) and any other error -> retryable; surfaced so the cluster stays DELETING and the reconciler retries once the instance releases the ENI. - Instance already gone -> idempotent. TerminateSystemInstance now returns a sysinstance.ErrSystemInstanceNotFound sentinel that the EKS path tolerates via errors.Is, so a retried delete after the VM drained completes. Add awserrors.IsErrorCode(err, code) as the shared delete-error classifier (substring match through %w wrapping) and route the lone ad-hoc strings.Contains guard in daemon/vm_adapters.go through it. Verified: delete-cluster on three clusters left wedged DELETING / FAILED (ENI + VM already gone) all complete -- clusters erased, SGs + ENIs reclaimed, no leak. * fix(eks): gate ACTIVE on verified JWKS cross-check, not pre-seeded key The controller pre-seeds OIDCJWKSKey at create time, so its presence proved nothing about the running cluster's actual signing key. A cluster could reach ACTIVE — and start signing IRSA tokens — before the K3s VM's published JWKS was ever cross-checked against the generated keypair. Add an OIDCJWKSVerifiedKey marker written by persistJWKS only after assertJWKSMatch passes. The reconciler's ACTIVE gate and BootstrapPendingKinds now key off the marker, not the pre-seeded JWKS. assertJWKSMatch is map-based and also rejects kty mismatch. * fix(eks): collapse duplicated gateway-host switch into resolveGatewayHost startCluster reimplemented the 5-case gateway-host precedence inline, duplicating resolveGatewayHost (used by the OIDC issuer and EKS NATS URL). If one drifted, the OIDC issuer host embedded in cluster tokens would diverge from the host LB VMs use to reach the daemon -> IRSA iss mismatch and cluster-wide token rejection. startCluster now calls resolveGatewayHost and derives the multi-node mgmt host route (mgmtRouteVia) from the resolved host. resolveGatewayHost carries the canonical case enumeration; a table test pins all five branches plus the case-1 skip guards and the no-host fallthrough. * fix(eks): make eks-server VM boot diagnosable + fix first-boot publisher crash Three issues found while diagnosing why K3s clusters never leave CREATING: 1. setup.sh: the stock Alpine cloud image lists `console=tty0` LAST in default_kernel_opts, so Linux binds /dev/console to the framebuffer and the host-side serial capture sees only kernel dmesg — OpenRC, cloud-init, and k3s-first-boot output were invisible. Reorder so console=ttyS0 is last. 2. k3s-first-boot.initd: command_background was "no" while output_log/error_log were set; start-stop-daemon rejects --stdout/--stderr without --background ("Failed to start k3s-first-boot"), so the bootstrap publisher never ran and the cluster wedged in CREATING. Background it (the publisher waits up to 5min on K3s /healthz and must not block the runlevel anyway) and route its output to the serial console, which the orchestrator captures (the VM has no login). 3. k3s-first-boot.sh: on the /healthz timeout, dump the tail of /var/log/k3s.log to the console so the apiserver's own failure is visible host-side. * fix(eks): seed K3s apiserver a public OIDC key, not the private key buildK3sUserData pointed both kube-apiserver service-account args at the same private-key file. --service-account-key-file requires a PUBLIC key — k8s ParsePublicKeysPEM rejects a private-key PEM with "data does not contain any valid RSA or ECDSA public keys" and the apiserver crash-loops, so K3s never reaches /healthz, first-boot never publishes, and the cluster wedges in CREATING. Add PublicKeyPEMFromPrivate (PKIX public PEM from the PKCS#8 private key) and seed it to a separate /etc/rancher/k3s/oidc-signing-key.pub.pem. Point service-account-key-file at the public file; keep service-account-signing-key-file on the private file. Runtime-verified: the apiserver crash is gone and K3s now starts and schedules system pods. * feat(eks): egress-only SNAT + DNS for K3s control-plane VM The K3s server VM (a hidden system instance) could not pull system-pod images: it had no internet egress and no working resolver, so coredns/traefik/metrics-server never started and /healthz timed out. Egress: give the single control-plane VM egress-only internet, confined to its /32, with no inbound exposure and no customer-visible resource. - policy/route.go: SystemInstanceEgressPriority (1200, above the drop gate) + AddSystemInstanceEgress/Delete — a reroute scoped to ip4.src == /32 so peers in a shared subnet are unaffected. - policy/nat.go: AddSystemInstanceSNAT/Delete — a plain snat (not dnat_and_snat, so no inbound path), idempotent on its pool external IP. - external/igw.go: L5 EnsureSystemInstanceEgress/Remove resolves the gateway nexthop and attaches the reroute + snat (mirrors the NAT-GW egress path; ADR-0006 S1/S4/S5 preserved). - subscribers: vpc.add/delete-system-egress topics + handlers. - handlers/eks: allocate a hidden (ManagedBy=eks) pool address on CreateCluster and publish add; release + publish delete on teardown. EIP dep wired through EKSServiceDeps + the daemon. DNS: the eks-server AMI is Alpine/dhcpcd and /etc/resolv.conf is a dangling symlink, so DHCP-supplied resolvers are never persisted. Write a real /etc/resolv.conf from the K3s VM cloud-config via bootcmd (not write_files — a write_files entry follows the dead symlink, fails, and aborts the whole block, dropping first-boot.env + the k3s config). * feat: EKS 6b single-node SQLite pivot + bootstrap-envelope fixes Switch the K3s server VM from embedded etcd to embedded SQLite (kine) for the single-node v1, so CreateCluster reaches a healthy control plane. etcd's per-commit fsync stalls past the apiserver deadline on viperblock's deferred-durability block path; SQLite tolerates it. - k3s server: omit cluster-init (selects SQLite/kine), add anonymous-auth=true so the reconciler's anonymous /healthz NLB probe returns 200. - first-boot readiness gate: anonymous /healthz (401 under CIS anonymous-auth =false) -> authenticated 'kubectl get --raw /readyz'. - first-boot publish: emit a JSON BootstrapEnvelope for all four subjects (token, admin-kubeconfig, oidc-jwks, ca); jwks and ca were absent before. - nats pub: --stdin -> --force-stdin (nats CLI 0.4.0). - manifest: add jq (builds the bootstrap-message JSON envelopes). * feat: EKS reconciler probes control-plane mgmt IP until DNS lands The host-side cluster reconciler cannot resolve or route to the VPC-internal NLB DNS endpoint (no authoritative DNS / Eclipso yet), so CreateCluster timed out in CREATING and was marked FAILED even though the control plane was healthy. Probe the control-plane VM's br-mgmt NIC address directly — the one apiserver endpoint reachable from the daemon. Capture the mgmt IP from the launch result (SystemInstanceOutput.MgmtIP -> K3sServerOutput.MgmtIP -> ClusterMeta. ControlPlaneMgmtIP) and build the reconciler health URL as https://:6443/healthz. The probe client already sets InsecureSkipVerify, so the mgmt IP need not be in the apiserver cert SAN. Workaround until authoritative DNS + a host-reachable NLB front-end land, at which point spawnReconciler reverts to the NLB endpoint. --- Makefile | 26 +- cmd/spinifex/cmd/admin.go | 5 + docs/COMMANDS.md | 2 +- scripts/build-system-image.sh | 7 +- scripts/dev-install.sh | 11 + .../images/eks-server/k3s-first-boot.initd | 13 +- scripts/images/eks-server/k3s-first-boot.sh | 104 ++- scripts/images/eks-server/k3s.initd | 14 +- scripts/images/eks-server/manifest.conf | 11 +- scripts/images/eks-server/setup.sh | 13 +- spinifex/awserrors/awserrors.go | 17 + spinifex/daemon/daemon.go | 63 +- spinifex/daemon/daemon_handlers_eks_test.go | 12 +- spinifex/daemon/daemon_system_instance.go | 126 ++- spinifex/daemon/eks_adapter.go | 31 + spinifex/daemon/eks_deps.go | 159 ++++ spinifex/daemon/eks_deps_test.go | 86 ++ spinifex/daemon/vm_adapters.go | 3 +- spinifex/daemon/vpc_adapter.go | 16 + spinifex/gateway/eks/handler.go | 9 +- spinifex/gateway/eks/handler_test.go | 60 ++ spinifex/handlers/ec2/instance/service.go | 19 +- .../handlers/ec2/instance/service_impl.go | 85 ++ .../ec2/instance/service_impl_test.go | 130 +++ spinifex/handlers/eks/awsgw_endpoint.go | 47 ++ spinifex/handlers/eks/awsgw_endpoint_test.go | 62 ++ spinifex/handlers/eks/cluster_reconciler.go | 338 ++++++++ .../handlers/eks/cluster_reconciler_test.go | 469 +++++++++++ spinifex/handlers/eks/cluster_state.go | 257 ++++++ spinifex/handlers/eks/cluster_state_test.go | 256 ++++++ spinifex/handlers/eks/create_cluster_test.go | 210 +++++ spinifex/handlers/eks/delete_cluster_test.go | 149 ++++ spinifex/handlers/eks/eip_test.go | 44 + spinifex/handlers/eks/k3s_server_vm.go | 424 ++++++++++ spinifex/handlers/eks/k3s_server_vm_test.go | 400 +++++++++ spinifex/handlers/eks/nats_bootstrap.go | 386 +++++++++ spinifex/handlers/eks/nats_bootstrap_test.go | 390 +++++++++ spinifex/handlers/eks/nlb.go | 353 ++++++++ spinifex/handlers/eks/nlb_test.go | 388 +++++++++ spinifex/handlers/eks/oidc_keypair.go | 210 +++++ spinifex/handlers/eks/oidc_keypair_test.go | 228 +++++ spinifex/handlers/eks/reconciler_registry.go | 166 ++++ .../handlers/eks/reconciler_registry_test.go | 95 +++ spinifex/handlers/eks/security_groups.go | 162 ++++ spinifex/handlers/eks/security_groups_test.go | 203 +++++ spinifex/handlers/eks/service_impl.go | 783 +++++++++++++++++- spinifex/handlers/eks/service_impl_test.go | 83 +- spinifex/handlers/eks/store.go | 9 + spinifex/handlers/elbv2/launcher.go | 123 +-- .../sts/assume_role_with_web_identity_test.go | 8 +- spinifex/handlers/sts/oidc_jwks.go | 48 +- spinifex/handlers/sts/oidc_jwks_test.go | 31 +- spinifex/handlers/sysinstance/launcher.go | 155 ++++ spinifex/network/external/igw.go | 76 +- spinifex/network/external/igw_test.go | 108 +++ spinifex/network/policy/nat.go | 55 ++ spinifex/network/policy/nat_test.go | 20 + spinifex/network/policy/route.go | 91 ++ spinifex/network/policy/route_test.go | 122 +++ spinifex/network/subscribers/events.go | 15 + spinifex/network/subscribers/subscribers.go | 2 + .../network/subscribers/subscribers_test.go | 61 ++ spinifex/network/subscribers/topology.go | 35 + 63 files changed, 7814 insertions(+), 270 deletions(-) create mode 100644 spinifex/daemon/eks_adapter.go create mode 100644 spinifex/daemon/eks_deps.go create mode 100644 spinifex/daemon/eks_deps_test.go create mode 100644 spinifex/handlers/eks/awsgw_endpoint.go create mode 100644 spinifex/handlers/eks/awsgw_endpoint_test.go create mode 100644 spinifex/handlers/eks/cluster_reconciler.go create mode 100644 spinifex/handlers/eks/cluster_reconciler_test.go create mode 100644 spinifex/handlers/eks/cluster_state.go create mode 100644 spinifex/handlers/eks/cluster_state_test.go create mode 100644 spinifex/handlers/eks/create_cluster_test.go create mode 100644 spinifex/handlers/eks/delete_cluster_test.go create mode 100644 spinifex/handlers/eks/eip_test.go create mode 100644 spinifex/handlers/eks/k3s_server_vm.go create mode 100644 spinifex/handlers/eks/k3s_server_vm_test.go create mode 100644 spinifex/handlers/eks/nats_bootstrap.go create mode 100644 spinifex/handlers/eks/nats_bootstrap_test.go create mode 100644 spinifex/handlers/eks/nlb.go create mode 100644 spinifex/handlers/eks/nlb_test.go create mode 100644 spinifex/handlers/eks/oidc_keypair.go create mode 100644 spinifex/handlers/eks/oidc_keypair_test.go create mode 100644 spinifex/handlers/eks/reconciler_registry.go create mode 100644 spinifex/handlers/eks/reconciler_registry_test.go create mode 100644 spinifex/handlers/eks/security_groups.go create mode 100644 spinifex/handlers/eks/security_groups_test.go create mode 100644 spinifex/handlers/sysinstance/launcher.go diff --git a/Makefile b/Makefile index f7764d23d..c4fac8bf5 100644 --- a/Makefile +++ b/Makefile @@ -78,17 +78,20 @@ ifndef IMAGE $(error IMAGE is required. Usage: make build-system-image IMAGE=lb) endif @if [ -f scripts/images/$(IMAGE).conf ]; then \ - ./scripts/build-system-image.sh scripts/images/$(IMAGE).conf; \ + ./scripts/build-system-image.sh scripts/images/$(IMAGE).conf $(if $(IMPORT),--import); \ elif [ -f scripts/images/$(IMAGE)/manifest.conf ]; then \ - ./scripts/build-system-image.sh scripts/images/$(IMAGE)/manifest.conf; \ + ./scripts/build-system-image.sh scripts/images/$(IMAGE)/manifest.conf $(if $(IMPORT),--import); \ else \ echo "ERROR: no manifest at scripts/images/$(IMAGE).conf or scripts/images/$(IMAGE)/manifest.conf"; \ exit 1; \ fi -build-eks-server-image: ## Build the eks-server AMI (K3s control-plane variant) +build-eks-server-image: ## Build the eks-server AMI (K3s control-plane variant; IMPORT=1 to register it) $(MAKE) build-system-image IMAGE=eks-server +import-eks-server-image: ## Build + register the eks-server AMI (requires a running cluster) + $(MAKE) build-system-image IMAGE=eks-server IMPORT=1 + build-eks-agent-image: ## Build the eks-agent AMI (K3s worker variant) $(MAKE) build-system-image IMAGE=eks-agent @@ -338,9 +341,22 @@ ansible-dev-version: ansible-dev-vpc: cd scripts/ansible && ansible-playbook playbooks/dev-vpc.yml $(ANSIBLE_EXTRA) -.PHONY: build build-ui build-installer build-lb-agent build-system-image build-eks-server-image build-eks-agent-image build-microvm-image install-microvm go_build go_run preflight test test-cover test-race diff-coverage bench run test-actions test-harness manifest-check diff-coverage bench run \ +# Multi-node cluster bootstrap against a tofu env (env1, env2, bryn, etc). +# Inventory is generated from scripts/tofu-cluster/envs/.tfvars. +# make ansible-cluster-bootstrap ENV=env1 POOL=192.168.1.150-192.168.1.159 +ENV ?= +POOL ?= +ansible-cluster-bootstrap: + @test -n "$(ENV)" || { echo "ENV= required (e.g. env1, env2)"; exit 64; } + cd scripts/ansible && CLUSTER_ENV=$(ENV) ansible-playbook -i inventory/tofu.py playbooks/cluster-bootstrap.yml \ + -e cluster_env=$(ENV) \ + $(if $(POOL),-e cluster_external_pool=$(POOL),) \ + $(_ANSIBLE_EXTRA) + +.PHONY: build build-ui build-installer build-lb-agent build-system-image build-eks-server-image import-eks-server-image build-eks-agent-image build-microvm-image install-microvm go_build go_run preflight test test-cover test-race diff-coverage bench run test-actions test-harness manifest-check diff-coverage bench run \ deploy reinstall clean \ install-system install-go install-aws quickinstall \ lint fix govulncheck \ distro distro-amd64 distro-arm64 distro-clean \ - ansible-dev-preflight ansible-dev-teardown ansible-dev-install ansible-dev-reset ansible-dev-deploy ansible-dev-status ansible-dev-logs ansible-dev-snapshot ansible-dev-restore ansible-dev-version ansible-dev-vpc + ansible-dev-preflight ansible-dev-teardown ansible-dev-install ansible-dev-reset ansible-dev-deploy ansible-dev-status ansible-dev-logs ansible-dev-snapshot ansible-dev-restore ansible-dev-version ansible-dev-vpc \ + ansible-cluster-bootstrap diff --git a/cmd/spinifex/cmd/admin.go b/cmd/spinifex/cmd/admin.go index 44f201de7..188700d33 100644 --- a/cmd/spinifex/cmd/admin.go +++ b/cmd/spinifex/cmd/admin.go @@ -325,6 +325,7 @@ func init() { imagesImportCmd.Flags().String("tmp-dir", os.TempDir(), "Temporary directory for image import processing") imagesImportCmd.Flags().String("name", "", "Import specified image by name") + imagesImportCmd.Flags().String("ami-name", "", "Override the registered AMI name (DescribeImages name). Defaults to ami-{distro}-{version}-{arch}. Use for locally-built appliances (e.g. --ami-name spinifex-eks-server).") imagesImportCmd.Flags().String("file", "", "Import file from specified path (raw, qcow2, compressed)") imagesImportCmd.Flags().String("distro", "", "Specified distro name (e.g debian)") imagesImportCmd.Flags().String("version", "", "Specified distro version (e.g 12)") @@ -380,6 +381,7 @@ func runimagesImportCmd(cmd *cobra.Command, args []string) { // and the file is used directly (no download). When only --file is set, // metadata comes from flags and no catalog tags are applied. imageName, _ := cmd.Flags().GetString("name") + amiNameOverride, _ := cmd.Flags().GetString("ami-name") localFile, _ := cmd.Flags().GetString("file") if imageName == "" && localFile == "" { @@ -535,6 +537,9 @@ func runimagesImportCmd(cmd *cobra.Command, args []string) { // Calculate the size manifest.AMIMetadata.Name = fmt.Sprintf("ami-%s-%s-%s", image.Distro, image.Version, image.Arch) + if amiNameOverride != "" { + manifest.AMIMetadata.Name = amiNameOverride + } volumeId := utils.GenerateResourceID("ami") manifest.AMIMetadata.ImageID = volumeId diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index d01dae7bf..e07b01ff2 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -89,7 +89,7 @@ Operational commands for inspecting cluster state. These fan out NATS requests t | Command | Flags | Prerequisites | Basic Logic | Test Cases | Status | |---------|-------|---------------|-------------|------------|--------| -| `spx admin images import` | `--name`, `--file`, `--distro`, `--version`, `--arch`, `--platform`, `--boot-mode` (bios/uefi/uefi-preferred), `--tag`, `--force`, `--skip-verify` | Cluster must be running; either `--name` (catalog download) or `--file` (operator-supplied media). `--file` mode additionally requires `--distro`, `--version`, `--arch`, `--boot-mode`. | Catalog imports (`--name`) download the image, fetch the catalog `Checksum` URL, verify the SHA-256/SHA-512 digest, and inherit `BootMode` from the catalog entry. `--boot-mode` overrides the catalog value when set. Mismatch fails closed; the cached file is left on disk and `--force` re-downloads. `--file` imports skip checksum verification (operator-supplied media is outside Spinifex's trust boundary, the skip is logged at INFO for audit) and require an explicit `--boot-mode` because there is no catalog metadata to inherit from. `--skip-verify` bypasses verification for catalog imports and emits a WARN slog + stderr notice; use only for debugging or when upstream mirrors are confirmed-broken. | 1. Import valid catalog image (verifies checksum)
2. Tampered cache hit fails with `ErrChecksumMismatch`
3. `--force` recovers after a mismatch
4. `--file` import skips verification
5. `--skip-verify` bypasses checksum with WARN
6. `--file` without `--boot-mode` rejected
7. `--boot-mode=invalid` rejected | **DONE** | +| `spx admin images import` | `--name`, `--ami-name`, `--file`, `--distro`, `--version`, `--arch`, `--platform`, `--boot-mode` (bios/uefi/uefi-preferred), `--tag`, `--force`, `--skip-verify` | Cluster must be running; either `--name` (catalog download) or `--file` (operator-supplied media). `--file` mode additionally requires `--distro`, `--version`, `--arch`, `--boot-mode`. | Catalog imports (`--name`) download the image, fetch the catalog `Checksum` URL, verify the SHA-256/SHA-512 digest, and inherit `BootMode` from the catalog entry. `--boot-mode` overrides the catalog value when set. Mismatch fails closed; the cached file is left on disk and `--force` re-downloads. `--file` imports skip checksum verification (operator-supplied media is outside Spinifex's trust boundary, the skip is logged at INFO for audit) and require an explicit `--boot-mode` because there is no catalog metadata to inherit from. `--ami-name` overrides the registered AMI name (the `DescribeImages` name), which otherwise defaults to `ami-{distro}-{version}-{arch}`; use it for locally-built appliance images (e.g. `--ami-name spinifex-eks-server`) not in the catalog. `--skip-verify` bypasses verification for catalog imports and emits a WARN slog + stderr notice; use only for debugging or when upstream mirrors are confirmed-broken. | 1. Import valid catalog image (verifies checksum)
2. Tampered cache hit fails with `ErrChecksumMismatch`
3. `--force` recovers after a mismatch
4. `--file` import skips verification
5. `--skip-verify` bypasses checksum with WARN
6. `--file` without `--boot-mode` rejected
7. `--boot-mode=invalid` rejected | **DONE** | | `spx admin images list` | — | None | Lists available OS images that can be imported or downloaded | 1. List available images | **DONE** | | `spx admin images remove` | `--image-id` (required), `--force`, `--yes` | Cluster must be running; predastore reachable. Targets AMIs imported via `spx admin images import` (non-account `ImageOwnerAlias`, e.g. `"system"`). | Loads `ami-/config.json`, walks transitive dependents — copied snapshots whose `VolumeID == imageID`, volumes whose `SnapshotID` references the internal `snap-ami-` or any derived snap, and account AMIs created via `CopyImage` whose `SnapshotID` is a derived snap — then prompts (skipped with `--yes`) before deleting `ami-/config.json` (the DescribeImages barrier) followed by the rest of `ami-/` and `snap-ami-/`. Account-owned AMIs are refused with a hint pointing at `aws ec2 deregister-image` + `aws ec2 delete-snapshot`. `--force` bypasses the dependency, ownership and config-corrupt checks for salvage of orphaned blocks. | 1. Happy path: system AMI, no deps → deleted
2. Account-owned → refused with AWS-flow hint
3. Missing/corrupt config → `InvalidAMIID.NotFound` (salvageable with `--force`)
4. Dependent volume (direct or via copied snap) → refused
5. Dependent account AMI → refused
6. `--force` overrides dependents
7. Idempotent re-run after partial delete | **DONE** | diff --git a/scripts/build-system-image.sh b/scripts/build-system-image.sh index eaff2b855..2ec0501da 100755 --- a/scripts/build-system-image.sh +++ b/scripts/build-system-image.sh @@ -192,6 +192,9 @@ if [[ -f "$OUTPUT_RAW" ]] && [[ $(( $(date +%s) - $(stat -c %Y "$OUTPUT_RAW") )) echo "Importing as AMI..." rm -f "$OUTPUT_IMAGE" IMPORT_ARGS=(--file "$OUTPUT_RAW" --distro "${DISTRO}" --version "${DISTRO_VERSION}" --arch x86_64 --boot-mode "${BOOT_MODE}") + if [[ -n "${AMI_NAME:-}" ]]; then + IMPORT_ARGS+=(--ami-name "$AMI_NAME") + fi if [[ -n "${SYSTEM_TAG:-}" ]]; then IMPORT_ARGS+=(--tag "$SYSTEM_TAG") fi @@ -453,7 +456,7 @@ if [[ "$DO_IMPORT" == true ]]; then rm -f "$OUTPUT_IMAGE" IMPORT_ARGS=(--file "$OUTPUT_RAW" --distro "${DISTRO}" --version "${DISTRO_VERSION}" --arch x86_64 --boot-mode "${BOOT_MODE}") if [[ -n "${AMI_NAME:-}" ]]; then - IMPORT_ARGS+=(--name "$AMI_NAME") + IMPORT_ARGS+=(--ami-name "$AMI_NAME") fi if [[ -n "${SYSTEM_TAG:-}" ]]; then IMPORT_ARGS+=(--tag "$SYSTEM_TAG") @@ -465,7 +468,7 @@ else echo " --file $OUTPUT_RAW \\" NAME_HINT="" if [[ -n "${AMI_NAME:-}" ]]; then - NAME_HINT=" \\\n --name ${AMI_NAME}" + NAME_HINT=" \\\n --ami-name ${AMI_NAME}" fi if [[ -n "${SYSTEM_TAG:-}" ]]; then echo -e " --distro ${DISTRO} --version ${DISTRO_VERSION} --arch x86_64 --boot-mode ${BOOT_MODE}${NAME_HINT} \\" diff --git a/scripts/dev-install.sh b/scripts/dev-install.sh index f3f221534..7044d105e 100755 --- a/scripts/dev-install.sh +++ b/scripts/dev-install.sh @@ -90,6 +90,17 @@ fi echo "=== Building and installing microVM artifacts ===" cd "$PROJECT_ROOT" && make build-lb-agent install-microvm +# EKS control-plane AMI. Heavy (full Alpine + K3s build, needs sudo + network), +# so it is opt-in: set DEV_INSTALL_EKS=1 to build + register it. Without it, +# `aws eks create-cluster` fails AMI resolution until the operator runs +# `make import-eks-server-image` manually. +if [ "${DEV_INSTALL_EKS:-0}" = "1" ]; then + echo "=== Building + importing eks-server AMI ===" + cd "$PROJECT_ROOT" && make import-eks-server-image +else + echo "=== Skipping eks-server AMI (set DEV_INSTALL_EKS=1 to enable, or run 'make import-eks-server-image') ===" +fi + echo "=== Done ===" echo "Services: sudo systemctl status spinifex.target" echo "Logs: journalctl -u 'spinifex-*' -f" diff --git a/scripts/images/eks-server/k3s-first-boot.initd b/scripts/images/eks-server/k3s-first-boot.initd index ab7029a06..2e6fa6da7 100644 --- a/scripts/images/eks-server/k3s-first-boot.initd +++ b/scripts/images/eks-server/k3s-first-boot.initd @@ -4,11 +4,18 @@ # once the sentinel file is gone. description="K3s first-boot publisher (node-token + admin kubeconfig)" +# Backgrounded: the publisher waits up to 5min for K3s /healthz before it can +# read the node-token + kubeconfig, so it must not block the default runlevel. +# command_background is also required for output_log/error_log — start-stop-daemon +# rejects --stdout/--stderr without --background ("Failed to start k3s-first-boot"). command="/usr/local/sbin/k3s-first-boot" -command_background="no" +command_background="yes" pidfile="/run/k3s-first-boot.pid" -output_log="/var/log/k3s-first-boot.log" -error_log="/var/log/k3s-first-boot.log" +# Route to the serial console so the bootstrap publisher's progress (healthz +# wait, token/kubeconfig publish, errors) is visible in the orchestrator's +# host-side console capture — the VM has no operator login. Low volume. +output_log="/dev/console" +error_log="/dev/console" depend() { need k3s diff --git a/scripts/images/eks-server/k3s-first-boot.sh b/scripts/images/eks-server/k3s-first-boot.sh index bd871fefc..991ac5060 100644 --- a/scripts/images/eks-server/k3s-first-boot.sh +++ b/scripts/images/eks-server/k3s-first-boot.sh @@ -2,15 +2,16 @@ set -eu # k3s-first-boot — runs once after the K3s server reaches a healthy state. -# Reads the bootstrap node-token and admin kubeconfig that K3s writes during -# `--cluster-init`, rewrites the kubeconfig server address to the cluster's +# Reads the bootstrap node-token and admin kubeconfig that K3s writes at +# server startup, rewrites the kubeconfig server address to the cluster's # NLB endpoint (so workers and external kubectl can use it), and publishes # both as one-shot NATS messages for the spinifex cluster reconciler to # consume into KV. # # Required env (from cloud-init user-data /etc/spinifex-eks/first-boot.env): # SPINIFEX_NATS_URL nats://... -# SPINIFEX_NATS_CREDS_FILE /etc/spinifex-eks/nats.creds +# SPINIFEX_NATS_TOKEN shared NATS auth token +# SPINIFEX_NATS_CA /etc/spinifex-eks/nats-ca.pem (TLS CA bundle) # EKS_ACCOUNT_ID # EKS_CLUSTER_NAME # EKS_NLB_ENDPOINT https://{cluster}.{accountID}.eks.{region}.{suffix} @@ -43,23 +44,51 @@ for v in SPINIFEX_NATS_URL EKS_ACCOUNT_ID EKS_CLUSTER_NAME EKS_NLB_ENDPOINT; do [ -n "${val}" ] || die "env ${v} not set" done -# 1. Wait for K3s /healthz. K3s self-signs initially; --insecure-skip is fine -# here, we are on loopback. -log "waiting for K3s /healthz on 127.0.0.1:6443" -i=0 -while [ "${i}" -lt 300 ]; do - if curl -sk --max-time 2 https://127.0.0.1:6443/healthz | grep -q '^ok$'; then - log "K3s healthz ok after ${i}s" - break - fi - i=$((i + 2)) - sleep 2 -done -[ "${i}" -lt 300 ] || die "K3s did not become healthy within 5 minutes" - -# 2. Read node-token + admin kubeconfig. +# Paths K3s writes during server startup: the bootstrap node-token and the +# admin kubeconfig (used both to gate readiness and to publish downstream). TOKEN_FILE=/var/lib/rancher/k3s/server/node-token KUBECONFIG_FILE=/etc/rancher/k3s/k3s.yaml + +# 1. Wait for the apiserver to be ready to serve, gating on /readyz. K3s runs +# the apiserver with anonymous-auth=false, so an anonymous probe returns 401, +# never "ok" — the probe must be authenticated. Use the node's admin +# kubeconfig (kubectl get --raw), which k3s writes early in startup. kubectl +# exits 0 only when /readyz returns 200; on a failing sub-check it exits +# non-zero, so the body "ok" check plus exit status gates correctly. Every +# 30s the failing /readyz checks are logged so a stuck boot is diagnosable +# from the captured serial console. +log "waiting for K3s apiserver readiness (/readyz) on 127.0.0.1:6443" +i=0 +ready=0 +while [ "${i}" -lt 300 ]; do + if [ -r "${KUBECONFIG_FILE}" ] && \ + [ "$(kubectl --kubeconfig "${KUBECONFIG_FILE}" get --raw='/readyz' 2>/dev/null)" = "ok" ]; then + log "K3s apiserver ready after ${i}s" + ready=1 + break + fi + if [ $((i % 30)) -eq 0 ]; then + log "apiserver not ready after ${i}s:" + if [ -r "${KUBECONFIG_FILE}" ]; then + kubectl --kubeconfig "${KUBECONFIG_FILE}" get --raw='/readyz?verbose' 2>&1 \ + | grep -E '^\[-\]|failed$' | head -20 | while IFS= read -r l; do log " ${l}"; done + else + log " (admin kubeconfig ${KUBECONFIG_FILE} not written yet)" + fi + fi + i=$((i + 5)) + sleep 5 +done +if [ "${ready}" -ne 1 ]; then + log "K3s apiserver not ready within 5 minutes; last /readyz body:" + kubectl --kubeconfig "${KUBECONFIG_FILE}" get --raw='/readyz?verbose' 2>&1 \ + | head -40 | while IFS= read -r l; do log " ${l}"; done + log "last 40 lines of /var/log/k3s.log follow:" + tail -n 40 /var/log/k3s.log 2>/dev/null || log "(no /var/log/k3s.log)" + die "K3s apiserver not ready within 5 minutes" +fi + +# 2. Read the four bootstrap artifacts K3s wrote at server startup. [ -r "${TOKEN_FILE}" ] || die "${TOKEN_FILE} unreadable" [ -r "${KUBECONFIG_FILE}" ] || die "${KUBECONFIG_FILE} unreadable" @@ -67,23 +96,38 @@ NODE_TOKEN=$(cat "${TOKEN_FILE}") # K3s ships kubeconfig with server: https://127.0.0.1:6443 — rewrite to the # NLB endpoint so it works from outside the control plane VM. KUBECONFIG_REWRITTEN=$(sed "s|server: https://127\.0\.0\.1:6443|server: ${EKS_NLB_ENDPOINT}|" "${KUBECONFIG_FILE}") +# The cluster CA the daemon records (base64 PEM) is exactly the +# certificate-authority-data the admin kubeconfig already embeds. +CA_B64=$(awk '/certificate-authority-data:/ {print $2; exit}' "${KUBECONFIG_FILE}") +[ -n "${CA_B64}" ] || die "no certificate-authority-data in ${KUBECONFIG_FILE}" +# The OIDC JWKS the apiserver serves from the signing key cloud-init seeded. The +# daemon cross-checks its kid/kty against the controller-generated keypair. +JWKS=$(kubectl --kubeconfig "${KUBECONFIG_FILE}" get --raw='/openid/v1/jwks' 2>/dev/null) +[ -n "${JWKS}" ] || die "apiserver returned empty /openid/v1/jwks" -# 3. Publish one-shot NATS messages. Subjects per eks-v1.md Q14 + Q15. -TOKEN_SUBJ="eks.bus.${EKS_ACCOUNT_ID}.${EKS_CLUSTER_NAME}.k3s-bootstrap-token" -KUBE_SUBJ="eks.bus.${EKS_ACCOUNT_ID}.${EKS_CLUSTER_NAME}.k3s-admin-kubeconfig" - +# 3. Publish the four one-shot bootstrap messages. Each is a BootstrapEnvelope +# JSON document (handlers/eks/nats_bootstrap.go); jq encodes the values so +# embedded newlines/quotes in the kubeconfig and JWKS stay valid JSON. NATS_ARGS="-s ${SPINIFEX_NATS_URL}" -if [ -n "${SPINIFEX_NATS_CREDS_FILE:-}" ] && [ -f "${SPINIFEX_NATS_CREDS_FILE}" ]; then - NATS_ARGS="${NATS_ARGS} --creds ${SPINIFEX_NATS_CREDS_FILE}" +if [ -n "${SPINIFEX_NATS_TOKEN:-}" ]; then + NATS_ARGS="${NATS_ARGS} --token ${SPINIFEX_NATS_TOKEN}" +fi +if [ -n "${SPINIFEX_NATS_CA:-}" ] && [ -f "${SPINIFEX_NATS_CA}" ]; then + NATS_ARGS="${NATS_ARGS} --tlsca ${SPINIFEX_NATS_CA}" fi -log "publishing node-token to ${TOKEN_SUBJ}" -# shellcheck disable=SC2086 -printf '%s' "${NODE_TOKEN}" | nats ${NATS_ARGS} pub "${TOKEN_SUBJ}" --stdin +# publish_envelope : reads the envelope JSON from stdin. +publish_envelope() { + subj="eks.bus.${EKS_ACCOUNT_ID}.${EKS_CLUSTER_NAME}.$1" + log "publishing $1 to ${subj}" + # shellcheck disable=SC2086 + nats ${NATS_ARGS} pub "${subj}" --force-stdin +} -log "publishing admin kubeconfig to ${KUBE_SUBJ}" -# shellcheck disable=SC2086 -printf '%s' "${KUBECONFIG_REWRITTEN}" | nats ${NATS_ARGS} pub "${KUBE_SUBJ}" --stdin +jq -n --arg t "${NODE_TOKEN}" '{token: $t}' | publish_envelope k3s-bootstrap-token +jq -n --arg k "${KUBECONFIG_REWRITTEN}" '{adminKubeconfig: $k}' | publish_envelope k3s-admin-kubeconfig +jq -n --arg j "${JWKS}" '{jwks: $j}' | publish_envelope k3s-oidc-jwks +jq -n --arg c "${CA_B64}" '{certificateAuthority: $c}' | publish_envelope k3s-ca # 4. Self-disable. Remove sentinel, pull from runlevel. rm -f "${SENTINEL}" diff --git a/scripts/images/eks-server/k3s.initd b/scripts/images/eks-server/k3s.initd index ca69f2269..04ed37d3b 100644 --- a/scripts/images/eks-server/k3s.initd +++ b/scripts/images/eks-server/k3s.initd @@ -1,9 +1,9 @@ #!/sbin/openrc-run -# K3s server control plane. v1 = single-node embedded etcd (eks-v1.md Q6). -# --cluster-init bootstraps a new etcd quorum on first start; subsequent -# starts pick up the existing data dir at /var/lib/rancher/k3s. v2 HA grows -# the cluster by launching additional eks-server VMs with --server pointing -# at the existing NLB endpoint (Q17) — no AMI change required. +# K3s server control plane. v1 = single-node embedded SQLite (kine) datastore; +# the per-cluster config.yaml omits cluster-init so k3s uses SQLite, not etcd +# (etcd's per-commit fsync stalls on the viperblock root volume). Data lives at +# /var/lib/rancher/k3s; subsequent starts reuse it. Multi-server HA needs etcd +# and is deferred. description="K3s Kubernetes server (Mulga EKS control plane)" command="/usr/local/bin/k3s" @@ -13,8 +13,8 @@ pidfile="/run/k3s.pid" output_log="/var/log/k3s.log" error_log="/var/log/k3s.log" -# Generous start timeout — K3s bootstraps containerd, runs etcd cluster-init, -# pulls system images. First boot can take 2-3 minutes on cold cache. +# Generous start timeout — K3s bootstraps containerd, initialises the SQLite +# datastore, pulls system images. First boot can take 2-3 minutes on cold cache. start_stop_daemon_args="--wait 5000" depend() { diff --git a/scripts/images/eks-server/manifest.conf b/scripts/images/eks-server/manifest.conf index aca0fab02..1dcaadce0 100644 --- a/scripts/images/eks-server/manifest.conf +++ b/scripts/images/eks-server/manifest.conf @@ -3,14 +3,15 @@ IMAGE_DESCRIPTION="EKS K3s server VM — Alpine + K3s v1.32.5+k3s1 + eks-token-w DISTRO="alpine" ALPINE_VERSION="3.21.7" -# 4G fits Alpine + K3s server binary (~80MB) + etcd snapshot working set. -# K3s embedded etcd lives on the data volume the orchestrator attaches at -# LaunchSystemInstance time; root disk only carries the image + logs. +# 4G fits Alpine + K3s server binary (~80MB) + SQLite datastore working set. +# v1 single-node uses the embedded SQLite (kine) datastore under +# /var/lib/rancher/k3s on the root disk, which also carries the image + logs. IMAGE_SIZE="4G" # Packages required at runtime (K3s pulls cgroups + iptables; nats-cli used by -# first-boot publisher + state-report; etcd-client used by snapshot script). -APK_PACKAGES="ca-certificates curl iptables ip6tables conntrack-tools cgroup-tools etcd-ctl openrc" +# first-boot publisher + state-report; jq builds the bootstrap-message JSON +# envelopes; etcd-client used by snapshot script). +APK_PACKAGES="ca-certificates curl jq iptables ip6tables conntrack-tools cgroup-tools etcd-ctl openrc" # k3s binary downloaded by setup.sh (network access inside chroot); SHA256 # verified at install time per spec Q12. diff --git a/scripts/images/eks-server/setup.sh b/scripts/images/eks-server/setup.sh index 5803b0a3b..c2a1a6be5 100644 --- a/scripts/images/eks-server/setup.sh +++ b/scripts/images/eks-server/setup.sh @@ -68,7 +68,7 @@ mkdir -p /etc/rancher/k3s cat > /etc/rancher/k3s/config.yaml.skel <<'EOF' # Populated at first boot by cloud-init user-data via k3s-first-boot.sh. # Fields documented at https://docs.k3s.io/installation/configuration. -cluster-init: true +# No cluster-init: single-node v1 uses the embedded SQLite datastore, not etcd. disable: - traefik - servicelb @@ -82,4 +82,15 @@ touch /var/lib/spinifex-eks/first-boot.pending 2>/dev/null || { touch /var/lib/spinifex-eks/first-boot.pending } +# Bind /dev/console to the serial port so userspace boot output — OpenRC +# service starts, cloud-init, and k3s-first-boot diagnostics — reaches ttyS0, +# which the orchestrator captures to a host-side log. The stock Alpine cloud +# image lists `console=tty0` LAST in default_kernel_opts; Linux makes the last +# console= the controlling /dev/console, so userspace logs to the framebuffer +# and the serial capture sees only kernel dmesg. Reorder so ttyS0 is last in +# both the generator config and the already-rendered extlinux.conf. +sed -i \ + 's|console=ttyS0,115200n8 console=ttyAMA0,115200n8 console=tty0|console=tty0 console=ttyAMA0,115200n8 console=ttyS0,115200n8|' \ + /etc/update-extlinux.conf /boot/extlinux.conf + echo "[eks-server-setup] done" diff --git a/spinifex/awserrors/awserrors.go b/spinifex/awserrors/awserrors.go index 9d982e7f8..4466632b3 100644 --- a/spinifex/awserrors/awserrors.go +++ b/spinifex/awserrors/awserrors.go @@ -1,5 +1,7 @@ package awserrors +import "strings" + type ErrorMessage struct { HTTPCode int Message string @@ -366,6 +368,9 @@ var ( ErrorResourceCountExceeded = "ResourceCountExceeded" ErrorResourceCountLimitExceeded = "ResourceCountLimitExceeded" ErrorResourceLimitExceeded = "ResourceLimitExceeded" + ErrorResourceNotFound = "ResourceNotFound" + ErrorEKSResourceInUse = "ResourceInUseException" + ErrorEKSResourceNotFound = "ResourceNotFoundException" ErrorRetryableError = "RetryableError" ErrorRouteAlreadyExists = "RouteAlreadyExists" ErrorRouteLimitExceeded = "RouteLimitExceeded" @@ -481,6 +486,15 @@ func ValidErrorCode(code string) string { return ErrorServerInternal } +// IsErrorCode reports whether err carries the named AWS error code. Service +// handlers return these codes as plain strings (errors.New(code)), commonly +// wrapped with %w by orchestration callers, so the match is a substring test +// against err.Error() rather than equality. Use it to classify a delete error +// as idempotent (already-gone) or retryable (still-in-use) in teardown paths. +func IsErrorCode(err error, code string) bool { + return err != nil && strings.Contains(err.Error(), code) +} + var ErrorLookup = map[string]ErrorMessage{ ErrorAccountDisabled: {HTTPCode: 400, Message: "The functionality you have requested has been administratively disabled for this account."}, ErrorActiveVpcPeeringConnectionPerVpcLimitExceeded: {HTTPCode: 400, Message: "You've reached the limit on the number of active VPC peering connections you can have for the specified VPC."}, @@ -842,6 +856,9 @@ var ErrorLookup = map[string]ErrorMessage{ ErrorResourceCountExceeded: {HTTPCode: 400, Message: "You have exceeded the number of resources allowed for this request; for example, if you try to launch more instances than AWS allows in a single request. This limit is separate from your individual resource limit. If you get this error, break up your request into smaller requests; for example, if you are launching 15 instances, try launching 5 instances in 3 separate requests."}, ErrorResourceCountLimitExceeded: {HTTPCode: 400, Message: "You have exceeded a resource limit for creating routes."}, ErrorResourceLimitExceeded: {HTTPCode: 400, Message: "You have exceeded an Amazon EC2 resource limit. For example, you might have too many snapshot copies in progress."}, + ErrorResourceNotFound: {HTTPCode: 404, Message: "The specified resource was not found."}, + ErrorEKSResourceInUse: {HTTPCode: 409, Message: "A cluster with this name already exists in this account and Region. Delete the existing cluster, or choose a different name."}, + ErrorEKSResourceNotFound: {HTTPCode: 404, Message: "The specified cluster could not be found. You can view your available clusters with ListClusters. Amazon EKS clusters are Region specific."}, ErrorRetryableError: {HTTPCode: 400, Message: "A request submitted by an AWS service on your behalf could not be completed. The requesting service might automatically retry the request."}, ErrorRouteAlreadyExists: {HTTPCode: 409, Message: "A route for the specified CIDR block already exists in this route table."}, ErrorRouteLimitExceeded: {HTTPCode: 400, Message: "You've reached the limit on the number of routes that you can add to a route table."}, diff --git a/spinifex/daemon/daemon.go b/spinifex/daemon/daemon.go index 6fd535d65..8b4003837 100644 --- a/spinifex/daemon/daemon.go +++ b/spinifex/daemon/daemon.go @@ -1332,11 +1332,14 @@ func (d *Daemon) startCluster() error { } d.eksService, err = initServiceWithRetry("EKS service", func() (*handlers_eks.EKSServiceImpl, error) { - return handlers_eks.NewEKSServiceImplWithNATS(d.config, d.natsConn) + return handlers_eks.NewEKSServiceImpl(d.buildEKSServiceDeps()) }) if err != nil { return fmt.Errorf("failed to initialize EKS service: %w", err) } + if err := d.eksService.SpawnRegisteredReconcilers(); err != nil { + slog.Warn("EKS: SpawnRegisteredReconcilers failed", "err", err) + } // Ensure default VPC exists for system and admin accounts // (matches AWS: every account has a default VPC with IGW + default SG) @@ -1931,6 +1934,11 @@ func (d *Daemon) setupShutdown() { d.elbv2Service.Close() } + // Stop EKS per-cluster reconciler + bootstrap goroutines. + if d.eksService != nil { + d.eksService.Shutdown() + } + // Final cleanup for _, sub := range d.natsSubscriptions { // Unsubscribe from each subscription @@ -2214,26 +2222,15 @@ func (d *Daemon) wireLBAgentConfig() { } // Resolve gateway URL — the address LB VMs use to reach the AWS gateway. - // Precedence: - // 1. br-mgmt present + AWSGW on a dedicated IP distinct from AdvertiseIP - // (multi-node: AWSGW on a mgmt-only IP, VPC path can't reach it) → - // gateway URL is the AWSGW bind IP and lb-agent gets a bootcmd host - // route via br-mgmt. - // 2. AdvertiseIP set (single-node, or multi-node where AWSGW binds to - // the advertised IP) → AdvertiseIP. VMs reach it via VPC → external - // (OVN's own dnat_and_snat SNATs their reply back to the ALB EIP). - // Critically, we do NOT add the mgmt host route here: when host IPs - // on the WAN share the advertiseIP, the /32 route would steal the - // return path for host-initiated ALB connections — replies would - // egress via mgmt with the VM's 10.x source IP, bypass OVN's SNAT, - // and arrive at the host with a source that doesn't match the open - // TCP socket (the client dialed the EIP, not the VM IP). - // 3. br-mgmt present + AWSGW on 0.0.0.0 → br-mgmt IP (both LB flavours - // reach the daemon via mgmt). - // 4. DevNetworking shim → 10.0.2.2. - // 5. AWSGW bound to specific IP (no br-mgmt, no advertise) → that IP. - // 6. Else: error and skip assignment — no silent empty URL. - var gatewayHost string + // Host selection is centralized in resolveGatewayHost so the OIDC issuer + // host and EKS NATS URL come from the same source (see M7). The only + // LB-specific extra here is the multi-node mgmt host route: when the host + // resolves to a dedicated AWSGW bind IP reachable only over br-mgmt, the + // lb-agent needs a bootcmd /32 route via br-mgmt. We deliberately do NOT + // add that route when the host is AdvertiseIP — WAN host IPs may share the + // advertiseIP and a /32 would steal the return path for host-initiated ALB + // connections (reply egresses mgmt with the VM's 10.x source, bypassing + // OVN's SNAT, mismatching the open TCP socket dialed against the EIP). awsgwBindIP := "" if d.config.AWSGW.Host != "" { if h, _, splitErr := net.SplitHostPort(d.config.AWSGW.Host); splitErr == nil { @@ -2243,25 +2240,13 @@ func (d *Daemon) wireLBAgentConfig() { advertiseIP := d.config.AdvertiseIP - switch { - case d.mgmtBridgeIP != "" && awsgwBindIP != "" && awsgwBindIP != "0.0.0.0" && - !net.ParseIP(awsgwBindIP).IsLoopback() && awsgwBindIP != advertiseIP: - // Multi-node: AWSGW on a dedicated mgmt IP. VMs can't reach it via - // VPC → external, so add a bootcmd host route via br-mgmt. - gatewayHost = awsgwBindIP + gatewayHost := d.resolveGatewayHost() + + // Multi-node mgmt-dedicated AWSGW: host resolved to the bind IP over + // br-mgmt (case 1 in resolveGatewayHost). Loopback / no-mgmt / advertiseIP + // paths can't satisfy all three guards, so this matches only that case. + if gatewayHost != "" && gatewayHost == awsgwBindIP && d.mgmtBridgeIP != "" && awsgwBindIP != advertiseIP { d.mgmtRouteVia = awsgwBindIP - case advertiseIP != "" && advertiseIP != "0.0.0.0": - // Single-node, or multi-node where AWSGW binds to AdvertiseIP: VMs - // reach AWSGW via the normal VPC → external path. No mgmt host route. - gatewayHost = advertiseIP - case d.mgmtBridgeIP != "": - // br-mgmt present + AWSGW on 0.0.0.0 and no advertiseIP — br-mgmt IP - // is the only reachable address. - gatewayHost = d.mgmtBridgeIP - case d.config.Daemon.DevNetworking: - gatewayHost = "10.0.2.2" - case awsgwBindIP != "" && awsgwBindIP != "0.0.0.0": - gatewayHost = awsgwBindIP } // Extract port from AWSGW host config (e.g. "0.0.0.0:9999" → "9999"). diff --git a/spinifex/daemon/daemon_handlers_eks_test.go b/spinifex/daemon/daemon_handlers_eks_test.go index 3a2265546..5d446bd2a 100644 --- a/spinifex/daemon/daemon_handlers_eks_test.go +++ b/spinifex/daemon/daemon_handlers_eks_test.go @@ -26,8 +26,10 @@ func setupEKSDaemon(t *testing.T) (*Daemon, *nats.Conn) { } // requestEKS publishes a request on the given subject and returns the response -// payload. Every EKS handler in this branch returns NotImplemented, so the -// payload always decodes to that error code. +// payload. The non-lifecycle EKS handlers all return NotImplemented so the +// payload always decodes to that error code; CreateCluster / DescribeCluster +// / ListClusters / DeleteCluster have real bodies and are covered by their +// own handlers/eks unit tests. func requestEKS(t *testing.T, nc *nats.Conn, subject string) []byte { t.Helper() msg := nats.NewMsg(subject) @@ -55,12 +57,8 @@ func TestDaemonHandleEKS_AllHandlersDispatchToService(t *testing.T) { subject string handler nats.MsgHandler }{ - {"eks.CreateCluster", d.handleEKSCreateCluster}, - {"eks.DescribeCluster", d.handleEKSDescribeCluster}, - {"eks.ListClusters", d.handleEKSListClusters}, {"eks.UpdateClusterConfig", d.handleEKSUpdateClusterConfig}, {"eks.UpdateClusterVersion", d.handleEKSUpdateClusterVersion}, - {"eks.DeleteCluster", d.handleEKSDeleteCluster}, {"eks.CreateNodegroup", d.handleEKSCreateNodegroup}, {"eks.DescribeNodegroup", d.handleEKSDescribeNodegroup}, {"eks.ListNodegroups", d.handleEKSListNodegroups}, @@ -90,7 +88,7 @@ func TestDaemonHandleEKS_AllHandlersDispatchToService(t *testing.T) { {"eks.UntagResource", d.handleEKSUntagResource}, {"eks.ListTagsForResource", d.handleEKSListTagsForResource}, } - require.Equal(t, 34, len(cases), "expected exactly one handler per AWS EKS action") + require.Equal(t, 30, len(cases), "expected exactly one handler per non-lifecycle AWS EKS action") for _, c := range cases { t.Run(c.subject, func(t *testing.T) { diff --git a/spinifex/daemon/daemon_system_instance.go b/spinifex/daemon/daemon_system_instance.go index 948c20f80..bc4c47485 100644 --- a/spinifex/daemon/daemon_system_instance.go +++ b/spinifex/daemon/daemon_system_instance.go @@ -1,6 +1,8 @@ package daemon import ( + "encoding/base64" + "errors" "fmt" "log/slog" "os" @@ -12,6 +14,7 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" handlers_ec2_vpc "github.com/mulgadc/spinifex/spinifex/handlers/ec2/vpc" handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2" + "github.com/mulgadc/spinifex/spinifex/handlers/sysinstance" "github.com/mulgadc/spinifex/spinifex/network/topology" "github.com/mulgadc/spinifex/spinifex/tags" "github.com/mulgadc/spinifex/spinifex/utils" @@ -27,6 +30,9 @@ var _ handlers_elbv2.SystemInstanceLauncher = (*Daemon)(nil) // (bundled vmlinuz+initramfs, fw_cfg-delivered config). There is no AMI, // volume, or cloud-init path. func (d *Daemon) LaunchSystemInstance(input *handlers_elbv2.SystemInstanceInput) (*handlers_elbv2.SystemInstanceOutput, error) { + if input.BootMode == sysinstance.BootAMI { + return d.launchAMISystemInstance(input) + } accountID := utils.GlobalAccountID // ENI account may differ from system account — the ENI is created under // the caller's account, so lookups/updates must use that account ID. @@ -365,11 +371,129 @@ func (d *Daemon) LaunchSystemInstance(input *handlers_elbv2.SystemInstanceInput) }, nil } +// launchAMISystemInstance is the BootAMI branch of LaunchSystemInstance: a full +// AMI boot (root volume cloned from an AMI, cloud-init user-data + network +// config seed) for a system-managed VM, with a management-bridge NIC so the +// guest can reach the daemon (NATS/AWSGW) off its tenant VPC subnet. +// +// It mirrors the daemon RunInstances handler's Prepare → Insert → Launch split, +// allocating the mgmt NIC on the VM record between Insert and Launch so the +// cloud-init network-config rendered during Launch carries a static mgmt0 +// interface. The instance is owned by input.AccountID (the account its +// pre-created ENI lives in) and tagged input.ManagedBy so customer listings +// hide it. +func (d *Daemon) launchAMISystemInstance(input *sysinstance.SystemInstanceInput) (*sysinstance.SystemInstanceOutput, error) { + if d.instanceService == nil { + return nil, errors.New("sysinstance: instance service not initialized") + } + if input.ImageID == "" { + return nil, errors.New("sysinstance: BootAMI requires ImageID") + } + if input.AccountID == "" { + return nil, errors.New("sysinstance: BootAMI requires AccountID") + } + if input.ENIID == "" { + return nil, errors.New("sysinstance: BootAMI requires a pre-created ENI") + } + + runInput := &ec2.RunInstancesInput{ + ImageId: aws.String(input.ImageID), + InstanceType: aws.String(input.InstanceType), + MinCount: aws.Int64(1), + MaxCount: aws.Int64(1), + NetworkInterfaces: []*ec2.InstanceNetworkInterfaceSpecification{{ + NetworkInterfaceId: aws.String(input.ENIID), + DeviceIndex: aws.Int64(0), + }}, + } + if input.UserData != "" { + runInput.UserData = aws.String(base64.StdEncoding.EncodeToString([]byte(input.UserData))) + } + if input.ManagedBy != "" { + runInput.TagSpecifications = []*ec2.TagSpecification{{ + ResourceType: aws.String("instance"), + Tags: []*ec2.Tag{{Key: aws.String(tags.ManagedByKey), Value: aws.String(input.ManagedBy)}}, + }} + } + + _, instances, instanceType, err := d.instanceService.PrepareRunInstances(runInput, input.AccountID) + if err != nil { + return nil, err + } + if len(instances) == 0 { + return nil, errors.New("sysinstance: PrepareRunInstances returned no instance") + } + inst := instances[0] + inst.ManagedBy = input.ManagedBy + + for _, instance := range instances { + d.vmMgr.Insert(instance) + } + + // Management NIC must be set before LaunchRunInstances so the cloud-init + // network-config (built during launch) renders a static mgmt0 interface. + if err := d.attachSystemMgmtNIC(inst); err != nil { + d.vmMgr.MarkFailed(inst, "mgmt_nic_setup_failed") + return nil, err + } + + d.instanceService.LaunchRunInstances(instances, runInput, instanceType) + + privateIP := input.ENIIP + if privateIP == "" && inst.Instance != nil { + privateIP = aws.StringValue(inst.Instance.PrivateIpAddress) + } + slog.Info("LaunchSystemInstance (AMI) completed", + "instanceId", inst.ID, + "managedBy", input.ManagedBy, + "imageId", input.ImageID, + "mgmtIP", inst.MgmtIP, + "privateIp", privateIP, + ) + return &sysinstance.SystemInstanceOutput{ + InstanceID: inst.ID, + PrivateIP: privateIP, + MgmtIP: inst.MgmtIP, + }, nil +} + +// attachSystemMgmtNIC allocates a management-bridge IP + MAC for a system VM and +// creates the host-side tap on br-mgmt. The mgmt NIC is mandatory for system +// instances that boot from an AMI: their VPC ENI has no route off the tenant +// subnet, so the mgmt NIC is the only path to the daemon (NATS/AWSGW). On +// failure it releases the IP and returns an error so the caller can fail the +// launch. +func (d *Daemon) attachSystemMgmtNIC(inst *vm.VM) error { + if d.mgmtIPAllocator == nil || d.mgmtBridgeIP == "" { + return errors.New("sysinstance: management bridge unavailable; system VM would have no route to the daemon") + } + mgmtBridge := "br-mgmt" + if d.config.Daemon.MgmtBridge != "" { + mgmtBridge = d.config.Daemon.MgmtBridge + } + mgmtIP, err := d.mgmtIPAllocator.Allocate(inst.ID) + if err != nil { + return fmt.Errorf("allocate mgmt IP: %w", err) + } + inst.MgmtMAC = vm.GenerateMgmtMAC(inst.ID) + inst.MgmtIP = mgmtIP + tapName := vm.MgmtTapName(inst.ID) + if err := d.networkPlumber.SetupTap(vm.TapSpec{Name: tapName, Bridge: mgmtBridge}); err != nil { + d.mgmtIPAllocator.Release(inst.ID) + inst.MgmtMAC = "" + inst.MgmtIP = "" + return fmt.Errorf("setup mgmt tap: %w", err) + } + slog.Info("System instance mgmt NIC configured", + "instanceId", inst.ID, "mgmtIP", mgmtIP, "mgmtMAC", inst.MgmtMAC, "mgmtTap", tapName) + return nil +} + // TerminateSystemInstance stops and cleans up a system-managed VM. func (d *Daemon) TerminateSystemInstance(instanceID string) error { instance, exists := d.vmMgr.Get(instanceID) if !exists { - return fmt.Errorf("instance %s not found", instanceID) + return fmt.Errorf("%w: %s", sysinstance.ErrSystemInstanceNotFound, instanceID) } // Release EIP through the EIP service for system VMs whose public IP was diff --git a/spinifex/daemon/eks_adapter.go b/spinifex/daemon/eks_adapter.go new file mode 100644 index 000000000..38e5a19ba --- /dev/null +++ b/spinifex/daemon/eks_adapter.go @@ -0,0 +1,31 @@ +package daemon + +import ( + "errors" + + handlers_eks "github.com/mulgadc/spinifex/spinifex/handlers/eks" +) + +// daemonEKSSubnetResolver adapts the daemon's VPCServiceImpl to the +// handlers_eks subnetVPCResolver-equivalent. handlers/eks declares the +// interface privately; the daemon needs an exported shape only because the +// constructor wires it via EKSServiceDeps.SubnetResolver = ... +// +// The translation is trivial: VPCService.GetSubnet returns a SubnetRecord +// with VpcId, which is the only field the EKS launcher needs. +type daemonEKSSubnetResolver struct { + d *Daemon +} + +func (a *daemonEKSSubnetResolver) GetSubnetVPC(accountID, subnetID string) (string, error) { + if a.d == nil || a.d.vpcService == nil { + return "", errors.New("eks: VPC service not initialized") + } + rec, err := a.d.vpcService.GetSubnet(accountID, subnetID) + if err != nil { + return "", err + } + return rec.VpcId, nil +} + +var _ handlers_eks.SubnetVPCResolver = (*daemonEKSSubnetResolver)(nil) diff --git a/spinifex/daemon/eks_deps.go b/spinifex/daemon/eks_deps.go new file mode 100644 index 000000000..2a0e63ef3 --- /dev/null +++ b/spinifex/daemon/eks_deps.go @@ -0,0 +1,159 @@ +package daemon + +import ( + "net" + "os" + "path/filepath" + + handlers_eks "github.com/mulgadc/spinifex/spinifex/handlers/eks" + handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam" + "log/slog" +) + +// buildEKSServiceDeps assembles the EKSServiceDeps the EKS service needs to +// run CreateCluster/DescribeCluster/ListClusters/DeleteCluster end-to-end. +// All collaborators must already be initialized; callers invoke this from +// Daemon.startCluster after VPC, ELBv2, Instance, and Image services are +// ready. +// +// MasterKey is loaded best-effort from the config dir (the directory holding +// spinifex.toml — same place admin init writes master.key, and the same +// resolution daemon TLS + predastore config use). A missing key disables OIDC +// envelope encryption, which in turn fails CreateCluster at the +// depsReadyForOrchestration gate — the daemon logs and continues. +func (d *Daemon) buildEKSServiceDeps() handlers_eks.EKSServiceDeps { + masterKey, err := handlers_iam.LoadMasterKey(filepath.Join(filepath.Dir(d.configPath), "master.key")) + if err != nil { + slog.Warn("EKS: LoadMasterKey failed; CreateCluster + DeleteCluster will reject until key is provisioned", + "err", err) + masterKey = nil + } + + // CA PEM the K3s server VM uses to verify the daemon's NATS TLS. Same CA + // that signs the AWSGW server cert; read here so the VM can publish its + // one-shot bootstrap messages over the token+TLS NATS endpoint. + natsCA := "" + if d.config.NATS.CACert != "" { + if caBytes, readErr := os.ReadFile(d.config.NATS.CACert); readErr == nil { + natsCA = string(caBytes) + } else { + slog.Warn("EKS: read NATS CACert failed; K3s server VM will not reach NATS over TLS", + "path", d.config.NATS.CACert, "err", readErr) + } + } + + return handlers_eks.EKSServiceDeps{ + Config: d.config, + NATSConn: d.natsConn, + MasterKey: masterKey, + GatewayBaseURL: d.resolveGatewayBaseURL(), + Region: d.config.Region, + HolderID: d.node, + NATSURL: d.resolveSystemNATSURL(), + NATSToken: d.config.NATS.ACL.Token, + NATSCACert: natsCA, + VPCSG: d.vpcService, + VPCK3s: d.vpcService, + VPCSubnet: &daemonEKSSubnetResolver{d: d}, + NLB: d.elbv2Service, + Instance: d, + Image: d.imageService, + EIP: d.eipService, + } +} + +// resolveGatewayHost is the single source of truth for the off-host-reachable +// address LB VMs, EKS OIDC issuers, and the EKS NATS URL all dial. startCluster +// and buildEKSServiceDeps both call it so the OIDC issuer host can never +// diverge from the host the lb-agent actually reaches (M7). Precedence: +// +// 1. br-mgmt present + AWSGW on a dedicated non-loopback IP distinct from +// AdvertiseIP (multi-node: AWSGW on a mgmt-only IP, VPC path can't reach +// it) → the AWSGW bind IP. startCluster additionally adds a bootcmd host +// route via br-mgmt for this case only. +// 2. AdvertiseIP set → AdvertiseIP (single-node, or multi-node where AWSGW +// binds the advertised IP; VMs reach it via VPC → external). +// 3. br-mgmt present + AWSGW on 0.0.0.0, no AdvertiseIP → the br-mgmt IP. +// 4. DevNetworking shim → 10.0.2.2. +// 5. AWSGW bound to a specific IP (no br-mgmt, no advertise) → that IP. +// +// Returns "" if no reachable host can be derived. +func (d *Daemon) resolveGatewayHost() string { + awsgwBindIP := "" + if d.config.AWSGW.Host != "" { + if h, _, splitErr := net.SplitHostPort(d.config.AWSGW.Host); splitErr == nil { + awsgwBindIP = h + } + } + advertiseIP := d.config.AdvertiseIP + + switch { + case d.mgmtBridgeIP != "" && awsgwBindIP != "" && awsgwBindIP != "0.0.0.0" && + !net.ParseIP(awsgwBindIP).IsLoopback() && awsgwBindIP != advertiseIP: + return awsgwBindIP + case advertiseIP != "" && advertiseIP != "0.0.0.0": + return advertiseIP + case d.mgmtBridgeIP != "": + return d.mgmtBridgeIP + case d.config.Daemon.DevNetworking: + return "10.0.2.2" + case awsgwBindIP != "" && awsgwBindIP != "0.0.0.0": + return awsgwBindIP + } + return "" +} + +// resolveGatewayBaseURL is the HTTPS AWSGW endpoint EKS OIDC issuers are built +// from. Returns "" if no reachable host can be derived, in which case +// CreateCluster fails at depsReadyForOrchestration. +func (d *Daemon) resolveGatewayBaseURL() string { + host := d.resolveGatewayHost() + if host == "" { + return "" + } + gatewayPort := "9999" + if d.config.AWSGW.Host != "" { + if _, port, splitErr := net.SplitHostPort(d.config.AWSGW.Host); splitErr == nil && port != "" { + gatewayPort = port + } + } + return "https://" + net.JoinHostPort(host, gatewayPort) +} + +// resolveSystemNATSURL derives the NATS URL a system instance (the K3s server +// VM) dials to publish its one-shot bootstrap messages. Unlike a customer VM, +// a system instance reaches the daemon only over the mgmt bridge: its cloud-init +// mgmt0 NIC is on-link to mgmtBridgeIP with no off-link route, so NATS must be +// dialed at the bridge address directly. NATS listens on 0.0.0.0:4222, so the +// bridge IP is reachable. Falls back to resolveNATSURL() (gateway-host +// precedence) when no mgmt bridge exists — e.g. dev-shim networking. +func (d *Daemon) resolveSystemNATSURL() string { + if d.mgmtBridgeIP == "" { + return d.resolveNATSURL() + } + natsPort := "4222" + if d.config.NATS.Host != "" { + if _, port, splitErr := net.SplitHostPort(d.config.NATS.Host); splitErr == nil && port != "" { + natsPort = port + } + } + return "nats://" + net.JoinHostPort(d.mgmtBridgeIP, natsPort) +} + +// resolveNATSURL derives the NATS URL the K3s server VM dials to publish its +// one-shot bootstrap messages. Host reuses the gateway host resolution; port +// comes from the configured NATS listen address (default 4222). Returns "" if +// no reachable host can be derived. +func (d *Daemon) resolveNATSURL() string { + host := d.resolveGatewayHost() + if host == "" { + return "" + } + natsPort := "4222" + if d.config.NATS.Host != "" { + if _, port, splitErr := net.SplitHostPort(d.config.NATS.Host); splitErr == nil && port != "" { + natsPort = port + } + } + return "nats://" + net.JoinHostPort(host, natsPort) +} diff --git a/spinifex/daemon/eks_deps_test.go b/spinifex/daemon/eks_deps_test.go new file mode 100644 index 000000000..3b5499440 --- /dev/null +++ b/spinifex/daemon/eks_deps_test.go @@ -0,0 +1,86 @@ +package daemon + +import ( + "testing" + + "github.com/mulgadc/spinifex/spinifex/config" + "github.com/stretchr/testify/assert" +) + +// TestResolveGatewayHost covers all five host-selection branches plus the +// no-reachable-host fallthrough. resolveGatewayHost is the single source of +// truth for the OIDC issuer host, EKS NATS URL, and lb-agent gateway URL, so +// each branch is pinned here to prevent silent divergence (M7). +func TestResolveGatewayHost(t *testing.T) { + tests := []struct { + name string + awsgwHost string + advertiseIP string + mgmtBridge string + devNet bool + want string + }{ + { + name: "1_mgmt_dedicated_awsgw_ip", + awsgwHost: "10.20.0.5:9999", + advertiseIP: "203.0.113.7", + mgmtBridge: "10.15.8.1", + want: "10.20.0.5", + }, + { + name: "1_skipped_when_bind_equals_advertise_falls_to_advertise", + awsgwHost: "203.0.113.7:9999", + advertiseIP: "203.0.113.7", + mgmtBridge: "10.15.8.1", + want: "203.0.113.7", + }, + { + name: "1_skipped_when_bind_loopback_falls_to_mgmt", + awsgwHost: "127.0.0.1:9999", + mgmtBridge: "10.15.8.1", + want: "10.15.8.1", + }, + { + name: "2_advertise_ip", + awsgwHost: "0.0.0.0:9999", + advertiseIP: "203.0.113.7", + want: "203.0.113.7", + }, + { + name: "3_mgmt_bridge_when_awsgw_wildcard", + awsgwHost: "0.0.0.0:9999", + mgmtBridge: "10.15.8.1", + want: "10.15.8.1", + }, + { + name: "4_dev_networking_shim", + awsgwHost: "0.0.0.0:9999", + devNet: true, + want: "10.0.2.2", + }, + { + name: "5_awsgw_specific_ip_no_mgmt_no_advertise", + awsgwHost: "198.51.100.9:9999", + want: "198.51.100.9", + }, + { + name: "6_no_reachable_host", + awsgwHost: "0.0.0.0:9999", + want: "", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + d := &Daemon{ + mgmtBridgeIP: tc.mgmtBridge, + config: &config.Config{ + AdvertiseIP: tc.advertiseIP, + AWSGW: config.AWSGWConfig{Host: tc.awsgwHost}, + Daemon: config.DaemonConfig{DevNetworking: tc.devNet}, + }, + } + assert.Equal(t, tc.want, d.resolveGatewayHost()) + }) + } +} diff --git a/spinifex/daemon/vm_adapters.go b/spinifex/daemon/vm_adapters.go index 95891d638..0210a88dd 100644 --- a/spinifex/daemon/vm_adapters.go +++ b/spinifex/daemon/vm_adapters.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "log/slog" - "strings" "time" "github.com/aws/aws-sdk-go/service/ec2" @@ -631,7 +630,7 @@ func (a *instanceCleanerAdapter) DetachAndDeleteENI(instance *vm.VM) { if _, eniErr := a.d.vpcService.DeleteNetworkInterface(&ec2.DeleteNetworkInterfaceInput{ NetworkInterfaceId: &instance.ENIId, }, instance.AccountID); eniErr != nil { - if strings.Contains(eniErr.Error(), awserrors.ErrorInvalidNetworkInterfaceIDNotFound) { + if awserrors.IsErrorCode(eniErr, awserrors.ErrorInvalidNetworkInterfaceIDNotFound) { slog.Debug("ENI already cleaned up on termination", "eni", instance.ENIId) } else { slog.Error("Failed to delete ENI on termination", diff --git a/spinifex/daemon/vpc_adapter.go b/spinifex/daemon/vpc_adapter.go index da9ca0466..b44431230 100644 --- a/spinifex/daemon/vpc_adapter.go +++ b/spinifex/daemon/vpc_adapter.go @@ -39,6 +39,22 @@ func (a *daemonENICreator) GetSubnet(accountID, subnetID string) (*handlers_ec2_ }, nil } +func (a *daemonENICreator) GetENI(accountID, eniID string) (*handlers_ec2_instance.ENIInfo, error) { + rec, err := a.d.vpcService.GetENIRecord(accountID, eniID) + if err != nil { + return nil, err + } + return &handlers_ec2_instance.ENIInfo{ + NetworkInterfaceID: rec.NetworkInterfaceId, + SubnetID: rec.SubnetId, + VpcID: rec.VpcId, + PrivateIpAddress: rec.PrivateIpAddress, + MacAddress: rec.MacAddress, + Status: rec.Status, + SecurityGroupIDs: rec.SecurityGroupIds, + }, nil +} + func (a *daemonENICreator) CreateNetworkInterface(input *ec2.CreateNetworkInterfaceInput, accountID string) (*ec2.CreateNetworkInterfaceOutput, error) { return a.d.vpcService.CreateNetworkInterface(input, accountID) } diff --git a/spinifex/gateway/eks/handler.go b/spinifex/gateway/eks/handler.go index 2c45485f2..837cc6825 100644 --- a/spinifex/gateway/eks/handler.go +++ b/spinifex/gateway/eks/handler.go @@ -12,6 +12,7 @@ import ( "log/slog" "net/http" + "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil" "github.com/mulgadc/spinifex/spinifex/awserrors" ) @@ -41,9 +42,13 @@ func GenerateEKSErrorResponse(code, message string) []byte { return body } -// WriteJSONResponse serializes obj as JSON and writes it as a 200 response. +// WriteJSONResponse serializes obj as AWS REST-JSON and writes it as a 200 +// response. aws-sdk-go *Output structs tag their fields with locationName (the +// restjson wire name) and carry no json: tags, so encoding/json would emit Go +// PascalCase keys the AWS SDK cannot parse. jsonutil.BuildJSON is the same +// marshaler the SDK uses for restjson bodies and honors locationName. func WriteJSONResponse(w http.ResponseWriter, obj any) { - body, err := json.Marshal(obj) + body, err := jsonutil.BuildJSON(obj) if err != nil { slog.Error("Failed to marshal EKS response JSON", "err", err) WriteJSONError(w, awserrors.ErrorInternalError, "failed to marshal response", http.StatusInternalServerError) diff --git a/spinifex/gateway/eks/handler_test.go b/spinifex/gateway/eks/handler_test.go index 711366bc3..68b9e2e2d 100644 --- a/spinifex/gateway/eks/handler_test.go +++ b/spinifex/gateway/eks/handler_test.go @@ -7,6 +7,8 @@ import ( "net/http/httptest" "testing" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/eks" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -42,6 +44,64 @@ func TestWriteJSONResponse_SerializesObject(t *testing.T) { assert.Equal(t, "bar", got["foo"]) } +// TestWriteJSONResponse_RestJSONWireShape guards against regressing to +// encoding/json, which ignores aws-sdk-go's locationName tags and emits Go +// PascalCase keys the AWS SDK cannot parse. The body must carry the lowercase +// restjson field names, nested all the way down. +func TestWriteJSONResponse_RestJSONWireShape(t *testing.T) { + w := httptest.NewRecorder() + out := &eks.DescribeClusterOutput{ + Cluster: &eks.Cluster{ + Name: aws.String("smoke"), + Status: aws.String("ACTIVE"), + Endpoint: aws.String("https://internal-eks-smoke:443"), + Identity: &eks.Identity{ + Oidc: &eks.OIDC{Issuer: aws.String("https://gw/oidc/eks/x")}, + }, + }, + } + WriteJSONResponse(w, out) + require.Equal(t, http.StatusOK, w.Code) + + body := w.Body.String() + for _, k := range []string{`"cluster"`, `"name"`, `"status"`, `"endpoint"`, `"identity"`, `"oidc"`, `"issuer"`} { + assert.Contains(t, body, k, "restjson body missing lowercase key %s", k) + } + for _, k := range []string{`"Cluster"`, `"Status"`, `"Endpoint"`, `"Identity"`, `"Issuer"`} { + assert.NotContains(t, body, k, "restjson body leaked PascalCase key %s — encoding/json regression", k) + } + + // The AWS SDK round-trips through the same restjson nested keys. + var got struct { + Cluster struct { + Status string `json:"status"` + Endpoint string `json:"endpoint"` + Identity struct { + Oidc struct { + Issuer string `json:"issuer"` + } `json:"oidc"` + } `json:"identity"` + } `json:"cluster"` + } + require.NoError(t, json.Unmarshal(w.Body.Bytes(), &got)) + assert.Equal(t, "ACTIVE", got.Cluster.Status) + assert.Equal(t, "https://internal-eks-smoke:443", got.Cluster.Endpoint) + assert.Equal(t, "https://gw/oidc/eks/x", got.Cluster.Identity.Oidc.Issuer) +} + +func TestWriteJSONResponse_ListClustersWireShape(t *testing.T) { + w := httptest.NewRecorder() + WriteJSONResponse(w, &eks.ListClustersOutput{ + Clusters: aws.StringSlice([]string{"alpha", "beta"}), + NextToken: aws.String("tok"), + }) + body := w.Body.String() + assert.Contains(t, body, `"clusters"`) + assert.Contains(t, body, `"nextToken"`) + assert.NotContains(t, body, `"Clusters"`) + assert.NotContains(t, body, `"NextToken"`) +} + type sampleInput struct { Name string `json:"name"` } diff --git a/spinifex/handlers/ec2/instance/service.go b/spinifex/handlers/ec2/instance/service.go index c552157c3..8c7e40d42 100644 --- a/spinifex/handlers/ec2/instance/service.go +++ b/spinifex/handlers/ec2/instance/service.go @@ -129,15 +129,32 @@ type SubnetInfo struct { MapPublicIpOnLaunch bool } +// ENIInfo carries the subset of ENI metadata RunInstances needs to attach a +// pre-created ENI as the primary interface. Translated from +// handlers/ec2/vpc.ENIRecord by the daemon adapter to avoid a cyclic +// instance↔vpc import. +type ENIInfo struct { + NetworkInterfaceID string + SubnetID string + VpcID string + PrivateIpAddress string + MacAddress string + Status string + SecurityGroupIDs []string +} + // ENICreator covers the VPC/ENI operations RunInstances performs while // auto-attaching a primary interface. Implemented via an adapter over // handlers/ec2/vpc.VPCServiceImpl on the daemon. DetachENI lives here (not on // ENIDeleter) because the launch-time NAT-rollback path needs to flip the ENI // to "available" before ENIDeleter.DeleteNetworkInterface, which rejects -// in-use ENIs. +// in-use ENIs. GetENI supports the pre-created-ENI launch path where the +// caller passes NetworkInterfaces[0].NetworkInterfaceId and RunInstances +// attaches the existing ENI instead of creating a new one. type ENICreator interface { GetDefaultSubnet(accountID string) (*SubnetInfo, error) GetSubnet(accountID, subnetID string) (*SubnetInfo, error) + GetENI(accountID, eniID string) (*ENIInfo, error) CreateNetworkInterface(input *ec2.CreateNetworkInterfaceInput, accountID string) (*ec2.CreateNetworkInterfaceOutput, error) AttachENI(accountID, eniID, instanceID string, deviceIndex int64) (string, error) DetachENI(accountID, eniID string) error diff --git a/spinifex/handlers/ec2/instance/service_impl.go b/spinifex/handlers/ec2/instance/service_impl.go index 5e0c17b53..7515443bf 100644 --- a/spinifex/handlers/ec2/instance/service_impl.go +++ b/spinifex/handlers/ec2/instance/service_impl.go @@ -631,6 +631,35 @@ func (s *InstanceServiceImpl) PrepareRunInstances(input *ec2.RunInstancesInput, } } + // Pre-created ENI path: when the caller passes + // NetworkInterfaces[0].NetworkInterfaceId, attach that existing ENI + // instead of auto-creating one. AWS-parity behaviour; consumed by the + // EKS cluster launcher which needs the ENI to live under the customer + // account before the K3s server VM is created. + preExistingENIID := "" + if len(input.NetworkInterfaces) > 0 && input.NetworkInterfaces[0] != nil { + preExistingENIID = aws.StringValue(input.NetworkInterfaces[0].NetworkInterfaceId) + } + if preExistingENIID != "" { + if s.eniCreator == nil { + slog.Error("PrepareRunInstances: pre-created ENI specified but ENI service unavailable", + "instanceId", instance.ID, "eniId", preExistingENIID) + lastRunErr = errors.New(awserrors.ErrorServerInternal) + s.resourceMgr.Deallocate(instanceType) + continue + } + if err := s.attachPreCreatedENI(accountID, preExistingENIID, instance, ec2Instance); err != nil { + slog.Error("PrepareRunInstances: pre-created ENI attach failed", + "instanceId", instance.ID, "eniId", preExistingENIID, "err", err) + lastRunErr = err + s.resourceMgr.Deallocate(instanceType) + continue + } + instances = append(instances, instance) + allEC2Instances = append(allEC2Instances, ec2Instance) + continue + } + if (input.SubnetId == nil || *input.SubnetId == "") && s.eniCreator != nil { defaultSubnet, dsErr := s.eniCreator.GetDefaultSubnet(accountID) if dsErr == nil && defaultSubnet != nil { @@ -774,6 +803,62 @@ func (s *InstanceServiceImpl) PrepareRunInstances(input *ec2.RunInstancesInput, return reservation, instances, instanceType, nil } +// attachPreCreatedENI looks up an existing ENI in accountID, verifies it is +// not already in-use, attaches it as device-0 to instance, and populates the +// VM + ec2.Instance with the ENI's network identity (private IP, MAC, subnet, +// VPC, security groups). Returns an error without mutating any state if the +// lookup or attach fails. Public-IP auto-assignment is skipped on the +// pre-created path because the caller is expected to manage that out-of-band. +func (s *InstanceServiceImpl) attachPreCreatedENI(accountID, eniID string, instance *vm.VM, ec2Instance *ec2.Instance) error { + eniInfo, err := s.eniCreator.GetENI(accountID, eniID) + if err != nil { + return err + } + if eniInfo == nil { + return errors.New(awserrors.ErrorInvalidNetworkInterfaceIDNotFound) + } + if eniInfo.Status == "in-use" { + return errors.New(awserrors.ErrorInvalidNetworkInterfaceInUse) + } + if _, err := s.eniCreator.AttachENI(accountID, eniID, instance.ID, 0); err != nil { + return err + } + + instance.ENIId = eniID + instance.ENIMac = eniInfo.MacAddress + + ec2Instance.SetPrivateIpAddress(eniInfo.PrivateIpAddress) + ec2Instance.SetSubnetId(eniInfo.SubnetID) + ec2Instance.SetVpcId(eniInfo.VpcID) + if len(eniInfo.SecurityGroupIDs) > 0 { + groups := make([]*ec2.GroupIdentifier, 0, len(eniInfo.SecurityGroupIDs)) + for _, id := range eniInfo.SecurityGroupIDs { + groups = append(groups, &ec2.GroupIdentifier{GroupId: aws.String(id)}) + } + ec2Instance.SecurityGroups = groups + } + ec2Instance.NetworkInterfaces = []*ec2.InstanceNetworkInterface{{ + NetworkInterfaceId: aws.String(eniID), + PrivateIpAddress: aws.String(eniInfo.PrivateIpAddress), + MacAddress: aws.String(eniInfo.MacAddress), + SubnetId: aws.String(eniInfo.SubnetID), + VpcId: aws.String(eniInfo.VpcID), + Status: aws.String("in-use"), + Attachment: &ec2.InstanceNetworkInterfaceAttachment{ + DeviceIndex: aws.Int64(0), + Status: aws.String("attached"), + }, + }} + + slog.Info("PrepareRunInstances: attached pre-created ENI", + "instanceId", instance.ID, + "eniId", eniID, + "privateIp", eniInfo.PrivateIpAddress, + "mac", eniInfo.MacAddress, + ) + return nil +} + // LaunchRunInstances takes the VMs created by PrepareRunInstances (already // inserted into vmMgr by the caller) and runs the heavyweight launch loop: // volume preparation, GPU claim, vmMgr.Run. Failures mark the VM as failed diff --git a/spinifex/handlers/ec2/instance/service_impl_test.go b/spinifex/handlers/ec2/instance/service_impl_test.go index 9d8e81b4f..099e64000 100644 --- a/spinifex/handlers/ec2/instance/service_impl_test.go +++ b/spinifex/handlers/ec2/instance/service_impl_test.go @@ -2451,7 +2451,10 @@ func TestStopOrTerminateInstance_TerminationProtection(t *testing.T) { type fakeENICreator struct { defaultSubnet *SubnetInfo subnet *SubnetInfo + getENIByID map[string]*ENIInfo + getENIErr error createOut *ec2.CreateNetworkInterfaceOutput + createCalls int createErr error attachErr error attachCalls int @@ -2474,7 +2477,22 @@ func (f *fakeENICreator) GetSubnet(_, _ string) (*SubnetInfo, error) { return f.subnet, nil } +func (f *fakeENICreator) GetENI(_, eniID string) (*ENIInfo, error) { + if f.getENIErr != nil { + return nil, f.getENIErr + } + if f.getENIByID == nil { + return nil, errors.New("no ENI configured") + } + info, ok := f.getENIByID[eniID] + if !ok { + return nil, errors.New("eni not found") + } + return info, nil +} + func (f *fakeENICreator) CreateNetworkInterface(_ *ec2.CreateNetworkInterfaceInput, _ string) (*ec2.CreateNetworkInterfaceOutput, error) { + f.createCalls++ if f.createErr != nil { return nil, f.createErr } @@ -3188,3 +3206,115 @@ func TestInstanceArchitecture(t *testing.T) { }) } } + +func TestPrepareRunInstances_PreCreatedENIAttachedSkipsAutoCreate(t *testing.T) { + eni := &fakeENICreator{ + getENIByID: map[string]*ENIInfo{ + "eni-pre": { + NetworkInterfaceID: "eni-pre", + SubnetID: "subnet-pre", + VpcID: "vpc-pre", + PrivateIpAddress: "10.0.5.42", + MacAddress: "aa:bb:cc:dd:ee:01", + Status: "available", + SecurityGroupIDs: []string{"sg-pre"}, + }, + }, + } + svc, _ := prepareSvcWithENI(t, eni, nil) + + _, instances, _, err := svc.PrepareRunInstances(&ec2.RunInstancesInput{ + InstanceType: aws.String("t3.micro"), + ImageId: aws.String("ami-1"), + MinCount: aws.Int64(1), + MaxCount: aws.Int64(1), + NetworkInterfaces: []*ec2.InstanceNetworkInterfaceSpecification{{ + NetworkInterfaceId: aws.String("eni-pre"), + DeviceIndex: aws.Int64(0), + }}, + }, "acc") + require.NoError(t, err) + require.Len(t, instances, 1) + assert.Equal(t, "eni-pre", instances[0].ENIId) + assert.Equal(t, "aa:bb:cc:dd:ee:01", instances[0].ENIMac) + assert.Equal(t, 1, eni.attachCalls) + assert.Equal(t, 0, eni.createCalls, "auto-create must not run when NetworkInterfaceId is specified") +} + +func TestPrepareRunInstances_PreCreatedENIInUseRejected(t *testing.T) { + eni := &fakeENICreator{ + getENIByID: map[string]*ENIInfo{ + "eni-busy": { + NetworkInterfaceID: "eni-busy", + Status: "in-use", + }, + }, + } + svc, _ := prepareSvcWithENI(t, eni, nil) + + _, _, _, err := svc.PrepareRunInstances(&ec2.RunInstancesInput{ + InstanceType: aws.String("t3.micro"), + ImageId: aws.String("ami-1"), + MinCount: aws.Int64(1), + MaxCount: aws.Int64(1), + NetworkInterfaces: []*ec2.InstanceNetworkInterfaceSpecification{{ + NetworkInterfaceId: aws.String("eni-busy"), + }}, + }, "acc") + require.Error(t, err) + assert.Equal(t, awserrors.ErrorInvalidNetworkInterfaceInUse, err.Error()) + assert.Equal(t, 0, eni.attachCalls, "in-use ENI must not be attached") + assert.Equal(t, 0, eni.createCalls, "auto-create must not run when NetworkInterfaceId is specified") +} + +func TestPrepareRunInstances_PreCreatedENILookupErrorSurfaced(t *testing.T) { + eni := &fakeENICreator{ + getENIErr: errors.New(awserrors.ErrorInvalidNetworkInterfaceIDNotFound), + } + svc, _ := prepareSvcWithENI(t, eni, nil) + + _, _, _, err := svc.PrepareRunInstances(&ec2.RunInstancesInput{ + InstanceType: aws.String("t3.micro"), + ImageId: aws.String("ami-1"), + MinCount: aws.Int64(1), + MaxCount: aws.Int64(1), + NetworkInterfaces: []*ec2.InstanceNetworkInterfaceSpecification{{ + NetworkInterfaceId: aws.String("eni-ghost"), + }}, + }, "acc") + require.Error(t, err) + assert.Equal(t, awserrors.ErrorInvalidNetworkInterfaceIDNotFound, err.Error()) + assert.Equal(t, 0, eni.attachCalls) + assert.Equal(t, 0, eni.createCalls) +} + +func TestPrepareRunInstances_PreCreatedENIAttachErrorSurfaced(t *testing.T) { + eni := &fakeENICreator{ + getENIByID: map[string]*ENIInfo{ + "eni-pre": { + NetworkInterfaceID: "eni-pre", + Status: "available", + PrivateIpAddress: "10.0.5.42", + MacAddress: "aa:bb:cc:dd:ee:01", + SubnetID: "subnet-pre", + VpcID: "vpc-pre", + }, + }, + attachErr: errors.New(awserrors.ErrorServerInternal), + } + svc, _ := prepareSvcWithENI(t, eni, nil) + + _, _, _, err := svc.PrepareRunInstances(&ec2.RunInstancesInput{ + InstanceType: aws.String("t3.micro"), + ImageId: aws.String("ami-1"), + MinCount: aws.Int64(1), + MaxCount: aws.Int64(1), + NetworkInterfaces: []*ec2.InstanceNetworkInterfaceSpecification{{ + NetworkInterfaceId: aws.String("eni-pre"), + }}, + }, "acc") + require.Error(t, err) + assert.Equal(t, awserrors.ErrorServerInternal, err.Error()) + assert.Equal(t, 1, eni.attachCalls) + assert.Equal(t, 0, eni.createCalls) +} diff --git a/spinifex/handlers/eks/awsgw_endpoint.go b/spinifex/handlers/eks/awsgw_endpoint.go new file mode 100644 index 000000000..4031512f3 --- /dev/null +++ b/spinifex/handlers/eks/awsgw_endpoint.go @@ -0,0 +1,47 @@ +package handlers_eks + +import ( + "errors" + "fmt" + "net/url" + "strings" +) + +// ClusterOIDCIssuer returns the public OIDC issuer URL for one cluster. This +// is the URL kube-apiserver advertises as service-account-issuer and the URL +// that AWS STS / external IRSA validators fetch /.well-known/openid-configuration +// against. Format per plan §10.6: +// +// {gatewayBaseURL}/oidc/eks/{region}/{accountID}/{clusterName} +// +// gatewayBaseURL is the awsgw HTTPS endpoint (e.g. "https://10.0.0.1:9999"), +// without a trailing /oidc. Validates that region/accountID/clusterName are +// non-empty and URL-safe. +func ClusterOIDCIssuer(gatewayBaseURL, region, accountID, clusterName string) (string, error) { + if gatewayBaseURL == "" { + return "", errors.New("eks: ClusterOIDCIssuer empty gatewayBaseURL") + } + if region == "" { + return "", errors.New("eks: ClusterOIDCIssuer empty region") + } + if accountID == "" { + return "", errors.New("eks: ClusterOIDCIssuer empty accountID") + } + if clusterName == "" { + return "", errors.New("eks: ClusterOIDCIssuer empty clusterName") + } + parsed, err := url.Parse(gatewayBaseURL) + if err != nil { + return "", fmt.Errorf("parse gatewayBaseURL %q: %w", gatewayBaseURL, err) + } + if parsed.Scheme == "" || parsed.Host == "" { + return "", fmt.Errorf("eks: gatewayBaseURL %q missing scheme or host", gatewayBaseURL) + } + for name, v := range map[string]string{"region": region, "accountID": accountID, "clusterName": clusterName} { + if strings.ContainsAny(v, "/?#") { + return "", fmt.Errorf("eks: %s %q contains URL-unsafe characters", name, v) + } + } + base := strings.TrimRight(gatewayBaseURL, "/") + return fmt.Sprintf("%s/oidc/eks/%s/%s/%s", base, region, accountID, clusterName), nil +} diff --git a/spinifex/handlers/eks/awsgw_endpoint_test.go b/spinifex/handlers/eks/awsgw_endpoint_test.go new file mode 100644 index 000000000..7fec30e97 --- /dev/null +++ b/spinifex/handlers/eks/awsgw_endpoint_test.go @@ -0,0 +1,62 @@ +package handlers_eks + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestClusterOIDCIssuer_HappyPath(t *testing.T) { + got, err := ClusterOIDCIssuer("https://gw.example:9999", "us-east-1", "111122223333", "alpha") + require.NoError(t, err) + assert.Equal(t, "https://gw.example:9999/oidc/eks/us-east-1/111122223333/alpha", got) +} + +func TestClusterOIDCIssuer_TrimsTrailingSlash(t *testing.T) { + got, err := ClusterOIDCIssuer("https://gw.example:9999/", "us-east-1", "111122223333", "alpha") + require.NoError(t, err) + assert.Equal(t, "https://gw.example:9999/oidc/eks/us-east-1/111122223333/alpha", got) +} + +func TestClusterOIDCIssuer_EmptyInputsRejected(t *testing.T) { + cases := []struct { + name string + base, region, accountID, clusterName, want string + }{ + {"empty base", "", "us-east-1", "111122223333", "alpha", "gatewayBaseURL"}, + {"empty region", "https://gw", "", "111122223333", "alpha", "region"}, + {"empty accountID", "https://gw", "us-east-1", "", "alpha", "accountID"}, + {"empty clusterName", "https://gw", "us-east-1", "111122223333", "", "clusterName"}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + _, err := ClusterOIDCIssuer(tc.base, tc.region, tc.accountID, tc.clusterName) + require.Error(t, err) + assert.Contains(t, err.Error(), tc.want) + }) + } +} + +func TestClusterOIDCIssuer_MalformedBaseRejected(t *testing.T) { + _, err := ClusterOIDCIssuer("not-a-url", "us-east-1", "111122223333", "alpha") + require.Error(t, err) + assert.Contains(t, err.Error(), "missing scheme or host") +} + +func TestClusterOIDCIssuer_URLUnsafeInputsRejected(t *testing.T) { + cases := []struct { + field, region, accountID, clusterName string + }{ + {"region", "us/east", "111122223333", "alpha"}, + {"accountID", "us-east-1", "111?ab", "alpha"}, + {"clusterName", "us-east-1", "111122223333", "alpha#frag"}, + } + for _, tc := range cases { + t.Run(tc.field, func(t *testing.T) { + _, err := ClusterOIDCIssuer("https://gw", tc.region, tc.accountID, tc.clusterName) + require.Error(t, err) + assert.Contains(t, err.Error(), "URL-unsafe") + }) + } +} diff --git a/spinifex/handlers/eks/cluster_reconciler.go b/spinifex/handlers/eks/cluster_reconciler.go new file mode 100644 index 000000000..fc4cde12d --- /dev/null +++ b/spinifex/handlers/eks/cluster_reconciler.go @@ -0,0 +1,338 @@ +package handlers_eks + +import ( + "context" + "crypto/tls" + "errors" + "fmt" + "log/slog" + "net/http" + "time" + + "github.com/nats-io/nats.go" +) + +const ( + defaultReconcileLeaseRefresh = 20 * time.Second + defaultReconcileInterval = 30 * time.Second + defaultHealthzTimeout = 5 * time.Second + // defaultCreateTimeout bounds how long a cluster may sit in CREATING before + // the reconciler gives up and marks it FAILED. Measured from meta.CreatedAt + // (absolute), so a VM that never boots reaches a terminal state even across + // daemon restarts. Plan Risk #1. + defaultCreateTimeout = 15 * time.Minute +) + +// ErrReconcilerLeaseLost is returned by Run when the leader lease was lost +// mid-loop. Callers can re-Acquire and re-Run if they want to keep driving +// reconcile from the same node. +var ErrReconcilerLeaseLost = errors.New("eks: reconciler lease lost") + +// ErrReconcilerClusterDeleting is returned by Run when meta.Status is +// observed as DELETING; the DeleteCluster service-impl path is responsible +// for teardown, so the reconciler exits without further work. +var ErrReconcilerClusterDeleting = errors.New("eks: cluster deleting") + +// ErrReconcilerClusterFailed is returned by Run when meta.Status is FAILED. +var ErrReconcilerClusterFailed = errors.New("eks: cluster failed") + +// HTTPDoer is the minimum http.Client surface the reconciler needs for +// /healthz probes; tests stub it without a TLS server. +type HTTPDoer interface { + Do(req *http.Request) (*http.Response, error) +} + +// ClusterReconciler drives one cluster's CREATING → ACTIVE → DELETING +// lifecycle under a leader lease. One instance per (accountID, clusterName); +// the leader lease arbitrates which spinifex node actually drives reconcile. +type ClusterReconciler struct { + leaderKV nats.KeyValue + acctKV nats.KeyValue + accountID string + clusterName string + holderID string + healthURL string + + leaseRefresh time.Duration + interval time.Duration + healthTimeout time.Duration + createTimeout time.Duration + httpClient HTTPDoer +} + +// ReconcilerOption tunes a ClusterReconciler. Tests use the With* helpers to +// shrink tickers and inject a stub HTTP client. +type ReconcilerOption func(*ClusterReconciler) + +// WithReconcileInterval overrides the default reconcile loop period. +func WithReconcileInterval(d time.Duration) ReconcilerOption { + return func(r *ClusterReconciler) { r.interval = d } +} + +// WithLeaseRefresh overrides the default leader-lease refresh period. Should +// be less than KVBucketEKSLeaderTTL. +func WithLeaseRefresh(d time.Duration) ReconcilerOption { + return func(r *ClusterReconciler) { r.leaseRefresh = d } +} + +// WithHealthzTimeout overrides the per-probe HTTP timeout. +func WithHealthzTimeout(d time.Duration) ReconcilerOption { + return func(r *ClusterReconciler) { r.healthTimeout = d } +} + +// WithCreateTimeout overrides how long a cluster may remain CREATING before the +// reconciler marks it FAILED. +func WithCreateTimeout(d time.Duration) ReconcilerOption { + return func(r *ClusterReconciler) { r.createTimeout = d } +} + +// WithHTTPClient injects a stub HTTPDoer (tests). +func WithHTTPClient(c HTTPDoer) ReconcilerOption { + return func(r *ClusterReconciler) { r.httpClient = c } +} + +// NewClusterReconciler constructs a ClusterReconciler. healthURL is the +// fully-qualified probe target (e.g. https://nlb-dns:443/healthz) or empty +// to skip /healthz probing (CREATING transitions on bootstrap state alone). +func NewClusterReconciler(leaderKV, acctKV nats.KeyValue, accountID, clusterName, holderID, healthURL string, opts ...ReconcilerOption) (*ClusterReconciler, error) { + if leaderKV == nil { + return nil, errors.New("eks: NewClusterReconciler nil leaderKV") + } + if acctKV == nil { + return nil, errors.New("eks: NewClusterReconciler nil acctKV") + } + if accountID == "" { + return nil, errors.New("eks: NewClusterReconciler empty accountID") + } + if clusterName == "" { + return nil, errors.New("eks: NewClusterReconciler empty clusterName") + } + if holderID == "" { + return nil, errors.New("eks: NewClusterReconciler empty holderID") + } + r := &ClusterReconciler{ + leaderKV: leaderKV, + acctKV: acctKV, + accountID: accountID, + clusterName: clusterName, + holderID: holderID, + healthURL: healthURL, + leaseRefresh: defaultReconcileLeaseRefresh, + interval: defaultReconcileInterval, + healthTimeout: defaultHealthzTimeout, + createTimeout: defaultCreateTimeout, + httpClient: &http.Client{ + Timeout: defaultHealthzTimeout, + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, //nolint:gosec // K3s NLB is self-signed; CA pinning is a v2 hardening item + }, + }, + }, + } + for _, o := range opts { + o(r) + } + return r, nil +} + +func reconcilerLeaderKey(accountID, clusterName string) string { + return accountID + "/" + clusterName +} + +// AcquireLease attempts a CAS Create on the leader bucket. Returns +// (release, true) if this caller is now the leader; (nil, false) otherwise. +// The release closure performs a best-effort kv.Delete; the bucket's 60s +// TTL reaps stale leases when release does not run (crashed leader). +func (r *ClusterReconciler) AcquireLease() (func(), bool) { + key := reconcilerLeaderKey(r.accountID, r.clusterName) + if _, err := r.leaderKV.Create(key, []byte(r.holderID)); err != nil { + slog.Debug("ClusterReconciler: lease held by another holder", + "key", key, "holderID", r.holderID, "err", err) + return nil, false + } + slog.Info("ClusterReconciler: lease acquired", "key", key, "holderID", r.holderID) + return func() { + if err := r.leaderKV.Delete(key); err != nil { + slog.Warn("ClusterReconciler: lease release failed (TTL will reap)", + "key", key, "holderID", r.holderID, "err", err) + } + }, true +} + +// RefreshLease re-asserts ownership via a CAS update on the leader key. +// Returns false if the key was taken by another holder or the CAS conflicts. +func (r *ClusterReconciler) RefreshLease() bool { + key := reconcilerLeaderKey(r.accountID, r.clusterName) + entry, err := r.leaderKV.Get(key) + if err != nil { + slog.Warn("ClusterReconciler: lease get failed", "key", key, "err", err) + return false + } + if string(entry.Value()) != r.holderID { + slog.Info("ClusterReconciler: lease now held by another holder", + "key", key, "holderID", r.holderID, "got", string(entry.Value())) + return false + } + if _, err := r.leaderKV.Update(key, []byte(r.holderID), entry.Revision()); err != nil { + slog.Warn("ClusterReconciler: lease CAS update failed", + "key", key, "holderID", r.holderID, "err", err) + return false + } + return true +} + +// Run drives reconcile until ctx is cancelled, the lease is lost, or the +// cluster reaches a terminal state. Caller is expected to AcquireLease first; +// Run does not re-acquire. +func (r *ClusterReconciler) Run(ctx context.Context) error { + refreshT := time.NewTicker(r.leaseRefresh) + defer refreshT.Stop() + reconcileT := time.NewTicker(r.interval) + defer reconcileT.Stop() + + if err := r.reconcileOnce(ctx); err != nil { + if terminalReconcileErr(err) { + return err + } + slog.Warn("ClusterReconciler: initial reconcile failed", + "cluster", r.clusterName, "err", err) + } + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case <-refreshT.C: + if !r.RefreshLease() { + return ErrReconcilerLeaseLost + } + case <-reconcileT.C: + if err := r.reconcileOnce(ctx); err != nil { + if terminalReconcileErr(err) { + return err + } + slog.Warn("ClusterReconciler: reconcile failed", + "cluster", r.clusterName, "err", err) + } + } + } +} + +func terminalReconcileErr(err error) bool { + return errors.Is(err, ErrReconcilerClusterDeleting) || + errors.Is(err, ErrReconcilerClusterFailed) || + errors.Is(err, ErrClusterNotFound) +} + +func (r *ClusterReconciler) reconcileOnce(ctx context.Context) error { + meta, err := GetClusterMeta(r.acctKV, r.clusterName) + if err != nil { + return err + } + switch meta.Status { + case ClusterStatusCreating: + ready, reason := r.bootstrapReady(meta) + if !ready { + slog.Debug("ClusterReconciler: bootstrap not ready", + "cluster", r.clusterName, "reason", reason) + return r.failIfCreateTimedOut(meta, "bootstrap not ready: "+reason) + } + if err := r.probeHealthz(ctx); err != nil { + slog.Debug("ClusterReconciler: /healthz still failing", + "cluster", r.clusterName, "err", err) + return r.failIfCreateTimedOut(meta, "healthz not ready: "+err.Error()) + } + if err := SetClusterStatus(r.acctKV, r.clusterName, ClusterStatusActive); err != nil { + return err + } + slog.Info("ClusterReconciler: cluster transitioned to ACTIVE", + "cluster", r.clusterName) + case ClusterStatusActive: + issue := "" + if err := r.probeHealthz(ctx); err != nil { + slog.Warn("ClusterReconciler: /healthz failing for ACTIVE cluster", + "cluster", r.clusterName, "err", err) + issue = err.Error() + } + if err := SetClusterHealth(r.acctKV, r.clusterName, issue); err != nil { + if errors.Is(err, ErrClusterNotFound) { + return ErrClusterNotFound + } + return fmt.Errorf("record cluster health: %w", err) + } + case ClusterStatusDeleting: + return ErrReconcilerClusterDeleting + case ClusterStatusFailed: + return ErrReconcilerClusterFailed + } + return nil +} + +// failIfCreateTimedOut transitions a still-CREATING cluster to FAILED once it +// has exceeded createTimeout since meta.CreatedAt, and returns +// ErrReconcilerClusterFailed so Run exits the loop. While still within the +// window it returns nil so the next tick retries. A zero or absent CreatedAt +// disables the deadline (no false-positive fail on a malformed record). +func (r *ClusterReconciler) failIfCreateTimedOut(meta *ClusterMeta, reason string) error { + if r.createTimeout <= 0 || meta.CreatedAt.IsZero() { + return nil + } + if time.Since(meta.CreatedAt) < r.createTimeout { + return nil + } + failReason := fmt.Sprintf("cluster did not become ACTIVE within %s: %s", r.createTimeout, reason) + if err := MarkClusterFailed(r.acctKV, r.clusterName, failReason); err != nil { + if errors.Is(err, ErrClusterNotFound) { + return ErrClusterNotFound + } + return fmt.Errorf("mark create-timeout failed: %w", err) + } + slog.Warn("ClusterReconciler: CREATING timed out, marked FAILED", + "cluster", r.clusterName, "timeout", r.createTimeout, "reason", reason) + return ErrReconcilerClusterFailed +} + +// bootstrapReady returns true once the four NATS bootstrap KV artifacts are +// present: node token, admin kubeconfig, the OIDC JWKS verified-marker, and the +// CA on meta. The JWKS gate is the verified-marker (written only after the VM's +// published JWKS passes the controller cross-check), NOT the pre-seeded +// OIDCJWKSKey — so a cluster never transitions to ACTIVE on an unverified or +// mismatched signing key. +func (r *ClusterReconciler) bootstrapReady(meta *ClusterMeta) (bool, string) { + if meta.CertificateAuthorityB64 == "" { + return false, "CA absent on meta" + } + keys := []string{ + NodeTokenKey(r.clusterName), + AdminKubeconfigKey(r.clusterName), + OIDCJWKSVerifiedKey(r.clusterName), + } + for _, k := range keys { + if _, err := r.acctKV.Get(k); err != nil { + return false, fmt.Sprintf("%s missing: %s", k, err) + } + } + return true, "" +} + +func (r *ClusterReconciler) probeHealthz(ctx context.Context) error { + if r.healthURL == "" { + return nil + } + probeCtx, cancel := context.WithTimeout(ctx, r.healthTimeout) + defer cancel() + req, err := http.NewRequestWithContext(probeCtx, http.MethodGet, r.healthURL, nil) + if err != nil { + return fmt.Errorf("new request: %w", err) + } + resp, err := r.httpClient.Do(req) + if err != nil { + return fmt.Errorf("healthz request: %w", err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("eks: /healthz status %d", resp.StatusCode) + } + return nil +} diff --git a/spinifex/handlers/eks/cluster_reconciler_test.go b/spinifex/handlers/eks/cluster_reconciler_test.go new file mode 100644 index 000000000..f327e5571 --- /dev/null +++ b/spinifex/handlers/eks/cluster_reconciler_test.go @@ -0,0 +1,469 @@ +package handlers_eks + +import ( + "context" + "errors" + "io" + "net/http" + "strings" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/mulgadc/spinifex/spinifex/testutil" + "github.com/nats-io/nats.go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// stubHTTPDoer is a fake HTTPDoer that returns a configurable status code + +// optional error, and tracks the number of calls for assertion. +type stubHTTPDoer struct { + mu sync.Mutex + calls atomic.Int32 + status int + err error +} + +func (s *stubHTTPDoer) Do(_ *http.Request) (*http.Response, error) { + s.calls.Add(1) + s.mu.Lock() + err := s.err + status := s.status + s.mu.Unlock() + if err != nil { + return nil, err + } + return &http.Response{StatusCode: status, Body: io.NopCloser(strings.NewReader(""))}, nil +} + +func (s *stubHTTPDoer) setResponse(status int, err error) { + s.mu.Lock() + defer s.mu.Unlock() + s.status = status + s.err = err +} + +func newReconcilerHarness(t *testing.T, healthURL string, opts ...ReconcilerOption) (*ClusterReconciler, nats.KeyValue, nats.KeyValue) { + t.Helper() + _, _, js := testutil.StartTestJetStream(t) + leaderKV, err := InitLeaderBucket(js) + require.NoError(t, err) + acctKV, err := GetOrCreateAccountBucket(js, testAccountID) + require.NoError(t, err) + require.NoError(t, PutClusterMeta(acctKV, sampleClusterMeta("alpha"))) + + r, err := NewClusterReconciler(leaderKV, acctKV, testAccountID, "alpha", "holder-1", healthURL, opts...) + require.NoError(t, err) + return r, leaderKV, acctKV +} + +func TestNewClusterReconciler_EmptyInputsRejected(t *testing.T) { + _, _, js := testutil.StartTestJetStream(t) + leaderKV, err := InitLeaderBucket(js) + require.NoError(t, err) + acctKV, err := GetOrCreateAccountBucket(js, testAccountID) + require.NoError(t, err) + + _, err = NewClusterReconciler(nil, acctKV, testAccountID, "alpha", "h", "") + require.Error(t, err) + _, err = NewClusterReconciler(leaderKV, nil, testAccountID, "alpha", "h", "") + require.Error(t, err) + _, err = NewClusterReconciler(leaderKV, acctKV, "", "alpha", "h", "") + require.Error(t, err) + _, err = NewClusterReconciler(leaderKV, acctKV, testAccountID, "", "h", "") + require.Error(t, err) + _, err = NewClusterReconciler(leaderKV, acctKV, testAccountID, "alpha", "", "") + require.Error(t, err) +} + +func TestClusterReconciler_AcquireLeaseFirstHolderWins(t *testing.T) { + r, _, _ := newReconcilerHarness(t, "") + + release, ok := r.AcquireLease() + require.True(t, ok) + require.NotNil(t, release) + defer release() + + // Second AcquireLease from same holder must fail (Create returns KeyExists). + release2, ok2 := r.AcquireLease() + assert.False(t, ok2) + assert.Nil(t, release2) +} + +func TestClusterReconciler_AcquireLeaseSecondHolderLoses(t *testing.T) { + r1, leaderKV, acctKV := newReconcilerHarness(t, "") + + release, ok := r1.AcquireLease() + require.True(t, ok) + defer release() + + r2, err := NewClusterReconciler(leaderKV, acctKV, testAccountID, "alpha", "holder-2", "") + require.NoError(t, err) + release2, ok2 := r2.AcquireLease() + assert.False(t, ok2) + assert.Nil(t, release2) +} + +func TestClusterReconciler_RefreshLeaseFailsAfterStolen(t *testing.T) { + r, leaderKV, _ := newReconcilerHarness(t, "") + + release, ok := r.AcquireLease() + require.True(t, ok) + defer release() + + assert.True(t, r.RefreshLease(), "refresh should succeed while we own the key") + + // Steal the key by overwriting its value via Put. + _, err := leaderKV.Put(reconcilerLeaderKey(testAccountID, "alpha"), []byte("holder-2")) + require.NoError(t, err) + + assert.False(t, r.RefreshLease(), "refresh should fail after another holder stole the key") +} + +func TestClusterReconciler_RefreshLeaseFailsWhenKeyDeleted(t *testing.T) { + r, leaderKV, _ := newReconcilerHarness(t, "") + release, ok := r.AcquireLease() + require.True(t, ok) + defer release() + + require.NoError(t, leaderKV.Delete(reconcilerLeaderKey(testAccountID, "alpha"))) + assert.False(t, r.RefreshLease()) +} + +// freshenClusterCreatedAt re-stamps the cluster meta's CreatedAt to now so the +// reconciler's CREATING deadline is far from expiry. sampleClusterMeta uses a +// fixed past date, which would otherwise trip the create-timeout in tests that +// assert the cluster stays CREATING. +func freshenClusterCreatedAt(t *testing.T, kv nats.KeyValue) { + t.Helper() + meta, err := GetClusterMeta(kv, "alpha") + require.NoError(t, err) + meta.CreatedAt = time.Now().UTC() + require.NoError(t, PutClusterMeta(kv, meta)) +} + +func seedBootstrapState(t *testing.T, kv nats.KeyValue) { + t.Helper() + _, err := kv.Put(NodeTokenKey("alpha"), []byte("enc-token")) + require.NoError(t, err) + _, err = kv.Put(AdminKubeconfigKey("alpha"), []byte("enc-kc")) + require.NoError(t, err) + // Pre-seeded JWKS plus the verified-marker persistJWKS writes on a passing + // cross-check — bootstrapReady gates ACTIVE on the marker, not the seed. + _, err = kv.Put(OIDCJWKSKey("alpha"), []byte(`{"keys":[]}`)) + require.NoError(t, err) + _, err = kv.Put(OIDCJWKSVerifiedKey("alpha"), []byte("verified")) + require.NoError(t, err) + require.NoError(t, SetClusterCertificateAuthority(kv, "alpha", "ca-blob-b64")) +} + +func TestClusterReconciler_CreatingTransitionsToActiveOnReadyAndHealthz(t *testing.T) { + stub := &stubHTTPDoer{status: http.StatusOK} + r, _, acctKV := newReconcilerHarness(t, + "https://nlb.example/healthz", + WithHTTPClient(stub), + WithReconcileInterval(10*time.Millisecond), + WithLeaseRefresh(10*time.Second), + ) + release, ok := r.AcquireLease() + require.True(t, ok) + defer release() + + seedBootstrapState(t, acctKV) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + + runErr := make(chan error, 1) + go func() { runErr <- r.Run(ctx) }() + + require.Eventually(t, func() bool { + meta, err := GetClusterMeta(acctKV, "alpha") + if err != nil { + return false + } + return meta.Status == ClusterStatusActive + }, 1500*time.Millisecond, 10*time.Millisecond, "CREATING should transition to ACTIVE") + + cancel() + select { + case err := <-runErr: + assert.ErrorIs(t, err, context.Canceled) + case <-time.After(2 * time.Second): + t.Fatal("Run did not return after cancel") + } + assert.Positive(t, stub.calls.Load(), "/healthz should have been probed at least once") +} + +func TestClusterReconciler_CreatingStaysWhenBootstrapMissing(t *testing.T) { + stub := &stubHTTPDoer{status: http.StatusOK} + r, _, acctKV := newReconcilerHarness(t, + "https://nlb.example/healthz", + WithHTTPClient(stub), + WithReconcileInterval(10*time.Millisecond), + WithLeaseRefresh(10*time.Second), + ) + release, ok := r.AcquireLease() + require.True(t, ok) + defer release() + + freshenClusterCreatedAt(t, acctKV) + + // Only seed two of the three KV keys (no CA, no JWKS). + _, err := acctKV.Put(NodeTokenKey("alpha"), []byte("enc-token")) + require.NoError(t, err) + _, err = acctKV.Put(AdminKubeconfigKey("alpha"), []byte("enc-kc")) + require.NoError(t, err) + + ctx, cancel := context.WithTimeout(context.Background(), 300*time.Millisecond) + defer cancel() + _ = r.Run(ctx) + + meta, err := GetClusterMeta(acctKV, "alpha") + require.NoError(t, err) + assert.Equal(t, ClusterStatusCreating, meta.Status, "must remain CREATING when bootstrap incomplete") +} + +func TestClusterReconciler_CreatingStaysWhenJWKSUnverified(t *testing.T) { + // Regression for the ACTIVE-on-pre-seeded-JWKS race: every artifact is + // present INCLUDING the controller-pre-seeded OIDCJWKSKey, but the VM's + // JWKS cross-check has not passed (no verified-marker). The cluster must + // stay CREATING — reaching ACTIVE here would mean signing IRSA tokens under + // a key the controller never confirmed. + stub := &stubHTTPDoer{status: http.StatusOK} + r, _, acctKV := newReconcilerHarness(t, + "https://nlb.example/healthz", + WithHTTPClient(stub), + WithReconcileInterval(10*time.Millisecond), + WithLeaseRefresh(10*time.Second), + ) + release, ok := r.AcquireLease() + require.True(t, ok) + defer release() + + freshenClusterCreatedAt(t, acctKV) + + _, err := acctKV.Put(NodeTokenKey("alpha"), []byte("enc-token")) + require.NoError(t, err) + _, err = acctKV.Put(AdminKubeconfigKey("alpha"), []byte("enc-kc")) + require.NoError(t, err) + require.NoError(t, SetClusterCertificateAuthority(acctKV, "alpha", "ca-blob-b64")) + // Pre-seeded JWKS present, but NO verified-marker. + _, err = acctKV.Put(OIDCJWKSKey("alpha"), []byte(`{"keys":[]}`)) + require.NoError(t, err) + + ctx, cancel := context.WithTimeout(context.Background(), 300*time.Millisecond) + defer cancel() + _ = r.Run(ctx) + + meta, err := GetClusterMeta(acctKV, "alpha") + require.NoError(t, err) + assert.Equal(t, ClusterStatusCreating, meta.Status, + "must remain CREATING until the JWKS cross-check positively passes") +} + +func TestClusterReconciler_CreatingStaysWhenHealthzFails(t *testing.T) { + stub := &stubHTTPDoer{err: errors.New("connection refused")} + r, _, acctKV := newReconcilerHarness(t, + "https://nlb.example/healthz", + WithHTTPClient(stub), + WithReconcileInterval(10*time.Millisecond), + WithLeaseRefresh(10*time.Second), + ) + release, ok := r.AcquireLease() + require.True(t, ok) + defer release() + + freshenClusterCreatedAt(t, acctKV) + seedBootstrapState(t, acctKV) + + ctx, cancel := context.WithTimeout(context.Background(), 300*time.Millisecond) + defer cancel() + _ = r.Run(ctx) + + meta, err := GetClusterMeta(acctKV, "alpha") + require.NoError(t, err) + assert.Equal(t, ClusterStatusCreating, meta.Status, "must remain CREATING when /healthz fails") +} + +func TestClusterReconciler_CreatingTimesOutToFailed(t *testing.T) { + stub := &stubHTTPDoer{err: errors.New("connection refused")} + r, _, acctKV := newReconcilerHarness(t, + "https://nlb.example/healthz", + WithHTTPClient(stub), + WithReconcileInterval(10*time.Millisecond), + WithLeaseRefresh(10*time.Second), + WithCreateTimeout(1*time.Millisecond), + ) + release, ok := r.AcquireLease() + require.True(t, ok) + defer release() + + // Stamp CreatedAt in the past so the 1ms deadline is already exceeded; the + // cluster never becomes ready, so the reconciler must mark it FAILED. + meta, err := GetClusterMeta(acctKV, "alpha") + require.NoError(t, err) + meta.CreatedAt = time.Now().Add(-time.Hour).UTC() + require.NoError(t, PutClusterMeta(acctKV, meta)) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + + err = r.Run(ctx) + assert.ErrorIs(t, err, ErrReconcilerClusterFailed) + + got, err := GetClusterMeta(acctKV, "alpha") + require.NoError(t, err) + assert.Equal(t, ClusterStatusFailed, got.Status) + assert.Contains(t, got.StatusReason, "did not become ACTIVE") +} + +func TestClusterReconciler_CreatingWithinDeadlineStaysCreating(t *testing.T) { + stub := &stubHTTPDoer{err: errors.New("connection refused")} + r, _, acctKV := newReconcilerHarness(t, + "https://nlb.example/healthz", + WithHTTPClient(stub), + WithReconcileInterval(10*time.Millisecond), + WithLeaseRefresh(10*time.Second), + WithCreateTimeout(time.Hour), + ) + release, ok := r.AcquireLease() + require.True(t, ok) + defer release() + + freshenClusterCreatedAt(t, acctKV) + + ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) + defer cancel() + _ = r.Run(ctx) + + meta, err := GetClusterMeta(acctKV, "alpha") + require.NoError(t, err) + assert.Equal(t, ClusterStatusCreating, meta.Status, "within deadline must stay CREATING") +} + +func TestClusterReconciler_DeletingExitsLoop(t *testing.T) { + stub := &stubHTTPDoer{status: http.StatusOK} + r, _, acctKV := newReconcilerHarness(t, + "https://nlb.example/healthz", + WithHTTPClient(stub), + WithReconcileInterval(10*time.Millisecond), + WithLeaseRefresh(10*time.Second), + ) + release, ok := r.AcquireLease() + require.True(t, ok) + defer release() + + require.NoError(t, SetClusterStatus(acctKV, "alpha", ClusterStatusDeleting)) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + + err := r.Run(ctx) + assert.ErrorIs(t, err, ErrReconcilerClusterDeleting) +} + +func TestClusterReconciler_LostLeaseExitsLoop(t *testing.T) { + stub := &stubHTTPDoer{status: http.StatusOK} + r, leaderKV, acctKV := newReconcilerHarness(t, + "https://nlb.example/healthz", + WithHTTPClient(stub), + WithReconcileInterval(10*time.Second), + WithLeaseRefresh(20*time.Millisecond), + ) + release, ok := r.AcquireLease() + require.True(t, ok) + defer release() + + seedBootstrapState(t, acctKV) + + ctx, cancel := context.WithCancel(t.Context()) + defer cancel() + + runErr := make(chan error, 1) + go func() { runErr <- r.Run(ctx) }() + + // Steal the lease in another holder's name. The next refresh tick should + // notice and return ErrReconcilerLeaseLost. + time.Sleep(40 * time.Millisecond) + _, err := leaderKV.Put(reconcilerLeaderKey(testAccountID, "alpha"), []byte("holder-2")) + require.NoError(t, err) + + select { + case err := <-runErr: + assert.ErrorIs(t, err, ErrReconcilerLeaseLost) + case <-time.After(2 * time.Second): + t.Fatal("Run did not exit after lease loss") + } +} + +func TestClusterReconciler_ActiveProbesAndWarnsOnHealthzFail(t *testing.T) { + stub := &stubHTTPDoer{status: http.StatusOK} + r, _, acctKV := newReconcilerHarness(t, + "https://nlb.example/healthz", + WithHTTPClient(stub), + WithReconcileInterval(10*time.Millisecond), + WithLeaseRefresh(10*time.Second), + ) + release, ok := r.AcquireLease() + require.True(t, ok) + defer release() + + require.NoError(t, SetClusterStatus(acctKV, "alpha", ClusterStatusActive)) + stub.setResponse(http.StatusServiceUnavailable, nil) + + ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) + defer cancel() + _ = r.Run(ctx) + + meta, err := GetClusterMeta(acctKV, "alpha") + require.NoError(t, err) + assert.Equal(t, ClusterStatusActive, meta.Status, "ACTIVE must not flip on healthz fail in this PR") + assert.Positive(t, stub.calls.Load()) + assert.NotEmpty(t, meta.HealthIssue, "failing /healthz must be recorded on meta") + assert.False(t, meta.LastHealthProbe.IsZero(), "health probe time must be stamped") +} + +func TestClusterReconciler_ActiveHealthRecoversClearsIssue(t *testing.T) { + stub := &stubHTTPDoer{status: http.StatusServiceUnavailable} + r, _, acctKV := newReconcilerHarness(t, + "https://nlb.example/healthz", + WithHTTPClient(stub), + WithReconcileInterval(10*time.Millisecond), + WithLeaseRefresh(10*time.Second), + ) + release, ok := r.AcquireLease() + require.True(t, ok) + defer release() + + require.NoError(t, SetClusterStatus(acctKV, "alpha", ClusterStatusActive)) + + // First probe fails and records the issue. + require.Error(t, r.probeHealthz(context.Background())) + require.NoError(t, r.reconcileOnce(context.Background())) + meta, err := GetClusterMeta(acctKV, "alpha") + require.NoError(t, err) + require.NotEmpty(t, meta.HealthIssue) + + // Probe recovers: the issue must be cleared. + stub.setResponse(http.StatusOK, nil) + require.NoError(t, r.reconcileOnce(context.Background())) + meta, err = GetClusterMeta(acctKV, "alpha") + require.NoError(t, err) + assert.Empty(t, meta.HealthIssue, "recovered /healthz must clear the recorded issue") +} + +func TestClusterReconciler_ProbeHealthzEmptyURLNoop(t *testing.T) { + stub := &stubHTTPDoer{} + r, _, _ := newReconcilerHarness(t, + "", + WithHTTPClient(stub), + WithReconcileInterval(10*time.Millisecond), + WithLeaseRefresh(10*time.Second), + ) + + require.NoError(t, r.probeHealthz(context.Background())) + assert.EqualValues(t, 0, stub.calls.Load(), "no HTTP call when URL empty") +} diff --git a/spinifex/handlers/eks/cluster_state.go b/spinifex/handlers/eks/cluster_state.go new file mode 100644 index 000000000..768ffc10e --- /dev/null +++ b/spinifex/handlers/eks/cluster_state.go @@ -0,0 +1,257 @@ +package handlers_eks + +import ( + "encoding/json" + "errors" + "fmt" + "strings" + "time" + + "github.com/nats-io/nats.go" +) + +// ClusterStatus is the persisted lifecycle state for a cluster. Values match +// the AWS EKS Cluster.status string set so DescribeCluster can pass them +// through verbatim. +type ClusterStatus string + +const ( + ClusterStatusCreating ClusterStatus = "CREATING" + ClusterStatusActive ClusterStatus = "ACTIVE" + ClusterStatusDeleting ClusterStatus = "DELETING" + ClusterStatusFailed ClusterStatus = "FAILED" +) + +// ClusterVpcConfig is the persisted subset of eks.VpcConfigResponse that the +// reconciler + DescribeCluster need at-rest. +type ClusterVpcConfig struct { + SubnetIds []string `json:"subnetIds"` + SecurityGroupIds []string `json:"securityGroupIds,omitempty"` + VpcId string `json:"vpcId,omitempty"` +} + +// ClusterMeta is the persisted control-plane record for one cluster. The +// blob lives at ClusterMetaKey(name) inside the per-account KV bucket and is +// the source of truth for DescribeCluster. +type ClusterMeta struct { + Name string `json:"name"` + Arn string `json:"arn"` + Status ClusterStatus `json:"status"` + StatusReason string `json:"statusReason,omitempty"` + Version string `json:"version"` + RoleArn string `json:"roleArn"` + Endpoint string `json:"endpoint,omitempty"` + OIDCIssuer string `json:"oidcIssuer,omitempty"` + CertificateAuthorityB64 string `json:"certificateAuthorityB64,omitempty"` + ResourcesVpcConfig *ClusterVpcConfig `json:"resourcesVpcConfig,omitempty"` + ControlPlaneInstanceID string `json:"controlPlaneInstanceId,omitempty"` + ControlPlaneENIID string `json:"controlPlaneEniId,omitempty"` + ControlPlaneENIIP string `json:"controlPlaneEniIp,omitempty"` + // ControlPlaneMgmtIP is the control-plane VM's br-mgmt NIC address. Until + // authoritative DNS (Eclipso/Route53) lands, the host-side reconciler cannot + // resolve or route to the VPC-internal NLB DNS endpoint, so it probes + // /healthz on this host-reachable address instead. + ControlPlaneMgmtIP string `json:"controlPlaneMgmtIp,omitempty"` + // EgressEIPAllocationID / EgressEIPPublicIP track the hidden pool address + // SNAT'd to the control-plane VM for egress-only internet (image pulls). + // Released + the snat removed on DeleteCluster. + EgressEIPAllocationID string `json:"egressEipAllocationId,omitempty"` + EgressEIPPublicIP string `json:"egressEipPublicIp,omitempty"` + NLBArn string `json:"nlbArn,omitempty"` + NLBTargetGroupArn string `json:"nlbTargetGroupArn,omitempty"` + CreatedAt time.Time `json:"createdAt"` + // HealthIssue is the last /healthz probe failure reason for an ACTIVE + // cluster; empty means healthy. DescribeCluster surfaces a non-empty value + // as a ClusterHealth issue so a dead control plane is visible behind the + // still-ACTIVE status. LastHealthProbe stamps when the health state changed. + HealthIssue string `json:"healthIssue,omitempty"` + LastHealthProbe time.Time `json:"lastHealthProbe,omitzero"` +} + +// ErrClusterNotFound is returned by GetClusterMeta / SetClusterStatus / +// DeleteClusterPrefix when the cluster meta key is absent. Callers translate +// to the AWS shape (ResourceNotFoundException) at the service boundary. +var ErrClusterNotFound = errors.New("eks: cluster not found") + +const maxClusterStateCASRetries = 5 + +// PutClusterMeta writes the meta record unconditionally. Used at +// CreateCluster time to lay down the initial CREATING record. +func PutClusterMeta(kv nats.KeyValue, meta *ClusterMeta) error { + if meta == nil { + return errors.New("eks: PutClusterMeta nil meta") + } + if meta.Name == "" { + return errors.New("eks: PutClusterMeta meta.Name empty") + } + data, err := json.Marshal(meta) + if err != nil { + return fmt.Errorf("marshal cluster meta %s: %w", meta.Name, err) + } + if _, err := kv.Put(ClusterMetaKey(meta.Name), data); err != nil { + return fmt.Errorf("kv put %s: %w", ClusterMetaKey(meta.Name), err) + } + return nil +} + +// GetClusterMeta reads the meta record. Returns ErrClusterNotFound if the +// key is absent. +func GetClusterMeta(kv nats.KeyValue, name string) (*ClusterMeta, error) { + if name == "" { + return nil, errors.New("eks: GetClusterMeta empty name") + } + entry, err := kv.Get(ClusterMetaKey(name)) + if err != nil { + if errors.Is(err, nats.ErrKeyNotFound) { + return nil, ErrClusterNotFound + } + return nil, fmt.Errorf("kv get %s: %w", ClusterMetaKey(name), err) + } + var meta ClusterMeta + if err := json.Unmarshal(entry.Value(), &meta); err != nil { + return nil, fmt.Errorf("unmarshal cluster meta %s: %w", name, err) + } + return &meta, nil +} + +// casUpdateMeta does a revision-checked read-modify-write of the cluster meta +// record. mutate receives the decoded meta and returns true if it changed a +// field (false short-circuits to a no-op success). Retries on KV CAS conflict +// (concurrent reconciler write) up to maxClusterStateCASRetries. Returns +// ErrClusterNotFound if the meta record was deleted underneath us. +func casUpdateMeta(kv nats.KeyValue, name string, mutate func(*ClusterMeta) bool) error { + if name == "" { + return errors.New("eks: casUpdateMeta empty name") + } + for range maxClusterStateCASRetries { + entry, err := kv.Get(ClusterMetaKey(name)) + if err != nil { + if errors.Is(err, nats.ErrKeyNotFound) { + return ErrClusterNotFound + } + return fmt.Errorf("kv get %s: %w", ClusterMetaKey(name), err) + } + var meta ClusterMeta + if err := json.Unmarshal(entry.Value(), &meta); err != nil { + return fmt.Errorf("unmarshal cluster meta %s: %w", name, err) + } + if !mutate(&meta) { + return nil + } + data, err := json.Marshal(&meta) + if err != nil { + return fmt.Errorf("marshal cluster meta %s: %w", name, err) + } + _, err = kv.Update(ClusterMetaKey(name), data, entry.Revision()) + if err == nil { + return nil + } + if errors.Is(err, nats.ErrKeyExists) { + continue + } + return fmt.Errorf("kv update %s: %w", ClusterMetaKey(name), err) + } + return fmt.Errorf("eks: casUpdateMeta %s exhausted CAS retries", name) +} + +// SetClusterStatus does a revision-checked update of the meta.Status field. +// Returns ErrClusterNotFound if the meta record was deleted underneath us. +func SetClusterStatus(kv nats.KeyValue, name string, status ClusterStatus) error { + if name == "" { + return errors.New("eks: SetClusterStatus empty name") + } + return casUpdateMeta(kv, name, func(m *ClusterMeta) bool { + if m.Status == status { + return false + } + m.Status = status + return true + }) +} + +// MarkClusterFailed transitions a cluster to FAILED with a human-readable +// reason, but only from CREATING — a cluster already DELETING/ACTIVE/FAILED is +// left untouched so a late bootstrap error cannot clobber a concurrent delete +// or an already-healthy cluster. Returns ErrClusterNotFound if the meta record +// was deleted underneath us. +func MarkClusterFailed(kv nats.KeyValue, name, reason string) error { + if name == "" { + return errors.New("eks: MarkClusterFailed empty name") + } + return casUpdateMeta(kv, name, func(m *ClusterMeta) bool { + if m.Status != ClusterStatusCreating { + return false + } + m.Status = ClusterStatusFailed + m.StatusReason = reason + return true + }) +} + +// SetClusterCertificateAuthority does a revision-checked update of the +// meta.CertificateAuthorityB64 field. The NATS bootstrap subscriber calls +// this once the K3s server VM publishes its CA on the bootstrap bus. Returns +// ErrClusterNotFound if the meta record was deleted underneath us. +func SetClusterCertificateAuthority(kv nats.KeyValue, name, caB64 string) error { + if name == "" { + return errors.New("eks: SetClusterCertificateAuthority empty name") + } + if caB64 == "" { + return errors.New("eks: SetClusterCertificateAuthority empty CA") + } + return casUpdateMeta(kv, name, func(m *ClusterMeta) bool { + if m.CertificateAuthorityB64 == caB64 { + return false + } + m.CertificateAuthorityB64 = caB64 + return true + }) +} + +// SetClusterHealth records the latest /healthz probe outcome for a cluster: +// issue is the failure reason (empty clears it / marks healthy). Writes only +// when the health state changes, stamping LastHealthProbe at the transition so +// a persistently-unhealthy cluster carries the time it first went bad rather +// than churning the KV every probe interval. Returns ErrClusterNotFound if the +// meta record was deleted underneath us. +func SetClusterHealth(kv nats.KeyValue, name, issue string) error { + if name == "" { + return errors.New("eks: SetClusterHealth empty name") + } + return casUpdateMeta(kv, name, func(m *ClusterMeta) bool { + if m.HealthIssue == issue { + return false + } + m.HealthIssue = issue + m.LastHealthProbe = time.Now().UTC() + return true + }) +} + +// DeleteClusterPrefix removes every KV key under clusters/{name}/. Called +// from DeleteCluster after the OIDC private key has been zeroized. +// Returns the first delete error encountered but continues sweeping so +// best-effort cleanup proceeds. +func DeleteClusterPrefix(kv nats.KeyValue, name string) error { + if name == "" { + return errors.New("eks: DeleteClusterPrefix empty name") + } + prefix := fmt.Sprintf("clusters/%s/", name) + keys, err := kv.Keys() + if err != nil { + if errors.Is(err, nats.ErrNoKeysFound) { + return nil + } + return fmt.Errorf("kv keys: %w", err) + } + var firstErr error + for _, k := range keys { + if !strings.HasPrefix(k, prefix) { + continue + } + if err := kv.Delete(k); err != nil && firstErr == nil { + firstErr = fmt.Errorf("kv delete %s: %w", k, err) + } + } + return firstErr +} diff --git a/spinifex/handlers/eks/cluster_state_test.go b/spinifex/handlers/eks/cluster_state_test.go new file mode 100644 index 000000000..d25d2ca52 --- /dev/null +++ b/spinifex/handlers/eks/cluster_state_test.go @@ -0,0 +1,256 @@ +package handlers_eks + +import ( + "encoding/json" + "errors" + "testing" + "time" + + "github.com/mulgadc/spinifex/spinifex/testutil" + "github.com/nats-io/nats.go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func newClusterStateTestKV(t *testing.T) nats.KeyValue { + t.Helper() + _, _, js := testutil.StartTestJetStream(t) + kv, err := GetOrCreateAccountBucket(js, testAccountID) + require.NoError(t, err) + return kv +} + +func sampleClusterMeta(name string) *ClusterMeta { + return &ClusterMeta{ + Name: name, + Arn: "arn:aws:eks:us-east-1:111122223333:cluster/" + name, + Status: ClusterStatusCreating, + Version: "1.32", + RoleArn: "arn:aws:iam::111122223333:role/eks-cluster", + ResourcesVpcConfig: &ClusterVpcConfig{ + SubnetIds: []string{"subnet-aaa"}, + SecurityGroupIds: []string{"sg-aaa"}, + }, + CreatedAt: time.Date(2026, 6, 1, 0, 0, 0, 0, time.UTC), + } +} + +func TestPutClusterMeta_NilOrEmptyNameRejected(t *testing.T) { + kv := newClusterStateTestKV(t) + + require.Error(t, PutClusterMeta(kv, nil)) + require.Error(t, PutClusterMeta(kv, &ClusterMeta{})) +} + +func TestPutClusterMeta_RoundTrip(t *testing.T) { + kv := newClusterStateTestKV(t) + + in := sampleClusterMeta("alpha") + require.NoError(t, PutClusterMeta(kv, in)) + + got, err := GetClusterMeta(kv, "alpha") + require.NoError(t, err) + assert.Equal(t, in.Name, got.Name) + assert.Equal(t, in.Arn, got.Arn) + assert.Equal(t, in.Status, got.Status) + assert.Equal(t, in.Version, got.Version) + assert.Equal(t, in.RoleArn, got.RoleArn) + require.NotNil(t, got.ResourcesVpcConfig) + assert.Equal(t, []string{"subnet-aaa"}, got.ResourcesVpcConfig.SubnetIds) + assert.True(t, got.CreatedAt.Equal(in.CreatedAt)) +} + +func TestGetClusterMeta_MissingReturnsErrClusterNotFound(t *testing.T) { + kv := newClusterStateTestKV(t) + + _, err := GetClusterMeta(kv, "missing") + require.ErrorIs(t, err, ErrClusterNotFound) +} + +func TestGetClusterMeta_EmptyNameRejected(t *testing.T) { + kv := newClusterStateTestKV(t) + + _, err := GetClusterMeta(kv, "") + require.Error(t, err) + assert.NotErrorIs(t, err, ErrClusterNotFound) +} + +func TestGetClusterMeta_CorruptBlobRejected(t *testing.T) { + kv := newClusterStateTestKV(t) + + _, err := kv.Put(ClusterMetaKey("corrupt"), []byte("{not json")) + require.NoError(t, err) + + _, err = GetClusterMeta(kv, "corrupt") + require.Error(t, err) + assert.NotErrorIs(t, err, ErrClusterNotFound) +} + +func TestSetClusterStatus_TransitionsAndIsIdempotent(t *testing.T) { + kv := newClusterStateTestKV(t) + require.NoError(t, PutClusterMeta(kv, sampleClusterMeta("alpha"))) + + require.NoError(t, SetClusterStatus(kv, "alpha", ClusterStatusActive)) + got, err := GetClusterMeta(kv, "alpha") + require.NoError(t, err) + assert.Equal(t, ClusterStatusActive, got.Status) + + require.NoError(t, SetClusterStatus(kv, "alpha", ClusterStatusActive)) + got, err = GetClusterMeta(kv, "alpha") + require.NoError(t, err) + assert.Equal(t, ClusterStatusActive, got.Status) +} + +func TestSetClusterStatus_DeletingAlwaysAllowedFromAnyState(t *testing.T) { + kv := newClusterStateTestKV(t) + + for _, from := range []ClusterStatus{ClusterStatusCreating, ClusterStatusActive, ClusterStatusFailed} { + meta := sampleClusterMeta("alpha") + meta.Status = from + require.NoError(t, PutClusterMeta(kv, meta)) + require.NoError(t, SetClusterStatus(kv, "alpha", ClusterStatusDeleting)) + got, err := GetClusterMeta(kv, "alpha") + require.NoError(t, err) + assert.Equal(t, ClusterStatusDeleting, got.Status, "from=%s", from) + } +} + +func TestSetClusterStatus_MissingReturnsErrClusterNotFound(t *testing.T) { + kv := newClusterStateTestKV(t) + + err := SetClusterStatus(kv, "missing", ClusterStatusActive) + require.ErrorIs(t, err, ErrClusterNotFound) +} + +func TestSetClusterStatus_RecoversFromConcurrentRevisionBump(t *testing.T) { + kv := newClusterStateTestKV(t) + require.NoError(t, PutClusterMeta(kv, sampleClusterMeta("alpha"))) + + // Read once to get a stale revision, then bump the record from another + // goroutine via Put to force one CAS conflict on the next Update. + entry, err := kv.Get(ClusterMetaKey("alpha")) + require.NoError(t, err) + + bumped := sampleClusterMeta("alpha") + bumped.Version = "1.32-bumped" + data, err := json.Marshal(bumped) + require.NoError(t, err) + _, err = kv.Update(ClusterMetaKey("alpha"), data, entry.Revision()) + require.NoError(t, err) + + // SetClusterStatus must succeed even though there has been an intervening + // revision bump — its internal loop re-reads + retries. + require.NoError(t, SetClusterStatus(kv, "alpha", ClusterStatusActive)) + got, err := GetClusterMeta(kv, "alpha") + require.NoError(t, err) + assert.Equal(t, ClusterStatusActive, got.Status) + assert.Equal(t, "1.32-bumped", got.Version) +} + +func TestMarkClusterFailed_FromCreatingSetsStatusAndReason(t *testing.T) { + kv := newClusterStateTestKV(t) + require.NoError(t, PutClusterMeta(kv, sampleClusterMeta("alpha"))) + + require.NoError(t, MarkClusterFailed(kv, "alpha", "bootstrap failed: boom")) + got, err := GetClusterMeta(kv, "alpha") + require.NoError(t, err) + assert.Equal(t, ClusterStatusFailed, got.Status) + assert.Equal(t, "bootstrap failed: boom", got.StatusReason) +} + +func TestMarkClusterFailed_NoopFromNonCreating(t *testing.T) { + kv := newClusterStateTestKV(t) + + for _, from := range []ClusterStatus{ClusterStatusActive, ClusterStatusDeleting, ClusterStatusFailed} { + meta := sampleClusterMeta("alpha") + meta.Status = from + require.NoError(t, PutClusterMeta(kv, meta)) + + require.NoError(t, MarkClusterFailed(kv, "alpha", "late bootstrap error")) + got, err := GetClusterMeta(kv, "alpha") + require.NoError(t, err) + assert.Equal(t, from, got.Status, "from=%s must be untouched", from) + assert.Empty(t, got.StatusReason, "from=%s reason must not be set", from) + } +} + +func TestMarkClusterFailed_MissingReturnsErrClusterNotFound(t *testing.T) { + kv := newClusterStateTestKV(t) + + err := MarkClusterFailed(kv, "ghost", "boom") + require.ErrorIs(t, err, ErrClusterNotFound) +} + +func TestSetClusterCertificateAuthority_WritesAndIsIdempotent(t *testing.T) { + kv := newClusterStateTestKV(t) + require.NoError(t, PutClusterMeta(kv, sampleClusterMeta("alpha"))) + + require.NoError(t, SetClusterCertificateAuthority(kv, "alpha", "ca-blob-b64")) + got, err := GetClusterMeta(kv, "alpha") + require.NoError(t, err) + assert.Equal(t, "ca-blob-b64", got.CertificateAuthorityB64) + + require.NoError(t, SetClusterCertificateAuthority(kv, "alpha", "ca-blob-b64")) + got, err = GetClusterMeta(kv, "alpha") + require.NoError(t, err) + assert.Equal(t, "ca-blob-b64", got.CertificateAuthorityB64) +} + +func TestSetClusterCertificateAuthority_MissingReturnsErrClusterNotFound(t *testing.T) { + kv := newClusterStateTestKV(t) + + err := SetClusterCertificateAuthority(kv, "ghost", "ca-blob") + require.ErrorIs(t, err, ErrClusterNotFound) +} + +func TestSetClusterCertificateAuthority_EmptyInputsRejected(t *testing.T) { + kv := newClusterStateTestKV(t) + + require.Error(t, SetClusterCertificateAuthority(kv, "", "ca-blob")) + require.Error(t, SetClusterCertificateAuthority(kv, "alpha", "")) +} + +func TestDeleteClusterPrefix_SweepsEveryKey(t *testing.T) { + kv := newClusterStateTestKV(t) + + require.NoError(t, PutClusterMeta(kv, sampleClusterMeta("alpha"))) + _, err := kv.Put(NodegroupKey("alpha", "ng-1"), []byte(`{"name":"ng-1"}`)) + require.NoError(t, err) + _, err = kv.Put(OIDCSigningKeyKey("alpha"), []byte("enc-blob")) + require.NoError(t, err) + _, err = kv.Put(OIDCJWKSKey("alpha"), []byte(`{"keys":[]}`)) + require.NoError(t, err) + _, err = kv.Put(EventKey("alpha", "1700000000"), []byte(`{"ts":"1700000000"}`)) + require.NoError(t, err) + // Sibling cluster must survive the sweep. + require.NoError(t, PutClusterMeta(kv, sampleClusterMeta("beta"))) + + require.NoError(t, DeleteClusterPrefix(kv, "alpha")) + + for _, k := range []string{ + ClusterMetaKey("alpha"), + NodegroupKey("alpha", "ng-1"), + OIDCSigningKeyKey("alpha"), + OIDCJWKSKey("alpha"), + EventKey("alpha", "1700000000"), + } { + _, err := kv.Get(k) + assert.True(t, errors.Is(err, nats.ErrKeyNotFound), "key %s should be gone, got err=%v", k, err) + } + + got, err := GetClusterMeta(kv, "beta") + require.NoError(t, err) + assert.Equal(t, "beta", got.Name) +} + +func TestDeleteClusterPrefix_EmptyBucketIsNoop(t *testing.T) { + kv := newClusterStateTestKV(t) + + require.NoError(t, DeleteClusterPrefix(kv, "ghost")) +} + +func TestDeleteClusterPrefix_EmptyNameRejected(t *testing.T) { + kv := newClusterStateTestKV(t) + + require.Error(t, DeleteClusterPrefix(kv, "")) +} diff --git a/spinifex/handlers/eks/create_cluster_test.go b/spinifex/handlers/eks/create_cluster_test.go new file mode 100644 index 000000000..084a2ec50 --- /dev/null +++ b/spinifex/handlers/eks/create_cluster_test.go @@ -0,0 +1,210 @@ +package handlers_eks + +import ( + "errors" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/eks" + "github.com/mulgadc/spinifex/spinifex/awserrors" + "github.com/mulgadc/spinifex/spinifex/tags" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func createInput(name string) *eks.CreateClusterInput { + return &eks.CreateClusterInput{ + Name: aws.String(name), + RoleArn: aws.String("arn:aws:iam::111122223333:role/eks-cluster"), + Version: aws.String("1.32"), + ResourcesVpcConfig: &eks.VpcConfigRequest{ + SubnetIds: aws.StringSlice([]string{"subnet-aaa"}), + }, + } +} + +// A create that fails after the NLB is provisioned must leave the NLB ARNs +// persisted on the (now FAILED) meta, otherwise the resources leak with no +// owning record and DeleteCluster cannot reclaim them (bead 165.3). +func TestCreateCluster_NLBArnPersistedBeforeLaterFailure(t *testing.T) { + f := newEKSServiceFixture(t) + + // Force the K3s VM launch to fail — this is after EnsureClusterNLB and the + // NLB-arn persist checkpoint, but before the final PutClusterMeta. + f.inst.launchErr = errors.New("no capacity") + + _, err := f.svc.CreateCluster(createInput("alpha"), testAccountID) + require.Error(t, err) + + meta, getErr := GetClusterMeta(f.kv, "alpha") + require.NoError(t, getErr, "meta must remain so the leaked NLB has an owning record") + assert.Equal(t, ClusterStatusFailed, meta.Status) + assert.NotEmpty(t, meta.NLBArn, "NLB ARN must be persisted before the VM-launch step") + assert.NotEmpty(t, meta.NLBTargetGroupArn) +} + +// End-to-end: a failed create followed by delete-cluster leaves zero orphaned +// NLB resources. The persisted ARNs from the partial create drive teardown. +func TestCreateCluster_FailedCreateThenDeleteReclaimsNLB(t *testing.T) { + f := newEKSServiceFixture(t) + f.inst.launchErr = errors.New("no capacity") + + _, err := f.svc.CreateCluster(createInput("alpha"), testAccountID) + require.Error(t, err) + + // The NLB the partial create provisioned exists in the fake. + require.NotEmpty(t, f.nlb.createLBCalls, "create provisioned an NLB") + + _, err = f.svc.DeleteCluster(deleteInput("alpha"), testAccountID) + require.NoError(t, err) + + assert.NotEmpty(t, f.nlb.deleteLBCalls, "DeleteCluster must tear down the NLB recorded by the failed create") + _, getErr := GetClusterMeta(f.kv, "alpha") + assert.ErrorIs(t, getErr, ErrClusterNotFound) +} + +// A live (CREATING/ACTIVE) cluster of the same name blocks create with a +// cluster-scoped ResourceInUseException, not the ELBv2 target-group message. +func TestCreateCluster_ExistingClusterReturnsResourceInUse(t *testing.T) { + f := newEKSServiceFixture(t) + + meta := sampleClusterMeta("alpha") + meta.Status = ClusterStatusActive + require.NoError(t, PutClusterMeta(f.kv, meta)) + + _, err := f.svc.CreateCluster(createInput("alpha"), testAccountID) + require.EqualError(t, err, awserrors.ErrorEKSResourceInUse) +} + +// A FAILED cluster from a prior attempt must not block a retry: create reclaims +// it (tearing down recorded resources) and proceeds to a fresh CREATING cluster. +func TestCreateCluster_FailedClusterIsReclaimedOnRetry(t *testing.T) { + f := newEKSServiceFixture(t) + + // First attempt fails at VM launch, leaving a FAILED meta with NLB ARNs. + f.inst.launchErr = errors.New("no capacity") + _, err := f.svc.CreateCluster(createInput("alpha"), testAccountID) + require.Error(t, err) + failed, err := GetClusterMeta(f.kv, "alpha") + require.NoError(t, err) + require.Equal(t, ClusterStatusFailed, failed.Status) + + // Retry now succeeds: the reclaim path purges the failed attempt's NLB and + // the create starts clean. + f.inst.launchErr = nil + _, err = f.svc.CreateCluster(createInput("alpha"), testAccountID) + require.NoError(t, err) + + got, err := GetClusterMeta(f.kv, "alpha") + require.NoError(t, err) + assert.Equal(t, ClusterStatusCreating, got.Status) + assert.NotEmpty(t, f.nlb.deleteLBCalls, "reclaim must tear down the failed attempt's NLB") +} + +// A FAILED cluster is observable via Describe and List (bead 165.6) — no state +// where create blocks but describe/list show nothing. +func TestCreateCluster_FailedClusterVisibleInDescribeAndList(t *testing.T) { + f := newEKSServiceFixture(t) + + meta := sampleClusterMeta("alpha") + meta.Status = ClusterStatusFailed + meta.StatusReason = "bootstrap failed: boom" + require.NoError(t, PutClusterMeta(f.kv, meta)) + + desc, err := f.svc.DescribeCluster(&eks.DescribeClusterInput{Name: aws.String("alpha")}, testAccountID) + require.NoError(t, err) + assert.Equal(t, eks.ClusterStatusFailed, aws.StringValue(desc.Cluster.Status)) + + list, err := f.svc.ListClusters(&eks.ListClustersInput{}, testAccountID) + require.NoError(t, err) + assert.Contains(t, aws.StringValueSlice(list.Clusters), "alpha") +} + +// An ACTIVE cluster whose reconciler recorded a /healthz failure must surface +// that as a ClusterHealth issue in describe-cluster, so a dead control plane is +// visible behind the still-ACTIVE status (bead 165.13). +func TestDescribeCluster_SurfacesHealthIssueForActiveCluster(t *testing.T) { + f := newEKSServiceFixture(t) + + meta := sampleClusterMeta("alpha") + meta.Status = ClusterStatusActive + require.NoError(t, PutClusterMeta(f.kv, meta)) + require.NoError(t, SetClusterHealth(f.kv, "alpha", "healthz request: connection refused")) + + desc, err := f.svc.DescribeCluster(&eks.DescribeClusterInput{Name: aws.String("alpha")}, testAccountID) + require.NoError(t, err) + assert.Equal(t, eks.ClusterStatusActive, aws.StringValue(desc.Cluster.Status)) + require.NotNil(t, desc.Cluster.Health) + require.Len(t, desc.Cluster.Health.Issues, 1) + assert.Equal(t, eks.ClusterIssueCodeClusterUnreachable, aws.StringValue(desc.Cluster.Health.Issues[0].Code)) + assert.Contains(t, aws.StringValue(desc.Cluster.Health.Issues[0].Message), "connection refused") +} + +// A healthy ACTIVE cluster carries no health issue in describe-cluster. +func TestDescribeCluster_HealthyActiveClusterHasNoIssues(t *testing.T) { + f := newEKSServiceFixture(t) + + meta := sampleClusterMeta("alpha") + meta.Status = ClusterStatusActive + require.NoError(t, PutClusterMeta(f.kv, meta)) + + desc, err := f.svc.DescribeCluster(&eks.DescribeClusterInput{Name: aws.String("alpha")}, testAccountID) + require.NoError(t, err) + assert.Nil(t, desc.Cluster.Health, "healthy cluster must not report a ClusterHealth issue") +} + +// A missing eks-server AMI is an operator/config gap, not an unrecoverable +// internal fault: CreateCluster must surface ServiceUnavailable (not a generic +// ServerInternal) and mark the half-built cluster FAILED (bead 165.4). +func TestCreateCluster_MissingAMIReturnsServiceUnavailable(t *testing.T) { + f := newEKSServiceFixture(t) + f.ami.describeOut = &ec2.DescribeImagesOutput{} // no images tagged managed-by=eks + + _, err := f.svc.CreateCluster(createInput("alpha"), testAccountID) + require.EqualError(t, err, awserrors.ErrorServiceUnavailable) + + meta, getErr := GetClusterMeta(f.kv, "alpha") + require.NoError(t, getErr) + assert.Equal(t, ClusterStatusFailed, meta.Status) +} + +func TestCreateCluster_HappyPathPersistsActiveCreatingMeta(t *testing.T) { + f := newEKSServiceFixture(t) + + out, err := f.svc.CreateCluster(createInput("alpha"), testAccountID) + require.NoError(t, err) + require.NotNil(t, out) + + meta, err := GetClusterMeta(f.kv, "alpha") + require.NoError(t, err) + assert.Equal(t, ClusterStatusCreating, meta.Status) + assert.NotEmpty(t, meta.NLBArn) + assert.NotEmpty(t, meta.ControlPlaneInstanceID) + assert.NotEmpty(t, meta.ControlPlaneENIID) +} + +func TestCreateCluster_AllocatesHiddenEgressEIP(t *testing.T) { + f := newEKSServiceFixture(t) + + _, err := f.svc.CreateCluster(createInput("egress"), testAccountID) + require.NoError(t, err) + + meta, err := GetClusterMeta(f.kv, "egress") + require.NoError(t, err) + assert.Equal(t, f.eip.publicIP, meta.EgressEIPPublicIP) + assert.Equal(t, f.eip.allocationID, meta.EgressEIPAllocationID) + + require.Len(t, f.eip.allocateCalls, 1) + // The pool address is tagged ManagedBy=eks so it stays out of customer + // DescribeAddresses listings. + tagged := false + for _, spec := range f.eip.allocateCalls[0].TagSpecifications { + for _, tg := range spec.Tags { + if aws.StringValue(tg.Key) == tags.ManagedByKey && aws.StringValue(tg.Value) == tags.ManagedByEKS { + tagged = true + } + } + } + assert.True(t, tagged, "egress EIP must carry the ManagedBy=eks tag") +} diff --git a/spinifex/handlers/eks/delete_cluster_test.go b/spinifex/handlers/eks/delete_cluster_test.go new file mode 100644 index 000000000..2088881c0 --- /dev/null +++ b/spinifex/handlers/eks/delete_cluster_test.go @@ -0,0 +1,149 @@ +package handlers_eks + +import ( + "errors" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/eks" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/testutil" + "github.com/nats-io/nats.go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type fakeSubnetResolver struct{} + +var _ SubnetVPCResolver = (*fakeSubnetResolver)(nil) + +func (fakeSubnetResolver) GetSubnetVPC(_, _ string) (string, error) { return "vpc-aaa", nil } + +func deleteInput(name string) *eks.DeleteClusterInput { + return &eks.DeleteClusterInput{Name: aws.String(name)} +} + +// eksServiceFixture stands up an EKSServiceImpl with fake orchestration deps +// and an embedded JetStream KV. Tests poke the fakes' *Err fields to force +// failures at specific lifecycle steps. +type eksServiceFixture struct { + svc *EKSServiceImpl + kv nats.KeyValue + nlb *fakeNLBProvisioner + inst *fakeK3sInst + vpc *fakeK3sVPC + ami *fakeK3sAMI + eip *fakeEIPProvisioner +} + +func newEKSServiceFixture(t *testing.T) *eksServiceFixture { + t.Helper() + _, nc, js := testutil.StartTestJetStream(t) + kv, err := GetOrCreateAccountBucket(js, testAccountID) + require.NoError(t, err) + + nlb := newFakeNLBProvisioner() + inst := &fakeK3sInst{} + vpc := &fakeK3sVPC{} + ami := &fakeK3sAMI{} + eip := newFakeEIPProvisioner() + + svc, err := NewEKSServiceImpl(EKSServiceDeps{ + NATSConn: nc, + MasterKey: bootstrapTestMasterKey, + GatewayBaseURL: "https://gw.local:9999", + Region: "us-east-1", + HolderID: "node-1", + NATSURL: "nats://gw.local:4222", + NATSToken: "s3cr3t-token", + NATSCACert: "-----BEGIN CERTIFICATE-----\nFAKECA\n-----END CERTIFICATE-----\n", + VPCSG: newFakeSGProvisioner(), + VPCK3s: vpc, + VPCSubnet: fakeSubnetResolver{}, + NLB: nlb, + Instance: inst, + Image: ami, + EIP: eip, + }) + require.NoError(t, err) + t.Cleanup(svc.Shutdown) + + return &eksServiceFixture{svc: svc, kv: kv, nlb: nlb, inst: inst, vpc: vpc, ami: ami, eip: eip} +} + +// deleteClusterFixture is an eksServiceFixture pre-seeded with a CREATING +// cluster meta whose NLB/VM/SG resource references are all populated so +// DeleteCluster exercises every teardown branch. +type deleteClusterFixture struct { + svc *EKSServiceImpl + kv nats.KeyValue + nlb *fakeNLBProvisioner + inst *fakeK3sInst + vpc *fakeK3sVPC +} + +func newDeleteClusterFixture(t *testing.T, clusterName string) *deleteClusterFixture { + t.Helper() + f := newEKSServiceFixture(t) + kv := f.kv + + meta := sampleClusterMeta(clusterName) + meta.NLBArn = "arn:aws:elasticloadbalancing:us-east-1:111122223333:loadbalancer/net/" + ClusterNLBName(clusterName) + "/lb-001" + meta.NLBTargetGroupArn = "arn:aws:elasticloadbalancing:us-east-1:111122223333:targetgroup/" + ClusterTargetGroupName(clusterName) + "/tg-001" + meta.ControlPlaneENIIP = "10.0.1.42" + meta.ControlPlaneInstanceID = "i-aaa111" + meta.ControlPlaneENIID = "eni-aaa111" + meta.ResourcesVpcConfig.VpcId = "vpc-aaa" + require.NoError(t, PutClusterMeta(kv, meta)) + + // Real OIDC key so ZeroizeClusterOIDCKey has material to wipe. + _, _, err := GenerateClusterOIDCKeypair(kv, clusterName, bootstrapTestMasterKey) + require.NoError(t, err) + + return &deleteClusterFixture{svc: f.svc, kv: kv, nlb: f.nlb, inst: f.inst, vpc: f.vpc} +} + +func TestDeleteCluster_AllTeardownSucceedsSweepsKV(t *testing.T) { + f := newDeleteClusterFixture(t, "alpha") + + out, err := f.svc.DeleteCluster(deleteInput("alpha"), testAccountID) + require.NoError(t, err) + require.NotNil(t, out) + + _, err = GetClusterMeta(f.kv, "alpha") + assert.ErrorIs(t, err, ErrClusterNotFound, "meta must be swept after successful teardown") + assert.Len(t, f.inst.terminateCalls, 1) + assert.Len(t, f.vpc.deleteCalls, 1) +} + +func TestDeleteCluster_NLBFailureLeavesMetaAndDELETING(t *testing.T) { + f := newDeleteClusterFixture(t, "alpha") + + // Seed the LB so delete is attempted, then force it to fail. + lbName := ClusterNLBName("alpha") + f.nlb.lbByName[lbName] = &elbv2.LoadBalancer{ + LoadBalancerArn: aws.String("arn:lb"), + LoadBalancerName: aws.String(lbName), + } + f.nlb.deleteLBErr = errors.New("elbv2 unavailable") + + _, err := f.svc.DeleteCluster(deleteInput("alpha"), testAccountID) + require.Error(t, err, "teardown failure must surface, not be swallowed") + + meta, getErr := GetClusterMeta(f.kv, "alpha") + require.NoError(t, getErr, "meta must survive so a retry can find the resource ARNs") + assert.Equal(t, ClusterStatusDeleting, meta.Status) + assert.NotEmpty(t, meta.NLBArn, "NLB ARN must remain recorded for retry") +} + +func TestDeleteCluster_VMTerminateFailureLeavesMeta(t *testing.T) { + f := newDeleteClusterFixture(t, "alpha") + f.inst.terminateErr = errors.New("hypervisor unreachable") + + _, err := f.svc.DeleteCluster(deleteInput("alpha"), testAccountID) + require.Error(t, err) + + meta, getErr := GetClusterMeta(f.kv, "alpha") + require.NoError(t, getErr) + assert.Equal(t, ClusterStatusDeleting, meta.Status) +} diff --git a/spinifex/handlers/eks/eip_test.go b/spinifex/handlers/eks/eip_test.go new file mode 100644 index 000000000..209f6c0fc --- /dev/null +++ b/spinifex/handlers/eks/eip_test.go @@ -0,0 +1,44 @@ +package handlers_eks + +import ( + "github.com/aws/aws-sdk-go/aws" + ec2 "github.com/aws/aws-sdk-go/service/ec2" +) + +// fakeEIPProvisioner records allocate/release calls and hands back a +// deterministic pool address so CreateCluster/DeleteCluster egress wiring is +// exercised without a live EIP service. +type fakeEIPProvisioner struct { + allocateCalls []*ec2.AllocateAddressInput + releaseCalls []*ec2.ReleaseAddressInput + + publicIP string + allocationID string + allocateErr error + releaseErr error +} + +var _ eipProvisioner = (*fakeEIPProvisioner)(nil) + +func newFakeEIPProvisioner() *fakeEIPProvisioner { + return &fakeEIPProvisioner{publicIP: "203.0.113.50", allocationID: "eipalloc-fake01"} +} + +func (f *fakeEIPProvisioner) AllocateAddress(input *ec2.AllocateAddressInput, _ string) (*ec2.AllocateAddressOutput, error) { + f.allocateCalls = append(f.allocateCalls, input) + if f.allocateErr != nil { + return nil, f.allocateErr + } + return &ec2.AllocateAddressOutput{ + PublicIp: aws.String(f.publicIP), + AllocationId: aws.String(f.allocationID), + }, nil +} + +func (f *fakeEIPProvisioner) ReleaseAddress(input *ec2.ReleaseAddressInput, _ string) (*ec2.ReleaseAddressOutput, error) { + f.releaseCalls = append(f.releaseCalls, input) + if f.releaseErr != nil { + return nil, f.releaseErr + } + return &ec2.ReleaseAddressOutput{}, nil +} diff --git a/spinifex/handlers/eks/k3s_server_vm.go b/spinifex/handlers/eks/k3s_server_vm.go new file mode 100644 index 000000000..b78c95ae9 --- /dev/null +++ b/spinifex/handlers/eks/k3s_server_vm.go @@ -0,0 +1,424 @@ +package handlers_eks + +import ( + "errors" + "fmt" + "log/slog" + "net" + "strconv" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/spinifex/spinifex/awserrors" + "github.com/mulgadc/spinifex/spinifex/handlers/sysinstance" + "github.com/mulgadc/spinifex/spinifex/tags" +) + +// ErrEKSServerAMINotFound is returned by the launcher when no AMI carrying the +// EKS managed-by tag exists in the account. CreateCluster maps it to a precise +// client error: it signals an operator/config gap (the eks-server image was +// never built/imported), not an unrecoverable internal fault. +var ErrEKSServerAMINotFound = errors.New("eks: eks-server AMI not found") + +// k3sVPCProvisioner is the subset of handlers_ec2_vpc.VPCService that the K3s +// server VM launcher needs. Narrow so tests can fake it without implementing +// the full VPC surface. +type k3sVPCProvisioner interface { + CreateNetworkInterface(input *ec2.CreateNetworkInterfaceInput, accountID string) (*ec2.CreateNetworkInterfaceOutput, error) + DeleteNetworkInterface(input *ec2.DeleteNetworkInterfaceInput, accountID string) (*ec2.DeleteNetworkInterfaceOutput, error) +} + +// k3sInstanceLauncher is the system-instance launch surface the K3s control-plane +// VM needs. The VM boots from the eks-server AMI (BootAMI) and must get a +// management-bridge NIC so it can reach the daemon's NATS endpoint off its +// tenant VPC subnet — which only the system-instance path provides. +// *daemon.Daemon satisfies this interface. +type k3sInstanceLauncher interface { + LaunchSystemInstance(input *sysinstance.SystemInstanceInput) (*sysinstance.SystemInstanceOutput, error) + TerminateSystemInstance(instanceID string) error +} + +// k3sAMIResolver is the subset of handlers_ec2_image.ImageService the launcher +// uses to resolve the eks-server AMI name to an AMI ID at launch time. +type k3sAMIResolver interface { + DescribeImages(input *ec2.DescribeImagesInput, accountID string) (*ec2.DescribeImagesOutput, error) +} + +const ( + // defaultK3sServerInstanceType is the spinifex instance type closest to + // the AWS EKS minimum control-plane footprint (2 vCPU / 8 GB / 40 GB). + // Callers can override via K3sServerInput.InstanceType. + defaultK3sServerInstanceType = "t3.medium" + + // k3sOIDCSigningKeyPath is the on-VM path where cloud-init drops the + // per-cluster OIDC private key PEM. K3s reads it via the + // service-account-signing-key-file kube-apiserver arg (signs SA tokens). + k3sOIDCSigningKeyPath = "/etc/rancher/k3s/oidc-signing-key.pem" + + // k3sOIDCPublicKeyPath is where cloud-init drops the matching public key + // PEM. kube-apiserver's service-account-key-file requires a PUBLIC key + // (it rejects a private-key PEM with "data does not contain any valid RSA + // or ECDSA public keys" and crash-loops), so it must be a separate file. + k3sOIDCPublicKeyPath = "/etc/rancher/k3s/oidc-signing-key.pub.pem" + + // k3sFirstBootEnvPath is the env file k3s-first-boot.sh sources at boot + // (see scripts/images/eks-server/k3s-first-boot.sh ENVFILE). + k3sFirstBootEnvPath = "/etc/spinifex-eks/first-boot.env" + + // k3sNATSCAPath is the on-VM destination for the NATS CA cert PEM. The K3s + // VM uses it to verify the daemon's NATS TLS when publishing bootstrap + // messages. Path matches k3s-first-boot.sh SPINIFEX_NATS_CA. + k3sNATSCAPath = "/etc/spinifex-eks/nats-ca.pem" + + // k3sConfigPath is the K3s server config file cloud-init writes; K3s + // reads it at startup (overrides the AMI-baked config.yaml.skel). + k3sConfigPath = "/etc/rancher/k3s/config.yaml" + + // k3sResolvConfPath is the on-VM resolver file. The Alpine eks-server AMI + // runs dhcpcd, whose resolv.conf hook fails to persist the DHCP-supplied + // nameservers ("can't create /etc/resolv.conf: nonexistent directory"), so + // the VM boots with no resolver and containerd cannot resolve registry-1. + // docker.io to pull the system-pod images. cloud-init writes a static + // resolver here; the dhcpcd hook never clobbers it (it errors before it + // would). Reachable via the cluster's egress SNAT. + k3sResolvConfPath = "/etc/resolv.conf" + + // k3sResolvConf is the static resolver content. Public anycast resolvers + // reached over the control-plane VM's egress path. + k3sResolvConf = "nameserver 1.1.1.1\nnameserver 8.8.8.8" +) + +// K3sServerInput is the launcher's input shape. AccountID is the customer +// account; the ENI + VM both live there in v1 (SystemAccount-owned VM is +// deferred behind cross-account-ENI work). Region is carried for future +// region-aware AMI lookups but not consumed today. +type K3sServerInput struct { + AccountID string + ClusterName string + Region string + SubnetID string + ControlPlaneSGID string + NLBDNS string + OIDCIssuer string + OIDCPrivateKeyPEM string + OIDCPublicKeyPEM string + NATSURL string + NATSToken string + NATSCACert string + InstanceType string +} + +// K3sServerOutput carries the identifiers the caller needs to persist into +// ClusterMeta and to register the ENI IP with the cluster NLB target group. +type K3sServerOutput struct { + InstanceID string + ENIID string + ENIIP string + MgmtIP string +} + +// LaunchK3sServerVM provisions the K3s control-plane VM for an EKS cluster. +// Sequence: resolve the eks-server AMI, pre-create the customer-account ENI +// in the supplied subnet with the control-plane SG, render cloud-init user +// data (env vars, OIDC PEM, K3s config), then call RunInstances with +// NetworkInterfaces[0].NetworkInterfaceId pointing at the pre-created ENI. +// Returns instance/ENI identity so the caller can register the ENI IP with +// the cluster NLB target group and persist the IDs in ClusterMeta. On +// RunInstances failure the pre-created ENI is deleted best-effort so the +// caller does not leak a customer-account resource. +func LaunchK3sServerVM( + vpcSvc k3sVPCProvisioner, + instSvc k3sInstanceLauncher, + amiSvc k3sAMIResolver, + in K3sServerInput, +) (*K3sServerOutput, error) { + if err := validateK3sServerInput(in); err != nil { + return nil, err + } + instanceType := in.InstanceType + if instanceType == "" { + instanceType = defaultK3sServerInstanceType + } + + amiID, err := lookupEKSServerAMI(amiSvc, in.AccountID) + if err != nil { + return nil, err + } + + eniOut, err := vpcSvc.CreateNetworkInterface(&ec2.CreateNetworkInterfaceInput{ + SubnetId: aws.String(in.SubnetID), + Description: aws.String("EKS K3s server ENI for " + in.ClusterName), + Groups: aws.StringSlice([]string{in.ControlPlaneSGID}), + TagSpecifications: []*ec2.TagSpecification{{ + ResourceType: aws.String("network-interface"), + Tags: []*ec2.Tag{ + {Key: aws.String(tags.ManagedByKey), Value: aws.String(tags.ManagedByEKS)}, + {Key: aws.String(clusterEKSClusterTagKey), Value: aws.String(in.ClusterName)}, + {Key: aws.String(clusterEKSRoleTagKey), Value: aws.String(clusterEKSRoleControlPlane)}, + }, + }}, + }, in.AccountID) + if err != nil { + return nil, fmt.Errorf("create K3s ENI in subnet %s: %w", in.SubnetID, err) + } + if eniOut == nil || eniOut.NetworkInterface == nil || + aws.StringValue(eniOut.NetworkInterface.NetworkInterfaceId) == "" || + aws.StringValue(eniOut.NetworkInterface.PrivateIpAddress) == "" { + return nil, errors.New("eks: CreateNetworkInterface returned incomplete ENI") + } + eniID := aws.StringValue(eniOut.NetworkInterface.NetworkInterfaceId) + eniIP := aws.StringValue(eniOut.NetworkInterface.PrivateIpAddress) + + userData := buildK3sUserData(in) + + sysOut, err := instSvc.LaunchSystemInstance(&sysinstance.SystemInstanceInput{ + BootMode: sysinstance.BootAMI, + ManagedBy: tags.ManagedByEKS, + InstanceType: instanceType, + ImageID: amiID, + AccountID: in.AccountID, + ENIID: eniID, + ENIMac: aws.StringValue(eniOut.NetworkInterface.MacAddress), + ENIIP: eniIP, + UserData: userData, + }) + if err != nil { + rollbackK3sENI(vpcSvc, in.AccountID, eniID) + return nil, fmt.Errorf("run K3s server instance for cluster %s: %w", in.ClusterName, err) + } + if sysOut == nil || sysOut.InstanceID == "" { + rollbackK3sENI(vpcSvc, in.AccountID, eniID) + return nil, fmt.Errorf("eks: LaunchSystemInstance returned no instance for cluster %s", in.ClusterName) + } + instanceID := sysOut.InstanceID + + slog.Info("LaunchK3sServerVM completed", + "clusterName", in.ClusterName, + "accountID", in.AccountID, + "instanceId", instanceID, + "eniId", eniID, + "eniIp", eniIP, + ) + + return &K3sServerOutput{ + InstanceID: instanceID, + ENIID: eniID, + ENIIP: eniIP, + MgmtIP: sysOut.MgmtIP, + }, nil +} + +// TerminateK3sServerVM tears down the K3s server VM for a cluster. The +// instance termination cascades ENI detach inside the customer instance path, +// then this helper deletes the ENI explicitly so DeleteCluster does not leak +// it. Missing instance/ENI is a no-op so retries stay safe. +func TerminateK3sServerVM( + vpcSvc k3sVPCProvisioner, + instSvc k3sInstanceLauncher, + accountID, instanceID, eniID string, +) error { + if instanceID == "" && eniID == "" { + return nil + } + var firstErr error + if instanceID != "" { + // A retried DeleteCluster reaches here after the VM already drained, so + // "instance not found" is the steady-state success case, not a failure — + // treat it as idempotent so teardown can proceed to the ENI/SG/KV sweep. + if err := instSvc.TerminateSystemInstance(instanceID); err != nil { + if errors.Is(err, sysinstance.ErrSystemInstanceNotFound) { + slog.Debug("TerminateK3sServerVM: instance already gone", "instanceId", instanceID) + } else { + slog.Warn("TerminateK3sServerVM: terminate failed", "instanceId", instanceID, "err", err) + firstErr = fmt.Errorf("terminate instance %s: %w", instanceID, err) + } + } + } + if eniID != "" { + if _, err := vpcSvc.DeleteNetworkInterface(&ec2.DeleteNetworkInterfaceInput{ + NetworkInterfaceId: aws.String(eniID), + }, accountID); err != nil { + switch { + case awserrors.IsErrorCode(err, awserrors.ErrorInvalidNetworkInterfaceIDNotFound), + awserrors.IsErrorCode(err, awserrors.ErrorInvalidNetworkInterfaceNotFound): + // The instance-terminate cascade (or a prior retry) already + // deleted the ENI. Idempotent success — must NOT block the SG + + // KV sweep, or the cluster wedges in DELETING permanently. + slog.Debug("TerminateK3sServerVM: ENI already gone", "eniId", eniID) + default: + // InvalidNetworkInterface.InUse (the VM is still terminating + // async and holds the ENI) and any other error are retryable: + // surface so the cluster stays DELETING and the reconciler + // retries once the instance releases the ENI. + slog.Warn("TerminateK3sServerVM: ENI delete failed", "eniId", eniID, "err", err) + if firstErr == nil { + firstErr = fmt.Errorf("delete ENI %s: %w", eniID, err) + } + } + } + } + return firstErr +} + +// lookupEKSServerAMI resolves the EKS control-plane AMI by the +// spinifex:managed-by=eks tag the build pipeline stamps on it, rather than a +// brittle exact name. This survives the planned server+agent → single EKS AMI +// unify untouched (the unified AMI keeps the tag; role is chosen per-instance +// at launch). If more than one AMI carries the tag (e.g. server + agent both +// imported pre-unify), the newest by CreationDate wins. +func lookupEKSServerAMI(amiSvc k3sAMIResolver, accountID string) (string, error) { + out, err := amiSvc.DescribeImages(&ec2.DescribeImagesInput{ + Filters: []*ec2.Filter{ + {Name: aws.String("tag:" + tags.ManagedByKey), Values: aws.StringSlice([]string{tags.ManagedByEKS})}, + }, + }, accountID) + if err != nil { + return "", fmt.Errorf("describe eks AMI (tag:%s=%s): %w", tags.ManagedByKey, tags.ManagedByEKS, err) + } + + var ( + newestID string + newestCreated string + matches int + ) + for _, img := range out.Images { + if img == nil || img.ImageId == nil || *img.ImageId == "" { + continue + } + matches++ + // CreationDate is a fixed-width RFC3339 timestamp, so lexicographic + // comparison orders it correctly without parsing. + if created := aws.StringValue(img.CreationDate); newestID == "" || created > newestCreated { + newestID, newestCreated = *img.ImageId, created + } + } + if newestID == "" { + return "", fmt.Errorf("%w (tag:%s=%s, account %s)", ErrEKSServerAMINotFound, tags.ManagedByKey, tags.ManagedByEKS, accountID) + } + if matches > 1 { + slog.Warn("eks: multiple AMIs match managed-by=eks; using newest", + "count", matches, "imageId", newestID, "created", newestCreated) + } + return newestID, nil +} + +func rollbackK3sENI(vpcSvc k3sVPCProvisioner, accountID, eniID string) { + if _, err := vpcSvc.DeleteNetworkInterface(&ec2.DeleteNetworkInterfaceInput{ + NetworkInterfaceId: aws.String(eniID), + }, accountID); err != nil { + slog.Warn("LaunchK3sServerVM: rollback ENI delete failed", "eniId", eniID, "err", err) + } +} + +func validateK3sServerInput(in K3sServerInput) error { + switch { + case in.AccountID == "": + return errors.New("eks: K3sServerInput empty AccountID") + case in.ClusterName == "": + return errors.New("eks: K3sServerInput empty ClusterName") + case in.SubnetID == "": + return errors.New("eks: K3sServerInput empty SubnetID") + case in.ControlPlaneSGID == "": + return errors.New("eks: K3sServerInput empty ControlPlaneSGID") + case in.NLBDNS == "": + return errors.New("eks: K3sServerInput empty NLBDNS") + case in.OIDCIssuer == "": + return errors.New("eks: K3sServerInput empty OIDCIssuer") + case strings.TrimSpace(in.OIDCPrivateKeyPEM) == "": + return errors.New("eks: K3sServerInput empty OIDCPrivateKeyPEM") + case strings.TrimSpace(in.OIDCPublicKeyPEM) == "": + return errors.New("eks: K3sServerInput empty OIDCPublicKeyPEM") + case in.NATSURL == "": + return errors.New("eks: K3sServerInput empty NATSURL") + case in.NATSToken == "": + return errors.New("eks: K3sServerInput empty NATSToken") + case strings.TrimSpace(in.NATSCACert) == "": + return errors.New("eks: K3sServerInput empty NATSCACert") + } + return nil +} + +// userDataFile is one entry in the cloud-config write_files block. +type userDataFile struct { + Path string + Perms string + Body string +} + +// buildK3sUserData renders the cloud-config YAML the K3s server VM consumes +// at first boot. Output is unencoded YAML; the caller base64-wraps it for +// the RunInstances UserData field. +func buildK3sUserData(in K3sServerInput) string { + nlbEndpoint := "https://" + net.JoinHostPort(in.NLBDNS, strconv.FormatInt(clusterNLBListenPort, 10)) + + envBody := strings.Join([]string{ + "SPINIFEX_NATS_URL=" + in.NATSURL, + "SPINIFEX_NATS_TOKEN=" + in.NATSToken, + "SPINIFEX_NATS_CA=" + k3sNATSCAPath, + "EKS_ACCOUNT_ID=" + in.AccountID, + "EKS_CLUSTER_NAME=" + in.ClusterName, + "EKS_NLB_ENDPOINT=" + nlbEndpoint, + "EKS_OIDC_ISSUER=" + in.OIDCIssuer, + }, "\n") + + // Omitting cluster-init selects the embedded SQLite (kine) datastore, not + // embedded etcd. etcd's per-commit fsync stalls past apiserver's 5s deadline + // on the viperblock-backed root volume, so it never reaches /healthz; kine + // tolerates the deferred-durability block path. Trade-off: no multi-server + // HA (that needs etcd) — acceptable for single-node v1. + // + // anonymous-auth=true: k3s hardens it off by default, which makes the + // apiserver answer 401 to an unauthenticated /healthz. The cluster reconciler + // probes https:///healthz anonymously to gate ACTIVE, so it must be + // reachable; the default RBAC binds only the health/version non-resource + // paths to system:unauthenticated, so this exposes nothing else. + k3sConfig := strings.Join([]string{ + "tls-san:", + " - " + in.NLBDNS, + "kube-apiserver-arg:", + " - service-account-key-file=" + k3sOIDCPublicKeyPath, + " - service-account-signing-key-file=" + k3sOIDCSigningKeyPath, + " - service-account-issuer=" + in.OIDCIssuer, + " - api-audiences=sts.amazonaws.com", + " - anonymous-auth=true", + }, "\n") + + files := []userDataFile{ + // first-boot.env carries the NATS token, so keep it root-only (0600). + {Path: k3sFirstBootEnvPath, Perms: "0600", Body: envBody}, + {Path: k3sOIDCSigningKeyPath, Perms: "0600", Body: strings.TrimRight(in.OIDCPrivateKeyPEM, "\n")}, + {Path: k3sOIDCPublicKeyPath, Perms: "0644", Body: strings.TrimRight(in.OIDCPublicKeyPEM, "\n")}, + {Path: k3sConfigPath, Perms: "0644", Body: k3sConfig}, + {Path: k3sNATSCAPath, Perms: "0644", Body: strings.TrimRight(in.NATSCACert, "\n")}, + } + + var buf strings.Builder + buf.WriteString("#cloud-config\n") + + // Resolver via bootcmd, NOT write_files: on the Alpine AMI /etc/resolv.conf + // is a dangling symlink (its target dir does not exist — which is why the + // dhcpcd hook cannot persist DHCP DNS), and pointing write_files at it makes + // cloud-init follow the dead link, fail, and abort the WHOLE write_files + // block (dropping first-boot.env + the k3s config). bootcmd runs before + // write_files in the init stage and as a shell, so it can drop the symlink + // and write a real file. Containerd needs this to resolve registry-1.docker. + // io for system-pod image pulls; reachable over the cluster egress SNAT. + buf.WriteString("bootcmd:\n") + buf.WriteString(" - rm -f " + k3sResolvConfPath + "\n") + fmt.Fprintf(&buf, " - printf '%s\\n' > %s\n", + strings.ReplaceAll(k3sResolvConf, "\n", "\\n"), k3sResolvConfPath) + + buf.WriteString("write_files:\n") + for _, f := range files { + fmt.Fprintf(&buf, " - path: %s\n", f.Path) + fmt.Fprintf(&buf, " permissions: '%s'\n", f.Perms) + buf.WriteString(" content: |\n") + for line := range strings.SplitSeq(f.Body, "\n") { + buf.WriteString(" ") + buf.WriteString(line) + buf.WriteString("\n") + } + } + return buf.String() +} diff --git a/spinifex/handlers/eks/k3s_server_vm_test.go b/spinifex/handlers/eks/k3s_server_vm_test.go new file mode 100644 index 000000000..88bde08de --- /dev/null +++ b/spinifex/handlers/eks/k3s_server_vm_test.go @@ -0,0 +1,400 @@ +package handlers_eks + +import ( + "errors" + "fmt" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/spinifex/spinifex/awserrors" + "github.com/mulgadc/spinifex/spinifex/handlers/sysinstance" + "github.com/mulgadc/spinifex/spinifex/tags" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type fakeK3sVPC struct { + createCalls []*ec2.CreateNetworkInterfaceInput + deleteCalls []*ec2.DeleteNetworkInterfaceInput + + createOut *ec2.CreateNetworkInterfaceOutput + createErr error + deleteErr error +} + +var _ k3sVPCProvisioner = (*fakeK3sVPC)(nil) + +func (f *fakeK3sVPC) CreateNetworkInterface(input *ec2.CreateNetworkInterfaceInput, _ string) (*ec2.CreateNetworkInterfaceOutput, error) { + f.createCalls = append(f.createCalls, input) + if f.createErr != nil { + return nil, f.createErr + } + if f.createOut != nil { + return f.createOut, nil + } + return &ec2.CreateNetworkInterfaceOutput{ + NetworkInterface: &ec2.NetworkInterface{ + NetworkInterfaceId: aws.String("eni-aaa111"), + PrivateIpAddress: aws.String("10.0.1.42"), + SubnetId: input.SubnetId, + }, + }, nil +} + +func (f *fakeK3sVPC) DeleteNetworkInterface(input *ec2.DeleteNetworkInterfaceInput, _ string) (*ec2.DeleteNetworkInterfaceOutput, error) { + f.deleteCalls = append(f.deleteCalls, input) + if f.deleteErr != nil { + return nil, f.deleteErr + } + return &ec2.DeleteNetworkInterfaceOutput{}, nil +} + +type fakeK3sInst struct { + launchCalls []*sysinstance.SystemInstanceInput + terminateCalls []string + + launchOut *sysinstance.SystemInstanceOutput + launchErr error + terminateErr error +} + +var _ k3sInstanceLauncher = (*fakeK3sInst)(nil) + +func (f *fakeK3sInst) LaunchSystemInstance(input *sysinstance.SystemInstanceInput) (*sysinstance.SystemInstanceOutput, error) { + f.launchCalls = append(f.launchCalls, input) + if f.launchErr != nil { + return nil, f.launchErr + } + if f.launchOut != nil { + return f.launchOut, nil + } + return &sysinstance.SystemInstanceOutput{InstanceID: "i-aaa111"}, nil +} + +func (f *fakeK3sInst) TerminateSystemInstance(instanceID string) error { + f.terminateCalls = append(f.terminateCalls, instanceID) + return f.terminateErr +} + +type fakeK3sAMI struct { + describeCalls []*ec2.DescribeImagesInput + + describeOut *ec2.DescribeImagesOutput + describeErr error +} + +var _ k3sAMIResolver = (*fakeK3sAMI)(nil) + +func (f *fakeK3sAMI) DescribeImages(input *ec2.DescribeImagesInput, _ string) (*ec2.DescribeImagesOutput, error) { + f.describeCalls = append(f.describeCalls, input) + if f.describeErr != nil { + return nil, f.describeErr + } + if f.describeOut != nil { + return f.describeOut, nil + } + return &ec2.DescribeImagesOutput{ + Images: []*ec2.Image{{ + ImageId: aws.String("ami-eks-server-001"), + Name: aws.String("spinifex-eks-server"), + CreationDate: aws.String("2026-06-01T00:00:00.000Z"), + Tags: []*ec2.Tag{ + {Key: aws.String(tags.ManagedByKey), Value: aws.String(tags.ManagedByEKS)}, + }, + }}, + }, nil +} + +func validK3sInput() K3sServerInput { + return K3sServerInput{ + AccountID: "111122223333", + ClusterName: "alpha", + Region: "us-east-1", + SubnetID: "subnet-aaa", + ControlPlaneSGID: "sg-cp-aaa", + NLBDNS: "eks-alpha-lb-001.us-east-1.elb.spinifex.local", + OIDCIssuer: "https://oidc.spinifex.local/clusters/111122223333/alpha", + OIDCPrivateKeyPEM: "-----BEGIN PRIVATE KEY-----\nFAKEKEY\n-----END PRIVATE KEY-----\n", + OIDCPublicKeyPEM: "-----BEGIN PUBLIC KEY-----\nFAKEPUB\n-----END PUBLIC KEY-----\n", + NATSURL: "nats://localhost:4222", + NATSToken: "s3cr3t-token", + NATSCACert: "-----BEGIN CERTIFICATE-----\nFAKECA\n-----END CERTIFICATE-----\n", + } +} + +func TestLaunchK3sServerVM_EmptyInputsRejected(t *testing.T) { + mk := func(mutate func(*K3sServerInput)) K3sServerInput { + in := validK3sInput() + mutate(&in) + return in + } + cases := []struct { + name string + in K3sServerInput + }{ + {"empty AccountID", mk(func(in *K3sServerInput) { in.AccountID = "" })}, + {"empty ClusterName", mk(func(in *K3sServerInput) { in.ClusterName = "" })}, + {"empty SubnetID", mk(func(in *K3sServerInput) { in.SubnetID = "" })}, + {"empty ControlPlaneSGID", mk(func(in *K3sServerInput) { in.ControlPlaneSGID = "" })}, + {"empty NLBDNS", mk(func(in *K3sServerInput) { in.NLBDNS = "" })}, + {"empty OIDCIssuer", mk(func(in *K3sServerInput) { in.OIDCIssuer = "" })}, + {"empty OIDCPrivateKeyPEM", mk(func(in *K3sServerInput) { in.OIDCPrivateKeyPEM = " \n " })}, + {"empty OIDCPublicKeyPEM", mk(func(in *K3sServerInput) { in.OIDCPublicKeyPEM = " \n " })}, + {"empty NATSURL", mk(func(in *K3sServerInput) { in.NATSURL = "" })}, + {"empty NATSToken", mk(func(in *K3sServerInput) { in.NATSToken = "" })}, + {"empty NATSCACert", mk(func(in *K3sServerInput) { in.NATSCACert = " \n" })}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + vpc, inst, ami := &fakeK3sVPC{}, &fakeK3sInst{}, &fakeK3sAMI{} + _, err := LaunchK3sServerVM(vpc, inst, ami, tc.in) + require.Error(t, err) + assert.Empty(t, vpc.createCalls) + assert.Empty(t, inst.launchCalls) + assert.Empty(t, ami.describeCalls) + }) + } +} + +func TestLaunchK3sServerVM_AMINotFound(t *testing.T) { + vpc, inst := &fakeK3sVPC{}, &fakeK3sInst{} + ami := &fakeK3sAMI{describeOut: &ec2.DescribeImagesOutput{}} + + _, err := LaunchK3sServerVM(vpc, inst, ami, validK3sInput()) + require.ErrorIs(t, err, ErrEKSServerAMINotFound) + assert.Contains(t, err.Error(), "spinifex:managed-by=eks") + assert.Empty(t, vpc.createCalls, "no ENI created when AMI lookup fails") + assert.Empty(t, inst.launchCalls) +} + +func TestLaunchK3sServerVM_AMILookupErrorPropagated(t *testing.T) { + vpc, inst := &fakeK3sVPC{}, &fakeK3sInst{} + ami := &fakeK3sAMI{describeErr: errors.New("DescribeImages backend down")} + + _, err := LaunchK3sServerVM(vpc, inst, ami, validK3sInput()) + require.Error(t, err) + assert.Contains(t, err.Error(), "describe eks AMI") + assert.Empty(t, vpc.createCalls) + assert.Empty(t, inst.launchCalls) +} + +func TestLaunchK3sServerVM_ENICreateFailureNoRunInstances(t *testing.T) { + vpc := &fakeK3sVPC{createErr: errors.New("InsufficientFreeAddressesInSubnet")} + inst, ami := &fakeK3sInst{}, &fakeK3sAMI{} + + _, err := LaunchK3sServerVM(vpc, inst, ami, validK3sInput()) + require.Error(t, err) + assert.Contains(t, err.Error(), "create K3s ENI in subnet subnet-aaa") + assert.Empty(t, inst.launchCalls) + assert.Empty(t, vpc.deleteCalls, "no ENI to roll back when create itself failed") +} + +func TestLaunchK3sServerVM_RunInstancesFailureRollsBackENI(t *testing.T) { + vpc := &fakeK3sVPC{} + inst := &fakeK3sInst{launchErr: errors.New("InsufficientInstanceCapacity")} + ami := &fakeK3sAMI{} + + _, err := LaunchK3sServerVM(vpc, inst, ami, validK3sInput()) + require.Error(t, err) + require.Len(t, vpc.createCalls, 1) + require.Len(t, vpc.deleteCalls, 1, "ENI must roll back when RunInstances fails") + assert.Equal(t, "eni-aaa111", aws.StringValue(vpc.deleteCalls[0].NetworkInterfaceId)) +} + +func TestLaunchK3sServerVM_HappyPath(t *testing.T) { + vpc, inst, ami := &fakeK3sVPC{}, &fakeK3sInst{}, &fakeK3sAMI{} + + out, err := LaunchK3sServerVM(vpc, inst, ami, validK3sInput()) + require.NoError(t, err) + require.NotNil(t, out) + assert.Equal(t, "i-aaa111", out.InstanceID) + assert.Equal(t, "eni-aaa111", out.ENIID) + assert.Equal(t, "10.0.1.42", out.ENIIP) + + require.Len(t, vpc.createCalls, 1) + eniIn := vpc.createCalls[0] + assert.Equal(t, "subnet-aaa", aws.StringValue(eniIn.SubnetId)) + assert.Equal(t, []string{"sg-cp-aaa"}, aws.StringValueSlice(eniIn.Groups)) + require.Len(t, eniIn.TagSpecifications, 1) + assertEC2TaggedAsEKSControlPlane(t, eniIn.TagSpecifications[0].Tags, "alpha") + + require.Len(t, inst.launchCalls, 1) + runIn := inst.launchCalls[0] + assert.Equal(t, sysinstance.BootAMI, runIn.BootMode) + assert.Equal(t, tags.ManagedByEKS, runIn.ManagedBy) + assert.Equal(t, "ami-eks-server-001", runIn.ImageID) + assert.Equal(t, defaultK3sServerInstanceType, runIn.InstanceType) + assert.Equal(t, "111122223333", runIn.AccountID) + assert.Equal(t, "eni-aaa111", runIn.ENIID) + assert.Equal(t, "10.0.1.42", runIn.ENIIP) + + assert.Empty(t, vpc.deleteCalls, "no rollback on success") +} + +func TestLaunchK3sServerVM_HonorsCustomInstanceType(t *testing.T) { + vpc, inst, ami := &fakeK3sVPC{}, &fakeK3sInst{}, &fakeK3sAMI{} + in := validK3sInput() + in.InstanceType = "t3.large" + + _, err := LaunchK3sServerVM(vpc, inst, ami, in) + require.NoError(t, err) + require.Len(t, inst.launchCalls, 1) + assert.Equal(t, "t3.large", inst.launchCalls[0].InstanceType) +} + +func TestLaunchK3sServerVM_UserDataContainsAllArtifacts(t *testing.T) { + vpc, inst, ami := &fakeK3sVPC{}, &fakeK3sInst{}, &fakeK3sAMI{} + + _, err := LaunchK3sServerVM(vpc, inst, ami, validK3sInput()) + require.NoError(t, err) + require.Len(t, inst.launchCalls, 1) + + udata := inst.launchCalls[0].UserData + + assert.True(t, strings.HasPrefix(udata, "#cloud-config\n")) + assert.Contains(t, udata, "write_files:") + + // Static resolver via bootcmd (NOT write_files — /etc/resolv.conf is a + // dangling symlink on the AMI; write_files would follow it, fail, and abort + // the whole block). Without it containerd image pulls cannot resolve. + assert.Contains(t, udata, "bootcmd:") + assert.Contains(t, udata, "rm -f "+k3sResolvConfPath) + assert.Contains(t, udata, "nameserver 1.1.1.1") + // Resolver must NOT be a write_files entry (that path is what broke seeding). + assert.NotContains(t, udata, "path: "+k3sResolvConfPath) + + assert.Contains(t, udata, "path: "+k3sFirstBootEnvPath) + assert.Contains(t, udata, "SPINIFEX_NATS_URL=nats://localhost:4222") + assert.Contains(t, udata, "SPINIFEX_NATS_TOKEN=s3cr3t-token") + assert.Contains(t, udata, "SPINIFEX_NATS_CA="+k3sNATSCAPath) + assert.Contains(t, udata, "EKS_ACCOUNT_ID=111122223333") + assert.Contains(t, udata, "EKS_CLUSTER_NAME=alpha") + assert.Contains(t, udata, "EKS_NLB_ENDPOINT=https://eks-alpha-lb-001.us-east-1.elb.spinifex.local:443") + assert.Contains(t, udata, "EKS_OIDC_ISSUER=https://oidc.spinifex.local/clusters/111122223333/alpha") + + assert.Contains(t, udata, "path: "+k3sOIDCSigningKeyPath) + assert.Contains(t, udata, "permissions: '0600'") + assert.Contains(t, udata, "-----BEGIN PRIVATE KEY-----") + assert.Contains(t, udata, "FAKEKEY") + + assert.Contains(t, udata, "path: "+k3sOIDCPublicKeyPath) + assert.Contains(t, udata, "-----BEGIN PUBLIC KEY-----") + assert.Contains(t, udata, "FAKEPUB") + + assert.Contains(t, udata, "path: "+k3sConfigPath) + assert.Contains(t, udata, "tls-san:") + assert.Contains(t, udata, " - eks-alpha-lb-001.us-east-1.elb.spinifex.local") + // service-account-key-file must point at the PUBLIC key; the signing key + // (private) is a separate file — pointing key-file at the private key + // crash-loops kube-apiserver. + assert.Contains(t, udata, "service-account-key-file="+k3sOIDCPublicKeyPath) + assert.Contains(t, udata, "service-account-signing-key-file="+k3sOIDCSigningKeyPath) + assert.NotContains(t, udata, "service-account-key-file="+k3sOIDCSigningKeyPath) + assert.Contains(t, udata, "service-account-issuer=https://oidc.spinifex.local/clusters/111122223333/alpha") + assert.Contains(t, udata, "api-audiences=sts.amazonaws.com") + + assert.Contains(t, udata, "path: "+k3sNATSCAPath) + assert.Contains(t, udata, "-----BEGIN CERTIFICATE-----") + assert.Contains(t, udata, "FAKECA") +} + +func TestLaunchK3sServerVM_RunInstancesEmptyReservationRollsBack(t *testing.T) { + vpc, ami := &fakeK3sVPC{}, &fakeK3sAMI{} + inst := &fakeK3sInst{launchOut: &sysinstance.SystemInstanceOutput{}} + + _, err := LaunchK3sServerVM(vpc, inst, ami, validK3sInput()) + require.Error(t, err) + assert.Contains(t, err.Error(), "LaunchSystemInstance returned no instance") + require.Len(t, vpc.deleteCalls, 1, "must roll back ENI when reservation empty") +} + +func TestLaunchK3sServerVM_AMIFilterShape(t *testing.T) { + vpc, inst, ami := &fakeK3sVPC{}, &fakeK3sInst{}, &fakeK3sAMI{} + + _, err := LaunchK3sServerVM(vpc, inst, ami, validK3sInput()) + require.NoError(t, err) + require.Len(t, ami.describeCalls, 1) + filters := ami.describeCalls[0].Filters + require.Len(t, filters, 1) + assert.Equal(t, "tag:"+tags.ManagedByKey, aws.StringValue(filters[0].Name)) + assert.Equal(t, []string{tags.ManagedByEKS}, aws.StringValueSlice(filters[0].Values)) +} + +func TestTerminateK3sServerVM_BothNoopOnEmpty(t *testing.T) { + vpc, inst := &fakeK3sVPC{}, &fakeK3sInst{} + + require.NoError(t, TerminateK3sServerVM(vpc, inst, "111122223333", "", "")) + assert.Empty(t, inst.terminateCalls) + assert.Empty(t, vpc.deleteCalls) +} + +func TestTerminateK3sServerVM_TerminatesInstanceAndDeletesENI(t *testing.T) { + vpc, inst := &fakeK3sVPC{}, &fakeK3sInst{} + + require.NoError(t, TerminateK3sServerVM(vpc, inst, "111122223333", "i-aaa111", "eni-aaa111")) + require.Len(t, inst.terminateCalls, 1) + assert.Equal(t, "i-aaa111", inst.terminateCalls[0]) + require.Len(t, vpc.deleteCalls, 1) + assert.Equal(t, "eni-aaa111", aws.StringValue(vpc.deleteCalls[0].NetworkInterfaceId)) +} + +func TestTerminateK3sServerVM_InstanceErrorReturnedENIStillDeleted(t *testing.T) { + vpc := &fakeK3sVPC{} + inst := &fakeK3sInst{terminateErr: errors.New("IncorrectInstanceState")} + + err := TerminateK3sServerVM(vpc, inst, "111122223333", "i-aaa111", "eni-aaa111") + require.Error(t, err) + assert.Contains(t, err.Error(), "terminate instance i-aaa111") + require.Len(t, vpc.deleteCalls, 1, "ENI delete should still run after instance terminate fails") +} + +func TestTerminateK3sServerVM_ENINotFoundIsIdempotent(t *testing.T) { + // A retried delete-cluster after the instance-terminate cascade already + // removed the ENI: DeleteNetworkInterface returns NotFound. This must be + // treated as success so the SG + KV sweep downstream is not blocked. + vpc := &fakeK3sVPC{deleteErr: errors.New(awserrors.ErrorInvalidNetworkInterfaceIDNotFound)} + inst := &fakeK3sInst{} + + err := TerminateK3sServerVM(vpc, inst, "111122223333", "i-aaa111", "eni-aaa111") + require.NoError(t, err, "ENI already gone must be idempotent success, not a blocking error") + require.Len(t, vpc.deleteCalls, 1) +} + +func TestTerminateK3sServerVM_ENIInUseIsRetryable(t *testing.T) { + // The VM is still terminating async and holds the ENI. InUse must surface + // as an error so the cluster stays DELETING and the reconciler retries. + vpc := &fakeK3sVPC{deleteErr: errors.New(awserrors.ErrorInvalidNetworkInterfaceInUse)} + inst := &fakeK3sInst{} + + err := TerminateK3sServerVM(vpc, inst, "111122223333", "i-aaa111", "eni-aaa111") + require.Error(t, err, "ENI still in use must be retryable, not swallowed") + assert.Contains(t, err.Error(), "delete ENI eni-aaa111") +} + +func TestTerminateK3sServerVM_InstanceAlreadyGoneIsIdempotent(t *testing.T) { + // On a reconciler retry the VM already drained, so TerminateSystemInstance + // returns ErrSystemInstanceNotFound. This must not block teardown; the ENI + // delete still runs. + vpc := &fakeK3sVPC{} + inst := &fakeK3sInst{terminateErr: fmt.Errorf("%w: i-aaa111", sysinstance.ErrSystemInstanceNotFound)} + + err := TerminateK3sServerVM(vpc, inst, "111122223333", "i-aaa111", "eni-aaa111") + require.NoError(t, err, "instance already gone must be idempotent success") + require.Len(t, vpc.deleteCalls, 1, "ENI delete still runs after a tolerated instance-gone") +} + +func assertEC2TaggedAsEKSControlPlane(t *testing.T, ec2Tags []*ec2.Tag, clusterName string) { + t.Helper() + got := map[string]string{} + for _, tg := range ec2Tags { + if tg == nil || tg.Key == nil || tg.Value == nil { + continue + } + got[*tg.Key] = *tg.Value + } + assert.Equal(t, tags.ManagedByEKS, got[tags.ManagedByKey]) + assert.Equal(t, clusterName, got[clusterEKSClusterTagKey]) + assert.Equal(t, clusterEKSRoleControlPlane, got[clusterEKSRoleTagKey]) +} diff --git a/spinifex/handlers/eks/nats_bootstrap.go b/spinifex/handlers/eks/nats_bootstrap.go new file mode 100644 index 000000000..fd7a64dbe --- /dev/null +++ b/spinifex/handlers/eks/nats_bootstrap.go @@ -0,0 +1,386 @@ +package handlers_eks + +import ( + "context" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "log/slog" + "sync" + "time" + + handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam" + "github.com/nats-io/nats.go" +) + +// errBootstrapPermanent marks a bootstrap persist failure that no amount of +// retrying will fix — a malformed envelope, a non-base64 CA, or a JWKS whose +// kid does not match the controller-generated keypair. Transient failures +// (KV write blips, JWKS-not-yet-propagated) are NOT wrapped with this, so +// persistWithRetry keeps retrying them. A permanent error fails the cluster. +var errBootstrapPermanent = errors.New("bootstrap permanent error") + +const ( + // bootstrapPersistAttempts bounds inline retries of a single subject's + // persist op on transient errors. A core-NATS publication is delivered + // once, so a transient KV blip must be ridden out in-handler rather than + // by tearing down the subscription and waiting for a re-publish that + // never comes. + bootstrapPersistAttempts = 3 + bootstrapPersistBackoff = 200 * time.Millisecond +) + +// persistWithRetry runs op, retrying on transient errors up to +// bootstrapPersistAttempts. A nil result or an errBootstrapPermanent result +// returns immediately (no retry). +func persistWithRetry(op func() error) error { + var err error + for attempt := 1; attempt <= bootstrapPersistAttempts; attempt++ { + err = op() + if err == nil || errors.Is(err, errBootstrapPermanent) { + return err + } + if attempt < bootstrapPersistAttempts { + time.Sleep(bootstrapPersistBackoff) + } + } + return err +} + +// Bootstrap subject kinds. Full subject is +// "eks.bus.{accountID}.{clusterName}.{kind}" — see BootstrapSubject. +const ( + BootstrapSubjectToken = "k3s-bootstrap-token" //nolint:gosec // subject suffix, not a credential + BootstrapSubjectKubeconfig = "k3s-admin-kubeconfig" + BootstrapSubjectJWKS = "k3s-oidc-jwks" + BootstrapSubjectCA = "k3s-ca" +) + +// BootstrapSubject returns the per-cluster bootstrap subject for one kind. +func BootstrapSubject(accountID, clusterName, kind string) string { + return fmt.Sprintf("eks.bus.%s.%s.%s", accountID, clusterName, kind) +} + +// BootstrapEnvelope is the JSON wire shape every k3s-first-boot.sh +// publication uses. Each subject populates the field matching its kind; the +// rest stay empty. Versioned implicitly by field shape — adding new optional +// fields is backwards-compatible. +type BootstrapEnvelope struct { + // Token is the K3s bootstrap node-token for the cluster (k3s-bootstrap-token). + Token string `json:"token,omitempty"` + // AdminKubeconfig is the cluster-admin kubeconfig YAML + // (k3s-admin-kubeconfig). + AdminKubeconfig string `json:"adminKubeconfig,omitempty"` + // JWKS is the K3s-published RFC 7517 JWKS document. The bootstrap + // subscriber cross-checks it against the controller-generated keypair + // (k3s-oidc-jwks). + JWKS string `json:"jwks,omitempty"` + // CertificateAuthority is the base64-encoded K3s server CA PEM + // (k3s-ca). Written onto meta.CertificateAuthorityB64. + CertificateAuthority string `json:"certificateAuthority,omitempty"` +} + +// NATSBootstrap collects the four single-shot bootstrap publications from a +// K3s server VM, validates the OIDC JWKS against what the controller wrote +// pre-VM, persists each artifact into the per-cluster KV bucket, and writes +// the CA onto meta.CertificateAuthorityB64. The reconciler observes +// completion via the four KV keys + meta.CertificateAuthorityB64. +type NATSBootstrap struct { + nc *nats.Conn + kv nats.KeyValue + masterKey []byte + accountID string + clusterName string +} + +// NewNATSBootstrap validates inputs and returns a ready subscriber. Run must +// be called to actually subscribe; constructor is side-effect-free. +func NewNATSBootstrap(nc *nats.Conn, kv nats.KeyValue, masterKey []byte, accountID, clusterName string) (*NATSBootstrap, error) { + if nc == nil { + return nil, errors.New("eks: NewNATSBootstrap nil nats conn") + } + if kv == nil { + return nil, errors.New("eks: NewNATSBootstrap nil kv") + } + if len(masterKey) == 0 { + return nil, errors.New("eks: NewNATSBootstrap empty master key") + } + if accountID == "" { + return nil, errors.New("eks: NewNATSBootstrap empty accountID") + } + if clusterName == "" { + return nil, errors.New("eks: NewNATSBootstrap empty clusterName") + } + return &NATSBootstrap{ + nc: nc, + kv: kv, + masterKey: masterKey, + accountID: accountID, + clusterName: clusterName, + }, nil +} + +// BootstrapPendingKinds reports which bootstrap subjects still lack their +// persisted artifact for a cluster, so a daemon-restart resume re-subscribes +// only to what is missing. The K3s VM publishes each subject once over core +// NATS and never republishes, so re-waiting on an already-arrived subject +// would deadlock. +// +// JWKS is tracked by its verified-marker (OIDCJWKSVerifiedKey), written by +// persistJWKS only after the cross-check passes — NOT by OIDCJWKSKey, which the +// controller pre-seeds at create time. Until the marker exists the cross-check +// has not positively passed, so resume re-subscribes to JWKS like any other +// pending subject. (If the VM published JWKS during the restart window the +// re-subscribe waits for a republish that never comes and the cluster fails on +// the create timeout — the same one-shot limitation every bootstrap subject +// shares, now applied uniformly so ACTIVE always implies a verified key.) +func BootstrapPendingKinds(kv nats.KeyValue, clusterName string, meta *ClusterMeta) []string { + var pending []string + if _, err := kv.Get(NodeTokenKey(clusterName)); err != nil { + pending = append(pending, BootstrapSubjectToken) + } + if _, err := kv.Get(AdminKubeconfigKey(clusterName)); err != nil { + pending = append(pending, BootstrapSubjectKubeconfig) + } + if _, err := kv.Get(OIDCJWKSVerifiedKey(clusterName)); err != nil { + pending = append(pending, BootstrapSubjectJWKS) + } + if meta == nil || meta.CertificateAuthorityB64 == "" { + pending = append(pending, BootstrapSubjectCA) + } + return pending +} + +type bootstrapSubjectHandler struct { + subject string + kind string + handler func([]byte) error +} + +// subjectHandlers returns the subject/handler entry for each requested kind. +// An unknown kind is an error — callers pass kinds from BootstrapSubject* +// constants. A nil/empty kinds slice means all four. +func (b *NATSBootstrap) subjectHandlers(kinds []string) ([]bootstrapSubjectHandler, error) { + all := map[string]func([]byte) error{ + BootstrapSubjectToken: b.persistToken, + BootstrapSubjectKubeconfig: b.persistKubeconfig, + BootstrapSubjectJWKS: b.persistJWKS, + BootstrapSubjectCA: b.persistCA, + } + if len(kinds) == 0 { + kinds = []string{BootstrapSubjectToken, BootstrapSubjectKubeconfig, BootstrapSubjectJWKS, BootstrapSubjectCA} + } + out := make([]bootstrapSubjectHandler, 0, len(kinds)) + for _, kind := range kinds { + handler, ok := all[kind] + if !ok { + return nil, fmt.Errorf("eks: unknown bootstrap kind %q", kind) + } + out = append(out, bootstrapSubjectHandler{ + subject: BootstrapSubject(b.accountID, b.clusterName, kind), + kind: kind, + handler: handler, + }) + } + return out, nil +} + +// Run subscribes to all four bootstrap subjects and returns when all four have +// arrived, ctx is cancelled, or a handler errors. See RunForKinds. +func (b *NATSBootstrap) Run(ctx context.Context) error { + return b.RunForKinds(ctx, nil) +} + +// RunForKinds subscribes only to the requested bootstrap subjects (nil = all +// four) and returns when: +// - every requested subject has arrived and persisted successfully (nil), +// - ctx is cancelled (ctx.Err()), +// - one of the persistence handlers returns an error (first error). +// +// The subset form drives daemon-restart recovery: a cluster that already has +// some artifacts in KV re-subscribes only to the missing ones, since the K3s +// VM published each subject once over core NATS and will not republish. +// +// Each subject is consumed at most once; subsequent publications on the same +// subject are dropped. Subscriptions are always cleaned up before return. +func (b *NATSBootstrap) RunForKinds(ctx context.Context, kinds []string) error { + subs, err := b.subjectHandlers(kinds) + if err != nil { + return err + } + want := len(subs) + + errCh := make(chan error, want) + doneCh := make(chan struct{}, 1) + var ( + mu sync.Mutex + done = make(map[string]struct{}, want) + ) + + var subscriptions []*nats.Subscription + defer func() { + for _, sub := range subscriptions { + _ = sub.Unsubscribe() + } + }() + + for _, s := range subs { + sub, err := b.nc.Subscribe(s.subject, func(m *nats.Msg) { + mu.Lock() + if _, ok := done[s.kind]; ok { + mu.Unlock() + return + } + mu.Unlock() + if err := persistWithRetry(func() error { return s.handler(m.Data) }); err != nil { + errCh <- fmt.Errorf("persist %s: %w", s.kind, err) + return + } + mu.Lock() + done[s.kind] = struct{}{} + full := len(done) == want + mu.Unlock() + if full { + select { + case doneCh <- struct{}{}: + default: + } + } + }) + if err != nil { + return fmt.Errorf("subscribe %s: %w", s.subject, err) + } + subscriptions = append(subscriptions, sub) + } + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case err := <-errCh: + return err + case <-doneCh: + slog.Info("NATSBootstrap: all requested bootstrap messages received", + "accountID", b.accountID, "cluster", b.clusterName, "kinds", want) + return nil + } + } +} + +func (b *NATSBootstrap) persistToken(data []byte) error { + env, err := unmarshalBootstrapEnvelope(data) + if err != nil { + return err + } + if env.Token == "" { + return fmt.Errorf("%w: token envelope empty", errBootstrapPermanent) + } + ct, err := handlers_iam.EncryptSecret(env.Token, b.masterKey) + if err != nil { + return fmt.Errorf("encrypt token: %w", err) + } + if _, err := b.kv.Put(NodeTokenKey(b.clusterName), []byte(ct)); err != nil { + return fmt.Errorf("kv put %s: %w", NodeTokenKey(b.clusterName), err) + } + return nil +} + +func (b *NATSBootstrap) persistKubeconfig(data []byte) error { + env, err := unmarshalBootstrapEnvelope(data) + if err != nil { + return err + } + if env.AdminKubeconfig == "" { + return fmt.Errorf("%w: adminKubeconfig envelope empty", errBootstrapPermanent) + } + ct, err := handlers_iam.EncryptSecret(env.AdminKubeconfig, b.masterKey) + if err != nil { + return fmt.Errorf("encrypt kubeconfig: %w", err) + } + if _, err := b.kv.Put(AdminKubeconfigKey(b.clusterName), []byte(ct)); err != nil { + return fmt.Errorf("kv put %s: %w", AdminKubeconfigKey(b.clusterName), err) + } + return nil +} + +func (b *NATSBootstrap) persistJWKS(data []byte) error { + env, err := unmarshalBootstrapEnvelope(data) + if err != nil { + return err + } + if env.JWKS == "" { + return fmt.Errorf("%w: jwks envelope empty", errBootstrapPermanent) + } + existing, err := b.kv.Get(OIDCJWKSKey(b.clusterName)) + if err != nil { + return fmt.Errorf("kv get %s: %w", OIDCJWKSKey(b.clusterName), err) + } + if err := assertJWKSMatch(existing.Value(), []byte(env.JWKS)); err != nil { + return err + } + // Record the positive cross-check as a distinct marker. The reconciler + // gates ACTIVE on this key — never on OIDCJWKSKey, which the controller + // pre-seeds at create time — so a cluster cannot reach ACTIVE on an + // unverified or mismatched signing key. + if _, err := b.kv.Put(OIDCJWKSVerifiedKey(b.clusterName), []byte("verified")); err != nil { + return fmt.Errorf("kv put %s: %w", OIDCJWKSVerifiedKey(b.clusterName), err) + } + return nil +} + +func (b *NATSBootstrap) persistCA(data []byte) error { + env, err := unmarshalBootstrapEnvelope(data) + if err != nil { + return err + } + if env.CertificateAuthority == "" { + return fmt.Errorf("%w: CA envelope empty", errBootstrapPermanent) + } + if _, err := base64.StdEncoding.DecodeString(env.CertificateAuthority); err != nil { + return fmt.Errorf("%w: CA not base64: %v", errBootstrapPermanent, err) + } + return SetClusterCertificateAuthority(b.kv, b.clusterName, env.CertificateAuthority) +} + +func unmarshalBootstrapEnvelope(data []byte) (BootstrapEnvelope, error) { + var env BootstrapEnvelope + if err := json.Unmarshal(data, &env); err != nil { + return env, fmt.Errorf("%w: unmarshal envelope: %v", errBootstrapPermanent, err) + } + return env, nil +} + +// assertJWKSMatch verifies that every key in the incoming JWKS matches a +// controller-generated key by both key id (kid) and key type (kty). A kid +// mismatch means the VM generated its own signing key instead of consuming our +// PEM; a kty mismatch (e.g. an RSA key carrying our EC key's kid) means the +// published key cannot be the one the controller distributed even though the +// kid collides. Either rejects the publication. +func assertJWKSMatch(existing, incoming []byte) error { + var ex, in oidcJWKS + if err := json.Unmarshal(existing, &ex); err != nil { + return fmt.Errorf("unmarshal existing JWKS: %w", err) + } + if err := json.Unmarshal(incoming, &in); err != nil { + return fmt.Errorf("%w: unmarshal incoming JWKS: %v", errBootstrapPermanent, err) + } + if len(in.Keys) == 0 { + return fmt.Errorf("%w: incoming JWKS has no keys", errBootstrapPermanent) + } + have := make(map[string]oidcJWK, len(ex.Keys)) + for _, k := range ex.Keys { + have[k.Kid] = k + } + for _, k := range in.Keys { + exKey, ok := have[k.Kid] + if !ok { + return fmt.Errorf("%w: bootstrap JWKS kid %q does not match generated keypair", errBootstrapPermanent, k.Kid) + } + if k.Kty != exKey.Kty { + return fmt.Errorf("%w: bootstrap JWKS kid %q key type %q does not match generated %q", + errBootstrapPermanent, k.Kid, k.Kty, exKey.Kty) + } + } + return nil +} diff --git a/spinifex/handlers/eks/nats_bootstrap_test.go b/spinifex/handlers/eks/nats_bootstrap_test.go new file mode 100644 index 000000000..08fdc7cef --- /dev/null +++ b/spinifex/handlers/eks/nats_bootstrap_test.go @@ -0,0 +1,390 @@ +package handlers_eks + +import ( + "context" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "strings" + "testing" + "time" + + handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam" + "github.com/mulgadc/spinifex/spinifex/testutil" + "github.com/nats-io/nats.go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const ( + bootstrapTestCluster = "alpha" +) + +var bootstrapTestMasterKey = []byte("0123456789abcdef0123456789abcdef") + +// natsBootstrapHarness wires an embedded JetStream NATS server, a per-account +// KV bucket, a published controller JWKS (so persistJWKS has something to +// cross-check against), and a NATSBootstrap subscriber. +type natsBootstrapHarness struct { + t *testing.T + nc *nats.Conn + kv nats.KeyValue + + subscriber *NATSBootstrap +} + +func newBootstrapHarness(t *testing.T) *natsBootstrapHarness { + t.Helper() + _, nc, js := testutil.StartTestJetStream(t) + kv, err := GetOrCreateAccountBucket(js, testAccountID) + require.NoError(t, err) + + require.NoError(t, PutClusterMeta(kv, sampleClusterMeta(bootstrapTestCluster))) + + // Lay down the controller-generated JWKS so persistJWKS has something + // to cross-check against. + _, _, err = GenerateClusterOIDCKeypair(kv, bootstrapTestCluster, bootstrapTestMasterKey) + require.NoError(t, err) + + sub, err := NewNATSBootstrap(nc, kv, bootstrapTestMasterKey, testAccountID, bootstrapTestCluster) + require.NoError(t, err) + + return &natsBootstrapHarness{t: t, nc: nc, kv: kv, subscriber: sub} +} + +func (h *natsBootstrapHarness) publish(kind string, env BootstrapEnvelope) { + h.t.Helper() + data, err := json.Marshal(env) + require.NoError(h.t, err) + subject := BootstrapSubject(testAccountID, bootstrapTestCluster, kind) + require.NoError(h.t, h.nc.Publish(subject, data)) + require.NoError(h.t, h.nc.Flush()) +} + +func (h *natsBootstrapHarness) loadControllerJWKS() []byte { + h.t.Helper() + entry, err := h.kv.Get(OIDCJWKSKey(bootstrapTestCluster)) + require.NoError(h.t, err) + return entry.Value() +} + +func TestNewNATSBootstrap_RejectsBadInputs(t *testing.T) { + _, nc, js := testutil.StartTestJetStream(t) + kv, err := GetOrCreateAccountBucket(js, testAccountID) + require.NoError(t, err) + + _, err = NewNATSBootstrap(nil, kv, bootstrapTestMasterKey, testAccountID, "alpha") + require.Error(t, err) + _, err = NewNATSBootstrap(nc, nil, bootstrapTestMasterKey, testAccountID, "alpha") + require.Error(t, err) + _, err = NewNATSBootstrap(nc, kv, nil, testAccountID, "alpha") + require.Error(t, err) + _, err = NewNATSBootstrap(nc, kv, bootstrapTestMasterKey, "", "alpha") + require.Error(t, err) + _, err = NewNATSBootstrap(nc, kv, bootstrapTestMasterKey, testAccountID, "") + require.Error(t, err) +} + +func TestNATSBootstrap_HappyPath(t *testing.T) { + h := newBootstrapHarness(t) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + jwks := string(h.loadControllerJWKS()) + caB64 := base64.StdEncoding.EncodeToString([]byte("-----BEGIN CERTIFICATE-----\nfakeCA\n-----END CERTIFICATE-----\n")) + + runErr := make(chan error, 1) + go func() { runErr <- h.subscriber.Run(ctx) }() + + // Give subscriptions time to bind before publishing. + require.Eventually(t, func() bool { + // Probe by sending a no-op flush — once Run is past Subscribe the + // subjects are live; we just need a small yield to the goroutine. + return true + }, 100*time.Millisecond, 10*time.Millisecond) + time.Sleep(50 * time.Millisecond) + + h.publish(BootstrapSubjectToken, BootstrapEnvelope{Token: "k3s::server-node-token::v1"}) + h.publish(BootstrapSubjectKubeconfig, BootstrapEnvelope{AdminKubeconfig: "apiVersion: v1\nkind: Config\n"}) + h.publish(BootstrapSubjectJWKS, BootstrapEnvelope{JWKS: jwks}) + h.publish(BootstrapSubjectCA, BootstrapEnvelope{CertificateAuthority: caB64}) + + select { + case err := <-runErr: + require.NoError(t, err) + case <-time.After(3 * time.Second): + t.Fatal("Run did not return after all four publications") + } + + tokEntry, err := h.kv.Get(NodeTokenKey(bootstrapTestCluster)) + require.NoError(t, err) + dec, err := handlers_iam.DecryptSecret(string(tokEntry.Value()), bootstrapTestMasterKey) + require.NoError(t, err) + assert.Equal(t, "k3s::server-node-token::v1", dec) + + kcEntry, err := h.kv.Get(AdminKubeconfigKey(bootstrapTestCluster)) + require.NoError(t, err) + dec, err = handlers_iam.DecryptSecret(string(kcEntry.Value()), bootstrapTestMasterKey) + require.NoError(t, err) + assert.Equal(t, "apiVersion: v1\nkind: Config\n", dec) + + meta, err := GetClusterMeta(h.kv, bootstrapTestCluster) + require.NoError(t, err) + assert.Equal(t, caB64, meta.CertificateAuthorityB64) + + // The passing JWKS cross-check must record the verified-marker the + // reconciler gates ACTIVE on. + _, err = h.kv.Get(OIDCJWKSVerifiedKey(bootstrapTestCluster)) + require.NoError(t, err, "persistJWKS must write the verified-marker on a passing cross-check") +} + +func TestNATSBootstrap_ContextCancelReturnsErr(t *testing.T) { + h := newBootstrapHarness(t) + ctx, cancel := context.WithCancel(context.Background()) + + runErr := make(chan error, 1) + go func() { runErr <- h.subscriber.Run(ctx) }() + time.Sleep(50 * time.Millisecond) + + cancel() + + select { + case err := <-runErr: + require.ErrorIs(t, err, context.Canceled) + case <-time.After(2 * time.Second): + t.Fatal("Run did not return after ctx cancel") + } +} + +func TestNATSBootstrap_JWKSMismatchReturnsErr(t *testing.T) { + h := newBootstrapHarness(t) + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + + runErr := make(chan error, 1) + go func() { runErr <- h.subscriber.Run(ctx) }() + time.Sleep(50 * time.Millisecond) + + // kid mismatch — controller generated a real kid, we send a bogus one. + badJWKS := `{"keys":[{"kty":"EC","kid":"not-the-controller-kid","crv":"P-256","x":"AAA","y":"BBB"}]}` + h.publish(BootstrapSubjectJWKS, BootstrapEnvelope{JWKS: badJWKS}) + + select { + case err := <-runErr: + require.Error(t, err) + assert.Contains(t, err.Error(), "JWKS kid") + case <-time.After(3 * time.Second): + t.Fatal("Run did not return on JWKS mismatch") + } +} + +func TestAssertJWKSMatch_RejectsKtyMismatch(t *testing.T) { + // Same kid as the controller key, but RSA instead of EC — a published key + // that cannot be the one the controller distributed despite the kid + // collision. Must be rejected. + existing := []byte(`{"keys":[{"kty":"EC","kid":"abc","crv":"P-256","x":"AAA","y":"BBB"}]}`) + incoming := []byte(`{"keys":[{"kty":"RSA","kid":"abc","n":"AAA","e":"AQAB"}]}`) + + err := assertJWKSMatch(existing, incoming) + require.Error(t, err) + require.ErrorIs(t, err, errBootstrapPermanent) + assert.Contains(t, err.Error(), "key type") +} + +func TestAssertJWKSMatch_AcceptsMatchingKidAndKty(t *testing.T) { + jwks := []byte(`{"keys":[{"kty":"EC","kid":"abc","crv":"P-256","x":"AAA","y":"BBB"}]}`) + require.NoError(t, assertJWKSMatch(jwks, jwks)) +} + +func TestNATSBootstrap_EmptyEnvelopeFieldsRejected(t *testing.T) { + h := newBootstrapHarness(t) + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + + runErr := make(chan error, 1) + go func() { runErr <- h.subscriber.Run(ctx) }() + time.Sleep(50 * time.Millisecond) + + h.publish(BootstrapSubjectToken, BootstrapEnvelope{}) + + select { + case err := <-runErr: + require.Error(t, err) + assert.Contains(t, err.Error(), "token envelope empty") + case <-time.After(3 * time.Second): + t.Fatal("Run did not return on empty envelope") + } +} + +func TestNATSBootstrap_OneShotIgnoresSubsequentMessages(t *testing.T) { + h := newBootstrapHarness(t) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + jwks := string(h.loadControllerJWKS()) + caB64 := base64.StdEncoding.EncodeToString([]byte("ca-pem")) + + runErr := make(chan error, 1) + go func() { runErr <- h.subscriber.Run(ctx) }() + time.Sleep(50 * time.Millisecond) + + // First, send only token so subsequent token publications are dropped. + h.publish(BootstrapSubjectToken, BootstrapEnvelope{Token: "first-token"}) + time.Sleep(50 * time.Millisecond) + // Second token publication has a different value; persistToken should not + // re-encrypt/overwrite because the one-shot map prevents reprocess. + h.publish(BootstrapSubjectToken, BootstrapEnvelope{Token: "second-token"}) + + h.publish(BootstrapSubjectKubeconfig, BootstrapEnvelope{AdminKubeconfig: "kc"}) + h.publish(BootstrapSubjectJWKS, BootstrapEnvelope{JWKS: jwks}) + h.publish(BootstrapSubjectCA, BootstrapEnvelope{CertificateAuthority: caB64}) + + select { + case err := <-runErr: + require.NoError(t, err) + case <-time.After(3 * time.Second): + t.Fatal("Run did not return") + } + + entry, err := h.kv.Get(NodeTokenKey(bootstrapTestCluster)) + require.NoError(t, err) + dec, err := handlers_iam.DecryptSecret(string(entry.Value()), bootstrapTestMasterKey) + require.NoError(t, err) + assert.Equal(t, "first-token", dec, "second token publication must be dropped") +} + +func TestNATSBootstrap_CANotBase64Rejected(t *testing.T) { + h := newBootstrapHarness(t) + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + + runErr := make(chan error, 1) + go func() { runErr <- h.subscriber.Run(ctx) }() + time.Sleep(50 * time.Millisecond) + + h.publish(BootstrapSubjectCA, BootstrapEnvelope{CertificateAuthority: "not!base64@@@"}) + + select { + case err := <-runErr: + require.Error(t, err) + assert.Contains(t, err.Error(), "CA not base64") + case <-time.After(3 * time.Second): + t.Fatal("Run did not return") + } +} + +func TestPersistWithRetry(t *testing.T) { + t.Run("succeeds first try", func(t *testing.T) { + calls := 0 + err := persistWithRetry(func() error { calls++; return nil }) + require.NoError(t, err) + assert.Equal(t, 1, calls) + }) + + t.Run("retries transient then succeeds", func(t *testing.T) { + calls := 0 + err := persistWithRetry(func() error { + calls++ + if calls < 2 { + return errors.New("transient kv blip") + } + return nil + }) + require.NoError(t, err) + assert.Equal(t, 2, calls) + }) + + t.Run("permanent error returns immediately without retry", func(t *testing.T) { + calls := 0 + err := persistWithRetry(func() error { + calls++ + return fmt.Errorf("%w: malformed envelope", errBootstrapPermanent) + }) + require.ErrorIs(t, err, errBootstrapPermanent) + assert.Equal(t, 1, calls, "permanent error must not be retried") + }) + + t.Run("transient error exhausts attempts", func(t *testing.T) { + calls := 0 + err := persistWithRetry(func() error { calls++; return errors.New("always transient") }) + require.Error(t, err) + assert.Equal(t, bootstrapPersistAttempts, calls) + }) +} + +func TestBootstrapPendingKinds(t *testing.T) { + h := newBootstrapHarness(t) + + meta, err := GetClusterMeta(h.kv, bootstrapTestCluster) + require.NoError(t, err) + + // Fresh cluster: all four pending. The JWKS verified-marker is absent even + // though the controller pre-seeded OIDCJWKSKey, so JWKS is still pending. + assert.Equal(t, + []string{BootstrapSubjectToken, BootstrapSubjectKubeconfig, BootstrapSubjectJWKS, BootstrapSubjectCA}, + BootstrapPendingKinds(h.kv, bootstrapTestCluster, meta)) + + // Persist token only -> token drops out of pending. + ct, err := handlers_iam.EncryptSecret("tok", bootstrapTestMasterKey) + require.NoError(t, err) + _, err = h.kv.Put(NodeTokenKey(bootstrapTestCluster), []byte(ct)) + require.NoError(t, err) + assert.Equal(t, + []string{BootstrapSubjectKubeconfig, BootstrapSubjectJWKS, BootstrapSubjectCA}, + BootstrapPendingKinds(h.kv, bootstrapTestCluster, meta)) + + // Persist kubeconfig + CA-on-meta -> only JWKS (unverified) still pending. + _, err = h.kv.Put(AdminKubeconfigKey(bootstrapTestCluster), []byte(ct)) + require.NoError(t, err) + meta.CertificateAuthorityB64 = "ca-b64" + assert.Equal(t, + []string{BootstrapSubjectJWKS}, + BootstrapPendingKinds(h.kv, bootstrapTestCluster, meta)) + + // Write the JWKS verified-marker (persistJWKS does this on a passing + // cross-check) -> nothing pending. + _, err = h.kv.Put(OIDCJWKSVerifiedKey(bootstrapTestCluster), []byte("verified")) + require.NoError(t, err) + assert.Empty(t, BootstrapPendingKinds(h.kv, bootstrapTestCluster, meta)) +} + +func TestNATSBootstrap_RunForKindsWaitsOnlyForSubset(t *testing.T) { + h := newBootstrapHarness(t) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + caB64 := base64.StdEncoding.EncodeToString([]byte("ca-pem")) + + runErr := make(chan error, 1) + go func() { runErr <- h.subscriber.RunForKinds(ctx, []string{BootstrapSubjectCA}) }() + time.Sleep(50 * time.Millisecond) + + // Only publish CA; the subset subscriber must complete without token, + // kubeconfig, or JWKS ever arriving (they were consumed pre-restart). + h.publish(BootstrapSubjectCA, BootstrapEnvelope{CertificateAuthority: caB64}) + + select { + case err := <-runErr: + require.NoError(t, err) + case <-time.After(3 * time.Second): + t.Fatal("RunForKinds did not return after CA-only publication") + } + + meta, err := GetClusterMeta(h.kv, bootstrapTestCluster) + require.NoError(t, err) + assert.Equal(t, caB64, meta.CertificateAuthorityB64) +} + +func TestNATSBootstrap_RunForKindsRejectsUnknownKind(t *testing.T) { + h := newBootstrapHarness(t) + err := h.subscriber.RunForKinds(context.Background(), []string{"bogus-kind"}) + require.Error(t, err) + assert.Contains(t, err.Error(), "unknown bootstrap kind") +} + +func TestBootstrapSubject_Shape(t *testing.T) { + got := BootstrapSubject("111122223333", "alpha", BootstrapSubjectToken) + assert.Equal(t, "eks.bus.111122223333.alpha.k3s-bootstrap-token", got) + assert.True(t, strings.HasPrefix(got, "eks.bus.")) +} diff --git a/spinifex/handlers/eks/nlb.go b/spinifex/handlers/eks/nlb.go new file mode 100644 index 000000000..dc7fc8b38 --- /dev/null +++ b/spinifex/handlers/eks/nlb.go @@ -0,0 +1,353 @@ +package handlers_eks + +import ( + "errors" + "fmt" + "log/slog" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/tags" +) + +// nlbProvisioner is the subset of handlers_elbv2.ELBv2Service that the +// cluster NLB helpers need. Narrow so tests can fake with hand-rolled +// recorders without implementing the full ELBv2 surface. +type nlbProvisioner interface { + CreateLoadBalancer(input *elbv2.CreateLoadBalancerInput, accountID string) (*elbv2.CreateLoadBalancerOutput, error) + DescribeLoadBalancers(input *elbv2.DescribeLoadBalancersInput, accountID string) (*elbv2.DescribeLoadBalancersOutput, error) + DeleteLoadBalancer(input *elbv2.DeleteLoadBalancerInput, accountID string) (*elbv2.DeleteLoadBalancerOutput, error) + + CreateTargetGroup(input *elbv2.CreateTargetGroupInput, accountID string) (*elbv2.CreateTargetGroupOutput, error) + DescribeTargetGroups(input *elbv2.DescribeTargetGroupsInput, accountID string) (*elbv2.DescribeTargetGroupsOutput, error) + DeleteTargetGroup(input *elbv2.DeleteTargetGroupInput, accountID string) (*elbv2.DeleteTargetGroupOutput, error) + + CreateListener(input *elbv2.CreateListenerInput, accountID string) (*elbv2.CreateListenerOutput, error) + DescribeListeners(input *elbv2.DescribeListenersInput, accountID string) (*elbv2.DescribeListenersOutput, error) + + RegisterTargets(input *elbv2.RegisterTargetsInput, accountID string) (*elbv2.RegisterTargetsOutput, error) + DeregisterTargets(input *elbv2.DeregisterTargetsInput, accountID string) (*elbv2.DeregisterTargetsOutput, error) +} + +// AWS load-balancer + target-group names are bounded to 32 alphanumeric or +// hyphen characters. EnsureClusterNLB rejects clusters whose derived name +// would exceed this before issuing the create call so callers see a clear +// error instead of a generic ELBv2 InvalidParameterValue. +const maxELBv2NameLen = 32 + +// k3sAPIServerPort is the in-VM K3s api-server bind port. The NLB target +// group sends traffic to this port on the K3s server VM's ENI. +const k3sAPIServerPort int64 = 6443 + +// clusterNLBListenPort is the customer-facing port the cluster NLB exposes. +// kubectl + the AWS SDK both expect TLS on 443. +const clusterNLBListenPort int64 = 443 + +// ClusterNLB is the in-process tuple produced by EnsureClusterNLB. Each ARN +// is persisted into ClusterMeta so the reconciler + DeleteCluster can act on +// the resources without re-resolving by name. +type ClusterNLB struct { + LoadBalancerArn string + TargetGroupArn string + ListenerArn string + DNSName string +} + +// ClusterNLBName returns the deterministic NLB name for a cluster. Stable so +// DeleteCluster can locate the NLB from clusterName alone after a daemon +// restart that lost the in-memory ARN. +func ClusterNLBName(clusterName string) string { + return "eks-" + clusterName +} + +// ClusterTargetGroupName returns the deterministic target-group name for a +// cluster's control-plane TG. +func ClusterTargetGroupName(clusterName string) string { + return "eks-" + clusterName + "-cp" +} + +// EnsureClusterNLB provisions (or returns) the cluster's NLB + target group + +// :443→:6443 TCP listener. Idempotent on clusterName: existing resources are +// reused so DeleteCluster failure-retry and reconciler crash-recovery both +// converge without duplicate creates. +// +// The K3s server VM ENI IP is NOT registered here — Stage 4 +// (k3s_server_vm.go) calls RegisterClusterTarget once the VM has its ENI IP. +func EnsureClusterNLB(nlbp nlbProvisioner, accountID, clusterName string, subnetIDs []string) (*ClusterNLB, error) { + if clusterName == "" { + return nil, errors.New("eks: EnsureClusterNLB empty cluster name") + } + if len(subnetIDs) == 0 { + return nil, errors.New("eks: EnsureClusterNLB empty subnet list") + } + lbName := ClusterNLBName(clusterName) + tgName := ClusterTargetGroupName(clusterName) + if len(lbName) > maxELBv2NameLen { + return nil, fmt.Errorf("eks: NLB name %q exceeds %d chars (cluster name too long)", lbName, maxELBv2NameLen) + } + if len(tgName) > maxELBv2NameLen { + return nil, fmt.Errorf("eks: TG name %q exceeds %d chars (cluster name too long)", tgName, maxELBv2NameLen) + } + + out := &ClusterNLB{} + + if err := ensureClusterLB(nlbp, accountID, clusterName, lbName, subnetIDs, out); err != nil { + return nil, err + } + if err := ensureClusterTG(nlbp, accountID, clusterName, tgName, out); err != nil { + return nil, err + } + if err := ensureClusterListener(nlbp, accountID, lbName, out); err != nil { + return nil, err + } + return out, nil +} + +// RegisterClusterTarget attaches the K3s server ENI IP to the cluster TG so +// the NLB starts forwarding :443 traffic to :6443 on the VM. The ELBv2 +// RegisterTargets impl already dedupes on (id, port), so re-invocation by +// the reconciler is idempotent. +func RegisterClusterTarget(nlbp nlbProvisioner, accountID, tgArn, eniIP string) error { + if tgArn == "" { + return errors.New("eks: RegisterClusterTarget empty TG arn") + } + if eniIP == "" { + return errors.New("eks: RegisterClusterTarget empty ENI IP") + } + if _, err := nlbp.RegisterTargets(&elbv2.RegisterTargetsInput{ + TargetGroupArn: aws.String(tgArn), + Targets: []*elbv2.TargetDescription{{ + Id: aws.String(eniIP), + Port: aws.Int64(k3sAPIServerPort), + }}, + }, accountID); err != nil { + return fmt.Errorf("register target %s on TG %s: %w", eniIP, tgArn, err) + } + return nil +} + +// DeregisterClusterTarget removes the K3s server ENI IP from the cluster TG. +// Called by DeleteCluster before VM termination so health checks stop hitting +// a dying target. +func DeregisterClusterTarget(nlbp nlbProvisioner, accountID, tgArn, eniIP string) error { + if tgArn == "" { + return errors.New("eks: DeregisterClusterTarget empty TG arn") + } + if eniIP == "" { + return errors.New("eks: DeregisterClusterTarget empty ENI IP") + } + if _, err := nlbp.DeregisterTargets(&elbv2.DeregisterTargetsInput{ + TargetGroupArn: aws.String(tgArn), + Targets: []*elbv2.TargetDescription{{ + Id: aws.String(eniIP), + Port: aws.Int64(k3sAPIServerPort), + }}, + }, accountID); err != nil { + return fmt.Errorf("deregister target %s on TG %s: %w", eniIP, tgArn, err) + } + return nil +} + +// DeleteClusterNLB tears down the cluster NLB + TG. DeleteLoadBalancer +// cascades listener cleanup inside the ELBv2 impl, so listeners do not need +// an explicit delete pass. Missing resources are no-ops to keep DeleteCluster +// retries safe. Both sub-sweeps always run; LB delete error takes precedence +// over TG delete error when both fail. +func DeleteClusterNLB(nlbp nlbProvisioner, accountID, clusterName string) error { + if clusterName == "" { + return errors.New("eks: DeleteClusterNLB empty cluster name") + } + lbErr := deleteClusterLB(nlbp, accountID, ClusterNLBName(clusterName)) + tgErr := deleteClusterTG(nlbp, accountID, ClusterTargetGroupName(clusterName)) + if lbErr != nil { + return lbErr + } + return tgErr +} + +func deleteClusterLB(nlbp nlbProvisioner, accountID, lbName string) error { + lb, err := lookupLBByName(nlbp, accountID, lbName) + if err != nil { + slog.Warn("DeleteClusterNLB: LB lookup failed", "name", lbName, "err", err) + return err + } + if lb == nil || lb.LoadBalancerArn == nil { + return nil + } + if _, err := nlbp.DeleteLoadBalancer(&elbv2.DeleteLoadBalancerInput{LoadBalancerArn: lb.LoadBalancerArn}, accountID); err != nil { + slog.Warn("DeleteClusterNLB: delete NLB failed", "name", lbName, "err", err) + return fmt.Errorf("delete NLB %s: %w", lbName, err) + } + return nil +} + +func deleteClusterTG(nlbp nlbProvisioner, accountID, tgName string) error { + tg, err := lookupTGByName(nlbp, accountID, tgName) + if err != nil { + slog.Warn("DeleteClusterNLB: TG lookup failed", "name", tgName, "err", err) + return err + } + if tg == nil || tg.TargetGroupArn == nil { + return nil + } + if _, err := nlbp.DeleteTargetGroup(&elbv2.DeleteTargetGroupInput{TargetGroupArn: tg.TargetGroupArn}, accountID); err != nil { + slog.Warn("DeleteClusterNLB: delete TG failed", "name", tgName, "err", err) + return fmt.Errorf("delete TG %s: %w", tgName, err) + } + return nil +} + +func ensureClusterLB(nlbp nlbProvisioner, accountID, clusterName, lbName string, subnetIDs []string, out *ClusterNLB) error { + if lb, err := lookupLBByName(nlbp, accountID, lbName); err != nil { + return err + } else if lb != nil { + out.LoadBalancerArn = aws.StringValue(lb.LoadBalancerArn) + out.DNSName = aws.StringValue(lb.DNSName) + if out.LoadBalancerArn == "" || out.DNSName == "" { + return fmt.Errorf("eks: existing NLB %s missing arn or DNS name", lbName) + } + return nil + } + + created, err := nlbp.CreateLoadBalancer(&elbv2.CreateLoadBalancerInput{ + Name: aws.String(lbName), + Type: aws.String(elbv2.LoadBalancerTypeEnumNetwork), + Scheme: aws.String(elbv2.LoadBalancerSchemeEnumInternal), + Subnets: aws.StringSlice(subnetIDs), + Tags: []*elbv2.Tag{ + {Key: aws.String(tags.ManagedByKey), Value: aws.String(tags.ManagedByEKS)}, + {Key: aws.String(clusterEKSClusterTagKey), Value: aws.String(clusterName)}, + }, + }, accountID) + if err != nil { + return fmt.Errorf("create NLB %s: %w", lbName, err) + } + if created == nil || len(created.LoadBalancers) == 0 || created.LoadBalancers[0] == nil { + return fmt.Errorf("eks: CreateLoadBalancer returned no LB for %s", lbName) + } + lb := created.LoadBalancers[0] + out.LoadBalancerArn = aws.StringValue(lb.LoadBalancerArn) + out.DNSName = aws.StringValue(lb.DNSName) + if out.LoadBalancerArn == "" || out.DNSName == "" { + return fmt.Errorf("eks: CreateLoadBalancer returned empty arn or DNS name for %s", lbName) + } + return nil +} + +func ensureClusterTG(nlbp nlbProvisioner, accountID, clusterName, tgName string, out *ClusterNLB) error { + if tg, err := lookupTGByName(nlbp, accountID, tgName); err != nil { + return err + } else if tg != nil { + out.TargetGroupArn = aws.StringValue(tg.TargetGroupArn) + if out.TargetGroupArn == "" { + return fmt.Errorf("eks: existing TG %s missing arn", tgName) + } + return nil + } + + created, err := nlbp.CreateTargetGroup(&elbv2.CreateTargetGroupInput{ + Name: aws.String(tgName), + Protocol: aws.String(elbv2.ProtocolEnumTcp), + Port: aws.Int64(k3sAPIServerPort), + TargetType: aws.String(elbv2.TargetTypeEnumIp), + Tags: []*elbv2.Tag{ + {Key: aws.String(tags.ManagedByKey), Value: aws.String(tags.ManagedByEKS)}, + {Key: aws.String(clusterEKSClusterTagKey), Value: aws.String(clusterName)}, + }, + }, accountID) + if err != nil { + return fmt.Errorf("create TG %s: %w", tgName, err) + } + if created == nil || len(created.TargetGroups) == 0 || created.TargetGroups[0] == nil { + return fmt.Errorf("eks: CreateTargetGroup returned no TG for %s", tgName) + } + out.TargetGroupArn = aws.StringValue(created.TargetGroups[0].TargetGroupArn) + if out.TargetGroupArn == "" { + return fmt.Errorf("eks: CreateTargetGroup returned empty arn for %s", tgName) + } + return nil +} + +func ensureClusterListener(nlbp nlbProvisioner, accountID, lbName string, out *ClusterNLB) error { + if l, err := lookupListenerByPort(nlbp, accountID, out.LoadBalancerArn, clusterNLBListenPort); err != nil { + return err + } else if l != nil { + out.ListenerArn = aws.StringValue(l.ListenerArn) + if out.ListenerArn == "" { + return fmt.Errorf("eks: existing listener for %s:%d missing arn", lbName, clusterNLBListenPort) + } + return nil + } + + created, err := nlbp.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: aws.String(out.LoadBalancerArn), + Protocol: aws.String(elbv2.ProtocolEnumTcp), + Port: aws.Int64(clusterNLBListenPort), + DefaultActions: []*elbv2.Action{{ + Type: aws.String(elbv2.ActionTypeEnumForward), + TargetGroupArn: aws.String(out.TargetGroupArn), + }}, + }, accountID) + if err != nil { + return fmt.Errorf("create listener %s:%d: %w", lbName, clusterNLBListenPort, err) + } + if created == nil || len(created.Listeners) == 0 || created.Listeners[0] == nil { + return fmt.Errorf("eks: CreateListener returned no listener for %s:%d", lbName, clusterNLBListenPort) + } + out.ListenerArn = aws.StringValue(created.Listeners[0].ListenerArn) + if out.ListenerArn == "" { + return fmt.Errorf("eks: CreateListener returned empty arn for %s:%d", lbName, clusterNLBListenPort) + } + return nil +} + +func lookupLBByName(nlbp nlbProvisioner, accountID, name string) (*elbv2.LoadBalancer, error) { + out, err := nlbp.DescribeLoadBalancers(&elbv2.DescribeLoadBalancersInput{ + Names: aws.StringSlice([]string{name}), + }, accountID) + if err != nil { + return nil, fmt.Errorf("describe NLB %s: %w", name, err) + } + for _, lb := range out.LoadBalancers { + if lb != nil { + return lb, nil + } + } + return nil, nil +} + +func lookupTGByName(nlbp nlbProvisioner, accountID, name string) (*elbv2.TargetGroup, error) { + out, err := nlbp.DescribeTargetGroups(&elbv2.DescribeTargetGroupsInput{ + Names: aws.StringSlice([]string{name}), + }, accountID) + if err != nil { + return nil, fmt.Errorf("describe TG %s: %w", name, err) + } + for _, tg := range out.TargetGroups { + if tg != nil { + return tg, nil + } + } + return nil, nil +} + +func lookupListenerByPort(nlbp nlbProvisioner, accountID, lbArn string, port int64) (*elbv2.Listener, error) { + if lbArn == "" { + return nil, errors.New("eks: lookupListenerByPort empty LB arn") + } + out, err := nlbp.DescribeListeners(&elbv2.DescribeListenersInput{ + LoadBalancerArn: aws.String(lbArn), + }, accountID) + if err != nil { + return nil, fmt.Errorf("describe listeners on %s: %w", lbArn, err) + } + for _, l := range out.Listeners { + if l == nil || l.Port == nil { + continue + } + if *l.Port == port { + return l, nil + } + } + return nil, nil +} diff --git a/spinifex/handlers/eks/nlb_test.go b/spinifex/handlers/eks/nlb_test.go new file mode 100644 index 000000000..0b60d9471 --- /dev/null +++ b/spinifex/handlers/eks/nlb_test.go @@ -0,0 +1,388 @@ +package handlers_eks + +import ( + "errors" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/tags" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type fakeNLBProvisioner struct { + createLBCalls []*elbv2.CreateLoadBalancerInput + describeLBCalls []*elbv2.DescribeLoadBalancersInput + deleteLBCalls []*elbv2.DeleteLoadBalancerInput + createTGCalls []*elbv2.CreateTargetGroupInput + describeTGCalls []*elbv2.DescribeTargetGroupsInput + deleteTGCalls []*elbv2.DeleteTargetGroupInput + createListenerCalls []*elbv2.CreateListenerInput + describeListeners []*elbv2.DescribeListenersInput + registerCalls []*elbv2.RegisterTargetsInput + deregisterCalls []*elbv2.DeregisterTargetsInput + + lbByName map[string]*elbv2.LoadBalancer + tgByName map[string]*elbv2.TargetGroup + listenerByPort map[string]map[int64]*elbv2.Listener // lbArn → port → listener + + createLBOut *elbv2.CreateLoadBalancerOutput + createTGOut *elbv2.CreateTargetGroupOutput + createListenerOut *elbv2.CreateListenerOutput + createLBErr error + createTGErr error + createListenerErr error + deleteLBErr error + deleteTGErr error + registerErr error + deregisterErr error +} + +var _ nlbProvisioner = (*fakeNLBProvisioner)(nil) + +func newFakeNLBProvisioner() *fakeNLBProvisioner { + return &fakeNLBProvisioner{ + lbByName: map[string]*elbv2.LoadBalancer{}, + tgByName: map[string]*elbv2.TargetGroup{}, + listenerByPort: map[string]map[int64]*elbv2.Listener{}, + } +} + +func (f *fakeNLBProvisioner) CreateLoadBalancer(input *elbv2.CreateLoadBalancerInput, _ string) (*elbv2.CreateLoadBalancerOutput, error) { + f.createLBCalls = append(f.createLBCalls, input) + if f.createLBErr != nil { + return nil, f.createLBErr + } + if f.createLBOut == nil { + name := aws.StringValue(input.Name) + arn := "arn:aws:elasticloadbalancing:us-east-1:111122223333:loadbalancer/net/" + name + "/lb-001" + dns := name + "-lb-001.us-east-1.elb.spinifex.local" + f.createLBOut = &elbv2.CreateLoadBalancerOutput{ + LoadBalancers: []*elbv2.LoadBalancer{{ + LoadBalancerArn: aws.String(arn), + LoadBalancerName: aws.String(name), + DNSName: aws.String(dns), + Type: aws.String(elbv2.LoadBalancerTypeEnumNetwork), + Scheme: aws.String(elbv2.LoadBalancerSchemeEnumInternal), + }}, + } + } + out := f.createLBOut + if len(out.LoadBalancers) > 0 { + name := aws.StringValue(out.LoadBalancers[0].LoadBalancerName) + f.lbByName[name] = out.LoadBalancers[0] + } + return out, nil +} + +func (f *fakeNLBProvisioner) DescribeLoadBalancers(input *elbv2.DescribeLoadBalancersInput, _ string) (*elbv2.DescribeLoadBalancersOutput, error) { + f.describeLBCalls = append(f.describeLBCalls, input) + out := &elbv2.DescribeLoadBalancersOutput{} + for _, n := range input.Names { + if n == nil { + continue + } + if lb, ok := f.lbByName[*n]; ok { + out.LoadBalancers = append(out.LoadBalancers, lb) + } + } + return out, nil +} + +func (f *fakeNLBProvisioner) DeleteLoadBalancer(input *elbv2.DeleteLoadBalancerInput, _ string) (*elbv2.DeleteLoadBalancerOutput, error) { + f.deleteLBCalls = append(f.deleteLBCalls, input) + if f.deleteLBErr != nil { + return nil, f.deleteLBErr + } + if input.LoadBalancerArn != nil { + for name, lb := range f.lbByName { + if aws.StringValue(lb.LoadBalancerArn) == *input.LoadBalancerArn { + delete(f.lbByName, name) + } + } + } + return &elbv2.DeleteLoadBalancerOutput{}, nil +} + +func (f *fakeNLBProvisioner) CreateTargetGroup(input *elbv2.CreateTargetGroupInput, _ string) (*elbv2.CreateTargetGroupOutput, error) { + f.createTGCalls = append(f.createTGCalls, input) + if f.createTGErr != nil { + return nil, f.createTGErr + } + if f.createTGOut == nil { + name := aws.StringValue(input.Name) + arn := "arn:aws:elasticloadbalancing:us-east-1:111122223333:targetgroup/" + name + "/tg-001" + f.createTGOut = &elbv2.CreateTargetGroupOutput{ + TargetGroups: []*elbv2.TargetGroup{{ + TargetGroupArn: aws.String(arn), + TargetGroupName: aws.String(name), + Protocol: input.Protocol, + Port: input.Port, + TargetType: input.TargetType, + }}, + } + } + out := f.createTGOut + if len(out.TargetGroups) > 0 { + name := aws.StringValue(out.TargetGroups[0].TargetGroupName) + f.tgByName[name] = out.TargetGroups[0] + } + return out, nil +} + +func (f *fakeNLBProvisioner) DescribeTargetGroups(input *elbv2.DescribeTargetGroupsInput, _ string) (*elbv2.DescribeTargetGroupsOutput, error) { + f.describeTGCalls = append(f.describeTGCalls, input) + out := &elbv2.DescribeTargetGroupsOutput{} + for _, n := range input.Names { + if n == nil { + continue + } + if tg, ok := f.tgByName[*n]; ok { + out.TargetGroups = append(out.TargetGroups, tg) + } + } + return out, nil +} + +func (f *fakeNLBProvisioner) DeleteTargetGroup(input *elbv2.DeleteTargetGroupInput, _ string) (*elbv2.DeleteTargetGroupOutput, error) { + f.deleteTGCalls = append(f.deleteTGCalls, input) + if f.deleteTGErr != nil { + return nil, f.deleteTGErr + } + if input.TargetGroupArn != nil { + for name, tg := range f.tgByName { + if aws.StringValue(tg.TargetGroupArn) == *input.TargetGroupArn { + delete(f.tgByName, name) + } + } + } + return &elbv2.DeleteTargetGroupOutput{}, nil +} + +func (f *fakeNLBProvisioner) CreateListener(input *elbv2.CreateListenerInput, _ string) (*elbv2.CreateListenerOutput, error) { + f.createListenerCalls = append(f.createListenerCalls, input) + if f.createListenerErr != nil { + return nil, f.createListenerErr + } + if f.createListenerOut == nil { + lbArn := aws.StringValue(input.LoadBalancerArn) + port := aws.Int64Value(input.Port) + listenerArn := lbArn + "/listener/lst-001" + f.createListenerOut = &elbv2.CreateListenerOutput{ + Listeners: []*elbv2.Listener{{ + ListenerArn: aws.String(listenerArn), + LoadBalancerArn: input.LoadBalancerArn, + Port: input.Port, + Protocol: input.Protocol, + DefaultActions: input.DefaultActions, + }}, + } + if f.listenerByPort[lbArn] == nil { + f.listenerByPort[lbArn] = map[int64]*elbv2.Listener{} + } + f.listenerByPort[lbArn][port] = f.createListenerOut.Listeners[0] + } + return f.createListenerOut, nil +} + +func (f *fakeNLBProvisioner) DescribeListeners(input *elbv2.DescribeListenersInput, _ string) (*elbv2.DescribeListenersOutput, error) { + f.describeListeners = append(f.describeListeners, input) + out := &elbv2.DescribeListenersOutput{} + if input.LoadBalancerArn != nil { + for _, l := range f.listenerByPort[*input.LoadBalancerArn] { + out.Listeners = append(out.Listeners, l) + } + } + return out, nil +} + +func (f *fakeNLBProvisioner) RegisterTargets(input *elbv2.RegisterTargetsInput, _ string) (*elbv2.RegisterTargetsOutput, error) { + f.registerCalls = append(f.registerCalls, input) + if f.registerErr != nil { + return nil, f.registerErr + } + return &elbv2.RegisterTargetsOutput{}, nil +} + +func (f *fakeNLBProvisioner) DeregisterTargets(input *elbv2.DeregisterTargetsInput, _ string) (*elbv2.DeregisterTargetsOutput, error) { + f.deregisterCalls = append(f.deregisterCalls, input) + if f.deregisterErr != nil { + return nil, f.deregisterErr + } + return &elbv2.DeregisterTargetsOutput{}, nil +} + +func TestEnsureClusterNLB_EmptyInputsRejected(t *testing.T) { + nlbp := newFakeNLBProvisioner() + + _, err := EnsureClusterNLB(nlbp, "111122223333", "", []string{"subnet-aaa"}) + require.Error(t, err) + + _, err = EnsureClusterNLB(nlbp, "111122223333", "alpha", nil) + require.Error(t, err) + + assert.Empty(t, nlbp.createLBCalls) +} + +func TestEnsureClusterNLB_NameTooLongRejected(t *testing.T) { + nlbp := newFakeNLBProvisioner() + + longName := strings.Repeat("x", maxELBv2NameLen) // "eks-" + 32x = 36 chars + _, err := EnsureClusterNLB(nlbp, "111122223333", longName, []string{"subnet-aaa"}) + require.Error(t, err) + assert.Contains(t, err.Error(), "exceeds") + assert.Empty(t, nlbp.createLBCalls) +} + +func TestEnsureClusterNLB_FreshCreatesAllThree(t *testing.T) { + nlbp := newFakeNLBProvisioner() + + out, err := EnsureClusterNLB(nlbp, "111122223333", "alpha", []string{"subnet-aaa", "subnet-bbb"}) + require.NoError(t, err) + require.NotNil(t, out) + assert.NotEmpty(t, out.LoadBalancerArn) + assert.NotEmpty(t, out.TargetGroupArn) + assert.NotEmpty(t, out.ListenerArn) + assert.Contains(t, out.DNSName, "eks-alpha") + + require.Len(t, nlbp.createLBCalls, 1) + lbIn := nlbp.createLBCalls[0] + assert.Equal(t, "eks-alpha", aws.StringValue(lbIn.Name)) + assert.Equal(t, elbv2.LoadBalancerTypeEnumNetwork, aws.StringValue(lbIn.Type)) + assert.Equal(t, elbv2.LoadBalancerSchemeEnumInternal, aws.StringValue(lbIn.Scheme)) + assert.Equal(t, []string{"subnet-aaa", "subnet-bbb"}, aws.StringValueSlice(lbIn.Subnets)) + assertELBv2TaggedAsEKS(t, lbIn.Tags, "alpha") + + require.Len(t, nlbp.createTGCalls, 1) + tgIn := nlbp.createTGCalls[0] + assert.Equal(t, "eks-alpha-cp", aws.StringValue(tgIn.Name)) + assert.Equal(t, elbv2.ProtocolEnumTcp, aws.StringValue(tgIn.Protocol)) + assert.Equal(t, k3sAPIServerPort, aws.Int64Value(tgIn.Port)) + assert.Equal(t, elbv2.TargetTypeEnumIp, aws.StringValue(tgIn.TargetType)) + assertELBv2TaggedAsEKS(t, tgIn.Tags, "alpha") + + require.Len(t, nlbp.createListenerCalls, 1) + lstIn := nlbp.createListenerCalls[0] + assert.Equal(t, out.LoadBalancerArn, aws.StringValue(lstIn.LoadBalancerArn)) + assert.Equal(t, elbv2.ProtocolEnumTcp, aws.StringValue(lstIn.Protocol)) + assert.Equal(t, clusterNLBListenPort, aws.Int64Value(lstIn.Port)) + require.Len(t, lstIn.DefaultActions, 1) + assert.Equal(t, elbv2.ActionTypeEnumForward, aws.StringValue(lstIn.DefaultActions[0].Type)) + assert.Equal(t, out.TargetGroupArn, aws.StringValue(lstIn.DefaultActions[0].TargetGroupArn)) +} + +func TestEnsureClusterNLB_IdempotentReusesExisting(t *testing.T) { + nlbp := newFakeNLBProvisioner() + + first, err := EnsureClusterNLB(nlbp, "111122223333", "alpha", []string{"subnet-aaa"}) + require.NoError(t, err) + + createLBCount := len(nlbp.createLBCalls) + createTGCount := len(nlbp.createTGCalls) + createListenerCount := len(nlbp.createListenerCalls) + + second, err := EnsureClusterNLB(nlbp, "111122223333", "alpha", []string{"subnet-aaa"}) + require.NoError(t, err) + + assert.Equal(t, first.LoadBalancerArn, second.LoadBalancerArn) + assert.Equal(t, first.TargetGroupArn, second.TargetGroupArn) + assert.Equal(t, first.ListenerArn, second.ListenerArn) + assert.Equal(t, first.DNSName, second.DNSName) + + assert.Equal(t, createLBCount, len(nlbp.createLBCalls), "no new LB create on idempotent call") + assert.Equal(t, createTGCount, len(nlbp.createTGCalls), "no new TG create on idempotent call") + assert.Equal(t, createListenerCount, len(nlbp.createListenerCalls), "no new listener create on idempotent call") +} + +func TestEnsureClusterNLB_LBCreateErrorSurfaced(t *testing.T) { + nlbp := newFakeNLBProvisioner() + nlbp.createLBErr = errors.New("InsufficientCapacity") + + _, err := EnsureClusterNLB(nlbp, "111122223333", "alpha", []string{"subnet-aaa"}) + require.Error(t, err) + assert.Contains(t, err.Error(), "create NLB eks-alpha") + assert.Empty(t, nlbp.createTGCalls, "TG create should not run when LB create fails") +} + +func TestRegisterClusterTarget_PostsENIIPAndAPIPort(t *testing.T) { + nlbp := newFakeNLBProvisioner() + + err := RegisterClusterTarget(nlbp, "111122223333", "arn:tg/alpha", "10.0.1.42") + require.NoError(t, err) + require.Len(t, nlbp.registerCalls, 1) + + in := nlbp.registerCalls[0] + assert.Equal(t, "arn:tg/alpha", aws.StringValue(in.TargetGroupArn)) + require.Len(t, in.Targets, 1) + assert.Equal(t, "10.0.1.42", aws.StringValue(in.Targets[0].Id)) + assert.Equal(t, k3sAPIServerPort, aws.Int64Value(in.Targets[0].Port)) +} + +func TestRegisterClusterTarget_EmptyInputsRejected(t *testing.T) { + nlbp := newFakeNLBProvisioner() + require.Error(t, RegisterClusterTarget(nlbp, "111122223333", "", "10.0.1.42")) + require.Error(t, RegisterClusterTarget(nlbp, "111122223333", "arn:tg/alpha", "")) + assert.Empty(t, nlbp.registerCalls) +} + +func TestDeregisterClusterTarget_PostsENIIPAndAPIPort(t *testing.T) { + nlbp := newFakeNLBProvisioner() + + err := DeregisterClusterTarget(nlbp, "111122223333", "arn:tg/alpha", "10.0.1.42") + require.NoError(t, err) + require.Len(t, nlbp.deregisterCalls, 1) + + in := nlbp.deregisterCalls[0] + assert.Equal(t, "arn:tg/alpha", aws.StringValue(in.TargetGroupArn)) + require.Len(t, in.Targets, 1) + assert.Equal(t, "10.0.1.42", aws.StringValue(in.Targets[0].Id)) + assert.Equal(t, k3sAPIServerPort, aws.Int64Value(in.Targets[0].Port)) +} + +func TestDeleteClusterNLB_DeletesBoth(t *testing.T) { + nlbp := newFakeNLBProvisioner() + out, err := EnsureClusterNLB(nlbp, "111122223333", "alpha", []string{"subnet-aaa"}) + require.NoError(t, err) + + require.NoError(t, DeleteClusterNLB(nlbp, "111122223333", "alpha")) + require.Len(t, nlbp.deleteLBCalls, 1) + assert.Equal(t, out.LoadBalancerArn, aws.StringValue(nlbp.deleteLBCalls[0].LoadBalancerArn)) + require.Len(t, nlbp.deleteTGCalls, 1) + assert.Equal(t, out.TargetGroupArn, aws.StringValue(nlbp.deleteTGCalls[0].TargetGroupArn)) +} + +func TestDeleteClusterNLB_MissingResourcesNoOp(t *testing.T) { + nlbp := newFakeNLBProvisioner() + + require.NoError(t, DeleteClusterNLB(nlbp, "111122223333", "alpha")) + assert.Empty(t, nlbp.deleteLBCalls) + assert.Empty(t, nlbp.deleteTGCalls) +} + +func TestDeleteClusterNLB_FirstErrorSurfacedSweepContinues(t *testing.T) { + nlbp := newFakeNLBProvisioner() + _, err := EnsureClusterNLB(nlbp, "111122223333", "alpha", []string{"subnet-aaa"}) + require.NoError(t, err) + nlbp.deleteLBErr = errors.New("LoadBalancerInUse") + + err = DeleteClusterNLB(nlbp, "111122223333", "alpha") + require.Error(t, err) + assert.Contains(t, err.Error(), "delete NLB eks-alpha") + assert.Len(t, nlbp.deleteLBCalls, 1) + assert.Len(t, nlbp.deleteTGCalls, 1, "TG delete should still be attempted after LB delete fails") +} + +func assertELBv2TaggedAsEKS(t *testing.T, tgs []*elbv2.Tag, clusterName string) { + t.Helper() + got := map[string]string{} + for _, tg := range tgs { + if tg == nil || tg.Key == nil || tg.Value == nil { + continue + } + got[*tg.Key] = *tg.Value + } + assert.Equal(t, tags.ManagedByEKS, got[tags.ManagedByKey]) + assert.Equal(t, clusterName, got[clusterEKSClusterTagKey]) +} diff --git a/spinifex/handlers/eks/oidc_keypair.go b/spinifex/handlers/eks/oidc_keypair.go new file mode 100644 index 000000000..3d2c8c3d2 --- /dev/null +++ b/spinifex/handlers/eks/oidc_keypair.go @@ -0,0 +1,210 @@ +package handlers_eks + +import ( + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/json" + "encoding/pem" + "errors" + "fmt" + + handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam" + "github.com/nats-io/nats.go" +) + +// PublicKeyPEMFromPrivate parses a PKCS#8 private-key PEM and returns the PKIX +// public-key PEM. kube-apiserver's --service-account-key-file requires a PUBLIC +// key (ParsePublicKeysPEM rejects private-key blocks), while the matching +// --service-account-signing-key-file takes the private key; the K3s server VM +// needs both, seeded to separate files. +func PublicKeyPEMFromPrivate(privPEM string) (string, error) { + block, _ := pem.Decode([]byte(privPEM)) + if block == nil { + return "", errors.New("eks: PublicKeyPEMFromPrivate: no PEM block in private key") + } + key, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return "", fmt.Errorf("parse pkcs8 private key: %w", err) + } + signer, ok := key.(crypto.Signer) + if !ok { + return "", errors.New("eks: PublicKeyPEMFromPrivate: private key is not a crypto.Signer") + } + pubDER, err := x509.MarshalPKIXPublicKey(signer.Public()) + if err != nil { + return "", fmt.Errorf("marshal pkix public key: %w", err) + } + return string(pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: pubDER})), nil +} + +// oidcJWK and oidcJWKS are the RFC 7517 wire shapes the per-cluster JWKS +// document uses. handlers_sts decodes the same JSON via its own JWK / JWKS +// types — wire compatibility (not Go type identity) is the contract. +type oidcJWK struct { + Kty string `json:"kty"` + Kid string `json:"kid"` + Use string `json:"use,omitempty"` + Alg string `json:"alg,omitempty"` + Crv string `json:"crv,omitempty"` + X string `json:"x,omitempty"` + Y string `json:"y,omitempty"` +} + +type oidcJWKS struct { + Keys []oidcJWK `json:"keys"` +} + +// P-256 coordinate width per SEC1 — JWK requires fixed-length base64url, not +// the variable-length big.Int byte representation. +const p256CoordLen = 32 + +// GenerateClusterOIDCKeypair creates a fresh ECDSA-P256 keypair for the +// cluster, PEM-marshals the private key as PKCS8, envelope-encrypts the PEM +// with masterKey, writes the ciphertext to OIDCSigningKeyKey and the JWKS +// document to OIDCJWKSKey. Returns the plaintext private-key PEM and the JWKS +// bytes so the caller (CreateCluster) can pass them straight to user-data +// without a follow-up KV read + decrypt. +func GenerateClusterOIDCKeypair(kv nats.KeyValue, clusterName string, masterKey []byte) (privPEM string, jwksBytes []byte, err error) { + if clusterName == "" { + return "", nil, errors.New("eks: GenerateClusterOIDCKeypair empty cluster name") + } + if len(masterKey) == 0 { + return "", nil, errors.New("eks: GenerateClusterOIDCKeypair empty master key") + } + + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return "", nil, fmt.Errorf("generate ECDSA-P256 key: %w", err) + } + + pkcs8, err := x509.MarshalPKCS8PrivateKey(priv) + if err != nil { + return "", nil, fmt.Errorf("marshal pkcs8 private key: %w", err) + } + pemBlock := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: pkcs8}) + + ciphertext, err := handlers_iam.EncryptSecret(string(pemBlock), masterKey) + if err != nil { + return "", nil, fmt.Errorf("encrypt OIDC private key: %w", err) + } + if _, err := kv.Put(OIDCSigningKeyKey(clusterName), []byte(ciphertext)); err != nil { + return "", nil, fmt.Errorf("kv put %s: %w", OIDCSigningKeyKey(clusterName), err) + } + + jwksBytes, err = marshalJWKS(&priv.PublicKey) + if err != nil { + return "", nil, err + } + if _, err := kv.Put(OIDCJWKSKey(clusterName), jwksBytes); err != nil { + return "", nil, fmt.Errorf("kv put %s: %w", OIDCJWKSKey(clusterName), err) + } + return string(pemBlock), jwksBytes, nil +} + +// LoadClusterOIDCPrivateKey reads the encrypted PEM from KV, decrypts with +// masterKey, parses it to *ecdsa.PrivateKey. Returns ErrClusterNotFound when +// the key is absent so DeleteCluster idempotency works. +func LoadClusterOIDCPrivateKey(kv nats.KeyValue, clusterName string, masterKey []byte) (*ecdsa.PrivateKey, error) { + if clusterName == "" { + return nil, errors.New("eks: LoadClusterOIDCPrivateKey empty cluster name") + } + if len(masterKey) == 0 { + return nil, errors.New("eks: LoadClusterOIDCPrivateKey empty master key") + } + entry, err := kv.Get(OIDCSigningKeyKey(clusterName)) + if err != nil { + if errors.Is(err, nats.ErrKeyNotFound) { + return nil, ErrClusterNotFound + } + return nil, fmt.Errorf("kv get %s: %w", OIDCSigningKeyKey(clusterName), err) + } + pemStr, err := handlers_iam.DecryptSecret(string(entry.Value()), masterKey) + if err != nil { + return nil, fmt.Errorf("decrypt OIDC private key: %w", err) + } + block, _ := pem.Decode([]byte(pemStr)) + if block == nil { + return nil, errors.New("eks: PEM decode produced no block") + } + keyAny, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return nil, fmt.Errorf("parse pkcs8 private key: %w", err) + } + priv, ok := keyAny.(*ecdsa.PrivateKey) + if !ok { + return nil, fmt.Errorf("eks: unexpected key type %T (want *ecdsa.PrivateKey)", keyAny) + } + if priv.Curve != elliptic.P256() { + return nil, fmt.Errorf("eks: unexpected curve %s (want P-256)", priv.Curve.Params().Name) + } + return priv, nil +} + +// ZeroizeClusterOIDCKey overwrites the encrypted private-key blob with zeros +// of the same length, then deletes the key. DeleteCluster calls this first +// so a crash after this point leaves no recoverable key material on disk. +// Absent key is a no-op — supports idempotent DeleteCluster retries. +func ZeroizeClusterOIDCKey(kv nats.KeyValue, clusterName string) error { + if clusterName == "" { + return errors.New("eks: ZeroizeClusterOIDCKey empty cluster name") + } + key := OIDCSigningKeyKey(clusterName) + entry, err := kv.Get(key) + if err != nil { + if errors.Is(err, nats.ErrKeyNotFound) { + return nil + } + return fmt.Errorf("kv get %s: %w", key, err) + } + zero := make([]byte, len(entry.Value())) + if _, err := kv.Put(key, zero); err != nil { + return fmt.Errorf("kv put zero %s: %w", key, err) + } + if err := kv.Delete(key); err != nil { + return fmt.Errorf("kv delete %s: %w", key, err) + } + return nil +} + +// marshalJWKS builds the single-key JWKS document for an ECDSA P-256 +// public key. kid is the base64url SHA-256 of the SPKI DER. +func marshalJWKS(pub *ecdsa.PublicKey) ([]byte, error) { + pubDER, err := x509.MarshalPKIXPublicKey(pub) + if err != nil { + return nil, fmt.Errorf("marshal public key DER: %w", err) + } + kidHash := sha256.Sum256(pubDER) + kid := base64.RawURLEncoding.EncodeToString(kidHash[:]) + + xb := padCoord(pub.X.Bytes()) + yb := padCoord(pub.Y.Bytes()) + + doc := oidcJWKS{Keys: []oidcJWK{{ + Kty: "EC", + Kid: kid, + Use: "sig", + Alg: "ES256", + Crv: "P-256", + X: base64.RawURLEncoding.EncodeToString(xb), + Y: base64.RawURLEncoding.EncodeToString(yb), + }}} + out, err := json.Marshal(&doc) + if err != nil { + return nil, fmt.Errorf("marshal JWKS: %w", err) + } + return out, nil +} + +func padCoord(b []byte) []byte { + if len(b) >= p256CoordLen { + return b + } + out := make([]byte, p256CoordLen) + copy(out[p256CoordLen-len(b):], b) + return out +} diff --git a/spinifex/handlers/eks/oidc_keypair_test.go b/spinifex/handlers/eks/oidc_keypair_test.go new file mode 100644 index 000000000..341e612f1 --- /dev/null +++ b/spinifex/handlers/eks/oidc_keypair_test.go @@ -0,0 +1,228 @@ +package handlers_eks + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "encoding/base64" + "encoding/json" + "encoding/pem" + "errors" + "testing" + + "github.com/nats-io/nats.go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var testMasterKey = func() []byte { + k := make([]byte, 32) + if _, err := rand.Read(k); err != nil { + panic(err) + } + return k +}() + +func TestGenerateClusterOIDCKeypair_PersistsJWKSAndEncryptedPrivateKey(t *testing.T) { + kv := newClusterStateTestKV(t) + + _, jwksBytes, err := GenerateClusterOIDCKeypair(kv, "alpha", testMasterKey) + require.NoError(t, err) + require.NotEmpty(t, jwksBytes) + + jwksEntry, err := kv.Get(OIDCJWKSKey("alpha")) + require.NoError(t, err) + assert.Equal(t, jwksBytes, jwksEntry.Value()) + + keyEntry, err := kv.Get(OIDCSigningKeyKey("alpha")) + require.NoError(t, err) + assert.NotEmpty(t, keyEntry.Value()) + assert.NotContains(t, string(keyEntry.Value()), "BEGIN PRIVATE KEY", + "encrypted blob must not contain a PEM header") +} + +// PublicKeyPEMFromPrivate must yield a PKIX PUBLIC KEY PEM matching the private +// key's public part — kube-apiserver's --service-account-key-file requires a +// public key and crash-loops on a private-key PEM. +func TestPublicKeyPEMFromPrivate_RoundTrips(t *testing.T) { + kv := newClusterStateTestKV(t) + privPEM, _, err := GenerateClusterOIDCKeypair(kv, "alpha", testMasterKey) + require.NoError(t, err) + + pubPEM, err := PublicKeyPEMFromPrivate(privPEM) + require.NoError(t, err) + require.Contains(t, pubPEM, "BEGIN PUBLIC KEY") + assert.NotContains(t, pubPEM, "PRIVATE KEY") + + block, _ := pem.Decode([]byte(pubPEM)) + require.NotNil(t, block) + pub, err := x509.ParsePKIXPublicKey(block.Bytes) + require.NoError(t, err) + pubEC, ok := pub.(*ecdsa.PublicKey) + require.True(t, ok) + + stored, err := LoadClusterOIDCPrivateKey(kv, "alpha", testMasterKey) + require.NoError(t, err) + assert.True(t, stored.PublicKey.Equal(pubEC), "derived public key must match the private key") +} + +func TestPublicKeyPEMFromPrivate_RejectsGarbage(t *testing.T) { + _, err := PublicKeyPEMFromPrivate("not a pem") + require.Error(t, err) + + _, err = PublicKeyPEMFromPrivate("-----BEGIN PRIVATE KEY-----\nbm90LWtleQ==\n-----END PRIVATE KEY-----\n") + require.Error(t, err) +} + +// The generator returns the plaintext private-key PEM directly so CreateCluster +// avoids a second KV read + decrypt; it must match the key persisted in KV. +func TestGenerateClusterOIDCKeypair_ReturnsPrivateKeyPEMMatchingStored(t *testing.T) { + kv := newClusterStateTestKV(t) + + privPEM, _, err := GenerateClusterOIDCKeypair(kv, "alpha", testMasterKey) + require.NoError(t, err) + require.Contains(t, privPEM, "BEGIN PRIVATE KEY", "returned PEM must be plaintext") + + block, _ := pem.Decode([]byte(privPEM)) + require.NotNil(t, block) + returned, err := x509.ParsePKCS8PrivateKey(block.Bytes) + require.NoError(t, err) + returnedEC, ok := returned.(*ecdsa.PrivateKey) + require.True(t, ok) + + stored, err := LoadClusterOIDCPrivateKey(kv, "alpha", testMasterKey) + require.NoError(t, err) + assert.True(t, stored.Equal(returnedEC), "returned PEM must match the persisted key") +} + +func TestGenerateClusterOIDCKeypair_JWKSShapeIsRFC7517EC_P256(t *testing.T) { + kv := newClusterStateTestKV(t) + + _, jwksBytes, err := GenerateClusterOIDCKeypair(kv, "alpha", testMasterKey) + require.NoError(t, err) + + var doc oidcJWKS + require.NoError(t, json.Unmarshal(jwksBytes, &doc)) + require.Len(t, doc.Keys, 1) + + k := doc.Keys[0] + assert.Equal(t, "EC", k.Kty) + assert.Equal(t, "P-256", k.Crv) + assert.Equal(t, "ES256", k.Alg) + assert.Equal(t, "sig", k.Use) + assert.NotEmpty(t, k.Kid) + + xBytes, err := base64.RawURLEncoding.DecodeString(k.X) + require.NoError(t, err) + assert.Len(t, xBytes, p256CoordLen, "JWK x must be 32-byte SEC1 coordinate") + yBytes, err := base64.RawURLEncoding.DecodeString(k.Y) + require.NoError(t, err) + assert.Len(t, yBytes, p256CoordLen, "JWK y must be 32-byte SEC1 coordinate") +} + +func TestGenerateClusterOIDCKeypair_TwoCallsProduceDistinctKeys(t *testing.T) { + kv := newClusterStateTestKV(t) + + _, a, err := GenerateClusterOIDCKeypair(kv, "alpha", testMasterKey) + require.NoError(t, err) + _, b, err := GenerateClusterOIDCKeypair(kv, "beta", testMasterKey) + require.NoError(t, err) + assert.NotEqual(t, a, b, "JWKS for distinct clusters must differ") +} + +func TestGenerateClusterOIDCKeypair_EmptyArgsRejected(t *testing.T) { + kv := newClusterStateTestKV(t) + + _, _, err := GenerateClusterOIDCKeypair(kv, "", testMasterKey) + require.Error(t, err) + _, _, err = GenerateClusterOIDCKeypair(kv, "alpha", nil) + require.Error(t, err) +} + +func TestLoadClusterOIDCPrivateKey_RoundTripMatchesJWKSPublic(t *testing.T) { + kv := newClusterStateTestKV(t) + + _, jwksBytes, err := GenerateClusterOIDCKeypair(kv, "alpha", testMasterKey) + require.NoError(t, err) + + priv, err := LoadClusterOIDCPrivateKey(kv, "alpha", testMasterKey) + require.NoError(t, err) + require.NotNil(t, priv) + assert.Equal(t, elliptic.P256(), priv.Curve) + + var doc oidcJWKS + require.NoError(t, json.Unmarshal(jwksBytes, &doc)) + require.Len(t, doc.Keys, 1) + + xExpected, err := base64.RawURLEncoding.DecodeString(doc.Keys[0].X) + require.NoError(t, err) + yExpected, err := base64.RawURLEncoding.DecodeString(doc.Keys[0].Y) + require.NoError(t, err) + + assert.Equal(t, padCoord(priv.X.Bytes()), xExpected) + assert.Equal(t, padCoord(priv.Y.Bytes()), yExpected) +} + +func TestLoadClusterOIDCPrivateKey_WrongMasterKeyFails(t *testing.T) { + kv := newClusterStateTestKV(t) + _, _, err := GenerateClusterOIDCKeypair(kv, "alpha", testMasterKey) + require.NoError(t, err) + + other := make([]byte, 32) + other[0] = 0xff + _, err = LoadClusterOIDCPrivateKey(kv, "alpha", other) + require.Error(t, err) +} + +func TestLoadClusterOIDCPrivateKey_MissingReturnsErrClusterNotFound(t *testing.T) { + kv := newClusterStateTestKV(t) + _, err := LoadClusterOIDCPrivateKey(kv, "ghost", testMasterKey) + require.ErrorIs(t, err, ErrClusterNotFound) +} + +func TestZeroizeClusterOIDCKey_DeletesKeyAndLeavesSiblingsIntact(t *testing.T) { + kv := newClusterStateTestKV(t) + _, _, err := GenerateClusterOIDCKeypair(kv, "alpha", testMasterKey) + require.NoError(t, err) + + require.NoError(t, ZeroizeClusterOIDCKey(kv, "alpha")) + + _, err = kv.Get(OIDCSigningKeyKey("alpha")) + assert.True(t, errors.Is(err, nats.ErrKeyNotFound)) + + jwks, err := kv.Get(OIDCJWKSKey("alpha")) + require.NoError(t, err, "JWKS must survive zeroize (it carries no secret material)") + assert.NotEmpty(t, jwks.Value()) +} + +func TestZeroizeClusterOIDCKey_MissingIsNoop(t *testing.T) { + kv := newClusterStateTestKV(t) + require.NoError(t, ZeroizeClusterOIDCKey(kv, "ghost")) +} + +func TestZeroizeClusterOIDCKey_EmptyNameRejected(t *testing.T) { + kv := newClusterStateTestKV(t) + require.Error(t, ZeroizeClusterOIDCKey(kv, "")) +} + +func TestMarshalJWKS_DeterministicForSameKey(t *testing.T) { + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + require.NoError(t, err) + + a, err := marshalJWKS(&priv.PublicKey) + require.NoError(t, err) + b, err := marshalJWKS(&priv.PublicKey) + require.NoError(t, err) + assert.Equal(t, a, b) +} + +func TestPadCoord_LeftPadsShortBigIntBytes(t *testing.T) { + got := padCoord([]byte{0x01, 0x02}) + require.Len(t, got, p256CoordLen) + assert.Equal(t, byte(0x01), got[p256CoordLen-2]) + assert.Equal(t, byte(0x02), got[p256CoordLen-1]) + for _, b := range got[:p256CoordLen-2] { + assert.Zero(t, b) + } +} diff --git a/spinifex/handlers/eks/reconciler_registry.go b/spinifex/handlers/eks/reconciler_registry.go new file mode 100644 index 000000000..06075928a --- /dev/null +++ b/spinifex/handlers/eks/reconciler_registry.go @@ -0,0 +1,166 @@ +package handlers_eks + +import ( + "context" + "errors" + "log/slog" + "sync" + + "github.com/nats-io/nats.go" +) + +// ReconcilerRegistry tracks active per-cluster reconciler goroutines so the +// daemon can spawn, stop, and graceful-shutdown them in unison. One entry per +// (accountID, clusterName) key. +type ReconcilerRegistry struct { + mu sync.Mutex + holders map[string]*reconcilerHandle +} + +type reconcilerHandle struct { + cancel context.CancelFunc + release func() + done chan struct{} +} + +// NewReconcilerRegistry returns an empty registry. +func NewReconcilerRegistry() *ReconcilerRegistry { + return &ReconcilerRegistry{holders: map[string]*reconcilerHandle{}} +} + +// SpawnReconcilerFn is the per-cluster goroutine starter the registry uses. +// Tests inject a fake; production wires a real ClusterReconciler under the +// hood (acquires lease, then loops via Run). +type SpawnReconcilerFn func(ctx context.Context, accountID, clusterName string) (release func(), err error) + +// Spawn launches one reconciler goroutine for (accountID, clusterName). If +// one is already running for that pair, returns nil without spawning a +// duplicate. SpawnFn is responsible for acquiring the leader lease + invoking +// Run; the registry only owns the ctx and the release. +func (r *ReconcilerRegistry) Spawn(parent context.Context, accountID, clusterName string, spawnFn SpawnReconcilerFn) error { + if accountID == "" || clusterName == "" { + return errors.New("eks: ReconcilerRegistry.Spawn empty ids") + } + if spawnFn == nil { + return errors.New("eks: ReconcilerRegistry.Spawn nil SpawnFn") + } + key := registryKey(accountID, clusterName) + + r.mu.Lock() + if _, ok := r.holders[key]; ok { + r.mu.Unlock() + return nil + } + ctx, cancel := context.WithCancel(parent) + done := make(chan struct{}) + h := &reconcilerHandle{cancel: cancel, done: done} + r.holders[key] = h + r.mu.Unlock() + + release, err := spawnFn(ctx, accountID, clusterName) + if err != nil { + r.mu.Lock() + delete(r.holders, key) + r.mu.Unlock() + cancel() + close(done) + return err + } + + r.mu.Lock() + h.release = release + r.mu.Unlock() + + go func() { + <-ctx.Done() + r.mu.Lock() + rel := h.release + r.mu.Unlock() + if rel != nil { + rel() + } + close(done) + }() + + slog.Info("ReconcilerRegistry: spawned", "accountID", accountID, "cluster", clusterName) + return nil +} + +// Stop cancels a single reconciler. Blocks until the goroutine has exited. +// No-op if no reconciler is registered for the key. +func (r *ReconcilerRegistry) Stop(accountID, clusterName string) { + key := registryKey(accountID, clusterName) + r.mu.Lock() + h, ok := r.holders[key] + if ok { + delete(r.holders, key) + } + r.mu.Unlock() + if !ok { + return + } + h.cancel() + <-h.done + slog.Info("ReconcilerRegistry: stopped", "accountID", accountID, "cluster", clusterName) +} + +// StopAll cancels every active reconciler and blocks until all goroutines +// have exited. Called from daemon graceful-shutdown. +func (r *ReconcilerRegistry) StopAll() { + r.mu.Lock() + handles := make([]*reconcilerHandle, 0, len(r.holders)) + for k, h := range r.holders { + handles = append(handles, h) + delete(r.holders, k) + } + r.mu.Unlock() + + for _, h := range handles { + h.cancel() + } + for _, h := range handles { + <-h.done + } +} + +// Has reports whether a reconciler is currently registered for the key. +func (r *ReconcilerRegistry) Has(accountID, clusterName string) bool { + r.mu.Lock() + defer r.mu.Unlock() + _, ok := r.holders[registryKey(accountID, clusterName)] + return ok +} + +func registryKey(accountID, clusterName string) string { + return accountID + "/" + clusterName +} + +// RunClusterReconciler is the production SpawnReconcilerFn: it constructs a +// ClusterReconciler, acquires the leader lease, then drives Run in a +// goroutine. Returns (release, nil) on lease acquired, or (nil, error) on +// constructor failure. If another node holds the lease, returns (nil, nil) +// without spawning — caller can retry on the next reconcile tick. +func RunClusterReconciler( + ctx context.Context, + leaderKV, acctKV nats.KeyValue, + accountID, clusterName, holderID, healthURL string, + opts ...ReconcilerOption, +) (func(), error) { + r, err := NewClusterReconciler(leaderKV, acctKV, accountID, clusterName, holderID, healthURL, opts...) + if err != nil { + return nil, err + } + release, ok := r.AcquireLease() + if !ok { + slog.Info("RunClusterReconciler: lease held elsewhere, skipping spawn", + "accountID", accountID, "cluster", clusterName) + return nil, nil + } + go func() { + if runErr := r.Run(ctx); runErr != nil && !errors.Is(runErr, context.Canceled) { + slog.Info("RunClusterReconciler: Run exited", + "accountID", accountID, "cluster", clusterName, "err", runErr) + } + }() + return release, nil +} diff --git a/spinifex/handlers/eks/reconciler_registry_test.go b/spinifex/handlers/eks/reconciler_registry_test.go new file mode 100644 index 000000000..67e1832ce --- /dev/null +++ b/spinifex/handlers/eks/reconciler_registry_test.go @@ -0,0 +1,95 @@ +package handlers_eks + +import ( + "context" + "errors" + "sync/atomic" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestReconcilerRegistry_SpawnAndStop(t *testing.T) { + reg := NewReconcilerRegistry() + + var ( + ran atomic.Bool + released atomic.Bool + ) + fn := func(ctx context.Context, accountID, clusterName string) (func(), error) { + ran.Store(true) + go func() { <-ctx.Done() }() + return func() { released.Store(true) }, nil + } + + require.NoError(t, reg.Spawn(t.Context(), "111122223333", "alpha", fn)) + assert.True(t, reg.Has("111122223333", "alpha")) + assert.True(t, ran.Load()) + + reg.Stop("111122223333", "alpha") + assert.False(t, reg.Has("111122223333", "alpha")) + require.Eventually(t, released.Load, 500*time.Millisecond, 5*time.Millisecond) +} + +func TestReconcilerRegistry_SpawnIdempotent(t *testing.T) { + reg := NewReconcilerRegistry() + var spawnCalls atomic.Int32 + fn := func(ctx context.Context, _, _ string) (func(), error) { + spawnCalls.Add(1) + go func() { <-ctx.Done() }() + return func() {}, nil + } + + require.NoError(t, reg.Spawn(t.Context(), "111122223333", "alpha", fn)) + require.NoError(t, reg.Spawn(t.Context(), "111122223333", "alpha", fn)) + + assert.EqualValues(t, 1, spawnCalls.Load(), "second Spawn must not re-invoke fn") + reg.StopAll() +} + +func TestReconcilerRegistry_SpawnFnErrorRemovesEntry(t *testing.T) { + reg := NewReconcilerRegistry() + fn := func(_ context.Context, _, _ string) (func(), error) { + return nil, errors.New("acquire lease failed") + } + + err := reg.Spawn(t.Context(), "111122223333", "alpha", fn) + require.Error(t, err) + assert.False(t, reg.Has("111122223333", "alpha"), "entry must not linger after spawn failure") +} + +func TestReconcilerRegistry_StopAllCancelsEvery(t *testing.T) { + reg := NewReconcilerRegistry() + var released atomic.Int32 + fn := func(ctx context.Context, _, _ string) (func(), error) { + go func() { <-ctx.Done() }() + return func() { released.Add(1) }, nil + } + + require.NoError(t, reg.Spawn(t.Context(), "111122223333", "alpha", fn)) + require.NoError(t, reg.Spawn(t.Context(), "111122223333", "beta", fn)) + require.NoError(t, reg.Spawn(t.Context(), "444455556666", "gamma", fn)) + + reg.StopAll() + require.Eventually(t, func() bool { return released.Load() == 3 }, 500*time.Millisecond, 5*time.Millisecond) + assert.False(t, reg.Has("111122223333", "alpha")) + assert.False(t, reg.Has("111122223333", "beta")) + assert.False(t, reg.Has("444455556666", "gamma")) +} + +func TestReconcilerRegistry_StopUnknownKeyNoop(t *testing.T) { + reg := NewReconcilerRegistry() + reg.Stop("111122223333", "ghost") + assert.False(t, reg.Has("111122223333", "ghost")) +} + +func TestReconcilerRegistry_SpawnRejectsBadArgs(t *testing.T) { + reg := NewReconcilerRegistry() + fn := func(_ context.Context, _, _ string) (func(), error) { return func() {}, nil } + + require.Error(t, reg.Spawn(t.Context(), "", "alpha", fn)) + require.Error(t, reg.Spawn(t.Context(), "111122223333", "", fn)) + require.Error(t, reg.Spawn(t.Context(), "111122223333", "alpha", nil)) +} diff --git a/spinifex/handlers/eks/security_groups.go b/spinifex/handlers/eks/security_groups.go new file mode 100644 index 000000000..33cf083dc --- /dev/null +++ b/spinifex/handlers/eks/security_groups.go @@ -0,0 +1,162 @@ +package handlers_eks + +import ( + "errors" + "fmt" + "log/slog" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/spinifex/spinifex/tags" +) + +// sgProvisioner is the subset of handlers_ec2_vpc.VPCService that the cluster +// SG helpers need. Narrow so tests can fake with hand-rolled recorders without +// implementing the full VPCService surface. +type sgProvisioner interface { + CreateSecurityGroup(input *ec2.CreateSecurityGroupInput, accountID string) (*ec2.CreateSecurityGroupOutput, error) + DescribeSecurityGroups(input *ec2.DescribeSecurityGroupsInput, accountID string) (*ec2.DescribeSecurityGroupsOutput, error) + DeleteSecurityGroup(input *ec2.DeleteSecurityGroupInput, accountID string) (*ec2.DeleteSecurityGroupOutput, error) +} + +// clusterEKSClusterTagKey is stamped on every cluster-scoped resource so the +// DeleteCluster sweep + the UI hide-from-customer filter can group them. +const clusterEKSClusterTagKey = "spinifex:eks-cluster" + +// clusterEKSRoleTagKey distinguishes the control-plane SG from the nodegroup +// SG when both live in the same VPC. +const clusterEKSRoleTagKey = "spinifex:eks-role" + +const ( + clusterEKSRoleControlPlane = "control-plane" + clusterEKSRoleNodegroup = "nodegroup" +) + +// ClusterControlPlaneSGName returns the deterministic SG name used for the +// cluster's control-plane SG. Stable so Stage-6 DeleteCluster can locate it +// from clusterName alone. +func ClusterControlPlaneSGName(clusterName string) string { + return fmt.Sprintf("eks-cluster-%s-control-plane-sg", clusterName) +} + +// ClusterNodegroupSGName returns the deterministic SG name used for the +// cluster's nodegroup SG. +func ClusterNodegroupSGName(clusterName string) string { + return fmt.Sprintf("eks-cluster-%s-nodegroup-sg", clusterName) +} + +// EnsureClusterSGs creates (or returns existing) control-plane + nodegroup +// security groups in the customer VPC. Both are tagged +// spinifex:managed-by=eks + spinifex:eks-cluster=. Idempotent: an SG +// whose group-name + vpc-id match the expected pair is reused without a +// second create call. The two creates are independent — a failure on the +// nodegroup SG does not unwind the control-plane SG (DeleteCluster cleans up). +func EnsureClusterSGs(sgp sgProvisioner, accountID, clusterName, vpcID string) (controlPlaneSGID, nodegroupSGID string, err error) { + if clusterName == "" { + return "", "", errors.New("eks: EnsureClusterSGs empty cluster name") + } + if vpcID == "" { + return "", "", errors.New("eks: EnsureClusterSGs empty vpc id") + } + + controlPlaneSGID, err = ensureClusterSG(sgp, accountID, vpcID, clusterName, + ClusterControlPlaneSGName(clusterName), + fmt.Sprintf("EKS control-plane SG for cluster %s", clusterName), + clusterEKSRoleControlPlane) + if err != nil { + return "", "", err + } + + nodegroupSGID, err = ensureClusterSG(sgp, accountID, vpcID, clusterName, + ClusterNodegroupSGName(clusterName), + fmt.Sprintf("EKS nodegroup SG for cluster %s", clusterName), + clusterEKSRoleNodegroup) + if err != nil { + return "", "", err + } + + return controlPlaneSGID, nodegroupSGID, nil +} + +// DeleteClusterSGs removes both cluster SGs in the customer VPC. Missing SGs +// are no-ops so DeleteCluster can retry safely. Delete errors are logged and +// the sweep continues; the first error is returned so the caller surfaces it +// without halting the broader teardown. +func DeleteClusterSGs(sgp sgProvisioner, accountID, clusterName, vpcID string) error { + if clusterName == "" { + return errors.New("eks: DeleteClusterSGs empty cluster name") + } + if vpcID == "" { + return errors.New("eks: DeleteClusterSGs empty vpc id") + } + + var firstErr error + for _, name := range []string{ClusterControlPlaneSGName(clusterName), ClusterNodegroupSGName(clusterName)} { + id, err := lookupSGByName(sgp, accountID, vpcID, name) + if err != nil { + slog.Warn("DeleteClusterSGs: SG lookup failed", "sg", name, "err", err) + if firstErr == nil { + firstErr = err + } + continue + } + if id == "" { + continue + } + if _, err := sgp.DeleteSecurityGroup(&ec2.DeleteSecurityGroupInput{GroupId: aws.String(id)}, accountID); err != nil { + slog.Warn("DeleteClusterSGs: SG delete failed", "sg", id, "name", name, "err", err) + if firstErr == nil { + firstErr = fmt.Errorf("delete SG %s: %w", id, err) + } + } + } + return firstErr +} + +func ensureClusterSG(sgp sgProvisioner, accountID, vpcID, clusterName, name, description, role string) (string, error) { + if id, err := lookupSGByName(sgp, accountID, vpcID, name); err != nil { + return "", err + } else if id != "" { + return id, nil + } + + out, err := sgp.CreateSecurityGroup(&ec2.CreateSecurityGroupInput{ + GroupName: aws.String(name), + Description: aws.String(description), + VpcId: aws.String(vpcID), + TagSpecifications: []*ec2.TagSpecification{{ + ResourceType: aws.String("security-group"), + Tags: []*ec2.Tag{ + {Key: aws.String(tags.ManagedByKey), Value: aws.String(tags.ManagedByEKS)}, + {Key: aws.String(clusterEKSClusterTagKey), Value: aws.String(clusterName)}, + {Key: aws.String(clusterEKSRoleTagKey), Value: aws.String(role)}, + }, + }}, + }, accountID) + if err != nil { + return "", fmt.Errorf("create SG %s: %w", name, err) + } + if out == nil || out.GroupId == nil || *out.GroupId == "" { + return "", fmt.Errorf("eks: CreateSecurityGroup returned empty GroupId for %s", name) + } + return *out.GroupId, nil +} + +func lookupSGByName(sgp sgProvisioner, accountID, vpcID, name string) (string, error) { + out, err := sgp.DescribeSecurityGroups(&ec2.DescribeSecurityGroupsInput{ + Filters: []*ec2.Filter{ + {Name: aws.String("group-name"), Values: aws.StringSlice([]string{name})}, + {Name: aws.String("vpc-id"), Values: aws.StringSlice([]string{vpcID})}, + }, + }, accountID) + if err != nil { + return "", fmt.Errorf("describe SG %s: %w", name, err) + } + for _, g := range out.SecurityGroups { + if g == nil || g.GroupId == nil { + continue + } + return *g.GroupId, nil + } + return "", nil +} diff --git a/spinifex/handlers/eks/security_groups_test.go b/spinifex/handlers/eks/security_groups_test.go new file mode 100644 index 000000000..b84a0e34a --- /dev/null +++ b/spinifex/handlers/eks/security_groups_test.go @@ -0,0 +1,203 @@ +package handlers_eks + +import ( + "errors" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/spinifex/spinifex/tags" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type fakeSGProvisioner struct { + createCalls []*ec2.CreateSecurityGroupInput + describeCalls []*ec2.DescribeSecurityGroupsInput + deleteCalls []*ec2.DeleteSecurityGroupInput + + // existing maps "name|vpcId" → groupId for DescribeSecurityGroups lookup. + existing map[string]string + + // nextCreateID is returned by the next CreateSecurityGroup call. Tests can + // pre-seed a queue via createIDs to differentiate the control-plane vs + // nodegroup SG IDs. + createIDs []string + + createErr error + describeErr error + deleteErr error +} + +var _ sgProvisioner = (*fakeSGProvisioner)(nil) + +func newFakeSGProvisioner() *fakeSGProvisioner { + return &fakeSGProvisioner{existing: map[string]string{}} +} + +func (f *fakeSGProvisioner) CreateSecurityGroup(input *ec2.CreateSecurityGroupInput, _ string) (*ec2.CreateSecurityGroupOutput, error) { + f.createCalls = append(f.createCalls, input) + if f.createErr != nil { + return nil, f.createErr + } + id := "sg-default" + if len(f.createIDs) > 0 { + id = f.createIDs[0] + f.createIDs = f.createIDs[1:] + } + if input.GroupName != nil && input.VpcId != nil { + f.existing[*input.GroupName+"|"+*input.VpcId] = id + } + return &ec2.CreateSecurityGroupOutput{GroupId: aws.String(id)}, nil +} + +func (f *fakeSGProvisioner) DescribeSecurityGroups(input *ec2.DescribeSecurityGroupsInput, _ string) (*ec2.DescribeSecurityGroupsOutput, error) { + f.describeCalls = append(f.describeCalls, input) + if f.describeErr != nil { + return nil, f.describeErr + } + var name, vpc string + for _, filt := range input.Filters { + if filt == nil || filt.Name == nil || len(filt.Values) == 0 || filt.Values[0] == nil { + continue + } + switch *filt.Name { + case "group-name": + name = *filt.Values[0] + case "vpc-id": + vpc = *filt.Values[0] + } + } + id, ok := f.existing[name+"|"+vpc] + out := &ec2.DescribeSecurityGroupsOutput{} + if ok { + out.SecurityGroups = []*ec2.SecurityGroup{{GroupId: aws.String(id), GroupName: aws.String(name), VpcId: aws.String(vpc)}} + } + return out, nil +} + +func (f *fakeSGProvisioner) DeleteSecurityGroup(input *ec2.DeleteSecurityGroupInput, _ string) (*ec2.DeleteSecurityGroupOutput, error) { + f.deleteCalls = append(f.deleteCalls, input) + if f.deleteErr != nil { + return nil, f.deleteErr + } + return &ec2.DeleteSecurityGroupOutput{}, nil +} + +func TestEnsureClusterSGs_EmptyInputsRejected(t *testing.T) { + sgp := newFakeSGProvisioner() + + _, _, err := EnsureClusterSGs(sgp, "111122223333", "", "vpc-aaa") + require.Error(t, err) + + _, _, err = EnsureClusterSGs(sgp, "111122223333", "alpha", "") + require.Error(t, err) + + assert.Empty(t, sgp.createCalls) + assert.Empty(t, sgp.describeCalls) +} + +func TestEnsureClusterSGs_FreshCreatesBoth(t *testing.T) { + sgp := newFakeSGProvisioner() + sgp.createIDs = []string{"sg-cp-001", "sg-ng-002"} + + cpID, ngID, err := EnsureClusterSGs(sgp, "111122223333", "alpha", "vpc-aaa") + require.NoError(t, err) + assert.Equal(t, "sg-cp-001", cpID) + assert.Equal(t, "sg-ng-002", ngID) + + require.Len(t, sgp.createCalls, 2) + + assertSGCreateTagged(t, sgp.createCalls[0], "eks-cluster-alpha-control-plane-sg", "vpc-aaa", "alpha", clusterEKSRoleControlPlane) + assertSGCreateTagged(t, sgp.createCalls[1], "eks-cluster-alpha-nodegroup-sg", "vpc-aaa", "alpha", clusterEKSRoleNodegroup) +} + +func TestEnsureClusterSGs_IdempotentReusesExisting(t *testing.T) { + sgp := newFakeSGProvisioner() + sgp.existing["eks-cluster-alpha-control-plane-sg|vpc-aaa"] = "sg-existing-cp" + sgp.existing["eks-cluster-alpha-nodegroup-sg|vpc-aaa"] = "sg-existing-ng" + + cpID, ngID, err := EnsureClusterSGs(sgp, "111122223333", "alpha", "vpc-aaa") + require.NoError(t, err) + assert.Equal(t, "sg-existing-cp", cpID) + assert.Equal(t, "sg-existing-ng", ngID) + assert.Empty(t, sgp.createCalls, "no create calls expected when SGs already exist") +} + +func TestEnsureClusterSGs_MixedExistenceCreatesMissing(t *testing.T) { + sgp := newFakeSGProvisioner() + sgp.existing["eks-cluster-alpha-control-plane-sg|vpc-aaa"] = "sg-existing-cp" + sgp.createIDs = []string{"sg-new-ng"} + + cpID, ngID, err := EnsureClusterSGs(sgp, "111122223333", "alpha", "vpc-aaa") + require.NoError(t, err) + assert.Equal(t, "sg-existing-cp", cpID) + assert.Equal(t, "sg-new-ng", ngID) + + require.Len(t, sgp.createCalls, 1, "only nodegroup SG should be created") + assert.Equal(t, "eks-cluster-alpha-nodegroup-sg", aws.StringValue(sgp.createCalls[0].GroupName)) +} + +func TestEnsureClusterSGs_CreateErrorSurfacedFromControlPlane(t *testing.T) { + sgp := newFakeSGProvisioner() + sgp.createErr = errors.New("vpcd unavailable") + + _, _, err := EnsureClusterSGs(sgp, "111122223333", "alpha", "vpc-aaa") + require.Error(t, err) + assert.Contains(t, err.Error(), "create SG eks-cluster-alpha-control-plane-sg") +} + +func TestDeleteClusterSGs_DeletesBothExisting(t *testing.T) { + sgp := newFakeSGProvisioner() + sgp.existing["eks-cluster-alpha-control-plane-sg|vpc-aaa"] = "sg-existing-cp" + sgp.existing["eks-cluster-alpha-nodegroup-sg|vpc-aaa"] = "sg-existing-ng" + + err := DeleteClusterSGs(sgp, "111122223333", "alpha", "vpc-aaa") + require.NoError(t, err) + + require.Len(t, sgp.deleteCalls, 2) + assert.Equal(t, "sg-existing-cp", aws.StringValue(sgp.deleteCalls[0].GroupId)) + assert.Equal(t, "sg-existing-ng", aws.StringValue(sgp.deleteCalls[1].GroupId)) +} + +func TestDeleteClusterSGs_MissingSGsNoOp(t *testing.T) { + sgp := newFakeSGProvisioner() + + err := DeleteClusterSGs(sgp, "111122223333", "alpha", "vpc-aaa") + require.NoError(t, err) + assert.Empty(t, sgp.deleteCalls, "no delete calls expected when SGs already absent") +} + +func TestDeleteClusterSGs_FirstErrorSurfacedSweepContinues(t *testing.T) { + sgp := newFakeSGProvisioner() + sgp.existing["eks-cluster-alpha-control-plane-sg|vpc-aaa"] = "sg-existing-cp" + sgp.existing["eks-cluster-alpha-nodegroup-sg|vpc-aaa"] = "sg-existing-ng" + sgp.deleteErr = errors.New("DependencyViolation") + + err := DeleteClusterSGs(sgp, "111122223333", "alpha", "vpc-aaa") + require.Error(t, err) + assert.Contains(t, err.Error(), "sg-existing-cp") + assert.Len(t, sgp.deleteCalls, 2, "both delete calls should be attempted despite first error") +} + +func assertSGCreateTagged(t *testing.T, in *ec2.CreateSecurityGroupInput, name, vpcID, clusterName, role string) { + t.Helper() + require.NotNil(t, in) + assert.Equal(t, name, aws.StringValue(in.GroupName)) + assert.Equal(t, vpcID, aws.StringValue(in.VpcId)) + require.Len(t, in.TagSpecifications, 1) + spec := in.TagSpecifications[0] + require.NotNil(t, spec) + assert.Equal(t, "security-group", aws.StringValue(spec.ResourceType)) + + got := map[string]string{} + for _, tg := range spec.Tags { + if tg == nil || tg.Key == nil || tg.Value == nil { + continue + } + got[*tg.Key] = *tg.Value + } + assert.Equal(t, tags.ManagedByEKS, got[tags.ManagedByKey]) + assert.Equal(t, clusterName, got[clusterEKSClusterTagKey]) + assert.Equal(t, role, got[clusterEKSRoleTagKey]) +} diff --git a/spinifex/handlers/eks/service_impl.go b/spinifex/handlers/eks/service_impl.go index 1ff9827e6..d6e457c45 100644 --- a/spinifex/handlers/eks/service_impl.go +++ b/spinifex/handlers/eks/service_impl.go @@ -1,35 +1,104 @@ package handlers_eks import ( + "context" "errors" "fmt" + "log/slog" + "net" + "slices" + "sort" + "strconv" + "strings" + "sync" + "time" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/eks" "github.com/mulgadc/spinifex/spinifex/awserrors" "github.com/mulgadc/spinifex/spinifex/config" + "github.com/mulgadc/spinifex/spinifex/tags" + "github.com/mulgadc/spinifex/spinifex/utils" "github.com/nats-io/nats.go" ) -// EKSServiceImpl is the daemon-side EKSService. All methods currently return -// NotImplemented; bodies land alongside the K3s control-plane work. +// SubnetVPCResolver resolves a subnet ID to its parent VPC ID. Narrow so +// EKSServiceImpl can stay free of the wider handlers/ec2/vpc surface; the +// daemon adapts VPCServiceImpl.GetSubnet onto this contract. +type SubnetVPCResolver interface { + GetSubnetVPC(accountID, subnetID string) (vpcID string, err error) +} + +// EKSServiceDeps wires every external collaborator EKSServiceImpl needs. +// The narrow per-area interfaces (sgProvisioner, nlbProvisioner, etc.) are +// already defined alongside their consumers; the daemon adapts each +// service's concrete type onto the interface. +type EKSServiceDeps struct { + Config *config.Config + NATSConn *nats.Conn + MasterKey []byte + GatewayBaseURL string + Region string + HolderID string + + // NATS auth handed to the K3s server VM so it can publish its one-shot + // bootstrap messages. Shared token + CA (PEM content) + a VM-reachable + // URL — spinifex has no per-principal nkeys hierarchy to scope against. + NATSURL string + NATSToken string + NATSCACert string + + VPCSG sgProvisioner + VPCK3s k3sVPCProvisioner + VPCSubnet SubnetVPCResolver + NLB nlbProvisioner + Instance k3sInstanceLauncher + Image k3sAMIResolver + EIP eipProvisioner +} + +// eipProvisioner is the narrow EIP surface CreateCluster needs to give the +// hidden K3s control-plane VM an egress-only public IP (the distributed-NAT +// dev/edge topology has no shared masquerade address). The daemon adapts the +// concrete EIP service onto this. +type eipProvisioner interface { + AllocateAddress(input *ec2.AllocateAddressInput, accountID string) (*ec2.AllocateAddressOutput, error) + ReleaseAddress(input *ec2.ReleaseAddressInput, accountID string) (*ec2.ReleaseAddressOutput, error) +} + +// EKSServiceImpl is the daemon-side EKSService. CreateCluster / +// DescribeCluster / ListClusters / DeleteCluster have real bodies; every +// other action is still NotImplemented pending follow-up sprints. type EKSServiceImpl struct { - config *config.Config - nc *nats.Conn + deps EKSServiceDeps store *Store leaderKV nats.KeyValue + registry *ReconcilerRegistry + + mu sync.Mutex + bgCtx context.Context + bgCancel context.CancelFunc } var _ EKSService = (*EKSServiceImpl)(nil) -// NewEKSServiceImplWithNATS wires the Store handle and creates the shared -// spinifex-eks-leader bucket so the leader-lease CAS loop has a ready bucket -// to CAS against without a chicken-and-egg bootstrap. -func NewEKSServiceImplWithNATS(cfg *config.Config, nc *nats.Conn) (*EKSServiceImpl, error) { - store, err := NewStore(nc) +const defaultK8sVersion = "1.32" + +// NewEKSServiceImpl wires the Store, leader bucket, reconciler registry, and +// per-cluster background-goroutine context. Validates that MasterKey, +// GatewayBaseURL, Region, and HolderID are set when called from the live +// daemon path; the legacy NewEKSServiceImplWithNATS shim leaves them empty +// and bodies that need them return ServerInternal. +func NewEKSServiceImpl(deps EKSServiceDeps) (*EKSServiceImpl, error) { + if deps.NATSConn == nil { + return nil, errors.New("eks: NewEKSServiceImpl nil NATSConn") + } + store, err := NewStore(deps.NATSConn) if err != nil { return nil, fmt.Errorf("failed to create EKS store: %w", err) } - js, err := nc.JetStream() + js, err := deps.NATSConn.JetStream() if err != nil { return nil, fmt.Errorf("failed to get JetStream context: %w", err) } @@ -37,28 +106,536 @@ func NewEKSServiceImplWithNATS(cfg *config.Config, nc *nats.Conn) (*EKSServiceIm if err != nil { return nil, err } + ctx, cancel := context.WithCancel(context.Background()) return &EKSServiceImpl{ - config: cfg, - nc: nc, + deps: deps, store: store, leaderKV: leaderKV, + registry: NewReconcilerRegistry(), + bgCtx: ctx, + bgCancel: cancel, }, nil } -func notImpl() error { return errors.New(awserrors.ErrorNotImplemented) } +// NewEKSServiceImplWithNATS is a back-compat shim. Bodies that need +// orchestration deps return ServerInternal when invoked through this shim; +// the daemon-handler routing test calls it to verify NATS subject wiring +// without standing up the full dependency graph. +func NewEKSServiceImplWithNATS(cfg *config.Config, nc *nats.Conn) (*EKSServiceImpl, error) { + return NewEKSServiceImpl(EKSServiceDeps{Config: cfg, NATSConn: nc}) +} + +// Shutdown stops the per-cluster reconciler goroutines and cancels every +// background bootstrap goroutine. Safe to call multiple times. +func (s *EKSServiceImpl) Shutdown() { + s.mu.Lock() + cancel := s.bgCancel + s.mu.Unlock() + if cancel != nil { + cancel() + } + s.registry.StopAll() +} + +// SpawnRegisteredReconcilers enumerates every cluster in every per-account +// bucket and registers a reconciler goroutine for each cluster in +// CREATING or ACTIVE state. Called by the daemon on boot so a node restart +// resumes lifecycle reconcile without waiting for the next CreateCluster. +func (s *EKSServiceImpl) SpawnRegisteredReconcilers() error { + if !s.depsReadyForOrchestration() { + slog.Debug("SpawnRegisteredReconcilers: deps not ready, skipping") + return nil + } + js, err := s.deps.NATSConn.JetStream() + if err != nil { + return fmt.Errorf("jetstream: %w", err) + } + buckets := js.KeyValueStoreNames() + for name := range buckets { + if !strings.HasPrefix(name, KVBucketEKSAccountPrefix) { + continue + } + accountID := strings.TrimPrefix(name, KVBucketEKSAccountPrefix) + acctKV, err := js.KeyValue(name) + if err != nil { + slog.Warn("SpawnRegisteredReconcilers: open bucket failed", "bucket", name, "err", err) + continue + } + clusters, err := listClusterNames(acctKV) + if err != nil { + slog.Warn("SpawnRegisteredReconcilers: list clusters failed", "bucket", name, "err", err) + continue + } + for _, cluster := range clusters { + meta, err := GetClusterMeta(acctKV, cluster) + if err != nil { + continue + } + if meta.Status != ClusterStatusCreating && meta.Status != ClusterStatusActive { + continue + } + // A restart mid-CREATING lost the bootstrap subscriptions; the K3s + // VM publishes its one-shot core-NATS messages once and to nobody. + // Re-subscribe to whichever artifacts are still missing so the + // cluster can still reach ACTIVE instead of hanging in CREATING. + if meta.Status == ClusterStatusCreating { + if pending := BootstrapPendingKinds(acctKV, cluster, meta); len(pending) > 0 { + slog.Info("SpawnRegisteredReconcilers: resuming bootstrap", + "cluster", cluster, "pending", pending) + s.spawnBootstrap(accountID, cluster, acctKV, pending) + } + } + s.spawnReconciler(accountID, cluster, meta) + } + } + return nil +} + +func (s *EKSServiceImpl) depsReadyForOrchestration() bool { + return len(s.missingOrchestrationDeps()) == 0 +} + +// requireOrchestrationDeps returns a client-facing ServiceUnavailable (with the +// specific unmet deps logged at ERROR) when the daemon is missing orchestration +// wiring, so the failure is diagnosable instead of a bare ServerInternal. +func (s *EKSServiceImpl) requireOrchestrationDeps(op string) error { + missing := s.missingOrchestrationDeps() + if len(missing) == 0 { + return nil + } + slog.Error("EKS orchestration deps not ready", "op", op, "missing", missing) + return errors.New(awserrors.ErrorServiceUnavailable) +} + +// missingOrchestrationDeps names the deps required for cluster orchestration +// that are unset, so a "deps not ready" rejection can log the precise cause +// instead of an opaque ServerInternal whose only hint is a one-time boot WARN. +func (s *EKSServiceImpl) missingOrchestrationDeps() []string { + var missing []string + if s.deps.VPCSG == nil { + missing = append(missing, "VPCSG") + } + if s.deps.VPCK3s == nil { + missing = append(missing, "VPCK3s") + } + if s.deps.VPCSubnet == nil { + missing = append(missing, "VPCSubnet") + } + if s.deps.NLB == nil { + missing = append(missing, "NLB") + } + if s.deps.Instance == nil { + missing = append(missing, "Instance") + } + if s.deps.Image == nil { + missing = append(missing, "Image") + } + if s.deps.EIP == nil { + missing = append(missing, "EIP") + } + if len(s.deps.MasterKey) == 0 { + missing = append(missing, "MasterKey") + } + if s.deps.GatewayBaseURL == "" { + missing = append(missing, "GatewayBaseURL") + } + if s.deps.Region == "" { + missing = append(missing, "Region") + } + if s.deps.HolderID == "" { + missing = append(missing, "HolderID") + } + return missing +} // --- Cluster --- -func (s *EKSServiceImpl) CreateCluster(_ *eks.CreateClusterInput, _ string) (*eks.CreateClusterOutput, error) { - return nil, notImpl() +func (s *EKSServiceImpl) CreateCluster(input *eks.CreateClusterInput, accountID string) (*eks.CreateClusterOutput, error) { + if err := s.requireOrchestrationDeps("CreateCluster"); err != nil { + return nil, err + } + if err := validateCreateClusterInput(input); err != nil { + return nil, err + } + name := aws.StringValue(input.Name) + subnetIDs := aws.StringValueSlice(input.ResourcesVpcConfig.SubnetIds) + + js, err := s.deps.NATSConn.JetStream() + if err != nil { + return nil, fmt.Errorf("jetstream: %w", err) + } + acctKV, err := GetOrCreateAccountBucket(js, accountID) + if err != nil { + return nil, fmt.Errorf("get account bucket: %w", err) + } + + if existing, err := GetClusterMeta(acctKV, name); err == nil { + if existing.Status != ClusterStatusFailed { + slog.Info("CreateCluster: cluster already exists", + "name", name, "accountID", accountID, "status", existing.Status) + return nil, errors.New(awserrors.ErrorEKSResourceInUse) + } + // A prior attempt failed. Reclaim whatever it left behind and clear its + // state so this create starts clean — makes a retry (including the + // SDK's own auto-retry) idempotent instead of masking the original + // failure with a spurious "already exists" error. If teardown of the + // failed attempt's resources fails, surface that rather than recreating + // on top of orphans. + slog.Info("CreateCluster: reclaiming FAILED cluster before recreate", + "name", name, "accountID", accountID) + if perr := s.purgeClusterInfra(accountID, name, existing, acctKV); perr != nil { + return nil, fmt.Errorf("reclaim failed cluster %s: %w", name, perr) + } + } else if !errors.Is(err, ErrClusterNotFound) { + return nil, fmt.Errorf("preflight get meta: %w", err) + } + + vpcID, err := s.deps.VPCSubnet.GetSubnetVPC(accountID, subnetIDs[0]) + if err != nil { + return nil, fmt.Errorf("resolve subnet VPC: %w", err) + } + + region := s.deps.Region + arn := fmt.Sprintf("arn:aws:eks:%s:%s:cluster/%s", region, accountID, name) + + meta := &ClusterMeta{ + Name: name, + Arn: arn, + Status: ClusterStatusCreating, + Version: deref(input.Version, defaultK8sVersion), + RoleArn: aws.StringValue(input.RoleArn), + ResourcesVpcConfig: &ClusterVpcConfig{ + SubnetIds: subnetIDs, + VpcId: vpcID, + }, + CreatedAt: time.Now().UTC(), + } + if err := PutClusterMeta(acctKV, meta); err != nil { + return nil, err + } + + cpSG, ngSG, err := EnsureClusterSGs(s.deps.VPCSG, accountID, name, vpcID) + if err != nil { + s.markFailed(acctKV, name) + return nil, fmt.Errorf("ensure cluster SGs: %w", err) + } + meta.ResourcesVpcConfig.SecurityGroupIds = []string{cpSG, ngSG} + + nlb, err := EnsureClusterNLB(s.deps.NLB, accountID, name, subnetIDs) + if err != nil { + s.markFailed(acctKV, name) + return nil, fmt.Errorf("ensure cluster NLB: %w", err) + } + meta.Endpoint = "https://" + net.JoinHostPort(nlb.DNSName, strconv.FormatInt(clusterNLBListenPort, 10)) + meta.NLBArn = nlb.LoadBalancerArn + meta.NLBTargetGroupArn = nlb.TargetGroupArn + + // Persist the NLB ARNs now, before any further fallible step. Without this + // a failure between here and the final PutClusterMeta would leave the NLB + + // target group + listener + backing LB VM created but unrecorded, so + // DeleteCluster (which keys teardown off the persisted ARNs) could not + // reclaim them. + if err := PutClusterMeta(acctKV, meta); err != nil { + s.markFailed(acctKV, name) + return nil, fmt.Errorf("persist NLB arns: %w", err) + } + + oidcIssuer, err := ClusterOIDCIssuer(s.deps.GatewayBaseURL, region, accountID, name) + if err != nil { + s.markFailed(acctKV, name) + return nil, fmt.Errorf("build OIDC issuer: %w", err) + } + meta.OIDCIssuer = oidcIssuer + + privPEM, _, err := GenerateClusterOIDCKeypair(acctKV, name, s.deps.MasterKey) + if err != nil { + s.markFailed(acctKV, name) + return nil, fmt.Errorf("generate OIDC keypair: %w", err) + } + pubPEM, err := PublicKeyPEMFromPrivate(privPEM) + if err != nil { + s.markFailed(acctKV, name) + return nil, fmt.Errorf("derive OIDC public key: %w", err) + } + + k3sOut, err := LaunchK3sServerVM(s.deps.VPCK3s, s.deps.Instance, s.deps.Image, K3sServerInput{ + AccountID: accountID, + ClusterName: name, + Region: region, + SubnetID: subnetIDs[0], + ControlPlaneSGID: cpSG, + NLBDNS: nlb.DNSName, + OIDCIssuer: oidcIssuer, + OIDCPrivateKeyPEM: privPEM, + OIDCPublicKeyPEM: pubPEM, + NATSURL: s.deps.NATSURL, + NATSToken: s.deps.NATSToken, + NATSCACert: s.deps.NATSCACert, + }) + if err != nil { + s.markFailed(acctKV, name) + if errors.Is(err, ErrEKSServerAMINotFound) { + slog.Error("CreateCluster: eks-server AMI not found; cannot launch control plane", + "cluster", name, "accountID", accountID, "err", err) + return nil, errors.New(awserrors.ErrorServiceUnavailable) + } + slog.Error("CreateCluster: K3s control-plane VM launch failed", + "cluster", name, "accountID", accountID, "err", err) + return nil, fmt.Errorf("launch K3s VM: %w", err) + } + meta.ControlPlaneInstanceID = k3sOut.InstanceID + meta.ControlPlaneENIID = k3sOut.ENIID + meta.ControlPlaneENIIP = k3sOut.ENIIP + meta.ControlPlaneMgmtIP = k3sOut.MgmtIP + + // Egress: the control-plane VM must pull container images. Allocate a + // hidden pool address and wire an egress-only SNAT for its /32 (no DNAT — + // the VM stays unreachable inbound; the NLB is its only front door). + egressIP, egressAllocID, err := s.allocateClusterEgressIP(accountID, name) + if err != nil { + s.markFailed(acctKV, name) + return nil, fmt.Errorf("allocate cluster egress IP: %w", err) + } + meta.EgressEIPAllocationID = egressAllocID + meta.EgressEIPPublicIP = egressIP + utils.PublishEvent(s.deps.NATSConn, "vpc.add-system-egress", systemEgressEvent{ + VpcId: vpcID, + SubnetId: subnetIDs[0], + InstanceIp: k3sOut.ENIIP, + ExternalIp: egressIP, + }) + + // Record the VM + ENI + egress IP before registering the target so a failed + // register (or anything after) leaves them recoverable by DeleteCluster. + if err := PutClusterMeta(acctKV, meta); err != nil { + s.markFailed(acctKV, name) + return nil, fmt.Errorf("persist control-plane ids: %w", err) + } + + if err := RegisterClusterTarget(s.deps.NLB, accountID, nlb.TargetGroupArn, k3sOut.ENIIP); err != nil { + s.markFailed(acctKV, name) + return nil, fmt.Errorf("register NLB target: %w", err) + } + + if err := PutClusterMeta(acctKV, meta); err != nil { + return nil, err + } + + s.spawnBootstrap(accountID, name, acctKV, nil) + s.spawnReconciler(accountID, name, meta) + + return &eks.CreateClusterOutput{Cluster: clusterMetaToAWS(meta)}, nil } -func (s *EKSServiceImpl) DescribeCluster(_ *eks.DescribeClusterInput, _ string) (*eks.DescribeClusterOutput, error) { - return nil, notImpl() +// systemEgressEvent is the wire shape for vpc.add-system-egress / +// vpc.delete-system-egress (mirrors network/subscribers.SystemEgressEvent; +// kept local to avoid importing the network layer from a handler). +type systemEgressEvent struct { + VpcId string `json:"vpc_id"` + SubnetId string `json:"subnet_id"` + InstanceIp string `json:"instance_ip"` + ExternalIp string `json:"external_ip"` } -func (s *EKSServiceImpl) ListClusters(_ *eks.ListClustersInput, _ string) (*eks.ListClustersOutput, error) { - return nil, notImpl() +// allocateClusterEgressIP allocates a hidden pool address for the cluster's +// control-plane VM egress, tagged ManagedBy=eks so it stays out of customer +// DescribeAddresses listings. +func (s *EKSServiceImpl) allocateClusterEgressIP(accountID, name string) (publicIP, allocationID string, err error) { + out, err := s.deps.EIP.AllocateAddress(&ec2.AllocateAddressInput{ + Domain: aws.String("vpc"), + TagSpecifications: []*ec2.TagSpecification{{ + ResourceType: aws.String("elastic-ip"), + Tags: []*ec2.Tag{{Key: aws.String(tags.ManagedByKey), Value: aws.String(tags.ManagedByEKS)}}, + }}, + }, accountID) + if err != nil { + return "", "", err + } + if out == nil || aws.StringValue(out.PublicIp) == "" || aws.StringValue(out.AllocationId) == "" { + return "", "", errors.New("eks: AllocateAddress returned incomplete EIP") + } + return aws.StringValue(out.PublicIp), aws.StringValue(out.AllocationId), nil +} + +func (s *EKSServiceImpl) DescribeCluster(input *eks.DescribeClusterInput, accountID string) (*eks.DescribeClusterOutput, error) { + name := aws.StringValue(input.Name) + if name == "" { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + js, err := s.deps.NATSConn.JetStream() + if err != nil { + return nil, fmt.Errorf("jetstream: %w", err) + } + acctKV, err := GetOrCreateAccountBucket(js, accountID) + if err != nil { + return nil, fmt.Errorf("get account bucket: %w", err) + } + meta, err := GetClusterMeta(acctKV, name) + if err != nil { + if errors.Is(err, ErrClusterNotFound) { + return nil, errors.New(awserrors.ErrorEKSResourceNotFound) + } + return nil, err + } + return &eks.DescribeClusterOutput{Cluster: clusterMetaToAWS(meta)}, nil +} + +func (s *EKSServiceImpl) ListClusters(input *eks.ListClustersInput, accountID string) (*eks.ListClustersOutput, error) { + js, err := s.deps.NATSConn.JetStream() + if err != nil { + return nil, fmt.Errorf("jetstream: %w", err) + } + acctKV, err := GetOrCreateAccountBucket(js, accountID) + if err != nil { + return nil, fmt.Errorf("get account bucket: %w", err) + } + names, err := listClusterNames(acctKV) + if err != nil { + return nil, err + } + sort.Strings(names) + + maxResults := int(aws.Int64Value(input.MaxResults)) + if maxResults <= 0 || maxResults > 100 { + maxResults = 100 + } + startToken := aws.StringValue(input.NextToken) + + page := make([]string, 0, maxResults) + var nextToken string + startIdx := 0 + if startToken != "" { + startIdx = sort.SearchStrings(names, startToken) + } + endIdx := min(startIdx+maxResults, len(names)) + page = append(page, names[startIdx:endIdx]...) + if endIdx < len(names) { + nextToken = names[endIdx] + } + + out := &eks.ListClustersOutput{Clusters: aws.StringSlice(page)} + if nextToken != "" { + out.NextToken = aws.String(nextToken) + } + return out, nil +} + +func (s *EKSServiceImpl) DeleteCluster(input *eks.DeleteClusterInput, accountID string) (*eks.DeleteClusterOutput, error) { + if err := s.requireOrchestrationDeps("DeleteCluster"); err != nil { + return nil, err + } + name := aws.StringValue(input.Name) + if name == "" { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + js, err := s.deps.NATSConn.JetStream() + if err != nil { + return nil, fmt.Errorf("jetstream: %w", err) + } + acctKV, err := GetOrCreateAccountBucket(js, accountID) + if err != nil { + return nil, fmt.Errorf("get account bucket: %w", err) + } + + meta, err := GetClusterMeta(acctKV, name) + if err != nil { + if errors.Is(err, ErrClusterNotFound) { + return nil, errors.New(awserrors.ErrorEKSResourceNotFound) + } + return nil, err + } + + if err := SetClusterStatus(acctKV, name, ClusterStatusDeleting); err != nil { + return nil, fmt.Errorf("set DELETING: %w", err) + } + meta.Status = ClusterStatusDeleting + + if err := s.purgeClusterInfra(accountID, name, meta, acctKV); err != nil { + slog.Error("DeleteCluster: teardown incomplete; leaving cluster DELETING for retry", + "cluster", name, "err", err) + return nil, fmt.Errorf("eks: DeleteCluster %s: %w", name, err) + } + + return &eks.DeleteClusterOutput{Cluster: clusterMetaToAWS(meta)}, nil +} + +// purgeClusterInfra tears down a cluster's live AWS resources and erases its +// per-cluster KV state. Zeroize (a security guarantee — no recoverable key +// material) plus NLB and VM teardown are blocking: their failures are joined +// and returned BEFORE the KV sweep, so a billable resource is never orphaned +// without the meta record that owns its ARNs/IDs. SG cleanup is best-effort +// (a leaked SG strands no owning record). Shared by DeleteCluster and the +// FAILED-cluster reclaim path in CreateCluster. +func (s *EKSServiceImpl) purgeClusterInfra(accountID, name string, meta *ClusterMeta, acctKV nats.KeyValue) error { + s.registry.Stop(accountID, name) + + var teardownErrs []error + + if err := ZeroizeClusterOIDCKey(acctKV, name); err != nil { + teardownErrs = append(teardownErrs, fmt.Errorf("zeroize OIDC key: %w", err)) + } + + if meta.NLBArn != "" { + // Deregister is best-effort: DeleteClusterNLB tears down the whole NLB + // + target group, so a stale target registration cannot leak past it. + if meta.NLBTargetGroupArn != "" && meta.ControlPlaneENIIP != "" { + if err := DeregisterClusterTarget(s.deps.NLB, accountID, meta.NLBTargetGroupArn, meta.ControlPlaneENIIP); err != nil { + slog.Warn("purgeClusterInfra: deregister NLB target failed", "cluster", name, "err", err) + } + } + if err := DeleteClusterNLB(s.deps.NLB, accountID, name); err != nil { + teardownErrs = append(teardownErrs, fmt.Errorf("delete NLB: %w", err)) + } + } + + if meta.ControlPlaneInstanceID != "" || meta.ControlPlaneENIID != "" { + if err := TerminateK3sServerVM(s.deps.VPCK3s, s.deps.Instance, + accountID, meta.ControlPlaneInstanceID, meta.ControlPlaneENIID); err != nil { + teardownErrs = append(teardownErrs, fmt.Errorf("terminate K3s VM: %w", err)) + } + } + + // Egress: drop the OVN reroute+snat (fire-and-forget event, prune-safe) and + // release the hidden pool address. ReleaseAddress is blocking — the EIP is + // billable and its allocation ID lives in the meta we are about to erase, so + // a release failure must not let the KV sweep orphan it. + if meta.EgressEIPPublicIP != "" || meta.EgressEIPAllocationID != "" { + if meta.ResourcesVpcConfig != nil && meta.ResourcesVpcConfig.VpcId != "" && meta.ControlPlaneENIIP != "" { + subnetID := "" + if len(meta.ResourcesVpcConfig.SubnetIds) > 0 { + subnetID = meta.ResourcesVpcConfig.SubnetIds[0] + } + utils.PublishEvent(s.deps.NATSConn, "vpc.delete-system-egress", systemEgressEvent{ + VpcId: meta.ResourcesVpcConfig.VpcId, + SubnetId: subnetID, + InstanceIp: meta.ControlPlaneENIIP, + ExternalIp: meta.EgressEIPPublicIP, + }) + } + if meta.EgressEIPAllocationID != "" { + if _, err := s.deps.EIP.ReleaseAddress(&ec2.ReleaseAddressInput{ + AllocationId: aws.String(meta.EgressEIPAllocationID), + }, accountID); err != nil { + teardownErrs = append(teardownErrs, fmt.Errorf("release egress EIP: %w", err)) + } + } + } + + if len(teardownErrs) > 0 { + return errors.Join(teardownErrs...) + } + + if meta.ResourcesVpcConfig != nil && meta.ResourcesVpcConfig.VpcId != "" { + if err := DeleteClusterSGs(s.deps.VPCSG, accountID, name, meta.ResourcesVpcConfig.VpcId); err != nil { + slog.Warn("purgeClusterInfra: DeleteClusterSGs failed", "cluster", name, "err", err) + } + } + + // Only now, with NLB + VM confirmed gone, erase the meta + per-cluster KV. + if err := DeleteClusterPrefix(acctKV, name); err != nil { + return fmt.Errorf("delete cluster prefix: %w", err) + } + return nil } func (s *EKSServiceImpl) UpdateClusterConfig(_ *eks.UpdateClusterConfigInput, _ string) (*eks.UpdateClusterConfigOutput, error) { @@ -69,10 +646,6 @@ func (s *EKSServiceImpl) UpdateClusterVersion(_ *eks.UpdateClusterVersionInput, return nil, notImpl() } -func (s *EKSServiceImpl) DeleteCluster(_ *eks.DeleteClusterInput, _ string) (*eks.DeleteClusterOutput, error) { - return nil, notImpl() -} - // --- Nodegroup --- func (s *EKSServiceImpl) CreateNodegroup(_ *eks.CreateNodegroupInput, _ string) (*eks.CreateNodegroupOutput, error) { @@ -194,3 +767,167 @@ func (s *EKSServiceImpl) UntagResource(_ *eks.UntagResourceInput, _ string) (*ek func (s *EKSServiceImpl) ListTagsForResource(_ *eks.ListTagsForResourceInput, _ string) (*eks.ListTagsForResourceOutput, error) { return nil, notImpl() } + +// --- helpers --- + +func notImpl() error { return errors.New(awserrors.ErrorNotImplemented) } + +func validateCreateClusterInput(input *eks.CreateClusterInput) error { + if input == nil || input.Name == nil || *input.Name == "" { + return errors.New(awserrors.ErrorInvalidParameterValue) + } + if input.RoleArn == nil || !strings.HasPrefix(*input.RoleArn, "arn:aws:iam:") { + return errors.New(awserrors.ErrorInvalidParameterValue) + } + if input.ResourcesVpcConfig == nil || len(input.ResourcesVpcConfig.SubnetIds) == 0 { + return errors.New(awserrors.ErrorInvalidParameterValue) + } + for _, sn := range input.ResourcesVpcConfig.SubnetIds { + if sn == nil || *sn == "" { + return errors.New(awserrors.ErrorInvalidParameterValue) + } + } + if input.AccessConfig != nil && input.AccessConfig.AuthenticationMode != nil { + mode := *input.AccessConfig.AuthenticationMode + if mode != "" && mode != eks.AuthenticationModeApi { + return errors.New(awserrors.ErrorInvalidParameter) + } + } + return nil +} + +func (s *EKSServiceImpl) markFailed(kv nats.KeyValue, name string) { + if err := SetClusterStatus(kv, name, ClusterStatusFailed); err != nil { + slog.Warn("CreateCluster: SetClusterStatus(FAILED) failed", "cluster", name, "err", err) + } +} + +// spawnBootstrap launches the one-shot NATS bootstrap subscriber for a cluster. +// kinds nil means a fresh CreateCluster (wait on all four subjects); a non-nil +// subset is a daemon-restart resume that waits only on the missing artifacts. +func (s *EKSServiceImpl) spawnBootstrap(accountID, clusterName string, kv nats.KeyValue, kinds []string) { + boot, err := NewNATSBootstrap(s.deps.NATSConn, kv, s.deps.MasterKey, accountID, clusterName) + if err != nil { + slog.Error("spawnBootstrap: NewNATSBootstrap failed", "cluster", clusterName, "err", err) + return + } + go func() { + err := boot.RunForKinds(s.bgCtx, kinds) + if err == nil || errors.Is(err, context.Canceled) { + return + } + // Bootstrap died without collecting all requested artifacts. Without + // this the cluster sits in CREATING forever — fail it so + // DescribeCluster surfaces the cause and DeleteCluster can reclaim the + // resources. + slog.Warn("NATSBootstrap exited; marking cluster FAILED", "cluster", clusterName, "err", err) + if markErr := MarkClusterFailed(kv, clusterName, "bootstrap failed: "+err.Error()); markErr != nil && + !errors.Is(markErr, ErrClusterNotFound) { + slog.Error("spawnBootstrap: MarkClusterFailed", "cluster", clusterName, "err", markErr) + } + }() +} + +func (s *EKSServiceImpl) spawnReconciler(accountID, clusterName string, meta *ClusterMeta) { + healthURL := "" + switch { + case meta.ControlPlaneMgmtIP != "": + // Workaround until authoritative DNS (Eclipso/Route53) lands: the + // reconciler runs on the host, outside the VPC overlay, and can neither + // resolve the NLB DNS name nor route to the VPC-internal NLB front-end. + // The control-plane VM's br-mgmt NIC is the one apiserver address + // reachable from the daemon, so probe :6443/healthz there directly. The + // probe client sets InsecureSkipVerify, so the mgmt IP need not be in the + // apiserver cert SAN. + healthURL = "https://" + net.JoinHostPort(meta.ControlPlaneMgmtIP, "6443") + "/healthz" + case meta.Endpoint != "": + healthURL = strings.TrimRight(meta.Endpoint, "/") + "/healthz" + } + js, err := s.deps.NATSConn.JetStream() + if err != nil { + slog.Error("spawnReconciler: jetstream", "err", err) + return + } + acctKV, err := GetOrCreateAccountBucket(js, accountID) + if err != nil { + slog.Error("spawnReconciler: account bucket", "err", err) + return + } + spawn := func(ctx context.Context, _, _ string) (func(), error) { + return RunClusterReconciler(ctx, s.leaderKV, acctKV, accountID, clusterName, s.deps.HolderID, healthURL) + } + if err := s.registry.Spawn(s.bgCtx, accountID, clusterName, spawn); err != nil { + slog.Error("spawnReconciler: registry spawn", "cluster", clusterName, "err", err) + } +} + +func clusterMetaToAWS(meta *ClusterMeta) *eks.Cluster { + if meta == nil { + return nil + } + out := &eks.Cluster{ + Name: aws.String(meta.Name), + Arn: aws.String(meta.Arn), + Status: aws.String(string(meta.Status)), + Version: aws.String(meta.Version), + RoleArn: aws.String(meta.RoleArn), + CreatedAt: aws.Time(meta.CreatedAt), + } + if meta.Endpoint != "" { + out.Endpoint = aws.String(meta.Endpoint) + } + if meta.OIDCIssuer != "" { + out.Identity = &eks.Identity{Oidc: &eks.OIDC{Issuer: aws.String(meta.OIDCIssuer)}} + } + if meta.CertificateAuthorityB64 != "" { + out.CertificateAuthority = &eks.Certificate{Data: aws.String(meta.CertificateAuthorityB64)} + } + if meta.ResourcesVpcConfig != nil { + out.ResourcesVpcConfig = &eks.VpcConfigResponse{ + SubnetIds: aws.StringSlice(meta.ResourcesVpcConfig.SubnetIds), + SecurityGroupIds: aws.StringSlice(meta.ResourcesVpcConfig.SecurityGroupIds), + VpcId: aws.String(meta.ResourcesVpcConfig.VpcId), + } + } + if meta.HealthIssue != "" { + out.Health = &eks.ClusterHealth{ + Issues: []*eks.ClusterIssue{{ + Code: aws.String(eks.ClusterIssueCodeClusterUnreachable), + Message: aws.String(meta.HealthIssue), + }}, + } + } + return out +} + +func listClusterNames(kv nats.KeyValue) ([]string, error) { + keys, err := kv.Keys() + if err != nil { + if errors.Is(err, nats.ErrNoKeysFound) { + return nil, nil + } + return nil, fmt.Errorf("kv keys: %w", err) + } + suffix := "/meta" + names := make([]string, 0, len(keys)) + for _, k := range keys { + if !strings.HasPrefix(k, "clusters/") || !strings.HasSuffix(k, suffix) { + continue + } + name := strings.TrimSuffix(strings.TrimPrefix(k, "clusters/"), suffix) + if name == "" || strings.Contains(name, "/") { + continue + } + if !slices.Contains(names, name) { + names = append(names, name) + } + } + return names, nil +} + +func deref(p *string, fallback string) string { + if p == nil || *p == "" { + return fallback + } + return *p +} diff --git a/spinifex/handlers/eks/service_impl_test.go b/spinifex/handlers/eks/service_impl_test.go index fce46a0a8..5b293d557 100644 --- a/spinifex/handlers/eks/service_impl_test.go +++ b/spinifex/handlers/eks/service_impl_test.go @@ -1,12 +1,15 @@ package handlers_eks import ( + "errors" "testing" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" "github.com/mulgadc/spinifex/spinifex/awserrors" "github.com/mulgadc/spinifex/spinifex/testutil" + "github.com/nats-io/nats.go" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -18,17 +21,27 @@ func setupTestService(t *testing.T) *EKSServiceImpl { return svc } -func TestEKSServiceImpl_ClusterMethodsReturnNotImplemented(t *testing.T) { +// TestEKSServiceImpl_ClusterLifecycleShimMode covers the four lifecycle +// methods when the service is constructed via NewEKSServiceImplWithNATS +// (the shim path the daemon-handler routing test uses): orchestration deps +// are absent so CreateCluster/DeleteCluster short-circuit to ServiceUnavailable +// (the missing deps are logged at ERROR), DescribeCluster hits an empty +// per-account bucket and surfaces ResourceNotFoundException, and ListClusters +// returns an empty list. The UpdateClusterConfig + UpdateClusterVersion paths +// stay NotImplemented. +func TestEKSServiceImpl_ClusterLifecycleShimMode(t *testing.T) { svc := setupTestService(t) _, err := svc.CreateCluster(&eks.CreateClusterInput{Name: aws.String("c1")}, testAccountID) - require.EqualError(t, err, awserrors.ErrorNotImplemented) + require.EqualError(t, err, awserrors.ErrorServiceUnavailable) _, err = svc.DescribeCluster(&eks.DescribeClusterInput{Name: aws.String("c1")}, testAccountID) - require.EqualError(t, err, awserrors.ErrorNotImplemented) + require.EqualError(t, err, awserrors.ErrorEKSResourceNotFound) - _, err = svc.ListClusters(&eks.ListClustersInput{}, testAccountID) - require.EqualError(t, err, awserrors.ErrorNotImplemented) + out, err := svc.ListClusters(&eks.ListClustersInput{}, testAccountID) + require.NoError(t, err) + require.NotNil(t, out) + require.Empty(t, out.Clusters) _, err = svc.UpdateClusterConfig(&eks.UpdateClusterConfigInput{Name: aws.String("c1")}, testAccountID) require.EqualError(t, err, awserrors.ErrorNotImplemented) @@ -37,7 +50,65 @@ func TestEKSServiceImpl_ClusterMethodsReturnNotImplemented(t *testing.T) { require.EqualError(t, err, awserrors.ErrorNotImplemented) _, err = svc.DeleteCluster(&eks.DeleteClusterInput{Name: aws.String("c1")}, testAccountID) - require.EqualError(t, err, awserrors.ErrorNotImplemented) + require.EqualError(t, err, awserrors.ErrorServiceUnavailable) +} + +// EKS only supports the API authentication mode here; CONFIG_MAP (and the +// API_AND_CONFIG_MAP hybrid) must be rejected with InvalidParameterException. +func TestValidateCreateClusterInput_RejectsConfigMapAuthMode(t *testing.T) { + in := createInput("alpha") + in.AccessConfig = &eks.CreateAccessConfigRequest{ + AuthenticationMode: aws.String(eks.AuthenticationModeConfigMap), + } + err := validateCreateClusterInput(in) + require.EqualError(t, err, awserrors.ErrorInvalidParameter) +} + +func TestValidateCreateClusterInput_AcceptsAPIAuthMode(t *testing.T) { + in := createInput("alpha") + in.AccessConfig = &eks.CreateAccessConfigRequest{ + AuthenticationMode: aws.String(eks.AuthenticationModeApi), + } + require.NoError(t, validateCreateClusterInput(in)) +} + +// A create request with no subnets is malformed and must be rejected before any +// orchestration work (InvalidParameterValue → 400). +func TestValidateCreateClusterInput_RejectsMissingSubnetIds(t *testing.T) { + in := createInput("alpha") + in.ResourcesVpcConfig = &eks.VpcConfigRequest{} + require.EqualError(t, validateCreateClusterInput(in), awserrors.ErrorInvalidParameterValue) + + in.ResourcesVpcConfig = nil + require.EqualError(t, validateCreateClusterInput(in), awserrors.ErrorInvalidParameterValue) +} + +// DescribeCluster on an absent cluster must reach the KV lookup (full deps +// wired, unlike the shim short-circuit) and surface ResourceNotFoundException. +func TestDescribeCluster_NotFoundWithFullDeps(t *testing.T) { + f := newEKSServiceFixture(t) + + _, err := f.svc.DescribeCluster(&eks.DescribeClusterInput{Name: aws.String("ghost")}, testAccountID) + require.EqualError(t, err, awserrors.ErrorEKSResourceNotFound) +} + +// Security guarantee: the OIDC signing key must be zeroized BEFORE infra +// teardown, so a teardown failure (which leaves the meta for retry) can never +// leave recoverable key material behind. Force VM terminate to fail and assert +// the key is already gone while the meta survives. +func TestDeleteCluster_ZeroizesOIDCKeyBeforeTeardown(t *testing.T) { + f := newDeleteClusterFixture(t, "alpha") + f.inst.terminateErr = errors.New("hypervisor unreachable") + + _, err := f.svc.DeleteCluster(deleteInput("alpha"), testAccountID) + require.Error(t, err, "teardown failure must surface") + + _, getErr := f.kv.Get(OIDCSigningKeyKey("alpha")) + assert.ErrorIs(t, getErr, nats.ErrKeyNotFound, "OIDC key must be zeroized before teardown, even when teardown fails") + + meta, metaErr := GetClusterMeta(f.kv, "alpha") + require.NoError(t, metaErr, "meta must survive a failed teardown for retry") + assert.Equal(t, ClusterStatusDeleting, meta.Status) } func TestEKSServiceImpl_NodegroupMethodsReturnNotImplemented(t *testing.T) { diff --git a/spinifex/handlers/eks/store.go b/spinifex/handlers/eks/store.go index b67aad680..2e4048e78 100644 --- a/spinifex/handlers/eks/store.go +++ b/spinifex/handlers/eks/store.go @@ -74,6 +74,15 @@ func OIDCJWKSKey(cluster string) string { return fmt.Sprintf("clusters/%s/oidc-jwks.json", cluster) } +// OIDCJWKSVerifiedKey returns the KV key marking that the K3s-VM-published JWKS +// passed the controller cross-check (kid + kty match the controller-generated +// keypair). The reconciler gates the ACTIVE transition on this marker, NOT on +// OIDCJWKSKey — the controller pre-seeds OIDCJWKSKey at create time, so its +// presence proves nothing about the running cluster's actual signing key. +func OIDCJWKSVerifiedKey(cluster string) string { + return fmt.Sprintf("clusters/%s/oidc-jwks-verified", cluster) +} + // AdminKubeconfigKey returns the KV key for a cluster's encrypted admin // kubeconfig (used by the spinifex-side nodegroup reconciler). func AdminKubeconfigKey(cluster string) string { diff --git a/spinifex/handlers/elbv2/launcher.go b/spinifex/handlers/elbv2/launcher.go index 3ca9b6e8b..26d65c184 100644 --- a/spinifex/handlers/elbv2/launcher.go +++ b/spinifex/handlers/elbv2/launcher.go @@ -1,112 +1,17 @@ package handlers_elbv2 -// SystemInstanceLauncher is the subset of daemon functionality needed by -// ELBv2 to launch and terminate system-managed VMs (e.g. ALB VMs). -// Defined here to avoid a circular import between handlers/elbv2 and daemon. -// -// System instances are owned by the system account and hidden from -// customer DescribeInstances calls. -type SystemInstanceLauncher interface { - // LaunchSystemInstance creates and starts a system-managed VM. - // The VM is assigned to the system account and not visible to customers. - // The caller provides the instance type, AMI, subnet, user data, and - // optionally a pre-created ENI to attach. - // - // Returns the instance ID and private IP once the VM is running. - LaunchSystemInstance(input *SystemInstanceInput) (*SystemInstanceOutput, error) +import "github.com/mulgadc/spinifex/spinifex/handlers/sysinstance" - // TerminateSystemInstance stops and cleans up a system-managed VM. - TerminateSystemInstance(instanceID string) error -} - -// SystemInstanceInput describes the direct-boot microVM to launch for an -// ELBv2 load balancer. There is no AMI or cloud-init path — kernel and -// initrd come from the bundled spinifex package and per-VM config is -// delivered via QEMU fw_cfg blobs. -// -// JSON tags are explicit because this struct crosses the -// system.LaunchInstance.* NATS subject root when ELBv2 hands a launch off -// to the cluster — see daemon/daemon_system_dispatch.go. -type SystemInstanceInput struct { - InstanceType string `json:"instance_type"` // e.g. "sys.micro" - SubnetID string `json:"subnet_id"` // VPC subnet for networking - - // ENI fields — the VM always uses a pre-created ENI (the ALB's primary ENI). - ENIID string `json:"eni_id"` - ENIMac string `json:"eni_mac"` - ENIIP string `json:"eni_ip"` - - // ExtraENIs lists additional pre-created ENIs that should be attached to - // the VM alongside the primary ENI. Used for multi-subnet ALBs so the VM - // has a NIC (and tap on br-int) in every subnet the LB spans. - ExtraENIs []ExtraENIInput `json:"extra_enis,omitempty"` - - // Scheme is the ALB scheme ("internet-facing" or "internal"). - // Internet-facing ALBs get a public IP and NAT rules; internal ALBs do not. - Scheme string `json:"scheme"` - - // AccountID is the owner account of the ALB's ENI. Required so the daemon - // can look up and update the ENI record (which is keyed by account). - AccountID string `json:"account_id"` - - // HostfwdPorts specifies additional guest ports to forward from the host - // via the QEMU user-mode dev NIC (dev_networking mode only). - // Each entry is a guest port (e.g. 80, 443). The host port is auto-assigned. - HostfwdPorts []int `json:"hostfwd_ports,omitempty"` - - // NICs defines the network interfaces for the microVM. - // Index 0 is the primary VPC ENI, index 1 is the management NIC, index 2+ are extra ENIs. - NICs []NICConfig `json:"nics,omitempty"` - - // LBAgentEnv is a KEY=value blob written to /etc/conf.d/lb-agent inside - // the guest via fw_cfg. - LBAgentEnv string `json:"lb_agent_env"` - - // CACert holds PEM-encoded CA certificate bytes delivered to the guest via fw_cfg. - CACert string `json:"ca_cert"` -} - -// ExtraENIInput describes an additional pre-created ENI to attach to a -// system instance. The primary ENI is still passed via ENIID/ENIMac/ENIIP. -type ExtraENIInput struct { - ENIID string `json:"eni_id"` - ENIMac string `json:"eni_mac"` - ENIIP string `json:"eni_ip"` - SubnetID string `json:"subnet_id"` -} - -// NICConfig describes a single network interface for a microVM direct-boot launch. -// Index 0 is the primary VPC ENI, index 1 is the management NIC, index 2+ are extra ENIs. -type NICConfig struct { - MAC string `json:"mac"` // e.g. "02:0a:01:23:45:67" - CIDR string `json:"cidr"` // e.g. "10.0.1.5/24" - Gateway string `json:"gateway,omitempty"` // e.g. "10.0.1.1"; empty for mgmt NIC - IsDefault bool `json:"is_default"` // true for exactly one NIC (primary VPC ENI) - RouteDst string `json:"route_dst,omitempty"` // specific host route dst, e.g. "10.20.0.5/32" - RouteVia string `json:"route_via,omitempty"` // next-hop for RouteDst -} - -// RecoveryContext carries the per-VM fields the ELBv2 service needs to -// reconstruct a SystemInstanceInput during host-reboot recovery, without -// importing the vm package (which would cycle back through daemon). -// MgmtMAC / MgmtIP are the values the daemon already allocated for this -// instance on a prior launch; the service injects them back into NIC[1] -// rather than re-allocating from the mgmt IPAM. -type RecoveryContext struct { - InstanceID string - InstanceType string - ENIMac string - MgmtMAC string - MgmtIP string -} - -// SystemInstanceOutput contains the result of a successful launch. -type SystemInstanceOutput struct { - InstanceID string `json:"instance_id"` // e.g. "i-xxxxx" - PrivateIP string `json:"private_ip"` // VPC private IP - PublicIP string `json:"public_ip,omitempty"` // Public IP (only for internet-facing scheme) - - // HostfwdMap maps guest port → host port for any forwarded ports. - // Only populated when dev_networking is enabled and HostfwdPorts were requested. - HostfwdMap map[int]int `json:"hostfwd_map,omitempty"` -} +// The system-instance launch contract now lives in the boot-agnostic +// handlers/sysinstance package so both ELBv2 and EKS can launch system VMs +// without an eks→elbv2 dependency. These aliases keep existing ELBv2 source +// (which builds direct-boot microVM inputs) compiling unchanged. ELBv2 always +// launches with BootMode=BootDirect (the zero value). +type ( + SystemInstanceLauncher = sysinstance.SystemInstanceLauncher + SystemInstanceInput = sysinstance.SystemInstanceInput + ExtraENIInput = sysinstance.ExtraENIInput + NICConfig = sysinstance.NICConfig + RecoveryContext = sysinstance.RecoveryContext + SystemInstanceOutput = sysinstance.SystemInstanceOutput +) diff --git a/spinifex/handlers/sts/assume_role_with_web_identity_test.go b/spinifex/handlers/sts/assume_role_with_web_identity_test.go index 367aec23e..5669d1257 100644 --- a/spinifex/handlers/sts/assume_role_with_web_identity_test.go +++ b/spinifex/handlers/sts/assume_role_with_web_identity_test.go @@ -56,8 +56,8 @@ func newWebIdentityFixture(t *testing.T, svc *STSServiceImpl, accountID string) Y: base64.RawURLEncoding.EncodeToString(priv.Y.Bytes()), }}} - issuer := fmt.Sprintf("https://oidc.eks.%s.%s/%s/%s", - testWebRegion, testWebSuffix, accountID, testWebClusterName) + issuer := fmt.Sprintf("https://gw.%s/oidc/eks/%s/%s/%s", + testWebSuffix, testWebRegion, accountID, testWebClusterName) issuerHostPath := strings.TrimPrefix(issuer, "https://") federatedARN := handlers_iam.OIDCProviderARN(accountID, issuerHostPath) @@ -346,8 +346,8 @@ func TestAssumeRoleWithWebIdentity_ProviderNotRegistered(t *testing.T) { priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) require.NoError(t, err) const kid = "unregistered" - issuer := fmt.Sprintf("https://oidc.eks.%s.%s/%s/%s", - testWebRegion, testWebSuffix, testCallerAccountID, "unregistered-cluster") + issuer := fmt.Sprintf("https://gw.%s/oidc/eks/%s/%s/%s", + testWebSuffix, testWebRegion, testCallerAccountID, "unregistered-cluster") issuerHostPath := strings.TrimPrefix(issuer, "https://") federatedARN := handlers_iam.OIDCProviderARN(testCallerAccountID, issuerHostPath) diff --git a/spinifex/handlers/sts/oidc_jwks.go b/spinifex/handlers/sts/oidc_jwks.go index 32bddb6a5..175b745cd 100644 --- a/spinifex/handlers/sts/oidc_jwks.go +++ b/spinifex/handlers/sts/oidc_jwks.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net/url" + "slices" "strings" handlers_eks "github.com/mulgadc/spinifex/spinifex/handlers/eks" @@ -47,15 +48,34 @@ func (s *JWKS) FindByKID(kid string) *JWK { return nil } -// ParseEKSIssuerURL extracts the (accountID, clusterName) pair encoded in an -// EKS OIDC issuer URL of the form: +// eksIssuerPathSegments is the fixed path layout of a spinifex EKS OIDC issuer: // -// https://oidc.eks.{region}.{suffix}/{accountID}/{clusterName} +// oidc / eks / {region} / {accountID} / {clusterName} +const ( + eksIssuerPathSegments = 5 + eksIssuerSegOIDC = 0 + eksIssuerSegEKS = 1 + eksIssuerSegRegion = 2 + eksIssuerSegAccountID = 3 + eksIssuerSegCluster = 4 +) + +// ParseEKSIssuerURL extracts the (accountID, clusterName) pair encoded in a +// spinifex EKS OIDC issuer URL of the form: // -// Returns an error for any URL that does not match that exact two-segment -// path structure under an `oidc.eks.` host prefix — defensive parsing prevents -// a maliciously crafted `iss` claim from steering the JWKS lookup at an -// attacker-controlled cluster bucket. +// https://{gateway-host}/oidc/eks/{region}/{accountID}/{clusterName} +// +// This matches the URL ClusterOIDCIssuer (handlers/eks) emits and that awsgw +// serves /.well-known/openid-configuration + /keys under. The host is the +// awsgw gateway (an IP:port on bare-metal/on-prem, not an `oidc.eks.*` vhost), +// so host trust is established by the IAM OIDC-provider registration — the full +// issuer string is the registry key in verifyOIDCProviderRegistered — and by +// the JWKS signature check, not by a host name pattern. +// +// Returns an error for any URL that does not match this exact 5-segment path +// structure: defensive parsing pins accountID and clusterName at fixed +// positions so a maliciously crafted `iss` claim cannot steer the JWKS lookup +// at a different cluster bucket. func ParseEKSIssuerURL(issuer string) (accountID, clusterName string, err error) { u, err := url.Parse(issuer) if err != nil { @@ -64,14 +84,18 @@ func ParseEKSIssuerURL(issuer string) (accountID, clusterName string, err error) if u.Scheme != "https" { return "", "", errors.New("issuer URL must use https scheme") } - if !strings.HasPrefix(u.Host, "oidc.eks.") { - return "", "", errors.New("issuer host must start with oidc.eks") + if u.Host == "" { + return "", "", errors.New("issuer URL missing host") } segments := strings.Split(strings.Trim(u.Path, "/"), "/") - if len(segments) != 2 || segments[0] == "" || segments[1] == "" { - return "", "", errors.New("issuer path must be /{accountID}/{clusterName}") + if len(segments) != eksIssuerPathSegments || + segments[eksIssuerSegOIDC] != "oidc" || segments[eksIssuerSegEKS] != "eks" { + return "", "", errors.New("issuer path must be /oidc/eks/{region}/{accountID}/{clusterName}") } - return segments[0], segments[1], nil + if slices.Contains(segments, "") { + return "", "", errors.New("issuer path has empty segment") + } + return segments[eksIssuerSegAccountID], segments[eksIssuerSegCluster], nil } // FetchClusterJWKS reads the JWKS document for an EKS cluster from the diff --git a/spinifex/handlers/sts/oidc_jwks_test.go b/spinifex/handlers/sts/oidc_jwks_test.go index d3a465861..c4ec3b5e4 100644 --- a/spinifex/handlers/sts/oidc_jwks_test.go +++ b/spinifex/handlers/sts/oidc_jwks_test.go @@ -12,7 +12,20 @@ import ( ) func TestParseEKSIssuerURL_Valid(t *testing.T) { - accountID, clusterName, err := ParseEKSIssuerURL("https://oidc.eks.au-mel-1.mulga.local/123456789012/my-cluster") + accountID, clusterName, err := ParseEKSIssuerURL("https://10.0.0.1:9999/oidc/eks/au-mel-1/123456789012/my-cluster") + require.NoError(t, err) + assert.Equal(t, "123456789012", accountID) + assert.Equal(t, "my-cluster", clusterName) +} + +// Cross-component contract: a token whose iss is built by ClusterOIDCIssuer +// must parse cleanly via ParseEKSIssuerURL and resolve to the same +// (accountID, clusterName). This is the collision that bead 165.11 fixes. +func TestParseEKSIssuerURL_RoundTripsClusterOIDCIssuer(t *testing.T) { + issuer, err := handlers_eks.ClusterOIDCIssuer("https://10.0.0.1:9999", "au-mel-1", "123456789012", "my-cluster") + require.NoError(t, err) + + accountID, clusterName, err := ParseEKSIssuerURL(issuer) require.NoError(t, err) assert.Equal(t, "123456789012", accountID) assert.Equal(t, "my-cluster", clusterName) @@ -23,13 +36,15 @@ func TestParseEKSIssuerURL_Invalid(t *testing.T) { name string issuer string }{ - {"http scheme", "http://oidc.eks.au-mel-1.mulga.local/123456789012/c1"}, - {"wrong host prefix", "https://attacker.example.com/123456789012/c1"}, - {"single segment", "https://oidc.eks.au-mel-1.mulga.local/123456789012"}, - {"three segments", "https://oidc.eks.au-mel-1.mulga.local/123/c/extra"}, - {"empty cluster segment", "https://oidc.eks.au-mel-1.mulga.local/123456789012/"}, - {"empty account segment", "https://oidc.eks.au-mel-1.mulga.local//c1"}, - {"empty path", "https://oidc.eks.au-mel-1.mulga.local"}, + {"http scheme", "http://10.0.0.1:9999/oidc/eks/au-mel-1/123456789012/c1"}, + {"missing host", "https:///oidc/eks/au-mel-1/123456789012/c1"}, + {"wrong path prefix", "https://10.0.0.1:9999/foo/eks/au-mel-1/123456789012/c1"}, + {"too few segments", "https://10.0.0.1:9999/oidc/eks/au-mel-1/123456789012"}, + {"too many segments", "https://10.0.0.1:9999/oidc/eks/au-mel-1/123456789012/c1/extra"}, + {"empty account segment", "https://10.0.0.1:9999/oidc/eks/au-mel-1//c1"}, + {"empty cluster segment", "https://10.0.0.1:9999/oidc/eks/au-mel-1/123456789012/"}, + {"empty path", "https://10.0.0.1:9999"}, + {"legacy aws two-segment shape", "https://oidc.eks.au-mel-1.mulga.local/123456789012/c1"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { diff --git a/spinifex/handlers/sysinstance/launcher.go b/spinifex/handlers/sysinstance/launcher.go new file mode 100644 index 000000000..7b20ee677 --- /dev/null +++ b/spinifex/handlers/sysinstance/launcher.go @@ -0,0 +1,155 @@ +// Package sysinstance holds the boot-agnostic contract for launching +// system-managed VMs. A system instance is owned by the system account and +// hidden from customer DescribeInstances calls. Two boot styles are supported: +// +// - BootDirect: a direct-boot microVM (bundled vmlinuz+initramfs, per-VM +// config delivered via QEMU fw_cfg blobs; no AMI, volume, or cloud-init). +// Used by the ELBv2 LB agent. +// - BootAMI: a full AMI boot (root volume cloned from an AMI, cloud-init +// user-data + network-config seed, q35 machine). Used by the EKS K3s +// control-plane VM. +// +// The types live here (not in handlers/elbv2) so both ELBv2 and EKS can launch +// system instances without an eks→elbv2 dependency. handlers/elbv2 re-exports +// them as type aliases for source compatibility. +package sysinstance + +import "errors" + +// ErrSystemInstanceNotFound is returned by TerminateSystemInstance when the +// target instance is unknown to the daemon — already terminated, or never +// present on this node. Teardown callers treat it as idempotent success so a +// retried delete (e.g. EKS DeleteCluster after the VM already drained) does not +// wedge forever on a VM that is legitimately gone. +var ErrSystemInstanceNotFound = errors.New("sysinstance: instance not found") + +// BootMode selects how a system instance boots. +type BootMode string + +const ( + // BootDirect is the direct-boot microVM path (fw_cfg-delivered config). + BootDirect BootMode = "direct" + // BootAMI is the AMI + cloud-init path (root volume + seed ISO). + BootAMI BootMode = "ami" +) + +// SystemInstanceLauncher is the subset of daemon functionality needed to launch +// and terminate system-managed VMs. Defined here to avoid a circular import +// between the launching handlers (elbv2, eks) and daemon. +type SystemInstanceLauncher interface { + // LaunchSystemInstance creates and starts a system-managed VM. The VM is + // assigned to the system account and not visible to customers. Returns the + // instance ID and private IP once the VM is running. + LaunchSystemInstance(input *SystemInstanceInput) (*SystemInstanceOutput, error) + + // TerminateSystemInstance stops and cleans up a system-managed VM. + TerminateSystemInstance(instanceID string) error +} + +// SystemInstanceInput describes a system VM to launch. The BootMode field +// selects which subset of fields is consumed: +// +// - BootDirect uses NICs, LBAgentEnv, CACert (fw_cfg blobs); ImageID/UserData +// are ignored. +// - BootAMI uses ImageID and UserData (cloud-init); NICs/LBAgentEnv/CACert are +// ignored. The mgmt NIC is allocated by the daemon and rendered into the +// cloud-init network-config from the VM record. +// +// JSON tags are explicit because this struct crosses the +// system.LaunchInstance.* NATS subject root when a launch is handed off to the +// cluster — see daemon/daemon_system_dispatch.go. +type SystemInstanceInput struct { + // BootMode selects the boot style. Empty defaults to BootDirect for + // backward compatibility with the original ELBv2-only contract. + BootMode BootMode `json:"boot_mode,omitempty"` + + // ManagedBy is the spinifex:managed-by tag value stamped on the instance so + // the UI/customer listings hide it (e.g. "elbv2", "eks"). + ManagedBy string `json:"managed_by,omitempty"` + + InstanceType string `json:"instance_type"` // e.g. "sys.micro" + SubnetID string `json:"subnet_id"` // VPC subnet for networking + + // ENI fields — the VM always uses a pre-created ENI (the primary ENI). + ENIID string `json:"eni_id"` + ENIMac string `json:"eni_mac"` + ENIIP string `json:"eni_ip"` + + // ExtraENIs lists additional pre-created ENIs to attach alongside the + // primary ENI (e.g. multi-subnet ALBs). + ExtraENIs []ExtraENIInput `json:"extra_enis,omitempty"` + + // Scheme is the ALB scheme ("internet-facing" or "internal"). BootDirect + // only; ignored for BootAMI. + Scheme string `json:"scheme,omitempty"` + + // AccountID is the owner account of the primary ENI. Required so the daemon + // can look up and update the ENI record (which is keyed by account). + AccountID string `json:"account_id"` + + // HostfwdPorts forwards additional guest ports from the host via the QEMU + // user-mode dev NIC (dev_networking mode only). + HostfwdPorts []int `json:"hostfwd_ports,omitempty"` + + // NICs defines the network interfaces for a BootDirect microVM. Index 0 is + // the primary VPC ENI, index 1 the mgmt NIC, index 2+ extra ENIs. + NICs []NICConfig `json:"nics,omitempty"` + + // LBAgentEnv is a KEY=value blob written to /etc/conf.d/lb-agent inside a + // BootDirect guest via fw_cfg. + LBAgentEnv string `json:"lb_agent_env,omitempty"` + + // CACert holds PEM CA bytes delivered to a BootDirect guest via fw_cfg. + CACert string `json:"ca_cert,omitempty"` + + // ImageID is the AMI to clone the root volume from (BootAMI only). + ImageID string `json:"image_id,omitempty"` + + // UserData is the raw (un-encoded) cloud-init user-data for a BootAMI guest. + // The launcher base64-encodes it for the RunInstances path. + UserData string `json:"user_data,omitempty"` +} + +// ExtraENIInput describes an additional pre-created ENI to attach to a system +// instance. The primary ENI is still passed via ENIID/ENIMac/ENIIP. +type ExtraENIInput struct { + ENIID string `json:"eni_id"` + ENIMac string `json:"eni_mac"` + ENIIP string `json:"eni_ip"` + SubnetID string `json:"subnet_id"` +} + +// NICConfig describes a single network interface for a BootDirect microVM. +// Index 0 is the primary VPC ENI, index 1 the management NIC, index 2+ extra. +type NICConfig struct { + MAC string `json:"mac"` // e.g. "02:0a:01:23:45:67" + CIDR string `json:"cidr"` // e.g. "10.0.1.5/24" + Gateway string `json:"gateway,omitempty"` // e.g. "10.0.1.1"; empty for mgmt NIC + IsDefault bool `json:"is_default"` // true for exactly one NIC (primary VPC ENI) + RouteDst string `json:"route_dst,omitempty"` // specific host route dst, e.g. "10.20.0.5/32" + RouteVia string `json:"route_via,omitempty"` // next-hop for RouteDst +} + +// RecoveryContext carries the per-VM fields needed to reconstruct a +// SystemInstanceInput during host-reboot recovery without importing the vm +// package. MgmtMAC / MgmtIP are the values the daemon already allocated on a +// prior launch; the service injects them back into NIC[1] rather than +// re-allocating from the mgmt IPAM. +type RecoveryContext struct { + InstanceID string + InstanceType string + ENIMac string + MgmtMAC string + MgmtIP string +} + +// SystemInstanceOutput contains the result of a successful launch. +type SystemInstanceOutput struct { + InstanceID string `json:"instance_id"` // e.g. "i-xxxxx" + PrivateIP string `json:"private_ip"` // VPC private IP + PublicIP string `json:"public_ip,omitempty"` // only for internet-facing scheme + MgmtIP string `json:"mgmt_ip,omitempty"` // br-mgmt NIC IP, reachable from the host + + // HostfwdMap maps guest port → host port for any forwarded ports. + HostfwdMap map[int]int `json:"hostfwd_map,omitempty"` +} diff --git a/spinifex/network/external/igw.go b/spinifex/network/external/igw.go index 7c9375ae9..1f2d5c351 100644 --- a/spinifex/network/external/igw.go +++ b/spinifex/network/external/igw.go @@ -47,6 +47,15 @@ type IGWManager interface { EnsureSubnetEgressDrop(ctx context.Context, vpcID, subnetID string, prefix netip.Prefix) error // RemoveSubnetEgressDrop is the inverse. Idempotent. RemoveSubnetEgressDrop(ctx context.Context, vpcID, subnetID string, prefix netip.Prefix) error + // EnsureSystemInstanceEgress wires egress-only internet access for a + // single system instance (e.g. an EKS K3s server VM) sourced from + // instanceIP in subnetID, SNAT'd to externalIP. Installs a /32 reroute + // policy at SystemInstanceEgressPriority (above the drop gate so it works + // even on a drop-gated subnet) plus a plain snat (no DNAT, no inbound). + // Requires AttachIGW to have run first. Idempotent. + EnsureSystemInstanceEgress(ctx context.Context, vpcID, subnetID, instanceIP, externalIP string) error + // RemoveSystemInstanceEgress is the inverse. Idempotent. + RemoveSystemInstanceEgress(ctx context.Context, vpcID, subnetID, instanceIP, externalIP string) error } // IGWManagerConfig is the construction-time bag for igwManager. @@ -356,12 +365,75 @@ func (m *igwManager) ensureSubnetEgressAtPriority(ctx context.Context, vpcID, su }) } +// EnsureSystemInstanceEgress installs an egress-only path for one system +// instance: a /32 reroute policy out the gateway port plus a plain snat +// (instanceIP -> externalIP). The reroute sits above the subnet drop gate so +// it works even where the instance's subnet is otherwise private; where the +// subnet already has a 1000 reroute it is harmless (same nexthop). The snat is +// not dnat_and_snat, so the instance is never reachable inbound. +func (m *igwManager) EnsureSystemInstanceEgress(ctx context.Context, vpcID, subnetID, instanceIP, externalIP string) error { + if vpcID == "" || subnetID == "" { + return errors.New("EnsureSystemInstanceEgress: vpcID and subnetID required") + } + srcIP, err := netip.ParseAddr(instanceIP) + if err != nil { + return fmt.Errorf("EnsureSystemInstanceEgress: parse instance IP %q: %w", instanceIP, err) + } + if externalIP == "" { + return errors.New("EnsureSystemInstanceEgress: externalIP required") + } + + _, nexthop, _, err := m.resolveGatewayNetwork(ctx, vpcID) + if err != nil { + return fmt.Errorf("resolve gateway network for %s: %w", vpcID, err) + } + if nexthop == "" { + return fmt.Errorf("EnsureSystemInstanceEgress: no gateway nexthop for %s (IGW not attached?)", vpcID) + } + + if err := m.routes.AddSystemInstanceEgress(ctx, vpcID, policy.SystemInstanceEgressSpec{ + SubnetID: subnetID, + SrcIP: srcIP, + Prefix: defaultRoutePrefix, + Nexthop: nexthop, + OutputPort: topology.GatewayRouterPort(vpcID), + ExcludeCIDRs: m.vpcExcludeCIDRs(ctx, vpcID), + }); err != nil { + return fmt.Errorf("add system instance egress reroute: %w", err) + } + if err := m.nat.AddSystemInstanceSNAT(ctx, vpcID, instanceIP+"/32", externalIP); err != nil { + return fmt.Errorf("add system instance egress snat: %w", err) + } + return nil +} + +// RemoveSystemInstanceEgress deletes the policy + snat installed by +// EnsureSystemInstanceEgress. Idempotent. +func (m *igwManager) RemoveSystemInstanceEgress(ctx context.Context, vpcID, subnetID, instanceIP, externalIP string) error { + if vpcID == "" || subnetID == "" { + return errors.New("RemoveSystemInstanceEgress: vpcID and subnetID required") + } + srcIP, err := netip.ParseAddr(instanceIP) + if err != nil { + return fmt.Errorf("RemoveSystemInstanceEgress: parse instance IP %q: %w", instanceIP, err) + } + var firstErr error + if err := m.routes.DeleteSystemInstanceEgress(ctx, vpcID, subnetID, srcIP, defaultRoutePrefix, m.vpcExcludeCIDRs(ctx, vpcID)); err != nil { + firstErr = fmt.Errorf("delete system instance egress reroute: %w", err) + } + if err := m.nat.DeleteSystemInstanceSNAT(ctx, vpcID, instanceIP+"/32"); err != nil && firstErr == nil { + firstErr = fmt.Errorf("delete system instance egress snat: %w", err) + } + return firstErr +} + // linkLocalCIDR / multicastCIDR are appended to drop-policy excludes so // link-local (DHCP, metadata, 169.254.169.254) and multicast destinations // are not killed by the per-subnet gate. var ( - linkLocalCIDR = netip.MustParsePrefix("169.254.0.0/16") - multicastCIDR = netip.MustParsePrefix("224.0.0.0/4") + linkLocalCIDR = netip.MustParsePrefix("169.254.0.0/16") + multicastCIDR = netip.MustParsePrefix("224.0.0.0/4") + defaultRoutePrefix = netip.MustParsePrefix("0.0.0.0/0") ) // dropExcludeCIDRs returns the exclusion list for a per-subnet drop policy: diff --git a/spinifex/network/external/igw_test.go b/spinifex/network/external/igw_test.go index 1a6802ded..1e46e85d9 100644 --- a/spinifex/network/external/igw_test.go +++ b/spinifex/network/external/igw_test.go @@ -375,6 +375,114 @@ func TestRemoveNATGatewaySubnetEgress_PropagatesDeleteError(t *testing.T) { require.Error(t, err) } +// TestEnsureSystemInstanceEgress installs the /32 reroute plus the snat-only +// NAT, and asserts no inbound dnat_and_snat row exists (egress-only). +func TestEnsureSystemInstanceEgress(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedVPCRouter(t, m, "vpc-1", "10.0.0.0/16") + pool := &ExternalPoolConfig{Name: "p", Gateway: "192.168.1.1", PrefixLen: 24} + mgr, _ := newTestIGWManager(t, m, policy.NATModeDistributed, pool, LinkLocalAllocator{}, []string{"chassis-a"}) + + require.NoError(t, mgr.AttachIGW(ctx, IGWSpec{VPCID: "vpc-1", InternetGatewayID: "igw-1"})) + require.NoError(t, mgr.EnsureSystemInstanceEgress(ctx, "vpc-1", "subnet-k3s", "10.0.4.10", "203.0.113.7")) + + policies, err := m.ListLogicalRouterPolicies(ctx, topology.VPCRouter("vpc-1")) + require.NoError(t, err) + require.Len(t, policies, 1) + assert.Equal(t, policy.SystemInstanceEgressPriority, policies[0].Priority) + assert.Contains(t, policies[0].Match, "ip4.src == 10.0.4.10/32") + + var snat, dnat *nbdb.NAT + for _, n := range m.NATs { + switch n.Type { + case "snat": + snat = n + case "dnat_and_snat": + dnat = n + } + } + require.NotNil(t, snat, "egress snat must be installed") + assert.Equal(t, "203.0.113.7", snat.ExternalIP) + assert.Equal(t, "10.0.4.10/32", snat.LogicalIP) + assert.Nil(t, dnat, "egress-only: no inbound dnat_and_snat may be installed") +} + +// TestEnsureSystemInstanceEgress_IsIdempotent re-runs install; row counts stay 1. +func TestEnsureSystemInstanceEgress_IsIdempotent(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedVPCRouter(t, m, "vpc-1", "10.0.0.0/16") + pool := &ExternalPoolConfig{Name: "p", Gateway: "192.168.1.1", PrefixLen: 24} + mgr, _ := newTestIGWManager(t, m, policy.NATModeDistributed, pool, LinkLocalAllocator{}, nil) + + require.NoError(t, mgr.AttachIGW(ctx, IGWSpec{VPCID: "vpc-1", InternetGatewayID: "igw-1"})) + require.NoError(t, mgr.EnsureSystemInstanceEgress(ctx, "vpc-1", "subnet-k3s", "10.0.4.10", "203.0.113.7")) + require.NoError(t, mgr.EnsureSystemInstanceEgress(ctx, "vpc-1", "subnet-k3s", "10.0.4.10", "203.0.113.7")) + + policies, err := m.ListLogicalRouterPolicies(ctx, topology.VPCRouter("vpc-1")) + require.NoError(t, err) + assert.Len(t, policies, 1) + snatCount := 0 + for _, n := range m.NATs { + if n.Type == "snat" { + snatCount++ + } + } + assert.Equal(t, 1, snatCount) +} + +// TestRemoveSystemInstanceEgress tears down both the reroute and the snat and +// is idempotent on a second call. +func TestRemoveSystemInstanceEgress(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedVPCRouter(t, m, "vpc-1", "10.0.0.0/16") + pool := &ExternalPoolConfig{Name: "p", Gateway: "192.168.1.1", PrefixLen: 24} + mgr, _ := newTestIGWManager(t, m, policy.NATModeDistributed, pool, LinkLocalAllocator{}, nil) + + require.NoError(t, mgr.AttachIGW(ctx, IGWSpec{VPCID: "vpc-1", InternetGatewayID: "igw-1"})) + require.NoError(t, mgr.EnsureSystemInstanceEgress(ctx, "vpc-1", "subnet-k3s", "10.0.4.10", "203.0.113.7")) + require.NoError(t, mgr.RemoveSystemInstanceEgress(ctx, "vpc-1", "subnet-k3s", "10.0.4.10", "203.0.113.7")) + + policies, err := m.ListLogicalRouterPolicies(ctx, topology.VPCRouter("vpc-1")) + require.NoError(t, err) + assert.Empty(t, policies) + for _, n := range m.NATs { + assert.NotEqual(t, "snat", n.Type, "snat must be removed") + } + + require.NoError(t, mgr.RemoveSystemInstanceEgress(ctx, "vpc-1", "subnet-k3s", "10.0.4.10", "203.0.113.7")) +} + +// TestSystemInstanceEgress_RejectsBadArgs guards validation for malformed events. +func TestSystemInstanceEgress_RejectsBadArgs(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedVPCRouter(t, m, "vpc-1", "10.0.0.0/16") + pool := &ExternalPoolConfig{Name: "p", Gateway: "192.168.1.1", PrefixLen: 24} + mgr, _ := newTestIGWManager(t, m, policy.NATModeDistributed, pool, LinkLocalAllocator{}, nil) + require.NoError(t, mgr.AttachIGW(ctx, IGWSpec{VPCID: "vpc-1", InternetGatewayID: "igw-1"})) + + require.Error(t, mgr.EnsureSystemInstanceEgress(ctx, "", "subnet-k3s", "10.0.4.10", "203.0.113.7")) + require.Error(t, mgr.EnsureSystemInstanceEgress(ctx, "vpc-1", "", "10.0.4.10", "203.0.113.7")) + require.Error(t, mgr.EnsureSystemInstanceEgress(ctx, "vpc-1", "subnet-k3s", "not-an-ip", "203.0.113.7")) + require.Error(t, mgr.EnsureSystemInstanceEgress(ctx, "vpc-1", "subnet-k3s", "10.0.4.10", "")) +} + +// TestEnsureSystemInstanceEgress_RequiresAttachedIGW asserts a clear error when +// no gateway nexthop exists — without it the reroute would be unreachable. +func TestEnsureSystemInstanceEgress_RequiresAttachedIGW(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedVPCRouter(t, m, "vpc-1", "10.0.0.0/16") + pool := &ExternalPoolConfig{Name: "p", PrefixLen: 24} // no Gateway → no centralized nexthop + mgr, _ := newTestIGWManager(t, m, policy.NATModeCentralized, pool, failingAllocator{}, nil) + + err := mgr.EnsureSystemInstanceEgress(ctx, "vpc-1", "subnet-k3s", "10.0.4.10", "203.0.113.7") + require.Error(t, err) +} + // TestRemoveSubnetEgress_RejectsEmptyArgs covers the IGW-priority sibling of // the NATGW empty-arg guard. Both vpcID and subnetID are mandatory. func TestRemoveSubnetEgress_RejectsEmptyArgs(t *testing.T) { diff --git a/spinifex/network/policy/nat.go b/spinifex/network/policy/nat.go index dd6d82993..3d7a71110 100644 --- a/spinifex/network/policy/nat.go +++ b/spinifex/network/policy/nat.go @@ -51,6 +51,16 @@ type NATManager interface { // DeleteSNAT removes the IGW default-outbound snat for vpcCIDR. DeleteSNAT(ctx context.Context, vpcID, vpcCIDR string) error + + // AddSystemInstanceSNAT installs an egress-only snat rewriting a single + // system instance's /32 (logicalIP) to externalIP. Unlike AddEIP it is a + // plain snat, not dnat_and_snat, so there is no inbound path to the + // instance. Idempotent; tagged role=system-instance-egress. + AddSystemInstanceSNAT(ctx context.Context, vpcID, logicalIP, externalIP string) error + + // DeleteSystemInstanceSNAT removes the egress-only snat by logicalIP; + // idempotent. + DeleteSystemInstanceSNAT(ctx context.Context, vpcID, logicalIP string) error } // FlowsBarrier blocks until ovn-northd has compiled NB → SB and every @@ -246,3 +256,48 @@ func (m *natManager) DeleteSNAT(ctx context.Context, vpcID, vpcCIDR string) erro } return nil } + +func (m *natManager) AddSystemInstanceSNAT(ctx context.Context, vpcID, logicalIP, externalIP string) error { + router := topology.VPCRouter(vpcID) + snatRule := &nbdb.NAT{ + Type: "snat", + ExternalIP: externalIP, + LogicalIP: logicalIP, + ExternalIDs: map[string]string{ + "spinifex:vpc_id": vpcID, + "spinifex:public_ip": externalIP, + "spinifex:role": "system-instance-egress", + }, + } + // Skip when the existing row already matches; avoids the duplicate-append + // on a re-published add (the snat is keyed by its unique pool external IP). + if existing, err := m.ovn.FindNATByExternalIP(ctx, "snat", externalIP); err != nil { + slog.Warn("policy: AddSystemInstanceSNAT idempotency lookup failed", "external_ip", externalIP, "err", err) + } else if existing != nil && existing.LogicalIP == logicalIP { + slog.Info("policy: AddSystemInstanceSNAT idempotent skip — rule already current", + "router", router, "external_ip", externalIP, "logical_ip", logicalIP) + return nil + } + + if err := m.ovn.AddNAT(ctx, router, snatRule); err != nil { + return fmt.Errorf("add system-instance snat %s -> %s on %s: %w", logicalIP, externalIP, router, err) + } + // Block until SB + chassis have the SNAT flow; otherwise first egress + // packets from the instance drop. + if err := m.barrier(); err != nil { + slog.Warn("policy: AddSystemInstanceSNAT flows barrier failed", + "logical_ip", logicalIP, "external_ip", externalIP, "err", err) + } + return nil +} + +func (m *natManager) DeleteSystemInstanceSNAT(ctx context.Context, vpcID, logicalIP string) error { + router := topology.VPCRouter(vpcID) + if err := m.ovn.DeleteNAT(ctx, router, "snat", logicalIP); err != nil { + if errors.Is(err, ovn.ErrNATNotFound) { + return nil + } + return fmt.Errorf("delete system-instance snat %s on %s: %w", logicalIP, router, err) + } + return nil +} diff --git a/spinifex/network/policy/nat_test.go b/spinifex/network/policy/nat_test.go index 9b065d832..866aea2a3 100644 --- a/spinifex/network/policy/nat_test.go +++ b/spinifex/network/policy/nat_test.go @@ -370,3 +370,23 @@ func TestNATManager_AddSNAT_AndDelete(t *testing.T) { assert.Nil(t, findNAT(m, "snat", "10.0.0.0/16")) require.NoError(t, nm.DeleteSNAT(ctx, "vpc-1", "10.0.0.0/16")) } + +func TestNATManager_AddSystemInstanceSNAT_AndDelete(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedRouter(t, m, "vpc-1") + nm, _ := NewNATManager(m, NATModeDistributed) + + require.NoError(t, nm.AddSystemInstanceSNAT(ctx, "vpc-1", "172.31.4.10/32", "1.2.3.4")) + got := findNAT(m, "snat", "172.31.4.10/32") + require.NotNil(t, got) + assert.Equal(t, "1.2.3.4", got.ExternalIP) + assert.Equal(t, "system-instance-egress", got.ExternalIDs["spinifex:role"]) + // snat-only: no dnat_and_snat row, so the instance stays unreachable inbound. + assert.Nil(t, findNAT(m, "dnat_and_snat", "172.31.4.10/32")) + + require.NoError(t, nm.DeleteSystemInstanceSNAT(ctx, "vpc-1", "172.31.4.10/32")) + assert.Nil(t, findNAT(m, "snat", "172.31.4.10/32")) + // Idempotent on a missing rule. + require.NoError(t, nm.DeleteSystemInstanceSNAT(ctx, "vpc-1", "172.31.4.10/32")) +} diff --git a/spinifex/network/policy/route.go b/spinifex/network/policy/route.go index 7893e8595..fcf5a0fac 100644 --- a/spinifex/network/policy/route.go +++ b/spinifex/network/policy/route.go @@ -24,6 +24,13 @@ const ( SubnetEgressPriorityDrop = 1100 SubnetEgressPriorityIGW = 1000 SubnetEgressPriorityNATGW = 900 + + // SystemInstanceEgressPriority sits above the drop gate (1100) so a single + // system instance (e.g. an EKS K3s server VM) egresses even when its subnet + // is otherwise drop-gated. The policy is scoped to the instance's /32 + // source, so peer instances in the same subnet are unaffected — they still + // hit the 1100 drop (or the subnet's own 1000 reroute where one exists). + SystemInstanceEgressPriority = 1200 ) // RouteSpec is a static route on a VPC's LogicalRouter. OutputPort is @@ -52,6 +59,20 @@ type SubnetEgressSpec struct { ExcludeCIDRs []netip.Prefix } +// SystemInstanceEgressSpec describes a per-instance egress override installed +// as an OVN Logical_Router_Policy at SystemInstanceEgressPriority. The match +// adds an `ip4.src == /32` clause to the subnet-egress shape so the +// reroute is confined to a single system instance; peer instances in the same +// subnet are untouched. Action is "reroute" via Nexthop out OutputPort. +type SystemInstanceEgressSpec struct { + SubnetID string + SrcIP netip.Addr + Prefix netip.Prefix + Nexthop string + OutputPort string + ExcludeCIDRs []netip.Prefix +} + // RouteManager owns static routes on VPC LogicalRouters. Adds are // idempotent (no-op on match, delete-then-add on drift) so the reconciler // can replay safely. @@ -64,6 +85,8 @@ type RouteManager interface { DeleteSubnetEgress(ctx context.Context, vpcID, subnetID string, prefix netip.Prefix, excludeCIDRs []netip.Prefix) error AddSubnetEgressDrop(ctx context.Context, vpcID string, spec SubnetEgressDropSpec) error DeleteSubnetEgressDrop(ctx context.Context, vpcID, subnetID string, prefix netip.Prefix, excludeCIDRs []netip.Prefix) error + AddSystemInstanceEgress(ctx context.Context, vpcID string, spec SystemInstanceEgressSpec) error + DeleteSystemInstanceEgress(ctx context.Context, vpcID, subnetID string, srcIP netip.Addr, prefix netip.Prefix, excludeCIDRs []netip.Prefix) error } // SubnetEgressDropSpec describes a per-subnet egress DROP override installed @@ -263,6 +286,62 @@ func (m *routeManager) DeleteSubnetEgressDrop(ctx context.Context, vpcID, subnet return nil } +func (m *routeManager) AddSystemInstanceEgress(ctx context.Context, vpcID string, spec SystemInstanceEgressSpec) error { + if spec.SubnetID == "" { + return fmt.Errorf("system instance egress: SubnetID required") + } + if !spec.SrcIP.IsValid() { + return fmt.Errorf("system instance egress: SrcIP required") + } + if spec.OutputPort == "" { + return fmt.Errorf("system instance egress: OutputPort required (ovn-northd drops policy reroute otherwise)") + } + router := topology.VPCRouter(vpcID) + match := systemInstanceEgressMatch(spec.SubnetID, spec.SrcIP, spec.Prefix, spec.ExcludeCIDRs) + + existing, err := m.ovn.FindLogicalRouterPolicy(ctx, router, SystemInstanceEgressPriority, match) + if err != nil { + return fmt.Errorf("find LR policy %q on %s: %w", match, router, err) + } + if existing != nil { + if existing.Action == "reroute" && existing.Nexthop != nil && *existing.Nexthop == spec.Nexthop && + existing.ExternalIDs["spinifex:output_port"] == spec.OutputPort { + return nil + } + if err := m.ovn.DeleteLogicalRouterPolicy(ctx, router, SystemInstanceEgressPriority, match); err != nil { + return fmt.Errorf("delete drifted LR policy %q on %s: %w", match, router, err) + } + } + + nexthop := spec.Nexthop + row := &nbdb.LogicalRouterPolicy{ + Priority: SystemInstanceEgressPriority, + Match: match, + Action: "reroute", + Nexthop: &nexthop, + Options: map[string]string{}, + ExternalIDs: map[string]string{ + "spinifex:subnet": spec.SubnetID, + "spinifex:src_ip": spec.SrcIP.String(), + "spinifex:output_port": spec.OutputPort, + "spinifex:role": "system-instance-egress", + }, + } + if err := m.ovn.AddLogicalRouterPolicy(ctx, router, row); err != nil { + return fmt.Errorf("add LR policy %q -> %s on %s: %w", match, spec.Nexthop, router, err) + } + return nil +} + +func (m *routeManager) DeleteSystemInstanceEgress(ctx context.Context, vpcID, subnetID string, srcIP netip.Addr, prefix netip.Prefix, excludeCIDRs []netip.Prefix) error { + router := topology.VPCRouter(vpcID) + match := systemInstanceEgressMatch(subnetID, srcIP, prefix, excludeCIDRs) + if err := m.ovn.DeleteLogicalRouterPolicy(ctx, router, SystemInstanceEgressPriority, match); err != nil { + return fmt.Errorf("delete system instance egress LR policy %q on %s: %w", match, router, err) + } + return nil +} + func subnetEgressMatch(subnetID string, prefix netip.Prefix, excludeCIDRs []netip.Prefix) string { match := fmt.Sprintf(`inport == %q && ip4.dst == %s`, topology.SubnetRouterPort(subnetID), prefix.String()) for _, ex := range excludeCIDRs { @@ -274,6 +353,18 @@ func subnetEgressMatch(subnetID string, prefix netip.Prefix, excludeCIDRs []neti return match } +func systemInstanceEgressMatch(subnetID string, srcIP netip.Addr, prefix netip.Prefix, excludeCIDRs []netip.Prefix) string { + match := fmt.Sprintf(`inport == %q && ip4.src == %s/32 && ip4.dst == %s`, + topology.SubnetRouterPort(subnetID), srcIP.String(), prefix.String()) + for _, ex := range excludeCIDRs { + if !ex.IsValid() { + continue + } + match += fmt.Sprintf(` && ip4.dst != %s`, ex.String()) + } + return match +} + func policyMatches(existing *nbdb.LogicalRouterPolicy, want SubnetEgressSpec) bool { if existing.Action != "reroute" { return false diff --git a/spinifex/network/policy/route_test.go b/spinifex/network/policy/route_test.go index 6fa5a4a33..0ba25dfe0 100644 --- a/spinifex/network/policy/route_test.go +++ b/spinifex/network/policy/route_test.go @@ -131,6 +131,128 @@ func TestRouteManager_AddSubnetEgress_InstallsScopedPolicy(t *testing.T) { assert.Equal(t, "gw-vpc-1", p.ExternalIDs["spinifex:output_port"]) } +func TestRouteManager_AddSystemInstanceEgress_InstallsScopedPolicy(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedRouter(t, m, "vpc-1") + rm := NewRouteManager(m) + + require.NoError(t, rm.AddSystemInstanceEgress(ctx, "vpc-1", SystemInstanceEgressSpec{ + SubnetID: "subnet-k3s", + SrcIP: netip.MustParseAddr("172.31.4.10"), + Prefix: netip.MustParsePrefix("0.0.0.0/0"), + Nexthop: "192.168.1.1", + OutputPort: "gw-vpc-1", + })) + + policies, err := m.ListLogicalRouterPolicies(ctx, topology.VPCRouter("vpc-1")) + require.NoError(t, err) + require.Len(t, policies, 1) + p := policies[0] + assert.Equal(t, "reroute", p.Action) + assert.Equal(t, SystemInstanceEgressPriority, p.Priority) + require.NotNil(t, p.Nexthop) + assert.Equal(t, "192.168.1.1", *p.Nexthop) + // Scoped to the single instance /32 source so peers in the subnet are untouched. + assert.Contains(t, p.Match, "ip4.src == 172.31.4.10/32") + assert.Contains(t, p.Match, topology.SubnetRouterPort("subnet-k3s")) + assert.Equal(t, "172.31.4.10", p.ExternalIDs["spinifex:src_ip"]) + assert.Equal(t, "system-instance-egress", p.ExternalIDs["spinifex:role"]) +} + +func TestRouteManager_AddSystemInstanceEgress_IsIdempotent(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedRouter(t, m, "vpc-1") + rm := NewRouteManager(m) + + spec := SystemInstanceEgressSpec{ + SubnetID: "subnet-k3s", + SrcIP: netip.MustParseAddr("172.31.4.10"), + Prefix: netip.MustParsePrefix("0.0.0.0/0"), + Nexthop: "192.168.1.1", + OutputPort: "gw-vpc-1", + } + require.NoError(t, rm.AddSystemInstanceEgress(ctx, "vpc-1", spec)) + require.NoError(t, rm.AddSystemInstanceEgress(ctx, "vpc-1", spec)) + require.NoError(t, rm.AddSystemInstanceEgress(ctx, "vpc-1", spec)) + + policies, err := m.ListLogicalRouterPolicies(ctx, topology.VPCRouter("vpc-1")) + require.NoError(t, err) + assert.Len(t, policies, 1) +} + +func TestRouteManager_AddSystemInstanceEgress_DriftReplacesNexthop(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedRouter(t, m, "vpc-1") + rm := NewRouteManager(m) + + spec := SystemInstanceEgressSpec{ + SubnetID: "subnet-k3s", + SrcIP: netip.MustParseAddr("172.31.4.10"), + Prefix: netip.MustParsePrefix("0.0.0.0/0"), + Nexthop: "192.168.1.1", + OutputPort: "gw-vpc-1", + } + require.NoError(t, rm.AddSystemInstanceEgress(ctx, "vpc-1", spec)) + spec.Nexthop = "192.168.1.254" + require.NoError(t, rm.AddSystemInstanceEgress(ctx, "vpc-1", spec)) + + policies, err := m.ListLogicalRouterPolicies(ctx, topology.VPCRouter("vpc-1")) + require.NoError(t, err) + require.Len(t, policies, 1) + require.NotNil(t, policies[0].Nexthop) + assert.Equal(t, "192.168.1.254", *policies[0].Nexthop) +} + +func TestRouteManager_AddSystemInstanceEgress_RejectsMissingFields(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedRouter(t, m, "vpc-1") + rm := NewRouteManager(m) + + valid := SystemInstanceEgressSpec{ + SubnetID: "subnet-k3s", + SrcIP: netip.MustParseAddr("172.31.4.10"), + Prefix: netip.MustParsePrefix("0.0.0.0/0"), + Nexthop: "192.168.1.1", + OutputPort: "gw-vpc-1", + } + + noSubnet := valid + noSubnet.SubnetID = "" + assert.Error(t, rm.AddSystemInstanceEgress(ctx, "vpc-1", noSubnet)) + + noSrc := valid + noSrc.SrcIP = netip.Addr{} + assert.Error(t, rm.AddSystemInstanceEgress(ctx, "vpc-1", noSrc)) + + noPort := valid + noPort.OutputPort = "" + assert.Error(t, rm.AddSystemInstanceEgress(ctx, "vpc-1", noPort)) +} + +func TestRouteManager_DeleteSystemInstanceEgress_RemovesAndIdempotent(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedRouter(t, m, "vpc-1") + rm := NewRouteManager(m) + + src := netip.MustParseAddr("172.31.4.10") + prefix := netip.MustParsePrefix("0.0.0.0/0") + require.NoError(t, rm.AddSystemInstanceEgress(ctx, "vpc-1", SystemInstanceEgressSpec{ + SubnetID: "subnet-k3s", SrcIP: src, Prefix: prefix, Nexthop: "192.168.1.1", OutputPort: "gw-vpc-1", + })) + + require.NoError(t, rm.DeleteSystemInstanceEgress(ctx, "vpc-1", "subnet-k3s", src, prefix, nil)) + policies, err := m.ListLogicalRouterPolicies(ctx, topology.VPCRouter("vpc-1")) + require.NoError(t, err) + assert.Empty(t, policies) + // Idempotent on a missing policy. + require.NoError(t, rm.DeleteSystemInstanceEgress(ctx, "vpc-1", "subnet-k3s", src, prefix, nil)) +} + func TestRouteManager_AddSubnetEgress_IsIdempotent(t *testing.T) { ctx := context.Background() m := mock.New() diff --git a/spinifex/network/subscribers/events.go b/spinifex/network/subscribers/events.go index de3bb0442..6e12c8198 100644 --- a/spinifex/network/subscribers/events.go +++ b/spinifex/network/subscribers/events.go @@ -19,6 +19,8 @@ const ( TopicDeleteIGWRoute = "vpc.delete-igw-route" TopicGateSubnetEgress = "vpc.gate-subnet-egress" TopicUngateSubnetEgress = "vpc.ungate-subnet-egress" + TopicAddSystemEgress = "vpc.add-system-egress" + TopicDeleteSystemEgress = "vpc.delete-system-egress" TopicCreateSG = "vpc.create-sg" TopicDeleteSG = "vpc.delete-sg" TopicUpdateSG = "vpc.update-sg" @@ -113,6 +115,19 @@ type SubnetEgressUngateEvent struct { DestinationCidr string `json:"destination_cidr"` } +// SystemEgressEvent is published on vpc.add-system-egress / +// vpc.delete-system-egress to give a single hidden system instance (e.g. an +// EKS K3s server VM) egress-only internet access. The subscriber installs (or +// removes) a /32 reroute policy at SystemInstanceEgressPriority plus a plain +// snat (InstanceIp -> ExternalIp) — no DNAT, so the instance stays unreachable +// inbound. +type SystemEgressEvent struct { + VpcId string `json:"vpc_id"` + SubnetId string `json:"subnet_id"` + InstanceIp string `json:"instance_ip"` + ExternalIp string `json:"external_ip"` +} + // SGRule mirrors handlers/ec2/vpc.SGRule on the wire (kept local to avoid // the handler import). type SGRule struct { diff --git a/spinifex/network/subscribers/subscribers.go b/spinifex/network/subscribers/subscribers.go index fc3368bc5..69fdd8ca6 100644 --- a/spinifex/network/subscribers/subscribers.go +++ b/spinifex/network/subscribers/subscribers.go @@ -82,6 +82,8 @@ func (s *Subscriber) Subscribe(nc *nats.Conn) ([]*nats.Subscription, error) { {TopicDeleteIGWRoute, s.handleDeleteIGWRoute}, {TopicGateSubnetEgress, s.handleGateSubnetEgress}, {TopicUngateSubnetEgress, s.handleUngateSubnetEgress}, + {TopicAddSystemEgress, s.handleAddSystemEgress}, + {TopicDeleteSystemEgress, s.handleDeleteSystemEgress}, {TopicCreateSG, s.handleCreateSG}, {TopicDeleteSG, s.handleDeleteSG}, {TopicUpdateSG, s.handleUpdateSG}, diff --git a/spinifex/network/subscribers/subscribers_test.go b/spinifex/network/subscribers/subscribers_test.go index 1d2f3c106..e528cb285 100644 --- a/spinifex/network/subscribers/subscribers_test.go +++ b/spinifex/network/subscribers/subscribers_test.go @@ -98,6 +98,7 @@ func TestSubscribe_RegistersAllTopics(t *testing.T) { TopicAddNATGateway, TopicDeleteNATGateway, TopicAddIGWRoute, TopicDeleteIGWRoute, TopicGateSubnetEgress, TopicUngateSubnetEgress, + TopicAddSystemEgress, TopicDeleteSystemEgress, TopicCreateSG, TopicDeleteSG, TopicUpdateSG, } if len(subs) != len(wantTopics) { @@ -173,6 +174,66 @@ func TestHandleAddNATGateway_InstallsPerSubnetEgress(t *testing.T) { }, 2*time.Second, 20*time.Millisecond, "NATGW egress policy must be removed on delete event") } +// TestHandleSystemEgress_InstallsAndRemoves drives the full event path: a +// vpc.add-system-egress event installs the /32 reroute + snat-only NAT, and +// vpc.delete-system-egress tears both down. +func TestHandleSystemEgress_InstallsAndRemoves(t *testing.T) { + ctx := context.Background() + _, nc := testutil.StartTestNATS(t) + sub, m := newTestSubscriber(t) + subs, err := sub.Subscribe(nc) + require.NoError(t, err) + defer func() { + for _, s := range subs { + _ = s.Unsubscribe() + } + }() + + require.NoError(t, m.CreateLogicalRouter(ctx, &nbdb.LogicalRouter{ + Name: topology.VPCRouter("vpc-1"), + ExternalIDs: map[string]string{"spinifex:vpc_id": "vpc-1"}, + })) + require.NoError(t, sub.igw.AttachIGW(ctx, external.IGWSpec{VPCID: "vpc-1", InternetGatewayID: "igw-1"})) + + evt := SystemEgressEvent{ + VpcId: "vpc-1", + SubnetId: "subnet-k3s", + InstanceIp: "10.0.4.10", + ExternalIp: "192.168.1.60", + } + data, err := json.Marshal(evt) + require.NoError(t, err) + require.NoError(t, nc.Publish(TopicAddSystemEgress, data)) + + require.Eventually(t, func() bool { + policies, perr := m.ListLogicalRouterPolicies(ctx, topology.VPCRouter("vpc-1")) + if perr != nil || len(policies) != 1 { + return false + } + return policies[0].Priority == policy.SystemInstanceEgressPriority + }, 2*time.Second, 20*time.Millisecond, "system egress reroute must be installed") + + policies, err := m.ListLogicalRouterPolicies(ctx, topology.VPCRouter("vpc-1")) + require.NoError(t, err) + require.Len(t, policies, 1) + assert.Contains(t, policies[0].Match, "ip4.src == 10.0.4.10/32") + + snat, err := m.FindNATByExternalIP(ctx, "snat", "192.168.1.60") + require.NoError(t, err) + require.NotNil(t, snat) + assert.Equal(t, "10.0.4.10/32", snat.LogicalIP) + + require.NoError(t, nc.Publish(TopicDeleteSystemEgress, data)) + require.Eventually(t, func() bool { + policies, perr := m.ListLogicalRouterPolicies(ctx, topology.VPCRouter("vpc-1")) + if perr != nil || len(policies) != 0 { + return false + } + got, gerr := m.FindNATByExternalIP(ctx, "snat", "192.168.1.60") + return gerr == nil && got == nil + }, 2*time.Second, 20*time.Millisecond, "system egress reroute + snat must be removed on delete") +} + // TestHandleAddNATGateway_InvalidCIDRSkipsPolicy: the SNAT install must still // happen, but a malformed DestinationCidr must not install any LR policy. func TestHandleAddNATGateway_InvalidCIDRSkipsPolicy(t *testing.T) { diff --git a/spinifex/network/subscribers/topology.go b/spinifex/network/subscribers/topology.go index 0db002c9d..745bb46eb 100644 --- a/spinifex/network/subscribers/topology.go +++ b/spinifex/network/subscribers/topology.go @@ -310,6 +310,41 @@ func (s *Subscriber) handleAddNATGateway(msg *nats.Msg) { "natgw_id", evt.NatGatewayId) } +func (s *Subscriber) handleAddSystemEgress(msg *nats.Msg) { + var evt SystemEgressEvent + if err := json.Unmarshal(msg.Data, &evt); err != nil { + slog.Error("subscribers: failed to unmarshal vpc.add-system-egress event", "err", err) + return + } + ctx := context.Background() + if err := s.igw.EnsureSystemInstanceEgress(ctx, evt.VpcId, evt.SubnetId, evt.InstanceIp, evt.ExternalIp); err != nil { + slog.Error("subscribers: EnsureSystemInstanceEgress failed", + "vpc_id", evt.VpcId, "subnet_id", evt.SubnetId, + "instance_ip", evt.InstanceIp, "external_ip", evt.ExternalIp, "err", err) + return + } + slog.Info("subscribers: system instance egress installed", + "vpc_id", evt.VpcId, "subnet_id", evt.SubnetId, + "instance_ip", evt.InstanceIp, "external_ip", evt.ExternalIp) +} + +func (s *Subscriber) handleDeleteSystemEgress(msg *nats.Msg) { + var evt SystemEgressEvent + if err := json.Unmarshal(msg.Data, &evt); err != nil { + slog.Error("subscribers: failed to unmarshal vpc.delete-system-egress event", "err", err) + return + } + ctx := context.Background() + if err := s.igw.RemoveSystemInstanceEgress(ctx, evt.VpcId, evt.SubnetId, evt.InstanceIp, evt.ExternalIp); err != nil { + slog.Error("subscribers: RemoveSystemInstanceEgress failed", + "vpc_id", evt.VpcId, "subnet_id", evt.SubnetId, + "instance_ip", evt.InstanceIp, "external_ip", evt.ExternalIp, "err", err) + return + } + slog.Info("subscribers: system instance egress removed", + "vpc_id", evt.VpcId, "subnet_id", evt.SubnetId, "instance_ip", evt.InstanceIp) +} + func (s *Subscriber) handleDeleteNATGateway(msg *nats.Msg) { var evt NATGatewayEvent if err := json.Unmarshal(msg.Data, &evt); err != nil { From e06d0c0865c41b24fab0a544366f5b422c0971a7 Mon Sep 17 00:00:00 2001 From: Josh Siviour Date: Thu, 4 Jun 2026 09:51:10 +1000 Subject: [PATCH 06/73] feat(elbv2): HTTPS listener certificates + SSL policies (Phase A) (#283) * feat(elbv2): HTTPS listener certificates + SSL policies Add Certificates[]/SslPolicy to ListenerRecord. CreateListener and ModifyListener validate secure protocols (HTTPS/TLS) require >=1 certificate with exactly one default, non-secure protocols reject certs/policy, and default+validate the SSL policy. DescribeListeners echoes certificates and SslPolicy. New endpoints: AddListenerCertificates, RemoveListenerCertificates, DescribeListenerCertificates, DescribeSSLPolicies (gateway ops, NATS subjects, daemon handlers, service-interfaces.yaml). No TLS termination yet. * test(elbv2): cover listener-cert gateway ops + handler error paths --- docs/service-interfaces.yaml | 4 + spinifex/awserrors/awserrors.go | 4 + spinifex/daemon/daemon.go | 4 + spinifex/daemon/daemon_handlers_elbv2.go | 16 + spinifex/gateway/elbv2.go | 12 + .../gateway/elbv2/AddListenerCertificates.go | 28 ++ .../elbv2/DescribeListenerCertificates.go | 28 ++ spinifex/gateway/elbv2/DescribeSSLPolicies.go | 21 ++ .../elbv2/RemoveListenerCertificates.go | 28 ++ spinifex/gateway/elbv2/listener_certs_test.go | 100 ++++++ spinifex/gateway/elbv2_test.go | 4 + spinifex/handlers/elbv2/service.go | 5 + spinifex/handlers/elbv2/service_impl.go | 99 ++++++ .../elbv2/service_impl_listener_certs.go | 170 ++++++++++ .../elbv2/service_impl_listener_certs_test.go | 317 ++++++++++++++++++ spinifex/handlers/elbv2/service_impl_test.go | 22 +- spinifex/handlers/elbv2/service_nats.go | 16 + spinifex/handlers/elbv2/ssl_policies.go | 92 +++++ spinifex/handlers/elbv2/types.go | 17 + 19 files changed, 981 insertions(+), 6 deletions(-) create mode 100644 spinifex/gateway/elbv2/AddListenerCertificates.go create mode 100644 spinifex/gateway/elbv2/DescribeListenerCertificates.go create mode 100644 spinifex/gateway/elbv2/DescribeSSLPolicies.go create mode 100644 spinifex/gateway/elbv2/RemoveListenerCertificates.go create mode 100644 spinifex/gateway/elbv2/listener_certs_test.go create mode 100644 spinifex/handlers/elbv2/service_impl_listener_certs.go create mode 100644 spinifex/handlers/elbv2/service_impl_listener_certs_test.go create mode 100644 spinifex/handlers/elbv2/ssl_policies.go diff --git a/docs/service-interfaces.yaml b/docs/service-interfaces.yaml index f92c6f276..ad04455ac 100644 --- a/docs/service-interfaces.yaml +++ b/docs/service-interfaces.yaml @@ -95,6 +95,10 @@ services: - "elbv2.CreateListener" - "elbv2.DeleteListener" - "elbv2.DescribeListeners" + - "elbv2.AddListenerCertificates" + - "elbv2.RemoveListenerCertificates" + - "elbv2.DescribeListenerCertificates" + - "elbv2.DescribeSSLPolicies" publishes: # → vpcd - "vpc.create" diff --git a/spinifex/awserrors/awserrors.go b/spinifex/awserrors/awserrors.go index 4466632b3..f7ddfa43c 100644 --- a/spinifex/awserrors/awserrors.go +++ b/spinifex/awserrors/awserrors.go @@ -474,6 +474,8 @@ var ( ErrorELBv2TooManyActions = "TooManyActions" ErrorELBv2InvalidRulePriority = "InvalidRulePriority" ErrorELBv2IncompatibleProtocols = "IncompatibleProtocols" + ErrorELBv2CertificateNotFound = "CertificateNotFound" + ErrorELBv2SSLPolicyNotFound = "SSLPolicyNotFound" ) // ValidErrorCode returns the error code if it exists in ErrorLookup, @@ -961,4 +963,6 @@ var ErrorLookup = map[string]ErrorMessage{ ErrorELBv2TooManyActions: {HTTPCode: 400, Message: "You've reached the limit on the number of actions per rule."}, ErrorELBv2InvalidRulePriority: {HTTPCode: 400, Message: "The specified rule priority is not valid. Priority must be between 1 and 50000."}, ErrorELBv2IncompatibleProtocols: {HTTPCode: 400, Message: "The listener protocol is incompatible with the target group protocol."}, + ErrorELBv2CertificateNotFound: {HTTPCode: 400, Message: "One or more specified certificates do not exist."}, + ErrorELBv2SSLPolicyNotFound: {HTTPCode: 400, Message: "The specified SSL policy does not exist."}, } diff --git a/spinifex/daemon/daemon.go b/spinifex/daemon/daemon.go index 8b4003837..a6fd2ce47 100644 --- a/spinifex/daemon/daemon.go +++ b/spinifex/daemon/daemon.go @@ -850,6 +850,10 @@ func (d *Daemon) subscribeAll() error { natsSub{"elbv2.DescribeLoadBalancerAttributes", d.handleELBv2DescribeLoadBalancerAttributes, "spinifex-workers"}, natsSub{"elbv2.SetSecurityGroups", d.handleELBv2SetSecurityGroups, "spinifex-workers"}, natsSub{"elbv2.SetIpAddressType", d.handleELBv2SetIpAddressType, "spinifex-workers"}, + natsSub{"elbv2.AddListenerCertificates", d.handleELBv2AddListenerCertificates, "spinifex-workers"}, + natsSub{"elbv2.RemoveListenerCertificates", d.handleELBv2RemoveListenerCertificates, "spinifex-workers"}, + natsSub{"elbv2.DescribeListenerCertificates", d.handleELBv2DescribeListenerCertificates, "spinifex-workers"}, + natsSub{"elbv2.DescribeSSLPolicies", d.handleELBv2DescribeSSLPolicies, "spinifex-workers"}, ) } diff --git a/spinifex/daemon/daemon_handlers_elbv2.go b/spinifex/daemon/daemon_handlers_elbv2.go index 17deb4a8c..dabb4a9a5 100644 --- a/spinifex/daemon/daemon_handlers_elbv2.go +++ b/spinifex/daemon/daemon_handlers_elbv2.go @@ -121,3 +121,19 @@ func (d *Daemon) handleELBv2SetSecurityGroups(msg *nats.Msg) { func (d *Daemon) handleELBv2SetIpAddressType(msg *nats.Msg) { handleNATSRequest(msg, d.elbv2Service.SetIpAddressType) } + +func (d *Daemon) handleELBv2AddListenerCertificates(msg *nats.Msg) { + handleNATSRequest(msg, d.elbv2Service.AddListenerCertificates) +} + +func (d *Daemon) handleELBv2RemoveListenerCertificates(msg *nats.Msg) { + handleNATSRequest(msg, d.elbv2Service.RemoveListenerCertificates) +} + +func (d *Daemon) handleELBv2DescribeListenerCertificates(msg *nats.Msg) { + handleNATSRequest(msg, d.elbv2Service.DescribeListenerCertificates) +} + +func (d *Daemon) handleELBv2DescribeSSLPolicies(msg *nats.Msg) { + handleNATSRequest(msg, d.elbv2Service.DescribeSSLPolicies) +} diff --git a/spinifex/gateway/elbv2.go b/spinifex/gateway/elbv2.go index e4d3fc4c3..bae968d6b 100644 --- a/spinifex/gateway/elbv2.go +++ b/spinifex/gateway/elbv2.go @@ -132,6 +132,18 @@ var elbv2Actions = map[string]ELBv2Handler{ "SetIpAddressType": elbv2Handler(func(input *elbv2.SetIpAddressTypeInput, gw *GatewayConfig, accountID string) (any, error) { return gateway_elbv2.SetIpAddressType(input, gw.NATSConn, accountID) }), + "AddListenerCertificates": elbv2Handler(func(input *elbv2.AddListenerCertificatesInput, gw *GatewayConfig, accountID string) (any, error) { + return gateway_elbv2.AddListenerCertificates(input, gw.NATSConn, accountID) + }), + "RemoveListenerCertificates": elbv2Handler(func(input *elbv2.RemoveListenerCertificatesInput, gw *GatewayConfig, accountID string) (any, error) { + return gateway_elbv2.RemoveListenerCertificates(input, gw.NATSConn, accountID) + }), + "DescribeListenerCertificates": elbv2Handler(func(input *elbv2.DescribeListenerCertificatesInput, gw *GatewayConfig, accountID string) (any, error) { + return gateway_elbv2.DescribeListenerCertificates(input, gw.NATSConn, accountID) + }), + "DescribeSSLPolicies": elbv2Handler(func(input *elbv2.DescribeSSLPoliciesInput, gw *GatewayConfig, accountID string) (any, error) { + return gateway_elbv2.DescribeSSLPolicies(input, gw.NATSConn, accountID) + }), "DescribeListenerAttributes": elbv2Handler(func(input *gateway_elbv2.DescribeListenerAttributesInput, gw *GatewayConfig, accountID string) (any, error) { return gateway_elbv2.DescribeListenerAttributes(input, accountID) }), diff --git a/spinifex/gateway/elbv2/AddListenerCertificates.go b/spinifex/gateway/elbv2/AddListenerCertificates.go new file mode 100644 index 000000000..bec99a5d6 --- /dev/null +++ b/spinifex/gateway/elbv2/AddListenerCertificates.go @@ -0,0 +1,28 @@ +package gateway_elbv2 + +import ( + "errors" + + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/awserrors" + handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2" + "github.com/nats-io/nats.go" +) + +// AddListenerCertificates handles the ELBv2 AddListenerCertificates API call. It +// attaches additional SNI certificates to a secure listener. +func AddListenerCertificates(input *elbv2.AddListenerCertificatesInput, natsConn *nats.Conn, accountID string) (elbv2.AddListenerCertificatesOutput, error) { + var output elbv2.AddListenerCertificatesOutput + + if input == nil || input.ListenerArn == nil || *input.ListenerArn == "" || len(input.Certificates) == 0 { + return output, errors.New(awserrors.ErrorMissingParameter) + } + + svc := handlers_elbv2.NewNATSELBv2Service(natsConn) + result, err := svc.AddListenerCertificates(input, accountID) + if err != nil { + return output, err + } + + return *result, nil +} diff --git a/spinifex/gateway/elbv2/DescribeListenerCertificates.go b/spinifex/gateway/elbv2/DescribeListenerCertificates.go new file mode 100644 index 000000000..7913c34b0 --- /dev/null +++ b/spinifex/gateway/elbv2/DescribeListenerCertificates.go @@ -0,0 +1,28 @@ +package gateway_elbv2 + +import ( + "errors" + + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/awserrors" + handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2" + "github.com/nats-io/nats.go" +) + +// DescribeListenerCertificates handles the ELBv2 DescribeListenerCertificates +// API call. It returns the certificates attached to a listener. +func DescribeListenerCertificates(input *elbv2.DescribeListenerCertificatesInput, natsConn *nats.Conn, accountID string) (elbv2.DescribeListenerCertificatesOutput, error) { + var output elbv2.DescribeListenerCertificatesOutput + + if input == nil || input.ListenerArn == nil || *input.ListenerArn == "" { + return output, errors.New(awserrors.ErrorMissingParameter) + } + + svc := handlers_elbv2.NewNATSELBv2Service(natsConn) + result, err := svc.DescribeListenerCertificates(input, accountID) + if err != nil { + return output, err + } + + return *result, nil +} diff --git a/spinifex/gateway/elbv2/DescribeSSLPolicies.go b/spinifex/gateway/elbv2/DescribeSSLPolicies.go new file mode 100644 index 000000000..43df8fa32 --- /dev/null +++ b/spinifex/gateway/elbv2/DescribeSSLPolicies.go @@ -0,0 +1,21 @@ +package gateway_elbv2 + +import ( + "github.com/aws/aws-sdk-go/service/elbv2" + handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2" + "github.com/nats-io/nats.go" +) + +// DescribeSSLPolicies handles the ELBv2 DescribeSSLPolicies API call. It serves +// the fixed catalog of supported security policies. +func DescribeSSLPolicies(input *elbv2.DescribeSSLPoliciesInput, natsConn *nats.Conn, accountID string) (elbv2.DescribeSSLPoliciesOutput, error) { + var output elbv2.DescribeSSLPoliciesOutput + + svc := handlers_elbv2.NewNATSELBv2Service(natsConn) + result, err := svc.DescribeSSLPolicies(input, accountID) + if err != nil { + return output, err + } + + return *result, nil +} diff --git a/spinifex/gateway/elbv2/RemoveListenerCertificates.go b/spinifex/gateway/elbv2/RemoveListenerCertificates.go new file mode 100644 index 000000000..29714ccbd --- /dev/null +++ b/spinifex/gateway/elbv2/RemoveListenerCertificates.go @@ -0,0 +1,28 @@ +package gateway_elbv2 + +import ( + "errors" + + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/awserrors" + handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2" + "github.com/nats-io/nats.go" +) + +// RemoveListenerCertificates handles the ELBv2 RemoveListenerCertificates API +// call. It detaches the named certificates from a listener. +func RemoveListenerCertificates(input *elbv2.RemoveListenerCertificatesInput, natsConn *nats.Conn, accountID string) (elbv2.RemoveListenerCertificatesOutput, error) { + var output elbv2.RemoveListenerCertificatesOutput + + if input == nil || input.ListenerArn == nil || *input.ListenerArn == "" || len(input.Certificates) == 0 { + return output, errors.New(awserrors.ErrorMissingParameter) + } + + svc := handlers_elbv2.NewNATSELBv2Service(natsConn) + result, err := svc.RemoveListenerCertificates(input, accountID) + if err != nil { + return output, err + } + + return *result, nil +} diff --git a/spinifex/gateway/elbv2/listener_certs_test.go b/spinifex/gateway/elbv2/listener_certs_test.go new file mode 100644 index 000000000..a3c9abe95 --- /dev/null +++ b/spinifex/gateway/elbv2/listener_certs_test.go @@ -0,0 +1,100 @@ +package gateway_elbv2 + +import ( + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/awserrors" + "github.com/mulgadc/spinifex/spinifex/testutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const testListenerArn = "arn:aws:elasticloadbalancing:us-east-1:123456789012:listener/app/lb/abc/def" +const testCertArn = "arn:aws:acm:us-east-1:123456789012:certificate/aaaa-1111" + +// Validation guards (no NATS call reached). + +func TestAddListenerCertificates_NilInput(t *testing.T) { + _, err := AddListenerCertificates(nil, nil, "123456789012") + assert.EqualError(t, err, awserrors.ErrorMissingParameter) +} + +func TestAddListenerCertificates_MissingArn(t *testing.T) { + _, err := AddListenerCertificates(&elbv2.AddListenerCertificatesInput{ + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn)}}, + }, nil, "123456789012") + assert.EqualError(t, err, awserrors.ErrorMissingParameter) +} + +func TestAddListenerCertificates_MissingCerts(t *testing.T) { + _, err := AddListenerCertificates(&elbv2.AddListenerCertificatesInput{ + ListenerArn: aws.String(testListenerArn), + }, nil, "123456789012") + assert.EqualError(t, err, awserrors.ErrorMissingParameter) +} + +func TestRemoveListenerCertificates_NilInput(t *testing.T) { + _, err := RemoveListenerCertificates(nil, nil, "123456789012") + assert.EqualError(t, err, awserrors.ErrorMissingParameter) +} + +func TestRemoveListenerCertificates_MissingArn(t *testing.T) { + _, err := RemoveListenerCertificates(&elbv2.RemoveListenerCertificatesInput{ + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn)}}, + }, nil, "123456789012") + assert.EqualError(t, err, awserrors.ErrorMissingParameter) +} + +func TestRemoveListenerCertificates_MissingCerts(t *testing.T) { + _, err := RemoveListenerCertificates(&elbv2.RemoveListenerCertificatesInput{ + ListenerArn: aws.String(testListenerArn), + }, nil, "123456789012") + assert.EqualError(t, err, awserrors.ErrorMissingParameter) +} + +func TestDescribeListenerCertificates_NilInput(t *testing.T) { + _, err := DescribeListenerCertificates(nil, nil, "123456789012") + assert.EqualError(t, err, awserrors.ErrorMissingParameter) +} + +func TestDescribeListenerCertificates_MissingArn(t *testing.T) { + _, err := DescribeListenerCertificates(&elbv2.DescribeListenerCertificatesInput{}, nil, "123456789012") + assert.EqualError(t, err, awserrors.ErrorMissingParameter) +} + +// Delegation paths: a valid input with no daemon listening fast-fails on the +// NATS request, exercising the svc.X call + error return in each gateway op. + +func TestAddListenerCertificates_DelegatesNoResponder(t *testing.T) { + _, nc, _ := testutil.StartTestJetStream(t) + _, err := AddListenerCertificates(&elbv2.AddListenerCertificatesInput{ + ListenerArn: aws.String(testListenerArn), + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn)}}, + }, nc, "123456789012") + require.Error(t, err) +} + +func TestRemoveListenerCertificates_DelegatesNoResponder(t *testing.T) { + _, nc, _ := testutil.StartTestJetStream(t) + _, err := RemoveListenerCertificates(&elbv2.RemoveListenerCertificatesInput{ + ListenerArn: aws.String(testListenerArn), + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn)}}, + }, nc, "123456789012") + require.Error(t, err) +} + +func TestDescribeListenerCertificates_DelegatesNoResponder(t *testing.T) { + _, nc, _ := testutil.StartTestJetStream(t) + _, err := DescribeListenerCertificates(&elbv2.DescribeListenerCertificatesInput{ + ListenerArn: aws.String(testListenerArn), + }, nc, "123456789012") + require.Error(t, err) +} + +func TestDescribeSSLPolicies_DelegatesNoResponder(t *testing.T) { + _, nc, _ := testutil.StartTestJetStream(t) + _, err := DescribeSSLPolicies(&elbv2.DescribeSSLPoliciesInput{}, nc, "123456789012") + require.Error(t, err) +} diff --git a/spinifex/gateway/elbv2_test.go b/spinifex/gateway/elbv2_test.go index dacb82bc6..001a6763e 100644 --- a/spinifex/gateway/elbv2_test.go +++ b/spinifex/gateway/elbv2_test.go @@ -69,6 +69,10 @@ func TestELBv2ActionsMap_AllActionsRegistered(t *testing.T) { "DeleteRule", "DescribeRules", "SetRulePriorities", + "AddListenerCertificates", + "RemoveListenerCertificates", + "DescribeListenerCertificates", + "DescribeSSLPolicies", } for _, action := range expectedActions { diff --git a/spinifex/handlers/elbv2/service.go b/spinifex/handlers/elbv2/service.go index b2784d9ba..6a94aaa60 100644 --- a/spinifex/handlers/elbv2/service.go +++ b/spinifex/handlers/elbv2/service.go @@ -28,6 +28,11 @@ type ELBv2Service interface { ModifyListener(input *elbv2.ModifyListenerInput, accountID string) (*elbv2.ModifyListenerOutput, error) DescribeListeners(input *elbv2.DescribeListenersInput, accountID string) (*elbv2.DescribeListenersOutput, error) + AddListenerCertificates(input *elbv2.AddListenerCertificatesInput, accountID string) (*elbv2.AddListenerCertificatesOutput, error) + RemoveListenerCertificates(input *elbv2.RemoveListenerCertificatesInput, accountID string) (*elbv2.RemoveListenerCertificatesOutput, error) + DescribeListenerCertificates(input *elbv2.DescribeListenerCertificatesInput, accountID string) (*elbv2.DescribeListenerCertificatesOutput, error) + DescribeSSLPolicies(input *elbv2.DescribeSSLPoliciesInput, accountID string) (*elbv2.DescribeSSLPoliciesOutput, error) + CreateRule(input *elbv2.CreateRuleInput, accountID string) (*elbv2.CreateRuleOutput, error) ModifyRule(input *elbv2.ModifyRuleInput, accountID string) (*elbv2.ModifyRuleOutput, error) DeleteRule(input *elbv2.DeleteRuleInput, accountID string) (*elbv2.DeleteRuleOutput, error) diff --git a/spinifex/handlers/elbv2/service_impl.go b/spinifex/handlers/elbv2/service_impl.go index 4d2492bfb..800d2ae4e 100644 --- a/spinifex/handlers/elbv2/service_impl.go +++ b/spinifex/handlers/elbv2/service_impl.go @@ -1772,6 +1772,60 @@ func validateRedirectAction(rd *RedirectAction) error { return nil } +// buildListenerCertificates validates and normalises the certificate set and +// SSL policy for a listener of the given protocol. Secure protocols (HTTPS, +// TLS) require at least one certificate and receive a default SslPolicy when +// unset; non-secure protocols must carry neither certificates nor an SslPolicy. +// Exactly one certificate is marked default. +func buildListenerCertificates(protocol string, in []*elbv2.Certificate, sslPolicy *string) ([]ListenerCertificate, string, error) { + policy := "" + if sslPolicy != nil { + policy = *sslPolicy + } + + if !protocolRequiresCert(protocol) { + if len(in) > 0 || policy != "" { + return nil, "", errors.New(awserrors.ErrorInvalidParameterValue) + } + return nil, "", nil + } + + if len(in) == 0 { + return nil, "", errors.New(awserrors.ErrorELBv2CertificateNotFound) + } + + certs := make([]ListenerCertificate, 0, len(in)) + defaults := 0 + for _, c := range in { + if c == nil || c.CertificateArn == nil || *c.CertificateArn == "" { + return nil, "", errors.New(awserrors.ErrorInvalidParameterValue) + } + isDefault := c.IsDefault != nil && *c.IsDefault + if isDefault { + defaults++ + } + certs = append(certs, ListenerCertificate{ + CertificateArn: *c.CertificateArn, + IsDefault: isDefault, + }) + } + switch defaults { + case 0: + certs[0].IsDefault = true + case 1: + default: + return nil, "", errors.New(awserrors.ErrorInvalidParameterValue) + } + + if policy == "" { + policy = DefaultSslPolicy + } else if !isKnownSslPolicy(policy) { + return nil, "", errors.New(awserrors.ErrorELBv2SSLPolicyNotFound) + } + + return certs, policy, nil +} + func (s *ELBv2ServiceImpl) CreateListener(input *elbv2.CreateListenerInput, accountID string) (*elbv2.CreateListenerOutput, error) { if input.LoadBalancerArn == nil || *input.LoadBalancerArn == "" { return nil, errors.New(awserrors.ErrorMissingParameter) @@ -1846,6 +1900,11 @@ func (s *ELBv2ServiceImpl) CreateListener(input *elbv2.CreateListenerInput, acco } } + certs, sslPolicy, err := buildListenerCertificates(protocol, input.Certificates, input.SslPolicy) + if err != nil { + return nil, err + } + listenerID := utils.GenerateResourceID("lst") listenerArn := buildListenerArn(s.region, accountID, lb.Name, lb.LoadBalancerID, listenerID, lb.Type) @@ -1874,6 +1933,8 @@ func (s *ELBv2ServiceImpl) CreateListener(input *elbv2.CreateListenerInput, acco DefaultActions: actions, AccountID: accountID, CreatedAt: time.Now().UTC(), + Certificates: certs, + SslPolicy: sslPolicy, Tags: tags, } @@ -2056,6 +2117,37 @@ func (s *ELBv2ServiceImpl) ModifyListener(input *elbv2.ModifyListenerInput, acco } } + // Certificates / SSL policy. The effective protocol after any change drives + // the requirement: switching to a non-secure protocol clears cert material; + // staying on or switching to a secure protocol validates and defaults it. + if !protocolRequiresCert(updated.Protocol) { + if len(input.Certificates) > 0 || (input.SslPolicy != nil && *input.SslPolicy != "") { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + updated.Certificates = nil + updated.SslPolicy = "" + } else { + inCerts := input.Certificates + if inCerts == nil { + for _, c := range updated.Certificates { + inCerts = append(inCerts, &elbv2.Certificate{ + CertificateArn: aws.String(c.CertificateArn), + IsDefault: aws.Bool(c.IsDefault), + }) + } + } + sslPolicy := input.SslPolicy + if sslPolicy == nil && updated.SslPolicy != "" { + sslPolicy = aws.String(updated.SslPolicy) + } + certs, policy, certErr := buildListenerCertificates(updated.Protocol, inCerts, sslPolicy) + if certErr != nil { + return nil, certErr + } + updated.Certificates = certs + updated.SslPolicy = policy + } + if err := s.store.PutListener(&updated); err != nil { slog.Error("ModifyListener: failed to persist record", "listenerId", updated.ListenerID, "err", err) return nil, errors.New(awserrors.ErrorServerInternal) @@ -2325,6 +2417,13 @@ func (s *ELBv2ServiceImpl) listenerRecordToSDK(r *ListenerRecord) *elbv2.Listene listener.DefaultActions = append(listener.DefaultActions, listenerActionToSDK(a)) } + if len(r.Certificates) > 0 { + listener.Certificates = listenerCertsToSDK(r.Certificates) + } + if r.SslPolicy != "" { + listener.SslPolicy = aws.String(r.SslPolicy) + } + return listener } diff --git a/spinifex/handlers/elbv2/service_impl_listener_certs.go b/spinifex/handlers/elbv2/service_impl_listener_certs.go new file mode 100644 index 000000000..4fa3e99b0 --- /dev/null +++ b/spinifex/handlers/elbv2/service_impl_listener_certs.go @@ -0,0 +1,170 @@ +package handlers_elbv2 + +import ( + "errors" + "log/slog" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/awserrors" +) + +// listenerCertsToSDK renders stored listener certificates as SDK certificates. +func listenerCertsToSDK(certs []ListenerCertificate) []*elbv2.Certificate { + out := make([]*elbv2.Certificate, 0, len(certs)) + for _, c := range certs { + out = append(out, &elbv2.Certificate{ + CertificateArn: aws.String(c.CertificateArn), + IsDefault: aws.Bool(c.IsDefault), + }) + } + return out +} + +// AddListenerCertificates attaches additional (SNI) certificates to a secure +// listener. The default certificate is set at create time and is unaffected; +// added certificates are non-default. Re-adding an existing certificate is a +// no-op. +func (s *ELBv2ServiceImpl) AddListenerCertificates(input *elbv2.AddListenerCertificatesInput, accountID string) (*elbv2.AddListenerCertificatesOutput, error) { + if input == nil || input.ListenerArn == nil || *input.ListenerArn == "" { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + if len(input.Certificates) == 0 { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + + listener, err := s.store.GetListenerByArn(*input.ListenerArn) + if err != nil { + slog.Error("AddListenerCertificates: failed to get listener", "arn", *input.ListenerArn, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } + if listener == nil || listener.AccountID != accountID { + return nil, errors.New(awserrors.ErrorELBv2ListenerNotFound) + } + if !protocolRequiresCert(listener.Protocol) { + return nil, errors.New(awserrors.ErrorELBv2InvalidConfigurationRequest) + } + + updated := *listener + certs := append([]ListenerCertificate(nil), updated.Certificates...) + seen := make(map[string]bool, len(certs)) + for _, c := range certs { + seen[c.CertificateArn] = true + } + for _, c := range input.Certificates { + if c == nil || c.CertificateArn == nil || *c.CertificateArn == "" { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + if seen[*c.CertificateArn] { + continue + } + certs = append(certs, ListenerCertificate{CertificateArn: *c.CertificateArn, IsDefault: false}) + seen[*c.CertificateArn] = true + } + updated.Certificates = certs + + if err := s.store.PutListener(&updated); err != nil { + slog.Error("AddListenerCertificates: failed to persist record", "listenerId", updated.ListenerID, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } + + return &elbv2.AddListenerCertificatesOutput{ + Certificates: listenerCertsToSDK(certs), + }, nil +} + +// RemoveListenerCertificates detaches certificates from a listener by ARN. The +// default certificate cannot be removed. Removing an absent certificate is a +// no-op (idempotent). +func (s *ELBv2ServiceImpl) RemoveListenerCertificates(input *elbv2.RemoveListenerCertificatesInput, accountID string) (*elbv2.RemoveListenerCertificatesOutput, error) { + if input == nil || input.ListenerArn == nil || *input.ListenerArn == "" { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + if len(input.Certificates) == 0 { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + + listener, err := s.store.GetListenerByArn(*input.ListenerArn) + if err != nil { + slog.Error("RemoveListenerCertificates: failed to get listener", "arn", *input.ListenerArn, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } + if listener == nil || listener.AccountID != accountID { + return nil, errors.New(awserrors.ErrorELBv2ListenerNotFound) + } + + remove := make(map[string]bool, len(input.Certificates)) + for _, c := range input.Certificates { + if c == nil || c.CertificateArn == nil || *c.CertificateArn == "" { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + remove[*c.CertificateArn] = true + } + + updated := *listener + kept := make([]ListenerCertificate, 0, len(updated.Certificates)) + for _, c := range updated.Certificates { + if remove[c.CertificateArn] { + if c.IsDefault { + // The default certificate is managed via the listener itself. + return nil, errors.New(awserrors.ErrorELBv2InvalidConfigurationRequest) + } + continue + } + kept = append(kept, c) + } + updated.Certificates = kept + + if err := s.store.PutListener(&updated); err != nil { + slog.Error("RemoveListenerCertificates: failed to persist record", "listenerId", updated.ListenerID, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } + + return &elbv2.RemoveListenerCertificatesOutput{}, nil +} + +// DescribeListenerCertificates returns the certificates attached to a listener. +func (s *ELBv2ServiceImpl) DescribeListenerCertificates(input *elbv2.DescribeListenerCertificatesInput, accountID string) (*elbv2.DescribeListenerCertificatesOutput, error) { + if input == nil || input.ListenerArn == nil || *input.ListenerArn == "" { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + + listener, err := s.store.GetListenerByArn(*input.ListenerArn) + if err != nil { + slog.Error("DescribeListenerCertificates: failed to get listener", "arn", *input.ListenerArn, "err", err) + return nil, errors.New(awserrors.ErrorServerInternal) + } + if listener == nil || listener.AccountID != accountID { + return nil, errors.New(awserrors.ErrorELBv2ListenerNotFound) + } + + return &elbv2.DescribeListenerCertificatesOutput{ + Certificates: listenerCertsToSDK(listener.Certificates), + }, nil +} + +// DescribeSSLPolicies returns the fixed catalog of supported security policies. +// An explicit Names filter selects a subset; an unknown name is rejected. +func (s *ELBv2ServiceImpl) DescribeSSLPolicies(input *elbv2.DescribeSSLPoliciesInput, _ string) (*elbv2.DescribeSSLPoliciesOutput, error) { + var names []string + if input != nil && len(input.Names) > 0 { + for _, n := range input.Names { + if n == nil || *n == "" { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + if !isKnownSslPolicy(*n) { + return nil, errors.New(awserrors.ErrorELBv2SSLPolicyNotFound) + } + names = append(names, *n) + } + } else { + names = sslPolicyOrder + } + + policies := make([]*elbv2.SslPolicy, 0, len(names)) + for _, n := range names { + policies = append(policies, sslPolicyToSDK(sslPolicyCatalog[n])) + } + + return &elbv2.DescribeSSLPoliciesOutput{SslPolicies: policies}, nil +} diff --git a/spinifex/handlers/elbv2/service_impl_listener_certs_test.go b/spinifex/handlers/elbv2/service_impl_listener_certs_test.go new file mode 100644 index 000000000..4528af027 --- /dev/null +++ b/spinifex/handlers/elbv2/service_impl_listener_certs_test.go @@ -0,0 +1,317 @@ +package handlers_elbv2 + +import ( + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/mulgadc/spinifex/spinifex/awserrors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const testCertArn = "arn:aws:acm:ap-southeast-2:000000000001:certificate/aaaaaaaa-1111" +const testCertArn2 = "arn:aws:acm:ap-southeast-2:000000000001:certificate/bbbbbbbb-2222" + +// fixedResponseAction is a valid default action that needs no target group. +func fixedResponseAction() []*elbv2.Action { + return []*elbv2.Action{{ + Type: aws.String(ActionTypeFixedResponse), + FixedResponseConfig: &elbv2.FixedResponseActionConfig{ + StatusCode: aws.String("200"), + }, + }} +} + +func createHTTPSListener(t *testing.T, svc *ELBv2ServiceImpl) string { + t.Helper() + lbArn := createLBArn(t, svc, "https-lb") + out, err := svc.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: aws.String(lbArn), + Protocol: aws.String(ProtocolHTTPS), + Port: aws.Int64(443), + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn)}}, + DefaultActions: fixedResponseAction(), + }, testAccountID) + require.NoError(t, err) + return *out.Listeners[0].ListenerArn +} + +func TestCreateListener_HTTPSRequiresCert(t *testing.T) { + svc := setupTestService(t) + lbArn := createLBArn(t, svc, "https-nocert") + + _, err := svc.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: aws.String(lbArn), + Protocol: aws.String(ProtocolHTTPS), + Port: aws.Int64(443), + DefaultActions: fixedResponseAction(), + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorELBv2CertificateNotFound) +} + +func TestCreateListener_HTTPSDefaultsSslPolicy(t *testing.T) { + svc := setupTestService(t) + lbArn := createLBArn(t, svc, "https-default-policy") + + out, err := svc.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: aws.String(lbArn), + Protocol: aws.String(ProtocolHTTPS), + Port: aws.Int64(443), + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn)}}, + DefaultActions: fixedResponseAction(), + }, testAccountID) + require.NoError(t, err) + + l := out.Listeners[0] + assert.Equal(t, DefaultSslPolicy, aws.StringValue(l.SslPolicy)) + require.Len(t, l.Certificates, 1) + assert.Equal(t, testCertArn, aws.StringValue(l.Certificates[0].CertificateArn)) + assert.True(t, aws.BoolValue(l.Certificates[0].IsDefault), "the sole cert must be marked default") + + // DescribeListeners round-trips certificates and SslPolicy. + desc, err := svc.DescribeListeners(&elbv2.DescribeListenersInput{ + ListenerArns: []*string{l.ListenerArn}, + }, testAccountID) + require.NoError(t, err) + require.Len(t, desc.Listeners, 1) + assert.Equal(t, DefaultSslPolicy, aws.StringValue(desc.Listeners[0].SslPolicy)) + require.Len(t, desc.Listeners[0].Certificates, 1) +} + +func TestCreateListener_HTTPRejectsCert(t *testing.T) { + svc := setupTestService(t) + lbArn := createLBArn(t, svc, "http-withcert") + + _, err := svc.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: aws.String(lbArn), + Protocol: aws.String(ProtocolHTTP), + Port: aws.Int64(80), + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn)}}, + DefaultActions: fixedResponseAction(), + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorInvalidParameterValue) +} + +func TestCreateListener_UnknownSslPolicy(t *testing.T) { + svc := setupTestService(t) + lbArn := createLBArn(t, svc, "https-badpolicy") + + _, err := svc.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: aws.String(lbArn), + Protocol: aws.String(ProtocolHTTPS), + Port: aws.Int64(443), + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn)}}, + SslPolicy: aws.String("ELBSecurityPolicy-Does-Not-Exist"), + DefaultActions: fixedResponseAction(), + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorELBv2SSLPolicyNotFound) +} + +func TestModifyListener_SwitchToHTTPSRequiresCert(t *testing.T) { + svc := setupTestService(t) + lbArn := createLBArn(t, svc, "switch-lb") + lst, err := svc.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: aws.String(lbArn), + Protocol: aws.String(ProtocolHTTP), + Port: aws.Int64(80), + DefaultActions: fixedResponseAction(), + }, testAccountID) + require.NoError(t, err) + arn := lst.Listeners[0].ListenerArn + + // HTTP -> HTTPS without a cert is rejected. + _, err = svc.ModifyListener(&elbv2.ModifyListenerInput{ + ListenerArn: arn, + Protocol: aws.String(ProtocolHTTPS), + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorELBv2CertificateNotFound) + + // HTTP -> HTTPS with a cert succeeds and defaults the policy. + out, err := svc.ModifyListener(&elbv2.ModifyListenerInput{ + ListenerArn: arn, + Protocol: aws.String(ProtocolHTTPS), + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn)}}, + }, testAccountID) + require.NoError(t, err) + assert.Equal(t, DefaultSslPolicy, aws.StringValue(out.Listeners[0].SslPolicy)) + require.Len(t, out.Listeners[0].Certificates, 1) +} + +func TestModifyListener_SwitchAwayClearsCerts(t *testing.T) { + svc := setupTestService(t) + arn := createHTTPSListener(t, svc) + + out, err := svc.ModifyListener(&elbv2.ModifyListenerInput{ + ListenerArn: aws.String(arn), + Protocol: aws.String(ProtocolHTTP), + }, testAccountID) + require.NoError(t, err) + assert.Empty(t, out.Listeners[0].Certificates, "certs cleared when leaving a secure protocol") + assert.Nil(t, out.Listeners[0].SslPolicy) +} + +func TestListenerCertificates_AddRemoveDescribe(t *testing.T) { + svc := setupTestService(t) + arn := createHTTPSListener(t, svc) + + // Add an SNI cert. + addOut, err := svc.AddListenerCertificates(&elbv2.AddListenerCertificatesInput{ + ListenerArn: aws.String(arn), + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn2)}}, + }, testAccountID) + require.NoError(t, err) + require.Len(t, addOut.Certificates, 2) + + // Re-adding is idempotent. + addOut, err = svc.AddListenerCertificates(&elbv2.AddListenerCertificatesInput{ + ListenerArn: aws.String(arn), + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn2)}}, + }, testAccountID) + require.NoError(t, err) + require.Len(t, addOut.Certificates, 2) + + // Describe shows both. + desc, err := svc.DescribeListenerCertificates(&elbv2.DescribeListenerCertificatesInput{ + ListenerArn: aws.String(arn), + }, testAccountID) + require.NoError(t, err) + require.Len(t, desc.Certificates, 2) + + // Removing the default cert is rejected. + _, err = svc.RemoveListenerCertificates(&elbv2.RemoveListenerCertificatesInput{ + ListenerArn: aws.String(arn), + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn)}}, + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorELBv2InvalidConfigurationRequest) + + // Removing the SNI cert succeeds. + _, err = svc.RemoveListenerCertificates(&elbv2.RemoveListenerCertificatesInput{ + ListenerArn: aws.String(arn), + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn2)}}, + }, testAccountID) + require.NoError(t, err) + + desc, err = svc.DescribeListenerCertificates(&elbv2.DescribeListenerCertificatesInput{ + ListenerArn: aws.String(arn), + }, testAccountID) + require.NoError(t, err) + require.Len(t, desc.Certificates, 1) + assert.Equal(t, testCertArn, aws.StringValue(desc.Certificates[0].CertificateArn)) +} + +func TestAddListenerCertificates_HTTPRejected(t *testing.T) { + svc := setupTestService(t) + lbArn := createLBArn(t, svc, "http-addcert") + lst, err := svc.CreateListener(&elbv2.CreateListenerInput{ + LoadBalancerArn: aws.String(lbArn), + Protocol: aws.String(ProtocolHTTP), + Port: aws.Int64(80), + DefaultActions: fixedResponseAction(), + }, testAccountID) + require.NoError(t, err) + + _, err = svc.AddListenerCertificates(&elbv2.AddListenerCertificatesInput{ + ListenerArn: lst.Listeners[0].ListenerArn, + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn)}}, + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorELBv2InvalidConfigurationRequest) +} + +func TestListenerCertificates_ValidationAndNotFound(t *testing.T) { + svc := setupTestService(t) + arn := createHTTPSListener(t, svc) + const otherAccount = "999999999999" + badArn := "arn:aws:elasticloadbalancing:us-east-1:000000000001:listener/app/x/y/z" + + // Add: missing arn, empty certs, nil cert entry, cross-account not-found. + _, err := svc.AddListenerCertificates(&elbv2.AddListenerCertificatesInput{}, testAccountID) + assert.EqualError(t, err, awserrors.ErrorMissingParameter) + + _, err = svc.AddListenerCertificates(&elbv2.AddListenerCertificatesInput{ + ListenerArn: aws.String(arn), + }, testAccountID) + assert.EqualError(t, err, awserrors.ErrorMissingParameter) + + _, err = svc.AddListenerCertificates(&elbv2.AddListenerCertificatesInput{ + ListenerArn: aws.String(arn), + Certificates: []*elbv2.Certificate{{}}, + }, testAccountID) + assert.EqualError(t, err, awserrors.ErrorInvalidParameterValue) + + _, err = svc.AddListenerCertificates(&elbv2.AddListenerCertificatesInput{ + ListenerArn: aws.String(arn), + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn2)}}, + }, otherAccount) + assert.EqualError(t, err, awserrors.ErrorELBv2ListenerNotFound) + + // Remove: missing arn, empty certs, nil cert entry, cross-account not-found. + _, err = svc.RemoveListenerCertificates(&elbv2.RemoveListenerCertificatesInput{}, testAccountID) + assert.EqualError(t, err, awserrors.ErrorMissingParameter) + + _, err = svc.RemoveListenerCertificates(&elbv2.RemoveListenerCertificatesInput{ + ListenerArn: aws.String(arn), + }, testAccountID) + assert.EqualError(t, err, awserrors.ErrorMissingParameter) + + _, err = svc.RemoveListenerCertificates(&elbv2.RemoveListenerCertificatesInput{ + ListenerArn: aws.String(arn), + Certificates: []*elbv2.Certificate{{}}, + }, testAccountID) + assert.EqualError(t, err, awserrors.ErrorInvalidParameterValue) + + _, err = svc.RemoveListenerCertificates(&elbv2.RemoveListenerCertificatesInput{ + ListenerArn: aws.String(badArn), + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn)}}, + }, testAccountID) + assert.EqualError(t, err, awserrors.ErrorELBv2ListenerNotFound) + + // Describe: missing arn, cross-account not-found. + _, err = svc.DescribeListenerCertificates(&elbv2.DescribeListenerCertificatesInput{}, testAccountID) + assert.EqualError(t, err, awserrors.ErrorMissingParameter) + + _, err = svc.DescribeListenerCertificates(&elbv2.DescribeListenerCertificatesInput{ + ListenerArn: aws.String(arn), + }, otherAccount) + assert.EqualError(t, err, awserrors.ErrorELBv2ListenerNotFound) +} + +func TestDescribeSSLPolicies_EmptyName(t *testing.T) { + svc := setupTestService(t) + _, err := svc.DescribeSSLPolicies(&elbv2.DescribeSSLPoliciesInput{ + Names: []*string{aws.String("")}, + }, testAccountID) + assert.EqualError(t, err, awserrors.ErrorInvalidParameterValue) +} + +func TestDescribeSSLPolicies(t *testing.T) { + svc := setupTestService(t) + + // No filter → full catalog. + all, err := svc.DescribeSSLPolicies(&elbv2.DescribeSSLPoliciesInput{}, testAccountID) + require.NoError(t, err) + require.Len(t, all.SslPolicies, len(sslPolicyOrder)) + assert.Equal(t, DefaultSslPolicy, aws.StringValue(all.SslPolicies[0].Name)) + require.NotEmpty(t, all.SslPolicies[0].Ciphers) + require.NotEmpty(t, all.SslPolicies[0].SslProtocols) + + // Name filter → subset. + one, err := svc.DescribeSSLPolicies(&elbv2.DescribeSSLPoliciesInput{ + Names: []*string{aws.String(DefaultSslPolicy)}, + }, testAccountID) + require.NoError(t, err) + require.Len(t, one.SslPolicies, 1) + + // Unknown name → error. + _, err = svc.DescribeSSLPolicies(&elbv2.DescribeSSLPoliciesInput{ + Names: []*string{aws.String("nope")}, + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorELBv2SSLPolicyNotFound) +} diff --git a/spinifex/handlers/elbv2/service_impl_test.go b/spinifex/handlers/elbv2/service_impl_test.go index 3ffbbe7cf..ca405bdda 100644 --- a/spinifex/handlers/elbv2/service_impl_test.go +++ b/spinifex/handlers/elbv2/service_impl_test.go @@ -1195,8 +1195,9 @@ func TestModifyListener_Protocol(t *testing.T) { require.NoError(t, err) out, err := svc.ModifyListener(&elbv2.ModifyListenerInput{ - ListenerArn: lstOut.Listeners[0].ListenerArn, - Protocol: aws.String("HTTPS"), + ListenerArn: lstOut.Listeners[0].ListenerArn, + Protocol: aws.String("HTTPS"), + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn)}}, }, testAccountID) require.NoError(t, err) assert.Equal(t, "HTTPS", *out.Listeners[0].Protocol) @@ -1419,10 +1420,14 @@ func TestModifyListener_NLB_AcceptsAllProtocols(t *testing.T) { }, testAccountID) require.NoError(t, err) - out, err := svc.ModifyListener(&elbv2.ModifyListenerInput{ + modIn := &elbv2.ModifyListenerInput{ ListenerArn: lstOut.Listeners[0].ListenerArn, Protocol: aws.String(tc.listenerProto), - }, testAccountID) + } + if protocolRequiresCert(tc.listenerProto) { + modIn.Certificates = []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn)}} + } + out, err := svc.ModifyListener(modIn, testAccountID) require.NoError(t, err) assert.Equal(t, tc.listenerProto, *out.Listeners[0].Protocol) }) @@ -1604,14 +1609,18 @@ func TestCreateListener_NLB_AllProtocols(t *testing.T) { Port: aws.Int64(8080), }, testAccountID) - out, err := svc.CreateListener(&elbv2.CreateListenerInput{ + createIn := &elbv2.CreateListenerInput{ LoadBalancerArn: lbOut.LoadBalancers[0].LoadBalancerArn, Protocol: aws.String(proto), Port: aws.Int64(8080), DefaultActions: []*elbv2.Action{ {Type: aws.String("forward"), TargetGroupArn: tgOut.TargetGroups[0].TargetGroupArn}, }, - }, testAccountID) + } + if protocolRequiresCert(proto) { + createIn.Certificates = []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn)}} + } + out, err := svc.CreateListener(createIn, testAccountID) require.NoError(t, err) assert.Equal(t, proto, *out.Listeners[0].Protocol) @@ -1707,6 +1716,7 @@ func TestCreateListener_NLB_ProtocolCompatibility_TLSToTCP(t *testing.T) { LoadBalancerArn: lbOut.LoadBalancers[0].LoadBalancerArn, Protocol: aws.String("TLS"), Port: aws.Int64(443), + Certificates: []*elbv2.Certificate{{CertificateArn: aws.String(testCertArn)}}, DefaultActions: []*elbv2.Action{ {Type: aws.String("forward"), TargetGroupArn: tgOut.TargetGroups[0].TargetGroupArn}, }, diff --git a/spinifex/handlers/elbv2/service_nats.go b/spinifex/handlers/elbv2/service_nats.go index 00797d140..8fde7f0db 100644 --- a/spinifex/handlers/elbv2/service_nats.go +++ b/spinifex/handlers/elbv2/service_nats.go @@ -143,6 +143,22 @@ func (s *NATSELBv2Service) SetIpAddressType(input *elbv2.SetIpAddressTypeInput, return utils.NATSRequest[elbv2.SetIpAddressTypeOutput](s.natsConn, "elbv2.SetIpAddressType", input, defaultTimeout, accountID) } +func (s *NATSELBv2Service) AddListenerCertificates(input *elbv2.AddListenerCertificatesInput, accountID string) (*elbv2.AddListenerCertificatesOutput, error) { + return utils.NATSRequest[elbv2.AddListenerCertificatesOutput](s.natsConn, "elbv2.AddListenerCertificates", input, defaultTimeout, accountID) +} + +func (s *NATSELBv2Service) RemoveListenerCertificates(input *elbv2.RemoveListenerCertificatesInput, accountID string) (*elbv2.RemoveListenerCertificatesOutput, error) { + return utils.NATSRequest[elbv2.RemoveListenerCertificatesOutput](s.natsConn, "elbv2.RemoveListenerCertificates", input, defaultTimeout, accountID) +} + +func (s *NATSELBv2Service) DescribeListenerCertificates(input *elbv2.DescribeListenerCertificatesInput, accountID string) (*elbv2.DescribeListenerCertificatesOutput, error) { + return utils.NATSRequest[elbv2.DescribeListenerCertificatesOutput](s.natsConn, "elbv2.DescribeListenerCertificates", input, defaultTimeout, accountID) +} + +func (s *NATSELBv2Service) DescribeSSLPolicies(input *elbv2.DescribeSSLPoliciesInput, accountID string) (*elbv2.DescribeSSLPoliciesOutput, error) { + return utils.NATSRequest[elbv2.DescribeSSLPoliciesOutput](s.natsConn, "elbv2.DescribeSSLPolicies", input, defaultTimeout, accountID) +} + func (s *NATSELBv2Service) LBAgentHeartbeat(input *LBAgentHeartbeatInput, accountID string) (*LBAgentHeartbeatOutput, error) { return utils.NATSRequest[LBAgentHeartbeatOutput](s.natsConn, "elbv2.LBAgentHeartbeat", input, defaultTimeout, accountID) } diff --git a/spinifex/handlers/elbv2/ssl_policies.go b/spinifex/handlers/elbv2/ssl_policies.go new file mode 100644 index 000000000..104cefc21 --- /dev/null +++ b/spinifex/handlers/elbv2/ssl_policies.go @@ -0,0 +1,92 @@ +package handlers_elbv2 + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/elbv2" +) + +// protocolRequiresCert reports whether a listener protocol terminates TLS and +// therefore requires at least one certificate: ALB HTTPS and NLB TLS. +func protocolRequiresCert(protocol string) bool { + switch protocol { + case ProtocolHTTPS, ProtocolTLS: + return true + default: + return false + } +} + +// sslPolicyCipher is a named cipher with its negotiation priority. +type sslPolicyCipher struct { + name string + priority int64 +} + +// sslPolicyDef is a static security-policy definition served by +// DescribeSSLPolicies. Spinifex does not terminate TLS yet, so these exist to +// satisfy listener SslPolicy validation and terraform reads. +type sslPolicyDef struct { + name string + protocols []string + ciphers []sslPolicyCipher +} + +// sslPolicyCatalog is the fixed set of supported security policies, keyed by +// name. Static data — no persistence. +var sslPolicyCatalog = map[string]sslPolicyDef{ + DefaultSslPolicy: { + name: DefaultSslPolicy, + protocols: []string{"TLSv1.2"}, + ciphers: []sslPolicyCipher{ + {"ECDHE-ECDSA-AES128-GCM-SHA256", 1}, + {"ECDHE-RSA-AES128-GCM-SHA256", 2}, + {"ECDHE-ECDSA-AES256-GCM-SHA384", 3}, + {"ECDHE-RSA-AES256-GCM-SHA384", 4}, + }, + }, + "ELBSecurityPolicy-TLS13-1-2-2021-06": { + name: "ELBSecurityPolicy-TLS13-1-2-2021-06", + protocols: []string{"TLSv1.3", "TLSv1.2"}, + ciphers: []sslPolicyCipher{ + {"TLS_AES_128_GCM_SHA256", 1}, + {"TLS_AES_256_GCM_SHA384", 2}, + {"TLS_CHACHA20_POLY1305_SHA256", 3}, + {"ECDHE-ECDSA-AES128-GCM-SHA256", 4}, + {"ECDHE-RSA-AES128-GCM-SHA256", 5}, + }, + }, +} + +// sslPolicyOrder is the deterministic order DescribeSSLPolicies returns the +// catalog in. +var sslPolicyOrder = []string{ + DefaultSslPolicy, + "ELBSecurityPolicy-TLS13-1-2-2021-06", +} + +// isKnownSslPolicy reports whether name is in the catalog. +func isKnownSslPolicy(name string) bool { + _, ok := sslPolicyCatalog[name] + return ok +} + +// sslPolicyToSDK renders a catalog definition as an SDK SslPolicy. +func sslPolicyToSDK(def sslPolicyDef) *elbv2.SslPolicy { + ciphers := make([]*elbv2.Cipher, 0, len(def.ciphers)) + for _, c := range def.ciphers { + ciphers = append(ciphers, &elbv2.Cipher{ + Name: aws.String(c.name), + Priority: aws.Int64(c.priority), + }) + } + protocols := make([]*string, 0, len(def.protocols)) + for _, p := range def.protocols { + protocols = append(protocols, aws.String(p)) + } + return &elbv2.SslPolicy{ + Name: aws.String(def.name), + SslProtocols: protocols, + Ciphers: ciphers, + SupportedLoadBalancerTypes: []*string{aws.String("application")}, + } +} diff --git a/spinifex/handlers/elbv2/types.go b/spinifex/handlers/elbv2/types.go index c9137b169..61a428394 100644 --- a/spinifex/handlers/elbv2/types.go +++ b/spinifex/handlers/elbv2/types.go @@ -40,6 +40,10 @@ const ( ProtocolTLS = "TLS" ProtocolTCPUDP = "TCP_UDP" + // DefaultSslPolicy is applied to a secure listener when the caller does + // not specify an SslPolicy. + DefaultSslPolicy = "ELBSecurityPolicy-2016-08" + // Listener action types ActionTypeForward = "forward" ActionTypeFixedResponse = "fixed-response" @@ -202,9 +206,22 @@ type ListenerRecord struct { AccountID string `json:"account_id"` CreatedAt time.Time `json:"created_at"` + // Certificates holds the listener's TLS certificates for a secure + // protocol (ALB HTTPS / NLB TLS). The first IsDefault entry is the + // default cert; the rest are additional SNI certs. Empty for non-secure + // listeners. SslPolicy is the negotiated security policy name. + Certificates []ListenerCertificate `json:"certificates,omitempty"` + SslPolicy string `json:"ssl_policy,omitempty"` + Tags map[string]string `json:"tags,omitempty"` } +// ListenerCertificate is a TLS certificate reference attached to a listener. +type ListenerCertificate struct { + CertificateArn string `json:"certificate_arn"` + IsDefault bool `json:"is_default"` +} + // ListenerAction defines a listener default action or a rule action. type ListenerAction struct { Type string `json:"type"` // "forward", "redirect", or "fixed-response" From 38f5dd0d4153e97a4484dea976a418810c732f11 Mon Sep 17 00:00:00 2001 From: Josh Siviour Date: Thu, 4 Jun 2026 10:13:10 +1000 Subject: [PATCH 07/73] feat(acm): minimal ACM-alike certificate service (#285) Stand up acm as its own AWS JSON 1.1 gateway service wiring the BYO-cert import/store path ELBv2 HTTPS listeners need. ImportCertificate validates tls.X509KeyPair, parses the leaf for domain/serial/expiry/key-algorithm, mints arn:aws:acm:::certificate/, and stores PEM (cert, chain, key) in JetStream KV. DescribeCertificate/ListCertificates/ DeleteCertificate round-trip; access is account-scoped. New gateway dispatch by X-Amz-Target (CertificateManager.); errors share the AWS JSON 1.1 envelope with EKS. Wired through gateway/acm ops, handlers/acm (service iface, store, NATS client), daemon handlers + acm.* subscriptions, and service-interfaces.yaml. Out of scope (future, same epic): RequestCertificate + DNS validation, managed renewal, Get/ExportCertificate, tagging, ACM-PCA. --- docs/service-interfaces.yaml | 8 + spinifex/awserrors/awserrors.go | 443 +++++++++++---------- spinifex/daemon/daemon.go | 20 + spinifex/daemon/daemon_handlers_acm.go | 19 + spinifex/gateway/acm.go | 91 +++++ spinifex/gateway/acm/certificates.go | 46 +++ spinifex/gateway/acm/certificates_test.go | 55 +++ spinifex/gateway/acm/handler.go | 40 ++ spinifex/gateway/acm_test.go | 69 ++++ spinifex/gateway/gateway.go | 10 +- spinifex/handlers/acm/service.go | 15 + spinifex/handlers/acm/service_impl.go | 236 +++++++++++ spinifex/handlers/acm/service_impl_test.go | 166 ++++++++ spinifex/handlers/acm/service_nats.go | 40 ++ spinifex/handlers/acm/service_nats_test.go | 25 ++ spinifex/handlers/acm/store.go | 143 +++++++ 16 files changed, 1205 insertions(+), 221 deletions(-) create mode 100644 spinifex/daemon/daemon_handlers_acm.go create mode 100644 spinifex/gateway/acm.go create mode 100644 spinifex/gateway/acm/certificates.go create mode 100644 spinifex/gateway/acm/certificates_test.go create mode 100644 spinifex/gateway/acm/handler.go create mode 100644 spinifex/gateway/acm_test.go create mode 100644 spinifex/handlers/acm/service.go create mode 100644 spinifex/handlers/acm/service_impl.go create mode 100644 spinifex/handlers/acm/service_impl_test.go create mode 100644 spinifex/handlers/acm/service_nats.go create mode 100644 spinifex/handlers/acm/service_nats_test.go create mode 100644 spinifex/handlers/acm/store.go diff --git a/docs/service-interfaces.yaml b/docs/service-interfaces.yaml index ad04455ac..af509c988 100644 --- a/docs/service-interfaces.yaml +++ b/docs/service-interfaces.yaml @@ -30,10 +30,12 @@ services: publishes: - "ec2.*" - "elbv2.*" + - "acm.*" - "iam.*" depends_on: - "ec2.*" - "elbv2.*" + - "acm.*" - "iam.*" spinifex_daemon: @@ -50,6 +52,7 @@ services: - spinifex/daemon - spinifex/handlers/ec2 - spinifex/handlers/elbv2 + - spinifex/handlers/acm - spinifex/handlers/iam subscribes: # EC2 instance lifecycle. @@ -95,6 +98,11 @@ services: - "elbv2.CreateListener" - "elbv2.DeleteListener" - "elbv2.DescribeListeners" + # ACM-alike certificate store (handlers/acm/service_nats.go topic map). + - "acm.ImportCertificate" + - "acm.DescribeCertificate" + - "acm.ListCertificates" + - "acm.DeleteCertificate" - "elbv2.AddListenerCertificates" - "elbv2.RemoveListenerCertificates" - "elbv2.DescribeListenerCertificates" diff --git a/spinifex/awserrors/awserrors.go b/spinifex/awserrors/awserrors.go index f7ddfa43c..65a71232c 100644 --- a/spinifex/awserrors/awserrors.go +++ b/spinifex/awserrors/awserrors.go @@ -221,225 +221,229 @@ var ( ErrorInvalidOptionConflict = "InvalidOption.Conflict" ErrorInvalidPaginationToken = "InvalidPaginationToken" ErrorInvalidParameter = "InvalidParameter" - ErrorInvalidParameterCombination = "InvalidParameterCombination" - ErrorInvalidParameterDependency = "InvalidParameterDependency" - ErrorInvalidParameterValue = "InvalidParameterValue" - ErrorInvalidPermissionDuplicate = "InvalidPermission.Duplicate" - ErrorInvalidPermissionMalformed = "InvalidPermission.Malformed" - ErrorInvalidPermissionNotFound = "InvalidPermission.NotFound" - ErrorInvalidPlacementGroupDuplicate = "InvalidPlacementGroup.Duplicate" - ErrorInvalidPlacementGroupInUse = "InvalidPlacementGroup.InUse" - ErrorInvalidPlacementGroupUnknown = "InvalidPlacementGroup.Unknown" - ErrorInvalidPlacementGroupIdMalformed = "InvalidPlacementGroupId.Malformed" - ErrorInvalidPolicyDocument = "InvalidPolicyDocument" - ErrorInvalidPrefixListIDNotFound = "InvalidPrefixListID.NotFound" - ErrorInvalidPrefixListIdMalformed = "InvalidPrefixListId.Malformed" - ErrorInvalidProductInfo = "InvalidProductInfo" - ErrorInvalidPurchaseTokenExpired = "InvalidPurchaseToken.Expired" - ErrorInvalidPurchaseTokenMalformed = "InvalidPurchaseToken.Malformed" - ErrorInvalidQuantity = "InvalidQuantity" - ErrorInvalidQueryParameter = "InvalidQueryParameter" - ErrorInvalidRamDiskIdMalformed = "InvalidRamDiskId.Malformed" - ErrorInvalidRegion = "InvalidRegion" - ErrorInvalidRequest = "InvalidRequest" - ErrorInvalidReservationIDMalformed = "InvalidReservationID.Malformed" - ErrorInvalidReservationIDNotFound = "InvalidReservationID.NotFound" - ErrorInvalidReservedInstancesId = "InvalidReservedInstancesId" - ErrorInvalidReservedInstancesOfferingId = "InvalidReservedInstancesOfferingId" - ErrorInvalidResourceConfigurationArnMalformed = "InvalidResourceConfigurationArn.Malformed" - ErrorInvalidResourceConfigurationArnNotFound = "InvalidResourceConfigurationArn.NotFound" - ErrorInvalidResourceTypeUnknown = "InvalidResourceType.Unknown" - ErrorInvalidRouteInvalidState = "InvalidRoute.InvalidState" - ErrorInvalidRouteMalformed = "InvalidRoute.Malformed" - ErrorInvalidRouteNotFound = "InvalidRoute.NotFound" - ErrorInvalidRouteTableIDNotFound = "InvalidRouteTableID.NotFound" - ErrorInvalidRouteTableIdMalformed = "InvalidRouteTableId.Malformed" - ErrorInvalidScheduledInstance = "InvalidScheduledInstance" - ErrorInvalidSecurityRequestHasExpired = "InvalidSecurity.RequestHasExpired" - ErrorInvalidSecurityGroupIDNotFound = "InvalidSecurityGroupID.NotFound" - ErrorInvalidSecurityGroupIdMalformed = "InvalidSecurityGroupId.Malformed" - ErrorInvalidSecurityGroupRuleIdMalformed = "InvalidSecurityGroupRuleId.Malformed" - ErrorInvalidSecurityGroupRuleIdNotFound = "InvalidSecurityGroupRuleId.NotFound" - ErrorInvalidServiceName = "InvalidServiceName" - ErrorInvalidSnapshotInUse = "InvalidSnapshot.InUse" - ErrorInvalidSnapshotNotFound = "InvalidSnapshot.NotFound" - ErrorInvalidSnapshotIDMalformed = "InvalidSnapshotID.Malformed" - ErrorInvalidSpotDatafeedNotFound = "InvalidSpotDatafeed.NotFound" - ErrorInvalidSpotFleetRequestConfig = "InvalidSpotFleetRequestConfig" - ErrorInvalidSpotFleetRequestIdMalformed = "InvalidSpotFleetRequestId.Malformed" - ErrorInvalidSpotFleetRequestIdNotFound = "InvalidSpotFleetRequestId.NotFound" - ErrorInvalidSpotInstanceRequestIDMalformed = "InvalidSpotInstanceRequestID.Malformed" - ErrorInvalidSpotInstanceRequestIDNotFound = "InvalidSpotInstanceRequestID.NotFound" - ErrorInvalidState = "InvalidState" - ErrorInvalidStateTransition = "InvalidStateTransition" - ErrorInvalidSubnet = "InvalidSubnet" - ErrorInvalidSubnetConflict = "InvalidSubnet.Conflict" - ErrorInvalidSubnetRange = "InvalidSubnet.Range" - ErrorInvalidSubnetIDMalformed = "InvalidSubnetID.Malformed" - ErrorInvalidSubnetIDNotFound = "InvalidSubnetID.NotFound" - ErrorInvalidTagKeyMalformed = "InvalidTagKey.Malformed" - ErrorInvalidTargetArnUnknown = "InvalidTargetArn.Unknown" - ErrorInvalidTargetException = "InvalidTargetException" - ErrorInvalidTenancy = "InvalidTenancy" - ErrorInvalidTime = "InvalidTime" - ErrorInvalidTrafficMirrorFilterNotFound = "InvalidTrafficMirrorFilterNotFound" - ErrorInvalidTrafficMirrorFilterRuleNotFound = "InvalidTrafficMirrorFilterRuleNotFound" - ErrorInvalidTrafficMirrorSessionNotFound = "InvalidTrafficMirrorSessionNotFound" - ErrorInvalidTrafficMirrorTargetNoFound = "InvalidTrafficMirrorTargetNoFound" - ErrorInvalidUserIDMalformed = "InvalidUserID.Malformed" - ErrorInvalidVolumeNotFound = "InvalidVolume.NotFound" - ErrorInvalidVolumeZoneMismatch = "InvalidVolume.ZoneMismatch" - ErrorInvalidVolumeIDDuplicate = "InvalidVolumeID.Duplicate" - ErrorInvalidVolumeIDMalformed = "InvalidVolumeID.Malformed" - ErrorInvalidVolumeIDZoneMismatch = "InvalidVolumeID.ZoneMismatch" - ErrorInvalidVpcEndpointNotFound = "InvalidVpcEndpoint.NotFound" - ErrorInvalidVpcEndpointIdMalformed = "InvalidVpcEndpointId.Malformed" - ErrorInvalidVpcEndpointIdNotFound = "InvalidVpcEndpointId.NotFound" - ErrorInvalidVpcEndpointServiceNotFound = "InvalidVpcEndpointService.NotFound" - ErrorInvalidVpcEndpointServiceIdNotFound = "InvalidVpcEndpointServiceId.NotFound" - ErrorInvalidVpcEndpointServiceIdIdMalformed = "InvalidVpcEndpointServiceIdId.Malformed" - ErrorInvalidVpcEndpointType = "InvalidVpcEndpointType" - ErrorInvalidVpcIDMalformed = "InvalidVpcID.Malformed" - ErrorInvalidVpcIDNotFound = "InvalidVpcID.NotFound" - ErrorInvalidVpcPeeringConnectionIDNotFound = "InvalidVpcPeeringConnectionID.NotFound" - ErrorInvalidVpcPeeringConnectionIdMalformed = "InvalidVpcPeeringConnectionId.Malformed" - ErrorInvalidVpcPeeringConnectionStateDnsHostnamesDisabled = "InvalidVpcPeeringConnectionState.DnsHostnamesDisabled" - ErrorInvalidVpcRange = "InvalidVpcRange" - ErrorInvalidVpcState = "InvalidVpcState" - ErrorInvalidVpnConnectionInvalidState = "InvalidVpnConnection.InvalidState" - ErrorInvalidVpnConnectionInvalidType = "InvalidVpnConnection.InvalidType" - ErrorInvalidVpnConnectionID = "InvalidVpnConnectionID" - ErrorInvalidVpnConnectionIDNotFound = "InvalidVpnConnectionID.NotFound" - ErrorInvalidVpnGatewayAttachmentNotFound = "InvalidVpnGatewayAttachment.NotFound" - ErrorInvalidVpnGatewayIDNotFound = "InvalidVpnGatewayID.NotFound" - ErrorInvalidVpnGatewayState = "InvalidVpnGatewayState" - ErrorInvalidZoneNotFound = "InvalidZone.NotFound" - ErrorKeyPairLimitExceeded = "KeyPairLimitExceeded" - ErrorLegacySecurityGroup = "LegacySecurityGroup" - ErrorLimitPriceExceeded = "LimitPriceExceeded" - ErrorLogDestinationNotFound = "LogDestinationNotFound" - ErrorLogDestinationPermissionIssue = "LogDestinationPermissionIssue" - ErrorMalformedQueryString = "MalformedQueryString" - ErrorMaxConfigLimitExceededException = "MaxConfigLimitExceededException" - ErrorMaxIOPSLimitExceeded = "MaxIOPSLimitExceeded" - ErrorMaxScheduledInstanceCapacityExceeded = "MaxScheduledInstanceCapacityExceeded" - ErrorMaxSpotFleetRequestCountExceeded = "MaxSpotFleetRequestCountExceeded" - ErrorMaxSpotInstanceCountExceeded = "MaxSpotInstanceCountExceeded" - ErrorMaxTemplateLimitExceeded = "MaxTemplateLimitExceeded" - ErrorMaxTemplateVersionLimitExceeded = "MaxTemplateVersionLimitExceeded" - ErrorMissingAction = "MissingAction" - ErrorMissingAuthenticationToken = "MissingAuthenticationToken" - ErrorMissingInput = "MissingInput" - ErrorMissingParameter = "MissingParameter" - ErrorNatGatewayLimitExceeded = "NatGatewayLimitExceeded" - ErrorNatGatewayMalformed = "NatGatewayMalformed" - ErrorNatGatewayNotFound = "NatGatewayNotFound" - ErrorNetworkAclEntryAlreadyExists = "NetworkAclEntryAlreadyExists" - ErrorNetworkAclEntryLimitExceeded = "NetworkAclEntryLimitExceeded" - ErrorNetworkAclLimitExceeded = "NetworkAclLimitExceeded" - ErrorNetworkInterfaceLimitExceeded = "NetworkInterfaceLimitExceeded" - ErrorNetworkInterfaceNotSupported = "NetworkInterfaceNotSupported" - ErrorNetworkLoadBalancerNotFoundException = "NetworkLoadBalancerNotFoundException" - ErrorNlbInUseByTrafficMirrorTargetException = "NlbInUseByTrafficMirrorTargetException" - ErrorNoSuchVersion = "NoSuchVersion" - ErrorNonEBSInstance = "NonEBSInstance" - ErrorNotExportable = "NotExportable" - ErrorNotImplemented = "NotImplemented" - ErrorOperationNotPermitted = "OperationNotPermitted" - ErrorOptInRequired = "OptInRequired" - ErrorOutstandingVpcPeeringConnectionLimitExceeded = "OutstandingVpcPeeringConnectionLimitExceeded" - ErrorPackedPolicyTooLarge = "PackedPolicyTooLarge" - ErrorPendingSnapshotLimitExceeded = "PendingSnapshotLimitExceeded" - ErrorPendingVerification = "PendingVerification" - ErrorPendingVpcPeeringConnectionLimitExceeded = "PendingVpcPeeringConnectionLimitExceeded" - ErrorPlacementGroupLimitExceeded = "PlacementGroupLimitExceeded" - ErrorPrivateIpAddressLimitExceeded = "PrivateIpAddressLimitExceeded" - ErrorRegionDisabled = "RegionDisabledException" - ErrorRequestEntityTooLarge = "RequestEntityTooLarge" - ErrorRequestExpired = "RequestExpired" - ErrorRequestLimitExceeded = "RequestLimitExceeded" - ErrorRequestResourceCountExceeded = "RequestResourceCountExceeded" - ErrorReservationCapacityExceeded = "ReservationCapacityExceeded" - ErrorReservedInstancesCountExceeded = "ReservedInstancesCountExceeded" - ErrorReservedInstancesLimitExceeded = "ReservedInstancesLimitExceeded" - ErrorReservedInstancesUnavailable = "ReservedInstancesUnavailable" - ErrorResourceAlreadyAssigned = "Resource.AlreadyAssigned" - ErrorResourceAlreadyAssociated = "Resource.AlreadyAssociated" - ErrorResourceCountExceeded = "ResourceCountExceeded" - ErrorResourceCountLimitExceeded = "ResourceCountLimitExceeded" - ErrorResourceLimitExceeded = "ResourceLimitExceeded" - ErrorResourceNotFound = "ResourceNotFound" - ErrorEKSResourceInUse = "ResourceInUseException" - ErrorEKSResourceNotFound = "ResourceNotFoundException" - ErrorRetryableError = "RetryableError" - ErrorRouteAlreadyExists = "RouteAlreadyExists" - ErrorRouteLimitExceeded = "RouteLimitExceeded" - ErrorRouteTableLimitExceeded = "RouteTableLimitExceeded" - ErrorRulesPerSecurityGroupLimitExceeded = "RulesPerSecurityGroupLimitExceeded" - ErrorScheduledInstanceLimitExceeded = "ScheduledInstanceLimitExceeded" - ErrorScheduledInstanceParameterMismatch = "ScheduledInstanceParameterMismatch" - ErrorScheduledInstanceSlotNotOpen = "ScheduledInstanceSlotNotOpen" - ErrorScheduledInstanceSlotUnavailable = "ScheduledInstanceSlotUnavailable" - ErrorSecurityGroupLimitExceeded = "SecurityGroupLimitExceeded" - ErrorSecurityGroupsPerInstanceLimitExceeded = "SecurityGroupsPerInstanceLimitExceeded" - ErrorSecurityGroupsPerInterfaceLimitExceeded = "SecurityGroupsPerInterfaceLimitExceeded" - ErrorSerialConsoleSessionUnavailable = "SerialConsoleSessionUnavailable" - ErrorServerInternal = "ServerInternal" - ErrorServiceUnavailable = "ServiceUnavailable" - ErrorSignatureDoesNotMatch = "SignatureDoesNotMatch" - ErrorSnapshotCopyUnsupportedInterRegion = "SnapshotCopyUnsupported.InterRegion" - ErrorSnapshotCreationPerVolumeRateExceeded = "SnapshotCreationPerVolumeRateExceeded" - ErrorSnapshotLimitExceeded = "SnapshotLimitExceeded" - ErrorSpotMaxPriceTooLow = "SpotMaxPriceTooLow" - ErrorSubnetLimitExceeded = "SubnetLimitExceeded" - ErrorTagLimitExceeded = "TagLimitExceeded" - ErrorTagPolicyViolation = "TagPolicyViolation" - ErrorThrottling = "Throttling" - ErrorTargetCapacityLimitExceededException = "TargetCapacityLimitExceededException" - ErrorTrafficMirrorFilterInUse = "TrafficMirrorFilterInUse" - ErrorTrafficMirrorFilterLimitExceeded = "TrafficMirrorFilterLimitExceeded" - ErrorTrafficMirrorFilterRuleAlreadyExists = "TrafficMirrorFilterRuleAlreadyExists" - ErrorTrafficMirrorFilterRuleLimitExceeded = "TrafficMirrorFilterRuleLimitExceeded" - ErrorTrafficMirrorSessionLimitExceeded = "TrafficMirrorSessionLimitExceeded" - ErrorTrafficMirrorSessionsPerInterfaceLimitExceeded = "TrafficMirrorSessionsPerInterfaceLimitExceeded" - ErrorTrafficMirrorSessionsPerTargetLimitExceeded = "TrafficMirrorSessionsPerTargetLimitExceeded" - ErrorTrafficMirrorSourcesPerTargetLimitExceeded = "TrafficMirrorSourcesPerTargetLimitExceeded" - ErrorTrafficMirrorTargetInUseException = "TrafficMirrorTargetInUseException" - ErrorTrafficMirrorTargetLimitExceeded = "TrafficMirrorTargetLimitExceeded" - ErrorUnauthorizedOperation = "UnauthorizedOperation" - ErrorUnavailable = "Unavailable" - ErrorUnavailableHostRequirements = "UnavailableHostRequirements" - ErrorUnfulfillableCapacity = "UnfulfillableCapacity" - ErrorUnknownParameter = "UnknownParameter" - ErrorUnknownPrincipalTypeUnsupported = "UnknownPrincipalType.Unsupported" - ErrorUnknownVolumeType = "UnknownVolumeType" - ErrorUnsupported = "Unsupported" - ErrorUnsupportedException = "UnsupportedException" - ErrorUnsupportedHibernationConfiguration = "UnsupportedHibernationConfiguration" - ErrorUnsupportedHostConfiguration = "UnsupportedHostConfiguration" - ErrorUnsupportedInstanceAttribute = "UnsupportedInstanceAttribute" - ErrorUnsupportedInstanceTypeOnHost = "UnsupportedInstanceTypeOnHost" - ErrorUnsupportedOperation = "UnsupportedOperation" - ErrorUnsupportedProtocol = "UnsupportedProtocol" - ErrorUnsupportedTenancy = "UnsupportedTenancy" - ErrorUpdateLimitExceeded = "UpdateLimitExceeded" - ErrorVPCIdNotSpecified = "VPCIdNotSpecified" - ErrorVPCResourceNotSpecified = "VPCResourceNotSpecified" - ErrorValidationError = "ValidationError" - ErrorVcpuLimitExceeded = "VcpuLimitExceeded" - ErrorVolumeIOPSLimit = "VolumeIOPSLimit" - ErrorVolumeInUse = "VolumeInUse" - ErrorVolumeLimitExceeded = "VolumeLimitExceeded" - ErrorVolumeModificationSizeLimitExceeded = "VolumeModificationSizeLimitExceeded" - ErrorVolumeTypeNotAvailableInZone = "VolumeTypeNotAvailableInZone" - ErrorVpcEndpointLimitExceeded = "VpcEndpointLimitExceeded" - ErrorVpcLimitExceeded = "VpcLimitExceeded" - ErrorVpcPeeringConnectionAlreadyExists = "VpcPeeringConnectionAlreadyExists" - ErrorVpcPeeringConnectionsPerVpcLimitExceeded = "VpcPeeringConnectionsPerVpcLimitExceeded" - ErrorVpnConnectionLimitExceeded = "VpnConnectionLimitExceeded" - ErrorVpnGatewayAttachmentLimitExceeded = "VpnGatewayAttachmentLimitExceeded" - ErrorVpnGatewayLimitExceeded = "VpnGatewayLimitExceeded" - ErrorZonesMismatched = "ZonesMismatched" + // ACM (AWS JSON 1.1). Suffix-less; the JSON error envelope appends + // "Exception" on the wire (InvalidArnException), matching aws-sdk-go acm + // ErrCode* values. Not-found reuses the shared ErrorResourceNotFound. + ErrorACMInvalidArn = "InvalidArn" + ErrorInvalidParameterCombination = "InvalidParameterCombination" + ErrorInvalidParameterDependency = "InvalidParameterDependency" + ErrorInvalidParameterValue = "InvalidParameterValue" + ErrorInvalidPermissionDuplicate = "InvalidPermission.Duplicate" + ErrorInvalidPermissionMalformed = "InvalidPermission.Malformed" + ErrorInvalidPermissionNotFound = "InvalidPermission.NotFound" + ErrorInvalidPlacementGroupDuplicate = "InvalidPlacementGroup.Duplicate" + ErrorInvalidPlacementGroupInUse = "InvalidPlacementGroup.InUse" + ErrorInvalidPlacementGroupUnknown = "InvalidPlacementGroup.Unknown" + ErrorInvalidPlacementGroupIdMalformed = "InvalidPlacementGroupId.Malformed" + ErrorInvalidPolicyDocument = "InvalidPolicyDocument" + ErrorInvalidPrefixListIDNotFound = "InvalidPrefixListID.NotFound" + ErrorInvalidPrefixListIdMalformed = "InvalidPrefixListId.Malformed" + ErrorInvalidProductInfo = "InvalidProductInfo" + ErrorInvalidPurchaseTokenExpired = "InvalidPurchaseToken.Expired" + ErrorInvalidPurchaseTokenMalformed = "InvalidPurchaseToken.Malformed" + ErrorInvalidQuantity = "InvalidQuantity" + ErrorInvalidQueryParameter = "InvalidQueryParameter" + ErrorInvalidRamDiskIdMalformed = "InvalidRamDiskId.Malformed" + ErrorInvalidRegion = "InvalidRegion" + ErrorInvalidRequest = "InvalidRequest" + ErrorInvalidReservationIDMalformed = "InvalidReservationID.Malformed" + ErrorInvalidReservationIDNotFound = "InvalidReservationID.NotFound" + ErrorInvalidReservedInstancesId = "InvalidReservedInstancesId" + ErrorInvalidReservedInstancesOfferingId = "InvalidReservedInstancesOfferingId" + ErrorInvalidResourceConfigurationArnMalformed = "InvalidResourceConfigurationArn.Malformed" + ErrorInvalidResourceConfigurationArnNotFound = "InvalidResourceConfigurationArn.NotFound" + ErrorInvalidResourceTypeUnknown = "InvalidResourceType.Unknown" + ErrorInvalidRouteInvalidState = "InvalidRoute.InvalidState" + ErrorInvalidRouteMalformed = "InvalidRoute.Malformed" + ErrorInvalidRouteNotFound = "InvalidRoute.NotFound" + ErrorInvalidRouteTableIDNotFound = "InvalidRouteTableID.NotFound" + ErrorInvalidRouteTableIdMalformed = "InvalidRouteTableId.Malformed" + ErrorInvalidScheduledInstance = "InvalidScheduledInstance" + ErrorInvalidSecurityRequestHasExpired = "InvalidSecurity.RequestHasExpired" + ErrorInvalidSecurityGroupIDNotFound = "InvalidSecurityGroupID.NotFound" + ErrorInvalidSecurityGroupIdMalformed = "InvalidSecurityGroupId.Malformed" + ErrorInvalidSecurityGroupRuleIdMalformed = "InvalidSecurityGroupRuleId.Malformed" + ErrorInvalidSecurityGroupRuleIdNotFound = "InvalidSecurityGroupRuleId.NotFound" + ErrorInvalidServiceName = "InvalidServiceName" + ErrorInvalidSnapshotInUse = "InvalidSnapshot.InUse" + ErrorInvalidSnapshotNotFound = "InvalidSnapshot.NotFound" + ErrorInvalidSnapshotIDMalformed = "InvalidSnapshotID.Malformed" + ErrorInvalidSpotDatafeedNotFound = "InvalidSpotDatafeed.NotFound" + ErrorInvalidSpotFleetRequestConfig = "InvalidSpotFleetRequestConfig" + ErrorInvalidSpotFleetRequestIdMalformed = "InvalidSpotFleetRequestId.Malformed" + ErrorInvalidSpotFleetRequestIdNotFound = "InvalidSpotFleetRequestId.NotFound" + ErrorInvalidSpotInstanceRequestIDMalformed = "InvalidSpotInstanceRequestID.Malformed" + ErrorInvalidSpotInstanceRequestIDNotFound = "InvalidSpotInstanceRequestID.NotFound" + ErrorInvalidState = "InvalidState" + ErrorInvalidStateTransition = "InvalidStateTransition" + ErrorInvalidSubnet = "InvalidSubnet" + ErrorInvalidSubnetConflict = "InvalidSubnet.Conflict" + ErrorInvalidSubnetRange = "InvalidSubnet.Range" + ErrorInvalidSubnetIDMalformed = "InvalidSubnetID.Malformed" + ErrorInvalidSubnetIDNotFound = "InvalidSubnetID.NotFound" + ErrorInvalidTagKeyMalformed = "InvalidTagKey.Malformed" + ErrorInvalidTargetArnUnknown = "InvalidTargetArn.Unknown" + ErrorInvalidTargetException = "InvalidTargetException" + ErrorInvalidTenancy = "InvalidTenancy" + ErrorInvalidTime = "InvalidTime" + ErrorInvalidTrafficMirrorFilterNotFound = "InvalidTrafficMirrorFilterNotFound" + ErrorInvalidTrafficMirrorFilterRuleNotFound = "InvalidTrafficMirrorFilterRuleNotFound" + ErrorInvalidTrafficMirrorSessionNotFound = "InvalidTrafficMirrorSessionNotFound" + ErrorInvalidTrafficMirrorTargetNoFound = "InvalidTrafficMirrorTargetNoFound" + ErrorInvalidUserIDMalformed = "InvalidUserID.Malformed" + ErrorInvalidVolumeNotFound = "InvalidVolume.NotFound" + ErrorInvalidVolumeZoneMismatch = "InvalidVolume.ZoneMismatch" + ErrorInvalidVolumeIDDuplicate = "InvalidVolumeID.Duplicate" + ErrorInvalidVolumeIDMalformed = "InvalidVolumeID.Malformed" + ErrorInvalidVolumeIDZoneMismatch = "InvalidVolumeID.ZoneMismatch" + ErrorInvalidVpcEndpointNotFound = "InvalidVpcEndpoint.NotFound" + ErrorInvalidVpcEndpointIdMalformed = "InvalidVpcEndpointId.Malformed" + ErrorInvalidVpcEndpointIdNotFound = "InvalidVpcEndpointId.NotFound" + ErrorInvalidVpcEndpointServiceNotFound = "InvalidVpcEndpointService.NotFound" + ErrorInvalidVpcEndpointServiceIdNotFound = "InvalidVpcEndpointServiceId.NotFound" + ErrorInvalidVpcEndpointServiceIdIdMalformed = "InvalidVpcEndpointServiceIdId.Malformed" + ErrorInvalidVpcEndpointType = "InvalidVpcEndpointType" + ErrorInvalidVpcIDMalformed = "InvalidVpcID.Malformed" + ErrorInvalidVpcIDNotFound = "InvalidVpcID.NotFound" + ErrorInvalidVpcPeeringConnectionIDNotFound = "InvalidVpcPeeringConnectionID.NotFound" + ErrorInvalidVpcPeeringConnectionIdMalformed = "InvalidVpcPeeringConnectionId.Malformed" + ErrorInvalidVpcPeeringConnectionStateDnsHostnamesDisabled = "InvalidVpcPeeringConnectionState.DnsHostnamesDisabled" + ErrorInvalidVpcRange = "InvalidVpcRange" + ErrorInvalidVpcState = "InvalidVpcState" + ErrorInvalidVpnConnectionInvalidState = "InvalidVpnConnection.InvalidState" + ErrorInvalidVpnConnectionInvalidType = "InvalidVpnConnection.InvalidType" + ErrorInvalidVpnConnectionID = "InvalidVpnConnectionID" + ErrorInvalidVpnConnectionIDNotFound = "InvalidVpnConnectionID.NotFound" + ErrorInvalidVpnGatewayAttachmentNotFound = "InvalidVpnGatewayAttachment.NotFound" + ErrorInvalidVpnGatewayIDNotFound = "InvalidVpnGatewayID.NotFound" + ErrorInvalidVpnGatewayState = "InvalidVpnGatewayState" + ErrorInvalidZoneNotFound = "InvalidZone.NotFound" + ErrorKeyPairLimitExceeded = "KeyPairLimitExceeded" + ErrorLegacySecurityGroup = "LegacySecurityGroup" + ErrorLimitPriceExceeded = "LimitPriceExceeded" + ErrorLogDestinationNotFound = "LogDestinationNotFound" + ErrorLogDestinationPermissionIssue = "LogDestinationPermissionIssue" + ErrorMalformedQueryString = "MalformedQueryString" + ErrorMaxConfigLimitExceededException = "MaxConfigLimitExceededException" + ErrorMaxIOPSLimitExceeded = "MaxIOPSLimitExceeded" + ErrorMaxScheduledInstanceCapacityExceeded = "MaxScheduledInstanceCapacityExceeded" + ErrorMaxSpotFleetRequestCountExceeded = "MaxSpotFleetRequestCountExceeded" + ErrorMaxSpotInstanceCountExceeded = "MaxSpotInstanceCountExceeded" + ErrorMaxTemplateLimitExceeded = "MaxTemplateLimitExceeded" + ErrorMaxTemplateVersionLimitExceeded = "MaxTemplateVersionLimitExceeded" + ErrorMissingAction = "MissingAction" + ErrorMissingAuthenticationToken = "MissingAuthenticationToken" + ErrorMissingInput = "MissingInput" + ErrorMissingParameter = "MissingParameter" + ErrorNatGatewayLimitExceeded = "NatGatewayLimitExceeded" + ErrorNatGatewayMalformed = "NatGatewayMalformed" + ErrorNatGatewayNotFound = "NatGatewayNotFound" + ErrorNetworkAclEntryAlreadyExists = "NetworkAclEntryAlreadyExists" + ErrorNetworkAclEntryLimitExceeded = "NetworkAclEntryLimitExceeded" + ErrorNetworkAclLimitExceeded = "NetworkAclLimitExceeded" + ErrorNetworkInterfaceLimitExceeded = "NetworkInterfaceLimitExceeded" + ErrorNetworkInterfaceNotSupported = "NetworkInterfaceNotSupported" + ErrorNetworkLoadBalancerNotFoundException = "NetworkLoadBalancerNotFoundException" + ErrorNlbInUseByTrafficMirrorTargetException = "NlbInUseByTrafficMirrorTargetException" + ErrorNoSuchVersion = "NoSuchVersion" + ErrorNonEBSInstance = "NonEBSInstance" + ErrorNotExportable = "NotExportable" + ErrorNotImplemented = "NotImplemented" + ErrorOperationNotPermitted = "OperationNotPermitted" + ErrorOptInRequired = "OptInRequired" + ErrorOutstandingVpcPeeringConnectionLimitExceeded = "OutstandingVpcPeeringConnectionLimitExceeded" + ErrorPackedPolicyTooLarge = "PackedPolicyTooLarge" + ErrorPendingSnapshotLimitExceeded = "PendingSnapshotLimitExceeded" + ErrorPendingVerification = "PendingVerification" + ErrorPendingVpcPeeringConnectionLimitExceeded = "PendingVpcPeeringConnectionLimitExceeded" + ErrorPlacementGroupLimitExceeded = "PlacementGroupLimitExceeded" + ErrorPrivateIpAddressLimitExceeded = "PrivateIpAddressLimitExceeded" + ErrorRegionDisabled = "RegionDisabledException" + ErrorRequestEntityTooLarge = "RequestEntityTooLarge" + ErrorRequestExpired = "RequestExpired" + ErrorRequestLimitExceeded = "RequestLimitExceeded" + ErrorRequestResourceCountExceeded = "RequestResourceCountExceeded" + ErrorReservationCapacityExceeded = "ReservationCapacityExceeded" + ErrorReservedInstancesCountExceeded = "ReservedInstancesCountExceeded" + ErrorReservedInstancesLimitExceeded = "ReservedInstancesLimitExceeded" + ErrorReservedInstancesUnavailable = "ReservedInstancesUnavailable" + ErrorResourceAlreadyAssigned = "Resource.AlreadyAssigned" + ErrorResourceAlreadyAssociated = "Resource.AlreadyAssociated" + ErrorResourceCountExceeded = "ResourceCountExceeded" + ErrorResourceCountLimitExceeded = "ResourceCountLimitExceeded" + ErrorResourceLimitExceeded = "ResourceLimitExceeded" + ErrorResourceNotFound = "ResourceNotFound" + ErrorEKSResourceInUse = "ResourceInUseException" + ErrorEKSResourceNotFound = "ResourceNotFoundException" + ErrorRetryableError = "RetryableError" + ErrorRouteAlreadyExists = "RouteAlreadyExists" + ErrorRouteLimitExceeded = "RouteLimitExceeded" + ErrorRouteTableLimitExceeded = "RouteTableLimitExceeded" + ErrorRulesPerSecurityGroupLimitExceeded = "RulesPerSecurityGroupLimitExceeded" + ErrorScheduledInstanceLimitExceeded = "ScheduledInstanceLimitExceeded" + ErrorScheduledInstanceParameterMismatch = "ScheduledInstanceParameterMismatch" + ErrorScheduledInstanceSlotNotOpen = "ScheduledInstanceSlotNotOpen" + ErrorScheduledInstanceSlotUnavailable = "ScheduledInstanceSlotUnavailable" + ErrorSecurityGroupLimitExceeded = "SecurityGroupLimitExceeded" + ErrorSecurityGroupsPerInstanceLimitExceeded = "SecurityGroupsPerInstanceLimitExceeded" + ErrorSecurityGroupsPerInterfaceLimitExceeded = "SecurityGroupsPerInterfaceLimitExceeded" + ErrorSerialConsoleSessionUnavailable = "SerialConsoleSessionUnavailable" + ErrorServerInternal = "ServerInternal" + ErrorServiceUnavailable = "ServiceUnavailable" + ErrorSignatureDoesNotMatch = "SignatureDoesNotMatch" + ErrorSnapshotCopyUnsupportedInterRegion = "SnapshotCopyUnsupported.InterRegion" + ErrorSnapshotCreationPerVolumeRateExceeded = "SnapshotCreationPerVolumeRateExceeded" + ErrorSnapshotLimitExceeded = "SnapshotLimitExceeded" + ErrorSpotMaxPriceTooLow = "SpotMaxPriceTooLow" + ErrorSubnetLimitExceeded = "SubnetLimitExceeded" + ErrorTagLimitExceeded = "TagLimitExceeded" + ErrorTagPolicyViolation = "TagPolicyViolation" + ErrorThrottling = "Throttling" + ErrorTargetCapacityLimitExceededException = "TargetCapacityLimitExceededException" + ErrorTrafficMirrorFilterInUse = "TrafficMirrorFilterInUse" + ErrorTrafficMirrorFilterLimitExceeded = "TrafficMirrorFilterLimitExceeded" + ErrorTrafficMirrorFilterRuleAlreadyExists = "TrafficMirrorFilterRuleAlreadyExists" + ErrorTrafficMirrorFilterRuleLimitExceeded = "TrafficMirrorFilterRuleLimitExceeded" + ErrorTrafficMirrorSessionLimitExceeded = "TrafficMirrorSessionLimitExceeded" + ErrorTrafficMirrorSessionsPerInterfaceLimitExceeded = "TrafficMirrorSessionsPerInterfaceLimitExceeded" + ErrorTrafficMirrorSessionsPerTargetLimitExceeded = "TrafficMirrorSessionsPerTargetLimitExceeded" + ErrorTrafficMirrorSourcesPerTargetLimitExceeded = "TrafficMirrorSourcesPerTargetLimitExceeded" + ErrorTrafficMirrorTargetInUseException = "TrafficMirrorTargetInUseException" + ErrorTrafficMirrorTargetLimitExceeded = "TrafficMirrorTargetLimitExceeded" + ErrorUnauthorizedOperation = "UnauthorizedOperation" + ErrorUnavailable = "Unavailable" + ErrorUnavailableHostRequirements = "UnavailableHostRequirements" + ErrorUnfulfillableCapacity = "UnfulfillableCapacity" + ErrorUnknownParameter = "UnknownParameter" + ErrorUnknownPrincipalTypeUnsupported = "UnknownPrincipalType.Unsupported" + ErrorUnknownVolumeType = "UnknownVolumeType" + ErrorUnsupported = "Unsupported" + ErrorUnsupportedException = "UnsupportedException" + ErrorUnsupportedHibernationConfiguration = "UnsupportedHibernationConfiguration" + ErrorUnsupportedHostConfiguration = "UnsupportedHostConfiguration" + ErrorUnsupportedInstanceAttribute = "UnsupportedInstanceAttribute" + ErrorUnsupportedInstanceTypeOnHost = "UnsupportedInstanceTypeOnHost" + ErrorUnsupportedOperation = "UnsupportedOperation" + ErrorUnsupportedProtocol = "UnsupportedProtocol" + ErrorUnsupportedTenancy = "UnsupportedTenancy" + ErrorUpdateLimitExceeded = "UpdateLimitExceeded" + ErrorVPCIdNotSpecified = "VPCIdNotSpecified" + ErrorVPCResourceNotSpecified = "VPCResourceNotSpecified" + ErrorValidationError = "ValidationError" + ErrorVcpuLimitExceeded = "VcpuLimitExceeded" + ErrorVolumeIOPSLimit = "VolumeIOPSLimit" + ErrorVolumeInUse = "VolumeInUse" + ErrorVolumeLimitExceeded = "VolumeLimitExceeded" + ErrorVolumeModificationSizeLimitExceeded = "VolumeModificationSizeLimitExceeded" + ErrorVolumeTypeNotAvailableInZone = "VolumeTypeNotAvailableInZone" + ErrorVpcEndpointLimitExceeded = "VpcEndpointLimitExceeded" + ErrorVpcLimitExceeded = "VpcLimitExceeded" + ErrorVpcPeeringConnectionAlreadyExists = "VpcPeeringConnectionAlreadyExists" + ErrorVpcPeeringConnectionsPerVpcLimitExceeded = "VpcPeeringConnectionsPerVpcLimitExceeded" + ErrorVpnConnectionLimitExceeded = "VpnConnectionLimitExceeded" + ErrorVpnGatewayAttachmentLimitExceeded = "VpnGatewayAttachmentLimitExceeded" + ErrorVpnGatewayLimitExceeded = "VpnGatewayLimitExceeded" + ErrorZonesMismatched = "ZonesMismatched" // IAM-specific error codes ErrorIAMNoSuchEntity = "NoSuchEntity" @@ -698,6 +702,7 @@ var ErrorLookup = map[string]ErrorMessage{ ErrorInvalidMaxResults: {HTTPCode: 400, Message: "The specified value for MaxResults is not valid."}, ErrorInvalidNatGatewayIDNotFound: {HTTPCode: 404, Message: "The specified NAT gateway ID does not exist. Ensure that you specify the AWS Region in which the NAT gateway is located, if it's not in the default Region."}, ErrorInvalidNetworkAclEntryNotFound: {HTTPCode: 404, Message: "The specified network ACL entry does not exist."}, + ErrorACMInvalidArn: {HTTPCode: 400, Message: "The requested Amazon Resource Name (ARN) does not refer to an existing resource."}, ErrorInvalidNetworkAclIDNotFound: {HTTPCode: 404, Message: "The specified network ACL does not exist. Ensure that you specify the AWS Region in which the network ACL is located, if it's not in the default Region."}, ErrorInvalidNetworkAclIdMalformed: {HTTPCode: 400, Message: "The specified network ACL ID is malformed. Ensure that you provide the ID in the form acl-xxxxxxxxxxxxxxxxx."}, ErrorInvalidNetworkInterfaceInUse: {HTTPCode: 409, Message: "The specified interface is currently in use and cannot be deleted or attached to another instance. Ensure that you have detached the network interface first. If a network interface is in use, you may also receive the InvalidParameterValue error."}, diff --git a/spinifex/daemon/daemon.go b/spinifex/daemon/daemon.go index a6fd2ce47..06c86945f 100644 --- a/spinifex/daemon/daemon.go +++ b/spinifex/daemon/daemon.go @@ -33,6 +33,7 @@ import ( "github.com/mulgadc/spinifex/spinifex/awserrors" "github.com/mulgadc/spinifex/spinifex/config" "github.com/mulgadc/spinifex/spinifex/gpu" + handlers_acm "github.com/mulgadc/spinifex/spinifex/handlers/acm" handlers_ec2_account "github.com/mulgadc/spinifex/spinifex/handlers/ec2/account" handlers_ec2_eigw "github.com/mulgadc/spinifex/spinifex/handlers/ec2/eigw" handlers_ec2_eip "github.com/mulgadc/spinifex/spinifex/handlers/ec2/eip" @@ -132,6 +133,7 @@ type Daemon struct { eipService *handlers_ec2_eip.EIPServiceImpl elbv2Service *handlers_elbv2.ELBv2ServiceImpl eksService *handlers_eks.EKSServiceImpl + acmService *handlers_acm.ACMServiceImpl routeTableService *handlers_ec2_routetable.RouteTableServiceImpl natGatewayService *handlers_ec2_natgw.NatGatewayServiceImpl externalIPAM *handlers_ec2_vpc.ExternalIPAM @@ -899,6 +901,16 @@ func (d *Daemon) subscribeAll() error { ) } + // ACM gateway → daemon subscriptions (minimal certificate store). + if d.acmService != nil { + subs = append(subs, + natsSub{"acm.ImportCertificate", d.handleACMImportCertificate, "spinifex-workers"}, + natsSub{"acm.DescribeCertificate", d.handleACMDescribeCertificate, "spinifex-workers"}, + natsSub{"acm.ListCertificates", d.handleACMListCertificates, "spinifex-workers"}, + natsSub{"acm.DeleteCertificate", d.handleACMDeleteCertificate, "spinifex-workers"}, + ) + } + // EIP operations require external IPAM (pool mode). Only subscribe when available; // without a subscriber the gateway returns a NATS timeout → clean error to the client. if d.eipService != nil { @@ -1341,6 +1353,14 @@ func (d *Daemon) startCluster() error { if err != nil { return fmt.Errorf("failed to initialize EKS service: %w", err) } + + d.acmService, err = initServiceWithRetry("ACM service", func() (*handlers_acm.ACMServiceImpl, error) { + return handlers_acm.NewACMServiceImplWithNATS(d.config, d.natsConn) + }) + if err != nil { + return fmt.Errorf("failed to initialize ACM service: %w", err) + } + if err := d.eksService.SpawnRegisteredReconcilers(); err != nil { slog.Warn("EKS: SpawnRegisteredReconcilers failed", "err", err) } diff --git a/spinifex/daemon/daemon_handlers_acm.go b/spinifex/daemon/daemon_handlers_acm.go new file mode 100644 index 000000000..cc6fdb526 --- /dev/null +++ b/spinifex/daemon/daemon_handlers_acm.go @@ -0,0 +1,19 @@ +package daemon + +import "github.com/nats-io/nats.go" + +func (d *Daemon) handleACMImportCertificate(msg *nats.Msg) { + handleNATSRequest(msg, d.acmService.ImportCertificate) +} + +func (d *Daemon) handleACMDescribeCertificate(msg *nats.Msg) { + handleNATSRequest(msg, d.acmService.DescribeCertificate) +} + +func (d *Daemon) handleACMListCertificates(msg *nats.Msg) { + handleNATSRequest(msg, d.acmService.ListCertificates) +} + +func (d *Daemon) handleACMDeleteCertificate(msg *nats.Msg) { + handleNATSRequest(msg, d.acmService.DeleteCertificate) +} diff --git a/spinifex/gateway/acm.go b/spinifex/gateway/acm.go new file mode 100644 index 000000000..33ae324b2 --- /dev/null +++ b/spinifex/gateway/acm.go @@ -0,0 +1,91 @@ +package gateway + +import ( + "errors" + "io" + "log/slog" + "net/http" + "strings" + + "github.com/mulgadc/spinifex/spinifex/awserrors" + gateway_acm "github.com/mulgadc/spinifex/spinifex/gateway/acm" +) + +// acmHandler invokes a per-action gateway function: it receives the parent +// gateway config, the caller's accountID, and the raw request body, and +// returns a typed *acm.Output (as any) or an error whose Error() is an +// awserrors code. +type acmHandler func(gw *GatewayConfig, accountID string, body []byte) (any, error) + +// acmActions maps an ACM action (the suffix of the X-Amz-Target header) to its +// handler. ACM speaks AWS JSON 1.1: the action is carried in +// "X-Amz-Target: CertificateManager.", not the query string. +var acmActions = map[string]acmHandler{ + "ImportCertificate": func(gw *GatewayConfig, acct string, b []byte) (any, error) { + return gateway_acm.ImportCertificate(gw.NATSConn, acct, b) + }, + "DescribeCertificate": func(gw *GatewayConfig, acct string, b []byte) (any, error) { + return gateway_acm.DescribeCertificate(gw.NATSConn, acct, b) + }, + "ListCertificates": func(gw *GatewayConfig, acct string, b []byte) (any, error) { + return gateway_acm.ListCertificates(gw.NATSConn, acct, b) + }, + "DeleteCertificate": func(gw *GatewayConfig, acct string, b []byte) (any, error) { + return gateway_acm.DeleteCertificate(gw.NATSConn, acct, b) + }, +} + +// acmActionFromTarget extracts the bare action name from an X-Amz-Target +// header value of the form "CertificateManager.". The service prefix +// is optional/ignored so any "." or bare "" resolves. +func acmActionFromTarget(target string) string { + if i := strings.LastIndex(target, "."); i >= 0 { + return target[i+1:] + } + return target +} + +// ACM_Request dispatches AWS JSON 1.1 ACM requests. The action is read from +// the X-Amz-Target header; the body is the JSON-encoded operation input. +// Errors are returned as plain awserrors codes; the caller (gateway.Request) +// routes them through ErrorHandler, which emits the JSON error envelope. +func (gw *GatewayConfig) ACM_Request(w http.ResponseWriter, r *http.Request) error { + action := acmActionFromTarget(r.Header.Get("X-Amz-Target")) + if action == "" { + return errors.New(awserrors.ErrorMissingAction) + } + + handler, ok := acmActions[action] + if !ok { + slog.Debug("ACM: unknown action", "action", action) + return errors.New(awserrors.ErrorInvalidAction) + } + + if err := gw.checkPolicy(r, "acm", action); err != nil { + return err + } + + if gw.NATSConn == nil { + return errors.New(awserrors.ErrorServerInternal) + } + + accountID, _ := r.Context().Value(ctxAccountID).(string) + if accountID == "" { + slog.Error("ACM_Request: no account ID in auth context") + return errors.New(awserrors.ErrorServerInternal) + } + + body, err := io.ReadAll(r.Body) + if err != nil { + slog.Error("ACM_Request: failed to read body", "err", err) + return errors.New(awserrors.ErrorInvalidParameterValue) + } + + output, err := handler(gw, accountID, body) + if err != nil { + return err + } + + gateway_acm.WriteJSONResponse(w, output) + return nil +} diff --git a/spinifex/gateway/acm/certificates.go b/spinifex/gateway/acm/certificates.go new file mode 100644 index 000000000..14c66e8ef --- /dev/null +++ b/spinifex/gateway/acm/certificates.go @@ -0,0 +1,46 @@ +package gateway_acm + +import ( + "errors" + + "github.com/aws/aws-sdk-go/service/acm" + "github.com/mulgadc/spinifex/spinifex/awserrors" + handlers_acm "github.com/mulgadc/spinifex/spinifex/handlers/acm" + "github.com/nats-io/nats.go" +) + +// ImportCertificate — CertificateManager.ImportCertificate +func ImportCertificate(natsConn *nats.Conn, accountID string, body []byte) (*acm.ImportCertificateOutput, error) { + input := new(acm.ImportCertificateInput) + if err := unmarshalIfBody(body, input); err != nil { + return nil, errors.New(awserrors.ErrorInvalidParameter) + } + return handlers_acm.NewNATSACMService(natsConn).ImportCertificate(input, accountID) +} + +// DescribeCertificate — CertificateManager.DescribeCertificate +func DescribeCertificate(natsConn *nats.Conn, accountID string, body []byte) (*acm.DescribeCertificateOutput, error) { + input := new(acm.DescribeCertificateInput) + if err := unmarshalIfBody(body, input); err != nil { + return nil, errors.New(awserrors.ErrorInvalidParameter) + } + return handlers_acm.NewNATSACMService(natsConn).DescribeCertificate(input, accountID) +} + +// ListCertificates — CertificateManager.ListCertificates +func ListCertificates(natsConn *nats.Conn, accountID string, body []byte) (*acm.ListCertificatesOutput, error) { + input := new(acm.ListCertificatesInput) + if err := unmarshalIfBody(body, input); err != nil { + return nil, errors.New(awserrors.ErrorInvalidParameter) + } + return handlers_acm.NewNATSACMService(natsConn).ListCertificates(input, accountID) +} + +// DeleteCertificate — CertificateManager.DeleteCertificate +func DeleteCertificate(natsConn *nats.Conn, accountID string, body []byte) (*acm.DeleteCertificateOutput, error) { + input := new(acm.DeleteCertificateInput) + if err := unmarshalIfBody(body, input); err != nil { + return nil, errors.New(awserrors.ErrorInvalidParameter) + } + return handlers_acm.NewNATSACMService(natsConn).DeleteCertificate(input, accountID) +} diff --git a/spinifex/gateway/acm/certificates_test.go b/spinifex/gateway/acm/certificates_test.go new file mode 100644 index 000000000..006b43fbb --- /dev/null +++ b/spinifex/gateway/acm/certificates_test.go @@ -0,0 +1,55 @@ +package gateway_acm + +import ( + "net/http/httptest" + "testing" + + "github.com/mulgadc/spinifex/spinifex/awserrors" + "github.com/mulgadc/spinifex/spinifex/testutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestUnmarshalIfBody(t *testing.T) { + var out struct { + A string `json:"a"` + } + require.NoError(t, unmarshalIfBody(nil, &out)) + require.NoError(t, unmarshalIfBody([]byte(`{"a":"x"}`), &out)) + assert.Equal(t, "x", out.A) + require.Error(t, unmarshalIfBody([]byte("{bad"), &out)) +} + +func TestWriteJSONResponse(t *testing.T) { + w := httptest.NewRecorder() + WriteJSONResponse(w, map[string]string{"CertificateArn": "arn:aws:acm:x"}) + assert.Equal(t, JSONContentType, w.Header().Get("Content-Type")) + assert.Contains(t, w.Body.String(), "CertificateArn") +} + +// Invalid JSON bodies are rejected before any NATS round-trip. +func TestOps_InvalidBodyRejected(t *testing.T) { + bad := []byte("{not json") + _, err := ImportCertificate(nil, "acct", bad) + assert.ErrorContains(t, err, awserrors.ErrorInvalidParameter) + _, err = DescribeCertificate(nil, "acct", bad) + assert.ErrorContains(t, err, awserrors.ErrorInvalidParameter) + _, err = ListCertificates(nil, "acct", bad) + assert.ErrorContains(t, err, awserrors.ErrorInvalidParameter) + _, err = DeleteCertificate(nil, "acct", bad) + assert.ErrorContains(t, err, awserrors.ErrorInvalidParameter) +} + +// With a live conn but no daemon subscriber, the delegate path fast-fails with +// no-responders — exercising the NATSRequest call site in each op. +func TestOps_DelegateNoResponder(t *testing.T) { + _, nc, _ := testutil.StartTestJetStream(t) + _, err := ImportCertificate(nc, "acct", []byte(`{}`)) + require.Error(t, err) + _, err = DescribeCertificate(nc, "acct", []byte(`{}`)) + require.Error(t, err) + _, err = ListCertificates(nc, "acct", []byte(`{}`)) + require.Error(t, err) + _, err = DeleteCertificate(nc, "acct", []byte(`{}`)) + require.Error(t, err) +} diff --git a/spinifex/gateway/acm/handler.go b/spinifex/gateway/acm/handler.go new file mode 100644 index 000000000..aa4bf6014 --- /dev/null +++ b/spinifex/gateway/acm/handler.go @@ -0,0 +1,40 @@ +// Package gateway_acm is the HTTP-side glue between awsgw and the acm handlers +// package. ACM speaks AWS JSON 1.1 (X-Amz-Target dispatch, Content-Type +// application/x-amz-json-1.1), so responses are JSON throughout. Error +// envelopes are emitted centrally by the shared gateway ErrorHandler. +package gateway_acm + +import ( + "encoding/json" + "log/slog" + "net/http" + + "github.com/mulgadc/spinifex/spinifex/awserrors" +) + +// JSONContentType is the AWS JSON 1.1 content type ACM clients expect. +const JSONContentType = "application/x-amz-json-1.1" + +// WriteJSONResponse serialises obj as a 200 AWS JSON 1.1 response. +func WriteJSONResponse(w http.ResponseWriter, obj any) { + body, err := json.Marshal(obj) + if err != nil { + slog.Error("ACM: failed to marshal response JSON", "err", err) + http.Error(w, awserrors.ErrorInternalError, http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", JSONContentType) + w.WriteHeader(http.StatusOK) + if _, err := w.Write(body); err != nil { + slog.Error("ACM: failed to write response", "err", err) + } +} + +// unmarshalIfBody decodes body into out only when body is non-empty, so +// actions with an optional body share one helper. +func unmarshalIfBody(body []byte, out any) error { + if len(body) == 0 { + return nil + } + return json.Unmarshal(body, out) +} diff --git a/spinifex/gateway/acm_test.go b/spinifex/gateway/acm_test.go new file mode 100644 index 000000000..8e24dffab --- /dev/null +++ b/spinifex/gateway/acm_test.go @@ -0,0 +1,69 @@ +package gateway + +import ( + "context" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/mulgadc/spinifex/spinifex/awserrors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func setupACMRequest(target, body string) *http.Request { + req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(body)) + if target != "" { + req.Header.Set("X-Amz-Target", target) + } + ctx := context.WithValue(req.Context(), ctxService, "acm") + ctx = context.WithValue(ctx, ctxAccountID, "123456789012") + return req.WithContext(ctx) +} + +func TestACMActionFromTarget(t *testing.T) { + assert.Equal(t, "ImportCertificate", acmActionFromTarget("CertificateManager.ImportCertificate")) + assert.Equal(t, "ListCertificates", acmActionFromTarget("ListCertificates")) + assert.Equal(t, "", acmActionFromTarget("")) +} + +func TestACMActionsMap_AllActionsRegistered(t *testing.T) { + expected := []string{ + "ImportCertificate", + "DescribeCertificate", + "ListCertificates", + "DeleteCertificate", + } + for _, action := range expected { + _, ok := acmActions[action] + assert.True(t, ok, "action %q should be registered in acmActions", action) + } + assert.Len(t, acmActions, len(expected)) +} + +func TestACMRequest_MissingTarget(t *testing.T) { + gw := &GatewayConfig{DisableLogging: true} + w := httptest.NewRecorder() + err := gw.ACM_Request(w, setupACMRequest("", "")) + require.Error(t, err) + assert.Equal(t, awserrors.ErrorMissingAction, err.Error()) +} + +func TestACMRequest_UnknownAction(t *testing.T) { + gw := &GatewayConfig{DisableLogging: true} + w := httptest.NewRecorder() + err := gw.ACM_Request(w, setupACMRequest("CertificateManager.RequestCertificate", "{}")) + require.Error(t, err) + assert.Equal(t, awserrors.ErrorInvalidAction, err.Error()) +} + +// A known action with no NATS connection passes routing + policy and fails at +// the NATS-availability guard. +func TestACMRequest_KnownActionNoNATS(t *testing.T) { + gw := &GatewayConfig{DisableLogging: true} + w := httptest.NewRecorder() + err := gw.ACM_Request(w, setupACMRequest("CertificateManager.ListCertificates", "{}")) + require.Error(t, err) + assert.Equal(t, awserrors.ErrorServerInternal, err.Error()) +} diff --git a/spinifex/gateway/gateway.go b/spinifex/gateway/gateway.go index 4705cc548..cbb3803f4 100644 --- a/spinifex/gateway/gateway.go +++ b/spinifex/gateway/gateway.go @@ -75,6 +75,7 @@ var supportedServices = map[string]bool{ "account": true, "elasticloadbalancing": true, "eks": true, + "acm": true, "spinifex": true, } @@ -305,6 +306,8 @@ func (gw *GatewayConfig) Request(w http.ResponseWriter, r *http.Request) { err = gw.ELBv2_Request(w, r) case "eks": err = gw.EKS_Request(w, r) + case "acm": + err = gw.ACM_Request(w, r) case "spinifex": err = gw.Spinifex_Request(w, r) default: @@ -457,9 +460,12 @@ func (gw *GatewayConfig) ErrorHandler(w http.ResponseWriter, r *http.Request, er errorMsg.HTTPCode = 500 } - if svc == "eks" { + // EKS and ACM both use the AWS JSON 1.1 error envelope + // ({"__type":"Exception","message":...}, Content-Type + // application/x-amz-json-1.1). Query/XML services fall through below. + if svc == "eks" || svc == "acm" { body := GenerateEKSErrorResponse(err.Error(), errorMsg.Message, requestId) - slog.Debug("Generated EKS error response", "error", err.Error(), "json", string(body), "requestId", requestId) + slog.Debug("Generated JSON error response", "service", svc, "error", err.Error(), "json", string(body), "requestId", requestId) w.Header().Set("Content-Type", eksJSONContentType) w.WriteHeader(errorMsg.HTTPCode) if _, err := w.Write(body); err != nil { diff --git a/spinifex/handlers/acm/service.go b/spinifex/handlers/acm/service.go new file mode 100644 index 000000000..c4cd937d1 --- /dev/null +++ b/spinifex/handlers/acm/service.go @@ -0,0 +1,15 @@ +package handlers_acm + +import "github.com/aws/aws-sdk-go/service/acm" + +// ACMService is the minimal AWS Certificate Manager-alike control plane: BYO +// certificate import and lifecycle. It covers only what ELBv2 HTTPS listeners +// need to resolve a Certificates[].CertificateArn to PEM material. Request +// flows (RequestCertificate + DNS/email validation), renewal, export, and +// tagging are intentionally out of scope for now. +type ACMService interface { + ImportCertificate(input *acm.ImportCertificateInput, accountID string) (*acm.ImportCertificateOutput, error) + DescribeCertificate(input *acm.DescribeCertificateInput, accountID string) (*acm.DescribeCertificateOutput, error) + ListCertificates(input *acm.ListCertificatesInput, accountID string) (*acm.ListCertificatesOutput, error) + DeleteCertificate(input *acm.DeleteCertificateInput, accountID string) (*acm.DeleteCertificateOutput, error) +} diff --git a/spinifex/handlers/acm/service_impl.go b/spinifex/handlers/acm/service_impl.go new file mode 100644 index 000000000..6ca51de2f --- /dev/null +++ b/spinifex/handlers/acm/service_impl.go @@ -0,0 +1,236 @@ +package handlers_acm + +import ( + "crypto/ecdsa" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "log/slog" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/acm" + "github.com/google/uuid" + "github.com/mulgadc/spinifex/spinifex/awserrors" + "github.com/mulgadc/spinifex/spinifex/config" + "github.com/nats-io/nats.go" +) + +const ( + defaultRegion = "ap-southeast-2" + + certStatusIssued = "ISSUED" + certTypeImported = "IMPORTED" +) + +// ACMServiceImpl is the local, KV-backed implementation of ACMService. +type ACMServiceImpl struct { + store *Store + region string +} + +var _ ACMService = (*ACMServiceImpl)(nil) + +// NewACMServiceImplWithNATS builds an ACM service backed by a JetStream KV +// store. cfg may be nil (tests); region then falls back to the default. +func NewACMServiceImplWithNATS(cfg *config.Config, nc *nats.Conn) (*ACMServiceImpl, error) { + store, err := NewStore(nc) + if err != nil { + return nil, err + } + region := defaultRegion + if cfg != nil && cfg.Region != "" { + region = cfg.Region + } + return &ACMServiceImpl{store: store, region: region}, nil +} + +// mintCertificateArn generates an ACM-style certificate ARN for accountID. +func (s *ACMServiceImpl) mintCertificateArn(accountID string) string { + return fmt.Sprintf("arn:aws:acm:%s:%s:certificate/%s", s.region, accountID, uuid.NewString()) +} + +// ImportCertificate validates the PEM material, parses the leaf for metadata, +// and stores it under a new (or, on re-import, the supplied) ACM ARN. +func (s *ACMServiceImpl) ImportCertificate(input *acm.ImportCertificateInput, accountID string) (*acm.ImportCertificateOutput, error) { + if input == nil || len(input.Certificate) == 0 || len(input.PrivateKey) == 0 { + return nil, errors.New(awserrors.ErrorInvalidParameter) + } + + // The leaf cert and private key must form a valid keypair. + if _, err := tls.X509KeyPair(input.Certificate, input.PrivateKey); err != nil { + slog.Debug("ImportCertificate: keypair validation failed", "err", err) + return nil, errors.New(awserrors.ErrorInvalidParameter) + } + + leaf, err := parseLeaf(input.Certificate) + if err != nil { + return nil, errors.New(awserrors.ErrorInvalidParameter) + } + + certArn := aws.StringValue(input.CertificateArn) + if certArn == "" { + certArn = s.mintCertificateArn(accountID) + } else { + // Re-import: the ARN must already exist and belong to the caller. + existing, gErr := s.store.GetCert(certArn) + if gErr != nil { + return nil, errors.New(awserrors.ErrorInternalError) + } + if existing == nil || existing.AccountID != accountID { + return nil, errors.New(awserrors.ErrorResourceNotFound) + } + } + + rec := &CertRecord{ + CertificateArn: certArn, + AccountID: accountID, + Certificate: string(input.Certificate), + CertificateChain: string(input.CertificateChain), + PrivateKey: string(input.PrivateKey), + DomainName: leafDomain(leaf), + SubjectAltNames: leaf.DNSNames, + Serial: leaf.SerialNumber.Text(16), + Subject: leaf.Subject.String(), + Issuer: leaf.Issuer.String(), + KeyAlgorithm: keyAlgorithm(leaf), + NotBefore: leaf.NotBefore, + NotAfter: leaf.NotAfter, + ImportedAt: time.Now().UTC(), + } + if err := s.store.PutCert(rec); err != nil { + slog.Error("ImportCertificate: store failed", "err", err) + return nil, errors.New(awserrors.ErrorInternalError) + } + + slog.Info("ImportCertificate: stored", "arn", certArn, "domain", rec.DomainName, "account", accountID) + return &acm.ImportCertificateOutput{CertificateArn: aws.String(certArn)}, nil +} + +// DescribeCertificate returns the CertificateDetail for an owned ARN. +func (s *ACMServiceImpl) DescribeCertificate(input *acm.DescribeCertificateInput, accountID string) (*acm.DescribeCertificateOutput, error) { + if input == nil || aws.StringValue(input.CertificateArn) == "" { + return nil, errors.New(awserrors.ErrorACMInvalidArn) + } + rec, err := s.lookupOwned(aws.StringValue(input.CertificateArn), accountID) + if err != nil { + return nil, err + } + return &acm.DescribeCertificateOutput{Certificate: recordToDetail(rec)}, nil +} + +// ListCertificates returns summaries for every cert owned by accountID. +func (s *ACMServiceImpl) ListCertificates(input *acm.ListCertificatesInput, accountID string) (*acm.ListCertificatesOutput, error) { + recs, err := s.store.ListCerts(accountID) + if err != nil { + return nil, errors.New(awserrors.ErrorInternalError) + } + out := &acm.ListCertificatesOutput{} + for _, rec := range recs { + out.CertificateSummaryList = append(out.CertificateSummaryList, &acm.CertificateSummary{ + CertificateArn: aws.String(rec.CertificateArn), + DomainName: aws.String(rec.DomainName), + Status: aws.String(certStatusIssued), + Type: aws.String(certTypeImported), + KeyAlgorithm: aws.String(rec.KeyAlgorithm), + NotBefore: timePtr(rec.NotBefore), + NotAfter: timePtr(rec.NotAfter), + ImportedAt: timePtr(rec.ImportedAt), + InUse: aws.Bool(false), + }) + } + return out, nil +} + +// DeleteCertificate removes an owned cert; unknown ARN → ResourceNotFound. +func (s *ACMServiceImpl) DeleteCertificate(input *acm.DeleteCertificateInput, accountID string) (*acm.DeleteCertificateOutput, error) { + if input == nil || aws.StringValue(input.CertificateArn) == "" { + return nil, errors.New(awserrors.ErrorACMInvalidArn) + } + if _, err := s.lookupOwned(aws.StringValue(input.CertificateArn), accountID); err != nil { + return nil, err + } + if _, err := s.store.DeleteCert(aws.StringValue(input.CertificateArn)); err != nil { + return nil, errors.New(awserrors.ErrorInternalError) + } + return &acm.DeleteCertificateOutput{}, nil +} + +// lookupOwned fetches a cert by ARN, returning ResourceNotFound when absent or +// owned by a different account (no cross-account disclosure). +func (s *ACMServiceImpl) lookupOwned(certArn, accountID string) (*CertRecord, error) { + rec, err := s.store.GetCert(certArn) + if err != nil { + return nil, errors.New(awserrors.ErrorInternalError) + } + if rec == nil || rec.AccountID != accountID { + return nil, errors.New(awserrors.ErrorResourceNotFound) + } + return rec, nil +} + +func recordToDetail(rec *CertRecord) *acm.CertificateDetail { + detail := &acm.CertificateDetail{ + CertificateArn: aws.String(rec.CertificateArn), + DomainName: aws.String(rec.DomainName), + Serial: aws.String(rec.Serial), + Subject: aws.String(rec.Subject), + Issuer: aws.String(rec.Issuer), + KeyAlgorithm: aws.String(rec.KeyAlgorithm), + Status: aws.String(certStatusIssued), + Type: aws.String(certTypeImported), + NotBefore: timePtr(rec.NotBefore), + NotAfter: timePtr(rec.NotAfter), + ImportedAt: timePtr(rec.ImportedAt), + InUseBy: []*string{}, + } + if len(rec.SubjectAltNames) > 0 { + detail.SubjectAlternativeNames = aws.StringSlice(rec.SubjectAltNames) + } + return detail +} + +func timePtr(t time.Time) *time.Time { + if t.IsZero() { + return nil + } + return &t +} + +// parseLeaf decodes the first CERTIFICATE block from certPEM and parses it. +func parseLeaf(certPEM []byte) (*x509.Certificate, error) { + block, _ := pem.Decode(certPEM) + if block == nil || block.Type != "CERTIFICATE" { + return nil, fmt.Errorf("no PEM CERTIFICATE block") + } + return x509.ParseCertificate(block.Bytes) +} + +// leafDomain returns the certificate's primary domain: CommonName, else the +// first SAN, else empty. +func leafDomain(leaf *x509.Certificate) string { + if cn := strings.TrimSpace(leaf.Subject.CommonName); cn != "" { + return cn + } + if len(leaf.DNSNames) > 0 { + return leaf.DNSNames[0] + } + return "" +} + +// keyAlgorithm maps the leaf public key to an ACM-style algorithm string +// (RSA_2048, EC_prime256v1, ...). +func keyAlgorithm(leaf *x509.Certificate) string { + switch pub := leaf.PublicKey.(type) { + case *rsa.PublicKey: + return fmt.Sprintf("RSA_%d", pub.N.BitLen()) + case *ecdsa.PublicKey: + return "EC_" + pub.Curve.Params().Name + default: + return "UNKNOWN" + } +} diff --git a/spinifex/handlers/acm/service_impl_test.go b/spinifex/handlers/acm/service_impl_test.go new file mode 100644 index 000000000..7c8729176 --- /dev/null +++ b/spinifex/handlers/acm/service_impl_test.go @@ -0,0 +1,166 @@ +package handlers_acm + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/acm" + "github.com/mulgadc/spinifex/spinifex/awserrors" + "github.com/mulgadc/spinifex/spinifex/testutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const testAccountID = "000000000001" + +func setupACMService(t *testing.T) *ACMServiceImpl { + t.Helper() + _, nc, _ := testutil.StartTestJetStream(t) + svc, err := NewACMServiceImplWithNATS(nil, nc) + require.NoError(t, err) + return svc +} + +// genCert returns a self-signed leaf certificate + private key as PEM for the +// given common name. +func genCert(t *testing.T, cn string, dnsNames ...string) (certPEM, keyPEM []byte) { + t.Helper() + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + require.NoError(t, err) + + tmpl := &x509.Certificate{ + SerialNumber: big.NewInt(time.Now().UnixNano()), + Subject: pkix.Name{CommonName: cn}, + DNSNames: dnsNames, + NotBefore: time.Now().Add(-time.Hour), + NotAfter: time.Now().Add(24 * time.Hour), + KeyUsage: x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + } + der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &key.PublicKey, key) + require.NoError(t, err) + keyDER, err := x509.MarshalECPrivateKey(key) + require.NoError(t, err) + + certPEM = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der}) + keyPEM = pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: keyDER}) + return certPEM, keyPEM +} + +func TestImportCertificate_MintsArnAndParsesLeaf(t *testing.T) { + svc := setupACMService(t) + certPEM, keyPEM := genCert(t, "example.com", "example.com", "www.example.com") + + out, err := svc.ImportCertificate(&acm.ImportCertificateInput{ + Certificate: certPEM, + PrivateKey: keyPEM, + }, testAccountID) + require.NoError(t, err) + require.NotNil(t, out.CertificateArn) + assert.Contains(t, aws.StringValue(out.CertificateArn), "arn:aws:acm:") + assert.Contains(t, aws.StringValue(out.CertificateArn), ":"+testAccountID+":certificate/") + + desc, err := svc.DescribeCertificate(&acm.DescribeCertificateInput{ + CertificateArn: out.CertificateArn, + }, testAccountID) + require.NoError(t, err) + d := desc.Certificate + assert.Equal(t, "example.com", aws.StringValue(d.DomainName)) + assert.Equal(t, certStatusIssued, aws.StringValue(d.Status)) + assert.Equal(t, certTypeImported, aws.StringValue(d.Type)) + assert.Equal(t, "EC_P-256", aws.StringValue(d.KeyAlgorithm)) + assert.ElementsMatch(t, []string{"example.com", "www.example.com"}, aws.StringValueSlice(d.SubjectAlternativeNames)) + require.NotNil(t, d.NotAfter) +} + +func TestImportCertificate_MismatchedKeyRejected(t *testing.T) { + svc := setupACMService(t) + certPEM, _ := genCert(t, "a.example.com") + _, otherKey := genCert(t, "b.example.com") + + _, err := svc.ImportCertificate(&acm.ImportCertificateInput{ + Certificate: certPEM, + PrivateKey: otherKey, + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorInvalidParameter) +} + +func TestImportCertificate_GarbagePEMRejected(t *testing.T) { + svc := setupACMService(t) + _, err := svc.ImportCertificate(&acm.ImportCertificateInput{ + Certificate: []byte("not a pem"), + PrivateKey: []byte("nope"), + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorInvalidParameter) +} + +func TestListCertificates_ScopedToAccount(t *testing.T) { + svc := setupACMService(t) + c1, k1 := genCert(t, "one.example.com") + c2, k2 := genCert(t, "two.example.com") + + _, err := svc.ImportCertificate(&acm.ImportCertificateInput{Certificate: c1, PrivateKey: k1}, testAccountID) + require.NoError(t, err) + _, err = svc.ImportCertificate(&acm.ImportCertificateInput{Certificate: c2, PrivateKey: k2}, "000000000002") + require.NoError(t, err) + + list, err := svc.ListCertificates(&acm.ListCertificatesInput{}, testAccountID) + require.NoError(t, err) + require.Len(t, list.CertificateSummaryList, 1) + assert.Equal(t, "one.example.com", aws.StringValue(list.CertificateSummaryList[0].DomainName)) +} + +func TestDescribeCertificate_CrossAccountHidden(t *testing.T) { + svc := setupACMService(t) + c1, k1 := genCert(t, "secret.example.com") + out, err := svc.ImportCertificate(&acm.ImportCertificateInput{Certificate: c1, PrivateKey: k1}, testAccountID) + require.NoError(t, err) + + _, err = svc.DescribeCertificate(&acm.DescribeCertificateInput{ + CertificateArn: out.CertificateArn, + }, "000000000002") + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorResourceNotFound) +} + +func TestDeleteCertificate(t *testing.T) { + svc := setupACMService(t) + c1, k1 := genCert(t, "del.example.com") + out, err := svc.ImportCertificate(&acm.ImportCertificateInput{Certificate: c1, PrivateKey: k1}, testAccountID) + require.NoError(t, err) + + _, err = svc.DeleteCertificate(&acm.DeleteCertificateInput{CertificateArn: out.CertificateArn}, testAccountID) + require.NoError(t, err) + + // Gone now. + _, err = svc.DescribeCertificate(&acm.DescribeCertificateInput{CertificateArn: out.CertificateArn}, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorResourceNotFound) + + // Deleting again → ResourceNotFound. + _, err = svc.DeleteCertificate(&acm.DeleteCertificateInput{CertificateArn: out.CertificateArn}, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorResourceNotFound) +} + +func TestImportCertificate_ReimportUnknownArnRejected(t *testing.T) { + svc := setupACMService(t) + c1, k1 := genCert(t, "re.example.com") + _, err := svc.ImportCertificate(&acm.ImportCertificateInput{ + Certificate: c1, + PrivateKey: k1, + CertificateArn: aws.String("arn:aws:acm:ap-southeast-2:000000000001:certificate/does-not-exist"), + }, testAccountID) + require.Error(t, err) + assert.Contains(t, err.Error(), awserrors.ErrorResourceNotFound) +} diff --git a/spinifex/handlers/acm/service_nats.go b/spinifex/handlers/acm/service_nats.go new file mode 100644 index 000000000..da5ad276f --- /dev/null +++ b/spinifex/handlers/acm/service_nats.go @@ -0,0 +1,40 @@ +package handlers_acm + +import ( + "time" + + "github.com/aws/aws-sdk-go/service/acm" + "github.com/mulgadc/spinifex/spinifex/utils" + "github.com/nats-io/nats.go" +) + +const defaultTimeout = 30 * time.Second + +// NATSACMService is the gateway-side client that forwards ACM operations to +// the daemon over NATS request/response. +type NATSACMService struct { + natsConn *nats.Conn +} + +var _ ACMService = (*NATSACMService)(nil) + +// NewNATSACMService creates a NATS-backed ACM service client. +func NewNATSACMService(conn *nats.Conn) ACMService { + return &NATSACMService{natsConn: conn} +} + +func (s *NATSACMService) ImportCertificate(input *acm.ImportCertificateInput, accountID string) (*acm.ImportCertificateOutput, error) { + return utils.NATSRequest[acm.ImportCertificateOutput](s.natsConn, "acm.ImportCertificate", input, defaultTimeout, accountID) +} + +func (s *NATSACMService) DescribeCertificate(input *acm.DescribeCertificateInput, accountID string) (*acm.DescribeCertificateOutput, error) { + return utils.NATSRequest[acm.DescribeCertificateOutput](s.natsConn, "acm.DescribeCertificate", input, defaultTimeout, accountID) +} + +func (s *NATSACMService) ListCertificates(input *acm.ListCertificatesInput, accountID string) (*acm.ListCertificatesOutput, error) { + return utils.NATSRequest[acm.ListCertificatesOutput](s.natsConn, "acm.ListCertificates", input, defaultTimeout, accountID) +} + +func (s *NATSACMService) DeleteCertificate(input *acm.DeleteCertificateInput, accountID string) (*acm.DeleteCertificateOutput, error) { + return utils.NATSRequest[acm.DeleteCertificateOutput](s.natsConn, "acm.DeleteCertificate", input, defaultTimeout, accountID) +} diff --git a/spinifex/handlers/acm/service_nats_test.go b/spinifex/handlers/acm/service_nats_test.go new file mode 100644 index 000000000..b2e0c8e64 --- /dev/null +++ b/spinifex/handlers/acm/service_nats_test.go @@ -0,0 +1,25 @@ +package handlers_acm + +import ( + "testing" + + "github.com/aws/aws-sdk-go/service/acm" + "github.com/mulgadc/spinifex/spinifex/testutil" + "github.com/stretchr/testify/require" +) + +// With no daemon subscribed to acm.*, each NATS request fast-fails with +// no-responders. The point is to exercise the client delegation paths. +func TestNATSACMService_NoResponder(t *testing.T) { + _, nc, _ := testutil.StartTestJetStream(t) + svc := NewNATSACMService(nc) + + _, err := svc.ImportCertificate(&acm.ImportCertificateInput{}, testAccountID) + require.Error(t, err) + _, err = svc.DescribeCertificate(&acm.DescribeCertificateInput{}, testAccountID) + require.Error(t, err) + _, err = svc.ListCertificates(&acm.ListCertificatesInput{}, testAccountID) + require.Error(t, err) + _, err = svc.DeleteCertificate(&acm.DeleteCertificateInput{}, testAccountID) + require.Error(t, err) +} diff --git a/spinifex/handlers/acm/store.go b/spinifex/handlers/acm/store.go new file mode 100644 index 000000000..7764f045f --- /dev/null +++ b/spinifex/handlers/acm/store.go @@ -0,0 +1,143 @@ +package handlers_acm + +import ( + "encoding/json" + "errors" + "fmt" + "log/slog" + "strings" + "time" + + "github.com/mulgadc/spinifex/spinifex/utils" + "github.com/nats-io/nats.go" +) + +const ( + KVBucketACM = "spinifex-acm" + KVBucketACMVersion = 1 + + // KeyPrefixCert namespaces certificate records within the bucket. + KeyPrefixCert = "cert." +) + +// CertRecord is the stored representation of an imported certificate. PEM +// material (leaf, chain, private key) is held alongside the parsed metadata +// surfaced by DescribeCertificate. AccountID scopes ownership so list/describe +// never cross account boundaries. +type CertRecord struct { + CertificateArn string `json:"certificate_arn"` + AccountID string `json:"account_id"` + Certificate string `json:"certificate"` + CertificateChain string `json:"certificate_chain,omitempty"` + PrivateKey string `json:"private_key"` + DomainName string `json:"domain_name"` + SubjectAltNames []string `json:"subject_alt_names,omitempty"` + Serial string `json:"serial"` + Subject string `json:"subject"` + Issuer string `json:"issuer"` + KeyAlgorithm string `json:"key_algorithm"` + NotBefore time.Time `json:"not_before"` + NotAfter time.Time `json:"not_after"` + ImportedAt time.Time `json:"imported_at"` +} + +// Store provides CRUD for ACM certificate records backed by JetStream KV. +type Store struct { + kv nats.KeyValue +} + +// NewStore creates an ACM store using the provided NATS connection. +func NewStore(nc *nats.Conn) (*Store, error) { + js, err := nc.JetStream() + if err != nil { + return nil, fmt.Errorf("failed to get JetStream context: %w", err) + } + + kv, err := utils.GetOrCreateKVBucket(js, KVBucketACM, KVBucketACMVersion) + if err != nil { + return nil, fmt.Errorf("failed to create KV bucket %s: %w", KVBucketACM, err) + } + + slog.Info("ACM store initialized", "bucket", KVBucketACM) + return &Store{kv: kv}, nil +} + +// certKey derives the KV key from a certificate ARN. The ARN's certificate ID +// (the UUID after "certificate/") is the stable per-record key. +func certKey(certArn string) string { + id := certArn + if i := strings.LastIndex(certArn, "/"); i >= 0 { + id = certArn[i+1:] + } + return KeyPrefixCert + id +} + +// PutCert stores (or replaces) a certificate record. +func (s *Store) PutCert(rec *CertRecord) error { + data, err := json.Marshal(rec) + if err != nil { + return fmt.Errorf("marshal cert: %w", err) + } + _, err = s.kv.Put(certKey(rec.CertificateArn), data) + return err +} + +// GetCert retrieves a certificate by ARN, returning (nil, nil) when absent. +func (s *Store) GetCert(certArn string) (*CertRecord, error) { + entry, err := s.kv.Get(certKey(certArn)) + if err != nil { + if errors.Is(err, nats.ErrKeyNotFound) { + return nil, nil + } + return nil, err + } + var rec CertRecord + if err := json.Unmarshal(entry.Value(), &rec); err != nil { + return nil, fmt.Errorf("unmarshal cert: %w", err) + } + return &rec, nil +} + +// DeleteCert removes a certificate by ARN. Returns (false, nil) when absent. +func (s *Store) DeleteCert(certArn string) (bool, error) { + if _, err := s.kv.Get(certKey(certArn)); err != nil { + if errors.Is(err, nats.ErrKeyNotFound) { + return false, nil + } + return false, err + } + if err := s.kv.Delete(certKey(certArn)); err != nil { + return false, err + } + return true, nil +} + +// ListCerts returns all certificate records owned by accountID. +func (s *Store) ListCerts(accountID string) ([]*CertRecord, error) { + keys, err := s.kv.Keys() + if err != nil { + if errors.Is(err, nats.ErrNoKeysFound) { + return nil, nil + } + return nil, err + } + var out []*CertRecord + for _, key := range keys { + if !strings.HasPrefix(key, KeyPrefixCert) { + continue + } + entry, err := s.kv.Get(key) + if err != nil { + continue + } + var rec CertRecord + if err := json.Unmarshal(entry.Value(), &rec); err != nil { + continue + } + if rec.AccountID != accountID { + continue + } + out = append(out, &rec) + } + return out, nil +} From 470954bbe864e9e00e74f27162d72c6b5bb68a6d Mon Sep 17 00:00:00 2001 From: Josh Siviour Date: Thu, 4 Jun 2026 10:45:11 +1000 Subject: [PATCH 08/73] =?UTF-8?q?feat(elbv2):=20HTTPS=20data=20plane=20?= =?UTF-8?q?=E2=80=94=20TLS=20termination=20via=20ssl=20crt=20+=20PEM=20del?= =?UTF-8?q?ivery=20(#286)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolve listener certificate ARNs to PEM via the ACM store (shared JetStream KV, no cross-service hop), render HAProxy 'ssl crt' for secure frontends, and deliver the combined cert+chain+key PEM to the LB agent alongside the config. ConfigHash folds in cert content so rotation triggers a reload; the agent writes each cert 0600 (path-constrained to its cert dir) before the config + reload. Phase B of the ELBv2 HTTPS epic (mulga-siv-180). --- spinifex/handlers/elbv2/agent_types.go | 16 +- spinifex/handlers/elbv2/haproxy.go | 96 +++++++-- spinifex/handlers/elbv2/haproxy_certs_test.go | 196 ++++++++++++++++++ spinifex/handlers/elbv2/service_impl.go | 134 +++++++++++- spinifex/handlers/elbv2/types.go | 3 +- spinifex/lbagent/agent.go | 56 ++++- spinifex/lbagent/agent_certs_test.go | 63 ++++++ 7 files changed, 530 insertions(+), 34 deletions(-) create mode 100644 spinifex/handlers/elbv2/haproxy_certs_test.go create mode 100644 spinifex/lbagent/agent_certs_test.go diff --git a/spinifex/handlers/elbv2/agent_types.go b/spinifex/handlers/elbv2/agent_types.go index 16a39c39f..c4b46b9b0 100644 --- a/spinifex/handlers/elbv2/agent_types.go +++ b/spinifex/handlers/elbv2/agent_types.go @@ -32,10 +32,20 @@ type GetLBConfigInput struct { LBID *string `locationName:"LBID" type:"string"` } -// GetLBConfigOutput returns the pre-computed HAProxy config and its hash. +// GetLBConfigOutput returns the pre-computed HAProxy config and its hash, plus +// any TLS certificate files the config's `ssl crt` directives reference. type GetLBConfigOutput struct { - ConfigText *string `type:"string"` - ConfigHash *string `type:"string"` + ConfigText *string `type:"string"` + ConfigHash *string `type:"string"` + CertFiles []*CertFile `locationName:"CertFiles" type:"list"` +} + +// CertFile is one TLS certificate PEM delivered to the LB agent. Path is the +// absolute destination (under lbagent.CertDir) the agent writes 0600 before +// reload; PEM is the combined cert+chain+key material. +type CertFile struct { + Path *string `locationName:"Path" type:"string"` + PEM *string `locationName:"PEM" type:"string"` } // toHealthReport converts the heartbeat input's server list to the lbagent diff --git a/spinifex/handlers/elbv2/haproxy.go b/spinifex/handlers/elbv2/haproxy.go index 0b87950f9..f4435d487 100644 --- a/spinifex/handlers/elbv2/haproxy.go +++ b/spinifex/handlers/elbv2/haproxy.go @@ -12,6 +12,8 @@ import ( "sync" "syscall" "text/template" + + "github.com/mulgadc/spinifex/spinifex/lbagent" ) // Every interpolated string field in the templates below MUST be regex-validated @@ -34,7 +36,7 @@ defaults timeout server 60s {{range .Frontends}} frontend {{.Name}} - bind *:{{.Port}} + bind *:{{.Port}}{{if .CertPath}} ssl crt {{.CertPath}}{{end}} {{- range .Rules}} {{- range .ACLs}} acl {{.Name}} {{.Expr}} @@ -74,7 +76,7 @@ defaults timeout server 60s {{range .Frontends}} frontend {{.Name}} - bind *:{{.Port}} + bind *:{{.Port}}{{if .CertPath}} ssl crt {{.CertPath}}{{end}} default_backend {{.DefaultBackend}} {{end}} {{range .Backends}} @@ -103,6 +105,10 @@ type HAProxyConfig struct { SocketPath string Frontends []HAProxyFrontend Backends []HAProxyBackend + // CertFiles maps each absolute `ssl crt` path referenced by a secure + // frontend to its combined PEM (cert+chain+key). Not rendered into the + // template — carried out to the caller for delivery to the LB agent. + CertFiles map[string]string } // HAProxyFrontend represents a listener frontend. @@ -110,6 +116,8 @@ type HAProxyFrontend struct { Name string BindAddr string Port int64 + Protocol string // listener protocol (HTTP/HTTPS/TCP/TLS); drives TLS termination + CertPath string // combined-PEM path for `ssl crt`; empty for non-secure frontends DefaultBackend string Rules []HAProxyRule } @@ -173,48 +181,61 @@ type HAProxyServer struct { // GenerateHAProxyConfig builds an HAProxy config string from the LB, its // listeners, target groups, and per-listener rules. For NLBs it generates a -// TCP-mode config and ignores rules (NLB has no L7 routing). +// TCP-mode config and ignores rules (NLB has no L7 routing). TLS termination +// is off (no certificates resolved) — use GenerateHAProxyConfigWithCerts for +// HTTPS listeners. func GenerateHAProxyConfig(lb *LoadBalancerRecord, listeners []*ListenerRecord, tgByArn map[string]*TargetGroupRecord, rulesByListener map[string][]*RuleRecord, bindAddr string) (string, error) { + config, _, err := GenerateHAProxyConfigWithCerts(lb, listeners, tgByArn, rulesByListener, bindAddr, nil) + return config, err +} + +// GenerateHAProxyConfigWithCerts is GenerateHAProxyConfig plus TLS termination. +// certPEMByArn maps each listener certificate ARN to its combined PEM; secure +// frontends render `ssl crt ` and the returned certFiles map carries each +// path → PEM for delivery to the LB agent. A secure listener whose default cert +// ARN is absent from certPEMByArn renders without `ssl crt` (HAProxy would fail +// to bind, surfacing the missing material). +func GenerateHAProxyConfigWithCerts(lb *LoadBalancerRecord, listeners []*ListenerRecord, tgByArn map[string]*TargetGroupRecord, rulesByListener map[string][]*RuleRecord, bindAddr string, certPEMByArn map[string]string) (string, map[string]string, error) { if lb.Type == LoadBalancerTypeNetwork { - return generateNLBConfig(lb, listeners, tgByArn, bindAddr) + return generateNLBConfig(lb, listeners, tgByArn, bindAddr, certPEMByArn) } - return generateALBConfig(lb, listeners, tgByArn, rulesByListener, bindAddr) + return generateALBConfig(lb, listeners, tgByArn, rulesByListener, bindAddr, certPEMByArn) } // generateALBConfig builds an HTTP-mode HAProxy config for ALBs. -func generateALBConfig(lb *LoadBalancerRecord, listeners []*ListenerRecord, tgByArn map[string]*TargetGroupRecord, rulesByListener map[string][]*RuleRecord, bindAddr string) (string, error) { - cfg, err := buildHAProxyConfig(lb, listeners, tgByArn, rulesByListener, bindAddr, false) +func generateALBConfig(lb *LoadBalancerRecord, listeners []*ListenerRecord, tgByArn map[string]*TargetGroupRecord, rulesByListener map[string][]*RuleRecord, bindAddr string, certPEMByArn map[string]string) (string, map[string]string, error) { + cfg, err := buildHAProxyConfig(lb, listeners, tgByArn, rulesByListener, bindAddr, false, certPEMByArn) if err != nil { - return "", err + return "", nil, err } var buf strings.Builder if err := haproxyHTTPTmpl.Execute(&buf, cfg); err != nil { - return "", fmt.Errorf("execute haproxy template: %w", err) + return "", nil, fmt.Errorf("execute haproxy template: %w", err) } - return buf.String(), nil + return buf.String(), cfg.CertFiles, nil } // generateNLBConfig builds a TCP-mode HAProxy config for NLBs. -func generateNLBConfig(lb *LoadBalancerRecord, listeners []*ListenerRecord, tgByArn map[string]*TargetGroupRecord, bindAddr string) (string, error) { - cfg, err := buildHAProxyConfig(lb, listeners, tgByArn, nil, bindAddr, true) +func generateNLBConfig(lb *LoadBalancerRecord, listeners []*ListenerRecord, tgByArn map[string]*TargetGroupRecord, bindAddr string, certPEMByArn map[string]string) (string, map[string]string, error) { + cfg, err := buildHAProxyConfig(lb, listeners, tgByArn, nil, bindAddr, true, certPEMByArn) if err != nil { - return "", err + return "", nil, err } var buf strings.Builder if err := haproxyTCPTmpl.Execute(&buf, cfg); err != nil { - return "", fmt.Errorf("execute haproxy tcp template: %w", err) + return "", nil, fmt.Errorf("execute haproxy tcp template: %w", err) } - return buf.String(), nil + return buf.String(), cfg.CertFiles, nil } // buildHAProxyConfig constructs the HAProxyConfig struct shared by ALB and NLB // generation. For ALBs, rulesByListener provides per-listener rules sorted by // priority; nil/empty for NLBs. -func buildHAProxyConfig(lb *LoadBalancerRecord, listeners []*ListenerRecord, tgByArn map[string]*TargetGroupRecord, rulesByListener map[string][]*RuleRecord, bindAddr string, isTCP bool) (HAProxyConfig, error) { +func buildHAProxyConfig(lb *LoadBalancerRecord, listeners []*ListenerRecord, tgByArn map[string]*TargetGroupRecord, rulesByListener map[string][]*RuleRecord, bindAddr string, isTCP bool, certPEMByArn map[string]string) (HAProxyConfig, error) { socketDir := filepath.Join(os.TempDir(), "spinifex-haproxy") // Use "lb" prefix for both ALB and NLB — must match the agent's socket path. socketPath := filepath.Join(socketDir, fmt.Sprintf("lb-%s.sock", lb.LoadBalancerID)) @@ -316,9 +337,24 @@ func buildHAProxyConfig(lb *LoadBalancerRecord, listeners []*ListenerRecord, tgB Name: sanitizeName("ft", l.ListenerArn), BindAddr: bindAddr, Port: l.Port, + Protocol: l.Protocol, DefaultBackend: defaultBackendName, } + // Secure listeners terminate TLS: resolve the default cert to a stable + // per-listener PEM path and stage it for delivery. Without resolved + // material the frontend renders plain (HAProxy then fails to bind, + // surfacing the gap rather than silently serving cleartext). + if protocolRequiresCert(l.Protocol) { + if pem, path := resolveFrontendCert(lb, l, certPEMByArn); pem != "" { + frontend.CertPath = path + if cfg.CertFiles == nil { + cfg.CertFiles = make(map[string]string) + } + cfg.CertFiles[path] = pem + } + } + if !isTCP { for _, r := range rulesByListener[l.ListenerArn] { backendName, err := registerRuleBackend(r, l, addBackend, addFixedResponseBackend, addRedirectBackend) @@ -351,6 +387,34 @@ func buildHAProxyConfig(lb *LoadBalancerRecord, listeners []*ListenerRecord, tgB return cfg, nil } +// frontendCertPath returns the stable absolute path of a listener's combined +// PEM file under the agent's cert dir. Daemon-rendered and agent-written paths +// must match exactly. +func frontendCertPath(lb *LoadBalancerRecord, l *ListenerRecord) string { + return filepath.Join(lbagent.CertDir, fmt.Sprintf("lb-%s-%s.pem", lb.LoadBalancerID, l.ListenerID)) +} + +// resolveFrontendCert picks a listener's default certificate, resolves its PEM +// from certPEMByArn, and returns (pem, path). Returns ("", "") when the listener +// has no certificate or its default ARN is unresolved. +func resolveFrontendCert(lb *LoadBalancerRecord, l *ListenerRecord, certPEMByArn map[string]string) (pem, path string) { + if len(l.Certificates) == 0 || certPEMByArn == nil { + return "", "" + } + arn := l.Certificates[0].CertificateArn + for _, c := range l.Certificates { + if c.IsDefault { + arn = c.CertificateArn + break + } + } + pem, ok := certPEMByArn[arn] + if !ok || pem == "" { + return "", "" + } + return pem, frontendCertPath(lb, l) +} + // registerRuleBackend resolves the HAProxy backend a rule's single action // routes to, registering a synthetic backend for redirect / fixed-response // rule actions, and returns its name. diff --git a/spinifex/handlers/elbv2/haproxy_certs_test.go b/spinifex/handlers/elbv2/haproxy_certs_test.go new file mode 100644 index 000000000..2f2a736bd --- /dev/null +++ b/spinifex/handlers/elbv2/haproxy_certs_test.go @@ -0,0 +1,196 @@ +package handlers_elbv2 + +import ( + "encoding/xml" + "path/filepath" + "testing" + + "github.com/aws/aws-sdk-go/aws" + handlers_acm "github.com/mulgadc/spinifex/spinifex/handlers/acm" + "github.com/mulgadc/spinifex/spinifex/lbagent" + "github.com/mulgadc/spinifex/spinifex/utils" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const certTestArn = "arn:aws:acm:ap-southeast-2:123456789012:certificate/cccc-3333" + +func httpsListener() *ListenerRecord { + return &ListenerRecord{ + ListenerArn: "arn:aws:elasticloadbalancing:us-east-1:123:listener/app/my-alb/lb-abc123/lst-https", + ListenerID: "lst-https", + Protocol: ProtocolHTTPS, + Port: 443, + Certificates: []ListenerCertificate{{CertificateArn: certTestArn, IsDefault: true}}, + SslPolicy: DefaultSslPolicy, + DefaultActions: []ListenerAction{{Type: ActionTypeFixedResponse, FixedResponse: &FixedResponseAction{StatusCode: "200"}}}, + LoadBalancerArn: "arn:lb", + } +} + +func TestGenerateHAProxyConfigWithCerts_HTTPSRendersSslCrt(t *testing.T) { + lb := &LoadBalancerRecord{LoadBalancerID: "lb-abc123", Name: "my-alb"} + listeners := []*ListenerRecord{httpsListener()} + certPEM := "CERTPEM\nKEYPEM\n" + + config, certFiles, err := GenerateHAProxyConfigWithCerts( + lb, listeners, nil, nil, "0.0.0.0", + map[string]string{certTestArn: certPEM}, + ) + require.NoError(t, err) + + wantPath := filepath.Join(lbagent.CertDir, "lb-lb-abc123-lst-https.pem") + assert.Contains(t, config, "bind *:443 ssl crt "+wantPath) + require.Len(t, certFiles, 1) + assert.Equal(t, certPEM, certFiles[wantPath]) +} + +func TestGenerateHAProxyConfigWithCerts_HTTPHasNoSslCrt(t *testing.T) { + lb := &LoadBalancerRecord{LoadBalancerID: "lb-abc123", Name: "my-alb"} + listeners := []*ListenerRecord{{ + ListenerArn: "arn:aws:elasticloadbalancing:us-east-1:123:listener/app/my-alb/lb-abc123/lst-http", + ListenerID: "lst-http", + Protocol: ProtocolHTTP, + Port: 80, + DefaultActions: []ListenerAction{{Type: ActionTypeFixedResponse, FixedResponse: &FixedResponseAction{StatusCode: "200"}}}, + }} + + config, certFiles, err := GenerateHAProxyConfigWithCerts(lb, listeners, nil, nil, "0.0.0.0", nil) + require.NoError(t, err) + assert.Contains(t, config, "bind *:80") + assert.NotContains(t, config, "ssl crt") + assert.Empty(t, certFiles) +} + +// A secure listener whose cert ARN is unresolved renders without ssl crt — the +// gap surfaces at HAProxy bind time rather than silently serving cleartext. +func TestGenerateHAProxyConfigWithCerts_MissingCertRendersPlain(t *testing.T) { + lb := &LoadBalancerRecord{LoadBalancerID: "lb-abc123", Name: "my-alb"} + config, certFiles, err := GenerateHAProxyConfigWithCerts( + lb, []*ListenerRecord{httpsListener()}, nil, nil, "0.0.0.0", nil, + ) + require.NoError(t, err) + assert.NotContains(t, config, "ssl crt") + assert.Empty(t, certFiles) +} + +func TestGenerateHAProxyConfig_BackwardCompatNoTLS(t *testing.T) { + lb := &LoadBalancerRecord{LoadBalancerID: "lb-abc123", Name: "my-alb"} + config, err := GenerateHAProxyConfig(lb, []*ListenerRecord{httpsListener()}, nil, nil, "0.0.0.0") + require.NoError(t, err) + assert.NotContains(t, config, "ssl crt", "legacy entrypoint resolves no certs") +} + +func TestConfigCertHash_ChangesOnRotation(t *testing.T) { + const cfg = "frontend ft\n bind *:443 ssl crt /etc/haproxy/certs/x.pem\n" + path := "/etc/haproxy/certs/x.pem" + + base := configCertHash(cfg, map[string]string{path: "PEM-A"}) + rotated := configCertHash(cfg, map[string]string{path: "PEM-B"}) + same := configCertHash(cfg, map[string]string{path: "PEM-A"}) + + assert.NotEqual(t, base, rotated, "rotating cert content must change the hash") + assert.Equal(t, base, same, "identical inputs hash identically") + + // Config-only change also moves the hash. + assert.NotEqual(t, base, configCertHash(cfg+"\n", map[string]string{path: "PEM-A"})) +} + +func putTestCert(t *testing.T, svc *ELBv2ServiceImpl, arn, account, leaf, chain, key string) { + t.Helper() + require.NoError(t, svc.acmStore.PutCert(&handlers_acm.CertRecord{ + CertificateArn: arn, + AccountID: account, + Certificate: leaf, + CertificateChain: chain, + PrivateKey: key, + DomainName: "example.com", + })) +} + +func TestResolveCertPEM_ConcatOrderAndOwnership(t *testing.T) { + svc := setupTestService(t) + require.NotNil(t, svc.acmStore) + putTestCert(t, svc, certTestArn, testAccountID, "LEAF", "CHAIN", "KEY") + + pem, err := svc.resolveCertPEM(certTestArn, testAccountID) + require.NoError(t, err) + assert.Equal(t, "LEAF\nCHAIN\nKEY\n", pem) + + // Wrong account → treated as not found. + _, err = svc.resolveCertPEM(certTestArn, "999999999999") + require.Error(t, err) + + // Unknown ARN → not found. + _, err = svc.resolveCertPEM("arn:aws:acm:ap-southeast-2:123456789012:certificate/missing", testAccountID) + require.Error(t, err) +} + +func TestResolveCertPEM_NoChain(t *testing.T) { + svc := setupTestService(t) + putTestCert(t, svc, certTestArn, testAccountID, "LEAF", "", "KEY") + + pem, err := svc.resolveCertPEM(certTestArn, testAccountID) + require.NoError(t, err) + assert.Equal(t, "LEAF\nKEY\n", pem) +} + +func TestResolveListenerCerts_DedupAndResolve(t *testing.T) { + svc := setupTestService(t) + putTestCert(t, svc, certTestArn, testAccountID, "LEAF", "", "KEY") + + // Two listeners share the same cert ARN — resolved once. + got, err := svc.resolveListenerCerts([]*ListenerRecord{httpsListener(), httpsListener()}, testAccountID) + require.NoError(t, err) + require.Len(t, got, 1) + assert.Equal(t, "LEAF\nKEY\n", got[certTestArn]) + + // HTTP-only listeners → nil map, no error. + got, err = svc.resolveListenerCerts([]*ListenerRecord{{Protocol: ProtocolHTTP}}, testAccountID) + require.NoError(t, err) + assert.Nil(t, got) +} + +func TestGetLBConfig_DeliversCertFiles(t *testing.T) { + svc := setupTestService(t) + rec := &LoadBalancerRecord{ + LoadBalancerID: "lb-deliver1", + AccountID: testAccountID, + ConfigText: "frontend ft\n bind *:443 ssl crt /etc/haproxy/certs/lb-deliver1-lst.pem\n", + ConfigHash: "hash123", + CertFiles: map[string]string{"/etc/haproxy/certs/lb-deliver1-lst.pem": "LEAF\nKEY\n"}, + } + require.NoError(t, svc.store.PutLoadBalancer(rec)) + + out, err := svc.GetLBConfig(&GetLBConfigInput{LBID: aws.String("lb-deliver1")}, testAccountID) + require.NoError(t, err) + require.Len(t, out.CertFiles, 1) + assert.Equal(t, "/etc/haproxy/certs/lb-deliver1-lst.pem", *out.CertFiles[0].Path) + assert.Equal(t, "LEAF\nKEY\n", *out.CertFiles[0].PEM) + + // The gateway marshals this output to XML; confirm the member shape the + // lb-agent parses (GetLBConfigResult>CertFiles>member>{Path,PEM}). + payload := utils.GenerateIAMXMLPayload("GetLBConfig", *out) + xmlBytes, err := utils.MarshalToXML(payload) + require.NoError(t, err) + var parsed struct { + Members []struct { + Path string `xml:"Path"` + PEM string `xml:"PEM"` + } `xml:"GetLBConfigResult>CertFiles>member"` + } + require.NoError(t, xml.Unmarshal(xmlBytes, &parsed)) + require.Len(t, parsed.Members, 1) + assert.Equal(t, "/etc/haproxy/certs/lb-deliver1-lst.pem", parsed.Members[0].Path) + assert.Equal(t, "LEAF\nKEY\n", parsed.Members[0].PEM) +} + +func TestCertFilesToSDK_SortedAndNilSafe(t *testing.T) { + assert.Nil(t, certFilesToSDK(nil)) + + out := certFilesToSDK(map[string]string{"/b.pem": "B", "/a.pem": "A"}) + require.Len(t, out, 2) + assert.Equal(t, "/a.pem", *out[0].Path) + assert.Equal(t, "A", *out[0].PEM) + assert.Equal(t, "/b.pem", *out[1].Path) +} diff --git a/spinifex/handlers/elbv2/service_impl.go b/spinifex/handlers/elbv2/service_impl.go index 800d2ae4e..ee02b8727 100644 --- a/spinifex/handlers/elbv2/service_impl.go +++ b/spinifex/handlers/elbv2/service_impl.go @@ -3,12 +3,14 @@ package handlers_elbv2 import ( "context" "crypto/sha256" + "encoding/hex" "errors" "fmt" "log/slog" "net" "regexp" "slices" + "sort" "strings" "sync" "time" @@ -18,6 +20,7 @@ import ( "github.com/aws/aws-sdk-go/service/elbv2" "github.com/mulgadc/spinifex/spinifex/awserrors" "github.com/mulgadc/spinifex/spinifex/config" + handlers_acm "github.com/mulgadc/spinifex/spinifex/handlers/acm" handlers_ec2_vpc "github.com/mulgadc/spinifex/spinifex/handlers/ec2/vpc" "github.com/mulgadc/spinifex/spinifex/tags" "github.com/mulgadc/spinifex/spinifex/utils" @@ -96,6 +99,7 @@ var _ ELBv2Service = (*ELBv2ServiceImpl)(nil) type ELBv2ServiceImpl struct { config *config.Config store *Store + acmStore *handlers_acm.Store // resolves listener cert ARNs → PEM; nil-safe (HTTPS unavailable when nil) nc *nats.Conn // NATS connection for JetStream KV store VPCService *handlers_ec2_vpc.VPCServiceImpl // nil-safe: ENI ops skipped when nil (e.g. in tests) InstanceLauncher SystemInstanceLauncher // nil-safe: system VM ops skipped when nil @@ -128,6 +132,16 @@ func NewELBv2ServiceImplWithNATS(cfg *config.Config, nc *nats.Conn) (*ELBv2Servi return nil, fmt.Errorf("failed to create ELBv2 store: %w", err) } + // ACM store shares the same JetStream KV — read cert PEM directly, no + // cross-service NATS hop. Non-fatal: a failure here only disables HTTPS + // termination (resolveCertPEM returns an error), it must not block the + // daemon from serving ELBv2 control-plane requests. + acmStore, acmErr := handlers_acm.NewStore(nc) + if acmErr != nil { + slog.Warn("ELBv2: ACM store unavailable, HTTPS listeners cannot resolve certs", "err", acmErr) + acmStore = nil + } + region := "us-east-1" nodeID := "" if cfg != nil { @@ -141,14 +155,15 @@ func NewELBv2ServiceImplWithNATS(cfg *config.Config, nc *nats.Conn) (*ELBv2Servi hc := newHealthChecker(store) return &ELBv2ServiceImpl{ - config: cfg, - store: store, - nc: nc, - nodeID: nodeID, - region: region, - ctx: ctx, - cancel: cancel, - hc: hc, + config: cfg, + store: store, + acmStore: acmStore, + nc: nc, + nodeID: nodeID, + region: region, + ctx: ctx, + cancel: cancel, + hc: hc, }, nil } @@ -577,15 +592,22 @@ func (s *ELBv2ServiceImpl) updateStoredConfig(lb *LoadBalancerRecord) error { } } - configContent, err := GenerateHAProxyConfig(lb, listeners, tgByArn, rulesByListener, bindAddr) + certPEMByArn, err := s.resolveListenerCerts(listeners, lb.AccountID) + if err != nil { + slog.Error("updateStoredConfig: failed to resolve certs", "lbId", lb.LoadBalancerID, "err", err) + return fmt.Errorf("resolve certs: %w", err) + } + + configContent, certFiles, err := GenerateHAProxyConfigWithCerts(lb, listeners, tgByArn, rulesByListener, bindAddr, certPEMByArn) if err != nil { slog.Error("updateStoredConfig: failed to generate config", "lbId", lb.LoadBalancerID, "err", err) return fmt.Errorf("generate config: %w", err) } - hash := fmt.Sprintf("%x", sha256.Sum256([]byte(configContent))) + hash := configCertHash(configContent, certFiles) lb.ConfigText = configContent lb.ConfigHash = hash + lb.CertFiles = certFiles if err := s.store.PutLoadBalancer(lb); err != nil { slog.Error("updateStoredConfig: failed to persist LB", "lbId", lb.LoadBalancerID, "err", err) @@ -593,10 +615,81 @@ func (s *ELBv2ServiceImpl) updateStoredConfig(lb *LoadBalancerRecord) error { } slog.Info("updateStoredConfig: config stored", - "lbId", lb.LoadBalancerID, "hash", hash[:12], "size", len(configContent)) + "lbId", lb.LoadBalancerID, "hash", hash[:12], "size", len(configContent), "certs", len(certFiles)) return nil } +// resolveListenerCerts resolves every distinct certificate ARN referenced by +// the listeners to its combined PEM via the ACM store. Returns nil when no +// listener carries a certificate (the common HTTP-only case). +func (s *ELBv2ServiceImpl) resolveListenerCerts(listeners []*ListenerRecord, accountID string) (map[string]string, error) { + var out map[string]string + for _, l := range listeners { + for _, c := range l.Certificates { + if _, ok := out[c.CertificateArn]; ok { + continue + } + pem, err := s.resolveCertPEM(c.CertificateArn, accountID) + if err != nil { + return nil, fmt.Errorf("cert %s: %w", c.CertificateArn, err) + } + if out == nil { + out = make(map[string]string) + } + out[c.CertificateArn] = pem + } + } + return out, nil +} + +// resolveCertPEM loads a certificate by ARN from the ACM store and returns its +// combined PEM (leaf + chain + key) in the order HAProxy `ssl crt` expects. +// Ownership is enforced: a cert belonging to another account is treated as +// absent. +func (s *ELBv2ServiceImpl) resolveCertPEM(arn, accountID string) (string, error) { + if s.acmStore == nil { + return "", errors.New(awserrors.ErrorELBv2CertificateNotFound) + } + rec, err := s.acmStore.GetCert(arn) + if err != nil { + return "", fmt.Errorf("get cert: %w", err) + } + if rec == nil || rec.AccountID != accountID { + return "", errors.New(awserrors.ErrorELBv2CertificateNotFound) + } + + var b strings.Builder + b.WriteString(strings.TrimRight(rec.Certificate, "\n")) + b.WriteByte('\n') + if rec.CertificateChain != "" { + b.WriteString(strings.TrimRight(rec.CertificateChain, "\n")) + b.WriteByte('\n') + } + b.WriteString(strings.TrimRight(rec.PrivateKey, "\n")) + b.WriteByte('\n') + return b.String(), nil +} + +// configCertHash hashes the rendered config plus every delivered cert file +// (path + content, in sorted path order) so a cert rotation changes the hash +// and triggers an agent reload even when the config text is unchanged. +func configCertHash(configContent string, certFiles map[string]string) string { + h := sha256.New() + h.Write([]byte(configContent)) + paths := make([]string, 0, len(certFiles)) + for p := range certFiles { + paths = append(paths, p) + } + sort.Strings(paths) + for _, p := range paths { + h.Write([]byte(p)) + h.Write([]byte{0}) + h.Write([]byte(certFiles[p])) + h.Write([]byte{0}) + } + return hex.EncodeToString(h.Sum(nil)) +} + // updateStoredConfigForTargetGroup finds all LBs that reference the given target // group (via listeners) and updates their stored config. func (s *ELBv2ServiceImpl) updateStoredConfigForTargetGroup(tgArn string) error { @@ -718,9 +811,28 @@ func (s *ELBv2ServiceImpl) GetLBConfig(input *GetLBConfigInput, accountID string return &GetLBConfigOutput{ ConfigText: aws.String(lb.ConfigText), ConfigHash: aws.String(lb.ConfigHash), + CertFiles: certFilesToSDK(lb.CertFiles), }, nil } +// certFilesToSDK converts the stored path→PEM map into the sorted CertFile +// slice delivered to the agent. Sorted for deterministic output. +func certFilesToSDK(certFiles map[string]string) []*CertFile { + if len(certFiles) == 0 { + return nil + } + paths := make([]string, 0, len(certFiles)) + for p := range certFiles { + paths = append(paths, p) + } + sort.Strings(paths) + out := make([]*CertFile, 0, len(paths)) + for _, p := range paths { + out = append(out, &CertFile{Path: aws.String(p), PEM: aws.String(certFiles[p])}) + } + return out +} + // lbArnPathSegment returns the ARN path segment for the given LB type: // "app" for application LBs, "net" for network LBs. func lbArnPathSegment(lbType string) string { diff --git a/spinifex/handlers/elbv2/types.go b/spinifex/handlers/elbv2/types.go index 61a428394..97111d3bf 100644 --- a/spinifex/handlers/elbv2/types.go +++ b/spinifex/handlers/elbv2/types.go @@ -109,7 +109,8 @@ type LoadBalancerRecord struct { InstanceID string `json:"instance_id,omitempty"` // ALB VM instance ID (system-managed) VPCIP string `json:"vpc_ip,omitempty"` // VPC private IP of the ALB VM ConfigText string `json:"config_text,omitempty"` // Pre-computed HAProxy config - ConfigHash string `json:"config_hash,omitempty"` // SHA256 of ConfigText + ConfigHash string `json:"config_hash,omitempty"` // SHA256 of ConfigText + cert material + CertFiles map[string]string `json:"cert_files,omitempty"` // Absolute path → combined PEM (cert+chain+key), delivered with config LastHeartbeat time.Time `json:"last_heartbeat"` // Last agent heartbeat timestamp HostPorts map[int]int `json:"host_ports,omitempty"` // Dev mode: guest port → host port forwarding NodeID string `json:"node_id"` // Daemon node running this ALB diff --git a/spinifex/lbagent/agent.go b/spinifex/lbagent/agent.go index f2e409643..fb0201e89 100644 --- a/spinifex/lbagent/agent.go +++ b/spinifex/lbagent/agent.go @@ -31,6 +31,12 @@ const ( DefaultConfigPath = "/etc/haproxy/haproxy.cfg" DefaultPIDPath = "/run/haproxy.pid" + // CertDir is the fixed directory holding TLS certificate PEM files for + // HTTPS listeners. The daemon renders `ssl crt` paths under this dir; the + // agent writes the delivered PEM files here (0600) before reload and + // rejects any delivered path that escapes it. + CertDir = "/etc/haproxy/certs" + // pollInterval is how often the agent sends a heartbeat. pollInterval = 5 * time.Second ) @@ -42,6 +48,7 @@ type Agent struct { region string // SigV4 signing region configPath string pidPath string + certDir string // dir for TLS cert PEM files; defaults to CertDir (overridable in tests) socketPath string // HAProxy stats socket accessKey string @@ -91,6 +98,7 @@ func New(lbID, gatewayURL, accessKey, secretKey, region string) (*Agent, error) region: region, configPath: DefaultConfigPath, pidPath: DefaultPIDPath, + certDir: CertDir, socketPath: fmt.Sprintf("/tmp/spinifex-haproxy/lb-%s.sock", lbID), accessKey: accessKey, secretKey: secretKey, @@ -162,11 +170,19 @@ type heartbeatResponse struct { ConfigHash string `xml:"LBAgentHeartbeatResult>ConfigHash"` } +// certFile is one delivered TLS certificate PEM parsed from the GetLBConfig +// response. Path is the absolute destination under CertDir. +type certFile struct { + Path string `xml:"Path"` + PEM string `xml:"PEM"` +} + // configResponse is the parsed XML response from GetLBConfig. type configResponse struct { - XMLName xml.Name `xml:"GetLBConfigResponse"` - ConfigText string `xml:"GetLBConfigResult>ConfigText"` - ConfigHash string `xml:"GetLBConfigResult>ConfigHash"` + XMLName xml.Name `xml:"GetLBConfigResponse"` + ConfigText string `xml:"GetLBConfigResult>ConfigText"` + ConfigHash string `xml:"GetLBConfigResult>ConfigHash"` + CertFiles []certFile `xml:"GetLBConfigResult>CertFiles>member"` } // sendHeartbeat sends a heartbeat with health report to the gateway. @@ -216,6 +232,12 @@ func (a *Agent) fetchAndApplyConfig() error { return fmt.Errorf("empty config returned") } + // Cert files must land before the config that references them via + // `ssl crt`, otherwise HAProxy fails to start/reload on a missing path. + if err := a.writeCertFiles(resp.CertFiles); err != nil { + return fmt.Errorf("write cert files: %w", err) + } + if err := WriteConfig(a.configPath, resp.ConfigText); err != nil { return fmt.Errorf("write config: %w", err) } @@ -262,6 +284,34 @@ func (a *Agent) signedPost(params url.Values) ([]byte, error) { return respBody, nil } +// writeCertFiles writes each delivered TLS certificate PEM to its path 0600, +// creating the cert dir as needed. Every path is constrained to a.certDir — a +// delivered path that escapes it (traversal, absolute elsewhere) is rejected +// rather than written, so a malformed/hostile response can't drop files across +// the filesystem. +func (a *Agent) writeCertFiles(certs []certFile) error { + if len(certs) == 0 { + return nil + } + if err := os.MkdirAll(a.certDir, 0o750); err != nil { + return fmt.Errorf("create cert dir: %w", err) + } + for _, c := range certs { + clean := filepath.Clean(c.Path) + if clean != filepath.Join(a.certDir, filepath.Base(clean)) { + return fmt.Errorf("cert path %q escapes %s", c.Path, a.certDir) + } + if c.PEM == "" { + return fmt.Errorf("cert %q has empty PEM", c.Path) + } + if err := os.WriteFile(clean, []byte(c.PEM), 0o600); err != nil { + return fmt.Errorf("write cert %q: %w", clean, err) + } + slog.Info("Wrote TLS cert", "path", clean, "bytes", len(c.PEM)) + } + return nil +} + // WriteConfig atomically writes an HAProxy config file. // It writes to a temp file first, then renames for atomicity. func WriteConfig(path, content string) error { diff --git a/spinifex/lbagent/agent_certs_test.go b/spinifex/lbagent/agent_certs_test.go new file mode 100644 index 000000000..00b196b6d --- /dev/null +++ b/spinifex/lbagent/agent_certs_test.go @@ -0,0 +1,63 @@ +package lbagent + +import ( + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func newCertTestAgent(t *testing.T) *Agent { + t.Helper() + a, err := New("lb-1", "https://gw.local", "AK", "SK", "us-east-1") + require.NoError(t, err) + a.certDir = t.TempDir() + return a +} + +func TestWriteCertFiles_WritesPEM0600(t *testing.T) { + a := newCertTestAgent(t) + path := filepath.Join(a.certDir, "lb-1-lst.pem") + + err := a.writeCertFiles([]certFile{{Path: path, PEM: "LEAF\nKEY\n"}}) + require.NoError(t, err) + + data, err := os.ReadFile(path) + require.NoError(t, err) + assert.Equal(t, "LEAF\nKEY\n", string(data)) + + if runtime.GOOS != "windows" { + fi, err := os.Stat(path) + require.NoError(t, err) + assert.Equal(t, os.FileMode(0o600), fi.Mode().Perm()) + } +} + +func TestWriteCertFiles_Empty(t *testing.T) { + a := newCertTestAgent(t) + assert.NoError(t, a.writeCertFiles(nil)) +} + +func TestWriteCertFiles_RejectsTraversal(t *testing.T) { + a := newCertTestAgent(t) + cases := []string{ + filepath.Join(a.certDir, "../escape.pem"), + "/etc/passwd", + filepath.Join(a.certDir, "sub/dir/x.pem"), + } + for _, p := range cases { + err := a.writeCertFiles([]certFile{{Path: p, PEM: "X"}}) + require.Error(t, err, "path %q must be rejected", p) + assert.Contains(t, err.Error(), "escapes") + } +} + +func TestWriteCertFiles_RejectsEmptyPEM(t *testing.T) { + a := newCertTestAgent(t) + err := a.writeCertFiles([]certFile{{Path: filepath.Join(a.certDir, "x.pem"), PEM: ""}}) + require.Error(t, err) + assert.Contains(t, err.Error(), "empty PEM") +} From 61d73d1d4ebcdf4b41e08b77f2b4fb154f9174b5 Mon Sep 17 00:00:00 2001 From: Josh Siviour Date: Thu, 4 Jun 2026 11:20:52 +1000 Subject: [PATCH 09/73] fix: reject unknown ACM cert ARN at listener API boundary (#289) An unresolvable certificate ARN was accepted into a listener record and only failed later at config-render time, which aborted updateStoredConfig wholesale and silently froze the load balancer's data-plane convergence. Validate every certificate ARN against the ACM store (existence + account ownership) in CreateListener, ModifyListener and AddListenerCertificates, returning CertificateNotFound up front. Skipped when the ACM store is unavailable, matching the nil-safe resolve path. --- spinifex/handlers/elbv2/haproxy_certs_test.go | 25 +++++++++++++++++++ spinifex/handlers/elbv2/service_impl.go | 25 +++++++++++++++++++ .../elbv2/service_impl_listener_certs.go | 4 +++ spinifex/handlers/elbv2/service_impl_test.go | 4 +++ 4 files changed, 58 insertions(+) diff --git a/spinifex/handlers/elbv2/haproxy_certs_test.go b/spinifex/handlers/elbv2/haproxy_certs_test.go index 2f2a736bd..f6575c600 100644 --- a/spinifex/handlers/elbv2/haproxy_certs_test.go +++ b/spinifex/handlers/elbv2/haproxy_certs_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/aws/aws-sdk-go/aws" + "github.com/mulgadc/spinifex/spinifex/awserrors" handlers_acm "github.com/mulgadc/spinifex/spinifex/handlers/acm" "github.com/mulgadc/spinifex/spinifex/lbagent" "github.com/mulgadc/spinifex/spinifex/utils" @@ -126,6 +127,30 @@ func TestResolveCertPEM_ConcatOrderAndOwnership(t *testing.T) { require.Error(t, err) } +func TestValidateListenerCerts_RejectsUnknownAndWrongAccount(t *testing.T) { + svc := setupTestService(t) + putTestCert(t, svc, certTestArn, testAccountID, "LEAF", "", "KEY") + + // Known, owned cert → accepted. + require.NoError(t, svc.validateListenerCerts( + []ListenerCertificate{{CertificateArn: certTestArn}}, testAccountID)) + + // Unknown ARN → CertificateNotFound, rejected at the API boundary. + err := svc.validateListenerCerts( + []ListenerCertificate{{CertificateArn: "arn:aws:acm:ap-southeast-2:123456789012:certificate/missing"}}, testAccountID) + require.EqualError(t, err, awserrors.ErrorELBv2CertificateNotFound) + + // Cert owned by another account → not found. + err = svc.validateListenerCerts( + []ListenerCertificate{{CertificateArn: certTestArn}}, "999999999999") + require.EqualError(t, err, awserrors.ErrorELBv2CertificateNotFound) + + // No ACM store (degraded) → validation skipped, never blocks. + svc.acmStore = nil + require.NoError(t, svc.validateListenerCerts( + []ListenerCertificate{{CertificateArn: certTestArn}}, testAccountID)) +} + func TestResolveCertPEM_NoChain(t *testing.T) { svc := setupTestService(t) putTestCert(t, svc, certTestArn, testAccountID, "LEAF", "", "KEY") diff --git a/spinifex/handlers/elbv2/service_impl.go b/spinifex/handlers/elbv2/service_impl.go index ee02b8727..cf81c08cd 100644 --- a/spinifex/handlers/elbv2/service_impl.go +++ b/spinifex/handlers/elbv2/service_impl.go @@ -670,6 +670,25 @@ func (s *ELBv2ServiceImpl) resolveCertPEM(arn, accountID string) (string, error) return b.String(), nil } +// validateListenerCerts confirms every certificate ARN resolves in the ACM +// store and is owned by the account, rejecting an unknown ARN at the API +// boundary (CreateListener/ModifyListener) with ErrorELBv2CertificateNotFound. +// Without this, an unresolvable ARN is accepted into the listener and only +// fails later at config-render time, which aborts updateStoredConfig wholesale +// and silently freezes the LB's data-plane convergence. Skipped when the ACM +// store is unavailable (cannot validate; matches the nil-safe resolve path). +func (s *ELBv2ServiceImpl) validateListenerCerts(certs []ListenerCertificate, accountID string) error { + if s.acmStore == nil { + return nil + } + for _, c := range certs { + if _, err := s.resolveCertPEM(c.CertificateArn, accountID); err != nil { + return errors.New(awserrors.ErrorELBv2CertificateNotFound) + } + } + return nil +} + // configCertHash hashes the rendered config plus every delivered cert file // (path + content, in sorted path order) so a cert rotation changes the hash // and triggers an agent reload even when the config text is unchanged. @@ -2016,6 +2035,9 @@ func (s *ELBv2ServiceImpl) CreateListener(input *elbv2.CreateListenerInput, acco if err != nil { return nil, err } + if err := s.validateListenerCerts(certs, accountID); err != nil { + return nil, err + } listenerID := utils.GenerateResourceID("lst") listenerArn := buildListenerArn(s.region, accountID, lb.Name, lb.LoadBalancerID, listenerID, lb.Type) @@ -2256,6 +2278,9 @@ func (s *ELBv2ServiceImpl) ModifyListener(input *elbv2.ModifyListenerInput, acco if certErr != nil { return nil, certErr } + if certErr := s.validateListenerCerts(certs, accountID); certErr != nil { + return nil, certErr + } updated.Certificates = certs updated.SslPolicy = policy } diff --git a/spinifex/handlers/elbv2/service_impl_listener_certs.go b/spinifex/handlers/elbv2/service_impl_listener_certs.go index 4fa3e99b0..2ba76fe6b 100644 --- a/spinifex/handlers/elbv2/service_impl_listener_certs.go +++ b/spinifex/handlers/elbv2/service_impl_listener_certs.go @@ -63,6 +63,10 @@ func (s *ELBv2ServiceImpl) AddListenerCertificates(input *elbv2.AddListenerCerti } updated.Certificates = certs + if err := s.validateListenerCerts(certs, accountID); err != nil { + return nil, err + } + if err := s.store.PutListener(&updated); err != nil { slog.Error("AddListenerCertificates: failed to persist record", "listenerId", updated.ListenerID, "err", err) return nil, errors.New(awserrors.ErrorServerInternal) diff --git a/spinifex/handlers/elbv2/service_impl_test.go b/spinifex/handlers/elbv2/service_impl_test.go index ca405bdda..19125d69d 100644 --- a/spinifex/handlers/elbv2/service_impl_test.go +++ b/spinifex/handlers/elbv2/service_impl_test.go @@ -22,6 +22,10 @@ func setupTestService(t *testing.T) *ELBv2ServiceImpl { svc, err := NewELBv2ServiceImplWithNATS(nil, nc) require.NoError(t, err) + // Seed the certificate ARNs the listener tests attach so the fail-closed + // cert validation in Create/Modify/AddListenerCertificates resolves them. + putTestCert(t, svc, testCertArn, testAccountID, "LEAF", "", "KEY") + putTestCert(t, svc, testCertArn2, testAccountID, "LEAF", "", "KEY") return svc } From b0227e7eebb7dc670c38d9f7ead3fa7294c09c8b Mon Sep 17 00:00:00 2001 From: Josh Siviour Date: Thu, 4 Jun 2026 11:23:08 +1000 Subject: [PATCH 10/73] chore(ansible): remove ansible tree, uplift to mulga/ansible/ (#287) Ansible orchestrates the whole stack (spinifex + predastore + viperblock + OVN + tofu hosts) and its spec/beads live in mulga. Moving it to top-level mulga/ansible/ ends the per-change submodule-pointer-bump friction. - git rm -r scripts/ansible/ - Makefile: drop ansible-dev-* / ansible-cluster-bootstrap targets + .PHONY The tree lands at mulga/ansible/ (flat copy, Option B). History pivot: tag feat/uplift-ansible-snapshot-pre-move marks the pre-move HEAD. Plan: docs/development/improvements/ansible-uplift-to-mulga.md (in mulga). --- Makefile | 62 +--- scripts/ansible/.gitignore | 2 - scripts/ansible/README.md | 222 ------------ scripts/ansible/ansible.cfg | 17 - scripts/ansible/inventory/localhost.yml | 6 - scripts/ansible/inventory/tofu.py | 170 --------- .../ansible/playbooks/cluster-bootstrap.yml | 330 ------------------ scripts/ansible/playbooks/dev-deploy.yml | 14 - scripts/ansible/playbooks/dev-install.yml | 67 ---- scripts/ansible/playbooks/dev-logs.yml | 17 - scripts/ansible/playbooks/dev-preflight.yml | 8 - scripts/ansible/playbooks/dev-reset.yml | 72 ---- scripts/ansible/playbooks/dev-restore.yml | 14 - scripts/ansible/playbooks/dev-snapshot.yml | 17 - scripts/ansible/playbooks/dev-status.yml | 13 - scripts/ansible/playbooks/dev-teardown.yml | 8 - scripts/ansible/playbooks/dev-version.yml | 11 - scripts/ansible/playbooks/dev-vpc.yml | 14 - scripts/ansible/requirements.yml | 6 - scripts/ansible/roles/build/meta/main.yml | 7 - scripts/ansible/roles/build/tasks/main.yml | 66 ---- .../ansible/roles/cluster-init/meta/main.yml | 9 - .../ansible/roles/cluster-init/tasks/main.yml | 77 ---- .../ansible/roles/cluster-join/meta/main.yml | 8 - .../ansible/roles/cluster-join/tasks/main.yml | 39 --- .../ansible/roles/cluster-post/meta/main.yml | 8 - .../ansible/roles/cluster-post/tasks/main.yml | 205 ----------- scripts/ansible/roles/deploy/meta/main.yml | 7 - scripts/ansible/roles/deploy/tasks/main.yml | 144 -------- scripts/ansible/roles/init/meta/main.yml | 7 - scripts/ansible/roles/init/tasks/main.yml | 90 ----- scripts/ansible/roles/install/meta/main.yml | 7 - scripts/ansible/roles/install/tasks/main.yml | 79 ----- scripts/ansible/roles/logs/meta/main.yml | 7 - scripts/ansible/roles/logs/tasks/main.yml | 153 -------- scripts/ansible/roles/preflight/meta/main.yml | 7 - .../ansible/roles/preflight/tasks/main.yml | 98 ------ scripts/ansible/roles/restore/meta/main.yml | 7 - scripts/ansible/roles/restore/tasks/main.yml | 140 -------- scripts/ansible/roles/smoketest/meta/main.yml | 7 - .../ansible/roles/smoketest/tasks/main.yml | 197 ----------- scripts/ansible/roles/snapshot/meta/main.yml | 7 - scripts/ansible/roles/snapshot/tasks/main.yml | 154 -------- scripts/ansible/roles/status/meta/main.yml | 7 - scripts/ansible/roles/status/tasks/main.yml | 259 -------------- scripts/ansible/roles/teardown/README.md | 54 --- scripts/ansible/roles/teardown/meta/main.yml | 7 - scripts/ansible/roles/teardown/tasks/main.yml | 242 ------------- scripts/ansible/roles/version/meta/main.yml | 7 - scripts/ansible/roles/version/tasks/main.yml | 161 --------- scripts/ansible/roles/vpc/meta/main.yml | 7 - scripts/ansible/roles/vpc/tasks/absent.yml | 128 ------- scripts/ansible/roles/vpc/tasks/main.yml | 3 - scripts/ansible/roles/vpc/tasks/present.yml | 209 ----------- scripts/ansible/scripts/aws-as-spinifex.sh | 27 -- scripts/ansible/scripts/spx-as-spinifex.sh | 18 - scripts/ansible/vars/defaults.yml | 137 -------- 57 files changed, 1 insertion(+), 3865 deletions(-) delete mode 100644 scripts/ansible/.gitignore delete mode 100644 scripts/ansible/README.md delete mode 100644 scripts/ansible/ansible.cfg delete mode 100644 scripts/ansible/inventory/localhost.yml delete mode 100755 scripts/ansible/inventory/tofu.py delete mode 100644 scripts/ansible/playbooks/cluster-bootstrap.yml delete mode 100644 scripts/ansible/playbooks/dev-deploy.yml delete mode 100644 scripts/ansible/playbooks/dev-install.yml delete mode 100644 scripts/ansible/playbooks/dev-logs.yml delete mode 100644 scripts/ansible/playbooks/dev-preflight.yml delete mode 100644 scripts/ansible/playbooks/dev-reset.yml delete mode 100644 scripts/ansible/playbooks/dev-restore.yml delete mode 100644 scripts/ansible/playbooks/dev-snapshot.yml delete mode 100644 scripts/ansible/playbooks/dev-status.yml delete mode 100644 scripts/ansible/playbooks/dev-teardown.yml delete mode 100644 scripts/ansible/playbooks/dev-version.yml delete mode 100644 scripts/ansible/playbooks/dev-vpc.yml delete mode 100644 scripts/ansible/requirements.yml delete mode 100644 scripts/ansible/roles/build/meta/main.yml delete mode 100644 scripts/ansible/roles/build/tasks/main.yml delete mode 100644 scripts/ansible/roles/cluster-init/meta/main.yml delete mode 100644 scripts/ansible/roles/cluster-init/tasks/main.yml delete mode 100644 scripts/ansible/roles/cluster-join/meta/main.yml delete mode 100644 scripts/ansible/roles/cluster-join/tasks/main.yml delete mode 100644 scripts/ansible/roles/cluster-post/meta/main.yml delete mode 100644 scripts/ansible/roles/cluster-post/tasks/main.yml delete mode 100644 scripts/ansible/roles/deploy/meta/main.yml delete mode 100644 scripts/ansible/roles/deploy/tasks/main.yml delete mode 100644 scripts/ansible/roles/init/meta/main.yml delete mode 100644 scripts/ansible/roles/init/tasks/main.yml delete mode 100644 scripts/ansible/roles/install/meta/main.yml delete mode 100644 scripts/ansible/roles/install/tasks/main.yml delete mode 100644 scripts/ansible/roles/logs/meta/main.yml delete mode 100644 scripts/ansible/roles/logs/tasks/main.yml delete mode 100644 scripts/ansible/roles/preflight/meta/main.yml delete mode 100644 scripts/ansible/roles/preflight/tasks/main.yml delete mode 100644 scripts/ansible/roles/restore/meta/main.yml delete mode 100644 scripts/ansible/roles/restore/tasks/main.yml delete mode 100644 scripts/ansible/roles/smoketest/meta/main.yml delete mode 100644 scripts/ansible/roles/smoketest/tasks/main.yml delete mode 100644 scripts/ansible/roles/snapshot/meta/main.yml delete mode 100644 scripts/ansible/roles/snapshot/tasks/main.yml delete mode 100644 scripts/ansible/roles/status/meta/main.yml delete mode 100644 scripts/ansible/roles/status/tasks/main.yml delete mode 100644 scripts/ansible/roles/teardown/README.md delete mode 100644 scripts/ansible/roles/teardown/meta/main.yml delete mode 100644 scripts/ansible/roles/teardown/tasks/main.yml delete mode 100644 scripts/ansible/roles/version/meta/main.yml delete mode 100644 scripts/ansible/roles/version/tasks/main.yml delete mode 100644 scripts/ansible/roles/vpc/meta/main.yml delete mode 100644 scripts/ansible/roles/vpc/tasks/absent.yml delete mode 100644 scripts/ansible/roles/vpc/tasks/main.yml delete mode 100644 scripts/ansible/roles/vpc/tasks/present.yml delete mode 100755 scripts/ansible/scripts/aws-as-spinifex.sh delete mode 100755 scripts/ansible/scripts/spx-as-spinifex.sh delete mode 100644 scripts/ansible/vars/defaults.yml diff --git a/Makefile b/Makefile index c4fac8bf5..b733eea44 100644 --- a/Makefile +++ b/Makefile @@ -295,68 +295,8 @@ distro-arm64: distro-clean: rm -rf dist/ -# Ansible dev lifecycle (experimental, parallel to dev-*.sh / reset-dev-env.sh). -# See scripts/ansible/README.md and docs/development/improvements/ansible-dev-lifecycle.md. -# -# Variable overrides: pass EXTRA_VARS="key=val key2=val2" to forward as -# `--extra-vars` to ansible-playbook. Plain `-e` on the make command line is -# make's own flag and does NOT reach ansible. -# make ansible-dev-install EXTRA_VARS="spinifex_external_pool_start=192.168.1.90 spinifex_external_pool_end=192.168.1.99" -EXTRA_VARS ?= -_ANSIBLE_EXTRA = $(if $(strip $(EXTRA_VARS)),--extra-vars "$(EXTRA_VARS)",) - -ansible-dev-preflight: - cd scripts/ansible && ansible-playbook playbooks/dev-preflight.yml $(_ANSIBLE_EXTRA) - -ansible-dev-teardown: - cd scripts/ansible && ansible-playbook playbooks/dev-teardown.yml $(_ANSIBLE_EXTRA) - -ansible-dev-install: - cd scripts/ansible && ansible-playbook playbooks/dev-install.yml $(_ANSIBLE_EXTRA) - -ansible-dev-reset: - cd scripts/ansible && ansible-playbook playbooks/dev-reset.yml $(_ANSIBLE_EXTRA) - -ansible-dev-deploy: - cd scripts/ansible && ansible-playbook playbooks/dev-deploy.yml $(_ANSIBLE_EXTRA) - -ansible-dev-status: - cd scripts/ansible && ansible-playbook playbooks/dev-status.yml - -ansible-dev-logs: - cd scripts/ansible && ansible-playbook playbooks/dev-logs.yml - -# Snapshot / restore require an explicit -e snapshot_name=. The -# wrapper passes ANSIBLE_EXTRA through so devs can run -# `make ansible-dev-snapshot ANSIBLE_EXTRA='-e snapshot_name=before-merge'`. -ansible-dev-snapshot: - cd scripts/ansible && ansible-playbook playbooks/dev-snapshot.yml $(ANSIBLE_EXTRA) - -ansible-dev-restore: - cd scripts/ansible && ansible-playbook playbooks/dev-restore.yml $(ANSIBLE_EXTRA) - -ansible-dev-version: - cd scripts/ansible && ansible-playbook playbooks/dev-version.yml - -ansible-dev-vpc: - cd scripts/ansible && ansible-playbook playbooks/dev-vpc.yml $(ANSIBLE_EXTRA) - -# Multi-node cluster bootstrap against a tofu env (env1, env2, bryn, etc). -# Inventory is generated from scripts/tofu-cluster/envs/.tfvars. -# make ansible-cluster-bootstrap ENV=env1 POOL=192.168.1.150-192.168.1.159 -ENV ?= -POOL ?= -ansible-cluster-bootstrap: - @test -n "$(ENV)" || { echo "ENV= required (e.g. env1, env2)"; exit 64; } - cd scripts/ansible && CLUSTER_ENV=$(ENV) ansible-playbook -i inventory/tofu.py playbooks/cluster-bootstrap.yml \ - -e cluster_env=$(ENV) \ - $(if $(POOL),-e cluster_external_pool=$(POOL),) \ - $(_ANSIBLE_EXTRA) - .PHONY: build build-ui build-installer build-lb-agent build-system-image build-eks-server-image import-eks-server-image build-eks-agent-image build-microvm-image install-microvm go_build go_run preflight test test-cover test-race diff-coverage bench run test-actions test-harness manifest-check diff-coverage bench run \ deploy reinstall clean \ install-system install-go install-aws quickinstall \ lint fix govulncheck \ - distro distro-amd64 distro-arm64 distro-clean \ - ansible-dev-preflight ansible-dev-teardown ansible-dev-install ansible-dev-reset ansible-dev-deploy ansible-dev-status ansible-dev-logs ansible-dev-snapshot ansible-dev-restore ansible-dev-version ansible-dev-vpc \ - ansible-cluster-bootstrap + distro distro-amd64 distro-arm64 distro-clean diff --git a/scripts/ansible/.gitignore b/scripts/ansible/.gitignore deleted file mode 100644 index 349f28175..000000000 --- a/scripts/ansible/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.creds/ -*.retry diff --git a/scripts/ansible/README.md b/scripts/ansible/README.md deleted file mode 100644 index 35e31b71f..000000000 --- a/scripts/ansible/README.md +++ /dev/null @@ -1,222 +0,0 @@ -# Ansible Dev Lifecycle (parallel to bash scripts) - -Experimental Ansible-based lifecycle for a single-node Spinifex dev host. -Lives alongside the existing `scripts/dev-*.sh` and `scripts/reset-dev-env.sh`; -neither set is removed. Decide which to keep after parity testing. - -Plan: `docs/development/improvements/ansible-dev-lifecycle.md` (mulga top-level). - -## Prerequisites - -Venv lives at sub-repo root (`spinifex/.venv/`) — one venv per sub-repo, -shared by any future python tooling in spinifex. Bootstrap from `spinifex/`: - -``` -sudo apt install python3.13-venv -python3 -m venv .venv -source .venv/bin/activate -pip install 'ansible>=9' -ansible-galaxy collection install -r scripts/ansible/requirements.yml -``` - -Then `cd scripts/ansible` to run playbooks — `ansible.cfg` resolves the -inventory and roles relative to CWD. - -## Playbooks - -| Playbook | Purpose | Bash parity | -|---|---|---| -| `playbooks/dev-preflight.yml` | Dependency + port check | `dev-setup.sh` §checks | -| `playbooks/dev-teardown.yml` | Wipe state only (no reinstall) | `reset-dev-env.sh` §teardown | -| `playbooks/dev-install.yml` | Build + install + init + smoketest on clean box | `dev-install.sh` | -| `playbooks/dev-reset.yml` | Capture settings → teardown → build → install → init → smoketest | `reset-dev-env.sh` (full) | -| `playbooks/dev-deploy.yml` | Rebuild + swap binaries/microvm artifacts + restart (no setup.sh, no smoketest) | `make deploy` | -| `playbooks/dev-status.yml` | Read-only health snapshot (units, ports, OVN/OVS, gateway, counts, drift) | none | -| `playbooks/dev-logs.yml` | Dump journald + `/var/log/spinifex/*` + status/networking/versions into a tarball | none | -| `playbooks/dev-snapshot.yml` | Quiesce spinifex+OVN+OVS, tar state paths to a named bundle, restart | none | -| `playbooks/dev-restore.yml` | Stop services, wipe + untar a named bundle, refresh CA, restart | none | -| `playbooks/dev-version.yml` | Build-vs-install drift report (spx, plugin, microvm) + sub-repo HEADs | none | -| `playbooks/dev-vpc.yml` | Idempotent dev VPC fixture (VPC + public subnet + IGW + default route); `-e dev_vpc_state=absent` tears down | partial overlap with `scripts/iac/examples/*` | - -Upcoming (not yet implemented): - -- `dev-mode-start.yml` / `dev-mode-stop.yml` — parity with `start-dev.sh` / `stop-dev.sh` - (lowest priority — deprecated bash scripts, CI-only callers). - -## Invocation - -``` -ansible-playbook playbooks/dev-preflight.yml -ansible-playbook playbooks/dev-teardown.yml -ansible-playbook playbooks/dev-install.yml -ansible-playbook playbooks/dev-reset.yml -ansible-playbook playbooks/dev-deploy.yml -ansible-playbook playbooks/dev-status.yml -ansible-playbook playbooks/dev-logs.yml -ansible-playbook playbooks/dev-snapshot.yml -e snapshot_name=before-merge -ansible-playbook playbooks/dev-restore.yml -e snapshot_name=before-merge -ansible-playbook playbooks/dev-version.yml -ansible-playbook playbooks/dev-vpc.yml -``` - -Or via `make` (from `spinifex/`): - -``` -make ansible-dev-preflight -make ansible-dev-teardown -make ansible-dev-install -make ansible-dev-reset -make ansible-dev-deploy -make ansible-dev-status -make ansible-dev-logs -make ansible-dev-snapshot ANSIBLE_EXTRA='-e snapshot_name=before-merge' -make ansible-dev-restore ANSIBLE_EXTRA='-e snapshot_name=before-merge' -make ansible-dev-version -make ansible-dev-vpc -make ansible-dev-vpc ANSIBLE_EXTRA='-e dev_vpc_state=absent' -``` - -### When to use which - -- First-time / clean box → `ansible-dev-install` -- Iterate on Go code, microvm initramfs, lb-agent → `ansible-dev-deploy` (fast) -- Changed systemd units, helper scripts, logrotate, setup.sh → `ansible-dev-reset` (slow, full rebuild) -- Need a clean slate without reinstall → `ansible-dev-teardown` -- "Is my dev box healthy?" → `ansible-dev-status` (read-only, never mutates) -- Filing a bug / capturing the state of a broken box → `ansible-dev-logs` (writes `/tmp/spinifex-logs--.tar.gz`; override `-e logs_since=10min` or `-e logs_include_dmesg=false`) -- Checkpoint before a risky op (branch switch, viperblock surgery, ovn restart cycle) → `ansible-dev-snapshot ANSIBLE_EXTRA='-e snapshot_name='`; roll back via `ansible-dev-restore` instead of a full `dev-reset`. Bundles live in `/var/lib/spinifex-snapshots/.tar.gz` (root-owned, survives `dev-teardown`). -- "Do I need to `ansible-dev-deploy`?" → `ansible-dev-version` (drift-only check; faster than `dev-status`) -- Want a known-good VPC/subnet for manual EC2 testing without writing tofu → `ansible-dev-vpc` (smoketest will then find and use it automatically). Tear down with `ANSIBLE_EXTRA='-e dev_vpc_state=absent'`. - -## Variable overrides - -Defaults in `vars/defaults.yml`. Override per run with `-e`: - -``` -ansible-playbook playbooks/dev-teardown.yml -e spinifex_wipe_ssh_keys=true -``` - -Useful overrides: - -| Var | Default | What it does | -|---|---|---| -| `spinifex_wipe_legacy_home` | `true` | Remove `$HOME/spinifex` (legacy dev-mode path) | -| `spinifex_wipe_ssh_keys` | `false` | Remove `~/.ssh/spinifex-key*` | -| `spinifex_wipe_aws_creds` | `false` | Remove spinifex profile from `~/.aws/credentials` | -| `teardown_process_wait_seconds` | `30` | Grace period for processes to exit | -| `spinifex_region` | `ap-southeast-2` | Region passed to `spx admin init` | -| `spinifex_az` | `{{ region }}a` | AZ passed to `spx admin init` | -| `spinifex_external_mode` | `pool` | External networking mode — `pool` or empty (NAT removed) | -| `spinifex_external_no_external` | `false` | `true` → emit `--no-external` and skip external networking | -| `spinifex_external_pool_start` | `""` | **Required** for `pool` mode — first IP of the static WAN pool | -| `spinifex_external_pool_end` | `""` | **Required** for `pool` mode — last IP of the static WAN pool | -| `spinifex_external_gateway` | `""` | WAN gateway (auto-detected when blank) | -| `spinifex_external_prefix_len` | `""` | WAN prefix length (auto-detected when blank) | -| `spinifex_external_gateway_ip` | `""` | OVN router external-IP override (`--gateway-ip`) | - -`pool` mode is mandatory unless you set `spinifex_external_no_external=true`. -`spx admin init` rejects the run without a `--external-pool` range, so the -init role asserts `spinifex_external_pool_start/_end` upfront. Either persist -them in `vars/defaults.yml`, or pass them at invocation: - -Direct `ansible-playbook` (use `-e` here — this is ansible's flag): - -``` -ansible-playbook playbooks/dev-install.yml \ - -e spinifex_external_pool_start=192.168.1.150 \ - -e spinifex_external_pool_end=192.168.1.250 -``` - -Via `make` (use `EXTRA_VARS=` — make eats its own `-e`): - -``` -make ansible-dev-install \ - EXTRA_VARS="spinifex_external_pool_start=192.168.1.150 spinifex_external_pool_end=192.168.1.250" -``` - -`dev-reset.yml` automatically captures `region`, `az`, `external_mode`, -pool range, gateway, prefix-len and `gateway_ip` from the existing -`/etc/spinifex/spinifex.toml` before teardown and replays them into -`init`. Legacy `external_mode = "nat"` is coerced to `"pool"` with a warn. -Use `-e` to override. - -## Helper scripts - -`scripts/aws-as-spinifex.sh` and `scripts/spx-as-spinifex.sh` wrap `aws` -and `spx` invocations in `sg spinifex -c '...'` so they run with the -`spinifex` supplementary group active. Both helpers preset -`AWS_PROFILE=spinifex`. All AWS-calling tasks in the roles use these -via `spinifex_aws_cli` / `spinifex_spx_cli` from `vars/defaults.yml`. - -Background: `/etc/spinifex/ca.pem` lives under `drwxr-x--- root:spinifex`, -so the AWS CLI needs `spinifex` group membership to read the CA bundle. -Ansible's `become_user` is a no-op when the target user equals the -calling user (no `sudo -u` invoked → no `initgroups(3)` → supplementary -groups inherited from the operator's shell). On a fresh login the -operator's shell would have `spinifex` (added by `setup.sh`); on shells -that predate the group add it does not. The helpers sidestep this -entirely. - -## Leak catalog - -`roles/teardown/README.md` tracks every known state source. When teardown -misses something, add it there and in `roles/teardown/tasks/main.yml`. - -## Multi-node cluster bootstrap - -`playbooks/cluster-bootstrap.yml` provisions a 2+ node Spinifex cluster -across a long-running tofu env (`env1`, `env2`, `bryn`, etc). Inventory -is generated dynamically from `scripts/tofu-cluster/envs/.tfvars` -via `inventory/tofu.py` — first node in `nodes = [...]` is the init host, -the rest are joins. - -```bash -make ansible-cluster-bootstrap ENV=env1 POOL=192.168.1.150-192.168.1.159 -``` - -`POOL` is optional; omit for DHCP fallback. Equivalent without make: - -```bash -cd scripts/ansible -CLUSTER_ENV=env1 ansible-playbook -i inventory/tofu.py \ - playbooks/cluster-bootstrap.yml \ - -e cluster_env=env1 \ - -e cluster_external_pool=192.168.1.150-192.168.1.159 -``` - -Plays sequence: - -1. **runner (localhost)** — `build` role produces `/tmp/spinifex-local.tar.gz`. -2. **all env hosts (parallel)** — copies tarball, stops any dev-layout - services (`~/spinifex/`), runs `preflight` + `install` roles. `setup.sh` - creates `/etc/spinifex`, the `spinifex` user/group, systemd units, and - installs `/usr/local/bin/spx`. -3. **init host only** — `cluster-init` role runs `spx admin init` in the - background, waits for the formation server, captures the join token. - CA is then copied into `/usr/local/share/ca-certificates/spinifex-ca.crt` - **before** `spinifex.target` starts (required — predastore enforces - strict TLS verify against the system trust store). -4. **join hosts (parallel)** — `cluster-join` role runs `spx admin join` - against the formation server, then installs CA, then starts - `spinifex.target`. -5. **all hosts** — polls `https://:4432/health` until `awsgw=ok`. -6. **init host only** — `cluster-post` role imports the SSH key + Ubuntu - AMI (both idempotent: skip if already present). - -Re-running the playbook against an already-bootstrapped env is safe — -`setup.sh`, `spx admin init --force`, CA copy, key/AMI import are all -idempotent. - -### Migration from `bootstrap.sh` - -`scripts/tofu-cluster/bootstrap.sh` ran services under `~/spinifex/` as -`tf-user` via `start-dev.sh` with no systemd supervision, and installed -the cluster CA *after* services started — predastore would crash with -`x509: certificate signed by unknown authority` on every first boot. -`cluster-bootstrap.yml` replaces that flow with production-layout -(`/etc/spinifex/` + systemd) and correct CA-before-services ordering. -The first run on an env previously bootstrapped by `bootstrap.sh` will -stop the dev-layout services, install the prod layout, and re-init the -cluster from scratch via `spx admin init --force`. - -`bootstrap.sh` stays in-tree for CI and pseudo-multinode envs. diff --git a/scripts/ansible/ansible.cfg b/scripts/ansible/ansible.cfg deleted file mode 100644 index fc4203126..000000000 --- a/scripts/ansible/ansible.cfg +++ /dev/null @@ -1,17 +0,0 @@ -[defaults] -inventory = inventory/localhost.yml -roles_path = roles -stdout_callback = ansible.builtin.default -host_key_checking = False -retry_files_enabled = False -interpreter_python = auto_silent -forks = 10 - -[inventory] -# inventory/tofu.py is an executable script inventory used by -# cluster-bootstrap.yml — opted into via `-i inventory/tofu.py` on the -# command line; not default to keep dev-* playbooks pointing at localhost. -enable_plugins = host_list, script, auto, yaml, ini, toml - -[callback_default] -result_format = yaml diff --git a/scripts/ansible/inventory/localhost.yml b/scripts/ansible/inventory/localhost.yml deleted file mode 100644 index 1b6373943..000000000 --- a/scripts/ansible/inventory/localhost.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -all: - hosts: - localhost: - ansible_connection: local - ansible_python_interpreter: "{{ ansible_playbook_python }}" diff --git a/scripts/ansible/inventory/tofu.py b/scripts/ansible/inventory/tofu.py deleted file mode 100755 index 822091ba8..000000000 --- a/scripts/ansible/inventory/tofu.py +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/env python3 -"""Dynamic ansible inventory generator from tofu-cluster tfvars. - -Reads scripts/tofu-cluster/envs/.tfvars (HCL subset) and emits ansible -JSON inventory. First node in the tfvars `nodes = [...]` list is the init -host (forms the cluster); the rest are join hosts. - -Usage: - inventory/tofu.py --list --env env1 - inventory/tofu.py --host --env env1 - -Selecting the env: - CLUSTER_ENV=env1 inventory/tofu.py --list - inventory/tofu.py --list --env env1 -""" - -from __future__ import annotations - -import argparse -import json -import os -import re -import sys -from pathlib import Path - - -def _repo_root() -> Path: - here = Path(__file__).resolve() - for parent in here.parents: - if (parent / "go.work").exists() or (parent / ".gitmodules").exists(): - return parent - raise SystemExit(f"could not locate mulga repo root from {here}") - - -def _tfvars_path(env: str) -> Path: - root = _repo_root() - candidate = root / "scripts" / "tofu-cluster" / "envs" / f"{env}.tfvars" - if not candidate.exists(): - raise SystemExit(f"tfvars file not found: {candidate}") - return candidate - - -_STRING_RE = re.compile(r'^\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*"([^"]*)"\s*$') -_NUMBER_RE = re.compile(r'^\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*([0-9]+)\s*$') -_NODE_FIELD_RE = re.compile(r'(\w+)\s*=\s*"([^"]*)"') - - -def _parse_tfvars(path: Path) -> dict: - """Minimal tfvars parser — handles the subset used by envs/*.tfvars. - - Supports: - key = "string" - key = 12345 - nodes = [ - { name = "x", wan_ip = "1.2.3.4", ... }, - ... - ] - """ - out: dict = {"nodes": []} - text = path.read_text() - - # Strip line comments - text = re.sub(r"#.*", "", text) - - # Pull the nodes block out first, then process remaining lines. - nodes_match = re.search(r"nodes\s*=\s*\[(.+?)\]\s*$", text, re.DOTALL | re.MULTILINE) - if nodes_match: - nodes_body = nodes_match.group(1) - for entry in re.finditer(r"\{([^}]+)\}", nodes_body): - fields = dict(_NODE_FIELD_RE.findall(entry.group(1))) - if "name" in fields and "wan_ip" in fields: - out["nodes"].append(fields) - text = text.replace(nodes_match.group(0), "") - - for line in text.splitlines(): - if m := _STRING_RE.match(line): - out[m.group(1)] = m.group(2) - elif m := _NUMBER_RE.match(line): - out[m.group(1)] = int(m.group(2)) - - return out - - -def _resolve_ssh_key(value: str | None) -> str: - if not value: - return os.path.expanduser("~/.ssh/tf-user-ap-southeast-2") - return os.path.expanduser(value) - - -def _build_inventory(env: str) -> dict: - data = _parse_tfvars(_tfvars_path(env)) - nodes = data.get("nodes") or [] - if not nodes: - raise SystemExit(f"{env}.tfvars has no nodes") - - ssh_user = data.get("ssh_user", "tf-user") - ssh_key = _resolve_ssh_key(data.get("ssh_public_key_path", "").replace(".pub", "")) - - hostvars: dict[str, dict] = {} - all_hosts: list[str] = [] - init_hosts: list[str] = [] - join_hosts: list[str] = [] - - for idx, node in enumerate(nodes): - ip = node["wan_ip"] - role = "init" if idx == 0 else "join" - hostvars[ip] = { - "ansible_host": ip, - "ansible_user": ssh_user, - "ansible_ssh_private_key_file": ssh_key, - "ansible_ssh_common_args": "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR", - "spinifex_node_name": node["name"], - "spinifex_node_role": role, - "spinifex_node_index": idx, - "spinifex_wan_ip": ip, - } - all_hosts.append(ip) - (init_hosts if role == "init" else join_hosts).append(ip) - - # Group-level vars derived from tfvars (operator can override with -e). - cluster_init_host = init_hosts[0] - group_vars = { - "cluster_env": env, - "cluster_init_host": cluster_init_host, - "cluster_init_ip": cluster_init_host, - "spinifex_node_count": len(nodes), - "spinifex_region": data.get("region", "ap-southeast-2"), - "spinifex_az": data.get("az", "ap-southeast-2a"), - } - if cidr := data.get("env_cidr"): - group_vars["cluster_env_cidr"] = cidr - - inventory = { - "_meta": {"hostvars": hostvars}, - env: {"hosts": all_hosts, "vars": group_vars}, - "cluster": {"children": [env]}, - "init": {"hosts": init_hosts}, - "join": {"hosts": join_hosts}, - } - return inventory - - -def main() -> int: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--list", action="store_true", help="emit full inventory") - parser.add_argument("--host", help="emit hostvars for a single host (ignored — _meta carries them)") - parser.add_argument( - "--env", - default=os.environ.get("CLUSTER_ENV"), - help="tofu env name (matches scripts/tofu-cluster/envs/.tfvars); also via CLUSTER_ENV env var", - ) - args = parser.parse_args() - - if not args.env: - sys.stderr.write("error: --env required (or CLUSTER_ENV)\n") - return 64 - - if args.host: - json.dump({}, sys.stdout) - sys.stdout.write("\n") - return 0 - - inventory = _build_inventory(args.env) - json.dump(inventory, sys.stdout, indent=2) - sys.stdout.write("\n") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/scripts/ansible/playbooks/cluster-bootstrap.yml b/scripts/ansible/playbooks/cluster-bootstrap.yml deleted file mode 100644 index d6670c56a..000000000 --- a/scripts/ansible/playbooks/cluster-bootstrap.yml +++ /dev/null @@ -1,330 +0,0 @@ ---- -# cluster-bootstrap.yml — multi-node Spinifex cluster bootstrap against a -# tofu-provisioned env. Inventory comes from inventory/tofu.py which parses -# scripts/tofu-cluster/envs/.tfvars. -# -# Usage: -# cd spinifex/scripts/ansible -# ansible-playbook -i inventory/tofu.py playbooks/cluster-bootstrap.yml \ -# -e cluster_env=env1 -e cluster_external_pool=192.168.1.150-192.168.1.159 -# -# Or via the make wrapper: -# make ansible-cluster-bootstrap ENV=env1 POOL=192.168.1.150-192.168.1.159 -# -# Behaviour: -# - all hosts: preflight + install (setup.sh) — production layout -# - init host: spx admin init (backgrounded) + CA install + spinifex.target -# - join hosts: spx admin join + CA install + spinifex.target (parallel) -# - init host: import ssh key + ubuntu AMI (idempotent) - -- name: Cluster bootstrap — build artifact once on runner - hosts: localhost - gather_facts: true - vars_files: - - ../vars/defaults.yml - tasks: - - name: assert cluster_env supplied - ansible.builtin.assert: - that: cluster_env | default('') | length > 0 - fail_msg: "Pass -e cluster_env= (matches scripts/tofu-cluster/envs/.tfvars)" - roles: - - build - -- name: Cluster bootstrap — install (all nodes, parallel) - hosts: "{{ cluster_env }}" - gather_facts: true - serial: 100% - vars: - install_run_ovn: false # we drive setup-ovn ourselves with role-aware args - cluster_bootstrap_purge: true # wipe stale single-node predastore.toml + raft data - vars_files: - - ../vars/defaults.yml - pre_tasks: - - name: copy build tarball to each node - ansible.builtin.copy: - src: "{{ build_tarball_path }}" - dest: "{{ build_tarball_path }}" - mode: "0644" - - - name: stop dev-layout services if running (migration from ~/spinifex/) - become: true - # Bracket trick on the first letter prevents the pattern literal in the - # shell command line from matching the running shell itself (pkill -f - # against literal patterns is otherwise self-killing — rc=-9). - # `spx [a]dmin` catches lingering formation servers from prior bootstrap - # attempts that own port 4432 and steal joins from the new init. - ansible.builtin.shell: - cmd: | - pkill -9 -f "[b]in/spx service" 2>/dev/null || true - pkill -9 -f "spx [a]dmin" 2>/dev/null || true - pkill -9 -f "spinifex-[u]i" 2>/dev/null || true - pkill -9 -f "[n]ats-server" 2>/dev/null || true - pkill -9 -f "[p]redastore" 2>/dev/null || true - pkill -9 -f "[v]iperblock" 2>/dev/null || true - sleep 2 - rm -rf "{{ ansible_env.HOME }}/spinifex" 2>/dev/null || true - exit 0 - changed_when: false - roles: - - install - -# Wipe OVN/OVS state before setup-ovn runs. Without this, re-bootstrapping a -# previously-built cluster leaves stale chassis rows in the SB DB, stale -# external_ids on Open_vSwitch, stale br-int flows + ports, stale -# systemd-networkd unit files, and stale ovs-monitor-ipsec strongSwan certs. -# Symptom: ovn-controller flows reference dead encap endpoints; IPsec SAs -# fail AUTHENTICATION_FAILED; new joins shadow ghosts under the same -# node-name. -- name: Cluster bootstrap — OVN/OVS state reset (all nodes, parallel) - hosts: "{{ cluster_env }}" - gather_facts: false - serial: 100% - vars_files: - - ../vars/defaults.yml - tasks: - - name: reset — stop OVN/OVS services - become: true - ansible.builtin.systemd: - name: "{{ item }}" - state: stopped - loop: - - ovn-controller - - ovn-central - - openvswitch-ipsec - - openvswitch-switch - failed_when: false - - - name: reset — delete OVN NB/SB databases - become: true - ansible.builtin.file: - path: "{{ item }}" - state: absent - loop: - - "{{ ovn_nb_db }}" - - "{{ ovn_sb_db }}" - - - name: reset — delete OVS conf.db + system-id (force fresh ovsdb) - become: true - ansible.builtin.file: - path: "{{ item }}" - state: absent - loop: - - /etc/openvswitch/conf.db - - /etc/openvswitch/.conf.db.~lock~ - - /etc/openvswitch/system-id.conf - - - name: reset — drop spinifex-managed systemd-networkd unit files - become: true - ansible.builtin.shell: | - rm -f /etc/systemd/network/14-spinifex-*.netdev \ - /etc/systemd/network/15-spinifex-*.netdev \ - /etc/systemd/network/15-spinifex-*.network \ - /etc/systemd/network/16-spinifex-*.network - networkctl reload 2>/dev/null || true - changed_when: true - - - name: reset — enumerate stale spinifex veth/tap netdevs - ansible.builtin.shell: | - ip -o link show | awk -F': ' '{print $2}' | cut -d'@' -f1 | \ - grep -E '^(veth-wan-br|veth-wan-ovs|spx-ext-|spx-tap-|spx-)' || true - register: reset_links - changed_when: false - - - name: reset — delete stale netdevs - become: true - ansible.builtin.command: "ip link delete {{ item }}" - loop: "{{ reset_links.stdout_lines }}" - changed_when: true - failed_when: false - - - name: reset — clear ovs-monitor-ipsec strongSwan state - become: true - ansible.builtin.shell: | - rm -rf /var/lib/openvswitch/pki 2>/dev/null || true - rm -f /etc/ipsec.d/certs/ovs-* /etc/ipsec.d/private/ovs-* 2>/dev/null || true - rm -f /etc/ipsec.conf.d/ovs-* 2>/dev/null || true - changed_when: true - - - name: reset — start openvswitch-switch with fresh conf.db - become: true - ansible.builtin.systemd: - name: openvswitch-switch - state: started - daemon_reload: true - -- name: Cluster bootstrap — OVN central (init host only) - hosts: init - gather_facts: false - vars_files: - - ../vars/defaults.yml - tasks: - - name: setup-ovn --management on init host - become: true - ansible.builtin.command: - cmd: >- - /usr/local/share/spinifex/setup-ovn.sh - --management - --encap-ip={{ spinifex_wan_ip }} - --node-name={{ hostvars[inventory_hostname]['spinifex_node_name'] }} - changed_when: true - -- name: Cluster bootstrap — OVN chassis (join hosts, parallel) - hosts: join - gather_facts: false - vars_files: - - ../vars/defaults.yml - tasks: - - name: setup-ovn --ovn-remote on join hosts - become: true - ansible.builtin.command: - cmd: >- - /usr/local/share/spinifex/setup-ovn.sh - --ovn-remote=tcp:{{ cluster_init_host }}:6642 - --encap-ip={{ spinifex_wan_ip }} - --node-name={{ hostvars[inventory_hostname]['spinifex_node_name'] }} - changed_when: true - -- name: Cluster bootstrap — init host (start formation server) - hosts: init - gather_facts: false - vars_files: - - ../vars/defaults.yml - roles: - - cluster-init - -- name: Cluster bootstrap — join hosts run spx admin join (parallel) - hosts: join - gather_facts: false - serial: 100% - vars_files: - - ../vars/defaults.yml - roles: - - cluster-join - -- name: Cluster bootstrap — wait for init to finish writing multi-node configs - hosts: init - gather_facts: false - vars_files: - - ../vars/defaults.yml - tasks: - - name: wait for spx admin init async job to complete - become: true - ansible.builtin.async_status: - jid: "{{ cluster_init_async.ansible_job_id }}" - register: cluster_init_done - until: cluster_init_done.finished - retries: 60 - delay: 5 - - - name: dump init log on failure - ansible.builtin.command: tail -100 /tmp/spx-admin-init.log - register: cluster_init_log - changed_when: false - when: cluster_init_done.rc | default(1) != 0 - - - name: assert init exited cleanly - ansible.builtin.assert: - that: cluster_init_done.rc == 0 - fail_msg: | - spx admin init failed (rc={{ cluster_init_done.rc }}) - {{ cluster_init_log.stdout | default('(log not captured)') }} - - - name: confirm multi-node predastore.toml written - become: true - ansible.builtin.shell: | - if grep -q '127\.0\.0\.1' {{ spinifex_etc_dir }}/predastore/predastore.toml 2>/dev/null; then - echo "ERROR: predastore.toml still references loopback — multi-node config not written" - exit 1 - fi - grep -c '^\[\[nodes\]\]' {{ spinifex_etc_dir }}/predastore/predastore.toml 2>/dev/null || echo 0 - register: predastore_node_count - changed_when: false - -- name: Cluster bootstrap — install CA on all nodes (before service start) - hosts: "{{ cluster_env }}" - gather_facts: false - vars_files: - - ../vars/defaults.yml - tasks: - - name: install CA into system trust - become: true - ansible.builtin.copy: - src: "{{ spinifex_ca_src }}" - dest: "{{ spinifex_ca_trust_path }}" - mode: "0644" - remote_src: true - - - name: rebuild CA bundle - become: true - ansible.builtin.command: update-ca-certificates - changed_when: true - - # spinifex-ui reverse-proxies localhost:9999 (awsgw) and localhost:8443 - # (predastore) — hardcoded in spinifex/services/spinifexui/spinifexui.go. - # spx admin init binds those services to BindIP only, so the loopback - # connection fails (BadGateway in UI). Patch to wildcard bind; cert - # already includes 127.0.0.1 in IP SANs. - - name: patch awsgw bind to 0.0.0.0 (UI proxies via localhost) - become: true - ansible.builtin.replace: - path: "{{ spinifex_config_file }}" - regexp: '^(\s*host\s*=\s*")[^"]+(:9999")' - replace: '\g<1>0.0.0.0\g<2>' - - - name: patch predastore bind to 0.0.0.0 (UI proxies via localhost) - become: true - ansible.builtin.replace: - path: "{{ spinifex_config_file }}" - regexp: '^(\s*host\s*=\s*")[^"]+(:8443")' - replace: '\g<1>0.0.0.0\g<2>' - -- name: Cluster bootstrap — start services (init first, then joins) - hosts: init - gather_facts: false - vars_files: - - ../vars/defaults.yml - tasks: - - name: start spinifex.target on init - become: true - ansible.builtin.systemd: - name: spinifex.target - state: started - -- name: Cluster bootstrap — start services on join hosts - hosts: join - gather_facts: false - serial: 100% - vars_files: - - ../vars/defaults.yml - tasks: - - name: start spinifex.target on joiners - become: true - ansible.builtin.systemd: - name: spinifex.target - state: started - -- name: Cluster bootstrap — readiness check (all nodes) - hosts: "{{ cluster_env }}" - gather_facts: false - vars_files: - - ../vars/defaults.yml - tasks: - - name: wait for awsgw responsiveness - ansible.builtin.uri: - url: "https://{{ spinifex_wan_ip }}:{{ cluster_formation_port }}/health" - validate_certs: false - return_content: true - register: cluster_health - until: - - cluster_health.status == 200 - - cluster_health.json.service_health.awsgw == "ok" - retries: 30 - delay: 5 - -- name: Cluster bootstrap — post-bootstrap fixtures (init host only) - hosts: init - gather_facts: true - vars_files: - - ../vars/defaults.yml - roles: - - cluster-post diff --git a/scripts/ansible/playbooks/dev-deploy.yml b/scripts/ansible/playbooks/dev-deploy.yml deleted file mode 100644 index 123f46b29..000000000 --- a/scripts/ansible/playbooks/dev-deploy.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -# In-place artifact swap: rebuilds + replaces binaries/microvm artifacts on -# an already-installed node, then restarts spinifex.target. Use when iterating -# on code without altering systemd units, users, dirs, or running the full -# smoketest. For first-time or unit/script changes use dev-install / dev-reset. -- name: Dev deploy — build + swap binaries + restart (no setup.sh, no smoketest) - hosts: localhost - gather_facts: true - vars_files: - - ../vars/defaults.yml - - roles: - - build - - deploy diff --git a/scripts/ansible/playbooks/dev-install.yml b/scripts/ansible/playbooks/dev-install.yml deleted file mode 100644 index d7a358413..000000000 --- a/scripts/ansible/playbooks/dev-install.yml +++ /dev/null @@ -1,67 +0,0 @@ ---- -- name: Dev install — build, install, init, smoketest (idempotent) - hosts: localhost - gather_facts: true - vars_files: - - ../vars/defaults.yml - - pre_tasks: - - name: preflight - ansible.builtin.include_role: - name: preflight - - - name: health — config file present? - ansible.builtin.stat: - path: "{{ spinifex_config_file }}" - register: health_config - - - name: health — spinifex.target active? - become: true - ansible.builtin.command: systemctl is-active spinifex.target - register: health_target - changed_when: false - failed_when: false - - - name: health — awsgw responds? - become: true - become_user: "{{ spinifex_invoking_user }}" - environment: - AWS_PROFILE: spinifex - ansible.builtin.command: aws ec2 describe-regions - register: health_gw - changed_when: false - failed_when: false - - - name: health — spx binary installed? - ansible.builtin.stat: - path: /usr/local/bin/spx - register: health_spx - - - name: health — set already_installed fact - ansible.builtin.set_fact: - spinifex_already_installed: >- - {{ health_config.stat.exists - and health_spx.stat.exists - and (health_target.stdout | trim) == 'active' - and health_gw.rc == 0 }} - - - name: health — summary - ansible.builtin.debug: - msg: | - Health: - spx binary: {{ 'present' if health_spx.stat.exists else 'missing' }} - config: {{ 'present' if health_config.stat.exists else 'missing' }} - target: {{ health_target.stdout | trim }} - awsgw: {{ 'ok' if health_gw.rc == 0 else 'not responding' }} - Already installed: {{ spinifex_already_installed }} - {% if spinifex_already_installed %} - → Skipping build/install/init. Smoketest only. - {% else %} - → Running full build → install → init → smoketest. - {% endif %} - - roles: - - { role: build, when: not (spinifex_already_installed | default(false)) } - - { role: install, when: not (spinifex_already_installed | default(false)) } - - { role: init, when: not (spinifex_already_installed | default(false)) } - - smoketest diff --git a/scripts/ansible/playbooks/dev-logs.yml b/scripts/ansible/playbooks/dev-logs.yml deleted file mode 100644 index 2461fd749..000000000 --- a/scripts/ansible/playbooks/dev-logs.yml +++ /dev/null @@ -1,17 +0,0 @@ ---- -# Capture spinifex + ovn/ovs + qemu/nbdkit logs from journald and -# /var/log/spinifex/ into a single tarball for bug reports. -# Tail mode is intentionally not provided — use `journalctl -u 'spinifex-*' -f` -# directly; ansible is the wrong tool for follow. -- name: Dev logs — dump journald + varlog + status into a bundle - hosts: localhost - gather_facts: true - vars_files: - - ../vars/defaults.yml - vars: - logs_since: "1h" - logs_output_dir: "/tmp" - logs_include_dmesg: true - - roles: - - logs diff --git a/scripts/ansible/playbooks/dev-preflight.yml b/scripts/ansible/playbooks/dev-preflight.yml deleted file mode 100644 index 4e54d3ff6..000000000 --- a/scripts/ansible/playbooks/dev-preflight.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -- name: Dev preflight — validate host dependencies - hosts: localhost - gather_facts: true - vars_files: - - ../vars/defaults.yml - roles: - - preflight diff --git a/scripts/ansible/playbooks/dev-reset.yml b/scripts/ansible/playbooks/dev-reset.yml deleted file mode 100644 index 82fa47d77..000000000 --- a/scripts/ansible/playbooks/dev-reset.yml +++ /dev/null @@ -1,72 +0,0 @@ ---- -- name: Dev reset — capture settings, wipe, rebuild, reinstall, re-init, smoketest - hosts: localhost - gather_facts: true - vars_files: - - ../vars/defaults.yml - - pre_tasks: - - name: capture — check existing spinifex.toml - ansible.builtin.stat: - path: "{{ spinifex_config_file }}" - register: reset_config_stat - - - name: capture — slurp existing config - ansible.builtin.slurp: - src: "{{ spinifex_config_file }}" - register: reset_config_raw - when: reset_config_stat.stat.exists - - - name: capture — decode config - ansible.builtin.set_fact: - reset_config_txt: "{{ reset_config_raw.content | b64decode }}" - when: reset_config_stat.stat.exists - - # List-concat-and-take-first pattern: missing regex match falls back to current default. - # `gateway\s*=` deliberately does not match `gateway_ip` / `gateway_lrp_*`. - - name: capture — extract scalars - ansible.builtin.set_fact: - spinifex_region: "{{ (reset_config_txt | regex_findall('region\\s*=\\s*\"([^\"]+)\"') + [spinifex_region])[0] }}" - spinifex_az: "{{ (reset_config_txt | regex_findall('\\baz\\s*=\\s*\"([^\"]+)\"') + [spinifex_az])[0] }}" - spinifex_external_mode: "{{ (reset_config_txt | regex_findall('external_mode\\s*=\\s*\"([^\"]+)\"') + [spinifex_external_mode])[0] }}" - spinifex_external_pool_start: "{{ (reset_config_txt | regex_findall('range_start\\s*=\\s*\"([^\"]+)\"') + [spinifex_external_pool_start])[0] }}" - spinifex_external_pool_end: "{{ (reset_config_txt | regex_findall('range_end\\s*=\\s*\"([^\"]+)\"') + [spinifex_external_pool_end])[0] }}" - spinifex_external_gateway: "{{ (reset_config_txt | regex_findall('\\bgateway\\s*=\\s*\"([^\"]+)\"') + [spinifex_external_gateway])[0] }}" - spinifex_external_prefix_len: "{{ (reset_config_txt | regex_findall('prefix_len\\s*=\\s*([0-9]+)') + [spinifex_external_prefix_len | string])[0] }}" - spinifex_external_gateway_ip: "{{ (reset_config_txt | regex_findall('gateway_ip\\s*=\\s*\"([^\"]+)\"') + [spinifex_external_gateway_ip])[0] }}" - when: reset_config_stat.stat.exists - - # Legacy: external_mode = "nat" was removed from spx. Coerce to "pool" - # so old configs still reset cleanly; warn so the operator notices. - - name: capture — coerce legacy external_mode=nat to pool - ansible.builtin.set_fact: - spinifex_external_mode: "pool" - when: spinifex_external_mode == 'nat' - - - name: capture — warn on legacy nat coercion - ansible.builtin.debug: - msg: "⚠️ Captured external_mode=nat from legacy config; coerced to 'pool' (NAT mode removed from spx admin init)." - when: - - reset_config_stat.stat.exists - - (reset_config_txt | regex_findall('external_mode\\s*=\\s*\"nat\"')) | length > 0 - - - name: capture — summary - ansible.builtin.debug: - msg: | - {% if reset_config_stat.stat.exists %} - Captured settings from {{ spinifex_config_file }}: - region={{ spinifex_region }}, az={{ spinifex_az }} - external_mode={{ spinifex_external_mode }} - pool={{ spinifex_external_pool_start }}-{{ spinifex_external_pool_end }} - gateway={{ spinifex_external_gateway }}, prefix={{ spinifex_external_prefix_len }} - gateway_ip={{ spinifex_external_gateway_ip }} - {% else %} - No existing config; using defaults from vars/defaults.yml (or -e overrides). - {% endif %} - - roles: - - teardown - - build - - install - - init - - smoketest diff --git a/scripts/ansible/playbooks/dev-restore.yml b/scripts/ansible/playbooks/dev-restore.yml deleted file mode 100644 index 1742cd4ef..000000000 --- a/scripts/ansible/playbooks/dev-restore.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -# Restore a dev-snapshot bundle: stop services, wipe the snapshot path -# set, untar the bundle, refresh CA trust, restart. -# -# Required: -e snapshot_name= -# Optional: -e snapshot_dir=/some/path -- name: Dev restore — wipe + untar snapshot + restart - hosts: localhost - gather_facts: true - vars_files: - - ../vars/defaults.yml - - roles: - - restore diff --git a/scripts/ansible/playbooks/dev-snapshot.yml b/scripts/ansible/playbooks/dev-snapshot.yml deleted file mode 100644 index 04875e073..000000000 --- a/scripts/ansible/playbooks/dev-snapshot.yml +++ /dev/null @@ -1,17 +0,0 @@ ---- -# Quiesce spinifex + ovn + ovs, tar /etc/spinifex + /var/lib/spinifex + -# /var/lib/ovn + /etc/openvswitch/conf.db into a named bundle, restart. -# Use to checkpoint a working state before a risky operation (branch -# switch, viperblock surgery, ovn-controller restart cycle). Roll back -# via dev-restore without a full dev-reset. -# -# Required: -e snapshot_name= -# Optional: -e snapshot_dir=/some/path -- name: Dev snapshot — quiesce + tar state + restart - hosts: localhost - gather_facts: true - vars_files: - - ../vars/defaults.yml - - roles: - - snapshot diff --git a/scripts/ansible/playbooks/dev-status.yml b/scripts/ansible/playbooks/dev-status.yml deleted file mode 100644 index 45a4e2d1e..000000000 --- a/scripts/ansible/playbooks/dev-status.yml +++ /dev/null @@ -1,13 +0,0 @@ ---- -# Read-only health snapshot for a Spinifex dev node. Never mutates state. -# Run any time the operator wants to know "is my box healthy?" — pairs with -# dev-preflight (run before install) as the post-install / running-system -# diagnostic. -- name: Dev status — health snapshot (read-only) - hosts: localhost - gather_facts: true - vars_files: - - ../vars/defaults.yml - - roles: - - status diff --git a/scripts/ansible/playbooks/dev-teardown.yml b/scripts/ansible/playbooks/dev-teardown.yml deleted file mode 100644 index bff1c9798..000000000 --- a/scripts/ansible/playbooks/dev-teardown.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -- name: Dev teardown — wipe Spinifex state (no reinstall) - hosts: localhost - gather_facts: true - vars_files: - - ../vars/defaults.yml - roles: - - teardown diff --git a/scripts/ansible/playbooks/dev-version.yml b/scripts/ansible/playbooks/dev-version.yml deleted file mode 100644 index 8698af643..000000000 --- a/scripts/ansible/playbooks/dev-version.yml +++ /dev/null @@ -1,11 +0,0 @@ ---- -# Detailed build-vs-install drift report. Faster than dev-status (no AWS, -# OVN, or port probing). Answers "do I need to ansible-dev-deploy?". -- name: Dev version — build vs install drift (read-only) - hosts: localhost - gather_facts: false - vars_files: - - ../vars/defaults.yml - - roles: - - version diff --git a/scripts/ansible/playbooks/dev-vpc.yml b/scripts/ansible/playbooks/dev-vpc.yml deleted file mode 100644 index 3981dbb9b..000000000 --- a/scripts/ansible/playbooks/dev-vpc.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -# Idempotent dev-mode VPC fixture: spinifex-dev-vpc + public subnet + -# IGW + default route. Hooks into smoketest's launch path (which finds -# the public subnet automatically). Re-runs are no-ops once converged. -# -# Default state: present. Tear down with -e dev_vpc_state=absent. -- name: Dev VPC — fixture VPC/subnet/IGW/route (idempotent) - hosts: localhost - gather_facts: false - vars_files: - - ../vars/defaults.yml - - roles: - - vpc diff --git a/scripts/ansible/requirements.yml b/scripts/ansible/requirements.yml deleted file mode 100644 index 3834074e0..000000000 --- a/scripts/ansible/requirements.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -collections: - - name: community.general - version: ">=8.0.0" - - name: ansible.posix - version: ">=1.5.0" diff --git a/scripts/ansible/roles/build/meta/main.yml b/scripts/ansible/roles/build/meta/main.yml deleted file mode 100644 index c03eba75c..000000000 --- a/scripts/ansible/roles/build/meta/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -galaxy_info: - role_name: build - description: Build spinifex + viperblock-nbdkit, stage tarball for setup.sh consumption. - license: BSD-3-Clause - min_ansible_version: "2.14" -dependencies: [] diff --git a/scripts/ansible/roles/build/tasks/main.yml b/scripts/ansible/roles/build/tasks/main.yml deleted file mode 100644 index 9096c62c0..000000000 --- a/scripts/ansible/roles/build/tasks/main.yml +++ /dev/null @@ -1,66 +0,0 @@ ---- -- name: build — spinifex (make build) - ansible.builtin.command: - cmd: make build - chdir: "{{ spinifex_root }}" - changed_when: true - -- name: build — viperblock nbdkit plugin (make go_build_nbd) - ansible.builtin.command: - cmd: make go_build_nbd - chdir: "{{ mulga_root }}/viperblock" - changed_when: true - -- name: build — detect microVM build script (present only on direct-boot branches) - ansible.builtin.stat: - path: "{{ spinifex_root }}/scripts/build-microvm-image.sh" - register: build_microvm_script - -- name: build — microVM kernel + initramfs (direct-boot LBs) - ansible.builtin.command: - cmd: make build-microvm-image - chdir: "{{ spinifex_root }}" - changed_when: true - when: build_microvm_script.stat.exists - -- name: build — verify build artifacts present - ansible.builtin.stat: - path: "{{ item }}" - register: build_artifacts - loop: - - "{{ spinifex_root }}/bin/spx" - - "{{ mulga_root }}/viperblock/lib/nbdkit-viperblock-plugin.so" - -- name: build — assert artifacts exist - ansible.builtin.assert: - that: item.stat.exists - fail_msg: "Missing build artifact: {{ item.item }}" - loop: "{{ build_artifacts.results }}" - loop_control: - label: "{{ item.item }}" - -- name: build — stage tarball contents (mirrors dev-install.sh) - ansible.builtin.shell: | - set -e - STAGING=$(mktemp -d) - trap 'rm -rf "$STAGING"' EXIT - cp "{{ spinifex_root }}/bin/spx" "$STAGING/spx" - cp "{{ mulga_root }}/viperblock/lib/nbdkit-viperblock-plugin.so" "$STAGING/" - cp "{{ spinifex_root }}/scripts/setup-ovn.sh" "$STAGING/" - mkdir -p "$STAGING/systemd" - cp "{{ spinifex_root }}/build/systemd/"* "$STAGING/systemd/" - mkdir -p "$STAGING/scripts" - cp "{{ spinifex_root }}/build/scripts/"* "$STAGING/scripts/" - cp "{{ spinifex_root }}/build/logrotate/spinifex" "$STAGING/logrotate-spinifex" - # microVM artifacts ship only when the branch built them. - if [ -f "{{ spinifex_root }}/build/microvm/vmlinuz" ] && [ -f "{{ spinifex_root }}/build/microvm/initramfs.cpio.gz" ]; then - mkdir -p "$STAGING/microvm" - cp "{{ spinifex_root }}/build/microvm/vmlinuz" "$STAGING/microvm/" - cp "{{ spinifex_root }}/build/microvm/initramfs.cpio.gz" "$STAGING/microvm/" - fi - tar czf "{{ build_tarball_path }}" -C "$STAGING" . - changed_when: true - -- name: build — summary - ansible.builtin.debug: - msg: "Built spx + nbdkit plugin{{ ' + microvm artifacts' if build_microvm_script.stat.exists else '' }}, tarball at {{ build_tarball_path }}" diff --git a/scripts/ansible/roles/cluster-init/meta/main.yml b/scripts/ansible/roles/cluster-init/meta/main.yml deleted file mode 100644 index b43eada69..000000000 --- a/scripts/ansible/roles/cluster-init/meta/main.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -galaxy_info: - role_name: cluster-init - description: | - Run `spx admin init` on the cluster's init host, backgrounded so the - formation server accepts joins from the cluster-join role. Installs - cluster CA into the system trust store BEFORE starting spinifex.target - so predastore's strict TLS verify is satisfied at first start. -dependencies: [] diff --git a/scripts/ansible/roles/cluster-init/tasks/main.yml b/scripts/ansible/roles/cluster-init/tasks/main.yml deleted file mode 100644 index 8f0725e35..000000000 --- a/scripts/ansible/roles/cluster-init/tasks/main.yml +++ /dev/null @@ -1,77 +0,0 @@ ---- -- name: cluster-init — assert this is the init host - ansible.builtin.assert: - that: spinifex_node_role == "init" - fail_msg: "cluster-init role must only run against hosts in the [init] group" - -# vars/defaults.yml sets spinifex_node_{name,count} for single-node dev use -# (precedence 11). Inventory hostvars (precedence 4) lose that fight, so -# we promote the inventory values via set_fact (precedence 15) before any -# task templates `{{ spinifex_node_count }}`. -- name: cluster-init — promote inventory node identity over defaults.yml - ansible.builtin.set_fact: - spinifex_node_name: "{{ hostvars[inventory_hostname]['spinifex_node_name'] }}" - spinifex_node_count: "{{ groups[cluster_env] | length }}" - -- name: cluster-init — assemble external network flags - ansible.builtin.set_fact: - cluster_external_flags: >- - {% if cluster_external_pool | length > 0 %}--external-mode=pool --external-pool={{ cluster_external_pool }}{% endif %} - -- name: cluster-init — run spx admin init (backgrounded, formation server waits for joins) - become: true - ansible.builtin.shell: | - set -o pipefail - spx admin init --force \ - --node {{ spinifex_node_name }} \ - --nodes {{ spinifex_node_count }} \ - --bind {{ spinifex_wan_ip }} \ - --cluster-bind {{ spinifex_wan_ip }} \ - --port {{ cluster_formation_port }} \ - --region {{ spinifex_region }} \ - --az {{ spinifex_az }} \ - {{ cluster_external_flags }} \ - > /tmp/spx-admin-init.log 2>&1 - async: 600 - poll: 0 - register: cluster_init_async - -- name: cluster-init — brief pause so init can fail fast if misconfigured - ansible.builtin.pause: - seconds: 5 - -- name: cluster-init — check if init exited prematurely (sanity) - ansible.builtin.shell: | - if pgrep -f 'spx admin init' >/dev/null; then - echo "running" - else - tail -50 /tmp/spx-admin-init.log 2>/dev/null - exit 1 - fi - register: cluster_init_alive - changed_when: false - failed_when: cluster_init_alive.rc != 0 - -- name: cluster-init — wait for formation server health - ansible.builtin.uri: - url: "https://{{ spinifex_wan_ip }}:{{ cluster_formation_port }}/formation/health" - validate_certs: false - status_code: 200 - register: cluster_init_health - until: cluster_init_health.status == 200 - retries: "{{ cluster_formation_timeout // 2 }}" - delay: 2 - -- name: cluster-init — fetch join token (delegated read for joiners) - become: true - ansible.builtin.slurp: - src: "{{ cluster_join_token_path }}" - register: cluster_join_token_raw - -- name: cluster-init — register join token as host fact - ansible.builtin.set_fact: - cluster_join_token: "{{ cluster_join_token_raw.content | b64decode | trim }}" - -- name: cluster-init — join token captured; waiting for joins handled by later play - ansible.builtin.debug: - msg: "Formation server up on {{ spinifex_wan_ip }}:{{ cluster_formation_port }}, {{ spinifex_node_count }} nodes expected" diff --git a/scripts/ansible/roles/cluster-join/meta/main.yml b/scripts/ansible/roles/cluster-join/meta/main.yml deleted file mode 100644 index bf45870de..000000000 --- a/scripts/ansible/roles/cluster-join/meta/main.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -galaxy_info: - role_name: cluster-join - description: | - Run `spx admin join` against the cluster init host's formation server. - Installs cluster CA + starts spinifex.target after join completes - (CA-before-services ordering avoids predastore TLS-verify crashes). -dependencies: [] diff --git a/scripts/ansible/roles/cluster-join/tasks/main.yml b/scripts/ansible/roles/cluster-join/tasks/main.yml deleted file mode 100644 index 2a3c77592..000000000 --- a/scripts/ansible/roles/cluster-join/tasks/main.yml +++ /dev/null @@ -1,39 +0,0 @@ ---- -- name: cluster-join — assert this is a join host - ansible.builtin.assert: - that: spinifex_node_role == "join" - fail_msg: "cluster-join role must only run against hosts in the [join] group" - -# Promote inventory hostvars over vars/defaults.yml (see cluster-init). -- name: cluster-join — promote inventory node identity over defaults.yml - ansible.builtin.set_fact: - spinifex_node_name: "{{ hostvars[inventory_hostname]['spinifex_node_name'] }}" - -- name: cluster-join — pull join token from init host - ansible.builtin.set_fact: - cluster_join_token: "{{ hostvars[cluster_init_host]['cluster_join_token'] }}" - -- name: cluster-join — assert token present - ansible.builtin.assert: - that: cluster_join_token | length > 0 - fail_msg: "join token missing — init host did not export cluster_join_token" - -- name: cluster-join — run spx admin join (retry up to 5 times) - become: true - ansible.builtin.command: - cmd: >- - spx admin join - --node {{ spinifex_node_name }} - --bind {{ spinifex_wan_ip }} - --cluster-bind {{ spinifex_wan_ip }} - --host {{ cluster_init_host }}:{{ cluster_formation_port }} - --token {{ cluster_join_token }} - --region {{ spinifex_region }} - --az {{ spinifex_az }} - register: cluster_join_result - retries: 5 - delay: 3 - until: cluster_join_result.rc == 0 - -# CA install + service start handled by cluster-bootstrap.yml plays that -# run after all joins complete and init has written multi-node configs. diff --git a/scripts/ansible/roles/cluster-post/meta/main.yml b/scripts/ansible/roles/cluster-post/meta/main.yml deleted file mode 100644 index bcc7079f0..000000000 --- a/scripts/ansible/roles/cluster-post/meta/main.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -galaxy_info: - role_name: cluster-post - description: | - Post-bootstrap idempotent fixtures on the init host: import SSH key, - import Ubuntu AMI (dual-version detect 24.04/26.04). Skip when - artifacts already exist. -dependencies: [] diff --git a/scripts/ansible/roles/cluster-post/tasks/main.yml b/scripts/ansible/roles/cluster-post/tasks/main.yml deleted file mode 100644 index 973f25d9e..000000000 --- a/scripts/ansible/roles/cluster-post/tasks/main.yml +++ /dev/null @@ -1,205 +0,0 @@ ---- -- name: cluster-post — locate ssh public key for import - ansible.builtin.find: - paths: "{{ ansible_env.HOME }}/.ssh" - patterns: - - spinifex-key.pub - - tf-user-*.pub - file_type: file - register: cluster_post_ssh_pubkey - -- name: cluster-post — fail when no public key found - ansible.builtin.assert: - that: cluster_post_ssh_pubkey.files | length > 0 - fail_msg: "no public key in ~/.ssh — needed for spinifex-key import" - -- name: cluster-post — set pubkey path fact - ansible.builtin.set_fact: - cluster_post_pubkey_path: "{{ cluster_post_ssh_pubkey.files[0].path }}" - -- name: cluster-post — check whether spinifex-key already imported - ansible.builtin.command: - cmd: "{{ spinifex_aws_cli }} ec2 describe-key-pairs --key-names spinifex-key" - register: cluster_post_key_check - changed_when: false - failed_when: false - -- name: cluster-post — import spinifex-key (if absent) - ansible.builtin.command: - cmd: >- - {{ spinifex_aws_cli }} ec2 import-key-pair - --key-name spinifex-key - --public-key-material fileb://{{ cluster_post_pubkey_path }} - register: cluster_post_key_import - retries: 10 - delay: 6 - until: cluster_post_key_import.rc == 0 - when: cluster_post_key_check.rc != 0 - -- name: cluster-post — locate ubuntu cloud image (26.04 preferred, 24.04 fallback) - ansible.builtin.stat: - path: "{{ item }}" - register: cluster_post_ubuntu_stat - loop: - - "{{ ansible_env.HOME }}/images/ubuntu-26.04.img" - - "{{ ansible_env.HOME }}/images/ubuntu-24.04.img" - -- name: cluster-post — pick first available image - ansible.builtin.set_fact: - cluster_post_ubuntu_image: "{{ (cluster_post_ubuntu_stat.results | selectattr('stat.exists') | map(attribute='item') | list | first) | default('') }}" - -- name: cluster-post — fail when no ubuntu image present - ansible.builtin.assert: - that: cluster_post_ubuntu_image | length > 0 - fail_msg: "no ubuntu-{24,26}.04.img in ~/images/ — gold image must stage it" - -- name: cluster-post — derive ubuntu version from image filename - ansible.builtin.set_fact: - cluster_post_ubuntu_version: "{{ cluster_post_ubuntu_image | regex_search('ubuntu-([0-9]+\\.[0-9]+)\\.img', '\\1') | first }}" - -- name: cluster-post — check whether ubuntu AMI already imported - ansible.builtin.command: - cmd: >- - {{ spinifex_aws_cli }} ec2 describe-images - --owners self - --filters Name=name,Values=ubuntu-{{ cluster_post_ubuntu_version }} - register: cluster_post_ami_check - changed_when: false - failed_when: false - -- name: cluster-post — import ubuntu AMI (if absent) - ansible.builtin.command: - cmd: >- - {{ spinifex_spx_cli }} admin images import - --file {{ cluster_post_ubuntu_image }} - --arch x86_64 - --distro ubuntu - --version {{ cluster_post_ubuntu_version }} - --boot-mode uefi - when: - - cluster_post_ami_check.rc != 0 - or "ubuntu-" + cluster_post_ubuntu_version not in cluster_post_ami_check.stdout - -- name: cluster-post — slurp final admin creds from ~/.aws/credentials - # Source of truth: SetupAWSCredentials writes the FINAL admin keys here. - # Init log shows obsolete keys (multi-node path silently regenerates them - # after the initial print — see cmd/spinifex/cmd/admin.go writeBootstrapFiles - # called twice in the multi-node flow). - ansible.builtin.slurp: - src: "{{ ansible_env.HOME }}/.aws/credentials" - register: cluster_post_aws_creds_raw - -- name: cluster-post — extract admin access/secret keys from spinifex profile - ansible.builtin.set_fact: - cluster_post_admin_access_key: >- - {{ (cluster_post_aws_creds_raw.content | b64decode - | regex_search('\[spinifex\][^\[]*aws_access_key_id\s*=\s*(\S+)', '\1') - | first) | default('') }} - cluster_post_admin_secret_key: >- - {{ (cluster_post_aws_creds_raw.content | b64decode - | regex_search('\[spinifex\][^\[]*aws_secret_access_key\s*=\s*(\S+)', '\1') - | first) | default('') }} - -- name: cluster-post — assert creds parsed - ansible.builtin.assert: - that: - - cluster_post_admin_access_key | length > 0 - - cluster_post_admin_secret_key | length > 0 - fail_msg: "could not parse admin keys from {{ ansible_env.HOME }}/.aws/credentials [spinifex] profile" - -- name: cluster-post — ensure local .creds dir exists - delegate_to: localhost - become: false - ansible.builtin.file: - path: "{{ playbook_dir }}/../.creds" - state: directory - mode: "0700" - -- name: cluster-post — write creds to operator workstation - delegate_to: localhost - become: false - ansible.builtin.copy: - dest: "{{ playbook_dir }}/../.creds/{{ cluster_env }}.txt" - mode: "0600" - content: | - # Spinifex cluster admin credentials — {{ cluster_env }} - # Generated: {{ ansible_facts['date_time']['iso8601'] }} - # Init host: {{ cluster_init_host }} - # - # UI: https://{{ cluster_init_host }}:3000 - # AWS API: https://{{ cluster_init_host }}:4432 - # Region: {{ spinifex_region }} - # - # Login (admin user / AWS profile spinifex): - AWS_ACCESS_KEY_ID={{ cluster_post_admin_access_key }} - AWS_SECRET_ACCESS_KEY={{ cluster_post_admin_secret_key }} - -# Per-env AWS profile in operator's ~/.aws/credentials so tofu / aws CLI can -# target this cluster via AWS_PROFILE=spinifex-{{ cluster_env }}. blockinfile -# marker keeps re-runs idempotent — replaces the block in place, never -# duplicates. Does not touch the user's existing [spinifex] profile (single- -# node dev). Tofu side: provider "aws" { profile = "spinifex-env1" ... }. -- name: cluster-post — ensure local ~/.aws dir exists - delegate_to: localhost - become: false - ansible.builtin.file: - path: "{{ lookup('env', 'HOME') }}/.aws" - state: directory - mode: "0700" - -- name: cluster-post — ensure local ~/.aws/credentials exists - delegate_to: localhost - become: false - ansible.builtin.copy: - dest: "{{ lookup('env', 'HOME') }}/.aws/credentials" - content: "" - force: false - mode: "0600" - -- name: cluster-post — upsert spinifex-{{ cluster_env }} profile in local ~/.aws/credentials - delegate_to: localhost - become: false - ansible.builtin.blockinfile: - path: "{{ lookup('env', 'HOME') }}/.aws/credentials" - marker: "# {mark} SPINIFEX-{{ cluster_env | upper }} MANAGED BLOCK" - block: | - [spinifex-{{ cluster_env }}] - aws_access_key_id = {{ cluster_post_admin_access_key }} - aws_secret_access_key = {{ cluster_post_admin_secret_key }} - region = {{ spinifex_region }} - ca_bundle = {{ playbook_dir }}/../.creds/{{ cluster_env }}-ca.pem - endpoint_url = https://{{ cluster_init_host }}:4432 - -- name: cluster-post — slurp cluster CA from init host - ansible.builtin.slurp: - src: "{{ spinifex_ca_src }}" - register: cluster_post_ca_raw - become: true - -- name: cluster-post — write CA pem to operator workstation - delegate_to: localhost - become: false - ansible.builtin.copy: - dest: "{{ playbook_dir }}/../.creds/{{ cluster_env }}-ca.pem" - mode: "0644" - content: "{{ cluster_post_ca_raw.content | b64decode }}" - -- name: cluster-post — resolve absolute paths for summary - delegate_to: localhost - become: false - ansible.builtin.command: "readlink -f {{ playbook_dir }}/../.creds" - register: cluster_post_creds_abs - changed_when: false - -- name: cluster-post — summary - ansible.builtin.debug: - msg: | - Post-bootstrap done: - spinifex-key: {{ 'imported now' if (cluster_post_key_import.changed | default(false)) else 'already present' }} - ubuntu AMI: ubuntu-{{ cluster_post_ubuntu_version }} - admin creds: {{ cluster_post_creds_abs.stdout }}/{{ cluster_env }}.txt - CA cert: {{ cluster_post_creds_abs.stdout }}/{{ cluster_env }}-ca.pem - AWS profile: spinifex-{{ cluster_env }} (in ~/.aws/credentials) - UI URL: https://{{ cluster_init_host }}:3000 - Access Key: {{ cluster_post_admin_access_key }} - Tofu usage: AWS_PROFILE=spinifex-{{ cluster_env }} tofu plan diff --git a/scripts/ansible/roles/deploy/meta/main.yml b/scripts/ansible/roles/deploy/meta/main.yml deleted file mode 100644 index 8e4aa0695..000000000 --- a/scripts/ansible/roles/deploy/meta/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -galaxy_info: - role_name: deploy - description: In-place binary + microvm artifact swap for a running Spinifex node (parity with `make deploy`). - license: BSD-3-Clause - min_ansible_version: "2.14" -dependencies: [] diff --git a/scripts/ansible/roles/deploy/tasks/main.yml b/scripts/ansible/roles/deploy/tasks/main.yml deleted file mode 100644 index 1153b7faf..000000000 --- a/scripts/ansible/roles/deploy/tasks/main.yml +++ /dev/null @@ -1,144 +0,0 @@ ---- -# In-place artifact swap for an already-installed spinifex node. Mirrors -# `make deploy`: replace binaries + microvm artifacts, restart services. -# Does NOT run setup.sh (no user/dir/systemd-unit changes) or smoketest. - -- name: deploy — fail fast if spinifex isn't already installed - ansible.builtin.stat: - path: "{{ spinifex_config_file }}" - register: deploy_installed_stat - failed_when: not deploy_installed_stat.stat.exists - -- name: deploy — assert config present - ansible.builtin.assert: - that: deploy_installed_stat.stat.exists - fail_msg: | - {{ spinifex_config_file }} missing — this playbook only updates an - existing install. Run ansible-dev-install or ansible-dev-reset first. - -- name: deploy — verify build artifacts present - ansible.builtin.stat: - path: "{{ item }}" - register: deploy_artifacts - loop: - - "{{ spinifex_root }}/bin/spx" - - "{{ mulga_root }}/viperblock/lib/nbdkit-viperblock-plugin.so" - -- name: deploy — assert artifacts exist after build role - ansible.builtin.assert: - that: item.stat.exists - fail_msg: "Build artifact missing: {{ item.item }} — build role should have produced it" - loop: "{{ deploy_artifacts.results }}" - loop_control: - label: "{{ item.item }}" - -- name: deploy — detect microvm artifacts (direct-boot branches only) - ansible.builtin.stat: - path: "{{ spinifex_root }}/build/microvm/{{ item }}" - register: deploy_microvm_stat - loop: - - vmlinuz - - initramfs.cpio.gz - -- name: deploy — set microvm presence fact - ansible.builtin.set_fact: - deploy_microvm_present: "{{ deploy_microvm_stat.results | map(attribute='stat.exists') | min }}" - -- name: deploy — detect nbdkit plugin directory - ansible.builtin.shell: | - set -e - nbdkit --dump-config | awk -F= '/^plugindir=/{print $2; exit}' - register: deploy_plugindir_cmd - changed_when: false - -- name: deploy — set plugin path fact - ansible.builtin.set_fact: - deploy_plugindir: "{{ deploy_plugindir_cmd.stdout | trim }}" - -- name: deploy — assert plugindir resolved - ansible.builtin.assert: - that: deploy_plugindir | length > 0 - fail_msg: "Could not detect nbdkit plugin directory via `nbdkit --dump-config`" - -- name: deploy — stop spinifex.target before binary swap - become: true - ansible.builtin.systemd: - name: spinifex.target - state: stopped - failed_when: false - -- name: deploy — install spx binary - become: true - ansible.builtin.copy: - src: "{{ spinifex_root }}/bin/spx" - dest: /usr/local/bin/spx - mode: "0755" - owner: root - group: root - -- name: deploy — install viperblock nbdkit plugin - become: true - ansible.builtin.copy: - src: "{{ mulga_root }}/viperblock/lib/nbdkit-viperblock-plugin.so" - dest: "{{ deploy_plugindir }}/nbdkit-viperblock-plugin.so" - mode: "0755" - owner: root - group: root - -- name: deploy — ensure microvm dir - become: true - ansible.builtin.file: - path: /usr/share/spinifex/microvm - state: directory - mode: "0755" - owner: root - group: root - when: deploy_microvm_present - -- name: deploy — install microvm kernel - become: true - ansible.builtin.copy: - src: "{{ spinifex_root }}/build/microvm/vmlinuz" - dest: /usr/share/spinifex/microvm/vmlinuz - mode: "0644" - owner: root - group: root - when: deploy_microvm_present - -- name: deploy — install microvm initramfs - become: true - ansible.builtin.copy: - src: "{{ spinifex_root }}/build/microvm/initramfs.cpio.gz" - dest: /usr/share/spinifex/microvm/initramfs.cpio.gz - mode: "0644" - owner: root - group: root - when: deploy_microvm_present - -- name: deploy — daemon-reload (covers any unit changes shipped via setup.sh later) - become: true - ansible.builtin.systemd: - daemon_reload: true - -- name: deploy — start spinifex.target - become: true - ansible.builtin.systemd: - name: spinifex.target - state: started - -- name: deploy — wait for awsgw to respond - ansible.builtin.command: "{{ spinifex_aws_cli }} ec2 describe-regions" - register: deploy_awsgw - retries: 15 - delay: 2 - until: deploy_awsgw.rc == 0 - changed_when: false - -- name: deploy — summary - ansible.builtin.debug: - msg: | - Deployed: - spx → /usr/local/bin/spx - nbdkit plugin → {{ deploy_plugindir }}/nbdkit-viperblock-plugin.so - microvm → {{ '/usr/share/spinifex/microvm/{vmlinuz,initramfs.cpio.gz}' if deploy_microvm_present else 'skipped (not built on this branch)' }} - spinifex.target restarted; awsgw responding. diff --git a/scripts/ansible/roles/init/meta/main.yml b/scripts/ansible/roles/init/meta/main.yml deleted file mode 100644 index ab1f3ffd0..000000000 --- a/scripts/ansible/roles/init/meta/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -galaxy_info: - role_name: init - description: Run spx admin init, install CA trust, start services, import LB image. - license: BSD-3-Clause - min_ansible_version: "2.14" -dependencies: [] diff --git a/scripts/ansible/roles/init/tasks/main.yml b/scripts/ansible/roles/init/tasks/main.yml deleted file mode 100644 index 62f49e5fb..000000000 --- a/scripts/ansible/roles/init/tasks/main.yml +++ /dev/null @@ -1,90 +0,0 @@ ---- -- name: init — base admin-init flags - ansible.builtin.set_fact: - init_base_flags: >- - --force - --region {{ spinifex_region }} - --az {{ spinifex_az }} - --node {{ spinifex_node_name }} - --nodes {{ spinifex_node_count }} - -- name: init — no-external opt-out - ansible.builtin.set_fact: - init_external_flags: "--no-external" - when: spinifex_external_no_external | bool - -- name: init — assert pool range supplied when mode=pool - ansible.builtin.assert: - that: - - spinifex_external_pool_start | length > 0 - - spinifex_external_pool_end | length > 0 - fail_msg: | - spx admin init requires --external-pool when --external-mode=pool. - Set spinifex_external_pool_start / spinifex_external_pool_end in - scripts/ansible/vars/defaults.yml, or pass: - -e spinifex_external_pool_start=192.168.1.150 - -e spinifex_external_pool_end=192.168.1.250 - Pass -e spinifex_external_no_external=true to skip external networking. - when: - - not (spinifex_external_no_external | bool) - - spinifex_external_mode == 'pool' - -- name: init — pool-mode external flags - ansible.builtin.set_fact: - init_external_flags: >- - --external-mode=pool - --external-pool={{ spinifex_external_pool_start }}-{{ spinifex_external_pool_end }} - {% if spinifex_external_gateway | length > 0 %}--external-gateway={{ spinifex_external_gateway }}{% endif %} - {% if spinifex_external_prefix_len | string | length > 0 %}--external-prefix-len={{ spinifex_external_prefix_len }}{% endif %} - {% if spinifex_external_gateway_ip | length > 0 %}--gateway-ip={{ spinifex_external_gateway_ip }}{% endif %} - when: - - not (spinifex_external_no_external | bool) - - spinifex_external_mode == 'pool' - -- name: init — assemble full flag string - ansible.builtin.set_fact: - init_all_flags: "{{ init_base_flags }} {{ init_external_flags | default('') }}" - -- name: init — run spx admin init - become: true - ansible.builtin.command: "spx admin init {{ init_all_flags }}" - changed_when: true - -- name: init — copy CA to system trust - become: true - ansible.builtin.copy: - src: "{{ spinifex_ca_src }}" - dest: "{{ spinifex_ca_trust_path }}" - mode: "0644" - remote_src: true - -- name: init — rebuild CA bundle (not --fresh — preserve other CAs) - become: true - ansible.builtin.command: update-ca-certificates - changed_when: true - -- name: init — start spinifex.target - become: true - ansible.builtin.systemd: - name: spinifex.target - state: started - -# systemctl start returns as soon as units activate; awsgw still wires up -# to NATS + daemons after that. Bash start-dev.sh has internal wait loops; -# systemd path does not. Poll a benign call until gateway is fully ready. -- name: init — wait for AWS gateway readiness - ansible.builtin.command: "{{ spinifex_aws_cli }} ec2 describe-regions" - register: init_gw_ready - until: init_gw_ready.rc == 0 - retries: 30 - delay: 2 - changed_when: false - -- name: init — summary - ansible.builtin.debug: - msg: | - Init complete: - region={{ spinifex_region }}, az={{ spinifex_az }}, node={{ spinifex_node_name }} - external_mode={{ 'disabled' if (spinifex_external_no_external | bool) else spinifex_external_mode }} - spinifex.target: started - CA: {{ spinifex_ca_trust_path }} diff --git a/scripts/ansible/roles/install/meta/main.yml b/scripts/ansible/roles/install/meta/main.yml deleted file mode 100644 index 958623e0d..000000000 --- a/scripts/ansible/roles/install/meta/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -galaxy_info: - role_name: install - description: Invoke setup.sh and setup-ovn.sh to install Spinifex into production paths. - license: BSD-3-Clause - min_ansible_version: "2.14" -dependencies: [] diff --git a/scripts/ansible/roles/install/tasks/main.yml b/scripts/ansible/roles/install/tasks/main.yml deleted file mode 100644 index aba7e19e0..000000000 --- a/scripts/ansible/roles/install/tasks/main.yml +++ /dev/null @@ -1,79 +0,0 @@ ---- -- name: install — assert tarball exists - ansible.builtin.stat: - path: "{{ build_tarball_path }}" - register: install_tarball - -- name: install — fail if tarball missing - ansible.builtin.assert: - that: install_tarball.stat.exists - fail_msg: "Tarball {{ build_tarball_path }} missing. Run the build role first." - -- name: install — stop spinifex.target before reinstall - become: true - ansible.builtin.systemd: - name: spinifex.target - state: stopped - failed_when: false - -- name: install — reset failed state (spinifex-* scope) - become: true - ansible.builtin.command: systemctl reset-failed 'spinifex-*' - changed_when: false - failed_when: false - -- name: install — scrub stale pid/log files from prior dev-mode installs - become: true - ansible.builtin.shell: | - for dir in {{ spinifex_data_dir }} {{ spinifex_log_dir }} {{ spinifex_etc_dir }}; do - if [ -d "$dir" ]; then - find "$dir" -name '*.pid' -delete 2>/dev/null || true - find "$dir" -name '*.log' -delete 2>/dev/null || true - find "$dir" -name '*.log.*' -delete 2>/dev/null || true - fi - done - changed_when: false - -- name: install — remove legacy /var/lib/spinifex/config - become: true - ansible.builtin.file: - path: "{{ spinifex_data_dir }}/config" - state: absent - -- name: install — purge stale cluster state (configs + raft + NATS KV) on bootstrap - become: true - ansible.builtin.file: - path: "{{ item }}" - state: absent - loop: - - "{{ spinifex_etc_dir }}/predastore/predastore.toml" - - "{{ spinifex_etc_dir }}/spinifex.toml" - - "{{ spinifex_data_dir }}/predastore" - - "{{ spinifex_data_dir }}/nats" - - "{{ spinifex_data_dir }}/awsgw" - when: cluster_bootstrap_purge | default(false) | bool - -- name: install — run setup.sh (creates users, dirs, systemd units) - become: true - ansible.builtin.command: - cmd: "bash {{ spinifex_root }}/scripts/setup.sh" - environment: - INSTALL_SPINIFEX_TARBALL: "{{ build_tarball_path }}" - INSTALL_SPINIFEX_SKIP_NEWGRP: "1" - changed_when: true - -- name: install — cleanup tarball - ansible.builtin.file: - path: "{{ build_tarball_path }}" - state: absent - -- name: install — run setup-ovn.sh --management - become: true - ansible.builtin.command: - cmd: "/usr/local/share/spinifex/setup-ovn.sh --management --node-name={{ spinifex_node_name }}" - changed_when: true - when: install_run_ovn | default(true) | bool - -- name: install — summary - ansible.builtin.debug: - msg: "Install complete — setup.sh + setup-ovn.sh ran. Services NOT yet started (init role handles that)." diff --git a/scripts/ansible/roles/logs/meta/main.yml b/scripts/ansible/roles/logs/meta/main.yml deleted file mode 100644 index 72b3aaa47..000000000 --- a/scripts/ansible/roles/logs/meta/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -galaxy_info: - role_name: logs - description: Dump spinifex + ovn + system logs into a tarball for bug reports. - license: BSD-3-Clause - min_ansible_version: "2.14" -dependencies: [] diff --git a/scripts/ansible/roles/logs/tasks/main.yml b/scripts/ansible/roles/logs/tasks/main.yml deleted file mode 100644 index 38cea5572..000000000 --- a/scripts/ansible/roles/logs/tasks/main.yml +++ /dev/null @@ -1,153 +0,0 @@ ---- -# Collect a self-contained log bundle for bug reports. NEVER mutates running -# state — only reads journalctl + /var/log/spinifex/* + status output, then -# tars into logs_output_dir. Errors on missing inputs are non-fatal so a -# half-broken node still produces a bundle. - -- name: logs — resolve staging directory - ansible.builtin.set_fact: - logs_stage_dir: "/tmp/spinifex-logs-{{ ansible_facts['hostname'] }}-{{ ansible_facts['date_time']['iso8601_basic_short'] }}" - logs_bundle_path: "{{ logs_output_dir }}/spinifex-logs-{{ ansible_facts['hostname'] }}-{{ ansible_facts['date_time']['iso8601_basic_short'] }}.tar.gz" - -- name: logs — create staging tree - ansible.builtin.file: - path: "{{ logs_stage_dir }}/{{ item }}" - state: directory - mode: "0755" - loop: - - journal - - varlog - - status - - kernel - -- name: logs — capture journalctl for spinifex-* units - become: true - ansible.builtin.shell: | - journalctl --no-pager --output=short-iso \ - -u 'spinifex-*' --since {{ logs_since | quote }} \ - > {{ logs_stage_dir }}/journal/spinifex.log 2>&1 || true - changed_when: true - -- name: logs — capture journalctl for ovn-* + openvswitch-switch - become: true - ansible.builtin.shell: | - journalctl --no-pager --output=short-iso \ - -u 'ovn-*' -u openvswitch-switch \ - --since {{ logs_since | quote }} \ - > {{ logs_stage_dir }}/journal/ovn-ovs.log 2>&1 || true - changed_when: true - -- name: logs — capture journalctl for nbdkit + qemu (best-effort match) - become: true - ansible.builtin.shell: | - journalctl --no-pager --output=short-iso \ - --since {{ logs_since | quote }} \ - _COMM=qemu-system-x86_64 + _COMM=qemu-system-aarch64 + _COMM=nbdkit \ - > {{ logs_stage_dir }}/journal/qemu-nbdkit.log 2>&1 || true - changed_when: true - -- name: logs — copy /var/log/spinifex/* - become: true - ansible.builtin.shell: | - if [ -d {{ spinifex_log_dir | quote }} ]; then - cp -a {{ spinifex_log_dir | quote }}/. {{ logs_stage_dir | quote }}/varlog/ 2>/dev/null || true - fi - changed_when: true - -- name: logs — systemctl status snapshot (spinifex-*) - become: true - ansible.builtin.shell: | - systemctl status 'spinifex-*' --no-pager --all \ - > {{ logs_stage_dir }}/status/spinifex-units.txt 2>&1 || true - systemctl status ovn-controller ovn-central openvswitch-switch \ - --no-pager > {{ logs_stage_dir }}/status/ovn-ovs-units.txt 2>&1 || true - systemctl list-units 'spinifex-*' --all --no-legend --plain \ - > {{ logs_stage_dir }}/status/spinifex-list.txt 2>&1 || true - changed_when: true - -- name: logs — networking snapshot (ip, ss, ovs) - become: true - ansible.builtin.shell: | - ip -d -s link show > {{ logs_stage_dir }}/status/ip-link.txt 2>&1 || true - ip addr show > {{ logs_stage_dir }}/status/ip-addr.txt 2>&1 || true - ip route show table all > {{ logs_stage_dir }}/status/ip-route.txt 2>&1 || true - ss -tlnp > {{ logs_stage_dir }}/status/ss-tlnp.txt 2>&1 || true - if command -v ovs-vsctl >/dev/null 2>&1; then - ovs-vsctl show > {{ logs_stage_dir }}/status/ovs-show.txt 2>&1 || true - ovs-vsctl list-br > {{ logs_stage_dir }}/status/ovs-br.txt 2>&1 || true - fi - if command -v ovn-nbctl >/dev/null 2>&1; then - ovn-nbctl show > {{ logs_stage_dir }}/status/ovn-nb.txt 2>&1 || true - ovn-sbctl show > {{ logs_stage_dir }}/status/ovn-sb.txt 2>&1 || true - fi - changed_when: true - -- name: logs — kernel ring buffer - become: true - ansible.builtin.shell: | - dmesg --time-format=iso > {{ logs_stage_dir }}/kernel/dmesg.txt 2>&1 || true - changed_when: true - when: logs_include_dmesg | bool - -- name: logs — capture spx + plugin versions - become: true - ansible.builtin.shell: | - { - echo '## spx version' - /usr/local/bin/spx version 2>&1 | grep -vE '^[0-9]{4}/' || true - echo - echo '## nbdkit plugin sha256' - pdir=$(nbdkit --dump-config 2>/dev/null | awk -F= '/^plugindir=/{print $2; exit}') - [ -n "$pdir" ] && sha256sum "$pdir/nbdkit-viperblock-plugin.so" 2>/dev/null || true - echo - echo '## microvm artifacts' - sha256sum /usr/share/spinifex/microvm/* 2>/dev/null || true - echo - echo '## kernel + os' - uname -a - cat /etc/os-release 2>/dev/null || true - } > {{ logs_stage_dir }}/status/versions.txt 2>&1 || true - changed_when: true - -- name: logs — create bundle tarball - become: true - ansible.builtin.shell: | - tar -C {{ logs_stage_dir | dirname | quote }} \ - -czf {{ logs_bundle_path | quote }} \ - {{ logs_stage_dir | basename | quote }} - changed_when: true - -- name: logs — make bundle owned by invoking user - become: true - ansible.builtin.file: - path: "{{ logs_bundle_path }}" - owner: "{{ spinifex_invoking_user }}" - group: "{{ spinifex_invoking_user }}" - mode: "0640" - -- name: logs — remove staging tree - become: true - ansible.builtin.file: - path: "{{ logs_stage_dir }}" - state: absent - -- name: logs — bundle size - ansible.builtin.stat: - path: "{{ logs_bundle_path }}" - register: logs_bundle_stat - -- name: logs — summary - ansible.builtin.debug: - msg: | - Log bundle written: - path : {{ logs_bundle_path }} - size : {{ (logs_bundle_stat.stat.size | int / 1024) | round(1) }} KiB - since : {{ logs_since }} - Contents: - journal/ spinifex-*, ovn-*+openvswitch-switch, qemu/nbdkit - varlog/ copy of {{ spinifex_log_dir }} - status/ systemctl status, ip/ss/ovs/ovn show, versions - kernel/ dmesg{{ '' if logs_include_dmesg else ' (skipped via -e logs_include_dmesg=false)' }} - - Attach to bug report. For live tail use: - journalctl -u 'spinifex-*' -f diff --git a/scripts/ansible/roles/preflight/meta/main.yml b/scripts/ansible/roles/preflight/meta/main.yml deleted file mode 100644 index 192dbf8c5..000000000 --- a/scripts/ansible/roles/preflight/meta/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -galaxy_info: - role_name: preflight - description: Validate dev-host dependencies for Spinifex (parity with dev-setup.sh). - license: BSD-3-Clause - min_ansible_version: "2.14" -dependencies: [] diff --git a/scripts/ansible/roles/preflight/tasks/main.yml b/scripts/ansible/roles/preflight/tasks/main.yml deleted file mode 100644 index a73d705ca..000000000 --- a/scripts/ansible/roles/preflight/tasks/main.yml +++ /dev/null @@ -1,98 +0,0 @@ ---- -- name: Check required commands - ansible.builtin.command: "which {{ item }}" - register: preflight_required - loop: "{{ spinifex_required_commands }}" - changed_when: false - failed_when: preflight_required.rc != 0 - loop_control: - label: "{{ item }}" - -- name: Check optional commands - ansible.builtin.command: "which {{ item }}" - register: preflight_optional - loop: "{{ spinifex_optional_commands }}" - changed_when: false - failed_when: false - loop_control: - label: "{{ item }}" - -- name: Warn on missing optional commands - ansible.builtin.debug: - msg: "WARN: optional command '{{ item.item }}' not found" - loop: "{{ preflight_optional.results }}" - when: item.rc != 0 - loop_control: - label: "{{ item.item }}" - -- name: Check OVN/OVS commands - ansible.builtin.command: "which {{ item }}" - register: preflight_ovn - loop: "{{ spinifex_ovn_commands }}" - changed_when: false - failed_when: false - loop_control: - label: "{{ item }}" - -- name: Warn on missing OVN/OVS tools - ansible.builtin.debug: - msg: "WARN: OVN/OVS tool '{{ item.item }}' not found (required for VPC networking). Install: sudo apt-get install ovn-central ovn-host openvswitch-switch" - loop: "{{ preflight_ovn.results }}" - when: item.rc != 0 - loop_control: - label: "{{ item.item }}" - -- name: Record OVN tool availability - ansible.builtin.set_fact: - preflight_ovs_present: "{{ (preflight_ovn.results | selectattr('item','eq','ovs-vsctl') | selectattr('rc','eq',0) | list | length) > 0 }}" - -- name: Check br-int bridge - ansible.builtin.command: ovs-vsctl br-exists br-int - register: preflight_brint - changed_when: false - failed_when: false - when: preflight_ovs_present - -- name: Warn if br-int missing - ansible.builtin.debug: - msg: "WARN: br-int missing. Run scripts/setup-ovn.sh --management to initialise OVN networking." - when: - - preflight_ovs_present - - preflight_brint.rc | default(0) != 0 - -- name: Check sibling component directories - ansible.builtin.stat: - path: "{{ playbook_dir }}/../../../../{{ item }}/go.mod" - register: preflight_components - loop: "{{ spinifex_components }}" - loop_control: - label: "{{ item }}" - -- name: Warn on missing component checkouts - ansible.builtin.debug: - msg: "WARN: component '{{ item.item }}' not found at expected sibling path (no go.mod). Run scripts/clone-deps.sh." - loop: "{{ preflight_components.results }}" - when: not item.stat.exists - loop_control: - label: "{{ item.item }}" - -- name: Check port availability - ansible.builtin.shell: "ss -tlnH 'sport = :{{ item.port }}' | head -1" - register: preflight_ports - loop: "{{ spinifex_ports }}" - changed_when: false - failed_when: false - loop_control: - label: "{{ item.service }} ({{ item.port }})" - -- name: Warn on occupied ports - ansible.builtin.debug: - msg: "WARN: port {{ item.item.port }} occupied (needed for {{ item.item.service }})" - loop: "{{ preflight_ports.results }}" - when: item.stdout | length > 0 - loop_control: - label: "{{ item.item.service }}" - -- name: Preflight summary - ansible.builtin.debug: - msg: "Preflight passed. Required: {{ spinifex_required_commands | join(', ') }}. Warnings above (if any) are non-fatal." diff --git a/scripts/ansible/roles/restore/meta/main.yml b/scripts/ansible/roles/restore/meta/main.yml deleted file mode 100644 index 30285dc4d..000000000 --- a/scripts/ansible/roles/restore/meta/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -galaxy_info: - role_name: restore - description: Restore a spinifex+ovn+ovs snapshot bundle, refresh CA trust, restart. - license: BSD-3-Clause - min_ansible_version: "2.14" -dependencies: [] diff --git a/scripts/ansible/roles/restore/tasks/main.yml b/scripts/ansible/roles/restore/tasks/main.yml deleted file mode 100644 index 862e39a4c..000000000 --- a/scripts/ansible/roles/restore/tasks/main.yml +++ /dev/null @@ -1,140 +0,0 @@ ---- -# Inverse of the snapshot role: stop services, wipe the same path set, -# untar the named bundle, refresh CA trust (because /etc/spinifex/ca.pem -# came from the snapshot but the system trust store didn't), restart. - -- name: restore — require snapshot_name - ansible.builtin.assert: - that: - - snapshot_name is defined - - snapshot_name | length > 0 - - snapshot_name is match('^[A-Za-z0-9._-]+$') - fail_msg: "snapshot_name required (alphanumeric/._-): -e snapshot_name=" - -- name: restore — resolve bundle path - ansible.builtin.set_fact: - snapshot_bundle_path: "{{ snapshot_dir }}/{{ snapshot_name }}.tar.gz" - -- name: restore — assert bundle exists - become: true - ansible.builtin.stat: - path: "{{ snapshot_bundle_path }}" - register: restore_bundle_stat - -- name: restore — fail if missing - ansible.builtin.assert: - that: restore_bundle_stat.stat.exists - fail_msg: | - Snapshot bundle missing: {{ snapshot_bundle_path }}. - Available bundles: - ls -lh {{ snapshot_dir }}/*.tar.gz 2>/dev/null - -- name: restore — stop services in dependency order - become: true - ansible.builtin.systemd: - name: "{{ item }}" - state: stopped - loop: "{{ snapshot_services_stop_order }}" - failed_when: false - -- name: restore — kill lingering QEMU VMs - become: true - ansible.builtin.command: "pkill -x {{ item }}" - loop: "{{ spinifex_qemu_processes }}" - changed_when: false - failed_when: false - -- name: restore — wait for QEMU exit - become: true - ansible.builtin.shell: | - set -e - for i in $(seq 1 {{ teardown_process_wait_seconds }}); do - alive=0 - for proc in {{ spinifex_qemu_processes | join(' ') }}; do - if pgrep -x "$proc" >/dev/null 2>&1; then alive=1; break; fi - done - if [ "$alive" = "0" ]; then exit 0; fi - sleep 1 - done - exit 1 - changed_when: false - -- name: restore — wipe target paths (only those the snapshot will replace) - become: true - ansible.builtin.file: - path: "{{ item }}" - state: absent - loop: "{{ snapshot_paths }}" - -- name: restore — recreate parent dirs that tar will refill - become: true - ansible.builtin.file: - path: "{{ item }}" - state: directory - owner: root - group: root - mode: "0755" - loop: - - "{{ ovn_db_dir }}" - - /etc/openvswitch - -- name: restore — extract bundle (preserve permissions/ACLs) - become: true - ansible.builtin.command: - cmd: >- - tar --acls --xattrs -xzpf {{ snapshot_bundle_path | quote }} - -C / - changed_when: true - -- name: restore — refresh spinifex CA in system trust - become: true - ansible.builtin.stat: - path: "{{ spinifex_ca_src }}" - register: restore_ca_stat - -- name: restore — copy CA back to trust path - become: true - ansible.builtin.copy: - src: "{{ spinifex_ca_src }}" - dest: "{{ spinifex_ca_trust_path }}" - mode: "0644" - remote_src: true - when: restore_ca_stat.stat.exists - -- name: restore — rebuild CA bundle - become: true - ansible.builtin.command: update-ca-certificates - changed_when: true - when: restore_ca_stat.stat.exists - -- name: restore — daemon-reload (covers any unit file delta in the snapshot) - become: true - ansible.builtin.systemd: - daemon_reload: true - -- name: restore — restart services in reverse order - become: true - ansible.builtin.systemd: - name: "{{ item }}" - state: started - loop: "{{ snapshot_services_stop_order | reverse | list }}" - failed_when: false - -- name: restore — wait for AWS gateway readiness - ansible.builtin.command: "{{ spinifex_aws_cli }} ec2 describe-regions" - register: restore_gw_ready - retries: 30 - delay: 2 - until: restore_gw_ready.rc == 0 - changed_when: false - failed_when: false - -- name: restore — summary - ansible.builtin.debug: - msg: | - Restore complete: - snapshot : {{ snapshot_name }} - bundle : {{ snapshot_bundle_path }} - paths : {{ snapshot_paths | join(', ') }} - CA : {{ 'refreshed' if restore_ca_stat.stat.exists else 'not in bundle — system trust unchanged' }} - gateway : {{ 'ready' if restore_gw_ready.rc == 0 else 'NOT ready after restart — investigate' }} diff --git a/scripts/ansible/roles/smoketest/meta/main.yml b/scripts/ansible/roles/smoketest/meta/main.yml deleted file mode 100644 index cf03cf808..000000000 --- a/scripts/ansible/roles/smoketest/meta/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -galaxy_info: - role_name: smoketest - description: Import SSH key, import Ubuntu AMI, launch one smoke-test instance. - license: BSD-3-Clause - min_ansible_version: "2.14" -dependencies: [] diff --git a/scripts/ansible/roles/smoketest/tasks/main.yml b/scripts/ansible/roles/smoketest/tasks/main.yml deleted file mode 100644 index d944bc36a..000000000 --- a/scripts/ansible/roles/smoketest/tasks/main.yml +++ /dev/null @@ -1,197 +0,0 @@ ---- -- name: smoketest — resolve invoking user's home - ansible.builtin.getent: - database: passwd - key: "{{ spinifex_invoking_user }}" - -- name: smoketest — set user home fact - ansible.builtin.set_fact: - smoketest_user_home: "{{ ansible_facts['getent_passwd'][spinifex_invoking_user][4] }}" - -- name: smoketest — generate SSH key if absent - become: true - become_user: "{{ spinifex_invoking_user }}" - ansible.builtin.command: - cmd: ssh-keygen -t ed25519 -f {{ smoketest_user_home }}/.ssh/spinifex-key -N "" - creates: "{{ smoketest_user_home }}/.ssh/spinifex-key" - -- name: smoketest — import SSH key to spinifex - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 import-key-pair - --key-name spinifex-key - --public-key-material fileb://{{ smoketest_user_home }}/.ssh/spinifex-key.pub - register: smoketest_keypair - until: >- - smoketest_keypair.rc == 0 or - 'InvalidKeyPair.Duplicate' in (smoketest_keypair.stderr | default('')) - retries: 10 - delay: 3 - changed_when: "'InvalidKeyPair.Duplicate' not in (smoketest_keypair.stderr | default(''))" - failed_when: - - smoketest_keypair.rc != 0 - - "'InvalidKeyPair.Duplicate' not in (smoketest_keypair.stderr | default(''))" - -- name: smoketest — detect architecture - ansible.builtin.set_fact: - smoketest_arch: "{{ 'arm64' if ansible_facts['architecture'] in ['aarch64','arm64'] else 'x86_64' }}" - -- name: smoketest — resolve local image path - ansible.builtin.set_fact: - smoketest_local_image_path: "{{ smoketest_local_image | expanduser }}" - vars: - smoketest_local_image: "{{ spinifex_smoketest_local_image | replace('~', smoketest_user_home) }}" - -- name: smoketest — check for local image - ansible.builtin.stat: - path: "{{ smoketest_local_image_path }}" - register: smoketest_local_img - -- name: smoketest — import AMI from local file - ansible.builtin.command: >- - {{ spinifex_spx_cli }} admin images import - --file {{ smoketest_local_image_path }} - --distro {{ spinifex_smoketest_distro }} - --version {{ spinifex_smoketest_version }} - --arch {{ smoketest_arch }} - --boot-mode uefi - register: smoketest_import_local - until: >- - smoketest_import_local.rc == 0 or - 'already exists' in (smoketest_import_local.stderr | default('')) - retries: 5 - delay: 3 - changed_when: smoketest_import_local.rc == 0 - failed_when: - - smoketest_import_local.rc != 0 - - "'already exists' not in (smoketest_import_local.stderr | default(''))" - when: smoketest_local_img.stat.exists - -- name: smoketest — import AMI by name (fallback) - ansible.builtin.command: >- - {{ spinifex_spx_cli }} admin images import - --name {{ spinifex_smoketest_distro }}-{{ spinifex_smoketest_version }}-{{ smoketest_arch }} - register: smoketest_import_remote - until: >- - smoketest_import_remote.rc == 0 or - 'already exists' in (smoketest_import_remote.stderr | default('')) - retries: 5 - delay: 3 - changed_when: smoketest_import_remote.rc == 0 - failed_when: - - smoketest_import_remote.rc != 0 - - "'already exists' not in (smoketest_import_remote.stderr | default(''))" - when: not smoketest_local_img.stat.exists - -- name: smoketest — detect CPU vendor for instance type choice - ansible.builtin.command: grep -q AuthenticAMD /proc/cpuinfo - register: smoketest_amd - changed_when: false - failed_when: false - -- name: smoketest — pick instance type - ansible.builtin.set_fact: - smoketest_instance_type: "{{ 't3a.small' if smoketest_amd.rc == 0 else 't3.small' }}" - -- name: smoketest — find AMI ID - ansible.builtin.command: "{{ spinifex_aws_cli }} ec2 describe-images --query Images[0].ImageId --output text" - register: smoketest_ami - until: smoketest_ami.rc == 0 - retries: 10 - delay: 3 - changed_when: false - -- name: smoketest — find public subnet (best-effort) - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 describe-subnets - --filters Name=map-public-ip-on-launch,Values=true - --query Subnets[0].SubnetId - --output text - register: smoketest_subnet_public - changed_when: false - failed_when: false - -- name: smoketest — fallback to first subnet (best-effort) - ansible.builtin.command: "{{ spinifex_aws_cli }} ec2 describe-subnets --query Subnets[0].SubnetId --output text" - register: smoketest_subnet_any - changed_when: false - failed_when: false - when: - - smoketest_subnet_public.rc != 0 or smoketest_subnet_public.stdout in ['', 'None'] - -- name: smoketest — resolve subnet id (empty string if none) - ansible.builtin.set_fact: - smoketest_subnet_id: >- - {%- if smoketest_subnet_public.rc == 0 and smoketest_subnet_public.stdout not in ['', 'None'] -%} - {{ smoketest_subnet_public.stdout }} - {%- elif (smoketest_subnet_any.rc | default(1)) == 0 and (smoketest_subnet_any.stdout | default('')) not in ['', 'None'] -%} - {{ smoketest_subnet_any.stdout }} - {%- else -%}{%- endif -%} - -- name: smoketest — skip launch if no subnet (fresh install with no user VPC) - ansible.builtin.debug: - msg: | - No subnet found — skipping instance launch. - Services are up, CA is trusted, keypair imported, AMI imported. - Create a VPC+subnet via tofu examples (or `aws ec2 create-vpc` / - `create-subnet`) then re-run if you want a live instance. - when: smoketest_subnet_id | trim == '' - -- name: smoketest — launch instance - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 run-instances - --image-id {{ smoketest_ami.stdout }} - --instance-type {{ smoketest_instance_type }} - --key-name spinifex-key - --subnet-id {{ smoketest_subnet_id | trim }} - --count 1 - --query Instances[0].InstanceId - --output text - register: smoketest_instance - until: smoketest_instance.rc == 0 - retries: 5 - delay: 3 - changed_when: true - when: smoketest_subnet_id | trim != '' - -- name: smoketest — wait for instance running (proves launch path works) - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 describe-instances - --instance-ids {{ smoketest_instance.stdout }} - --query Reservations[0].Instances[0].State.Name - --output text - register: smoketest_instance_state - until: smoketest_instance_state.stdout | trim == 'running' - retries: 30 - delay: 2 - changed_when: false - failed_when: false - when: - - smoketest_subnet_id | trim != '' - - smoketest_instance.stdout is defined - - smoketest_instance.stdout | trim != '' - -- name: smoketest — terminate instance (cleanup) - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 terminate-instances - --instance-ids {{ smoketest_instance.stdout }} - register: smoketest_terminate - until: smoketest_terminate.rc == 0 - retries: 5 - delay: 3 - changed_when: true - failed_when: false - when: - - smoketest_subnet_id | trim != '' - - smoketest_instance.stdout is defined - - smoketest_instance.stdout | trim != '' - -- name: smoketest — summary - ansible.builtin.debug: - msg: | - Smoketest complete: - AMI: {{ smoketest_ami.stdout }} - Subnet: {{ smoketest_subnet_id | trim | default('(none — launch skipped)', true) }} - Instance type: {{ smoketest_instance_type }} - Instance ID: {{ smoketest_instance.stdout | default('(skipped)', true) }} - Final state: {{ smoketest_instance_state.stdout | default('(skipped)', true) | trim }} - Terminated: {{ 'yes' if smoketest_terminate.rc | default(1) == 0 else 'no (launch skipped or terminate failed)' }} diff --git a/scripts/ansible/roles/snapshot/meta/main.yml b/scripts/ansible/roles/snapshot/meta/main.yml deleted file mode 100644 index 2c415c4a1..000000000 --- a/scripts/ansible/roles/snapshot/meta/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -galaxy_info: - role_name: snapshot - description: Quiesce spinifex + ovn + ovs, tar state paths, restart. - license: BSD-3-Clause - min_ansible_version: "2.14" -dependencies: [] diff --git a/scripts/ansible/roles/snapshot/tasks/main.yml b/scripts/ansible/roles/snapshot/tasks/main.yml deleted file mode 100644 index 5458c6542..000000000 --- a/scripts/ansible/roles/snapshot/tasks/main.yml +++ /dev/null @@ -1,154 +0,0 @@ ---- -# Snapshot a quiesced spinifex node: stop spinifex.target → ovn → ovs in order, -# tar /etc/spinifex + /var/lib/spinifex + /var/lib/ovn + /etc/openvswitch/conf.db, -# restart in reverse. Lets devs checkpoint a working state before risky ops -# (branch switch, viperblock surgery, ovn-controller restart cycle) and roll -# back via dev-restore without a full ~10-min dev-reset. -# -# Caveat: /var/lib/spinifex contains viperblock volumes — snapshot size scales -# with VM disks. Default gzip; switch to a faster compressor by hand if needed. - -- name: snapshot — require snapshot_name - ansible.builtin.assert: - that: - - snapshot_name is defined - - snapshot_name | length > 0 - - snapshot_name is match('^[A-Za-z0-9._-]+$') - fail_msg: "snapshot_name required (alphanumeric/._-): -e snapshot_name=" - -- name: snapshot — resolve bundle path - ansible.builtin.set_fact: - snapshot_bundle_path: "{{ snapshot_dir }}/{{ snapshot_name }}.tar.gz" - -- name: snapshot — refuse to overwrite existing bundle - ansible.builtin.stat: - path: "{{ snapshot_bundle_path }}" - register: snapshot_existing - -- name: snapshot — assert not already present - ansible.builtin.assert: - that: not snapshot_existing.stat.exists - fail_msg: | - Snapshot {{ snapshot_bundle_path }} already exists. Pick another - name, or `sudo rm` the existing bundle first. - -- name: snapshot — ensure snapshot dir exists - become: true - ansible.builtin.file: - path: "{{ snapshot_dir }}" - state: directory - owner: root - group: root - mode: "0750" - -- name: snapshot — stop services in dependency order - become: true - ansible.builtin.systemd: - name: "{{ item }}" - state: stopped - loop: "{{ snapshot_services_stop_order }}" - failed_when: false - -- name: snapshot — kill lingering QEMU VMs - become: true - ansible.builtin.command: "pkill -x {{ item }}" - loop: "{{ spinifex_qemu_processes }}" - changed_when: false - failed_when: false - -- name: snapshot — wait for QEMU exit (up to {{ teardown_process_wait_seconds }}s) - become: true - ansible.builtin.shell: | - set -e - for i in $(seq 1 {{ teardown_process_wait_seconds }}); do - alive=0 - for proc in {{ spinifex_qemu_processes | join(' ') }}; do - if pgrep -x "$proc" >/dev/null 2>&1; then alive=1; break; fi - done - if [ "$alive" = "0" ]; then exit 0; fi - sleep 1 - done - echo "QEMU still running after {{ teardown_process_wait_seconds }}s" >&2 - exit 1 - changed_when: false - -- name: snapshot — verify which paths actually exist (skip missing silently) - ansible.builtin.stat: - path: "{{ item }}" - register: snapshot_path_stats - loop: "{{ snapshot_paths }}" - loop_control: - label: "{{ item }}" - -- name: snapshot — assemble list of present paths - ansible.builtin.set_fact: - snapshot_present_paths: >- - {{ snapshot_path_stats.results - | selectattr('stat.exists') | map(attribute='item') | list }} - -- name: snapshot — assert at least one path present - ansible.builtin.assert: - that: snapshot_present_paths | length > 0 - fail_msg: | - None of the snapshot paths exist: - {{ snapshot_paths | join(', ') }} - Has spinifex ever been installed on this node? - -- name: snapshot — create bundle (tar czf with absolute paths) - become: true - ansible.builtin.command: - cmd: >- - tar --acls --xattrs -czpf {{ snapshot_bundle_path | quote }} - {{ snapshot_present_paths | map('quote') | join(' ') }} - changed_when: true - -- name: snapshot — record manifest inside the bundle dir for traceability - become: true - ansible.builtin.copy: - dest: "{{ snapshot_dir }}/{{ snapshot_name }}.manifest" - mode: "0640" - content: | - snapshot_name: {{ snapshot_name }} - created_at: {{ ansible_facts['date_time']['iso8601'] }} - hostname: {{ ansible_facts['hostname'] }} - paths: - {% for p in snapshot_present_paths %} - {{ p }} - {% endfor %} - services_quiesced: - {% for s in snapshot_services_stop_order %} - {{ s }} - {% endfor %} - -- name: snapshot — restart services in reverse order - become: true - ansible.builtin.systemd: - name: "{{ item }}" - state: started - loop: "{{ snapshot_services_stop_order | reverse | list }}" - failed_when: false - -- name: snapshot — wait for AWS gateway readiness - ansible.builtin.command: "{{ spinifex_aws_cli }} ec2 describe-regions" - register: snapshot_gw_ready - retries: 30 - delay: 2 - until: snapshot_gw_ready.rc == 0 - changed_when: false - failed_when: false - -- name: snapshot — bundle size - become: true - ansible.builtin.stat: - path: "{{ snapshot_bundle_path }}" - register: snapshot_bundle_stat - -- name: snapshot — summary - ansible.builtin.debug: - msg: | - Snapshot complete: - name : {{ snapshot_name }} - path : {{ snapshot_bundle_path }} - size : {{ (snapshot_bundle_stat.stat.size | int / 1024 / 1024) | round(1) }} MiB - paths : {{ snapshot_present_paths | join(', ') }} - gateway : {{ 'ready' if snapshot_gw_ready.rc == 0 else 'NOT ready after restart — investigate' }} - - Restore with: ansible-playbook playbooks/dev-restore.yml -e snapshot_name={{ snapshot_name }} diff --git a/scripts/ansible/roles/status/meta/main.yml b/scripts/ansible/roles/status/meta/main.yml deleted file mode 100644 index a3abdbf04..000000000 --- a/scripts/ansible/roles/status/meta/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -galaxy_info: - role_name: status - description: Read-only health snapshot for a Spinifex dev node (doctor). - license: BSD-3-Clause - min_ansible_version: "2.14" -dependencies: [] diff --git a/scripts/ansible/roles/status/tasks/main.yml b/scripts/ansible/roles/status/tasks/main.yml deleted file mode 100644 index 2e37b03ea..000000000 --- a/scripts/ansible/roles/status/tasks/main.yml +++ /dev/null @@ -1,259 +0,0 @@ ---- -# Read-only health snapshot. NEVER mutates state. Every probe must use -# `changed_when: false` and `failed_when: false` so the role always reaches -# the summary task even when the node is half-broken — surfacing brokenness -# is the whole point. - -- name: status — spinifex.target activation - ansible.builtin.command: systemctl is-active spinifex.target - register: status_target - changed_when: false - failed_when: false - -- name: status — list spinifex-* units (active + failed) - ansible.builtin.shell: | - systemctl list-units 'spinifex-*' --all --no-legend --plain \ - --output=json 2>/dev/null || \ - systemctl list-units 'spinifex-*' --all --no-legend --plain - register: status_units - changed_when: false - failed_when: false - -- name: status — failed spinifex-* units (one line per) - ansible.builtin.shell: | - systemctl list-units 'spinifex-*' --state=failed --no-legend --plain \ - | awk '{print $1}' - register: status_failed_units - changed_when: false - failed_when: false - -- name: status — port listeners (which process holds each spinifex port) - ansible.builtin.shell: | - ss -tlnpH 'sport = :{{ item.port }}' | head -1 - register: status_ports - loop: "{{ spinifex_ports }}" - changed_when: false - failed_when: false - loop_control: - label: "{{ item.service }} ({{ item.port }})" - -- name: status — OVS tooling present? - ansible.builtin.command: which ovs-vsctl - register: status_ovs_which - changed_when: false - failed_when: false - -- name: status — OVS bridges - become: true - ansible.builtin.command: ovs-vsctl list-br - register: status_ovs_brs - changed_when: false - failed_when: false - when: status_ovs_which.rc == 0 - -- name: status — br-int exists? - become: true - ansible.builtin.command: ovs-vsctl br-exists br-int - register: status_brint - changed_when: false - failed_when: false - when: status_ovs_which.rc == 0 - -- name: status — ovn-controller active? - ansible.builtin.command: systemctl is-active ovn-controller - register: status_ovn_ctrl - changed_when: false - failed_when: false - -- name: status — ovn-central active? - ansible.builtin.command: systemctl is-active ovn-central - register: status_ovn_central - changed_when: false - failed_when: false - -- name: status — OVN NB/SB DB files present? - become: true - ansible.builtin.stat: - path: "{{ item }}" - register: status_ovn_dbs - loop: - - "{{ ovn_nb_db }}" - - "{{ ovn_sb_db }}" - loop_control: - label: "{{ item }}" - -- name: status — spinifex.toml present? - become: true - ansible.builtin.stat: - path: "{{ spinifex_config_file }}" - register: status_config - -- name: status — CA trust present? - become: true - ansible.builtin.stat: - path: "{{ spinifex_ca_trust_path }}" - register: status_ca - -- name: status — AWS gateway round-trip (describe-regions) - ansible.builtin.command: "{{ spinifex_aws_cli }} ec2 describe-regions --output text" - register: status_awsgw - changed_when: false - failed_when: false - -- name: status — installed spx binary - become: true - ansible.builtin.stat: - path: /usr/local/bin/spx - checksum_algorithm: sha256 - register: status_spx_installed - -- name: status — built spx binary - ansible.builtin.stat: - path: "{{ spinifex_root }}/bin/spx" - checksum_algorithm: sha256 - register: status_spx_built - -- name: status — spx version (installed) - ansible.builtin.shell: | - /usr/local/bin/spx version 2>/dev/null | grep -vE '^[0-9]{4}/' | head -1 - register: status_spx_version - changed_when: false - failed_when: false - when: status_spx_installed.stat.exists - -- name: status — installed nbdkit plugin - become: true - ansible.builtin.shell: | - set -e - pdir=$(nbdkit --dump-config | awk -F= '/^plugindir=/{print $2; exit}') - [ -f "$pdir/nbdkit-viperblock-plugin.so" ] && \ - sha256sum "$pdir/nbdkit-viperblock-plugin.so" | awk '{print $1}' - register: status_plugin_installed_sha - changed_when: false - failed_when: false - -- name: status — built nbdkit plugin - ansible.builtin.stat: - path: "{{ mulga_root }}/viperblock/lib/nbdkit-viperblock-plugin.so" - checksum_algorithm: sha256 - register: status_plugin_built - -- name: status — microvm artifacts (built) - ansible.builtin.stat: - path: "{{ spinifex_root }}/build/microvm/{{ item }}" - checksum_algorithm: sha256 - register: status_microvm_built - loop: - - vmlinuz - - initramfs.cpio.gz - -- name: status — microvm artifacts (installed) - become: true - ansible.builtin.stat: - path: /usr/share/spinifex/microvm/{{ item }} - checksum_algorithm: sha256 - register: status_microvm_installed - loop: - - vmlinuz - - initramfs.cpio.gz - -- name: status — running QEMU VMs - ansible.builtin.shell: pgrep -fa 'qemu-system-' | wc -l - register: status_qemu_count - changed_when: false - failed_when: false - -- name: status — count AMIs - ansible.builtin.command: "{{ spinifex_aws_cli }} ec2 describe-images --query length(Images) --output text" - register: status_ami_count - changed_when: false - failed_when: false - -- name: status — count keypairs - ansible.builtin.command: "{{ spinifex_aws_cli }} ec2 describe-key-pairs --query length(KeyPairs) --output text" - register: status_key_count - changed_when: false - failed_when: false - -- name: status — count volumes - ansible.builtin.command: "{{ spinifex_aws_cli }} ec2 describe-volumes --query length(Volumes) --output text" - register: status_vol_count - changed_when: false - failed_when: false - -- name: status — count running instances - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 describe-instances - --filters Name=instance-state-name,Values=running - --query length(Reservations[].Instances[]) --output text - register: status_instance_count - changed_when: false - failed_when: false - -- name: status — compute drift facts - ansible.builtin.set_fact: - status_spx_drift: >- - {{ status_spx_installed.stat.exists and status_spx_built.stat.exists and - (status_spx_installed.stat.checksum | default('')) != - (status_spx_built.stat.checksum | default('')) }} - status_plugin_drift: >- - {{ status_plugin_built.stat.exists and - (status_plugin_installed_sha.stdout | default('') | trim) != - (status_plugin_built.stat.checksum | default('')) }} - status_microvm_built_present: "{{ status_microvm_built.results - | map(attribute='stat.exists') | min }}" - -- name: status — render port lines - ansible.builtin.set_fact: - status_port_lines: >- - {{ status_port_lines | default([]) + - [('%-24s' | format(item.item.service ~ ' (' ~ item.item.port ~ ')')) - ~ ': ' - ~ ('listening' if (item.stdout | length) > 0 else 'free')] }} - loop: "{{ status_ports.results }}" - loop_control: - label: "{{ item.item.service }}" - -- name: status — assemble summary - ansible.builtin.set_fact: - status_summary_lines: >- - {{ - [ - '── Spinifex dev-node status ──────────────────────────────────────────────', - 'target : ' ~ (status_target.stdout | trim), - 'failed units : ' ~ (status_failed_units.stdout_lines | length) - ~ ((' → ' ~ (status_failed_units.stdout_lines | join(', '))) if (status_failed_units.stdout_lines | length) > 0 else ''), - '── Ports ──' - ] - + status_port_lines - + [ - '── Networking ──', - 'ovs-vsctl : ' ~ ('present' if status_ovs_which.rc == 0 else 'MISSING'), - 'ovs bridges : ' ~ ((status_ovs_brs.stdout_lines | default([]) | join(', ')) or '(none)'), - 'br-int : ' ~ ('present' if (status_brint.rc | default(1)) == 0 else 'MISSING'), - 'ovn-controller : ' ~ (status_ovn_ctrl.stdout | trim), - 'ovn-central : ' ~ (status_ovn_central.stdout | trim), - 'ovn NB DB : ' ~ ('present' if status_ovn_dbs.results[0].stat.exists else 'absent'), - 'ovn SB DB : ' ~ ('present' if status_ovn_dbs.results[1].stat.exists else 'absent'), - '── Config / trust ──', - 'spinifex.toml : ' ~ ('present' if status_config.stat.exists else 'MISSING') ~ ' (' ~ spinifex_config_file ~ ')', - 'CA trust : ' ~ ('present' if status_ca.stat.exists else 'MISSING') ~ ' (' ~ spinifex_ca_trust_path ~ ')', - '── AWS gateway ──', - 'describe-regions : ' ~ ('OK' if status_awsgw.rc == 0 else 'FAIL (rc=' ~ status_awsgw.rc ~ ')'), - 'AMIs : ' ~ (status_ami_count.stdout | default('?') | trim), - 'keypairs : ' ~ (status_key_count.stdout | default('?') | trim), - 'volumes : ' ~ (status_vol_count.stdout | default('?') | trim), - 'running instances: ' ~ (status_instance_count.stdout | default('?') | trim), - 'running QEMU : ' ~ (status_qemu_count.stdout | default('?') | trim), - '── Versions / drift ──', - 'spx (installed) : ' ~ ((status_spx_version.stdout | default('') | trim) or '(not installed)'), - 'spx drift : ' ~ ('YES (built ≠ installed) — run ansible-dev-deploy' if status_spx_drift else 'no'), - 'plugin drift : ' ~ ('YES (built ≠ installed) — run ansible-dev-deploy' if status_plugin_drift else 'no'), - 'microvm built : ' ~ ('present' if status_microvm_built_present else 'not built on this branch'), - '──────────────────────────────────────────────────────────────────────────' - ] - }} - -- name: status — summary - ansible.builtin.debug: - msg: "{{ status_summary_lines }}" diff --git a/scripts/ansible/roles/teardown/README.md b/scripts/ansible/roles/teardown/README.md deleted file mode 100644 index dd2f1a46f..000000000 --- a/scripts/ansible/roles/teardown/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# teardown — Leak Catalog - -Every task in this role corresponds to a known state source that survived a -previous reset. When the operator reports "reset didn't clean X", add a new -task and a new row here citing the symptom. - -## Initial catalog (from reset-dev-env.sh + reset-dev-env.md target) - -| State source | Cleaned by | Symptom if leaked | -|---|---|---| -| `spinifex.target` active | `systemctl stop` | Services keep running, file locks held | -| `spinifex-*` units in failed state | `systemctl reset-failed 'spinifex-*'` | `systemctl status` shows red units, next start refuses | -| Spinifex processes (spx, nats, predastore, etc.) | `pkill` pattern + wait loop | Stale listeners on 4222/8443/9999, start fails with "address in use" | -| QEMU VMs | `pkill qemu-system-*` + wait loop | Zombie VMs hold tap interfaces and viperblock state | -| `/etc/spinifex/` | `file: state=absent` | Stale TOML, stale CA, service users can't read fresh config | -| `/var/lib/spinifex/` | `file: state=absent` | Stale WAL, stale volumes, viperblock mounts fail | -| `/var/log/spinifex/` | `file: state=absent` | Logrotate confusion, permission drift after user changes | -| `/run/spinifex/` | `file: state=absent` | Stale sockets, pidfiles from prior systemd run | -| `$HOME/spinifex/` (legacy) | `file: state=absent` | Old dev-mode state shadowing new install | -| OVS bridges (all) | `ovs-vsctl del-br` loop | `br-int` populated with stale ports → `ovn-controller` commit loop | -| OVS `external_ids` | `ovs-vsctl clear Open_vSwitch .` | Stale chassis entries in SBDB | -| `/var/lib/ovn/ovnnb_db.db`, `ovnsb_db.db` | `file: state=absent` | "OVNSB commit failed, force recompute" loop after reset | -| `veth-wan-br` / `veth-wan-ovs` | `ip link delete` | Pair left dangling after setup-ovn.sh re-run | -| `spx-ext-*` macvlan interfaces | `ip link delete` loop | Stale macvlan on WAN NIC, packet duplication | -| Spinifex CA in trust store | remove + `update-ca-certificates` | TLS clients trust old CA, new cert fails verification | - -## Not cleaned by default (opt-in) - -| State source | Flag | Why opt-in | -|---|---|---| -| `~/.ssh/spinifex-key*` | `-e spinifex_wipe_ssh_keys=true` | Operator may want key to persist across resets | -| `~/.aws/credentials` spinifex profile | `-e spinifex_wipe_aws_creds=true` | `spx admin init --force` rewrites this block anyway; wipe only on demand | - -## Known traps - -- **`pgrep -f` self-match.** A literal pattern that matches the pattern - string itself causes `pgrep -f` to match our own shell. Mitigation: - bracket trick (`[b]in/spx` matches `bin/spx` but not `[b]in/spx`). -- **Log followers / ansible wrapper false positives.** `journalctl -f - _SYSTEMD_UNIT=spinifex-*` and ansible's own module shell matches the - service-name patterns in their cmdlines. Mitigation: - `spinifex_process_exclude` filter drops `journalctl|ansible|/bin/sh|pgrep|pkill|tail -[fF]`. -- **SIGTERM survivors.** `spx service spinifex start` (and potentially - other service-supervisor processes) ignore or delay SIGTERM. Mitigation: - kill task escalates SIGTERM → SIGKILL after 5s. - -## Adding a new entry - -1. Add a task to `tasks/main.yml` in the right section (services / state-dirs / - ovn / ovs / netlink / trust / user-owned). -2. Prefix the task `name:` with the state class (e.g. `netlink:`, `ovn:`). -3. Add a row to the catalog above — symptom is what the operator described. -4. If the leak class is general (e.g. "any interface matching spx-*"), - generalise the task; do not pattern-match on a single instance name. diff --git a/scripts/ansible/roles/teardown/meta/main.yml b/scripts/ansible/roles/teardown/meta/main.yml deleted file mode 100644 index f87f28d85..000000000 --- a/scripts/ansible/roles/teardown/meta/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -galaxy_info: - role_name: teardown - description: Wipe Spinifex dev state. Central leak-enumeration surface — every state location cleaned here is a known leak source. See README.md for catalog. - license: BSD-3-Clause - min_ansible_version: "2.14" -dependencies: [] diff --git a/scripts/ansible/roles/teardown/tasks/main.yml b/scripts/ansible/roles/teardown/tasks/main.yml deleted file mode 100644 index f3fcea4d6..000000000 --- a/scripts/ansible/roles/teardown/tasks/main.yml +++ /dev/null @@ -1,242 +0,0 @@ ---- -- name: guard — detect node count in spinifex.toml - ansible.builtin.shell: | - set -e - if [ -f {{ spinifex_config_file | quote }} ]; then - grep -cE '^\[nodes\.[^.]+\]' {{ spinifex_config_file | quote }} || echo 0 - else - echo 0 - fi - register: teardown_node_count - changed_when: false - -- name: guard — refuse to run on multi-node cluster - ansible.builtin.assert: - that: teardown_node_count.stdout | int <= 1 - fail_msg: >- - Multi-node cluster detected ({{ teardown_node_count.stdout }} nodes in - {{ spinifex_config_file }}). Teardown supports single-node only; - use 'spx admin cluster shutdown' per node. - -- name: services — stop spinifex.target - become: true - ansible.builtin.systemd: - name: spinifex.target - state: stopped - failed_when: false - -- name: services — reset failed state (spinifex-* scope only) - become: true - ansible.builtin.command: systemctl reset-failed 'spinifex-*' - changed_when: false - failed_when: false - -- name: processes — kill spinifex processes (SIGTERM, escalate to SIGKILL after 5s) - become: true - ansible.builtin.shell: | - pids=$(pgrep -af "{{ spinifex_process_pattern }}" \ - | grep -vE "{{ spinifex_process_exclude }}" \ - | awk '{print $1}') - if [ -n "$pids" ]; then - kill $pids 2>/dev/null || true - sleep 5 - pids=$(pgrep -af "{{ spinifex_process_pattern }}" \ - | grep -vE "{{ spinifex_process_exclude }}" \ - | awk '{print $1}') - if [ -n "$pids" ]; then - kill -9 $pids 2>/dev/null || true - fi - fi - changed_when: false - failed_when: false - -- name: processes — wait for exit (up to {{ teardown_process_wait_seconds }}s) - become: true - ansible.builtin.shell: | - for i in $(seq 1 {{ teardown_process_wait_seconds }}); do - pids=$(pgrep -af "{{ spinifex_process_pattern }}" \ - | grep -vE "{{ spinifex_process_exclude }}" \ - | awk '{print $1}') - if [ -z "$pids" ]; then - exit 0 - fi - sleep 1 - done - echo "still running after {{ teardown_process_wait_seconds }}s:" >&2 - pgrep -af "{{ spinifex_process_pattern }}" \ - | grep -vE "{{ spinifex_process_exclude }}" >&2 || true - exit 1 - changed_when: false - -- name: qemu — kill lingering VMs - become: true - ansible.builtin.command: "pkill -x {{ item }}" - loop: "{{ spinifex_qemu_processes }}" - changed_when: false - failed_when: false - -- name: qemu — wait for exit (up to {{ teardown_process_wait_seconds }}s) - become: true - ansible.builtin.shell: | - set -e - for i in $(seq 1 {{ teardown_process_wait_seconds }}); do - alive=0 - for proc in {{ spinifex_qemu_processes | join(' ') }}; do - if pgrep -x "$proc" >/dev/null 2>&1; then alive=1; break; fi - done - if [ "$alive" = "0" ]; then exit 0; fi - sleep 1 - done - echo "QEMU still running after {{ teardown_process_wait_seconds }}s" >&2 - exit 1 - changed_when: false - -- name: state-dirs — remove production dirs - become: true - ansible.builtin.file: - path: "{{ item }}" - state: absent - loop: - - "{{ spinifex_etc_dir }}" - - "{{ spinifex_data_dir }}" - - "{{ spinifex_log_dir }}" - - "{{ spinifex_run_dir }}" - -- name: state-dirs — remove legacy $HOME/spinifex (opt-in) - become: true - become_user: "{{ spinifex_invoking_user }}" - ansible.builtin.file: - path: "{{ spinifex_legacy_home_dir }}" - state: absent - when: spinifex_wipe_legacy_home | bool - -- name: ovs — detect tooling - ansible.builtin.command: which ovs-vsctl - register: teardown_ovs_which - changed_when: false - failed_when: false - -- name: ovs — ensure openvswitch-switch is running for cleanup - become: true - ansible.builtin.systemd: - name: openvswitch-switch - state: started - when: teardown_ovs_which.rc == 0 - failed_when: false - -- name: ovs — list bridges - become: true - ansible.builtin.command: ovs-vsctl list-br - register: teardown_ovs_brs - changed_when: false - failed_when: false - when: teardown_ovs_which.rc == 0 - -- name: ovs — delete all bridges - become: true - ansible.builtin.command: "ovs-vsctl --if-exists del-br {{ item }}" - loop: "{{ teardown_ovs_brs.stdout_lines | default([]) }}" - changed_when: true - when: teardown_ovs_which.rc == 0 - -- name: ovs — clear external_ids - become: true - ansible.builtin.command: ovs-vsctl --if-exists clear Open_vSwitch . external_ids - changed_when: true - failed_when: false - when: teardown_ovs_which.rc == 0 - -- name: ovs — stop openvswitch-switch after cleanup - become: true - ansible.builtin.systemd: - name: openvswitch-switch - state: stopped - when: teardown_ovs_which.rc == 0 - failed_when: false - -- name: ovn — stop ovn-central - become: true - ansible.builtin.systemd: - name: ovn-central - state: stopped - failed_when: false - -- name: ovn — stop ovn-controller - become: true - ansible.builtin.systemd: - name: ovn-controller - state: stopped - failed_when: false - -- name: ovn — delete NB/SB DB files - become: true - ansible.builtin.file: - path: "{{ item }}" - state: absent - loop: - - "{{ ovn_nb_db }}" - - "{{ ovn_sb_db }}" - -- name: netlink — enumerate spinifex-managed veth/tap - ansible.builtin.shell: | - ip -o link show | awk -F': ' '{print $2}' | cut -d'@' -f1 | \ - grep -E '^(veth-wan-br|veth-wan-ovs|spx-ext-|spx-tap-|spx-)' || true - register: teardown_links - changed_when: false - -- name: netlink — delete enumerated interfaces - become: true - ansible.builtin.command: "ip link delete {{ item }}" - loop: "{{ teardown_links.stdout_lines }}" - changed_when: true - failed_when: false - -- name: trust — remove spinifex CA from system store - become: true - ansible.builtin.file: - path: "{{ spinifex_ca_trust_path }}" - state: absent - register: teardown_ca_removed - -- name: trust — rebuild CA bundle (without --fresh, preserve other CAs) - become: true - ansible.builtin.command: update-ca-certificates - changed_when: true - when: teardown_ca_removed.changed - -- name: user-owned — remove spinifex profile from AWS credentials (opt-in) - become: true - become_user: "{{ spinifex_invoking_user }}" - ansible.builtin.blockinfile: - path: "~/.aws/credentials" - marker: "# {mark} SPINIFEX MANAGED BLOCK" - block: "" - state: absent - when: spinifex_wipe_aws_creds | bool - failed_when: false - -- name: user-owned — remove spinifex SSH key (opt-in) - become: true - become_user: "{{ spinifex_invoking_user }}" - ansible.builtin.file: - path: "~/.ssh/{{ item }}" - state: absent - loop: - - spinifex-key - - spinifex-key.pub - when: spinifex_wipe_ssh_keys | bool - -- name: summary - ansible.builtin.debug: - msg: | - Teardown complete. Catalog: roles/teardown/README.md - systemd : spinifex.target stopped, spinifex-* failed cleared - procs : {{ spinifex_process_pattern }} - qemu : {{ spinifex_qemu_processes | join(', ') }} - dirs : {{ spinifex_etc_dir }}, {{ spinifex_data_dir }}, {{ spinifex_log_dir }}, {{ spinifex_run_dir }}{{ ', ' ~ spinifex_legacy_home_dir if spinifex_wipe_legacy_home else '' }} - ovs : all bridges deleted, external_ids cleared - ovn : NB/SB DB files removed - netlink : {{ teardown_links.stdout_lines | length }} interface(s) removed - trust : {{ spinifex_ca_trust_path }} removed{% if spinifex_wipe_aws_creds %} - aws : credentials block removed{% endif %}{% if spinifex_wipe_ssh_keys %} - ssh : spinifex-key pair removed{% endif %} diff --git a/scripts/ansible/roles/version/meta/main.yml b/scripts/ansible/roles/version/meta/main.yml deleted file mode 100644 index 780fdbf08..000000000 --- a/scripts/ansible/roles/version/meta/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -galaxy_info: - role_name: version - description: Detailed build-vs-install drift report for spinifex artifacts. - license: BSD-3-Clause - min_ansible_version: "2.14" -dependencies: [] diff --git a/scripts/ansible/roles/version/tasks/main.yml b/scripts/ansible/roles/version/tasks/main.yml deleted file mode 100644 index 3c794c816..000000000 --- a/scripts/ansible/roles/version/tasks/main.yml +++ /dev/null @@ -1,161 +0,0 @@ ---- -# Detailed build-vs-install drift report for the four artifacts that -# `ansible-dev-deploy` swaps: spx, the nbdkit viperblock plugin, and the -# two microvm artifacts (kernel + initramfs). Pure read-only; faster -# than dev-status (no AWS / OVN / port probing). - -- name: version — built spx - ansible.builtin.stat: - path: "{{ spinifex_root }}/bin/spx" - checksum_algorithm: sha256 - register: ver_spx_built - -- name: version — installed spx - become: true - ansible.builtin.stat: - path: /usr/local/bin/spx - checksum_algorithm: sha256 - register: ver_spx_installed - -- name: version — installed spx version string - ansible.builtin.shell: | - /usr/local/bin/spx version 2>/dev/null | grep -vE '^[0-9]{4}/' | head -1 - register: ver_spx_version - changed_when: false - failed_when: false - when: ver_spx_installed.stat.exists - -- name: version — built plugin - ansible.builtin.stat: - path: "{{ mulga_root }}/viperblock/lib/nbdkit-viperblock-plugin.so" - checksum_algorithm: sha256 - register: ver_plugin_built - -- name: version — nbdkit plugin dir - ansible.builtin.shell: | - nbdkit --dump-config 2>/dev/null | awk -F= '/^plugindir=/{print $2; exit}' - register: ver_plugindir - changed_when: false - failed_when: false - -- name: version — installed plugin - become: true - ansible.builtin.stat: - path: "{{ ver_plugindir.stdout | trim }}/nbdkit-viperblock-plugin.so" - checksum_algorithm: sha256 - register: ver_plugin_installed - when: ver_plugindir.stdout | trim | length > 0 - -- name: version — built microvm artifacts - ansible.builtin.stat: - path: "{{ spinifex_root }}/build/microvm/{{ item }}" - checksum_algorithm: sha256 - register: ver_microvm_built - loop: - - vmlinuz - - initramfs.cpio.gz - -- name: version — installed microvm artifacts - become: true - ansible.builtin.stat: - path: /usr/share/spinifex/microvm/{{ item }} - checksum_algorithm: sha256 - register: ver_microvm_installed - loop: - - vmlinuz - - initramfs.cpio.gz - -- name: version — sub-repo HEAD short-rev (spinifex) - ansible.builtin.command: git -C {{ spinifex_root | quote }} rev-parse --short HEAD - register: ver_spinifex_head - changed_when: false - failed_when: false - -- name: version — sub-repo HEAD short-rev (viperblock) - ansible.builtin.command: git -C {{ mulga_root }}/viperblock rev-parse --short HEAD - register: ver_viperblock_head - changed_when: false - failed_when: false - -- name: version — sub-repo HEAD short-rev (predastore) - ansible.builtin.command: git -C {{ mulga_root }}/predastore rev-parse --short HEAD - register: ver_predastore_head - changed_when: false - failed_when: false - -- name: version — assemble per-artifact rows - ansible.builtin.set_fact: - ver_artifact_rows: >- - {{ - [ - ('%-18s built=%s installed=%s drift=%s' | format( - 'spx', - (ver_spx_built.stat.checksum | default('-') | truncate(13, true, '')) - if ver_spx_built.stat.exists else 'MISSING', - (ver_spx_installed.stat.checksum | default('-') | truncate(13, true, '')) - if ver_spx_installed.stat.exists else 'MISSING', - ('YES' if ver_spx_built.stat.exists and ver_spx_installed.stat.exists - and ver_spx_built.stat.checksum != ver_spx_installed.stat.checksum - else 'no') - )), - ('%-18s built=%s installed=%s drift=%s' | format( - 'plugin (nbdkit)', - (ver_plugin_built.stat.checksum | default('-') | truncate(13, true, '')) - if ver_plugin_built.stat.exists else 'MISSING', - (ver_plugin_installed.stat.checksum | default('-') | truncate(13, true, '')) - if (ver_plugin_installed.stat | default({})).get('exists', false) else 'MISSING', - ('YES' if ver_plugin_built.stat.exists - and (ver_plugin_installed.stat | default({})).get('exists', false) - and ver_plugin_built.stat.checksum != ver_plugin_installed.stat.checksum - else 'no') - )), - ('%-18s built=%s installed=%s drift=%s' | format( - 'microvm vmlinuz', - (ver_microvm_built.results[0].stat.checksum | default('-') | truncate(13, true, '')) - if ver_microvm_built.results[0].stat.exists else 'MISSING', - (ver_microvm_installed.results[0].stat.checksum | default('-') | truncate(13, true, '')) - if ver_microvm_installed.results[0].stat.exists else 'MISSING', - ('YES' if ver_microvm_built.results[0].stat.exists - and ver_microvm_installed.results[0].stat.exists - and ver_microvm_built.results[0].stat.checksum - != ver_microvm_installed.results[0].stat.checksum - else 'no') - )), - ('%-18s built=%s installed=%s drift=%s' | format( - 'microvm initramfs', - (ver_microvm_built.results[1].stat.checksum | default('-') | truncate(13, true, '')) - if ver_microvm_built.results[1].stat.exists else 'MISSING', - (ver_microvm_installed.results[1].stat.checksum | default('-') | truncate(13, true, '')) - if ver_microvm_installed.results[1].stat.exists else 'MISSING', - ('YES' if ver_microvm_built.results[1].stat.exists - and ver_microvm_installed.results[1].stat.exists - and ver_microvm_built.results[1].stat.checksum - != ver_microvm_installed.results[1].stat.checksum - else 'no') - )) - ] - }} - -- name: version — compute any-drift flag - ansible.builtin.set_fact: - ver_any_drift: "{{ 'YES' in (ver_artifact_rows | join(' ')) }}" - -- name: version — summary - ansible.builtin.debug: - msg: >- - {{ - [ - '── Spinifex build vs install ─────────────────────────────────────────────', - 'spx (installed): ' ~ ((ver_spx_version.stdout | default('') | trim) or '(not installed)') - ] - + ver_artifact_rows - + [ - '── Sub-repo HEADs ──', - 'spinifex : ' ~ ((ver_spinifex_head.stdout | default('') | trim) or '(not a git repo)'), - 'viperblock : ' ~ ((ver_viperblock_head.stdout | default('') | trim) or '(missing)'), - 'predastore : ' ~ ((ver_predastore_head.stdout | default('') | trim) or '(missing)'), - '──────────────────────────────────────────────────────────────────────────', - ('DRIFT detected — run: make ansible-dev-deploy' if ver_any_drift - else 'No drift; built = installed for all artifacts.') - ] - }} diff --git a/scripts/ansible/roles/vpc/meta/main.yml b/scripts/ansible/roles/vpc/meta/main.yml deleted file mode 100644 index cc90f9d83..000000000 --- a/scripts/ansible/roles/vpc/meta/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -galaxy_info: - role_name: vpc - description: Idempotent dev-mode VPC + public subnet + IGW + default route fixture. - license: BSD-3-Clause - min_ansible_version: "2.14" -dependencies: [] diff --git a/scripts/ansible/roles/vpc/tasks/absent.yml b/scripts/ansible/roles/vpc/tasks/absent.yml deleted file mode 100644 index 2f72e21fd..000000000 --- a/scripts/ansible/roles/vpc/tasks/absent.yml +++ /dev/null @@ -1,128 +0,0 @@ ---- -# Tear down the dev VPC fixture. Deletes in reverse dependency order: -# route-table associations, route table, subnet, IGW (detach + delete), -# VPC. Each step is best-effort so a partially-converged fixture still -# converges to "gone" on re-run. - -- name: vpc — find VPC by Name tag - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 describe-vpcs - --filters Name=tag:Name,Values={{ dev_vpc_name }} - --query Vpcs[0].VpcId --output text - register: absent_vpc - changed_when: false - -- name: vpc — nothing to do - ansible.builtin.debug: - msg: "VPC tagged Name={{ dev_vpc_name }} not found; nothing to delete." - when: absent_vpc.stdout | trim in ['', 'None'] - -- name: vpc — short-circuit when no VPC - ansible.builtin.meta: end_play - when: absent_vpc.stdout | trim in ['', 'None'] - -- name: vpc — set VPC id fact - ansible.builtin.set_fact: - absent_vpc_id: "{{ absent_vpc.stdout | trim }}" - -- name: vpc — find subnet - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 describe-subnets - --filters Name=vpc-id,Values={{ absent_vpc_id }} - Name=tag:Name,Values={{ dev_vpc_name }}-public - --query Subnets[0].SubnetId --output text - register: absent_subnet - changed_when: false - -# Enumerate ALL non-main route tables in the VPC (main RT can't be -# deleted; it goes when the VPC does). Catches orphans from earlier -# runs that landed before the create-tags workaround. -- name: vpc — find all non-main route tables in VPC - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 describe-route-tables - --filters Name=vpc-id,Values={{ absent_vpc_id }} - --query RouteTables[?!(Associations[?Main==`true`])].RouteTableId - --output text - register: absent_rt_list - changed_when: false - -- name: vpc — split RT id list - ansible.builtin.set_fact: - absent_rt_ids: "{{ absent_rt_list.stdout.split() | reject('equalto', '') | list }}" - -- name: vpc — find all subnet/RT associations to disassociate - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 describe-route-tables - --route-table-ids {{ item }} - --query RouteTables[0].Associations[?SubnetId!=null].RouteTableAssociationId - --output text - register: absent_assocs - loop: "{{ absent_rt_ids }}" - changed_when: false - failed_when: false - -- name: vpc — disassociate subnets from route tables - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 disassociate-route-table - --association-id {{ item }} - loop: "{{ absent_assocs.results - | map(attribute='stdout') - | map('default', '') - | map('split') - | flatten - | reject('equalto', '') - | list }}" - changed_when: true - failed_when: false - -- name: vpc — delete all non-main route tables - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 delete-route-table - --route-table-id {{ item }} - loop: "{{ absent_rt_ids }}" - changed_when: true - failed_when: false - -- name: vpc — delete subnet - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 delete-subnet - --subnet-id {{ absent_subnet.stdout | trim }} - when: absent_subnet.stdout | trim not in ['', 'None'] - changed_when: true - failed_when: false - -- name: vpc — find IGW - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 describe-internet-gateways - --filters Name=attachment.vpc-id,Values={{ absent_vpc_id }} - --query InternetGateways[0].InternetGatewayId --output text - register: absent_igw - changed_when: false - -- name: vpc — detach IGW - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 detach-internet-gateway - --internet-gateway-id {{ absent_igw.stdout | trim }} - --vpc-id {{ absent_vpc_id }} - when: absent_igw.stdout | trim not in ['', 'None'] - changed_when: true - failed_when: false - -- name: vpc — delete IGW - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 delete-internet-gateway - --internet-gateway-id {{ absent_igw.stdout | trim }} - when: absent_igw.stdout | trim not in ['', 'None'] - changed_when: true - failed_when: false - -- name: vpc — delete VPC - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 delete-vpc - --vpc-id {{ absent_vpc_id }} - changed_when: true - failed_when: false - -- name: vpc — summary (absent) - ansible.builtin.debug: - msg: "Dev VPC {{ dev_vpc_name }} (was {{ absent_vpc_id }}) torn down." diff --git a/scripts/ansible/roles/vpc/tasks/main.yml b/scripts/ansible/roles/vpc/tasks/main.yml deleted file mode 100644 index 5258f3bd4..000000000 --- a/scripts/ansible/roles/vpc/tasks/main.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -- name: vpc — dispatch by state - ansible.builtin.include_tasks: "{{ dev_vpc_state }}.yml" diff --git a/scripts/ansible/roles/vpc/tasks/present.yml b/scripts/ansible/roles/vpc/tasks/present.yml deleted file mode 100644 index 275c7def9..000000000 --- a/scripts/ansible/roles/vpc/tasks/present.yml +++ /dev/null @@ -1,209 +0,0 @@ ---- -# Idempotent create. Every step describes-then-creates: re-running on an -# already-converged VPC produces zero changes. Tag everything with -# Name={{ dev_vpc_name }} so a single tag query finds the whole graph. - -- name: vpc — find existing VPC by Name tag - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 describe-vpcs - --filters Name=tag:Name,Values={{ dev_vpc_name }} - --query Vpcs[0].VpcId --output text - register: vpc_existing - changed_when: false - -- name: vpc — create VPC if missing - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 create-vpc - --cidr-block {{ dev_vpc_cidr }} - --tag-specifications - ResourceType=vpc,Tags=[{Key=Name,Value={{ dev_vpc_name }}}] - --query Vpc.VpcId --output text - register: vpc_created - when: vpc_existing.stdout | trim in ['', 'None'] - changed_when: true - -- name: vpc — set VPC id fact - ansible.builtin.set_fact: - dev_vpc_id: >- - {{ vpc_created.stdout | default('') | trim - if (vpc_existing.stdout | trim in ['', 'None']) - else vpc_existing.stdout | trim }} - -- name: vpc — assert VPC id resolved - ansible.builtin.assert: - that: dev_vpc_id | length > 0 - fail_msg: "VPC id could not be resolved after describe/create" - -- name: vpc — find existing IGW attached to this VPC - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 describe-internet-gateways - --filters Name=attachment.vpc-id,Values={{ dev_vpc_id }} - --query InternetGateways[0].InternetGatewayId --output text - register: vpc_igw_existing - changed_when: false - -- name: vpc — create IGW if missing - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 create-internet-gateway - --tag-specifications - ResourceType=internet-gateway,Tags=[{Key=Name,Value={{ dev_vpc_name }}-igw}] - --query InternetGateway.InternetGatewayId --output text - register: vpc_igw_created - when: vpc_igw_existing.stdout | trim in ['', 'None'] - changed_when: true - -- name: vpc — set IGW id fact - ansible.builtin.set_fact: - dev_vpc_igw_id: >- - {{ vpc_igw_created.stdout | default('') | trim - if (vpc_igw_existing.stdout | trim in ['', 'None']) - else vpc_igw_existing.stdout | trim }} - -- name: vpc — attach IGW to VPC if needed - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 attach-internet-gateway - --internet-gateway-id {{ dev_vpc_igw_id }} - --vpc-id {{ dev_vpc_id }} - register: vpc_igw_attach - when: vpc_igw_existing.stdout | trim in ['', 'None'] - changed_when: true - failed_when: - - vpc_igw_attach.rc | default(0) != 0 - - "'Resource.AlreadyAssociated' not in (vpc_igw_attach.stderr | default(''))" - -- name: vpc — find existing subnet by Name tag - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 describe-subnets - --filters Name=vpc-id,Values={{ dev_vpc_id }} - Name=tag:Name,Values={{ dev_vpc_name }}-public - --query Subnets[0].SubnetId --output text - register: vpc_subnet_existing - changed_when: false - -- name: vpc — create subnet if missing - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 create-subnet - --vpc-id {{ dev_vpc_id }} - --cidr-block {{ dev_vpc_subnet_cidr }} - --availability-zone {{ dev_vpc_subnet_az }} - --tag-specifications - ResourceType=subnet,Tags=[{Key=Name,Value={{ dev_vpc_name }}-public}] - --query Subnet.SubnetId --output text - register: vpc_subnet_created - when: vpc_subnet_existing.stdout | trim in ['', 'None'] - changed_when: true - -- name: vpc — set subnet id fact - ansible.builtin.set_fact: - dev_vpc_subnet_id: >- - {{ vpc_subnet_created.stdout | default('') | trim - if (vpc_subnet_existing.stdout | trim in ['', 'None']) - else vpc_subnet_existing.stdout | trim }} - -- name: vpc — ensure subnet has map-public-ip-on-launch - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 modify-subnet-attribute - --subnet-id {{ dev_vpc_subnet_id }} - --map-public-ip-on-launch - register: vpc_subnet_mapip - changed_when: vpc_subnet_existing.stdout | trim in ['', 'None'] - failed_when: false - -# Try tag-based lookup first. If the gateway didn't tag a previously -# created RT (spinifex gateway silently drops --tag-specifications on -# create-route-table AND no-ops create-tags for route tables — see -# mulga-siv-94; works correctly for subnets), fall back to "RT -# associated with our subnet" which doesn't need tags. -- name: vpc — find existing route table by Name tag - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 describe-route-tables - --filters Name=vpc-id,Values={{ dev_vpc_id }} - Name=tag:Name,Values={{ dev_vpc_name }}-public - --query RouteTables[0].RouteTableId --output text - register: vpc_rt_existing - changed_when: false - -- name: vpc — fallback lookup by subnet association - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 describe-route-tables - --filters Name=association.subnet-id,Values={{ dev_vpc_subnet_id }} - --query RouteTables[0].RouteTableId --output text - register: vpc_rt_byassoc - changed_when: false - when: vpc_rt_existing.stdout | trim in ['', 'None'] - -- name: vpc — create route table if neither lookup found one - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 create-route-table - --vpc-id {{ dev_vpc_id }} - --query RouteTable.RouteTableId --output text - register: vpc_rt_created - when: - - vpc_rt_existing.stdout | trim in ['', 'None'] - - (vpc_rt_byassoc.stdout | default('') | trim) in ['', 'None'] - changed_when: true - -- name: vpc — set route-table id fact - ansible.builtin.set_fact: - dev_vpc_rt_id: >- - {%- if (vpc_rt_existing.stdout | trim) not in ['', 'None'] -%} - {{ vpc_rt_existing.stdout | trim }} - {%- elif (vpc_rt_byassoc.stdout | default('') | trim) not in ['', 'None'] -%} - {{ vpc_rt_byassoc.stdout | default('') | trim }} - {%- else -%} - {{ vpc_rt_created.stdout | default('') | trim }} - {%- endif -%} - -- name: vpc — assert route-table id resolved - ansible.builtin.assert: - that: dev_vpc_rt_id | length > 0 - fail_msg: "Route table id could not be resolved after describe/create" - -# Spinifex gateway dropped --tag-specifications on the create call; -# apply via create-tags so re-runs can find the RT via tag filter. -- name: vpc — tag route table (workaround for create-tag-specifications gap) - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 create-tags - --resources {{ dev_vpc_rt_id }} - --tags Key=Name,Value={{ dev_vpc_name }}-public - changed_when: false - failed_when: false - -- name: vpc — add default route via IGW (ignore RouteAlreadyExists) - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 create-route - --route-table-id {{ dev_vpc_rt_id }} - --destination-cidr-block 0.0.0.0/0 - --gateway-id {{ dev_vpc_igw_id }} - register: vpc_route_add - changed_when: - - vpc_route_add.rc == 0 - - "'RouteAlreadyExists' not in (vpc_route_add.stderr | default(''))" - failed_when: - - vpc_route_add.rc != 0 - - "'RouteAlreadyExists' not in (vpc_route_add.stderr | default(''))" - -- name: vpc — associate subnet with route table (ignore already-associated) - ansible.builtin.command: >- - {{ spinifex_aws_cli }} ec2 associate-route-table - --route-table-id {{ dev_vpc_rt_id }} - --subnet-id {{ dev_vpc_subnet_id }} - register: vpc_assoc - changed_when: - - vpc_assoc.rc == 0 - - "'Resource.AlreadyAssociated' not in (vpc_assoc.stderr | default(''))" - failed_when: - - vpc_assoc.rc != 0 - - "'Resource.AlreadyAssociated' not in (vpc_assoc.stderr | default(''))" - -- name: vpc — summary (present) - ansible.builtin.debug: - msg: | - Dev VPC ready: - VPC : {{ dev_vpc_id }} ({{ dev_vpc_cidr }}) - IGW : {{ dev_vpc_igw_id }} - Subnet : {{ dev_vpc_subnet_id }} ({{ dev_vpc_subnet_cidr }} @ {{ dev_vpc_subnet_az }}, public) - Route table : {{ dev_vpc_rt_id }} - - Smoketest now finds this subnet via its existing - Name=map-public-ip-on-launch,Values=true filter. diff --git a/scripts/ansible/scripts/aws-as-spinifex.sh b/scripts/ansible/scripts/aws-as-spinifex.sh deleted file mode 100755 index 59b0fffe2..000000000 --- a/scripts/ansible/scripts/aws-as-spinifex.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -# Run `aws` CLI inside a shell that has the `spinifex` supplementary group -# active, with AWS_PROFILE=spinifex preset. Works around mulga-siv-92: -# ansible's `become` is a no-op when the target user equals the calling -# user, so `sudo -u` is never invoked and supplementary groups are not -# re-initialised. Without the `spinifex` group, /etc/spinifex/ca.pem (the -# AWS endpoint CA bundle) is unreadable and aws fails with SSL Errno 13. -# -# Usage from ansible tasks: -# ansible.builtin.command: -# cmd: "{{ playbook_dir }}/../scripts/aws-as-spinifex.sh ec2 describe-regions" -# -# All args are forwarded to `aws`. Quoting is preserved via printf %q so -# things like `--query 'length(Images)'` reach aws intact. -set -euo pipefail - -if [[ $# -eq 0 ]]; then - echo "usage: $0 " >&2 - exit 64 -fi - -cmd="AWS_PROFILE=spinifex aws" -for arg in "$@"; do - cmd+=" $(printf '%q' "$arg")" -done - -exec sg spinifex -c "$cmd" diff --git a/scripts/ansible/scripts/spx-as-spinifex.sh b/scripts/ansible/scripts/spx-as-spinifex.sh deleted file mode 100755 index 8d8ab3538..000000000 --- a/scripts/ansible/scripts/spx-as-spinifex.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash -# Run `spx` inside a shell that has the `spinifex` supplementary group -# active. Works around mulga-siv-92 (see aws-as-spinifex.sh for details). -# All args are forwarded to /usr/local/bin/spx via printf %q so flag -# values with spaces or shell metachars survive intact. -set -euo pipefail - -if [[ $# -eq 0 ]]; then - echo "usage: $0 " >&2 - exit 64 -fi - -cmd="AWS_PROFILE=spinifex /usr/local/bin/spx" -for arg in "$@"; do - cmd+=" $(printf '%q' "$arg")" -done - -exec sg spinifex -c "$cmd" diff --git a/scripts/ansible/vars/defaults.yml b/scripts/ansible/vars/defaults.yml deleted file mode 100644 index c4270dd2d..000000000 --- a/scripts/ansible/vars/defaults.yml +++ /dev/null @@ -1,137 +0,0 @@ ---- -# Production layout (per spinifex/scripts/setup.sh). -spinifex_etc_dir: /etc/spinifex -spinifex_data_dir: /var/lib/spinifex -spinifex_log_dir: /var/log/spinifex -spinifex_run_dir: /run/spinifex -spinifex_config_file: "{{ spinifex_etc_dir }}/spinifex.toml" -spinifex_ca_trust_path: /usr/local/share/ca-certificates/spinifex-ca.crt -spinifex_ca_src: "{{ spinifex_etc_dir }}/ca.pem" - -# Legacy $HOME layout (still present on older dev boxes). -spinifex_legacy_home_dir: "{{ lookup('env','HOME') }}/spinifex" - -# OVN state. -ovn_db_dir: /var/lib/ovn -ovn_nb_db: "{{ ovn_db_dir }}/ovnnb_db.db" -ovn_sb_db: "{{ ovn_db_dir }}/ovnsb_db.db" - -# Region / init. -spinifex_region: ap-southeast-2 -spinifex_az: "{{ spinifex_region }}a" -spinifex_node_name: node1 -spinifex_node_count: 1 - -# External network. -# spx admin init contract (as of network-layer-redesign): -# external_mode : "pool" or "" (NAT path removed) -# external_pool : MANDATORY when mode=pool — set start/end below or pass -e. -# external_gw : auto-detected from default route when blank. -# external_prefix: auto-detected from WAN when blank. -# external_gw_ip : OVN router external-IP override (was nat_gateway_ip). -# no_external : true → emit --no-external (skip external networking). -spinifex_external_mode: pool -spinifex_external_no_external: false -spinifex_external_pool_start: "" -spinifex_external_pool_end: "" -spinifex_external_gateway: "" -spinifex_external_prefix_len: "" -spinifex_external_gateway_ip: "" - -# Preflight checks. -spinifex_ports: - - { port: 4222, service: NATS } - - { port: 8443, service: Predastore } - - { port: 9999, service: "Spinifex Gateway" } - -spinifex_required_commands: - - go - - make - - nbdkit -spinifex_optional_commands: - - air -spinifex_ovn_commands: - - ovs-vsctl - - ovn-controller - - ovn-nbctl - -spinifex_components: - - viperblock - - predastore - -# Process patterns for teardown. -# Bracket trick ([b]in/spx etc.) prevents the pattern literal from matching -# our own pgrep/shell cmdline. Exclude filter drops benign log followers and -# ansible's own wrappers that also mention these service names. -spinifex_process_pattern: "([b]in/spx|spinifex-[u]i|nats-[s]erver|[p]redastore|[v]iperblock|[v]pcd)" -spinifex_process_exclude: "(journalctl|ansible|/bin/sh|pgrep|pkill|tail -[fF])" -spinifex_qemu_processes: - - qemu-system-x86_64 - - qemu-system-aarch64 - -# Invoking user (when run under sudo). -spinifex_invoking_user: "{{ lookup('env','SUDO_USER') | default(ansible_facts['user_id'], true) }}" - -# Opt-in wipes. -spinifex_wipe_ssh_keys: false -spinifex_wipe_aws_creds: false -spinifex_wipe_legacy_home: true - -# Timeouts. -teardown_process_wait_seconds: 30 - -# Path resolution — playbook_dir is scripts/ansible/playbooks/ at runtime. -spinifex_root: "{{ lookup('pipe', 'readlink -f ' ~ playbook_dir ~ '/../../..') }}" -mulga_root: "{{ lookup('pipe', 'readlink -f ' ~ playbook_dir ~ '/../../../..') }}" - -# Wrappers around `aws` and `spx` that re-enter a shell with the -# `spinifex` supplementary group active. Needed because ansible's -# `become_user` is a no-op when target user equals current user, so -# supplementary groups are never re-initialised and /etc/spinifex/ca.pem -# (drwxr-x--- root:spinifex) is unreadable. -spinifex_aws_cli: "{{ playbook_dir }}/../scripts/aws-as-spinifex.sh" -spinifex_spx_cli: "{{ playbook_dir }}/../scripts/spx-as-spinifex.sh" - -# dev-vpc fixture. Deterministic VPC + public subnet + IGW + default -# route. Idempotent: re-running detects existing resources by Name tag. -# Used by smoketest's launch path (which looks for any -# map-public-ip-on-launch=true subnet). -dev_vpc_name: spinifex-dev-vpc -dev_vpc_cidr: 10.99.0.0/16 -dev_vpc_subnet_cidr: 10.99.1.0/24 -dev_vpc_subnet_az: "{{ spinifex_az }}" -dev_vpc_state: present # present | absent - -# Build output. -build_tarball_path: /tmp/spinifex-local.tar.gz - -# Snapshot / restore. Snapshots quiesce the full spinifex+ovn+ovs stack, -# tar these paths, then restart services. Restore wipes + untars + restarts. -# Default snapshot dir is root-owned so it survives `dev-teardown` -# (teardown only removes the four spinifex_*_dir paths above). -snapshot_dir: /var/lib/spinifex-snapshots -snapshot_paths: - - "{{ spinifex_etc_dir }}" - - "{{ spinifex_data_dir }}" - - "{{ ovn_db_dir }}" - - /etc/openvswitch/conf.db -# Order matters: stop spinifex first (depends on OVN/OVS), then OVN, then OVS. -# Restart in reverse. -snapshot_services_stop_order: - - spinifex.target - - ovn-controller - - ovn-central - - openvswitch-switch - -# Smoketest image — parameterised so tofu examples can share the same base. -spinifex_smoketest_distro: debian -spinifex_smoketest_version: "13" -# Local image file path (if present, imported directly; otherwise fall back to --name). -spinifex_smoketest_local_image: "~/images/{{ spinifex_smoketest_distro }}-{{ spinifex_smoketest_version }}.img" - -# Multi-node cluster bootstrap (cluster-bootstrap.yml). -# cluster_env, cluster_init_host, spinifex_node_count come from inventory/tofu.py. -cluster_external_pool: "" # "-" or empty for DHCP fallback -cluster_join_token_path: /etc/spinifex/join-token -cluster_formation_port: 4432 -cluster_formation_timeout: 60 # seconds (uri retries = value // 2) From bfacca7789353b56df4d8cdb48a450e4236fea50 Mon Sep 17 00:00:00 2001 From: Josh Siviour Date: Thu, 4 Jun 2026 11:25:56 +1000 Subject: [PATCH 11/73] =?UTF-8?q?feat(eks):=206c=20token=20webhook=20+=20A?= =?UTF-8?q?ccessEntry=20(IAM=20auth=20=E2=86=92=20kubectl)=20(#284)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(eks): 6c AccessEntry CRUD + access-policy association Replace the nine notImpl() AccessEntry/AccessPolicy stubs with real KV-backed handlers (Q9, API auth mode): - AccessEntry CRUD persisted at clusters/{name}/access-entries/{hash}; the principal ARN is hashed into the key (ARNs carry ':', illegal in NATS KV keys) while the record keeps the plaintext ARN. - AssociateAccessPolicy/Disassociate/ListAssociated against the four supported AWS-managed policies; unsupported policy ARN or bad access scope -> InvalidParameterValue. - ListAccessPolicies returns the static supported catalogue. - Cluster-existence gate -> ResourceNotFoundException; duplicate create -> ResourceInUseException; node-type entries rejected until 6d. Updates the daemon routing test for the now-implemented handlers. * feat(eks): plumb caller principal ARN + bootstrap-creator-admin Thread the caller's resolved IAM principal ARN from the gateway to the EKS control plane via a new X-Principal-ARN NATS header, so CreateCluster can mint the bootstrapClusterCreatorAdminPermissions AccessEntry (Q9): - utils.NATSRequest takes optional extra headers; PrincipalARNHeader + PrincipalARNFromMsg added. - Gateway resolves the caller ARN best-effort (buildCallerARN) and passes it down the EKS route table; only CreateCluster consumes it. - CreateCluster signature gains callerPrincipalARN; default-true bootstrap flag mints a system:masters entry keyed by the caller's exact ARN (the token webhook resolves the same ARN from STS). '' degrades gracefully. - Dedicated daemon handler reads both headers. * feat(eks): IAM token webhook + STS verify-over-NATS + apiserver wiring The eks-token-webhook (baked into the eks-server AMI) authenticates kubectl requests that present an `aws eks get-token` bearer token: decode the presigned STS GetCallerIdentity URL, verify it, resolve the principal ARN to its cluster AccessEntry, and answer the apiserver TokenReview with the mapped username + groups. STS is hosted in-process in the awsgw service and is not otherwise on the bus, so awsgw now serves an `eks.VerifyToken` NATS subject that wraps VerifyPresignedGetCallerIdentity (the cluster name is forwarded so STS enforces the x-k8s-aws-id anti-replay pin). The webhook reads the AccessEntry KV directly over its own NATS connection. Apiserver wiring: the k3s config skeleton sets authentication-token-webhook-config-file; the webhook writes its own self-signed serving cert + the apiserver kubeconfig at startup (ordered `before k3s`, with a bounded wait in the k3s start_pre so the apiserver never loads a missing file). * fix(eks): omit empty spec from token webhook TokenReview response * fix(sts): presigned GetCallerIdentity must hash empty body, not UNSIGNED-PAYLOAD VerifyPresignedGetCallerIdentity built the SigV4 canonical request with "UNSIGNED-PAYLOAD" as the payload hash. That is an S3-only convention; botocore and the aws-sdk presign non-S3 requests (sts:GetCallerIdentity, the shape `aws eks get-token` produces) with the SHA256 of the empty string. Every real get-token therefore failed signature verification with InvalidIdentityToken, breaking the entire EKS IAM token-auth flow end to end. Use the empty-string SHA256. The existing hand-rolled presign tests masked the bug by signing with the same wrong constant; they now sign correctly, and a new test presigns with the real aws-sdk-go v4 signer (the same canonicalisation the CLI uses) so this can't regress silently. Verified live: a real `aws eks get-token --cluster-name dev1` now resolves to the caller principal over the awsgw eks.VerifyToken surface; an otherwise-valid token presented for a different cluster is still rejected (anti-replay intact). * fix(eks): match access-entry routes on escaped path so slashed principal ARNs resolve IAM principal ARNs (user/admin, role/foo) embed a '/' that the AWS CLI percent-encodes in the request path. The dispatcher matched r.URL.Path (decoded), so %2F became a literal '/' and split the ARN across the ([^/]+) capture, dropping every describe/update/delete-access-entry and associate/disassociate/list-access-policy call to InvalidActionException. Match r.URL.EscapedPath() so the encoded ARN stays one segment, then url.PathUnescape each captured param before it reaches the handler. * test(eks): unit-cover access-entry scope validation, AWS converters, store guards --- cmd/eks-token-webhook/cert.go | 137 ++++++++ cmd/eks-token-webhook/main.go | 253 +++++++++++++- cmd/eks-token-webhook/main_test.go | 123 +++++++ cmd/eks-token-webhook/tokenreview.go | 29 ++ .../images/eks-server/eks-token-webhook.initd | 21 +- scripts/images/eks-server/k3s.initd | 13 + scripts/images/eks-server/setup.sh | 15 +- spinifex/daemon/daemon_handlers.go | 22 ++ spinifex/daemon/daemon_handlers_eks.go | 2 +- spinifex/daemon/daemon_handlers_eks_test.go | 96 +++--- spinifex/gateway/eks.go | 123 ++++--- spinifex/gateway/eks/cluster.go | 8 +- spinifex/gateway/eks/wrappers_test.go | 6 +- spinifex/gateway/eks_test.go | 31 ++ spinifex/handlers/eks/access_entry.go | 263 +++++++++++++++ spinifex/handlers/eks/access_entry_test.go | 95 ++++++ spinifex/handlers/eks/create_cluster_test.go | 49 ++- spinifex/handlers/eks/service.go | 6 +- spinifex/handlers/eks/service_impl.go | 319 +++++++++++++++++- spinifex/handlers/eks/service_impl_test.go | 174 ++++++++-- spinifex/handlers/eks/service_nats.go | 5 +- spinifex/handlers/eks/store.go | 18 +- spinifex/handlers/eks/store_test.go | 2 +- spinifex/handlers/eks/token_webhook.go | 58 ++++ spinifex/handlers/eks/token_webhook_test.go | 44 +++ spinifex/handlers/eks/types.go | 33 +- spinifex/handlers/sts/presigned_url_verify.go | 10 +- .../handlers/sts/presigned_url_verify_test.go | 42 ++- spinifex/services/awsgw/awsgw.go | 13 + spinifex/services/awsgw/eks_token_verify.go | 76 +++++ .../services/awsgw/eks_token_verify_test.go | 79 +++++ spinifex/utils/nats.go | 31 +- 32 files changed, 2019 insertions(+), 177 deletions(-) create mode 100644 cmd/eks-token-webhook/cert.go create mode 100644 cmd/eks-token-webhook/main_test.go create mode 100644 cmd/eks-token-webhook/tokenreview.go create mode 100644 spinifex/handlers/eks/access_entry.go create mode 100644 spinifex/handlers/eks/access_entry_test.go create mode 100644 spinifex/handlers/eks/token_webhook.go create mode 100644 spinifex/handlers/eks/token_webhook_test.go create mode 100644 spinifex/services/awsgw/eks_token_verify.go create mode 100644 spinifex/services/awsgw/eks_token_verify_test.go diff --git a/cmd/eks-token-webhook/cert.go b/cmd/eks-token-webhook/cert.go new file mode 100644 index 000000000..3a4763197 --- /dev/null +++ b/cmd/eks-token-webhook/cert.go @@ -0,0 +1,137 @@ +package main + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/base64" + "encoding/pem" + "fmt" + "math/big" + "net" + "os" + "time" + + "github.com/mulgadc/spinifex/internal/tlsconfig" +) + +// tlsCertificate is the webhook's loopback serving certificate. +type tlsCertificate struct { + cert tls.Certificate +} + +func (c tlsCertificate) serverTLSConfig() *tls.Config { + return &tls.Config{ + Certificates: []tls.Certificate{c.cert}, + MinVersion: tls.VersionTLS13, + CurvePreferences: tlsconfig.Curves, + } +} + +// ensureServingCert loads the persisted self-signed serving cert/key, or mints +// a fresh ECDSA-P256 pair (SAN 127.0.0.1 / localhost) and persists it. Reusing +// across restarts keeps the CA the apiserver loaded into its webhook kubeconfig +// valid even if the webhook process is restarted. Returns the parsed cert and +// the certificate PEM (for embedding as the kubeconfig CA bundle). +func ensureServingCert(certPath, keyPath string) (tlsCertificate, []byte, error) { + if certPEM, keyPEM, ok := readCertPair(certPath, keyPath); ok { + cert, err := tls.X509KeyPair(certPEM, keyPEM) + if err == nil { + return tlsCertificate{cert: cert}, certPEM, nil + } + // Fall through to regenerate on a corrupt/incompatible persisted pair. + } + + certPEM, keyPEM, err := generateSelfSigned() + if err != nil { + return tlsCertificate{}, nil, err + } + if err := os.WriteFile(certPath, certPEM, 0o644); err != nil { + return tlsCertificate{}, nil, fmt.Errorf("write cert %s: %w", certPath, err) + } + if err := os.WriteFile(keyPath, keyPEM, 0o600); err != nil { + return tlsCertificate{}, nil, fmt.Errorf("write key %s: %w", keyPath, err) + } + cert, err := tls.X509KeyPair(certPEM, keyPEM) + if err != nil { + return tlsCertificate{}, nil, fmt.Errorf("parse minted keypair: %w", err) + } + return tlsCertificate{cert: cert}, certPEM, nil +} + +func readCertPair(certPath, keyPath string) (certPEM, keyPEM []byte, ok bool) { + c, err := os.ReadFile(certPath) + if err != nil { + return nil, nil, false + } + k, err := os.ReadFile(keyPath) + if err != nil { + return nil, nil, false + } + return c, k, true +} + +func generateSelfSigned() (certPEM, keyPEM []byte, err error) { + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return nil, nil, fmt.Errorf("generate key: %w", err) + } + serial, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) + if err != nil { + return nil, nil, fmt.Errorf("serial: %w", err) + } + now := time.Now().UTC() + tmpl := x509.Certificate{ + SerialNumber: serial, + Subject: pkix.Name{CommonName: "eks-token-webhook"}, + NotBefore: now.Add(-time.Hour), + NotAfter: now.AddDate(10, 0, 0), + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + IsCA: true, + IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback}, + DNSNames: []string{"localhost"}, + } + der, err := x509.CreateCertificate(rand.Reader, &tmpl, &tmpl, &priv.PublicKey, priv) + if err != nil { + return nil, nil, fmt.Errorf("create cert: %w", err) + } + keyDER, err := x509.MarshalECPrivateKey(priv) + if err != nil { + return nil, nil, fmt.Errorf("marshal key: %w", err) + } + certPEM = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der}) + keyPEM = pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: keyDER}) + return certPEM, keyPEM, nil +} + +// writeAPIServerKubeconfig writes the kubeconfig kube-apiserver loads via +// --authentication-token-webhook-config-file. It points the apiserver at the +// loopback webhook and trusts its self-signed serving cert as the CA bundle. +func writeAPIServerKubeconfig(path, addr string, certPEM []byte) error { + caB64 := base64.StdEncoding.EncodeToString(certPEM) + kubeconfig := fmt.Sprintf(`apiVersion: v1 +kind: Config +clusters: +- name: mulga-eks-token-webhook + cluster: + certificate-authority-data: %s + server: https://%s/authenticate +users: +- name: kube-apiserver +contexts: +- name: webhook + context: + cluster: mulga-eks-token-webhook + user: kube-apiserver +current-context: webhook +`, caB64, addr) + if err := os.WriteFile(path, []byte(kubeconfig), 0o600); err != nil { + return fmt.Errorf("write %s: %w", path, err) + } + return nil +} diff --git a/cmd/eks-token-webhook/main.go b/cmd/eks-token-webhook/main.go index b2b28ba55..5457d8c9c 100644 --- a/cmd/eks-token-webhook/main.go +++ b/cmd/eks-token-webhook/main.go @@ -1,38 +1,257 @@ // eks-token-webhook is the K8s TokenReview webhook authenticator baked into // the eks-server AMI. It decodes the SigV4-presigned GetCallerIdentity URL -// produced by `aws eks get-token`, enforces the X-K8s-Aws-Id cross-cluster -// pin, calls Mulga STS over NATS, and resolves the principal to a TokenReview -// response via the cluster's AccessEntry KV. +// produced by `aws eks get-token`, calls Mulga STS over NATS (which enforces +// the x-k8s-aws-id cross-cluster pin against this cluster's name), and resolves +// the principal ARN to a TokenReview response via the cluster's AccessEntry KV. // -// This is a placeholder build that returns 503 Service Unavailable on every -// path. It exists so the eks-server AMI build succeeds (INSTALL_BINARIES is -// satisfied) and the K3s server VM boots cleanly. Real implementation lands -// with bead mulga-cs-eks-6c. +// It binds 127.0.0.1 only; the kube-apiserver is the sole client (loopback). +// On startup it writes the apiserver webhook kubeconfig (with its self-signed +// serving CA) so k3s can be pointed at it via +// --authentication-token-webhook-config-file. package main import ( + "encoding/json" + "errors" "flag" + "fmt" "log/slog" "net/http" "os" + "time" + + handlers_eks "github.com/mulgadc/spinifex/spinifex/handlers/eks" + "github.com/mulgadc/spinifex/spinifex/utils" + "github.com/nats-io/nats.go" ) +// config is the webhook's runtime configuration, sourced from the first-boot +// env (/etc/spinifex-eks/first-boot.env) cloud-init seeds onto the VM. +type config struct { + addr string + natsURL string + natsToken string + natsCA string + accountID string + clusterName string + certPath string + keyPath string + kubeconfig string + verifyTO time.Duration +} + +func loadConfig() (config, error) { + c := config{ + addr: flagAddr, + natsURL: os.Getenv("SPINIFEX_NATS_URL"), + natsToken: os.Getenv("SPINIFEX_NATS_TOKEN"), + natsCA: os.Getenv("SPINIFEX_NATS_CA"), + accountID: os.Getenv("EKS_ACCOUNT_ID"), + clusterName: os.Getenv("EKS_CLUSTER_NAME"), + certPath: envOr("EKS_WEBHOOK_CERT", "/etc/spinifex-eks/token-webhook.crt"), + keyPath: envOr("EKS_WEBHOOK_KEY", "/etc/spinifex-eks/token-webhook.key"), + kubeconfig: envOr("EKS_WEBHOOK_KUBECONFIG", "/etc/spinifex-eks/token-webhook.kubeconfig"), + verifyTO: 5 * time.Second, + } + if c.natsURL == "" { + return c, errors.New("SPINIFEX_NATS_URL not set") + } + if c.accountID == "" { + return c, errors.New("EKS_ACCOUNT_ID not set") + } + if c.clusterName == "" { + return c, errors.New("EKS_CLUSTER_NAME not set") + } + return c, nil +} + +func envOr(key, def string) string { + if v := os.Getenv(key); v != "" { + return v + } + return def +} + +var flagAddr string + func main() { - addr := flag.String("addr", "127.0.0.1:8443", "listen address") + flag.StringVar(&flagAddr, "addr", "127.0.0.1:8443", "listen address (loopback only)") flag.Parse() slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelInfo}))) - mux := http.NewServeMux() - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Retry-After", "30") - w.Header().Set("Content-Type", "application/json") - http.Error(w, `{"error":"eks-token-webhook stub: real implementation not yet deployed"}`, http.StatusServiceUnavailable) - }) + cfg, err := loadConfig() + if err != nil { + slog.Error("eks-token-webhook config error", "err", err) + os.Exit(1) + } - slog.Info("eks-token-webhook stub starting", "addr", *addr) - if err := http.ListenAndServe(*addr, mux); err != nil { - slog.Error("listen failed", "err", err) + if err := run(cfg); err != nil { + slog.Error("eks-token-webhook fatal", "err", err) os.Exit(1) } } + +func run(cfg config) error { + // Serving cert + apiserver kubeconfig. Persisted and reused across restarts + // so a webhook crash does not invalidate the CA the apiserver already loaded. + tlsCert, certPEM, err := ensureServingCert(cfg.certPath, cfg.keyPath) + if err != nil { + return fmt.Errorf("serving cert: %w", err) + } + if err := writeAPIServerKubeconfig(cfg.kubeconfig, cfg.addr, certPEM); err != nil { + return fmt.Errorf("write apiserver kubeconfig: %w", err) + } + + nc, err := utils.ConnectNATSWithRetry(cfg.natsURL, cfg.natsToken, cfg.natsCA) + if err != nil { + return fmt.Errorf("connect NATS: %w", err) + } + defer nc.Close() + + kv, err := openAccountKV(nc, cfg.accountID) + if err != nil { + return fmt.Errorf("open account KV: %w", err) + } + + authr := &authenticator{ + nc: nc, + kv: kv, + clusterName: cfg.clusterName, + verifyTO: cfg.verifyTO, + } + + mux := http.NewServeMux() + mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("ok")) + }) + mux.HandleFunc("/authenticate", authr.handle) + + server := newServer(cfg.addr, mux, tlsCert) + slog.Info("eks-token-webhook listening", "addr", cfg.addr, "cluster", cfg.clusterName) + if err := server.ListenAndServeTLS("", ""); err != nil && !errors.Is(err, http.ErrServerClosed) { + return fmt.Errorf("serve: %w", err) + } + return nil +} + +// openAccountKV attaches to the per-account EKS KV bucket. The bucket already +// exists by the time a control-plane VM is running (CreateCluster created it), +// but JetStream may briefly lag at boot, so retry a few times. +func openAccountKV(nc *nats.Conn, accountID string) (nats.KeyValue, error) { + js, err := nc.JetStream() + if err != nil { + return nil, fmt.Errorf("jetstream: %w", err) + } + bucket := handlers_eks.AccountBucketName(accountID) + var lastErr error + for range 30 { + kv, kvErr := js.KeyValue(bucket) + if kvErr == nil { + return kv, nil + } + lastErr = kvErr + time.Sleep(2 * time.Second) + } + return nil, fmt.Errorf("kv bucket %s not available: %w", bucket, lastErr) +} + +// authenticator resolves a TokenReview against STS (over NATS) + AccessEntry KV. +type authenticator struct { + nc *nats.Conn + kv nats.KeyValue + clusterName string + verifyTO time.Duration +} + +// verify resolves a presigned get-token URL into the caller principal via the +// awsgw-hosted STS verify subject, binding the signature to this cluster name. +func (a *authenticator) verify(presignedURL string) (*handlers_eks.TokenVerifyResponse, error) { + req := handlers_eks.TokenVerifyRequest{ + PresignedURL: presignedURL, + ClusterName: a.clusterName, + } + // accountID header is unused by the verify responder; pass empty. + return utils.NATSRequest[handlers_eks.TokenVerifyResponse]( + a.nc, handlers_eks.TokenVerifySubject, req, a.verifyTO, "") +} + +// lookup reads the AccessEntry for a principal ARN from the cluster KV. +func (a *authenticator) lookup(principalARN string) (*handlers_eks.AccessEntryRecord, error) { + return handlers_eks.GetAccessEntryRecord(a.kv, a.clusterName, principalARN) +} + +func (a *authenticator) handle(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + var review tokenReview + if err := json.NewDecoder(r.Body).Decode(&review); err != nil { + http.Error(w, "bad request", http.StatusBadRequest) + return + } + + status := authenticate(review.Spec.Token, a.verify, a.lookup) + + resp := tokenReview{ + APIVersion: "authentication.k8s.io/v1", + Kind: "TokenReview", + Status: status, + } + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(resp); err != nil { + slog.Error("encode TokenReview response", "err", err) + } +} + +// authenticate is the pure decision core: decode token → STS verify → KV +// AccessEntry lookup → TokenReview status. Any failure yields an unauthenticated +// status (never a 5xx) so a forged/unknown token is a clean K8s 401, not a +// webhook outage. verify and lookup are injected so the logic is unit-testable. +func authenticate( + token string, + verify func(presignedURL string) (*handlers_eks.TokenVerifyResponse, error), + lookup func(principalARN string) (*handlers_eks.AccessEntryRecord, error), +) tokenReviewStatus { + presignedURL, err := handlers_eks.DecodeGetToken(token) + if err != nil { + return tokenReviewStatus{Authenticated: false} + } + ident, err := verify(presignedURL) + if err != nil { + slog.Debug("token verify rejected", "err", err) + return tokenReviewStatus{Authenticated: false} + } + rec, err := lookup(ident.ARN) + if err != nil { + // No AccessEntry for an otherwise-valid IAM principal: authenticated to + // AWS, but not granted any K8s identity on this cluster. + slog.Debug("no access entry for principal", "arn", ident.ARN, "err", err) + return tokenReviewStatus{Authenticated: false} + } + uid := ident.UserID + if uid == "" { + uid = ident.ARN + } + return tokenReviewStatus{ + Authenticated: true, + User: userInfo{ + Username: rec.KubernetesUsername, + UID: uid, + Groups: rec.KubernetesGroups, + }, + } +} + +// newServer builds the loopback TLS server. Split out so tests can construct it +// without binding a port. +func newServer(addr string, handler http.Handler, cert tlsCertificate) *http.Server { + return &http.Server{ + Addr: addr, + Handler: handler, + ReadHeaderTimeout: 5 * time.Second, + TLSConfig: cert.serverTLSConfig(), + } +} diff --git a/cmd/eks-token-webhook/main_test.go b/cmd/eks-token-webhook/main_test.go new file mode 100644 index 000000000..8b35e5e64 --- /dev/null +++ b/cmd/eks-token-webhook/main_test.go @@ -0,0 +1,123 @@ +package main + +import ( + "encoding/base64" + "errors" + "os" + "path/filepath" + "testing" + + handlers_eks "github.com/mulgadc/spinifex/spinifex/handlers/eks" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func validToken(url string) string { + return "k8s-aws-v1." + base64.RawURLEncoding.EncodeToString([]byte(url)) +} + +const testARN = "arn:aws:iam::111122223333:role/admin" + +func okVerify(_ string) (*handlers_eks.TokenVerifyResponse, error) { + return &handlers_eks.TokenVerifyResponse{ + AccountID: "111122223333", + ARN: testARN, + UserID: "AROAEXAMPLE:session", + PrincipalType: "AssumedRole", + }, nil +} + +func TestAuthenticate_GrantsWhenEntryExists(t *testing.T) { + lookup := func(arn string) (*handlers_eks.AccessEntryRecord, error) { + assert.Equal(t, testARN, arn) + return &handlers_eks.AccessEntryRecord{ + KubernetesUsername: testARN, + KubernetesGroups: []string{"system:masters"}, + }, nil + } + + st := authenticate(validToken("https://sts.amazonaws.com/?Action=GetCallerIdentity"), okVerify, lookup) + + require.True(t, st.Authenticated) + assert.Equal(t, testARN, st.User.Username) + assert.Equal(t, "AROAEXAMPLE:session", st.User.UID) + assert.Equal(t, []string{"system:masters"}, st.User.Groups) +} + +func TestAuthenticate_DeniesMalformedToken(t *testing.T) { + called := false + verify := func(string) (*handlers_eks.TokenVerifyResponse, error) { called = true; return nil, nil } + lookup := func(string) (*handlers_eks.AccessEntryRecord, error) { return nil, nil } + + st := authenticate("not-a-k8s-aws-token", verify, lookup) + + assert.False(t, st.Authenticated) + assert.False(t, called, "must not call STS for a token that fails to decode") +} + +func TestAuthenticate_DeniesWhenVerifyFails(t *testing.T) { + verify := func(string) (*handlers_eks.TokenVerifyResponse, error) { + return nil, errors.New("signature mismatch") + } + lookup := func(string) (*handlers_eks.AccessEntryRecord, error) { + t.Fatal("lookup must not run when verify fails") + return nil, nil + } + + st := authenticate(validToken("https://sts/?x=1"), verify, lookup) + assert.False(t, st.Authenticated) +} + +func TestAuthenticate_DeniesWhenNoAccessEntry(t *testing.T) { + lookup := func(string) (*handlers_eks.AccessEntryRecord, error) { + return nil, handlers_eks.ErrAccessEntryNotFound + } + + st := authenticate(validToken("https://sts/?x=1"), okVerify, lookup) + assert.False(t, st.Authenticated) + assert.Empty(t, st.User.Username) +} + +func TestAuthenticate_FallsBackUIDToARN(t *testing.T) { + verify := func(string) (*handlers_eks.TokenVerifyResponse, error) { + return &handlers_eks.TokenVerifyResponse{ARN: testARN}, nil // no UserID + } + lookup := func(string) (*handlers_eks.AccessEntryRecord, error) { + return &handlers_eks.AccessEntryRecord{KubernetesUsername: testARN, KubernetesGroups: []string{"system:masters"}}, nil + } + + st := authenticate(validToken("https://sts/?x=1"), verify, lookup) + require.True(t, st.Authenticated) + assert.Equal(t, testARN, st.User.UID) +} + +func TestEnsureServingCert_PersistsAndReuses(t *testing.T) { + dir := t.TempDir() + certPath := filepath.Join(dir, "wh.crt") + keyPath := filepath.Join(dir, "wh.key") + + c1, pem1, err := ensureServingCert(certPath, keyPath) + require.NoError(t, err) + require.NotEmpty(t, pem1) + require.NotNil(t, c1.serverTLSConfig()) + + // Second call reuses the persisted pair (same cert bytes). + _, pem2, err := ensureServingCert(certPath, keyPath) + require.NoError(t, err) + assert.Equal(t, pem1, pem2) +} + +func TestWriteAPIServerKubeconfig(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "wh.kubeconfig") + certPEM := []byte("-----BEGIN CERTIFICATE-----\nMIIB\n-----END CERTIFICATE-----\n") + + require.NoError(t, writeAPIServerKubeconfig(path, "127.0.0.1:8443", certPEM)) + + data, err := os.ReadFile(path) + require.NoError(t, err) + body := string(data) + assert.Contains(t, body, "server: https://127.0.0.1:8443/authenticate") + assert.Contains(t, body, base64.StdEncoding.EncodeToString(certPEM)) + assert.Contains(t, body, "current-context: webhook") +} diff --git a/cmd/eks-token-webhook/tokenreview.go b/cmd/eks-token-webhook/tokenreview.go new file mode 100644 index 000000000..a3610f778 --- /dev/null +++ b/cmd/eks-token-webhook/tokenreview.go @@ -0,0 +1,29 @@ +package main + +// Minimal authentication.k8s.io/v1 TokenReview wire types. Hand-rolled to avoid +// pulling k8s.io/api into the spinifex module for these few fields; the shapes +// match what kube-apiserver sends and expects on the webhook contract. + +type tokenReview struct { + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Spec tokenReviewSpec `json:"spec,omitzero"` + Status tokenReviewStatus `json:"status"` +} + +type tokenReviewSpec struct { + Token string `json:"token"` + Audiences []string `json:"audiences,omitempty"` +} + +type tokenReviewStatus struct { + Authenticated bool `json:"authenticated"` + User userInfo `json:"user,omitzero"` + Error string `json:"error,omitempty"` +} + +type userInfo struct { + Username string `json:"username,omitempty"` + UID string `json:"uid,omitempty"` + Groups []string `json:"groups,omitempty"` +} diff --git a/scripts/images/eks-server/eks-token-webhook.initd b/scripts/images/eks-server/eks-token-webhook.initd index 9f18d2147..c6a752fd9 100644 --- a/scripts/images/eks-server/eks-token-webhook.initd +++ b/scripts/images/eks-server/eks-token-webhook.initd @@ -1,7 +1,10 @@ #!/sbin/openrc-run # eks-token-webhook — K8s TokenReview authenticator for IAM-backed kubectl. # Binds 127.0.0.1:8443 only; kube-apiserver is the sole client (loopback path). -# Stub binary returns 503 on every request until cs-eks-6c lands. +# Decodes `aws eks get-token` presigned URLs, verifies them via Mulga STS over +# NATS, and resolves the principal to a TokenReview via the cluster AccessEntry +# KV. Ordered `before k3s` so its apiserver kubeconfig exists before k3s reads +# --authentication-token-webhook-config-file. description="EKS Token Review webhook (Mulga)" command="/usr/local/bin/eks-token-webhook" @@ -11,7 +14,23 @@ pidfile="/run/eks-token-webhook.pid" output_log="/var/log/eks-token-webhook.log" error_log="/var/log/eks-token-webhook.log" +# NATS creds + cluster identity come from the cloud-init-seeded first-boot env. +# Sourced here and exported so start-stop-daemon hands them to the binary, which +# reads SPINIFEX_NATS_* / EKS_ACCOUNT_ID / EKS_CLUSTER_NAME from its environment. +if [ -f /etc/spinifex-eks/first-boot.env ]; then + # shellcheck disable=SC1091 + . /etc/spinifex-eks/first-boot.env + export SPINIFEX_NATS_URL SPINIFEX_NATS_TOKEN SPINIFEX_NATS_CA EKS_ACCOUNT_ID EKS_CLUSTER_NAME +fi + depend() { need net before k3s } + +start_pre() { + if [ ! -f /etc/spinifex-eks/first-boot.env ]; then + eerror "/etc/spinifex-eks/first-boot.env not present — cloud-init did not seed NATS creds" + return 1 + fi +} diff --git a/scripts/images/eks-server/k3s.initd b/scripts/images/eks-server/k3s.initd index 04ed37d3b..b48ea792e 100644 --- a/scripts/images/eks-server/k3s.initd +++ b/scripts/images/eks-server/k3s.initd @@ -33,4 +33,17 @@ start_pre() { return 1 fi fi + + # The apiserver is configured with --authentication-token-webhook-config-file + # pointing at the kubeconfig eks-token-webhook writes at startup. `before k3s` + # orders the webhook's start but it backgrounds, so wait (bounded) for the + # kubeconfig to land before letting the apiserver load a missing file. + i=0 + while [ ! -f /etc/spinifex-eks/token-webhook.kubeconfig ] && [ "${i}" -lt 30 ]; do + sleep 1 + i=$((i + 1)) + done + if [ ! -f /etc/spinifex-eks/token-webhook.kubeconfig ]; then + ewarn "eks-token-webhook kubeconfig absent after ${i}s; IAM token auth will be unavailable until the webhook starts" + fi } diff --git a/scripts/images/eks-server/setup.sh b/scripts/images/eks-server/setup.sh index c2a1a6be5..f47d4e02b 100644 --- a/scripts/images/eks-server/setup.sh +++ b/scripts/images/eks-server/setup.sh @@ -57,13 +57,13 @@ chmod 0755 /usr/local/sbin/k3s-first-boot chmod 0755 /etc/periodic/15min/mulga-eks-state-report chmod 0755 /etc/periodic/daily/mulga-eks-etcd-snapshot -# K3s server config — empty skeleton; cloud-init / first-boot fills in the +# K3s server config — skeleton; cloud-init / first-boot fills in the # per-cluster fields (cluster-cidr, service-cidr, token-file, etc). -# Webhook-token-auth is NOT wired in the skeleton: enabling it before the -# eks-token-webhook binary is the real implementation (currently a 503 stub, -# replaced by cs-eks-6c) would block /healthz from anonymous callers. The -# Sprint 6c orchestrator drops a webhook-config.yaml + restarts k3s once -# the binary is the real one. +# IAM token-auth is wired here via kube-apiserver-arg: the eks-token-webhook +# service (ordered `before k3s`) writes its kubeconfig to +# /etc/spinifex-eks/token-webhook.kubeconfig before the apiserver reads it. +# This only affects bearer-token requests; anonymous and client-cert paths +# (the first-boot /readyz probe uses the admin kubeconfig) are unaffected. mkdir -p /etc/rancher/k3s cat > /etc/rancher/k3s/config.yaml.skel <<'EOF' # Populated at first boot by cloud-init user-data via k3s-first-boot.sh. @@ -73,6 +73,9 @@ disable: - traefik - servicelb - local-storage +kube-apiserver-arg: + - "authentication-token-webhook-config-file=/etc/spinifex-eks/token-webhook.kubeconfig" + - "authentication-token-webhook-cache-ttl=5m" EOF # Sentinel file marker — k3s-first-boot self-disables after first success by diff --git a/spinifex/daemon/daemon_handlers.go b/spinifex/daemon/daemon_handlers.go index 2dd71a721..62be46a9d 100644 --- a/spinifex/daemon/daemon_handlers.go +++ b/spinifex/daemon/daemon_handlers.go @@ -58,6 +58,28 @@ func handleNATSRequest[I any, O any](msg *nats.Msg, serviceFn func(*I, string) ( respondWithJSON(msg, output) } +// handleNATSRequestWithPrincipal is handleNATSRequest for service methods that +// also need the caller's IAM principal ARN (X-Principal-ARN header) — e.g. EKS +// CreateCluster, which mints the bootstrap-creator-admin AccessEntry for the +// caller. +func handleNATSRequestWithPrincipal[I any, O any](msg *nats.Msg, serviceFn func(*I, string, string) (*O, error)) { + accountID := utils.AccountIDFromMsg(msg) + principalARN := utils.PrincipalARNFromMsg(msg) + input := new(I) + if errResp := utils.UnmarshalJsonPayload(input, msg.Data); errResp != nil { + if err := msg.Respond(errResp); err != nil { + slog.Error("Failed to respond to NATS request", "err", err) + } + return + } + output, err := serviceFn(input, accountID, principalARN) + if err != nil { + respondWithError(msg, awserrors.ValidErrorCode(err.Error())) + return + } + respondWithJSON(msg, output) +} + // handleEC2Events processes incoming EC2 instance events (start, stop, terminate, attach-volume) func (d *Daemon) handleEC2Events(msg *nats.Msg) { var command types.EC2InstanceCommand diff --git a/spinifex/daemon/daemon_handlers_eks.go b/spinifex/daemon/daemon_handlers_eks.go index 12147a168..ada154367 100644 --- a/spinifex/daemon/daemon_handlers_eks.go +++ b/spinifex/daemon/daemon_handlers_eks.go @@ -5,7 +5,7 @@ import "github.com/nats-io/nats.go" // --- Cluster --- func (d *Daemon) handleEKSCreateCluster(msg *nats.Msg) { - handleNATSRequest(msg, d.eksService.CreateCluster) + handleNATSRequestWithPrincipal(msg, d.eksService.CreateCluster) } func (d *Daemon) handleEKSDescribeCluster(msg *nats.Msg) { diff --git a/spinifex/daemon/daemon_handlers_eks_test.go b/spinifex/daemon/daemon_handlers_eks_test.go index 5d446bd2a..9c9623aa3 100644 --- a/spinifex/daemon/daemon_handlers_eks_test.go +++ b/spinifex/daemon/daemon_handlers_eks_test.go @@ -26,10 +26,10 @@ func setupEKSDaemon(t *testing.T) (*Daemon, *nats.Conn) { } // requestEKS publishes a request on the given subject and returns the response -// payload. The non-lifecycle EKS handlers all return NotImplemented so the -// payload always decodes to that error code; CreateCluster / DescribeCluster -// / ListClusters / DeleteCluster have real bodies and are covered by their -// own handlers/eks unit tests. +// payload. Proves a responder is wired for the subject and dispatched to the +// service. The expected Code per case is asserted by the caller; the empty `{}` +// body steers implemented handlers into a deterministic validation/dispatch +// error so the wiring is provable without a full orchestration graph. func requestEKS(t *testing.T, nc *nats.Conn, subject string) []byte { t.Helper() msg := nats.NewMsg(subject) @@ -40,53 +40,62 @@ func requestEKS(t *testing.T, nc *nats.Conn, subject string) []byte { return resp.Data } -func assertNotImpl(t *testing.T, payload []byte) { +// assertErrorCode decodes the error envelope and asserts the AWS error Code. +func assertErrorCode(t *testing.T, payload []byte, want string) { t.Helper() var env struct { Code *string `json:"Code"` } require.NoError(t, json.Unmarshal(payload, &env), "decode payload %q", payload) require.NotNil(t, env.Code, "payload %q has no Code field", payload) - assert.Equal(t, awserrors.ErrorNotImplemented, *env.Code) + assert.Equal(t, want, *env.Code) } func TestDaemonHandleEKS_AllHandlersDispatchToService(t *testing.T) { d, nc := setupEKSDaemon(t) + // wantCode is the error Code an empty-body request must elicit, proving the + // subject dispatched to its service method. Access-entry handlers are + // implemented (Sprint 6c): an empty body fails input/cluster validation with + // InvalidParameterValue. ListAccessPolicies returns the static catalogue with + // no error, so wantCode is "" (success — assert a non-error payload). + notImpl := awserrors.ErrorNotImplemented + invalid := awserrors.ErrorInvalidParameterValue cases := []struct { - subject string - handler nats.MsgHandler + subject string + handler nats.MsgHandler + wantCode string }{ - {"eks.UpdateClusterConfig", d.handleEKSUpdateClusterConfig}, - {"eks.UpdateClusterVersion", d.handleEKSUpdateClusterVersion}, - {"eks.CreateNodegroup", d.handleEKSCreateNodegroup}, - {"eks.DescribeNodegroup", d.handleEKSDescribeNodegroup}, - {"eks.ListNodegroups", d.handleEKSListNodegroups}, - {"eks.UpdateNodegroupConfig", d.handleEKSUpdateNodegroupConfig}, - {"eks.UpdateNodegroupVersion", d.handleEKSUpdateNodegroupVersion}, - {"eks.DeleteNodegroup", d.handleEKSDeleteNodegroup}, - {"eks.CreateAccessEntry", d.handleEKSCreateAccessEntry}, - {"eks.DescribeAccessEntry", d.handleEKSDescribeAccessEntry}, - {"eks.ListAccessEntries", d.handleEKSListAccessEntries}, - {"eks.UpdateAccessEntry", d.handleEKSUpdateAccessEntry}, - {"eks.DeleteAccessEntry", d.handleEKSDeleteAccessEntry}, - {"eks.AssociateAccessPolicy", d.handleEKSAssociateAccessPolicy}, - {"eks.DisassociateAccessPolicy", d.handleEKSDisassociateAccessPolicy}, - {"eks.ListAssociatedAccessPolicies", d.handleEKSListAssociatedAccessPolicies}, - {"eks.ListAccessPolicies", d.handleEKSListAccessPolicies}, - {"eks.ListAddons", d.handleEKSListAddons}, - {"eks.DescribeAddonVersions", d.handleEKSDescribeAddonVersions}, - {"eks.CreateAddon", d.handleEKSCreateAddon}, - {"eks.DeleteAddon", d.handleEKSDeleteAddon}, - {"eks.DescribeAddon", d.handleEKSDescribeAddon}, - {"eks.UpdateAddon", d.handleEKSUpdateAddon}, - {"eks.AssociateIdentityProviderConfig", d.handleEKSAssociateIdentityProviderConfig}, - {"eks.DescribeIdentityProviderConfig", d.handleEKSDescribeIdentityProviderConfig}, - {"eks.ListIdentityProviderConfigs", d.handleEKSListIdentityProviderConfigs}, - {"eks.DisassociateIdentityProviderConfig", d.handleEKSDisassociateIdentityProviderConfig}, - {"eks.TagResource", d.handleEKSTagResource}, - {"eks.UntagResource", d.handleEKSUntagResource}, - {"eks.ListTagsForResource", d.handleEKSListTagsForResource}, + {"eks.UpdateClusterConfig", d.handleEKSUpdateClusterConfig, notImpl}, + {"eks.UpdateClusterVersion", d.handleEKSUpdateClusterVersion, notImpl}, + {"eks.CreateNodegroup", d.handleEKSCreateNodegroup, notImpl}, + {"eks.DescribeNodegroup", d.handleEKSDescribeNodegroup, notImpl}, + {"eks.ListNodegroups", d.handleEKSListNodegroups, notImpl}, + {"eks.UpdateNodegroupConfig", d.handleEKSUpdateNodegroupConfig, notImpl}, + {"eks.UpdateNodegroupVersion", d.handleEKSUpdateNodegroupVersion, notImpl}, + {"eks.DeleteNodegroup", d.handleEKSDeleteNodegroup, notImpl}, + {"eks.CreateAccessEntry", d.handleEKSCreateAccessEntry, invalid}, + {"eks.DescribeAccessEntry", d.handleEKSDescribeAccessEntry, invalid}, + {"eks.ListAccessEntries", d.handleEKSListAccessEntries, invalid}, + {"eks.UpdateAccessEntry", d.handleEKSUpdateAccessEntry, invalid}, + {"eks.DeleteAccessEntry", d.handleEKSDeleteAccessEntry, invalid}, + {"eks.AssociateAccessPolicy", d.handleEKSAssociateAccessPolicy, invalid}, + {"eks.DisassociateAccessPolicy", d.handleEKSDisassociateAccessPolicy, invalid}, + {"eks.ListAssociatedAccessPolicies", d.handleEKSListAssociatedAccessPolicies, invalid}, + {"eks.ListAccessPolicies", d.handleEKSListAccessPolicies, ""}, + {"eks.ListAddons", d.handleEKSListAddons, notImpl}, + {"eks.DescribeAddonVersions", d.handleEKSDescribeAddonVersions, notImpl}, + {"eks.CreateAddon", d.handleEKSCreateAddon, notImpl}, + {"eks.DeleteAddon", d.handleEKSDeleteAddon, notImpl}, + {"eks.DescribeAddon", d.handleEKSDescribeAddon, notImpl}, + {"eks.UpdateAddon", d.handleEKSUpdateAddon, notImpl}, + {"eks.AssociateIdentityProviderConfig", d.handleEKSAssociateIdentityProviderConfig, notImpl}, + {"eks.DescribeIdentityProviderConfig", d.handleEKSDescribeIdentityProviderConfig, notImpl}, + {"eks.ListIdentityProviderConfigs", d.handleEKSListIdentityProviderConfigs, notImpl}, + {"eks.DisassociateIdentityProviderConfig", d.handleEKSDisassociateIdentityProviderConfig, notImpl}, + {"eks.TagResource", d.handleEKSTagResource, notImpl}, + {"eks.UntagResource", d.handleEKSUntagResource, notImpl}, + {"eks.ListTagsForResource", d.handleEKSListTagsForResource, notImpl}, } require.Equal(t, 30, len(cases), "expected exactly one handler per non-lifecycle AWS EKS action") @@ -97,7 +106,16 @@ func TestDaemonHandleEKS_AllHandlersDispatchToService(t *testing.T) { t.Cleanup(func() { _ = sub.Unsubscribe() }) payload := requestEKS(t, nc, c.subject) - assertNotImpl(t, payload) + if c.wantCode == "" { + // Success payload: dispatch is proven by a decodable non-error body. + var env struct { + Code *string `json:"Code"` + } + require.NoError(t, json.Unmarshal(payload, &env), "decode payload %q", payload) + assert.Nil(t, env.Code, "expected success, got error %q", payload) + return + } + assertErrorCode(t, payload, c.wantCode) }) } } diff --git a/spinifex/gateway/eks.go b/spinifex/gateway/eks.go index 69a17751a..ce6ab2d9f 100644 --- a/spinifex/gateway/eks.go +++ b/spinifex/gateway/eks.go @@ -5,6 +5,7 @@ import ( "io" "log/slog" "net/http" + "net/url" "regexp" "github.com/mulgadc/spinifex/spinifex/awserrors" @@ -30,10 +31,12 @@ type eksRoute struct { // eksRouteHandler invokes the per-action gateway function. It receives the // path-capture values in declaration order, the request body, the parent -// gateway config (NATS conn + ServiceURL), and the caller's accountID. It -// returns the response payload object (already a typed *eks.Output) or an -// error whose Error() is an awserrors code. -type eksRouteHandler func(gw *GatewayConfig, accountID string, params []string, body []byte) (any, error) +// gateway config (NATS conn + ServiceURL), the caller's accountID, and the +// caller's resolved IAM principal ARN (used by CreateCluster for the +// bootstrap-creator-admin AccessEntry; ignored by the rest). It returns the +// response payload object (already a typed *eks.Output) or an error whose +// Error() is an awserrors code. +type eksRouteHandler func(gw *GatewayConfig, accountID, callerARN string, params []string, body []byte) (any, error) // eksRoutes is the dispatch table. Order matters: more-specific paths must // come before less-specific ones with the same prefix (e.g. the @@ -42,127 +45,127 @@ type eksRouteHandler func(gw *GatewayConfig, accountID string, params []string, var eksRoutes = []eksRoute{ // Cluster {"POST", regexp.MustCompile(`^/clusters$`), "CreateCluster", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { - return gateway_eks.CreateCluster(gw.NATSConn, acct, b) + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { + return gateway_eks.CreateCluster(gw.NATSConn, acct, callerARN, b) }}, {"GET", regexp.MustCompile(`^/clusters$`), "ListClusters", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.ListClusters(gw.NATSConn, acct) }}, {"POST", regexp.MustCompile(`^/clusters/([^/]+)/update-config$`), "UpdateClusterConfig", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.UpdateClusterConfig(gw.NATSConn, acct, p[0], b) }}, {"POST", regexp.MustCompile(`^/clusters/([^/]+)/update-version$`), "UpdateClusterVersion", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.UpdateClusterVersion(gw.NATSConn, acct, p[0], b) }}, // Nodegroup {"POST", regexp.MustCompile(`^/clusters/([^/]+)/node-groups$`), "CreateNodegroup", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.CreateNodegroup(gw.NATSConn, acct, p[0], b) }}, {"GET", regexp.MustCompile(`^/clusters/([^/]+)/node-groups$`), "ListNodegroups", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.ListNodegroups(gw.NATSConn, acct, p[0]) }}, {"POST", regexp.MustCompile(`^/clusters/([^/]+)/node-groups/([^/]+)/update-config$`), "UpdateNodegroupConfig", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.UpdateNodegroupConfig(gw.NATSConn, acct, p[0], p[1], b) }}, {"POST", regexp.MustCompile(`^/clusters/([^/]+)/node-groups/([^/]+)/update-version$`), "UpdateNodegroupVersion", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.UpdateNodegroupVersion(gw.NATSConn, acct, p[0], p[1], b) }}, {"GET", regexp.MustCompile(`^/clusters/([^/]+)/node-groups/([^/]+)$`), "DescribeNodegroup", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.DescribeNodegroup(gw.NATSConn, acct, p[0], p[1]) }}, {"DELETE", regexp.MustCompile(`^/clusters/([^/]+)/node-groups/([^/]+)$`), "DeleteNodegroup", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.DeleteNodegroup(gw.NATSConn, acct, p[0], p[1]) }}, // AccessEntry / AccessPolicy {"POST", regexp.MustCompile(`^/clusters/([^/]+)/access-entries$`), "CreateAccessEntry", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.CreateAccessEntry(gw.NATSConn, acct, p[0], b) }}, {"GET", regexp.MustCompile(`^/clusters/([^/]+)/access-entries$`), "ListAccessEntries", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.ListAccessEntries(gw.NATSConn, acct, p[0]) }}, {"POST", regexp.MustCompile(`^/clusters/([^/]+)/access-entries/([^/]+)/access-policies$`), "AssociateAccessPolicy", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.AssociateAccessPolicy(gw.NATSConn, acct, p[0], p[1], b) }}, {"DELETE", regexp.MustCompile(`^/clusters/([^/]+)/access-entries/([^/]+)/access-policies$`), "DisassociateAccessPolicy", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.DisassociateAccessPolicy(gw.NATSConn, acct, p[0], p[1], b) }}, {"GET", regexp.MustCompile(`^/clusters/([^/]+)/access-entries/([^/]+)/access-policies$`), "ListAssociatedAccessPolicies", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.ListAssociatedAccessPolicies(gw.NATSConn, acct, p[0], p[1]) }}, {"GET", regexp.MustCompile(`^/clusters/([^/]+)/access-entries/([^/]+)$`), "DescribeAccessEntry", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.DescribeAccessEntry(gw.NATSConn, acct, p[0], p[1]) }}, {"POST", regexp.MustCompile(`^/clusters/([^/]+)/access-entries/([^/]+)$`), "UpdateAccessEntry", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.UpdateAccessEntry(gw.NATSConn, acct, p[0], p[1], b) }}, {"DELETE", regexp.MustCompile(`^/clusters/([^/]+)/access-entries/([^/]+)$`), "DeleteAccessEntry", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.DeleteAccessEntry(gw.NATSConn, acct, p[0], p[1]) }}, {"GET", regexp.MustCompile(`^/access-policies$`), "ListAccessPolicies", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.ListAccessPolicies(gw.NATSConn, acct) }}, // Addons {"GET", regexp.MustCompile(`^/addons/supported-versions$`), "DescribeAddonVersions", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.DescribeAddonVersions(gw.NATSConn, acct) }}, {"GET", regexp.MustCompile(`^/addons$`), "ListAddons", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.ListAddons(gw.NATSConn, acct) }}, {"POST", regexp.MustCompile(`^/clusters/([^/]+)/addons$`), "CreateAddon", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.CreateAddon(gw.NATSConn, acct, p[0], b) }}, {"POST", regexp.MustCompile(`^/clusters/([^/]+)/addons/([^/]+)/update$`), "UpdateAddon", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.UpdateAddon(gw.NATSConn, acct, p[0], p[1], b) }}, {"GET", regexp.MustCompile(`^/clusters/([^/]+)/addons/([^/]+)$`), "DescribeAddon", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.DescribeAddon(gw.NATSConn, acct, p[0], p[1]) }}, {"DELETE", regexp.MustCompile(`^/clusters/([^/]+)/addons/([^/]+)$`), "DeleteAddon", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.DeleteAddon(gw.NATSConn, acct, p[0], p[1]) }}, // OIDC identity-provider configs {"POST", regexp.MustCompile(`^/clusters/([^/]+)/identity-provider-configs/associate$`), "AssociateIdentityProviderConfig", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.AssociateIdentityProviderConfig(gw.NATSConn, acct, p[0], b) }}, {"POST", regexp.MustCompile(`^/clusters/([^/]+)/identity-provider-configs/describe$`), "DescribeIdentityProviderConfig", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.DescribeIdentityProviderConfig(gw.NATSConn, acct, p[0], b) }}, {"POST", regexp.MustCompile(`^/clusters/([^/]+)/identity-provider-configs/disassociate$`), "DisassociateIdentityProviderConfig", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.DisassociateIdentityProviderConfig(gw.NATSConn, acct, p[0], b) }}, {"GET", regexp.MustCompile(`^/clusters/([^/]+)/identity-provider-configs$`), "ListIdentityProviderConfigs", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.ListIdentityProviderConfigs(gw.NATSConn, acct, p[0]) }}, @@ -170,25 +173,25 @@ var eksRoutes = []eksRoute{ // /clusters/{name}/... routes so the regexp matcher prefers the deeper // matches first when iterating in declaration order. {"GET", regexp.MustCompile(`^/clusters/([^/]+)$`), "DescribeCluster", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.DescribeCluster(gw.NATSConn, acct, p[0]) }}, {"DELETE", regexp.MustCompile(`^/clusters/([^/]+)$`), "DeleteCluster", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.DeleteCluster(gw.NATSConn, acct, p[0]) }}, // Tags {"POST", regexp.MustCompile(`^/tags/(.+)$`), "TagResource", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.TagResource(gw.NATSConn, acct, p[0], b) }}, {"DELETE", regexp.MustCompile(`^/tags/(.+)$`), "UntagResource", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.UntagResource(gw.NATSConn, acct, p[0], b) }}, {"GET", regexp.MustCompile(`^/tags/(.+)$`), "ListTagsForResource", - func(gw *GatewayConfig, acct string, p []string, b []byte) (any, error) { + func(gw *GatewayConfig, acct, callerARN string, p []string, b []byte) (any, error) { return gateway_eks.ListTagsForResource(gw.NATSConn, acct, p[0]) }}, } @@ -196,6 +199,12 @@ var eksRoutes = []eksRoute{ // lookupEKSAction walks eksRoutes in declaration order, returning the matched // route's action name + path params, or ("", nil, false) when nothing matches. // Used by EKS_Request and unit tests to verify routing. +// +// path must be the *escaped* request path (r.URL.EscapedPath()): IAM principal +// ARNs are passed as a path segment and the CLI percent-encodes the embedded +// `/` (`user%2Fadmin`). Matching the decoded path would split that ARN across +// the `([^/]+)` capture and no route would match. Captured params are +// PathUnescape'd here so handlers receive the real value. func lookupEKSAction(method, path string) (string, []string, eksRouteHandler, bool) { for _, route := range eksRoutes { if route.method != method { @@ -207,7 +216,15 @@ func lookupEKSAction(method, path string) (string, []string, eksRouteHandler, bo } var params []string if len(m) > 1 { - params = m[1:] + params = make([]string, 0, len(m)-1) + for _, raw := range m[1:] { + decoded, err := url.PathUnescape(raw) + if err != nil { + slog.Debug("EKS: bad percent-encoding in path param", "param", raw, "err", err) + decoded = raw + } + params = append(params, decoded) + } } return route.action, params, route.handler, true } @@ -220,7 +237,7 @@ func lookupEKSAction(method, path string) (string, []string, eksRouteHandler, bo // are returned as plain awserrors codes; the caller (gateway.Request) routes // them through the shared ErrorHandler, which now emits EKS REST-JSON. func (gw *GatewayConfig) EKS_Request(w http.ResponseWriter, r *http.Request) error { - action, params, handler, ok := lookupEKSAction(r.Method, r.URL.Path) + action, params, handler, ok := lookupEKSAction(r.Method, r.URL.EscapedPath()) if !ok { slog.Debug("EKS: no route for request", "method", r.Method, "path", r.URL.Path) return errors.New(awserrors.ErrorInvalidAction) @@ -246,7 +263,11 @@ func (gw *GatewayConfig) EKS_Request(w http.ResponseWriter, r *http.Request) err return errors.New(awserrors.ErrorInvalidParameterValue) } - output, err := handler(gw, accountID, params, body) + // Resolve the caller's IAM principal ARN best-effort; only CreateCluster + // consumes it (bootstrap-creator-admin) and it degrades gracefully to "". + callerARN := eksCallerPrincipalARN(r) + + output, err := handler(gw, accountID, callerARN, params, body) if err != nil { return err } @@ -254,3 +275,21 @@ func (gw *GatewayConfig) EKS_Request(w http.ResponseWriter, r *http.Request) err gateway_eks.WriteJSONResponse(w, output) return nil } + +// eksCallerPrincipalARN resolves the caller's IAM principal ARN from the SigV4 +// auth context, best-effort. Returns "" when the context is incomplete or the +// ARN can't be composed — CreateCluster then skips the creator-admin entry +// rather than failing the request. +func eksCallerPrincipalARN(r *http.Request) string { + ctx := r.Context() + accountID, _ := ctx.Value(ctxAccountID).(string) + identity, _ := ctx.Value(ctxIdentity).(string) + principalType, _ := ctx.Value(ctxPrincipalType).(string) + assumedRoleARN, _ := ctx.Value(ctxAssumedRoleARN).(string) + arn, err := buildCallerARN(accountID, identity, principalType, assumedRoleARN) + if err != nil { + slog.Debug("EKS_Request: could not resolve caller principal ARN", "err", err) + return "" + } + return arn +} diff --git a/spinifex/gateway/eks/cluster.go b/spinifex/gateway/eks/cluster.go index c4168a573..22ed19dcb 100644 --- a/spinifex/gateway/eks/cluster.go +++ b/spinifex/gateway/eks/cluster.go @@ -9,13 +9,15 @@ import ( "github.com/nats-io/nats.go" ) -// CreateCluster — POST /clusters -func CreateCluster(natsConn *nats.Conn, accountID string, body []byte) (*eks.CreateClusterOutput, error) { +// CreateCluster — POST /clusters. callerPrincipalARN is the resolved caller IAM +// principal ARN, plumbed through so the control plane can mint the +// bootstrap-creator-admin AccessEntry for the caller. +func CreateCluster(natsConn *nats.Conn, accountID, callerPrincipalARN string, body []byte) (*eks.CreateClusterOutput, error) { input := new(eks.CreateClusterInput) if err := unmarshalIfBody(body, input); err != nil { return nil, err } - return handlers_eks.NewNATSEKSService(natsConn).CreateCluster(input, accountID) + return handlers_eks.NewNATSEKSService(natsConn).CreateCluster(input, accountID, callerPrincipalARN) } // DescribeCluster — GET /clusters/{name} diff --git a/spinifex/gateway/eks/wrappers_test.go b/spinifex/gateway/eks/wrappers_test.go index a97405dc0..a012fd0b7 100644 --- a/spinifex/gateway/eks/wrappers_test.go +++ b/spinifex/gateway/eks/wrappers_test.go @@ -30,11 +30,11 @@ func TestGatewayWrappers_Cluster(t *testing.T) { _, nc := testutil.StartTestNATS(t) stubEKSResponder(t, nc) - out1, err := CreateCluster(nc, acct, []byte(`{"name":"alpha"}`)) + out1, err := CreateCluster(nc, acct, "arn:aws:iam::111122223333:role/dev", []byte(`{"name":"alpha"}`)) require.NoError(t, err) assert.NotNil(t, out1) - out2, err := CreateCluster(nc, acct, nil) + out2, err := CreateCluster(nc, acct, "", nil) require.NoError(t, err) assert.NotNil(t, out2) @@ -71,7 +71,7 @@ func TestGatewayWrappers_Cluster_BadJSON(t *testing.T) { _, nc := testutil.StartTestNATS(t) stubEKSResponder(t, nc) - _, err := CreateCluster(nc, acct, []byte(`{not-json`)) + _, err := CreateCluster(nc, acct, "", []byte(`{not-json`)) require.Error(t, err) _, err = UpdateClusterConfig(nc, acct, "alpha", []byte(`{not-json`)) require.Error(t, err) diff --git a/spinifex/gateway/eks_test.go b/spinifex/gateway/eks_test.go index 3398f218b..f581ae9d6 100644 --- a/spinifex/gateway/eks_test.go +++ b/spinifex/gateway/eks_test.go @@ -66,6 +66,37 @@ func TestLookupEKSAction_ResolvesKnownRoutes(t *testing.T) { } } +// IAM principal ARNs contain a `/` (`user/admin`) and a `:` which the AWS CLI +// percent-encodes in the request path. lookupEKSAction is fed r.URL.EscapedPath() +// so `%2F` stays a single `([^/]+)` segment; the captured param is then +// PathUnescape'd back to the real ARN before reaching the handler. +func TestLookupEKSAction_EncodedPrincipalARN(t *testing.T) { + const ( + arn = "arn:aws:iam::000000000001:user/admin" + escaped = "arn%3Aaws%3Aiam%3A%3A000000000001%3Auser%2Fadmin" + ) + cases := []struct { + method, path string + wantAction string + }{ + {"GET", "/clusters/alpha/access-entries/" + escaped, "DescribeAccessEntry"}, + {"POST", "/clusters/alpha/access-entries/" + escaped, "UpdateAccessEntry"}, + {"DELETE", "/clusters/alpha/access-entries/" + escaped, "DeleteAccessEntry"}, + {"POST", "/clusters/alpha/access-entries/" + escaped + "/access-policies", "AssociateAccessPolicy"}, + {"DELETE", "/clusters/alpha/access-entries/" + escaped + "/access-policies", "DisassociateAccessPolicy"}, + {"GET", "/clusters/alpha/access-entries/" + escaped + "/access-policies", "ListAssociatedAccessPolicies"}, + } + for _, tc := range cases { + t.Run(tc.method+"_"+tc.wantAction, func(t *testing.T) { + action, params, handler, ok := lookupEKSAction(tc.method, tc.path) + require.True(t, ok, "encoded ARN path should match: %s %s", tc.method, tc.path) + require.NotNil(t, handler) + assert.Equal(t, tc.wantAction, action) + assert.Equal(t, []string{"alpha", arn}, params) + }) + } +} + func TestLookupEKSAction_CoversAll34Actions(t *testing.T) { expected := map[string]bool{ "CreateCluster": false, diff --git a/spinifex/handlers/eks/access_entry.go b/spinifex/handlers/eks/access_entry.go new file mode 100644 index 000000000..736014afc --- /dev/null +++ b/spinifex/handlers/eks/access_entry.go @@ -0,0 +1,263 @@ +package handlers_eks + +import ( + "encoding/json" + "errors" + "fmt" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/eks" + "github.com/nats-io/nats.go" +) + +// Access-entry types (Q9). v1 supports STANDARD principals only; the node +// types (EC2_LINUX/EC2_WINDOWS/FARGATE_LINUX) are accepted by AWS but the +// nodegroup join path (Sprint 6d) handles node identity, so they are rejected +// here until that lands. +const ( + AccessEntryTypeStandard = "STANDARD" + + accessScopeCluster = "cluster" + accessScopeNamespace = "namespace" +) + +// Supported AWS-managed access policies (Q9). The map value is the K8s +// ClusterRole the policy maps onto; the token webhook + RBAC bindings consume +// it. Any policy ARN outside this set is rejected with InvalidParameterValue. +var supportedAccessPolicies = map[string]string{ + "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy": "cluster-admin", + "arn:aws:eks::aws:cluster-access-policy/AmazonEKSAdminPolicy": "admin", + "arn:aws:eks::aws:cluster-access-policy/AmazonEKSEditPolicy": "edit", + "arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy": "view", +} + +// ErrAccessEntryNotFound is returned by GetAccessEntryRecord / the CAS helper +// when no entry exists for the principal. Callers translate to the AWS shape +// (ResourceNotFoundException) at the service boundary. +var ErrAccessEntryNotFound = errors.New("eks: access entry not found") + +// AccessEntryARN composes the access-entry ARN. AWS uses a per-entry UUID; this +// build keys the discriminator off the principal-ARN hash instead so the ARN is +// deterministic (no RNG) and one-per-principal — clients address access entries +// by principalArn, not by this ARN, so the divergence is informational only. +func AccessEntryARN(region, accountID, cluster, principalARN string) string { + return fmt.Sprintf("arn:aws:eks:%s:%s:access-entry/%s/%s", + region, accountID, cluster, PrincipalARNHash(principalARN)) +} + +// PutAccessEntryRecord writes the entry unconditionally. +func PutAccessEntryRecord(kv nats.KeyValue, rec *AccessEntryRecord) error { + if rec == nil { + return errors.New("eks: PutAccessEntryRecord nil record") + } + if rec.ClusterName == "" || rec.PrincipalARN == "" { + return errors.New("eks: PutAccessEntryRecord missing cluster or principal ARN") + } + data, err := json.Marshal(rec) + if err != nil { + return fmt.Errorf("marshal access entry %s: %w", rec.PrincipalARN, err) + } + key := AccessEntryKey(rec.ClusterName, rec.PrincipalARN) + if _, err := kv.Put(key, data); err != nil { + return fmt.Errorf("kv put %s: %w", key, err) + } + return nil +} + +// GetAccessEntryRecord reads one entry. Returns ErrAccessEntryNotFound if absent. +func GetAccessEntryRecord(kv nats.KeyValue, cluster, principalARN string) (*AccessEntryRecord, error) { + if cluster == "" || principalARN == "" { + return nil, errors.New("eks: GetAccessEntryRecord empty cluster or principal ARN") + } + entry, err := kv.Get(AccessEntryKey(cluster, principalARN)) + if err != nil { + if errors.Is(err, nats.ErrKeyNotFound) { + return nil, ErrAccessEntryNotFound + } + return nil, fmt.Errorf("kv get access entry: %w", err) + } + var rec AccessEntryRecord + if err := json.Unmarshal(entry.Value(), &rec); err != nil { + return nil, fmt.Errorf("unmarshal access entry %s: %w", principalARN, err) + } + return &rec, nil +} + +// ListAccessEntryRecords returns every access entry under a cluster, sorted by +// principal ARN for stable output. +func ListAccessEntryRecords(kv nats.KeyValue, cluster string) ([]*AccessEntryRecord, error) { + if cluster == "" { + return nil, errors.New("eks: ListAccessEntryRecords empty cluster") + } + keys, err := kv.Keys() + if err != nil { + if errors.Is(err, nats.ErrNoKeysFound) { + return nil, nil + } + return nil, fmt.Errorf("kv keys: %w", err) + } + prefix := AccessEntriesPrefix(cluster) + out := make([]*AccessEntryRecord, 0) + for _, k := range keys { + if !strings.HasPrefix(k, prefix) { + continue + } + entry, err := kv.Get(k) + if err != nil { + if errors.Is(err, nats.ErrKeyNotFound) { + continue + } + return nil, fmt.Errorf("kv get %s: %w", k, err) + } + var rec AccessEntryRecord + if err := json.Unmarshal(entry.Value(), &rec); err != nil { + return nil, fmt.Errorf("unmarshal access entry %s: %w", k, err) + } + out = append(out, &rec) + } + sortAccessEntries(out) + return out, nil +} + +// DeleteAccessEntryRecord removes one entry. Returns ErrAccessEntryNotFound if +// it did not exist so DeleteAccessEntry can surface ResourceNotFoundException. +func DeleteAccessEntryRecord(kv nats.KeyValue, cluster, principalARN string) error { + key := AccessEntryKey(cluster, principalARN) + if _, err := kv.Get(key); err != nil { + if errors.Is(err, nats.ErrKeyNotFound) { + return ErrAccessEntryNotFound + } + return fmt.Errorf("kv get %s: %w", key, err) + } + if err := kv.Delete(key); err != nil { + return fmt.Errorf("kv delete %s: %w", key, err) + } + return nil +} + +// casUpdateAccessEntry does a revision-checked read-modify-write. mutate returns +// true if it changed a field. Returns ErrAccessEntryNotFound if absent. +func casUpdateAccessEntry(kv nats.KeyValue, cluster, principalARN string, mutate func(*AccessEntryRecord) bool) (*AccessEntryRecord, error) { + key := AccessEntryKey(cluster, principalARN) + for range maxClusterStateCASRetries { + entry, err := kv.Get(key) + if err != nil { + if errors.Is(err, nats.ErrKeyNotFound) { + return nil, ErrAccessEntryNotFound + } + return nil, fmt.Errorf("kv get %s: %w", key, err) + } + var rec AccessEntryRecord + if err := json.Unmarshal(entry.Value(), &rec); err != nil { + return nil, fmt.Errorf("unmarshal access entry %s: %w", principalARN, err) + } + if !mutate(&rec) { + return &rec, nil + } + data, err := json.Marshal(&rec) + if err != nil { + return nil, fmt.Errorf("marshal access entry %s: %w", principalARN, err) + } + _, err = kv.Update(key, data, entry.Revision()) + if err == nil { + return &rec, nil + } + if errors.Is(err, nats.ErrKeyExists) { + continue + } + return nil, fmt.Errorf("kv update %s: %w", key, err) + } + return nil, fmt.Errorf("eks: casUpdateAccessEntry %s exhausted CAS retries", principalARN) +} + +func sortAccessEntries(recs []*AccessEntryRecord) { + for i := 1; i < len(recs); i++ { + for j := i; j > 0 && recs[j-1].PrincipalARN > recs[j].PrincipalARN; j-- { + recs[j-1], recs[j] = recs[j], recs[j-1] + } + } +} + +// validateAccessScope checks an AccessScope per AWS rules: type ∈ +// {cluster, namespace}; namespace scope requires at least one namespace and +// cluster scope must not carry any. +func validateAccessScope(scope *eks.AccessScope) (AccessScope, error) { + if scope == nil || aws.StringValue(scope.Type) == "" { + return AccessScope{}, errors.New("eks: accessScope.type is required") + } + t := strings.ToLower(aws.StringValue(scope.Type)) + ns := aws.StringValueSlice(scope.Namespaces) + switch t { + case accessScopeCluster: + if len(ns) > 0 { + return AccessScope{}, errors.New("eks: cluster-scoped policy must not list namespaces") + } + return AccessScope{Type: accessScopeCluster}, nil + case accessScopeNamespace: + if len(ns) == 0 { + return AccessScope{}, errors.New("eks: namespace-scoped policy requires at least one namespace") + } + return AccessScope{Type: accessScopeNamespace, Namespaces: ns}, nil + default: + return AccessScope{}, fmt.Errorf("eks: unsupported accessScope.type %q", t) + } +} + +// accessEntryRecordToAWS converts the persisted record to the SDK shape. +func accessEntryRecordToAWS(rec *AccessEntryRecord) *eks.AccessEntry { + out := &eks.AccessEntry{ + AccessEntryArn: aws.String(rec.ARN), + ClusterName: aws.String(rec.ClusterName), + PrincipalArn: aws.String(rec.PrincipalARN), + Username: aws.String(rec.KubernetesUsername), + KubernetesGroups: aws.StringSlice(rec.KubernetesGroups), + Type: aws.String(rec.Type), + CreatedAt: aws.Time(rec.CreatedAt), + ModifiedAt: aws.Time(rec.ModifiedAt), + } + if len(rec.Tags) > 0 { + out.Tags = aws.StringMap(rec.Tags) + } + return out +} + +// associatedPolicyToAWS converts a persisted associated policy to the SDK shape. +func associatedPolicyToAWS(p AssociatedAccessPolicy) *eks.AssociatedAccessPolicy { + scope := &eks.AccessScope{Type: aws.String(p.AccessScope.Type)} + if len(p.AccessScope.Namespaces) > 0 { + scope.Namespaces = aws.StringSlice(p.AccessScope.Namespaces) + } + return &eks.AssociatedAccessPolicy{ + PolicyArn: aws.String(p.PolicyARN), + AccessScope: scope, + AssociatedAt: aws.Time(p.AssociatedAt), + ModifiedAt: aws.Time(p.ModifiedAt), + } +} + +// defaultKubernetesUsername mirrors AWS: when the caller omits username, EKS +// derives it from the principal ARN. +func defaultKubernetesUsername(principalARN string) string { + return principalARN +} + +// newAccessEntryRecord builds a record, defaulting the username to the +// principal ARN when unset (AWS behaviour). now stamps Created/Modified. +func newAccessEntryRecord(region, accountID, cluster, principalARN, username string, groups []string, entryType string, tags map[string]string, now time.Time) *AccessEntryRecord { + if username == "" { + username = defaultKubernetesUsername(principalARN) + } + return &AccessEntryRecord{ + ARN: AccessEntryARN(region, accountID, cluster, principalARN), + ClusterName: cluster, + PrincipalARN: principalARN, + KubernetesUsername: username, + KubernetesGroups: groups, + Type: entryType, + Tags: tags, + CreatedAt: now, + ModifiedAt: now, + } +} diff --git a/spinifex/handlers/eks/access_entry_test.go b/spinifex/handlers/eks/access_entry_test.go new file mode 100644 index 000000000..882609c28 --- /dev/null +++ b/spinifex/handlers/eks/access_entry_test.go @@ -0,0 +1,95 @@ +package handlers_eks + +import ( + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/eks" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestValidateAccessScope(t *testing.T) { + cases := []struct { + name string + scope *eks.AccessScope + want AccessScope + wantErr bool + }{ + {"nil scope", nil, AccessScope{}, true}, + {"empty type", &eks.AccessScope{}, AccessScope{}, true}, + {"cluster ok", &eks.AccessScope{Type: aws.String("cluster")}, AccessScope{Type: "cluster"}, false}, + {"cluster mixed case", &eks.AccessScope{Type: aws.String("Cluster")}, AccessScope{Type: "cluster"}, false}, + {"cluster with namespaces", &eks.AccessScope{Type: aws.String("cluster"), Namespaces: aws.StringSlice([]string{"kube-system"})}, AccessScope{}, true}, + {"namespace ok", &eks.AccessScope{Type: aws.String("namespace"), Namespaces: aws.StringSlice([]string{"team-a", "team-b"})}, AccessScope{Type: "namespace", Namespaces: []string{"team-a", "team-b"}}, false}, + {"namespace without namespaces", &eks.AccessScope{Type: aws.String("namespace")}, AccessScope{}, true}, + {"unsupported type", &eks.AccessScope{Type: aws.String("galaxy")}, AccessScope{}, true}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + got, err := validateAccessScope(tc.scope) + if tc.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, tc.want, got) + }) + } +} + +func TestAccessEntryRecordToAWS_IncludesTags(t *testing.T) { + now := time.Unix(1700000000, 0).UTC() + rec := &AccessEntryRecord{ + ARN: "arn:aws:eks:ap-southeast-2:000000000001:access-entry/dev1/abc", + ClusterName: "dev1", + PrincipalARN: "arn:aws:iam::000000000001:user/admin", + KubernetesUsername: "arn:aws:iam::000000000001:user/admin", + KubernetesGroups: []string{"system:masters"}, + Type: AccessEntryTypeStandard, + Tags: map[string]string{"team": "platform"}, + CreatedAt: now, + ModifiedAt: now, + } + out := accessEntryRecordToAWS(rec) + assert.Equal(t, "dev1", aws.StringValue(out.ClusterName)) + assert.Equal(t, rec.PrincipalARN, aws.StringValue(out.PrincipalArn)) + assert.Equal(t, []string{"system:masters"}, aws.StringValueSlice(out.KubernetesGroups)) + require.NotNil(t, out.Tags) + assert.Equal(t, "platform", aws.StringValue(out.Tags["team"])) +} + +func TestAssociatedPolicyToAWS_ScopeNamespaces(t *testing.T) { + now := time.Unix(1700000000, 0).UTC() + p := AssociatedAccessPolicy{ + PolicyARN: "arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy", + AccessScope: AccessScope{Type: "namespace", Namespaces: []string{"team-a"}}, + AssociatedAt: now, + ModifiedAt: now, + } + out := associatedPolicyToAWS(p) + assert.Equal(t, p.PolicyARN, aws.StringValue(out.PolicyArn)) + assert.Equal(t, "namespace", aws.StringValue(out.AccessScope.Type)) + assert.Equal(t, []string{"team-a"}, aws.StringValueSlice(out.AccessScope.Namespaces)) + + cluster := associatedPolicyToAWS(AssociatedAccessPolicy{ + PolicyARN: "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy", + AccessScope: AccessScope{Type: "cluster"}, + }) + assert.Equal(t, "cluster", aws.StringValue(cluster.AccessScope.Type)) + assert.Empty(t, cluster.AccessScope.Namespaces) +} + +// The record-store guard clauses reject malformed input before touching the KV, +// so a nil handle is enough to exercise them. +func TestAccessEntryRecordGuards(t *testing.T) { + require.Error(t, PutAccessEntryRecord(nil, nil)) + require.Error(t, PutAccessEntryRecord(nil, &AccessEntryRecord{PrincipalARN: "arn:aws:iam::000000000001:user/admin"})) + + _, err := GetAccessEntryRecord(nil, "", "arn:aws:iam::000000000001:user/admin") + require.Error(t, err) + + _, err = ListAccessEntryRecords(nil, "") + require.Error(t, err) +} diff --git a/spinifex/handlers/eks/create_cluster_test.go b/spinifex/handlers/eks/create_cluster_test.go index 084a2ec50..f283bb465 100644 --- a/spinifex/handlers/eks/create_cluster_test.go +++ b/spinifex/handlers/eks/create_cluster_test.go @@ -34,7 +34,7 @@ func TestCreateCluster_NLBArnPersistedBeforeLaterFailure(t *testing.T) { // NLB-arn persist checkpoint, but before the final PutClusterMeta. f.inst.launchErr = errors.New("no capacity") - _, err := f.svc.CreateCluster(createInput("alpha"), testAccountID) + _, err := f.svc.CreateCluster(createInput("alpha"), testAccountID, "") require.Error(t, err) meta, getErr := GetClusterMeta(f.kv, "alpha") @@ -50,7 +50,7 @@ func TestCreateCluster_FailedCreateThenDeleteReclaimsNLB(t *testing.T) { f := newEKSServiceFixture(t) f.inst.launchErr = errors.New("no capacity") - _, err := f.svc.CreateCluster(createInput("alpha"), testAccountID) + _, err := f.svc.CreateCluster(createInput("alpha"), testAccountID, "") require.Error(t, err) // The NLB the partial create provisioned exists in the fake. @@ -73,7 +73,7 @@ func TestCreateCluster_ExistingClusterReturnsResourceInUse(t *testing.T) { meta.Status = ClusterStatusActive require.NoError(t, PutClusterMeta(f.kv, meta)) - _, err := f.svc.CreateCluster(createInput("alpha"), testAccountID) + _, err := f.svc.CreateCluster(createInput("alpha"), testAccountID, "") require.EqualError(t, err, awserrors.ErrorEKSResourceInUse) } @@ -84,7 +84,7 @@ func TestCreateCluster_FailedClusterIsReclaimedOnRetry(t *testing.T) { // First attempt fails at VM launch, leaving a FAILED meta with NLB ARNs. f.inst.launchErr = errors.New("no capacity") - _, err := f.svc.CreateCluster(createInput("alpha"), testAccountID) + _, err := f.svc.CreateCluster(createInput("alpha"), testAccountID, "") require.Error(t, err) failed, err := GetClusterMeta(f.kv, "alpha") require.NoError(t, err) @@ -93,7 +93,7 @@ func TestCreateCluster_FailedClusterIsReclaimedOnRetry(t *testing.T) { // Retry now succeeds: the reclaim path purges the failed attempt's NLB and // the create starts clean. f.inst.launchErr = nil - _, err = f.svc.CreateCluster(createInput("alpha"), testAccountID) + _, err = f.svc.CreateCluster(createInput("alpha"), testAccountID, "") require.NoError(t, err) got, err := GetClusterMeta(f.kv, "alpha") @@ -161,7 +161,7 @@ func TestCreateCluster_MissingAMIReturnsServiceUnavailable(t *testing.T) { f := newEKSServiceFixture(t) f.ami.describeOut = &ec2.DescribeImagesOutput{} // no images tagged managed-by=eks - _, err := f.svc.CreateCluster(createInput("alpha"), testAccountID) + _, err := f.svc.CreateCluster(createInput("alpha"), testAccountID, "") require.EqualError(t, err, awserrors.ErrorServiceUnavailable) meta, getErr := GetClusterMeta(f.kv, "alpha") @@ -172,7 +172,7 @@ func TestCreateCluster_MissingAMIReturnsServiceUnavailable(t *testing.T) { func TestCreateCluster_HappyPathPersistsActiveCreatingMeta(t *testing.T) { f := newEKSServiceFixture(t) - out, err := f.svc.CreateCluster(createInput("alpha"), testAccountID) + out, err := f.svc.CreateCluster(createInput("alpha"), testAccountID, "") require.NoError(t, err) require.NotNil(t, out) @@ -184,10 +184,43 @@ func TestCreateCluster_HappyPathPersistsActiveCreatingMeta(t *testing.T) { assert.NotEmpty(t, meta.ControlPlaneENIID) } +// bootstrapClusterCreatorAdminPermissions defaults true: a successful create +// with a known caller principal ARN mints a system:masters AccessEntry for the +// caller, keyed by their exact ARN (the token webhook looks it up by the same). +func TestCreateCluster_SeedsCreatorAdminAccessEntry(t *testing.T) { + f := newEKSServiceFixture(t) + const caller = "arn:aws:iam::111122223333:role/admin" + + _, err := f.svc.CreateCluster(createInput("alpha"), testAccountID, caller) + require.NoError(t, err) + + rec, err := GetAccessEntryRecord(f.kv, "alpha", caller) + require.NoError(t, err) + assert.Equal(t, []string{"system:masters"}, rec.KubernetesGroups) + assert.Equal(t, caller, rec.KubernetesUsername) + assert.Equal(t, AccessEntryTypeStandard, rec.Type) +} + +// With the bootstrap flag explicitly false, no creator-admin entry is minted. +func TestCreateCluster_SkipsCreatorAdminWhenDisabled(t *testing.T) { + f := newEKSServiceFixture(t) + const caller = "arn:aws:iam::111122223333:role/admin" + in := createInput("alpha") + in.AccessConfig = &eks.CreateAccessConfigRequest{ + BootstrapClusterCreatorAdminPermissions: aws.Bool(false), + } + + _, err := f.svc.CreateCluster(in, testAccountID, caller) + require.NoError(t, err) + + _, err = GetAccessEntryRecord(f.kv, "alpha", caller) + assert.ErrorIs(t, err, ErrAccessEntryNotFound) +} + func TestCreateCluster_AllocatesHiddenEgressEIP(t *testing.T) { f := newEKSServiceFixture(t) - _, err := f.svc.CreateCluster(createInput("egress"), testAccountID) + _, err := f.svc.CreateCluster(createInput("egress"), testAccountID, "") require.NoError(t, err) meta, err := GetClusterMeta(f.kv, "egress") diff --git a/spinifex/handlers/eks/service.go b/spinifex/handlers/eks/service.go index 96f793e39..aaf17ede8 100644 --- a/spinifex/handlers/eks/service.go +++ b/spinifex/handlers/eks/service.go @@ -11,8 +11,10 @@ import "github.com/aws/aws-sdk-go/service/eks" // (PascalCase). Signatures use the aws-sdk-go input/output types verbatim so // downstream callers can pass straight through from generated SDK code. type EKSService interface { - // Cluster - CreateCluster(input *eks.CreateClusterInput, accountID string) (*eks.CreateClusterOutput, error) + // Cluster. CreateCluster also takes the caller's resolved IAM principal ARN + // (from the X-Principal-ARN header) so it can mint the bootstrap + // cluster-creator-admin AccessEntry; "" skips that step. + CreateCluster(input *eks.CreateClusterInput, accountID, callerPrincipalARN string) (*eks.CreateClusterOutput, error) DescribeCluster(input *eks.DescribeClusterInput, accountID string) (*eks.DescribeClusterOutput, error) ListClusters(input *eks.ListClustersInput, accountID string) (*eks.ListClustersOutput, error) UpdateClusterConfig(input *eks.UpdateClusterConfigInput, accountID string) (*eks.UpdateClusterConfigOutput, error) diff --git a/spinifex/handlers/eks/service_impl.go b/spinifex/handlers/eks/service_impl.go index d6e457c45..e490e5bfc 100644 --- a/spinifex/handlers/eks/service_impl.go +++ b/spinifex/handlers/eks/service_impl.go @@ -250,7 +250,7 @@ func (s *EKSServiceImpl) missingOrchestrationDeps() []string { // --- Cluster --- -func (s *EKSServiceImpl) CreateCluster(input *eks.CreateClusterInput, accountID string) (*eks.CreateClusterOutput, error) { +func (s *EKSServiceImpl) CreateCluster(input *eks.CreateClusterInput, accountID, callerPrincipalARN string) (*eks.CreateClusterOutput, error) { if err := s.requireOrchestrationDeps("CreateCluster"); err != nil { return nil, err } @@ -421,12 +421,37 @@ func (s *EKSServiceImpl) CreateCluster(input *eks.CreateClusterInput, accountID return nil, err } + // bootstrapClusterCreatorAdminPermissions (default true): grant the caller + // system:masters via an AccessEntry so the cluster creator can immediately + // authenticate through the token webhook (Q9). Keyed by the caller's exact + // principal ARN — the webhook looks the entry up by the same ARN STS returns. + if bootstrapCreatorAdmin(input) && callerPrincipalARN != "" { + rec := newAccessEntryRecord(region, accountID, name, callerPrincipalARN, "", + []string{"system:masters"}, AccessEntryTypeStandard, nil, time.Now().UTC()) + if err := PutAccessEntryRecord(acctKV, rec); err != nil { + s.markFailed(acctKV, name) + return nil, fmt.Errorf("seed cluster-creator admin access entry: %w", err) + } + } else if bootstrapCreatorAdmin(input) { + slog.Warn("CreateCluster: bootstrapClusterCreatorAdminPermissions set but caller principal ARN unknown; skipping creator-admin AccessEntry", + "cluster", name, "accountID", accountID) + } + s.spawnBootstrap(accountID, name, acctKV, nil) s.spawnReconciler(accountID, name, meta) return &eks.CreateClusterOutput{Cluster: clusterMetaToAWS(meta)}, nil } +// bootstrapCreatorAdmin reports whether the cluster-creator-admin AccessEntry +// should be minted. AWS defaults this to true when unspecified. +func bootstrapCreatorAdmin(input *eks.CreateClusterInput) bool { + if input.AccessConfig == nil || input.AccessConfig.BootstrapClusterCreatorAdminPermissions == nil { + return true + } + return *input.AccessConfig.BootstrapClusterCreatorAdminPermissions +} + // systemEgressEvent is the wire shape for vpc.add-system-egress / // vpc.delete-system-egress (mirrors network/subscribers.SystemEgressEvent; // kept local to avoid importing the network layer from a handler). @@ -674,40 +699,298 @@ func (s *EKSServiceImpl) DeleteNodegroup(_ *eks.DeleteNodegroupInput, _ string) // --- AccessEntry + AccessPolicy --- -func (s *EKSServiceImpl) CreateAccessEntry(_ *eks.CreateAccessEntryInput, _ string) (*eks.CreateAccessEntryOutput, error) { - return nil, notImpl() +// acctKVForCluster opens the per-account bucket and verifies the cluster exists, +// translating absence to the AWS ResourceNotFoundException shape. The +// AccessEntry handlers all need both. +func (s *EKSServiceImpl) acctKVForCluster(accountID, cluster string) (nats.KeyValue, error) { + if cluster == "" { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + js, err := s.deps.NATSConn.JetStream() + if err != nil { + return nil, fmt.Errorf("jetstream: %w", err) + } + acctKV, err := GetOrCreateAccountBucket(js, accountID) + if err != nil { + return nil, fmt.Errorf("get account bucket: %w", err) + } + if _, err := GetClusterMeta(acctKV, cluster); err != nil { + if errors.Is(err, ErrClusterNotFound) { + return nil, errors.New(awserrors.ErrorEKSResourceNotFound) + } + return nil, err + } + return acctKV, nil } -func (s *EKSServiceImpl) DescribeAccessEntry(_ *eks.DescribeAccessEntryInput, _ string) (*eks.DescribeAccessEntryOutput, error) { - return nil, notImpl() +func (s *EKSServiceImpl) CreateAccessEntry(input *eks.CreateAccessEntryInput, accountID string) (*eks.CreateAccessEntryOutput, error) { + if input == nil { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + cluster := aws.StringValue(input.ClusterName) + principalARN := aws.StringValue(input.PrincipalArn) + if principalARN == "" { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + entryType := aws.StringValue(input.Type) + if entryType == "" { + entryType = AccessEntryTypeStandard + } + if entryType != AccessEntryTypeStandard { + // Node-type entries (EC2_LINUX/etc.) need the nodegroup join path; reject + // until Sprint 6d wires them. + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + acctKV, err := s.acctKVForCluster(accountID, cluster) + if err != nil { + return nil, err + } + if _, err := GetAccessEntryRecord(acctKV, cluster, principalARN); err == nil { + return nil, errors.New(awserrors.ErrorEKSResourceInUse) + } else if !errors.Is(err, ErrAccessEntryNotFound) { + return nil, err + } + rec := newAccessEntryRecord(s.deps.Region, accountID, cluster, principalARN, + aws.StringValue(input.Username), aws.StringValueSlice(input.KubernetesGroups), + entryType, aws.StringValueMap(input.Tags), time.Now().UTC()) + if err := PutAccessEntryRecord(acctKV, rec); err != nil { + return nil, err + } + return &eks.CreateAccessEntryOutput{AccessEntry: accessEntryRecordToAWS(rec)}, nil } -func (s *EKSServiceImpl) ListAccessEntries(_ *eks.ListAccessEntriesInput, _ string) (*eks.ListAccessEntriesOutput, error) { - return nil, notImpl() +func (s *EKSServiceImpl) DescribeAccessEntry(input *eks.DescribeAccessEntryInput, accountID string) (*eks.DescribeAccessEntryOutput, error) { + if input == nil { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + cluster := aws.StringValue(input.ClusterName) + principalARN := aws.StringValue(input.PrincipalArn) + acctKV, err := s.acctKVForCluster(accountID, cluster) + if err != nil { + return nil, err + } + rec, err := GetAccessEntryRecord(acctKV, cluster, principalARN) + if err != nil { + if errors.Is(err, ErrAccessEntryNotFound) { + return nil, errors.New(awserrors.ErrorEKSResourceNotFound) + } + return nil, err + } + return &eks.DescribeAccessEntryOutput{AccessEntry: accessEntryRecordToAWS(rec)}, nil } -func (s *EKSServiceImpl) UpdateAccessEntry(_ *eks.UpdateAccessEntryInput, _ string) (*eks.UpdateAccessEntryOutput, error) { - return nil, notImpl() +func (s *EKSServiceImpl) ListAccessEntries(input *eks.ListAccessEntriesInput, accountID string) (*eks.ListAccessEntriesOutput, error) { + if input == nil { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + cluster := aws.StringValue(input.ClusterName) + acctKV, err := s.acctKVForCluster(accountID, cluster) + if err != nil { + return nil, err + } + recs, err := ListAccessEntryRecords(acctKV, cluster) + if err != nil { + return nil, err + } + filter := aws.StringValue(input.AssociatedPolicyArn) + arns := make([]string, 0, len(recs)) + for _, rec := range recs { + if filter != "" && !hasAssociatedPolicy(rec, filter) { + continue + } + arns = append(arns, rec.PrincipalARN) + } + return &eks.ListAccessEntriesOutput{AccessEntries: aws.StringSlice(arns)}, nil } -func (s *EKSServiceImpl) DeleteAccessEntry(_ *eks.DeleteAccessEntryInput, _ string) (*eks.DeleteAccessEntryOutput, error) { - return nil, notImpl() +func (s *EKSServiceImpl) UpdateAccessEntry(input *eks.UpdateAccessEntryInput, accountID string) (*eks.UpdateAccessEntryOutput, error) { + if input == nil { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + cluster := aws.StringValue(input.ClusterName) + principalARN := aws.StringValue(input.PrincipalArn) + acctKV, err := s.acctKVForCluster(accountID, cluster) + if err != nil { + return nil, err + } + now := time.Now().UTC() + rec, err := casUpdateAccessEntry(acctKV, cluster, principalARN, func(r *AccessEntryRecord) bool { + if input.KubernetesGroups != nil { + r.KubernetesGroups = aws.StringValueSlice(input.KubernetesGroups) + } + if u := aws.StringValue(input.Username); u != "" { + r.KubernetesUsername = u + } + r.ModifiedAt = now + return true + }) + if err != nil { + if errors.Is(err, ErrAccessEntryNotFound) { + return nil, errors.New(awserrors.ErrorEKSResourceNotFound) + } + return nil, err + } + return &eks.UpdateAccessEntryOutput{AccessEntry: accessEntryRecordToAWS(rec)}, nil } -func (s *EKSServiceImpl) AssociateAccessPolicy(_ *eks.AssociateAccessPolicyInput, _ string) (*eks.AssociateAccessPolicyOutput, error) { - return nil, notImpl() +func (s *EKSServiceImpl) DeleteAccessEntry(input *eks.DeleteAccessEntryInput, accountID string) (*eks.DeleteAccessEntryOutput, error) { + if input == nil { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + cluster := aws.StringValue(input.ClusterName) + principalARN := aws.StringValue(input.PrincipalArn) + acctKV, err := s.acctKVForCluster(accountID, cluster) + if err != nil { + return nil, err + } + if err := DeleteAccessEntryRecord(acctKV, cluster, principalARN); err != nil { + if errors.Is(err, ErrAccessEntryNotFound) { + return nil, errors.New(awserrors.ErrorEKSResourceNotFound) + } + return nil, err + } + return &eks.DeleteAccessEntryOutput{}, nil } -func (s *EKSServiceImpl) DisassociateAccessPolicy(_ *eks.DisassociateAccessPolicyInput, _ string) (*eks.DisassociateAccessPolicyOutput, error) { - return nil, notImpl() +func (s *EKSServiceImpl) AssociateAccessPolicy(input *eks.AssociateAccessPolicyInput, accountID string) (*eks.AssociateAccessPolicyOutput, error) { + if input == nil { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + cluster := aws.StringValue(input.ClusterName) + principalARN := aws.StringValue(input.PrincipalArn) + policyARN := aws.StringValue(input.PolicyArn) + if _, ok := supportedAccessPolicies[policyARN]; !ok { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + scope, err := validateAccessScope(input.AccessScope) + if err != nil { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + acctKV, err := s.acctKVForCluster(accountID, cluster) + if err != nil { + return nil, err + } + now := time.Now().UTC() + var assoc AssociatedAccessPolicy + _, err = casUpdateAccessEntry(acctKV, cluster, principalARN, func(r *AccessEntryRecord) bool { + assoc = AssociatedAccessPolicy{PolicyARN: policyARN, AccessScope: scope, AssociatedAt: now, ModifiedAt: now} + for i := range r.AssociatedPolicies { + if r.AssociatedPolicies[i].PolicyARN == policyARN { + assoc.AssociatedAt = r.AssociatedPolicies[i].AssociatedAt + r.AssociatedPolicies[i] = assoc + r.ModifiedAt = now + return true + } + } + r.AssociatedPolicies = append(r.AssociatedPolicies, assoc) + r.ModifiedAt = now + return true + }) + if err != nil { + if errors.Is(err, ErrAccessEntryNotFound) { + return nil, errors.New(awserrors.ErrorEKSResourceNotFound) + } + return nil, err + } + return &eks.AssociateAccessPolicyOutput{ + ClusterName: aws.String(cluster), + PrincipalArn: aws.String(principalARN), + AssociatedAccessPolicy: associatedPolicyToAWS(assoc), + }, nil } -func (s *EKSServiceImpl) ListAssociatedAccessPolicies(_ *eks.ListAssociatedAccessPoliciesInput, _ string) (*eks.ListAssociatedAccessPoliciesOutput, error) { - return nil, notImpl() +func (s *EKSServiceImpl) DisassociateAccessPolicy(input *eks.DisassociateAccessPolicyInput, accountID string) (*eks.DisassociateAccessPolicyOutput, error) { + if input == nil { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + cluster := aws.StringValue(input.ClusterName) + principalARN := aws.StringValue(input.PrincipalArn) + policyARN := aws.StringValue(input.PolicyArn) + acctKV, err := s.acctKVForCluster(accountID, cluster) + if err != nil { + return nil, err + } + now := time.Now().UTC() + _, err = casUpdateAccessEntry(acctKV, cluster, principalARN, func(r *AccessEntryRecord) bool { + for i := range r.AssociatedPolicies { + if r.AssociatedPolicies[i].PolicyARN == policyARN { + r.AssociatedPolicies = append(r.AssociatedPolicies[:i], r.AssociatedPolicies[i+1:]...) + r.ModifiedAt = now + return true + } + } + return false + }) + if err != nil { + if errors.Is(err, ErrAccessEntryNotFound) { + return nil, errors.New(awserrors.ErrorEKSResourceNotFound) + } + return nil, err + } + return &eks.DisassociateAccessPolicyOutput{}, nil +} + +func (s *EKSServiceImpl) ListAssociatedAccessPolicies(input *eks.ListAssociatedAccessPoliciesInput, accountID string) (*eks.ListAssociatedAccessPoliciesOutput, error) { + if input == nil { + return nil, errors.New(awserrors.ErrorInvalidParameterValue) + } + cluster := aws.StringValue(input.ClusterName) + principalARN := aws.StringValue(input.PrincipalArn) + acctKV, err := s.acctKVForCluster(accountID, cluster) + if err != nil { + return nil, err + } + rec, err := GetAccessEntryRecord(acctKV, cluster, principalARN) + if err != nil { + if errors.Is(err, ErrAccessEntryNotFound) { + return nil, errors.New(awserrors.ErrorEKSResourceNotFound) + } + return nil, err + } + policies := make([]*eks.AssociatedAccessPolicy, 0, len(rec.AssociatedPolicies)) + for _, p := range rec.AssociatedPolicies { + policies = append(policies, associatedPolicyToAWS(p)) + } + return &eks.ListAssociatedAccessPoliciesOutput{ + ClusterName: aws.String(cluster), + PrincipalArn: aws.String(principalARN), + AssociatedAccessPolicies: policies, + }, nil } func (s *EKSServiceImpl) ListAccessPolicies(_ *eks.ListAccessPoliciesInput, _ string) (*eks.ListAccessPoliciesOutput, error) { - return nil, notImpl() + arns := make([]string, 0, len(supportedAccessPolicies)) + for arn := range supportedAccessPolicies { + arns = append(arns, arn) + } + sort.Strings(arns) + policies := make([]*eks.AccessPolicy, 0, len(arns)) + for _, arn := range arns { + policies = append(policies, &eks.AccessPolicy{ + Arn: aws.String(arn), + Name: aws.String(accessPolicyName(arn)), + }) + } + return &eks.ListAccessPoliciesOutput{AccessPolicies: policies}, nil +} + +// hasAssociatedPolicy reports whether the entry has the given policy ARN bound. +func hasAssociatedPolicy(rec *AccessEntryRecord, policyARN string) bool { + for _, p := range rec.AssociatedPolicies { + if p.PolicyARN == policyARN { + return true + } + } + return false +} + +// accessPolicyName extracts the policy short name from its ARN +// (…/cluster-access-policy/AmazonEKSViewPolicy → AmazonEKSViewPolicy). +func accessPolicyName(arn string) string { + if i := strings.LastIndex(arn, "/"); i >= 0 { + return arn[i+1:] + } + return arn } // --- Addons --- diff --git a/spinifex/handlers/eks/service_impl_test.go b/spinifex/handlers/eks/service_impl_test.go index 5b293d557..b6dfe9a00 100644 --- a/spinifex/handlers/eks/service_impl_test.go +++ b/spinifex/handlers/eks/service_impl_test.go @@ -32,7 +32,7 @@ func setupTestService(t *testing.T) *EKSServiceImpl { func TestEKSServiceImpl_ClusterLifecycleShimMode(t *testing.T) { svc := setupTestService(t) - _, err := svc.CreateCluster(&eks.CreateClusterInput{Name: aws.String("c1")}, testAccountID) + _, err := svc.CreateCluster(&eks.CreateClusterInput{Name: aws.String("c1")}, testAccountID, "") require.EqualError(t, err, awserrors.ErrorServiceUnavailable) _, err = svc.DescribeCluster(&eks.DescribeClusterInput{Name: aws.String("c1")}, testAccountID) @@ -133,35 +133,169 @@ func TestEKSServiceImpl_NodegroupMethodsReturnNotImplemented(t *testing.T) { require.EqualError(t, err, awserrors.ErrorNotImplemented) } -func TestEKSServiceImpl_AccessMethodsReturnNotImplemented(t *testing.T) { +// seedTestCluster lays down a minimal ACTIVE cluster meta in the per-account +// bucket so the AccessEntry handlers (which gate on cluster existence) can run. +func seedTestCluster(t *testing.T, svc *EKSServiceImpl, cluster string) { + t.Helper() + js, err := svc.deps.NATSConn.JetStream() + require.NoError(t, err) + kv, err := GetOrCreateAccountBucket(js, testAccountID) + require.NoError(t, err) + require.NoError(t, PutClusterMeta(kv, &ClusterMeta{Name: cluster, Status: ClusterStatusActive})) +} + +const testPrincipalARN = "arn:aws:iam::111122223333:role/dev" + +func TestAccessEntry_UnknownClusterIsNotFound(t *testing.T) { svc := setupTestService(t) + _, err := svc.CreateAccessEntry(&eks.CreateAccessEntryInput{ + ClusterName: aws.String("missing"), PrincipalArn: aws.String(testPrincipalARN), + }, testAccountID) + require.EqualError(t, err, awserrors.ErrorEKSResourceNotFound) +} - _, err := svc.CreateAccessEntry(&eks.CreateAccessEntryInput{ClusterName: aws.String("c1"), PrincipalArn: aws.String("arn:aws:iam::111122223333:user/dev")}, testAccountID) - require.EqualError(t, err, awserrors.ErrorNotImplemented) +func TestAccessEntry_CreateDescribeListDelete(t *testing.T) { + svc := setupTestService(t) + seedTestCluster(t, svc, "c1") - _, err = svc.DescribeAccessEntry(&eks.DescribeAccessEntryInput{ClusterName: aws.String("c1")}, testAccountID) - require.EqualError(t, err, awserrors.ErrorNotImplemented) + out, err := svc.CreateAccessEntry(&eks.CreateAccessEntryInput{ + ClusterName: aws.String("c1"), + PrincipalArn: aws.String(testPrincipalARN), + KubernetesGroups: aws.StringSlice([]string{"system:masters"}), + }, testAccountID) + require.NoError(t, err) + require.NotNil(t, out.AccessEntry) + // Username defaults to the principal ARN; type defaults to STANDARD. + assert.Equal(t, testPrincipalARN, aws.StringValue(out.AccessEntry.Username)) + assert.Equal(t, AccessEntryTypeStandard, aws.StringValue(out.AccessEntry.Type)) + assert.Contains(t, aws.StringValue(out.AccessEntry.AccessEntryArn), ":access-entry/c1/") - _, err = svc.ListAccessEntries(&eks.ListAccessEntriesInput{ClusterName: aws.String("c1")}, testAccountID) - require.EqualError(t, err, awserrors.ErrorNotImplemented) + // Duplicate Create → ResourceInUseException. + _, err = svc.CreateAccessEntry(&eks.CreateAccessEntryInput{ + ClusterName: aws.String("c1"), PrincipalArn: aws.String(testPrincipalARN), + }, testAccountID) + require.EqualError(t, err, awserrors.ErrorEKSResourceInUse) - _, err = svc.UpdateAccessEntry(&eks.UpdateAccessEntryInput{ClusterName: aws.String("c1")}, testAccountID) - require.EqualError(t, err, awserrors.ErrorNotImplemented) + desc, err := svc.DescribeAccessEntry(&eks.DescribeAccessEntryInput{ + ClusterName: aws.String("c1"), PrincipalArn: aws.String(testPrincipalARN), + }, testAccountID) + require.NoError(t, err) + assert.Equal(t, []string{"system:masters"}, aws.StringValueSlice(desc.AccessEntry.KubernetesGroups)) - _, err = svc.DeleteAccessEntry(&eks.DeleteAccessEntryInput{ClusterName: aws.String("c1")}, testAccountID) - require.EqualError(t, err, awserrors.ErrorNotImplemented) + list, err := svc.ListAccessEntries(&eks.ListAccessEntriesInput{ClusterName: aws.String("c1")}, testAccountID) + require.NoError(t, err) + assert.Equal(t, []string{testPrincipalARN}, aws.StringValueSlice(list.AccessEntries)) - _, err = svc.AssociateAccessPolicy(&eks.AssociateAccessPolicyInput{ClusterName: aws.String("c1")}, testAccountID) - require.EqualError(t, err, awserrors.ErrorNotImplemented) + _, err = svc.DeleteAccessEntry(&eks.DeleteAccessEntryInput{ + ClusterName: aws.String("c1"), PrincipalArn: aws.String(testPrincipalARN), + }, testAccountID) + require.NoError(t, err) - _, err = svc.DisassociateAccessPolicy(&eks.DisassociateAccessPolicyInput{ClusterName: aws.String("c1")}, testAccountID) - require.EqualError(t, err, awserrors.ErrorNotImplemented) + _, err = svc.DescribeAccessEntry(&eks.DescribeAccessEntryInput{ + ClusterName: aws.String("c1"), PrincipalArn: aws.String(testPrincipalARN), + }, testAccountID) + require.EqualError(t, err, awserrors.ErrorEKSResourceNotFound) +} - _, err = svc.ListAssociatedAccessPolicies(&eks.ListAssociatedAccessPoliciesInput{ClusterName: aws.String("c1")}, testAccountID) - require.EqualError(t, err, awserrors.ErrorNotImplemented) +func TestAccessEntry_RejectsNodeType(t *testing.T) { + svc := setupTestService(t) + seedTestCluster(t, svc, "c1") + _, err := svc.CreateAccessEntry(&eks.CreateAccessEntryInput{ + ClusterName: aws.String("c1"), PrincipalArn: aws.String(testPrincipalARN), Type: aws.String("EC2_LINUX"), + }, testAccountID) + require.EqualError(t, err, awserrors.ErrorInvalidParameterValue) +} - _, err = svc.ListAccessPolicies(&eks.ListAccessPoliciesInput{}, testAccountID) - require.EqualError(t, err, awserrors.ErrorNotImplemented) +func TestAccessEntry_DescribeDeleteMissingIsNotFound(t *testing.T) { + svc := setupTestService(t) + seedTestCluster(t, svc, "c1") + _, err := svc.DescribeAccessEntry(&eks.DescribeAccessEntryInput{ + ClusterName: aws.String("c1"), PrincipalArn: aws.String(testPrincipalARN), + }, testAccountID) + require.EqualError(t, err, awserrors.ErrorEKSResourceNotFound) + _, err = svc.DeleteAccessEntry(&eks.DeleteAccessEntryInput{ + ClusterName: aws.String("c1"), PrincipalArn: aws.String(testPrincipalARN), + }, testAccountID) + require.EqualError(t, err, awserrors.ErrorEKSResourceNotFound) +} + +func TestAccessPolicy_AssociateListDisassociate(t *testing.T) { + svc := setupTestService(t) + seedTestCluster(t, svc, "c1") + _, err := svc.CreateAccessEntry(&eks.CreateAccessEntryInput{ + ClusterName: aws.String("c1"), PrincipalArn: aws.String(testPrincipalARN), + }, testAccountID) + require.NoError(t, err) + + const viewPolicy = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy" + assoc, err := svc.AssociateAccessPolicy(&eks.AssociateAccessPolicyInput{ + ClusterName: aws.String("c1"), + PrincipalArn: aws.String(testPrincipalARN), + PolicyArn: aws.String(viewPolicy), + AccessScope: &eks.AccessScope{Type: aws.String("cluster")}, + }, testAccountID) + require.NoError(t, err) + assert.Equal(t, viewPolicy, aws.StringValue(assoc.AssociatedAccessPolicy.PolicyArn)) + + listed, err := svc.ListAssociatedAccessPolicies(&eks.ListAssociatedAccessPoliciesInput{ + ClusterName: aws.String("c1"), PrincipalArn: aws.String(testPrincipalARN), + }, testAccountID) + require.NoError(t, err) + require.Len(t, listed.AssociatedAccessPolicies, 1) + + // Entry now discoverable by the associated-policy filter. + filtered, err := svc.ListAccessEntries(&eks.ListAccessEntriesInput{ + ClusterName: aws.String("c1"), AssociatedPolicyArn: aws.String(viewPolicy), + }, testAccountID) + require.NoError(t, err) + assert.Equal(t, []string{testPrincipalARN}, aws.StringValueSlice(filtered.AccessEntries)) + + _, err = svc.DisassociateAccessPolicy(&eks.DisassociateAccessPolicyInput{ + ClusterName: aws.String("c1"), PrincipalArn: aws.String(testPrincipalARN), PolicyArn: aws.String(viewPolicy), + }, testAccountID) + require.NoError(t, err) + listed, err = svc.ListAssociatedAccessPolicies(&eks.ListAssociatedAccessPoliciesInput{ + ClusterName: aws.String("c1"), PrincipalArn: aws.String(testPrincipalARN), + }, testAccountID) + require.NoError(t, err) + assert.Empty(t, listed.AssociatedAccessPolicies) +} + +func TestAccessPolicy_AssociateRejectsUnsupportedPolicyAndScope(t *testing.T) { + svc := setupTestService(t) + seedTestCluster(t, svc, "c1") + _, err := svc.CreateAccessEntry(&eks.CreateAccessEntryInput{ + ClusterName: aws.String("c1"), PrincipalArn: aws.String(testPrincipalARN), + }, testAccountID) + require.NoError(t, err) + + // Unsupported policy ARN. + _, err = svc.AssociateAccessPolicy(&eks.AssociateAccessPolicyInput{ + ClusterName: aws.String("c1"), PrincipalArn: aws.String(testPrincipalARN), + PolicyArn: aws.String("arn:aws:eks::aws:cluster-access-policy/MadeUpPolicy"), + AccessScope: &eks.AccessScope{Type: aws.String("cluster")}, + }, testAccountID) + require.EqualError(t, err, awserrors.ErrorInvalidParameterValue) + + // namespace scope without namespaces. + _, err = svc.AssociateAccessPolicy(&eks.AssociateAccessPolicyInput{ + ClusterName: aws.String("c1"), PrincipalArn: aws.String(testPrincipalARN), + PolicyArn: aws.String("arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy"), + AccessScope: &eks.AccessScope{Type: aws.String("namespace")}, + }, testAccountID) + require.EqualError(t, err, awserrors.ErrorInvalidParameterValue) +} + +func TestListAccessPolicies_ReturnsSupportedCatalogue(t *testing.T) { + svc := setupTestService(t) + out, err := svc.ListAccessPolicies(&eks.ListAccessPoliciesInput{}, testAccountID) + require.NoError(t, err) + require.Len(t, out.AccessPolicies, len(supportedAccessPolicies)) + for _, p := range out.AccessPolicies { + _, ok := supportedAccessPolicies[aws.StringValue(p.Arn)] + assert.True(t, ok, "unexpected policy %s", aws.StringValue(p.Arn)) + assert.NotEmpty(t, aws.StringValue(p.Name)) + } } func TestEKSServiceImpl_AddonsMethodsReturnNotImplemented(t *testing.T) { diff --git a/spinifex/handlers/eks/service_nats.go b/spinifex/handlers/eks/service_nats.go index e82194731..89534411a 100644 --- a/spinifex/handlers/eks/service_nats.go +++ b/spinifex/handlers/eks/service_nats.go @@ -25,8 +25,9 @@ func NewNATSEKSService(conn *nats.Conn) EKSService { // --- Cluster --- -func (s *NATSEKSService) CreateCluster(input *eks.CreateClusterInput, accountID string) (*eks.CreateClusterOutput, error) { - return utils.NATSRequest[eks.CreateClusterOutput](s.natsConn, "eks.CreateCluster", input, defaultTimeout, accountID) +func (s *NATSEKSService) CreateCluster(input *eks.CreateClusterInput, accountID, callerPrincipalARN string) (*eks.CreateClusterOutput, error) { + return utils.NATSRequest[eks.CreateClusterOutput](s.natsConn, "eks.CreateCluster", input, defaultTimeout, accountID, + utils.NATSHeader{Key: utils.PrincipalARNHeader, Value: callerPrincipalARN}) } func (s *NATSEKSService) DescribeCluster(input *eks.DescribeClusterInput, accountID string) (*eks.DescribeClusterOutput, error) { diff --git a/spinifex/handlers/eks/store.go b/spinifex/handlers/eks/store.go index 2e4048e78..1deca7f96 100644 --- a/spinifex/handlers/eks/store.go +++ b/spinifex/handlers/eks/store.go @@ -1,6 +1,8 @@ package handlers_eks import ( + "crypto/sha256" + "encoding/hex" "errors" "fmt" "log/slog" @@ -52,9 +54,23 @@ func NodegroupKey(cluster, ng string) string { return fmt.Sprintf("clusters/%s/nodegroups/%s", cluster, ng) } +// AccessEntriesPrefix returns the KV key prefix under which all of a cluster's +// AccessEntry records live. Used by ListAccessEntries to enumerate. +func AccessEntriesPrefix(cluster string) string { + return fmt.Sprintf("clusters/%s/access-entries/", cluster) +} + // AccessEntryKey returns the KV key for an AccessEntry record under a cluster. +// The principal ARN is hashed because IAM ARNs contain ':' which is not a legal +// NATS JetStream KV key character; the record itself carries the plaintext ARN. func AccessEntryKey(cluster, principalARN string) string { - return fmt.Sprintf("clusters/%s/access-entries/%s", cluster, principalARN) + return AccessEntriesPrefix(cluster) + PrincipalARNHash(principalARN) +} + +// PrincipalARNHash maps an IAM principal ARN to a KV-key-safe token. +func PrincipalARNHash(principalARN string) string { + sum := sha256.Sum256([]byte(principalARN)) + return hex.EncodeToString(sum[:]) } // OIDCProviderKey returns the KV key for a registered OIDC provider config diff --git a/spinifex/handlers/eks/store_test.go b/spinifex/handlers/eks/store_test.go index 64879eb2e..8432a6a88 100644 --- a/spinifex/handlers/eks/store_test.go +++ b/spinifex/handlers/eks/store_test.go @@ -47,7 +47,7 @@ func TestKeyPaths_MatchQ2Spec(t *testing.T) { }{ {"ClusterMetaKey", ClusterMetaKey("alpha"), "clusters/alpha/meta"}, {"NodegroupKey", NodegroupKey("alpha", "ng-1"), "clusters/alpha/nodegroups/ng-1"}, - {"AccessEntryKey", AccessEntryKey("alpha", "arn:aws:iam::111122223333:user/dev"), "clusters/alpha/access-entries/arn:aws:iam::111122223333:user/dev"}, + {"AccessEntryKey", AccessEntryKey("alpha", "arn:aws:iam::111122223333:user/dev"), "clusters/alpha/access-entries/" + PrincipalARNHash("arn:aws:iam::111122223333:user/dev")}, {"OIDCProviderKey", OIDCProviderKey("alpha", "abc123"), "clusters/alpha/oidc-providers/abc123"}, {"OIDCSigningKeyKey", OIDCSigningKeyKey("alpha"), "clusters/alpha/oidc-signing-key.pem.enc"}, {"OIDCJWKSKey", OIDCJWKSKey("alpha"), "clusters/alpha/oidc-jwks.json"}, diff --git a/spinifex/handlers/eks/token_webhook.go b/spinifex/handlers/eks/token_webhook.go new file mode 100644 index 000000000..8f4e483e0 --- /dev/null +++ b/spinifex/handlers/eks/token_webhook.go @@ -0,0 +1,58 @@ +package handlers_eks + +import ( + "encoding/base64" + "errors" + "strings" +) + +// TokenVerifySubject is the NATS request subject the EKS token webhook calls to +// resolve an `aws eks get-token` presigned URL into a caller principal. It is +// served by the awsgw service (which hosts the in-process STS service) because +// STS is gateway-local and not otherwise exposed on NATS. +const TokenVerifySubject = "eks.VerifyToken" //nolint:gosec // NATS subject name, not a credential + +// getTokenV1Prefix is the scheme prefix `aws eks get-token` prepends to the +// base64url-encoded presigned STS GetCallerIdentity URL. +const getTokenV1Prefix = "k8s-aws-v1." //nolint:gosec // token scheme prefix, not a credential + +// ErrMalformedToken is returned by DecodeGetToken when the bearer token is not +// a well-formed `k8s-aws-v1.` value. +var ErrMalformedToken = errors.New("eks: malformed k8s-aws-v1 token") + +// TokenVerifyRequest is the NATS request payload sent to TokenVerifySubject. +// ClusterName is the anti-replay binding (Q10): the webhook passes its own +// cluster name and STS rejects a URL signed for any other x-k8s-aws-id. +type TokenVerifyRequest struct { + PresignedURL string `json:"presignedURL"` + ClusterName string `json:"clusterName"` +} + +// TokenVerifyResponse is the NATS reply: the resolved caller principal. It +// mirrors the fields of handlers_sts.PresignedCallerIdentity the webhook needs +// to key its AccessEntry lookup. +type TokenVerifyResponse struct { + AccountID string `json:"accountID"` + ARN string `json:"arn"` + UserID string `json:"userID"` + PrincipalType string `json:"principalType"` +} + +// DecodeGetToken extracts the presigned STS GetCallerIdentity URL from a +// `k8s-aws-v1.` bearer token. The encoding is base64url without +// padding, matching the aws-iam-authenticator / aws-cli get-token output. +func DecodeGetToken(token string) (string, error) { + token = strings.TrimSpace(token) + if !strings.HasPrefix(token, getTokenV1Prefix) { + return "", ErrMalformedToken + } + encoded := strings.TrimPrefix(token, getTokenV1Prefix) + raw, err := base64.RawURLEncoding.DecodeString(encoded) + if err != nil { + return "", ErrMalformedToken + } + if len(raw) == 0 { + return "", ErrMalformedToken + } + return string(raw), nil +} diff --git a/spinifex/handlers/eks/token_webhook_test.go b/spinifex/handlers/eks/token_webhook_test.go new file mode 100644 index 000000000..69f89c1a8 --- /dev/null +++ b/spinifex/handlers/eks/token_webhook_test.go @@ -0,0 +1,44 @@ +package handlers_eks + +import ( + "encoding/base64" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDecodeGetToken_RoundTrips(t *testing.T) { + url := "https://sts.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15&X-Amz-Algorithm=AWS4-HMAC-SHA256" + token := getTokenV1Prefix + base64.RawURLEncoding.EncodeToString([]byte(url)) + + got, err := DecodeGetToken(token) + require.NoError(t, err) + assert.Equal(t, url, got) +} + +func TestDecodeGetToken_TrimsWhitespace(t *testing.T) { + url := "https://sts.amazonaws.com/?Action=GetCallerIdentity" + token := " " + getTokenV1Prefix + base64.RawURLEncoding.EncodeToString([]byte(url)) + "\n" + + got, err := DecodeGetToken(token) + require.NoError(t, err) + assert.Equal(t, url, got) +} + +func TestDecodeGetToken_RejectsMalformed(t *testing.T) { + cases := map[string]string{ + "missing prefix": base64.RawURLEncoding.EncodeToString([]byte("https://sts")), + "empty": "", + "prefix only": getTokenV1Prefix, + "bad base64": getTokenV1Prefix + "!!!not-base64!!!", + "padded base64": getTokenV1Prefix + base64.URLEncoding.EncodeToString([]byte("https://sts.amazonaws.com/?x=12")), + "wrong scheme": "k8s-aws-v2." + base64.RawURLEncoding.EncodeToString([]byte("https://sts")), + } + for name, tok := range cases { + t.Run(name, func(t *testing.T) { + _, err := DecodeGetToken(tok) + assert.ErrorIs(t, err, ErrMalformedToken) + }) + } +} diff --git a/spinifex/handlers/eks/types.go b/spinifex/handlers/eks/types.go index c42bf0997..3e91d889d 100644 --- a/spinifex/handlers/eks/types.go +++ b/spinifex/handlers/eks/types.go @@ -40,12 +40,33 @@ type NodegroupRecord struct { // AccessEntryRecord is the persisted-state envelope for an EKS API-mode // AccessEntry (Q9). type AccessEntryRecord struct { - ClusterName string `json:"clusterName"` - PrincipalARN string `json:"principalARN"` - KubernetesUsername string `json:"kubernetesUsername"` - KubernetesGroups []string `json:"kubernetesGroups,omitempty"` - Type string `json:"type"` - CreatedAt time.Time `json:"createdAt"` + ARN string `json:"arn"` + ClusterName string `json:"clusterName"` + PrincipalARN string `json:"principalARN"` + KubernetesUsername string `json:"kubernetesUsername"` + KubernetesGroups []string `json:"kubernetesGroups,omitempty"` + Type string `json:"type"` + Tags map[string]string `json:"tags,omitempty"` + AssociatedPolicies []AssociatedAccessPolicy `json:"associatedPolicies,omitempty"` + CreatedAt time.Time `json:"createdAt"` + ModifiedAt time.Time `json:"modifiedAt"` +} + +// AssociatedAccessPolicy is a managed access policy bound to an AccessEntry +// with a cluster- or namespace-scoped grant (Q9). +type AssociatedAccessPolicy struct { + PolicyARN string `json:"policyARN"` + AccessScope AccessScope `json:"accessScope"` + AssociatedAt time.Time `json:"associatedAt"` + ModifiedAt time.Time `json:"modifiedAt"` +} + +// AccessScope restricts an associated access policy to the whole cluster or a +// set of namespaces. Type is "cluster" or "namespace"; Namespaces is required +// (and only meaningful) when Type is "namespace". +type AccessScope struct { + Type string `json:"type"` + Namespaces []string `json:"namespaces,omitempty"` } // OIDCProviderConfigRecord captures the minimum needed to register an OIDC diff --git a/spinifex/handlers/sts/presigned_url_verify.go b/spinifex/handlers/sts/presigned_url_verify.go index 1414149b3..c605c58f4 100644 --- a/spinifex/handlers/sts/presigned_url_verify.go +++ b/spinifex/handlers/sts/presigned_url_verify.go @@ -143,7 +143,11 @@ func (s *STSServiceImpl) VerifyPresignedGetCallerIdentity(presignedURL, expected canonicalQuery, canonicalHeaders, signedHeadersList, - "UNSIGNED-PAYLOAD", + // botocore / aws-sdk presign `sts:GetCallerIdentity` (a non-S3, empty-body + // request) with the SHA256 of the empty string as the payload hash. + // "UNSIGNED-PAYLOAD" is an S3-only convention and would mismatch every + // real `aws eks get-token`. + emptyStringSHA256, }, "\n") stringToSign := strings.Join([]string{ @@ -360,6 +364,10 @@ func hexSHA256(s string) string { return hex.EncodeToString(sum[:]) } +// emptyStringSHA256 is the SigV4 payload hash for an empty body — the value +// botocore/aws-sdk use when presigning non-S3 requests like GetCallerIdentity. +var emptyStringSHA256 = hexSHA256("") + func hmacSHA256(key []byte, data string) []byte { mac := hmac.New(sha256.New, key) mac.Write([]byte(data)) diff --git a/spinifex/handlers/sts/presigned_url_verify_test.go b/spinifex/handlers/sts/presigned_url_verify_test.go index ed0b5af05..e7c05b7dd 100644 --- a/spinifex/handlers/sts/presigned_url_verify_test.go +++ b/spinifex/handlers/sts/presigned_url_verify_test.go @@ -2,6 +2,7 @@ package handlers_sts import ( "encoding/hex" + "net/http" "net/url" "sort" "strconv" @@ -10,6 +11,8 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + v4 "github.com/aws/aws-sdk-go/aws/signer/v4" "github.com/aws/aws-sdk-go/service/iam" "github.com/mulgadc/spinifex/spinifex/awserrors" "github.com/stretchr/testify/assert" @@ -52,7 +55,7 @@ func presignTestURL(t *testing.T, accessKeyID, secret, clusterName string, signe canonHeaders := "host:" + host + "\n" + "x-k8s-aws-id:" + clusterName + "\n" signedHeadersList := "host;x-k8s-aws-id" canonRequest := strings.Join([]string{ - "GET", "/", canonQ, canonHeaders, signedHeadersList, "UNSIGNED-PAYLOAD", + "GET", "/", canonQ, canonHeaders, signedHeadersList, emptyStringSHA256, }, "\n") stringToSign := strings.Join([]string{ @@ -204,7 +207,7 @@ func TestVerifyPresignedGetCallerIdentity_MissingXK8sAwsIdInSignedHeaders(t *tes canonQ := canonicalQueryStringForTest(q) canonHeaders := "host:" + testPresignedHost + "\n" canonReq := strings.Join([]string{ - "GET", "/", canonQ, canonHeaders, "host", "UNSIGNED-PAYLOAD", + "GET", "/", canonQ, canonHeaders, "host", emptyStringSHA256, }, "\n") stringToSign := strings.Join([]string{ "AWS4-HMAC-SHA256", amzDate, credentialScope, hexSHA256(canonReq), @@ -383,3 +386,38 @@ func TestDeriveSigningKey_KnownVector(t *testing.T) { const wantHex = "f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d" assert.Equal(t, wantHex, hex.EncodeToString(key)) } + +// TestVerifyPresignedGetCallerIdentity_RealSDKPresign signs the URL with the +// actual aws-sdk-go v4 presigner — the same canonicalisation `aws eks +// get-token` uses — rather than the hand-rolled presignTestURL. This is the +// faithful end-to-end guard: it caught the payload-hash bug (verify used the +// S3-only "UNSIGNED-PAYLOAD" instead of the empty-string SHA256 that botocore +// signs non-S3 requests with), which every hand-rolled test masked by using +// the same wrong constant. +func TestVerifyPresignedGetCallerIdentity_RealSDKPresign(t *testing.T) { + svc, _ := newTestSetup(t) + akid, secret := seedAccessKey(t, svc, testCallerAccountID, "carol") + + signedAt := time.Now().UTC().Truncate(time.Second) + withFrozenTime(t, signedAt) + + const cluster = "prod-cluster" + req, err := http.NewRequest(http.MethodGet, + "https://"+testPresignedHost+"/?Action=GetCallerIdentity&Version=2011-06-15", nil) + require.NoError(t, err) + req.Header.Set("X-K8s-Aws-Id", cluster) + + signer := v4.NewSigner(credentials.NewStaticCredentials(akid, secret, "")) + _, err = signer.Presign(req, nil, "sts", testPresignedRegion, 900*time.Second, signedAt) + require.NoError(t, err) + + got, err := svc.VerifyPresignedGetCallerIdentity(req.URL.String(), cluster) + require.NoError(t, err) + require.NotNil(t, got) + assert.Equal(t, cluster, got.XK8sAwsID) + assert.Contains(t, got.ARN, ":user/carol") + + // Anti-replay: the SDK-signed URL must NOT verify against a different cluster. + _, err = svc.VerifyPresignedGetCallerIdentity(req.URL.String(), "other-cluster") + require.Error(t, err) +} diff --git a/spinifex/services/awsgw/awsgw.go b/spinifex/services/awsgw/awsgw.go index ac7f49c1e..992089724 100644 --- a/spinifex/services/awsgw/awsgw.go +++ b/spinifex/services/awsgw/awsgw.go @@ -146,6 +146,19 @@ func launchService(config *config.ClusterConfig) error { defer cancelJanitor() go stsService.RunJanitor(janitorCtx) + // Expose the in-process STS presigned-URL verify over NATS for the + // in-cluster eks-token-webhook (STS is gateway-local, not otherwise on the + // bus). Bound to the process lifetime via natsConn.Close on return. + tokenVerifySub, err := registerEKSTokenVerify(natsConn, stsService) + if err != nil { + return fmt.Errorf("subscribe EKS token verify: %w", err) + } + defer func() { + if err := tokenVerifySub.Unsubscribe(); err != nil { + slog.Warn("EKS token verify: unsubscribe failed", "err", err) + } + }() + // First boot: consume bootstrap.json → seed IAM users into NATS KV → delete file. // Check data directory first (production: /var/lib/spinifex/awsgw/), then // awsgw subdir (dev: ~/spinifex/awsgw/), then legacy config dir. diff --git a/spinifex/services/awsgw/eks_token_verify.go b/spinifex/services/awsgw/eks_token_verify.go new file mode 100644 index 000000000..730fc8e9c --- /dev/null +++ b/spinifex/services/awsgw/eks_token_verify.go @@ -0,0 +1,76 @@ +package awsgw + +import ( + "encoding/json" + "log/slog" + + "github.com/mulgadc/spinifex/spinifex/awserrors" + handlers_eks "github.com/mulgadc/spinifex/spinifex/handlers/eks" + handlers_sts "github.com/mulgadc/spinifex/spinifex/handlers/sts" + "github.com/mulgadc/spinifex/spinifex/utils" + "github.com/nats-io/nats.go" +) + +// eksTokenVerifyQueue is the NATS queue group for the EKS token-verify +// responders so the request is load-balanced across awsgw nodes. +const eksTokenVerifyQueue = "awsgw-eks-token-verify" //nolint:gosec // queue-group name, not a credential + +// presignedVerifier is the slice of the STS service the token-verify responder +// needs: resolve an `aws eks get-token` presigned URL into a caller principal, +// binding the signature to the expected cluster name (anti-replay, Q10). +type presignedVerifier interface { + VerifyPresignedGetCallerIdentity(presignedURL, expectedClusterName string) (*handlers_sts.PresignedCallerIdentity, error) +} + +var _ presignedVerifier = (*handlers_sts.STSServiceImpl)(nil) + +// registerEKSTokenVerify subscribes the awsgw service to TokenVerifySubject so +// the in-cluster eks-token-webhook can resolve get-token presigned URLs over +// NATS (STS is hosted in-process here and is not otherwise on the bus). +func registerEKSTokenVerify(nc *nats.Conn, verifier presignedVerifier) (*nats.Subscription, error) { + return nc.QueueSubscribe(handlers_eks.TokenVerifySubject, eksTokenVerifyQueue, handleEKSTokenVerify(verifier)) +} + +func handleEKSTokenVerify(verifier presignedVerifier) nats.MsgHandler { + return func(msg *nats.Msg) { + var req handlers_eks.TokenVerifyRequest + if err := json.Unmarshal(msg.Data, &req); err != nil { + respondTokenVerifyErr(msg, awserrors.ErrorInvalidParameterValue) + return + } + if req.PresignedURL == "" || req.ClusterName == "" { + respondTokenVerifyErr(msg, awserrors.ErrorInvalidParameterValue) + return + } + + ident, err := verifier.VerifyPresignedGetCallerIdentity(req.PresignedURL, req.ClusterName) + if err != nil { + // A verify failure is the common, expected case for a forged/replayed + // token — log at debug so a port-scan does not flood the error log. + slog.Debug("EKS token verify rejected", "cluster", req.ClusterName, "err", err) + respondTokenVerifyErr(msg, awserrors.ValidErrorCode(err.Error())) + return + } + + resp := handlers_eks.TokenVerifyResponse{ + AccountID: ident.AccountID, + ARN: ident.ARN, + UserID: ident.UserID, + PrincipalType: ident.PrincipalType, + } + data, err := json.Marshal(resp) + if err != nil { + respondTokenVerifyErr(msg, awserrors.ErrorServerInternal) + return + } + if err := msg.Respond(data); err != nil { + slog.Error("EKS token verify: failed to respond", "err", err) + } + } +} + +func respondTokenVerifyErr(msg *nats.Msg, code string) { + if err := msg.Respond(utils.GenerateErrorPayload(code)); err != nil { + slog.Error("EKS token verify: failed to respond with error", "err", err) + } +} diff --git a/spinifex/services/awsgw/eks_token_verify_test.go b/spinifex/services/awsgw/eks_token_verify_test.go new file mode 100644 index 000000000..069193fed --- /dev/null +++ b/spinifex/services/awsgw/eks_token_verify_test.go @@ -0,0 +1,79 @@ +package awsgw + +import ( + "errors" + "testing" + "time" + + handlers_eks "github.com/mulgadc/spinifex/spinifex/handlers/eks" + handlers_sts "github.com/mulgadc/spinifex/spinifex/handlers/sts" + "github.com/mulgadc/spinifex/spinifex/testutil" + "github.com/mulgadc/spinifex/spinifex/utils" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type fakeVerifier struct { + ident *handlers_sts.PresignedCallerIdentity + err error + gotURL string + gotName string +} + +func (f *fakeVerifier) VerifyPresignedGetCallerIdentity(presignedURL, expectedClusterName string) (*handlers_sts.PresignedCallerIdentity, error) { + f.gotURL = presignedURL + f.gotName = expectedClusterName + return f.ident, f.err +} + +func TestEKSTokenVerify_ResolvesPrincipal(t *testing.T) { + _, nc := testutil.StartTestNATS(t) + fake := &fakeVerifier{ident: &handlers_sts.PresignedCallerIdentity{ + AccountID: "111122223333", + ARN: "arn:aws:iam::111122223333:role/admin", + UserID: "AROAEXAMPLE:sess", + PrincipalType: "AssumedRole", + }} + sub, err := registerEKSTokenVerify(nc, fake) + require.NoError(t, err) + defer func() { _ = sub.Unsubscribe() }() + + req := handlers_eks.TokenVerifyRequest{PresignedURL: "https://sts/?x=1", ClusterName: "alpha"} + resp, err := utils.NATSRequest[handlers_eks.TokenVerifyResponse]( + nc, handlers_eks.TokenVerifySubject, req, 2*time.Second, "") + require.NoError(t, err) + + assert.Equal(t, "arn:aws:iam::111122223333:role/admin", resp.ARN) + assert.Equal(t, "AROAEXAMPLE:sess", resp.UserID) + assert.Equal(t, "AssumedRole", resp.PrincipalType) + // Cluster name is forwarded for the STS anti-replay pin. + assert.Equal(t, "alpha", fake.gotName) +} + +func TestEKSTokenVerify_RejectedTokenIsError(t *testing.T) { + _, nc := testutil.StartTestNATS(t) + fake := &fakeVerifier{err: errors.New("signature mismatch (cluster name replay)")} + sub, err := registerEKSTokenVerify(nc, fake) + require.NoError(t, err) + defer func() { _ = sub.Unsubscribe() }() + + req := handlers_eks.TokenVerifyRequest{PresignedURL: "https://sts/?x=1", ClusterName: "alpha"} + _, err = utils.NATSRequest[handlers_eks.TokenVerifyResponse]( + nc, handlers_eks.TokenVerifySubject, req, 2*time.Second, "") + require.Error(t, err, "a verify failure must surface as a NATS error payload") +} + +func TestEKSTokenVerify_RejectsEmptyFields(t *testing.T) { + _, nc := testutil.StartTestNATS(t) + fake := &fakeVerifier{ident: &handlers_sts.PresignedCallerIdentity{ARN: "arn:..."}} + sub, err := registerEKSTokenVerify(nc, fake) + require.NoError(t, err) + defer func() { _ = sub.Unsubscribe() }() + + // Missing ClusterName — responder rejects before calling the verifier. + req := handlers_eks.TokenVerifyRequest{PresignedURL: "https://sts/?x=1"} + _, err = utils.NATSRequest[handlers_eks.TokenVerifyResponse]( + nc, handlers_eks.TokenVerifySubject, req, 2*time.Second, "") + require.Error(t, err) + assert.Empty(t, fake.gotURL, "verifier must not run on an invalid request") +} diff --git a/spinifex/utils/nats.go b/spinifex/utils/nats.go index 19426f24b..bda51cbe3 100644 --- a/spinifex/utils/nats.go +++ b/spinifex/utils/nats.go @@ -230,12 +230,30 @@ func ConnectNATSWithRetry(host, token, caCertPath string, opts ...RetryOption) ( // AWS account ID from the gateway to daemon handlers. const AccountIDHeader = "X-Account-ID" +// PrincipalARNHeader carries the caller's resolved IAM principal ARN from the +// gateway to daemon handlers that attribute an action to its caller (e.g. the +// EKS bootstrap-creator-admin AccessEntry). +const PrincipalARNHeader = "X-Principal-ARN" + +// NATSHeader is an extra request header passed to NATSRequest beyond the +// always-set X-Account-ID. +type NATSHeader struct{ Key, Value string } + +// PrincipalARNFromMsg extracts the caller's principal ARN from a NATS message +// header. Returns "" when absent. +func PrincipalARNFromMsg(msg *nats.Msg) string { + if msg == nil || msg.Header == nil { + return "" + } + return msg.Header.Get(PrincipalARNHeader) +} + // NATSRequest performs a NATS request-response with JSON marshaling. // It marshals the input, sends to the given subject with the X-Account-ID -// header, validates the response for error payloads, and unmarshals the -// successful response into Out. Handlers can ignore the account ID if the -// operation is unscoped (e.g. DescribeInstanceTypes). -func NATSRequest[Out any](conn *nats.Conn, subject string, input any, timeout time.Duration, accountID string) (*Out, error) { +// header (plus any extra headers), validates the response for error payloads, +// and unmarshals the successful response into Out. Handlers can ignore the +// account ID if the operation is unscoped (e.g. DescribeInstanceTypes). +func NATSRequest[Out any](conn *nats.Conn, subject string, input any, timeout time.Duration, accountID string, headers ...NATSHeader) (*Out, error) { if conn == nil || !conn.IsConnected() { return nil, ErrClusterUnavailable } @@ -248,6 +266,11 @@ func NATSRequest[Out any](conn *nats.Conn, subject string, input any, timeout ti reqMsg := nats.NewMsg(subject) reqMsg.Data = jsonData reqMsg.Header.Set(AccountIDHeader, accountID) + for _, h := range headers { + if h.Key != "" { + reqMsg.Header.Set(h.Key, h.Value) + } + } msg, err := conn.RequestMsg(reqMsg, timeout) if err != nil { From f14fb645626939266317ec4f7966ce81c12b6a7f Mon Sep 17 00:00:00 2001 From: Josh Siviour Date: Thu, 4 Jun 2026 12:28:56 +1000 Subject: [PATCH 12/73] feat(eks): unify eks-server + eks-agent into one eks-node AMI (#288) * feat(eks): unify eks-server + eks-agent into one eks-node AMI Collapse the two K3s AMIs into a single spinifex-eks-node image whose role (server vs agent) is chosen per-instance at first boot, halving build time, storage, and CVE-rotation surface. - scripts/images/eks-node/: superset manifest + merged setup.sh; all role services baked but only crond + the new eks-node-role selector enabled. - eks-node-role first-boot selector reads SPINIFEX_K3S_ROLE, rc-update adds + starts the matching services (server: k3s + eks-token-webhook + k3s-first-boot publisher; agent: k3s-agent), records /etc/spinifex-eks/role, self-disables. Paths are env-overridable; eks-node-role_test.sh covers all five cases. - mulga-eks-etcd-snapshot.sh early-exits on agent nodes. - k3s_server_vm.go seeds SPINIFEX_K3S_ROLE=server into first-boot.env. - Makefile/dev-install: build-eks-node-image / import-eks-node-image replace the server+agent targets. - Delete scripts/images/eks-server + eks-agent. The launcher resolves the AMI by the spinifex:managed-by=eks tag, so running clusters (which hold the resolved AMI ID) are unaffected. AMI bake + cluster boot are operational integration steps, not yet run. * fix(eks): order eks-node-role after cloud-config/cloud-final The first-boot role selector reads /etc/spinifex-eks/first-boot.env, which cloud-init delivers via write_files in the cloud-config/cloud-final stages. The selector only depended on net+cgroups, so on a fast boot it could start before write_files landed and read a missing role env. Add an after-ordering on cloud-config + cloud-final so the env file is always present first. --- Makefile | 73 +++++++++++-- cmd/spinifex/cmd/admin.go | 2 +- docs/COMMANDS.md | 2 +- scripts/dev-install.sh | 14 +-- scripts/images/eks-agent/manifest.conf | 25 ----- .../eks-agent/mulga-eks-state-report.sh | 38 ------- scripts/images/eks-agent/setup.sh | 47 -------- scripts/images/eks-node/eks-node-role.initd | 27 +++++ scripts/images/eks-node/eks-node-role.sh | 69 ++++++++++++ scripts/images/eks-node/eks-node-role_test.sh | 103 ++++++++++++++++++ .../eks-token-webhook.initd | 0 .../{eks-agent => eks-node}/k3s-agent.initd | 0 .../k3s-first-boot.initd | 0 .../k3s-first-boot.sh | 0 .../images/{eks-server => eks-node}/k3s.initd | 0 scripts/images/eks-node/manifest.conf | 44 ++++++++ .../mulga-eks-etcd-snapshot.sh | 6 + .../mulga-eks-state-report.sh | 0 .../images/{eks-server => eks-node}/setup.sh | 49 +++++---- scripts/images/eks-server/manifest.conf | 35 ------ spinifex/handlers/eks/k3s_server_vm.go | 4 + spinifex/handlers/eks/k3s_server_vm_test.go | 3 + spinifex/tags/tags.go | 2 +- 23 files changed, 358 insertions(+), 185 deletions(-) delete mode 100644 scripts/images/eks-agent/manifest.conf delete mode 100644 scripts/images/eks-agent/mulga-eks-state-report.sh delete mode 100644 scripts/images/eks-agent/setup.sh create mode 100755 scripts/images/eks-node/eks-node-role.initd create mode 100755 scripts/images/eks-node/eks-node-role.sh create mode 100755 scripts/images/eks-node/eks-node-role_test.sh rename scripts/images/{eks-server => eks-node}/eks-token-webhook.initd (100%) mode change 100644 => 100755 rename scripts/images/{eks-agent => eks-node}/k3s-agent.initd (100%) mode change 100644 => 100755 rename scripts/images/{eks-server => eks-node}/k3s-first-boot.initd (100%) mode change 100644 => 100755 rename scripts/images/{eks-server => eks-node}/k3s-first-boot.sh (100%) mode change 100644 => 100755 rename scripts/images/{eks-server => eks-node}/k3s.initd (100%) mode change 100644 => 100755 create mode 100644 scripts/images/eks-node/manifest.conf rename scripts/images/{eks-server => eks-node}/mulga-eks-etcd-snapshot.sh (90%) mode change 100644 => 100755 rename scripts/images/{eks-server => eks-node}/mulga-eks-state-report.sh (100%) mode change 100644 => 100755 rename scripts/images/{eks-server => eks-node}/setup.sh (67%) mode change 100644 => 100755 delete mode 100644 scripts/images/eks-server/manifest.conf diff --git a/Makefile b/Makefile index b733eea44..4bf597b2f 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,7 @@ build-lb-agent: @echo -e "\n....Building lb-agent (static)" CGO_ENABLED=0 GOFIPS140=v1.0.0 go build -ldflags "-s -w" -o ./bin/lb-agent cmd/lb-agent/main.go -build-system-image: ## Build a system image from manifest (use IMAGE=lb or IMAGE=eks-server) +build-system-image: ## Build a system image from manifest (use IMAGE=lb or IMAGE=eks-node) ifndef IMAGE $(error IMAGE is required. Usage: make build-system-image IMAGE=lb) endif @@ -86,14 +86,11 @@ endif exit 1; \ fi -build-eks-server-image: ## Build the eks-server AMI (K3s control-plane variant; IMPORT=1 to register it) - $(MAKE) build-system-image IMAGE=eks-server +build-eks-node-image: ## Build the unified eks-node AMI (K3s server+agent; role at first boot; IMPORT=1 to register) + $(MAKE) build-system-image IMAGE=eks-node -import-eks-server-image: ## Build + register the eks-server AMI (requires a running cluster) - $(MAKE) build-system-image IMAGE=eks-server IMPORT=1 - -build-eks-agent-image: ## Build the eks-agent AMI (K3s worker variant) - $(MAKE) build-system-image IMAGE=eks-agent +import-eks-node-image: ## Build + register the eks-node AMI (requires a running cluster) + $(MAKE) build-system-image IMAGE=eks-node IMPORT=1 MICROVM_OUT_DIR := build/microvm MICROVM_ARTIFACTS := $(MICROVM_OUT_DIR)/vmlinuz $(MICROVM_OUT_DIR)/initramfs.cpio.gz @@ -295,7 +292,65 @@ distro-arm64: distro-clean: rm -rf dist/ -.PHONY: build build-ui build-installer build-lb-agent build-system-image build-eks-server-image import-eks-server-image build-eks-agent-image build-microvm-image install-microvm go_build go_run preflight test test-cover test-race diff-coverage bench run test-actions test-harness manifest-check diff-coverage bench run \ +# Ansible dev lifecycle (experimental, parallel to dev-*.sh / reset-dev-env.sh). +# See scripts/ansible/README.md and docs/development/improvements/ansible-dev-lifecycle.md. +# +# Variable overrides: pass EXTRA_VARS="key=val key2=val2" to forward as +# `--extra-vars` to ansible-playbook. Plain `-e` on the make command line is +# make's own flag and does NOT reach ansible. +# make ansible-dev-install EXTRA_VARS="spinifex_external_pool_start=192.168.1.90 spinifex_external_pool_end=192.168.1.99" +EXTRA_VARS ?= +_ANSIBLE_EXTRA = $(if $(strip $(EXTRA_VARS)),--extra-vars "$(EXTRA_VARS)",) + +ansible-dev-preflight: + cd scripts/ansible && ansible-playbook playbooks/dev-preflight.yml $(_ANSIBLE_EXTRA) + +ansible-dev-teardown: + cd scripts/ansible && ansible-playbook playbooks/dev-teardown.yml $(_ANSIBLE_EXTRA) + +ansible-dev-install: + cd scripts/ansible && ansible-playbook playbooks/dev-install.yml $(_ANSIBLE_EXTRA) + +ansible-dev-reset: + cd scripts/ansible && ansible-playbook playbooks/dev-reset.yml $(_ANSIBLE_EXTRA) + +ansible-dev-deploy: + cd scripts/ansible && ansible-playbook playbooks/dev-deploy.yml $(_ANSIBLE_EXTRA) + +ansible-dev-status: + cd scripts/ansible && ansible-playbook playbooks/dev-status.yml + +ansible-dev-logs: + cd scripts/ansible && ansible-playbook playbooks/dev-logs.yml + +# Snapshot / restore require an explicit -e snapshot_name=. The +# wrapper passes ANSIBLE_EXTRA through so devs can run +# `make ansible-dev-snapshot ANSIBLE_EXTRA='-e snapshot_name=before-merge'`. +ansible-dev-snapshot: + cd scripts/ansible && ansible-playbook playbooks/dev-snapshot.yml $(ANSIBLE_EXTRA) + +ansible-dev-restore: + cd scripts/ansible && ansible-playbook playbooks/dev-restore.yml $(ANSIBLE_EXTRA) + +ansible-dev-version: + cd scripts/ansible && ansible-playbook playbooks/dev-version.yml + +ansible-dev-vpc: + cd scripts/ansible && ansible-playbook playbooks/dev-vpc.yml $(ANSIBLE_EXTRA) + +# Multi-node cluster bootstrap against a tofu env (env1, env2, bryn, etc). +# Inventory is generated from scripts/tofu-cluster/envs/.tfvars. +# make ansible-cluster-bootstrap ENV=env1 POOL=192.168.1.150-192.168.1.159 +ENV ?= +POOL ?= +ansible-cluster-bootstrap: + @test -n "$(ENV)" || { echo "ENV= required (e.g. env1, env2)"; exit 64; } + cd scripts/ansible && CLUSTER_ENV=$(ENV) ansible-playbook -i inventory/tofu.py playbooks/cluster-bootstrap.yml \ + -e cluster_env=$(ENV) \ + $(if $(POOL),-e cluster_external_pool=$(POOL),) \ + $(_ANSIBLE_EXTRA) + +.PHONY: build build-ui build-installer build-lb-agent build-system-image build-eks-node-image import-eks-node-image build-microvm-image install-microvm go_build go_run preflight test test-cover test-race diff-coverage bench run test-actions test-harness manifest-check diff-coverage bench run \ deploy reinstall clean \ install-system install-go install-aws quickinstall \ lint fix govulncheck \ diff --git a/cmd/spinifex/cmd/admin.go b/cmd/spinifex/cmd/admin.go index 188700d33..655e5ded0 100644 --- a/cmd/spinifex/cmd/admin.go +++ b/cmd/spinifex/cmd/admin.go @@ -325,7 +325,7 @@ func init() { imagesImportCmd.Flags().String("tmp-dir", os.TempDir(), "Temporary directory for image import processing") imagesImportCmd.Flags().String("name", "", "Import specified image by name") - imagesImportCmd.Flags().String("ami-name", "", "Override the registered AMI name (DescribeImages name). Defaults to ami-{distro}-{version}-{arch}. Use for locally-built appliances (e.g. --ami-name spinifex-eks-server).") + imagesImportCmd.Flags().String("ami-name", "", "Override the registered AMI name (DescribeImages name). Defaults to ami-{distro}-{version}-{arch}. Use for locally-built appliances (e.g. --ami-name spinifex-eks-node).") imagesImportCmd.Flags().String("file", "", "Import file from specified path (raw, qcow2, compressed)") imagesImportCmd.Flags().String("distro", "", "Specified distro name (e.g debian)") imagesImportCmd.Flags().String("version", "", "Specified distro version (e.g 12)") diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index e07b01ff2..7b746f8ca 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -89,7 +89,7 @@ Operational commands for inspecting cluster state. These fan out NATS requests t | Command | Flags | Prerequisites | Basic Logic | Test Cases | Status | |---------|-------|---------------|-------------|------------|--------| -| `spx admin images import` | `--name`, `--ami-name`, `--file`, `--distro`, `--version`, `--arch`, `--platform`, `--boot-mode` (bios/uefi/uefi-preferred), `--tag`, `--force`, `--skip-verify` | Cluster must be running; either `--name` (catalog download) or `--file` (operator-supplied media). `--file` mode additionally requires `--distro`, `--version`, `--arch`, `--boot-mode`. | Catalog imports (`--name`) download the image, fetch the catalog `Checksum` URL, verify the SHA-256/SHA-512 digest, and inherit `BootMode` from the catalog entry. `--boot-mode` overrides the catalog value when set. Mismatch fails closed; the cached file is left on disk and `--force` re-downloads. `--file` imports skip checksum verification (operator-supplied media is outside Spinifex's trust boundary, the skip is logged at INFO for audit) and require an explicit `--boot-mode` because there is no catalog metadata to inherit from. `--ami-name` overrides the registered AMI name (the `DescribeImages` name), which otherwise defaults to `ami-{distro}-{version}-{arch}`; use it for locally-built appliance images (e.g. `--ami-name spinifex-eks-server`) not in the catalog. `--skip-verify` bypasses verification for catalog imports and emits a WARN slog + stderr notice; use only for debugging or when upstream mirrors are confirmed-broken. | 1. Import valid catalog image (verifies checksum)
2. Tampered cache hit fails with `ErrChecksumMismatch`
3. `--force` recovers after a mismatch
4. `--file` import skips verification
5. `--skip-verify` bypasses checksum with WARN
6. `--file` without `--boot-mode` rejected
7. `--boot-mode=invalid` rejected | **DONE** | +| `spx admin images import` | `--name`, `--ami-name`, `--file`, `--distro`, `--version`, `--arch`, `--platform`, `--boot-mode` (bios/uefi/uefi-preferred), `--tag`, `--force`, `--skip-verify` | Cluster must be running; either `--name` (catalog download) or `--file` (operator-supplied media). `--file` mode additionally requires `--distro`, `--version`, `--arch`, `--boot-mode`. | Catalog imports (`--name`) download the image, fetch the catalog `Checksum` URL, verify the SHA-256/SHA-512 digest, and inherit `BootMode` from the catalog entry. `--boot-mode` overrides the catalog value when set. Mismatch fails closed; the cached file is left on disk and `--force` re-downloads. `--file` imports skip checksum verification (operator-supplied media is outside Spinifex's trust boundary, the skip is logged at INFO for audit) and require an explicit `--boot-mode` because there is no catalog metadata to inherit from. `--ami-name` overrides the registered AMI name (the `DescribeImages` name), which otherwise defaults to `ami-{distro}-{version}-{arch}`; use it for locally-built appliance images (e.g. `--ami-name spinifex-eks-node`) not in the catalog. `--skip-verify` bypasses verification for catalog imports and emits a WARN slog + stderr notice; use only for debugging or when upstream mirrors are confirmed-broken. | 1. Import valid catalog image (verifies checksum)
2. Tampered cache hit fails with `ErrChecksumMismatch`
3. `--force` recovers after a mismatch
4. `--file` import skips verification
5. `--skip-verify` bypasses checksum with WARN
6. `--file` without `--boot-mode` rejected
7. `--boot-mode=invalid` rejected | **DONE** | | `spx admin images list` | — | None | Lists available OS images that can be imported or downloaded | 1. List available images | **DONE** | | `spx admin images remove` | `--image-id` (required), `--force`, `--yes` | Cluster must be running; predastore reachable. Targets AMIs imported via `spx admin images import` (non-account `ImageOwnerAlias`, e.g. `"system"`). | Loads `ami-/config.json`, walks transitive dependents — copied snapshots whose `VolumeID == imageID`, volumes whose `SnapshotID` references the internal `snap-ami-` or any derived snap, and account AMIs created via `CopyImage` whose `SnapshotID` is a derived snap — then prompts (skipped with `--yes`) before deleting `ami-/config.json` (the DescribeImages barrier) followed by the rest of `ami-/` and `snap-ami-/`. Account-owned AMIs are refused with a hint pointing at `aws ec2 deregister-image` + `aws ec2 delete-snapshot`. `--force` bypasses the dependency, ownership and config-corrupt checks for salvage of orphaned blocks. | 1. Happy path: system AMI, no deps → deleted
2. Account-owned → refused with AWS-flow hint
3. Missing/corrupt config → `InvalidAMIID.NotFound` (salvageable with `--force`)
4. Dependent volume (direct or via copied snap) → refused
5. Dependent account AMI → refused
6. `--force` overrides dependents
7. Idempotent re-run after partial delete | **DONE** | diff --git a/scripts/dev-install.sh b/scripts/dev-install.sh index 7044d105e..e3a86969a 100755 --- a/scripts/dev-install.sh +++ b/scripts/dev-install.sh @@ -90,15 +90,15 @@ fi echo "=== Building and installing microVM artifacts ===" cd "$PROJECT_ROOT" && make build-lb-agent install-microvm -# EKS control-plane AMI. Heavy (full Alpine + K3s build, needs sudo + network), -# so it is opt-in: set DEV_INSTALL_EKS=1 to build + register it. Without it, -# `aws eks create-cluster` fails AMI resolution until the operator runs -# `make import-eks-server-image` manually. +# Unified EKS node AMI (server + agent; role chosen at first boot). Heavy (full +# Alpine + K3s build, needs sudo + network), so it is opt-in: set +# DEV_INSTALL_EKS=1 to build + register it. Without it, `aws eks create-cluster` +# fails AMI resolution until the operator runs `make import-eks-node-image`. if [ "${DEV_INSTALL_EKS:-0}" = "1" ]; then - echo "=== Building + importing eks-server AMI ===" - cd "$PROJECT_ROOT" && make import-eks-server-image + echo "=== Building + importing eks-node AMI ===" + cd "$PROJECT_ROOT" && make import-eks-node-image else - echo "=== Skipping eks-server AMI (set DEV_INSTALL_EKS=1 to enable, or run 'make import-eks-server-image') ===" + echo "=== Skipping eks-node AMI (set DEV_INSTALL_EKS=1 to enable, or run 'make import-eks-node-image') ===" fi echo "=== Done ===" diff --git a/scripts/images/eks-agent/manifest.conf b/scripts/images/eks-agent/manifest.conf deleted file mode 100644 index fc8b5c7bb..000000000 --- a/scripts/images/eks-agent/manifest.conf +++ /dev/null @@ -1,25 +0,0 @@ -IMAGE_NAME="eks-agent" -IMAGE_DESCRIPTION="EKS K3s agent VM — Alpine + K3s v1.32.5+k3s1 (worker node)" -DISTRO="alpine" -ALPINE_VERSION="3.21.7" - -# 2G for the worker — kubelet + containerd + node images. Customer workload -# storage attaches via separate EBS volumes (managed by viperblock); this is -# the OS root only. -IMAGE_SIZE="2G" - -APK_PACKAGES="ca-certificates curl iptables ip6tables conntrack-tools cgroup-tools openrc" - -# K3s binary downloaded by setup.sh (same pinned version + SHA path as -# eks-server) to keep server / agent in lock-step. - -INSTALL_FILES="\ -scripts/images/eks-agent/k3s-agent.initd:/etc/init.d/k3s-agent \ -scripts/images/eks-agent/mulga-eks-state-report.sh:/etc/periodic/15min/mulga-eks-state-report" - -ENABLE_SERVICES="crond k3s-agent" - -SETUP_SCRIPT="scripts/images/eks-agent/setup.sh" - -AMI_NAME="spinifex-eks-agent" -SYSTEM_TAG="spinifex:managed-by=eks" diff --git a/scripts/images/eks-agent/mulga-eks-state-report.sh b/scripts/images/eks-agent/mulga-eks-state-report.sh deleted file mode 100644 index bb382bf38..000000000 --- a/scripts/images/eks-agent/mulga-eks-state-report.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -set -eu - -# mulga-eks-state-report (agent variant) — periodic NATS publish of agent -# liveness signal. Subject: eks.state.{accountID}.{clusterName}.agent.{nodeName} -# Payload: JSON { kubelet: "ok"|"fail", ts: } -# -# The agent has no API server to query for its own status; we shell-check the -# local kubelet socket via crictl, and fall back to a process check. - -ENVFILE=/etc/spinifex-eks/state-report.env -[ -f "${ENVFILE}" ] || { logger -t mulga-eks-state-report "${ENVFILE} missing"; exit 0; } -# shellcheck disable=SC1090 -. "${ENVFILE}" - -: "${SPINIFEX_NATS_URL:?}" -: "${EKS_ACCOUNT_ID:?}" -: "${EKS_CLUSTER_NAME:?}" -: "${EKS_NODE_NAME:?}" - -if pgrep -f 'k3s agent' >/dev/null 2>&1; then - KUBELET=ok -else - KUBELET=fail -fi - -TS=$(date +%s) -PAYLOAD=$(printf '{"kubelet":"%s","ts":%s}' "${KUBELET}" "${TS}") -SUBJ="eks.state.${EKS_ACCOUNT_ID}.${EKS_CLUSTER_NAME}.agent.${EKS_NODE_NAME}" - -NATS_ARGS="-s ${SPINIFEX_NATS_URL}" -if [ -n "${SPINIFEX_NATS_CREDS_FILE:-}" ] && [ -f "${SPINIFEX_NATS_CREDS_FILE}" ]; then - NATS_ARGS="${NATS_ARGS} --creds ${SPINIFEX_NATS_CREDS_FILE}" -fi - -# shellcheck disable=SC2086 -printf '%s' "${PAYLOAD}" | nats ${NATS_ARGS} pub "${SUBJ}" --stdin 2>&1 \ - | logger -t mulga-eks-state-report diff --git a/scripts/images/eks-agent/setup.sh b/scripts/images/eks-agent/setup.sh deleted file mode 100644 index b1ad1897a..000000000 --- a/scripts/images/eks-agent/setup.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/sh -set -eu - -# setup.sh — chroot customisation for the eks-agent AMI. -# Pulls the same K3s release as eks-server (lock-step versioning per Q12) and -# wires the k3s-agent OpenRC service. - -K3S_VERSION="v1.32.5+k3s1" -K3S_URL_BASE="https://github.com/k3s-io/k3s/releases/download/${K3S_VERSION}" - -echo "[eks-agent-setup] fetching k3s checksums ${K3S_VERSION}" -curl -fsSL -o /tmp/k3s-checksums.txt "${K3S_URL_BASE}/sha256sum-amd64.txt" -K3S_SHA256=$(awk '/[ \t]k3s$/{print $1; exit}' /tmp/k3s-checksums.txt) -if [ -z "${K3S_SHA256}" ]; then - echo "[eks-agent-setup] could not parse k3s sha256 from upstream checksums" - cat /tmp/k3s-checksums.txt - exit 1 -fi - -echo "[eks-agent-setup] downloading k3s ${K3S_VERSION} (sha256=${K3S_SHA256})" -curl -fsSL -o /usr/local/bin/k3s "${K3S_URL_BASE}/k3s" -echo "${K3S_SHA256} /usr/local/bin/k3s" > /tmp/k3s.sha256 -if ! sha256sum -c /tmp/k3s.sha256; then - echo "[eks-agent-setup] k3s SHA256 mismatch — refusing to bake AMI" - exit 1 -fi -chmod 0755 /usr/local/bin/k3s -ln -sf /usr/local/bin/k3s /usr/local/bin/kubectl -ln -sf /usr/local/bin/k3s /usr/local/bin/crictl -ln -sf /usr/local/bin/k3s /usr/local/bin/ctr - -# nats-cli — see eks-server setup.sh for rationale. -NATS_CLI_VERSION="0.4.0" -NATS_CLI_URL="https://github.com/nats-io/natscli/releases/download/v${NATS_CLI_VERSION}/nats-${NATS_CLI_VERSION}-linux-amd64.zip" -echo "[eks-agent-setup] downloading nats-cli ${NATS_CLI_VERSION}" -curl -fsSL -o /tmp/nats-cli.zip "${NATS_CLI_URL}" -apk add --no-cache unzip -unzip -q -d /tmp/nats-cli /tmp/nats-cli.zip -install -m 0755 /tmp/nats-cli/nats-${NATS_CLI_VERSION}-linux-amd64/nats /usr/local/bin/nats -rm -rf /tmp/nats-cli /tmp/nats-cli.zip -apk del --no-cache unzip - -chmod 0755 /etc/init.d/k3s-agent -chmod 0755 /etc/periodic/15min/mulga-eks-state-report - -mkdir -p /etc/spinifex-eks -echo "[eks-agent-setup] done" diff --git a/scripts/images/eks-node/eks-node-role.initd b/scripts/images/eks-node/eks-node-role.initd new file mode 100755 index 000000000..8d737672e --- /dev/null +++ b/scripts/images/eks-node/eks-node-role.initd @@ -0,0 +1,27 @@ +#!/sbin/openrc-run +# eks-node-role — one-shot first-boot service that selects the node's role +# (server vs agent) from the cloud-init env and enables + starts the matching +# K3s services. The unified eks-node AMI bakes every role's services but leaves +# them out of the default runlevel; this selector adds the correct ones and then +# removes itself so it runs exactly once. + +description="EKS node role selector (server vs agent)" +# Backgrounded: the selector calls `rc-service k3s start`, which blocks on k3s' +# start-stop-daemon --wait window; backgrounding keeps it off the runlevel's +# critical path. command_background is also required for output_log/error_log. +command="/usr/local/sbin/eks-node-role" +command_background="yes" +pidfile="/run/eks-node-role.pid" +# Route to the serial console so the role decision + any failure is visible in +# the orchestrator's host-side console capture — the VM has no operator login. +output_log="/dev/console" +error_log="/dev/console" + +depend() { + # Needs the same substrate the role services do, since it starts them. + need net cgroups + # cloud-init write_files delivers /etc/spinifex-eks/first-boot.env (the role + # source) in the cloud-config/cloud-final stages. Order after them so the + # selector never races ahead and reads a missing env file on a fast boot. + after firewall cloud-config cloud-final +} diff --git a/scripts/images/eks-node/eks-node-role.sh b/scripts/images/eks-node/eks-node-role.sh new file mode 100755 index 000000000..2d3663a77 --- /dev/null +++ b/scripts/images/eks-node/eks-node-role.sh @@ -0,0 +1,69 @@ +#!/bin/sh +set -eu + +# eks-node-role — first-boot role selector for the unified eks-node AMI. +# +# The same image boots either as a K3s control-plane server or a worker agent; +# the role is chosen per-instance at first boot from SPINIFEX_K3S_ROLE in the +# cloud-init env file. This script enables + starts the matching OpenRC services +# (none are in the default runlevel at bake time), records the resolved role to +# ROLE_FILE so later boots and the etcd-snapshot cron can branch without +# re-parsing, then removes itself from the runlevel so it runs exactly once. +# +# server → eks-token-webhook, k3s (server), k3s-first-boot (bootstrap publish) +# agent → k3s-agent +# +# Paths are overridable via env so the selection logic is unit-testable (bats) +# without root or a real /etc. + +ROLE_FILE="${EKS_NODE_ROLE_FILE:-/etc/spinifex-eks/role}" +ENVFILE="${EKS_NODE_ENVFILE:-/etc/spinifex-eks/first-boot.env}" +AGENT_ENVFILE="${EKS_NODE_AGENT_ENVFILE:-/etc/spinifex-eks/agent.env}" +LOGTAG="eks-node-role" + +log() { echo "[${LOGTAG}] $*"; } +die() { log "ERROR: $*"; exit 1; } + +# Already resolved on a prior boot — the role services are in the runlevel and +# this service should have been pulled, but guard anyway so a stray re-run is a +# no-op rather than a double-enable. +if [ -f "${ROLE_FILE}" ]; then + log "role already resolved ($(cat "${ROLE_FILE}")); nothing to do" + exit 0 +fi + +# Resolve the role. Server seeds SPINIFEX_K3S_ROLE in first-boot.env; a worker +# seed that predates the explicit var is inferred from the presence of agent.env +# (K3S_URL/K3S_TOKEN live there). +ROLE="" +if [ -f "${ENVFILE}" ]; then + ROLE=$(. "${ENVFILE}"; printf '%s' "${SPINIFEX_K3S_ROLE:-}") +fi +if [ -z "${ROLE}" ] && [ -f "${AGENT_ENVFILE}" ]; then + ROLE="agent" +fi + +case "${ROLE}" in + server) + log "configuring server role" + rc-update add eks-token-webhook default + rc-update add k3s default + rc-update add k3s-first-boot default + rc-service eks-token-webhook start + rc-service k3s start + rc-service k3s-first-boot start + ;; + agent) + log "configuring agent role" + rc-update add k3s-agent default + rc-service k3s-agent start + ;; + *) + die "SPINIFEX_K3S_ROLE missing or invalid: '${ROLE}'" + ;; +esac + +mkdir -p "$(dirname "${ROLE_FILE}")" +printf '%s\n' "${ROLE}" > "${ROLE_FILE}" +rc-update del eks-node-role default 2>/dev/null || true +log "role '${ROLE}' configured" diff --git a/scripts/images/eks-node/eks-node-role_test.sh b/scripts/images/eks-node/eks-node-role_test.sh new file mode 100755 index 000000000..ac6d78f33 --- /dev/null +++ b/scripts/images/eks-node/eks-node-role_test.sh @@ -0,0 +1,103 @@ +#!/bin/sh +# Self-contained POSIX test for eks-node-role.sh role selection. No bats/root +# needed: rc-update / rc-service are stubbed on PATH and record their calls; the +# script's file paths are redirected into a temp dir via its EKS_NODE_* env knobs. +# +# Run: sh scripts/images/eks-node/eks-node-role_test.sh +set -eu + +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) +SELECTOR="${SCRIPT_DIR}/eks-node-role.sh" +WORK=$(mktemp -d) +trap 'rm -rf "${WORK}"' EXIT + +# Stub rc-update / rc-service: append "cmd args" to ${CALLS} when invoked. +STUBBIN="${WORK}/bin" +mkdir -p "${STUBBIN}" +for tool in rc-update rc-service; do + cat > "${STUBBIN}/${tool}" <> "\${CALLS}" +exit 0 +EOF + chmod +x "${STUBBIN}/${tool}" +done + +PASS=0 +FAIL=0 +check() { # check + if [ "$2" = "$3" ]; then + PASS=$((PASS + 1)) + else + FAIL=$((FAIL + 1)) + echo "FAIL: $1" + echo " expected: [$2]" + echo " actual: [$3]" + fi +} + +# run_case : resets a per-case dir, exports the knobs; caller seeds env +# files then invokes the selector. Sets CASE (dir), CALLS (log), ROLE_FILE. +run_case() { + CASE="${WORK}/$1" + mkdir -p "${CASE}" + CALLS="${CASE}/calls" + : > "${CALLS}" + ROLE_FILE="${CASE}/role" + export CALLS + export EKS_NODE_ROLE_FILE="${ROLE_FILE}" + export EKS_NODE_ENVFILE="${CASE}/first-boot.env" + export EKS_NODE_AGENT_ENVFILE="${CASE}/agent.env" +} + +# Run the selector, capturing its exit code in ${rc} without tripping set -e. +invoke() { rc=0; PATH="${STUBBIN}:${PATH}" sh "${SELECTOR}" >/dev/null 2>&1 || rc=$?; } + +# --- Case 1: explicit server role --- +run_case server +printf 'SPINIFEX_K3S_ROLE=server\nEKS_CLUSTER_NAME=alpha\n' > "${EKS_NODE_ENVFILE}" +invoke +check "server: exit 0" 0 "${rc}" +check "server: role file" "server" "$(cat "${ROLE_FILE}")" +check "server: enables webhook" "yes" "$(grep -q 'rc-update add eks-token-webhook default' "${CALLS}" && echo yes || echo no)" +check "server: enables k3s" "yes" "$(grep -q 'rc-update add k3s default' "${CALLS}" && echo yes || echo no)" +check "server: enables k3s-first-boot" "yes" "$(grep -q 'rc-update add k3s-first-boot default' "${CALLS}" && echo yes || echo no)" +check "server: starts k3s" "yes" "$(grep -q 'rc-service k3s start' "${CALLS}" && echo yes || echo no)" +check "server: no k3s-agent" "no" "$(grep -q 'k3s-agent' "${CALLS}" && echo yes || echo no)" +check "server: self-disables" "yes" "$(grep -q 'rc-update del eks-node-role default' "${CALLS}" && echo yes || echo no)" + +# --- Case 2: explicit agent role --- +run_case agent_explicit +printf 'SPINIFEX_K3S_ROLE=agent\n' > "${EKS_NODE_ENVFILE}" +invoke +check "agent: exit 0" 0 "${rc}" +check "agent: role file" "agent" "$(cat "${ROLE_FILE}")" +check "agent: enables k3s-agent" "yes" "$(grep -q 'rc-update add k3s-agent default' "${CALLS}" && echo yes || echo no)" +check "agent: no server services" "no" "$(grep -qE 'eks-token-webhook|k3s-first-boot|add k3s default' "${CALLS}" && echo yes || echo no)" + +# --- Case 3: agent inferred from agent.env (no explicit role) --- +run_case agent_inferred +printf 'K3S_URL=https://nlb:443\nK3S_TOKEN=abc\n' > "${EKS_NODE_AGENT_ENVFILE}" +invoke +check "infer: exit 0" 0 "${rc}" +check "infer: role file" "agent" "$(cat "${ROLE_FILE}")" +check "infer: enables k3s-agent" "yes" "$(grep -q 'rc-update add k3s-agent default' "${CALLS}" && echo yes || echo no)" + +# --- Case 4: missing role + no env files → fail, no role file, no services --- +run_case missing +invoke +check "missing: nonzero exit" "1" "${rc}" +check "missing: no role file" "absent" "$([ -f "${ROLE_FILE}" ] && echo present || echo absent)" +check "missing: no rc calls" "" "$(cat "${CALLS}")" + +# --- Case 5: already resolved (role file present) → no-op, exit 0 --- +run_case resolved +printf 'SPINIFEX_K3S_ROLE=server\n' > "${EKS_NODE_ENVFILE}" +printf 'server\n' > "${ROLE_FILE}" +invoke +check "resolved: exit 0" 0 "${rc}" +check "resolved: no rc calls" "" "$(cat "${CALLS}")" + +echo "---" +echo "PASS=${PASS} FAIL=${FAIL}" +[ "${FAIL}" -eq 0 ] diff --git a/scripts/images/eks-server/eks-token-webhook.initd b/scripts/images/eks-node/eks-token-webhook.initd old mode 100644 new mode 100755 similarity index 100% rename from scripts/images/eks-server/eks-token-webhook.initd rename to scripts/images/eks-node/eks-token-webhook.initd diff --git a/scripts/images/eks-agent/k3s-agent.initd b/scripts/images/eks-node/k3s-agent.initd old mode 100644 new mode 100755 similarity index 100% rename from scripts/images/eks-agent/k3s-agent.initd rename to scripts/images/eks-node/k3s-agent.initd diff --git a/scripts/images/eks-server/k3s-first-boot.initd b/scripts/images/eks-node/k3s-first-boot.initd old mode 100644 new mode 100755 similarity index 100% rename from scripts/images/eks-server/k3s-first-boot.initd rename to scripts/images/eks-node/k3s-first-boot.initd diff --git a/scripts/images/eks-server/k3s-first-boot.sh b/scripts/images/eks-node/k3s-first-boot.sh old mode 100644 new mode 100755 similarity index 100% rename from scripts/images/eks-server/k3s-first-boot.sh rename to scripts/images/eks-node/k3s-first-boot.sh diff --git a/scripts/images/eks-server/k3s.initd b/scripts/images/eks-node/k3s.initd old mode 100644 new mode 100755 similarity index 100% rename from scripts/images/eks-server/k3s.initd rename to scripts/images/eks-node/k3s.initd diff --git a/scripts/images/eks-node/manifest.conf b/scripts/images/eks-node/manifest.conf new file mode 100644 index 000000000..6d1e9d13d --- /dev/null +++ b/scripts/images/eks-node/manifest.conf @@ -0,0 +1,44 @@ +IMAGE_NAME="eks-node" +IMAGE_DESCRIPTION="Unified EKS K3s node VM — Alpine + K3s v1.32.5+k3s1 + eks-token-webhook; role (server|agent) chosen at first boot" +DISTRO="alpine" +ALPINE_VERSION="3.21.7" + +# 4G — server superset (K3s server binary + SQLite datastore working set under +# /var/lib/rancher/k3s on the root disk). Agents use the same image; the ~10MB +# of unused server binary + webhook is dwarfed by the headroom for node images. +IMAGE_SIZE="4G" + +# Server superset of both package sets (etcd-ctl is ~5MB, not worth branching). +# K3s pulls cgroups + iptables; nats-cli used by k3s-first-boot publisher + +# state-report; jq builds the bootstrap-message JSON envelopes; etcd-client +# used by the snapshot script (server role only). +APK_PACKAGES="ca-certificates curl jq iptables ip6tables conntrack-tools cgroup-tools etcd-ctl openrc" + +# eks-token-webhook binary always installed (agents never start it). The k3s +# binary is downloaded + SHA256-verified by setup.sh (network in chroot). +BUILD_COMMANDS="CGO_ENABLED=0 go build -o bin/eks-token-webhook ./cmd/eks-token-webhook" + +INSTALL_BINARIES="bin/eks-token-webhook:/usr/local/bin/eks-token-webhook" + +# All role services ship; none but the selector are enabled at bake time. +# eks-node-role picks server vs agent at first boot and enables the rest. +INSTALL_FILES="\ +scripts/images/eks-node/eks-node-role.initd:/etc/init.d/eks-node-role \ +scripts/images/eks-node/eks-node-role.sh:/usr/local/sbin/eks-node-role \ +scripts/images/eks-node/k3s.initd:/etc/init.d/k3s \ +scripts/images/eks-node/k3s-agent.initd:/etc/init.d/k3s-agent \ +scripts/images/eks-node/eks-token-webhook.initd:/etc/init.d/eks-token-webhook \ +scripts/images/eks-node/k3s-first-boot.initd:/etc/init.d/k3s-first-boot \ +scripts/images/eks-node/k3s-first-boot.sh:/usr/local/sbin/k3s-first-boot \ +scripts/images/eks-node/mulga-eks-state-report.sh:/etc/periodic/15min/mulga-eks-state-report \ +scripts/images/eks-node/mulga-eks-etcd-snapshot.sh:/etc/periodic/daily/mulga-eks-etcd-snapshot" + +# Only crond (state-report) + the role selector at bake. The selector adds the +# role-specific services (k3s/eks-token-webhook/k3s-first-boot or k3s-agent) to +# the default runlevel on first boot. +ENABLE_SERVICES="crond eks-node-role" + +SETUP_SCRIPT="scripts/images/eks-node/setup.sh" + +AMI_NAME="spinifex-eks-node" +SYSTEM_TAG="spinifex:managed-by=eks" diff --git a/scripts/images/eks-server/mulga-eks-etcd-snapshot.sh b/scripts/images/eks-node/mulga-eks-etcd-snapshot.sh old mode 100644 new mode 100755 similarity index 90% rename from scripts/images/eks-server/mulga-eks-etcd-snapshot.sh rename to scripts/images/eks-node/mulga-eks-etcd-snapshot.sh index 3798b258f..782a4b2ae --- a/scripts/images/eks-server/mulga-eks-etcd-snapshot.sh +++ b/scripts/images/eks-node/mulga-eks-etcd-snapshot.sh @@ -12,6 +12,12 @@ set -eu # Retention: managed via S3 lifecycle policy on the bucket; this script does # not prune. +# Worker nodes share the unified eks-node AMI but have no etcd/SQLite datastore +# to snapshot. The role file is written once by eks-node-role at first boot. +if [ "$(cat /etc/spinifex-eks/role 2>/dev/null)" = "agent" ]; then + exit 0 +fi + ENVFILE=/etc/spinifex-eks/etcd-snapshot.env [ -f "${ENVFILE}" ] || { logger -t mulga-eks-etcd-snapshot "${ENVFILE} missing"; exit 0; } # shellcheck disable=SC1090 diff --git a/scripts/images/eks-server/mulga-eks-state-report.sh b/scripts/images/eks-node/mulga-eks-state-report.sh old mode 100644 new mode 100755 similarity index 100% rename from scripts/images/eks-server/mulga-eks-state-report.sh rename to scripts/images/eks-node/mulga-eks-state-report.sh diff --git a/scripts/images/eks-server/setup.sh b/scripts/images/eks-node/setup.sh old mode 100644 new mode 100755 similarity index 67% rename from scripts/images/eks-server/setup.sh rename to scripts/images/eks-node/setup.sh index f47d4e02b..d0dc65088 --- a/scripts/images/eks-server/setup.sh +++ b/scripts/images/eks-node/setup.sh @@ -1,12 +1,13 @@ #!/bin/sh set -eu -# setup.sh — chroot customisation for the eks-server AMI. +# setup.sh — chroot customisation for the unified eks-node AMI (server + agent). # # Runs inside an Alpine 3.21 chroot under build-system-image.sh after packages # and binaries are installed. Downloads the pinned K3s binary, verifies its -# SHA256, drops it into /usr/local/bin, sets executable bits on init scripts + -# cron entries, and writes the K3s server config skeleton. +# SHA256, drops it into /usr/local/bin, sets executable bits on all role init +# scripts + cron entries, and writes the K3s server config skeleton. The role +# (server vs agent) is selected per-instance at first boot by eks-node-role. # # Network access inside the chroot is provided by the host's /etc/resolv.conf # (build-system-image.sh copies it in). curl is in APK_PACKAGES. @@ -18,19 +19,19 @@ K3S_URL_BASE="https://github.com/k3s-io/k3s/releases/download/${K3S_VERSION}" # release replacing both files would still produce a self-consistent download, # so the SHA file URL is the trust anchor — anyone forging a Mulga AMI build # would need to compromise the k3s-io GitHub release artefacts. -echo "[eks-server-setup] fetching k3s checksums ${K3S_VERSION}" +echo "[eks-node-setup] fetching k3s checksums ${K3S_VERSION}" curl -fsSL -o /tmp/k3s-checksums.txt "${K3S_URL_BASE}/sha256sum-amd64.txt" K3S_SHA256=$(awk '/[ \t]k3s$/{print $1; exit}' /tmp/k3s-checksums.txt) if [ -z "${K3S_SHA256}" ]; then - echo "[eks-server-setup] could not parse k3s sha256 from upstream checksums" + echo "[eks-node-setup] could not parse k3s sha256 from upstream checksums" cat /tmp/k3s-checksums.txt exit 1 fi -echo "[eks-server-setup] downloading k3s ${K3S_VERSION} (sha256=${K3S_SHA256})" +echo "[eks-node-setup] downloading k3s ${K3S_VERSION} (sha256=${K3S_SHA256})" curl -fsSL -o /usr/local/bin/k3s "${K3S_URL_BASE}/k3s" echo "${K3S_SHA256} /usr/local/bin/k3s" > /tmp/k3s.sha256 if ! sha256sum -c /tmp/k3s.sha256; then - echo "[eks-server-setup] k3s SHA256 mismatch — refusing to bake AMI" + echo "[eks-node-setup] k3s SHA256 mismatch — refusing to bake AMI" exit 1 fi chmod 0755 /usr/local/bin/k3s @@ -43,7 +44,7 @@ ln -sf /usr/local/bin/k3s /usr/local/bin/ctr # (periodic publishes). NATS_CLI_VERSION="0.4.0" NATS_CLI_URL="https://github.com/nats-io/natscli/releases/download/v${NATS_CLI_VERSION}/nats-${NATS_CLI_VERSION}-linux-amd64.zip" -echo "[eks-server-setup] downloading nats-cli ${NATS_CLI_VERSION}" +echo "[eks-node-setup] downloading nats-cli ${NATS_CLI_VERSION}" curl -fsSL -o /tmp/nats-cli.zip "${NATS_CLI_URL}" apk add --no-cache unzip unzip -q -d /tmp/nats-cli /tmp/nats-cli.zip @@ -51,14 +52,17 @@ install -m 0755 /tmp/nats-cli/nats-${NATS_CLI_VERSION}-linux-amd64/nats /usr/loc rm -rf /tmp/nats-cli /tmp/nats-cli.zip apk del --no-cache unzip -# Init scripts ship as 0644 from INSTALL_FILES; OpenRC requires 0755. -chmod 0755 /etc/init.d/k3s /etc/init.d/eks-token-webhook /etc/init.d/k3s-first-boot -chmod 0755 /usr/local/sbin/k3s-first-boot +# Init scripts ship as 0644 from INSTALL_FILES; OpenRC requires 0755. Every +# role's services are baked; the selector enables the right ones at first boot. +chmod 0755 /etc/init.d/eks-node-role /etc/init.d/k3s /etc/init.d/k3s-agent \ + /etc/init.d/eks-token-webhook /etc/init.d/k3s-first-boot +chmod 0755 /usr/local/sbin/eks-node-role /usr/local/sbin/k3s-first-boot chmod 0755 /etc/periodic/15min/mulga-eks-state-report chmod 0755 /etc/periodic/daily/mulga-eks-etcd-snapshot # K3s server config — skeleton; cloud-init / first-boot fills in the -# per-cluster fields (cluster-cidr, service-cidr, token-file, etc). +# per-cluster fields (cluster-cidr, service-cidr, token-file, etc). Agents +# ignore this file (they run `k3s agent`). # IAM token-auth is wired here via kube-apiserver-arg: the eks-token-webhook # service (ordered `before k3s`) writes its kubeconfig to # /etc/spinifex-eks/token-webhook.kubeconfig before the apiserver reads it. @@ -78,22 +82,25 @@ kube-apiserver-arg: - "authentication-token-webhook-cache-ttl=5m" EOF -# Sentinel file marker — k3s-first-boot self-disables after first success by -# checking for this path. Initial state is "not yet run". +# Shared state dir for both roles (agent.env / role marker live here). +mkdir -p /etc/spinifex-eks + +# Sentinel file marker — k3s-first-boot (server role) self-disables after first +# success by checking for this path. Initial state is "not yet run". touch /var/lib/spinifex-eks/first-boot.pending 2>/dev/null || { mkdir -p /var/lib/spinifex-eks touch /var/lib/spinifex-eks/first-boot.pending } # Bind /dev/console to the serial port so userspace boot output — OpenRC -# service starts, cloud-init, and k3s-first-boot diagnostics — reaches ttyS0, -# which the orchestrator captures to a host-side log. The stock Alpine cloud -# image lists `console=tty0` LAST in default_kernel_opts; Linux makes the last -# console= the controlling /dev/console, so userspace logs to the framebuffer -# and the serial capture sees only kernel dmesg. Reorder so ttyS0 is last in -# both the generator config and the already-rendered extlinux.conf. +# service starts, cloud-init, role selection, and k3s-first-boot diagnostics — +# reaches ttyS0, which the orchestrator captures to a host-side log. The stock +# Alpine cloud image lists `console=tty0` LAST in default_kernel_opts; Linux +# makes the last console= the controlling /dev/console, so userspace logs to +# the framebuffer and the serial capture sees only kernel dmesg. Reorder so +# ttyS0 is last in both the generator config and the rendered extlinux.conf. sed -i \ 's|console=ttyS0,115200n8 console=ttyAMA0,115200n8 console=tty0|console=tty0 console=ttyAMA0,115200n8 console=ttyS0,115200n8|' \ /etc/update-extlinux.conf /boot/extlinux.conf -echo "[eks-server-setup] done" +echo "[eks-node-setup] done" diff --git a/scripts/images/eks-server/manifest.conf b/scripts/images/eks-server/manifest.conf deleted file mode 100644 index 1dcaadce0..000000000 --- a/scripts/images/eks-server/manifest.conf +++ /dev/null @@ -1,35 +0,0 @@ -IMAGE_NAME="eks-server" -IMAGE_DESCRIPTION="EKS K3s server VM — Alpine + K3s v1.32.5+k3s1 + eks-token-webhook + state-report + etcd-snapshot" -DISTRO="alpine" -ALPINE_VERSION="3.21.7" - -# 4G fits Alpine + K3s server binary (~80MB) + SQLite datastore working set. -# v1 single-node uses the embedded SQLite (kine) datastore under -# /var/lib/rancher/k3s on the root disk, which also carries the image + logs. -IMAGE_SIZE="4G" - -# Packages required at runtime (K3s pulls cgroups + iptables; nats-cli used by -# first-boot publisher + state-report; jq builds the bootstrap-message JSON -# envelopes; etcd-client used by snapshot script). -APK_PACKAGES="ca-certificates curl jq iptables ip6tables conntrack-tools cgroup-tools etcd-ctl openrc" - -# k3s binary downloaded by setup.sh (network access inside chroot); SHA256 -# verified at install time per spec Q12. -BUILD_COMMANDS="CGO_ENABLED=0 go build -o bin/eks-token-webhook ./cmd/eks-token-webhook" - -INSTALL_BINARIES="bin/eks-token-webhook:/usr/local/bin/eks-token-webhook" - -INSTALL_FILES="\ -scripts/images/eks-server/k3s.initd:/etc/init.d/k3s \ -scripts/images/eks-server/eks-token-webhook.initd:/etc/init.d/eks-token-webhook \ -scripts/images/eks-server/k3s-first-boot.initd:/etc/init.d/k3s-first-boot \ -scripts/images/eks-server/k3s-first-boot.sh:/usr/local/sbin/k3s-first-boot \ -scripts/images/eks-server/mulga-eks-state-report.sh:/etc/periodic/15min/mulga-eks-state-report \ -scripts/images/eks-server/mulga-eks-etcd-snapshot.sh:/etc/periodic/daily/mulga-eks-etcd-snapshot" - -ENABLE_SERVICES="crond k3s eks-token-webhook k3s-first-boot" - -SETUP_SCRIPT="scripts/images/eks-server/setup.sh" - -AMI_NAME="spinifex-eks-server" -SYSTEM_TAG="spinifex:managed-by=eks" diff --git a/spinifex/handlers/eks/k3s_server_vm.go b/spinifex/handlers/eks/k3s_server_vm.go index b78c95ae9..794f251e2 100644 --- a/spinifex/handlers/eks/k3s_server_vm.go +++ b/spinifex/handlers/eks/k3s_server_vm.go @@ -353,6 +353,10 @@ func buildK3sUserData(in K3sServerInput) string { nlbEndpoint := "https://" + net.JoinHostPort(in.NLBDNS, strconv.FormatInt(clusterNLBListenPort, 10)) envBody := strings.Join([]string{ + // Role the eks-node-role first-boot selector reads to enable the + // control-plane services (k3s server + token webhook + bootstrap + // publisher). Nodegroup workers seed "agent" through their own path. + "SPINIFEX_K3S_ROLE=server", "SPINIFEX_NATS_URL=" + in.NATSURL, "SPINIFEX_NATS_TOKEN=" + in.NATSToken, "SPINIFEX_NATS_CA=" + k3sNATSCAPath, diff --git a/spinifex/handlers/eks/k3s_server_vm_test.go b/spinifex/handlers/eks/k3s_server_vm_test.go index 88bde08de..bed201978 100644 --- a/spinifex/handlers/eks/k3s_server_vm_test.go +++ b/spinifex/handlers/eks/k3s_server_vm_test.go @@ -266,6 +266,9 @@ func TestLaunchK3sServerVM_UserDataContainsAllArtifacts(t *testing.T) { assert.NotContains(t, udata, "path: "+k3sResolvConfPath) assert.Contains(t, udata, "path: "+k3sFirstBootEnvPath) + // The eks-node-role first-boot selector keys off this to start control-plane + // services; without it the unified AMI boots into no role. + assert.Contains(t, udata, "SPINIFEX_K3S_ROLE=server") assert.Contains(t, udata, "SPINIFEX_NATS_URL=nats://localhost:4222") assert.Contains(t, udata, "SPINIFEX_NATS_TOKEN=s3cr3t-token") assert.Contains(t, udata, "SPINIFEX_NATS_CA="+k3sNATSCAPath) diff --git a/spinifex/tags/tags.go b/spinifex/tags/tags.go index 53910c6e6..d705d798b 100644 --- a/spinifex/tags/tags.go +++ b/spinifex/tags/tags.go @@ -15,7 +15,7 @@ const ( ManagedByELBv2 = "elbv2" // ManagedByEKS identifies EKS-owned resources (K3s control-plane VMs, - // their ENIs, the eks-server / eks-agent AMIs, cluster + nodegroup SGs). + // their ENIs, the unified eks-node AMI, cluster + nodegroup SGs). ManagedByEKS = "eks" // LBARNKey stores the parent LB ARN on ELBv2-managed ENIs. From bcb49cd7717cd263b4c706737fe718d0f68680bb Mon Sep 17 00:00:00 2001 From: Julian Sommer <115516918+juliansommer@users.noreply.github.com> Date: Thu, 4 Jun 2026 13:32:44 +1000 Subject: [PATCH 13/73] feat: IMDS v1 (#266) --- build/systemd/spinifex-vpcd.service | 40 +- docs/COMMANDS.md | 267 +++++----- spinifex/daemon/daemon.go | 11 + spinifex/daemon/daemon_handlers_test.go | 7 +- spinifex/gateway/auth.go | 3 +- spinifex/gateway/auth_test.go | 3 + spinifex/gateway/ratelimit.go | 13 - spinifex/gateway/ratelimit_test.go | 23 - spinifex/gateway/sts/handler_test.go | 7 + spinifex/gateway/sts_request_test.go | 6 + .../handlers/ec2/instance/service_impl.go | 13 +- .../ec2/instance/service_impl_test.go | 9 +- spinifex/handlers/ec2/vpc/eni.go | 18 + spinifex/handlers/ec2/vpc/eni_index.go | 52 ++ spinifex/handlers/ec2/vpc/eni_index_test.go | 147 ++++++ spinifex/handlers/ec2/vpc/invariants_test.go | 72 +++ spinifex/handlers/ec2/vpc/service_impl.go | 12 + spinifex/handlers/iam/imds_rpc.go | 57 +++ spinifex/handlers/imds/buckets.go | 72 +++ spinifex/handlers/imds/buckets_test.go | 31 ++ spinifex/handlers/imds/constants.go | 6 + spinifex/handlers/imds/credentials.go | 120 +++++ spinifex/handlers/imds/credentials_test.go | 139 ++++++ spinifex/handlers/imds/instance_lookup.go | 87 ++++ .../handlers/imds/instance_lookup_test.go | 33 ++ spinifex/handlers/imds/metadata.go | 387 +++++++++++++++ spinifex/handlers/imds/metadata_test.go | 418 ++++++++++++++++ spinifex/handlers/imds/nats_clients.go | 134 +++++ spinifex/handlers/imds/nats_clients_test.go | 136 ++++++ spinifex/handlers/imds/resolver.go | 189 ++++++++ spinifex/handlers/imds/resolver_test.go | 190 ++++++++ spinifex/handlers/imds/server.go | 303 ++++++++++++ spinifex/handlers/imds/server_test.go | 122 +++++ spinifex/handlers/imds/service.go | 161 ++++++ spinifex/handlers/imds/token.go | 85 ++++ spinifex/handlers/imds/token_test.go | 95 ++++ spinifex/handlers/imds/veth_store.go | 72 +++ spinifex/handlers/imds/veth_store_test.go | 57 +++ spinifex/handlers/sts/assume_role.go | 139 ++++-- spinifex/handlers/sts/assume_role_test.go | 105 +++- spinifex/handlers/sts/imds_rpc.go | 36 ++ spinifex/handlers/sts/service.go | 5 + spinifex/network/external/igw.go | 27 +- .../external/imds_datapath_contract_test.go | 252 ++++++++++ spinifex/network/external/imds_topology.go | 209 ++++++++ .../network/external/imds_topology_test.go | 168 +++++++ spinifex/network/external/invariants_test.go | 122 +++++ spinifex/network/host/imds_names.go | 34 ++ spinifex/network/host/imds_netns_unit_test.go | 97 ++++ spinifex/network/host/imds_veth.go | 217 +++++++++ spinifex/network/host/imds_veth_test.go | 351 ++++++++++++++ spinifex/network/reconcile/apply.go | 55 ++- spinifex/network/reconcile/invariants_test.go | 135 ++++++ spinifex/network/reconcile/reconcile.go | 8 +- spinifex/network/subscribers/subscribers.go | 8 +- spinifex/network/subscribers/topology.go | 23 +- spinifex/network/topology/dhcp_options.go | 4 + .../network/topology/dhcp_options_test.go | 24 + spinifex/network/topology/manager_live.go | 2 + spinifex/network/topology/names.go | 17 + spinifex/services/awsgw/awsgw.go | 10 + spinifex/services/awsgw/imds_absent_test.go | 23 + spinifex/utils/nats.go | 29 ++ spinifex/utils/utils.go | 10 + spinifex/utils/utils_test.go | 19 + spinifex/vm/vm.go | 3 - spinifex/vpcd/vpcd.go | 37 ++ tests/e2e/harness/diag.go | 34 +- tests/e2e/harness/imds_diag.go | 129 +++++ tests/e2e/single/discovery_test.go | 2 +- tests/e2e/single/imds_test.go | 459 ++++++++++++++++++ tests/e2e/single/main_test.go | 30 +- tests/e2e/single/tests_test.go | 10 + tests/e2e/single/vpc_test.go | 2 +- 74 files changed, 6127 insertions(+), 305 deletions(-) create mode 100644 spinifex/handlers/ec2/vpc/eni_index.go create mode 100644 spinifex/handlers/ec2/vpc/eni_index_test.go create mode 100644 spinifex/handlers/ec2/vpc/invariants_test.go create mode 100644 spinifex/handlers/iam/imds_rpc.go create mode 100644 spinifex/handlers/imds/buckets.go create mode 100644 spinifex/handlers/imds/buckets_test.go create mode 100644 spinifex/handlers/imds/constants.go create mode 100644 spinifex/handlers/imds/credentials.go create mode 100644 spinifex/handlers/imds/credentials_test.go create mode 100644 spinifex/handlers/imds/instance_lookup.go create mode 100644 spinifex/handlers/imds/instance_lookup_test.go create mode 100644 spinifex/handlers/imds/metadata.go create mode 100644 spinifex/handlers/imds/metadata_test.go create mode 100644 spinifex/handlers/imds/nats_clients.go create mode 100644 spinifex/handlers/imds/nats_clients_test.go create mode 100644 spinifex/handlers/imds/resolver.go create mode 100644 spinifex/handlers/imds/resolver_test.go create mode 100644 spinifex/handlers/imds/server.go create mode 100644 spinifex/handlers/imds/server_test.go create mode 100644 spinifex/handlers/imds/service.go create mode 100644 spinifex/handlers/imds/token.go create mode 100644 spinifex/handlers/imds/token_test.go create mode 100644 spinifex/handlers/imds/veth_store.go create mode 100644 spinifex/handlers/imds/veth_store_test.go create mode 100644 spinifex/handlers/sts/imds_rpc.go create mode 100644 spinifex/network/external/imds_datapath_contract_test.go create mode 100644 spinifex/network/external/imds_topology.go create mode 100644 spinifex/network/external/imds_topology_test.go create mode 100644 spinifex/network/external/invariants_test.go create mode 100644 spinifex/network/host/imds_names.go create mode 100644 spinifex/network/host/imds_netns_unit_test.go create mode 100644 spinifex/network/host/imds_veth.go create mode 100644 spinifex/network/host/imds_veth_test.go create mode 100644 spinifex/network/reconcile/invariants_test.go create mode 100644 spinifex/network/topology/dhcp_options_test.go create mode 100644 spinifex/services/awsgw/imds_absent_test.go create mode 100644 tests/e2e/harness/imds_diag.go create mode 100644 tests/e2e/single/imds_test.go diff --git a/build/systemd/spinifex-vpcd.service b/build/systemd/spinifex-vpcd.service index 4c3582779..9e68bd7cc 100644 --- a/build/systemd/spinifex-vpcd.service +++ b/build/systemd/spinifex-vpcd.service @@ -16,25 +16,34 @@ OOMScoreAdjust=-500 Environment=SPINIFEX_CONFIG_PATH=/etc/spinifex/spinifex.toml Environment=SPINIFEX_BASE_DIR=/var/lib/spinifex/vpcd/ -# Filesystem access — NoNewPrivileges omitted (vpcd uses sudo for ovs-vsctl, ovn-nbctl, systemctl) -ProtectSystem=full +# vpcd MUST share the HOST mount namespace. IMDS binds one listener per VPC inside +# a per-VPC netns entered in-process via setns(CLONE_NEWNET); the /run/netns/ +# bind-mount that `ip netns add` creates must be host-visible (for diagnostics) and +# must survive a vpcd restart (so the listener can rebind). ANY filesystem-sandbox +# directive — ProtectSystem / ProtectHome / PrivateTmp / ProtectKernel* / +# ProtectControlGroups / ProtectProc / Read{Only,Write}Paths — forks a PRIVATE +# mount namespace that traps that bind-mount inside vpcd, leaving the host a stale +# handle that fails setns(2) with EINVAL (CI runs 26920490454, 26922587471). Those +# directives are therefore omitted by design, and so is the MountFlags=shared / +# spinifex-netns.service propagation workaround they required. +# +# Boundary that REMAINS: DAC (User=spinifex-vpcd) plus the seccomp / capability / +# namespace / address-family restrictions below. The durable fix that restores +# filesystem sandboxing AND drops CAP_SYS_ADMIN is the process-per-netns model +# (`ip netns exec` helper instead of in-process setns) — see +# docs/development/improvements/imds-l2-datapath.md Phase 5. PrivateDevices=no -ReadOnlyPaths=/etc/spinifex/spinifex.toml /etc/spinifex/ca.pem -ReadWritePaths=/var/lib/spinifex/vpcd /var/log/spinifex -# Hardening -ProtectHome=yes -PrivateTmp=yes +# Hardening that does NOT fork a mount namespace (kept) RestrictSUIDSGID=no LockPersonality=yes RestrictRealtime=yes -RestrictNamespaces=yes ProtectClock=yes -ProtectKernelTunables=yes -ProtectKernelModules=yes -ProtectKernelLogs=yes -ProtectControlGroups=yes -ProtectProc=invisible +# IMDS enters the per-VPC netns via setns(CLONE_NEWNET); the `ip -n ` / +# `ip netns exec` plumbing also unshares a mount namespace (CLONE_NEWNS, to give +# the netns its own /sys), so `mnt` must be allowlisted alongside `net` or the +# first in-netns command fails with EPERM. +RestrictNamespaces=net mnt SystemCallArchitectures=native MemoryDenyWriteExecute=no # AF_PACKET: required by the in-process DHCP client (github.com/insomniacslk/dhcp @@ -44,9 +53,10 @@ RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX AF_NETLINK AF_PACKET # CAP_NET_RAW: open AF_PACKET sockets. # CAP_NET_BIND_SERVICE: covers unicast RENEW to UDP :68. # CAP_NET_ADMIN: already used for ovs-vsctl / ip link wiring on the bridge. +# CAP_SYS_ADMIN: setns(CLONE_NEWNET) into per-VPC IMDS netns to bind the listener. # Note, disabled for now, sudo issue with ovs -AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SETUID CAP_SETGID -CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SETUID CAP_SETGID +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SETUID CAP_SETGID CAP_SYS_ADMIN +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SETUID CAP_SETGID CAP_SYS_ADMIN NoNewPrivileges=no ProtectHostname=yes KeyringMode=private diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index 7b746f8ca..d0e366422 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -8,162 +8,102 @@ Platform management commands not exposed via the AWS gateway API. These are CLI- Service lifecycle commands for starting, stopping, and checking status of all Spinifex cluster services. Each service subcommand supports `start`, `stop`, and `status` operations. -| Command | Flags | Prerequisites | Basic Logic | Status | -|---------|-------|---------------|-------------|--------| -| `spx service predastore start` | `--port` (default: 8443), `--host` (default: 0.0.0.0), `--base-path`, `--config-path`, `--debug`, `--tls-cert`, `--tls-key`, `--backend` (distributed/filesystem, default: distributed), `--node-id` (default: 0), `--pprof`, `--pprof-output` | TLS cert/key, base-path, config-path required | Creates predastore service instance with S3-compatible storage backend → starts service | **DONE** | -| `spx service predastore stop` | — | Predastore must be running | Stops the predastore service | **DONE** | -| `spx service predastore status` | — | None | Reports predastore service status | **DONE** | -| `spx service viperblock start` | `--s3-host` (default: 0.0.0.0:8443), `--s3-bucket` (default: predastore), `--s3-region` (default: ap-southeast-2), `--plugin-path` (auto-detected via `nbdkit --dump-config plugindir`; typically `/usr/lib/x86_64-linux-gnu/nbdkit/plugins/nbdkit-viperblock-plugin.so` on amd64, overridable via `SPINIFEX_VIPERBLOCK_PLUGIN_PATH` in `/etc/spinifex/systemd.env`) | `--config` required, plugin-path must exist on disk | Loads cluster config → connects to NATS and Predastore → starts viperblock block storage service with NBD plugin | **DONE** | -| `spx service viperblock stop` | — | Viperblock must be running | Stops the viperblock service | **DONE** | -| `spx service viperblock status` | — | None | Reports viperblock service status | **DONE** | -| `spx service nats start` | `--port` (default: 4222), `--host` (default: 0.0.0.0), `--debug`, `--data-dir`, `--jetstream` | None | Starts embedded NATS server with optional JetStream | **DONE** | -| `spx service nats stop` | — | NATS must be running | Stops the NATS service | **DONE** | -| `spx service nats status` | — | None | Reports NATS service status | **DONE** | -| `spx service spinifex start` | `--wal-dir` | `--config` required | Loads cluster config → starts spinifex daemon (VM orchestration, NATS subscriptions, health endpoint) | **DONE** | -| `spx service spinifex stop` | — | Spinifex daemon must be running | Stops the spinifex daemon service | **DONE** | -| `spx service spinifex status` | — | None | Reports spinifex daemon service status | **DONE** | -| `spx service awsgw start` | `--host` (default: 0.0.0.0:9999), `--tls-cert`, `--tls-key`, `--debug` | `--config` required | Loads cluster config → starts AWS-compatible gateway with SigV4 auth, IAM policy enforcement, TLS | **DONE** | -| `spx service awsgw stop` | — | AWS gateway must be running | Stops the AWS gateway service | **DONE** | -| `spx service awsgw status` | — | None | Reports AWS gateway service status | **DONE** | -| `spx service spinifex-ui start` | `--port` (default: 3000), `--host` (default: 0.0.0.0), `--tls-cert`, `--tls-key` | None | Starts embedded web UI server serving the React frontend. Aliases: `ui`, `spinifexui` | **DONE** | -| `spx service spinifex-ui stop` | — | spinifex-ui must be running | Stops the spinifex-ui service | **DONE** | -| `spx service spinifex-ui status` | — | None | Reports spinifex-ui service status | **DONE** | -| `spx service vpcd start` | — | `--config` required, OVN/OVS installed | Loads cluster config → starts VPC daemon (subscribes to `vpc.*` NATS events, translates to OVN logical switches/ports/routers) | **DONE** | -| `spx service vpcd stop` | — | vpcd must be running | Stops the vpcd service | **DONE** | -| `spx service vpcd status` | — | None | Reports vpcd service status | **DONE** | +| Command | Flags | Description | +|---------|-------|-------------| +| `spx service predastore start` | `--port` (default: 8443), `--host` (default: 0.0.0.0), `--base-path`, `--config-path`, `--debug`, `--tls-cert`, `--tls-key`, `--backend` (distributed/filesystem, default: distributed), `--node-id` (default: 0), `--pprof`, `--pprof-output` | Creates predastore service instance with S3-compatible storage backend → starts service | +| `spx service predastore stop` | — | Stops the predastore service | +| `spx service predastore status` | — | Reports predastore service status | +| `spx service viperblock start` | `--s3-host` (default: 0.0.0.0:8443), `--s3-bucket` (default: predastore), `--s3-region` (default: ap-southeast-2), `--plugin-path` (auto-detected via `nbdkit --dump-config plugindir`; typically `/usr/lib/x86_64-linux-gnu/nbdkit/plugins/nbdkit-viperblock-plugin.so` on amd64, overridable via `SPINIFEX_VIPERBLOCK_PLUGIN_PATH` in `/etc/spinifex/systemd.env`) | Loads cluster config → connects to NATS and Predastore → starts viperblock block storage service with NBD plugin | +| `spx service viperblock stop` | — | Stops the viperblock service | +| `spx service viperblock status` | — | Reports viperblock service status | +| `spx service nats start` | `--port` (default: 4222), `--host` (default: 0.0.0.0), `--debug`, `--data-dir`, `--jetstream` | Starts embedded NATS server with optional JetStream | +| `spx service nats stop` | — | Stops the NATS service | +| `spx service nats status` | — | Reports NATS service status | +| `spx service spinifex start` | `--wal-dir` | Loads cluster config → starts spinifex daemon (VM orchestration, NATS subscriptions, health endpoint) | +| `spx service spinifex stop` | — | Stops the spinifex daemon service | +| `spx service spinifex status` | — | Reports spinifex daemon service status | +| `spx service awsgw start` | `--host` (default: 0.0.0.0:9999), `--tls-cert`, `--tls-key`, `--debug` | Loads cluster config → starts AWS-compatible gateway with SigV4 auth, IAM policy enforcement, TLS | +| `spx service awsgw stop` | — | Stops the AWS gateway service | +| `spx service awsgw status` | — | Reports AWS gateway service status | +| `spx service spinifex-ui start` | `--port` (default: 3000), `--host` (default: 0.0.0.0), `--tls-cert`, `--tls-key` | Starts embedded web UI server serving the React frontend. Aliases: `ui`, `spinifexui` | +| `spx service spinifex-ui stop` | — | Stops the spinifex-ui service | +| `spx service spinifex-ui status` | — | Reports spinifex-ui service status | +| `spx service vpcd start` | — | Loads cluster config → starts VPC daemon (subscribes to `vpc.*` NATS events, translates to OVN logical switches/ports/routers) | +| `spx service vpcd stop` | — | Stops the vpcd service | +| `spx service vpcd status` | — | Reports vpcd service status | ### Cluster Inspection Operational commands for inspecting cluster state. These fan out NATS requests to all nodes and aggregate responses. -| Command | Flags | Prerequisites | Basic Logic | Output Columns | Status | -|---------|-------|---------------|-------------|----------------|--------| -| `spx get nodes` | `--timeout` (default: 3s) | Cluster must be running (NATS) | Loads config → publishes to `spinifex.node.status` fan-out topic → collects responses within timeout → merges config-known nodes with NATS responders → nodes that don't respond shown as `NotReady` | NAME, STATUS, IP, REGION, AZ, UPTIME, VMs, SERVICES | **DONE** | -| `spx get vms` | `--timeout` (default: 3s) | Cluster must be running (NATS) | Publishes to `spinifex.node.vms` fan-out topic → collects VM info from all nodes → sorts by node then instance ID → prints table. Alias: `spx get instances` | INSTANCE, STATUS, TYPE, VCPU, MEM, NODE, IP, AGE | **DONE** | +| Command | Flags | Description | +|---------|-------|-------------| +| `spx get nodes` | `--timeout` (default: 3s) | Loads config → publishes to `spinifex.node.status` fan-out topic → collects responses within timeout → merges config-known nodes with NATS responders → nodes that don't respond shown as `NotReady` | +| `spx get vms` | `--timeout` (default: 3s) | Publishes to `spinifex.node.vms` fan-out topic → collects VM info from all nodes → sorts by node then instance ID → prints table. Alias: `spx get instances` | ### Resource Monitoring -| Command | Flags | Prerequisites | Basic Logic | Output | Status | -|---------|-------|---------------|-------------|--------|--------| -| `spx top nodes` | `--timeout` (default: 3s) | Cluster must be running (NATS) | Publishes to `spinifex.node.status` fan-out topic → collects CPU/memory usage per node → aggregates instance type capacity across all nodes → prints two tables: per-node resource usage and cluster-wide instance type availability | Table 1: NAME, CPU (used/total), MEM (used/total), GPU (used/total), VMs — GPU column shows `allocated/total` when passthrough is enabled, `0/count*` when the node is GPU-capable but passthrough is disabled, or `-` when no GPU is present. Table 2: INSTANCE TYPE, AVAILABLE, VCPU, MEMORY | **DONE** | +| Command | Flags | Description | +|---------|-------|-------------| +| `spx top nodes` | `--timeout` (default: 3s) | Publishes to `spinifex.node.status` fan-out topic → collects CPU/memory usage per node → aggregates instance type capacity across all nodes → prints two tables: per-node resource usage and cluster-wide instance type availability | ### Cluster Initialization -| Command | Flags | Prerequisites | Basic Logic | Test Cases | Status | -|---------|-------|---------------|-------------|------------|--------| -| `spx admin init` | `--nodes`, `--node`, `--bind`, `--port`, `--region`, `--az`, `--cluster-name`, `--cluster-bind`, `--cluster-routes`, `--predastore-nodes`, `--services`, `--formation-timeout`, `--token-ttl`, `--force` | None (first-time setup) | Generates root IAM credentials (AKIA-prefixed access key + secret) → creates master.key (AES-256, 32 bytes, 0600) → writes bootstrap.json (consumed on first start) → generates CA + server TLS certificates → generates join token (written to `join-token` file, displayed in join command) → creates NATS config with auth token → writes spinifex.toml, awsgw.toml, predastore.toml → configures AWS CLI `spx` profile → creates directory structure under `~/spinifex/` | 1. Init creates all config files
2. Root credentials printed once
3. master.key is 32 bytes, mode 0600
4. bootstrap.json consumed on first start
5. `--force` re-initializes existing config
6. AWS CLI profile `spx` auto-configured
7. Multi-node init generates join token and writes to `/join-token` | **DONE** | -| `spx admin join` | `--host` (required), `--node` (required), `--token` (required), `--bind`, `--port`, `--region`, `--az`, `--cluster-bind`, `--cluster-routes`, `--data-dir`, `--services` | Leader node must be running | Connects to leader node with join token (Authorization: Bearer header) → retrieves cluster configuration → configures local node to join cluster and participate in distributed operations | 1. Join existing cluster
2. Missing host (error)
3. Missing node name (error)
4. Missing token (error)
5. Invalid token (401)
6. Expired token (401) | **DONE** | +| Command | Flags | Description | +|---------|-------|-------------| +| `spx admin init` | `--nodes`, `--node`, `--bind`, `--port`, `--region`, `--az`, `--cluster-name`, `--cluster-bind`, `--cluster-routes`, `--predastore-nodes`, `--services`, `--formation-timeout`, `--token-ttl`, `--force` | Generates root IAM credentials (AKIA-prefixed access key + secret) → creates master.key (AES-256, 32 bytes, 0600) → writes bootstrap.json (consumed on first start) → generates CA + server TLS certificates → generates join token (written to `join-token` file, displayed in join command) → creates NATS config with auth token → writes spinifex.toml, awsgw.toml, predastore.toml → configures AWS CLI `spx` profile → creates directory structure under `~/spinifex/` | +| `spx admin join` | `--host` (required), `--node` (required), `--token` (required), `--bind`, `--port`, `--region`, `--az`, `--cluster-bind`, `--cluster-routes`, `--data-dir`, `--services` | Connects to leader node with join token (Authorization: Bearer header) → retrieves cluster configuration → configures local node to join cluster and participate in distributed operations | ### Version -| Command | Flags | Prerequisites | Basic Logic | Status | -|---------|-------|---------------|-------------|--------| -| `spx version` | — | None | Prints Spinifex version, commit hash, OS, and architecture (populated via build-time ldflags) | **DONE** | +| Command | Flags | Description | +|---------|-------|-------------| +| `spx version` | — | Prints Spinifex version, commit hash, OS, and architecture (populated via build-time ldflags) | ### Cluster Operations -| Command | Flags | Prerequisites | Basic Logic | Test Cases | Status | -|---------|-------|---------------|-------------|------------|--------| -| `spx admin cluster shutdown` | `--force` (shutdown even if nodes don't respond), `--timeout` (max wait per phase, default 120s), `--dry-run` (print phase plan without executing) | Cluster must be running | Performs coordinated, phased shutdown of entire cluster. Phases execute in order: GATE (stop API/UI) → DRAIN (stop VMs) → STORAGE (stop viperblock) → PERSIST (stop predastore) → INFRA (stop NATS/daemon). Each phase waits for all nodes to ACK before proceeding. Uses JetStream state tracking. | 1. Shutdown running cluster
2. All nodes stop cleanly
3. Force shutdown with unresponsive nodes
4. Dry-run prints plan | **DONE** | +| Command | Flags | Description | +|---------|-------|-------------| +| `spx admin cluster shutdown` | `--force` (shutdown even if nodes don't respond), `--timeout` (max wait per phase, default 120s), `--dry-run` (print phase plan without executing) | Performs coordinated, phased shutdown of entire cluster. Phases execute in order: GATE (stop API/UI) → DRAIN (stop VMs) → STORAGE (stop viperblock) → PERSIST (stop predastore) → INFRA (stop NATS/daemon). Each phase waits for all nodes to ACK before proceeding. Uses JetStream state tracking. | ### Certificate Management -| Command | Flags | Prerequisites | Basic Logic | Test Cases | Status | -|---------|-------|---------------|-------------|------------|--------| -| `spx admin cert renew` | `--extra-ip` (additional IPs for SANs), `--extra-dns` (additional DNS names for SANs) | Existing CA from `spx admin init` | Reads existing CA → regenerates server certificate with all current network interface IPs and machine hostname in SANs → writes new cert. Use after adding a new network interface or changing IP addresses. | 1. Renew with auto-detected IPs
2. Renew with extra IPs
3. Renew with extra DNS names | **DONE** | +| Command | Flags | Description | +|---------|-------|-------------| +| `spx admin cert renew` | `--extra-ip` (additional IPs for SANs), `--extra-dns` (additional DNS names for SANs) | Reads existing CA → regenerates server certificate with all current network interface IPs and machine hostname in SANs → writes new cert. Use after adding a new network interface or changing IP addresses. | ### Upgrade Management -| Command | Flags | Prerequisites | Basic Logic | Test Cases | Status | -|---------|-------|---------------|-------------|------------|--------| -| `spx admin upgrade` | `--yes` (apply without prompting), `--config-dir` (persistent, default: `~/spinifex/config`), `--spinifex-dir` (persistent, default: `~/spinifex`) | Existing installation (`spinifex.toml` must exist in config dir) | Reads current config versions from registry → computes pending config migrations (from→to per target) → prints version summary and pending list → prompts for confirmation unless `--yes` → runs `migrate.DefaultRegistry.RunAllConfig()` to apply migrations to config files. Intended for upgrades between Spinifex versions. Operators can skip migrations during install by setting `INSTALL_SPINIFEX_SKIP_MIGRATE=1`, then run `spx admin upgrade` manually to review and apply. After completion, services must be restarted with `sudo systemctl restart spinifex.target`. Invoked non-interactively by `scripts/setup.sh` with `--yes`. | 1. No installation present (error, suggests `spx admin init`)
2. No pending migrations (prints "No pending config migrations")
3. Pending migrations with interactive confirmation (y/yes applies, anything else aborts)
4. Pending migrations with `--yes` (applies without prompt)
5. Migration failure surfaces error and exits non-zero | **DONE** | +| Command | Flags | Description | +|---------|-------|-------------| +| `spx admin upgrade` | `--yes` (apply without prompting), `--config-dir` (persistent, default: `~/spinifex/config`), `--spinifex-dir` (persistent, default: `~/spinifex`) | Reads current config versions from registry → computes pending config migrations (from→to per target) → prints version summary and pending list → prompts for confirmation unless `--yes` → runs `migrate.DefaultRegistry.RunAllConfig()` to apply migrations to config files. Intended for upgrades between Spinifex versions. Operators can skip migrations during install by setting `INSTALL_SPINIFEX_SKIP_MIGRATE=1`, then run `spx admin upgrade` manually to review and apply. After completion, services must be restarted with `sudo systemctl restart spinifex.target`. Invoked non-interactively by `scripts/setup.sh` with `--yes`. | ### Account Management -| Command | Flags | Prerequisites | Basic Logic | Test Cases | Status | -|---------|-------|---------------|-------------|------------|--------| -| `spx admin account create` | `--name` | Cluster must be running (NATS), master key must exist | Connects to NATS → CAS loop on `spinifex-account-counter:next_id` for sequential 12-digit ID → creates Account record in `spinifex-accounts` KV → creates `admin` user in new account → creates access key for admin → creates AdministratorAccess policy (Action:*, Resource:*) → attaches policy → prints credentials | 1. Create first account (ID 000000000001)
2. Sequential IDs (000000000002, etc.)
3. Admin user has full access
4. Credentials printed once | **DONE** | -| `spx admin account list` | — | Cluster must be running (NATS), master key must exist | Connects to NATS → IAMService.ListAccounts() → prints table with Account ID, Name, Status, Created | 1. List all accounts
2. Empty list (only global account) | **DONE** | +| Command | Flags | Description | +|---------|-------|-------------| +| `spx admin account create` | `--name` | Connects to NATS → CAS loop on `spinifex-account-counter:next_id` for sequential 12-digit ID → creates Account record in `spinifex-accounts` KV → creates `admin` user in new account → creates access key for admin → creates AdministratorAccess policy (Action:*, Resource:*) → attaches policy → prints credentials | +| `spx admin account list` | — | Connects to NATS → IAMService.ListAccounts() → prints table with Account ID, Name, Status, Created | ### Image Management -| Command | Flags | Prerequisites | Basic Logic | Test Cases | Status | -|---------|-------|---------------|-------------|------------|--------| -| `spx admin images import` | `--name`, `--ami-name`, `--file`, `--distro`, `--version`, `--arch`, `--platform`, `--boot-mode` (bios/uefi/uefi-preferred), `--tag`, `--force`, `--skip-verify` | Cluster must be running; either `--name` (catalog download) or `--file` (operator-supplied media). `--file` mode additionally requires `--distro`, `--version`, `--arch`, `--boot-mode`. | Catalog imports (`--name`) download the image, fetch the catalog `Checksum` URL, verify the SHA-256/SHA-512 digest, and inherit `BootMode` from the catalog entry. `--boot-mode` overrides the catalog value when set. Mismatch fails closed; the cached file is left on disk and `--force` re-downloads. `--file` imports skip checksum verification (operator-supplied media is outside Spinifex's trust boundary, the skip is logged at INFO for audit) and require an explicit `--boot-mode` because there is no catalog metadata to inherit from. `--ami-name` overrides the registered AMI name (the `DescribeImages` name), which otherwise defaults to `ami-{distro}-{version}-{arch}`; use it for locally-built appliance images (e.g. `--ami-name spinifex-eks-node`) not in the catalog. `--skip-verify` bypasses verification for catalog imports and emits a WARN slog + stderr notice; use only for debugging or when upstream mirrors are confirmed-broken. | 1. Import valid catalog image (verifies checksum)
2. Tampered cache hit fails with `ErrChecksumMismatch`
3. `--force` recovers after a mismatch
4. `--file` import skips verification
5. `--skip-verify` bypasses checksum with WARN
6. `--file` without `--boot-mode` rejected
7. `--boot-mode=invalid` rejected | **DONE** | -| `spx admin images list` | — | None | Lists available OS images that can be imported or downloaded | 1. List available images | **DONE** | -| `spx admin images remove` | `--image-id` (required), `--force`, `--yes` | Cluster must be running; predastore reachable. Targets AMIs imported via `spx admin images import` (non-account `ImageOwnerAlias`, e.g. `"system"`). | Loads `ami-/config.json`, walks transitive dependents — copied snapshots whose `VolumeID == imageID`, volumes whose `SnapshotID` references the internal `snap-ami-` or any derived snap, and account AMIs created via `CopyImage` whose `SnapshotID` is a derived snap — then prompts (skipped with `--yes`) before deleting `ami-/config.json` (the DescribeImages barrier) followed by the rest of `ami-/` and `snap-ami-/`. Account-owned AMIs are refused with a hint pointing at `aws ec2 deregister-image` + `aws ec2 delete-snapshot`. `--force` bypasses the dependency, ownership and config-corrupt checks for salvage of orphaned blocks. | 1. Happy path: system AMI, no deps → deleted
2. Account-owned → refused with AWS-flow hint
3. Missing/corrupt config → `InvalidAMIID.NotFound` (salvageable with `--force`)
4. Dependent volume (direct or via copied snap) → refused
5. Dependent account AMI → refused
6. `--force` overrides dependents
7. Idempotent re-run after partial delete | **DONE** | - -#### Image integrity verification (CMMC SI.L1-3.14.2) - -Catalog imports (`spx admin images import --name `) verify the image -against the catalog-declared SHA-256/SHA-512 digest before extraction. The sums -file is fetched from the catalog `Checksum` URL over HTTPS only (cross-scheme -redirects refused), and verification runs on both fresh downloads and cache -hits so a poisoned cache is caught on the next import. - -On mismatch the import exits non-zero, the cached file is left on disk for -inspection, and the printed guidance is `spx admin images import --name ---force` to re-download. - -`--file` imports skip verification by design: operator-supplied media is -outside Spinifex's trust boundary and the operator is responsible for -integrity (e.g. `sha256sum` against a trusted upstream digest before import). -The skip is recorded as an INFO `slog` event with `reason=local-file-import` -so a CMMC assessor can audit the decision from journald. - -`--skip-verify` bypasses the checksum step for catalog imports. The command -still downloads via the catalog URL but does not compare the image digest -against the sums file. Intended for narrow cases such as debugging upstream -mirror issues or running against a transiently-broken `latest/` path; the -skip is logged at WARN with `reason=skip-verify-flag` and printed to stderr -so operators and assessors see it. Prefer `--file` with an out-of-band -verified image over `--skip-verify` whenever possible. - -**Limitation:** verification confirms the image matches the digest the mirror -served. A mirror compromise that swaps both image and sums file is not -detected; closing that gap requires GPG signature verification of the sums -file, deferred to a later phase. - -#### `spx admin images remove` caveats - -Admin-imported AMIs (`ImageOwnerAlias = "system"`) live -under the `ami-/` S3 prefix and use a viperblock-internal snap checkpoint -at `snap-ami-/` — there is no `snap-/metadata.json`. The AWS handlers -(`DeregisterImage`, `DeleteSnapshot`) reject system owners with -`UnauthorizedOperation`, which is the right behaviour for tenant API callers -but leaves no AWS-flow path to reclaim space. `spx admin images remove` is -the admin-trust-boundary counterpart that performs the dependency walk and -hard-deletes the blocks directly against predastore. - -`CopyImage` of a system AMI is metadata-only: it writes a fresh -`snap-/metadata.json` whose `VolumeID` points at `ami-` and a new -`ami-/config.json` referencing that snap. Volumes launched from the -copied AMI read transitively from `ami-/chunks/...`. The remove command -walks this transitive set and refuses if anything references the target. - -**TOCTOU window:** between the safety scan and the `config.json` delete a -concurrent `RunInstances` against the AMI could create a new dependent -volume. The window is sub-second on a healthy cluster. The admin running -this command is expected to know the fleet's operational state; if the race -fires the result is a `vol-` with deleted backing blocks, recovered by -terminating the orphaned instance. - -**`--force` bypasses every safety check** (dependents, ownership, missing / -corrupt `config.json`). Use only for salvage of orphaned blocks. Running it -against a live system AMI corrupts every dependent volume on the next disk -read. +| Command | Flags | Description | +|---------|-------|-------------| +| `spx admin images import` | `--name`, `--file`, `--distro`, `--version`, `--arch`, `--platform`, `--boot-mode` (bios/uefi/uefi-preferred), `--tag`, `--force`, `--skip-verify` | Catalog imports (`--name`) download the image, fetch the catalog `Checksum` URL, verify the SHA-256/SHA-512 digest, and inherit `BootMode` from the catalog entry. `--boot-mode` overrides the catalog value when set. Mismatch fails closed; the cached file is left on disk and `--force` re-downloads. `--file` imports skip checksum verification (operator-supplied media is outside Spinifex's trust boundary, the skip is logged at INFO for audit) and require an explicit `--boot-mode` because there is no catalog metadata to inherit from. `--skip-verify` bypasses verification for catalog imports and emits a WARN slog + stderr notice; use only for debugging or when upstream mirrors are confirmed-broken. | +| `spx admin images list` | — | Lists available OS images that can be imported or downloaded | +| `spx admin images remove` | `--image-id` (required), `--force`, `--yes` | Loads `ami-/config.json`, walks transitive dependents — copied snapshots whose `VolumeID == imageID`, volumes whose `SnapshotID` references the internal `snap-ami-` or any derived snap, and account AMIs created via `CopyImage` whose `SnapshotID` is a derived snap — then prompts (skipped with `--yes`) before deleting `ami-/config.json` (the DescribeImages barrier) followed by the rest of `ami-/` and `snap-ami-/`. Account-owned AMIs are refused with a hint pointing at `aws ec2 deregister-image` + `aws ec2 delete-snapshot`. `--force` bypasses the dependency, ownership and config-corrupt checks for salvage of orphaned blocks. | ### GPU Management -| Command | Flags | Prerequisites | Basic Logic | Test Cases | Status | -|---------|-------|---------------|-------------|------------|--------| -| `spx admin gpu status` | `--node` (default: local node) | Cluster must be running (NATS) | Queries `spinifex.node.status` fan-out → finds the target node response → prints Node, GPU hardware (model list or "none detected"), IOMMU state, vfio-pci state, passthrough enabled/disabled, and GPU pool allocation (`allocated/total`). Also lists GPU-capable instance types when passthrough is active. | 1. Local node with passthrough enabled (shows pool and instance types)
2. Local node capable but passthrough disabled (shows "run enable")
3. Node without GPU hardware (shows "none detected")
4. `--node` targets a remote node
5. Node not found or not responding (error) | **DONE** | -| `spx admin gpu enable` | — | Cluster must be running (NATS); node must be GPU-capable (IOMMU + vfio-pci configured) | Checks current passthrough state via NATS → errors if already enabled or prerequisites not met (directs to `setup`) → writes `gpu_passthrough = true` to `spinifex.toml` via `admin.SetGPUPassthrough` → sends SIGHUP to `spinifex-daemon` via `systemctl kill -s HUP` → polls node status for up to 30 s until daemon confirms new state → prints final `gpu status` output. Must be run directly on the target host. | 1. Enable on capable node
2. Already enabled (no-op)
3. Prerequisites not met (error, suggests `setup`)
4. Daemon does not confirm within 30 s (timeout error) | **DONE** | -| `spx admin gpu disable` | — | Cluster must be running (NATS); no GPU instances may be running | Checks current passthrough state via NATS → errors if already disabled or if `AllocGPUs > 0` (must terminate GPU instances first) → writes `gpu_passthrough = false` → sends SIGHUP to `spinifex-daemon` → polls for up to 30 s → prints final `gpu status` output. Must be run directly on the target host. | 1. Disable with no GPU instances running
2. Already disabled (no-op)
3. GPU instances running (error with count)
4. Daemon does not confirm within 30 s (timeout error) | **DONE** | -| `spx admin gpu setup` | — | Must be run as root; NVIDIA or AMD GPU must be present | Idempotent host configuration for GPU passthrough. Steps (skipped if already applied): detect GPUs via `gpu.Discover` → collect PCI IDs for all IOMMU-group siblings → check/enable IOMMU in GRUB (`intel_iommu=on iommu=pt` or `amd_iommu=on iommu=pt`) → write vfio udev rule (`/etc/udev/rules.d/99-spinifex-vfio.rules`) → blacklist nouveau (`/etc/modprobe.d/blacklist-nouveau.conf`) → blacklist amdgpu if AMD GPU present (`/etc/modprobe.d/blacklist-amdgpu.conf`) → write vfio-pci early binding config (`/etc/modprobe.d/vfio-pci.conf`) → add vfio modules to initramfs. If any change requires a reboot: runs `update-initramfs -u` and exits with reboot instructions. After reboot: verifies `vfio_pci` module is loaded → verifies each GPU is bound to `vfio-pci` (binds explicitly via `driver_override` if unbound) → calls `gpu enable` to activate passthrough. | 1. First run on unconfigured host (GRUB updated, reboot required)
2. Re-run after reboot (verifies bindings, enables passthrough)
3. Already fully configured (all steps skipped, enables passthrough)
4. AMD GPU present (blacklists amdgpu in addition to nouveau)
5. Not run as root (error)
6. No GPU hardware detected (error) | **DONE** | -| `spx admin gpu mig status` | — (must be run on target host) | NVIDIA GPU with MIG support present | Runs `gpu.Discover()` locally → for each GPU prints: PCI address, model, MIG capability, MIG mode (enabled/disabled/N/A); for GPUs with MIG enabled lists active MIG slices with GI ID, profile name, and mdev path. | 1. Node with MIG enabled (shows slices)
2. MIG capable but not enabled (shows disabled)
3. No MIG-capable GPU (shows N/A for MIG fields) | **DONE** | -| `spx admin gpu mig enable` | `--profile ` (required, e.g. `1g.10gb`), `--gpu ` (optional, default: all MIG-capable GPUs) | Must be run as root; MIG-capable GPU present; no GPU instances running | Checks no GPU instances running (NATS) → discovers MIG-capable GPUs via `gpu.Discover()` (filtered by `--gpu` if set) → enables MIG mode on each target (`gpu.EnableMIGMode`) → lists available profiles (`gpu.ListProfiles`) and validates requested profile name → destroys any existing instances (`gpu.DestroyAllInstances`) → creates new instances filling GPU capacity (`gpu.CreateInstances`) → writes `mig_profile` to `spinifex.toml` via `admin.SetMIGProfile` → sends SIGHUP to `spinifex-daemon`. Must be run directly on the target host. | 1. Enable MIG with valid profile
2. Invalid profile name (error with available profile list)
3. No MIG-capable GPU (error)
4. GPU instances running (error)
5. `--gpu` targets specific GPU
6. Not run as root (error) | **DONE** | -| `spx admin gpu mig disable` | `--gpu ` (optional, default: all MIG-capable GPUs) | Must be run as root; no GPU instances running | Checks no GPU instances running (NATS) → discovers MIG-capable GPUs via `gpu.Discover()` (filtered by `--gpu` if set) → destroys all GPU instances (`gpu.DestroyAllInstances`) → disables MIG mode (`gpu.DisableMIGMode`) → clears `mig_profile` in `spinifex.toml` via `admin.SetMIGProfile` → sends SIGHUP to `spinifex-daemon`. Must be run directly on the target host. | 1. Disable with no running GPU instances
2. GPU instances running (error)
3. MIG not enabled on GPU (skips that GPU)
4. `--gpu` targets specific GPU
5. Not run as root (error) | **DONE** | +| Command | Flags | Description | +|---------|-------|-------------| +| `spx admin gpu status` | `--node` (default: local node) | Queries `spinifex.node.status` fan-out → finds the target node response → prints Node, GPU hardware (model list or "none detected"), IOMMU state, vfio-pci state, passthrough enabled/disabled, and GPU pool allocation (`allocated/total`). Also lists GPU-capable instance types when passthrough is active. | +| `spx admin gpu enable` | — | Checks current passthrough state via NATS → errors if already enabled or prerequisites not met (directs to `setup`) → writes `gpu_passthrough = true` to `spinifex.toml` via `admin.SetGPUPassthrough` → sends SIGHUP to `spinifex-daemon` via `systemctl kill -s HUP` → polls node status for up to 30 s until daemon confirms new state → prints final `gpu status` output. Must be run directly on the target host. | +| `spx admin gpu disable` | — | Checks current passthrough state via NATS → errors if already disabled or if `AllocGPUs > 0` (must terminate GPU instances first) → writes `gpu_passthrough = false` → sends SIGHUP to `spinifex-daemon` → polls for up to 30 s → prints final `gpu status` output. Must be run directly on the target host. | +| `spx admin gpu setup` | — | Idempotent host configuration for GPU passthrough. Steps (skipped if already applied): detect GPUs via `gpu.Discover` → collect PCI IDs for all IOMMU-group siblings → check/enable IOMMU in GRUB (`intel_iommu=on iommu=pt` or `amd_iommu=on iommu=pt`) → write vfio udev rule (`/etc/udev/rules.d/99-spinifex-vfio.rules`) → blacklist nouveau (`/etc/modprobe.d/blacklist-nouveau.conf`) → blacklist amdgpu if AMD GPU present (`/etc/modprobe.d/blacklist-amdgpu.conf`) → write vfio-pci early binding config (`/etc/modprobe.d/vfio-pci.conf`) → add vfio modules to initramfs. If any change requires a reboot: runs `update-initramfs -u` and exits with reboot instructions. After reboot: verifies `vfio_pci` module is loaded → verifies each GPU is bound to `vfio-pci` (binds explicitly via `driver_override` if unbound) → calls `gpu enable` to activate passthrough. | +| `spx admin gpu mig status` | — (must be run on target host) | Runs `gpu.Discover()` locally → for each GPU prints: PCI address, model, MIG capability, MIG mode (enabled/disabled/N/A); for GPUs with MIG enabled lists active MIG slices with GI ID, profile name, and mdev path. | +| `spx admin gpu mig enable` | `--profile ` (required, e.g. `1g.10gb`), `--gpu ` (optional, default: all MIG-capable GPUs) | Checks no GPU instances running (NATS) → discovers MIG-capable GPUs via `gpu.Discover()` (filtered by `--gpu` if set) → enables MIG mode on each target (`gpu.EnableMIGMode`) → lists available profiles (`gpu.ListProfiles`) and validates requested profile name → destroys any existing instances (`gpu.DestroyAllInstances`) → creates new instances filling GPU capacity (`gpu.CreateInstances`) → writes `mig_profile` to `spinifex.toml` via `admin.SetMIGProfile` → sends SIGHUP to `spinifex-daemon`. Must be run directly on the target host. | +| `spx admin gpu mig disable` | `--gpu ` (optional, default: all MIG-capable GPUs) | Checks no GPU instances running (NATS) → discovers MIG-capable GPUs via `gpu.Discover()` (filtered by `--gpu` if set) → destroys all GPU instances (`gpu.DestroyAllInstances`) → disables MIG mode (`gpu.DisableMIGMode`) → clears `mig_profile` in `spinifex.toml` via `admin.SetMIGProfile` → sends SIGHUP to `spinifex-daemon`. Must be run directly on the target host. | ## AWS-Compatible API @@ -295,9 +235,6 @@ by downstream services. ### EC2 — VPC Core -VPC/Subnet/ENI/SG CRUD stores metadata in NATS KV and publishes events to -vpcd for OVN translation. Single AZ for Spinifex v1. - | Command | Implemented Flags | Missing Flags | Status | |---------|-------------------|---------------|--------| | `create-vpc` | `--cidr-block`, `--tag-specifications` | `--instance-tenancy`, `--dry-run` | **DONE** | @@ -393,9 +330,6 @@ EIP commands are only registered when an external IPAM pool is configured. ### EC2 — NAT Gateway -Deleted gateways move to a separate KV bucket with 1-hour TTL for Terraform -polling. - | Command | Implemented Flags | Missing Flags | Status | |---------|-------------------|---------------|--------| | `create-nat-gateway` | `--subnet-id`, `--allocation-id` | `--connectivity-type`, `--tag-specifications`, `--dry-run` | **DONE** | @@ -406,9 +340,6 @@ polling. ### EC2 — Placement Groups -Strategies: `spread` (1 instance per node, strict) and `cluster` (all pinned -to single node). `partition` rejected. - | Command | Implemented Flags | Missing Flags | Status | |---------|-------------------|---------------|--------| | `create-placement-group` | `--group-name`, `--strategy` (spread/cluster) | `--partition-count`, `--spread-level`, `--tag-specifications`, `--dry-run` | **DONE** | @@ -543,9 +474,6 @@ bypasses policy evaluation entirely. ### IAM — Access Keys -Max 2 keys per user. Secrets encrypted with AES-256-GCM using master key, -returned plaintext only at creation. - | Command | Implemented Flags | Missing Flags | Status | |---------|-------------------|---------------|--------| | `create-access-key` | `--user-name` | — | **DONE** | @@ -555,10 +483,6 @@ returned plaintext only at creation. ### IAM — Policies -Policy documents require `Version: "2012-10-17"` and a valid Statement array. -Wildcard action matching supported (`ec2:*`, `ec2:Describe*`, `*`). Evaluation -order: explicit Deny > explicit Allow > implicit Deny. - | Command | Implemented Flags | Missing Flags | Status | |---------|-------------------|---------------|--------| | `create-policy` | `--policy-name`, `--policy-document`, `--path`, `--description` | `--tags` | **DONE** | @@ -570,19 +494,6 @@ order: explicit Deny > explicit Allow > implicit Deny. | `detach-user-policy` | `--user-name`, `--policy-arn` | — | **DONE** | | `list-attached-user-policies` | `--user-name` | `--path-prefix`, `--max-items`, `--marker` | **DONE** | -### IAM — Policy Evaluation (internal — not an AWS API) - -| Feature | Status | -|---------|--------| -| Root user bypass | **DONE** | -| Default deny | **DONE** | -| Explicit allow | **DONE** | -| Explicit deny | **DONE** | -| Wildcard matching (`*`, `ec2:*`, `ec2:Describe*`) | **DONE** | -| Account-scoped evaluation | **DONE** | -| EC2 action mapping | **DONE** | -| IAM action mapping (16 actions) | **DONE** | - ### IAM — Roles | Command | Implemented Flags | Missing Flags | Status | @@ -599,9 +510,6 @@ order: explicit Deny > explicit Allow > implicit Deny. ### IAM — Instance Profiles -Containers for IAM roles that allow EC2 instances to assume a role. Required -for `run-instances --iam-instance-profile`. Max 1 role per profile. - | Command | Implemented Flags | Missing Flags | Status | |---------|-------------------|---------------|--------| | `create-instance-profile` | `--instance-profile-name`, `--path`, `--tags` | — | **DONE** | @@ -631,7 +539,7 @@ for `run-instances --iam-instance-profile`. Max 1 role per profile. ## STS -| Command | Implemented Flags | Missing Flags (rejected if supplied) | Status | +| Command | Implemented Flags | Missing Flags | Status | |---------|-------------------|--------------------------------------|--------| | `get-caller-identity` | — | — | **DONE** | | `assume-role` | `--role-arn`, `--role-session-name`, `--duration-seconds` (900–min(role MaxSessionDuration, 43200)) | `--policy`, `--policy-arns` (→ `PackedPolicyTooLarge`); `--tags`, `--transitive-tag-keys` (→ `InvalidParameterValue`); `--serial-number`, `--token-code` (→ `InvalidParameterValue`); `--external-id`, `--source-identity` (accepted and logged, **not enforced** — no Condition evaluator in v1) | **DONE** | @@ -649,9 +557,52 @@ Condition evaluator so accepting them would silently allow. --- +## IMDS (Instance Metadata Service) + +Available at `169.254.169.254` from inside every running guest VM, matching AWS. The endpoint is reached from within a guest over plain HTTP, exactly as on EC2, with no in-VM agent to install. DHCP and fully static guests reach it identically, with no in-guest route configuration. + +**IMDSv2-only.** Every read requires a session token. A tokenless (v1-style) `GET` returns `401 Unauthorized` with an empty body. Obtain a token with a `PUT /latest/api/token` carrying `X-aws-ec2-metadata-token-ttl-seconds` (1–21600), then send it back in `X-aws-ec2-metadata-token` on every read. + +```bash +# Inside the guest VM: +TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \ + -H "X-aws-ec2-metadata-token-ttl-seconds: 60") +curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \ + http://169.254.169.254/latest/meta-data/instance-id + +# Tokenless GET → 401 Unauthorized (empty body) +curl -i http://169.254.169.254/latest/meta-data/instance-id +``` + +### IMDS — Supported Paths + +| Path | Method | Source | Status | +|------|--------|--------|--------| +| `/latest/api/token` | PUT | Issues an ENI-bound IMDSv2 token; `X-aws-ec2-metadata-token-ttl-seconds` ∈ [1, 21600] required | **DONE** | +| `/latest/meta-data/` | GET | Directory listing of supported children | **DONE** | +| `/latest/meta-data/instance-id` | GET | `vm.ID` | **DONE** | +| `/latest/meta-data/instance-type` | GET | `vm.InstanceType` | **DONE** | +| `/latest/meta-data/ami-id` | GET | launch `ImageId` | **DONE** | +| `/latest/meta-data/local-ipv4` | GET | `ENIRecord.PrivateIpAddress` (== request source IP) | **DONE** | +| `/latest/meta-data/public-ipv4` | GET | EIP, else instance public IP; empty body if none | **DONE** | +| `/latest/meta-data/mac` | GET | `ENIRecord.MacAddress` | **DONE** | +| `/latest/meta-data/security-groups` | GET | `ENIRecord.SecurityGroupIds`, newline-separated | **DONE** | +| `/latest/meta-data/hostname`, `/local-hostname` | GET | Synthesised `ip-..compute.internal` | **DONE** | +| `/latest/meta-data/placement/availability-zone` | GET | `ENIRecord.AvailabilityZone` | **DONE** | +| `/latest/meta-data/placement/region` | GET | Derived from AZ (trailing letter stripped) | **DONE** | +| `/latest/meta-data/iam/info` | GET | `{InstanceProfileArn, InstanceProfileId}`; 404 if no profile | **DONE** | +| `/latest/meta-data/iam/security-credentials/` | GET | Role name(s) under the profile, one per line; empty body if none | **DONE** | +| `/latest/meta-data/iam/security-credentials/` | GET | STS `AssumeRoleForInstance` → ASIA-prefixed temporary credential JSON | **DONE** | +| `/latest/user-data` | GET | `vm.UserData`; 404 if none | **DONE** | +| `/latest/dynamic/instance-identity/document` | GET | Needs a per-cluster signing key | **NOT STARTED** (404; lands with EKS IRSA) | +| `/latest/meta-data/network/interfaces/...` | GET | Multi-ENI rendering | **NOT STARTED** (404) | +| `/latest/meta-data/tags/...` | GET | Instance-tag metadata | **NOT STARTED** (404) | + +--- + ## ELBv2 (Application & Network Load Balancer) -The data plane uses a system-managed LB VM running HAProxy, launched automatically during `create-load-balancer`. HAProxy config is pushed via NATS on listener/target changes. +The data plane uses a system-managed LB VM running HAProxy, launched automatically during `create-load-balancer`. ### ELBv2 — Load Balancers diff --git a/spinifex/daemon/daemon.go b/spinifex/daemon/daemon.go index 06c86945f..fa7323cd2 100644 --- a/spinifex/daemon/daemon.go +++ b/spinifex/daemon/daemon.go @@ -50,6 +50,7 @@ import ( handlers_ec2_vpc "github.com/mulgadc/spinifex/spinifex/handlers/ec2/vpc" handlers_eks "github.com/mulgadc/spinifex/spinifex/handlers/eks" handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2" + handlers_imds "github.com/mulgadc/spinifex/spinifex/handlers/imds" "github.com/mulgadc/spinifex/spinifex/instancetypes" "github.com/mulgadc/spinifex/spinifex/network/external/dhcp" "github.com/mulgadc/spinifex/spinifex/network/host" @@ -1206,6 +1207,16 @@ func (d *Daemon) startCluster() error { return fmt.Errorf("failed to initialize VPC service: %w", err) } + // Wire the eni-by-vpc-ip reverse index so the ENI controller keeps the + // IMDS source-IP→ENI lookup in sync on Create/DeleteNetworkInterface. + if vpcJS, jsErr := d.natsConn.JetStream(); jsErr != nil { + slog.Warn("Failed to get JetStream for eni-by-ip index", "err", jsErr) + } else if eniByIPKV, kvErr := handlers_imds.InitENIByIPBucket(vpcJS, 1); kvErr != nil { + slog.Warn("Failed to init eni-by-ip index bucket", "err", kvErr) + } else { + d.vpcService.SetENIByIPIndex(handlers_ec2_vpc.NewENIByIPIndex(eniByIPKV)) + } + d.routeTableService, err = initServiceWithRetry("RouteTable service", func() (*handlers_ec2_routetable.RouteTableServiceImpl, error) { return handlers_ec2_routetable.NewRouteTableServiceImplWithNATS(d.config, d.natsConn) }) diff --git a/spinifex/daemon/daemon_handlers_test.go b/spinifex/daemon/daemon_handlers_test.go index c1119f817..86108dbfe 100644 --- a/spinifex/daemon/daemon_handlers_test.go +++ b/spinifex/daemon/daemon_handlers_test.go @@ -1658,7 +1658,10 @@ func TestHandleEC2DescribeInstanceAttribute_UserData(t *testing.T) { Status: vm.StateStopped, InstanceType: "t3.micro", AccountID: testAccountID, - UserData: "#!/bin/bash", + RunInstancesInput: &ec2.RunInstancesInput{ + // base64("#!/bin/bash") — DescribeInstanceAttribute returns user-data base64-encoded. + UserData: aws.String("IyEvYmluL2Jhc2g="), + }, Instance: &ec2.Instance{ InstanceId: aws.String(instanceID), }, @@ -1679,7 +1682,7 @@ func TestHandleEC2DescribeInstanceAttribute_UserData(t *testing.T) { err = json.Unmarshal(reply.Data, &output) require.NoError(t, err) require.NotNil(t, output.UserData) - assert.Equal(t, "#!/bin/bash", *output.UserData.Value) + assert.Equal(t, "IyEvYmluL2Jhc2g=", *output.UserData.Value) } func TestHandleEC2DescribeInstanceAttribute_DefaultAttribute_DisableApiTermination(t *testing.T) { diff --git a/spinifex/gateway/auth.go b/spinifex/gateway/auth.go index ac64a88d3..b254fe78c 100644 --- a/spinifex/gateway/auth.go +++ b/spinifex/gateway/auth.go @@ -16,6 +16,7 @@ import ( "github.com/mulgadc/predastore/auth" "github.com/mulgadc/spinifex/spinifex/awserrors" handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam" + "github.com/mulgadc/spinifex/spinifex/utils" ) // Maximum request body size for signature validation (10 MB). @@ -36,7 +37,7 @@ func (gw *GatewayConfig) SigV4AuthMiddleware() func(http.Handler) http.Handler { } return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - clientIP := extractClientIP(r) + clientIP := utils.ClientIP(r.RemoteAddr) if errCode := gw.RateLimiter.CheckIP(clientIP); errCode != "" { gw.writeSigV4Error(w, r, errCode) return diff --git a/spinifex/gateway/auth_test.go b/spinifex/gateway/auth_test.go index bebca1008..c2421f295 100644 --- a/spinifex/gateway/auth_test.go +++ b/spinifex/gateway/auth_test.go @@ -1561,6 +1561,9 @@ type mockSTSService struct { func (m *mockSTSService) AssumeRole(_, _, _ string, _ *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) { return nil, nil } +func (m *mockSTSService) AssumeRoleForInstance(_, _, _ string, _ int64) (*sts.AssumeRoleOutput, error) { + return nil, nil +} func (m *mockSTSService) GetCallerIdentity(_, _, _ string, _ *sts.GetCallerIdentityInput) (*sts.GetCallerIdentityOutput, error) { return nil, nil } diff --git a/spinifex/gateway/ratelimit.go b/spinifex/gateway/ratelimit.go index 42155715c..05b40aa50 100644 --- a/spinifex/gateway/ratelimit.go +++ b/spinifex/gateway/ratelimit.go @@ -2,8 +2,6 @@ package gateway import ( "log/slog" - "net" - "net/http" "sync" "time" @@ -187,17 +185,6 @@ func (rl *AuthRateLimiter) cleanup() { } } -// extractClientIP returns the IP address from the request's RemoteAddr, -// stripping the port. Handles both IPv4 and IPv6. -func extractClientIP(r *http.Request) string { - host, _, err := net.SplitHostPort(r.RemoteAddr) - if err != nil { - // RemoteAddr might already be bare IP (no port). - return r.RemoteAddr - } - return host -} - // pruneOldFailures returns only the failures within the sliding window. func pruneOldFailures(failures []time.Time, now time.Time) []time.Time { cutoff := now.Add(-failureWindow) diff --git a/spinifex/gateway/ratelimit_test.go b/spinifex/gateway/ratelimit_test.go index 9ce9e9ecf..4ae068e10 100644 --- a/spinifex/gateway/ratelimit_test.go +++ b/spinifex/gateway/ratelimit_test.go @@ -311,29 +311,6 @@ func TestConcurrentAccess(t *testing.T) { wg.Wait() } -func TestExtractClientIP(t *testing.T) { - tests := []struct { - name string - remoteAddr string - expected string - }{ - {"IPv4 with port", "192.168.1.1:12345", "192.168.1.1"}, - {"IPv6 with port", "[::1]:12345", "::1"}, - {"IPv4 bare", "192.168.1.1", "192.168.1.1"}, - {"IPv6 full with port", "[2001:db8::1]:443", "2001:db8::1"}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := &http.Request{RemoteAddr: tt.remoteAddr} - got := extractClientIP(r) - if got != tt.expected { - t.Errorf("extractClientIP(%q) = %q, want %q", tt.remoteAddr, got, tt.expected) - } - }) - } -} - // setupTestAppWithRateLimiter creates a test HTTP handler with SigV4 auth and // the given rate limiter attached. A real NATS test connection is attached so // the SigV4 middleware's cluster-unavailable short-circuit (mulga-siv-23) does diff --git a/spinifex/gateway/sts/handler_test.go b/spinifex/gateway/sts/handler_test.go index 2eda64bab..35b71dc49 100644 --- a/spinifex/gateway/sts/handler_test.go +++ b/spinifex/gateway/sts/handler_test.go @@ -32,6 +32,13 @@ func (s *stubSTSService) AssumeRole(callerAccountID, callerARN, callerIdentity s return &sts.AssumeRoleOutput{}, nil } +// AssumeRoleForInstance is the in-process IMDS entry point and is never +// dispatched over the HTTPS gateway; the stub exists only to satisfy the +// interface. +func (s *stubSTSService) AssumeRoleForInstance(_, _, _ string, _ int64) (*sts.AssumeRoleOutput, error) { + return &sts.AssumeRoleOutput{}, nil +} + func (s *stubSTSService) GetCallerIdentity(callerAccountID, callerARN, callerUserID string, input *sts.GetCallerIdentityInput) (*sts.GetCallerIdentityOutput, error) { if s.getCallerIdentityFn != nil { return s.getCallerIdentityFn(callerAccountID, callerARN, callerUserID, input) diff --git a/spinifex/gateway/sts_request_test.go b/spinifex/gateway/sts_request_test.go index 0ffd9c64d..639804387 100644 --- a/spinifex/gateway/sts_request_test.go +++ b/spinifex/gateway/sts_request_test.go @@ -37,6 +37,12 @@ func (m *flexMockSTSService) AssumeRole(callerAccountID, callerARN, callerIdenti return &sts.AssumeRoleOutput{}, nil } +// AssumeRoleForInstance is the in-process IMDS entry point, never dispatched +// over the HTTPS gateway; the mock exists only to satisfy the interface. +func (m *flexMockSTSService) AssumeRoleForInstance(_, _, _ string, _ int64) (*sts.AssumeRoleOutput, error) { + return &sts.AssumeRoleOutput{}, nil +} + func (m *flexMockSTSService) GetCallerIdentity(callerAccountID, callerARN, callerUserID string, input *sts.GetCallerIdentityInput) (*sts.GetCallerIdentityOutput, error) { if m.getCallerIdentityFn != nil { return m.getCallerIdentityFn(callerAccountID, callerARN, callerUserID, input) diff --git a/spinifex/handlers/ec2/instance/service_impl.go b/spinifex/handlers/ec2/instance/service_impl.go index 7515443bf..92e3aa606 100644 --- a/spinifex/handlers/ec2/instance/service_impl.go +++ b/spinifex/handlers/ec2/instance/service_impl.go @@ -2426,10 +2426,10 @@ func (s *InstanceServiceImpl) ModifyInstanceAttribute(input *ec2.ModifyInstanceA if input.UserData != nil && input.UserData.Value != nil { slog.Info("ModifyInstanceAttribute: changing user data", "instanceId", instanceID) - instance.UserData = string(input.UserData.Value) - if instance.RunInstancesInput != nil { - instance.RunInstancesInput.UserData = aws.String(base64.StdEncoding.EncodeToString(input.UserData.Value)) + if instance.RunInstancesInput == nil { + instance.RunInstancesInput = &ec2.RunInstancesInput{} } + instance.RunInstancesInput.UserData = aws.String(base64.StdEncoding.EncodeToString(input.UserData.Value)) } if input.DisableApiTermination != nil && input.DisableApiTermination.Value != nil { @@ -2803,7 +2803,12 @@ func (s *InstanceServiceImpl) DescribeInstanceAttribute(input *ec2.DescribeInsta output.InstanceType = &ec2.AttributeValue{Value: &val} case ec2.InstanceAttributeNameUserData: - val := instance.UserData + // AWS returns user-data base64-encoded; RunInstancesInput.UserData is the + // canonical base64 store, set at launch and kept in sync by Modify. + var val string + if instance.RunInstancesInput != nil && instance.RunInstancesInput.UserData != nil { + val = *instance.RunInstancesInput.UserData + } output.UserData = &ec2.AttributeValue{Value: &val} case ec2.InstanceAttributeNameDisableApiTermination: diff --git a/spinifex/handlers/ec2/instance/service_impl_test.go b/spinifex/handlers/ec2/instance/service_impl_test.go index 099e64000..2f0f45adc 100644 --- a/spinifex/handlers/ec2/instance/service_impl_test.go +++ b/spinifex/handlers/ec2/instance/service_impl_test.go @@ -1129,7 +1129,10 @@ func TestDescribeInstanceAttribute_RunningInstance(t *testing.T) { ID: id, InstanceType: "t3.large", AccountID: owner, - UserData: "raw-user-data", + RunInstancesInput: &ec2.RunInstancesInput{ + // base64("raw-user-data") — DescribeInstanceAttribute returns user-data base64-encoded. + UserData: aws.String("cmF3LXVzZXItZGF0YQ=="), + }, } svc := &InstanceServiceImpl{vmMgr: mgrWith(map[string]*vm.VM{id: v})} @@ -1151,7 +1154,7 @@ func TestDescribeInstanceAttribute_RunningInstance(t *testing.T) { attribute: ec2.InstanceAttributeNameUserData, assertions: func(t *testing.T, out *ec2.DescribeInstanceAttributeOutput) { require.NotNil(t, out.UserData) - assert.Equal(t, "raw-user-data", *out.UserData.Value) + assert.Equal(t, "cmF3LXVzZXItZGF0YQ==", *out.UserData.Value) }, }, { @@ -1530,7 +1533,6 @@ func TestModifyInstanceAttribute_ChangeUserData(t *testing.T) { ID: id, Status: vm.StateStopped, AccountID: "acc", - UserData: "old", RunInstancesInput: &ec2.RunInstancesInput{ UserData: aws.String("b2xk"), }, @@ -1548,7 +1550,6 @@ func TestModifyInstanceAttribute_ChangeUserData(t *testing.T) { updated := store.wroteStopped[id] require.NotNil(t, updated) - assert.Equal(t, newContent, updated.UserData) assert.Equal(t, "IyEvYmluL2Jhc2g=", *updated.RunInstancesInput.UserData) } diff --git a/spinifex/handlers/ec2/vpc/eni.go b/spinifex/handlers/ec2/vpc/eni.go index a90494b10..e28749bcf 100644 --- a/spinifex/handlers/ec2/vpc/eni.go +++ b/spinifex/handlers/ec2/vpc/eni.go @@ -144,6 +144,15 @@ func (s *VPCServiceImpl) CreateNetworkInterface(input *ec2.CreateNetworkInterfac return nil, errors.New(awserrors.ErrorServerInternal) } + // Maintain the eni-by-vpc-ip reverse index after the source-of-truth ENI + // write. A failure here leaves IMDS returning safe 404s for this IP rather + // than phantom permissions, so it is logged, not fatal. + if s.eniIndex != nil { + if err := s.eniIndex.Put(subnet.VpcId, privateIP, eniId, accountID); err != nil { + slog.Warn("CreateNetworkInterface: eni-by-ip index write failed", "eniId", eniId, "vpcId", subnet.VpcId, "ip", privateIP, "err", err) + } + } + slog.Info("CreateNetworkInterface completed", "eniId", eniId, "subnetId", subnetId, "ip", privateIP, "accountID", accountID) // Send vpc.create-port synchronously so vpcd OVSDB errors surface to the @@ -213,6 +222,15 @@ func (s *VPCServiceImpl) DeleteNetworkInterface(input *ec2.DeleteNetworkInterfac return nil, errors.New(awserrors.ErrorServerInternal) } + // Drop the eni-by-vpc-ip reverse index entry. Idempotent and non-fatal: + // the source-of-truth ENI is already gone, so a stale index entry would + // only resolve to a now-missing ENI and surface as a safe 404. + if s.eniIndex != nil { + if err := s.eniIndex.Delete(record.VpcId, record.PrivateIpAddress); err != nil { + slog.Warn("DeleteNetworkInterface: eni-by-ip index delete failed", "eniId", eniId, "vpcId", record.VpcId, "ip", record.PrivateIpAddress, "err", err) + } + } + slog.Info("DeleteNetworkInterface completed", "eniId", eniId, "accountID", accountID) // Publish vpc.delete-port event for vpcd topology cleanup. SG IDs are diff --git a/spinifex/handlers/ec2/vpc/eni_index.go b/spinifex/handlers/ec2/vpc/eni_index.go new file mode 100644 index 000000000..226555a55 --- /dev/null +++ b/spinifex/handlers/ec2/vpc/eni_index.go @@ -0,0 +1,52 @@ +package handlers_ec2_vpc + +import ( + "encoding/json" + "errors" + "fmt" + + "github.com/nats-io/nats.go" +) + +// eniByIPValue is the stored shape of a spinifex-network-eni-by-vpc-ip row: the ENI +// ID plus its owning account (the ENI bucket is keyed "{accountID}.{eniID}"). Both are +// immutable identity, letting the handler resolve the ENI's account in a single Get. +type eniByIPValue struct { + ENIId string `json:"eni_id"` + AccountID string `json:"account_id"` +} + +// ENIByIPIndex maintains the spinifex-network-eni-by-vpc-ip reverse index +// (vpcID/ip → eniID), so the IMDS handler resolves a source IP to an ENI in one +// KV read. Written on CreateNetworkInterface, deleted on DeleteNetworkInterface. +type ENIByIPIndex struct { + kv nats.KeyValue +} + +// NewENIByIPIndex wraps an already-opened eni-by-vpc-ip KV bucket. +func NewENIByIPIndex(kv nats.KeyValue) *ENIByIPIndex { return &ENIByIPIndex{kv: kv} } + +// eniByVPCIPKey builds the composite vpcID/ip key. +func eniByVPCIPKey(vpcID, ip string) string { return vpcID + "/" + ip } + +// Put writes the vpcID/ip → {eniID, accountID} mapping, overwriting any prior +// entry. Called after the source-of-truth ENI record is persisted so that a +// failure here leaves IMDS returning safe 404s rather than phantom permissions. +func (i *ENIByIPIndex) Put(vpcID, ip, eniID, accountID string) error { + data, err := json.Marshal(eniByIPValue{ENIId: eniID, AccountID: accountID}) + if err != nil { + return fmt.Errorf("marshal eni-by-ip value: %w", err) + } + if _, err := i.kv.Put(eniByVPCIPKey(vpcID, ip), data); err != nil { + return fmt.Errorf("put eni-by-ip index %s/%s: %w", vpcID, ip, err) + } + return nil +} + +// Delete removes the vpcID/ip mapping. Idempotent: a missing key returns nil. +func (i *ENIByIPIndex) Delete(vpcID, ip string) error { + if err := i.kv.Delete(eniByVPCIPKey(vpcID, ip)); err != nil && !errors.Is(err, nats.ErrKeyNotFound) { + return fmt.Errorf("delete eni-by-ip index %s/%s: %w", vpcID, ip, err) + } + return nil +} diff --git a/spinifex/handlers/ec2/vpc/eni_index_test.go b/spinifex/handlers/ec2/vpc/eni_index_test.go new file mode 100644 index 000000000..58a792add --- /dev/null +++ b/spinifex/handlers/ec2/vpc/eni_index_test.go @@ -0,0 +1,147 @@ +package handlers_ec2_vpc + +import ( + "encoding/json" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + handlers_imds "github.com/mulgadc/spinifex/spinifex/handlers/imds" + "github.com/nats-io/nats.go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// openTestENIByIPBucket opens the eni-by-vpc-ip reverse-index bucket on the +// test JetStream, exercising the same init path the daemon uses. +func openTestENIByIPBucket(t *testing.T, nc *nats.Conn) nats.KeyValue { + t.Helper() + js, err := nc.JetStream() + require.NoError(t, err) + kv, err := handlers_imds.InitENIByIPBucket(js, 1) + require.NoError(t, err) + return kv +} + +// readIndexEntry reads the raw vpcID/ip entry and returns its eni_id and +// account_id, or ("", "") when the key is absent. +func readIndexEntry(t *testing.T, kv nats.KeyValue, vpcID, ip string) (eniID, accountID string) { + t.Helper() + entry, err := kv.Get(vpcID + "/" + ip) + if err != nil { + require.ErrorIs(t, err, nats.ErrKeyNotFound) + return "", "" + } + var v struct { + ENIId string `json:"eni_id"` + AccountID string `json:"account_id"` + } + require.NoError(t, json.Unmarshal(entry.Value(), &v)) + return v.ENIId, v.AccountID +} + +// readIndexENIID is the eni_id-only convenience wrapper. +func readIndexENIID(t *testing.T, kv nats.KeyValue, vpcID, ip string) string { + t.Helper() + eniID, _ := readIndexEntry(t, kv, vpcID, ip) + return eniID +} + +func TestENIByIPIndex_PutGetDelete(t *testing.T) { + _, nc := setupTestVPCServiceWithNC(t) + kv := openTestENIByIPBucket(t, nc) + idx := NewENIByIPIndex(kv) + + require.NoError(t, idx.Put("vpc-abc12345", "10.0.1.5", "eni-deadbeef", "111122223333")) + eniID, accountID := readIndexEntry(t, kv, "vpc-abc12345", "10.0.1.5") + assert.Equal(t, "eni-deadbeef", eniID) + assert.Equal(t, "111122223333", accountID) + + // Overwrite is allowed (rebind is a Put). + require.NoError(t, idx.Put("vpc-abc12345", "10.0.1.5", "eni-cafef00d", "111122223333")) + assert.Equal(t, "eni-cafef00d", readIndexENIID(t, kv, "vpc-abc12345", "10.0.1.5")) + + require.NoError(t, idx.Delete("vpc-abc12345", "10.0.1.5")) + assert.Equal(t, "", readIndexENIID(t, kv, "vpc-abc12345", "10.0.1.5")) +} + +func TestENIByIPIndex_DeleteAbsentIsIdempotent(t *testing.T) { + _, nc := setupTestVPCServiceWithNC(t) + idx := NewENIByIPIndex(openTestENIByIPBucket(t, nc)) + require.NoError(t, idx.Delete("vpc-nope", "10.0.0.1")) +} + +func TestENIByIPIndex_KeysAreVPCScoped(t *testing.T) { + // Same IP in two VPCs must not collide — the key includes the VPC ID. + _, nc := setupTestVPCServiceWithNC(t) + kv := openTestENIByIPBucket(t, nc) + idx := NewENIByIPIndex(kv) + + require.NoError(t, idx.Put("vpc-aaaaaaaa", "10.0.1.5", "eni-aaa", "111122223333")) + require.NoError(t, idx.Put("vpc-bbbbbbbb", "10.0.1.5", "eni-bbb", "444455556666")) + + assert.Equal(t, "eni-aaa", readIndexENIID(t, kv, "vpc-aaaaaaaa", "10.0.1.5")) + assert.Equal(t, "eni-bbb", readIndexENIID(t, kv, "vpc-bbbbbbbb", "10.0.1.5")) +} + +func TestCreateNetworkInterface_WritesENIIndex(t *testing.T) { + svc, nc := setupTestVPCServiceWithNC(t) + kv := openTestENIByIPBucket(t, nc) + svc.SetENIByIPIndex(NewENIByIPIndex(kv)) + + vpcID := createTestVPC(t, svc, "10.0.0.0/16") + subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") + + out, err := svc.CreateNetworkInterface(&ec2.CreateNetworkInterfaceInput{ + SubnetId: aws.String(subnetID), + }, testAccountID) + require.NoError(t, err) + + eniID := *out.NetworkInterface.NetworkInterfaceId + ip := *out.NetworkInterface.PrivateIpAddress + gotENI, gotAccount := readIndexEntry(t, kv, vpcID, ip) + assert.Equal(t, eniID, gotENI) + assert.Equal(t, testAccountID, gotAccount) +} + +func TestDeleteNetworkInterface_RemovesENIIndex(t *testing.T) { + svc, nc := setupTestVPCServiceWithNC(t) + kv := openTestENIByIPBucket(t, nc) + svc.SetENIByIPIndex(NewENIByIPIndex(kv)) + + vpcID := createTestVPC(t, svc, "10.0.0.0/16") + subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") + + out, err := svc.CreateNetworkInterface(&ec2.CreateNetworkInterfaceInput{ + SubnetId: aws.String(subnetID), + }, testAccountID) + require.NoError(t, err) + eniID := *out.NetworkInterface.NetworkInterfaceId + ip := *out.NetworkInterface.PrivateIpAddress + require.Equal(t, eniID, readIndexENIID(t, kv, vpcID, ip)) + + _, err = svc.DeleteNetworkInterface(&ec2.DeleteNetworkInterfaceInput{ + NetworkInterfaceId: aws.String(eniID), + }, testAccountID) + require.NoError(t, err) + + assert.Equal(t, "", readIndexENIID(t, kv, vpcID, ip)) +} + +// Regression: ENI lifecycle must not panic or error when no index is wired +// (IMDS-less deployments, focused tests). +func TestCreateDeleteNetworkInterface_NoIndexWired(t *testing.T) { + svc := setupTestVPCService(t) + vpcID := createTestVPC(t, svc, "10.0.0.0/16") + subnetID := createTestSubnet(t, svc, vpcID, "10.0.1.0/24") + + out, err := svc.CreateNetworkInterface(&ec2.CreateNetworkInterfaceInput{ + SubnetId: aws.String(subnetID), + }, testAccountID) + require.NoError(t, err) + + _, err = svc.DeleteNetworkInterface(&ec2.DeleteNetworkInterfaceInput{ + NetworkInterfaceId: out.NetworkInterface.NetworkInterfaceId, + }, testAccountID) + require.NoError(t, err) +} diff --git a/spinifex/handlers/ec2/vpc/invariants_test.go b/spinifex/handlers/ec2/vpc/invariants_test.go new file mode 100644 index 000000000..b33a70d7f --- /dev/null +++ b/spinifex/handlers/ec2/vpc/invariants_test.go @@ -0,0 +1,72 @@ +package handlers_ec2_vpc + +import ( + "encoding/json" + "net" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// IMDS-datapath invariant. + +// TestI4_ENIIndexBucketShape asserts the spinifex-network-eni-by-vpc-ip reverse +// index keeps its contract: keys parse as "vpcID/ip" with a valid IP, values +// carry a non-empty eni_id, and no mutable/denormalised fields creep back into +// the value. The index is identity-only (eni_id + the immutable account_id) by +// design — every mutable field (IPs, MAC, instance ID, profile ARN) is read +// live off the ENIRecord + instance record at request time. A denormalised +// field here resurrects the staleness class the design deliberately removed: +// an IMDS handler trusting a stale profile ARN would mint credentials for the +// wrong role. +func TestI4_ENIIndexBucketShape(t *testing.T) { + _, nc := setupTestVPCServiceWithNC(t) + kv := openTestENIByIPBucket(t, nc) + idx := NewENIByIPIndex(kv) + + // Seed a couple of entries through the real writer. + require.NoError(t, idx.Put("vpc-aaaaaaaa", "10.0.1.5", "eni-aaa", "111122223333")) + require.NoError(t, idx.Put("vpc-bbbbbbbb", "10.0.2.9", "eni-bbb", "444455556666")) + + // allowedFields is the closed set the value JSON may contain. Adding a field + // to eniByIPValue without updating this set fails the test by design — a + // reviewer must justify any new field as immutable identity, not cached + // mutable state. + allowedFields := map[string]struct{}{"eni_id": {}, "account_id": {}} + + keys, err := kv.Keys() + require.NoError(t, err) + require.NotEmpty(t, keys) + + for _, key := range keys { + // Skip migration framework metadata (e.g. _version). + if strings.HasPrefix(key, "_") { + continue + } + vpcID, ip, ok := strings.Cut(key, "/") + require.Truef(t, ok, "key %q does not parse as vpcID/ip", key) + assert.NotEmptyf(t, vpcID, "key %q has empty vpcID", key) + assert.NotNilf(t, net.ParseIP(ip), "key %q has invalid IP %q", key, ip) + + entry, err := kv.Get(key) + require.NoError(t, err) + + var raw map[string]json.RawMessage + require.NoError(t, json.Unmarshal(entry.Value(), &raw)) + + var v struct { + ENIId string `json:"eni_id"` + } + require.NoError(t, json.Unmarshal(entry.Value(), &v)) + assert.NotEmptyf(t, v.ENIId, "index entry %q has empty eni_id", key) + + for field := range raw { + _, allowed := allowedFields[field] + assert.Truef(t, allowed, "index entry %q carries unexpected field %q: the "+ + "eni-by-vpc-ip index is IP→ENI identity only — denormalised mutable "+ + "fields reintroduce the staleness class the design removed", key, field) + } + } +} diff --git a/spinifex/handlers/ec2/vpc/service_impl.go b/spinifex/handlers/ec2/vpc/service_impl.go index 6d6b5a9cd..898ad64f0 100644 --- a/spinifex/handlers/ec2/vpc/service_impl.go +++ b/spinifex/handlers/ec2/vpc/service_impl.go @@ -82,6 +82,11 @@ type VPCServiceImpl struct { // Optional: injected after construction for public IP cleanup in DeleteNetworkInterface. externalIPAM *ExternalIPAM eipKV nats.KeyValue + + // Optional: injected after construction. Maintains the eni-by-vpc-ip + // reverse index the IMDS handler reads. Nil-safe — focused tests and + // IMDS-less deployments leave it unset. + eniIndex *ENIByIPIndex } // SetExternalIPAM injects external IPAM and EIP KV store references so that @@ -91,6 +96,13 @@ func (s *VPCServiceImpl) SetExternalIPAM(ipam *ExternalIPAM, eipKV nats.KeyValue s.eipKV = eipKV } +// SetENIByIPIndex injects the eni-by-vpc-ip reverse-index writer so +// CreateNetworkInterface / DeleteNetworkInterface keep the IMDS source-IP→ENI +// lookup index in sync. Optional: when unset, the index is simply not written. +func (s *VPCServiceImpl) SetENIByIPIndex(index *ENIByIPIndex) { + s.eniIndex = index +} + // localAZ returns the node's local availability zone, sourced from // s.config.AZ. Returns "" when no config is wired (mostly test paths), // which the reconciler treats as a legacy record matching every AZ. diff --git a/spinifex/handlers/iam/imds_rpc.go b/spinifex/handlers/iam/imds_rpc.go new file mode 100644 index 000000000..9cb1bc48e --- /dev/null +++ b/spinifex/handlers/iam/imds_rpc.go @@ -0,0 +1,57 @@ +package handlers_iam + +import ( + "github.com/aws/aws-sdk-go/service/iam" + "github.com/mulgadc/spinifex/spinifex/utils" + "github.com/nats-io/nats.go" +) + +// imdsResponderQueue load-balances the IMDS control-plane RPCs across every +// awsgw in the cluster, matching the cluster-wide worker convention. +const imdsResponderQueue = "spinifex-workers" + +// SubjectResolveInstanceProfile and SubjectGetRole are the internal, ACL-gated +// subjects the IMDS handler (in vpcd) calls to resolve an instance profile and its +// role from awsgw's in-process IAM. Only these two read RPCs are surfaced. +const ( + SubjectResolveInstanceProfile = "imds.iam.resolve_instance_profile" + SubjectGetRole = "imds.iam.get_role" +) + +// ResolveInstanceProfileRequest is the SubjectResolveInstanceProfile payload. +type ResolveInstanceProfileRequest struct { + AccountID string `json:"account_id"` + NameOrARN string `json:"name_or_arn"` +} + +// GetRoleRequest is the SubjectGetRole payload. +type GetRoleRequest struct { + AccountID string `json:"account_id"` + Input *iam.GetRoleInput `json:"input"` +} + +// SubscribeIMDSResponders wires the profile/role responders onto nc, +// queue-grouped so any awsgw can answer. The returned subscriptions are for +// caller-side cleanup. +func (s *IAMServiceImpl) SubscribeIMDSResponders(nc *nats.Conn) ([]*nats.Subscription, error) { + profileSub, err := nc.QueueSubscribe(SubjectResolveInstanceProfile, imdsResponderQueue, func(msg *nats.Msg) { + utils.ServeNATSRequest(msg, func(req *ResolveInstanceProfileRequest) (*InstanceProfile, error) { + return s.ResolveInstanceProfile(req.AccountID, req.NameOrARN) + }) + }) + if err != nil { + return nil, err + } + + roleSub, err := nc.QueueSubscribe(SubjectGetRole, imdsResponderQueue, func(msg *nats.Msg) { + utils.ServeNATSRequest(msg, func(req *GetRoleRequest) (*iam.GetRoleOutput, error) { + return s.GetRole(req.AccountID, req.Input) + }) + }) + if err != nil { + _ = profileSub.Unsubscribe() + return nil, err + } + + return []*nats.Subscription{profileSub, roleSub}, nil +} diff --git a/spinifex/handlers/imds/buckets.go b/spinifex/handlers/imds/buckets.go new file mode 100644 index 000000000..fbcb6679b --- /dev/null +++ b/spinifex/handlers/imds/buckets.go @@ -0,0 +1,72 @@ +package handlers_imds + +import ( + "fmt" + + "github.com/mulgadc/spinifex/spinifex/migrate" + "github.com/nats-io/nats.go" +) + +const ( + // KVBucketIMDSVPCVeth is the canonical record that a VPC has IMDS plumbing + // installed. Keyed by vpcID, the value carries the per-VPC veth/LSP spec the + // BindManager replays to materialise host-side state on every chassis. + KVBucketIMDSVPCVeth = "spinifex-network-imds-vpc-veth" + KVBucketIMDSVPCVethVersion = 1 + + // KVBucketENIByVPCIP is a pure reverse index (vpcID/ip → eniID) so the IMDS + // handler can resolve a request's datapath-attested source IP to an ENI in + // one KV read instead of an O(N) scan of the ENI bucket. + KVBucketENIByVPCIP = "spinifex-network-eni-by-vpc-ip" + KVBucketENIByVPCIPVersion = 1 +) + +// InitBuckets opens (or creates) both IMDS KV buckets and runs any pending +// migrations. History is fixed at 1: both are write-once-per-key, so retained +// revisions only waste storage and lengthen tombstone lifetime. +func InitBuckets(js nats.JetStreamContext, replicas int) (vpcVeth, eniByIP nats.KeyValue, err error) { + vpcVeth, err = initIMDSBucket(js, KVBucketIMDSVPCVeth, KVBucketIMDSVPCVethVersion, replicas) + if err != nil { + return nil, nil, err + } + + eniByIP, err = initIMDSBucket(js, KVBucketENIByVPCIP, KVBucketENIByVPCIPVersion, replicas) + if err != nil { + return nil, nil, err + } + + return vpcVeth, eniByIP, nil +} + +// InitENIByIPBucket opens (or creates) just the eni-by-vpc-ip reverse-index +// bucket, for the ENI controller (in the daemon), which may start before the +// IMDS service and so needs an init path independent of InitBuckets. Idempotent. +func InitENIByIPBucket(js nats.JetStreamContext, replicas int) (nats.KeyValue, error) { + return initIMDSBucket(js, KVBucketENIByVPCIP, KVBucketENIByVPCIPVersion, replicas) +} + +// initIMDSBucket opens (or creates) a single IMDS KV bucket and runs any +// pending migrations. +func initIMDSBucket(js nats.JetStreamContext, bucket string, version, replicas int) (nats.KeyValue, error) { + if replicas < 1 { + replicas = 1 + } + + kv, err := js.CreateKeyValue(&nats.KeyValueConfig{ + Bucket: bucket, + History: 1, + Replicas: replicas, + }) + if err != nil { + kv, err = js.KeyValue(bucket) + if err != nil { + return nil, fmt.Errorf("open %s bucket: %w", bucket, err) + } + } + + if err := migrate.DefaultRegistry.RunKV(bucket, kv, version); err != nil { + return nil, fmt.Errorf("migrate %s: %w", bucket, err) + } + + return kv, nil +} diff --git a/spinifex/handlers/imds/buckets_test.go b/spinifex/handlers/imds/buckets_test.go new file mode 100644 index 000000000..ac02d1460 --- /dev/null +++ b/spinifex/handlers/imds/buckets_test.go @@ -0,0 +1,31 @@ +package handlers_imds + +import ( + "testing" + + "github.com/mulgadc/spinifex/spinifex/testutil" + "github.com/stretchr/testify/require" +) + +func TestInitENIByIPBucket(t *testing.T) { + _, _, js := testutil.StartTestJetStream(t) + kv, err := InitENIByIPBucket(js, 1) + require.NoError(t, err) + require.NotNil(t, kv) +} + +// InitBuckets clamps replicas < 1 to 1, and a second call converges on the +// open-existing fallback rather than failing on the already-created bucket. +func TestInitBuckets_ReplicaClampAndIdempotent(t *testing.T) { + _, _, js := testutil.StartTestJetStream(t) + + vpcVeth, eniByIP, err := InitBuckets(js, 0) + require.NoError(t, err) + require.NotNil(t, vpcVeth) + require.NotNil(t, eniByIP) + + vpcVeth2, eniByIP2, err := InitBuckets(js, 1) + require.NoError(t, err) + require.NotNil(t, vpcVeth2) + require.NotNil(t, eniByIP2) +} diff --git a/spinifex/handlers/imds/constants.go b/spinifex/handlers/imds/constants.go new file mode 100644 index 000000000..6210dece2 --- /dev/null +++ b/spinifex/handlers/imds/constants.go @@ -0,0 +1,6 @@ +package handlers_imds + +// MetaDataServerIP is the link-local address the EC2 Instance Metadata Service is +// served on, identical to AWS. Exported so the network topology layer can set it as +// options:arp_proxy on every subnet router LSP, answering ARP for any guest. +const MetaDataServerIP = "169.254.169.254" diff --git a/spinifex/handlers/imds/credentials.go b/spinifex/handlers/imds/credentials.go new file mode 100644 index 000000000..1a57e01bf --- /dev/null +++ b/spinifex/handlers/imds/credentials.go @@ -0,0 +1,120 @@ +package handlers_imds + +import ( + "encoding/json" + "fmt" + "sync" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/sts" +) + +const ( + // credDurationSeconds is the lifetime of instance-role credentials. 1 hour + // is the AWS default and matches the storage-backed STS v1 design. + credDurationSeconds = 3600 + + // credRefreshWindow is how far before expiry a cached credential is treated + // as stale and re-minted. AWS SDKs refresh at the same 5-minute mark. + credRefreshWindow = 5 * time.Minute +) + +// instanceCredential is the JSON body served at +// /latest/meta-data/iam/security-credentials/, byte-for-byte matching the +// AWS shape so unmodified SDK credential providers parse it. +type instanceCredential struct { + Code string `json:"Code"` + LastUpdated string `json:"LastUpdated"` + Type string `json:"Type"` + AccessKeyId string `json:"AccessKeyId"` + SecretAccessKey string `json:"SecretAccessKey"` + Token string `json:"Token"` + Expiration string `json:"Expiration"` + AccountId string `json:"AccountId"` +} + +// stsAssumer is the narrow slice of STSService the IMDS credential path needs: +// the in-process, EC2-service-principal AssumeRole entry point. Narrowed to an +// interface so the cred cache is unit-testable with a fake. +type stsAssumer interface { + AssumeRoleForInstance(accountID, roleARN, instanceID string, durationSeconds int64) (*sts.AssumeRoleOutput, error) +} + +// cachedCred holds a rendered credential body and the instant at which it should +// be re-minted (expiry minus the refresh window). +type cachedCred struct { + body []byte + refreshAt time.Time +} + +// credCache memoises minted instance-role credentials per (ENI, role) until the +// refresh window. It keeps STS off the hot path: the typical request returns a +// cached body, and only a near-expiry request triggers a fresh assume. +type credCache struct { + sts stsAssumer + mu sync.Mutex + entries map[string]cachedCred +} + +func newCredCache(assumer stsAssumer) *credCache { + return &credCache{sts: assumer, entries: make(map[string]cachedCred)} +} + +// get returns the credential JSON body for an instance's role, minting fresh +// credentials via STS when the cache is cold or within the refresh window. The +// cache key is (eniID, roleName) so two ENIs sharing a role don't collide. +func (c *credCache) get(eni *eniFacts, roleName, roleARN string, now time.Time) ([]byte, error) { + key := eni.eniID + "\x00" + roleName + + c.mu.Lock() + if entry, ok := c.entries[key]; ok && now.Before(entry.refreshAt) { + body := entry.body + c.mu.Unlock() + return body, nil + } + c.mu.Unlock() + + out, err := c.sts.AssumeRoleForInstance(eni.accountID, roleARN, eni.instanceID, credDurationSeconds) + if err != nil { + return nil, err + } + if out == nil || out.Credentials == nil { + return nil, fmt.Errorf("assume role for instance %s returned no credentials", eni.instanceID) + } + + expiration := aws.TimeValue(out.Credentials.Expiration) + body, err := json.Marshal(instanceCredential{ + Code: "Success", + LastUpdated: now.UTC().Format(time.RFC3339), + Type: "AWS-HMAC", + AccessKeyId: aws.StringValue(out.Credentials.AccessKeyId), + SecretAccessKey: aws.StringValue(out.Credentials.SecretAccessKey), + Token: aws.StringValue(out.Credentials.SessionToken), + Expiration: expiration.UTC().Format(time.RFC3339), + AccountId: eni.accountID, + }) + if err != nil { + return nil, fmt.Errorf("marshal instance credential: %w", err) + } + + c.mu.Lock() + c.entries[key] = cachedCred{body: body, refreshAt: expiration.Add(-credRefreshWindow)} + c.mu.Unlock() + + return body, nil +} + +// sweep drops fully-expired entries (past refreshAt + the refresh window, i.e. +// past the credential's actual expiry), bounding the cache against ENI churn: +// a terminated instance's entry is never overwritten and would otherwise leak. +// Evicting a live entry would only force a re-mint, so this is always safe. +func (c *credCache) sweep(now time.Time) { + c.mu.Lock() + defer c.mu.Unlock() + for key, entry := range c.entries { + if now.After(entry.refreshAt.Add(credRefreshWindow)) { + delete(c.entries, key) + } + } +} diff --git a/spinifex/handlers/imds/credentials_test.go b/spinifex/handlers/imds/credentials_test.go new file mode 100644 index 000000000..58d87007b --- /dev/null +++ b/spinifex/handlers/imds/credentials_test.go @@ -0,0 +1,139 @@ +package handlers_imds + +import ( + "encoding/json" + "errors" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/sts" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// fakeAssumer is a programmable stsAssumer that records call counts. +type fakeAssumer struct { + out *sts.AssumeRoleOutput + err error + calls int +} + +func (f *fakeAssumer) AssumeRoleForInstance(_, _, _ string, _ int64) (*sts.AssumeRoleOutput, error) { + f.calls++ + return f.out, f.err +} + +func assumeOutput(akid string, exp time.Time) *sts.AssumeRoleOutput { + return &sts.AssumeRoleOutput{ + Credentials: &sts.Credentials{ + AccessKeyId: aws.String(akid), + SecretAccessKey: aws.String("secret"), + SessionToken: aws.String("token"), + Expiration: aws.Time(exp), + }, + } +} + +func TestCredCache_MintsAndRendersAWSShape(t *testing.T) { + now := time.Unix(1_700_000_000, 0).UTC() + exp := now.Add(time.Hour) + assumer := &fakeAssumer{out: assumeOutput("ASIAEXAMPLE", exp)} + cache := newCredCache(assumer) + + eni := &eniFacts{eniID: "eni-aaa", accountID: "111122223333", instanceID: "i-123"} + body, err := cache.get(eni, "app-role", "arn:aws:iam::111122223333:role/app-role", now) + require.NoError(t, err) + + var cred instanceCredential + require.NoError(t, json.Unmarshal(body, &cred)) + assert.Equal(t, "Success", cred.Code) + assert.Equal(t, "AWS-HMAC", cred.Type) + assert.Equal(t, "ASIAEXAMPLE", cred.AccessKeyId) + assert.Equal(t, "secret", cred.SecretAccessKey) + assert.Equal(t, "token", cred.Token) + assert.Equal(t, "111122223333", cred.AccountId) + assert.Equal(t, exp.Format(time.RFC3339), cred.Expiration) +} + +func TestCredCache_ServesCachedUntilRefreshWindow(t *testing.T) { + now := time.Unix(1_700_000_000, 0).UTC() + exp := now.Add(time.Hour) + assumer := &fakeAssumer{out: assumeOutput("ASIAEXAMPLE", exp)} + cache := newCredCache(assumer) + eni := &eniFacts{eniID: "eni-aaa", accountID: "111122223333", instanceID: "i-123"} + + _, err := cache.get(eni, "app-role", "arn:aws:iam::111122223333:role/app-role", now) + require.NoError(t, err) + // Still well outside the 5-minute refresh window → cached, no new mint. + _, err = cache.get(eni, "app-role", "arn:aws:iam::111122223333:role/app-role", now.Add(50*time.Minute)) + require.NoError(t, err) + assert.Equal(t, 1, assumer.calls, "second request inside the refresh window must hit the cache") +} + +func TestCredCache_RemintsInsideRefreshWindow(t *testing.T) { + now := time.Unix(1_700_000_000, 0).UTC() + exp := now.Add(time.Hour) + assumer := &fakeAssumer{out: assumeOutput("ASIAEXAMPLE", exp)} + cache := newCredCache(assumer) + eni := &eniFacts{eniID: "eni-aaa", accountID: "111122223333", instanceID: "i-123"} + + _, err := cache.get(eni, "app-role", "arn:aws:iam::111122223333:role/app-role", now) + require.NoError(t, err) + // 56 minutes in → within 5 min of expiry → re-mint. + assumer.out = assumeOutput("ASIAREFRESHED", now.Add(2*time.Hour)) + _, err = cache.get(eni, "app-role", "arn:aws:iam::111122223333:role/app-role", now.Add(56*time.Minute)) + require.NoError(t, err) + assert.Equal(t, 2, assumer.calls, "request inside the refresh window must re-mint") +} + +func TestCredCache_PropagatesAssumeError(t *testing.T) { + now := time.Unix(1_700_000_000, 0).UTC() + assumer := &fakeAssumer{err: errors.New("AccessDenied")} + cache := newCredCache(assumer) + eni := &eniFacts{eniID: "eni-aaa", accountID: "111122223333", instanceID: "i-123"} + + _, err := cache.get(eni, "app-role", "arn:aws:iam::111122223333:role/app-role", now) + require.Error(t, err) +} + +func TestCredCache_SweepEvictsExpiredOnly(t *testing.T) { + now := time.Unix(1_700_000_000, 0).UTC() + assumer := &fakeAssumer{out: assumeOutput("ASIAEXAMPLE", now.Add(time.Hour))} + cache := newCredCache(assumer) + + stale := &eniFacts{eniID: "eni-gone", accountID: "111122223333", instanceID: "i-old"} + live := &eniFacts{eniID: "eni-live", accountID: "111122223333", instanceID: "i-new"} + _, err := cache.get(stale, "app-role", "arn:aws:iam::111122223333:role/app-role", now) + require.NoError(t, err) + + // Mint the live entry an hour later so its expiry is still in the future + // when we sweep at the original expiry boundary. + assumer.out = assumeOutput("ASIALIVE", now.Add(2*time.Hour)) + _, err = cache.get(live, "app-role", "arn:aws:iam::111122223333:role/app-role", now.Add(time.Hour)) + require.NoError(t, err) + + // Sweep just past the stale entry's full expiry (mint + 1h). The live entry + // expires at mint + 2h, so it must survive. + cache.sweep(now.Add(time.Hour).Add(time.Second)) + + cache.mu.Lock() + _, staleExists := cache.entries[stale.eniID+"\x00"+"app-role"] + _, liveExists := cache.entries[live.eniID+"\x00"+"app-role"] + cache.mu.Unlock() + assert.False(t, staleExists, "expired entry must be swept") + assert.True(t, liveExists, "still-valid entry must survive the sweep") +} + +func TestCredCache_PerENIPerRoleKeying(t *testing.T) { + now := time.Unix(1_700_000_000, 0).UTC() + exp := now.Add(time.Hour) + assumer := &fakeAssumer{out: assumeOutput("ASIAEXAMPLE", exp)} + cache := newCredCache(assumer) + + a := &eniFacts{eniID: "eni-aaa", accountID: "111122223333", instanceID: "i-1"} + b := &eniFacts{eniID: "eni-bbb", accountID: "111122223333", instanceID: "i-2"} + _, _ = cache.get(a, "app-role", "arn:aws:iam::111122223333:role/app-role", now) + _, _ = cache.get(b, "app-role", "arn:aws:iam::111122223333:role/app-role", now) + assert.Equal(t, 2, assumer.calls, "distinct ENIs must not share a cache entry") +} diff --git a/spinifex/handlers/imds/instance_lookup.go b/spinifex/handlers/imds/instance_lookup.go new file mode 100644 index 000000000..123cc0096 --- /dev/null +++ b/spinifex/handlers/imds/instance_lookup.go @@ -0,0 +1,87 @@ +package handlers_imds + +import ( + "encoding/base64" + "fmt" + "log/slog" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + gateway_ec2_instance "github.com/mulgadc/spinifex/spinifex/gateway/ec2/instance" + "github.com/nats-io/nats.go" +) + +// natsInstanceLookup resolves the instance-only metadata fields via the same +// account-scoped NATS fan-out the gateway's DescribeInstances path uses, since +// the instance record lives in each daemon's in-memory manager, not a central KV. +type natsInstanceLookup struct { + nc *nats.Conn + expectedNodes int +} + +var _ instanceLookup = (*natsInstanceLookup)(nil) + +func (l *natsInstanceLookup) describe(accountID, instanceID string) (*instanceFacts, error) { + out, err := gateway_ec2_instance.DescribeInstances(&ec2.DescribeInstancesInput{ + InstanceIds: []*string{aws.String(instanceID)}, + }, l.nc, l.expectedNodes, accountID) + if err != nil { + return nil, fmt.Errorf("describe instance %s: %w", instanceID, err) + } + + inst := firstInstance(out) + if inst == nil { + // The ENI references an instance the daemons no longer report (mid + // terminate, or not yet visible). Treated as a miss → 404. + return nil, nil + } + + facts := &instanceFacts{ + instanceType: aws.StringValue(inst.InstanceType), + imageID: aws.StringValue(inst.ImageId), + } + if inst.IamInstanceProfile != nil { + facts.iamInstanceProfileArn = aws.StringValue(inst.IamInstanceProfile.Arn) + } + + facts.userData = l.userData(accountID, instanceID) + return facts, nil +} + +// userData fetches the base64 user-data blob via DescribeInstanceAttribute and +// decodes it. A miss or decode failure yields nil — /latest/user-data then 404s, +// matching AWS for instances launched without user-data. +func (l *natsInstanceLookup) userData(accountID, instanceID string) []byte { + attr, err := gateway_ec2_instance.DescribeInstanceAttribute(&ec2.DescribeInstanceAttributeInput{ + InstanceId: aws.String(instanceID), + Attribute: aws.String("userData"), + }, l.nc, l.expectedNodes, accountID) + if err != nil || attr == nil || attr.UserData == nil || attr.UserData.Value == nil { + return nil + } + decoded, err := base64.StdEncoding.DecodeString(aws.StringValue(attr.UserData.Value)) + if err != nil { + slog.Warn("IMDS: failed to decode instance user-data", "instance_id", instanceID, "err", err) + return nil + } + return decoded +} + +// firstInstance returns the first instance in a DescribeInstances response, or +// nil when the response carries none. +func firstInstance(out *ec2.DescribeInstancesOutput) *ec2.Instance { + if out == nil { + return nil + } + for _, res := range out.Reservations { + if res == nil { + continue + } + for _, inst := range res.Instances { + if inst != nil { + return inst + } + } + } + return nil +} diff --git a/spinifex/handlers/imds/instance_lookup_test.go b/spinifex/handlers/imds/instance_lookup_test.go new file mode 100644 index 000000000..e68321635 --- /dev/null +++ b/spinifex/handlers/imds/instance_lookup_test.go @@ -0,0 +1,33 @@ +package handlers_imds + +import ( + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestFirstInstance_NilAndEmpty(t *testing.T) { + assert.Nil(t, firstInstance(nil)) + assert.Nil(t, firstInstance(&ec2.DescribeInstancesOutput{})) + assert.Nil(t, firstInstance(&ec2.DescribeInstancesOutput{ + Reservations: []*ec2.Reservation{nil, {Instances: []*ec2.Instance{nil}}}, + })) +} + +// firstInstance skips nil reservations and nil instance slots and returns the +// first concrete instance it finds. +func TestFirstInstance_SkipsNilsAndReturnsFirst(t *testing.T) { + out := &ec2.DescribeInstancesOutput{ + Reservations: []*ec2.Reservation{ + nil, + {Instances: []*ec2.Instance{nil}}, + {Instances: []*ec2.Instance{{InstanceId: aws.String("i-first")}, {InstanceId: aws.String("i-second")}}}, + }, + } + got := firstInstance(out) + require.NotNil(t, got) + assert.Equal(t, "i-first", aws.StringValue(got.InstanceId)) +} diff --git a/spinifex/handlers/imds/metadata.go b/spinifex/handlers/imds/metadata.go new file mode 100644 index 000000000..cabe07310 --- /dev/null +++ b/spinifex/handlers/imds/metadata.go @@ -0,0 +1,387 @@ +package handlers_imds + +import ( + "encoding/json" + "fmt" + "io" + "log/slog" + "net/http" + "strconv" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/mulgadc/spinifex/spinifex/awserrors" + "github.com/mulgadc/spinifex/spinifex/utils" +) + +// HTTP paths. IMDSv2 token issuance is a PUT; everything else is a token-gated +// GET under /latest/. +const ( + pathToken = "/latest/api/token" //nolint:gosec // URL path, not a credential + prefixMetaData = "/latest/meta-data/" + pathMetaDataRoot = "/latest/meta-data" + pathUserData = "/latest/user-data" + prefixSecurityCreds = "/latest/meta-data/iam/security-credentials/" //nolint:gosec // URL path, not a credential + pathSecurityCredsDir = "/latest/meta-data/iam/security-credentials" //nolint:gosec // URL path, not a credential + + hdrToken = "X-Aws-Ec2-Metadata-Token" //nolint:gosec // HTTP header name, not a credential + hdrTokenTTL = "X-Aws-Ec2-Metadata-Token-Ttl-Seconds" //nolint:gosec // HTTP header name, not a credential + + hdrForwardedFor = "X-Forwarded-For" +) + +// rejectForwarded enforces AWS IMDS's SSRF defence: any request carrying an +// X-Forwarded-For header is refused with 403 before token or identity checks, +// blocking the classic "trick a server-side app into relaying metadata" attack. +func rejectForwarded(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Header.Get(hdrForwardedFor) != "" { + w.WriteHeader(http.StatusForbidden) + return + } + next.ServeHTTP(w, r) + }) +} + +// handleToken serves PUT /latest/api/token. It binds a fresh token to the +// requesting ENI (resolved from the datapath-attested source IP) and returns it +// as a text/plain body, matching AWS IMDSv2. +func (s *IMDSServiceImpl) handleToken(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPut { + w.Header().Set("Allow", http.MethodPut) + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + ttl, ok := parseTokenTTL(r.Header.Get(hdrTokenTTL)) + if !ok { + w.WriteHeader(http.StatusBadRequest) + return + } + + eni := s.resolveCaller(r) + if eni == nil { + w.WriteHeader(http.StatusNotFound) + return + } + + token, err := s.tokens.issue(eni.eniID, ttl, s.now()) + if err != nil { + slog.Error("IMDS: token issuance failed", "eni_id", eni.eniID, "err", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "text/plain") + w.Header().Set(hdrTokenTTL, strconv.Itoa(int(ttl.Seconds()))) + _, _ = w.Write([]byte(token)) +} + +// handleMetadata serves every token-gated read path. It resolves the caller's +// ENI, enforces the IMDSv2 token, then dispatches on the request path. +func (s *IMDSServiceImpl) handleMetadata(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + w.Header().Set("Allow", http.MethodGet) + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + eni := s.resolveCaller(r) + if eni == nil { + w.WriteHeader(http.StatusNotFound) + return + } + + // IMDSv2: a valid, ENI-bound token is mandatory on every read. A missing, + // unknown, expired, or wrong-ENI token is an indistinguishable 401 so a + // guest cannot probe which tokens exist. + if !s.tokens.validate(r.Header.Get(hdrToken), eni.eniID, s.now()) { + w.WriteHeader(http.StatusUnauthorized) + return + } + + s.dispatch(w, r, eni) +} + +// resolveCaller maps the request's (vpcID-from-context, source-IP) to the +// owning ENI, or nil when no mapping exists (logged for operator triage). A +// backend error is also surfaced as nil → the caller 404s, never 500s, matching +// AWS's opaque "eventually available" boot posture. +func (s *IMDSServiceImpl) resolveCaller(r *http.Request) *eniFacts { + vpcID, _ := r.Context().Value(ctxKeyVPCID).(string) + srcIP := utils.ClientIP(r.RemoteAddr) + if vpcID == "" || srcIP == "" { + slog.Warn("IMDS: request missing VPC context or source IP", "vpc_id", vpcID, "remote_addr", r.RemoteAddr) + return nil + } + + eni, err := s.resolver.resolveENI(vpcID, srcIP) + if err != nil { + slog.Error("IMDS: ENI resolution failed", "vpc_id", vpcID, "src_ip", srcIP, "err", err) + return nil + } + if eni == nil { + slog.Warn("IMDS: no ENI for source IP", "vpc_id", vpcID, "src_ip", srcIP) + return nil + } + return eni +} + +// dispatch routes a token-validated GET to the right metadata producer. +func (s *IMDSServiceImpl) dispatch(w http.ResponseWriter, r *http.Request, eni *eniFacts) { + path := r.URL.Path + + // Credential fetch for a specific role: /iam/security-credentials/. + if strings.HasPrefix(path, prefixSecurityCreds) && len(path) > len(prefixSecurityCreds) { + s.serveRoleCredentials(w, eni, strings.TrimPrefix(path, prefixSecurityCreds)) + return + } + + switch path { + case pathMetaDataRoot, prefixMetaData: + writeText(w, "ami-id\nhostname\niam/\ninstance-id\ninstance-type\nlocal-hostname\nlocal-ipv4\nmac\nplacement/\npublic-ipv4\nsecurity-groups") + case prefixMetaData + "instance-id": + writeText(w, eni.instanceID) + case prefixMetaData + "local-ipv4": + writeText(w, eni.privateIP) + case prefixMetaData + "public-ipv4": + writeText(w, eni.publicIP) + case prefixMetaData + "mac": + writeText(w, eni.mac) + case prefixMetaData + "security-groups": + writeText(w, strings.Join(s.resolver.resolveSGNames(eni.accountID, eni.securityGroupIDs), "\n")) + case prefixMetaData + "hostname", prefixMetaData + "local-hostname": + writeText(w, synthHostname(eni.privateIP, regionFromAZ(eni.availabilityZone))) + case prefixMetaData + "placement", prefixMetaData + "placement/": + writeText(w, "availability-zone\nregion") + case prefixMetaData + "placement/availability-zone": + writeText(w, eni.availabilityZone) + case prefixMetaData + "placement/region": + writeText(w, regionFromAZ(eni.availabilityZone)) + case prefixMetaData + "instance-type": + s.serveInstanceField(w, eni, func(i *instanceFacts) string { return i.instanceType }) + case prefixMetaData + "ami-id": + s.serveInstanceField(w, eni, func(i *instanceFacts) string { return i.imageID }) + case prefixMetaData + "iam", prefixMetaData + "iam/": + writeText(w, "info\nsecurity-credentials/") + case prefixMetaData + "iam/info": + s.serveIAMInfo(w, eni) + case pathSecurityCredsDir, prefixSecurityCreds: + s.serveSecurityCredentialsList(w, eni) + case pathUserData: + s.serveUserData(w, eni) + default: + // /latest/dynamic/instance-identity/document and + // /latest/meta-data/network/interfaces/... are out of scope in v1. + w.WriteHeader(http.StatusNotFound) + } +} + +// serveInstanceField resolves the instance record and writes one of its +// string fields, 404ing when the instance is no longer visible. +func (s *IMDSServiceImpl) serveInstanceField(w http.ResponseWriter, eni *eniFacts, field func(*instanceFacts) string) { + inst := s.instanceFor(w, eni) + if inst == nil { + return + } + writeText(w, field(inst)) +} + +// serveUserData writes the instance's user-data, or 404 when there is none — +// matching AWS for instances launched without user-data. +func (s *IMDSServiceImpl) serveUserData(w http.ResponseWriter, eni *eniFacts) { + inst := s.instanceFor(w, eni) + if inst == nil { + return + } + if len(inst.userData) == 0 { + w.WriteHeader(http.StatusNotFound) + return + } + w.Header().Set("Content-Type", "text/plain") + _, _ = w.Write(inst.userData) +} + +// serveIAMInfo writes {InstanceProfileArn, InstanceProfileId}, 404 when the +// instance has no instance profile, or 500 when the profile can't be resolved. +func (s *IMDSServiceImpl) serveIAMInfo(w http.ResponseWriter, eni *eniFacts) { + profile, err := s.profileFor(eni) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + if profile == nil { + w.WriteHeader(http.StatusNotFound) + return + } + writeJSON(w, map[string]string{ + "InstanceProfileArn": profile.ARN, + "InstanceProfileId": profile.InstanceProfileID, + }) +} + +// serveSecurityCredentialsList writes the role name(s) under the profile, one +// per line. No profile/role is an empty 200 (matching AWS); a backend failure is +// a 500, never an empty 200 that would silently strip the instance's creds. +func (s *IMDSServiceImpl) serveSecurityCredentialsList(w http.ResponseWriter, eni *eniFacts) { + profile, err := s.profileFor(eni) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + if profile == nil || profile.RoleName == "" { + writeText(w, "") + return + } + writeText(w, profile.RoleName) +} + +// serveRoleCredentials mints (or serves cached) credentials for the named role. +// AWS only accepts the actual role name as the path parameter, not the profile +// name, so a mismatch is 404; a backend failure resolving the profile is 500. +func (s *IMDSServiceImpl) serveRoleCredentials(w http.ResponseWriter, eni *eniFacts, roleParam string) { + profile, err := s.profileFor(eni) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + if profile == nil || profile.RoleName == "" || roleParam != profile.RoleName { + w.WriteHeader(http.StatusNotFound) + return + } + + role, err := s.iam.GetRole(eni.accountID, &iam.GetRoleInput{RoleName: aws.String(profile.RoleName)}) + if err != nil || role == nil || role.Role == nil || role.Role.Arn == nil { + slog.Error("IMDS: resolve role ARN failed", "account_id", eni.accountID, "role", profile.RoleName, "err", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + body, err := s.creds.get(eni, profile.RoleName, *role.Role.Arn, s.now()) + if err != nil { + // AWS surfaces a trust-policy failure as a JSON body with Code:"Failed"; + // the SDK reports it as "EC2RoleProvider failed". Mirror that rather than + // a bare HTTP error so the SDK error message is AWS-accurate. + slog.Warn("IMDS: AssumeRoleForInstance failed", "account_id", eni.accountID, "role", profile.RoleName, "instance_id", eni.instanceID, "err", err) + writeJSON(w, map[string]string{ + "Code": "Failed", + "LastUpdated": s.now().UTC().Format(time.RFC3339), + "Message": "failed to assume instance role", + }) + return + } + + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write(body) +} + +// instanceFor resolves the instance record for an ENI, writing the appropriate +// HTTP error and returning nil on miss/failure so callers can early-return. +func (s *IMDSServiceImpl) instanceFor(w http.ResponseWriter, eni *eniFacts) *instanceFacts { + inst, err := s.resolver.resolveInstance(eni) + if err != nil { + slog.Error("IMDS: instance resolution failed", "instance_id", eni.instanceID, "err", err) + w.WriteHeader(http.StatusInternalServerError) + return nil + } + if inst == nil { + w.WriteHeader(http.StatusNotFound) + return nil + } + return inst +} + +// profileFor resolves the instance's IAM instance profile. Returns (profile, nil) +// when resolvable, (nil, nil) when genuinely absent (404/empty), (nil, err) on +// backend failure (500) — collapsing err into absent would silently drop creds. +func (s *IMDSServiceImpl) profileFor(eni *eniFacts) (*resolvedProfile, error) { + inst, err := s.resolver.resolveInstance(eni) + if err != nil { + slog.Error("IMDS: instance resolution failed", "instance_id", eni.instanceID, "err", err) + return nil, err + } + if inst == nil || inst.iamInstanceProfileArn == "" { + return nil, nil + } + profile, err := s.iam.ResolveInstanceProfile(eni.accountID, inst.iamInstanceProfileArn) + if err != nil { + if err.Error() == awserrors.ErrorIAMNoSuchEntity { + // The profile was deleted out from under the instance. AWS treats this + // as "no instance role", not a backend fault — NoSuchEntity is raised + // only for a genuinely absent record, never a transient. + return nil, nil + } + slog.Error("IMDS: resolve instance profile failed", "account_id", eni.accountID, "arn", inst.iamInstanceProfileArn, "err", err) + return nil, err + } + if profile == nil { + return nil, nil + } + return &resolvedProfile{ARN: profile.ARN, InstanceProfileID: profile.InstanceProfileID, RoleName: profile.RoleName}, nil +} + +// resolvedProfile is the slice of an IAM instance profile the metadata surface +// serves, decoupled from the handlers_iam type so this package needn't import +// it for the field access. +type resolvedProfile struct { + ARN string + InstanceProfileID string + RoleName string +} + +// parseTokenTTL validates the X-aws-ec2-metadata-token-ttl-seconds header. +func parseTokenTTL(raw string) (time.Duration, bool) { + if raw == "" { + return 0, false + } + n, err := strconv.Atoi(raw) + if err != nil || n < tokenTTLMin || n > tokenTTLMax { + return 0, false + } + return time.Duration(n) * time.Second, true +} + +// regionFromAZ derives the region from an availability-zone name by stripping +// the trailing AZ letter ("ap-southeast-2a" → "ap-southeast-2"). +func regionFromAZ(az string) string { + if az == "" { + return "" + } + last := az[len(az)-1] + if last >= 'a' && last <= 'z' { + return az[:len(az)-1] + } + return az +} + +// synthHostname builds the AWS-style internal hostname +// "ip-10-0-1-5..compute.internal" from a private IP and region. +func synthHostname(ip, region string) string { + if ip == "" || region == "" { + return "" + } + return fmt.Sprintf("ip-%s.%s.compute.internal", strings.ReplaceAll(ip, ".", "-"), region) +} + +func writeText(w http.ResponseWriter, body string) { + w.Header().Set("Content-Type", "text/plain") + _, _ = io.WriteString(w, body) +} + +func writeJSON(w http.ResponseWriter, v any) { + data, err := json.Marshal(v) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write(data) +} + +// ctxKey is the unexported context-key type for values the bind manager threads +// into each request (the VPC ID the listener's veth maps to). +type ctxKey int + +const ctxKeyVPCID ctxKey = iota diff --git a/spinifex/handlers/imds/metadata_test.go b/spinifex/handlers/imds/metadata_test.go new file mode 100644 index 000000000..7f308eb14 --- /dev/null +++ b/spinifex/handlers/imds/metadata_test.go @@ -0,0 +1,418 @@ +package handlers_imds + +import ( + "context" + "errors" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go/service/sts" + "github.com/mulgadc/spinifex/spinifex/awserrors" + handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// ----- fakes ------------------------------------------------------------- + +type fakeResolver struct { + eni *eniFacts + eniErr error + inst *instanceFacts + instErr error + sgNames map[string]string // sg-id → group name; absent IDs fall back to the ID +} + +func (f *fakeResolver) resolveENI(_, _ string) (*eniFacts, error) { return f.eni, f.eniErr } +func (f *fakeResolver) resolveInstance(_ *eniFacts) (*instanceFacts, error) { + return f.inst, f.instErr +} + +func (f *fakeResolver) resolveSGNames(_ string, sgIDs []string) []string { + out := make([]string, len(sgIDs)) + for i, id := range sgIDs { + if name, ok := f.sgNames[id]; ok { + out[i] = name + } else { + out[i] = id + } + } + return out +} + +type fakeIAM struct { + profile *handlers_iam.InstanceProfile + profileErr error + roleARN string + roleErr error +} + +func (f *fakeIAM) ResolveInstanceProfile(_, _ string) (*handlers_iam.InstanceProfile, error) { + return f.profile, f.profileErr +} + +func (f *fakeIAM) GetRole(_ string, _ *iam.GetRoleInput) (*iam.GetRoleOutput, error) { + if f.roleErr != nil { + return nil, f.roleErr + } + return &iam.GetRoleOutput{Role: &iam.Role{Arn: aws.String(f.roleARN)}}, nil +} + +const ( + testVPC = "vpc-abc12345" + testIP = "10.0.1.5" +) + +func testENI() *eniFacts { + return &eniFacts{ + eniID: "eni-aaa", + accountID: "111122223333", + instanceID: "i-0123456789", + vpcID: testVPC, + subnetID: "subnet-1", + privateIP: testIP, + publicIP: "203.0.113.7", + mac: "02:11:22:33:44:55", + availabilityZone: "ap-southeast-2a", + securityGroupIDs: []string{"sg-1", "sg-2"}, + } +} + +// newTestService builds an IMDSServiceImpl with injected fakes and a fixed +// clock. The bind manager is left nil — the HTTP handler is exercised directly. +func newTestService(res eniResolver, fIAM profileLookup, assumer stsAssumer) (*IMDSServiceImpl, time.Time) { + now := time.Unix(1_700_000_000, 0).UTC() + return &IMDSServiceImpl{ + resolver: res, + tokens: newTokenStore(), + creds: newCredCache(assumer), + iam: fIAM, + now: func() time.Time { return now }, + }, now +} + +// get issues a token-gated GET with the VPC context + source IP a real listener +// would have threaded in, plus the supplied token header. +func get(t *testing.T, h http.Handler, path, token string) *httptest.ResponseRecorder { + t.Helper() + req := httptest.NewRequest(http.MethodGet, "http://"+MetaDataServerIP+path, nil) + req.RemoteAddr = testIP + ":50000" + req = req.WithContext(context.WithValue(req.Context(), ctxKeyVPCID, testVPC)) + if token != "" { + req.Header.Set(hdrToken, token) + } + rec := httptest.NewRecorder() + h.ServeHTTP(rec, req) + return rec +} + +// issueToken performs the PUT /latest/api/token handshake and returns the token. +func issueToken(t *testing.T, h http.Handler) string { + t.Helper() + req := httptest.NewRequest(http.MethodPut, "http://"+MetaDataServerIP+pathToken, nil) + req.RemoteAddr = testIP + ":50000" + req = req.WithContext(context.WithValue(req.Context(), ctxKeyVPCID, testVPC)) + req.Header.Set(hdrTokenTTL, "60") + rec := httptest.NewRecorder() + h.ServeHTTP(rec, req) + require.Equal(t, http.StatusOK, rec.Code) + require.NotEmpty(t, rec.Body.String()) + return rec.Body.String() +} + +// ----- token model ------------------------------------------------------ + +func TestHTTP_TokenlessGETRejected(t *testing.T) { + svc, _ := newTestService(&fakeResolver{eni: testENI()}, &fakeIAM{}, &fakeAssumer{}) + h := svc.httpHandler() + rec := get(t, h, prefixMetaData+"instance-id", "") + assert.Equal(t, http.StatusUnauthorized, rec.Code) + assert.Empty(t, rec.Body.String()) +} + +func TestHTTP_TokenPUTValidation(t *testing.T) { + svc, _ := newTestService(&fakeResolver{eni: testENI()}, &fakeIAM{}, &fakeAssumer{}) + h := svc.httpHandler() + + for _, ttl := range []string{"", "0", "21601", "notanumber"} { + req := httptest.NewRequest(http.MethodPut, "http://"+MetaDataServerIP+pathToken, nil) + req.RemoteAddr = testIP + ":50000" + req = req.WithContext(context.WithValue(req.Context(), ctxKeyVPCID, testVPC)) + if ttl != "" { + req.Header.Set(hdrTokenTTL, ttl) + } + rec := httptest.NewRecorder() + h.ServeHTTP(rec, req) + assert.Equal(t, http.StatusBadRequest, rec.Code, "ttl=%q", ttl) + } +} + +func TestHTTP_TokenGETMethodNotAllowed(t *testing.T) { + svc, _ := newTestService(&fakeResolver{eni: testENI()}, &fakeIAM{}, &fakeAssumer{}) + h := svc.httpHandler() + req := httptest.NewRequest(http.MethodGet, "http://"+MetaDataServerIP+pathToken, nil) + req.RemoteAddr = testIP + ":50000" + req = req.WithContext(context.WithValue(req.Context(), ctxKeyVPCID, testVPC)) + rec := httptest.NewRecorder() + h.ServeHTTP(rec, req) + assert.Equal(t, http.StatusMethodNotAllowed, rec.Code) +} + +// TestHTTP_ForwardedForRejected pins AWS IMDS's SSRF defence: any request +// carrying X-Forwarded-For is refused with 403 regardless of token or identity, +// on both the read path and token issuance. +func TestHTTP_ForwardedForRejected(t *testing.T) { + svc, _ := newTestService(&fakeResolver{eni: testENI()}, &fakeIAM{}, &fakeAssumer{}) + h := svc.httpHandler() + + // A valid token + resolvable ENI is still refused once X-Forwarded-For is set. + token := issueToken(t, h) + req := httptest.NewRequest(http.MethodGet, "http://"+MetaDataServerIP+prefixMetaData+"instance-id", nil) + req.RemoteAddr = testIP + ":50000" + req = req.WithContext(context.WithValue(req.Context(), ctxKeyVPCID, testVPC)) + req.Header.Set(hdrToken, token) + req.Header.Set(hdrForwardedFor, "10.0.0.99") + rec := httptest.NewRecorder() + h.ServeHTTP(rec, req) + assert.Equal(t, http.StatusForbidden, rec.Code) + + // Token issuance is refused too. + put := httptest.NewRequest(http.MethodPut, "http://"+MetaDataServerIP+pathToken, nil) + put.RemoteAddr = testIP + ":50000" + put = put.WithContext(context.WithValue(put.Context(), ctxKeyVPCID, testVPC)) + put.Header.Set(hdrTokenTTL, "60") + put.Header.Set(hdrForwardedFor, "10.0.0.99") + putRec := httptest.NewRecorder() + h.ServeHTTP(putRec, put) + assert.Equal(t, http.StatusForbidden, putRec.Code) +} + +func TestHTTP_ENIMissReturns404(t *testing.T) { + svc, _ := newTestService(&fakeResolver{eni: nil}, &fakeIAM{}, &fakeAssumer{}) + h := svc.httpHandler() + + // Token PUT and metadata GET both 404 when the source IP maps to no ENI. + req := httptest.NewRequest(http.MethodPut, "http://"+MetaDataServerIP+pathToken, nil) + req.RemoteAddr = testIP + ":50000" + req = req.WithContext(context.WithValue(req.Context(), ctxKeyVPCID, testVPC)) + req.Header.Set(hdrTokenTTL, "60") + rec := httptest.NewRecorder() + h.ServeHTTP(rec, req) + assert.Equal(t, http.StatusNotFound, rec.Code) +} + +// ----- metadata surface -------------------------------------------------- + +func TestHTTP_MetadataPaths(t *testing.T) { + res := &fakeResolver{ + eni: testENI(), + inst: &instanceFacts{instanceType: "t3.micro", imageID: "ami-12345", userData: []byte("#!/bin/sh\necho hi")}, + sgNames: map[string]string{"sg-1": "web-sg", "sg-2": "db-sg"}, + } + svc, _ := newTestService(res, &fakeIAM{}, &fakeAssumer{}) + h := svc.httpHandler() + token := issueToken(t, h) + + cases := []struct{ path, want string }{ + {prefixMetaData + "instance-id", "i-0123456789"}, + {prefixMetaData + "instance-type", "t3.micro"}, + {prefixMetaData + "ami-id", "ami-12345"}, + {prefixMetaData + "local-ipv4", "10.0.1.5"}, + {prefixMetaData + "public-ipv4", "203.0.113.7"}, + {prefixMetaData + "mac", "02:11:22:33:44:55"}, + {prefixMetaData + "placement/availability-zone", "ap-southeast-2a"}, + {prefixMetaData + "placement/region", "ap-southeast-2"}, + {prefixMetaData + "security-groups", "web-sg\ndb-sg"}, + {prefixMetaData + "hostname", "ip-10-0-1-5.ap-southeast-2.compute.internal"}, + {prefixMetaData + "local-hostname", "ip-10-0-1-5.ap-southeast-2.compute.internal"}, + {pathUserData, "#!/bin/sh\necho hi"}, + } + for _, c := range cases { + rec := get(t, h, c.path, token) + assert.Equal(t, http.StatusOK, rec.Code, "path=%s", c.path) + assert.Equal(t, c.want, rec.Body.String(), "path=%s", c.path) + } +} + +func TestHTTP_DirectoryListing(t *testing.T) { + svc, _ := newTestService(&fakeResolver{eni: testENI()}, &fakeIAM{}, &fakeAssumer{}) + h := svc.httpHandler() + token := issueToken(t, h) + rec := get(t, h, pathMetaDataRoot, token) + assert.Equal(t, http.StatusOK, rec.Code) + assert.Contains(t, rec.Body.String(), "instance-id") + assert.Contains(t, rec.Body.String(), "iam/") +} + +func TestHTTP_UserDataAbsent404(t *testing.T) { + res := &fakeResolver{eni: testENI(), inst: &instanceFacts{}} + svc, _ := newTestService(res, &fakeIAM{}, &fakeAssumer{}) + h := svc.httpHandler() + token := issueToken(t, h) + rec := get(t, h, pathUserData, token) + assert.Equal(t, http.StatusNotFound, rec.Code) +} + +func TestHTTP_OutOfScopePaths404(t *testing.T) { + res := &fakeResolver{eni: testENI(), inst: &instanceFacts{}} + svc, _ := newTestService(res, &fakeIAM{}, &fakeAssumer{}) + h := svc.httpHandler() + token := issueToken(t, h) + for _, p := range []string{ + "/latest/dynamic/instance-identity/document", + prefixMetaData + "network/interfaces/macs", + prefixMetaData + "nonsense", + } { + rec := get(t, h, p, token) + assert.Equal(t, http.StatusNotFound, rec.Code, "path=%s", p) + } +} + +// ----- IAM / credentials ------------------------------------------------- + +func profileFixture() *handlers_iam.InstanceProfile { + return &handlers_iam.InstanceProfile{ + InstanceProfileName: "app-profile", + InstanceProfileID: "AIPAEXAMPLE", + AccountID: "111122223333", + ARN: "arn:aws:iam::111122223333:instance-profile/app-profile", + RoleName: "app-role", + } +} + +func TestHTTP_IAMInfo(t *testing.T) { + res := &fakeResolver{eni: testENI(), inst: &instanceFacts{iamInstanceProfileArn: "arn:aws:iam::111122223333:instance-profile/app-profile"}} + svc, _ := newTestService(res, &fakeIAM{profile: profileFixture()}, &fakeAssumer{}) + h := svc.httpHandler() + token := issueToken(t, h) + + rec := get(t, h, prefixMetaData+"iam/info", token) + assert.Equal(t, http.StatusOK, rec.Code) + assert.Contains(t, rec.Body.String(), "arn:aws:iam::111122223333:instance-profile/app-profile") + assert.Contains(t, rec.Body.String(), "AIPAEXAMPLE") +} + +func TestHTTP_IAMInfoNoProfile404(t *testing.T) { + res := &fakeResolver{eni: testENI(), inst: &instanceFacts{}} // no profile ARN + svc, _ := newTestService(res, &fakeIAM{}, &fakeAssumer{}) + h := svc.httpHandler() + token := issueToken(t, h) + rec := get(t, h, prefixMetaData+"iam/info", token) + assert.Equal(t, http.StatusNotFound, rec.Code) +} + +func TestHTTP_SecurityCredentialsList(t *testing.T) { + res := &fakeResolver{eni: testENI(), inst: &instanceFacts{iamInstanceProfileArn: "arn:aws:iam::111122223333:instance-profile/app-profile"}} + svc, _ := newTestService(res, &fakeIAM{profile: profileFixture()}, &fakeAssumer{}) + h := svc.httpHandler() + token := issueToken(t, h) + rec := get(t, h, pathSecurityCredsDir, token) + assert.Equal(t, http.StatusOK, rec.Code) + assert.Equal(t, "app-role", rec.Body.String()) +} + +func TestHTTP_SecurityCredentialsListNoRoleEmpty(t *testing.T) { + res := &fakeResolver{eni: testENI(), inst: &instanceFacts{}} + svc, _ := newTestService(res, &fakeIAM{}, &fakeAssumer{}) + h := svc.httpHandler() + token := issueToken(t, h) + rec := get(t, h, pathSecurityCredsDir, token) + assert.Equal(t, http.StatusOK, rec.Code) + assert.Empty(t, rec.Body.String()) +} + +// A backend failure resolving the instance must surface as 500, never an empty +// 200 — otherwise a transient hiccup is indistinguishable from "instance has no +// role" and the SDK silently proceeds unauthenticated. +func TestHTTP_SecurityCredentialsListBackendError500(t *testing.T) { + res := &fakeResolver{eni: testENI(), instErr: errors.New("backend unavailable")} + svc, _ := newTestService(res, &fakeIAM{}, &fakeAssumer{}) + h := svc.httpHandler() + token := issueToken(t, h) + rec := get(t, h, pathSecurityCredsDir, token) + assert.Equal(t, http.StatusInternalServerError, rec.Code) +} + +// A profile deleted out from under a running instance (the ARN dereferences to +// NoSuchEntity) is "no instance role", not a backend fault: iam/info 404s, the +// creds list is an empty 200, and the role path 404s — matching AWS. Only a +// genuine backend error (TestHTTP_*BackendError500) is a 500. +func TestHTTP_IAMInfoDeletedProfile404(t *testing.T) { + res := &fakeResolver{eni: testENI(), inst: &instanceFacts{iamInstanceProfileArn: "arn:aws:iam::111122223333:instance-profile/gone"}} + svc, _ := newTestService(res, &fakeIAM{profileErr: errors.New(awserrors.ErrorIAMNoSuchEntity)}, &fakeAssumer{}) + h := svc.httpHandler() + token := issueToken(t, h) + rec := get(t, h, prefixMetaData+"iam/info", token) + assert.Equal(t, http.StatusNotFound, rec.Code) +} + +func TestHTTP_SecurityCredentialsListDeletedProfileEmpty(t *testing.T) { + res := &fakeResolver{eni: testENI(), inst: &instanceFacts{iamInstanceProfileArn: "arn:aws:iam::111122223333:instance-profile/gone"}} + svc, _ := newTestService(res, &fakeIAM{profileErr: errors.New(awserrors.ErrorIAMNoSuchEntity)}, &fakeAssumer{}) + h := svc.httpHandler() + token := issueToken(t, h) + rec := get(t, h, pathSecurityCredsDir, token) + assert.Equal(t, http.StatusOK, rec.Code) + assert.Empty(t, rec.Body.String()) +} + +func TestHTTP_RoleCredentialsDeletedProfile404(t *testing.T) { + res := &fakeResolver{eni: testENI(), inst: &instanceFacts{iamInstanceProfileArn: "arn:aws:iam::111122223333:instance-profile/gone"}} + svc, _ := newTestService(res, &fakeIAM{profileErr: errors.New(awserrors.ErrorIAMNoSuchEntity)}, &fakeAssumer{}) + h := svc.httpHandler() + token := issueToken(t, h) + rec := get(t, h, prefixSecurityCreds+"app-role", token) + assert.Equal(t, http.StatusNotFound, rec.Code) +} + +func TestHTTP_IAMInfoBackendError500(t *testing.T) { + res := &fakeResolver{eni: testENI(), inst: &instanceFacts{iamInstanceProfileArn: "arn:aws:iam::111122223333:instance-profile/app-profile"}} + svc, _ := newTestService(res, &fakeIAM{profileErr: errors.New("iam unavailable")}, &fakeAssumer{}) + h := svc.httpHandler() + token := issueToken(t, h) + rec := get(t, h, prefixMetaData+"iam/info", token) + assert.Equal(t, http.StatusInternalServerError, rec.Code) +} + +func TestHTTP_RoleCredentialsBackendError500(t *testing.T) { + res := &fakeResolver{eni: testENI(), instErr: errors.New("backend unavailable")} + svc, _ := newTestService(res, &fakeIAM{}, &fakeAssumer{}) + h := svc.httpHandler() + token := issueToken(t, h) + rec := get(t, h, prefixSecurityCreds+"app-role", token) + assert.Equal(t, http.StatusInternalServerError, rec.Code) +} + +func TestHTTP_RoleCredentials(t *testing.T) { + now := time.Unix(1_700_000_000, 0).UTC() + res := &fakeResolver{eni: testENI(), inst: &instanceFacts{iamInstanceProfileArn: "arn:aws:iam::111122223333:instance-profile/app-profile"}} + assumer := &fakeAssumer{out: &sts.AssumeRoleOutput{Credentials: &sts.Credentials{ + AccessKeyId: aws.String("ASIAEXAMPLE"), + SecretAccessKey: aws.String("secret"), + SessionToken: aws.String("token"), + Expiration: aws.Time(now.Add(time.Hour)), + }}} + svc, _ := newTestService(res, &fakeIAM{profile: profileFixture(), roleARN: "arn:aws:iam::111122223333:role/app-role"}, assumer) + h := svc.httpHandler() + token := issueToken(t, h) + + rec := get(t, h, prefixSecurityCreds+"app-role", token) + assert.Equal(t, http.StatusOK, rec.Code) + assert.Contains(t, rec.Body.String(), "ASIAEXAMPLE") + assert.Contains(t, rec.Body.String(), `"Code":"Success"`) +} + +func TestHTTP_RoleCredentialsWrongRole404(t *testing.T) { + res := &fakeResolver{eni: testENI(), inst: &instanceFacts{iamInstanceProfileArn: "arn:aws:iam::111122223333:instance-profile/app-profile"}} + svc, _ := newTestService(res, &fakeIAM{profile: profileFixture(), roleARN: "arn:aws:iam::111122223333:role/app-role"}, &fakeAssumer{}) + h := svc.httpHandler() + token := issueToken(t, h) + + // AWS only accepts the actual role name, never the profile name. + rec := get(t, h, prefixSecurityCreds+"app-profile", token) + assert.Equal(t, http.StatusNotFound, rec.Code) +} diff --git a/spinifex/handlers/imds/nats_clients.go b/spinifex/handlers/imds/nats_clients.go new file mode 100644 index 000000000..adbf15362 --- /dev/null +++ b/spinifex/handlers/imds/nats_clients.go @@ -0,0 +1,134 @@ +package handlers_imds + +import ( + "sync" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go/service/sts" + handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam" + handlers_sts "github.com/mulgadc/spinifex/spinifex/handlers/sts" + "github.com/mulgadc/spinifex/spinifex/utils" + "github.com/nats-io/nats.go" +) + +const ( + // imdsRPCTimeout bounds each internal control-plane round-trip to awsgw. + imdsRPCTimeout = 10 * time.Second + + // profileCacheTTL memoises profile/role lookups. Both mappings are effectively + // static, so a short TTL keeps the iam/* GETs off a NATS round-trip per request. + profileCacheTTL = 5 * time.Minute +) + +// NATSSTSAssumer is the NATS-backed stsAssumer. It mints instance-role credentials +// via awsgw's SubjectAssumeRoleForInstance responder, keeping no local cache — +// credCache already memoises minted credentials, so STS stays off the hot path. +type NATSSTSAssumer struct { + nc *nats.Conn +} + +var _ stsAssumer = (*NATSSTSAssumer)(nil) + +// NewNATSSTSAssumer constructs a NATSSTSAssumer over nc. +func NewNATSSTSAssumer(nc *nats.Conn) *NATSSTSAssumer { + return &NATSSTSAssumer{nc: nc} +} + +func (a *NATSSTSAssumer) AssumeRoleForInstance(accountID, roleARN, instanceID string, durationSeconds int64) (*sts.AssumeRoleOutput, error) { + return utils.NATSRequest[sts.AssumeRoleOutput](a.nc, handlers_sts.SubjectAssumeRoleForInstance, handlers_sts.AssumeRoleForInstanceRequest{ + AccountID: accountID, + RoleARN: roleARN, + InstanceID: instanceID, + DurationSeconds: durationSeconds, + }, imdsRPCTimeout, accountID) +} + +// NATSProfileLookup is the NATS-backed profileLookup. It resolves instance +// profiles and roles via awsgw's IAM responders, fronted by a short-TTL cache +// so repeat iam/* GETs don't take a round-trip each. +type NATSProfileLookup struct { + nc *nats.Conn + profiles *ttlCache[*handlers_iam.InstanceProfile] + roles *ttlCache[*iam.GetRoleOutput] +} + +var _ profileLookup = (*NATSProfileLookup)(nil) + +// NewNATSProfileLookup constructs a NATSProfileLookup over nc. +func NewNATSProfileLookup(nc *nats.Conn) *NATSProfileLookup { + return &NATSProfileLookup{ + nc: nc, + profiles: newTTLCache[*handlers_iam.InstanceProfile](profileCacheTTL), + roles: newTTLCache[*iam.GetRoleOutput](profileCacheTTL), + } +} + +func (p *NATSProfileLookup) ResolveInstanceProfile(accountID, nameOrARN string) (*handlers_iam.InstanceProfile, error) { + key := accountID + "\x00" + nameOrARN + if v, ok := p.profiles.get(key); ok { + return v, nil + } + out, err := utils.NATSRequest[handlers_iam.InstanceProfile](p.nc, handlers_iam.SubjectResolveInstanceProfile, handlers_iam.ResolveInstanceProfileRequest{ + AccountID: accountID, + NameOrARN: nameOrARN, + }, imdsRPCTimeout, accountID) + if err != nil { + return nil, err + } + p.profiles.put(key, out) + return out, nil +} + +func (p *NATSProfileLookup) GetRole(accountID string, input *iam.GetRoleInput) (*iam.GetRoleOutput, error) { + key := accountID + "\x00" + aws.StringValue(input.RoleName) + if v, ok := p.roles.get(key); ok { + return v, nil + } + out, err := utils.NATSRequest[iam.GetRoleOutput](p.nc, handlers_iam.SubjectGetRole, handlers_iam.GetRoleRequest{ + AccountID: accountID, + Input: input, + }, imdsRPCTimeout, accountID) + if err != nil { + return nil, err + } + p.roles.put(key, out) + return out, nil +} + +// ttlCache is a minimal concurrency-safe map with per-entry expiry, used to +// keep effectively-static IAM lookups off the NATS round-trip. now is a field +// so tests can drive expiry deterministically. +type ttlCache[V any] struct { + mu sync.Mutex + ttl time.Duration + now func() time.Time + m map[string]ttlCacheEntry[V] +} + +type ttlCacheEntry[V any] struct { + val V + expiresAt time.Time +} + +func newTTLCache[V any](ttl time.Duration) *ttlCache[V] { + return &ttlCache[V]{ttl: ttl, now: time.Now, m: make(map[string]ttlCacheEntry[V])} +} + +func (c *ttlCache[V]) get(key string) (V, bool) { + c.mu.Lock() + defer c.mu.Unlock() + entry, ok := c.m[key] + if !ok || c.now().After(entry.expiresAt) { + var zero V + return zero, false + } + return entry.val, true +} + +func (c *ttlCache[V]) put(key string, v V) { + c.mu.Lock() + defer c.mu.Unlock() + c.m[key] = ttlCacheEntry[V]{val: v, expiresAt: c.now().Add(c.ttl)} +} diff --git a/spinifex/handlers/imds/nats_clients_test.go b/spinifex/handlers/imds/nats_clients_test.go new file mode 100644 index 000000000..1eaa71e56 --- /dev/null +++ b/spinifex/handlers/imds/nats_clients_test.go @@ -0,0 +1,136 @@ +package handlers_imds + +import ( + "sync/atomic" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go/service/sts" + handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam" + handlers_sts "github.com/mulgadc/spinifex/spinifex/handlers/sts" + "github.com/mulgadc/spinifex/spinifex/testutil" + "github.com/mulgadc/spinifex/spinifex/utils" + "github.com/nats-io/nats.go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const imdsTestAccountID = "123456789012" + +// serveCounted subscribes fn to subject and returns a counter of how many +// requests the responder actually handled — the assertion hook for the TTL +// cache (a cache hit must not reach the responder). +func serveCounted[I any, O any](t *testing.T, nc *nats.Conn, subject string, fn func(*I) (*O, error)) *int32 { + t.Helper() + var calls int32 + sub, err := nc.Subscribe(subject, func(msg *nats.Msg) { + atomic.AddInt32(&calls, 1) + utils.ServeNATSRequest(msg, fn) + }) + require.NoError(t, err) + t.Cleanup(func() { _ = sub.Unsubscribe() }) + return &calls +} + +func TestNATSSTSAssumer_RoundTrip(t *testing.T) { + _, nc := testutil.StartTestNATS(t) + + var gotReq handlers_sts.AssumeRoleForInstanceRequest + calls := serveCounted(t, nc, handlers_sts.SubjectAssumeRoleForInstance, + func(req *handlers_sts.AssumeRoleForInstanceRequest) (*sts.AssumeRoleOutput, error) { + gotReq = *req + return &sts.AssumeRoleOutput{Credentials: &sts.Credentials{ + AccessKeyId: aws.String("ASIATESTKEY"), + SecretAccessKey: aws.String("secret"), + SessionToken: aws.String("token"), + Expiration: aws.Time(time.Unix(1700000000, 0).UTC()), + }}, nil + }) + + assumer := NewNATSSTSAssumer(nc) + out, err := assumer.AssumeRoleForInstance(imdsTestAccountID, "arn:aws:iam::123456789012:role/app", "i-abc", 3600) + require.NoError(t, err) + require.NotNil(t, out.Credentials) + + assert.Equal(t, "ASIATESTKEY", aws.StringValue(out.Credentials.AccessKeyId)) + assert.Equal(t, int32(1), atomic.LoadInt32(calls)) + // The request payload must round-trip every field the responder needs. + assert.Equal(t, handlers_sts.AssumeRoleForInstanceRequest{ + AccountID: imdsTestAccountID, + RoleARN: "arn:aws:iam::123456789012:role/app", + InstanceID: "i-abc", + DurationSeconds: 3600, + }, gotReq) +} + +func TestNATSProfileLookup_CachesProfile(t *testing.T) { + _, nc := testutil.StartTestNATS(t) + + calls := serveCounted(t, nc, handlers_iam.SubjectResolveInstanceProfile, + func(req *handlers_iam.ResolveInstanceProfileRequest) (*handlers_iam.InstanceProfile, error) { + return &handlers_iam.InstanceProfile{ + InstanceProfileName: "app", + AccountID: req.AccountID, + RoleName: "app-role", + }, nil + }) + + lookup := NewNATSProfileLookup(nc) + for range 3 { + prof, err := lookup.ResolveInstanceProfile(imdsTestAccountID, "app") + require.NoError(t, err) + assert.Equal(t, "app-role", prof.RoleName) + } + // Three lookups, one round-trip: the TTL cache suppressed the repeats. + assert.Equal(t, int32(1), atomic.LoadInt32(calls)) +} + +func TestNATSProfileLookup_CachesRole(t *testing.T) { + _, nc := testutil.StartTestNATS(t) + + calls := serveCounted(t, nc, handlers_iam.SubjectGetRole, + func(req *handlers_iam.GetRoleRequest) (*iam.GetRoleOutput, error) { + return &iam.GetRoleOutput{Role: &iam.Role{ + RoleName: req.Input.RoleName, + Arn: aws.String("arn:aws:iam::123456789012:role/app-role"), + }}, nil + }) + + lookup := NewNATSProfileLookup(nc) + for range 3 { + out, err := lookup.GetRole(imdsTestAccountID, &iam.GetRoleInput{RoleName: aws.String("app-role")}) + require.NoError(t, err) + assert.Equal(t, "arn:aws:iam::123456789012:role/app-role", aws.StringValue(out.Role.Arn)) + } + assert.Equal(t, int32(1), atomic.LoadInt32(calls)) +} + +func TestNATSProfileLookup_PropagatesError(t *testing.T) { + _, nc := testutil.StartTestNATS(t) + + serveCounted(t, nc, handlers_iam.SubjectResolveInstanceProfile, + func(_ *handlers_iam.ResolveInstanceProfileRequest) (*handlers_iam.InstanceProfile, error) { + return nil, assert.AnError + }) + + lookup := NewNATSProfileLookup(nc) + _, err := lookup.ResolveInstanceProfile(imdsTestAccountID, "missing") + require.Error(t, err) +} + +func TestTTLCache_ExpiresEntries(t *testing.T) { + now := time.Unix(1700000000, 0) + c := newTTLCache[string](time.Minute) + c.now = func() time.Time { return now } + + c.put("k", "v") + got, ok := c.get("k") + require.True(t, ok) + assert.Equal(t, "v", got) + + now = now.Add(2 * time.Minute) // past the TTL + _, ok = c.get("k") + assert.False(t, ok) +} diff --git a/spinifex/handlers/imds/resolver.go b/spinifex/handlers/imds/resolver.go new file mode 100644 index 000000000..8400d7f13 --- /dev/null +++ b/spinifex/handlers/imds/resolver.go @@ -0,0 +1,189 @@ +package handlers_imds + +import ( + "encoding/json" + "errors" + "fmt" + "log/slog" + + "github.com/nats-io/nats.go" +) + +// kvBucketENIs is the ENI source-of-truth bucket (handlers_ec2_vpc.KVBucketENIs), +// duplicated as a literal rather than imported because importing handlers/ec2/vpc +// back would close an import cycle (the veth_store record type does likewise). +const kvBucketENIs = "spinifex-vpc-enis" + +// kvBucketSecurityGroups is the security-group source-of-truth bucket +// (handlers_ec2_vpc.KVBucketSecurityGroups). Duplicated as a literal for the +// same import-cycle reason as kvBucketENIs. +const kvBucketSecurityGroups = "spinifex-vpc-security-groups" + +// eniFacts is the subset of an ENIRecord the IMDS metadata surface serves +// directly, plus the account ID recovered from the ENI bucket key. Everything +// here is read live off the ENI record, so a change (e.g. a re-associated EIP) +// is reflected on the next request. +type eniFacts struct { + eniID string + accountID string + instanceID string + vpcID string + subnetID string + privateIP string + publicIP string + mac string + availabilityZone string + securityGroupIDs []string +} + +// instanceFacts carries the four metadata fields not present on the ENI record. +// They live in the daemon's in-memory instance manager, so they are fetched via +// the account-scoped DescribeInstances fan-out behind instanceLookup. +type instanceFacts struct { + instanceType string + imageID string + iamInstanceProfileArn string + userData []byte +} + +// instanceLookup resolves the instance-only metadata fields by instance ID. It +// is an interface so the metadata handlers stay unit-testable without a live +// NATS cluster; the production implementation (natsInstanceLookup) fans out +// DescribeInstances + DescribeInstanceAttribute. +type instanceLookup interface { + describe(accountID, instanceID string) (*instanceFacts, error) +} + +// eniIndexValue mirrors the stored shape of a spinifex-network-eni-by-vpc-ip +// row (handlers_ec2_vpc.eniByIPValue). Duplicated for the same cycle reason as +// kvBucketENIs. Both fields are the ENI's immutable identity; everything mutable +// is read live off the ENI record. +type eniIndexValue struct { + ENIId string `json:"eni_id"` + AccountID string `json:"account_id"` +} + +// sgNameRecord is the slice of handlers_ec2_vpc.SecurityGroupRecord the metadata +// surface needs: the human-readable group name AWS serves at +// /latest/meta-data/security-groups (not the sg-* ID). +type sgNameRecord struct { + GroupName string `json:"group_name"` +} + +// eniRecord is the subset of handlers_ec2_vpc.ENIRecord the resolver reads. The +// full record is owned by the ENI controller; only these fields feed IMDS. +type eniRecord struct { + NetworkInterfaceId string `json:"network_interface_id"` + SubnetId string `json:"subnet_id"` + VpcId string `json:"vpc_id"` + AvailabilityZone string `json:"availability_zone"` + PrivateIpAddress string `json:"private_ip_address"` + MacAddress string `json:"mac_address"` + InstanceId string `json:"instance_id,omitempty"` + PublicIpAddress string `json:"public_ip_address,omitempty"` + SecurityGroupIds []string `json:"security_group_ids,omitempty"` +} + +// metadataResolver maps a datapath-attested (vpcID, srcIP) to the ENI + instance +// facts the metadata surface serves. The chain is: +// +// (vpcID, ip) → {eniID, accountID} via the eni-by-vpc-ip reverse index +// (account, eniID) → ENIRecord via a direct KV Get +// (account, instanceID) → facts via the account-scoped DescribeInstances fan-out +// +// The index carries the ENI's immutable identity so the account resolves in one +// Get; every mutable field is read live off the record, so there's no staleness. +type metadataResolver struct { + index nats.KeyValue // spinifex-network-eni-by-vpc-ip + eniKV nats.KeyValue // spinifex-vpc-enis + sgKV nats.KeyValue // spinifex-vpc-security-groups (nil-safe: degrades to IDs) + lookup instanceLookup +} + +var _ eniResolver = (*metadataResolver)(nil) + +// resolveENI returns the ENI facts for a request's (vpcID, srcIP), or (nil, nil) +// when no mapping exists — the caller maps a miss to 404, matching AWS's +// "eventually available during boot" posture. A non-nil error is reserved for +// genuine backend failures. +func (r *metadataResolver) resolveENI(vpcID, srcIP string) (*eniFacts, error) { + entry, err := r.index.Get(vpcID + "/" + srcIP) + if err != nil { + if errors.Is(err, nats.ErrKeyNotFound) { + return nil, nil + } + return nil, fmt.Errorf("get eni-by-ip index %s/%s: %w", vpcID, srcIP, err) + } + + var idx eniIndexValue + if err := json.Unmarshal(entry.Value(), &idx); err != nil { + return nil, fmt.Errorf("unmarshal eni-by-ip index %s/%s: %w", vpcID, srcIP, err) + } + if idx.ENIId == "" || idx.AccountID == "" { + return nil, nil + } + + raw, err := r.eniKV.Get(idx.AccountID + "." + idx.ENIId) + if err != nil { + if errors.Is(err, nats.ErrKeyNotFound) { + return nil, nil + } + return nil, fmt.Errorf("get eni record %s.%s: %w", idx.AccountID, idx.ENIId, err) + } + + var rec eniRecord + if err := json.Unmarshal(raw.Value(), &rec); err != nil { + return nil, fmt.Errorf("unmarshal eni record %s: %w", idx.ENIId, err) + } + + return &eniFacts{ + eniID: rec.NetworkInterfaceId, + accountID: idx.AccountID, + instanceID: rec.InstanceId, + vpcID: rec.VpcId, + subnetID: rec.SubnetId, + privateIP: rec.PrivateIpAddress, + publicIP: rec.PublicIpAddress, + mac: rec.MacAddress, + availabilityZone: rec.AvailabilityZone, + securityGroupIDs: rec.SecurityGroupIds, + }, nil +} + +// resolveInstance fetches the instance-only metadata fields for an ENI's +// attached instance. Returns (nil, nil) when the ENI has no attached instance. +func (r *metadataResolver) resolveInstance(eni *eniFacts) (*instanceFacts, error) { + if eni.instanceID == "" { + return nil, nil + } + return r.lookup.describe(eni.accountID, eni.instanceID) +} + +// resolveSGNames maps security-group IDs to the group names AWS serves at +// /latest/meta-data/security-groups. Best-effort and order-preserving: a missing +// record or nil sgKV falls back to the raw ID rather than failing the request. +func (r *metadataResolver) resolveSGNames(accountID string, sgIDs []string) []string { + names := make([]string, len(sgIDs)) + for i, id := range sgIDs { + names[i] = id + if r.sgKV == nil { + continue + } + raw, err := r.sgKV.Get(accountID + "." + id) + if err != nil { + if !errors.Is(err, nats.ErrKeyNotFound) { + slog.Warn("IMDS: security-group name lookup failed", "account_id", accountID, "sg_id", id, "err", err) + } + continue + } + var rec sgNameRecord + if err := json.Unmarshal(raw.Value(), &rec); err != nil { + slog.Warn("IMDS: security-group unmarshal failed", "sg_id", id, "err", err) + continue + } + if rec.GroupName != "" { + names[i] = rec.GroupName + } + } + return names +} diff --git a/spinifex/handlers/imds/resolver_test.go b/spinifex/handlers/imds/resolver_test.go new file mode 100644 index 000000000..5577570d7 --- /dev/null +++ b/spinifex/handlers/imds/resolver_test.go @@ -0,0 +1,190 @@ +package handlers_imds + +import ( + "encoding/json" + "errors" + "testing" + + "github.com/mulgadc/spinifex/spinifex/testutil" + "github.com/nats-io/nats.go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// fakeLookup is a programmable instanceLookup so resolver tests never need the +// account-scoped instance fan-out. +type fakeLookup struct { + facts *instanceFacts + err error + calls int +} + +func (f *fakeLookup) describe(_, _ string) (*instanceFacts, error) { + f.calls++ + return f.facts, f.err +} + +// newTestResolver wires a metadataResolver onto a live test JetStream with the +// three buckets it reads (eni-by-vpc-ip index, ENI source-of-truth, SG names) +// created empty, plus a fake instance lookup the caller can program. +func newTestResolver(t *testing.T) (*metadataResolver, *fakeLookup) { + t.Helper() + _, _, js := testutil.StartTestJetStream(t) + index, err := InitENIByIPBucket(js, 1) + require.NoError(t, err) + eniKV, err := js.CreateKeyValue(&nats.KeyValueConfig{Bucket: kvBucketENIs, History: 1}) + require.NoError(t, err) + sgKV, err := js.CreateKeyValue(&nats.KeyValueConfig{Bucket: kvBucketSecurityGroups, History: 1}) + require.NoError(t, err) + + lookup := &fakeLookup{} + return &metadataResolver{index: index, eniKV: eniKV, sgKV: sgKV, lookup: lookup}, lookup +} + +func putJSON(t *testing.T, kv nats.KeyValue, key string, v any) { + t.Helper() + data, err := json.Marshal(v) + require.NoError(t, err) + _, err = kv.Put(key, data) + require.NoError(t, err) +} + +// seedENI writes a complete index → ENI chain for (testVPC, testIP) and returns +// the resolver ready to serve it. +func seedENI(t *testing.T, r *metadataResolver) { + t.Helper() + putJSON(t, r.index, testVPC+"/"+testIP, eniIndexValue{ENIId: "eni-aaa", AccountID: "111122223333"}) + putJSON(t, r.eniKV, "111122223333.eni-aaa", eniRecord{ + NetworkInterfaceId: "eni-aaa", + SubnetId: "subnet-1", + VpcId: testVPC, + AvailabilityZone: "ap-southeast-2a", + PrivateIpAddress: testIP, + MacAddress: "02:11:22:33:44:55", + InstanceId: "i-0123456789", + PublicIpAddress: "203.0.113.7", + SecurityGroupIds: []string{"sg-1", "sg-2"}, + }) +} + +func TestResolveENI_Hit(t *testing.T) { + r, _ := newTestResolver(t) + seedENI(t, r) + + eni, err := r.resolveENI(testVPC, testIP) + require.NoError(t, err) + require.NotNil(t, eni) + assert.Equal(t, "eni-aaa", eni.eniID) + assert.Equal(t, "111122223333", eni.accountID) + assert.Equal(t, "i-0123456789", eni.instanceID) + assert.Equal(t, testVPC, eni.vpcID) + assert.Equal(t, "subnet-1", eni.subnetID) + assert.Equal(t, testIP, eni.privateIP) + assert.Equal(t, "203.0.113.7", eni.publicIP) + assert.Equal(t, "02:11:22:33:44:55", eni.mac) + assert.Equal(t, "ap-southeast-2a", eni.availabilityZone) + assert.Equal(t, []string{"sg-1", "sg-2"}, eni.securityGroupIDs) +} + +// A source IP with no reverse-index row is a miss, not an error — the caller +// maps it to 404 per AWS's "eventually available during boot" posture. +func TestResolveENI_IndexMissIsNilNil(t *testing.T) { + r, _ := newTestResolver(t) + eni, err := r.resolveENI(testVPC, "10.9.9.9") + require.NoError(t, err) + assert.Nil(t, eni) +} + +func TestResolveENI_IndexBadJSONErrors(t *testing.T) { + r, _ := newTestResolver(t) + _, err := r.index.Put(testVPC+"/"+testIP, []byte("not json")) + require.NoError(t, err) + + _, err = r.resolveENI(testVPC, testIP) + require.Error(t, err) +} + +// An index row missing either identity field is treated as a miss rather than +// being chased into a malformed ENI Get. +func TestResolveENI_EmptyIndexFieldsIsNilNil(t *testing.T) { + r, _ := newTestResolver(t) + putJSON(t, r.index, testVPC+"/"+testIP, eniIndexValue{ENIId: "eni-aaa"}) // no account + eni, err := r.resolveENI(testVPC, testIP) + require.NoError(t, err) + assert.Nil(t, eni) +} + +// A dangling index pointing at an ENI record that no longer exists is a miss, +// matching a mid-teardown race. +func TestResolveENI_ENIRecordMissIsNilNil(t *testing.T) { + r, _ := newTestResolver(t) + putJSON(t, r.index, testVPC+"/"+testIP, eniIndexValue{ENIId: "eni-gone", AccountID: "111122223333"}) + eni, err := r.resolveENI(testVPC, testIP) + require.NoError(t, err) + assert.Nil(t, eni) +} + +func TestResolveENI_ENIRecordBadJSONErrors(t *testing.T) { + r, _ := newTestResolver(t) + putJSON(t, r.index, testVPC+"/"+testIP, eniIndexValue{ENIId: "eni-aaa", AccountID: "111122223333"}) + _, err := r.eniKV.Put("111122223333.eni-aaa", []byte("not json")) + require.NoError(t, err) + + _, err = r.resolveENI(testVPC, testIP) + require.Error(t, err) +} + +func TestResolveInstance_NoAttachedInstance(t *testing.T) { + r, lookup := newTestResolver(t) + inst, err := r.resolveInstance(&eniFacts{instanceID: ""}) + require.NoError(t, err) + assert.Nil(t, inst) + assert.Equal(t, 0, lookup.calls, "lookup must be skipped when no instance is attached") +} + +func TestResolveInstance_DelegatesToLookup(t *testing.T) { + r, lookup := newTestResolver(t) + lookup.facts = &instanceFacts{instanceType: "t3.micro", imageID: "ami-1"} + + inst, err := r.resolveInstance(&eniFacts{accountID: "111122223333", instanceID: "i-1"}) + require.NoError(t, err) + require.NotNil(t, inst) + assert.Equal(t, "t3.micro", inst.instanceType) + assert.Equal(t, 1, lookup.calls) +} + +func TestResolveInstance_LookupErrorPropagates(t *testing.T) { + r, lookup := newTestResolver(t) + lookup.err = errors.New("fan-out failed") + _, err := r.resolveInstance(&eniFacts{accountID: "111122223333", instanceID: "i-1"}) + require.Error(t, err) +} + +// A nil SG bucket (not yet up at start) must degrade the endpoint to raw IDs +// rather than failing the request. +func TestResolveSGNames_NilBucketDegradesToIDs(t *testing.T) { + r, _ := newTestResolver(t) + r.sgKV = nil + got := r.resolveSGNames("111122223333", []string{"sg-1", "sg-2"}) + assert.Equal(t, []string{"sg-1", "sg-2"}, got) +} + +// Names resolve where a record exists; a missing record or one with an empty +// name falls back to the ID, and order is preserved throughout. +func TestResolveSGNames_ResolvesAndFallsBack(t *testing.T) { + r, _ := newTestResolver(t) + putJSON(t, r.sgKV, "111122223333.sg-1", sgNameRecord{GroupName: "web-sg"}) + putJSON(t, r.sgKV, "111122223333.sg-3", sgNameRecord{GroupName: ""}) // empty → ID + + got := r.resolveSGNames("111122223333", []string{"sg-1", "sg-2", "sg-3"}) + assert.Equal(t, []string{"web-sg", "sg-2", "sg-3"}, got) +} + +func TestResolveSGNames_BadJSONFallsBackToID(t *testing.T) { + r, _ := newTestResolver(t) + _, err := r.sgKV.Put("111122223333.sg-1", []byte("not json")) + require.NoError(t, err) + + got := r.resolveSGNames("111122223333", []string{"sg-1"}) + assert.Equal(t, []string{"sg-1"}, got) +} diff --git a/spinifex/handlers/imds/server.go b/spinifex/handlers/imds/server.go new file mode 100644 index 000000000..2443ff140 --- /dev/null +++ b/spinifex/handlers/imds/server.go @@ -0,0 +1,303 @@ +package handlers_imds + +import ( + "context" + "errors" + "fmt" + "log/slog" + "net" + "net/http" + "os" + "runtime" + "sync" + "syscall" + "time" + + "github.com/mulgadc/spinifex/spinifex/utils" + "github.com/nats-io/nats.go" + "golang.org/x/sys/unix" +) + +// ensureVethFunc / removeVethFunc are the per-VPC host veth lifecycle hooks, +// injected (not imported) to avoid an import cycle via network/host. vpcd passes +// host.EnsureIMDSVeth / host.RemoveIMDSVeth; tests pass root-free fakes. ensure +// returns the per-VPC netns the listener must be created in plus the host-end +// veth name (now living inside that netns). +type ensureVethFunc func(ctx context.Context, vpcID string) (netnsName, hostEnd string, err error) +type removeVethFunc func(ctx context.Context, vpcID string) error + +// listenFunc binds a TCP listener on 169.254.169.254:80 inside the VPC's netns, +// scoped to its host veth. Swappable in tests so bind-manager logic runs without +// CAP_NET_ADMIN or a real netns. An empty netnsName binds in the current netns. +type listenFunc func(ctx context.Context, netnsName, hostEnd string) (net.Listener, error) + +// activeBinding is the per-VPC realised state: a listener bound to the VPC's +// host veth and the http.Server serving it. +type activeBinding struct { + listener net.Listener + server *http.Server +} + +// bindManager realises the per-chassis IMDS listener stack. It runs on every +// chassis and eagerly materialises a veth + OVS port + listener for every VPC in +// the vpc-veth bucket — lifecycle is "watch the bucket, ensure local state". +type bindManager struct { + kv nats.KeyValue // spinifex-network-imds-vpc-veth + handler http.Handler + ensureVeth ensureVethFunc + removeVeth removeVethFunc + listen listenFunc + + mu sync.Mutex + active map[string]*activeBinding // vpcID → binding +} + +func newBindManager(kv nats.KeyValue, handler http.Handler, ensure ensureVethFunc, remove removeVethFunc, listen listenFunc) *bindManager { + return &bindManager{ + kv: kv, + handler: handler, + ensureVeth: ensure, + removeVeth: remove, + listen: listen, + active: make(map[string]*activeBinding), + } +} + +// sync reads the full vpc-veth bucket and binds a listener for every entry. Run +// once at startup; idempotent, so a re-sync after a transient error is safe. +func (b *bindManager) sync(ctx context.Context) error { + keys, err := b.kv.Keys() + if err != nil { + if errors.Is(err, nats.ErrNoKeysFound) { + return nil + } + return fmt.Errorf("list vpc-veth keys: %w", err) + } + for _, vpcID := range keys { + if vpcID == utils.VersionKey { + continue // schema-version marker written by migrate.RunKV, not a VPC + } + if err := b.bind(ctx, vpcID); err != nil { + slog.Error("IMDS: bind failed during sync", "vpc_id", vpcID, "err", err) + } + } + return nil +} + +// watch reacts to vpc-veth bucket changes for the life of ctx: a Put binds the +// VPC (if not already bound), a Delete unbinds it and tears down the veth. Both +// transitions are idempotent. +func (b *bindManager) watch(ctx context.Context) { + watcher, err := b.kv.WatchAll(nats.Context(ctx)) + if err != nil { + slog.Error("IMDS: failed to start vpc-veth watcher", "err", err) + return + } + defer func() { _ = watcher.Stop() }() + + for { + select { + case <-ctx.Done(): + return + case entry, ok := <-watcher.Updates(): + if !ok { + return + } + if entry == nil { + // nil marks the end of the initial replay; sync() already + // covered those, so there is nothing extra to do. + continue + } + if entry.Key() == utils.VersionKey { + continue // schema-version marker written by migrate.RunKV, not a VPC + } + switch entry.Operation() { + case nats.KeyValuePut: + if err := b.bind(ctx, entry.Key()); err != nil { + slog.Error("IMDS: bind failed on watch", "vpc_id", entry.Key(), "err", err) + } + case nats.KeyValueDelete, nats.KeyValuePurge: + b.unbind(ctx, entry.Key()) + } + } + } +} + +// bind ensures the host veth then opens a device-scoped listener for vpcID. A +// no-op if the VPC is already bound. +func (b *bindManager) bind(ctx context.Context, vpcID string) error { + b.mu.Lock() + if _, ok := b.active[vpcID]; ok { + b.mu.Unlock() + return nil + } + b.mu.Unlock() + + netnsName, hostEnd, err := b.ensureVeth(ctx, vpcID) + if err != nil { + return fmt.Errorf("ensure veth: %w", err) + } + + listener, err := b.listen(ctx, netnsName, hostEnd) + if err != nil { + return fmt.Errorf("listen on %s in netns %s: %w", hostEnd, netnsName, err) + } + + server := &http.Server{ + Handler: b.handler, + ReadHeaderTimeout: 10 * time.Second, + // Tag every request from this listener with its VPC ID. The handler + // pairs it with the datapath-attested source IP to resolve the ENI. + BaseContext: func(net.Listener) context.Context { + return context.WithValue(ctx, ctxKeyVPCID, vpcID) + }, + } + + b.mu.Lock() + // Re-check under lock in case a concurrent bind won the race. + if _, ok := b.active[vpcID]; ok { + b.mu.Unlock() + _ = listener.Close() + return nil + } + b.active[vpcID] = &activeBinding{listener: listener, server: server} + b.mu.Unlock() + + go func() { + if err := server.Serve(listener); err != nil && !errors.Is(err, http.ErrServerClosed) { + slog.Error("IMDS: listener serve exited", "vpc_id", vpcID, "host_end", hostEnd, "err", err) + } + }() + + slog.Info("IMDS: listener bound", "vpc_id", vpcID, "netns", netnsName, "host_end", hostEnd, "addr", listener.Addr().String()) + return nil +} + +// unbind closes the VPC's listener and removes its host veth. Idempotent. +func (b *bindManager) unbind(ctx context.Context, vpcID string) { + b.mu.Lock() + binding := b.active[vpcID] + delete(b.active, vpcID) + b.mu.Unlock() + + if binding != nil { + if err := binding.server.Close(); err != nil { + slog.Warn("IMDS: listener close failed", "vpc_id", vpcID, "err", err) + } + } + if err := b.removeVeth(ctx, vpcID); err != nil { + slog.Warn("IMDS: veth removal failed", "vpc_id", vpcID, "err", err) + } + slog.Info("IMDS: listener unbound", "vpc_id", vpcID) +} + +// shutdown closes every active listener. The host veths are intentionally left +// in place: they are cheap, idempotent to re-ensure on the next start, and +// tearing them down on a clean vpcd restart would needlessly disrupt any other +// chassis-local consumer. +func (b *bindManager) shutdown() { + b.mu.Lock() + defer b.mu.Unlock() + for vpcID, binding := range b.active { + if err := binding.server.Close(); err != nil { + slog.Warn("IMDS: listener close failed during shutdown", "vpc_id", vpcID, "err", err) + } + delete(b.active, vpcID) + } +} + +// bindLocalListener opens a TCP listener on 169.254.169.254:80 inside the VPC's +// netns, where the host-end veth carries 169.254.169.254/30 with a default route +// via the .253 LRP — so the host-served reply has a real L3 next-hop back to the +// guest (SO_BINDTODEVICE alone in the root netns could not route the SYN-ACK). +// The netns also isolates VPCs whose CIDRs overlap, since each is its own routing +// domain. The socket must be *created* in the netns, so we enter it on a locked +// thread for the socket call and restore the root netns before serving. +// SO_BINDTODEVICE (belt-and-braces — there is only one veth in the netns) and +// SO_REUSEADDR (fast rebind on vpcd restart) are still set on the fd. +func bindLocalListener(ctx context.Context, netnsName, hostEnd string) (net.Listener, error) { + lc := net.ListenConfig{ + Control: func(_, _ string, c syscall.RawConn) error { + var sockErr error + if err := c.Control(func(fd uintptr) { + if sockErr = unix.SetsockoptString(int(fd), unix.SOL_SOCKET, unix.SO_BINDTODEVICE, hostEnd); sockErr != nil { + return + } + sockErr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1) + }); err != nil { + return err + } + return sockErr + }, + } + + bind := func() (net.Listener, error) { + return lc.Listen(ctx, "tcp4", net.JoinHostPort(MetaDataServerIP, "80")) + } + + if netnsName == "" { + // No netns (tests, or a degraded host): bind in the current netns. + return bind() + } + + var ln net.Listener + err := inNetns(netnsName, func() error { + var e error + ln, e = bind() + return e + }) + if err != nil { + return nil, err + } + return ln, nil +} + +// inNetns runs fn on a dedicated OS thread switched into the named network +// namespace, then restores the root netns. fn's socket-creating syscalls happen +// in the target netns, so the listener fd belongs to it; once created, the fd is +// served normally from any thread. If the root netns cannot be restored the +// thread is poisoned, so the goroutine returns while still locked and the Go +// runtime retires the thread rather than returning it to the pool. +func inNetns(netnsName string, fn func() error) error { + const netnsDir = "/var/run/netns/" + errCh := make(chan error, 1) + + go func() { + runtime.LockOSThread() + + orig, err := os.Open("/proc/thread-self/ns/net") + if err != nil { + runtime.UnlockOSThread() + errCh <- fmt.Errorf("open current netns: %w", err) + return + } + defer func() { _ = orig.Close() }() + + target, err := os.Open(netnsDir + netnsName) + if err != nil { + runtime.UnlockOSThread() + errCh <- fmt.Errorf("open netns %s: %w", netnsName, err) + return + } + defer func() { _ = target.Close() }() + + if err := unix.Setns(int(target.Fd()), unix.CLONE_NEWNET); err != nil { + runtime.UnlockOSThread() + errCh <- fmt.Errorf("setns into %s: %w", netnsName, err) + return + } + + fnErr := fn() + + if err := unix.Setns(int(orig.Fd()), unix.CLONE_NEWNET); err != nil { + // Cannot return to the root netns — leave the thread locked so the + // runtime destroys it when this goroutine exits. + errCh <- errors.Join(fnErr, fmt.Errorf("restore root netns: %w", err)) + return + } + runtime.UnlockOSThread() + errCh <- fnErr + }() + + return <-errCh +} diff --git a/spinifex/handlers/imds/server_test.go b/spinifex/handlers/imds/server_test.go new file mode 100644 index 000000000..59acaea75 --- /dev/null +++ b/spinifex/handlers/imds/server_test.go @@ -0,0 +1,122 @@ +package handlers_imds + +import ( + "context" + "io" + "net" + "net/http" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/mulgadc/spinifex/spinifex/testutil" + "github.com/mulgadc/spinifex/spinifex/utils" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// loopbackListen returns a listenFunc backed by a real 127.0.0.1 listener so +// bind-manager logic runs end-to-end (including http.Server.Serve and the +// per-listener BaseContext) without root or the link-local address. It records +// the bound address per host-end so the test can dial it. +func loopbackListen(addrs *sync.Map) listenFunc { + return func(ctx context.Context, netnsName, hostEnd string) (net.Listener, error) { + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + return nil, err + } + addrs.Store(hostEnd, ln.Addr().String()) + return ln, nil + } +} + +func TestBindManager_BindServesWithVPCContext(t *testing.T) { + const hostEnd = "imds-h-abc12345" + var ensured, removed atomic.Int32 + ensure := func(_ context.Context, _ string) (string, string, error) { + ensured.Add(1) + return "", hostEnd, nil + } + remove := func(_ context.Context, _ string) error { + removed.Add(1) + return nil + } + + // Echo the VPC ID the bind manager threaded into the request context — this + // is the (VPC-ID, source-IP) → identity path the security model relies on. + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + vpcID, _ := r.Context().Value(ctxKeyVPCID).(string) + _, _ = io.WriteString(w, vpcID) + }) + + var addrs sync.Map + bm := newBindManager(nil, handler, ensure, remove, loopbackListen(&addrs)) + ctx := context.Background() + + require.NoError(t, bm.bind(ctx, "vpc-abc12345")) + assert.Equal(t, int32(1), ensured.Load()) + + // Second bind of the same VPC is a no-op (idempotent), no extra veth ensure. + require.NoError(t, bm.bind(ctx, "vpc-abc12345")) + assert.Equal(t, int32(1), ensured.Load()) + + raw, ok := addrs.Load(hostEnd) + require.True(t, ok) + addr, ok := raw.(string) + require.True(t, ok) + + resp, err := http.Get("http://" + addr + prefixMetaData) + require.NoError(t, err) + body, _ := io.ReadAll(resp.Body) + _ = resp.Body.Close() + assert.Equal(t, "vpc-abc12345", string(body), "handler must see the listener's VPC ID") + + // Unbind closes the listener and tears down the veth. + bm.unbind(ctx, "vpc-abc12345") + assert.Equal(t, int32(1), removed.Load()) + + client := http.Client{Timeout: 500 * time.Millisecond} + _, err = client.Get("http://" + addr + prefixMetaData) + assert.Error(t, err, "listener must be closed after unbind") +} + +func TestBindManager_BindPropagatesVethError(t *testing.T) { + ensure := func(_ context.Context, _ string) (string, string, error) { + return "", "", errEnsureFailed + } + bm := newBindManager(nil, http.NewServeMux(), ensure, func(context.Context, string) error { return nil }, loopbackListen(&sync.Map{})) + err := bm.bind(context.Background(), "vpc-x") + require.Error(t, err) +} + +var errEnsureFailed = io.ErrUnexpectedEOF + +// TestBindManager_SyncSkipsVersionKey guards that the schema-version marker +// migrate.RunKV stamps into the vpc-veth bucket is not mistaken for a VPC ID +// and made to bring up a bogus veth + listener. +func TestBindManager_SyncSkipsVersionKey(t *testing.T) { + _, _, js := testutil.StartTestJetStream(t) + vpcVeth, _, err := InitBuckets(js, 1) + require.NoError(t, err) + + // InitBuckets → migrate.RunKV stamps utils.VersionKey; add one real VPC too. + _, err = vpcVeth.PutString("vpc-abcdef12", "{}") + require.NoError(t, err) + + var bound sync.Map + ensure := func(_ context.Context, vpcID string) (string, string, error) { + bound.Store(vpcID, true) + return "imds-" + vpcID, "imds-h-" + vpcID, nil + } + remove := func(context.Context, string) error { return nil } + bm := newBindManager(vpcVeth, http.NewServeMux(), ensure, remove, loopbackListen(&sync.Map{})) + + require.NoError(t, bm.sync(context.Background())) + defer bm.shutdown() + + _, versionBound := bound.Load(utils.VersionKey) + assert.False(t, versionBound, "_version marker must not be bound as a VPC") + _, vpcBound := bound.Load("vpc-abcdef12") + assert.True(t, vpcBound, "real VPC entry must be bound") +} diff --git a/spinifex/handlers/imds/service.go b/spinifex/handlers/imds/service.go new file mode 100644 index 000000000..417111e3a --- /dev/null +++ b/spinifex/handlers/imds/service.go @@ -0,0 +1,161 @@ +package handlers_imds + +import ( + "context" + "errors" + "fmt" + "log/slog" + "net/http" + "time" + + "github.com/aws/aws-sdk-go/service/iam" + handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam" + "github.com/nats-io/nats.go" +) + +// tokenSweepInterval is how often abandoned/expired IMDSv2 tokens are swept. +const tokenSweepInterval = time.Minute + +// profileLookup is the slice of IAMService the IMDS credential + iam/* paths +// need: dereference an instance-profile ARN to its record, and resolve a role +// name to its canonical ARN. Narrowed to an interface for unit testing. +type profileLookup interface { + ResolveInstanceProfile(accountID, nameOrARN string) (*handlers_iam.InstanceProfile, error) + GetRole(accountID string, input *iam.GetRoleInput) (*iam.GetRoleOutput, error) +} + +// IMDSService is the host-served EC2 Instance Metadata Service. It runs in +// vpcd on every chassis, serving 169.254.169.254 to local guest VMs over +// per-VPC veths. Run owns the listener lifecycle and blocks until ctx is done. +type IMDSService interface { + Run(ctx context.Context) error +} + +var _ IMDSService = (*IMDSServiceImpl)(nil) + +// eniResolver maps a datapath-attested (vpcID, srcIP) to ENI + instance facts. +// An interface so the HTTP handlers are unit-testable without a live KV; +// metadataResolver is the production implementation. +type eniResolver interface { + resolveENI(vpcID, srcIP string) (*eniFacts, error) + resolveInstance(eni *eniFacts) (*instanceFacts, error) + resolveSGNames(accountID string, sgIDs []string) []string +} + +// IMDSServiceImpl is the in-process IMDS implementation. It is not part of the +// HTTPS gateway dispatch surface — it owns its own per-VPC listener stack. +type IMDSServiceImpl struct { + resolver eniResolver + tokens *tokenStore + creds *credCache + iam profileLookup + bind *bindManager + now func() time.Time +} + +// NewIMDSServiceImpl wires the IMDS service. natsConn backs the KV reads and the +// account-scoped instance fan-out (sized by expectedNodes); ensureVeth/removeVeth +// are injected rather than imported to avoid an import cycle via network/host. +func NewIMDSServiceImpl(natsConn *nats.Conn, sts stsAssumer, iamSvc profileLookup, expectedNodes int, ensureVeth ensureVethFunc, removeVeth removeVethFunc) (*IMDSServiceImpl, error) { + if natsConn == nil { + return nil, errors.New("nil NATS connection") + } + if sts == nil { + return nil, errors.New("nil STS service") + } + if iamSvc == nil { + return nil, errors.New("nil IAM service") + } + if ensureVeth == nil || removeVeth == nil { + return nil, errors.New("nil veth lifecycle hooks") + } + + js, err := natsConn.JetStream() + if err != nil { + return nil, fmt.Errorf("get JetStream context: %w", err) + } + + indexKV, err := js.KeyValue(KVBucketENIByVPCIP) + if err != nil { + return nil, fmt.Errorf("open %s bucket: %w", KVBucketENIByVPCIP, err) + } + eniKV, err := js.KeyValue(kvBucketENIs) + if err != nil { + return nil, fmt.Errorf("open %s bucket: %w", kvBucketENIs, err) + } + vethKV, err := js.KeyValue(KVBucketIMDSVPCVeth) + if err != nil { + return nil, fmt.Errorf("open %s bucket: %w", KVBucketIMDSVPCVeth, err) + } + + // The SG bucket is owned by the VPC service and only feeds the non-critical + // security-groups path. Open it best-effort: if it isn't up yet, IMDS still + // starts and resolveSGNames degrades to serving raw IDs. + sgKV, err := js.KeyValue(kvBucketSecurityGroups) + if err != nil { + slog.Warn("IMDS: security-group bucket unavailable, /security-groups will serve IDs", "bucket", kvBucketSecurityGroups, "err", err) + sgKV = nil + } + + svc := &IMDSServiceImpl{ + resolver: &metadataResolver{ + index: indexKV, + eniKV: eniKV, + sgKV: sgKV, + lookup: &natsInstanceLookup{nc: natsConn, expectedNodes: expectedNodes}, + }, + tokens: newTokenStore(), + creds: newCredCache(sts), + iam: iamSvc, + now: time.Now, + } + svc.bind = newBindManager(vethKV, svc.httpHandler(), ensureVeth, removeVeth, bindLocalListener) + + slog.Info("IMDS service initialized", + "index_bucket", KVBucketENIByVPCIP, + "veth_bucket", KVBucketIMDSVPCVeth) + return svc, nil +} + +// httpHandler builds the shared mux used by every per-VPC listener. The token +// PUT is the only path reachable without a token; everything else is gated. +func (s *IMDSServiceImpl) httpHandler() http.Handler { + mux := http.NewServeMux() + mux.HandleFunc(pathToken, s.handleToken) + mux.HandleFunc("/", s.handleMetadata) + return rejectForwarded(mux) +} + +// Run starts the bind manager (sync + watch) and the token-sweep ticker, then +// blocks until ctx is cancelled. The initial sync failing is logged but not +// fatal — other vpcd services must not have their readiness gated on IMDS +// plumbing, and SDKs retry while it converges. +func (s *IMDSServiceImpl) Run(ctx context.Context) error { + if err := s.bind.sync(ctx); err != nil { + slog.Warn("IMDS: initial bind sync failed, continuing", "err", err) + } + go s.bind.watch(ctx) + go s.sweepExpired(ctx) + + <-ctx.Done() + s.bind.shutdown() + return ctx.Err() +} + +// sweepExpired evicts expired IMDSv2 tokens and stale credential-cache entries +// on a ticker for the life of ctx. Both stores are in-memory and accrete on VM +// churn, so a single sweep keeps them bounded without a per-store goroutine. +func (s *IMDSServiceImpl) sweepExpired(ctx context.Context) { + ticker := time.NewTicker(tokenSweepInterval) + defer ticker.Stop() + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + now := s.now() + s.tokens.sweep(now) + s.creds.sweep(now) + } + } +} diff --git a/spinifex/handlers/imds/token.go b/spinifex/handlers/imds/token.go new file mode 100644 index 000000000..5dd30280f --- /dev/null +++ b/spinifex/handlers/imds/token.go @@ -0,0 +1,85 @@ +package handlers_imds + +import ( + "crypto/rand" + "encoding/base64" + "sync" + "time" +) + +const ( + // tokenTTLMin / tokenTTLMax bound the X-aws-ec2-metadata-token-ttl-seconds + // header, matching AWS (1 second to 6 hours). + tokenTTLMin = 1 + tokenTTLMax = 21600 + + // tokenBytes is the random token length before base64url encoding. + tokenBytes = 32 +) + +// tokenEntry binds an issued IMDSv2 token to the ENI that requested it (not the +// IP — so the session survives a DHCP-renew IP change but dies on ENI detach) +// and its expiry. +type tokenEntry struct { + eniID string + expiresAt time.Time +} + +// tokenStore holds outstanding IMDSv2 tokens in memory, per process. Tokens are +// a CSRF defence, not a security artefact, so they are never persisted; a +// vpcd restart drops them and SDKs reissue transparently. +type tokenStore struct { + mu sync.Mutex + tokens map[string]tokenEntry +} + +func newTokenStore() *tokenStore { + return &tokenStore{tokens: make(map[string]tokenEntry)} +} + +// issue mints a fresh token bound to eniID, valid for ttl from now. +func (s *tokenStore) issue(eniID string, ttl time.Duration, now time.Time) (string, error) { + buf := make([]byte, tokenBytes) + if _, err := rand.Read(buf); err != nil { + return "", err + } + token := base64.RawURLEncoding.EncodeToString(buf) + + s.mu.Lock() + s.tokens[token] = tokenEntry{eniID: eniID, expiresAt: now.Add(ttl)} + s.mu.Unlock() + return token, nil +} + +// validate reports whether token is currently valid AND was issued to +// expectedENI. A wrong-ENI token is rejected exactly like an unknown one so the +// caller cannot probe which tokens exist. Expired tokens are evicted lazily. +func (s *tokenStore) validate(token, expectedENI string, now time.Time) bool { + if token == "" { + return false + } + s.mu.Lock() + defer s.mu.Unlock() + + entry, ok := s.tokens[token] + if !ok { + return false + } + if now.After(entry.expiresAt) { + delete(s.tokens, token) + return false + } + return entry.eniID == expectedENI +} + +// sweep deletes every token that expired at or before now. Called on a 1-minute +// ticker so abandoned tokens (an SDK that issues then never reads) don't leak. +func (s *tokenStore) sweep(now time.Time) { + s.mu.Lock() + defer s.mu.Unlock() + for token, entry := range s.tokens { + if now.After(entry.expiresAt) { + delete(s.tokens, token) + } + } +} diff --git a/spinifex/handlers/imds/token_test.go b/spinifex/handlers/imds/token_test.go new file mode 100644 index 000000000..7dde4b500 --- /dev/null +++ b/spinifex/handlers/imds/token_test.go @@ -0,0 +1,95 @@ +package handlers_imds + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTokenStore_IssueAndValidate(t *testing.T) { + s := newTokenStore() + now := time.Unix(1_700_000_000, 0) + + token, err := s.issue("eni-aaa", 60*time.Second, now) + require.NoError(t, err) + require.NotEmpty(t, token) + + assert.True(t, s.validate(token, "eni-aaa", now), "fresh token for its ENI must validate") + assert.True(t, s.validate(token, "eni-aaa", now.Add(59*time.Second)), "token valid until TTL") +} + +func TestTokenStore_WrongENIRejected(t *testing.T) { + s := newTokenStore() + now := time.Unix(1_700_000_000, 0) + token, err := s.issue("eni-aaa", 60*time.Second, now) + require.NoError(t, err) + + // A token issued to eni-aaa must not validate for eni-bbb — otherwise a + // guest could replay a peer's token to read the peer's session. + assert.False(t, s.validate(token, "eni-bbb", now)) +} + +func TestTokenStore_ExpiredRejectedAndEvicted(t *testing.T) { + s := newTokenStore() + now := time.Unix(1_700_000_000, 0) + token, err := s.issue("eni-aaa", 1*time.Second, now) + require.NoError(t, err) + + assert.False(t, s.validate(token, "eni-aaa", now.Add(2*time.Second)), "expired token must be rejected") + // Lazy eviction: the failed validate above dropped it, so even at a valid + // time it no longer exists. + assert.False(t, s.validate(token, "eni-aaa", now)) +} + +func TestTokenStore_UnknownAndEmptyRejected(t *testing.T) { + s := newTokenStore() + now := time.Unix(1_700_000_000, 0) + assert.False(t, s.validate("", "eni-aaa", now)) + assert.False(t, s.validate("never-issued", "eni-aaa", now)) +} + +func TestTokenStore_Sweep(t *testing.T) { + s := newTokenStore() + now := time.Unix(1_700_000_000, 0) + live, _ := s.issue("eni-live", 3600*time.Second, now) + dead, _ := s.issue("eni-dead", 1*time.Second, now) + + s.sweep(now.Add(2 * time.Second)) + + assert.True(t, s.validate(live, "eni-live", now.Add(2*time.Second)), "live token survives sweep") + assert.False(t, s.validate(dead, "eni-dead", now), "expired token swept") +} + +func TestTokenStore_IssueUnique(t *testing.T) { + s := newTokenStore() + now := time.Unix(1_700_000_000, 0) + a, _ := s.issue("eni-aaa", 60*time.Second, now) + b, _ := s.issue("eni-aaa", 60*time.Second, now) + assert.NotEqual(t, a, b, "each issued token must be distinct") +} + +func TestParseTokenTTL(t *testing.T) { + cases := []struct { + in string + ok bool + secs int + }{ + {"", false, 0}, + {"abc", false, 0}, + {"0", false, 0}, + {"21601", false, 0}, + {"-5", false, 0}, + {"1", true, 1}, + {"21600", true, 21600}, + {"60", true, 60}, + } + for _, c := range cases { + d, ok := parseTokenTTL(c.in) + assert.Equal(t, c.ok, ok, "ttl=%q", c.in) + if ok { + assert.Equal(t, c.secs, int(d.Seconds()), "ttl=%q", c.in) + } + } +} diff --git a/spinifex/handlers/imds/veth_store.go b/spinifex/handlers/imds/veth_store.go new file mode 100644 index 000000000..353ba7647 --- /dev/null +++ b/spinifex/handlers/imds/veth_store.go @@ -0,0 +1,72 @@ +package handlers_imds + +import ( + "encoding/json" + "errors" + "fmt" + + "github.com/nats-io/nats.go" +) + +// VPCVethRecord is the persisted per-VPC IMDS plumbing record (KVBucketIMDSVPCVeth, +// keyed by VPC ID): the signal that a VPC's IMDS OVN topology is installed, replayed +// by each chassis's BindManager. It carries only the LSP MAC and LRP /30 the host can't re-derive. +type VPCVethRecord struct { + VPCID string `json:"vpc_id"` + ShortVPCID string `json:"short_vpc_id"` + IMDSPortMAC string `json:"imds_port_mac"` + LRPNetwork string `json:"lrp_network"` + CreatedAt string `json:"created_at"` +} + +// VethStore is the persistence surface for VPCVethRecord rows in +// KVBucketIMDSVPCVeth. Backed by a NATS JetStream KV bucket opened by +// InitBuckets in production; tests inject the handle via NewVethStore. +type VethStore struct { + kv nats.KeyValue +} + +// NewVethStore wraps an already-opened vpc-veth KV bucket. +func NewVethStore(kv nats.KeyValue) *VethStore { return &VethStore{kv: kv} } + +// Get returns the record for vpcID, or (nil, nil) when absent. +func (s *VethStore) Get(vpcID string) (*VPCVethRecord, error) { + raw, err := s.kv.Get(vpcID) + if err != nil { + if errors.Is(err, nats.ErrKeyNotFound) { + return nil, nil + } + return nil, fmt.Errorf("get imds veth record %q: %w", vpcID, err) + } + var rec VPCVethRecord + if err := json.Unmarshal(raw.Value(), &rec); err != nil { + return nil, fmt.Errorf("unmarshal imds veth record %q: %w", vpcID, err) + } + return &rec, nil +} + +// Put writes the record keyed by its VPCID, overwriting any prior entry. +func (s *VethStore) Put(rec VPCVethRecord) error { + if rec.VPCID == "" { + return errors.New("imds veth store put: vpc_id is empty") + } + data, err := json.Marshal(rec) + if err != nil { + return fmt.Errorf("marshal imds veth record: %w", err) + } + if _, err := s.kv.Put(rec.VPCID, data); err != nil { + return fmt.Errorf("put imds veth record %q: %w", rec.VPCID, err) + } + return nil +} + +// Delete removes the record. Idempotent: a missing key returns nil. +func (s *VethStore) Delete(vpcID string) error { + if err := s.kv.Delete(vpcID); err != nil { + if errors.Is(err, nats.ErrKeyNotFound) { + return nil + } + return fmt.Errorf("delete imds veth record %q: %w", vpcID, err) + } + return nil +} diff --git a/spinifex/handlers/imds/veth_store_test.go b/spinifex/handlers/imds/veth_store_test.go new file mode 100644 index 000000000..b0b41ae93 --- /dev/null +++ b/spinifex/handlers/imds/veth_store_test.go @@ -0,0 +1,57 @@ +package handlers_imds + +import ( + "testing" + + "github.com/mulgadc/spinifex/spinifex/testutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func newTestVethStore(t *testing.T) *VethStore { + t.Helper() + _, _, js := testutil.StartTestJetStream(t) + vpcVeth, _, err := InitBuckets(js, 1) + require.NoError(t, err) + return NewVethStore(vpcVeth) +} + +func TestVethStore_PutGetRoundTrip(t *testing.T) { + s := newTestVethStore(t) + rec := VPCVethRecord{ + VPCID: "vpc-abc12345", + ShortVPCID: "abc12345", + IMDSPortMAC: "02:aa:bb:cc:dd:ee", + LRPNetwork: "169.254.169.253/30", + CreatedAt: "2026-05-29T00:00:00Z", + } + require.NoError(t, s.Put(rec)) + + got, err := s.Get("vpc-abc12345") + require.NoError(t, err) + require.NotNil(t, got) + assert.Equal(t, rec, *got) +} + +func TestVethStore_GetAbsentReturnsNil(t *testing.T) { + s := newTestVethStore(t) + got, err := s.Get("vpc-nope") + require.NoError(t, err) + assert.Nil(t, got) +} + +func TestVethStore_PutRejectsEmptyVPCID(t *testing.T) { + s := newTestVethStore(t) + require.Error(t, s.Put(VPCVethRecord{ShortVPCID: "abc12345"})) +} + +func TestVethStore_DeleteIsIdempotent(t *testing.T) { + s := newTestVethStore(t) + require.NoError(t, s.Delete("vpc-missing")) + + require.NoError(t, s.Put(VPCVethRecord{VPCID: "vpc-1"})) + require.NoError(t, s.Delete("vpc-1")) + got, err := s.Get("vpc-1") + require.NoError(t, err) + assert.Nil(t, got) +} diff --git a/spinifex/handlers/sts/assume_role.go b/spinifex/handlers/sts/assume_role.go index 79d387870..3dca2a526 100644 --- a/spinifex/handlers/sts/assume_role.go +++ b/spinifex/handlers/sts/assume_role.go @@ -11,6 +11,7 @@ import ( "fmt" "log/slog" "regexp" + "slices" "strings" "time" @@ -28,6 +29,11 @@ const ( stsActionWildcard = "sts:*" globalWildcard = "*" + // ec2ServicePrincipal is the synthetic caller used by AssumeRoleForInstance — the + // only service principal that matches a trust policy in v1. The HTTPS AssumeRole + // path supplies an empty principalSource, so service principals never match there. + ec2ServicePrincipal = "ec2.amazonaws.com" + minDurationSeconds int64 = 900 maxDurationSeconds int64 = 43200 defaultDurationSeconds int64 = 3600 @@ -72,7 +78,62 @@ func (s *STSServiceImpl) AssumeRole(callerAccountID, callerARN, callerIdentity s return nil, errors.New(awserrors.ErrorInvalidParameterValue) } - roleAccountID, roleName, err := parseRoleARN(*input.RoleArn) + duration := int64(0) + if input.DurationSeconds != nil { + duration = *input.DurationSeconds + } + + out, err := s.assumeRoleForCaller(callerAccountID, callerARN, "", *input.RoleArn, sessionName, aws.StringValue(input.SourceIdentity), duration) + if err != nil { + return nil, err + } + + slog.Info("AssumeRole success", + "caller_arn", callerARN, + "caller_identity", callerIdentity, + "role_arn", aws.StringValue(input.RoleArn), + "session_name", sessionName, + "akid", aws.StringValue(out.Credentials.AccessKeyId), + "expires_at", aws.TimeValue(out.Credentials.Expiration), + "source_identity", aws.StringValue(input.SourceIdentity), + "external_id", aws.StringValue(input.ExternalId), + ) + + return out, nil +} + +// AssumeRoleForInstance is the in-process IMDS entry point, not reachable over HTTPS. +// The caller is synthesised as the EC2 service principal (principalSource = +// ec2.amazonaws.com); the session name is the instanceID, yielding an AWS-style ARN. +func (s *STSServiceImpl) AssumeRoleForInstance(accountID, roleARN, instanceID string, durationSeconds int64) (*sts.AssumeRoleOutput, error) { + if accountID == "" || roleARN == "" || instanceID == "" { + return nil, errors.New(awserrors.ErrorMissingParameter) + } + if !roleSessionNameRegex.MatchString(instanceID) { + return nil, errors.New(awserrors.ErrorValidationError) + } + + out, err := s.assumeRoleForCaller(accountID, "", ec2ServicePrincipal, roleARN, instanceID, "", durationSeconds) + if err != nil { + return nil, err + } + + slog.Info("AssumeRoleForInstance success", + "account_id", accountID, + "instance_id", instanceID, + "role_arn", roleARN, + "akid", aws.StringValue(out.Credentials.AccessKeyId), + "expires_at", aws.TimeValue(out.Credentials.Expiration), + ) + + return out, nil +} + +// assumeRoleForCaller is the shared core of AssumeRole (HTTPS) and AssumeRoleForInstance +// (IMDS): resolves the role, validates the duration (0 → default), evaluates the trust +// policy, and mints credentials. principalSource is "" for HTTPS, ec2.amazonaws.com for IMDS. +func (s *STSServiceImpl) assumeRoleForCaller(callerAccountID, callerARN, principalSource, roleARN, sessionName, sourceIdentity string, requestedDuration int64) (*sts.AssumeRoleOutput, error) { + roleAccountID, roleName, err := parseRoleARN(roleARN) if err != nil { return nil, errors.New(awserrors.ErrorValidationError) } @@ -90,9 +151,9 @@ func (s *STSServiceImpl) AssumeRole(callerAccountID, callerARN, callerIdentity s } role := roleOut.Role - duration := defaultDurationSeconds - if input.DurationSeconds != nil { - duration = *input.DurationSeconds + duration := requestedDuration + if duration == 0 { + duration = defaultDurationSeconds } effectiveMax := aws.Int64Value(role.MaxSessionDuration) if effectiveMax == 0 { @@ -105,26 +166,15 @@ func (s *STSServiceImpl) AssumeRole(callerAccountID, callerARN, callerIdentity s return nil, errors.New(awserrors.ErrorValidationError) } - if err := evalTrustPolicy(aws.StringValue(role.AssumeRolePolicyDocument), callerARN); err != nil { + if err := evalTrustPolicy(aws.StringValue(role.AssumeRolePolicyDocument), callerARN, principalSource); err != nil { return nil, err } - cred, plainSecret, plainToken, err := s.mintSessionCredential(role, roleAccountID, sessionName, aws.StringValue(input.SourceIdentity), duration) + cred, plainSecret, plainToken, err := s.mintSessionCredential(role, roleAccountID, sessionName, sourceIdentity, duration) if err != nil { return nil, err } - slog.Info("AssumeRole success", - "caller_arn", callerARN, - "caller_identity", callerIdentity, - "role_arn", aws.StringValue(role.Arn), - "session_name", sessionName, - "akid", cred.AccessKeyID, - "expires_at", cred.ExpiresAt, - "source_identity", aws.StringValue(input.SourceIdentity), - "external_id", aws.StringValue(input.ExternalId), - ) - return &sts.AssumeRoleOutput{ Credentials: &sts.Credentials{ AccessKeyId: aws.String(cred.AccessKeyID), @@ -172,7 +222,7 @@ func parseRoleARN(arnStr string) (accountID, name string, err error) { // pass scans every Allow statement (returning nil on the first match). A // single-pass "return on first Allow" loop would silently skip a later Deny // and is a real authorisation bug. -func evalTrustPolicy(docJSON, callerARN string) error { +func evalTrustPolicy(docJSON, callerARN, principalSource string) error { doc, err := handlers_iam.ValidateTrustPolicyDocument(docJSON) if err != nil { // Stored docs were validated at CreateRole / UpdateAssumeRolePolicy @@ -187,7 +237,7 @@ func evalTrustPolicy(docJSON, callerARN string) error { if !matchTrustAction(stmt.Action) { continue } - match, err := matchTrustPrincipal(stmt.Principal, callerARN) + match, err := matchTrustPrincipal(stmt.Principal, callerARN, principalSource) if err != nil { return err } @@ -203,7 +253,7 @@ func evalTrustPolicy(docJSON, callerARN string) error { if !matchTrustAction(stmt.Action) { continue } - match, err := matchTrustPrincipal(stmt.Principal, callerARN) + match, err := matchTrustPrincipal(stmt.Principal, callerARN, principalSource) if err != nil { return err } @@ -224,11 +274,10 @@ func matchTrustAction(actions []string) bool { return false } -// matchTrustPrincipal evaluates each top-level Principal key independently — -// AWS semantics treat the map as an OR across keys, and unsupported keys -// (Service, Federated) skip at the entry level rather than failing the whole -// statement. -func matchTrustPrincipal(raw json.RawMessage, callerARN string) (bool, error) { +// matchTrustPrincipal evaluates each top-level Principal key independently (AWS +// treats the map as an OR). AWS matches callerARN, Service matches principalSource +// (set only by the IMDS path); unsupported keys (Federated) skip, not fail. +func matchTrustPrincipal(raw json.RawMessage, callerARN, principalSource string) (bool, error) { if len(raw) == 0 { return false, nil } @@ -242,11 +291,45 @@ func matchTrustPrincipal(raw json.RawMessage, callerARN string) (bool, error) { if err := json.Unmarshal(raw, &m); err != nil { return false, fmt.Errorf("unmarshal Principal: %w", err) } - awsRaw, ok := m["AWS"] - if !ok { + if awsRaw, ok := m["AWS"]; ok { + match, err := matchAWSPrincipal(awsRaw, callerARN) + if err != nil { + return false, err + } + if match { + return true, nil + } + } + if svcRaw, ok := m["Service"]; ok { + match, err := matchServicePrincipal(svcRaw, principalSource) + if err != nil { + return false, err + } + if match { + return true, nil + } + } + return false, nil +} + +// matchServicePrincipal matches a Service principal against the synthesised caller. +// v1 trusts only the EC2 service principal: any other principalSource (including +// the empty one used by the HTTPS path) is rejected up front, so unsupported +// service principals are denied even if a future caller synthesised one. +// Expanding the whitelist (ecs-tasks, lambda) is a one-line change to this guard. +func matchServicePrincipal(raw json.RawMessage, principalSource string) (bool, error) { + if principalSource != ec2ServicePrincipal { return false, nil } - return matchAWSPrincipal(awsRaw, callerARN) + var single string + if err := json.Unmarshal(raw, &single); err == nil { + return single == principalSource, nil + } + var arr []string + if err := json.Unmarshal(raw, &arr); err != nil { + return false, fmt.Errorf("Principal.Service must be string or array: %w", err) + } + return slices.Contains(arr, principalSource), nil } func matchAWSPrincipal(raw json.RawMessage, callerARN string) (bool, error) { diff --git a/spinifex/handlers/sts/assume_role_test.go b/spinifex/handlers/sts/assume_role_test.go index b3345930f..fbb6bc1fb 100644 --- a/spinifex/handlers/sts/assume_role_test.go +++ b/spinifex/handlers/sts/assume_role_test.go @@ -557,6 +557,109 @@ func TestAssumeRole_ServicePrincipal_NeverMatchesInV1(t *testing.T) { assert.Equal(t, awserrors.ErrorAccessDenied, err.Error()) } +// ----- AssumeRoleForInstance (IMDS in-process path) ---------------------- + +const testInstanceID = "i-0123456789abcdef0" + +func trustPolicyAllowingEC2Service() string { + return `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ec2.amazonaws.com"},"Action":"sts:AssumeRole"}]}` +} + +func TestAssumeRoleForInstance_EC2ServicePrincipal_Allowed(t *testing.T) { + svc, _ := newTestSetup(t) + role := createRoleInAccount(t, svc, testCallerAccountID, "app-role", trustPolicyAllowingEC2Service()) + + out, err := svc.AssumeRoleForInstance(testCallerAccountID, *role.Arn, testInstanceID, defaultDurationSeconds) + require.NoError(t, err) + require.NotNil(t, out) + require.NotNil(t, out.Credentials) + + akid := aws.StringValue(out.Credentials.AccessKeyId) + assert.True(t, strings.HasPrefix(akid, SessionAccessKeyIDPrefix)) + assert.Len(t, akid, 20) + + // The session name is the instance ID, matching AWS. + assert.Equal(t, fmt.Sprintf("arn:aws:sts::%s:assumed-role/app-role/%s", testCallerAccountID, testInstanceID), + aws.StringValue(out.AssumedRoleUser.Arn)) + + stored, err := svc.LookupSessionCredential(akid) + require.NoError(t, err) + require.NotNil(t, stored) + assert.Equal(t, testInstanceID, stored.SessionName) + assert.Equal(t, testCallerAccountID, stored.AccountID) +} + +// Service principals other than ec2.amazonaws.com are not whitelisted in v1, so +// even though the caller is synthesised as the EC2 service principal, a +// lambda.amazonaws.com trust statement must not match. +func TestAssumeRoleForInstance_NonWhitelistedService_Denied(t *testing.T) { + svc, _ := newTestSetup(t) + policy := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"},"Action":"sts:AssumeRole"}]}` + role := createRoleInAccount(t, svc, testCallerAccountID, "lambda-role", policy) + + _, err := svc.AssumeRoleForInstance(testCallerAccountID, *role.Arn, testInstanceID, defaultDurationSeconds) + require.Error(t, err) + assert.Equal(t, awserrors.ErrorAccessDenied, err.Error()) +} + +// A role that only trusts an AWS principal (no Service entry) must not be +// assumable by an instance — the synthesised EC2 caller has no ARN to match. +func TestAssumeRoleForInstance_AWSOnlyPrincipal_Denied(t *testing.T) { + svc, _ := newTestSetup(t) + role := createRoleInAccount(t, svc, testCallerAccountID, "user-role", trustPolicyAllowingUser(testCallerARN())) + + _, err := svc.AssumeRoleForInstance(testCallerAccountID, *role.Arn, testInstanceID, defaultDurationSeconds) + require.Error(t, err) + assert.Equal(t, awserrors.ErrorAccessDenied, err.Error()) +} + +// Regression: the EC2 service principal must remain unreachable over the HTTPS +// AssumeRole path. A role trusting only ec2.amazonaws.com is never assumable by +// a normal SigV4 caller, no matter what — the security boundary between the two +// entry points. +func TestAssumeRoleForInstance_EC2ServiceUnreachableViaHTTPS(t *testing.T) { + svc, _ := newTestSetup(t) + role := createRoleInAccount(t, svc, testCallerAccountID, "ec2-only", trustPolicyAllowingEC2Service()) + + _, err := svc.AssumeRole(testCallerAccountID, testCallerARN(), testCallerUserName, + basicAssumeRoleInput(*role.Arn, "sess")) + require.Error(t, err) + assert.Equal(t, awserrors.ErrorAccessDenied, err.Error()) +} + +func TestAssumeRoleForInstance_RejectsMissingFields(t *testing.T) { + svc, _ := newTestSetup(t) + role := createRoleInAccount(t, svc, testCallerAccountID, "fields", trustPolicyAllowingEC2Service()) + + cases := []struct { + name string + accountID string + roleARN string + instanceID string + }{ + {"missing_account", "", *role.Arn, testInstanceID}, + {"missing_role_arn", testCallerAccountID, "", testInstanceID}, + {"missing_instance_id", testCallerAccountID, *role.Arn, ""}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + _, err := svc.AssumeRoleForInstance(tc.accountID, tc.roleARN, tc.instanceID, defaultDurationSeconds) + require.Error(t, err) + assert.Equal(t, awserrors.ErrorMissingParameter, err.Error()) + }) + } +} + +func TestAssumeRoleForInstance_CrossAccountRoleMiss_AccessDenied(t *testing.T) { + svc, _ := newTestSetup(t) + // Instance's account differs from the role's account and the role is + // missing — masked to AccessDenied to prevent cross-account enumeration. + _, err := svc.AssumeRoleForInstance(testCallerAccountID, + fmt.Sprintf("arn:aws:iam::%s:role/ghost", testCrossAccountID), testInstanceID, defaultDurationSeconds) + require.Error(t, err) + assert.Equal(t, awserrors.ErrorAccessDenied, err.Error()) +} + func TestAssumeRole_RetriesOnAKIDCollision(t *testing.T) { svc, _ := newTestSetup(t) caller := testCallerARN() @@ -643,7 +746,7 @@ func TestEvalTrustPolicy_CorruptDocReturnsError(t *testing.T) { // Stored docs are validated upstream; reaching evalTrustPolicy with a // malformed doc indicates corruption — must fail closed and NOT collapse // to AccessDenied (which would hide the corruption from operators). - err := evalTrustPolicy(`{not json`, testCallerARN()) + err := evalTrustPolicy(`{not json`, testCallerARN(), "") require.Error(t, err) assert.NotEqual(t, awserrors.ErrorAccessDenied, err.Error(), "corrupt doc must not be reported as AccessDenied — operators need to see the corruption signal") diff --git a/spinifex/handlers/sts/imds_rpc.go b/spinifex/handlers/sts/imds_rpc.go new file mode 100644 index 000000000..7bb54e265 --- /dev/null +++ b/spinifex/handlers/sts/imds_rpc.go @@ -0,0 +1,36 @@ +package handlers_sts + +import ( + "github.com/aws/aws-sdk-go/service/sts" + "github.com/mulgadc/spinifex/spinifex/utils" + "github.com/nats-io/nats.go" +) + +// imdsResponderQueue load-balances the IMDS control-plane RPCs across every +// awsgw in the cluster, matching the cluster-wide worker convention. +const imdsResponderQueue = "spinifex-workers" + +// SubjectAssumeRoleForInstance is the internal, ACL-gated subject the IMDS handler +// (in vpcd) calls to mint instance-role credentials. STS keeps the IAM master key +// in-process inside awsgw; only this narrow RPC is surfaced, never to a guest. +const SubjectAssumeRoleForInstance = "imds.sts.assume_role_for_instance" + +// AssumeRoleForInstanceRequest is the SubjectAssumeRoleForInstance payload. The +// account ID is data here (resolved from the requesting ENI), not an +// authenticated caller identity. +type AssumeRoleForInstanceRequest struct { + AccountID string `json:"account_id"` + RoleARN string `json:"role_arn"` + InstanceID string `json:"instance_id"` + DurationSeconds int64 `json:"duration_seconds"` +} + +// SubscribeIMDSResponder wires the AssumeRoleForInstance responder onto nc, +// queue-grouped so any awsgw can answer. +func (s *STSServiceImpl) SubscribeIMDSResponder(nc *nats.Conn) (*nats.Subscription, error) { + return nc.QueueSubscribe(SubjectAssumeRoleForInstance, imdsResponderQueue, func(msg *nats.Msg) { + utils.ServeNATSRequest(msg, func(req *AssumeRoleForInstanceRequest) (*sts.AssumeRoleOutput, error) { + return s.AssumeRoleForInstance(req.AccountID, req.RoleARN, req.InstanceID, req.DurationSeconds) + }) + }) +} diff --git a/spinifex/handlers/sts/service.go b/spinifex/handlers/sts/service.go index 3a65d502f..3781affdd 100644 --- a/spinifex/handlers/sts/service.go +++ b/spinifex/handlers/sts/service.go @@ -17,6 +17,11 @@ type STSService interface { // strings to keep the handler unit-testable. AssumeRole(callerAccountID, callerARN, callerIdentity string, input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) + // AssumeRoleForInstance mints role-bound temporary credentials for an EC2 instance. + // It is the in-process IMDS entry point, NOT reachable over HTTPS: the caller is the + // synthesised EC2 service principal (trust must allow Service ec2.amazonaws.com). + AssumeRoleForInstance(accountID, roleARN, instanceID string, durationSeconds int64) (*sts.AssumeRoleOutput, error) + // AssumeRoleWithWebIdentity exchanges an OIDC ID token (typically a // projected K8s ServiceAccount token signed by an EKS cluster's // per-cluster signing key) for short-lived AWS credentials bound to the diff --git a/spinifex/network/external/igw.go b/spinifex/network/external/igw.go index 1f2d5c351..63473523f 100644 --- a/spinifex/network/external/igw.go +++ b/spinifex/network/external/igw.go @@ -298,7 +298,7 @@ func (m *igwManager) RemoveSubnetEgress(ctx context.Context, vpcID, subnetID str if vpcID == "" || subnetID == "" { return errors.New("RemoveSubnetEgress: vpcID and subnetID required") } - return m.routes.DeleteSubnetEgress(ctx, vpcID, subnetID, prefix, m.vpcExcludeCIDRs(ctx, vpcID)) + return m.routes.DeleteSubnetEgress(ctx, vpcID, subnetID, prefix, m.rerouteExcludeCIDRs(ctx, vpcID)) } // EnsureNATGatewaySubnetEgress is the NATGW priority sibling of @@ -315,7 +315,7 @@ func (m *igwManager) RemoveNATGatewaySubnetEgress(ctx context.Context, vpcID, su if vpcID == "" || subnetID == "" { return errors.New("RemoveNATGatewaySubnetEgress: vpcID and subnetID required") } - return m.routes.DeleteSubnetEgress(ctx, vpcID, subnetID, prefix, m.vpcExcludeCIDRs(ctx, vpcID)) + return m.routes.DeleteSubnetEgress(ctx, vpcID, subnetID, prefix, m.rerouteExcludeCIDRs(ctx, vpcID)) } // EnsureSubnetEgressDrop installs a drop policy at SubnetEgressPriorityDrop @@ -361,7 +361,7 @@ func (m *igwManager) ensureSubnetEgressAtPriority(ctx context.Context, vpcID, su Nexthop: nexthop, OutputPort: topology.GatewayRouterPort(vpcID), Priority: priority, - ExcludeCIDRs: m.vpcExcludeCIDRs(ctx, vpcID), + ExcludeCIDRs: m.rerouteExcludeCIDRs(ctx, vpcID), }) } @@ -437,10 +437,9 @@ var ( ) // dropExcludeCIDRs returns the exclusion list for a per-subnet drop policy: -// VPC CIDR (if discoverable) plus link-local and multicast. Reroute policies -// only need the VPC CIDR exclusion because their match scope is narrower; the -// drop policy is a default-deny within the subnet's egress so it must spare -// any class the platform legitimately uses outside the VPC. +// VPC CIDR (if discoverable) plus link-local and multicast. The drop policy is +// a default-deny within the subnet's egress so it must spare any class the +// platform legitimately uses outside the VPC. func (m *igwManager) dropExcludeCIDRs(ctx context.Context, vpcID string) []netip.Prefix { excludes := []netip.Prefix{linkLocalCIDR, multicastCIDR} if vpc := m.vpcExcludeCIDRs(ctx, vpcID); len(vpc) > 0 { @@ -449,6 +448,20 @@ func (m *igwManager) dropExcludeCIDRs(ctx context.Context, vpcID string) []netip return excludes } +// rerouteExcludeCIDRs returns the exclusion list for a per-subnet egress +// reroute policy: VPC CIDR (if discoverable) plus link-local. The reroute +// matches 0.0.0.0/0 — the widest possible scope — so it would otherwise +// hijack 169.254.169.254 (IMDS) out the gateway and defeat the per-VPC IMDS +// /32 static route, which fires earlier in lr_in_ip_routing but is overridden +// by this lr_in_policy reroute. Excluding link-local lets IMDS fall through to +// the /32. Multicast is not excluded here (unlike the drop policy): a reroute +// only diverts traffic that already has somewhere to go, so leaking multicast +// to the gateway is harmless, whereas the drop policy would kill it outright. +func (m *igwManager) rerouteExcludeCIDRs(ctx context.Context, vpcID string) []netip.Prefix { + excludes := m.vpcExcludeCIDRs(ctx, vpcID) + return append(excludes, linkLocalCIDR) +} + // vpcExcludeCIDRs fetches the VPC's primary CIDR from the LR ExternalIDs // label so per-subnet egress reroute policies skip in-VPC destinations. // Returns nil on lookup failure or unset label — caller installs a policy diff --git a/spinifex/network/external/imds_datapath_contract_test.go b/spinifex/network/external/imds_datapath_contract_test.go new file mode 100644 index 000000000..76b33d7ad --- /dev/null +++ b/spinifex/network/external/imds_datapath_contract_test.go @@ -0,0 +1,252 @@ +package external + +import ( + "context" + "net/netip" + "sort" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + handlers_imds "github.com/mulgadc/spinifex/spinifex/handlers/imds" + "github.com/mulgadc/spinifex/spinifex/network/ovn/mock" + "github.com/mulgadc/spinifex/spinifex/network/policy" + "github.com/mulgadc/spinifex/spinifex/network/topology" +) + +// IMDS datapath contract — desk-speed pipeline oracle. +// +// Every IMDS datapath bug to date (the egress-reroute hijack of the /32, the +// reply-path break) lived inside the VPC logical-router pipeline and was only +// caught by a full VM-boot E2E run, one bug per deploy. This test makes the +// load-bearing half of that pipeline assertable in `go test`: it builds the +// REAL managers (IGW egress reroute + drop, IMDS topology) against the OVN mock +// for two VPCs that share the *identical* CIDR — the overlapping-CIDR case that +// is the whole point of per-VPC IMDS identity — then runs a faithful, minimal +// simulation of OVN's two ingress stages (lr_in_policy, then lr_in_ip_routing) +// and asserts a guest packet to 169.254.169.254 reaches the IMDS LRP rather +// than being rerouted out the WAN or dropped. +// +// A true round-trip oracle is ovn-trace against a live SB DB; that belongs in +// the e2e harness. This is its desk-speed counterpart over the same NB rows — +// it runs on every `make preflight`, so a future broad lr_in_policy rule that +// forgets to spare link-local fails here instead of in a deploy. + +const ( + imdsContractGuestIP = "10.211.0.5" + imdsContractCIDR = "10.211.0.0/16" +) + +func TestIMDSDatapathContract_SurvivesVPCPipeline_OverlappingCIDRs(t *testing.T) { + ctx := context.Background() + m := mock.New() + + // Two VPCs on the IDENTICAL CIDR, each with internet egress and a subnet + // whose first guest gets the same private IP. The OVN NB rows for the two + // must each independently route IMDS correctly. + vpcs := []struct{ vpcID, subnetID string }{ + {"vpc-aaaa1111", "subnet-aaaa1111"}, + {"vpc-bbbb2222", "subnet-bbbb2222"}, + } + + imdsMgr, _ := newIMDSManager(t, m) + igwMgr, _ := newTestIGWManager(t, m, policy.NATModeDistributed, + &ExternalPoolConfig{Name: "p", Gateway: "192.168.1.1", PrefixLen: 24}, + LinkLocalAllocator{}, []string{"chassis-a"}) + + defaultRoute := netip.MustParsePrefix("0.0.0.0/0") + + for _, v := range vpcs { + seedVPCRouter(t, m, v.vpcID, imdsContractCIDR) + require.NoError(t, igwMgr.AttachIGW(ctx, IGWSpec{VPCID: v.vpcID, InternetGatewayID: "igw-" + v.vpcID})) + // The broad 0.0.0.0/0 egress reroute + drop — the pipeline stages that + // previously hijacked / killed the IMDS /32 before #19 excluded link-local. + require.NoError(t, igwMgr.EnsureSubnetEgress(ctx, v.vpcID, v.subnetID, defaultRoute)) + require.NoError(t, igwMgr.EnsureSubnetEgressDrop(ctx, v.vpcID, v.subnetID, defaultRoute)) + // The IMDS /32 static route + imds-lrp. + _, err := imdsMgr.EnsureForVPC(ctx, v.vpcID) + require.NoError(t, err) + } + + for _, v := range vpcs { + assertIMDSDatapathContract(t, m, v.vpcID, v.subnetID, imdsContractGuestIP) + } +} + +// TestIMDSDatapathContract_OracleHasTeeth proves the simulator actually detects +// the regression it guards against: a 0.0.0.0/0 egress reroute that does NOT +// exclude link-local (the pre-#19 bug) must be reported as diverting IMDS. +// Without this, a vacuously-passing contract test would give false confidence. +func TestIMDSDatapathContract_OracleHasTeeth(t *testing.T) { + ctx := context.Background() + m := mock.New() + const vpcID, subnetID = "vpc-cccc3333", "subnet-cccc3333" + seedVPCRouter(t, m, vpcID, imdsContractCIDR) + + rm := policy.NewRouteManager(m) + gw := "169.254.0.2" + // Reroute excluding ONLY the VPC CIDR — link-local omitted, reproducing the + // bug #19 fixed. IMDS (169.254.169.254) is in 0.0.0.0/0 and not in the VPC + // CIDR, so this policy hijacks it. + require.NoError(t, rm.AddSubnetEgress(ctx, vpcID, policy.SubnetEgressSpec{ + SubnetID: subnetID, + Prefix: netip.MustParsePrefix("0.0.0.0/0"), + Nexthop: gw, + OutputPort: topology.GatewayRouterPort(vpcID), + Priority: policy.SubnetEgressPriorityIGW, + ExcludeCIDRs: []netip.Prefix{netip.MustParsePrefix(imdsContractCIDR)}, + })) + + res := resolveEgress(t, m, vpcID, subnetID, handlers_imds.MetaDataServerIP) + assert.True(t, res.diverted, + "simulator must detect a link-local-unaware reroute as hijacking IMDS; if this fails the oracle is blind") +} + +// assertIMDSDatapathContract is the contract: a guest packet to +// 169.254.169.254 must reach the IMDS LRP, and the IMDS reply must not be +// caught by any egress policy. +func assertIMDSDatapathContract(t *testing.T, m *mock.Client, vpcID, subnetID, guestIP string) { + t.Helper() + imdsLRP := topology.IMDSRouterPort(vpcID) + + // Request: guest -> 169.254.169.254, ingressing on the subnet LRP. + req := resolveEgress(t, m, vpcID, subnetID, handlers_imds.MetaDataServerIP) + assert.Falsef(t, req.diverted, + "IMDS contract (%s): an lr_in_policy reroute on 0.0.0.0/0 hijacks 169.254.169.254 out the WAN; "+ + "every broad egress reroute MUST exclude 169.254.0.0/16 (see decision #19)", vpcID) + assert.Falsef(t, req.dropped, + "IMDS contract (%s): an lr_in_policy drop kills 169.254.169.254; "+ + "the per-subnet drop policy MUST exclude 169.254.0.0/16", vpcID) + assert.Equalf(t, "169.254.169.254/32", req.routePrefix, + "IMDS contract (%s): 169.254.169.254 must be resolved by the /32 IMDS static route, not a broader route", vpcID) + assert.Equalf(t, imdsLRP, req.outputPort, + "IMDS contract (%s): the IMDS /32 must egress via %s", vpcID, imdsLRP) + + // Reply: 169.254.169.254 -> guest, ingressing on the IMDS LRP. The egress + // policies are inport-scoped to the subnet LRP, so none may catch the reply; + // a future inport-less broad policy would break IMDS replies and fail here. + reply := resolveEgressFrom(t, m, vpcID, imdsLRP, guestIP) + assert.Falsef(t, reply.diverted, + "IMDS contract (%s): an lr_in_policy must not divert the IMDS reply to %s (policies must stay inport-scoped)", vpcID, guestIP) + assert.Falsef(t, reply.dropped, + "IMDS contract (%s): an lr_in_policy must not drop the IMDS reply to %s", vpcID, guestIP) +} + +// --- minimal OVN LR ingress-pipeline model ------------------------------------ + +type egressResult struct { + diverted bool // a reroute lr_in_policy matched + dropped bool // a drop lr_in_policy matched + outputPort string // lr_in_ip_routing winner's output port (empty if a policy already decided) + routePrefix string // lr_in_ip_routing winner's prefix +} + +// resolveEgress simulates the VPC LR ingress pipeline for a packet arriving on +// the subnet LRP destined to dstIP. +func resolveEgress(t *testing.T, m *mock.Client, vpcID, subnetID, dstIP string) egressResult { + t.Helper() + return resolveEgressFrom(t, m, vpcID, topology.SubnetRouterPort(subnetID), dstIP) +} + +// resolveEgressFrom models OVN's two ingress stages in order: +// +// lr_in_policy — Logical_Router_Policy, highest Priority first, first +// applicable wins (reroute => diverted, drop => dropped). +// lr_in_ip_routing — longest-prefix-match over static routes. +func resolveEgressFrom(t *testing.T, m *mock.Client, vpcID, inport, dstIP string) egressResult { + t.Helper() + dst, err := netip.ParseAddr(dstIP) + require.NoError(t, err) + router := topology.VPCRouter(vpcID) + + // Stage 1: lr_in_policy. + policies, err := m.ListLogicalRouterPolicies(context.Background(), router) + require.NoError(t, err) + sort.SliceStable(policies, func(i, j int) bool { return policies[i].Priority > policies[j].Priority }) + for _, p := range policies { + mt, ok := parsePolicyMatch(p.Match) + if !ok || !mt.applies(inport, dst) { + continue + } + switch p.Action { + case "reroute": + return egressResult{diverted: true} + case "drop": + return egressResult{dropped: true} + case "allow": + // falls through to routing + } + break + } + + // Stage 2: lr_in_ip_routing (longest-prefix-match). + lr, err := m.GetLogicalRouter(context.Background(), router) + require.NoError(t, err) + var best egressResult + bestBits := -1 + for _, uuid := range lr.StaticRoutes { + r := m.StaticRoutes[uuid] + if r == nil { + continue + } + pfx, err := netip.ParsePrefix(r.IPPrefix) + if err != nil || !pfx.Contains(dst) { + continue + } + if pfx.Bits() > bestBits { + bestBits = pfx.Bits() + out := "" + if r.OutputPort != nil { + out = *r.OutputPort + } + best = egressResult{outputPort: out, routePrefix: r.IPPrefix} + } + } + return best +} + +type policyMatch struct { + inport string // "" => no inport constraint + dst netip.Prefix + excludes []netip.Prefix +} + +func (mt policyMatch) applies(inport string, dst netip.Addr) bool { + if mt.inport != "" && mt.inport != inport { + return false + } + if mt.dst.IsValid() && !mt.dst.Contains(dst) { + return false + } + for _, ex := range mt.excludes { + if ex.Contains(dst) { + return false + } + } + return true +} + +// parsePolicyMatch parses the match strings produced by subnetEgressMatch: +// +// inport == "rtr-subnet-x" && ip4.dst == 0.0.0.0/0 && ip4.dst != 10.0.0.0/16 && ip4.dst != 169.254.0.0/16 +func parsePolicyMatch(match string) (policyMatch, bool) { + var mt policyMatch + for clause := range strings.SplitSeq(match, "&&") { + clause = strings.TrimSpace(clause) + switch { + case strings.HasPrefix(clause, "inport =="): + mt.inport = strings.Trim(strings.TrimSpace(strings.TrimPrefix(clause, "inport ==")), `"`) + case strings.HasPrefix(clause, "ip4.dst =="): + if p, err := netip.ParsePrefix(strings.TrimSpace(strings.TrimPrefix(clause, "ip4.dst =="))); err == nil { + mt.dst = p + } + case strings.HasPrefix(clause, "ip4.dst !="): + if p, err := netip.ParsePrefix(strings.TrimSpace(strings.TrimPrefix(clause, "ip4.dst !="))); err == nil { + mt.excludes = append(mt.excludes, p) + } + } + } + return mt, true +} diff --git a/spinifex/network/external/imds_topology.go b/spinifex/network/external/imds_topology.go new file mode 100644 index 000000000..2a8ba646a --- /dev/null +++ b/spinifex/network/external/imds_topology.go @@ -0,0 +1,209 @@ +package external + +import ( + "context" + "errors" + "fmt" + "log/slog" + "net/netip" + "time" + + handlers_imds "github.com/mulgadc/spinifex/spinifex/handlers/imds" + "github.com/mulgadc/spinifex/spinifex/network/host" + "github.com/mulgadc/spinifex/spinifex/network/ovn" + "github.com/mulgadc/spinifex/spinifex/network/ovn/nbdb" + "github.com/mulgadc/spinifex/spinifex/network/policy" + "github.com/mulgadc/spinifex/spinifex/network/topology" + "github.com/mulgadc/spinifex/spinifex/utils" +) + +// imdsLRPNetwork is the /30 the IMDS LRP terminates on the VPC router. .253 is +// the LRP, .254 is the host-owned IMDS LSP (MetaDataServerIP); the /30 makes +// the route to .254 directly-connected on the IMDS switch. +const imdsLRPNetwork = "169.254.169.253/30" + +// metaDataServerRoute is the /32 the VPC router uses to send IMDS traffic out +// the IMDS LRP instead of the WAN default. +var metaDataServerRoute = netip.PrefixFrom(netip.MustParseAddr(handlers_imds.MetaDataServerIP), 32) + +// IMDSVPCSpec is the resolved set of OVN + host names for a VPC's IMDS +// plumbing. Every field is a deterministic function of the VPC ID, so callers +// can rebuild it from the VPC ID alone (BindManager does this per bucket entry). +type IMDSVPCSpec struct { + VPCID string + ShortVPCID string // last 8 chars of VPCID + LSName string // imds-ls-{vpcID} + LRPName string // imds-lrp-{vpcID} + RouterLSPName string // imds-rtr-{vpcID} (type=router) + LSPName string // imds-port-{vpcID} (localport; host veth binds here) + LSPMAC string // 02:.. — HashMAC("imds-"+vpcID) + LRPNetwork string // imdsLRPNetwork + OVSEndName string // imds-o-{shortVpcID} + HostEndName string // imds-h-{shortVpcID} +} + +// IMDSTopologyManager installs and removes the per-VPC OVN topology that makes +// 169.254.169.254 routable to the host-owned IMDS localport. Idempotent. Lives in +// external (not policy): it composes L2 creation with L3 routing (ADR-0006 S5). +type IMDSTopologyManager interface { + EnsureForVPC(ctx context.Context, vpcID string) (IMDSVPCSpec, error) + RemoveForVPC(ctx context.Context, vpcID string) error +} + +type imdsTopologyManager struct { + ovn ovn.Client + routes policy.RouteManager + store *handlers_imds.VethStore +} + +var _ IMDSTopologyManager = (*imdsTopologyManager)(nil) + +// NewIMDSTopologyManager constructs an IMDSTopologyManager. store is the +// vpc-veth KV bucket the installer publishes records to. +func NewIMDSTopologyManager(client ovn.Client, routes policy.RouteManager, store *handlers_imds.VethStore) (IMDSTopologyManager, error) { + switch { + case client == nil: + return nil, errors.New("IMDSTopologyManager: OVN client required") + case routes == nil: + return nil, errors.New("IMDSTopologyManager: RouteManager required") + case store == nil: + return nil, errors.New("IMDSTopologyManager: VethStore required") + } + return &imdsTopologyManager{ovn: client, routes: routes, store: store}, nil +} + +// IMDSSpecForVPC returns the deterministic name/MAC set for a VPC's IMDS +// plumbing without touching OVN or the bucket. +func IMDSSpecForVPC(vpcID string) IMDSVPCSpec { + return IMDSVPCSpec{ + VPCID: vpcID, + ShortVPCID: host.IMDSShortVPCID(vpcID), + LSName: topology.IMDSSwitch(vpcID), + LRPName: topology.IMDSRouterPort(vpcID), + RouterLSPName: topology.IMDSSwitchRouterPort(vpcID), + LSPName: topology.IMDSPort(vpcID), + LSPMAC: utils.HashMAC("imds-" + vpcID), + LRPNetwork: imdsLRPNetwork, + OVSEndName: host.IMDSOVSPortName(vpcID), + HostEndName: host.IMDSHostVethName(vpcID), + } +} + +// EnsureForVPC installs the IMDS OVN topology for vpcID and publishes the vpc-veth +// record. Idempotent: a present record short-circuits, and each OVN object is created +// only when absent so a lost record still converges. The VPC router must already exist. +func (m *imdsTopologyManager) EnsureForVPC(ctx context.Context, vpcID string) (IMDSVPCSpec, error) { + if vpcID == "" { + return IMDSVPCSpec{}, errors.New("EnsureForVPC: vpcID required") + } + spec := IMDSSpecForVPC(vpcID) + + // The bucket record is the publish gate: present means topology is + // installed and BindManagers have (or will) materialise host state. + rec, err := m.store.Get(vpcID) + if err != nil { + return IMDSVPCSpec{}, fmt.Errorf("read imds veth record for %s: %w", vpcID, err) + } + if rec != nil { + return spec, nil + } + + router := topology.VPCRouter(vpcID) + extIDs := map[string]string{"spinifex:vpc_id": vpcID, "spinifex:role": "imds"} + + if _, err := m.ovn.EnsureLogicalSwitch(ctx, &nbdb.LogicalSwitch{Name: spec.LSName, ExternalIDs: extIDs}); err != nil { + return IMDSVPCSpec{}, fmt.Errorf("ensure imds switch %s: %w", spec.LSName, err) + } + + if _, err := m.ovn.GetLogicalRouterPort(ctx, spec.LRPName); err != nil { + if cErr := m.ovn.CreateLogicalRouterPort(ctx, router, &nbdb.LogicalRouterPort{ + Name: spec.LRPName, + MAC: utils.HashMAC(spec.LRPName), + Networks: []string{spec.LRPNetwork}, + ExternalIDs: extIDs, + }); cErr != nil { + return IMDSVPCSpec{}, fmt.Errorf("create imds router port %s: %w", spec.LRPName, cErr) + } + } + + if _, err := m.ovn.GetLogicalSwitchPort(ctx, spec.RouterLSPName); err != nil { + if cErr := m.ovn.CreateLogicalSwitchPort(ctx, spec.LSName, &nbdb.LogicalSwitchPort{ + Name: spec.RouterLSPName, + Type: "router", + Addresses: []string{"router"}, + Options: map[string]string{"router-port": spec.LRPName}, + ExternalIDs: extIDs, + }); cErr != nil { + return IMDSVPCSpec{}, fmt.Errorf("create imds router LSP %s: %w", spec.RouterLSPName, cErr) + } + } + + // Host-owned localport: no port_security (the host is trusted to source + // 169.254.169.254 frames, and port_security would make ovn-controller drop + // reply frames from the host veth's MAC). localport binds on every chassis. + if _, err := m.ovn.GetLogicalSwitchPort(ctx, spec.LSPName); err != nil { + if cErr := m.ovn.CreateLogicalSwitchPort(ctx, spec.LSName, &nbdb.LogicalSwitchPort{ + Name: spec.LSPName, + Type: "localport", + Addresses: []string{spec.LSPMAC + " " + handlers_imds.MetaDataServerIP}, + ExternalIDs: extIDs, + }); cErr != nil { + return IMDSVPCSpec{}, fmt.Errorf("create imds localport %s: %w", spec.LSPName, cErr) + } + } + + if err := m.routes.AddStaticRoute(ctx, vpcID, policy.RouteSpec{ + Prefix: metaDataServerRoute, + Nexthop: handlers_imds.MetaDataServerIP, + OutputPort: spec.LRPName, + }); err != nil { + return IMDSVPCSpec{}, fmt.Errorf("add imds static route on %s: %w", router, err) + } + + if err := m.store.Put(handlers_imds.VPCVethRecord{ + VPCID: vpcID, + ShortVPCID: spec.ShortVPCID, + IMDSPortMAC: spec.LSPMAC, + LRPNetwork: spec.LRPNetwork, + CreatedAt: time.Now().UTC().Format(time.RFC3339), + }); err != nil { + return IMDSVPCSpec{}, fmt.Errorf("publish imds veth record for %s: %w", vpcID, err) + } + + slog.Info("external: installed IMDS topology", + "vpc_id", vpcID, "imds_switch", spec.LSName, "imds_lrp", spec.LRPName, "imds_port", spec.LSPName) + return spec, nil +} + +// RemoveForVPC tears down the IMDS OVN topology and the vpc-veth record. +// Idempotent and drift-tolerant: missing OVN objects are logged and skipped so the +// record delete always runs. Must run before the VPC router (it holds the LRP/route). +func (m *imdsTopologyManager) RemoveForVPC(ctx context.Context, vpcID string) error { + if vpcID == "" { + return errors.New("RemoveForVPC: vpcID required") + } + spec := IMDSSpecForVPC(vpcID) + router := topology.VPCRouter(vpcID) + + if err := m.routes.DeleteStaticRoute(ctx, vpcID, metaDataServerRoute); err != nil { + slog.Warn("external: delete imds static route failed", "vpc_id", vpcID, "err", err) + } + if err := m.ovn.DeleteLogicalSwitchPort(ctx, spec.LSName, spec.LSPName); err != nil { + slog.Warn("external: delete imds localport failed", "port", spec.LSPName, "err", err) + } + if err := m.ovn.DeleteLogicalSwitchPort(ctx, spec.LSName, spec.RouterLSPName); err != nil { + slog.Warn("external: delete imds router LSP failed", "port", spec.RouterLSPName, "err", err) + } + if err := m.ovn.DeleteLogicalRouterPort(ctx, router, spec.LRPName); err != nil { + slog.Warn("external: delete imds router port failed", "port", spec.LRPName, "err", err) + } + if err := m.ovn.DeleteLogicalSwitch(ctx, spec.LSName); err != nil { + slog.Warn("external: delete imds switch failed", "switch", spec.LSName, "err", err) + } + if err := m.store.Delete(vpcID); err != nil { + return fmt.Errorf("delete imds veth record for %s: %w", vpcID, err) + } + + slog.Info("external: removed IMDS topology", "vpc_id", vpcID) + return nil +} diff --git a/spinifex/network/external/imds_topology_test.go b/spinifex/network/external/imds_topology_test.go new file mode 100644 index 000000000..475faf3a0 --- /dev/null +++ b/spinifex/network/external/imds_topology_test.go @@ -0,0 +1,168 @@ +package external + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + handlers_imds "github.com/mulgadc/spinifex/spinifex/handlers/imds" + "github.com/mulgadc/spinifex/spinifex/network/ovn/mock" + "github.com/mulgadc/spinifex/spinifex/network/ovn/nbdb" + "github.com/mulgadc/spinifex/spinifex/network/policy" + "github.com/mulgadc/spinifex/spinifex/testutil" +) + +func newIMDSManager(t *testing.T, m *mock.Client) (IMDSTopologyManager, *handlers_imds.VethStore) { + t.Helper() + _, _, js := testutil.StartTestJetStream(t) + vpcVeth, _, err := handlers_imds.InitBuckets(js, 1) + require.NoError(t, err) + store := handlers_imds.NewVethStore(vpcVeth) + mgr, err := NewIMDSTopologyManager(m, policy.NewRouteManager(m), store) + require.NoError(t, err) + return mgr, store +} + +func findIMDSRoute(m *mock.Client, prefix string) *nbdb.LogicalRouterStaticRoute { + for _, r := range m.StaticRoutes { + if r.IPPrefix == prefix { + return r + } + } + return nil +} + +func TestNewIMDSTopologyManager_RejectsMissingDeps(t *testing.T) { + m := mock.New() + _, _, js := testutil.StartTestJetStream(t) + vpcVeth, _, err := handlers_imds.InitBuckets(js, 1) + require.NoError(t, err) + store := handlers_imds.NewVethStore(vpcVeth) + + _, err = NewIMDSTopologyManager(nil, policy.NewRouteManager(m), store) + require.Error(t, err) + _, err = NewIMDSTopologyManager(m, nil, store) + require.Error(t, err) + _, err = NewIMDSTopologyManager(m, policy.NewRouteManager(m), nil) + require.Error(t, err) +} + +func TestIMDSEnsureForVPC_InstallsTopology(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedVPCRouter(t, m, "vpc-0a1b2c3d4e5f6789", "10.0.0.0/16") + mgr, store := newIMDSManager(t, m) + + spec, err := mgr.EnsureForVPC(ctx, "vpc-0a1b2c3d4e5f6789") + require.NoError(t, err) + + // Resolved names are deterministic functions of the VPC ID. + assert.Equal(t, "imds-ls-vpc-0a1b2c3d4e5f6789", spec.LSName) + assert.Equal(t, "imds-lrp-vpc-0a1b2c3d4e5f6789", spec.LRPName) + assert.Equal(t, "imds-port-vpc-0a1b2c3d4e5f6789", spec.LSPName) + assert.Equal(t, "4e5f6789", spec.ShortVPCID) + assert.Equal(t, "imds-o-4e5f6789", spec.OVSEndName) + assert.Equal(t, "imds-h-4e5f6789", spec.HostEndName) + + // Logical switch exists, tagged as IMDS. + ls, err := m.GetLogicalSwitch(ctx, spec.LSName) + require.NoError(t, err) + assert.Equal(t, "imds", ls.ExternalIDs["spinifex:role"]) + + // LRP on the VPC router holds the /30. + lrp, err := m.GetLogicalRouterPort(ctx, spec.LRPName) + require.NoError(t, err) + assert.Equal(t, []string{imdsLRPNetwork}, lrp.Networks) + + // type=router LSP peers the switch with the LRP. + rlsp, err := m.GetLogicalSwitchPort(ctx, spec.RouterLSPName) + require.NoError(t, err) + assert.Equal(t, "router", rlsp.Type) + assert.Equal(t, spec.LRPName, rlsp.Options["router-port"]) + + // Host-owned localport: claims the MetaData IP, no port_security. + lsp, err := m.GetLogicalSwitchPort(ctx, spec.LSPName) + require.NoError(t, err) + assert.Equal(t, "localport", lsp.Type) + assert.Empty(t, lsp.PortSecurity) + assert.Equal(t, []string{spec.LSPMAC + " " + handlers_imds.MetaDataServerIP}, lsp.Addresses) + + // Static route on vpc-{vpcID} points 169.254.169.254/32 at the IMDS LRP. + route := findIMDSRoute(m, handlers_imds.MetaDataServerIP+"/32") + require.NotNil(t, route) + assert.Equal(t, handlers_imds.MetaDataServerIP, route.Nexthop) + require.NotNil(t, route.OutputPort) + assert.Equal(t, spec.LRPName, *route.OutputPort) + + // Record published to the bucket. + rec, err := store.Get("vpc-0a1b2c3d4e5f6789") + require.NoError(t, err) + require.NotNil(t, rec) + assert.Equal(t, spec.ShortVPCID, rec.ShortVPCID) + assert.Equal(t, spec.LSPMAC, rec.IMDSPortMAC) + assert.Equal(t, imdsLRPNetwork, rec.LRPNetwork) + assert.NotEmpty(t, rec.CreatedAt) +} + +func TestIMDSEnsureForVPC_Idempotent(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedVPCRouter(t, m, "vpc-1", "10.0.0.0/16") + mgr, _ := newIMDSManager(t, m) + + for range 3 { + _, err := mgr.EnsureForVPC(ctx, "vpc-1") + require.NoError(t, err) + } + + // Exactly one IMDS switch and one static route. + assert.Len(t, m.Switches, 1) + count := 0 + for _, r := range m.StaticRoutes { + if r.IPPrefix == handlers_imds.MetaDataServerIP+"/32" { + count++ + } + } + assert.Equal(t, 1, count) + lsp, err := m.GetLogicalSwitchPort(ctx, "imds-port-vpc-1") + require.NoError(t, err) + assert.Equal(t, "localport", lsp.Type) +} + +func TestIMDSEnsureForVPC_MissingRouterErrors(t *testing.T) { + ctx := context.Background() + m := mock.New() + // No router seeded — the LRP create has nowhere to land. + mgr, store := newIMDSManager(t, m) + + _, err := mgr.EnsureForVPC(ctx, "vpc-missing") + require.Error(t, err) + + // No record published when install fails. + rec, err := store.Get("vpc-missing") + require.NoError(t, err) + assert.Nil(t, rec) +} + +func TestIMDSRemoveForVPC_TearsDownAndIsIdempotent(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedVPCRouter(t, m, "vpc-1", "10.0.0.0/16") + mgr, store := newIMDSManager(t, m) + + _, err := mgr.EnsureForVPC(ctx, "vpc-1") + require.NoError(t, err) + + require.NoError(t, mgr.RemoveForVPC(ctx, "vpc-1")) + + assert.Empty(t, m.Switches) + assert.Nil(t, findIMDSRoute(m, handlers_imds.MetaDataServerIP+"/32")) + rec, err := store.Get("vpc-1") + require.NoError(t, err) + assert.Nil(t, rec) + + // Second remove is a no-op. + require.NoError(t, mgr.RemoveForVPC(ctx, "vpc-1")) +} diff --git a/spinifex/network/external/invariants_test.go b/spinifex/network/external/invariants_test.go new file mode 100644 index 000000000..c07a4af17 --- /dev/null +++ b/spinifex/network/external/invariants_test.go @@ -0,0 +1,122 @@ +package external + +import ( + "context" + "fmt" + "net/netip" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + handlers_imds "github.com/mulgadc/spinifex/spinifex/handlers/imds" + "github.com/mulgadc/spinifex/spinifex/network/ovn/mock" + "github.com/mulgadc/spinifex/spinifex/network/policy" + "github.com/mulgadc/spinifex/spinifex/network/topology" +) + +// IMDS-datapath invariants. These guard the OVN topology +// the IMDS handler trusts as a security + availability boundary. A regression +// in either is a privilege-escalation or single-point-of-failure vector, so the +// failure messages quote the offending design clause verbatim. + +// TestI2_IMDSLSPMustBeLocalportNoPortSecurity asserts the host-owned +// imds-port-{vpcID} LSP is a localport with no port_security. The host — not a +// guest — sources 169.254.169.254 frames on this port, so port_security would +// be actively harmful (it pins the allowed src MAC to the LSP's claimed MAC, +// and ovn-controller would drop reply frames egressing from the host veth's +// MAC). A regular (non-localport) LSP would bind to a single chassis, defeating +// the per-chassis self-serve design. +func TestI2_IMDSLSPMustBeLocalportNoPortSecurity(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedVPCRouter(t, m, "vpc-0a1b2c3d4e5f6789", "10.0.0.0/16") + mgr, _ := newIMDSManager(t, m) + + spec, err := mgr.EnsureForVPC(ctx, "vpc-0a1b2c3d4e5f6789") + require.NoError(t, err) + + lsp, err := m.GetLogicalSwitchPort(ctx, spec.LSPName) + require.NoError(t, err) + + if lsp.Type != "localport" { + t.Errorf("imds LSP %s Type = %q, want \"localport\": a regular LSP binds to "+ + "one chassis only, forcing IMDS through Geneve and creating a single point "+ + "of failure per VPC", spec.LSPName, lsp.Type) + } + if len(lsp.PortSecurity) != 0 { + t.Errorf("imds LSP %s PortSecurity = %v, want empty: port_security set on the "+ + "host-owned LSP would cause ovn-controller to drop reply frames from the "+ + "host veth's MAC", spec.LSPName, lsp.PortSecurity) + } +} + +// TestI3_IMDSStaticRouteShape asserts the static route on vpc-{vpcID} that +// diverts 169.254.169.254 off the WAN default and out the IMDS LRP has the +// exact shape the datapath depends on. A drifted prefix, nexthop, or output +// port silently sends IMDS traffic to the WAN, where it disappears. +func TestI3_IMDSStaticRouteShape(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedVPCRouter(t, m, "vpc-0a1b2c3d4e5f6789", "10.0.0.0/16") + mgr, _ := newIMDSManager(t, m) + + spec, err := mgr.EnsureForVPC(ctx, "vpc-0a1b2c3d4e5f6789") + require.NoError(t, err) + + route := findIMDSRoute(m, handlers_imds.MetaDataServerIP+"/32") + require.NotNil(t, route, "no static route for %s/32 on the VPC router — IMDS traffic "+ + "falls through to the WAN default", handlers_imds.MetaDataServerIP) + + assert.Equal(t, handlers_imds.MetaDataServerIP+"/32", route.IPPrefix) + assert.Equal(t, handlers_imds.MetaDataServerIP, route.Nexthop) + require.NotNil(t, route.OutputPort, "IMDS static route has no output port — OVN cannot "+ + "resolve which LRP to send 169.254.169.254 traffic out of") + assert.Equal(t, spec.LRPName, *route.OutputPort) +} + +// TestI4_SubnetEgressRerouteMustExcludeLinkLocal asserts every per-subnet +// internet-egress reroute policy excludes 169.254.0.0/16. The reroute matches +// 0.0.0.0/0 — the widest possible scope — and fires in lr_in_policy AFTER the +// IMDS /32 static route matches in lr_in_ip_routing, so without this exclusion +// it overrides the /32 and SNAT-reroutes 169.254.169.254 out the WAN, where +// IMDS disappears (the guest's PUT for a token never reaches the per-VPC netns +// listener). Both the IGW- and NATGW-priority reroutes carry the gate, so both +// must spare link-local. A drifted exclude list silently breaks IMDS on any +// VPC with internet egress. +func TestI4_SubnetEgressRerouteMustExcludeLinkLocal(t *testing.T) { + linkLocal := fmt.Sprintf("ip4.dst != %s", linkLocalCIDR.String()) + + cases := []struct { + name string + install func(mgr IGWManager, ctx context.Context) error + }{ + {"IGW", func(mgr IGWManager, ctx context.Context) error { + return mgr.EnsureSubnetEgress(ctx, "vpc-1", "subnet-pub", netip.MustParsePrefix("0.0.0.0/0")) + }}, + {"NATGW", func(mgr IGWManager, ctx context.Context) error { + return mgr.EnsureNATGatewaySubnetEgress(ctx, "vpc-1", "subnet-priv", netip.MustParsePrefix("0.0.0.0/0")) + }}, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + ctx := context.Background() + m := mock.New() + seedVPCRouter(t, m, "vpc-1", "10.0.0.0/16") + pool := &ExternalPoolConfig{Name: "p", Gateway: "192.168.1.1", PrefixLen: 24} + mgr, _ := newTestIGWManager(t, m, policy.NATModeDistributed, pool, LinkLocalAllocator{}, []string{"chassis-a"}) + + require.NoError(t, mgr.AttachIGW(ctx, IGWSpec{VPCID: "vpc-1", InternetGatewayID: "igw-1"})) + require.NoError(t, tc.install(mgr, ctx)) + + policies, err := m.ListLogicalRouterPolicies(ctx, topology.VPCRouter("vpc-1")) + require.NoError(t, err) + require.Len(t, policies, 1) + assert.Contains(t, policies[0].Match, linkLocal, + "%s egress reroute %q does not exclude %s — it will hijack 169.254.169.254 "+ + "out the WAN and override the IMDS /32 static route, making IMDS unreachable", + tc.name, policies[0].Match, linkLocalCIDR) + }) + } +} diff --git a/spinifex/network/host/imds_names.go b/spinifex/network/host/imds_names.go new file mode 100644 index 000000000..95957d863 --- /dev/null +++ b/spinifex/network/host/imds_names.go @@ -0,0 +1,34 @@ +package host + +// IMDS per-VPC veth naming. The names live here (not in network/topology) so +// the IMDS BindManager can derive them without importing topology, which would +// form an import cycle (topology imports handlers/imds for MetaDataServerIP). + +// IMDSShortVPCID is the last 8 chars of the VPC ID. Linux IFNAMSIZ caps interface +// names at 15 chars, so the IMDS veth names key off this short form. Deterministic +// and stable: every chassis serving IMDS for VPC X derives the same names. +func IMDSShortVPCID(vpcID string) string { + if len(vpcID) <= 8 { + return vpcID + } + return vpcID[len(vpcID)-8:] +} + +// IMDSOVSPortName is the br-int side of the per-VPC IMDS veth pair, bound to the +// imds-port LSP via external_ids:iface-id. The 7-char prefix keeps "imds-o-" + the +// 8-char short VPC ID at exactly IFNAMSIZ-1 (15); longer fails `ip link add`. +func IMDSOVSPortName(vpcID string) string { return "imds-o-" + IMDSShortVPCID(vpcID) } + +// IMDSHostVethName is the host-end side of the per-VPC IMDS veth pair — the +// device the IMDS listener binds to via SO_BINDTODEVICE. Same 7-char prefix +// budget as IMDSOVSPortName: "imds-h-" + 8-char short VPC ID = 15 chars. It +// lives inside the VPC's netns (see IMDSNetnsName), not the root netns. +func IMDSHostVethName(vpcID string) string { return "imds-h-" + IMDSShortVPCID(vpcID) } + +// IMDSNetnsName is the per-VPC network namespace the IMDS host-end veth and its +// listener live in. The netns gives the reply path a real L3 next-hop — the +// host end carries 169.254.169.254/30 with a default route via the .253 LRP — +// and structurally isolates VPCs with overlapping CIDRs, since each netns is its +// own routing domain. Netns names are filesystem-scoped, not IFNAMSIZ-bound, so +// "imds-" + 8-char short VPC ID (13 chars) is comfortably within budget. +func IMDSNetnsName(vpcID string) string { return "imds-" + IMDSShortVPCID(vpcID) } diff --git a/spinifex/network/host/imds_netns_unit_test.go b/spinifex/network/host/imds_netns_unit_test.go new file mode 100644 index 000000000..47fd99cb3 --- /dev/null +++ b/spinifex/network/host/imds_netns_unit_test.go @@ -0,0 +1,97 @@ +package host + +import ( + "os" + "path/filepath" + "runtime" + "strings" + "testing" +) + +// repoRoot resolves the spinifex submodule root from this test file's location +// (spinifex/network/host/ → three levels up) so the systemd-unit invariants can +// read build/ artifacts regardless of the test's working directory. +func repoRoot(t *testing.T) string { + t.Helper() + _, file, _, ok := runtime.Caller(0) + if !ok { + t.Fatal("runtime.Caller failed") + } + root := filepath.Clean(filepath.Join(filepath.Dir(file), "..", "..", "..")) + if _, err := os.Stat(filepath.Join(root, "build", "systemd")); err != nil { + t.Fatalf("could not locate build/systemd from %s: %v", root, err) + } + return root +} + +func readUnit(t *testing.T, root, rel string) string { + t.Helper() + b, err := os.ReadFile(filepath.Join(root, rel)) + if err != nil { + t.Fatalf("read %s: %v", rel, err) + } + return string(b) +} + +// TestIMDS_NetnsHostMountNSInvariant pins the host-mount-namespace contract for +// per-VPC IMDS netns (see spinifex-vpcd.service + bead js-133): vpcd creates the +// netns via `ip netns add` and binds the listener via in-process setns, so the +// /run/netns/ bind-mount must live in the HOST mount namespace — host-visible +// for diagnostics and durable across a vpcd restart. Any filesystem-sandbox +// directive forks a PRIVATE mount ns that traps the bind-mount inside vpcd, so the +// host sees only a stale handle that fails setns(2) EINVAL (CI runs 26920490454, +// 26922587471). The earlier MountFlags=shared + spinifex-netns.service shared-mount +// workaround was proven insufficient and removed; vpcd now simply shares the host +// mount ns. Guard that shape: re-adding any mount-ns directive reintroduces the bug. +func TestIMDS_NetnsHostMountNSInvariant(t *testing.T) { + root := repoRoot(t) + + vpcd := readUnit(t, root, "build/systemd/spinifex-vpcd.service") + target := readUnit(t, root, "build/systemd/spinifex.target") + + // No filesystem-sandbox directive may be set on vpcd: each forks a private + // mount namespace and re-traps the netns bind-mount. + for _, banned := range []string{ + "ProtectSystem", "ProtectHome", "PrivateTmp", "ProtectKernelTunables", + "ProtectKernelModules", "ProtectKernelLogs", "ProtectControlGroups", + "ProtectProc", "ReadOnlyPaths", "ReadWritePaths", "MountFlags", + } { + if directiveSet(vpcd, banned) { + t.Errorf("spinifex-vpcd.service must share the HOST mount ns but sets %s= — a private mount ns traps /run/netns/ and host setns(2) fails EINVAL", banned) + } + } + + // vpcd still needs CAP_SYS_ADMIN for setns(CLONE_NEWNET) and the net+mnt + // namespace allowance for the in-netns `ip` plumbing. + mustContain(t, "spinifex-vpcd.service", vpcd, "CAP_SYS_ADMIN") + mustContain(t, "spinifex-vpcd.service", vpcd, "RestrictNamespaces=net mnt") + + // The removed shared-mount workaround must not reappear by reference. + if strings.Contains(vpcd, "spinifex-netns.service") && !strings.Contains(vpcd, "# ") { + t.Errorf("spinifex-vpcd.service must not depend on spinifex-netns.service (removed)") + } + if directiveSet(target, "Wants") && strings.Contains(target, "spinifex-netns.service") { + t.Errorf("spinifex.target must not pull in spinifex-netns.service (removed)") + } + if _, err := os.Stat(filepath.Join(root, "build", "systemd", "spinifex-netns.service")); err == nil { + t.Errorf("build/systemd/spinifex-netns.service must be removed — the shared-mount workaround was proven insufficient") + } +} + +// directiveSet reports whether key is set as an actual unit directive (a line +// `key=...`), ignoring comment prose that merely names it. +func directiveSet(body, key string) bool { + for line := range strings.SplitSeq(body, "\n") { + if strings.HasPrefix(strings.TrimSpace(line), key+"=") { + return true + } + } + return false +} + +func mustContain(t *testing.T, name, body, want string) { + t.Helper() + if !strings.Contains(body, want) { + t.Errorf("%s: missing %q", name, want) + } +} diff --git a/spinifex/network/host/imds_veth.go b/spinifex/network/host/imds_veth.go new file mode 100644 index 000000000..18ec0ca86 --- /dev/null +++ b/spinifex/network/host/imds_veth.go @@ -0,0 +1,217 @@ +package host + +import ( + "context" + "fmt" + "log/slog" + "strings" + + "github.com/mulgadc/spinifex/spinifex/utils" +) + +const ( + // imdsNetnsAddr is the host/listener side of the IMDS /30, assigned to the + // veth host end inside the per-VPC netns. .254 is MetaDataServerIP; the /30 + // makes .253 (the LRP) directly connected so the reply path has a next-hop. + imdsNetnsAddr = "169.254.169.254/30" + // imdsNetnsGateway is the IMDS LRP (.253) — the netns default gateway that + // routes guest replies back into OVN. Mirrors external.imdsLRPNetwork's .253. + imdsNetnsGateway = "169.254.169.253" +) + +// imdsPortLSPName is the OVN logical-switch-port the OVS-side veth binds to via +// external_ids:iface-id. It mirrors topology.IMDSPort but is duplicated here to +// avoid an import cycle (host ← handlers/imds ← topology). +func imdsPortLSPName(vpcID string) string { return "imds-port-" + vpcID } + +// imdsLSPMAC is the logical MAC OVN advertises for 169.254.169.254 (the localport +// address). The netns veth host end MUST carry this exact MAC: OVN resolves .254 +// to it and delivers IMDS request frames with dl_dst set to it, so a kernel-random +// veth MAC makes the netns drop every frame not-for-me and the listener never sees +// a SYN. Mirrors external.IMDSSpecForVPC's LSPMAC, duplicated here (like +// imdsPortLSPName) to avoid the import cycle. +func imdsLSPMAC(vpcID string) string { return utils.HashMAC("imds-" + vpcID) } + +// EnsureIMDSVeth idempotently creates the per-VPC IMDS veth pair, moves the host end +// into a dedicated netns with 169.254.169.254/30 + a default route via the .253 LRP, +// and attaches the OVS end to br-int so ovn-controller binds the localport here. The +// netns gives the host-served reply a real L3 next-hop (SO_BINDTODEVICE alone cannot +// route the SYN-ACK) and isolates overlapping VPC CIDRs into separate routing domains. +// Returns the netns name and host-end name the listener enters and binds. +func EnsureIMDSVeth(ctx context.Context, vpcID string) (netnsName, hostEndName string, err error) { + ovsEnd := IMDSOVSPortName(vpcID) + hostEnd := IMDSHostVethName(vpcID) + netns := IMDSNetnsName(vpcID) + + // Idempotency probe: the full plumbing (veth pair, netns, host-end address + + // route) exists from a prior boot only when the OVS end is a port on br-int + // AND the netns is enterable. A live OVS port over a stale netns (name + // present but setns(2) fails EINVAL — e.g. a crash between umount and unlink, + // or a tmpfs remount across reboot) leaves the listener permanently + // unbindable, so that case must NOT short-circuit: tear the inconsistent + // plumbing down and rebuild it below. + if imdsOVSPortOnBrInt(ovsEnd) { + if netnsEnterable(netns) { + slog.Debug("IMDS veth already present", "vpc", vpcID, "ovs_end", ovsEnd, "host_end", hostEnd, "netns", netns) + return netns, hostEnd, nil + } + slog.Warn("IMDS netns unenterable behind a live OVS port (stale handle), rebuilding plumbing", + "vpc", vpcID, "netns", netns, "ovs_end", ovsEnd) + if err := removeIMDSPlumbing(ovsEnd, hostEnd, netns); err != nil { + slog.Warn("Failed to tear down stale IMDS plumbing before rebuild", "vpc", vpcID, "err", err) + } + } + + if err := ensureNetns(netns); err != nil { + return "", "", err + } + + if out, err := utils.SudoCommand("ip", "link", "add", ovsEnd, "type", "veth", "peer", "name", hostEnd).CombinedOutput(); err != nil { + if cleanErr := removeIMDSPlumbing(ovsEnd, hostEnd, netns); cleanErr != nil { + slog.Warn("Failed to clean up IMDS plumbing after veth-create failure", "vpc", vpcID, "err", cleanErr) + } + return "", "", fmt.Errorf("create IMDS veth pair %s/%s: %s: %w", ovsEnd, hostEnd, strings.TrimSpace(string(out)), err) + } + + if err := configureIMDSNetns(netns, hostEnd, ovsEnd, imdsLSPMAC(vpcID)); err != nil { + if cleanErr := removeIMDSPlumbing(ovsEnd, hostEnd, netns); cleanErr != nil { + slog.Warn("Failed to clean up IMDS plumbing after netns config failure", "vpc", vpcID, "err", cleanErr) + } + return "", "", err + } + + ifaceID := imdsPortLSPName(vpcID) + if out, err := utils.SudoCommand("ovs-vsctl", "add-port", "br-int", ovsEnd, + "--", "set", "Interface", ovsEnd, "external_ids:iface-id="+ifaceID).CombinedOutput(); err != nil { + if cleanErr := removeIMDSPlumbing(ovsEnd, hostEnd, netns); cleanErr != nil { + slog.Warn("Failed to clean up IMDS plumbing after OVS failure", "vpc", vpcID, "err", cleanErr) + } + return "", "", fmt.Errorf("add IMDS veth %s to br-int: %s: %w", ovsEnd, strings.TrimSpace(string(out)), err) + } + + slog.Info("IMDS veth plumbing complete", "vpc", vpcID, "ovs_end", ovsEnd, "host_end", hostEnd, "netns", netns, "iface_id", ifaceID) + return netns, hostEnd, nil +} + +// configureIMDSNetns moves the host end into the netns, sets its MAC to the +// localport's logical MAC, brings it (and lo) up, and assigns the IMDS address + +// default route so the host-served reply has a real next-hop. The OVS end stays in +// the root netns for ovn-controller to bind. The MAC set is the request-path +// contract: OVN delivers frames with dl_dst = the localport MAC, so the veth host +// end must own that MAC or the netns silently drops them. The addr/route adds +// tolerate "File exists" so a re-run after a partial failure converges rather than +// wedging. +func configureIMDSNetns(netns, hostEnd, ovsEnd, hostEndMAC string) error { + if out, err := utils.SudoCommand("ip", "link", "set", ovsEnd, "up").CombinedOutput(); err != nil { + return fmt.Errorf("bring up IMDS OVS end %s: %s: %w", ovsEnd, strings.TrimSpace(string(out)), err) + } + if out, err := utils.SudoCommand("ip", "link", "set", hostEnd, "netns", netns).CombinedOutput(); err != nil { + return fmt.Errorf("move IMDS host end %s into netns %s: %s: %w", hostEnd, netns, strings.TrimSpace(string(out)), err) + } + if out, err := utils.SudoCommand("ip", "-n", netns, "link", "set", hostEnd, "address", hostEndMAC).CombinedOutput(); err != nil { + return fmt.Errorf("set IMDS host end %s MAC %s in netns %s: %s: %w", hostEnd, hostEndMAC, netns, strings.TrimSpace(string(out)), err) + } + for _, dev := range []string{"lo", hostEnd} { + if out, err := utils.SudoCommand("ip", "-n", netns, "link", "set", dev, "up").CombinedOutput(); err != nil { + return fmt.Errorf("bring up %s in netns %s: %s: %w", dev, netns, strings.TrimSpace(string(out)), err) + } + } + if err := ipNetnsTolerate(netns, "File exists", "addr", "add", imdsNetnsAddr, "dev", hostEnd); err != nil { + return err + } + return ipNetnsTolerate(netns, "File exists", "route", "add", "default", "via", imdsNetnsGateway) +} + +// ensureNetns creates the netns, treating "already exists" as success — but +// only when the pre-existing handle is actually enterable. A stale +// /run/netns/ bind-mount (name resolves yet setns(2) fails EINVAL) returns +// "File exists" from `ip netns add` while being unusable, which would leave the +// IMDS listener permanently unbindable; that handle is torn down and recreated. +func ensureNetns(netns string) error { + out, err := utils.SudoCommand("ip", "netns", "add", netns).CombinedOutput() + if err == nil { + return nil + } + if !strings.Contains(string(out), "File exists") { + return fmt.Errorf("create IMDS netns %s: %s: %w", netns, strings.TrimSpace(string(out)), err) + } + if netnsEnterable(netns) { + return nil + } + slog.Warn("IMDS netns present but unenterable (stale handle), recreating", "netns", netns) + if out, err := utils.SudoCommand("ip", "netns", "del", netns).CombinedOutput(); err != nil { + if msg := strings.TrimSpace(string(out)); !strings.Contains(msg, "No such file") { + return fmt.Errorf("delete stale IMDS netns %s: %s: %w", netns, msg, err) + } + } + if out, err := utils.SudoCommand("ip", "netns", "add", netns).CombinedOutput(); err != nil { + return fmt.Errorf("recreate IMDS netns %s: %s: %w", netns, strings.TrimSpace(string(out)), err) + } + return nil +} + +// imdsOVSPortOnBrInt reports whether the IMDS OVS-end veth is currently a port +// on br-int — the cheap signal that prior plumbing exists. +func imdsOVSPortOnBrInt(ovsEnd string) bool { + out, err := utils.SudoCommand("ovs-vsctl", "port-to-br", ovsEnd).CombinedOutput() + return err == nil && strings.TrimSpace(string(out)) == "br-int" +} + +// netnsEnterable reports whether netns can be entered via setns(2). A stale +// bind-mount resolves by name but fails EINVAL; `ip -n link show lo` +// performs the setns and surfaces it. A truly-absent netns also reports false, +// which is the correct signal for both callers (recreate / rebuild). +func netnsEnterable(netns string) bool { + return utils.SudoCommand("ip", "-n", netns, "link", "show", "lo").Run() == nil +} + +// ipNetnsTolerate runs `ip -n `, treating output containing +// tolerate as success (for idempotent re-runs of addr/route adds). +func ipNetnsTolerate(netns, tolerate string, args ...string) error { + full := append([]string{"-n", netns}, args...) + if out, err := utils.SudoCommand("ip", full...).CombinedOutput(); err != nil { + if strings.Contains(string(out), tolerate) { + return nil + } + return fmt.Errorf("ip %s: %s: %w", strings.Join(full, " "), strings.TrimSpace(string(out)), err) + } + return nil +} + +// RemoveIMDSVeth detaches the OVS port, deletes the netns (which destroys the +// host end and thus the veth pair), and clears any root-netns remnant. Idempotent: +// safe to call for a VPC that never had a veth on this chassis. +func RemoveIMDSVeth(ctx context.Context, vpcID string) error { + return removeIMDSPlumbing(IMDSOVSPortName(vpcID), IMDSHostVethName(vpcID), IMDSNetnsName(vpcID)) +} + +// removeIMDSPlumbing tears down the OVS port, the netns, and any leftover veth. +// Deleting the netns destroys the host end (and its peer); the trailing link del +// covers the partial state where the host end was never moved into the netns. +func removeIMDSPlumbing(ovsEnd, hostEnd, netns string) error { + if out, err := utils.SudoCommand("ovs-vsctl", "--if-exists", "del-port", ovsEnd).CombinedOutput(); err != nil { + slog.Warn("Failed to remove IMDS veth from OVS", "ovs_end", ovsEnd, "err", err, "out", strings.TrimSpace(string(out))) + } + + if out, err := utils.SudoCommand("ip", "netns", "del", netns).CombinedOutput(); err != nil { + msg := strings.TrimSpace(string(out)) + // "No such file or directory" — already gone. Anything else is logged + // but not fatal: the link del below still runs. + if !strings.Contains(msg, "No such file") { + slog.Warn("Failed to delete IMDS netns", "netns", netns, "err", err, "out", msg) + } + } + + if out, err := utils.SudoCommand("ip", "link", "del", ovsEnd).CombinedOutput(); err != nil { + // "Cannot find device" — the pair was already destroyed with the netns. + msg := strings.TrimSpace(string(out)) + if strings.Contains(msg, "Cannot find device") { + slog.Debug("IMDS veth already absent", "ovs_end", ovsEnd) + return nil + } + return fmt.Errorf("delete IMDS veth %s: %s: %w", ovsEnd, msg, err) + } + + slog.Info("IMDS veth removed", "ovs_end", ovsEnd, "host_end", hostEnd, "netns", netns) + return nil +} diff --git a/spinifex/network/host/imds_veth_test.go b/spinifex/network/host/imds_veth_test.go new file mode 100644 index 000000000..1ece52750 --- /dev/null +++ b/spinifex/network/host/imds_veth_test.go @@ -0,0 +1,351 @@ +package host + +import ( + "context" + "os/exec" + "slices" + "strings" + "testing" + + "github.com/mulgadc/spinifex/spinifex/utils" +) + +const testVPCID = "vpc-0123456789abcdef" // short form: "89abcdef" + +func recordSudo(t *testing.T, fail func(name string, args []string) *exec.Cmd) *[][]string { + t.Helper() + var calls [][]string + t.Cleanup(utils.SetSudoCommandForTest(func(name string, args ...string) *exec.Cmd { + calls = append(calls, append([]string{name}, args...)) + if fail != nil { + if c := fail(name, args); c != nil { + return c + } + } + return exec.Command("/bin/true") + })) + return &calls +} + +func TestEnsureIMDSVeth_HappyPath(t *testing.T) { + // Probe must report "not a port" so creation proceeds. + calls := recordSudo(t, func(name string, args []string) *exec.Cmd { + if name == "ovs-vsctl" && len(args) >= 1 && args[0] == "port-to-br" { + return exec.Command("/bin/false") + } + return nil + }) + + netns, hostEnd, err := EnsureIMDSVeth(context.Background(), testVPCID) + if err != nil { + t.Fatalf("EnsureIMDSVeth: %v", err) + } + if netns != "imds-89abcdef" { + t.Errorf("netns = %q, want imds-89abcdef", netns) + } + if hostEnd != "imds-h-89abcdef" { + t.Errorf("hostEnd = %q, want imds-h-89abcdef", hostEnd) + } + + want := [][]string{ + {"ovs-vsctl", "port-to-br", "imds-o-89abcdef"}, + {"ip", "netns", "add", "imds-89abcdef"}, + {"ip", "link", "add", "imds-o-89abcdef", "type", "veth", "peer", "name", "imds-h-89abcdef"}, + {"ip", "link", "set", "imds-o-89abcdef", "up"}, + {"ip", "link", "set", "imds-h-89abcdef", "netns", "imds-89abcdef"}, + {"ip", "-n", "imds-89abcdef", "link", "set", "imds-h-89abcdef", "address", utils.HashMAC("imds-" + testVPCID)}, + {"ip", "-n", "imds-89abcdef", "link", "set", "lo", "up"}, + {"ip", "-n", "imds-89abcdef", "link", "set", "imds-h-89abcdef", "up"}, + {"ip", "-n", "imds-89abcdef", "addr", "add", "169.254.169.254/30", "dev", "imds-h-89abcdef"}, + {"ip", "-n", "imds-89abcdef", "route", "add", "default", "via", "169.254.169.253"}, + {"ovs-vsctl", "add-port", "br-int", "imds-o-89abcdef", + "--", "set", "Interface", "imds-o-89abcdef", + "external_ids:iface-id=imds-port-" + testVPCID}, + } + if len(*calls) != len(want) { + t.Fatalf("got %d calls, want %d: %v", len(*calls), len(want), *calls) + } + for i := range want { + if !slices.Equal((*calls)[i], want[i]) { + t.Errorf("call %d = %v, want %v", i, (*calls)[i], want[i]) + } + } +} + +func TestEnsureIMDSVeth_Idempotent(t *testing.T) { + // Probe reports the OVS end is already on br-int and the netns is enterable + // (default mock = /bin/true) → early return, no mutation. + calls := recordSudo(t, func(name string, args []string) *exec.Cmd { + if name == "ovs-vsctl" && len(args) >= 1 && args[0] == "port-to-br" { + return exec.Command("echo", "br-int") + } + return nil + }) + + netns, hostEnd, err := EnsureIMDSVeth(context.Background(), testVPCID) + if err != nil { + t.Fatalf("EnsureIMDSVeth: %v", err) + } + if netns != "imds-89abcdef" { + t.Errorf("netns = %q, want imds-89abcdef", netns) + } + if hostEnd != "imds-h-89abcdef" { + t.Errorf("hostEnd = %q, want imds-h-89abcdef", hostEnd) + } + want := [][]string{ + {"ovs-vsctl", "port-to-br", "imds-o-89abcdef"}, + {"ip", "-n", "imds-89abcdef", "link", "show", "lo"}, + } + if len(*calls) != len(want) { + t.Fatalf("expected only the two probe calls, got %v", *calls) + } + for i := range want { + if !slices.Equal((*calls)[i], want[i]) { + t.Errorf("call %d = %v, want %v", i, (*calls)[i], want[i]) + } + } +} + +// TestEnsureIMDSVeth_StaleNetnsBehindLivePort_Rebuilds guards Fix #2: a live +// OVS port over an unenterable netns (stale /run/netns handle, setns EINVAL) +// must NOT short-circuit. The inconsistent plumbing is torn down and rebuilt so +// the IMDS listener becomes bindable again, rather than wedging forever. +func TestEnsureIMDSVeth_StaleNetnsBehindLivePort_Rebuilds(t *testing.T) { + calls := recordSudo(t, func(name string, args []string) *exec.Cmd { + if name == "ovs-vsctl" && len(args) >= 1 && args[0] == "port-to-br" { + return exec.Command("echo", "br-int") + } + // Netns enterability probe fails with the kernel's EINVAL message. + if name == "ip" && len(args) >= 5 && args[0] == "-n" && args[2] == "link" && args[3] == "show" { + return exec.Command("sh", "-c", `echo 'setting the network namespace "imds-89abcdef" failed: Invalid argument' >&2; exit 1`) + } + return nil + }) + + if _, _, err := EnsureIMDSVeth(context.Background(), testVPCID); err != nil { + t.Fatalf("EnsureIMDSVeth: %v", err) + } + + // Teardown (removeIMDSPlumbing) must run before the rebuild, and the rebuild + // must re-add the OVS port — proving we did not short-circuit. + var sawDelPort, sawNetnsDel, sawAddPort bool + for _, c := range *calls { + if c[0] == "ovs-vsctl" && slices.Contains(c, "del-port") { + sawDelPort = true + } + if c[0] == "ip" && len(c) >= 3 && c[1] == "netns" && c[2] == "del" { + sawNetnsDel = true + } + if c[0] == "ovs-vsctl" && slices.Contains(c, "add-port") { + sawAddPort = true + } + } + if !sawDelPort || !sawNetnsDel || !sawAddPort { + t.Errorf("expected stale plumbing torn down and rebuilt (del-port=%v, netns del=%v, add-port=%v); calls=%v", + sawDelPort, sawNetnsDel, sawAddPort, *calls) + } +} + +// TestEnsureIMDSVeth_StaleNetnsRecreated guards Fix #1: when `ip netns add` +// reports "File exists" but the handle is unenterable, ensureNetns deletes the +// stale handle and recreates it, then plumbing proceeds to completion. +func TestEnsureIMDSVeth_StaleNetnsRecreated(t *testing.T) { + netnsAdds := 0 + calls := recordSudo(t, func(name string, args []string) *exec.Cmd { + if name == "ovs-vsctl" && len(args) >= 1 && args[0] == "port-to-br" { + return exec.Command("/bin/false") + } + if name == "ip" && len(args) >= 2 && args[0] == "netns" && args[1] == "add" { + netnsAdds++ + if netnsAdds == 1 { + // First add: name already present as a stale handle. + return exec.Command("sh", "-c", "echo 'Cannot create namespace file: File exists' >&2; exit 1") + } + return nil // recreate succeeds + } + // Enterability probe fails → stale handle detected. + if name == "ip" && len(args) >= 5 && args[0] == "-n" && args[2] == "link" && args[3] == "show" { + return exec.Command("sh", "-c", `echo 'setting the network namespace "imds-89abcdef" failed: Invalid argument' >&2; exit 1`) + } + return nil + }) + + if _, _, err := EnsureIMDSVeth(context.Background(), testVPCID); err != nil { + t.Fatalf("EnsureIMDSVeth: %v", err) + } + + // Stale handle deleted then re-added, and the rebuild ran to the add-port. + var sawNetnsDel, sawAddPort bool + for _, c := range *calls { + if c[0] == "ip" && len(c) >= 3 && c[1] == "netns" && c[2] == "del" { + sawNetnsDel = true + } + if c[0] == "ovs-vsctl" && slices.Contains(c, "add-port") { + sawAddPort = true + } + } + if !sawNetnsDel { + t.Errorf("expected stale netns to be deleted before recreate; calls=%v", *calls) + } + if !sawAddPort { + t.Errorf("expected plumbing to complete after recreate; calls=%v", *calls) + } + if netnsAdds != 2 { + t.Errorf("expected two netns add attempts (stale + recreate), got %d", netnsAdds) + } +} + +// TestEnsureIMDSVeth_NetnsExistsTolerated guards idempotent re-runs after a +// partial prior attempt: `ip netns add` reporting "File exists" must not abort. +func TestEnsureIMDSVeth_NetnsExistsTolerated(t *testing.T) { + recordSudo(t, func(name string, args []string) *exec.Cmd { + if name == "ovs-vsctl" && len(args) >= 1 && args[0] == "port-to-br" { + return exec.Command("/bin/false") + } + if name == "ip" && len(args) >= 2 && args[0] == "netns" && args[1] == "add" { + return exec.Command("sh", "-c", "echo 'Cannot create namespace file: File exists' >&2; exit 1") + } + return nil + }) + + if _, _, err := EnsureIMDSVeth(context.Background(), testVPCID); err != nil { + t.Fatalf("expected nil for pre-existing netns, got %v", err) + } +} + +func TestEnsureIMDSVeth_AddPortFailureCleansUp(t *testing.T) { + calls := recordSudo(t, func(name string, args []string) *exec.Cmd { + if name == "ovs-vsctl" && len(args) >= 1 && args[0] == "port-to-br" { + return exec.Command("/bin/false") + } + if name == "ovs-vsctl" && len(args) >= 1 && args[0] == "add-port" { + return exec.Command("/bin/false") + } + return nil + }) + + _, _, err := EnsureIMDSVeth(context.Background(), testVPCID) + if err == nil || !strings.Contains(err.Error(), "add IMDS veth") { + t.Fatalf("expected add-port error, got %v", err) + } + // Cleanup must have run: del-port, netns del, then link del. + var sawDelPort, sawNetnsDel, sawLinkDel bool + for _, c := range *calls { + if c[0] == "ovs-vsctl" && slices.Contains(c, "del-port") { + sawDelPort = true + } + if c[0] == "ip" && len(c) >= 3 && c[1] == "netns" && c[2] == "del" { + sawNetnsDel = true + } + if c[0] == "ip" && len(c) >= 3 && c[1] == "link" && c[2] == "del" { + sawLinkDel = true + } + } + if !sawDelPort || !sawNetnsDel || !sawLinkDel { + t.Errorf("expected cleanup (del-port=%v, netns del=%v, link del=%v); calls=%v", sawDelPort, sawNetnsDel, sawLinkDel, *calls) + } +} + +func TestEnsureIMDSVeth_LinkAddFailureSurfaces(t *testing.T) { + recordSudo(t, func(name string, args []string) *exec.Cmd { + if name == "ovs-vsctl" && len(args) >= 1 && args[0] == "port-to-br" { + return exec.Command("/bin/false") + } + if name == "ip" && len(args) >= 3 && args[0] == "link" && args[1] == "add" { + return exec.Command("/bin/false") + } + return nil + }) + + _, _, err := EnsureIMDSVeth(context.Background(), testVPCID) + if err == nil || !strings.Contains(err.Error(), "create IMDS veth pair") { + t.Fatalf("expected create error, got %v", err) + } +} + +// TestEnsureIMDSVeth_AddrFailureCleansUp asserts a failure assigning the IMDS +// address inside the netns surfaces and tears the half-built plumbing down. +func TestEnsureIMDSVeth_AddrFailureCleansUp(t *testing.T) { + calls := recordSudo(t, func(name string, args []string) *exec.Cmd { + if name == "ovs-vsctl" && len(args) >= 1 && args[0] == "port-to-br" { + return exec.Command("/bin/false") + } + if name == "ip" && len(args) >= 4 && args[0] == "-n" && args[2] == "addr" && args[3] == "add" { + return exec.Command("/bin/false") + } + return nil + }) + + _, _, err := EnsureIMDSVeth(context.Background(), testVPCID) + if err == nil || !strings.Contains(err.Error(), "addr add") { + t.Fatalf("expected addr-add error, got %v", err) + } + var sawNetnsDel bool + for _, c := range *calls { + if c[0] == "ip" && len(c) >= 3 && c[1] == "netns" && c[2] == "del" { + sawNetnsDel = true + } + } + if !sawNetnsDel { + t.Errorf("expected netns cleanup after addr failure; calls=%v", *calls) + } +} + +func TestRemoveIMDSVeth(t *testing.T) { + calls := recordSudo(t, nil) + + if err := RemoveIMDSVeth(context.Background(), testVPCID); err != nil { + t.Fatalf("RemoveIMDSVeth: %v", err) + } + + want := [][]string{ + {"ovs-vsctl", "--if-exists", "del-port", "imds-o-89abcdef"}, + {"ip", "netns", "del", "imds-89abcdef"}, + {"ip", "link", "del", "imds-o-89abcdef"}, + } + if len(*calls) != len(want) { + t.Fatalf("got %d calls, want %d: %v", len(*calls), len(want), *calls) + } + for i := range want { + if !slices.Equal((*calls)[i], want[i]) { + t.Errorf("call %d = %v, want %v", i, (*calls)[i], want[i]) + } + } +} + +func TestRemoveIMDSVeth_MissingDeviceIsNotError(t *testing.T) { + recordSudo(t, func(name string, args []string) *exec.Cmd { + if name == "ip" && len(args) >= 2 && args[0] == "netns" && args[1] == "del" { + return exec.Command("sh", "-c", "echo 'Cannot remove namespace file \"/var/run/netns/imds-89abcdef\": No such file or directory' >&2; exit 1") + } + if name == "ip" && len(args) >= 2 && args[0] == "link" && args[1] == "del" { + // Emit the kernel's "absent device" message on stderr and fail. + return exec.Command("sh", "-c", "echo 'Cannot find device \"imds-o-89abcdef\"' >&2; exit 1") + } + return nil + }) + + if err := RemoveIMDSVeth(context.Background(), testVPCID); err != nil { + t.Fatalf("expected nil for absent device, got %v", err) + } +} + +// TestIMDSVethNamesWithinIFNAMSIZ guards the load-bearing constraint that both +// veth-end names fit Linux's IFNAMSIZ-1 (15 chars). A longer name makes +// `ip link add` fail with "name too long" for every VPC, silently taking IMDS +// offline cluster-wide — and the SudoCommand mock would never catch it. +func TestIMDSVethNamesWithinIFNAMSIZ(t *testing.T) { + const ifnamsizMax = 15 + for _, vpcID := range []string{ + "vpc-0123456789abcdef", + "vpc-0a1b2c3d4e5f6a7b8", + "vpc-deadbeef", + "short", + } { + for _, name := range []string{IMDSOVSPortName(vpcID), IMDSHostVethName(vpcID)} { + if len(name) > ifnamsizMax { + t.Errorf("veth name %q (%d chars) exceeds IFNAMSIZ-1 (%d) for vpc %q", name, len(name), ifnamsizMax, vpcID) + } + } + } +} diff --git a/spinifex/network/reconcile/apply.go b/spinifex/network/reconcile/apply.go index ff904e45f..bc8d62218 100644 --- a/spinifex/network/reconcile/apply.go +++ b/spinifex/network/reconcile/apply.go @@ -5,6 +5,7 @@ import ( "fmt" "log/slog" + handlers_imds "github.com/mulgadc/spinifex/spinifex/handlers/imds" "github.com/mulgadc/spinifex/spinifex/network/ovn/nbdb" "github.com/mulgadc/spinifex/spinifex/network/topology" "github.com/mulgadc/spinifex/spinifex/utils" @@ -15,22 +16,28 @@ import ( func (r *reconciler) applyVPCs(ctx context.Context, intent IntentState, actual ActualState) { for vpcID, spec := range intent.VPCs { routerName := topology.VPCRouter(vpcID) - if _, ok := actual.Routers[routerName]; ok { - continue + if _, ok := actual.Routers[routerName]; !ok { + lr := &nbdb.LogicalRouter{ + Name: routerName, + ExternalIDs: map[string]string{ + "spinifex:vpc_id": vpcID, + "spinifex:cidr": spec.CIDR.String(), + }, + } + if _, err := r.ovn.EnsureLogicalRouter(ctx, lr); err != nil { + slog.Error("reconcile/apply: ensure VPC router failed", "vpc_id", vpcID, "err", err) + continue + } + actual.Routers[routerName] = struct{}{} + slog.Info("reconcile/apply: ensured VPC router", "vpc_id", vpcID, "router", routerName) } - lr := &nbdb.LogicalRouter{ - Name: routerName, - ExternalIDs: map[string]string{ - "spinifex:vpc_id": vpcID, - "spinifex:cidr": spec.CIDR.String(), - }, + // Install IMDS topology for every intent VPC (idempotent via the + // vpc-veth bucket gate); the router must exist for the IMDS LRP. + if r.imds != nil { + if _, err := r.imds.EnsureForVPC(ctx, vpcID); err != nil { + slog.Error("reconcile/apply: IMDS EnsureForVPC failed", "vpc_id", vpcID, "err", err) + } } - if _, err := r.ovn.EnsureLogicalRouter(ctx, lr); err != nil { - slog.Error("reconcile/apply: ensure VPC router failed", "vpc_id", vpcID, "err", err) - continue - } - actual.Routers[routerName] = struct{}{} - slog.Info("reconcile/apply: ensured VPC router", "vpc_id", vpcID, "router", routerName) } } @@ -83,12 +90,15 @@ func (r *reconciler) applySubnets(ctx context.Context, intent IntentState, actua actual.RouterPorts[routerPortName] = struct{}{} } - if _, err := r.ovn.GetLogicalSwitchPort(ctx, switchRouterPortName); err != nil { + if existing, err := r.ovn.GetLogicalSwitchPort(ctx, switchRouterPortName); err != nil { lsp := &nbdb.LogicalSwitchPort{ Name: switchRouterPortName, Type: "router", Addresses: []string{"router"}, - Options: map[string]string{"router-port": routerPortName}, + Options: map[string]string{ + "router-port": routerPortName, + "arp_proxy": handlers_imds.MetaDataServerIP, + }, ExternalIDs: map[string]string{ "spinifex:subnet_id": subnetID, "spinifex:vpc_id": spec.VPCID, @@ -98,6 +108,19 @@ func (r *reconciler) applySubnets(ctx context.Context, intent IntentState, actua slog.Error("reconcile/apply: create subnet router-LSP failed", "subnet_id", subnetID, "err", err) continue } + } else if existing.Options["arp_proxy"] != handlers_imds.MetaDataServerIP { + // Drift convergence: a subnet router LSP created before IMDS proxy-ARP + // landed won't gain arp_proxy from a redeploy alone (the create branch + // only fires when absent), so patch it in place to make it IMDS-reachable. + if existing.Options == nil { + existing.Options = map[string]string{} + } + existing.Options["arp_proxy"] = handlers_imds.MetaDataServerIP + if err := r.ovn.UpdateLogicalSwitchPort(ctx, existing); err != nil { + slog.Error("reconcile/apply: patch subnet router-LSP arp_proxy failed", "subnet_id", subnetID, "err", err) + } else { + slog.Info("reconcile/apply: patched subnet router-LSP with IMDS arp_proxy", "subnet_id", subnetID, "port", switchRouterPortName) + } } if existing, err := r.ovn.FindDHCPOptionsByExternalID(ctx, "spinifex:subnet_id", subnetID); err != nil || existing == nil { diff --git a/spinifex/network/reconcile/invariants_test.go b/spinifex/network/reconcile/invariants_test.go new file mode 100644 index 000000000..fb3ab56c3 --- /dev/null +++ b/spinifex/network/reconcile/invariants_test.go @@ -0,0 +1,135 @@ +package reconcile + +import ( + "context" + "net" + "net/netip" + "testing" + + imds "github.com/mulgadc/spinifex/spinifex/handlers/imds" + "github.com/mulgadc/spinifex/spinifex/network/ovn/mock" + "github.com/mulgadc/spinifex/spinifex/network/topology" +) + +// IMDS-datapath invariants. A guest LSP is created by two +// independent paths — the live topology manager (EnsurePort) and the reconciler +// (applyPorts) — and the per-subnet DHCPOptions row likewise. Both paths are +// exercised here so neither can drift away from the contract the IMDS handler +// trusts. These live in the reconcile package because it is the only network +// package that can import both topology (the live path) and itself (the +// reconciler path) without a cycle. + +// TestI1_GuestLSPMustHavePortSecurity asserts that every guest-attached LSP, +// created by either path, carries port_security equal to its addresses +// (" "). This is the load-bearing security boundary: ovn-controller +// drops any frame whose eth.src/ip4.src doesn't match port_security at the +// ingress LSP, so a compromised guest cannot forge a peer's source IP. Without +// it the IMDS (VPC-ID, source-IP) → ENI mapping is forgeable. +func TestI1_GuestLSPMustHavePortSecurity(t *testing.T) { + ctx := context.Background() + + // Live path: topology.EnsurePort. + t.Run("live", func(t *testing.T) { + m := mock.New() + mgr := topology.NewLiveManager(m) + vpc := topology.VPCSpec{VPCID: "vpc-a", CIDR: netip.MustParsePrefix("10.0.0.0/16")} + sub := topology.SubnetSpec{SubnetID: "subnet-a", VPCID: "vpc-a", CIDR: netip.MustParsePrefix("10.0.1.0/24")} + mac, _ := net.ParseMAC("02:00:00:00:00:01") + port := topology.PortSpec{ + PortID: "eni-a", SubnetID: "subnet-a", VPCID: "vpc-a", + PrivateIP: netip.MustParseAddr("10.0.1.5"), MAC: mac, + } + if err := mgr.EnsureVPC(ctx, vpc); err != nil { + t.Fatalf("EnsureVPC: %v", err) + } + if err := mgr.EnsureSubnet(ctx, sub); err != nil { + t.Fatalf("EnsureSubnet: %v", err) + } + if err := mgr.EnsurePort(ctx, port); err != nil { + t.Fatalf("EnsurePort: %v", err) + } + assertPortSecurity(t, m, topology.Port(port.PortID), "02:00:00:00:00:01 10.0.1.5") + }) + + // Reconciler path: applyPorts. + t.Run("reconciler", func(t *testing.T) { + rec, m := newTestReconciler(t) + intent := freshIntent(t) + if err := rec.Reconcile(ctx, intent); err != nil { + t.Fatalf("Reconcile: %v", err) + } + port := intent.Ports["eni-a"] + want := port.MAC.String() + " " + port.PrivateIP.String() + assertPortSecurity(t, m, topology.Port(port.PortID), want) + }) +} + +// assertPortSecurity fails with the ADR clause when the LSP lacks port_security +// equal to its addresses. +func assertPortSecurity(t *testing.T, m *mock.Client, portName, want string) { + t.Helper() + lsp, err := m.GetLogicalSwitchPort(context.Background(), portName) + if err != nil { + t.Fatalf("guest LSP %s missing: %v", portName, err) + } + if len(lsp.PortSecurity) != 1 || lsp.PortSecurity[0] != want { + t.Errorf("guest LSP %s PortSecurity = %v, want [%q]: guest LSPs without "+ + "port_security allow source-IP spoofing, breaking the IMDS "+ + "(VPC-ID, source-IP) → ENI mapping", portName, lsp.PortSecurity, want) + } + // port_security must mirror addresses exactly, or the enforced identity and + // the advertised identity diverge. + if len(lsp.Addresses) != 1 || lsp.Addresses[0] != lsp.PortSecurity[0] { + t.Errorf("guest LSP %s Addresses %v != PortSecurity %v: enforced and advertised "+ + "identity must match", portName, lsp.Addresses, lsp.PortSecurity) + } +} + +// TestI5_SubnetRouterPortProxiesIMDSARP asserts the subnet router LSP carries +// options:arp_proxy = 169.254.169.254, so the subnet LRP answers ARP/ND for the +// IMDS address link-local. Both emission paths (live EnsureSubnet, reconciler +// applySubnets) are checked so they cannot diverge. This replaces the former +// DHCP option-121 mechanism: proxy-ARP reaches DHCP and fully static guests +// identically (AWS Nitro parity), whereas option 121 never reached a guest with +// no DHCP client. +func TestI5_SubnetRouterPortProxiesIMDSARP(t *testing.T) { + ctx := context.Background() + const cidr = "10.0.1.0/24" + + t.Run("live", func(t *testing.T) { + m := mock.New() + mgr := topology.NewLiveManager(m) + if err := mgr.EnsureVPC(ctx, topology.VPCSpec{VPCID: "vpc-a", CIDR: netip.MustParsePrefix("10.0.0.0/16")}); err != nil { + t.Fatalf("EnsureVPC: %v", err) + } + if err := mgr.EnsureSubnet(ctx, topology.SubnetSpec{SubnetID: "subnet-a", VPCID: "vpc-a", CIDR: netip.MustParsePrefix(cidr)}); err != nil { + t.Fatalf("EnsureSubnet: %v", err) + } + assertARPProxy(t, m, topology.SubnetSwitchRouterPort("subnet-a")) + }) + + t.Run("reconciler", func(t *testing.T) { + rec, m := newTestReconciler(t) + if err := rec.Reconcile(ctx, freshIntent(t)); err != nil { + t.Fatalf("Reconcile: %v", err) + } + assertARPProxy(t, m, topology.SubnetSwitchRouterPort("subnet-a")) + }) +} + +// assertARPProxy fails with the ADR clause unless the subnet router LSP carries +// options:arp_proxy for the IMDS address. +func assertARPProxy(t *testing.T, m *mock.Client, portName string) { + t.Helper() + lsp, err := m.GetLogicalSwitchPort(context.Background(), portName) + if err != nil { + t.Fatalf("subnet router LSP %s missing: %v", portName, err) + } + if lsp.Options["arp_proxy"] != imds.MetaDataServerIP { + t.Errorf("subnet router LSP %s options:arp_proxy = %q, want %q: subnet router "+ + "ports without options:arp_proxy for %s leave IMDS unreachable for any guest "+ + "that treats the address as link-local (the common static-IP and "+ + "NetworkManager/RHEL/Ubuntu case)", + portName, lsp.Options["arp_proxy"], imds.MetaDataServerIP, imds.MetaDataServerIP) + } +} diff --git a/spinifex/network/reconcile/reconcile.go b/spinifex/network/reconcile/reconcile.go index 02946b490..37078949a 100644 --- a/spinifex/network/reconcile/reconcile.go +++ b/spinifex/network/reconcile/reconcile.go @@ -36,7 +36,11 @@ type Config struct { Routes policy.RouteManager IGW external.IGWManager Topology topology.Manager - LocalAZ string + // IMDS installs per-VPC IMDS OVN topology during the VPC apply pass. + // Optional: nil skips IMDS plumbing (focused reconcile tests leave it + // unset; production always wires it). + IMDS external.IMDSTopologyManager + LocalAZ string // NodeHostname is the holder identity for leader-election CAS. NodeHostname string // Chassis is the SBDB-discovered chassis list for gateway LRP rebinding. @@ -54,6 +58,7 @@ type reconciler struct { routes policy.RouteManager igw external.IGWManager topology topology.Manager + imds external.IMDSTopologyManager localAZ string host string chassis []string @@ -92,6 +97,7 @@ func New(cfg Config) (Reconciler, error) { routes: cfg.Routes, igw: cfg.IGW, topology: cfg.Topology, + imds: cfg.IMDS, localAZ: cfg.LocalAZ, host: cfg.NodeHostname, chassis: cfg.Chassis, diff --git a/spinifex/network/subscribers/subscribers.go b/spinifex/network/subscribers/subscribers.go index 69fdd8ca6..ccd785b4e 100644 --- a/spinifex/network/subscribers/subscribers.go +++ b/spinifex/network/subscribers/subscribers.go @@ -23,15 +23,20 @@ type Subscriber struct { eip external.EIPManager natgw external.NATGWManager igw external.IGWManager + imds external.IMDSTopologyManager } -// Config: all fields required. +// Config: all fields required except IMDS. type Config struct { Topology topology.Manager SG policy.SecurityGroupManager EIP external.EIPManager NATGW external.NATGWManager IGW external.IGWManager + // IMDS installs per-VPC IMDS OVN topology on vpc.create / removes it on + // vpc.delete. Optional: nil disables IMDS plumbing (focused topology tests + // leave it unset; production always wires it). + IMDS external.IMDSTopologyManager } // New constructs a Subscriber, returning an error when any manager is nil. @@ -54,6 +59,7 @@ func New(cfg Config) (*Subscriber, error) { eip: cfg.EIP, natgw: cfg.NATGW, igw: cfg.IGW, + imds: cfg.IMDS, }, nil } diff --git a/spinifex/network/subscribers/topology.go b/spinifex/network/subscribers/topology.go index 745bb46eb..e46af64dc 100644 --- a/spinifex/network/subscribers/topology.go +++ b/spinifex/network/subscribers/topology.go @@ -31,11 +31,20 @@ func (s *Subscriber) handleVPCCreate(msg *nats.Msg) { } spec.CIDR = cidr } - if err := s.topology.EnsureVPC(context.Background(), spec); err != nil { + ctx := context.Background() + if err := s.topology.EnsureVPC(ctx, spec); err != nil { slog.Error("subscribers: EnsureVPC failed", "vpc_id", evt.VpcId, "err", err) respond(msg, err) return } + // IMDS topology rides on every VPC (private instances still need metadata + + // role creds). Install is best-effort — the reconciler re-ensures it idempotently, + // so a transient OVN failure here must not fail CreateVpc. + if s.imds != nil { + if _, err := s.imds.EnsureForVPC(ctx, evt.VpcId); err != nil { + slog.Warn("subscribers: IMDS EnsureForVPC failed; reconciler will converge", "vpc_id", evt.VpcId, "err", err) + } + } respond(msg, nil) } @@ -46,7 +55,17 @@ func (s *Subscriber) handleVPCDelete(msg *nats.Msg) { respond(msg, err) return } - if err := s.topology.DeleteVPC(context.Background(), evt.VpcId); err != nil { + ctx := context.Background() + // Remove IMDS topology before the router goes away — the IMDS LRP and + // static route live on vpc-{vpcID}. + if s.imds != nil { + if err := s.imds.RemoveForVPC(ctx, evt.VpcId); err != nil { + slog.Error("subscribers: IMDS RemoveForVPC failed", "vpc_id", evt.VpcId, "err", err) + respond(msg, err) + return + } + } + if err := s.topology.DeleteVPC(ctx, evt.VpcId); err != nil { slog.Error("subscribers: DeleteVPC failed", "vpc_id", evt.VpcId, "err", err) respond(msg, err) return diff --git a/spinifex/network/topology/dhcp_options.go b/spinifex/network/topology/dhcp_options.go index 553c4f61e..61a1dd77f 100644 --- a/spinifex/network/topology/dhcp_options.go +++ b/spinifex/network/topology/dhcp_options.go @@ -4,6 +4,10 @@ package topology // subnet's DHCPOptions row. Both the live topology manager and the reconciler // call it so the two paths cannot drift — they previously hard-coded divergent // dns_server values (live used the configured server, the reconciler "8.8.8.8"). +// +// IMDS reachability (169.254.169.254) is no longer steered via DHCP option 121; it +// is answered link-local by the subnet router LSP's options:arp_proxy, so DHCP and +// static guests reach IMDS identically. The default gateway stays option 3 (router). func BuildSubnetDHCPOptions(gwIP, routerMAC, dnsServer string) map[string]string { return map[string]string{ "server_id": gwIP, diff --git a/spinifex/network/topology/dhcp_options_test.go b/spinifex/network/topology/dhcp_options_test.go new file mode 100644 index 000000000..e639efe0e --- /dev/null +++ b/spinifex/network/topology/dhcp_options_test.go @@ -0,0 +1,24 @@ +package topology + +import "testing" + +// IMDS reachability moved from DHCP option 121 to the subnet router LSP's +// options:arp_proxy (Step 14), so BuildSubnetDHCPOptions must no longer emit a +// classless_static_route key. The default gateway is still carried by option 3 +// (router), and dns_server/server_id remain present. +func TestBuildSubnetDHCPOptions_NoClasslessStaticRoute(t *testing.T) { + opts := BuildSubnetDHCPOptions("10.0.1.1", "02:00:00:00:00:01", "{8.8.8.8, 1.1.1.1}") + + if _, ok := opts["classless_static_route"]; ok { + t.Errorf("classless_static_route must be absent (IMDS now uses subnet-router proxy-ARP, not DHCP option 121); got %q", opts["classless_static_route"]) + } + if got := opts["router"]; got != "10.0.1.1" { + t.Errorf("router = %q, want %q", got, "10.0.1.1") + } + if got := opts["dns_server"]; got != "{8.8.8.8, 1.1.1.1}" { + t.Errorf("dns_server = %q, want %q", got, "{8.8.8.8, 1.1.1.1}") + } + if got := opts["server_id"]; got != "10.0.1.1" { + t.Errorf("server_id = %q, want %q", got, "10.0.1.1") + } +} diff --git a/spinifex/network/topology/manager_live.go b/spinifex/network/topology/manager_live.go index fe6f576c3..5f12f2d34 100644 --- a/spinifex/network/topology/manager_live.go +++ b/spinifex/network/topology/manager_live.go @@ -9,6 +9,7 @@ import ( "strconv" "strings" + handlers_imds "github.com/mulgadc/spinifex/spinifex/handlers/imds" "github.com/mulgadc/spinifex/spinifex/network/ovn" "github.com/mulgadc/spinifex/spinifex/network/ovn/nbdb" "github.com/mulgadc/spinifex/spinifex/utils" @@ -205,6 +206,7 @@ func (m *liveManager) EnsureSubnet(ctx context.Context, spec SubnetSpec) error { Addresses: []string{"router"}, Options: map[string]string{ "router-port": routerPortName, + "arp_proxy": handlers_imds.MetaDataServerIP, }, ExternalIDs: map[string]string{ "spinifex:subnet_id": spec.SubnetID, diff --git a/spinifex/network/topology/names.go b/spinifex/network/topology/names.go index ce9e8aa84..9212aebd7 100644 --- a/spinifex/network/topology/names.go +++ b/spinifex/network/topology/names.go @@ -36,6 +36,23 @@ func ExternalSwitch(vpcID string) string { return "ext-" + vpcID } // external switch onto the host uplink. func ExternalLocalnetPort(vpcID string) string { return "ext-port-" + vpcID } +// IMDSSwitch is the OVN logical switch dedicated to IMDS for a VPC. The +// host-owned 169.254.169.254 LSP lives here, off the subnet switches. +func IMDSSwitch(vpcID string) string { return "imds-ls-" + vpcID } + +// IMDSRouterPort is the LRP on the VPC router that terminates the IMDS /30 and +// is the output port for the 169.254.169.254/32 static route. +func IMDSRouterPort(vpcID string) string { return "imds-lrp-" + vpcID } + +// IMDSSwitchRouterPort is the type=router LSP on the IMDS switch peered with +// IMDSRouterPort. +func IMDSSwitchRouterPort(vpcID string) string { return "imds-rtr-" + vpcID } + +// IMDSPort is the host-owned localport LSP that claims 169.254.169.254 on the +// IMDS switch. ovn-controller binds it on every chassis with a matching +// iface-id OVS port, so each chassis self-serves IMDS for its local VMs. +func IMDSPort(vpcID string) string { return "imds-port-" + vpcID } + // SecurityGroupPortGroup is the OVN port group name for an SG. // OVN names match [a-zA-Z_][a-zA-Z0-9_]*, so hyphens become underscores. func SecurityGroupPortGroup(sgID string) string { diff --git a/spinifex/services/awsgw/awsgw.go b/spinifex/services/awsgw/awsgw.go index 992089724..29daa81a1 100644 --- a/spinifex/services/awsgw/awsgw.go +++ b/spinifex/services/awsgw/awsgw.go @@ -146,6 +146,16 @@ func launchService(config *config.ClusterConfig) error { defer cancelJanitor() go stsService.RunJanitor(janitorCtx) + // IMDS serves 169.254.169.254 to guest VMs from vpcd, which holds the network + // capabilities the hardened awsgw sandbox can't grant. awsgw stays the home of + // STS + IAM, answering the IMDS handler's control-plane RPCs over NATS. + if _, err := stsService.SubscribeIMDSResponder(natsConn); err != nil { + return fmt.Errorf("subscribe IMDS STS responder: %w", err) + } + if _, err := iamService.SubscribeIMDSResponders(natsConn); err != nil { + return fmt.Errorf("subscribe IMDS IAM responders: %w", err) + } + // Expose the in-process STS presigned-URL verify over NATS for the // in-cluster eks-token-webhook (STS is gateway-local, not otherwise on the // bus). Bound to the process lifetime via natsConn.Close on return. diff --git a/spinifex/services/awsgw/imds_absent_test.go b/spinifex/services/awsgw/imds_absent_test.go new file mode 100644 index 000000000..6640e703e --- /dev/null +++ b/spinifex/services/awsgw/imds_absent_test.go @@ -0,0 +1,23 @@ +package awsgw + +import ( + "os" + "strings" + "testing" +) + +// TestIMDSRuntimeAbsentFromAWSGW guards against re-introducing the privileged +// IMDS listener stack into awsgw, whose systemd unit is the most hardened in +// the fleet (NoNewPrivileges=yes, empty CapabilityBoundingSet). The veth + +// privileged-socket bind cannot succeed there; the runtime lives in vpcd, and +// awsgw only answers the IMDS control-plane RPCs (STS + IAM). +func TestIMDSRuntimeAbsentFromAWSGW(t *testing.T) { + src, err := os.ReadFile("awsgw.go") + if err != nil { + t.Fatalf("read awsgw.go: %v", err) + } + if strings.Contains(string(src), "NewIMDSServiceImpl") { + t.Fatal("awsgw must not construct the IMDS runtime (NewIMDSServiceImpl) — " + + "the privileged listener stack belongs in vpcd.") + } +} diff --git a/spinifex/utils/nats.go b/spinifex/utils/nats.go index bda51cbe3..7990b87de 100644 --- a/spinifex/utils/nats.go +++ b/spinifex/utils/nats.go @@ -12,6 +12,7 @@ import ( "time" "github.com/mulgadc/spinifex/internal/tlsconfig" + "github.com/mulgadc/spinifex/spinifex/awserrors" "github.com/nats-io/nats.go" ) @@ -293,6 +294,34 @@ func NATSRequest[Out any](conn *nats.Conn, subject string, input any, timeout ti return &output, nil } +// ServeNATSRequest is the responder-side counterpart to NATSRequest: it unmarshals +// the request payload into *I, invokes fn, and replies with the JSON result or an +// awserrors envelope. The payload carries its own context; no X-Account-ID header. +func ServeNATSRequest[I any, O any](msg *nats.Msg, fn func(*I) (*O, error)) { + input := new(I) + if errResp := UnmarshalJsonPayload(input, msg.Data); errResp != nil { + respondNATS(msg, errResp) + return + } + out, err := fn(input) + if err != nil { + respondNATS(msg, GenerateErrorPayload(awserrors.ValidErrorCode(err.Error()))) + return + } + data, err := json.Marshal(out) + if err != nil { + respondNATS(msg, GenerateErrorPayload(awserrors.ErrorServerInternal)) + return + } + respondNATS(msg, data) +} + +func respondNATS(msg *nats.Msg, data []byte) { + if err := msg.Respond(data); err != nil { + slog.Error("failed to respond to NATS request", "subject", msg.Subject, "err", err) + } +} + const ( // maxScatterGatherResponseSize is the maximum allowed size for a single // scatter-gather response payload (10 MB). Responses exceeding this are diff --git a/spinifex/utils/utils.go b/spinifex/utils/utils.go index 8f7e095dc..dbc93dacc 100644 --- a/spinifex/utils/utils.go +++ b/spinifex/utils/utils.go @@ -326,6 +326,16 @@ func HashMAC(id string) string { return net.HardwareAddr(b).String() } +// ClientIP returns the IP from a RemoteAddr, stripping the port. Handles both +// IPv4 and IPv6, and tolerates a RemoteAddr that is already a bare IP (no port). +func ClientIP(remoteAddr string) string { + host, _, err := net.SplitHostPort(remoteAddr) + if err != nil { + return remoteAddr + } + return host +} + func dirExists(path string) bool { info, err := os.Stat(path) if os.IsNotExist(err) { diff --git a/spinifex/utils/utils_test.go b/spinifex/utils/utils_test.go index 98770f8c5..e004ee9b0 100644 --- a/spinifex/utils/utils_test.go +++ b/spinifex/utils/utils_test.go @@ -1686,3 +1686,22 @@ func TestDistroFamily(t *testing.T) { }) } } + +func TestClientIP(t *testing.T) { + tests := []struct { + name string + remoteAddr string + expected string + }{ + {"IPv4 with port", "192.168.1.1:12345", "192.168.1.1"}, + {"IPv6 with port", "[::1]:12345", "::1"}, + {"IPv4 bare", "192.168.1.1", "192.168.1.1"}, + {"IPv6 full with port", "[2001:db8::1]:443", "2001:db8::1"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.expected, ClientIP(tt.remoteAddr)) + }) + } +} diff --git a/spinifex/vm/vm.go b/spinifex/vm/vm.go index 35665bc27..6218c8240 100644 --- a/spinifex/vm/vm.go +++ b/spinifex/vm/vm.go @@ -61,9 +61,6 @@ type VM struct { // Set when ownership is released on stop for shared KV storage. LastNode string `json:"last_node,omitempty"` - // User data for cloud-init (decoded from base64) - UserData string `json:"user_data,omitempty"` - // Metadata server address (e.g., "127.0.0.1:12345") for EC2 metadata service MetadataServerAddress string `json:"metadata_server_address,omitempty"` diff --git a/spinifex/vpcd/vpcd.go b/spinifex/vpcd/vpcd.go index 7e3acf84c..9d995bb4d 100644 --- a/spinifex/vpcd/vpcd.go +++ b/spinifex/vpcd/vpcd.go @@ -2,6 +2,7 @@ package vpcd import ( "context" + "errors" "fmt" "log/slog" "net" @@ -15,6 +16,7 @@ import ( "time" "github.com/mulgadc/spinifex/spinifex/admin" + handlers_imds "github.com/mulgadc/spinifex/spinifex/handlers/imds" "github.com/mulgadc/spinifex/spinifex/network/external" "github.com/mulgadc/spinifex/spinifex/network/external/dhcp" "github.com/mulgadc/spinifex/spinifex/network/host" @@ -523,6 +525,39 @@ func launchService(cfg *Config) error { return fmt.Errorf("get JetStream context: %w", err) } + // IMDS per-VPC OVN topology installer. Replicas track the chassis count so + // the vpc-veth bucket survives a node loss (create-or-open: awsgw inits the + // same bucket; first writer wins). + imdsVethKV, _, err := handlers_imds.InitBuckets(js, max(len(chassisNames), 1)) + if err != nil { + return fmt.Errorf("init imds buckets: %w", err) + } + imdsTopoMgr, err := external.NewIMDSTopologyManager(liveClient, routeMgr, handlers_imds.NewVethStore(imdsVethKV)) + if err != nil { + return fmt.Errorf("construct IMDS topology manager: %w", err) + } + + // IMDS host-served datapath. vpcd holds the network capabilities the listener + // stack needs (the awsgw sandbox can't grant them); STS/IAM stay in awsgw over + // NATS RPCs. Run blocks, so it gets its own goroutine. + imdsCtx, cancelIMDS := context.WithCancel(ctx) + defer cancelIMDS() + imdsSvc, err := handlers_imds.NewIMDSServiceImpl( + nc, + handlers_imds.NewNATSSTSAssumer(nc), + handlers_imds.NewNATSProfileLookup(nc), + max(len(chassisNames), 1), + host.EnsureIMDSVeth, host.RemoveIMDSVeth, + ) + if err != nil { + return fmt.Errorf("construct IMDS service: %w", err) + } + go func() { + if err := imdsSvc.Run(imdsCtx); err != nil && !errors.Is(err, context.Canceled) { + slog.Error("vpcd: IMDS service exited", "err", err) + } + }() + dhcpMgr, dhcpSubs, err := startDHCPManagerIfNeeded(ctx, nc, js, cfg) if err != nil { return fmt.Errorf("start dhcp manager: %w", err) @@ -574,6 +609,7 @@ func launchService(cfg *Config) error { EIP: eipMgr, NATGW: natgwMgr, IGW: igwMgr, + IMDS: imdsTopoMgr, }) if err != nil { return fmt.Errorf("construct subscriber: %w", err) @@ -596,6 +632,7 @@ func launchService(cfg *Config) error { Routes: routeMgr, IGW: igwMgr, Topology: topoMgr, + IMDS: imdsTopoMgr, LocalAZ: cfg.AZ, NodeHostname: holder, Chassis: chassisNames, diff --git a/tests/e2e/harness/diag.go b/tests/e2e/harness/diag.go index 4b60f8cce..a6de32495 100644 --- a/tests/e2e/harness/diag.go +++ b/tests/e2e/harness/diag.go @@ -156,16 +156,7 @@ func dumpDatapathState(t *testing.T, opts VPCDiagnosticsOpts) { return } - type capture struct { - filename string - label string - argv []string - // grepFor, when non-empty, post-filters stdout to lines - // containing this substring. Lets us keep ovs-ofctl / conntrack - // output tight without an external pipe. - grepFor []string - } - caps := []capture{ + runHostCaptures(t, opts.ArtifactDir, []hostCapture{ { filename: "ovs-flows-extip.txt", label: "ovs-ofctl dump-flows br-int (filtered)", @@ -190,8 +181,25 @@ func dumpDatapathState(t *testing.T, opts VPCDiagnosticsOpts) { argv: []string{"ovn-nbctl", "--bare", "--columns=_uuid,type,external_ip,logical_ip,external_mac,logical_port", "find", "NAT", "external_ip=" + opts.ExternalIP}, }, - } + }) +} +// hostCapture is one `sudo`-run diagnostic command. grepFor, when non-empty, +// post-filters stdout to lines containing any of the substrings (keeps +// ovs-ofctl / conntrack output tight without an external pipe). +type hostCapture struct { + filename string + label string + argv []string + grepFor []string +} + +// runHostCaptures runs each capture under `sudo -n`, echoes it to stdout for the +// CI log, and persists it as a separate file under artifactDir (when set) so the +// Stage 2 analyzer bundler picks it up. Assumes the caller already verified +// passwordless sudo is available. +func runHostCaptures(t *testing.T, artifactDir string, caps []hostCapture) { + t.Helper() for _, cap := range caps { fmt.Printf(" --- %s ---\n", cap.label) var stdout, stderr bytes.Buffer @@ -212,8 +220,8 @@ func dumpDatapathState(t *testing.T, opts VPCDiagnosticsOpts) { for _, line := range strings.Split(strings.TrimRight(body, "\n"), "\n") { fmt.Printf(" %s\n", line) } - if opts.ArtifactDir != "" { - path := filepath.Join(opts.ArtifactDir, cap.filename) + if artifactDir != "" { + path := filepath.Join(artifactDir, cap.filename) header := fmt.Sprintf("$ sudo %s\n", strings.Join(cap.argv, " ")) if len(cap.grepFor) > 0 { header += "# filtered to lines matching: " + strings.Join(cap.grepFor, ", ") + "\n" diff --git a/tests/e2e/harness/imds_diag.go b/tests/e2e/harness/imds_diag.go new file mode 100644 index 000000000..9a02451aa --- /dev/null +++ b/tests/e2e/harness/imds_diag.go @@ -0,0 +1,129 @@ +//go:build e2e + +package harness + +import ( + "fmt" + "os/exec" + "testing" + + "github.com/mulgadc/spinifex/spinifex/network/host" +) + +// DumpIMDSDatapathDiagnostics emits a triage bundle for an IMDS reachability +// failure (guest curl to 169.254.169.254 times out). It captures both halves of +// the per-VPC datapath so a triager can tell request-path from reply-path: +// +// - OVN realisation: is imds-port- bound/up on this chassis, is the +// 169.254.169.254/32 static route installed on the VPC LR, is the localport +// LSP defined as expected. +// - Host realisation (inside the per-VPC netns imds-): the imds-h- +// veth's address/route/neighbour state and the listener socket — the +// load-bearing question is whether the netns has a real L3 path back to +// guestIP. After the per-VPC-netns fix the veth carries 169.254.169.254/30 +// with a default route via the .253 LRP, so a healthy dump shows the IPv4 +// address, a neighbour entry for .253, and a reply route via .253; the +// pre-fix failure showed an addressless veth that accepted the SYN but never +// returned the SYN-ACK. +// - In-flight evidence: conntrack (per-netns) for 169.254.169.254 (a stuck +// SYN_RECV is the smoking gun that the host received the SYN and replied but +// the ACK never came back) and the br-int flows touching the IMDS / guest +// addresses. +// +// Non-fatal — runs purely for log/artifact signal so the test's own Fatal still +// wins. Skips silently when OVN tooling / passwordless sudo aren't available, so +// it's safe to call from developer laptops. +func DumpIMDSDatapathDiagnostics(t *testing.T, vpcID, guestIP, artifactDir string) { + t.Helper() + fmt.Printf("\n%s%s── DIAGNOSTICS: IMDS datapath (vpc=%s guest=%s) ──%s\n", + colorBold, colorCyan, vpcID, guestIP, colorReset) + defer fmt.Printf("%s%s── END DIAGNOSTICS ──%s\n\n", colorBold, colorCyan, colorReset) + + if _, err := exec.LookPath("ovn-nbctl"); err != nil { + fmt.Printf(" ovn-nbctl unavailable (%v); skipping IMDS datapath dump\n", err) + return + } + if err := exec.Command("sudo", "-n", "true").Run(); err != nil { + fmt.Printf(" passwordless sudo unavailable (%v); skipping IMDS datapath dump\n", err) + return + } + + imdsPort := "imds-port-" + vpcID + hostEnd := host.IMDSHostVethName(vpcID) + ovsEnd := host.IMDSOVSPortName(vpcID) + netns := host.IMDSNetnsName(vpcID) + vpcRouter := "vpc-" + vpcID + const imdsIP = "169.254.169.254" + + // nsExec wraps an argv to run inside the per-VPC netns, where the host veth + // end and the IMDS listener now live. + nsExec := func(argv ...string) []string { + return append([]string{"ip", "netns", "exec", netns}, argv...) + } + + runHostCaptures(t, artifactDir, []hostCapture{ + { + filename: "imds-portbinding.txt", + label: "ovn-sbctl Port_Binding imds-port (chassis,up)", + argv: []string{"ovn-sbctl", "--bare", "--columns=logical_port,chassis,up,mac", + "find", "Port_Binding", "logical_port=" + imdsPort}, + }, + { + filename: "imds-lsp-nb.txt", + label: "ovn-nbctl imds-port LSP (type,addresses,options)", + argv: []string{"ovn-nbctl", "--bare", "--columns=name,type,addresses,options", + "find", "Logical_Switch_Port", "name=" + imdsPort}, + }, + { + filename: "imds-lr-routes.txt", + label: "ovn-nbctl lr-route-list (169.254.169.254/32 static route?)", + argv: []string{"ovn-nbctl", "lr-route-list", vpcRouter}, + grepFor: []string{imdsIP}, + }, + { + filename: "imds-netns.txt", + label: "ip netns list (per-VPC IMDS netns present?)", + argv: []string{"ip", "netns", "list"}, + grepFor: []string{netns}, + }, + { + filename: "imds-host-veth-addr.txt", + label: "ip -d addr show imds-h in netns (expect 169.254.169.254/30)", + argv: nsExec("ip", "-d", "addr", "show", "dev", hostEnd), + }, + { + filename: "imds-host-route-to-guest.txt", + label: "ip route get in netns (expect via 169.254.169.253)", + argv: nsExec("ip", "route", "get", guestIP), + }, + { + filename: "imds-host-neigh.txt", + label: "ip neigh show in netns (expect .253 LRP entry)", + argv: nsExec("ip", "neigh", "show"), + }, + { + filename: "imds-listener.txt", + label: "ss -ltnp in netns (IMDS listener bound?)", + argv: nsExec("ss", "-ltnp"), + grepFor: []string{imdsIP, ":80"}, + }, + { + filename: "imds-conntrack.txt", + label: "conntrack -L in netns (169.254.169.254 — SYN_RECV = reply lost)", + argv: nsExec("conntrack", "-L"), + grepFor: []string{imdsIP}, + }, + { + filename: "imds-ovs-flows.txt", + label: "ovs-ofctl dump-flows br-int (IMDS + guest, filtered)", + argv: []string{"ovs-ofctl", "dump-flows", "br-int"}, + grepFor: []string{imdsIP, guestIP}, + }, + { + filename: "imds-ovs-iface.txt", + label: "ovs-vsctl Interface imds-o (iface-id binding, ofport)", + argv: []string{"ovs-vsctl", "--columns=name,external_ids,ofport", + "list", "Interface", ovsEnd}, + }, + }) +} diff --git a/tests/e2e/single/discovery_test.go b/tests/e2e/single/discovery_test.go index 0f4be757d..f4fe34c93 100644 --- a/tests/e2e/single/discovery_test.go +++ b/tests/e2e/single/discovery_test.go @@ -83,7 +83,7 @@ func runEnvironment(t *testing.T, fix *Fixture) { harness.Detail(t, "az", azName, "region", aws.StringValue(azOut.AvailabilityZones[0].RegionName)) harness.OnFailure(t, func() { - harness.DumpCmd(t, fix.Artifacts, "phase1-az.txt", + harness.DumpCmd(t, fix.ArtifactDir(t), "phase1-az.txt", "aws", "ec2", "describe-availability-zones") }) } diff --git a/tests/e2e/single/imds_test.go b/tests/e2e/single/imds_test.go new file mode 100644 index 000000000..c585f43b1 --- /dev/null +++ b/tests/e2e/single/imds_test.go @@ -0,0 +1,459 @@ +//go:build e2e + +package single + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "strings" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go/service/sts" + "github.com/mulgadc/spinifex/tests/e2e/harness" + "github.com/stretchr/testify/require" +) + +// IMDS E2E identifiers. The role/profile carry an imds-e2e- prefix so they +// never collide with the IAM-roles suite ("app-role"/"app-profile") or the +// STS suite ("sts-e2e-role"). +const ( + imdsRoleName = "imds-e2e-role" + imdsProfileName = "imds-e2e-profile" + + // metaURL is the AWS-compatible link-local IMDS endpoint, served from the + // host per-VPC via SO_BINDTODEVICE on the imds-h- veth. + metaURL = "http://169.254.169.254" + + // imdsUserData is a no-op cloud-config carrying a unique marker so the + // /latest/user-data round-trip can assert the body the guest sees matches + // what RunInstances was given. A comment-only cloud-config is a valid empty + // config, so it doesn't perturb boot. + imdsUserData = "#cloud-config\n# imds-e2e-userdata-marker-7f3a91\n" + imdsUDMarker = "imds-e2e-userdata-marker-7f3a91" + + // imdsProbeVPCCIDR / imdsProbeSubnetCIDR are shared by BOTH isolation VPCs. + // Overlapping CIDRs across VPCs are legal (each VPC is its own routing + // domain); using identical subnets makes IPAM hand the first VM in each the + // SAME private IP (network+4, deterministic per ipam.go), which is exactly + // the cross-VPC source-IP collision the isolation assertion needs. + imdsProbeVPCCIDR = "10.211.0.0/16" + imdsProbeSubnetCIDR = "10.211.7.0/24" +) + +// imdsCredDoc mirrors the AWS credential JSON served at +// /latest/meta-data/iam/security-credentials/. Only the fields the test +// asserts on are decoded. +type imdsCredDoc struct { + Code string `json:"Code"` + Type string `json:"Type"` + AccessKeyId string `json:"AccessKeyId"` + SecretAccessKey string `json:"SecretAccessKey"` + Token string `json:"Token"` + Expiration string `json:"Expiration"` + AccountId string `json:"AccountId"` +} + +// runIMDS exercises the host-served IMDSv2 surface end-to-end against real guest +// VMs (docs/development/feature/imds-v1.md Step 11). It stands up two VPCs with +// identical subnet CIDRs and one VM in each so the two VMs share a private IP: +// +// - VM X (profile-bound, user-data) drives the full surface: IMDSv2 token +// issuance, the v2-only stance (tokenless / garbage-token GET → 401), the +// metadata fields, the instance-role credential path + a wire round-trip +// proving the ASIA creds resolve to the instance assumed-role ARN, the +// /latest/user-data round-trip, and the DHCP option-121 guest route. +// - The per-VPC datapath invariant: imds-port- is a localport LSP. +// - Cross-VPC isolation: VM X and VM Y share the same source IP in different +// VPCs, yet each IMDS returns its OWN instance-id — the load-bearing +// (VPC-ID, source-IP) → ENI boundary (plan §Datapath-attested identity). +// +// OVN + SSH gated: the IMDS datapath needs ovn-controller to bind the localport +// per chassis, and every assertion runs via SSH into the guest. +func runIMDS(t *testing.T, fix *Fixture) { + harness.Phase(t, "Single — IMDSv2 Host-Served Instance Metadata") + harness.SkipIfNoOVN(t) + requireSSHHealthy(t) + + adminAccount := iamEnsureAdminAccountID(t, fix) + _, keyPath := needKeyPair(t, fix) + imdsEnsureRoleProfile(t, fix, adminAccount) + + // Two VPCs, identical subnet CIDR → the first VM in each gets the same IP. + vpcX, subX, sgX := imdsEnsureProbeVPC(t, fix, imdsProbeVPCCIDR, imdsProbeSubnetCIDR) + vpcY, subY, sgY := imdsEnsureProbeVPC(t, fix, imdsProbeVPCCIDR, imdsProbeSubnetCIDR) + + // VM X — profile-bound + user-data; drives the full surface. + idX, privX, tgtX := imdsProbe(t, fix, keyPath, imdsVMSpec{ + subnetID: subX, + sgID: sgX, + profileName: imdsProfileName, + userData: imdsUserData, + }) + // VM Y — isolation peer; no profile needed for the instance-id probe. + idY, privY, tgtY := imdsProbe(t, fix, keyPath, imdsVMSpec{ + subnetID: subY, + sgID: sgY, + }) + require.NotEqual(t, idX, idY, "the two probe VMs must be distinct instances") + require.Equalf(t, privX, privY, + "isolation premise: both first-in-subnet VMs must share a private IP "+ + "(IPAM is deterministic at network+4) — got %s vs %s", privX, privY) + harness.Detail(t, "vm_x", idX, "vm_y", idY, "shared_priv", privX) + + // --- Per-VPC OVN datapath invariant: imds-port- is a localport ------ + harness.Step(t, "ovn-nbctl imds-port-%s must be a localport LSP", vpcX) + imdsLSP := "imds-port-" + vpcX // mirrors topology.IMDSPort (inlined, as datapath_test does) + lspType := harness.OvnNbctl(t, "--no-leader-only", "--bare", "--columns=type", + "find", "logical_switch_port", "name="+imdsLSP) + require.Equalf(t, "localport", lspType, + "imds-port LSP %s must be type=localport so every chassis self-serves IMDS "+ + "(a regular LSP binds one chassis and forces Geneve tunnelling)", imdsLSP) + + // --- Subnet-router proxy-ARP makes 169.254.169.254 reachable link-local -- + // IMDS reachability no longer depends on a DHCP option-121 route in the + // guest; the subnet router LSP answers ARP for the IMDS address via OVN + // options:arp_proxy, so DHCP and fully static guests reach it identically. + harness.Step(t, "subnet router LSP rtr-port-%s must carry options:arp_proxy", subX) + rtrLSP := "rtr-port-" + subX // mirrors topology.SubnetSwitchRouterPort + lspOpts := harness.OvnNbctl(t, "--no-leader-only", "--bare", "--columns=options", + "find", "logical_switch_port", "name="+rtrLSP) + require.Containsf(t, lspOpts, "arp_proxy=169.254.169.254", + "subnet router LSP %s must set options:arp_proxy=169.254.169.254 so the subnet LRP "+ + "answers ARP for IMDS link-local (static-IP and NetworkManager/RHEL/Ubuntu guests)", rtrLSP) + + // --- IMDSv2 token issuance ---------------------------------------------- + harness.Step(t, "PUT /latest/api/token (IMDSv2)") + tokenX := imdsAwaitToken(t, fix, tgtX, vpcX, privX) + harness.Detail(t, "token_len", len(tokenX)) + + // --- v2-only stance: tokenless + garbage-token GET → 401 ----------------- + harness.Step(t, "tokenless GET /latest/meta-data/instance-id → 401") + require.Equal(t, "401", imdsCode(tgtX, "", "/latest/meta-data/instance-id"), + "IMDSv1 (tokenless) GET must be rejected with 401") + harness.Step(t, "garbage-token GET → 401") + require.Equal(t, "401", + imdsCode(tgtX, `-H "X-aws-ec2-metadata-token: not-a-real-token"`, "/latest/meta-data/instance-id"), + "unknown token must be rejected with 401 (no token-exists leak)") + + // --- Metadata surface ---------------------------------------------------- + harness.Step(t, "GET metadata surface") + require.Equal(t, idX, imdsGet(t, tgtX, tokenX, "/latest/meta-data/instance-id"), + "instance-id mismatch") + require.Equal(t, privX, imdsGet(t, tgtX, tokenX, "/latest/meta-data/local-ipv4"), + "local-ipv4 must equal the request source IP") + require.NotEmpty(t, imdsGet(t, tgtX, tokenX, "/latest/meta-data/instance-type"), + "instance-type must be populated") + require.NotEmpty(t, imdsGet(t, tgtX, tokenX, "/latest/meta-data/mac"), + "mac must be populated") + require.NotEmpty(t, imdsGet(t, tgtX, tokenX, "/latest/meta-data/placement/availability-zone"), + "placement/availability-zone must be populated") + + // iam/info → InstanceProfileArn ends with the bound profile. + iamInfo := imdsGet(t, tgtX, tokenX, "/latest/meta-data/iam/info") + require.Containsf(t, iamInfo, ":instance-profile/"+imdsProfileName, + "iam/info must carry the bound InstanceProfileArn (got %q)", iamInfo) + // security-credentials/ lists the role name (not the profile name). + require.Equal(t, imdsRoleName, imdsGet(t, tgtX, tokenX, "/latest/meta-data/iam/security-credentials/"), + "security-credentials/ must list the resolved role name") + + // --- user-data round-trip ------------------------------------------------ + harness.Step(t, "GET /latest/user-data round-trips launch user-data") + require.Contains(t, imdsGet(t, tgtX, tokenX, "/latest/user-data"), imdsUDMarker, + "user-data must round-trip the launch user-data") + + // --- Instance-role credentials + wire round-trip ------------------------- + harness.Step(t, "GET security-credentials/%s → ASIA creds", imdsRoleName) + credBody := imdsGet(t, tgtX, tokenX, "/latest/meta-data/iam/security-credentials/"+imdsRoleName) + var cred imdsCredDoc + require.NoError(t, json.Unmarshal([]byte(credBody), &cred), + "credential body must be valid JSON: %s", credBody) + require.Equal(t, "Success", cred.Code, "credential Code must be Success (body=%s)", credBody) + require.True(t, strings.HasPrefix(cred.AccessKeyId, "ASIA"), + "instance-role AKID must start with ASIA, got %q", cred.AccessKeyId) + require.NotEmpty(t, cred.SecretAccessKey, "empty SecretAccessKey") + require.NotEmpty(t, cred.Token, "empty session Token") + require.Equal(t, adminAccount, cred.AccountId, "credential AccountId mismatch") + harness.Detail(t, "cred_akid", cred.AccessKeyId) + + // Prove the minted creds verify on the gateway and resolve to the instance- + // bound assumed-role identity. The session name is the instance ID, so the + // ARN is .../assumed-role//. + harness.Step(t, "get-caller-identity with the IMDS-minted creds (ASIA path)") + sessionCli := harness.NewAWSClientWithSessionCreds(t, fix.Env, + cred.AccessKeyId, cred.SecretAccessKey, cred.Token) + who, err := sessionCli.STS.GetCallerIdentity(&sts.GetCallerIdentityInput{}) + require.NoError(t, err, "get-caller-identity with instance-role creds") + expectedARN := "arn:aws:sts::" + adminAccount + ":assumed-role/" + imdsRoleName + "/" + idX + require.Equal(t, expectedARN, aws.StringValue(who.Arn), + "IMDS-minted creds must resolve to the instance assumed-role ARN") + + // --- Cross-VPC isolation ------------------------------------------------- + // VM X and VM Y query 169.254.169.254 from the IDENTICAL source IP, in + // different VPCs. Each must get its own instance-id; a leak here means the + // per-VPC SO_BINDTODEVICE veth / (VPC-ID, source-IP) → ENI mapping is broken. + harness.Step(t, "cross-VPC isolation: shared IP %s, distinct identities", privX) + tokenY := imdsAwaitToken(t, fix, tgtY, vpcY, privY) + gotY := imdsGet(t, tgtY, tokenY, "/latest/meta-data/instance-id") + require.Equalf(t, idY, gotY, "VM Y IMDS must return VM Y's instance-id (got %q)", gotY) + require.NotEqualf(t, idX, gotY, + "cross-VPC leak: VM Y (source IP %s) resolved to VM X — the "+ + "(VPC-ID, source-IP) → ENI boundary is broken", privX) + // And VM X still resolves to itself (not Y) after Y came up on the same IP. + require.Equal(t, idX, imdsGet(t, tgtX, tokenX, "/latest/meta-data/instance-id"), + "VM X IMDS must still return VM X's instance-id") + harness.Detail(t, "isolation", "ok") +} + +// imdsVMSpec parameterises a launch for the IMDS suite. profileName / userData +// are optional. +type imdsVMSpec struct { + subnetID string + sgID string + profileName string + userData string +} + +// imdsProbe launches a VM per spec, waits for it to run + become SSH-reachable, +// and returns (instanceID, privateIP, sshTarget). Registers terminate cleanup +// so the VM is torn down before its VPC/subnet are deleted (LIFO). +func imdsProbe(t *testing.T, fix *Fixture, keyPath string, spec imdsVMSpec) (string, string, harness.SSHTarget) { + t.Helper() + id := imdsRunVM(t, fix, spec) + t.Cleanup(func() { + _, _ = fix.AWS.EC2.TerminateInstances(&ec2.TerminateInstancesInput{ + InstanceIds: []*string{aws.String(id)}, + }) + _ = waitForInstanceStateSoft(fix.AWS, id, "terminated", 5*time.Minute) + }) + + inst := harness.WaitForInstanceState(t, fix.AWS, id, "running") + priv := aws.StringValue(inst.PrivateIpAddress) + require.NotEmptyf(t, priv, "instance %s has no PrivateIpAddress", id) + + host, port := harness.InstancePublicSSHHost(t, inst) + harness.Step(t, "wait for %s SSH at %s:%d", id, host, port) + waitForSSHHandshake(t, host, port, keyPath) + return id, priv, harness.SSHTarget{User: "ec2-user", Host: host, Port: port, KeyPath: keyPath} +} + +// imdsRunVM launches a single instance per spec and returns its ID. AMI / type / +// key come from the suite discovery helpers. +func imdsRunVM(t *testing.T, fix *Fixture, spec imdsVMSpec) string { + t.Helper() + amiID := needAMI(t, fix) + instType, _ := needInstanceTypeArch(t, fix) + keyName, _ := needKeyPair(t, fix) + + in := &ec2.RunInstancesInput{ + ImageId: aws.String(amiID), + InstanceType: aws.String(instType), + KeyName: aws.String(keyName), + SubnetId: aws.String(spec.subnetID), + SecurityGroupIds: []*string{aws.String(spec.sgID)}, + MinCount: aws.Int64(1), + MaxCount: aws.Int64(1), + } + if spec.profileName != "" { + in.IamInstanceProfile = &ec2.IamInstanceProfileSpecification{Name: aws.String(spec.profileName)} + } + if spec.userData != "" { + in.UserData = aws.String(base64.StdEncoding.EncodeToString([]byte(spec.userData))) + } + out, err := fix.AWS.EC2.RunInstances(in) + require.NoError(t, err, "run-instances subnet=%s", spec.subnetID) + require.NotEmpty(t, out.Instances, "run-instances returned no Instances") + id := aws.StringValue(out.Instances[0].InstanceId) + require.True(t, strings.HasPrefix(id, "i-"), "unexpected InstanceId %q", id) + return id +} + +// imdsEnsureProbeVPC creates a VPC + subnet wired for SSH reachability and +// returns (vpcID, subnetID, sgID). In pool mode it adds the public-IP path +// (MapPublicIpOnLaunch + IGW + 0.0.0.0/0 route) so the runner reaches the guest +// by public IP; in dev_networking mode SSH lands via the per-VM qemu hostfwd, so +// the IGW plumbing is skipped. All resources are torn down LIFO via t.Cleanup. +func imdsEnsureProbeVPC(t *testing.T, fix *Fixture, vpcCIDR, subnetCIDR string) (string, string, string) { + t.Helper() + c := fix.AWS + + vpcOut, err := c.EC2.CreateVpc(&ec2.CreateVpcInput{CidrBlock: aws.String(vpcCIDR)}) + require.NoError(t, err, "create-vpc %s", vpcCIDR) + vpcID := aws.StringValue(vpcOut.Vpc.VpcId) + require.NotEmpty(t, vpcID, "VpcId empty") + t.Cleanup(func() { _, _ = c.EC2.DeleteVpc(&ec2.DeleteVpcInput{VpcId: aws.String(vpcID)}) }) + + subOut, err := c.EC2.CreateSubnet(&ec2.CreateSubnetInput{ + VpcId: aws.String(vpcID), + CidrBlock: aws.String(subnetCIDR), + }) + require.NoError(t, err, "create-subnet %s", subnetCIDR) + subnetID := aws.StringValue(subOut.Subnet.SubnetId) + require.NotEmpty(t, subnetID, "SubnetId empty") + t.Cleanup(func() { _, _ = c.EC2.DeleteSubnet(&ec2.DeleteSubnetInput{SubnetId: aws.String(subnetID)}) }) + + if fix.PoolMode { + imdsAttachInternet(t, c, vpcID, subnetID) + } + + sgID := imdsDefaultSG(t, c, vpcID) + harness.AuthorizeSSHIngress(t, c, sgID) + harness.Detail(t, "probe_vpc", vpcID, "subnet", subnetID, "sg", sgID) + return vpcID, subnetID, sgID +} + +// imdsAttachInternet gives subnetID a public-IP egress path (pool mode only): +// MapPublicIpOnLaunch + a fresh IGW + a 0.0.0.0/0 route table. Cleanups unwind +// LIFO before the subnet/VPC are deleted by the caller's earlier-registered +// cleanups. +func imdsAttachInternet(t *testing.T, c *harness.AWSClient, vpcID, subnetID string) { + t.Helper() + _, err := c.EC2.ModifySubnetAttribute(&ec2.ModifySubnetAttributeInput{ + SubnetId: aws.String(subnetID), + MapPublicIpOnLaunch: &ec2.AttributeBooleanValue{Value: aws.Bool(true)}, + }) + require.NoError(t, err, "modify-subnet-attribute MapPublicIpOnLaunch") + + igwOut, err := c.EC2.CreateInternetGateway(&ec2.CreateInternetGatewayInput{}) + require.NoError(t, err, "create-internet-gateway") + igwID := aws.StringValue(igwOut.InternetGateway.InternetGatewayId) + require.NotEmpty(t, igwID, "InternetGatewayId empty") + t.Cleanup(func() { + _, _ = c.EC2.DetachInternetGateway(&ec2.DetachInternetGatewayInput{ + InternetGatewayId: aws.String(igwID), VpcId: aws.String(vpcID), + }) + _, _ = c.EC2.DeleteInternetGateway(&ec2.DeleteInternetGatewayInput{InternetGatewayId: aws.String(igwID)}) + }) + _, err = c.EC2.AttachInternetGateway(&ec2.AttachInternetGatewayInput{ + InternetGatewayId: aws.String(igwID), VpcId: aws.String(vpcID), + }) + require.NoError(t, err, "attach-internet-gateway") + + rtOut, err := c.EC2.CreateRouteTable(&ec2.CreateRouteTableInput{VpcId: aws.String(vpcID)}) + require.NoError(t, err, "create-route-table") + rtbID := aws.StringValue(rtOut.RouteTable.RouteTableId) + require.NotEmpty(t, rtbID, "RouteTableId empty") + t.Cleanup(func() { _, _ = c.EC2.DeleteRouteTable(&ec2.DeleteRouteTableInput{RouteTableId: aws.String(rtbID)}) }) + + assocOut, err := c.EC2.AssociateRouteTable(&ec2.AssociateRouteTableInput{ + RouteTableId: aws.String(rtbID), SubnetId: aws.String(subnetID), + }) + require.NoError(t, err, "associate-route-table") + assocID := aws.StringValue(assocOut.AssociationId) + t.Cleanup(func() { + _, _ = c.EC2.DisassociateRouteTable(&ec2.DisassociateRouteTableInput{AssociationId: aws.String(assocID)}) + }) + + _, err = c.EC2.CreateRoute(&ec2.CreateRouteInput{ + RouteTableId: aws.String(rtbID), + DestinationCidrBlock: aws.String("0.0.0.0/0"), + GatewayId: aws.String(igwID), + }) + require.NoError(t, err, "create-route 0.0.0.0/0 -> IGW") +} + +// imdsEnsureRoleProfile creates the EC2-trusted role + instance profile the +// IMDS credential path resolves, attaching AdministratorAccess so the minted +// session creds round-trip a real call. Registers fixture-teardown cleanup and +// sweeps any residue from a prior run first. +func imdsEnsureRoleProfile(t *testing.T, fix *Fixture, adminAccount string) { + t.Helper() + adminPolicyARN := iamPolicyARN(adminAccount, iamPolicyAdministrator) + iamDeleteRoleAndProfilesBestEffort(fix, imdsRoleName, []string{imdsProfileName}, adminPolicyARN) + fix.Harness.RegisterCleanup(func() { + iamDeleteRoleAndProfilesBestEffort(fix, imdsRoleName, []string{imdsProfileName}, adminPolicyARN) + }) + + harness.Step(t, "create-role %q (trust=ec2.amazonaws.com) + profile %q", imdsRoleName, imdsProfileName) + _, err := fix.AWS.IAM.CreateRole(&iam.CreateRoleInput{ + RoleName: aws.String(imdsRoleName), + AssumeRolePolicyDocument: aws.String(iamTrustPolicyEC2Standard), + Description: aws.String("E2E IMDS instance-role credentials"), + }) + require.NoError(t, err, "create-role") + + _, err = fix.AWS.IAM.AttachRolePolicy(&iam.AttachRolePolicyInput{ + RoleName: aws.String(imdsRoleName), + PolicyArn: aws.String(adminPolicyARN), + }) + require.NoError(t, err, "attach AdministratorAccess to role") + + _, err = fix.AWS.IAM.CreateInstanceProfile(&iam.CreateInstanceProfileInput{ + InstanceProfileName: aws.String(imdsProfileName), + }) + require.NoError(t, err, "create-instance-profile") + _, err = fix.AWS.IAM.AddRoleToInstanceProfile(&iam.AddRoleToInstanceProfileInput{ + InstanceProfileName: aws.String(imdsProfileName), + RoleName: aws.String(imdsRoleName), + }) + require.NoError(t, err, "add-role-to-instance-profile") +} + +// imdsAwaitToken PUTs an IMDSv2 token from inside the guest, retrying to ride +// out the cold-start window before BindManager.Sync + the ENI reverse-index +// land. Returns the token. On timeout it dumps the per-VPC IMDS datapath +// (OVN realisation + host veth route/neigh + conntrack) before failing, so a +// reachability timeout (exit 28) is triaged as request-path vs reply-path +// rather than a bare "condition not met". +func imdsAwaitToken(t *testing.T, fix *Fixture, tgt harness.SSHTarget, vpcID, guestIP string) string { + t.Helper() + deadline := time.Now().Add(90 * time.Second) + var lastErr error + for { + cmd := fmt.Sprintf( + `curl -sf -X PUT "%s/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 120"`, metaURL) + out, err := runSSHCombined(tgt, cmd) + switch { + case err != nil: + lastErr = fmt.Errorf("token PUT failed: %w (out=%q)", err, out) + case strings.TrimSpace(out) == "": + lastErr = fmt.Errorf("token PUT returned empty body") + default: + return strings.TrimSpace(out) + } + if time.Now().After(deadline) { + harness.DumpIMDSDatapathDiagnostics(t, vpcID, guestIP, fix.ArtifactDir(t)) + t.Fatalf("imdsAwaitToken: token never minted within 90s (vpc=%s guest=%s): %v "+ + "(see IMDS datapath diagnostics above)", vpcID, guestIP, lastErr) + } + time.Sleep(3 * time.Second) + } +} + +// imdsGet fetches a token-gated path from inside the guest and returns the +// trimmed body. -sf turns any HTTP >= 400 into a non-zero exit, so a 4xx/5xx +// fails the test loudly with the server status visible via runSSH's stderr. +func imdsGet(t *testing.T, tgt harness.SSHTarget, token, path string) string { + t.Helper() + cmd := fmt.Sprintf(`curl -sf -H "X-aws-ec2-metadata-token: %s" %s%s`, token, metaURL, path) + return strings.TrimSpace(runSSH(t, tgt, cmd)) +} + +// imdsCode returns the HTTP status code (as a string) the guest sees for a GET, +// without failing on non-2xx. headerArg is an optional pre-formatted curl -H +// argument (empty for the tokenless probe). +func imdsCode(tgt harness.SSHTarget, headerArg, path string) string { + cmd := fmt.Sprintf(`curl -s -o /dev/null -w '%%{http_code}' %s %s%s`, headerArg, metaURL, path) + out, _ := runSSHCombined(tgt, cmd) + return strings.TrimSpace(out) +} + +// imdsDefaultSG returns the auto-created default security group ID for a VPC. +func imdsDefaultSG(t *testing.T, c *harness.AWSClient, vpcID string) string { + t.Helper() + out, err := c.EC2.DescribeSecurityGroups(&ec2.DescribeSecurityGroupsInput{ + Filters: []*ec2.Filter{ + {Name: aws.String("vpc-id"), Values: []*string{aws.String(vpcID)}}, + {Name: aws.String("group-name"), Values: []*string{aws.String("default")}}, + }, + }) + require.NoError(t, err, "describe-security-groups default (vpc=%s)", vpcID) + require.NotEmpty(t, out.SecurityGroups, "no default SG for vpc=%s", vpcID) + id := aws.StringValue(out.SecurityGroups[0].GroupId) + require.NotEmpty(t, id, "default SG GroupId empty (vpc=%s)", vpcID) + return id +} diff --git a/tests/e2e/single/main_test.go b/tests/e2e/single/main_test.go index 15e7eaea8..c9e5c129f 100644 --- a/tests/e2e/single/main_test.go +++ b/tests/e2e/single/main_test.go @@ -72,11 +72,10 @@ func requireSingleNodeFixture(t *testing.T) *Fixture { return } fix := &Fixture{ - Env: env, - AWS: awsCli, - Harness: h, - Artifacts: harness.ArtifactDir(t, env), - TmpDir: tmpDir, + Env: env, + AWS: awsCli, + Harness: h, + TmpDir: tmpDir, } fix.PoolMode = detectPoolMode(env) // admin init leaves the default SG closed (AWS parity); the e2e suite @@ -100,12 +99,21 @@ func requireSingleNodeFixture(t *testing.T) *Fixture { // memoized on Harness (harness.Fixture) and surfaced via the package-local // need* helpers / harness.Ensure* + harness.Discover*. type Fixture struct { - Env *harness.Env - AWS *harness.AWSClient - Harness *harness.Fixture // memoized Ensure* fixture; spans the whole process. - Artifacts string - TmpDir string // package-scoped scratch dir; survives every Test* in the package. - PoolMode bool // gates 8b / 8d + Env *harness.Env + AWS *harness.AWSClient + Harness *harness.Fixture // memoized Ensure* fixture; spans the whole process. + TmpDir string // package-scoped scratch dir; survives every Test* in the package. + PoolMode bool // gates 8b / 8d +} + +// ArtifactDir returns the artifact directory for the *currently running* test. +// It must be derived per-call from the live t (not memoized on the singleton +// Fixture): the process fixture is built lazily during whichever test runs +// first, so a stored dir would freeze to that test's name and every later test +// would write into a stale — and, once that test passes, pruned — directory. +func (f *Fixture) ArtifactDir(t *testing.T) string { + t.Helper() + return harness.ArtifactDir(t, f.Env) } // detectPoolMode reads external_mode from spinifex.toml. Defaults to false diff --git a/tests/e2e/single/tests_test.go b/tests/e2e/single/tests_test.go index 21877bb46..4141ac9cf 100644 --- a/tests/e2e/single/tests_test.go +++ b/tests/e2e/single/tests_test.go @@ -225,6 +225,16 @@ func TestSTSAssumeRoleAndGetCallerIdentity(t *testing.T) { runSTS(t, requireSingleNodeFixture(t)) } +// TestIMDS exercises the host-served IMDSv2 surface end-to-end: token +// issuance, the v2-only stance, the metadata surface, the +// instance-role credential path + wire round-trip, DHCP option 121, the +// per-VPC localport datapath, and cross-VPC source-IP isolation. Owns its own +// role/profile + a second VPC, but sequential: it launches profile-bound VMs +// and a fresh VPC, so it must not race the singleton-mutation tests above. +func TestIMDS(t *testing.T) { + runIMDS(t, requireSingleNodeFixture(t)) +} + // TestFinalClusterStats runs as the last sequential test (parallel bucket // runs afterwards, but those Tests are read-only / own-everything so a // later cluster-stats snapshot would still be valid). diff --git a/tests/e2e/single/vpc_test.go b/tests/e2e/single/vpc_test.go index df685d5e9..8a9752d68 100644 --- a/tests/e2e/single/vpc_test.go +++ b/tests/e2e/single/vpc_test.go @@ -254,7 +254,7 @@ func runVPCSubnetE2E(t *testing.T, fix *Fixture) { harness.VPCDiagnosticsOpts{ ExternalIP: pubIP, LogicalIP: privIP, - ArtifactDir: fix.Artifacts, + ArtifactDir: fix.ArtifactDir(t), }) t.Fatalf("SSH handshake %s:22 never completed within 3min (see diagnostics above; tracking mulga-siv-111)", pubIP) } From 216b9c7682a6f7810171f47396ee1840ebfc4a0f Mon Sep 17 00:00:00 2001 From: Josh Siviour Date: Thu, 4 Jun 2026 14:19:30 +1000 Subject: [PATCH 14/73] =?UTF-8?q?feat(ui):=20HTTPS=20listeners=20=E2=80=94?= =?UTF-8?q?=20ACM=20certificate=20+=20SSL=20policy=20(Phase=20C)=20(#290)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(ui): HTTPS listeners with ACM certificate + SSL policy Expose HTTPS in the load balancer listener UI. The ListenerForm gains a HTTPS protocol option that reveals a certificate selector (backed by a new ACM ListCertificates query), an inline certificate import dialog (ImportCertificate), and an SSL security-policy selector (DescribeSSLPolicies). CreateListener/ModifyListener now carry Certificates + SslPolicy for HTTPS; the listeners table summarises the policy and certificate per HTTPS listener. Adds an ACM client (getAcmClient) and @aws-sdk/client-acm. Server, gateway and ACM endpoints already exist (epic phases A + B); this is frontend-only. * fix: ACM JSON timestamps, react-compiler watch reactivity, scroll-chaining - gateway/acm: serialise responses with jsonutil.BuildJSON so time.Time fields emit epoch seconds (AWS JSON 1.1 wire format). encoding/json emitted RFC3339 strings the JS SDK rejected with 'Expected real number', crashing the LB detail Listeners tab once any cert exists. - frontend: replace watch() with useWatch across forms so the React Compiler tracks the subscription and re-renders on field change (HTTPS listener cert/policy fields now reveal). Add toggle regression test for listener-form. - frontend: scope overscroll-none to html,body instead of *, restoring wheel scroll-chaining over nested scroll containers (sidebar, tables, dialogs). --- spinifex/gateway/acm/handler.go | 9 +- .../spinifexui/frontend/dist/assets/_.js | 2 +- .../spinifexui/frontend/dist/assets/_auth.js | 2 +- .../frontend/dist/assets/_bucket.js | 2 +- .../spinifexui/frontend/dist/assets/_id.js | 2 +- .../spinifexui/frontend/dist/assets/_id10.js | 2 +- .../spinifexui/frontend/dist/assets/_id11.js | 2 +- .../spinifexui/frontend/dist/assets/_id12.js | 2 +- .../spinifexui/frontend/dist/assets/_id2.js | 2 +- .../spinifexui/frontend/dist/assets/_id3.js | 2 +- .../spinifexui/frontend/dist/assets/_id4.js | 2 +- .../spinifexui/frontend/dist/assets/_id5.js | 2 +- .../spinifexui/frontend/dist/assets/_id6.js | 2 +- .../spinifexui/frontend/dist/assets/_id7.js | 2 +- .../spinifexui/frontend/dist/assets/_id8.js | 2 +- .../spinifexui/frontend/dist/assets/_id9.js | 2 +- .../frontend/dist/assets/_policyArn.js | 2 +- .../frontend/dist/assets/_userName.js | 2 +- .../spinifexui/frontend/dist/assets/admin.js | 2 +- .../frontend/dist/assets/alert-dialog.js | 2 +- .../frontend/dist/assets/ami-details.js | 2 +- .../frontend/dist/assets/back-link.js | 2 +- .../spinifexui/frontend/dist/assets/badge.js | 2 +- .../spinifexui/frontend/dist/assets/card.js | 2 +- .../spinifexui/frontend/dist/assets/check.js | 2 +- .../frontend/dist/assets/chevron-down.js | 2 +- .../frontend/dist/assets/chevron-right.js | 2 +- .../frontend/dist/assets/cli-command-panel.js | 4 +- .../frontend/dist/assets/collapsible.js | 2 +- .../spinifexui/frontend/dist/assets/copy.js | 2 +- .../frontend/dist/assets/create-bucket.js | 2 +- .../frontend/dist/assets/create-key-pair.js | 2 +- .../dist/assets/create-load-balancer.js | 4 +- .../dist/assets/create-placement-group.js | 6 +- .../frontend/dist/assets/create-policy.js | 4 +- .../dist/assets/create-security-group.js | 4 +- .../frontend/dist/assets/create-snapshot.js | 4 +- .../frontend/dist/assets/create-subnet.js | 4 +- .../dist/assets/create-target-group.js | 2 +- .../frontend/dist/assets/create-user.js | 2 +- .../frontend/dist/assets/create-volume.js | 2 +- .../frontend/dist/assets/create-vpc.js | 2 +- .../dist/assets/delete-confirmation-dialog.js | 2 +- .../frontend/dist/assets/describe-images.js | 2 +- .../dist/assets/describe-instances.js | 2 +- .../dist/assets/describe-key-pairs.js | 2 +- .../dist/assets/describe-load-balancers.js | 2 +- .../dist/assets/describe-placement-groups.js | 2 +- .../dist/assets/describe-security-groups.js | 2 +- .../dist/assets/describe-snapshots.js | 2 +- .../frontend/dist/assets/describe-subnets.js | 2 +- .../dist/assets/describe-target-groups.js | 2 +- .../frontend/dist/assets/describe-volumes.js | 2 +- .../frontend/dist/assets/describe-vpcs.js | 2 +- .../frontend/dist/assets/detail-row.js | 2 +- .../frontend/dist/assets/download.js | 2 +- .../spinifexui/frontend/dist/assets/ec2.js | 2 +- .../spinifexui/frontend/dist/assets/ec22.js | 2 +- .../spinifexui/frontend/dist/assets/elbv2.js | 2 +- .../spinifexui/frontend/dist/assets/elbv22.js | 2 +- .../frontend/dist/assets/error-banner.js | 2 +- .../frontend/dist/assets/event-streams.js | 2 +- .../spinifexui/frontend/dist/assets/field.js | 2 +- .../frontend/dist/assets/form-actions.js | 2 +- .../spinifexui/frontend/dist/assets/iam.js | 2 +- .../spinifexui/frontend/dist/assets/iam2.js | 2 +- .../frontend/dist/assets/import-key-pair.js | 4 +- .../frontend/dist/assets/index.browser.js | 1 + .../spinifexui/frontend/dist/assets/index.css | 2 +- .../spinifexui/frontend/dist/assets/index.js | 49 +-- .../frontend/dist/assets/list-card.js | 2 +- .../frontend/dist/assets/list-policies.js | 2 +- .../frontend/dist/assets/list-users.js | 2 +- .../spinifexui/frontend/dist/assets/login.js | 2 +- .../spinifexui/frontend/dist/assets/ls.js | 2 +- .../spinifexui/frontend/dist/assets/nodes.js | 2 +- .../frontend/dist/assets/page-heading.js | 2 +- .../spinifexui/frontend/dist/assets/plus.js | 2 +- .../spinifexui/frontend/dist/assets/route.js | 2 +- .../spinifexui/frontend/dist/assets/route2.js | 2 +- .../frontend/dist/assets/run-instances.js | 4 +- .../spinifexui/frontend/dist/assets/s3.js | 4 +- .../spinifexui/frontend/dist/assets/select.js | 2 +- .../frontend/dist/assets/service-metrics.js | 2 +- .../frontend/dist/assets/state-badge.js | 2 +- .../spinifexui/frontend/dist/assets/tabs.js | 2 +- .../frontend/dist/assets/target-group-form.js | 2 +- .../frontend/dist/assets/textarea.js | 2 +- .../frontend/dist/assets/trash-2.js | 2 +- .../frontend/dist/assets/triangle-alert.js | 2 +- .../frontend/dist/assets/upload-button.js | 2 +- .../dist/assets/use-copy-to-clipboard.js | 2 +- .../frontend/dist/assets/useBaseQuery.js | 2 +- .../spinifexui/frontend/dist/assets/zod.js | 2 +- .../services/spinifexui/frontend/package.json | 1 + .../spinifexui/frontend/pnpm-lock.yaml | 282 +++++++++++++++++- .../elbv2/certificate-import-dialog.tsx | 151 ++++++++++ .../components/elbv2/listener-form.test.tsx | 112 ++++++- .../src/components/elbv2/listener-form.tsx | 160 +++++++++- .../components/elbv2/listeners-tab.test.tsx | 80 +++++ .../src/components/elbv2/listeners-tab.tsx | 82 ++++- .../components/elbv2/target-group-form.tsx | 5 +- .../src/components/vpc-wizard/tag-editor.tsx | 3 +- .../spinifexui/frontend/src/lib/awsClient.ts | 32 ++ .../spinifexui/frontend/src/mutations/acm.ts | 35 +++ .../frontend/src/mutations/elbv2.ts | 37 ++- .../spinifexui/frontend/src/queries/acm.ts | 12 + .../spinifexui/frontend/src/queries/elbv2.ts | 12 + .../_auth/ec2/(key)/create-key-pair.tsx | 10 +- .../_auth/ec2/(key)/import-key-pair.tsx | 10 +- .../create-placement-group.tsx | 11 +- .../create-security-group.tsx | 11 +- .../_auth/ec2/(snapshots)/create-snapshot.tsx | 9 +- .../_auth/ec2/(subnet)/create-subnet.tsx | 9 +- .../_auth/iam/(policies)/create-policy.tsx | 10 +- .../routes/_auth/iam/(users)/create-user.tsx | 10 +- .../_auth/s3/(buckets)/create-bucket.tsx | 10 +- .../spinifexui/frontend/src/styles.css | 11 +- .../spinifexui/frontend/src/types/elbv2.ts | 26 +- 119 files changed, 1205 insertions(+), 189 deletions(-) create mode 100644 spinifex/services/spinifexui/frontend/dist/assets/index.browser.js create mode 100644 spinifex/services/spinifexui/frontend/src/components/elbv2/certificate-import-dialog.tsx create mode 100644 spinifex/services/spinifexui/frontend/src/mutations/acm.ts create mode 100644 spinifex/services/spinifexui/frontend/src/queries/acm.ts diff --git a/spinifex/gateway/acm/handler.go b/spinifex/gateway/acm/handler.go index aa4bf6014..df02430c0 100644 --- a/spinifex/gateway/acm/handler.go +++ b/spinifex/gateway/acm/handler.go @@ -9,15 +9,20 @@ import ( "log/slog" "net/http" + "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil" "github.com/mulgadc/spinifex/spinifex/awserrors" ) // JSONContentType is the AWS JSON 1.1 content type ACM clients expect. const JSONContentType = "application/x-amz-json-1.1" -// WriteJSONResponse serialises obj as a 200 AWS JSON 1.1 response. +// WriteJSONResponse serialises obj as a 200 AWS JSON 1.1 response. obj is an +// aws-sdk-go *Output struct whose time.Time fields must serialise as epoch +// seconds (the AWS JSON 1.1 timestamp wire format); encoding/json would emit +// RFC3339 strings the AWS SDKs reject with "Expected real number". jsonutil +// is the marshaler the SDK itself uses for this protocol. func WriteJSONResponse(w http.ResponseWriter, obj any) { - body, err := json.Marshal(obj) + body, err := jsonutil.BuildJSON(obj) if err != nil { slog.Error("ACM: failed to marshal response JSON", "err", err) http.Error(w, awserrors.ErrorInternalError, http.StatusInternalServerError) diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_.js b/spinifex/services/spinifexui/frontend/dist/assets/_.js index 67785de33..d58a5f13e 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{n as r,r as i,t as a}from"./upload-button.js";import{r as o}from"./s3.js";import{Aa as s,Da as c,F as l,Fa as u,h as d,ka as f,lo as p,mo as m,so as h}from"./index.js";var g=h(),_=m();function v(){let m=(0,g.c)(24),{bucket:h,_splat:v}=d.useParams(),y=f(v??``),{data:b}=t(l(h,y)),x=o(),S;m[0]===b.Contents?S=m[1]:(S=b.Contents??[],m[0]=b.Contents,m[1]=S);let C=S,w;m[2]===b.CommonPrefixes?w=m[3]:(w=b.CommonPrefixes??[],m[2]=b.CommonPrefixes,m[3]=w);let T=w,E=y.split(`/`).filter(Boolean),D=[{name:h,path:`/s3/ls/${h}`},...E.map((e,t)=>({name:e,path:`/s3/ls/${h}/${`${E.slice(0,t+1).join(`/`)}/`}`}))],O=E.length>1?`/s3/ls/${h}/${E.slice(0,-1).join(`/`)}/`:`/s3/ls/${h}`,k;m[4]===O?k=m[5]:(k=(0,_.jsx)(n,{to:O,children:`Back`}),m[4]=O,m[5]=k);let A;m[6]!==h||m[7]!==y||m[8]!==x.isPending||m[9]!==x.mutateAsync?(A=(0,_.jsx)(a,{bucket:h,isPending:x.isPending,onUpload:x.mutateAsync,prefix:y}),m[6]=h,m[7]=y,m[8]=x.isPending,m[9]=x.mutateAsync,m[10]=A):A=m[10];let j;m[11]===x.error?j=m[12]:(j=x.error&&(0,_.jsx)(e,{error:x.error,msg:`Failed to upload object`}),m[11]=x.error,m[12]=j);let M;m[13]!==h||m[14]!==T||m[15]!==y?(M=T.length>0&&(0,_.jsxs)(`div`,{className:`mb-6`,children:[(0,_.jsx)(`h2`,{className:`mb-3 text-lg font-semibold`,children:`Folders`}),(0,_.jsx)(`div`,{className:`space-y-2`,children:T.map(e=>e.Prefix?(0,_.jsx)(i,{bucketName:h,folderName:u(s(e.Prefix,y)),fullPrefix:c(e.Prefix,y)},e.Prefix):null)})]}),m[13]=h,m[14]=T,m[15]=y,m[16]=M):M=m[16];let N;m[17]!==h||m[18]!==C||m[19]!==y?(N=C.length>0&&(0,_.jsxs)(`div`,{className:`space-y-2`,children:[(0,_.jsx)(`h2`,{className:`mb-3 text-lg font-semibold`,children:`Objects`}),C.map(e=>e.Key?(0,_.jsx)(r,{bucketName:h,displayName:s(e.Key,y),fullKey:c(e.Key,y),object:e},e.Key):null)]}),m[17]=h,m[18]=C,m[19]=y,m[20]=N):N=m[20];let P;return m[21]!==T.length||m[22]!==C.length?(P=C.length===0&&T.length===0&&(0,_.jsx)(`p`,{className:`text-muted-foreground`,children:`No objects found in this folder.`}),m[21]=T.length,m[22]=C.length,m[23]=P):P=m[23],(0,_.jsxs)(_.Fragment,{children:[k,(0,_.jsx)(`div`,{className:`mb-6`,children:(0,_.jsxs)(`div`,{className:`mb-2 flex items-center justify-between`,children:[(0,_.jsx)(`div`,{className:`flex items-center gap-2 text-sm text-muted-foreground`,children:D.map((e,t)=>(0,_.jsxs)(`div`,{className:`flex items-center gap-2`,children:[t>0&&(0,_.jsx)(`span`,{children:`/`}),t===D.length-1?(0,_.jsx)(`span`,{className:`text-foreground`,children:e.name}):(0,_.jsx)(p,{className:`hover:text-foreground`,to:e.path,children:e.name})]},e.path))}),A]})}),j,M,N,P]})}export{v as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{n as r,r as i,t as a}from"./upload-button.js";import{r as o}from"./s3.js";import{Co as s,I as c,Oo as l,Ua as u,Va as d,Wa as f,Ya as p,h as m,xo as h}from"./index.js";var g=h(),_=l();function v(){let l=(0,g.c)(24),{bucket:h,_splat:v}=m.useParams(),y=u(v??``),{data:b}=t(c(h,y)),x=o(),S;l[0]===b.Contents?S=l[1]:(S=b.Contents??[],l[0]=b.Contents,l[1]=S);let C=S,w;l[2]===b.CommonPrefixes?w=l[3]:(w=b.CommonPrefixes??[],l[2]=b.CommonPrefixes,l[3]=w);let T=w,E=y.split(`/`).filter(Boolean),D=[{name:h,path:`/s3/ls/${h}`},...E.map((e,t)=>({name:e,path:`/s3/ls/${h}/${`${E.slice(0,t+1).join(`/`)}/`}`}))],O=E.length>1?`/s3/ls/${h}/${E.slice(0,-1).join(`/`)}/`:`/s3/ls/${h}`,k;l[4]===O?k=l[5]:(k=(0,_.jsx)(n,{to:O,children:`Back`}),l[4]=O,l[5]=k);let A;l[6]!==h||l[7]!==y||l[8]!==x.isPending||l[9]!==x.mutateAsync?(A=(0,_.jsx)(a,{bucket:h,isPending:x.isPending,onUpload:x.mutateAsync,prefix:y}),l[6]=h,l[7]=y,l[8]=x.isPending,l[9]=x.mutateAsync,l[10]=A):A=l[10];let j;l[11]===x.error?j=l[12]:(j=x.error&&(0,_.jsx)(e,{error:x.error,msg:`Failed to upload object`}),l[11]=x.error,l[12]=j);let M;l[13]!==h||l[14]!==T||l[15]!==y?(M=T.length>0&&(0,_.jsxs)(`div`,{className:`mb-6`,children:[(0,_.jsx)(`h2`,{className:`mb-3 text-lg font-semibold`,children:`Folders`}),(0,_.jsx)(`div`,{className:`space-y-2`,children:T.map(e=>e.Prefix?(0,_.jsx)(i,{bucketName:h,folderName:p(f(e.Prefix,y)),fullPrefix:d(e.Prefix,y)},e.Prefix):null)})]}),l[13]=h,l[14]=T,l[15]=y,l[16]=M):M=l[16];let N;l[17]!==h||l[18]!==C||l[19]!==y?(N=C.length>0&&(0,_.jsxs)(`div`,{className:`space-y-2`,children:[(0,_.jsx)(`h2`,{className:`mb-3 text-lg font-semibold`,children:`Objects`}),C.map(e=>e.Key?(0,_.jsx)(r,{bucketName:h,displayName:f(e.Key,y),fullKey:d(e.Key,y),object:e},e.Key):null)]}),l[17]=h,l[18]=C,l[19]=y,l[20]=N):N=l[20];let P;return l[21]!==T.length||l[22]!==C.length?(P=C.length===0&&T.length===0&&(0,_.jsx)(`p`,{className:`text-muted-foreground`,children:`No objects found in this folder.`}),l[21]=T.length,l[22]=C.length,l[23]=P):P=l[23],(0,_.jsxs)(_.Fragment,{children:[k,(0,_.jsx)(`div`,{className:`mb-6`,children:(0,_.jsxs)(`div`,{className:`mb-2 flex items-center justify-between`,children:[(0,_.jsx)(`div`,{className:`flex items-center gap-2 text-sm text-muted-foreground`,children:D.map((e,t)=>(0,_.jsxs)(`div`,{className:`flex items-center gap-2`,children:[t>0&&(0,_.jsx)(`span`,{children:`/`}),t===D.length-1?(0,_.jsx)(`span`,{className:`text-foreground`,children:e.name}):(0,_.jsx)(s,{className:`hover:text-foreground`,to:e.path,children:e.name})]},e.path))}),A]})}),j,M,N,P]})}export{v as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_auth.js b/spinifex/services/spinifexui/frontend/dist/assets/_auth.js index 5a0a0d0aa..b7488894b 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_auth.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_auth.js @@ -1 +1 @@ -import{t as e}from"./useQuery.js";import{t}from"./chevron-down.js";import{t as n}from"./chevron-right.js";import{Ga as r,Gn as i,H as a,I as o,Ja as s,Ka as c,Pa as l,Po as u,W as d,Wa as f,Xa as p,Y as m,ho as h,lo as g,mo as _,qa as v,rt as y,so as b,tt as x}from"./index.js";import{t as S}from"./page-heading.js";import{t as C}from"./state-badge.js";import{r as w,t as T}from"./admin.js";import{t as ee}from"./badge.js";import{a as E,i as D,n as O,o as te,r as k,t as A}from"./card.js";var j=p(`box`,[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]),M=p(`folder-open`,[[`path`,{d:`m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2`,key:`usdka0`}]]),ne=p(`lock`,[[`rect`,{width:`18`,height:`11`,x:`3`,y:`11`,rx:`2`,ry:`2`,key:`1w4ew1`}],[`path`,{d:`M7 11V7a5 5 0 0 1 10 0v4`,key:`fwvmzm`}]]),re=p(`monitor`,[[`rect`,{width:`20`,height:`14`,x:`2`,y:`3`,rx:`2`,key:`48i651`}],[`line`,{x1:`8`,x2:`16`,y1:`21`,y2:`21`,key:`1svkeh`}],[`line`,{x1:`12`,x2:`12`,y1:`17`,y2:`21`,key:`vw1qmm`}]]),N=b(),P=u(h(),1),F=_(),ie=[{name:`Air-gap Support`,key:`airgap`},{name:`NVIDIA Bluefield DPU`,key:`bluefield`},{name:`NVIDIA MIG Support`,key:`mig`}];function I(e){let t=Math.floor(e/86400),n=Math.floor(e%86400/3600);if(t>0)return`${t}d ${n}h`;let r=Math.floor(e%3600/60);return n>0?`${n}h ${r}m`:`${r}m`}function L(){let a=(0,N.c)(110),{isAdmin:o,version:s,license:c}=i(),[l,u]=(0,P.useState)(!1),d;a[0]===o?d=a[1]:(d={...T,enabled:o},a[0]=o,a[1]=d);let{data:f}=e(d),p;a[2]===o?p=a[3]:(p={...w,enabled:o},a[2]=o,a[3]=p);let{data:m}=e(p);if(!o||!s)return null;let h,g,_,v,y,b,x,S,C,D,O,j,M,I,L,z,B,V,H;if(a[4]!==c||a[5]!==f?.cluster_mode||a[6]!==f?.nodes||a[7]!==s.arch||a[8]!==s.commit||a[9]!==s.os||a[10]!==s.version||a[11]!==m?.vms){v=f?.nodes??[];let e;a[31]===m?.vms?e=a[32]:(e=m?.vms??[],a[31]=m?.vms,a[32]=e);let t=e,n=f?.cluster_mode??`single-node`;_=c===`open-source`;let i=v[0]?.region??null,o=v.reduce(ce,0),l=v.reduce(se,0),u=v.reduce(oe,0),d=v.reduce(ae,0);O=`mb-6 space-y-4`,S=`grid grid-cols-1 gap-4 md:grid-cols-3`;let p;a[33]===Symbol.for(`react.memo_cache_sentinel`)?(p=(0,F.jsx)(E,{className:`pb-2`,children:(0,F.jsxs)(te,{className:`flex items-center gap-2 text-sm`,children:[(0,F.jsx)(re,{className:`size-3.5`}),`Spinifex Info`]})}),a[33]=p):p=a[33];let w;a[34]===Symbol.for(`react.memo_cache_sentinel`)?(w=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`Version`}),a[34]=w):w=a[34];let T;a[35]===s.version?T=a[36]:(T=(0,F.jsxs)(`div`,{className:`flex justify-between`,children:[w,(0,F.jsx)(`span`,{className:`font-mono`,children:s.version})]}),a[35]=s.version,a[36]=T);let ne;a[37]===Symbol.for(`react.memo_cache_sentinel`)?(ne=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`Commit`}),a[37]=ne):ne=a[37];let N;a[38]===s.commit?N=a[39]:(N=(0,F.jsxs)(`div`,{className:`flex justify-between`,children:[ne,(0,F.jsx)(`span`,{className:`font-mono`,children:s.commit})]}),a[38]=s.commit,a[39]=N);let P;a[40]===Symbol.for(`react.memo_cache_sentinel`)?(P=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`Platform`}),a[40]=P):P=a[40];let ie;a[41]!==s.arch||a[42]!==s.os?(ie=(0,F.jsxs)(`div`,{className:`flex justify-between`,children:[P,(0,F.jsxs)(`span`,{children:[s.os,`/`,s.arch]})]}),a[41]=s.arch,a[42]=s.os,a[43]=ie):ie=a[43],C=(0,F.jsxs)(A,{children:[p,(0,F.jsxs)(k,{className:`space-y-1 text-xs`,children:[T,N,ie,i&&(0,F.jsxs)(`div`,{className:`flex justify-between`,children:[(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`Region`}),(0,F.jsx)(`span`,{children:i})]})]})]});let R;a[44]===Symbol.for(`react.memo_cache_sentinel`)?(R=(0,F.jsx)(E,{className:`pb-2`,children:(0,F.jsx)(te,{className:`text-sm`,children:`License & Support`})}),a[44]=R):R=a[44];let U;a[45]===Symbol.for(`react.memo_cache_sentinel`)?(U=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`License`}),a[45]=U):U=a[45];let W=_?`secondary`:`default`,G=_?`Open Source (AGPLv3)`:`Commercial`,K;a[46]!==W||a[47]!==G?(K=(0,F.jsxs)(`div`,{className:`flex items-center justify-between`,children:[U,(0,F.jsx)(ee,{variant:W,children:G})]}),a[46]=W,a[47]=G,a[48]=K):K=a[48];let q;a[49]===Symbol.for(`react.memo_cache_sentinel`)?(q=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`Support`}),a[49]=q):q=a[49];let J=_?`Community`:`Standard`,Y;a[50]===J?Y=a[51]:(Y=(0,F.jsxs)(`div`,{className:`flex items-center justify-between`,children:[q,(0,F.jsx)(`span`,{children:J})]}),a[50]=J,a[51]=Y);let X;a[52]===_?X=a[53]:(X=_&&(0,F.jsx)(`a`,{href:`https://mulgadc.com/purchase`,target:`_blank`,rel:`noopener noreferrer`,className:`mt-2 block text-xs font-medium text-primary hover:underline`,children:`Upgrade to Commercial →`}),a[52]=_,a[53]=X),a[54]!==K||a[55]!==Y||a[56]!==X?(D=(0,F.jsxs)(A,{children:[R,(0,F.jsxs)(k,{className:`space-y-2 text-xs`,children:[K,Y,X]})]}),a[54]=K,a[55]=Y,a[56]=X,a[57]=D):D=a[57],g=A,a[58]===Symbol.for(`react.memo_cache_sentinel`)?(x=(0,F.jsx)(E,{className:`pb-2`,children:(0,F.jsxs)(te,{className:`flex items-center gap-2 text-sm`,children:[(0,F.jsx)(r,{className:`size-3.5`}),`Cluster Status`]})}),a[58]=x):x=a[58],h=k,B=`space-y-2 text-xs`,a[59]===n?V=a[60]:(V=(0,F.jsx)(`div`,{className:`flex items-center gap-2`,children:(0,F.jsx)(ee,{variant:`outline`,children:n})}),a[59]=n,a[60]=V);let Z;a[61]===Symbol.for(`react.memo_cache_sentinel`)?(Z=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`Nodes`}),a[61]=Z):Z=a[61],H=(0,F.jsxs)(`div`,{className:`flex justify-between`,children:[Z,(0,F.jsx)(`span`,{children:v.length})]});let Q;a[62]===Symbol.for(`react.memo_cache_sentinel`)?(Q=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`Instances`}),a[62]=Q):Q=a[62],a[63]===t.length?y=a[64]:(y=(0,F.jsxs)(`div`,{className:`flex justify-between`,children:[Q,(0,F.jsx)(`span`,{children:t.length})]}),a[63]=t.length,a[64]=y);let $;a[65]===Symbol.for(`react.memo_cache_sentinel`)?($=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`vCPU`}),a[65]=$):$=a[65],b=(0,F.jsxs)(`div`,{className:`flex justify-between`,children:[$,(0,F.jsxs)(`span`,{children:[l,` / `,o]})]}),L=`flex justify-between`,a[66]===Symbol.for(`react.memo_cache_sentinel`)?(z=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`Memory`}),a[66]=z):z=a[66],j=d.toFixed(1),M=` / `,I=u.toFixed(1),a[4]=c,a[5]=f?.cluster_mode,a[6]=f?.nodes,a[7]=s.arch,a[8]=s.commit,a[9]=s.os,a[10]=s.version,a[11]=m?.vms,a[12]=h,a[13]=g,a[14]=_,a[15]=v,a[16]=y,a[17]=b,a[18]=x,a[19]=S,a[20]=C,a[21]=D,a[22]=O,a[23]=j,a[24]=M,a[25]=I,a[26]=L,a[27]=z,a[28]=B,a[29]=V,a[30]=H}else h=a[12],g=a[13],_=a[14],v=a[15],y=a[16],b=a[17],x=a[18],S=a[19],C=a[20],D=a[21],O=a[22],j=a[23],M=a[24],I=a[25],L=a[26],z=a[27],B=a[28],V=a[29],H=a[30];let U;a[67]!==j||a[68]!==M||a[69]!==I?(U=(0,F.jsxs)(`span`,{children:[j,M,I,` GB`]}),a[67]=j,a[68]=M,a[69]=I,a[70]=U):U=a[70];let W;a[71]!==U||a[72]!==L||a[73]!==z?(W=(0,F.jsxs)(`div`,{className:L,children:[z,U]}),a[71]=U,a[72]=L,a[73]=z,a[74]=W):W=a[74];let G;a[75]!==h||a[76]!==y||a[77]!==b||a[78]!==W||a[79]!==B||a[80]!==V||a[81]!==H?(G=(0,F.jsxs)(h,{className:B,children:[V,H,y,b,W]}),a[75]=h,a[76]=y,a[77]=b,a[78]=W,a[79]=B,a[80]=V,a[81]=H,a[82]=G):G=a[82];let K;a[83]!==g||a[84]!==x||a[85]!==G?(K=(0,F.jsxs)(g,{children:[x,G]}),a[83]=g,a[84]=x,a[85]=G,a[86]=K):K=a[86];let q;a[87]!==S||a[88]!==C||a[89]!==D||a[90]!==K?(q=(0,F.jsxs)(`div`,{className:S,children:[C,D,K]}),a[87]=S,a[88]=C,a[89]=D,a[90]=K,a[91]=q):q=a[91];let J;a[92]!==v||a[93]!==l?(J=v.length>0&&(0,F.jsxs)(A,{children:[(0,F.jsx)(E,{className:`pb-0`,children:(0,F.jsxs)(`button`,{type:`button`,className:`flex items-center gap-2 text-sm font-medium`,onClick:()=>u(!l),children:[l?(0,F.jsx)(t,{className:`size-3.5`}):(0,F.jsx)(n,{className:`size-3.5`}),`Nodes (`,v.length,`)`]})}),l&&(0,F.jsx)(k,{className:`pt-2`,children:(0,F.jsx)(R,{nodes:v})})]}),a[92]=v,a[93]=l,a[94]=J):J=a[94];let Y;a[95]===Symbol.for(`react.memo_cache_sentinel`)?(Y=(0,F.jsx)(E,{className:`pb-2`,children:(0,F.jsx)(te,{className:`text-sm`,children:`Commercial Add-ons`})}),a[95]=Y):Y=a[95];let X;a[96]===_?X=a[97]:(X=ie.map(e=>(0,F.jsxs)(`div`,{className:`flex items-center justify-between text-xs`,children:[(0,F.jsx)(`span`,{className:_?`text-muted-foreground`:void 0,children:e.name}),_?(0,F.jsx)(ne,{className:`size-3 text-muted-foreground`}):(0,F.jsx)(ee,{variant:`outline`,className:`text-[0.625rem]`,children:`Active`})]},e.key)),a[96]=_,a[97]=X);let Z;a[98]===X?Z=a[99]:(Z=(0,F.jsx)(`div`,{className:`space-y-2`,children:X}),a[98]=X,a[99]=Z);let Q;a[100]===_?Q=a[101]:(Q=_&&(0,F.jsx)(`a`,{href:`https://mulgadc.com/purchase`,target:`_blank`,rel:`noopener noreferrer`,className:`mt-3 block text-xs font-medium text-primary hover:underline`,children:`Learn more about commercial features →`}),a[100]=_,a[101]=Q);let $;a[102]!==Z||a[103]!==Q?($=(0,F.jsxs)(A,{children:[Y,(0,F.jsxs)(k,{children:[Z,Q]})]}),a[102]=Z,a[103]=Q,a[104]=$):$=a[104];let le;return a[105]!==O||a[106]!==q||a[107]!==J||a[108]!==$?(le=(0,F.jsxs)(`div`,{className:O,children:[q,J,$]}),a[105]=O,a[106]=q,a[107]=J,a[108]=$,a[109]=le):le=a[109],le}function ae(e,t){return e+t.alloc_mem_gb}function oe(e,t){return e+t.total_mem_gb}function se(e,t){return e+t.alloc_vcpu}function ce(e,t){return e+t.total_vcpu}function R(e){let t=(0,N.c)(5),{nodes:n}=e,r;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,F.jsx)(`thead`,{children:(0,F.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,F.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Name`}),(0,F.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Status`}),(0,F.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Roles`}),(0,F.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`IP`}),(0,F.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Region`}),(0,F.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`AZ`}),(0,F.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Uptime`}),(0,F.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`EC2`}),(0,F.jsx)(`th`,{className:`pb-1 font-medium`,children:`Services`})]})}),t[0]=r):r=t[0];let i;t[1]===n?i=t[2]:(i=n.map(z),t[1]=n,t[2]=i);let a;return t[3]===i?a=t[4]:(a=(0,F.jsx)(`div`,{className:`overflow-x-auto`,children:(0,F.jsxs)(`table`,{className:`w-full text-xs`,children:[r,(0,F.jsx)(`tbody`,{children:i})]})}),t[3]=i,t[4]=a),a}function z(e){return(0,F.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,F.jsx)(`td`,{className:`py-1.5 pr-4 font-mono font-medium`,children:e.node}),(0,F.jsx)(`td`,{className:`py-1.5 pr-4`,children:(0,F.jsx)(ee,{variant:e.status===`Ready`?`default`:`secondary`,className:`text-[0.625rem]`,children:e.status})}),(0,F.jsx)(`td`,{className:`py-1.5 pr-4`,children:(0,F.jsxs)(`div`,{className:`flex gap-1`,children:[e.nats_role&&(0,F.jsxs)(`span`,{className:`text-muted-foreground`,children:[`nats:`,e.nats_role]}),e.predastore_role&&(0,F.jsxs)(`span`,{className:`text-muted-foreground`,children:[`ps:`,e.predastore_role]})]})}),(0,F.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.host}),(0,F.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.region}),(0,F.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.az}),(0,F.jsx)(`td`,{className:`py-1.5 pr-4`,children:I(e.uptime)}),(0,F.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.vm_count}),(0,F.jsx)(`td`,{className:`py-1.5`,children:(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:e.services.length})})]},e.node)}var B=5;function V(){let e=(0,N.c)(8),t,n;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(t=(0,F.jsx)(S,{title:`Dashboard`}),n=(0,F.jsx)(L,{}),e[0]=t,e[1]=n):(t=e[0],n=e[1]);let r;e[2]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,F.jsx)(P.Suspense,{fallback:(0,F.jsx)(H,{}),children:(0,F.jsx)(K,{})}),e[2]=r):r=e[2];let i;e[3]===Symbol.for(`react.memo_cache_sentinel`)?(i=(0,F.jsx)(P.Suspense,{fallback:(0,F.jsx)(H,{}),children:(0,F.jsx)($,{})}),e[3]=i):i=e[3];let a;e[4]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,F.jsx)(P.Suspense,{fallback:(0,F.jsx)(H,{}),children:(0,F.jsx)(pe,{})}),e[4]=a):a=e[4];let o;e[5]===Symbol.for(`react.memo_cache_sentinel`)?(o=(0,F.jsx)(P.Suspense,{fallback:(0,F.jsx)(H,{}),children:(0,F.jsx)(he,{})}),e[5]=o):o=e[5];let s;e[6]===Symbol.for(`react.memo_cache_sentinel`)?(s=(0,F.jsx)(P.Suspense,{fallback:(0,F.jsx)(H,{}),children:(0,F.jsx)(_e,{})}),e[6]=s):s=e[6];let c;return e[7]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,F.jsxs)(F.Fragment,{children:[t,n,(0,F.jsxs)(`div`,{className:`grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3`,children:[r,i,a,o,s,(0,F.jsx)(P.Suspense,{fallback:(0,F.jsx)(H,{}),children:(0,F.jsx)(ye,{})})]})]}),e[7]=c):c=e[7],c}function H(){let e=(0,N.c)(2),t;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(t=(0,F.jsx)(E,{children:(0,F.jsx)(`div`,{className:`h-4 w-32 animate-pulse rounded bg-muted`})}),e[0]=t):t=e[0];let n;return e[1]===Symbol.for(`react.memo_cache_sentinel`)?(n=(0,F.jsxs)(A,{children:[t,(0,F.jsx)(k,{children:(0,F.jsxs)(`div`,{className:`space-y-2`,children:[(0,F.jsx)(`div`,{className:`h-3 w-48 animate-pulse rounded bg-muted`}),(0,F.jsx)(`div`,{className:`h-3 w-36 animate-pulse rounded bg-muted`})]})})]}),e[1]=n):n=e[1],n}function U(e){let t=(0,N.c)(16),{title:n,icon:r,count:i,to:a,children:o}=e,s;t[0]!==r||t[1]!==n?(s=(0,F.jsxs)(te,{className:`flex items-center gap-2`,children:[r,n]}),t[0]=r,t[1]=n,t[2]=s):s=t[2];let c;t[3]===i?c=t[4]:(c=(0,F.jsx)(O,{children:(0,F.jsx)(`span`,{className:`rounded-md bg-muted px-2 py-0.5 text-xs font-semibold tabular-nums`,children:i})}),t[3]=i,t[4]=c);let l;t[5]!==s||t[6]!==c?(l=(0,F.jsxs)(E,{children:[s,c]}),t[5]=s,t[6]=c,t[7]=l):l=t[7];let u;t[8]===o?u=t[9]:(u=(0,F.jsx)(k,{children:o}),t[8]=o,t[9]=u);let d;t[10]===a?d=t[11]:(d=(0,F.jsx)(D,{children:(0,F.jsx)(g,{to:a,className:`text-xs font-medium text-primary hover:underline`,children:`View all →`})}),t[10]=a,t[11]=d);let f;return t[12]!==l||t[13]!==u||t[14]!==d?(f=(0,F.jsxs)(A,{children:[l,u,d]}),t[12]=l,t[13]=u,t[14]=d,t[15]=f):f=t[15],f}function W(e){let t=(0,N.c)(2),{total:n}=e;if(n<=B)return null;let r=n-B,i;return t[0]===r?i=t[1]:(i=(0,F.jsxs)(`p`,{className:`mt-1 text-[0.625rem] text-muted-foreground`,children:[`+`,r,` more`]}),t[0]=r,t[1]=i),i}function G(e){let t=(0,N.c)(2),{children:n}=e,r;return t[0]===n?r=t[1]:(r=(0,F.jsx)(`div`,{className:`flex items-center justify-between py-0.5 text-xs`,children:n}),t[0]=n,t[1]=r),r}function K(){let t=(0,N.c)(16),{data:n}=e(a),r,i,o,c,l;if(t[0]!==n?.Reservations){let e=n?.Reservations?.flatMap(Q)??[];r=e.filter(Z),o=e.filter(X),c=e.filter(Y),i=e.filter(J),l=[...o,...i].slice(0,B),t[0]=n?.Reservations,t[1]=r,t[2]=i,t[3]=o,t[4]=c,t[5]=l}else r=t[1],i=t[2],o=t[3],c=t[4],l=t[5];let u=l,d;t[6]===Symbol.for(`react.memo_cache_sentinel`)?(d=(0,F.jsx)(s,{className:`size-3.5`}),t[6]=d):d=t[6];let f;t[7]!==r.length||t[8]!==u||t[9]!==i||t[10]!==o||t[11]!==c?(f=r.length===0?(0,F.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No instances`}):(0,F.jsxs)(F.Fragment,{children:[(0,F.jsxs)(`div`,{className:`mb-2 flex gap-3 text-[0.625rem] text-muted-foreground`,children:[(0,F.jsxs)(`span`,{children:[o.length,` running`]}),(0,F.jsxs)(`span`,{children:[c.length,` stopped`]})]}),(0,F.jsx)(`div`,{className:`space-y-0.5`,children:u.map(q)}),(0,F.jsx)(W,{total:o.length+i.length})]}),t[7]=r.length,t[8]=u,t[9]=i,t[10]=o,t[11]=c,t[12]=f):f=t[12];let p;return t[13]!==r.length||t[14]!==f?(p=(0,F.jsx)(U,{title:`Instances`,icon:d,count:r.length,to:`/ec2/describe-instances`,children:f}),t[13]=r.length,t[14]=f,t[15]=p):p=t[15],p}function q(e){return(0,F.jsxs)(G,{children:[(0,F.jsx)(`span`,{className:`font-mono`,children:e.InstanceId}),(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:e.InstanceType})]},e.InstanceId)}function J(e){return e.State?.Name===`pending`}function Y(e){return e.State?.Name===`stopped`}function X(e){return e.State?.Name===`running`}function Z(e){return e.State?.Name!==`terminated`}function Q(e){return e.Instances??[]}function $(){let t=(0,N.c)(3),{data:n}=e(x),r;if(t[0]!==n?.Volumes){let e=n?.Volumes??[],i=e.reduce(fe,0),a=e.filter(de),o=e.filter(ue),s=e.slice(0,B),c;t[2]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,F.jsx)(j,{className:`size-3.5`}),t[2]=c):c=t[2],r=(0,F.jsx)(U,{title:`Volumes`,icon:c,count:e.length,to:`/ec2/describe-volumes`,children:e.length===0?(0,F.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No volumes`}):(0,F.jsxs)(F.Fragment,{children:[(0,F.jsxs)(`div`,{className:`mb-2 flex gap-3 text-[0.625rem] text-muted-foreground`,children:[(0,F.jsxs)(`span`,{children:[i,` GiB total`]}),(0,F.jsxs)(`span`,{children:[a.length,` in-use`]}),(0,F.jsxs)(`span`,{children:[o.length,` available`]})]}),(0,F.jsx)(`div`,{className:`space-y-0.5`,children:s.map(le)}),(0,F.jsx)(W,{total:e.length})]})}),t[0]=n?.Volumes,t[1]=r}else r=t[1];return r}function le(e){return(0,F.jsxs)(G,{children:[(0,F.jsx)(`span`,{className:`font-mono`,children:e.VolumeId}),(0,F.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,F.jsxs)(`span`,{className:`text-muted-foreground`,children:[e.Size,` GiB`]}),(0,F.jsx)(C,{state:e.State})]})]},e.VolumeId)}function ue(e){return e.State===`available`}function de(e){return e.State===`in-use`}function fe(e,t){return e+(t.Size??0)}function pe(){let t=(0,N.c)(3),{data:n}=e(y),r;if(t[0]!==n?.Vpcs){let e=n?.Vpcs??[],i=e.slice(0,B),a;t[2]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,F.jsx)(c,{className:`size-3.5`}),t[2]=a):a=t[2],r=(0,F.jsx)(U,{title:`VPCs`,icon:a,count:e.length,to:`/ec2/describe-vpcs`,children:e.length===0?(0,F.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No VPCs`}):(0,F.jsxs)(`div`,{className:`space-y-0.5`,children:[i.map(me),(0,F.jsx)(W,{total:e.length})]})}),t[0]=n?.Vpcs,t[1]=r}else r=t[1];return r}function me(e){let t=l(e.Tags);return(0,F.jsxs)(G,{children:[(0,F.jsxs)(`span`,{className:`font-mono`,children:[e.VpcId,t&&(0,F.jsxs)(`span`,{className:`ml-1 font-sans text-muted-foreground`,children:[`(`,t,`)`]})]}),(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:e.CidrBlock})]},e.VpcId)}function he(){let t=(0,N.c)(3),{data:n}=e(d),r;if(t[0]!==n?.KeyPairs){let e=n?.KeyPairs??[],i=e.slice(0,B),a;t[2]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,F.jsx)(v,{className:`size-3.5`}),t[2]=a):a=t[2],r=(0,F.jsx)(U,{title:`Key Pairs`,icon:a,count:e.length,to:`/ec2/describe-key-pairs`,children:e.length===0?(0,F.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No key pairs`}):(0,F.jsxs)(`div`,{className:`space-y-0.5`,children:[i.map(ge),(0,F.jsx)(W,{total:e.length})]})}),t[0]=n?.KeyPairs,t[1]=r}else r=t[1];return r}function ge(e){return(0,F.jsx)(G,{children:(0,F.jsx)(`span`,{className:`font-mono`,children:e.KeyName})},e.KeyPairId)}function _e(){let t=(0,N.c)(3),{data:n}=e(o),r;if(t[0]!==n?.Buckets){let e=n?.Buckets??[],i=e.slice(0,B),a;t[2]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,F.jsx)(M,{className:`size-3.5`}),t[2]=a):a=t[2],r=(0,F.jsx)(U,{title:`S3 Buckets`,icon:a,count:e.length,to:`/s3/ls`,children:e.length===0?(0,F.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No buckets`}):(0,F.jsxs)(`div`,{className:`space-y-0.5`,children:[i.map(ve),(0,F.jsx)(W,{total:e.length})]})}),t[0]=n?.Buckets,t[1]=r}else r=t[1];return r}function ve(e){return(0,F.jsx)(G,{children:(0,F.jsx)(`span`,{className:`font-mono`,children:e.Name})},e.Name)}function ye(){let t=(0,N.c)(3),{data:n}=e(m),r;if(t[0]!==n?.SecurityGroups){let e=n?.SecurityGroups??[],i=e.slice(0,B),a;t[2]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,F.jsx)(f,{className:`size-3.5`}),t[2]=a):a=t[2],r=(0,F.jsx)(U,{title:`Security Groups`,icon:a,count:e.length,to:`/ec2/describe-security-groups`,children:e.length===0?(0,F.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No security groups`}):(0,F.jsxs)(`div`,{className:`space-y-0.5`,children:[i.map(be),(0,F.jsx)(W,{total:e.length})]})}),t[0]=n?.SecurityGroups,t[1]=r}else r=t[1];return r}function be(e){return(0,F.jsxs)(G,{children:[(0,F.jsx)(`span`,{className:`font-mono`,children:e.GroupName}),(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:e.VpcId})]},e.GroupId)}export{V as component}; \ No newline at end of file +import{t as e}from"./useQuery.js";import{t}from"./chevron-down.js";import{t as n}from"./chevron-right.js";import{Co as r,G as i,Ja as a,Jo as o,L as s,Oo as c,U as l,X as u,ao as d,ar as f,co as p,io as m,it as h,ko as g,nt as _,oo as v,so as y,uo as b,xo as x}from"./index.js";import{t as S}from"./page-heading.js";import{t as C}from"./state-badge.js";import{r as w,t as ee}from"./admin.js";import{t as te}from"./badge.js";import{a as T,i as E,n as D,o as ne,r as O,t as k}from"./card.js";var A=b(`box`,[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]),j=b(`folder-open`,[[`path`,{d:`m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2`,key:`usdka0`}]]),M=b(`lock`,[[`rect`,{width:`18`,height:`11`,x:`3`,y:`11`,rx:`2`,ry:`2`,key:`1w4ew1`}],[`path`,{d:`M7 11V7a5 5 0 0 1 10 0v4`,key:`fwvmzm`}]]),re=b(`monitor`,[[`rect`,{width:`20`,height:`14`,x:`2`,y:`3`,rx:`2`,key:`48i651`}],[`line`,{x1:`8`,x2:`16`,y1:`21`,y2:`21`,key:`1svkeh`}],[`line`,{x1:`12`,x2:`12`,y1:`17`,y2:`21`,key:`vw1qmm`}]]),N=x(),P=o(g(),1),F=c(),I=[{name:`Air-gap Support`,key:`airgap`},{name:`NVIDIA Bluefield DPU`,key:`bluefield`},{name:`NVIDIA MIG Support`,key:`mig`}];function L(e){let t=Math.floor(e/86400),n=Math.floor(e%86400/3600);if(t>0)return`${t}d ${n}h`;let r=Math.floor(e%3600/60);return n>0?`${n}h ${r}m`:`${r}m`}function R(){let r=(0,N.c)(110),{isAdmin:i,version:a,license:o}=f(),[s,c]=(0,P.useState)(!1),l;r[0]===i?l=r[1]:(l={...ee,enabled:i},r[0]=i,r[1]=l);let{data:u}=e(l),p;r[2]===i?p=r[3]:(p={...w,enabled:i},r[2]=i,r[3]=p);let{data:m}=e(p);if(!i||!a)return null;let h,g,_,v,y,b,x,S,C,E,D,A,j,L,R,z,B,V,H;if(r[4]!==o||r[5]!==u?.cluster_mode||r[6]!==u?.nodes||r[7]!==a.arch||r[8]!==a.commit||r[9]!==a.os||r[10]!==a.version||r[11]!==m?.vms){v=u?.nodes??[];let e;r[31]===m?.vms?e=r[32]:(e=m?.vms??[],r[31]=m?.vms,r[32]=e);let t=e,n=u?.cluster_mode??`single-node`;_=o===`open-source`;let i=v[0]?.region??null,s=v.reduce(se,0),c=v.reduce(oe,0),l=v.reduce(ae,0),f=v.reduce(ie,0);D=`mb-6 space-y-4`,S=`grid grid-cols-1 gap-4 md:grid-cols-3`;let p;r[33]===Symbol.for(`react.memo_cache_sentinel`)?(p=(0,F.jsx)(T,{className:`pb-2`,children:(0,F.jsxs)(ne,{className:`flex items-center gap-2 text-sm`,children:[(0,F.jsx)(re,{className:`size-3.5`}),`Spinifex Info`]})}),r[33]=p):p=r[33];let w;r[34]===Symbol.for(`react.memo_cache_sentinel`)?(w=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`Version`}),r[34]=w):w=r[34];let ee;r[35]===a.version?ee=r[36]:(ee=(0,F.jsxs)(`div`,{className:`flex justify-between`,children:[w,(0,F.jsx)(`span`,{className:`font-mono`,children:a.version})]}),r[35]=a.version,r[36]=ee);let M;r[37]===Symbol.for(`react.memo_cache_sentinel`)?(M=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`Commit`}),r[37]=M):M=r[37];let N;r[38]===a.commit?N=r[39]:(N=(0,F.jsxs)(`div`,{className:`flex justify-between`,children:[M,(0,F.jsx)(`span`,{className:`font-mono`,children:a.commit})]}),r[38]=a.commit,r[39]=N);let P;r[40]===Symbol.for(`react.memo_cache_sentinel`)?(P=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`Platform`}),r[40]=P):P=r[40];let I;r[41]!==a.arch||r[42]!==a.os?(I=(0,F.jsxs)(`div`,{className:`flex justify-between`,children:[P,(0,F.jsxs)(`span`,{children:[a.os,`/`,a.arch]})]}),r[41]=a.arch,r[42]=a.os,r[43]=I):I=r[43],C=(0,F.jsxs)(k,{children:[p,(0,F.jsxs)(O,{className:`space-y-1 text-xs`,children:[ee,N,I,i&&(0,F.jsxs)(`div`,{className:`flex justify-between`,children:[(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`Region`}),(0,F.jsx)(`span`,{children:i})]})]})]});let ce;r[44]===Symbol.for(`react.memo_cache_sentinel`)?(ce=(0,F.jsx)(T,{className:`pb-2`,children:(0,F.jsx)(ne,{className:`text-sm`,children:`License & Support`})}),r[44]=ce):ce=r[44];let U;r[45]===Symbol.for(`react.memo_cache_sentinel`)?(U=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`License`}),r[45]=U):U=r[45];let W=_?`secondary`:`default`,G=_?`Open Source (AGPLv3)`:`Commercial`,K;r[46]!==W||r[47]!==G?(K=(0,F.jsxs)(`div`,{className:`flex items-center justify-between`,children:[U,(0,F.jsx)(te,{variant:W,children:G})]}),r[46]=W,r[47]=G,r[48]=K):K=r[48];let q;r[49]===Symbol.for(`react.memo_cache_sentinel`)?(q=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`Support`}),r[49]=q):q=r[49];let J=_?`Community`:`Standard`,Y;r[50]===J?Y=r[51]:(Y=(0,F.jsxs)(`div`,{className:`flex items-center justify-between`,children:[q,(0,F.jsx)(`span`,{children:J})]}),r[50]=J,r[51]=Y);let X;r[52]===_?X=r[53]:(X=_&&(0,F.jsx)(`a`,{href:`https://mulgadc.com/purchase`,target:`_blank`,rel:`noopener noreferrer`,className:`mt-2 block text-xs font-medium text-primary hover:underline`,children:`Upgrade to Commercial →`}),r[52]=_,r[53]=X),r[54]!==K||r[55]!==Y||r[56]!==X?(E=(0,F.jsxs)(k,{children:[ce,(0,F.jsxs)(O,{className:`space-y-2 text-xs`,children:[K,Y,X]})]}),r[54]=K,r[55]=Y,r[56]=X,r[57]=E):E=r[57],g=k,r[58]===Symbol.for(`react.memo_cache_sentinel`)?(x=(0,F.jsx)(T,{className:`pb-2`,children:(0,F.jsxs)(ne,{className:`flex items-center gap-2 text-sm`,children:[(0,F.jsx)(d,{className:`size-3.5`}),`Cluster Status`]})}),r[58]=x):x=r[58],h=O,B=`space-y-2 text-xs`,r[59]===n?V=r[60]:(V=(0,F.jsx)(`div`,{className:`flex items-center gap-2`,children:(0,F.jsx)(te,{variant:`outline`,children:n})}),r[59]=n,r[60]=V);let Z;r[61]===Symbol.for(`react.memo_cache_sentinel`)?(Z=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`Nodes`}),r[61]=Z):Z=r[61],H=(0,F.jsxs)(`div`,{className:`flex justify-between`,children:[Z,(0,F.jsx)(`span`,{children:v.length})]});let Q;r[62]===Symbol.for(`react.memo_cache_sentinel`)?(Q=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`Instances`}),r[62]=Q):Q=r[62],r[63]===t.length?y=r[64]:(y=(0,F.jsxs)(`div`,{className:`flex justify-between`,children:[Q,(0,F.jsx)(`span`,{children:t.length})]}),r[63]=t.length,r[64]=y);let $;r[65]===Symbol.for(`react.memo_cache_sentinel`)?($=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`vCPU`}),r[65]=$):$=r[65],b=(0,F.jsxs)(`div`,{className:`flex justify-between`,children:[$,(0,F.jsxs)(`span`,{children:[c,` / `,s]})]}),R=`flex justify-between`,r[66]===Symbol.for(`react.memo_cache_sentinel`)?(z=(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:`Memory`}),r[66]=z):z=r[66],A=f.toFixed(1),j=` / `,L=l.toFixed(1),r[4]=o,r[5]=u?.cluster_mode,r[6]=u?.nodes,r[7]=a.arch,r[8]=a.commit,r[9]=a.os,r[10]=a.version,r[11]=m?.vms,r[12]=h,r[13]=g,r[14]=_,r[15]=v,r[16]=y,r[17]=b,r[18]=x,r[19]=S,r[20]=C,r[21]=E,r[22]=D,r[23]=A,r[24]=j,r[25]=L,r[26]=R,r[27]=z,r[28]=B,r[29]=V,r[30]=H}else h=r[12],g=r[13],_=r[14],v=r[15],y=r[16],b=r[17],x=r[18],S=r[19],C=r[20],E=r[21],D=r[22],A=r[23],j=r[24],L=r[25],R=r[26],z=r[27],B=r[28],V=r[29],H=r[30];let U;r[67]!==A||r[68]!==j||r[69]!==L?(U=(0,F.jsxs)(`span`,{children:[A,j,L,` GB`]}),r[67]=A,r[68]=j,r[69]=L,r[70]=U):U=r[70];let W;r[71]!==U||r[72]!==R||r[73]!==z?(W=(0,F.jsxs)(`div`,{className:R,children:[z,U]}),r[71]=U,r[72]=R,r[73]=z,r[74]=W):W=r[74];let G;r[75]!==h||r[76]!==y||r[77]!==b||r[78]!==W||r[79]!==B||r[80]!==V||r[81]!==H?(G=(0,F.jsxs)(h,{className:B,children:[V,H,y,b,W]}),r[75]=h,r[76]=y,r[77]=b,r[78]=W,r[79]=B,r[80]=V,r[81]=H,r[82]=G):G=r[82];let K;r[83]!==g||r[84]!==x||r[85]!==G?(K=(0,F.jsxs)(g,{children:[x,G]}),r[83]=g,r[84]=x,r[85]=G,r[86]=K):K=r[86];let q;r[87]!==S||r[88]!==C||r[89]!==E||r[90]!==K?(q=(0,F.jsxs)(`div`,{className:S,children:[C,E,K]}),r[87]=S,r[88]=C,r[89]=E,r[90]=K,r[91]=q):q=r[91];let J;r[92]!==v||r[93]!==s?(J=v.length>0&&(0,F.jsxs)(k,{children:[(0,F.jsx)(T,{className:`pb-0`,children:(0,F.jsxs)(`button`,{type:`button`,className:`flex items-center gap-2 text-sm font-medium`,onClick:()=>c(!s),children:[s?(0,F.jsx)(t,{className:`size-3.5`}):(0,F.jsx)(n,{className:`size-3.5`}),`Nodes (`,v.length,`)`]})}),s&&(0,F.jsx)(O,{className:`pt-2`,children:(0,F.jsx)(ce,{nodes:v})})]}),r[92]=v,r[93]=s,r[94]=J):J=r[94];let Y;r[95]===Symbol.for(`react.memo_cache_sentinel`)?(Y=(0,F.jsx)(T,{className:`pb-2`,children:(0,F.jsx)(ne,{className:`text-sm`,children:`Commercial Add-ons`})}),r[95]=Y):Y=r[95];let X;r[96]===_?X=r[97]:(X=I.map(e=>(0,F.jsxs)(`div`,{className:`flex items-center justify-between text-xs`,children:[(0,F.jsx)(`span`,{className:_?`text-muted-foreground`:void 0,children:e.name}),_?(0,F.jsx)(M,{className:`size-3 text-muted-foreground`}):(0,F.jsx)(te,{variant:`outline`,className:`text-[0.625rem]`,children:`Active`})]},e.key)),r[96]=_,r[97]=X);let Z;r[98]===X?Z=r[99]:(Z=(0,F.jsx)(`div`,{className:`space-y-2`,children:X}),r[98]=X,r[99]=Z);let Q;r[100]===_?Q=r[101]:(Q=_&&(0,F.jsx)(`a`,{href:`https://mulgadc.com/purchase`,target:`_blank`,rel:`noopener noreferrer`,className:`mt-3 block text-xs font-medium text-primary hover:underline`,children:`Learn more about commercial features →`}),r[100]=_,r[101]=Q);let $;r[102]!==Z||r[103]!==Q?($=(0,F.jsxs)(k,{children:[Y,(0,F.jsxs)(O,{children:[Z,Q]})]}),r[102]=Z,r[103]=Q,r[104]=$):$=r[104];let le;return r[105]!==D||r[106]!==q||r[107]!==J||r[108]!==$?(le=(0,F.jsxs)(`div`,{className:D,children:[q,J,$]}),r[105]=D,r[106]=q,r[107]=J,r[108]=$,r[109]=le):le=r[109],le}function ie(e,t){return e+t.alloc_mem_gb}function ae(e,t){return e+t.total_mem_gb}function oe(e,t){return e+t.alloc_vcpu}function se(e,t){return e+t.total_vcpu}function ce(e){let t=(0,N.c)(5),{nodes:n}=e,r;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,F.jsx)(`thead`,{children:(0,F.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,F.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Name`}),(0,F.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Status`}),(0,F.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Roles`}),(0,F.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`IP`}),(0,F.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Region`}),(0,F.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`AZ`}),(0,F.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Uptime`}),(0,F.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`EC2`}),(0,F.jsx)(`th`,{className:`pb-1 font-medium`,children:`Services`})]})}),t[0]=r):r=t[0];let i;t[1]===n?i=t[2]:(i=n.map(z),t[1]=n,t[2]=i);let a;return t[3]===i?a=t[4]:(a=(0,F.jsx)(`div`,{className:`overflow-x-auto`,children:(0,F.jsxs)(`table`,{className:`w-full text-xs`,children:[r,(0,F.jsx)(`tbody`,{children:i})]})}),t[3]=i,t[4]=a),a}function z(e){return(0,F.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,F.jsx)(`td`,{className:`py-1.5 pr-4 font-mono font-medium`,children:e.node}),(0,F.jsx)(`td`,{className:`py-1.5 pr-4`,children:(0,F.jsx)(te,{variant:e.status===`Ready`?`default`:`secondary`,className:`text-[0.625rem]`,children:e.status})}),(0,F.jsx)(`td`,{className:`py-1.5 pr-4`,children:(0,F.jsxs)(`div`,{className:`flex gap-1`,children:[e.nats_role&&(0,F.jsxs)(`span`,{className:`text-muted-foreground`,children:[`nats:`,e.nats_role]}),e.predastore_role&&(0,F.jsxs)(`span`,{className:`text-muted-foreground`,children:[`ps:`,e.predastore_role]})]})}),(0,F.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.host}),(0,F.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.region}),(0,F.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.az}),(0,F.jsx)(`td`,{className:`py-1.5 pr-4`,children:L(e.uptime)}),(0,F.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.vm_count}),(0,F.jsx)(`td`,{className:`py-1.5`,children:(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:e.services.length})})]},e.node)}var B=5;function V(){let e=(0,N.c)(8),t,n;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(t=(0,F.jsx)(S,{title:`Dashboard`}),n=(0,F.jsx)(R,{}),e[0]=t,e[1]=n):(t=e[0],n=e[1]);let r;e[2]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,F.jsx)(P.Suspense,{fallback:(0,F.jsx)(H,{}),children:(0,F.jsx)(K,{})}),e[2]=r):r=e[2];let i;e[3]===Symbol.for(`react.memo_cache_sentinel`)?(i=(0,F.jsx)(P.Suspense,{fallback:(0,F.jsx)(H,{}),children:(0,F.jsx)($,{})}),e[3]=i):i=e[3];let a;e[4]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,F.jsx)(P.Suspense,{fallback:(0,F.jsx)(H,{}),children:(0,F.jsx)(pe,{})}),e[4]=a):a=e[4];let o;e[5]===Symbol.for(`react.memo_cache_sentinel`)?(o=(0,F.jsx)(P.Suspense,{fallback:(0,F.jsx)(H,{}),children:(0,F.jsx)(he,{})}),e[5]=o):o=e[5];let s;e[6]===Symbol.for(`react.memo_cache_sentinel`)?(s=(0,F.jsx)(P.Suspense,{fallback:(0,F.jsx)(H,{}),children:(0,F.jsx)(_e,{})}),e[6]=s):s=e[6];let c;return e[7]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,F.jsxs)(F.Fragment,{children:[t,n,(0,F.jsxs)(`div`,{className:`grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3`,children:[r,i,a,o,s,(0,F.jsx)(P.Suspense,{fallback:(0,F.jsx)(H,{}),children:(0,F.jsx)(ye,{})})]})]}),e[7]=c):c=e[7],c}function H(){let e=(0,N.c)(2),t;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(t=(0,F.jsx)(T,{children:(0,F.jsx)(`div`,{className:`h-4 w-32 animate-pulse rounded bg-muted`})}),e[0]=t):t=e[0];let n;return e[1]===Symbol.for(`react.memo_cache_sentinel`)?(n=(0,F.jsxs)(k,{children:[t,(0,F.jsx)(O,{children:(0,F.jsxs)(`div`,{className:`space-y-2`,children:[(0,F.jsx)(`div`,{className:`h-3 w-48 animate-pulse rounded bg-muted`}),(0,F.jsx)(`div`,{className:`h-3 w-36 animate-pulse rounded bg-muted`})]})})]}),e[1]=n):n=e[1],n}function U(e){let t=(0,N.c)(16),{title:n,icon:i,count:a,to:o,children:s}=e,c;t[0]!==i||t[1]!==n?(c=(0,F.jsxs)(ne,{className:`flex items-center gap-2`,children:[i,n]}),t[0]=i,t[1]=n,t[2]=c):c=t[2];let l;t[3]===a?l=t[4]:(l=(0,F.jsx)(D,{children:(0,F.jsx)(`span`,{className:`rounded-md bg-muted px-2 py-0.5 text-xs font-semibold tabular-nums`,children:a})}),t[3]=a,t[4]=l);let u;t[5]!==c||t[6]!==l?(u=(0,F.jsxs)(T,{children:[c,l]}),t[5]=c,t[6]=l,t[7]=u):u=t[7];let d;t[8]===s?d=t[9]:(d=(0,F.jsx)(O,{children:s}),t[8]=s,t[9]=d);let f;t[10]===o?f=t[11]:(f=(0,F.jsx)(E,{children:(0,F.jsx)(r,{to:o,className:`text-xs font-medium text-primary hover:underline`,children:`View all →`})}),t[10]=o,t[11]=f);let p;return t[12]!==u||t[13]!==d||t[14]!==f?(p=(0,F.jsxs)(k,{children:[u,d,f]}),t[12]=u,t[13]=d,t[14]=f,t[15]=p):p=t[15],p}function W(e){let t=(0,N.c)(2),{total:n}=e;if(n<=B)return null;let r=n-B,i;return t[0]===r?i=t[1]:(i=(0,F.jsxs)(`p`,{className:`mt-1 text-[0.625rem] text-muted-foreground`,children:[`+`,r,` more`]}),t[0]=r,t[1]=i),i}function G(e){let t=(0,N.c)(2),{children:n}=e,r;return t[0]===n?r=t[1]:(r=(0,F.jsx)(`div`,{className:`flex items-center justify-between py-0.5 text-xs`,children:n}),t[0]=n,t[1]=r),r}function K(){let t=(0,N.c)(16),{data:n}=e(l),r,i,a,o,s;if(t[0]!==n?.Reservations){let e=n?.Reservations?.flatMap(Q)??[];r=e.filter(Z),a=e.filter(X),o=e.filter(Y),i=e.filter(J),s=[...a,...i].slice(0,B),t[0]=n?.Reservations,t[1]=r,t[2]=i,t[3]=a,t[4]=o,t[5]=s}else r=t[1],i=t[2],a=t[3],o=t[4],s=t[5];let c=s,u;t[6]===Symbol.for(`react.memo_cache_sentinel`)?(u=(0,F.jsx)(p,{className:`size-3.5`}),t[6]=u):u=t[6];let d;t[7]!==r.length||t[8]!==c||t[9]!==i||t[10]!==a||t[11]!==o?(d=r.length===0?(0,F.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No instances`}):(0,F.jsxs)(F.Fragment,{children:[(0,F.jsxs)(`div`,{className:`mb-2 flex gap-3 text-[0.625rem] text-muted-foreground`,children:[(0,F.jsxs)(`span`,{children:[a.length,` running`]}),(0,F.jsxs)(`span`,{children:[o.length,` stopped`]})]}),(0,F.jsx)(`div`,{className:`space-y-0.5`,children:c.map(q)}),(0,F.jsx)(W,{total:a.length+i.length})]}),t[7]=r.length,t[8]=c,t[9]=i,t[10]=a,t[11]=o,t[12]=d):d=t[12];let f;return t[13]!==r.length||t[14]!==d?(f=(0,F.jsx)(U,{title:`Instances`,icon:u,count:r.length,to:`/ec2/describe-instances`,children:d}),t[13]=r.length,t[14]=d,t[15]=f):f=t[15],f}function q(e){return(0,F.jsxs)(G,{children:[(0,F.jsx)(`span`,{className:`font-mono`,children:e.InstanceId}),(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:e.InstanceType})]},e.InstanceId)}function J(e){return e.State?.Name===`pending`}function Y(e){return e.State?.Name===`stopped`}function X(e){return e.State?.Name===`running`}function Z(e){return e.State?.Name!==`terminated`}function Q(e){return e.Instances??[]}function $(){let t=(0,N.c)(3),{data:n}=e(_),r;if(t[0]!==n?.Volumes){let e=n?.Volumes??[],i=e.reduce(fe,0),a=e.filter(de),o=e.filter(ue),s=e.slice(0,B),c;t[2]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,F.jsx)(A,{className:`size-3.5`}),t[2]=c):c=t[2],r=(0,F.jsx)(U,{title:`Volumes`,icon:c,count:e.length,to:`/ec2/describe-volumes`,children:e.length===0?(0,F.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No volumes`}):(0,F.jsxs)(F.Fragment,{children:[(0,F.jsxs)(`div`,{className:`mb-2 flex gap-3 text-[0.625rem] text-muted-foreground`,children:[(0,F.jsxs)(`span`,{children:[i,` GiB total`]}),(0,F.jsxs)(`span`,{children:[a.length,` in-use`]}),(0,F.jsxs)(`span`,{children:[o.length,` available`]})]}),(0,F.jsx)(`div`,{className:`space-y-0.5`,children:s.map(le)}),(0,F.jsx)(W,{total:e.length})]})}),t[0]=n?.Volumes,t[1]=r}else r=t[1];return r}function le(e){return(0,F.jsxs)(G,{children:[(0,F.jsx)(`span`,{className:`font-mono`,children:e.VolumeId}),(0,F.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,F.jsxs)(`span`,{className:`text-muted-foreground`,children:[e.Size,` GiB`]}),(0,F.jsx)(C,{state:e.State})]})]},e.VolumeId)}function ue(e){return e.State===`available`}function de(e){return e.State===`in-use`}function fe(e,t){return e+(t.Size??0)}function pe(){let t=(0,N.c)(3),{data:n}=e(h),r;if(t[0]!==n?.Vpcs){let e=n?.Vpcs??[],i=e.slice(0,B),a;t[2]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,F.jsx)(v,{className:`size-3.5`}),t[2]=a):a=t[2],r=(0,F.jsx)(U,{title:`VPCs`,icon:a,count:e.length,to:`/ec2/describe-vpcs`,children:e.length===0?(0,F.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No VPCs`}):(0,F.jsxs)(`div`,{className:`space-y-0.5`,children:[i.map(me),(0,F.jsx)(W,{total:e.length})]})}),t[0]=n?.Vpcs,t[1]=r}else r=t[1];return r}function me(e){let t=a(e.Tags);return(0,F.jsxs)(G,{children:[(0,F.jsxs)(`span`,{className:`font-mono`,children:[e.VpcId,t&&(0,F.jsxs)(`span`,{className:`ml-1 font-sans text-muted-foreground`,children:[`(`,t,`)`]})]}),(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:e.CidrBlock})]},e.VpcId)}function he(){let t=(0,N.c)(3),{data:n}=e(i),r;if(t[0]!==n?.KeyPairs){let e=n?.KeyPairs??[],i=e.slice(0,B),a;t[2]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,F.jsx)(y,{className:`size-3.5`}),t[2]=a):a=t[2],r=(0,F.jsx)(U,{title:`Key Pairs`,icon:a,count:e.length,to:`/ec2/describe-key-pairs`,children:e.length===0?(0,F.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No key pairs`}):(0,F.jsxs)(`div`,{className:`space-y-0.5`,children:[i.map(ge),(0,F.jsx)(W,{total:e.length})]})}),t[0]=n?.KeyPairs,t[1]=r}else r=t[1];return r}function ge(e){return(0,F.jsx)(G,{children:(0,F.jsx)(`span`,{className:`font-mono`,children:e.KeyName})},e.KeyPairId)}function _e(){let t=(0,N.c)(3),{data:n}=e(s),r;if(t[0]!==n?.Buckets){let e=n?.Buckets??[],i=e.slice(0,B),a;t[2]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,F.jsx)(j,{className:`size-3.5`}),t[2]=a):a=t[2],r=(0,F.jsx)(U,{title:`S3 Buckets`,icon:a,count:e.length,to:`/s3/ls`,children:e.length===0?(0,F.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No buckets`}):(0,F.jsxs)(`div`,{className:`space-y-0.5`,children:[i.map(ve),(0,F.jsx)(W,{total:e.length})]})}),t[0]=n?.Buckets,t[1]=r}else r=t[1];return r}function ve(e){return(0,F.jsx)(G,{children:(0,F.jsx)(`span`,{className:`font-mono`,children:e.Name})},e.Name)}function ye(){let t=(0,N.c)(3),{data:n}=e(u),r;if(t[0]!==n?.SecurityGroups){let e=n?.SecurityGroups??[],i=e.slice(0,B),a;t[2]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,F.jsx)(m,{className:`size-3.5`}),t[2]=a):a=t[2],r=(0,F.jsx)(U,{title:`Security Groups`,icon:a,count:e.length,to:`/ec2/describe-security-groups`,children:e.length===0?(0,F.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No security groups`}):(0,F.jsxs)(`div`,{className:`space-y-0.5`,children:[i.map(be),(0,F.jsx)(W,{total:e.length})]})}),t[0]=n?.SecurityGroups,t[1]=r}else r=t[1];return r}function be(e){return(0,F.jsxs)(G,{children:[(0,F.jsx)(`span`,{className:`font-mono`,children:e.GroupName}),(0,F.jsx)(`span`,{className:`text-muted-foreground`,children:e.VpcId})]},e.GroupId)}export{V as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_bucket.js b/spinifex/services/spinifexui/frontend/dist/assets/_bucket.js index 284ba64f0..2ece70fef 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_bucket.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_bucket.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{n as r,r as i,t as a}from"./upload-button.js";import{r as o}from"./s3.js";import{C as s,F as c,Fa as l,mo as u,so as d}from"./index.js";import{t as f}from"./page-heading.js";var p=d(),m=u();function h(){let u=(0,p.c)(31),{bucket:d}=s.useParams(),h;u[0]===d?h=u[1]:(h=c(d),u[0]=d,u[1]=h);let{data:g}=t(h),_=o(),v;u[2]===g.Contents?v=u[3]:(v=g.Contents??[],u[2]=g.Contents,u[3]=v);let y=v,b;u[4]===g.CommonPrefixes?b=u[5]:(b=g.CommonPrefixes??[],u[4]=g.CommonPrefixes,u[5]=b);let x=b,S;u[6]===Symbol.for(`react.memo_cache_sentinel`)?(S=(0,m.jsx)(n,{to:`/s3/ls`,children:`Back to buckets`}),u[6]=S):S=u[6];let C;u[7]!==d||u[8]!==_.isPending||u[9]!==_.mutateAsync?(C=(0,m.jsx)(a,{bucket:d,isPending:_.isPending,onUpload:_.mutateAsync}),u[7]=d,u[8]=_.isPending,u[9]=_.mutateAsync,u[10]=C):C=u[10];let w;u[11]!==d||u[12]!==C?(w=(0,m.jsx)(f,{actions:C,title:d}),u[11]=d,u[12]=C,u[13]=w):w=u[13];let T;u[14]===_.error?T=u[15]:(T=_.error&&(0,m.jsx)(e,{error:_.error,msg:`Failed to upload object`}),u[14]=_.error,u[15]=T);let E;u[16]!==d||u[17]!==x?(E=x.length>0&&(0,m.jsxs)(`div`,{className:`mb-6`,children:[(0,m.jsx)(`h2`,{className:`mb-3 text-lg font-semibold`,children:`Folders`}),(0,m.jsx)(`div`,{className:`space-y-2`,children:x.map(e=>e.Prefix?(0,m.jsx)(i,{bucketName:d,folderName:l(e.Prefix),fullPrefix:e.Prefix},e.Prefix):null)})]}),u[16]=d,u[17]=x,u[18]=E):E=u[18];let D;u[19]!==d||u[20]!==y?(D=y.length>0&&(0,m.jsxs)(`div`,{className:`space-y-2`,children:[(0,m.jsx)(`h2`,{className:`mb-3 text-lg font-semibold`,children:`Objects`}),y.map(e=>e.Key?(0,m.jsx)(r,{bucketName:d,displayName:e.Key,fullKey:e.Key,object:e},e.Key):null)]}),u[19]=d,u[20]=y,u[21]=D):D=u[21];let O;u[22]!==x.length||u[23]!==y.length?(O=y.length===0&&x.length===0&&(0,m.jsx)(`p`,{className:`text-muted-foreground`,children:`No objects found in this bucket.`}),u[22]=x.length,u[23]=y.length,u[24]=O):O=u[24];let k;return u[25]!==w||u[26]!==T||u[27]!==E||u[28]!==D||u[29]!==O?(k=(0,m.jsxs)(m.Fragment,{children:[S,w,T,E,D,O]}),u[25]=w,u[26]=T,u[27]=E,u[28]=D,u[29]=O,u[30]=k):k=u[30],k}export{h as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{n as r,r as i,t as a}from"./upload-button.js";import{r as o}from"./s3.js";import{C as s,I as c,Oo as l,Ya as u,xo as d}from"./index.js";import{t as f}from"./page-heading.js";var p=d(),m=l();function h(){let l=(0,p.c)(31),{bucket:d}=s.useParams(),h;l[0]===d?h=l[1]:(h=c(d),l[0]=d,l[1]=h);let{data:g}=t(h),_=o(),v;l[2]===g.Contents?v=l[3]:(v=g.Contents??[],l[2]=g.Contents,l[3]=v);let y=v,b;l[4]===g.CommonPrefixes?b=l[5]:(b=g.CommonPrefixes??[],l[4]=g.CommonPrefixes,l[5]=b);let x=b,S;l[6]===Symbol.for(`react.memo_cache_sentinel`)?(S=(0,m.jsx)(n,{to:`/s3/ls`,children:`Back to buckets`}),l[6]=S):S=l[6];let C;l[7]!==d||l[8]!==_.isPending||l[9]!==_.mutateAsync?(C=(0,m.jsx)(a,{bucket:d,isPending:_.isPending,onUpload:_.mutateAsync}),l[7]=d,l[8]=_.isPending,l[9]=_.mutateAsync,l[10]=C):C=l[10];let w;l[11]!==d||l[12]!==C?(w=(0,m.jsx)(f,{actions:C,title:d}),l[11]=d,l[12]=C,l[13]=w):w=l[13];let T;l[14]===_.error?T=l[15]:(T=_.error&&(0,m.jsx)(e,{error:_.error,msg:`Failed to upload object`}),l[14]=_.error,l[15]=T);let E;l[16]!==d||l[17]!==x?(E=x.length>0&&(0,m.jsxs)(`div`,{className:`mb-6`,children:[(0,m.jsx)(`h2`,{className:`mb-3 text-lg font-semibold`,children:`Folders`}),(0,m.jsx)(`div`,{className:`space-y-2`,children:x.map(e=>e.Prefix?(0,m.jsx)(i,{bucketName:d,folderName:u(e.Prefix),fullPrefix:e.Prefix},e.Prefix):null)})]}),l[16]=d,l[17]=x,l[18]=E):E=l[18];let D;l[19]!==d||l[20]!==y?(D=y.length>0&&(0,m.jsxs)(`div`,{className:`space-y-2`,children:[(0,m.jsx)(`h2`,{className:`mb-3 text-lg font-semibold`,children:`Objects`}),y.map(e=>e.Key?(0,m.jsx)(r,{bucketName:d,displayName:e.Key,fullKey:e.Key,object:e},e.Key):null)]}),l[19]=d,l[20]=y,l[21]=D):D=l[21];let O;l[22]!==x.length||l[23]!==y.length?(O=y.length===0&&x.length===0&&(0,m.jsx)(`p`,{className:`text-muted-foreground`,children:`No objects found in this bucket.`}),l[22]=x.length,l[23]=y.length,l[24]=O):O=l[24];let k;return l[25]!==w||l[26]!==T||l[27]!==E||l[28]!==D||l[29]!==O?(k=(0,m.jsxs)(m.Fragment,{children:[S,w,T,E,D,O]}),l[25]=w,l[26]=T,l[27]=E,l[28]=D,l[29]=O,l[30]=k):k=l[30],k}export{h as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_id.js b/spinifex/services/spinifexui/frontend/dist/assets/_id.js index d9f2eb211..a5e1ff373 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_id.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_id.js @@ -1 +1 @@ -import{t as e}from"./useSuspenseQuery.js";import{t}from"./back-link.js";import{R as n,mo as r,so as i,t as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./state-badge.js";import{t as c}from"./system-managed.js";import{t as l}from"./ami-details.js";var u=i(),d=r();function f(){let r=(0,u.c)(14),{id:i}=a.useParams(),f;r[0]===i?f=r[1]:(f=n(i),r[0]=i,r[1]=f);let{data:p}=e(f),m=p?.Images?.[0];if(!m?.ImageId||c(m)){let e;return r[2]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(t,{to:`/ec2/describe-images`,children:`Back to images`}),(0,d.jsx)(`p`,{className:`text-muted-foreground`,children:`Image not found.`})]}),r[2]=e):e=r[2],e}let h;r[3]===Symbol.for(`react.memo_cache_sentinel`)?(h=(0,d.jsx)(t,{to:`/ec2/describe-images`,children:`Back to images`}),r[3]=h):h=r[3];let g;r[4]===m.State?g=r[5]:(g=(0,d.jsx)(s,{state:m.State}),r[4]=m.State,r[5]=g);let _;r[6]!==m.ImageId||r[7]!==g?(_=(0,d.jsx)(o,{actions:g,subtitle:`Image Details`,title:m.ImageId}),r[6]=m.ImageId,r[7]=g,r[8]=_):_=r[8];let v;r[9]===m?v=r[10]:(v=(0,d.jsx)(l,{image:m,showExtendedDetails:!0}),r[9]=m,r[10]=v);let y;return r[11]!==_||r[12]!==v?(y=(0,d.jsxs)(d.Fragment,{children:[h,(0,d.jsxs)(`div`,{className:`space-y-6`,children:[_,v]})]}),r[11]=_,r[12]=v,r[13]=y):y=r[13],y}export{f as component}; \ No newline at end of file +import{t as e}from"./useSuspenseQuery.js";import{t}from"./back-link.js";import{Oo as n,t as r,xo as i,z as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./state-badge.js";import{t as c}from"./system-managed.js";import{t as l}from"./ami-details.js";var u=i(),d=n();function f(){let n=(0,u.c)(14),{id:i}=r.useParams(),f;n[0]===i?f=n[1]:(f=a(i),n[0]=i,n[1]=f);let{data:p}=e(f),m=p?.Images?.[0];if(!m?.ImageId||c(m)){let e;return n[2]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(t,{to:`/ec2/describe-images`,children:`Back to images`}),(0,d.jsx)(`p`,{className:`text-muted-foreground`,children:`Image not found.`})]}),n[2]=e):e=n[2],e}let h;n[3]===Symbol.for(`react.memo_cache_sentinel`)?(h=(0,d.jsx)(t,{to:`/ec2/describe-images`,children:`Back to images`}),n[3]=h):h=n[3];let g;n[4]===m.State?g=n[5]:(g=(0,d.jsx)(s,{state:m.State}),n[4]=m.State,n[5]=g);let _;n[6]!==m.ImageId||n[7]!==g?(_=(0,d.jsx)(o,{actions:g,subtitle:`Image Details`,title:m.ImageId}),n[6]=m.ImageId,n[7]=g,n[8]=_):_=n[8];let v;n[9]===m?v=n[10]:(v=(0,d.jsx)(l,{image:m,showExtendedDetails:!0}),n[9]=m,n[10]=v);let y;return n[11]!==_||n[12]!==v?(y=(0,d.jsxs)(d.Fragment,{children:[h,(0,d.jsxs)(`div`,{className:`space-y-6`,children:[_,v]})]}),n[11]=_,n[12]=v,n[13]=y):y=n[13],y}export{f as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_id10.js b/spinifex/services/spinifexui/frontend/dist/assets/_id10.js index 02a5a6103..385f10cca 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_id10.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_id10.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{c as ee,i as r,n as i,s as a,t as te}from"./select.js";import{t as o}from"./trash-2.js";import{S as s,b as c,t as l}from"./ec2.js";import{Ea as u,H as ne,Pa as d,Po as f,Ta as p,Ti as m,Xa as h,Ya as g,et as _,ho as v,ja as y,lo as b,mo as x,u as re,uo as ie}from"./index.js";import{t as ae}from"./page-heading.js";import{t as S}from"./state-badge.js";import{n as C,t as w}from"./detail-row.js";import{a as T,i as E,l as D,n as O,o as k,r as A,s as j,t as M}from"./alert-dialog.js";import{a as N,t as P}from"./field.js";import{t as F}from"./delete-confirmation-dialog.js";var I=h(`link-2-off`,[[`path`,{d:`M9 17H7A5 5 0 0 1 7 7`,key:`10o201`}],[`path`,{d:`M15 7h2a5 5 0 0 1 4 8`,key:`1d3206`}],[`line`,{x1:`8`,x2:`12`,y1:`12`,y2:`12`,key:`rvw6j4`}],[`line`,{x1:`2`,x2:`22`,y1:`2`,y2:`22`,key:`a6p6uj`}]]),L=h(`link-2`,[[`path`,{d:`M9 17H7A5 5 0 0 1 7 7h2`,key:`8i5ue5`}],[`path`,{d:`M15 7h2a5 5 0 1 1 0 10h-2`,key:`1b9ql8`}],[`line`,{x1:`8`,x2:`16`,y1:`12`,y2:`12`,key:`1jonct`}]]),R=f(v()),z=x();function B(){let{id:f}=re.useParams(),h=ie(),{data:v}=t(_(f)),{data:x}=t(ne),B=v.Volumes?.[0],V=c(),H=l(),U=s(),[W,G]=(0,R.useState)(null),[K,q]=(0,R.useState)(``),[J,Y]=(0,R.useState)(``),[X,Z]=(0,R.useState)(!1),oe=x.Reservations?.flatMap(e=>e.Instances?.filter(e=>e.State?.Name===`running`)??[])??[],Q=B?.State===`available`&&(!B.Attachments||B.Attachments.length===0),$=()=>G(null);return B?.VolumeId?(0,z.jsxs)(z.Fragment,{children:[(0,z.jsx)(n,{to:`/ec2/describe-volumes`,children:`Back to volumes`}),V.error&&(0,z.jsx)(e,{error:V.error,msg:`Failed to delete volume`}),H.error&&(0,z.jsx)(e,{error:H.error,msg:`Failed to attach volume`}),U.error&&(0,z.jsx)(e,{error:U.error,msg:`Failed to detach volume`}),(0,z.jsxs)(`div`,{className:`space-y-6`,children:[(0,z.jsx)(ae,{actions:(0,z.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,z.jsxs)(p,{disabled:!Q,onClick:()=>G(`delete`),size:`sm`,variant:`destructive`,children:[(0,z.jsx)(o,{className:`size-4`}),`Delete`]}),Q?(0,z.jsx)(b,{className:u({variant:`outline`}),params:{id:B.VolumeId},to:`/ec2/modify-volume/$id`,children:`Resize Volume`}):(0,z.jsx)(p,{disabled:!0,variant:`outline`,children:`Resize Volume`}),Q?(0,z.jsxs)(p,{onClick:()=>G(`attach`),size:`sm`,variant:`outline`,children:[(0,z.jsx)(L,{className:`size-4`}),`Attach`]}):null,B.Attachments&&B.Attachments.length>0?(0,z.jsxs)(p,{onClick:()=>G(`detach`),size:`sm`,variant:`outline`,children:[(0,z.jsx)(I,{className:`size-4`}),`Detach`]}):null,(0,z.jsxs)(b,{className:u({variant:`outline`,size:`sm`}),search:{volumeId:B.VolumeId},to:`/ec2/create-snapshot`,children:[(0,z.jsx)(g,{className:`size-4`}),`Create Snapshot`]}),(0,z.jsx)(S,{state:B.State})]}),subtitle:`Volume Details`,title:B.VolumeId}),(0,z.jsxs)(C,{children:[(0,z.jsx)(C.Header,{children:`Volume Information`}),(0,z.jsxs)(C.Content,{children:[(0,z.jsx)(w,{label:`Volume ID`,value:B.VolumeId}),(0,z.jsx)(w,{label:`Size`,value:`${B.Size} GiB`}),(0,z.jsx)(w,{label:`Volume Type`,value:B.VolumeType}),(0,z.jsx)(w,{label:`State`,value:B.State}),(0,z.jsx)(w,{label:`Availability Zone`,value:B.AvailabilityZone}),(0,z.jsx)(w,{label:`Create Time`,value:y(B.CreateTime)}),(0,z.jsx)(w,{label:`Encrypted`,value:B.Encrypted?`Yes`:`No`}),(0,z.jsx)(w,{label:`KMS Key ID`,value:B.KmsKeyId})]})]}),B.Attachments&&B.Attachments.length>0&&(0,z.jsxs)(C,{children:[(0,z.jsx)(C.Header,{children:`Attachments`}),B.Attachments.map(e=>(0,z.jsxs)(C.Content,{children:[(0,z.jsx)(w,{label:`Instance ID`,value:e.InstanceId?(0,z.jsx)(b,{className:`text-primary hover:underline`,params:{id:e.InstanceId},to:`/ec2/describe-instances/$id`,children:e.InstanceId}):void 0}),(0,z.jsx)(w,{label:`Device`,value:e.Device}),(0,z.jsx)(w,{label:`Status`,value:e.State}),(0,z.jsx)(w,{label:`Attach Time`,value:y(e.AttachTime)}),(0,z.jsx)(w,{label:`Delete on Termination`,value:e.DeleteOnTermination?`Yes`:`No`})]},e.InstanceId))]})]}),(0,z.jsx)(F,{description:`Are you sure you want to delete the volume "${B.VolumeId}"? This action cannot be undone.`,isPending:V.isPending,onConfirm:async()=>{try{await V.mutateAsync(f),h({to:`/ec2/describe-volumes`})}finally{$()}},onOpenChange:e=>{e||$()},open:W===`delete`,title:`Delete Volume`}),(0,z.jsx)(M,{onOpenChange:e=>{e||($(),q(``),Y(``))},open:W===`attach`,children:(0,z.jsxs)(E,{children:[(0,z.jsxs)(j,{children:[(0,z.jsx)(D,{children:`Attach Volume`}),(0,z.jsx)(T,{children:`Attach this volume to a running instance.`})]}),(0,z.jsxs)(P,{children:[(0,z.jsx)(N,{children:(0,z.jsx)(`label`,{htmlFor:`attachInstance`,children:`Instance`})}),(0,z.jsxs)(te,{onValueChange:e=>q(e??``),value:K,children:[(0,z.jsx)(a,{className:`w-full`,id:`attachInstance`,children:(0,z.jsx)(ee,{placeholder:`Select an instance`})}),(0,z.jsx)(i,{children:oe.map(e=>{let t=d(e.Tags);return(0,z.jsxs)(r,{value:e.InstanceId??``,children:[e.InstanceId,t?` (${t})`:``]},e.InstanceId)})})]})]}),(0,z.jsxs)(P,{children:[(0,z.jsx)(N,{children:(0,z.jsx)(`label`,{htmlFor:`attachDevice`,children:`Device (optional)`})}),(0,z.jsx)(m,{id:`attachDevice`,onChange:e=>Y(e.target.value),placeholder:`/dev/sdf`,value:J})]}),(0,z.jsxs)(k,{children:[(0,z.jsx)(A,{children:`Cancel`}),(0,z.jsx)(O,{disabled:H.isPending||!K,onClick:async()=>{try{await H.mutateAsync({volumeId:f,instanceId:K,device:J||void 0}),$(),q(``),Y(``)}catch{}},children:H.isPending?`Attaching…`:`Attach`})]})]})}),(0,z.jsx)(M,{onOpenChange:e=>{e||($(),Z(!1))},open:W===`detach`,children:(0,z.jsxs)(E,{children:[(0,z.jsxs)(j,{children:[(0,z.jsx)(D,{children:`Detach Volume`}),(0,z.jsxs)(T,{children:[`Are you sure you want to detach the volume "`,B.VolumeId,`" from instance "`,B.Attachments?.[0]?.InstanceId,`"?`]})]}),(0,z.jsxs)(`label`,{className:`flex items-center gap-2 text-sm`,children:[(0,z.jsx)(`input`,{"aria-label":`Force detach`,checked:X,onChange:e=>Z(e.target.checked),type:`checkbox`}),`Force detach`]}),(0,z.jsxs)(k,{children:[(0,z.jsx)(A,{children:`Cancel`}),(0,z.jsx)(O,{disabled:U.isPending,onClick:async()=>{let e=B?.Attachments?.[0]?.InstanceId;try{await U.mutateAsync({volumeId:f,instanceId:e??void 0,force:X||void 0}),$(),Z(!1)}catch{}},children:U.isPending?`Detaching…`:`Detach`})]})]})})]}):(0,z.jsxs)(z.Fragment,{children:[(0,z.jsx)(n,{to:`/ec2/describe-volumes`,children:`Back to volumes`}),(0,z.jsx)(`p`,{className:`text-muted-foreground`,children:`Volume not found.`})]})}export{B as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{c as ee,i as r,n as i,s as a,t as te}from"./select.js";import{t as o}from"./trash-2.js";import{S as s,b as c,t as ne}from"./ec2.js";import{Ba as l,Co as u,Ga as d,Ja as f,Jo as p,Oo as m,U as h,ko as g,lo as _,tt as re,u as ie,uo as v,wo as y,za as b,zi as ae}from"./index.js";import{t as x}from"./page-heading.js";import{t as S}from"./state-badge.js";import{n as C,t as w}from"./detail-row.js";import{a as T,i as E,l as D,n as O,o as k,r as A,s as j,t as M}from"./alert-dialog.js";import{a as N,t as P}from"./field.js";import{t as F}from"./delete-confirmation-dialog.js";var I=v(`link-2-off`,[[`path`,{d:`M9 17H7A5 5 0 0 1 7 7`,key:`10o201`}],[`path`,{d:`M15 7h2a5 5 0 0 1 4 8`,key:`1d3206`}],[`line`,{x1:`8`,x2:`12`,y1:`12`,y2:`12`,key:`rvw6j4`}],[`line`,{x1:`2`,x2:`22`,y1:`2`,y2:`22`,key:`a6p6uj`}]]),L=v(`link-2`,[[`path`,{d:`M9 17H7A5 5 0 0 1 7 7h2`,key:`8i5ue5`}],[`path`,{d:`M15 7h2a5 5 0 1 1 0 10h-2`,key:`1b9ql8`}],[`line`,{x1:`8`,x2:`16`,y1:`12`,y2:`12`,key:`1jonct`}]]),R=p(g()),z=m();function B(){let{id:p}=ie.useParams(),m=y(),{data:g}=t(re(p)),{data:v}=t(h),B=g.Volumes?.[0],V=c(),H=ne(),U=s(),[W,G]=(0,R.useState)(null),[K,q]=(0,R.useState)(``),[J,Y]=(0,R.useState)(``),[X,Z]=(0,R.useState)(!1),oe=v.Reservations?.flatMap(e=>e.Instances?.filter(e=>e.State?.Name===`running`)??[])??[],Q=B?.State===`available`&&(!B.Attachments||B.Attachments.length===0),$=()=>G(null);return B?.VolumeId?(0,z.jsxs)(z.Fragment,{children:[(0,z.jsx)(n,{to:`/ec2/describe-volumes`,children:`Back to volumes`}),V.error&&(0,z.jsx)(e,{error:V.error,msg:`Failed to delete volume`}),H.error&&(0,z.jsx)(e,{error:H.error,msg:`Failed to attach volume`}),U.error&&(0,z.jsx)(e,{error:U.error,msg:`Failed to detach volume`}),(0,z.jsxs)(`div`,{className:`space-y-6`,children:[(0,z.jsx)(x,{actions:(0,z.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,z.jsxs)(b,{disabled:!Q,onClick:()=>G(`delete`),size:`sm`,variant:`destructive`,children:[(0,z.jsx)(o,{className:`size-4`}),`Delete`]}),Q?(0,z.jsx)(u,{className:l({variant:`outline`}),params:{id:B.VolumeId},to:`/ec2/modify-volume/$id`,children:`Resize Volume`}):(0,z.jsx)(b,{disabled:!0,variant:`outline`,children:`Resize Volume`}),Q?(0,z.jsxs)(b,{onClick:()=>G(`attach`),size:`sm`,variant:`outline`,children:[(0,z.jsx)(L,{className:`size-4`}),`Attach`]}):null,B.Attachments&&B.Attachments.length>0?(0,z.jsxs)(b,{onClick:()=>G(`detach`),size:`sm`,variant:`outline`,children:[(0,z.jsx)(I,{className:`size-4`}),`Detach`]}):null,(0,z.jsxs)(u,{className:l({variant:`outline`,size:`sm`}),search:{volumeId:B.VolumeId},to:`/ec2/create-snapshot`,children:[(0,z.jsx)(_,{className:`size-4`}),`Create Snapshot`]}),(0,z.jsx)(S,{state:B.State})]}),subtitle:`Volume Details`,title:B.VolumeId}),(0,z.jsxs)(C,{children:[(0,z.jsx)(C.Header,{children:`Volume Information`}),(0,z.jsxs)(C.Content,{children:[(0,z.jsx)(w,{label:`Volume ID`,value:B.VolumeId}),(0,z.jsx)(w,{label:`Size`,value:`${B.Size} GiB`}),(0,z.jsx)(w,{label:`Volume Type`,value:B.VolumeType}),(0,z.jsx)(w,{label:`State`,value:B.State}),(0,z.jsx)(w,{label:`Availability Zone`,value:B.AvailabilityZone}),(0,z.jsx)(w,{label:`Create Time`,value:d(B.CreateTime)}),(0,z.jsx)(w,{label:`Encrypted`,value:B.Encrypted?`Yes`:`No`}),(0,z.jsx)(w,{label:`KMS Key ID`,value:B.KmsKeyId})]})]}),B.Attachments&&B.Attachments.length>0&&(0,z.jsxs)(C,{children:[(0,z.jsx)(C.Header,{children:`Attachments`}),B.Attachments.map(e=>(0,z.jsxs)(C.Content,{children:[(0,z.jsx)(w,{label:`Instance ID`,value:e.InstanceId?(0,z.jsx)(u,{className:`text-primary hover:underline`,params:{id:e.InstanceId},to:`/ec2/describe-instances/$id`,children:e.InstanceId}):void 0}),(0,z.jsx)(w,{label:`Device`,value:e.Device}),(0,z.jsx)(w,{label:`Status`,value:e.State}),(0,z.jsx)(w,{label:`Attach Time`,value:d(e.AttachTime)}),(0,z.jsx)(w,{label:`Delete on Termination`,value:e.DeleteOnTermination?`Yes`:`No`})]},e.InstanceId))]})]}),(0,z.jsx)(F,{description:`Are you sure you want to delete the volume "${B.VolumeId}"? This action cannot be undone.`,isPending:V.isPending,onConfirm:async()=>{try{await V.mutateAsync(p),m({to:`/ec2/describe-volumes`})}finally{$()}},onOpenChange:e=>{e||$()},open:W===`delete`,title:`Delete Volume`}),(0,z.jsx)(M,{onOpenChange:e=>{e||($(),q(``),Y(``))},open:W===`attach`,children:(0,z.jsxs)(E,{children:[(0,z.jsxs)(j,{children:[(0,z.jsx)(D,{children:`Attach Volume`}),(0,z.jsx)(T,{children:`Attach this volume to a running instance.`})]}),(0,z.jsxs)(P,{children:[(0,z.jsx)(N,{children:(0,z.jsx)(`label`,{htmlFor:`attachInstance`,children:`Instance`})}),(0,z.jsxs)(te,{onValueChange:e=>q(e??``),value:K,children:[(0,z.jsx)(a,{className:`w-full`,id:`attachInstance`,children:(0,z.jsx)(ee,{placeholder:`Select an instance`})}),(0,z.jsx)(i,{children:oe.map(e=>{let t=f(e.Tags);return(0,z.jsxs)(r,{value:e.InstanceId??``,children:[e.InstanceId,t?` (${t})`:``]},e.InstanceId)})})]})]}),(0,z.jsxs)(P,{children:[(0,z.jsx)(N,{children:(0,z.jsx)(`label`,{htmlFor:`attachDevice`,children:`Device (optional)`})}),(0,z.jsx)(ae,{id:`attachDevice`,onChange:e=>Y(e.target.value),placeholder:`/dev/sdf`,value:J})]}),(0,z.jsxs)(k,{children:[(0,z.jsx)(A,{children:`Cancel`}),(0,z.jsx)(O,{disabled:H.isPending||!K,onClick:async()=>{try{await H.mutateAsync({volumeId:p,instanceId:K,device:J||void 0}),$(),q(``),Y(``)}catch{}},children:H.isPending?`Attaching…`:`Attach`})]})]})}),(0,z.jsx)(M,{onOpenChange:e=>{e||($(),Z(!1))},open:W===`detach`,children:(0,z.jsxs)(E,{children:[(0,z.jsxs)(j,{children:[(0,z.jsx)(D,{children:`Detach Volume`}),(0,z.jsxs)(T,{children:[`Are you sure you want to detach the volume "`,B.VolumeId,`" from instance "`,B.Attachments?.[0]?.InstanceId,`"?`]})]}),(0,z.jsxs)(`label`,{className:`flex items-center gap-2 text-sm`,children:[(0,z.jsx)(`input`,{"aria-label":`Force detach`,checked:X,onChange:e=>Z(e.target.checked),type:`checkbox`}),`Force detach`]}),(0,z.jsxs)(k,{children:[(0,z.jsx)(A,{children:`Cancel`}),(0,z.jsx)(O,{disabled:U.isPending,onClick:async()=>{let e=B?.Attachments?.[0]?.InstanceId;try{await U.mutateAsync({volumeId:p,instanceId:e??void 0,force:X||void 0}),$(),Z(!1)}catch{}},children:U.isPending?`Detaching…`:`Detach`})]})]})})]}):(0,z.jsxs)(z.Fragment,{children:[(0,z.jsx)(n,{to:`/ec2/describe-volumes`,children:`Back to volumes`}),(0,z.jsx)(`p`,{className:`text-muted-foreground`,children:`Volume not found.`})]})}export{B as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_id11.js b/spinifex/services/spinifexui/frontend/dist/assets/_id11.js index 4f524ad70..f0efacf12 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_id11.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_id11.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{E as r}from"./ec2.js";import{Ti as i,d as a,et as o,mo as s,so as c,uo as l}from"./index.js";import{t as u}from"./page-heading.js";import{a as d,r as f,t as p}from"./field.js";import{i as m,t as h}from"./zod.js";import{d as g}from"./ec22.js";import{t as _}from"./form-actions.js";var v=c(),y=s();function b(){let s=(0,v.c)(53),{id:c}=a.useParams(),b=l(),x;s[0]===c?x=s[1]:(x=o(c),s[0]=c,s[1]=x);let{data:S}=t(x),C=S.Volumes?.[0],w=C?.VolumeId,T=r(),E=C?.Size??1,D;s[2]===E?D=s[3]:(D=h(g.refine(e=>e.size>E,{message:`New size must be greater than current size (${E} GiB)`,path:[`size`]})),s[2]=E,s[3]=D);let O;s[4]===E?O=s[5]:(O={size:E},s[4]=E,s[5]=O);let k;s[6]!==D||s[7]!==O?(k={resolver:D,defaultValues:O},s[6]=D,s[7]=O,s[8]=k):k=s[8];let{handleSubmit:A,register:j,formState:M}=m(k),{errors:N,isSubmitting:P}=M;if(!w){let e;return s[9]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,y.jsxs)(y.Fragment,{children:[(0,y.jsx)(n,{to:`/ec2/describe-volumes`,children:`Back to volumes`}),(0,y.jsx)(`p`,{className:`text-muted-foreground`,children:`Volume not found.`})]}),s[9]=e):e=s[9],e}let F;s[10]!==T||s[11]!==b||s[12]!==w?(F=async e=>{await T.mutateAsync({...e,volumeId:w}),b({to:`/ec2/describe-volumes/$id`,params:{id:w}})},s[10]=T,s[11]=b,s[12]=w,s[13]=F):F=s[13];let I=F,L,R;s[14]===w?(L=s[15],R=s[16]):(L=(0,y.jsx)(n,{params:{id:w},to:`/ec2/describe-volumes/$id`,children:`Back to volume`}),R=(0,y.jsx)(u,{subtitle:w,title:`Resize Volume`}),s[14]=w,s[15]=L,s[16]=R);let z;s[17]===T.error?z=s[18]:(z=T.error&&(0,y.jsx)(e,{error:T.error,msg:`Failed to resize volume`}),s[17]=T.error,s[18]=z);let B;s[19]!==A||s[20]!==I?(B=A(I),s[19]=A,s[20]=I,s[21]=B):B=s[21];let V;s[22]===E?V=s[23]:(V=(0,y.jsx)(`div`,{className:`space-y-2`,children:(0,y.jsxs)(`p`,{className:`text-sm text-muted-foreground`,children:[`Current size: `,E,` GiB`]})}),s[22]=E,s[23]=V);let H;s[24]===Symbol.for(`react.memo_cache_sentinel`)?(H=(0,y.jsx)(d,{children:(0,y.jsx)(`label`,{htmlFor:`size`,children:`New size (GiB)`})}),s[24]=H):H=s[24];let U=!!N.size,W=E+1,G;s[25]===j?G=s[26]:(G=j(`size`,{valueAsNumber:!0}),s[25]=j,s[26]=G);let K;s[27]!==U||s[28]!==W||s[29]!==G?(K=(0,y.jsx)(i,{"aria-invalid":U,id:`size`,min:W,type:`number`,...G}),s[27]=U,s[28]=W,s[29]=G,s[30]=K):K=s[30];let q;s[31]===N.size?q=s[32]:(q=(0,y.jsx)(f,{errors:[N.size]}),s[31]=N.size,s[32]=q);let J;s[33]!==K||s[34]!==q?(J=(0,y.jsxs)(p,{children:[H,K,q]}),s[33]=K,s[34]=q,s[35]=J):J=s[35];let Y;s[36]!==b||s[37]!==w?(Y=async()=>await b({to:`/ec2/describe-volumes/$id`,params:{id:w}}),s[36]=b,s[37]=w,s[38]=Y):Y=s[38];let X;s[39]!==P||s[40]!==T.isPending||s[41]!==Y?(X=(0,y.jsx)(_,{isPending:T.isPending,isSubmitting:P,onCancel:Y,pendingLabel:`Resizing\\u2026`,submitLabel:`Resize Volume`}),s[39]=P,s[40]=T.isPending,s[41]=Y,s[42]=X):X=s[42];let Z;s[43]!==V||s[44]!==J||s[45]!==X||s[46]!==B?(Z=(0,y.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:B,children:[V,J,X]}),s[43]=V,s[44]=J,s[45]=X,s[46]=B,s[47]=Z):Z=s[47];let Q;return s[48]!==Z||s[49]!==L||s[50]!==R||s[51]!==z?(Q=(0,y.jsxs)(y.Fragment,{children:[L,R,z,Z]}),s[48]=Z,s[49]=L,s[50]=R,s[51]=z,s[52]=Q):Q=s[52],Q}export{b as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{E as r}from"./ec2.js";import{Oo as i,d as a,tt as o,wo as s,xo as c,zi as l}from"./index.js";import{t as u}from"./page-heading.js";import{a as d,r as f,t as p}from"./field.js";import{i as m,t as h}from"./zod.js";import{d as g}from"./ec22.js";import{t as _}from"./form-actions.js";var v=c(),y=i();function b(){let i=(0,v.c)(53),{id:c}=a.useParams(),b=s(),x;i[0]===c?x=i[1]:(x=o(c),i[0]=c,i[1]=x);let{data:S}=t(x),C=S.Volumes?.[0],w=C?.VolumeId,T=r(),E=C?.Size??1,D;i[2]===E?D=i[3]:(D=h(g.refine(e=>e.size>E,{message:`New size must be greater than current size (${E} GiB)`,path:[`size`]})),i[2]=E,i[3]=D);let O;i[4]===E?O=i[5]:(O={size:E},i[4]=E,i[5]=O);let k;i[6]!==D||i[7]!==O?(k={resolver:D,defaultValues:O},i[6]=D,i[7]=O,i[8]=k):k=i[8];let{handleSubmit:A,register:j,formState:M}=m(k),{errors:N,isSubmitting:P}=M;if(!w){let e;return i[9]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,y.jsxs)(y.Fragment,{children:[(0,y.jsx)(n,{to:`/ec2/describe-volumes`,children:`Back to volumes`}),(0,y.jsx)(`p`,{className:`text-muted-foreground`,children:`Volume not found.`})]}),i[9]=e):e=i[9],e}let F;i[10]!==T||i[11]!==b||i[12]!==w?(F=async e=>{await T.mutateAsync({...e,volumeId:w}),b({to:`/ec2/describe-volumes/$id`,params:{id:w}})},i[10]=T,i[11]=b,i[12]=w,i[13]=F):F=i[13];let I=F,L,R;i[14]===w?(L=i[15],R=i[16]):(L=(0,y.jsx)(n,{params:{id:w},to:`/ec2/describe-volumes/$id`,children:`Back to volume`}),R=(0,y.jsx)(u,{subtitle:w,title:`Resize Volume`}),i[14]=w,i[15]=L,i[16]=R);let z;i[17]===T.error?z=i[18]:(z=T.error&&(0,y.jsx)(e,{error:T.error,msg:`Failed to resize volume`}),i[17]=T.error,i[18]=z);let B;i[19]!==A||i[20]!==I?(B=A(I),i[19]=A,i[20]=I,i[21]=B):B=i[21];let V;i[22]===E?V=i[23]:(V=(0,y.jsx)(`div`,{className:`space-y-2`,children:(0,y.jsxs)(`p`,{className:`text-sm text-muted-foreground`,children:[`Current size: `,E,` GiB`]})}),i[22]=E,i[23]=V);let H;i[24]===Symbol.for(`react.memo_cache_sentinel`)?(H=(0,y.jsx)(d,{children:(0,y.jsx)(`label`,{htmlFor:`size`,children:`New size (GiB)`})}),i[24]=H):H=i[24];let U=!!N.size,W=E+1,G;i[25]===j?G=i[26]:(G=j(`size`,{valueAsNumber:!0}),i[25]=j,i[26]=G);let K;i[27]!==U||i[28]!==W||i[29]!==G?(K=(0,y.jsx)(l,{"aria-invalid":U,id:`size`,min:W,type:`number`,...G}),i[27]=U,i[28]=W,i[29]=G,i[30]=K):K=i[30];let q;i[31]===N.size?q=i[32]:(q=(0,y.jsx)(f,{errors:[N.size]}),i[31]=N.size,i[32]=q);let J;i[33]!==K||i[34]!==q?(J=(0,y.jsxs)(p,{children:[H,K,q]}),i[33]=K,i[34]=q,i[35]=J):J=i[35];let Y;i[36]!==b||i[37]!==w?(Y=async()=>await b({to:`/ec2/describe-volumes/$id`,params:{id:w}}),i[36]=b,i[37]=w,i[38]=Y):Y=i[38];let X;i[39]!==P||i[40]!==T.isPending||i[41]!==Y?(X=(0,y.jsx)(_,{isPending:T.isPending,isSubmitting:P,onCancel:Y,pendingLabel:`Resizing\\u2026`,submitLabel:`Resize Volume`}),i[39]=P,i[40]=T.isPending,i[41]=Y,i[42]=X):X=i[42];let Z;i[43]!==V||i[44]!==J||i[45]!==X||i[46]!==B?(Z=(0,y.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:B,children:[V,J,X]}),i[43]=V,i[44]=J,i[45]=X,i[46]=B,i[47]=Z):Z=i[47];let Q;return i[48]!==Z||i[49]!==L||i[50]!==R||i[51]!==z?(Q=(0,y.jsxs)(y.Fragment,{children:[L,R,z,Z]}),i[48]=Z,i[49]=L,i[50]=R,i[51]=z,i[52]=Q):Q=i[52],Q}export{b as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_id12.js b/spinifex/services/spinifexui/frontend/dist/assets/_id12.js index 33d0f9924..26be00fb3 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_id12.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_id12.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./trash-2.js";import{x as i}from"./ec2.js";import{$ as a,Pa as o,Po as s,Ta as c,f as l,ho as u,lo as d,mo as f,nt as p,uo as m}from"./index.js";import{t as h}from"./page-heading.js";import{t as g}from"./state-badge.js";import{n as _,t as v}from"./detail-row.js";import{t as y}from"./delete-confirmation-dialog.js";var b=s(u()),x=f();function S(){let{id:s}=l.useParams(),u=m(),{data:f}=t(p(s)),{data:S}=t(a),C=f.Vpcs?.[0],w=i(),[T,E]=(0,b.useState)(!1),D=S.Subnets?.filter(e=>e.VpcId===s)??[],O=async()=>{try{await w.mutateAsync(s),u({to:`/ec2/describe-vpcs`})}finally{E(!1)}};if(!C?.VpcId)return(0,x.jsxs)(x.Fragment,{children:[(0,x.jsx)(n,{to:`/ec2/describe-vpcs`,children:`Back to VPCs`}),(0,x.jsx)(`p`,{className:`text-muted-foreground`,children:`VPC not found.`})]});let k=o(C.Tags);return(0,x.jsxs)(x.Fragment,{children:[(0,x.jsx)(n,{to:`/ec2/describe-vpcs`,children:`Back to VPCs`}),w.error&&(0,x.jsx)(e,{error:w.error,msg:`Failed to delete VPC`}),(0,x.jsxs)(`div`,{className:`space-y-6`,children:[(0,x.jsx)(h,{actions:(0,x.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,x.jsxs)(c,{onClick:()=>E(!0),size:`sm`,variant:`destructive`,children:[(0,x.jsx)(r,{className:`size-4`}),`Delete`]}),(0,x.jsx)(g,{state:C.State})]}),subtitle:`VPC Details`,title:k?`${C.VpcId} (${k})`:C.VpcId}),(0,x.jsxs)(_,{children:[(0,x.jsx)(_.Header,{children:`VPC Information`}),(0,x.jsxs)(_.Content,{children:[(0,x.jsx)(v,{label:`VPC ID`,value:C.VpcId}),(0,x.jsx)(v,{label:`State`,value:C.State}),(0,x.jsx)(v,{label:`CIDR Block`,value:C.CidrBlock}),(0,x.jsx)(v,{label:`Is Default`,value:C.IsDefault?`Yes`:`No`}),(0,x.jsx)(v,{label:`DHCP Options ID`,value:C.DhcpOptionsId}),(0,x.jsx)(v,{label:`Instance Tenancy`,value:C.InstanceTenancy}),(0,x.jsx)(v,{label:`Owner ID`,value:C.OwnerId})]})]}),D.length>0&&(0,x.jsxs)(_,{children:[(0,x.jsxs)(_.Header,{children:[`Subnets (`,D.length,`)`]}),D.map(e=>e.SubnetId?(0,x.jsxs)(_.Content,{children:[(0,x.jsx)(v,{label:`Subnet ID`,value:(0,x.jsx)(d,{className:`text-primary hover:underline`,params:{id:e.SubnetId},to:`/ec2/describe-subnets/$id`,children:e.SubnetId})}),(0,x.jsx)(v,{label:`CIDR Block`,value:e.CidrBlock}),(0,x.jsx)(v,{label:`Availability Zone`,value:e.AvailabilityZone}),(0,x.jsx)(v,{label:`State`,value:e.State})]},e.SubnetId):null)]})]}),(0,x.jsx)(y,{description:`Are you sure you want to delete the VPC "${C.VpcId}"? This action cannot be undone. The VPC must have no associated subnets or internet gateways.`,isPending:w.isPending,onConfirm:O,onOpenChange:E,open:T,title:`Delete VPC`})]})}export{S as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./trash-2.js";import{x as i}from"./ec2.js";import{Co as a,Ja as o,Jo as s,Oo as c,et as l,f as u,ko as d,rt as f,wo as p,za as m}from"./index.js";import{t as h}from"./page-heading.js";import{t as g}from"./state-badge.js";import{n as _,t as v}from"./detail-row.js";import{t as y}from"./delete-confirmation-dialog.js";var b=s(d()),x=c();function S(){let{id:s}=u.useParams(),c=p(),{data:d}=t(f(s)),{data:S}=t(l),C=d.Vpcs?.[0],w=i(),[T,E]=(0,b.useState)(!1),D=S.Subnets?.filter(e=>e.VpcId===s)??[],O=async()=>{try{await w.mutateAsync(s),c({to:`/ec2/describe-vpcs`})}finally{E(!1)}};if(!C?.VpcId)return(0,x.jsxs)(x.Fragment,{children:[(0,x.jsx)(n,{to:`/ec2/describe-vpcs`,children:`Back to VPCs`}),(0,x.jsx)(`p`,{className:`text-muted-foreground`,children:`VPC not found.`})]});let k=o(C.Tags);return(0,x.jsxs)(x.Fragment,{children:[(0,x.jsx)(n,{to:`/ec2/describe-vpcs`,children:`Back to VPCs`}),w.error&&(0,x.jsx)(e,{error:w.error,msg:`Failed to delete VPC`}),(0,x.jsxs)(`div`,{className:`space-y-6`,children:[(0,x.jsx)(h,{actions:(0,x.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,x.jsxs)(m,{onClick:()=>E(!0),size:`sm`,variant:`destructive`,children:[(0,x.jsx)(r,{className:`size-4`}),`Delete`]}),(0,x.jsx)(g,{state:C.State})]}),subtitle:`VPC Details`,title:k?`${C.VpcId} (${k})`:C.VpcId}),(0,x.jsxs)(_,{children:[(0,x.jsx)(_.Header,{children:`VPC Information`}),(0,x.jsxs)(_.Content,{children:[(0,x.jsx)(v,{label:`VPC ID`,value:C.VpcId}),(0,x.jsx)(v,{label:`State`,value:C.State}),(0,x.jsx)(v,{label:`CIDR Block`,value:C.CidrBlock}),(0,x.jsx)(v,{label:`Is Default`,value:C.IsDefault?`Yes`:`No`}),(0,x.jsx)(v,{label:`DHCP Options ID`,value:C.DhcpOptionsId}),(0,x.jsx)(v,{label:`Instance Tenancy`,value:C.InstanceTenancy}),(0,x.jsx)(v,{label:`Owner ID`,value:C.OwnerId})]})]}),D.length>0&&(0,x.jsxs)(_,{children:[(0,x.jsxs)(_.Header,{children:[`Subnets (`,D.length,`)`]}),D.map(e=>e.SubnetId?(0,x.jsxs)(_.Content,{children:[(0,x.jsx)(v,{label:`Subnet ID`,value:(0,x.jsx)(a,{className:`text-primary hover:underline`,params:{id:e.SubnetId},to:`/ec2/describe-subnets/$id`,children:e.SubnetId})}),(0,x.jsx)(v,{label:`CIDR Block`,value:e.CidrBlock}),(0,x.jsx)(v,{label:`Availability Zone`,value:e.AvailabilityZone}),(0,x.jsx)(v,{label:`State`,value:e.State})]},e.SubnetId):null)]})]}),(0,x.jsx)(y,{description:`Are you sure you want to delete the VPC "${C.VpcId}"? This action cannot be undone. The VPC must have no associated subnets or internet gateways.`,isPending:w.isPending,onConfirm:O,onOpenChange:E,open:T,title:`Delete VPC`})]})}export{S as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_id2.js b/spinifex/services/spinifexui/frontend/dist/assets/_id2.js index c488bda8e..5fa9b0470 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_id2.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_id2.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./useQuery.js";import{t as n}from"./useSuspenseQuery.js";import{t as r}from"./back-link.js";import{c as i,i as a,n as o,s,t as c}from"./select.js";import{t as l}from"./trash-2.js";import{A as u,C as d,D as f,M as p,T as m,a as h,j as g}from"./ec2.js";import{B as _,Gn as v,Na as y,Po as b,R as x,Ta as S,Ti as C,V as w,Xa as T,ho as E,ja as D,lo as O,mo as k,n as A,so as j}from"./index.js";import{t as ee}from"./page-heading.js";import{t as te}from"./state-badge.js";import{n as M,t as N}from"./detail-row.js";import{t as ne}from"./ami-details.js";import{a as P,i as F,l as I,n as L,o as R,r as z,s as B,t as V}from"./alert-dialog.js";import{a as H,t as U}from"./field.js";import{r as re}from"./admin.js";import{t as W}from"./textarea.js";import{t as G}from"./delete-confirmation-dialog.js";var ie=T(`image-plus`,[[`path`,{d:`M16 5h6`,key:`1vod17`}],[`path`,{d:`M19 2v6`,key:`4bpg5p`}],[`path`,{d:`M21 11.5V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7.5`,key:`1ue2ih`}],[`path`,{d:`m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21`,key:`1xmnt7`}],[`circle`,{cx:`9`,cy:`9`,r:`2`,key:`af1f0g`}]]),K=T(`pause`,[[`rect`,{x:`14`,y:`3`,width:`5`,height:`18`,rx:`1`,key:`kaeet6`}],[`rect`,{x:`5`,y:`3`,width:`5`,height:`18`,rx:`1`,key:`1wsw3u`}]]),q=T(`play`,[[`path`,{d:`M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z`,key:`10ikf1`}]]),J=T(`rotate-cw`,[[`path`,{d:`M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8`,key:`1p45f6`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}]]),ae=T(`settings-2`,[[`path`,{d:`M14 17H5`,key:`gfn3mx`}],[`path`,{d:`M19 7h-9`,key:`6i9tg`}],[`circle`,{cx:`17`,cy:`17`,r:`3`,key:`18b49y`}],[`circle`,{cx:`7`,cy:`7`,r:`3`,key:`dfmy0x`}]]),oe=T(`terminal`,[[`path`,{d:`M12 19h8`,key:`baeox8`}],[`path`,{d:`m4 17 6-6-6-6`,key:`1yngyt`}]]),Y=b(E(),1),X=k();function se({instanceId:e,open:t,onOpenChange:n}){let r=h(),[i,a]=(0,Y.useState)(``),[o,s]=(0,Y.useState)(``),[c,l]=(0,Y.useState)(null);function u(e){e||(a(``),s(``),l(null)),n(e)}async function d(){try{l((await r.mutateAsync({instanceId:e,name:i,description:o||void 0})).ImageId??null),a(``),s(``)}catch{}}return(0,X.jsx)(V,{onOpenChange:u,open:t,children:(0,X.jsxs)(F,{children:[(0,X.jsxs)(B,{children:[(0,X.jsx)(I,{children:c?`Image Created`:`Create Image (AMI)`}),(0,X.jsx)(P,{children:c?`Image "${c}" was created successfully.`:`Create an AMI from instance "${e}".`})]}),!c&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsxs)(U,{children:[(0,X.jsx)(H,{children:(0,X.jsx)(`label`,{htmlFor:`imageName`,children:`Name`})}),(0,X.jsx)(C,{id:`imageName`,onChange:e=>a(e.target.value),placeholder:`my-image`,value:i})]}),(0,X.jsxs)(U,{children:[(0,X.jsx)(H,{children:(0,X.jsx)(`label`,{htmlFor:`imageDescription`,children:`Description`})}),(0,X.jsx)(W,{id:`imageDescription`,onChange:e=>s(e.target.value),placeholder:`Optional description`,rows:2,value:o})]})]}),(0,X.jsxs)(R,{children:[(0,X.jsx)(z,{children:c?`Close`:`Cancel`}),!c&&(0,X.jsx)(L,{disabled:r.isPending||!i.trim(),onClick:d,children:r.isPending?`Creating…`:`Create Image`})]})]})})}var Z=j(),Q=new Set([`pending`,`stopping`,`shutting-down`,`terminated`]);function ce(t){let n=(0,Z.c)(43),{instanceId:r,state:i}=t,a=u(),o=g(),s=f(),c=p(),[d,m]=(0,Y.useState)(!1),h=Q.has(i??``),_;n[0]!==r||n[1]!==c?(_=()=>{c.mutate(r,{onSettled:()=>m(!1)})},n[0]=r,n[1]=c,n[2]=_):_=n[2];let v=_;if(h&&i!==`terminated`){let e;return n[3]===i?e=n[4]:(e=(0,X.jsx)(`div`,{className:`rounded-lg border bg-muted/50 p-4`,children:(0,X.jsxs)(`p`,{className:`text-center text-sm text-muted-foreground`,children:[`Instance is `,i,`. Actions will be available once the operation completes.`]})}),n[3]=i,n[4]=e),e}if(i===`terminated`){let e;return n[5]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,X.jsx)(`div`,{className:`rounded-lg border bg-muted/50 p-4`,children:(0,X.jsx)(`p`,{className:`text-center text-sm text-muted-foreground`,children:`This instance has been terminated and cannot be managed.`})}),n[5]=e):e=n[5],e}let y;n[6]===Symbol.for(`react.memo_cache_sentinel`)?(y=(0,X.jsx)(`h2`,{className:`mb-4 font-semibold`,children:`Instance Actions`}),n[6]=y):y=n[6];let b;n[7]===a.error?b=n[8]:(b=a.error&&(0,X.jsx)(e,{error:a.error,msg:`Failed to start instance`}),n[7]=a.error,n[8]=b);let x;n[9]===o.error?x=n[10]:(x=o.error&&(0,X.jsx)(e,{error:o.error,msg:`Failed to stop instance`}),n[9]=o.error,n[10]=x);let C;n[11]===s.error?C=n[12]:(C=s.error&&(0,X.jsx)(e,{error:s.error,msg:`Failed to reboot instance`}),n[11]=s.error,n[12]=C);let w;n[13]===c.error?w=n[14]:(w=c.error&&(0,X.jsx)(e,{error:c.error,msg:`Failed to terminate instance`}),n[13]=c.error,n[14]=w);let T;n[15]!==r||n[16]!==a||n[17]!==i?(T=i===`stopped`&&(0,X.jsxs)(S,{disabled:a.isPending,onClick:()=>a.mutate(r),size:`sm`,variant:`default`,children:[(0,X.jsx)(q,{className:`size-4`}),a.isPending?`Starting`:`Start`]}),n[15]=r,n[16]=a,n[17]=i,n[18]=T):T=n[18];let E;n[19]!==r||n[20]!==s||n[21]!==i||n[22]!==o?(E=i===`running`&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsxs)(S,{disabled:o.isPending,onClick:()=>o.mutate(r),size:`sm`,variant:`outline`,children:[(0,X.jsx)(K,{className:`size-4`}),o.isPending?`Stopping`:`Stop`]}),(0,X.jsxs)(S,{disabled:s.isPending,onClick:()=>s.mutate(r),size:`sm`,variant:`outline`,children:[(0,X.jsx)(J,{className:`size-4`}),s.isPending?`Rebooting`:`Reboot`]})]}),n[19]=r,n[20]=s,n[21]=i,n[22]=o,n[23]=E):E=n[23];let D;n[24]!==i||n[25]!==c.isPending?(D=(i===`stopped`||i===`running`)&&(0,X.jsxs)(S,{disabled:c.isPending,onClick:()=>m(!0),size:`sm`,variant:`destructive`,children:[(0,X.jsx)(l,{className:`size-4`}),c.isPending?`Terminating`:`Terminate`]}),n[24]=i,n[25]=c.isPending,n[26]=D):D=n[26];let O;n[27]!==T||n[28]!==E||n[29]!==D?(O=(0,X.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[T,E,D]}),n[27]=T,n[28]=E,n[29]=D,n[30]=O):O=n[30];let k=`Are you sure you want to terminate the instance "${r}"? This action cannot be undone.`,A;n[31]!==v||n[32]!==d||n[33]!==k||n[34]!==c.isPending?(A=(0,X.jsx)(G,{confirmLabel:`Terminate`,description:k,isPending:c.isPending,onConfirm:v,onOpenChange:m,open:d,pendingLabel:`Terminating…`,title:`Terminate Instance`}),n[31]=v,n[32]=d,n[33]=k,n[34]=c.isPending,n[35]=A):A=n[35];let j;return n[36]!==O||n[37]!==A||n[38]!==b||n[39]!==x||n[40]!==C||n[41]!==w?(j=(0,X.jsxs)(`div`,{className:`rounded-lg border bg-card p-4`,children:[y,b,x,C,w,O,A]}),n[36]=O,n[37]=A,n[38]=b,n[39]=x,n[40]=C,n[41]=w,n[42]=j):j=n[42],j}function $(){let{id:l}=A.useParams(),{isAdmin:u}=v(),{data:f}=n(_(l)),p=f.Reservations?.[0]?.Instances?.[0],{data:h}=n(x(p?.ImageId)),g=h?.Images?.[0],{data:b}=n(w),{data:C}=t({...re,enabled:u,refetchInterval:5e3}),T=C?.vms?.find(e=>e.instance_id===l),E=m(),k=d(),[j,W]=(0,Y.useState)(!1),[G,K]=(0,Y.useState)(``),[q,J]=(0,Y.useState)(!1),[Z,Q]=(0,Y.useState)(null),[$,le]=(0,Y.useState)(!1),ue=[...new Set(b.InstanceTypes?.flatMap(e=>e.InstanceType?[e.InstanceType]:[]))].toSorted();if(!p?.InstanceId)return(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(r,{to:`/ec2/describe-instances`,children:`Back to instances`}),(0,X.jsx)(`p`,{className:`text-muted-foreground`,children:`Instance not found.`})]});let de=D(p.LaunchTime),fe=p.State?.Name===`running`,pe=p.State?.Name===`stopped`;async function me(){try{await E.mutateAsync({instanceId:l,instanceType:G}),W(!1),K(``)}catch{}}async function he(){try{let e=await k.mutateAsync(l);Q(e.Output?atob(e.Output):`(no output)`),J(!0)}catch{}}return(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(r,{to:`/ec2/describe-instances`,children:`Back to instances`}),E.error&&(0,X.jsx)(e,{error:E.error,msg:`Failed to modify instance`}),k.error&&(0,X.jsx)(e,{error:k.error,msg:`Failed to get console output`}),(0,X.jsxs)(`div`,{className:`space-y-6`,children:[(0,X.jsx)(ee,{actions:(0,X.jsxs)(`div`,{className:`flex items-center gap-2`,children:[fe&&(0,X.jsxs)(S,{disabled:k.isPending,onClick:he,size:`sm`,variant:`outline`,children:[(0,X.jsx)(oe,{className:`size-4`}),k.isPending?`Fetching…`:`View Console`]}),(fe||pe)&&(0,X.jsxs)(S,{onClick:()=>le(!0),size:`sm`,variant:`outline`,children:[(0,X.jsx)(ie,{className:`size-4`}),`Create Image`]}),pe&&(0,X.jsxs)(S,{onClick:()=>{K(p.InstanceType??``),W(!0)},size:`sm`,variant:`outline`,children:[(0,X.jsx)(ae,{className:`size-4`}),`Modify Instance`]}),(0,X.jsx)(te,{state:p.State?.Name})]}),subtitle:`Instance Details`,title:p.InstanceId}),(0,X.jsx)(ce,{instanceId:p.InstanceId,state:p.State?.Name}),q&&Z!==null&&(0,X.jsxs)(M,{children:[(0,X.jsx)(M.Header,{children:(0,X.jsxs)(`div`,{className:`flex items-center justify-between`,children:[`Console Output`,(0,X.jsx)(S,{onClick:()=>{J(!1),Q(null)},size:`sm`,variant:`ghost`,children:`Hide`})]})}),(0,X.jsx)(`div`,{className:`p-4`,children:(0,X.jsx)(`pre`,{className:`max-h-96 overflow-y-auto rounded bg-muted p-3 font-mono text-xs whitespace-pre-wrap`,children:Z})})]}),(0,X.jsxs)(M,{children:[(0,X.jsx)(M.Header,{children:`Instance Information`}),(0,X.jsxs)(M.Content,{children:[(0,X.jsx)(N,{label:`Instance ID`,value:p.InstanceId}),(0,X.jsx)(N,{label:`Instance Type`,value:p.InstanceType}),(0,X.jsx)(N,{label:`Instance State`,value:p.State?.Name}),(0,X.jsx)(N,{label:`State Code`,value:p.State?.Code?.toString()}),(0,X.jsx)(N,{label:`Launch Time`,value:de}),(0,X.jsx)(N,{label:`Availability Zone`,value:p.Placement?.AvailabilityZone}),(0,X.jsx)(N,{label:`Placement Group`,value:p.Placement?.GroupName?(0,X.jsx)(O,{className:`text-primary hover:underline`,to:`/ec2/describe-placement-groups`,children:p.Placement.GroupName}):void 0})]})]}),(p.PrivateIpAddress||p.PublicIpAddress||p.VpcId||p.SubnetId||p.SecurityGroups&&p.SecurityGroups.length>0)&&(0,X.jsxs)(M,{children:[(0,X.jsx)(M.Header,{children:`Network & Security`}),(0,X.jsxs)(M.Content,{children:[(0,X.jsx)(N,{label:`Private IP Address`,value:p.PrivateIpAddress}),(0,X.jsx)(N,{label:`Public IP Address`,value:p.PublicIpAddress}),(0,X.jsx)(N,{label:`Private DNS`,value:p.PrivateDnsName}),(0,X.jsx)(N,{label:`Public DNS`,value:p.PublicDnsName}),(0,X.jsx)(N,{label:`VPC ID`,value:p.VpcId?(0,X.jsx)(O,{className:`text-primary hover:underline`,params:{id:p.VpcId},to:`/ec2/describe-vpcs/$id`,children:p.VpcId}):void 0}),(0,X.jsx)(N,{label:`Subnet ID`,value:p.SubnetId?(0,X.jsx)(O,{className:`text-primary hover:underline`,params:{id:p.SubnetId},to:`/ec2/describe-subnets/$id`,children:p.SubnetId}):void 0}),(0,X.jsx)(N,{label:`Key Name`,value:p.KeyName}),(0,X.jsx)(N,{label:`Security Groups`,value:p.SecurityGroups?.map(e=>e.GroupName).join(`, `)})]})]}),u&&T?.gpu&&(0,X.jsxs)(M,{children:[(0,X.jsx)(M.Header,{children:`GPU`}),(0,X.jsxs)(M.Content,{children:[(0,X.jsx)(N,{label:`Model`,value:T.gpu.model}),(0,X.jsx)(N,{label:`VRAM`,value:y(T.gpu.vram_mib)}),(0,X.jsx)(N,{label:`Attachment`,value:T.gpu.profile?`MIG slice`:`PCIe passthrough`}),T.gpu.profile&&(0,X.jsx)(N,{label:`Profile`,value:T.gpu.profile}),T.gpu.mdev_path&&(0,X.jsx)(N,{label:`Mdev path`,value:T.gpu.mdev_path}),T.gpu.pci_address&&(0,X.jsx)(N,{label:`PCI address`,value:T.gpu.pci_address})]})]}),p.BlockDeviceMappings&&p.BlockDeviceMappings.length>0&&(0,X.jsxs)(M,{children:[(0,X.jsx)(M.Header,{children:`Block Device Mappings`}),p.BlockDeviceMappings.map(e=>(0,X.jsxs)(M.Content,{children:[(0,X.jsx)(N,{label:`Device Name`,value:e.DeviceName}),(0,X.jsx)(N,{label:`Volume ID`,value:e.Ebs?.VolumeId?(0,X.jsx)(O,{className:`text-primary hover:underline`,params:{id:e.Ebs.VolumeId},to:`/ec2/describe-volumes/$id`,children:e.Ebs.VolumeId}):void 0}),(0,X.jsx)(N,{label:`Status`,value:e.Ebs?.Status}),(0,X.jsx)(N,{label:`Attach Time`,value:D(e.Ebs?.AttachTime)}),(0,X.jsx)(N,{label:`Delete on Termination`,value:e.Ebs?.DeleteOnTermination?`Yes`:`No`})]},e.DeviceName))]}),g&&(0,X.jsx)(ne,{image:g})]}),(0,X.jsx)(V,{onOpenChange:e=>{e||(W(!1),K(``))},open:j,children:(0,X.jsxs)(F,{children:[(0,X.jsxs)(B,{children:[(0,X.jsx)(I,{children:`Modify Instance`}),(0,X.jsxs)(P,{children:[`Select a new instance type for "`,p.InstanceId,`". The instance must be stopped to modify its attributes.`]})]}),(0,X.jsxs)(U,{children:[(0,X.jsx)(H,{children:(0,X.jsx)(`label`,{htmlFor:`instanceType`,children:`Instance Type`})}),(0,X.jsxs)(c,{onValueChange:e=>K(e??``),value:G,children:[(0,X.jsx)(s,{className:`w-full`,id:`instanceType`,children:(0,X.jsx)(i,{})}),(0,X.jsx)(o,{children:ue.map(e=>(0,X.jsx)(a,{value:e,children:e},e))})]})]}),(0,X.jsxs)(R,{children:[(0,X.jsx)(z,{children:`Cancel`}),(0,X.jsx)(L,{disabled:E.isPending||!G||G===p.InstanceType,onClick:me,children:E.isPending?`Saving…`:`Save Changes`})]})]})}),(0,X.jsx)(se,{instanceId:p.InstanceId,onOpenChange:le,open:$})]})}export{$ as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./useQuery.js";import{t as n}from"./useSuspenseQuery.js";import{t as r}from"./back-link.js";import{c as i,i as a,n as o,s,t as c}from"./select.js";import{t as l}from"./trash-2.js";import{A as u,C as d,D as f,M as p,T as m,a as h,j as g}from"./ec2.js";import{Co as _,Ga as v,H as y,Jo as b,Oo as x,V as S,ar as C,ko as w,n as T,qa as E,uo as D,xo as O,z as k,za as A,zi as j}from"./index.js";import{t as ee}from"./page-heading.js";import{t as te}from"./state-badge.js";import{n as M,t as N}from"./detail-row.js";import{t as ne}from"./ami-details.js";import{a as P,i as F,l as I,n as L,o as R,r as z,s as B,t as V}from"./alert-dialog.js";import{a as H,t as U}from"./field.js";import{r as re}from"./admin.js";import{t as W}from"./textarea.js";import{t as G}from"./delete-confirmation-dialog.js";var ie=D(`image-plus`,[[`path`,{d:`M16 5h6`,key:`1vod17`}],[`path`,{d:`M19 2v6`,key:`4bpg5p`}],[`path`,{d:`M21 11.5V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7.5`,key:`1ue2ih`}],[`path`,{d:`m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21`,key:`1xmnt7`}],[`circle`,{cx:`9`,cy:`9`,r:`2`,key:`af1f0g`}]]),K=D(`pause`,[[`rect`,{x:`14`,y:`3`,width:`5`,height:`18`,rx:`1`,key:`kaeet6`}],[`rect`,{x:`5`,y:`3`,width:`5`,height:`18`,rx:`1`,key:`1wsw3u`}]]),q=D(`play`,[[`path`,{d:`M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z`,key:`10ikf1`}]]),J=D(`rotate-cw`,[[`path`,{d:`M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8`,key:`1p45f6`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}]]),ae=D(`settings-2`,[[`path`,{d:`M14 17H5`,key:`gfn3mx`}],[`path`,{d:`M19 7h-9`,key:`6i9tg`}],[`circle`,{cx:`17`,cy:`17`,r:`3`,key:`18b49y`}],[`circle`,{cx:`7`,cy:`7`,r:`3`,key:`dfmy0x`}]]),oe=D(`terminal`,[[`path`,{d:`M12 19h8`,key:`baeox8`}],[`path`,{d:`m4 17 6-6-6-6`,key:`1yngyt`}]]),Y=b(w(),1),X=x();function se({instanceId:e,open:t,onOpenChange:n}){let r=h(),[i,a]=(0,Y.useState)(``),[o,s]=(0,Y.useState)(``),[c,l]=(0,Y.useState)(null);function u(e){e||(a(``),s(``),l(null)),n(e)}async function d(){try{l((await r.mutateAsync({instanceId:e,name:i,description:o||void 0})).ImageId??null),a(``),s(``)}catch{}}return(0,X.jsx)(V,{onOpenChange:u,open:t,children:(0,X.jsxs)(F,{children:[(0,X.jsxs)(B,{children:[(0,X.jsx)(I,{children:c?`Image Created`:`Create Image (AMI)`}),(0,X.jsx)(P,{children:c?`Image "${c}" was created successfully.`:`Create an AMI from instance "${e}".`})]}),!c&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsxs)(U,{children:[(0,X.jsx)(H,{children:(0,X.jsx)(`label`,{htmlFor:`imageName`,children:`Name`})}),(0,X.jsx)(j,{id:`imageName`,onChange:e=>a(e.target.value),placeholder:`my-image`,value:i})]}),(0,X.jsxs)(U,{children:[(0,X.jsx)(H,{children:(0,X.jsx)(`label`,{htmlFor:`imageDescription`,children:`Description`})}),(0,X.jsx)(W,{id:`imageDescription`,onChange:e=>s(e.target.value),placeholder:`Optional description`,rows:2,value:o})]})]}),(0,X.jsxs)(R,{children:[(0,X.jsx)(z,{children:c?`Close`:`Cancel`}),!c&&(0,X.jsx)(L,{disabled:r.isPending||!i.trim(),onClick:d,children:r.isPending?`Creating…`:`Create Image`})]})]})})}var Z=O(),Q=new Set([`pending`,`stopping`,`shutting-down`,`terminated`]);function ce(t){let n=(0,Z.c)(43),{instanceId:r,state:i}=t,a=u(),o=g(),s=f(),c=p(),[d,m]=(0,Y.useState)(!1),h=Q.has(i??``),_;n[0]!==r||n[1]!==c?(_=()=>{c.mutate(r,{onSettled:()=>m(!1)})},n[0]=r,n[1]=c,n[2]=_):_=n[2];let v=_;if(h&&i!==`terminated`){let e;return n[3]===i?e=n[4]:(e=(0,X.jsx)(`div`,{className:`rounded-lg border bg-muted/50 p-4`,children:(0,X.jsxs)(`p`,{className:`text-center text-sm text-muted-foreground`,children:[`Instance is `,i,`. Actions will be available once the operation completes.`]})}),n[3]=i,n[4]=e),e}if(i===`terminated`){let e;return n[5]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,X.jsx)(`div`,{className:`rounded-lg border bg-muted/50 p-4`,children:(0,X.jsx)(`p`,{className:`text-center text-sm text-muted-foreground`,children:`This instance has been terminated and cannot be managed.`})}),n[5]=e):e=n[5],e}let y;n[6]===Symbol.for(`react.memo_cache_sentinel`)?(y=(0,X.jsx)(`h2`,{className:`mb-4 font-semibold`,children:`Instance Actions`}),n[6]=y):y=n[6];let b;n[7]===a.error?b=n[8]:(b=a.error&&(0,X.jsx)(e,{error:a.error,msg:`Failed to start instance`}),n[7]=a.error,n[8]=b);let x;n[9]===o.error?x=n[10]:(x=o.error&&(0,X.jsx)(e,{error:o.error,msg:`Failed to stop instance`}),n[9]=o.error,n[10]=x);let S;n[11]===s.error?S=n[12]:(S=s.error&&(0,X.jsx)(e,{error:s.error,msg:`Failed to reboot instance`}),n[11]=s.error,n[12]=S);let C;n[13]===c.error?C=n[14]:(C=c.error&&(0,X.jsx)(e,{error:c.error,msg:`Failed to terminate instance`}),n[13]=c.error,n[14]=C);let w;n[15]!==r||n[16]!==a||n[17]!==i?(w=i===`stopped`&&(0,X.jsxs)(A,{disabled:a.isPending,onClick:()=>a.mutate(r),size:`sm`,variant:`default`,children:[(0,X.jsx)(q,{className:`size-4`}),a.isPending?`Starting`:`Start`]}),n[15]=r,n[16]=a,n[17]=i,n[18]=w):w=n[18];let T;n[19]!==r||n[20]!==s||n[21]!==i||n[22]!==o?(T=i===`running`&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsxs)(A,{disabled:o.isPending,onClick:()=>o.mutate(r),size:`sm`,variant:`outline`,children:[(0,X.jsx)(K,{className:`size-4`}),o.isPending?`Stopping`:`Stop`]}),(0,X.jsxs)(A,{disabled:s.isPending,onClick:()=>s.mutate(r),size:`sm`,variant:`outline`,children:[(0,X.jsx)(J,{className:`size-4`}),s.isPending?`Rebooting`:`Reboot`]})]}),n[19]=r,n[20]=s,n[21]=i,n[22]=o,n[23]=T):T=n[23];let E;n[24]!==i||n[25]!==c.isPending?(E=(i===`stopped`||i===`running`)&&(0,X.jsxs)(A,{disabled:c.isPending,onClick:()=>m(!0),size:`sm`,variant:`destructive`,children:[(0,X.jsx)(l,{className:`size-4`}),c.isPending?`Terminating`:`Terminate`]}),n[24]=i,n[25]=c.isPending,n[26]=E):E=n[26];let D;n[27]!==w||n[28]!==T||n[29]!==E?(D=(0,X.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[w,T,E]}),n[27]=w,n[28]=T,n[29]=E,n[30]=D):D=n[30];let O=`Are you sure you want to terminate the instance "${r}"? This action cannot be undone.`,k;n[31]!==v||n[32]!==d||n[33]!==O||n[34]!==c.isPending?(k=(0,X.jsx)(G,{confirmLabel:`Terminate`,description:O,isPending:c.isPending,onConfirm:v,onOpenChange:m,open:d,pendingLabel:`Terminating…`,title:`Terminate Instance`}),n[31]=v,n[32]=d,n[33]=O,n[34]=c.isPending,n[35]=k):k=n[35];let j;return n[36]!==D||n[37]!==k||n[38]!==b||n[39]!==x||n[40]!==S||n[41]!==C?(j=(0,X.jsxs)(`div`,{className:`rounded-lg border bg-card p-4`,children:[y,b,x,S,C,D,k]}),n[36]=D,n[37]=k,n[38]=b,n[39]=x,n[40]=S,n[41]=C,n[42]=j):j=n[42],j}function $(){let{id:l}=T.useParams(),{isAdmin:u}=C(),{data:f}=n(S(l)),p=f.Reservations?.[0]?.Instances?.[0],{data:h}=n(k(p?.ImageId)),g=h?.Images?.[0],{data:b}=n(y),{data:x}=t({...re,enabled:u,refetchInterval:5e3}),w=x?.vms?.find(e=>e.instance_id===l),D=m(),O=d(),[j,W]=(0,Y.useState)(!1),[G,K]=(0,Y.useState)(``),[q,J]=(0,Y.useState)(!1),[Z,Q]=(0,Y.useState)(null),[$,le]=(0,Y.useState)(!1),ue=[...new Set(b.InstanceTypes?.flatMap(e=>e.InstanceType?[e.InstanceType]:[]))].toSorted();if(!p?.InstanceId)return(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(r,{to:`/ec2/describe-instances`,children:`Back to instances`}),(0,X.jsx)(`p`,{className:`text-muted-foreground`,children:`Instance not found.`})]});let de=v(p.LaunchTime),fe=p.State?.Name===`running`,pe=p.State?.Name===`stopped`;async function me(){try{await D.mutateAsync({instanceId:l,instanceType:G}),W(!1),K(``)}catch{}}async function he(){try{let e=await O.mutateAsync(l);Q(e.Output?atob(e.Output):`(no output)`),J(!0)}catch{}}return(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(r,{to:`/ec2/describe-instances`,children:`Back to instances`}),D.error&&(0,X.jsx)(e,{error:D.error,msg:`Failed to modify instance`}),O.error&&(0,X.jsx)(e,{error:O.error,msg:`Failed to get console output`}),(0,X.jsxs)(`div`,{className:`space-y-6`,children:[(0,X.jsx)(ee,{actions:(0,X.jsxs)(`div`,{className:`flex items-center gap-2`,children:[fe&&(0,X.jsxs)(A,{disabled:O.isPending,onClick:he,size:`sm`,variant:`outline`,children:[(0,X.jsx)(oe,{className:`size-4`}),O.isPending?`Fetching…`:`View Console`]}),(fe||pe)&&(0,X.jsxs)(A,{onClick:()=>le(!0),size:`sm`,variant:`outline`,children:[(0,X.jsx)(ie,{className:`size-4`}),`Create Image`]}),pe&&(0,X.jsxs)(A,{onClick:()=>{K(p.InstanceType??``),W(!0)},size:`sm`,variant:`outline`,children:[(0,X.jsx)(ae,{className:`size-4`}),`Modify Instance`]}),(0,X.jsx)(te,{state:p.State?.Name})]}),subtitle:`Instance Details`,title:p.InstanceId}),(0,X.jsx)(ce,{instanceId:p.InstanceId,state:p.State?.Name}),q&&Z!==null&&(0,X.jsxs)(M,{children:[(0,X.jsx)(M.Header,{children:(0,X.jsxs)(`div`,{className:`flex items-center justify-between`,children:[`Console Output`,(0,X.jsx)(A,{onClick:()=>{J(!1),Q(null)},size:`sm`,variant:`ghost`,children:`Hide`})]})}),(0,X.jsx)(`div`,{className:`p-4`,children:(0,X.jsx)(`pre`,{className:`max-h-96 overflow-y-auto rounded bg-muted p-3 font-mono text-xs whitespace-pre-wrap`,children:Z})})]}),(0,X.jsxs)(M,{children:[(0,X.jsx)(M.Header,{children:`Instance Information`}),(0,X.jsxs)(M.Content,{children:[(0,X.jsx)(N,{label:`Instance ID`,value:p.InstanceId}),(0,X.jsx)(N,{label:`Instance Type`,value:p.InstanceType}),(0,X.jsx)(N,{label:`Instance State`,value:p.State?.Name}),(0,X.jsx)(N,{label:`State Code`,value:p.State?.Code?.toString()}),(0,X.jsx)(N,{label:`Launch Time`,value:de}),(0,X.jsx)(N,{label:`Availability Zone`,value:p.Placement?.AvailabilityZone}),(0,X.jsx)(N,{label:`Placement Group`,value:p.Placement?.GroupName?(0,X.jsx)(_,{className:`text-primary hover:underline`,to:`/ec2/describe-placement-groups`,children:p.Placement.GroupName}):void 0})]})]}),(p.PrivateIpAddress||p.PublicIpAddress||p.VpcId||p.SubnetId||p.SecurityGroups&&p.SecurityGroups.length>0)&&(0,X.jsxs)(M,{children:[(0,X.jsx)(M.Header,{children:`Network & Security`}),(0,X.jsxs)(M.Content,{children:[(0,X.jsx)(N,{label:`Private IP Address`,value:p.PrivateIpAddress}),(0,X.jsx)(N,{label:`Public IP Address`,value:p.PublicIpAddress}),(0,X.jsx)(N,{label:`Private DNS`,value:p.PrivateDnsName}),(0,X.jsx)(N,{label:`Public DNS`,value:p.PublicDnsName}),(0,X.jsx)(N,{label:`VPC ID`,value:p.VpcId?(0,X.jsx)(_,{className:`text-primary hover:underline`,params:{id:p.VpcId},to:`/ec2/describe-vpcs/$id`,children:p.VpcId}):void 0}),(0,X.jsx)(N,{label:`Subnet ID`,value:p.SubnetId?(0,X.jsx)(_,{className:`text-primary hover:underline`,params:{id:p.SubnetId},to:`/ec2/describe-subnets/$id`,children:p.SubnetId}):void 0}),(0,X.jsx)(N,{label:`Key Name`,value:p.KeyName}),(0,X.jsx)(N,{label:`Security Groups`,value:p.SecurityGroups?.map(e=>e.GroupName).join(`, `)})]})]}),u&&w?.gpu&&(0,X.jsxs)(M,{children:[(0,X.jsx)(M.Header,{children:`GPU`}),(0,X.jsxs)(M.Content,{children:[(0,X.jsx)(N,{label:`Model`,value:w.gpu.model}),(0,X.jsx)(N,{label:`VRAM`,value:E(w.gpu.vram_mib)}),(0,X.jsx)(N,{label:`Attachment`,value:w.gpu.profile?`MIG slice`:`PCIe passthrough`}),w.gpu.profile&&(0,X.jsx)(N,{label:`Profile`,value:w.gpu.profile}),w.gpu.mdev_path&&(0,X.jsx)(N,{label:`Mdev path`,value:w.gpu.mdev_path}),w.gpu.pci_address&&(0,X.jsx)(N,{label:`PCI address`,value:w.gpu.pci_address})]})]}),p.BlockDeviceMappings&&p.BlockDeviceMappings.length>0&&(0,X.jsxs)(M,{children:[(0,X.jsx)(M.Header,{children:`Block Device Mappings`}),p.BlockDeviceMappings.map(e=>(0,X.jsxs)(M.Content,{children:[(0,X.jsx)(N,{label:`Device Name`,value:e.DeviceName}),(0,X.jsx)(N,{label:`Volume ID`,value:e.Ebs?.VolumeId?(0,X.jsx)(_,{className:`text-primary hover:underline`,params:{id:e.Ebs.VolumeId},to:`/ec2/describe-volumes/$id`,children:e.Ebs.VolumeId}):void 0}),(0,X.jsx)(N,{label:`Status`,value:e.Ebs?.Status}),(0,X.jsx)(N,{label:`Attach Time`,value:v(e.Ebs?.AttachTime)}),(0,X.jsx)(N,{label:`Delete on Termination`,value:e.Ebs?.DeleteOnTermination?`Yes`:`No`})]},e.DeviceName))]}),g&&(0,X.jsx)(ne,{image:g})]}),(0,X.jsx)(V,{onOpenChange:e=>{e||(W(!1),K(``))},open:j,children:(0,X.jsxs)(F,{children:[(0,X.jsxs)(B,{children:[(0,X.jsx)(I,{children:`Modify Instance`}),(0,X.jsxs)(P,{children:[`Select a new instance type for "`,p.InstanceId,`". The instance must be stopped to modify its attributes.`]})]}),(0,X.jsxs)(U,{children:[(0,X.jsx)(H,{children:(0,X.jsx)(`label`,{htmlFor:`instanceType`,children:`Instance Type`})}),(0,X.jsxs)(c,{onValueChange:e=>K(e??``),value:G,children:[(0,X.jsx)(s,{className:`w-full`,id:`instanceType`,children:(0,X.jsx)(i,{})}),(0,X.jsx)(o,{children:ue.map(e=>(0,X.jsx)(a,{value:e,children:e},e))})]})]}),(0,X.jsxs)(R,{children:[(0,X.jsx)(z,{children:`Cancel`}),(0,X.jsx)(L,{disabled:D.isPending||!G||G===p.InstanceType,onClick:me,children:D.isPending?`Saving…`:`Save Changes`})]})]})}),(0,X.jsx)(se,{instanceId:p.InstanceId,onOpenChange:le,open:$})]})}export{$ as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_id3.js b/spinifex/services/spinifexui/frontend/dist/assets/_id3.js index 4f608a5ac..052351137 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_id3.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_id3.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./trash-2.js";import{h as i}from"./ec2.js";import{Po as a,Ta as o,U as s,ho as c,ja as l,mo as u,r as d,uo as f}from"./index.js";import{t as p}from"./page-heading.js";import{n as m,t as h}from"./detail-row.js";import{t as g}from"./delete-confirmation-dialog.js";var _=a(c()),v=u();function y(){let{id:a}=d.useParams(),c=f(),{data:u}=t(s(a)),y=u.KeyPairs?.[0],b=i(),[x,S]=(0,_.useState)(!1),C=async()=>{try{await b.mutateAsync(a),c({to:`/ec2/describe-key-pairs`})}finally{S(!1)}};if(!y?.KeyPairId)return(0,v.jsxs)(v.Fragment,{children:[(0,v.jsx)(n,{to:`/ec2/describe-key-pairs`,children:`Back to key pairs`}),(0,v.jsx)(`p`,{className:`text-muted-foreground`,children:`Key pair not found.`})]});let w=l(y.CreateTime);return(0,v.jsxs)(v.Fragment,{children:[(0,v.jsx)(n,{to:`/ec2/describe-key-pairs`,children:`Back to key pairs`}),b.error&&(0,v.jsx)(e,{error:b.error,msg:`Failed to delete key pair`}),(0,v.jsxs)(`div`,{className:`space-y-6`,children:[(0,v.jsx)(p,{actions:(0,v.jsxs)(o,{onClick:()=>S(!0),size:`sm`,variant:`destructive`,children:[(0,v.jsx)(r,{className:`size-4`}),`Delete`]}),subtitle:`Key Pair Details`,title:y.KeyName??``}),(0,v.jsxs)(m,{children:[(0,v.jsx)(m.Header,{children:`Key Pair Information`}),(0,v.jsxs)(m.Content,{children:[(0,v.jsx)(h,{label:`Key Pair ID`,value:y.KeyPairId}),(0,v.jsx)(h,{label:`Key Name`,value:y.KeyName}),(0,v.jsx)(h,{label:`Key Type`,value:y.KeyType}),(0,v.jsx)(h,{label:`Key Fingerprint`,value:y.KeyFingerprint}),(0,v.jsx)(h,{label:`Creation Date`,value:w})]})]}),y.Tags&&y.Tags.length>0&&(0,v.jsxs)(m,{children:[(0,v.jsx)(m.Header,{children:`Tags`}),(0,v.jsx)(m.Content,{children:y.Tags.map(e=>(0,v.jsx)(h,{label:e.Key??``,value:e.Value},e.Key))})]})]}),(0,v.jsx)(g,{description:`Are you sure you want to delete the key pair "${y.KeyName}"? This action cannot be undone. Any instances using this key pair will no longer be able to be accessed with it.`,isPending:b.isPending,onConfirm:C,onOpenChange:S,open:x,title:`Delete Key Pair`})]})}export{y as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./trash-2.js";import{h as i}from"./ec2.js";import{Ga as a,Jo as o,Oo as s,W as c,ko as l,r as u,wo as d,za as f}from"./index.js";import{t as p}from"./page-heading.js";import{n as m,t as h}from"./detail-row.js";import{t as g}from"./delete-confirmation-dialog.js";var _=o(l()),v=s();function y(){let{id:o}=u.useParams(),s=d(),{data:l}=t(c(o)),y=l.KeyPairs?.[0],b=i(),[x,S]=(0,_.useState)(!1),C=async()=>{try{await b.mutateAsync(o),s({to:`/ec2/describe-key-pairs`})}finally{S(!1)}};if(!y?.KeyPairId)return(0,v.jsxs)(v.Fragment,{children:[(0,v.jsx)(n,{to:`/ec2/describe-key-pairs`,children:`Back to key pairs`}),(0,v.jsx)(`p`,{className:`text-muted-foreground`,children:`Key pair not found.`})]});let w=a(y.CreateTime);return(0,v.jsxs)(v.Fragment,{children:[(0,v.jsx)(n,{to:`/ec2/describe-key-pairs`,children:`Back to key pairs`}),b.error&&(0,v.jsx)(e,{error:b.error,msg:`Failed to delete key pair`}),(0,v.jsxs)(`div`,{className:`space-y-6`,children:[(0,v.jsx)(p,{actions:(0,v.jsxs)(f,{onClick:()=>S(!0),size:`sm`,variant:`destructive`,children:[(0,v.jsx)(r,{className:`size-4`}),`Delete`]}),subtitle:`Key Pair Details`,title:y.KeyName??``}),(0,v.jsxs)(m,{children:[(0,v.jsx)(m.Header,{children:`Key Pair Information`}),(0,v.jsxs)(m.Content,{children:[(0,v.jsx)(h,{label:`Key Pair ID`,value:y.KeyPairId}),(0,v.jsx)(h,{label:`Key Name`,value:y.KeyName}),(0,v.jsx)(h,{label:`Key Type`,value:y.KeyType}),(0,v.jsx)(h,{label:`Key Fingerprint`,value:y.KeyFingerprint}),(0,v.jsx)(h,{label:`Creation Date`,value:w})]})]}),y.Tags&&y.Tags.length>0&&(0,v.jsxs)(m,{children:[(0,v.jsx)(m.Header,{children:`Tags`}),(0,v.jsx)(m.Content,{children:y.Tags.map(e=>(0,v.jsx)(h,{label:e.Key??``,value:e.Value},e.Key))})]})]}),(0,v.jsx)(g,{description:`Are you sure you want to delete the key pair "${y.KeyName}"? This action cannot be undone. Any instances using this key pair will no longer be able to be accessed with it.`,isPending:b.isPending,onConfirm:C,onOpenChange:S,open:x,title:`Delete Key Pair`})]})}export{y as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_id4.js b/spinifex/services/spinifexui/frontend/dist/assets/_id4.js index d4dacc38e..7c84c32ed 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_id4.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_id4.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{c as r,i,n as a,s as o,t as s}from"./select.js";import{t as c}from"./trash-2.js";import{a as l,d as u,f as d,o as f,r as p,s as m,t as h,u as g}from"./elbv2.js";import{$ as _,D as v,E as y,M as b,Pa as x,Po as S,T as C,Ta as w,Ti as T,Xa as E,ho as D,i as O,ja as k,k as A,mo as j,so as ee,uo as te,w as ne}from"./index.js";import{t as re}from"./page-heading.js";import{t as ie}from"./state-badge.js";import{n as M,t as N}from"./detail-row.js";import{a as P,i as F,l as I,n as L,o as R,r as z,s as B,t as V}from"./alert-dialog.js";import{a as H,r as U,t as W}from"./field.js";import{t as G}from"./delete-confirmation-dialog.js";import{i as K,n as q,r as ae,t as J}from"./zod.js";import{r as oe,t as se}from"./elbv22.js";import{a as ce,i as Y,n as le,o as ue,r as X,t as de}from"./tabs.js";var fe=E(`pencil`,[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}],[`path`,{d:`m15 5 4 4`,key:`1mk7zo`}]]),Z=S(D(),1),Q=ee(),$=j();function pe(e){let t=(0,Q.c)(33),{form:n,targetGroups:i}=e,{control:c,register:l,formState:u}=n,{errors:d}=u,f;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(f=(0,$.jsx)(H,{children:(0,$.jsx)(`label`,{htmlFor:`listener-protocol`,children:`Protocol`})}),t[0]=f):f=t[0];let p;t[1]===c?p=t[2]:(p=(0,$.jsxs)(W,{children:[f,(0,$.jsx)(q,{control:c,name:`protocol`,render:he})]}),t[1]=c,t[2]=p);let m;t[3]===Symbol.for(`react.memo_cache_sentinel`)?(m=(0,$.jsx)(H,{children:(0,$.jsx)(`label`,{htmlFor:`listener-port`,children:`Port`})}),t[3]=m):m=t[3];let h=!!d.port,g;t[4]===l?g=t[5]:(g=l(`port`,{valueAsNumber:!0}),t[4]=l,t[5]=g);let _;t[6]!==h||t[7]!==g?(_=(0,$.jsx)(T,{"aria-invalid":h,id:`listener-port`,inputMode:`numeric`,placeholder:`80`,type:`number`,...g}),t[6]=h,t[7]=g,t[8]=_):_=t[8];let v;t[9]===d.port?v=t[10]:(v=(0,$.jsx)(U,{errors:[d.port]}),t[9]=d.port,t[10]=v);let y;t[11]!==_||t[12]!==v?(y=(0,$.jsxs)(W,{children:[m,_,v]}),t[11]=_,t[12]=v,t[13]=y):y=t[13];let b;t[14]===Symbol.for(`react.memo_cache_sentinel`)?(b=(0,$.jsx)(H,{children:(0,$.jsx)(`label`,{htmlFor:`listener-default-tg`,children:`Default target group`})}),t[14]=b):b=t[14];let x;t[15]!==d.defaultTargetGroupArn||t[16]!==i?(x=e=>{let{field:t}=e;return(0,$.jsxs)(s,{onValueChange:t.onChange,value:t.value??``,children:[(0,$.jsx)(o,{"aria-invalid":!!d.defaultTargetGroupArn,className:`w-full`,id:`listener-default-tg`,children:(0,$.jsx)(r,{placeholder:`Select target group`})}),(0,$.jsx)(a,{children:i.map(me)})]})},t[15]=d.defaultTargetGroupArn,t[16]=i,t[17]=x):x=t[17];let S;t[18]!==c||t[19]!==x?(S=(0,$.jsx)(q,{control:c,name:`defaultTargetGroupArn`,render:x}),t[18]=c,t[19]=x,t[20]=S):S=t[20];let C;t[21]===d.defaultTargetGroupArn?C=t[22]:(C=(0,$.jsx)(U,{errors:[d.defaultTargetGroupArn]}),t[21]=d.defaultTargetGroupArn,t[22]=C);let w;t[23]===i.length?w=t[24]:(w=i.length===0&&(0,$.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground`,children:`No target groups available in this VPC. Create one first.`}),t[23]=i.length,t[24]=w);let E;t[25]!==S||t[26]!==C||t[27]!==w?(E=(0,$.jsxs)(W,{children:[b,S,C,w]}),t[25]=S,t[26]=C,t[27]=w,t[28]=E):E=t[28];let D;return t[29]!==E||t[30]!==p||t[31]!==y?(D=(0,$.jsxs)($.Fragment,{children:[p,y,E]}),t[29]=E,t[30]=p,t[31]=y,t[32]=D):D=t[32],D}function me(e){return(0,$.jsxs)(i,{value:e.TargetGroupArn??``,children:[e.TargetGroupName,` · `,e.Protocol,`:`,e.Port]},e.TargetGroupArn)}function he(e){let{field:t}=e;return(0,$.jsxs)(s,{onValueChange:t.onChange,value:t.value,children:[(0,$.jsx)(o,{className:`w-full`,id:`listener-protocol`,children:(0,$.jsx)(r,{})}),(0,$.jsx)(a,{children:(0,$.jsx)(i,{value:`HTTP`,children:`HTTP`})})]})}function ge({listenerArn:n,targetGroups:r}){let{data:i}=t(ne(n)),a=p(),o=d(),s=m(),[l,u]=(0,Z.useState)(!1),[f,h]=(0,Z.useState)(),[g,_]=(0,Z.useState)(),v=i.Rules??[],y=new Map;for(let e of r)e.TargetGroupArn&&e.TargetGroupName&&y.set(e.TargetGroupArn,e.TargetGroupName);return(0,$.jsxs)(`div`,{className:`space-y-3`,children:[a.error&&(0,$.jsx)(e,{error:a.error,msg:`Failed to create rule`}),o.error&&(0,$.jsx)(e,{error:o.error,msg:`Failed to modify rule`}),s.error&&(0,$.jsx)(e,{error:s.error,msg:`Failed to delete rule`}),(0,$.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,$.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[v.length,` rule`,v.length===1?``:`s`,` (including default)`]}),(0,$.jsx)(w,{onClick:()=>u(!0),size:`sm`,children:`Add rule`})]}),(0,$.jsx)(`div`,{className:`overflow-x-auto rounded-lg border bg-card`,children:(0,$.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,$.jsx)(`thead`,{children:(0,$.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Priority`}),(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Conditions`}),(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Forward to`}),(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:(0,$.jsx)(`span`,{className:`sr-only`,children:`Actions`})})]})}),(0,$.jsx)(`tbody`,{children:v.map(e=>(0,$.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,$.jsx)(`td`,{className:`px-4 py-2`,children:e.Priority}),(0,$.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:_e(e.Conditions,e.IsDefault===!0)}),(0,$.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:ye(e,y)}),(0,$.jsx)(`td`,{className:`px-4 py-2 text-right`,children:e.IsDefault===!0?(0,$.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`Edit via listener`}):(0,$.jsxs)(`div`,{className:`flex justify-end gap-1`,children:[(0,$.jsx)(w,{"aria-label":`Edit rule ${e.Priority}`,onClick:()=>h(e),size:`sm`,variant:`ghost`,children:(0,$.jsx)(fe,{className:`size-4`})}),(0,$.jsx)(w,{"aria-label":`Delete rule ${e.Priority}`,onClick:()=>_(e),size:`sm`,variant:`ghost`,children:(0,$.jsx)(c,{className:`size-4`})})]})})]},e.RuleArn??e.Priority??`default`))})]})}),(0,$.jsx)(xe,{isPending:a.isPending,mode:`add`,onOpenChange:u,onSubmit:async e=>{try{await a.mutateAsync({listenerArn:n,priority:e.priority,conditions:e.conditions.map(be),forwardTargetGroupArn:e.forwardTargetGroupArn}),u(!1)}catch{}},open:l,targetGroups:r}),(0,$.jsx)(xe,{initialRule:f,isPending:o.isPending,mode:`edit`,onOpenChange:e=>!e&&h(void 0),onSubmit:async e=>{if(f?.RuleArn)try{await o.mutateAsync({ruleArn:f.RuleArn,listenerArn:n,conditions:e.conditions.map(be),forwardTargetGroupArn:e.forwardTargetGroupArn}),h(void 0)}catch{}},open:f!==void 0,targetGroups:r}),(0,$.jsx)(G,{description:g?`Delete rule with priority ${g.Priority}? This cannot be undone.`:``,isPending:s.isPending,onConfirm:async()=>{if(g?.RuleArn)try{await s.mutateAsync({ruleArn:g.RuleArn,listenerArn:n})}finally{_(void 0)}},onOpenChange:e=>!e&&_(void 0),open:g!==void 0,title:`Delete rule`})]})}function _e(e,t){return t?`default`:!e||e.length===0?`—`:e.map(e=>{let t=ve(e);return`${e.Field}: ${t.join(`, `)}`}).join(` AND `)}function ve(e){if(e.Field===void 0)return e.Values??[];switch(e.Field){case`host-header`:return e.HostHeaderConfig?.Values??e.Values??[];case`path-pattern`:return e.PathPatternConfig?.Values??e.Values??[];case`http-header`:{let t=e.HttpHeaderConfig?.HttpHeaderName??`?`;return(e.HttpHeaderConfig?.Values??[]).map(e=>`${t}=${e}`)}case`http-request-method`:return e.HttpRequestMethodConfig?.Values??[];case`source-ip`:return e.SourceIpConfig?.Values??[];case`query-string`:return(e.QueryStringConfig?.Values??[]).map(e=>e.Key?`${e.Key}=${e.Value??``}`:e.Value??``);default:return e.Values??[]}}function ye(e,t){let n=e.Actions?.[0];return n?n.Type===`forward`&&n.TargetGroupArn?t.get(n.TargetGroupArn)??n.TargetGroupArn:n.Type??`—`:`—`}function be(e){let t=e.rawValues.split(/[\n,]/).map(e=>e.trim()).filter(e=>e.length>0);return e.field===`query-string`?{field:e.field,values:[],queryStringPairs:t.map(e=>{let t=e.indexOf(`=`);return t===-1?{value:e}:{key:e.slice(0,t),value:e.slice(t+1)}})}:{field:e.field,values:t,httpHeaderName:e.httpHeaderName}}function xe({open:e,onOpenChange:t,onSubmit:n,isPending:c,targetGroups:l,mode:u,initialRule:d}){let f=[{field:`path-pattern`,rawValues:``}],p=K({resolver:J(oe),defaultValues:{priority:1,conditions:f,forwardTargetGroupArn:``}}),{fields:m,append:h,remove:g}=ae({control:p.control,name:`conditions`});(0,Z.useEffect)(()=>{if(u===`add`){e||p.reset({priority:1,conditions:f,forwardTargetGroupArn:``});return}if(!d)return;let t=Number(d.Priority??1),n=d.Conditions?.map(e=>Ee(e))??f;p.reset({priority:Number.isFinite(t)?t:1,conditions:n.length>0?n:f,forwardTargetGroupArn:d.Actions?.[0]?.TargetGroupArn??``})},[d,e,u]);let _=p.handleSubmit(n);return(0,$.jsx)(V,{onOpenChange:t,open:e,children:(0,$.jsxs)(F,{className:`grid-cols-[minmax(0,1fr)]`,style:{maxWidth:`40rem`,width:`calc(100vw - 2rem)`},children:[(0,$.jsxs)(B,{children:[(0,$.jsx)(I,{children:u===`add`?`Add rule`:`Edit rule`}),(0,$.jsx)(P,{children:`Routing rules match incoming requests and forward them to a target group. Rules evaluate in priority order; the listener default applies when no rule matches.`})]}),(0,$.jsxs)(`form`,{className:`min-w-0 space-y-4`,onSubmit:e=>{e.preventDefault(),_()},children:[(0,$.jsxs)(W,{children:[(0,$.jsx)(H,{children:(0,$.jsx)(`label`,{htmlFor:`rule-priority`,children:`Priority`})}),(0,$.jsx)(T,{"aria-invalid":!!p.formState.errors.priority,id:`rule-priority`,inputMode:`numeric`,type:`number`,...p.register(`priority`,{valueAsNumber:!0})}),(0,$.jsx)(U,{errors:[p.formState.errors.priority]})]}),(0,$.jsxs)(`div`,{className:`space-y-3`,children:[(0,$.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,$.jsx)(H,{children:`Conditions`}),(0,$.jsx)(w,{disabled:m.length>=5,onClick:()=>h({field:`path-pattern`,rawValues:``}),size:`sm`,type:`button`,variant:`outline`,children:`Add condition`})]}),m.map((e,t)=>(0,$.jsx)(Se,{form:p,index:t,onRemove:m.length>1?()=>g(t):void 0},e.id))]}),(0,$.jsxs)(W,{children:[(0,$.jsx)(H,{children:(0,$.jsx)(`label`,{htmlFor:`rule-forward-tg`,children:`Forward to target group`})}),(0,$.jsx)(q,{control:p.control,name:`forwardTargetGroupArn`,render:({field:e})=>(0,$.jsxs)(s,{onValueChange:e.onChange,value:e.value??``,children:[(0,$.jsx)(o,{"aria-invalid":!!p.formState.errors.forwardTargetGroupArn,className:`w-full`,id:`rule-forward-tg`,children:(0,$.jsx)(r,{placeholder:`Select target group`})}),(0,$.jsx)(a,{children:l.map(e=>(0,$.jsxs)(i,{value:e.TargetGroupArn??``,children:[e.TargetGroupName,` · `,e.Protocol,`:`,e.Port]},e.TargetGroupArn))})]})}),(0,$.jsx)(U,{errors:[p.formState.errors.forwardTargetGroupArn]})]})]}),(0,$.jsxs)(R,{children:[(0,$.jsx)(z,{disabled:c,children:`Cancel`}),(0,$.jsx)(L,{disabled:c,onClick:_,children:De(u,c)})]})]})})}function Se(e){let t=(0,Q.c)(54),{form:n,index:l,onRemove:u}=e,d,f,p,m,h,g,_,v,y,b;if(t[0]!==n||t[1]!==l||t[2]!==u){let e=n.watch(`conditions.${l}.field`);p=n.formState.errors.conditions?.[l],v=`space-y-2 rounded-md border p-3`;let x=`rule-cond-${l}-field`,S;t[13]===x?S=t[14]:(S=(0,$.jsx)(H,{children:(0,$.jsx)(`label`,{htmlFor:x,children:`Type`})}),t[13]=x,t[14]=S);let C=`conditions.${l}.field`,E;t[15]===l?E=t[16]:(E=e=>{let{field:t}=e;return(0,$.jsxs)(s,{onValueChange:t.onChange,value:t.value,children:[(0,$.jsx)(o,{className:`w-full`,id:`rule-cond-${l}-field`,children:(0,$.jsx)(r,{})}),(0,$.jsxs)(a,{children:[(0,$.jsx)(i,{value:`path-pattern`,children:`Path pattern`}),(0,$.jsx)(i,{value:`host-header`,children:`Host header`}),(0,$.jsx)(i,{value:`http-header`,children:`HTTP header`}),(0,$.jsx)(i,{value:`http-request-method`,children:`HTTP method`}),(0,$.jsx)(i,{value:`source-ip`,children:`Source IP CIDR`}),(0,$.jsx)(i,{value:`query-string`,children:`Query string`})]})]})},t[15]=l,t[16]=E);let D;t[17]!==n.control||t[18]!==C||t[19]!==E?(D=(0,$.jsx)(q,{control:n.control,name:C,render:E}),t[17]=n.control,t[18]=C,t[19]=E,t[20]=D):D=t[20];let O;t[21]!==D||t[22]!==S?(O=(0,$.jsxs)(`div`,{className:`flex-1`,children:[S,D]}),t[21]=D,t[22]=S,t[23]=O):O=t[23];let k;t[24]!==l||t[25]!==u?(k=u&&(0,$.jsx)(w,{"aria-label":`Remove condition ${l+1}`,className:`self-end`,onClick:u,size:`sm`,type:`button`,variant:`ghost`,children:(0,$.jsx)(c,{className:`size-4`})}),t[24]=l,t[25]=u,t[26]=k):k=t[26],t[27]!==O||t[28]!==k?(y=(0,$.jsxs)(`div`,{className:`flex gap-2`,children:[O,k]}),t[27]=O,t[28]=k,t[29]=y):y=t[29],b=e===`http-header`&&(0,$.jsxs)(W,{children:[(0,$.jsx)(H,{children:(0,$.jsx)(`label`,{htmlFor:`rule-cond-${l}-hdr-name`,children:`Header name`})}),(0,$.jsx)(T,{"aria-invalid":!!p?.httpHeaderName,id:`rule-cond-${l}-hdr-name`,placeholder:`X-Tenant`,...n.register(`conditions.${l}.httpHeaderName`)}),(0,$.jsx)(U,{errors:[p?.httpHeaderName]})]}),f=W;let A=`rule-cond-${l}-values`,j;t[30]===Symbol.for(`react.memo_cache_sentinel`)?(j=(0,$.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`(comma or newline separated, max 5)`}),t[30]=j):j=t[30],t[31]===A?_=t[32]:(_=(0,$.jsx)(H,{children:(0,$.jsxs)(`label`,{htmlFor:A,children:[`Values`,` `,j]})}),t[31]=A,t[32]=_),d=T,m=!!p?.rawValues,h=`rule-cond-${l}-values`,g=Ce(e),t[0]=n,t[1]=l,t[2]=u,t[3]=d,t[4]=f,t[5]=p,t[6]=m,t[7]=h,t[8]=g,t[9]=_,t[10]=v,t[11]=y,t[12]=b}else d=t[3],f=t[4],p=t[5],m=t[6],h=t[7],g=t[8],_=t[9],v=t[10],y=t[11],b=t[12];let x;t[33]!==n||t[34]!==l?(x=n.register(`conditions.${l}.rawValues`),t[33]=n,t[34]=l,t[35]=x):x=t[35];let S;t[36]!==d||t[37]!==m||t[38]!==h||t[39]!==g||t[40]!==x?(S=(0,$.jsx)(d,{"aria-invalid":m,id:h,placeholder:g,...x}),t[36]=d,t[37]=m,t[38]=h,t[39]=g,t[40]=x,t[41]=S):S=t[41];let C=p?.rawValues,E;t[42]===C?E=t[43]:(E=(0,$.jsx)(U,{errors:[C]}),t[42]=C,t[43]=E);let D;t[44]!==f||t[45]!==E||t[46]!==_||t[47]!==S?(D=(0,$.jsxs)(f,{children:[_,S,E]}),t[44]=f,t[45]=E,t[46]=_,t[47]=S,t[48]=D):D=t[48];let O;return t[49]!==D||t[50]!==v||t[51]!==y||t[52]!==b?(O=(0,$.jsxs)(`div`,{className:v,children:[y,b,D]}),t[49]=D,t[50]=v,t[51]=y,t[52]=b,t[53]=O):O=t[53],O}function Ce(e){switch(e){case`path-pattern`:return`/api/*`;case`host-header`:return`*.example.com`;case`http-header`:return`acme`;case`http-request-method`:return`GET, POST`;case`source-ip`:return`10.0.0.0/8`;case`query-string`:return`key=value`;default:return``}}var we=new Set([`host-header`,`path-pattern`,`http-header`,`http-request-method`,`source-ip`,`query-string`]);function Te(e){return e!==void 0&&we.has(e)}function Ee(e){let t=ve(e);return{field:Te(e.Field)?e.Field:`path-pattern`,httpHeaderName:e.HttpHeaderConfig?.HttpHeaderName,rawValues:t.join(`, `)}}function De(e,t){return t?e===`add`?`Adding…`:`Saving…`:e===`add`?`Add rule`:`Save changes`}function Oe({loadBalancerArn:n,vpcId:r}){let{data:i}=t(C(n)),{data:a}=t(b),o=h(),s=l(),u=g(),[d,f]=(0,Z.useState)(!1),[p,m]=(0,Z.useState)(),[_,v]=(0,Z.useState)(),[y,x]=(0,Z.useState)(),S=i.Listeners??[],T=a.TargetGroups??[],E=T.filter(e=>e.VpcId===r),D=new Map;for(let e of T)e.TargetGroupArn&&e.TargetGroupName&&D.set(e.TargetGroupArn,e.TargetGroupName);let O=e=>{let t=e.DefaultActions?.[0];if(!t)return`—`;if(t.Type===`forward`&&t.TargetGroupArn){let e=D.get(t.TargetGroupArn);return e?`forward → ${e}`:`forward → ${t.TargetGroupArn}`}return t.Type??`—`};return(0,$.jsxs)(`div`,{className:`space-y-3`,children:[o.error&&(0,$.jsx)(e,{error:o.error,msg:`Failed to create listener`}),u.error&&(0,$.jsx)(e,{error:u.error,msg:`Failed to modify listener`}),s.error&&(0,$.jsx)(e,{error:s.error,msg:`Failed to delete listener`}),(0,$.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,$.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[S.length,` listener`,S.length===1?``:`s`]}),(0,$.jsx)(w,{onClick:()=>f(!0),size:`sm`,children:`Add listener`})]}),S.length===0?(0,$.jsx)(`p`,{className:`text-muted-foreground`,children:`No listeners configured.`}):(0,$.jsx)(`div`,{className:`overflow-x-auto rounded-lg border bg-card`,children:(0,$.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,$.jsx)(`thead`,{children:(0,$.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Protocol`}),(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Port`}),(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Default action`}),(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Listener ARN`}),(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:(0,$.jsx)(`span`,{className:`sr-only`,children:`Actions`})})]})}),(0,$.jsx)(`tbody`,{children:S.map(e=>{let t=e.ListenerArn??``,n=y===t;return(0,$.jsxs)(Z.Fragment,{children:[(0,$.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,$.jsx)(`td`,{className:`px-4 py-2`,children:e.Protocol}),(0,$.jsx)(`td`,{className:`px-4 py-2`,children:e.Port}),(0,$.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:O(e)}),(0,$.jsx)(`td`,{className:`px-4 py-2 font-mono text-xs`,children:t}),(0,$.jsx)(`td`,{className:`px-4 py-2 text-right`,children:(0,$.jsxs)(`div`,{className:`flex justify-end gap-1`,children:[(0,$.jsx)(w,{"aria-label":`${n?`Hide`:`Show`} rules for listener ${e.Protocol}:${e.Port}`,onClick:()=>x(n?void 0:t),size:`sm`,variant:`ghost`,children:n?`Hide rules`:`Rules`}),(0,$.jsx)(w,{"aria-label":`Edit listener ${e.Protocol}:${e.Port}`,onClick:()=>m(e),size:`sm`,variant:`ghost`,children:(0,$.jsx)(fe,{className:`size-4`})}),(0,$.jsx)(w,{"aria-label":`Delete listener ${e.Protocol}:${e.Port}`,onClick:()=>v(e),size:`sm`,variant:`ghost`,children:(0,$.jsx)(c,{className:`size-4`})})]})})]}),n&&t&&(0,$.jsx)(`tr`,{className:`border-b bg-muted/30 last:border-0`,children:(0,$.jsx)(`td`,{className:`px-4 py-3`,colSpan:5,children:(0,$.jsx)(ge,{listenerArn:t,targetGroups:E})})})]},t)})})]})}),(0,$.jsx)(ke,{isPending:o.isPending,onOpenChange:f,onSubmit:async e=>{try{await o.mutateAsync({loadBalancerArn:n,protocol:e.protocol,port:e.port,defaultTargetGroupArn:e.defaultTargetGroupArn}),f(!1)}catch{}},open:d,targetGroups:E}),(0,$.jsx)(Ae,{isPending:u.isPending,listener:p,onOpenChange:e=>!e&&m(void 0),onSubmit:async e=>{if(p?.ListenerArn)try{await u.mutateAsync({listenerArn:p.ListenerArn,loadBalancerArn:n,protocol:e.protocol,port:e.port,defaultTargetGroupArn:e.defaultTargetGroupArn}),m(void 0)}catch{}},targetGroups:E}),(0,$.jsx)(G,{description:_?`Delete listener ${_.Protocol}:${_.Port}? This cannot be undone.`:``,isPending:s.isPending,onConfirm:async()=>{if(_?.ListenerArn)try{await s.mutateAsync(_.ListenerArn)}finally{v(void 0)}},onOpenChange:e=>!e&&v(void 0),open:_!==void 0,title:`Delete listener`})]})}function ke(e){let t=(0,Q.c)(34),{open:n,onOpenChange:r,targetGroups:i,isPending:a,onSubmit:o}=e,s;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(s={resolver:J(se),defaultValues:{protocol:`HTTP`,port:80,defaultTargetGroupArn:``}},t[0]=s):s=t[0];let c=K(s),l,u;t[1]!==c||t[2]!==n?(l=()=>{n||c.reset({protocol:`HTTP`,port:80,defaultTargetGroupArn:``})},u=[n,c],t[1]=c,t[2]=n,t[3]=l,t[4]=u):(l=t[3],u=t[4]),(0,Z.useEffect)(l,u);let d;t[5]!==c||t[6]!==o?(d=c.handleSubmit(o),t[5]=c,t[6]=o,t[7]=d):d=t[7];let f=d,p;t[8]===Symbol.for(`react.memo_cache_sentinel`)?(p={maxWidth:`32rem`,width:`calc(100vw - 2rem)`},t[8]=p):p=t[8];let m;t[9]===Symbol.for(`react.memo_cache_sentinel`)?(m=(0,$.jsxs)(B,{children:[(0,$.jsx)(I,{children:`Add listener`}),(0,$.jsx)(P,{children:`Listeners forward incoming traffic to a default target group.`})]}),t[9]=m):m=t[9];let h;t[10]===f?h=t[11]:(h=e=>{e.preventDefault(),f()},t[10]=f,t[11]=h);let g;t[12]!==c||t[13]!==i?(g=(0,$.jsx)(pe,{form:c,targetGroups:i}),t[12]=c,t[13]=i,t[14]=g):g=t[14];let _;t[15]!==h||t[16]!==g?(_=(0,$.jsx)(`form`,{className:`min-w-0 space-y-4`,onSubmit:h,children:g}),t[15]=h,t[16]=g,t[17]=_):_=t[17];let v;t[18]===a?v=t[19]:(v=(0,$.jsx)(z,{disabled:a,children:`Cancel`}),t[18]=a,t[19]=v);let y=a?`Adding…`:`Add listener`,b;t[20]!==f||t[21]!==a||t[22]!==y?(b=(0,$.jsx)(L,{disabled:a,onClick:f,children:y}),t[20]=f,t[21]=a,t[22]=y,t[23]=b):b=t[23];let x;t[24]!==v||t[25]!==b?(x=(0,$.jsxs)(R,{children:[v,b]}),t[24]=v,t[25]=b,t[26]=x):x=t[26];let S;t[27]!==x||t[28]!==_?(S=(0,$.jsxs)(F,{className:`grid-cols-[minmax(0,1fr)]`,style:p,children:[m,_,x]}),t[27]=x,t[28]=_,t[29]=S):S=t[29];let C;return t[30]!==r||t[31]!==n||t[32]!==S?(C=(0,$.jsx)(V,{onOpenChange:r,open:n,children:S}),t[30]=r,t[31]=n,t[32]=S,t[33]=C):C=t[33],C}function Ae(e){let t=(0,Q.c)(34),{listener:n,onOpenChange:r,targetGroups:i,isPending:a,onSubmit:o}=e,s=n!==void 0,c;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(c={resolver:J(se),defaultValues:{protocol:`HTTP`,port:80,defaultTargetGroupArn:``}},t[0]=c):c=t[0];let l=K(c),u,d;t[1]!==l||t[2]!==n?(u=()=>{n&&l.reset({protocol:`HTTP`,port:n.Port??80,defaultTargetGroupArn:n.DefaultActions?.[0]?.TargetGroupArn??``})},d=[n,l],t[1]=l,t[2]=n,t[3]=u,t[4]=d):(u=t[3],d=t[4]),(0,Z.useEffect)(u,d);let f;t[5]!==l||t[6]!==o?(f=l.handleSubmit(o),t[5]=l,t[6]=o,t[7]=f):f=t[7];let p=f,m;t[8]===Symbol.for(`react.memo_cache_sentinel`)?(m={maxWidth:`32rem`,width:`calc(100vw - 2rem)`},t[8]=m):m=t[8];let h;t[9]===Symbol.for(`react.memo_cache_sentinel`)?(h=(0,$.jsxs)(B,{children:[(0,$.jsx)(I,{children:`Edit listener`}),(0,$.jsx)(P,{children:`Update port, protocol, or default target group. Changes apply without dropping the listener.`})]}),t[9]=h):h=t[9];let g;t[10]===p?g=t[11]:(g=e=>{e.preventDefault(),p()},t[10]=p,t[11]=g);let _;t[12]!==l||t[13]!==i?(_=(0,$.jsx)(pe,{form:l,targetGroups:i}),t[12]=l,t[13]=i,t[14]=_):_=t[14];let v;t[15]!==g||t[16]!==_?(v=(0,$.jsx)(`form`,{className:`min-w-0 space-y-4`,onSubmit:g,children:_}),t[15]=g,t[16]=_,t[17]=v):v=t[17];let y;t[18]===a?y=t[19]:(y=(0,$.jsx)(z,{disabled:a,children:`Cancel`}),t[18]=a,t[19]=y);let b=a?`Saving…`:`Save changes`,x;t[20]!==p||t[21]!==a||t[22]!==b?(x=(0,$.jsx)(L,{disabled:a,onClick:p,children:b}),t[20]=p,t[21]=a,t[22]=b,t[23]=x):x=t[23];let S;t[24]!==y||t[25]!==x?(S=(0,$.jsxs)(R,{children:[y,x]}),t[24]=y,t[25]=x,t[26]=S):S=t[26];let C;t[27]!==S||t[28]!==v?(C=(0,$.jsxs)(F,{className:`grid-cols-[minmax(0,1fr)]`,style:m,children:[h,v,S]}),t[27]=S,t[28]=v,t[29]=C):C=t[29];let w;return t[30]!==r||t[31]!==s||t[32]!==C?(w=(0,$.jsx)(V,{onOpenChange:r,open:s,children:C}),t[30]=r,t[31]=s,t[32]=C,t[33]=w):w=t[33],w}function je({arn:r}){let i=te(),{data:a}=t(v(r)),{data:o}=t(y(r)),{data:s}=t(A([r])),{data:l}=t(_),d=f(),p=u(),[m,h]=(0,Z.useState)(!1),g=a.LoadBalancers?.[0];if(!g?.LoadBalancerArn)return(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(n,{to:`/ec2/describe-load-balancers`,children:`Back to load balancers`}),(0,$.jsx)(`p`,{className:`text-muted-foreground`,children:`Load balancer not found.`})]});let b=async()=>{try{await d.mutateAsync(r),i({to:`/ec2/describe-load-balancers`})}finally{h(!1)}},S=l.Subnets??[],C=e=>{let t=S.find(t=>t.SubnetId===e);if(!t)return e;let n=x(t.Tags),r=t.CidrBlock?` (${t.CidrBlock})`:``;return n?`${e} — ${n}${r}`:`${e}${r}`},T=o.Attributes??[],E=s?.TagDescriptions?.find(e=>e.ResourceArn===r)?.Tags??[];return(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(n,{to:`/ec2/describe-load-balancers`,children:`Back to load balancers`}),d.error&&(0,$.jsx)(e,{error:d.error,msg:`Failed to delete load balancer`}),(0,$.jsxs)(`div`,{className:`space-y-6`,children:[(0,$.jsx)(re,{actions:(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsxs)(w,{onClick:()=>h(!0),size:`sm`,variant:`destructive`,children:[(0,$.jsx)(c,{className:`size-4`}),`Delete`]}),(0,$.jsx)(ie,{state:g.State?.Code})]}),subtitle:`Load Balancer Details`,title:g.LoadBalancerName??g.LoadBalancerArn}),(0,$.jsxs)(de,{defaultValue:`overview`,children:[(0,$.jsxs)(le,{children:[(0,$.jsx)(Y,{value:`overview`,children:`Overview`}),(0,$.jsx)(Y,{value:`listeners`,children:`Listeners`}),(0,$.jsx)(Y,{value:`attributes`,children:`Attributes`}),(0,$.jsx)(Y,{value:`tags`,children:`Tags`})]}),(0,$.jsxs)(X,{value:`overview`,children:[(0,$.jsxs)(M,{children:[(0,$.jsx)(M.Header,{children:`Load balancer`}),(0,$.jsxs)(M.Content,{children:[(0,$.jsx)(N,{label:`ARN`,value:g.LoadBalancerArn}),(0,$.jsx)(N,{label:`DNS name`,value:g.DNSName}),(0,$.jsx)(N,{label:`State`,value:g.State?.Reason?`${g.State.Code} — ${g.State.Reason}`:g.State?.Code}),(0,$.jsx)(N,{label:`Type`,value:g.Type}),(0,$.jsx)(N,{label:`Scheme`,value:g.Scheme}),(0,$.jsx)(N,{label:`IP address type`,value:g.IpAddressType}),(0,$.jsx)(N,{label:`VPC`,value:g.VpcId}),(0,$.jsx)(N,{label:`Created at`,value:k(g.CreatedTime)})]})]}),(0,$.jsxs)(M,{children:[(0,$.jsx)(M.Header,{children:`Availability zones`}),(0,$.jsx)(M.Content,{children:(g.AvailabilityZones??[]).map(e=>(0,$.jsx)(N,{label:e.ZoneName??`—`,value:e.SubnetId?C(e.SubnetId):void 0},`${e.ZoneName}-${e.SubnetId}`))})]}),(g.SecurityGroups??[]).length>0&&(0,$.jsxs)(M,{children:[(0,$.jsx)(M.Header,{children:`Security groups`}),(0,$.jsx)(M.Content,{children:(g.SecurityGroups??[]).map(e=>(0,$.jsx)(N,{label:`Security group`,value:e},e))})]})]}),(0,$.jsx)(X,{value:`listeners`,children:(0,$.jsx)(Oe,{loadBalancerArn:r,vpcId:g.VpcId})}),(0,$.jsx)(X,{value:`attributes`,children:(0,$.jsx)(ce,{attributes:T,error:p.error,isPending:p.isPending,isSuccess:p.isSuccess,onSubmit:e=>{p.mutate({loadBalancerArn:r,attributes:e})},specs:ue})}),(0,$.jsx)(X,{value:`tags`,children:E.length>0?(0,$.jsxs)(M,{children:[(0,$.jsx)(M.Header,{children:`Tags`}),(0,$.jsx)(M.Content,{children:E.map(e=>(0,$.jsx)(N,{label:e.Key??``,value:e.Value},e.Key??``))})]}):(0,$.jsx)(`p`,{className:`text-muted-foreground`,children:`No tags.`})})]})]}),(0,$.jsx)(G,{description:`Are you sure you want to delete load balancer "${g.LoadBalancerName??g.LoadBalancerArn}"? This action cannot be undone.`,isPending:d.isPending,onConfirm:b,onOpenChange:h,open:m,title:`Delete load balancer`})]})}function Me(){let e=(0,Q.c)(2),{id:t}=O.useParams(),n=decodeURIComponent(t),r;return e[0]===n?r=e[1]:(r=(0,$.jsx)(je,{arn:n}),e[0]=n,e[1]=r),r}export{Me as component}; \ No newline at end of file +import{n as e,t}from"./error-banner.js";import{t as n}from"./useSuspenseQuery.js";import{t as r}from"./back-link.js";import{c as i,i as a,n as o,s,t as c}from"./select.js";import{t as l}from"./trash-2.js";import{a as u,d,f,g as p,h as m,o as h,r as g,s as _,t as v,u as y}from"./elbv2.js";import{$n as b,A as x,D as S,Do as C,E as w,Eo as T,Ga as E,Ja as D,Jo as O,N as k,Oo as A,Qn as j,T as M,X as N,Xn as P,Zn as F,et as I,i as L,ir as R,k as z,ko as B,nr as V,ot as H,rr as U,uo as ee,w as te,wo as ne,xo as re,za as W,zi as ie}from"./index.js";import{t as ae}from"./page-heading.js";import{t as oe}from"./state-badge.js";import{n as G,t as K}from"./detail-row.js";import{a as se,i as ce,l as le,n as ue,o as de,r as fe,s as pe,t as me}from"./alert-dialog.js";import{a as q,r as J,t as Y}from"./field.js";import{t as he}from"./textarea.js";import{t as ge}from"./delete-confirmation-dialog.js";import{a as _e,i as ve,n as X,r as ye,t as be}from"./zod.js";import{i as xe,n as Se,t as Ce}from"./elbv22.js";import{a as we,i as Te,n as Ee,o as De,r as Oe,s as ke,t as Ae}from"./tabs.js";var je=ee(`pencil`,[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}],[`path`,{d:`m15 5 4 4`,key:`1mk7zo`}]]),Me=`***SensitiveInformation***`;function Ne(e,t){if(t==null)return t;let n=V.of(e);if(n.getMergedTraits().sensitive)return Me;if(n.isListSchema()){if(n.getValueSchema().getMergedTraits().sensitive)return Me}else if(n.isMapSchema()){if(n.getKeySchema().getMergedTraits().sensitive||n.getValueSchema().getMergedTraits().sensitive)return Me}else if(n.isStructSchema()&&typeof t==`object`){let e=t,r={};for(let[t,i]of n.structIterator())e[t]!=null&&(r[t]=Ne(i,e[t]));return r}return t}var Pe=class{middlewareStack=R();schema;static classBuilder(){return new Fe}resolveMiddlewareWithContext(e,t,n,{middlewareFn:r,clientName:i,commandName:a,inputFilterSensitiveLog:o,outputFilterSensitiveLog:s,smithyContext:c,additionalContext:l,CommandCtor:u}){for(let i of r.bind(this)(u,e,t,n))this.middlewareStack.use(i);let d=e.concat(this.middlewareStack),{logger:f}=t,p={logger:f,clientName:i,commandName:a,inputFilterSensitiveLog:o,outputFilterSensitiveLog:s,[U]:{commandInstance:this,...c},...l},{requestHandler:m}=t,h=n??{};return c.eventStream&&(h={isEventStream:!0,...h}),d.resolve(e=>m.handle(e.request,h),p)}},Fe=class{_init=()=>{};_ep={};_middlewareFn=()=>[];_commandName=``;_clientName=``;_additionalContext={};_smithyContext={};_inputFilterSensitiveLog=void 0;_outputFilterSensitiveLog=void 0;_serializer=null;_deserializer=null;_operationSchema;init(e){this._init=e}ep(e){return this._ep=e,this}m(e){return this._middlewareFn=e,this}s(e,t,n={}){return this._smithyContext={service:e,operation:t,...n},this}c(e={}){return this._additionalContext=e,this}n(e,t){return this._clientName=e,this._commandName=t,this}f(e=e=>e,t=e=>e){return this._inputFilterSensitiveLog=e,this._outputFilterSensitiveLog=t,this}ser(e){return this._serializer=e,this}de(e){return this._deserializer=e,this}sc(e){return this._operationSchema=e,this._smithyContext.operationSchema=e,this}build(){let e=this,t;return t=class extends Pe{input;static getEndpointParameterInstructions(){return e._ep}constructor(...[t]){super(),this.input=t??{},e._init(this),this.schema=e._operationSchema}resolveMiddleware(n,r,i){let a=e._operationSchema,o=a?.[4]??a?.input,s=a?.[5]??a?.output;return this.resolveMiddlewareWithContext(n,r,i,{CommandCtor:t,middlewareFn:e._middlewareFn,clientName:e._clientName,commandName:e._commandName,inputFilterSensitiveLog:e._inputFilterSensitiveLog??(a?Ne.bind(null,o):e=>e),outputFilterSensitiveLog:e._outputFilterSensitiveLog??(a?Ne.bind(null,s):e=>e),smithyContext:e._smithyContext,additionalContext:e._additionalContext})}serialize=e._serializer;deserialize=e._deserializer}}},Ie=class extends Pe.classBuilder().ep(j).m(function(e,t,n,r){return[b(n,e.getEndpointParameterInstructions())]}).s(`CertificateManager`,`ImportCertificate`,{}).n(`ACMClient`,`ImportCertificateCommand`).sc(P).build(){},Le=class extends Pe.classBuilder().ep(j).m(function(e,t,n,r){return[b(n,e.getEndpointParameterInstructions())]}).s(`CertificateManager`,`ListCertificates`,{}).n(`ACMClient`,`ListCertificatesCommand`).sc(F).build(){},Z=O(B(),1),Q=re(),Re=new TextEncoder;function ze(){let t=(0,Q.c)(2),n=C(),r;return t[0]===n?r=t[1]:(r={mutationFn:Be,onSuccess:()=>{n.invalidateQueries({queryKey:[`acm`,`certificates`]})}},t[0]=n,t[1]=r),e(r)}async function Be(e){let t=new Ie({Certificate:Re.encode(e.certificate),PrivateKey:Re.encode(e.privateKey),CertificateChain:e.certificateChain&&e.certificateChain.length>0?Re.encode(e.certificateChain):void 0});return await H().send(t)}var $=A();function Ve(e){let n=(0,Q.c)(54),{open:r,onOpenChange:i,onImported:a}=e,[o,s]=(0,Z.useState)(``),[c,l]=(0,Z.useState)(``),[u,d]=(0,Z.useState)(``),f=ze(),p;n[0]===f?p=n[1]:(p=()=>{s(``),l(``),d(``),f.reset()},n[0]=f,n[1]=p);let m=p,h;n[2]!==i||n[3]!==m?(h=e=>{e||m(),i(e)},n[2]=i,n[3]=m,n[4]=h):h=n[4];let g=h,_;n[5]!==o||n[6]!==c?(_=o.trim().length>0&&c.trim().length>0,n[5]=o,n[6]=c,n[7]=_):_=n[7];let v=_,y;n[8]!==v||n[9]!==o||n[10]!==u||n[11]!==f||n[12]!==a||n[13]!==i||n[14]!==c||n[15]!==m?(y=async()=>{if(v)try{let e=await f.mutateAsync({certificate:o,privateKey:c,certificateChain:u});e.CertificateArn&&a(e.CertificateArn),m(),i(!1)}catch{}},n[8]=v,n[9]=o,n[10]=u,n[11]=f,n[12]=a,n[13]=i,n[14]=c,n[15]=m,n[16]=y):y=n[16];let b=y,x;n[17]===Symbol.for(`react.memo_cache_sentinel`)?(x={maxWidth:`36rem`,width:`calc(100vw - 2rem)`},n[17]=x):x=n[17];let S;n[18]===Symbol.for(`react.memo_cache_sentinel`)?(S=(0,$.jsxs)(pe,{children:[(0,$.jsx)(le,{children:`Import certificate`}),(0,$.jsx)(se,{children:`Paste a PEM-encoded certificate and its private key. The optional chain is appended for intermediate CAs.`})]}),n[18]=S):S=n[18];let C;n[19]===f.error?C=n[20]:(C=f.error&&(0,$.jsx)(t,{error:f.error,msg:`Failed to import certificate`}),n[19]=f.error,n[20]=C);let w;n[21]===Symbol.for(`react.memo_cache_sentinel`)?(w=(0,$.jsx)(q,{children:(0,$.jsx)(`label`,{htmlFor:`cert-body`,children:`Certificate body`})}),n[21]=w):w=n[21];let T;n[22]===Symbol.for(`react.memo_cache_sentinel`)?(T=e=>s(e.target.value),n[22]=T):T=n[22];let E;n[23]===o?E=n[24]:(E=(0,$.jsxs)(Y,{children:[w,(0,$.jsx)(he,{className:`font-mono text-xs`,id:`cert-body`,onChange:T,placeholder:`-----BEGIN CERTIFICATE-----`,rows:5,value:o})]}),n[23]=o,n[24]=E);let D;n[25]===Symbol.for(`react.memo_cache_sentinel`)?(D=(0,$.jsx)(q,{children:(0,$.jsx)(`label`,{htmlFor:`cert-key`,children:`Private key`})}),n[25]=D):D=n[25];let O;n[26]===Symbol.for(`react.memo_cache_sentinel`)?(O=e=>l(e.target.value),n[26]=O):O=n[26];let k;n[27]===c?k=n[28]:(k=(0,$.jsxs)(Y,{children:[D,(0,$.jsx)(he,{className:`font-mono text-xs`,id:`cert-key`,onChange:O,placeholder:`-----BEGIN PRIVATE KEY-----`,rows:5,value:c})]}),n[27]=c,n[28]=k);let A;n[29]===Symbol.for(`react.memo_cache_sentinel`)?(A=(0,$.jsx)(q,{children:(0,$.jsx)(`label`,{htmlFor:`cert-chain`,children:`Certificate chain (optional)`})}),n[29]=A):A=n[29];let j;n[30]===Symbol.for(`react.memo_cache_sentinel`)?(j=e=>d(e.target.value),n[30]=j):j=n[30];let M;n[31]===u?M=n[32]:(M=(0,$.jsxs)(Y,{children:[A,(0,$.jsx)(he,{className:`font-mono text-xs`,id:`cert-chain`,onChange:j,placeholder:`-----BEGIN CERTIFICATE-----`,rows:4,value:u})]}),n[31]=u,n[32]=M);let N;n[33]!==E||n[34]!==k||n[35]!==M?(N=(0,$.jsxs)(`div`,{className:`min-w-0 space-y-4`,children:[E,k,M]}),n[33]=E,n[34]=k,n[35]=M,n[36]=N):N=n[36];let P;n[37]===f.isPending?P=n[38]:(P=(0,$.jsx)(fe,{disabled:f.isPending,children:`Cancel`}),n[37]=f.isPending,n[38]=P);let F=!v||f.isPending,I=f.isPending?`Importing…`:`Import`,L;n[39]!==b||n[40]!==F||n[41]!==I?(L=(0,$.jsx)(ue,{disabled:F,onClick:b,children:I}),n[39]=b,n[40]=F,n[41]=I,n[42]=L):L=n[42];let R;n[43]!==P||n[44]!==L?(R=(0,$.jsxs)(de,{children:[P,L]}),n[43]=P,n[44]=L,n[45]=R):R=n[45];let z;n[46]!==N||n[47]!==R||n[48]!==C?(z=(0,$.jsxs)(ce,{className:`grid-cols-[minmax(0,1fr)]`,style:x,children:[S,C,N,R]}),n[46]=N,n[47]=R,n[48]=C,n[49]=z):z=n[49];let B;return n[50]!==g||n[51]!==r||n[52]!==z?(B=(0,$.jsx)(me,{onOpenChange:g,open:r,children:z}),n[50]=g,n[51]=r,n[52]=z,n[53]=B):B=n[53],B}var He=80,Ue=443;function We(e){let t=e.CertificateArn?.split(`/`).pop()??e.CertificateArn??``;return e.DomainName?`${e.DomainName} · ${t}`:t}function Ge(e){let t=(0,Q.c)(55),{form:n,targetGroups:r,certificates:l,sslPolicies:u}=e,d;t[0]===l?d=t[1]:(d=l===void 0?[]:l,t[0]=l,t[1]=d);let f=d,p;t[2]===u?p=t[3]:(p=u===void 0?[]:u,t[2]=u,t[3]=p);let m=p,{control:h,register:g,getValues:_,setValue:v,formState:y}=n,{errors:b}=y,[x,S]=(0,Z.useState)(!1),C;t[4]===h?C=t[5]:(C={control:h,name:`protocol`},t[4]=h,t[5]=C);let w=_e(C)===`HTTPS`,T;t[6]!==_||t[7]!==v?(T=e=>{let t=_(`port`);e===`HTTPS`?(t===He&&v(`port`,Ue),_(`sslPolicy`)||v(`sslPolicy`,Ce)):(t===Ue&&v(`port`,He),v(`certificateArn`,void 0),v(`sslPolicy`,void 0))},t[6]=_,t[7]=v,t[8]=T):T=t[8];let E=T,D;t[9]===Symbol.for(`react.memo_cache_sentinel`)?(D=(0,$.jsx)(q,{children:(0,$.jsx)(`label`,{htmlFor:`listener-protocol`,children:`Protocol`})}),t[9]=D):D=t[9];let O;t[10]===E?O=t[11]:(O=e=>{let{field:t}=e;return(0,$.jsxs)(c,{onValueChange:e=>{t.onChange(e),E(e)},value:t.value,children:[(0,$.jsx)(s,{className:`w-full`,id:`listener-protocol`,children:(0,$.jsx)(i,{})}),(0,$.jsxs)(o,{children:[(0,$.jsx)(a,{value:`HTTP`,children:`HTTP`}),(0,$.jsx)(a,{value:`HTTPS`,children:`HTTPS`})]})]})},t[10]=E,t[11]=O);let k;t[12]!==h||t[13]!==O?(k=(0,$.jsxs)(Y,{children:[D,(0,$.jsx)(X,{control:h,name:`protocol`,render:O})]}),t[12]=h,t[13]=O,t[14]=k):k=t[14];let A;t[15]===Symbol.for(`react.memo_cache_sentinel`)?(A=(0,$.jsx)(q,{children:(0,$.jsx)(`label`,{htmlFor:`listener-port`,children:`Port`})}),t[15]=A):A=t[15];let j=!!b.port,M=w?`443`:`80`,N;t[16]===g?N=t[17]:(N=g(`port`,{valueAsNumber:!0}),t[16]=g,t[17]=N);let P;t[18]!==j||t[19]!==M||t[20]!==N?(P=(0,$.jsx)(ie,{"aria-invalid":j,id:`listener-port`,inputMode:`numeric`,placeholder:M,type:`number`,...N}),t[18]=j,t[19]=M,t[20]=N,t[21]=P):P=t[21];let F;t[22]===b.port?F=t[23]:(F=(0,$.jsx)(J,{errors:[b.port]}),t[22]=b.port,t[23]=F);let I;t[24]!==P||t[25]!==F?(I=(0,$.jsxs)(Y,{children:[A,P,F]}),t[24]=P,t[25]=F,t[26]=I):I=t[26];let L;t[27]!==f||t[28]!==h||t[29]!==b.certificateArn||t[30]!==x||t[31]!==w||t[32]!==v||t[33]!==m?(L=w&&(0,$.jsxs)($.Fragment,{children:[(0,$.jsxs)(Y,{children:[(0,$.jsx)(q,{children:(0,$.jsx)(`label`,{htmlFor:`listener-certificate`,children:`Certificate`})}),(0,$.jsx)(X,{control:h,name:`certificateArn`,render:e=>{let{field:t}=e;return(0,$.jsxs)(c,{onValueChange:t.onChange,value:t.value??``,children:[(0,$.jsx)(s,{"aria-invalid":!!b.certificateArn,className:`w-full`,id:`listener-certificate`,children:(0,$.jsx)(i,{placeholder:`Select certificate`})}),(0,$.jsx)(o,{children:f.map(Je)})]})}}),(0,$.jsx)(J,{errors:[b.certificateArn]}),(0,$.jsxs)(`div`,{className:`mt-1 flex items-center justify-between`,children:[f.length===0&&(0,$.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No certificates imported yet.`}),(0,$.jsx)(W,{className:`ml-auto`,onClick:()=>S(!0),size:`sm`,type:`button`,variant:`ghost`,children:`Import certificate…`})]})]}),(0,$.jsxs)(Y,{children:[(0,$.jsx)(q,{children:(0,$.jsx)(`label`,{htmlFor:`listener-ssl-policy`,children:`Security policy`})}),(0,$.jsx)(X,{control:h,name:`sslPolicy`,render:e=>{let{field:t}=e;return(0,$.jsxs)(c,{onValueChange:t.onChange,value:t.value??`ELBSecurityPolicy-2016-08`,children:[(0,$.jsx)(s,{className:`w-full`,id:`listener-ssl-policy`,children:(0,$.jsx)(i,{})}),(0,$.jsx)(o,{children:m.map(qe)})]})}})]}),(0,$.jsx)(Ve,{onImported:e=>v(`certificateArn`,e,{shouldValidate:!0}),onOpenChange:S,open:x})]}),t[27]=f,t[28]=h,t[29]=b.certificateArn,t[30]=x,t[31]=w,t[32]=v,t[33]=m,t[34]=L):L=t[34];let R;t[35]===Symbol.for(`react.memo_cache_sentinel`)?(R=(0,$.jsx)(q,{children:(0,$.jsx)(`label`,{htmlFor:`listener-default-tg`,children:`Default target group`})}),t[35]=R):R=t[35];let z;t[36]!==b.defaultTargetGroupArn||t[37]!==r?(z=e=>{let{field:t}=e;return(0,$.jsxs)(c,{onValueChange:t.onChange,value:t.value??``,children:[(0,$.jsx)(s,{"aria-invalid":!!b.defaultTargetGroupArn,className:`w-full`,id:`listener-default-tg`,children:(0,$.jsx)(i,{placeholder:`Select target group`})}),(0,$.jsx)(o,{children:r.map(Ke)})]})},t[36]=b.defaultTargetGroupArn,t[37]=r,t[38]=z):z=t[38];let B;t[39]!==h||t[40]!==z?(B=(0,$.jsx)(X,{control:h,name:`defaultTargetGroupArn`,render:z}),t[39]=h,t[40]=z,t[41]=B):B=t[41];let V;t[42]===b.defaultTargetGroupArn?V=t[43]:(V=(0,$.jsx)(J,{errors:[b.defaultTargetGroupArn]}),t[42]=b.defaultTargetGroupArn,t[43]=V);let H;t[44]===r.length?H=t[45]:(H=r.length===0&&(0,$.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground`,children:`No target groups available in this VPC. Create one first.`}),t[44]=r.length,t[45]=H);let U;t[46]!==B||t[47]!==V||t[48]!==H?(U=(0,$.jsxs)(Y,{children:[R,B,V,H]}),t[46]=B,t[47]=V,t[48]=H,t[49]=U):U=t[49];let ee;return t[50]!==k||t[51]!==I||t[52]!==L||t[53]!==U?(ee=(0,$.jsxs)($.Fragment,{children:[k,I,L,U]}),t[50]=k,t[51]=I,t[52]=L,t[53]=U,t[54]=ee):ee=t[54],ee}function Ke(e){return(0,$.jsxs)(a,{value:e.TargetGroupArn??``,children:[e.TargetGroupName,` · `,e.Protocol,`:`,e.Port]},e.TargetGroupArn)}function qe(e){return(0,$.jsx)(a,{value:e.Name??``,children:e.Name},e.Name)}function Je(e){return(0,$.jsx)(a,{value:e.CertificateArn??``,children:We(e)},e.CertificateArn)}function Ye({listenerArn:e,targetGroups:r}){let{data:i}=n(te(e)),a=g(),o=f(),s=_(),[c,u]=(0,Z.useState)(!1),[d,p]=(0,Z.useState)(),[m,h]=(0,Z.useState)(),v=i.Rules??[],y=new Map;for(let e of r)e.TargetGroupArn&&e.TargetGroupName&&y.set(e.TargetGroupArn,e.TargetGroupName);return(0,$.jsxs)(`div`,{className:`space-y-3`,children:[a.error&&(0,$.jsx)(t,{error:a.error,msg:`Failed to create rule`}),o.error&&(0,$.jsx)(t,{error:o.error,msg:`Failed to modify rule`}),s.error&&(0,$.jsx)(t,{error:s.error,msg:`Failed to delete rule`}),(0,$.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,$.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[v.length,` rule`,v.length===1?``:`s`,` (including default)`]}),(0,$.jsx)(W,{onClick:()=>u(!0),size:`sm`,children:`Add rule`})]}),(0,$.jsx)(`div`,{className:`overflow-x-auto rounded-lg border bg-card`,children:(0,$.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,$.jsx)(`thead`,{children:(0,$.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Priority`}),(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Conditions`}),(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Forward to`}),(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:(0,$.jsx)(`span`,{className:`sr-only`,children:`Actions`})})]})}),(0,$.jsx)(`tbody`,{children:v.map(e=>(0,$.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,$.jsx)(`td`,{className:`px-4 py-2`,children:e.Priority}),(0,$.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:Xe(e.Conditions,e.IsDefault===!0)}),(0,$.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:Qe(e,y)}),(0,$.jsx)(`td`,{className:`px-4 py-2 text-right`,children:e.IsDefault===!0?(0,$.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`Edit via listener`}):(0,$.jsxs)(`div`,{className:`flex justify-end gap-1`,children:[(0,$.jsx)(W,{"aria-label":`Edit rule ${e.Priority}`,onClick:()=>p(e),size:`sm`,variant:`ghost`,children:(0,$.jsx)(je,{className:`size-4`})}),(0,$.jsx)(W,{"aria-label":`Delete rule ${e.Priority}`,onClick:()=>h(e),size:`sm`,variant:`ghost`,children:(0,$.jsx)(l,{className:`size-4`})})]})})]},e.RuleArn??e.Priority??`default`))})]})}),(0,$.jsx)(et,{isPending:a.isPending,mode:`add`,onOpenChange:u,onSubmit:async t=>{try{await a.mutateAsync({listenerArn:e,priority:t.priority,conditions:t.conditions.map($e),forwardTargetGroupArn:t.forwardTargetGroupArn}),u(!1)}catch{}},open:c,targetGroups:r}),(0,$.jsx)(et,{initialRule:d,isPending:o.isPending,mode:`edit`,onOpenChange:e=>!e&&p(void 0),onSubmit:async t=>{if(d?.RuleArn)try{await o.mutateAsync({ruleArn:d.RuleArn,listenerArn:e,conditions:t.conditions.map($e),forwardTargetGroupArn:t.forwardTargetGroupArn}),p(void 0)}catch{}},open:d!==void 0,targetGroups:r}),(0,$.jsx)(ge,{description:m?`Delete rule with priority ${m.Priority}? This cannot be undone.`:``,isPending:s.isPending,onConfirm:async()=>{if(m?.RuleArn)try{await s.mutateAsync({ruleArn:m.RuleArn,listenerArn:e})}finally{h(void 0)}},onOpenChange:e=>!e&&h(void 0),open:m!==void 0,title:`Delete rule`})]})}function Xe(e,t){return t?`default`:!e||e.length===0?`—`:e.map(e=>{let t=Ze(e);return`${e.Field}: ${t.join(`, `)}`}).join(` AND `)}function Ze(e){if(e.Field===void 0)return e.Values??[];switch(e.Field){case`host-header`:return e.HostHeaderConfig?.Values??e.Values??[];case`path-pattern`:return e.PathPatternConfig?.Values??e.Values??[];case`http-header`:{let t=e.HttpHeaderConfig?.HttpHeaderName??`?`;return(e.HttpHeaderConfig?.Values??[]).map(e=>`${t}=${e}`)}case`http-request-method`:return e.HttpRequestMethodConfig?.Values??[];case`source-ip`:return e.SourceIpConfig?.Values??[];case`query-string`:return(e.QueryStringConfig?.Values??[]).map(e=>e.Key?`${e.Key}=${e.Value??``}`:e.Value??``);default:return e.Values??[]}}function Qe(e,t){let n=e.Actions?.[0];return n?n.Type===`forward`&&n.TargetGroupArn?t.get(n.TargetGroupArn)??n.TargetGroupArn:n.Type??`—`:`—`}function $e(e){let t=e.rawValues.split(/[\n,]/).map(e=>e.trim()).filter(e=>e.length>0);return e.field===`query-string`?{field:e.field,values:[],queryStringPairs:t.map(e=>{let t=e.indexOf(`=`);return t===-1?{value:e}:{key:e.slice(0,t),value:e.slice(t+1)}})}:{field:e.field,values:t,httpHeaderName:e.httpHeaderName}}function et({open:e,onOpenChange:t,onSubmit:n,isPending:r,targetGroups:l,mode:u,initialRule:d}){let f=[{field:`path-pattern`,rawValues:``}],p=ve({resolver:be(xe),defaultValues:{priority:1,conditions:f,forwardTargetGroupArn:``}}),{fields:m,append:h,remove:g}=ye({control:p.control,name:`conditions`});(0,Z.useEffect)(()=>{if(u===`add`){e||p.reset({priority:1,conditions:f,forwardTargetGroupArn:``});return}if(!d)return;let t=Number(d.Priority??1),n=d.Conditions?.map(e=>at(e))??f;p.reset({priority:Number.isFinite(t)?t:1,conditions:n.length>0?n:f,forwardTargetGroupArn:d.Actions?.[0]?.TargetGroupArn??``})},[d,e,u]);let _=p.handleSubmit(n);return(0,$.jsx)(me,{onOpenChange:t,open:e,children:(0,$.jsxs)(ce,{className:`grid-cols-[minmax(0,1fr)]`,style:{maxWidth:`40rem`,width:`calc(100vw - 2rem)`},children:[(0,$.jsxs)(pe,{children:[(0,$.jsx)(le,{children:u===`add`?`Add rule`:`Edit rule`}),(0,$.jsx)(se,{children:`Routing rules match incoming requests and forward them to a target group. Rules evaluate in priority order; the listener default applies when no rule matches.`})]}),(0,$.jsxs)(`form`,{className:`min-w-0 space-y-4`,onSubmit:e=>{e.preventDefault(),_()},children:[(0,$.jsxs)(Y,{children:[(0,$.jsx)(q,{children:(0,$.jsx)(`label`,{htmlFor:`rule-priority`,children:`Priority`})}),(0,$.jsx)(ie,{"aria-invalid":!!p.formState.errors.priority,id:`rule-priority`,inputMode:`numeric`,type:`number`,...p.register(`priority`,{valueAsNumber:!0})}),(0,$.jsx)(J,{errors:[p.formState.errors.priority]})]}),(0,$.jsxs)(`div`,{className:`space-y-3`,children:[(0,$.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,$.jsx)(q,{children:`Conditions`}),(0,$.jsx)(W,{disabled:m.length>=5,onClick:()=>h({field:`path-pattern`,rawValues:``}),size:`sm`,type:`button`,variant:`outline`,children:`Add condition`})]}),m.map((e,t)=>(0,$.jsx)(tt,{form:p,index:t,onRemove:m.length>1?()=>g(t):void 0},e.id))]}),(0,$.jsxs)(Y,{children:[(0,$.jsx)(q,{children:(0,$.jsx)(`label`,{htmlFor:`rule-forward-tg`,children:`Forward to target group`})}),(0,$.jsx)(X,{control:p.control,name:`forwardTargetGroupArn`,render:({field:e})=>(0,$.jsxs)(c,{onValueChange:e.onChange,value:e.value??``,children:[(0,$.jsx)(s,{"aria-invalid":!!p.formState.errors.forwardTargetGroupArn,className:`w-full`,id:`rule-forward-tg`,children:(0,$.jsx)(i,{placeholder:`Select target group`})}),(0,$.jsx)(o,{children:l.map(e=>(0,$.jsxs)(a,{value:e.TargetGroupArn??``,children:[e.TargetGroupName,` · `,e.Protocol,`:`,e.Port]},e.TargetGroupArn))})]})}),(0,$.jsx)(J,{errors:[p.formState.errors.forwardTargetGroupArn]})]})]}),(0,$.jsxs)(de,{children:[(0,$.jsx)(fe,{disabled:r,children:`Cancel`}),(0,$.jsx)(ue,{disabled:r,onClick:_,children:ot(u,r)})]})]})})}function tt(e){let t=(0,Q.c)(54),{form:n,index:r,onRemove:u}=e,d,f,p,m,h,g,_,v,y,b;if(t[0]!==n||t[1]!==r||t[2]!==u){let e=n.watch(`conditions.${r}.field`);p=n.formState.errors.conditions?.[r],v=`space-y-2 rounded-md border p-3`;let x=`rule-cond-${r}-field`,S;t[13]===x?S=t[14]:(S=(0,$.jsx)(q,{children:(0,$.jsx)(`label`,{htmlFor:x,children:`Type`})}),t[13]=x,t[14]=S);let C=`conditions.${r}.field`,w;t[15]===r?w=t[16]:(w=e=>{let{field:t}=e;return(0,$.jsxs)(c,{onValueChange:t.onChange,value:t.value,children:[(0,$.jsx)(s,{className:`w-full`,id:`rule-cond-${r}-field`,children:(0,$.jsx)(i,{})}),(0,$.jsxs)(o,{children:[(0,$.jsx)(a,{value:`path-pattern`,children:`Path pattern`}),(0,$.jsx)(a,{value:`host-header`,children:`Host header`}),(0,$.jsx)(a,{value:`http-header`,children:`HTTP header`}),(0,$.jsx)(a,{value:`http-request-method`,children:`HTTP method`}),(0,$.jsx)(a,{value:`source-ip`,children:`Source IP CIDR`}),(0,$.jsx)(a,{value:`query-string`,children:`Query string`})]})]})},t[15]=r,t[16]=w);let T;t[17]!==n.control||t[18]!==C||t[19]!==w?(T=(0,$.jsx)(X,{control:n.control,name:C,render:w}),t[17]=n.control,t[18]=C,t[19]=w,t[20]=T):T=t[20];let E;t[21]!==T||t[22]!==S?(E=(0,$.jsxs)(`div`,{className:`flex-1`,children:[S,T]}),t[21]=T,t[22]=S,t[23]=E):E=t[23];let D;t[24]!==r||t[25]!==u?(D=u&&(0,$.jsx)(W,{"aria-label":`Remove condition ${r+1}`,className:`self-end`,onClick:u,size:`sm`,type:`button`,variant:`ghost`,children:(0,$.jsx)(l,{className:`size-4`})}),t[24]=r,t[25]=u,t[26]=D):D=t[26],t[27]!==E||t[28]!==D?(y=(0,$.jsxs)(`div`,{className:`flex gap-2`,children:[E,D]}),t[27]=E,t[28]=D,t[29]=y):y=t[29],b=e===`http-header`&&(0,$.jsxs)(Y,{children:[(0,$.jsx)(q,{children:(0,$.jsx)(`label`,{htmlFor:`rule-cond-${r}-hdr-name`,children:`Header name`})}),(0,$.jsx)(ie,{"aria-invalid":!!p?.httpHeaderName,id:`rule-cond-${r}-hdr-name`,placeholder:`X-Tenant`,...n.register(`conditions.${r}.httpHeaderName`)}),(0,$.jsx)(J,{errors:[p?.httpHeaderName]})]}),f=Y;let O=`rule-cond-${r}-values`,k;t[30]===Symbol.for(`react.memo_cache_sentinel`)?(k=(0,$.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`(comma or newline separated, max 5)`}),t[30]=k):k=t[30],t[31]===O?_=t[32]:(_=(0,$.jsx)(q,{children:(0,$.jsxs)(`label`,{htmlFor:O,children:[`Values`,` `,k]})}),t[31]=O,t[32]=_),d=ie,m=!!p?.rawValues,h=`rule-cond-${r}-values`,g=nt(e),t[0]=n,t[1]=r,t[2]=u,t[3]=d,t[4]=f,t[5]=p,t[6]=m,t[7]=h,t[8]=g,t[9]=_,t[10]=v,t[11]=y,t[12]=b}else d=t[3],f=t[4],p=t[5],m=t[6],h=t[7],g=t[8],_=t[9],v=t[10],y=t[11],b=t[12];let x;t[33]!==n||t[34]!==r?(x=n.register(`conditions.${r}.rawValues`),t[33]=n,t[34]=r,t[35]=x):x=t[35];let S;t[36]!==d||t[37]!==m||t[38]!==h||t[39]!==g||t[40]!==x?(S=(0,$.jsx)(d,{"aria-invalid":m,id:h,placeholder:g,...x}),t[36]=d,t[37]=m,t[38]=h,t[39]=g,t[40]=x,t[41]=S):S=t[41];let C=p?.rawValues,w;t[42]===C?w=t[43]:(w=(0,$.jsx)(J,{errors:[C]}),t[42]=C,t[43]=w);let T;t[44]!==f||t[45]!==w||t[46]!==_||t[47]!==S?(T=(0,$.jsxs)(f,{children:[_,S,w]}),t[44]=f,t[45]=w,t[46]=_,t[47]=S,t[48]=T):T=t[48];let E;return t[49]!==T||t[50]!==v||t[51]!==y||t[52]!==b?(E=(0,$.jsxs)(`div`,{className:v,children:[y,b,T]}),t[49]=T,t[50]=v,t[51]=y,t[52]=b,t[53]=E):E=t[53],E}function nt(e){switch(e){case`path-pattern`:return`/api/*`;case`host-header`:return`*.example.com`;case`http-header`:return`acme`;case`http-request-method`:return`GET, POST`;case`source-ip`:return`10.0.0.0/8`;case`query-string`:return`key=value`;default:return``}}var rt=new Set([`host-header`,`path-pattern`,`http-header`,`http-request-method`,`source-ip`,`query-string`]);function it(e){return e!==void 0&&rt.has(e)}function at(e){let t=Ze(e);return{field:it(e.Field)?e.Field:`path-pattern`,httpHeaderName:e.HttpHeaderConfig?.HttpHeaderName,rawValues:t.join(`, `)}}function ot(e,t){return t?e===`add`?`Adding…`:`Saving…`:e===`add`?`Add rule`:`Save changes`}var st=T({queryKey:[`acm`,`certificates`],queryFn:async()=>{let e=new Le({});return await H().send(e)}});function ct(e){if(e.Protocol!==`HTTPS`)return`—`;let t=e.Certificates?.[0]?.CertificateArn?.split(`/`).pop(),n=e.SslPolicy;return t&&n?`${n} · ${t}`:n??t??`—`}function lt({loadBalancerArn:e,vpcId:r}){let{data:i}=n(M(e)),{data:a}=n(k),{data:o}=n(st),{data:s}=n(z),c=v(),d=u(),f=y(),[p,m]=(0,Z.useState)(!1),[h,g]=(0,Z.useState)(),[_,b]=(0,Z.useState)(),[x,S]=(0,Z.useState)(),C=i.Listeners??[],w=a.TargetGroups??[],T=w.filter(e=>e.VpcId===r),E=o.CertificateSummaryList??[],D=s.SslPolicies??[],O=new Map;for(let e of w)e.TargetGroupArn&&e.TargetGroupName&&O.set(e.TargetGroupArn,e.TargetGroupName);let A=e=>{let t=e.DefaultActions?.[0];if(!t)return`—`;if(t.Type===`forward`&&t.TargetGroupArn){let e=O.get(t.TargetGroupArn);return e?`forward → ${e}`:`forward → ${t.TargetGroupArn}`}return t.Type??`—`};return(0,$.jsxs)(`div`,{className:`space-y-3`,children:[c.error&&(0,$.jsx)(t,{error:c.error,msg:`Failed to create listener`}),f.error&&(0,$.jsx)(t,{error:f.error,msg:`Failed to modify listener`}),d.error&&(0,$.jsx)(t,{error:d.error,msg:`Failed to delete listener`}),(0,$.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,$.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[C.length,` listener`,C.length===1?``:`s`]}),(0,$.jsx)(W,{onClick:()=>m(!0),size:`sm`,children:`Add listener`})]}),C.length===0?(0,$.jsx)(`p`,{className:`text-muted-foreground`,children:`No listeners configured.`}):(0,$.jsx)(`div`,{className:`overflow-x-auto rounded-lg border bg-card`,children:(0,$.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,$.jsx)(`thead`,{children:(0,$.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Protocol`}),(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Port`}),(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`TLS`}),(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Default action`}),(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Listener ARN`}),(0,$.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:(0,$.jsx)(`span`,{className:`sr-only`,children:`Actions`})})]})}),(0,$.jsx)(`tbody`,{children:C.map(e=>{let t=e.ListenerArn??``,n=x===t;return(0,$.jsxs)(Z.Fragment,{children:[(0,$.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,$.jsx)(`td`,{className:`px-4 py-2`,children:e.Protocol}),(0,$.jsx)(`td`,{className:`px-4 py-2`,children:e.Port}),(0,$.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:ct(e)}),(0,$.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:A(e)}),(0,$.jsx)(`td`,{className:`px-4 py-2 font-mono text-xs`,children:t}),(0,$.jsx)(`td`,{className:`px-4 py-2 text-right`,children:(0,$.jsxs)(`div`,{className:`flex justify-end gap-1`,children:[(0,$.jsx)(W,{"aria-label":`${n?`Hide`:`Show`} rules for listener ${e.Protocol}:${e.Port}`,onClick:()=>S(n?void 0:t),size:`sm`,variant:`ghost`,children:n?`Hide rules`:`Rules`}),(0,$.jsx)(W,{"aria-label":`Edit listener ${e.Protocol}:${e.Port}`,onClick:()=>g(e),size:`sm`,variant:`ghost`,children:(0,$.jsx)(je,{className:`size-4`})}),(0,$.jsx)(W,{"aria-label":`Delete listener ${e.Protocol}:${e.Port}`,onClick:()=>b(e),size:`sm`,variant:`ghost`,children:(0,$.jsx)(l,{className:`size-4`})})]})})]}),n&&t&&(0,$.jsx)(`tr`,{className:`border-b bg-muted/30 last:border-0`,children:(0,$.jsx)(`td`,{className:`px-4 py-3`,colSpan:6,children:(0,$.jsx)(Ye,{listenerArn:t,targetGroups:T})})})]},t)})})]})}),(0,$.jsx)(dt,{certificates:E,isPending:c.isPending,onOpenChange:m,onSubmit:async t=>{try{await c.mutateAsync({loadBalancerArn:e,protocol:t.protocol,port:t.port,defaultTargetGroupArn:t.defaultTargetGroupArn,certificateArn:t.certificateArn,sslPolicy:t.sslPolicy}),m(!1)}catch{}},open:p,sslPolicies:D,targetGroups:T}),(0,$.jsx)(ft,{certificates:E,isPending:f.isPending,listener:h,onOpenChange:e=>!e&&g(void 0),onSubmit:async t=>{if(h?.ListenerArn)try{await f.mutateAsync({listenerArn:h.ListenerArn,loadBalancerArn:e,protocol:t.protocol,port:t.port,defaultTargetGroupArn:t.defaultTargetGroupArn,certificateArn:t.certificateArn,sslPolicy:t.sslPolicy}),g(void 0)}catch{}},sslPolicies:D,targetGroups:T}),(0,$.jsx)(ge,{description:_?`Delete listener ${_.Protocol}:${_.Port}? This cannot be undone.`:``,isPending:d.isPending,onConfirm:async()=>{if(_?.ListenerArn)try{await d.mutateAsync(_.ListenerArn)}finally{b(void 0)}},onOpenChange:e=>!e&&b(void 0),open:_!==void 0,title:`Delete listener`})]})}var ut={protocol:`HTTP`,port:80,defaultTargetGroupArn:``};function dt(e){let t=(0,Q.c)(36),{open:n,onOpenChange:r,targetGroups:i,certificates:a,sslPolicies:o,isPending:s,onSubmit:c}=e,l;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(l={resolver:be(Se),defaultValues:ut},t[0]=l):l=t[0];let u=ve(l),d,f;t[1]!==u||t[2]!==n?(d=()=>{n||u.reset(ut)},f=[n,u],t[1]=u,t[2]=n,t[3]=d,t[4]=f):(d=t[3],f=t[4]),(0,Z.useEffect)(d,f);let p;t[5]!==u||t[6]!==c?(p=u.handleSubmit(c),t[5]=u,t[6]=c,t[7]=p):p=t[7];let m=p,h;t[8]===Symbol.for(`react.memo_cache_sentinel`)?(h={maxWidth:`32rem`,width:`calc(100vw - 2rem)`},t[8]=h):h=t[8];let g;t[9]===Symbol.for(`react.memo_cache_sentinel`)?(g=(0,$.jsxs)(pe,{children:[(0,$.jsx)(le,{children:`Add listener`}),(0,$.jsx)(se,{children:`Listeners forward incoming traffic to a default target group.`})]}),t[9]=g):g=t[9];let _;t[10]===m?_=t[11]:(_=e=>{e.preventDefault(),m()},t[10]=m,t[11]=_);let v;t[12]!==a||t[13]!==u||t[14]!==o||t[15]!==i?(v=(0,$.jsx)(Ge,{certificates:a,form:u,sslPolicies:o,targetGroups:i}),t[12]=a,t[13]=u,t[14]=o,t[15]=i,t[16]=v):v=t[16];let y;t[17]!==_||t[18]!==v?(y=(0,$.jsx)(`form`,{className:`min-w-0 space-y-4`,onSubmit:_,children:v}),t[17]=_,t[18]=v,t[19]=y):y=t[19];let b;t[20]===s?b=t[21]:(b=(0,$.jsx)(fe,{disabled:s,children:`Cancel`}),t[20]=s,t[21]=b);let x=s?`Adding…`:`Add listener`,S;t[22]!==m||t[23]!==s||t[24]!==x?(S=(0,$.jsx)(ue,{disabled:s,onClick:m,children:x}),t[22]=m,t[23]=s,t[24]=x,t[25]=S):S=t[25];let C;t[26]!==b||t[27]!==S?(C=(0,$.jsxs)(de,{children:[b,S]}),t[26]=b,t[27]=S,t[28]=C):C=t[28];let w;t[29]!==C||t[30]!==y?(w=(0,$.jsxs)(ce,{className:`grid-cols-[minmax(0,1fr)]`,style:h,children:[g,y,C]}),t[29]=C,t[30]=y,t[31]=w):w=t[31];let T;return t[32]!==r||t[33]!==n||t[34]!==w?(T=(0,$.jsx)(me,{onOpenChange:r,open:n,children:w}),t[32]=r,t[33]=n,t[34]=w,t[35]=T):T=t[35],T}function ft(e){let t=(0,Q.c)(36),{listener:n,onOpenChange:r,targetGroups:i,certificates:a,sslPolicies:o,isPending:s,onSubmit:c}=e,l=n!==void 0,u;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(u={resolver:be(Se),defaultValues:{protocol:`HTTP`,port:80,defaultTargetGroupArn:``}},t[0]=u):u=t[0];let d=ve(u),f,p;t[1]!==d||t[2]!==n?(f=()=>{if(!n)return;let e=n.Protocol===`HTTPS`?`HTTPS`:`HTTP`;d.reset({protocol:e,port:n.Port??80,defaultTargetGroupArn:n.DefaultActions?.[0]?.TargetGroupArn??``,certificateArn:e===`HTTPS`?n.Certificates?.[0]?.CertificateArn:void 0,sslPolicy:e===`HTTPS`?n.SslPolicy:void 0})},p=[n,d],t[1]=d,t[2]=n,t[3]=f,t[4]=p):(f=t[3],p=t[4]),(0,Z.useEffect)(f,p);let m;t[5]!==d||t[6]!==c?(m=d.handleSubmit(c),t[5]=d,t[6]=c,t[7]=m):m=t[7];let h=m,g;t[8]===Symbol.for(`react.memo_cache_sentinel`)?(g={maxWidth:`32rem`,width:`calc(100vw - 2rem)`},t[8]=g):g=t[8];let _;t[9]===Symbol.for(`react.memo_cache_sentinel`)?(_=(0,$.jsxs)(pe,{children:[(0,$.jsx)(le,{children:`Edit listener`}),(0,$.jsx)(se,{children:`Update port, protocol, or default target group. Changes apply without dropping the listener.`})]}),t[9]=_):_=t[9];let v;t[10]===h?v=t[11]:(v=e=>{e.preventDefault(),h()},t[10]=h,t[11]=v);let y;t[12]!==a||t[13]!==d||t[14]!==o||t[15]!==i?(y=(0,$.jsx)(Ge,{certificates:a,form:d,sslPolicies:o,targetGroups:i}),t[12]=a,t[13]=d,t[14]=o,t[15]=i,t[16]=y):y=t[16];let b;t[17]!==v||t[18]!==y?(b=(0,$.jsx)(`form`,{className:`min-w-0 space-y-4`,onSubmit:v,children:y}),t[17]=v,t[18]=y,t[19]=b):b=t[19];let x;t[20]===s?x=t[21]:(x=(0,$.jsx)(fe,{disabled:s,children:`Cancel`}),t[20]=s,t[21]=x);let S=s?`Saving…`:`Save changes`,C;t[22]!==h||t[23]!==s||t[24]!==S?(C=(0,$.jsx)(ue,{disabled:s,onClick:h,children:S}),t[22]=h,t[23]=s,t[24]=S,t[25]=C):C=t[25];let w;t[26]!==x||t[27]!==C?(w=(0,$.jsxs)(de,{children:[x,C]}),t[26]=x,t[27]=C,t[28]=w):w=t[28];let T;t[29]!==w||t[30]!==b?(T=(0,$.jsxs)(ce,{className:`grid-cols-[minmax(0,1fr)]`,style:g,children:[_,b,w]}),t[29]=w,t[30]=b,t[31]=T):T=t[31];let E;return t[32]!==r||t[33]!==l||t[34]!==T?(E=(0,$.jsx)(me,{onOpenChange:r,open:l,children:T}),t[32]=r,t[33]=l,t[34]=T,t[35]=E):E=t[35],E}function pt(e,t){if(e.length!==t.length)return!1;let n=new Set(t);return e.every(e=>n.has(e))}function mt(e){let t=(0,Q.c)(46),{available:n,current:r,onSubmit:i,isPending:a,error:o,isSuccess:s}=e,c;t[0]===r?c=t[1]:(c=[...r],t[0]=r,t[1]=c);let l=c,[u,d]=(0,Z.useState)(l),f;t[2]===Symbol.for(`react.memo_cache_sentinel`)?(f=e=>{d(t=>t.includes(e)?t.filter(t=>t!==e):[...t,e])},t[2]=f):f=t[2];let p=f,m;t[3]===l?m=t[4]:(m=()=>d(l),t[3]=l,t[4]=m);let h=m,g;t[5]!==l||t[6]!==u?(g=pt(u,l),t[5]=l,t[6]=u,t[7]=g):g=t[7];let _=!g,v=u.length===0,y;t[8]!==_||t[9]!==v||t[10]!==i||t[11]!==u?(y=e=>{e.preventDefault(),!(!_||v)&&i(u)},t[8]=_,t[9]=v,t[10]=i,t[11]=u,t[12]=y):y=t[12];let b;t[13]===o?b=t[14]:(b=o&&(0,$.jsx)(`div`,{className:`mb-4 rounded-md border border-destructive bg-destructive/10 p-3 text-sm text-destructive`,role:`alert`,children:o.message||`Failed to update security groups`}),t[13]=o,t[14]=b);let x;t[15]!==_||t[16]!==s?(x=s&&!_&&(0,$.jsx)(`div`,{className:`mb-4 rounded-md border border-emerald-500 bg-emerald-500/10 p-3 text-sm text-emerald-700 dark:text-emerald-400`,role:`status`,children:`Security groups updated.`}),t[15]=_,t[16]=s,t[17]=x):x=t[17];let S;t[18]!==n||t[19]!==u?(S=n.length===0?(0,$.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`No security groups in this VPC.`}):n.map(e=>(0,$.jsxs)(`label`,{className:`flex items-center gap-2 text-sm`,children:[(0,$.jsx)(`input`,{"aria-label":`Security group ${e.GroupId} (${e.GroupName})`,checked:u.includes(e.GroupId??``),onChange:()=>p(e.GroupId??``),type:`checkbox`}),(0,$.jsxs)(`span`,{className:`font-mono`,children:[e.GroupId,` (`,e.GroupName,`)`]})]},e.GroupId)),t[18]=n,t[19]=u,t[20]=S):S=t[20];let C;t[21]===v?C=t[22]:(C=v&&(0,$.jsx)(`p`,{className:`text-xs text-destructive`,children:`At least one security group is required.`}),t[21]=v,t[22]=C);let w;t[23]!==S||t[24]!==C?(w=(0,$.jsxs)(`div`,{className:`flex flex-col gap-1 p-4`,children:[S,C]}),t[23]=S,t[24]=C,t[25]=w):w=t[25];let T=_?`Unsaved changes`:`No changes`,E;t[26]===T?E=t[27]:(E=(0,$.jsx)(`span`,{className:`mr-auto text-xs text-muted-foreground`,children:T}),t[26]=T,t[27]=E);let D=a||!_,O;t[28]!==h||t[29]!==D?(O=(0,$.jsx)(W,{disabled:D,onClick:h,size:`sm`,type:`button`,variant:`secondary`,children:`Reset`}),t[28]=h,t[29]=D,t[30]=O):O=t[30];let k=a||!_||v,A=a?`Saving…`:`Save changes`,j;t[31]!==k||t[32]!==A?(j=(0,$.jsx)(W,{disabled:k,size:`sm`,type:`submit`,children:A}),t[31]=k,t[32]=A,t[33]=j):j=t[33];let M;t[34]!==E||t[35]!==O||t[36]!==j?(M=(0,$.jsxs)(`div`,{className:`flex items-center justify-end gap-2 border-t p-4`,children:[E,O,j]}),t[34]=E,t[35]=O,t[36]=j,t[37]=M):M=t[37];let N;t[38]!==w||t[39]!==M?(N=(0,$.jsxs)(`div`,{className:`rounded-lg border bg-card`,children:[w,M]}),t[38]=w,t[39]=M,t[40]=N):N=t[40];let P;return t[41]!==N||t[42]!==y||t[43]!==b||t[44]!==x?(P=(0,$.jsxs)(`form`,{onSubmit:y,children:[b,x,N]}),t[41]=N,t[42]=y,t[43]=b,t[44]=x,t[45]=P):P=t[45],P}function ht({arn:e}){let i=ne(),{data:a}=n(S(e)),{data:o}=n(w(e)),{data:s}=n(x([e])),{data:c}=n(I),{data:u}=n(N),f=h(),g=d(),_=p(),v=m(),[y,b]=(0,Z.useState)(!1),C=a.LoadBalancers?.[0];if(!C?.LoadBalancerArn)return(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(r,{to:`/ec2/describe-load-balancers`,children:`Back to load balancers`}),(0,$.jsx)(`p`,{className:`text-muted-foreground`,children:`Load balancer not found.`})]});let T=async()=>{try{await f.mutateAsync(e),i({to:`/ec2/describe-load-balancers`})}finally{b(!1)}},O=c.Subnets??[],k=e=>{let t=O.find(t=>t.SubnetId===e);if(!t)return e;let n=D(t.Tags),r=t.CidrBlock?` (${t.CidrBlock})`:``;return n?`${e} — ${n}${r}`:`${e}${r}`},A=o.Attributes??[],j=s?.TagDescriptions?.find(t=>t.ResourceArn===e)?.Tags??[],M=(C.SecurityGroups??[]).filter(e=>e!==void 0),P=(u.SecurityGroups??[]).filter(e=>e.VpcId===C.VpcId);return(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(r,{to:`/ec2/describe-load-balancers`,children:`Back to load balancers`}),f.error&&(0,$.jsx)(t,{error:f.error,msg:`Failed to delete load balancer`}),(0,$.jsxs)(`div`,{className:`space-y-6`,children:[(0,$.jsx)(ae,{actions:(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsxs)(W,{onClick:()=>b(!0),size:`sm`,variant:`destructive`,children:[(0,$.jsx)(l,{className:`size-4`}),`Delete`]}),(0,$.jsx)(oe,{state:C.State?.Code})]}),subtitle:`Load Balancer Details`,title:C.LoadBalancerName??C.LoadBalancerArn}),(0,$.jsxs)(Ae,{defaultValue:`overview`,children:[(0,$.jsxs)(Ee,{children:[(0,$.jsx)(Te,{value:`overview`,children:`Overview`}),(0,$.jsx)(Te,{value:`listeners`,children:`Listeners`}),(0,$.jsx)(Te,{value:`security-groups`,children:`Security groups`}),(0,$.jsx)(Te,{value:`attributes`,children:`Attributes`}),(0,$.jsx)(Te,{value:`tags`,children:`Tags`})]}),(0,$.jsxs)(Oe,{value:`overview`,children:[(0,$.jsxs)(G,{children:[(0,$.jsx)(G.Header,{children:`Load balancer`}),(0,$.jsxs)(G.Content,{children:[(0,$.jsx)(K,{label:`ARN`,value:C.LoadBalancerArn}),(0,$.jsx)(K,{label:`DNS name`,value:C.DNSName}),(0,$.jsx)(K,{label:`State`,value:C.State?.Reason?`${C.State.Code} — ${C.State.Reason}`:C.State?.Code}),(0,$.jsx)(K,{label:`Type`,value:C.Type}),(0,$.jsx)(K,{label:`Scheme`,value:C.Scheme}),(0,$.jsx)(K,{label:`IP address type`,value:C.IpAddressType}),(0,$.jsx)(K,{label:`VPC`,value:C.VpcId}),(0,$.jsx)(K,{label:`Created at`,value:E(C.CreatedTime)})]})]}),(0,$.jsxs)(G,{children:[(0,$.jsx)(G.Header,{children:`Availability zones`}),(0,$.jsx)(G.Content,{children:(C.AvailabilityZones??[]).map(e=>(0,$.jsx)(K,{label:e.ZoneName??`—`,value:e.SubnetId?k(e.SubnetId):void 0},`${e.ZoneName}-${e.SubnetId}`))})]}),(C.SecurityGroups??[]).length>0&&(0,$.jsxs)(G,{children:[(0,$.jsx)(G.Header,{children:`Security groups`}),(0,$.jsx)(G.Content,{children:(C.SecurityGroups??[]).map(e=>(0,$.jsx)(K,{label:`Security group`,value:e},e))})]})]}),(0,$.jsx)(Oe,{value:`listeners`,children:(0,$.jsx)(lt,{loadBalancerArn:e,vpcId:C.VpcId})}),(0,$.jsx)(Oe,{value:`security-groups`,children:(0,$.jsx)(mt,{available:P,current:M,error:v.error,isPending:v.isPending,isSuccess:v.isSuccess,onSubmit:t=>v.mutate({loadBalancerArn:e,securityGroupIds:t})})}),(0,$.jsx)(Oe,{value:`attributes`,children:(0,$.jsx)(De,{attributes:A,error:g.error,isPending:g.isPending,isSuccess:g.isSuccess,onSubmit:t=>{g.mutate({loadBalancerArn:e,attributes:t})},specs:ke})}),(0,$.jsx)(Oe,{value:`tags`,children:(0,$.jsx)(we,{error:_.error,isPending:_.isPending,isSuccess:_.isSuccess,onSubmit:t=>_.mutate({resourceArn:e,tags:t,initialKeys:j.map(e=>e.Key??``).filter(e=>e.length>0)}),tags:j})})]})]}),(0,$.jsx)(ge,{description:`Are you sure you want to delete load balancer "${C.LoadBalancerName??C.LoadBalancerArn}"? This action cannot be undone.`,isPending:f.isPending,onConfirm:T,onOpenChange:b,open:y,title:`Delete load balancer`})]})}function gt(){let e=(0,Q.c)(2),{id:t}=L.useParams(),n=decodeURIComponent(t),r;return e[0]===n?r=e[1]:(r=(0,$.jsx)(ht,{arn:n}),e[0]=n,e[1]=r),r}export{gt as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_id5.js b/spinifex/services/spinifexui/frontend/dist/assets/_id5.js index caf3dab7b..dbc153235 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_id5.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_id5.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./trash-2.js";import{g as i}from"./ec2.js";import{G as a,H as o,Po as s,Ta as c,a as l,ho as u,lo as d,mo as f,uo as p}from"./index.js";import{t as m}from"./page-heading.js";import{t as h}from"./state-badge.js";import{n as g,t as _}from"./detail-row.js";import{t as v}from"./delete-confirmation-dialog.js";var y=s(u()),b=f();function x(){let{id:s}=l.useParams(),u=p(),{data:f}=t(a(s)),{data:x}=t(o),S=i(),[C,w]=(0,y.useState)(!1),T=f.PlacementGroups?.[0],E=x.Reservations?.flatMap(e=>e.Instances??[]).filter(e=>e.Placement?.GroupName===T?.GroupName)??[];return T?.GroupId?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(n,{to:`/ec2/describe-placement-groups`,children:`Back to placement groups`}),S.error&&(0,b.jsx)(e,{error:S.error,msg:`Failed to delete placement group`}),(0,b.jsxs)(`div`,{className:`space-y-6`,children:[(0,b.jsx)(m,{actions:(0,b.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,b.jsxs)(c,{onClick:()=>w(!0),size:`sm`,variant:`destructive`,children:[(0,b.jsx)(r,{className:`size-4`}),`Delete`]}),(0,b.jsx)(h,{state:T.State})]}),subtitle:`Placement Group Details`,title:T.GroupName??T.GroupId}),(0,b.jsxs)(g,{children:[(0,b.jsx)(g.Header,{children:`Placement Group Information`}),(0,b.jsxs)(g.Content,{children:[(0,b.jsx)(_,{label:`Group ID`,value:T.GroupId}),(0,b.jsx)(_,{label:`Group Name`,value:T.GroupName}),(0,b.jsx)(_,{label:`Strategy`,value:T.Strategy}),(0,b.jsx)(_,{label:`State`,value:T.State}),(0,b.jsx)(_,{label:`Spread Level`,value:T.SpreadLevel})]})]}),(0,b.jsxs)(g,{children:[(0,b.jsx)(g.Header,{children:`Instances`}),E.length>0?E.map(e=>(0,b.jsxs)(g.Content,{children:[(0,b.jsx)(_,{label:`Instance ID`,value:e.InstanceId?(0,b.jsx)(d,{className:`text-primary hover:underline`,params:{id:e.InstanceId},to:`/ec2/describe-instances/$id`,children:e.InstanceId}):void 0}),(0,b.jsx)(_,{label:`State`,value:e.State?.Name}),(0,b.jsx)(_,{label:`Instance Type`,value:e.InstanceType}),(0,b.jsx)(_,{label:`Availability Zone`,value:e.Placement?.AvailabilityZone})]},e.InstanceId)):(0,b.jsx)(g.Content,{children:(0,b.jsx)(`p`,{className:`text-muted-foreground`,children:`No instances in this placement group.`})})]})]}),(0,b.jsx)(v,{description:`Are you sure you want to delete the placement group "${T.GroupName}"? The group must have no running instances.`,isPending:S.isPending,onConfirm:async()=>{if(T?.GroupName)try{await S.mutateAsync(T.GroupName),u({to:`/ec2/describe-placement-groups`})}finally{w(!1)}},onOpenChange:w,open:C,title:`Delete Placement Group`})]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(n,{to:`/ec2/describe-placement-groups`,children:`Back to placement groups`}),(0,b.jsx)(`p`,{className:`text-muted-foreground`,children:`Placement group not found.`})]})}export{x as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./trash-2.js";import{g as i}from"./ec2.js";import{Co as a,Jo as o,K as s,Oo as c,U as l,a as u,ko as d,wo as f,za as p}from"./index.js";import{t as m}from"./page-heading.js";import{t as h}from"./state-badge.js";import{n as g,t as _}from"./detail-row.js";import{t as v}from"./delete-confirmation-dialog.js";var y=o(d()),b=c();function x(){let{id:o}=u.useParams(),c=f(),{data:d}=t(s(o)),{data:x}=t(l),S=i(),[C,w]=(0,y.useState)(!1),T=d.PlacementGroups?.[0],E=x.Reservations?.flatMap(e=>e.Instances??[]).filter(e=>e.Placement?.GroupName===T?.GroupName)??[];return T?.GroupId?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(n,{to:`/ec2/describe-placement-groups`,children:`Back to placement groups`}),S.error&&(0,b.jsx)(e,{error:S.error,msg:`Failed to delete placement group`}),(0,b.jsxs)(`div`,{className:`space-y-6`,children:[(0,b.jsx)(m,{actions:(0,b.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,b.jsxs)(p,{onClick:()=>w(!0),size:`sm`,variant:`destructive`,children:[(0,b.jsx)(r,{className:`size-4`}),`Delete`]}),(0,b.jsx)(h,{state:T.State})]}),subtitle:`Placement Group Details`,title:T.GroupName??T.GroupId}),(0,b.jsxs)(g,{children:[(0,b.jsx)(g.Header,{children:`Placement Group Information`}),(0,b.jsxs)(g.Content,{children:[(0,b.jsx)(_,{label:`Group ID`,value:T.GroupId}),(0,b.jsx)(_,{label:`Group Name`,value:T.GroupName}),(0,b.jsx)(_,{label:`Strategy`,value:T.Strategy}),(0,b.jsx)(_,{label:`State`,value:T.State}),(0,b.jsx)(_,{label:`Spread Level`,value:T.SpreadLevel})]})]}),(0,b.jsxs)(g,{children:[(0,b.jsx)(g.Header,{children:`Instances`}),E.length>0?E.map(e=>(0,b.jsxs)(g.Content,{children:[(0,b.jsx)(_,{label:`Instance ID`,value:e.InstanceId?(0,b.jsx)(a,{className:`text-primary hover:underline`,params:{id:e.InstanceId},to:`/ec2/describe-instances/$id`,children:e.InstanceId}):void 0}),(0,b.jsx)(_,{label:`State`,value:e.State?.Name}),(0,b.jsx)(_,{label:`Instance Type`,value:e.InstanceType}),(0,b.jsx)(_,{label:`Availability Zone`,value:e.Placement?.AvailabilityZone})]},e.InstanceId)):(0,b.jsx)(g.Content,{children:(0,b.jsx)(`p`,{className:`text-muted-foreground`,children:`No instances in this placement group.`})})]})]}),(0,b.jsx)(v,{description:`Are you sure you want to delete the placement group "${T.GroupName}"? The group must have no running instances.`,isPending:S.isPending,onConfirm:async()=>{if(T?.GroupName)try{await S.mutateAsync(T.GroupName),c({to:`/ec2/describe-placement-groups`})}finally{w(!1)}},onOpenChange:w,open:C,title:`Delete Placement Group`})]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(n,{to:`/ec2/describe-placement-groups`,children:`Back to placement groups`}),(0,b.jsx)(`p`,{className:`text-muted-foreground`,children:`Placement group not found.`})]})}export{x as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_id6.js b/spinifex/services/spinifexui/frontend/dist/assets/_id6.js index 3c1be1e77..e6e71f7b6 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_id6.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_id6.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{c as r,i,n as a,s as o,t as s}from"./select.js";import{t as c}from"./plus.js";import{t as l}from"./trash-2.js";import{O as u,_ as d,k as f,n as p,r as m}from"./ec2.js";import{J as h,Po as g,Ta as _,Ti as v,Ua as y,ho as b,lo as x,mo as S,o as C,uo as w}from"./index.js";import{t as T}from"./page-heading.js";import{n as E,t as D}from"./detail-row.js";import{i as O,l as k,n as A,o as j,r as M,s as N,t as P}from"./alert-dialog.js";import{a as F,r as I,t as L}from"./field.js";import{t as R}from"./delete-confirmation-dialog.js";import{i as z,n as B,t as V}from"./zod.js";import{f as H}from"./ec22.js";var U=g(b()),W=S();function G(e){if(!e||e===`-1`)return`All traffic`;let t=e.toUpperCase();return t===`TCP`||t===`UDP`||t===`ICMP`?t:e}function K(e,t,n){return!n||n===`-1`||e===void 0||t===void 0||e===-1&&t===-1?`All`:e===t?e.toString():`${e}-${t}`}function q({open:t,onOpenChange:n,direction:c,groupId:l}){let u=m(),d=p(),f=c===`ingress`?u:d,{control:h,handleSubmit:g,register:_,reset:y,watch:b,formState:{errors:x}}=z({resolver:V(H),defaultValues:{ipProtocol:`tcp`,fromPort:0,toPort:0,cidrIp:`0.0.0.0/0`}}),S=b(`ipProtocol`),C=S===`-1`||S===`icmp`;return(0,W.jsx)(P,{onOpenChange:n,open:t,children:(0,W.jsxs)(O,{children:[(0,W.jsx)(N,{children:(0,W.jsxs)(k,{children:[`Add `,c===`ingress`?`Inbound`:`Outbound`,` Rule`]})}),f.error&&(0,W.jsx)(e,{error:f.error,msg:`Failed to add rule`}),(0,W.jsxs)(`form`,{className:`space-y-4`,id:`add-rule-form`,onSubmit:g(async e=>{let t={groupId:l,ipProtocol:e.ipProtocol,fromPort:C?-1:e.fromPort,toPort:C?-1:e.toPort,cidrIp:e.cidrIp};await f.mutateAsync(t),y(),n(!1)}),children:[(0,W.jsxs)(L,{children:[(0,W.jsx)(F,{children:(0,W.jsx)(`label`,{htmlFor:`ipProtocol`,children:`Protocol`})}),(0,W.jsx)(B,{control:h,name:`ipProtocol`,render:({field:e})=>(0,W.jsxs)(s,{onValueChange:t=>e.onChange(t),value:e.value,children:[(0,W.jsx)(o,{className:`w-full`,id:`ipProtocol`,children:(0,W.jsx)(r,{})}),(0,W.jsxs)(a,{children:[(0,W.jsx)(i,{value:`tcp`,children:`TCP`}),(0,W.jsx)(i,{value:`udp`,children:`UDP`}),(0,W.jsx)(i,{value:`icmp`,children:`ICMP`}),(0,W.jsx)(i,{value:`-1`,children:`All traffic (-1)`})]})]})}),(0,W.jsx)(I,{errors:[x.ipProtocol]})]}),(0,W.jsxs)(`div`,{className:`grid grid-cols-2 gap-4`,children:[(0,W.jsxs)(L,{children:[(0,W.jsx)(F,{children:(0,W.jsx)(`label`,{htmlFor:`fromPort`,children:`From Port`})}),(0,W.jsx)(v,{"aria-invalid":!!x.fromPort,disabled:C,id:`fromPort`,type:`number`,..._(`fromPort`,{valueAsNumber:!0})}),(0,W.jsx)(I,{errors:[x.fromPort]})]}),(0,W.jsxs)(L,{children:[(0,W.jsx)(F,{children:(0,W.jsx)(`label`,{htmlFor:`toPort`,children:`To Port`})}),(0,W.jsx)(v,{"aria-invalid":!!x.toPort,disabled:C,id:`toPort`,type:`number`,..._(`toPort`,{valueAsNumber:!0})}),(0,W.jsx)(I,{errors:[x.toPort]})]})]}),(0,W.jsxs)(L,{children:[(0,W.jsx)(F,{children:(0,W.jsxs)(`label`,{htmlFor:`cidrIp`,children:[c===`ingress`?`Source`:`Destination`,` CIDR`]})}),(0,W.jsx)(v,{"aria-invalid":!!x.cidrIp,id:`cidrIp`,placeholder:`0.0.0.0/0`,..._(`cidrIp`)}),(0,W.jsx)(I,{errors:[x.cidrIp]})]})]}),(0,W.jsxs)(j,{children:[(0,W.jsx)(M,{onClick:()=>{y(),f.reset()},children:`Cancel`}),(0,W.jsx)(A,{disabled:f.isPending,form:`add-rule-form`,type:`submit`,children:f.isPending?`Adding…`:`Add Rule`})]})]})})}function J({rule:t,cidr:n,groupId:r,direction:i}){let a=f(),o=u(),s=i===`ingress`?a:o;return(0,W.jsxs)(`div`,{className:`space-y-0`,children:[(0,W.jsxs)(`div`,{className:`flex items-center justify-between border-b px-4 py-3 last:border-b-0`,children:[(0,W.jsxs)(`div`,{className:`grid flex-1 grid-cols-3 gap-4 text-sm`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`span`,{className:`text-muted-foreground`,children:`Protocol: `}),G(t.IpProtocol)]}),(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`span`,{className:`text-muted-foreground`,children:`Port Range: `}),K(t.FromPort,t.ToPort,t.IpProtocol)]}),(0,W.jsxs)(`div`,{children:[(0,W.jsxs)(`span`,{className:`text-muted-foreground`,children:[i===`ingress`?`Source`:`Destination`,`:`,` `]}),n]})]}),(0,W.jsx)(_,{disabled:s.isPending,onClick:async()=>{try{await s.mutateAsync({groupId:r,ipProtocol:t.IpProtocol??`-1`,fromPort:t.FromPort??-1,toPort:t.ToPort??-1,cidrIp:n})}catch{}},size:`icon-xs`,variant:`ghost`,children:(0,W.jsx)(y,{className:`size-3`})})]}),s.error&&(0,W.jsx)(`div`,{className:`px-4 pb-2`,children:(0,W.jsx)(e,{error:s.error,msg:`Failed to remove rule`})})]})}function Y(){let{id:r}=C.useParams(),i=w(),{data:a}=t(h(r)),o=a.SecurityGroups?.[0],s=d(),[u,f]=(0,U.useState)(!1),[p,m]=(0,U.useState)(!1),[g,v]=(0,U.useState)(!1),y=async()=>{try{await s.mutateAsync(r),i({to:`/ec2/describe-security-groups`})}finally{f(!1)}};if(!o?.GroupId)return(0,W.jsxs)(W.Fragment,{children:[(0,W.jsx)(n,{to:`/ec2/describe-security-groups`,children:`Back to Security Groups`}),(0,W.jsx)(`p`,{className:`text-muted-foreground`,children:`Security group not found.`})]});let b=o.IpPermissions??[],S=o.IpPermissionsEgress??[];return(0,W.jsxs)(W.Fragment,{children:[(0,W.jsx)(n,{to:`/ec2/describe-security-groups`,children:`Back to Security Groups`}),s.error&&(0,W.jsx)(e,{error:s.error,msg:`Failed to delete security group`}),(0,W.jsxs)(`div`,{className:`space-y-6`,children:[(0,W.jsx)(T,{actions:(0,W.jsx)(`div`,{className:`flex items-center gap-2`,children:(0,W.jsxs)(_,{onClick:()=>f(!0),size:`sm`,variant:`destructive`,children:[(0,W.jsx)(l,{className:`size-4`}),`Delete`]})}),subtitle:`Security Group Details`,title:o.GroupName?`${o.GroupId} (${o.GroupName})`:o.GroupId}),(0,W.jsxs)(E,{children:[(0,W.jsx)(E.Header,{children:`Security Group Information`}),(0,W.jsxs)(E.Content,{children:[(0,W.jsx)(D,{label:`Group ID`,value:o.GroupId}),(0,W.jsx)(D,{label:`Group Name`,value:o.GroupName}),(0,W.jsx)(D,{label:`Description`,value:o.Description}),(0,W.jsx)(D,{label:`VPC ID`,value:o.VpcId?(0,W.jsx)(x,{className:`text-primary hover:underline`,params:{id:o.VpcId},to:`/ec2/describe-vpcs/$id`,children:o.VpcId}):`—`}),(0,W.jsx)(D,{label:`Owner ID`,value:o.OwnerId})]})]}),(0,W.jsxs)(E,{children:[(0,W.jsxs)(`div`,{className:`flex items-center justify-between border-b p-4`,children:[(0,W.jsxs)(`h2`,{className:`font-semibold`,children:[`Inbound Rules (`,b.length,`)`]}),(0,W.jsxs)(_,{onClick:()=>m(!0),size:`sm`,variant:`outline`,children:[(0,W.jsx)(c,{className:`size-4`}),`Add Rule`]})]}),b.length>0?(0,W.jsx)(`div`,{children:b.map(e=>(e.IpRanges??[]).map(t=>(0,W.jsx)(J,{cidr:t.CidrIp??``,direction:`ingress`,groupId:o.GroupId??``,rule:e},`${e.IpProtocol}-${e.FromPort}-${e.ToPort}-${t.CidrIp}`)))}):(0,W.jsx)(`p`,{className:`p-4 text-sm text-muted-foreground`,children:`No inbound rules.`})]}),(0,W.jsxs)(E,{children:[(0,W.jsxs)(`div`,{className:`flex items-center justify-between border-b p-4`,children:[(0,W.jsxs)(`h2`,{className:`font-semibold`,children:[`Outbound Rules (`,S.length,`)`]}),(0,W.jsxs)(_,{onClick:()=>v(!0),size:`sm`,variant:`outline`,children:[(0,W.jsx)(c,{className:`size-4`}),`Add Rule`]})]}),S.length>0?(0,W.jsx)(`div`,{children:S.map(e=>(e.IpRanges??[]).map(t=>(0,W.jsx)(J,{cidr:t.CidrIp??``,direction:`egress`,groupId:o.GroupId??``,rule:e},`${e.IpProtocol}-${e.FromPort}-${e.ToPort}-${t.CidrIp}`)))}):(0,W.jsx)(`p`,{className:`p-4 text-sm text-muted-foreground`,children:`No outbound rules.`})]})]}),(0,W.jsx)(R,{description:`Are you sure you want to delete the security group "${o.GroupId}"? This action cannot be undone.`,isPending:s.isPending,onConfirm:y,onOpenChange:f,open:u,title:`Delete Security Group`}),(0,W.jsx)(q,{direction:`ingress`,groupId:o.GroupId,onOpenChange:m,open:p}),(0,W.jsx)(q,{direction:`egress`,groupId:o.GroupId,onOpenChange:v,open:g})]})}export{Y as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{c as r,i,n as a,s as o,t as s}from"./select.js";import{t as c}from"./plus.js";import{t as l}from"./trash-2.js";import{O as u,_ as d,k as f,n as p,r as m}from"./ec2.js";import{Co as h,Jo as g,Oo as _,Y as v,ko as y,o as b,ro as x,wo as S,za as C,zi as w}from"./index.js";import{t as T}from"./page-heading.js";import{n as E,t as D}from"./detail-row.js";import{i as O,l as k,n as A,o as j,r as M,s as N,t as P}from"./alert-dialog.js";import{a as F,r as I,t as L}from"./field.js";import{t as R}from"./delete-confirmation-dialog.js";import{i as z,n as B,t as V}from"./zod.js";import{f as H}from"./ec22.js";var U=g(y()),W=_();function G(e){if(!e||e===`-1`)return`All traffic`;let t=e.toUpperCase();return t===`TCP`||t===`UDP`||t===`ICMP`?t:e}function K(e,t,n){return!n||n===`-1`||e===void 0||t===void 0||e===-1&&t===-1?`All`:e===t?e.toString():`${e}-${t}`}function q({open:t,onOpenChange:n,direction:c,groupId:l}){let u=m(),d=p(),f=c===`ingress`?u:d,{control:h,handleSubmit:g,register:_,reset:v,watch:y,formState:{errors:b}}=z({resolver:V(H),defaultValues:{ipProtocol:`tcp`,fromPort:0,toPort:0,cidrIp:`0.0.0.0/0`}}),x=y(`ipProtocol`),S=x===`-1`||x===`icmp`;return(0,W.jsx)(P,{onOpenChange:n,open:t,children:(0,W.jsxs)(O,{children:[(0,W.jsx)(N,{children:(0,W.jsxs)(k,{children:[`Add `,c===`ingress`?`Inbound`:`Outbound`,` Rule`]})}),f.error&&(0,W.jsx)(e,{error:f.error,msg:`Failed to add rule`}),(0,W.jsxs)(`form`,{className:`space-y-4`,id:`add-rule-form`,onSubmit:g(async e=>{let t={groupId:l,ipProtocol:e.ipProtocol,fromPort:S?-1:e.fromPort,toPort:S?-1:e.toPort,cidrIp:e.cidrIp};await f.mutateAsync(t),v(),n(!1)}),children:[(0,W.jsxs)(L,{children:[(0,W.jsx)(F,{children:(0,W.jsx)(`label`,{htmlFor:`ipProtocol`,children:`Protocol`})}),(0,W.jsx)(B,{control:h,name:`ipProtocol`,render:({field:e})=>(0,W.jsxs)(s,{onValueChange:t=>e.onChange(t),value:e.value,children:[(0,W.jsx)(o,{className:`w-full`,id:`ipProtocol`,children:(0,W.jsx)(r,{})}),(0,W.jsxs)(a,{children:[(0,W.jsx)(i,{value:`tcp`,children:`TCP`}),(0,W.jsx)(i,{value:`udp`,children:`UDP`}),(0,W.jsx)(i,{value:`icmp`,children:`ICMP`}),(0,W.jsx)(i,{value:`-1`,children:`All traffic (-1)`})]})]})}),(0,W.jsx)(I,{errors:[b.ipProtocol]})]}),(0,W.jsxs)(`div`,{className:`grid grid-cols-2 gap-4`,children:[(0,W.jsxs)(L,{children:[(0,W.jsx)(F,{children:(0,W.jsx)(`label`,{htmlFor:`fromPort`,children:`From Port`})}),(0,W.jsx)(w,{"aria-invalid":!!b.fromPort,disabled:S,id:`fromPort`,type:`number`,..._(`fromPort`,{valueAsNumber:!0})}),(0,W.jsx)(I,{errors:[b.fromPort]})]}),(0,W.jsxs)(L,{children:[(0,W.jsx)(F,{children:(0,W.jsx)(`label`,{htmlFor:`toPort`,children:`To Port`})}),(0,W.jsx)(w,{"aria-invalid":!!b.toPort,disabled:S,id:`toPort`,type:`number`,..._(`toPort`,{valueAsNumber:!0})}),(0,W.jsx)(I,{errors:[b.toPort]})]})]}),(0,W.jsxs)(L,{children:[(0,W.jsx)(F,{children:(0,W.jsxs)(`label`,{htmlFor:`cidrIp`,children:[c===`ingress`?`Source`:`Destination`,` CIDR`]})}),(0,W.jsx)(w,{"aria-invalid":!!b.cidrIp,id:`cidrIp`,placeholder:`0.0.0.0/0`,..._(`cidrIp`)}),(0,W.jsx)(I,{errors:[b.cidrIp]})]})]}),(0,W.jsxs)(j,{children:[(0,W.jsx)(M,{onClick:()=>{v(),f.reset()},children:`Cancel`}),(0,W.jsx)(A,{disabled:f.isPending,form:`add-rule-form`,type:`submit`,children:f.isPending?`Adding…`:`Add Rule`})]})]})})}function J({rule:t,cidr:n,groupId:r,direction:i}){let a=f(),o=u(),s=i===`ingress`?a:o;return(0,W.jsxs)(`div`,{className:`space-y-0`,children:[(0,W.jsxs)(`div`,{className:`flex items-center justify-between border-b px-4 py-3 last:border-b-0`,children:[(0,W.jsxs)(`div`,{className:`grid flex-1 grid-cols-3 gap-4 text-sm`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`span`,{className:`text-muted-foreground`,children:`Protocol: `}),G(t.IpProtocol)]}),(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`span`,{className:`text-muted-foreground`,children:`Port Range: `}),K(t.FromPort,t.ToPort,t.IpProtocol)]}),(0,W.jsxs)(`div`,{children:[(0,W.jsxs)(`span`,{className:`text-muted-foreground`,children:[i===`ingress`?`Source`:`Destination`,`:`,` `]}),n]})]}),(0,W.jsx)(C,{disabled:s.isPending,onClick:async()=>{try{await s.mutateAsync({groupId:r,ipProtocol:t.IpProtocol??`-1`,fromPort:t.FromPort??-1,toPort:t.ToPort??-1,cidrIp:n})}catch{}},size:`icon-xs`,variant:`ghost`,children:(0,W.jsx)(x,{className:`size-3`})})]}),s.error&&(0,W.jsx)(`div`,{className:`px-4 pb-2`,children:(0,W.jsx)(e,{error:s.error,msg:`Failed to remove rule`})})]})}function Y(){let{id:r}=b.useParams(),i=S(),{data:a}=t(v(r)),o=a.SecurityGroups?.[0],s=d(),[u,f]=(0,U.useState)(!1),[p,m]=(0,U.useState)(!1),[g,_]=(0,U.useState)(!1),y=async()=>{try{await s.mutateAsync(r),i({to:`/ec2/describe-security-groups`})}finally{f(!1)}};if(!o?.GroupId)return(0,W.jsxs)(W.Fragment,{children:[(0,W.jsx)(n,{to:`/ec2/describe-security-groups`,children:`Back to Security Groups`}),(0,W.jsx)(`p`,{className:`text-muted-foreground`,children:`Security group not found.`})]});let x=o.IpPermissions??[],w=o.IpPermissionsEgress??[];return(0,W.jsxs)(W.Fragment,{children:[(0,W.jsx)(n,{to:`/ec2/describe-security-groups`,children:`Back to Security Groups`}),s.error&&(0,W.jsx)(e,{error:s.error,msg:`Failed to delete security group`}),(0,W.jsxs)(`div`,{className:`space-y-6`,children:[(0,W.jsx)(T,{actions:(0,W.jsx)(`div`,{className:`flex items-center gap-2`,children:(0,W.jsxs)(C,{onClick:()=>f(!0),size:`sm`,variant:`destructive`,children:[(0,W.jsx)(l,{className:`size-4`}),`Delete`]})}),subtitle:`Security Group Details`,title:o.GroupName?`${o.GroupId} (${o.GroupName})`:o.GroupId}),(0,W.jsxs)(E,{children:[(0,W.jsx)(E.Header,{children:`Security Group Information`}),(0,W.jsxs)(E.Content,{children:[(0,W.jsx)(D,{label:`Group ID`,value:o.GroupId}),(0,W.jsx)(D,{label:`Group Name`,value:o.GroupName}),(0,W.jsx)(D,{label:`Description`,value:o.Description}),(0,W.jsx)(D,{label:`VPC ID`,value:o.VpcId?(0,W.jsx)(h,{className:`text-primary hover:underline`,params:{id:o.VpcId},to:`/ec2/describe-vpcs/$id`,children:o.VpcId}):`—`}),(0,W.jsx)(D,{label:`Owner ID`,value:o.OwnerId})]})]}),(0,W.jsxs)(E,{children:[(0,W.jsxs)(`div`,{className:`flex items-center justify-between border-b p-4`,children:[(0,W.jsxs)(`h2`,{className:`font-semibold`,children:[`Inbound Rules (`,x.length,`)`]}),(0,W.jsxs)(C,{onClick:()=>m(!0),size:`sm`,variant:`outline`,children:[(0,W.jsx)(c,{className:`size-4`}),`Add Rule`]})]}),x.length>0?(0,W.jsx)(`div`,{children:x.map(e=>(e.IpRanges??[]).map(t=>(0,W.jsx)(J,{cidr:t.CidrIp??``,direction:`ingress`,groupId:o.GroupId??``,rule:e},`${e.IpProtocol}-${e.FromPort}-${e.ToPort}-${t.CidrIp}`)))}):(0,W.jsx)(`p`,{className:`p-4 text-sm text-muted-foreground`,children:`No inbound rules.`})]}),(0,W.jsxs)(E,{children:[(0,W.jsxs)(`div`,{className:`flex items-center justify-between border-b p-4`,children:[(0,W.jsxs)(`h2`,{className:`font-semibold`,children:[`Outbound Rules (`,w.length,`)`]}),(0,W.jsxs)(C,{onClick:()=>_(!0),size:`sm`,variant:`outline`,children:[(0,W.jsx)(c,{className:`size-4`}),`Add Rule`]})]}),w.length>0?(0,W.jsx)(`div`,{children:w.map(e=>(e.IpRanges??[]).map(t=>(0,W.jsx)(J,{cidr:t.CidrIp??``,direction:`egress`,groupId:o.GroupId??``,rule:e},`${e.IpProtocol}-${e.FromPort}-${e.ToPort}-${t.CidrIp}`)))}):(0,W.jsx)(`p`,{className:`p-4 text-sm text-muted-foreground`,children:`No outbound rules.`})]})]}),(0,W.jsx)(R,{description:`Are you sure you want to delete the security group "${o.GroupId}"? This action cannot be undone.`,isPending:s.isPending,onConfirm:y,onOpenChange:f,open:u,title:`Delete Security Group`}),(0,W.jsx)(q,{direction:`ingress`,groupId:o.GroupId,onOpenChange:m,open:p}),(0,W.jsx)(q,{direction:`egress`,groupId:o.GroupId,onOpenChange:_,open:g})]})}export{Y as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_id7.js b/spinifex/services/spinifexui/frontend/dist/assets/_id7.js index 00fbf35d6..9f7ba9ddc 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_id7.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_id7.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./copy.js";import{t as i}from"./trash-2.js";import{i as a,v as o}from"./ec2.js";import{Po as s,Ta as c,Ti as l,X as u,ho as d,ja as f,lo as p,mo as m,q as h,s as g,uo as _}from"./index.js";import{t as v}from"./page-heading.js";import{t as y}from"./state-badge.js";import{n as b,t as x}from"./detail-row.js";import{a as S,i as C,l as w,n as T,o as E,r as D,s as O,t as k}from"./alert-dialog.js";import{a as A,t as j}from"./field.js";import{t as M}from"./delete-confirmation-dialog.js";var N=s(d()),P=m();function F(){let{id:s}=g.useParams(),d=_(),{data:m}=t(u(s)),{data:F}=t(h),I=m.Snapshots?.[0],L=o(),R=a(),[z,B]=(0,N.useState)(!1),[V,H]=(0,N.useState)(!1),[U,W]=(0,N.useState)(``),G=F.Regions?.[0]?.RegionName??`ap-southeast-2`,K=I?.State===`completed`,q=async()=>{try{await L.mutateAsync(s),d({to:`/ec2/describe-snapshots`})}finally{B(!1)}},J=async()=>{try{await R.mutateAsync({sourceSnapshotId:s,sourceRegion:G,description:U||void 0}),H(!1),W(``)}catch{}};if(!I?.SnapshotId)return(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(n,{to:`/ec2/describe-snapshots`,children:`Back to snapshots`}),(0,P.jsx)(`p`,{className:`text-muted-foreground`,children:`Snapshot not found.`})]});let Y=f(I.StartTime);return(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(n,{to:`/ec2/describe-snapshots`,children:`Back to snapshots`}),L.error&&(0,P.jsx)(e,{error:L.error,msg:`Failed to delete snapshot`}),R.error&&(0,P.jsx)(e,{error:R.error,msg:`Failed to copy snapshot`}),(0,P.jsxs)(`div`,{className:`space-y-6`,children:[(0,P.jsx)(v,{actions:(0,P.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,P.jsxs)(c,{disabled:!K,onClick:()=>B(!0),size:`sm`,variant:`destructive`,children:[(0,P.jsx)(i,{className:`size-4`}),`Delete`]}),(0,P.jsxs)(c,{disabled:!K,onClick:()=>H(!0),size:`sm`,variant:`outline`,children:[(0,P.jsx)(r,{className:`size-4`}),`Copy Snapshot`]}),(0,P.jsx)(y,{state:I.State})]}),subtitle:`Snapshot Details`,title:I.SnapshotId}),(0,P.jsxs)(b,{children:[(0,P.jsx)(b.Header,{children:`Snapshot Information`}),(0,P.jsxs)(b.Content,{children:[(0,P.jsx)(x,{label:`Snapshot ID`,value:I.SnapshotId}),(0,P.jsx)(x,{label:`Volume ID`,value:I.VolumeId?(0,P.jsx)(p,{className:`text-primary hover:underline`,params:{id:I.VolumeId},to:`/ec2/describe-volumes/$id`,children:I.VolumeId}):void 0}),(0,P.jsx)(x,{label:`Volume Size`,value:`${I.VolumeSize} GiB`}),(0,P.jsx)(x,{label:`State`,value:I.State}),(0,P.jsx)(x,{label:`Description`,value:I.Description}),(0,P.jsx)(x,{label:`Progress`,value:I.Progress}),(0,P.jsx)(x,{label:`Start Time`,value:Y}),(0,P.jsx)(x,{label:`Owner ID`,value:I.OwnerId}),(0,P.jsx)(x,{label:`Encrypted`,value:I.Encrypted?`Yes`:`No`})]})]})]}),(0,P.jsx)(M,{description:`Are you sure you want to delete the snapshot "${I.SnapshotId}"? This action cannot be undone.`,isPending:L.isPending,onConfirm:q,onOpenChange:B,open:z,title:`Delete Snapshot`}),(0,P.jsx)(k,{onOpenChange:H,open:V,children:(0,P.jsxs)(C,{children:[(0,P.jsxs)(O,{children:[(0,P.jsx)(w,{children:`Copy Snapshot`}),(0,P.jsx)(S,{children:`Create a copy of this snapshot in the current region.`})]}),(0,P.jsxs)(j,{children:[(0,P.jsx)(A,{children:(0,P.jsx)(`label`,{htmlFor:`copyDescription`,children:`Description (optional)`})}),(0,P.jsx)(l,{id:`copyDescription`,onChange:e=>W(e.target.value),placeholder:`Description for the snapshot copy`,value:U})]}),(0,P.jsxs)(E,{children:[(0,P.jsx)(D,{children:`Cancel`}),(0,P.jsx)(T,{disabled:R.isPending,onClick:J,children:R.isPending?`Copying…`:`Copy Snapshot`})]})]})})]})}export{F as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./copy.js";import{t as i}from"./trash-2.js";import{i as a,v as o}from"./ec2.js";import{Co as s,Ga as c,J as l,Jo as u,Oo as d,Z as f,ko as p,s as m,wo as h,za as g,zi as _}from"./index.js";import{t as v}from"./page-heading.js";import{t as y}from"./state-badge.js";import{n as b,t as x}from"./detail-row.js";import{a as S,i as C,l as w,n as T,o as E,r as D,s as O,t as k}from"./alert-dialog.js";import{a as A,t as j}from"./field.js";import{t as M}from"./delete-confirmation-dialog.js";var N=u(p()),P=d();function F(){let{id:u}=m.useParams(),d=h(),{data:p}=t(f(u)),{data:F}=t(l),I=p.Snapshots?.[0],L=o(),R=a(),[z,B]=(0,N.useState)(!1),[V,H]=(0,N.useState)(!1),[U,W]=(0,N.useState)(``),G=F.Regions?.[0]?.RegionName??`ap-southeast-2`,K=I?.State===`completed`,q=async()=>{try{await L.mutateAsync(u),d({to:`/ec2/describe-snapshots`})}finally{B(!1)}},J=async()=>{try{await R.mutateAsync({sourceSnapshotId:u,sourceRegion:G,description:U||void 0}),H(!1),W(``)}catch{}};if(!I?.SnapshotId)return(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(n,{to:`/ec2/describe-snapshots`,children:`Back to snapshots`}),(0,P.jsx)(`p`,{className:`text-muted-foreground`,children:`Snapshot not found.`})]});let Y=c(I.StartTime);return(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(n,{to:`/ec2/describe-snapshots`,children:`Back to snapshots`}),L.error&&(0,P.jsx)(e,{error:L.error,msg:`Failed to delete snapshot`}),R.error&&(0,P.jsx)(e,{error:R.error,msg:`Failed to copy snapshot`}),(0,P.jsxs)(`div`,{className:`space-y-6`,children:[(0,P.jsx)(v,{actions:(0,P.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,P.jsxs)(g,{disabled:!K,onClick:()=>B(!0),size:`sm`,variant:`destructive`,children:[(0,P.jsx)(i,{className:`size-4`}),`Delete`]}),(0,P.jsxs)(g,{disabled:!K,onClick:()=>H(!0),size:`sm`,variant:`outline`,children:[(0,P.jsx)(r,{className:`size-4`}),`Copy Snapshot`]}),(0,P.jsx)(y,{state:I.State})]}),subtitle:`Snapshot Details`,title:I.SnapshotId}),(0,P.jsxs)(b,{children:[(0,P.jsx)(b.Header,{children:`Snapshot Information`}),(0,P.jsxs)(b.Content,{children:[(0,P.jsx)(x,{label:`Snapshot ID`,value:I.SnapshotId}),(0,P.jsx)(x,{label:`Volume ID`,value:I.VolumeId?(0,P.jsx)(s,{className:`text-primary hover:underline`,params:{id:I.VolumeId},to:`/ec2/describe-volumes/$id`,children:I.VolumeId}):void 0}),(0,P.jsx)(x,{label:`Volume Size`,value:`${I.VolumeSize} GiB`}),(0,P.jsx)(x,{label:`State`,value:I.State}),(0,P.jsx)(x,{label:`Description`,value:I.Description}),(0,P.jsx)(x,{label:`Progress`,value:I.Progress}),(0,P.jsx)(x,{label:`Start Time`,value:Y}),(0,P.jsx)(x,{label:`Owner ID`,value:I.OwnerId}),(0,P.jsx)(x,{label:`Encrypted`,value:I.Encrypted?`Yes`:`No`})]})]})]}),(0,P.jsx)(M,{description:`Are you sure you want to delete the snapshot "${I.SnapshotId}"? This action cannot be undone.`,isPending:L.isPending,onConfirm:q,onOpenChange:B,open:z,title:`Delete Snapshot`}),(0,P.jsx)(k,{onOpenChange:H,open:V,children:(0,P.jsxs)(C,{children:[(0,P.jsxs)(O,{children:[(0,P.jsx)(w,{children:`Copy Snapshot`}),(0,P.jsx)(S,{children:`Create a copy of this snapshot in the current region.`})]}),(0,P.jsxs)(j,{children:[(0,P.jsx)(A,{children:(0,P.jsx)(`label`,{htmlFor:`copyDescription`,children:`Description (optional)`})}),(0,P.jsx)(_,{id:`copyDescription`,onChange:e=>W(e.target.value),placeholder:`Description for the snapshot copy`,value:U})]}),(0,P.jsxs)(E,{children:[(0,P.jsx)(D,{children:`Cancel`}),(0,P.jsx)(T,{disabled:R.isPending,onClick:J,children:R.isPending?`Copying…`:`Copy Snapshot`})]})]})})]})}export{F as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_id8.js b/spinifex/services/spinifexui/frontend/dist/assets/_id8.js index 5f0cd90f6..47ef7b301 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_id8.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_id8.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./trash-2.js";import{y as i}from"./ec2.js";import{Pa as a,Po as o,Q as s,Ta as c,c as l,ho as u,lo as d,mo as f,uo as p}from"./index.js";import{t as m}from"./page-heading.js";import{t as h}from"./state-badge.js";import{n as g,t as _}from"./detail-row.js";import{t as v}from"./delete-confirmation-dialog.js";var y=o(u()),b=f();function x(){let{id:o}=l.useParams(),u=p(),{data:f}=t(s(o)),x=f.Subnets?.[0],S=i(),[C,w]=(0,y.useState)(!1),T=async()=>{try{await S.mutateAsync(o),u({to:`/ec2/describe-subnets`})}finally{w(!1)}};if(!x?.SubnetId)return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(n,{to:`/ec2/describe-subnets`,children:`Back to Subnets`}),(0,b.jsx)(`p`,{className:`text-muted-foreground`,children:`Subnet not found.`})]});let E=a(x.Tags);return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(n,{to:`/ec2/describe-subnets`,children:`Back to Subnets`}),S.error&&(0,b.jsx)(e,{error:S.error,msg:`Failed to delete subnet`}),(0,b.jsxs)(`div`,{className:`space-y-6`,children:[(0,b.jsx)(m,{actions:(0,b.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,b.jsxs)(c,{onClick:()=>w(!0),size:`sm`,variant:`destructive`,children:[(0,b.jsx)(r,{className:`size-4`}),`Delete`]}),(0,b.jsx)(h,{state:x.State})]}),subtitle:`Subnet Details`,title:E?`${x.SubnetId} (${E})`:x.SubnetId}),(0,b.jsxs)(g,{children:[(0,b.jsx)(g.Header,{children:`Subnet Information`}),(0,b.jsxs)(g.Content,{children:[(0,b.jsx)(_,{label:`Subnet ID`,value:x.SubnetId}),(0,b.jsx)(_,{label:`VPC ID`,value:x.VpcId?(0,b.jsx)(d,{className:`text-primary hover:underline`,params:{id:x.VpcId},to:`/ec2/describe-vpcs/$id`,children:x.VpcId}):`—`}),(0,b.jsx)(_,{label:`State`,value:x.State}),(0,b.jsx)(_,{label:`CIDR Block`,value:x.CidrBlock}),(0,b.jsx)(_,{label:`Availability Zone`,value:x.AvailabilityZone}),(0,b.jsx)(_,{label:`Available IP Count`,value:x.AvailableIpAddressCount?.toString()}),(0,b.jsx)(_,{label:`Map Public IP on Launch`,value:x.MapPublicIpOnLaunch?`Yes`:`No`}),(0,b.jsx)(_,{label:`Default for AZ`,value:x.DefaultForAz?`Yes`:`No`})]})]})]}),(0,b.jsx)(v,{description:`Are you sure you want to delete the subnet "${x.SubnetId}"? This action cannot be undone.`,isPending:S.isPending,onConfirm:T,onOpenChange:w,open:C,title:`Delete Subnet`})]})}export{x as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./trash-2.js";import{y as i}from"./ec2.js";import{$ as a,Co as o,Ja as s,Jo as c,Oo as l,c as u,ko as d,wo as f,za as p}from"./index.js";import{t as m}from"./page-heading.js";import{t as h}from"./state-badge.js";import{n as g,t as _}from"./detail-row.js";import{t as v}from"./delete-confirmation-dialog.js";var y=c(d()),b=l();function x(){let{id:c}=u.useParams(),l=f(),{data:d}=t(a(c)),x=d.Subnets?.[0],S=i(),[C,w]=(0,y.useState)(!1),T=async()=>{try{await S.mutateAsync(c),l({to:`/ec2/describe-subnets`})}finally{w(!1)}};if(!x?.SubnetId)return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(n,{to:`/ec2/describe-subnets`,children:`Back to Subnets`}),(0,b.jsx)(`p`,{className:`text-muted-foreground`,children:`Subnet not found.`})]});let E=s(x.Tags);return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(n,{to:`/ec2/describe-subnets`,children:`Back to Subnets`}),S.error&&(0,b.jsx)(e,{error:S.error,msg:`Failed to delete subnet`}),(0,b.jsxs)(`div`,{className:`space-y-6`,children:[(0,b.jsx)(m,{actions:(0,b.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,b.jsxs)(p,{onClick:()=>w(!0),size:`sm`,variant:`destructive`,children:[(0,b.jsx)(r,{className:`size-4`}),`Delete`]}),(0,b.jsx)(h,{state:x.State})]}),subtitle:`Subnet Details`,title:E?`${x.SubnetId} (${E})`:x.SubnetId}),(0,b.jsxs)(g,{children:[(0,b.jsx)(g.Header,{children:`Subnet Information`}),(0,b.jsxs)(g.Content,{children:[(0,b.jsx)(_,{label:`Subnet ID`,value:x.SubnetId}),(0,b.jsx)(_,{label:`VPC ID`,value:x.VpcId?(0,b.jsx)(o,{className:`text-primary hover:underline`,params:{id:x.VpcId},to:`/ec2/describe-vpcs/$id`,children:x.VpcId}):`—`}),(0,b.jsx)(_,{label:`State`,value:x.State}),(0,b.jsx)(_,{label:`CIDR Block`,value:x.CidrBlock}),(0,b.jsx)(_,{label:`Availability Zone`,value:x.AvailabilityZone}),(0,b.jsx)(_,{label:`Available IP Count`,value:x.AvailableIpAddressCount?.toString()}),(0,b.jsx)(_,{label:`Map Public IP on Launch`,value:x.MapPublicIpOnLaunch?`Yes`:`No`}),(0,b.jsx)(_,{label:`Default for AZ`,value:x.DefaultForAz?`Yes`:`No`})]})]})]}),(0,b.jsx)(v,{description:`Are you sure you want to delete the subnet "${x.SubnetId}"? This action cannot be undone.`,isPending:S.isPending,onConfirm:T,onOpenChange:w,open:C,title:`Delete Subnet`})]})}export{x as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_id9.js b/spinifex/services/spinifexui/frontend/dist/assets/_id9.js index 812674db9..cb5cdf2e9 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_id9.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_id9.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./useQuery.js";import{t as n}from"./useSuspenseQuery.js";import{t as r}from"./back-link.js";import{t as i}from"./trash-2.js";import{c as a,l as o,m as s,p as c}from"./elbv2.js";import{A as l,H as u,N as d,Oa as f,Pa as p,Po as m,Ta as h,Ti as g,ho as _,j as v,k as y,l as b,mo as x,so as S,uo as C}from"./index.js";import{t as w}from"./page-heading.js";import{n as T,t as E}from"./detail-row.js";import{a as D,i as O,l as k,n as A,o as j,r as M,s as N,t as P}from"./alert-dialog.js";import{t as F}from"./delete-confirmation-dialog.js";import{a as I,i as L,n as R,r as z,s as B,t as V}from"./tabs.js";var H=S(),U=m(_(),1),W=x();function G(e){let t=e.trim();if(t===``)return;let n=Number(t);if(!(!Number.isInteger(n)||n<1||n>65535))return n}function K(e){let t=(0,H.c)(36),{open:n,onOpenChange:r,instances:i,defaultPort:a,isPending:o,onConfirm:s}=e,c;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(c={},t[0]=c):c=t[0];let[l,u]=(0,U.useState)(c),[d,f]=(0,U.useState)(),m,h;t[1]===n?(m=t[2],h=t[3]):(m=()=>{n||(u({}),f(void 0))},h=[n],t[1]=n,t[2]=m,t[3]=h),(0,U.useEffect)(m,h);let _;t[4]===Symbol.for(`react.memo_cache_sentinel`)?(_=e=>{u(t=>{let n=t[e];return n?.checked?{...t,[e]:{...n,checked:!1}}:{...t,[e]:{checked:!0,port:n?.port??``}}})},t[4]=_):_=t[4];let v=_,y;t[5]===Symbol.for(`react.memo_cache_sentinel`)?(y=(e,t)=>{u(n=>({...n,[e]:{checked:n[e]?.checked??!0,port:t}}))},t[5]=y):y=t[5];let b=y,x;t[6]!==s||t[7]!==l?(x=()=>{let e=Object.entries(l).filter(q);if(e.length===0){f(`Select at least one instance.`);return}let t=[];for(let[n,r]of e){if(r.port.trim()===``){t.push({id:n});continue}let e=G(r.port);if(e===void 0){f(`Port for ${n} must be an integer between 1 and 65535.`);return}t.push({id:n,port:e})}f(void 0),s(t)},t[6]=s,t[7]=l,t[8]=x):x=t[8];let S=x,C;t[9]===Symbol.for(`react.memo_cache_sentinel`)?(C=(0,W.jsx)(k,{children:`Register targets`}),t[9]=C):C=t[9];let w;t[10]===a?w=t[11]:(w=(0,W.jsxs)(N,{children:[C,(0,W.jsxs)(D,{children:[`Select instances to register. Leave port blank to use the target group port (`,a,`).`]})]}),t[10]=a,t[11]=w);let T;t[12]!==a||t[13]!==i||t[14]!==l?(T=i.length===0?(0,W.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No instances available in this VPC.`}):(0,W.jsx)(`div`,{className:`max-h-72 space-y-1 overflow-y-auto`,children:i.map(e=>{let t=e.InstanceId??``,n=l[t],r=n?.checked??!1,i=p(e.Tags);return(0,W.jsxs)(`div`,{className:`flex items-center gap-2 rounded px-1 py-1 text-xs hover:bg-accent`,children:[(0,W.jsx)(`input`,{"aria-label":`Register target ${t}`,checked:r,id:`register-target-${t}`,onChange:()=>v(t),type:`checkbox`}),(0,W.jsxs)(`label`,{className:`flex flex-1 items-center gap-2`,htmlFor:`register-target-${t}`,children:[(0,W.jsx)(`span`,{className:`font-mono`,children:t}),i&&(0,W.jsxs)(`span`,{className:`text-muted-foreground`,children:[`(`,i,`)`]}),(0,W.jsx)(`span`,{className:`text-muted-foreground`,children:e.State?.Name??``})]}),r&&(0,W.jsx)(g,{"aria-label":`Port override for ${t}`,className:`w-24`,onChange:e=>b(t,e.target.value),placeholder:String(a),value:n?.port??``})]},t)})}),t[12]=a,t[13]=i,t[14]=l,t[15]=T):T=t[15];let E;t[16]===d?E=t[17]:(E=d&&(0,W.jsx)(`p`,{className:`text-xs text-destructive`,role:`alert`,children:d}),t[16]=d,t[17]=E);let F;t[18]===o?F=t[19]:(F=(0,W.jsx)(M,{disabled:o,children:`Cancel`}),t[18]=o,t[19]=F);let I=o?`Registering…`:`Register`,L;t[20]!==S||t[21]!==o||t[22]!==I?(L=(0,W.jsx)(A,{disabled:o,onClick:S,children:I}),t[20]=S,t[21]=o,t[22]=I,t[23]=L):L=t[23];let R;t[24]!==F||t[25]!==L?(R=(0,W.jsxs)(j,{children:[F,L]}),t[24]=F,t[25]=L,t[26]=R):R=t[26];let z;t[27]!==E||t[28]!==R||t[29]!==w||t[30]!==T?(z=(0,W.jsxs)(O,{className:`sm:max-w-lg`,children:[w,T,E,R]}),t[27]=E,t[28]=R,t[29]=w,t[30]=T,t[31]=z):z=t[31];let B;return t[32]!==r||t[33]!==n||t[34]!==z?(B=(0,W.jsx)(P,{onOpenChange:r,open:n,children:z}),t[32]=r,t[33]=n,t[34]=z,t[35]=B):B=t[35],B}function q(e){let[,t]=e;return t.checked&&t!==void 0}var J=5e3,Y=new Set([`healthy`]),X=new Set([`unhealthy`,`unavailable`]),Z=new Set([`initial`,`draining`]);function Q(e){return e&&Y.has(e)?`bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-100`:e&&X.has(e)?`bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-100`:e&&Z.has(e)?`bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-100`:`bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-100`}function $(e){return`${e.Id??``}:${e.Port??``}`}function ee({targetGroupArn:r,vpcId:a,defaultPort:c,isActive:l}){let{data:p}=n(u),{data:m,isLoading:g,error:_}=t({...d(r),refetchInterval:l?J:!1,refetchIntervalInBackground:!1}),v=s(),y=o(),[b,x]=(0,U.useState)(!1),[S,C]=(0,U.useState)(),w=(p.Reservations?.flatMap(e=>e.Instances??[])??[]).filter(e=>e.VpcId===a&&e.State?.Name!==`terminated`),T=m?.TargetHealthDescriptions??[];return(0,W.jsxs)(`div`,{className:`space-y-3`,children:[v.error&&(0,W.jsx)(e,{error:v.error,msg:`Failed to register targets`}),y.error&&(0,W.jsx)(e,{error:y.error,msg:`Failed to deregister target`}),_&&(0,W.jsx)(e,{error:_,msg:`Failed to load target health`}),(0,W.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,W.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:g?`Loading target health…`:`${T.length} target${T.length===1?``:`s`}`}),(0,W.jsx)(h,{onClick:()=>x(!0),size:`sm`,children:`Register targets`})]}),T.length===0?(0,W.jsx)(`p`,{className:`text-muted-foreground`,children:`No targets registered.`}):(0,W.jsx)(`div`,{className:`overflow-x-auto rounded-lg border bg-card`,children:(0,W.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,W.jsx)(`thead`,{children:(0,W.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,W.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Target`}),(0,W.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Port`}),(0,W.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`AZ`}),(0,W.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Health`}),(0,W.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Reason`}),(0,W.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Description`}),(0,W.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:(0,W.jsx)(`span`,{className:`sr-only`,children:`Actions`})})]})}),(0,W.jsx)(`tbody`,{children:T.map(e=>{let t=e.Target??{Id:``},n=e.TargetHealth?.State;return(0,W.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,W.jsx)(`td`,{className:`px-4 py-2 font-mono text-xs`,children:t.Id??``}),(0,W.jsx)(`td`,{className:`px-4 py-2`,children:t.Port??``}),(0,W.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:t.AvailabilityZone??``}),(0,W.jsx)(`td`,{className:`px-4 py-2`,children:(0,W.jsx)(`span`,{className:f(`rounded-full px-2 py-0.5 text-xs`,Q(n)),children:n??`unknown`})}),(0,W.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:e.TargetHealth?.Reason??``}),(0,W.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:e.TargetHealth?.Description??``}),(0,W.jsx)(`td`,{className:`px-4 py-2 text-right`,children:(0,W.jsx)(h,{"aria-label":`Deregister ${t.Id}`,onClick:()=>C(t),size:`sm`,variant:`ghost`,children:(0,W.jsx)(i,{className:`size-4`})})})]},$(t))})})]})}),(0,W.jsx)(K,{defaultPort:c,instances:w,isPending:v.isPending,onConfirm:async e=>{try{await v.mutateAsync({targetGroupArn:r,targets:e}),x(!1)}catch{}},onOpenChange:x,open:b}),(0,W.jsx)(F,{description:S?`Deregister ${S.Id}${S.Port?`:${S.Port}`:``} from this target group?`:``,isPending:y.isPending,onConfirm:async()=>{if(S?.Id)try{await y.mutateAsync({targetGroupArn:r,targets:[{id:S.Id,port:S.Port}]})}finally{C(void 0)}},onOpenChange:e=>!e&&C(void 0),open:S!==void 0,title:`Deregister target`})]})}function te({arn:t}){let o=C(),{data:s}=n(v(t)),{data:u}=n(l(t)),{data:d}=n(y([t])),f=a(),p=c(),[m,g]=(0,U.useState)(!1),[_,b]=(0,U.useState)(`overview`),x=s.TargetGroups?.[0];if(!x?.TargetGroupArn)return(0,W.jsxs)(W.Fragment,{children:[(0,W.jsx)(r,{to:`/ec2/describe-target-groups`,children:`Back to target groups`}),(0,W.jsx)(`p`,{className:`text-muted-foreground`,children:`Target group not found.`})]});let S=async()=>{try{await f.mutateAsync(t),o({to:`/ec2/describe-target-groups`})}finally{g(!1)}},D=u.Attributes??[],O=d?.TagDescriptions?.find(e=>e.ResourceArn===t)?.Tags??[];return(0,W.jsxs)(W.Fragment,{children:[(0,W.jsx)(r,{to:`/ec2/describe-target-groups`,children:`Back to target groups`}),f.error&&(0,W.jsx)(e,{error:f.error,msg:`Failed to delete target group`}),(0,W.jsxs)(`div`,{className:`space-y-6`,children:[(0,W.jsx)(w,{actions:(0,W.jsxs)(h,{onClick:()=>g(!0),size:`sm`,variant:`destructive`,children:[(0,W.jsx)(i,{className:`size-4`}),`Delete`]}),subtitle:`Target Group Details`,title:x.TargetGroupName??x.TargetGroupArn}),(0,W.jsxs)(V,{onValueChange:b,value:_,children:[(0,W.jsxs)(R,{children:[(0,W.jsx)(L,{value:`overview`,children:`Overview`}),(0,W.jsx)(L,{value:`targets`,children:`Targets`}),(0,W.jsx)(L,{value:`health-checks`,children:`Health checks`}),(0,W.jsx)(L,{value:`attributes`,children:`Attributes`}),(0,W.jsx)(L,{value:`tags`,children:`Tags`})]}),(0,W.jsx)(z,{value:`overview`,children:(0,W.jsxs)(T,{children:[(0,W.jsx)(T.Header,{children:`Target group`}),(0,W.jsxs)(T.Content,{children:[(0,W.jsx)(E,{label:`ARN`,value:x.TargetGroupArn}),(0,W.jsx)(E,{label:`Protocol`,value:x.Protocol}),(0,W.jsx)(E,{label:`Port`,value:x.Port?.toString()}),(0,W.jsx)(E,{label:`VPC`,value:x.VpcId}),(0,W.jsx)(E,{label:`Target type`,value:x.TargetType}),(0,W.jsx)(E,{label:`Protocol version`,value:x.ProtocolVersion}),(0,W.jsx)(E,{label:`IP address type`,value:x.IpAddressType})]})]})}),(0,W.jsx)(z,{value:`targets`,children:(0,W.jsx)(ee,{defaultPort:x.Port??80,isActive:_===`targets`,targetGroupArn:x.TargetGroupArn,vpcId:x.VpcId})}),(0,W.jsxs)(z,{value:`health-checks`,children:[(0,W.jsx)(`p`,{className:`mb-3 text-sm text-muted-foreground`,children:`Health-check settings are set at creation time. Editing lands in a future slice (mulga-948).`}),(0,W.jsxs)(T,{children:[(0,W.jsx)(T.Header,{children:`Health check`}),(0,W.jsxs)(T.Content,{children:[(0,W.jsx)(E,{label:`Enabled`,value:x.HealthCheckEnabled===void 0?void 0:String(x.HealthCheckEnabled)}),(0,W.jsx)(E,{label:`Protocol`,value:x.HealthCheckProtocol}),(0,W.jsx)(E,{label:`Path`,value:x.HealthCheckPath}),(0,W.jsx)(E,{label:`Port`,value:x.HealthCheckPort}),(0,W.jsx)(E,{label:`Interval (s)`,value:x.HealthCheckIntervalSeconds?.toString()}),(0,W.jsx)(E,{label:`Timeout (s)`,value:x.HealthCheckTimeoutSeconds?.toString()}),(0,W.jsx)(E,{label:`Healthy threshold`,value:x.HealthyThresholdCount?.toString()}),(0,W.jsx)(E,{label:`Unhealthy threshold`,value:x.UnhealthyThresholdCount?.toString()}),(0,W.jsx)(E,{label:`Matcher (HTTP codes)`,value:x.Matcher?.HttpCode??x.Matcher?.GrpcCode})]})]})]}),(0,W.jsx)(z,{value:`attributes`,children:(0,W.jsx)(I,{attributes:D,error:p.error,isPending:p.isPending,isSuccess:p.isSuccess,onSubmit:e=>{p.mutate({targetGroupArn:t,attributes:e})},specs:B})}),(0,W.jsx)(z,{value:`tags`,children:O.length>0?(0,W.jsxs)(T,{children:[(0,W.jsx)(T.Header,{children:`Tags`}),(0,W.jsx)(T.Content,{children:O.map(e=>(0,W.jsx)(E,{label:e.Key??``,value:e.Value},e.Key??``))})]}):(0,W.jsx)(`p`,{className:`text-muted-foreground`,children:`No tags.`})})]})]}),(0,W.jsx)(F,{description:`Are you sure you want to delete target group "${x.TargetGroupName??x.TargetGroupArn}"? This action cannot be undone.`,isPending:f.isPending,onConfirm:S,onOpenChange:g,open:m,title:`Delete Target Group`})]})}function ne(){let e=(0,H.c)(2),{id:t}=b.useParams(),n=decodeURIComponent(t),r;return e[0]===n?r=e[1]:(r=(0,W.jsx)(te,{arn:n}),e[0]=n,e[1]=r),r}export{ne as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./useQuery.js";import{t as n}from"./useSuspenseQuery.js";import{t as r}from"./back-link.js";import{t as i}from"./trash-2.js";import{c as a,g as o,l as s,m as c,p as l}from"./elbv2.js";import{A as u,Ha as d,Ja as f,Jo as p,M as m,Oo as h,P as g,U as _,j as v,ko as y,l as b,wo as x,xo as S,za as C,zi as w}from"./index.js";import{t as T}from"./page-heading.js";import{n as E,t as D}from"./detail-row.js";import{a as O,i as k,l as A,n as j,o as M,r as N,s as P,t as F}from"./alert-dialog.js";import{t as I}from"./delete-confirmation-dialog.js";import{a as L,c as R,i as z,n as B,o as V,r as H,t as U}from"./tabs.js";var W=S(),G=p(y(),1),K=h();function q(e){let t=e.trim();if(t===``)return;let n=Number(t);if(!(!Number.isInteger(n)||n<1||n>65535))return n}function J(e){let t=(0,W.c)(36),{open:n,onOpenChange:r,instances:i,defaultPort:a,isPending:o,onConfirm:s}=e,c;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(c={},t[0]=c):c=t[0];let[l,u]=(0,G.useState)(c),[d,p]=(0,G.useState)(),m,h;t[1]===n?(m=t[2],h=t[3]):(m=()=>{n||(u({}),p(void 0))},h=[n],t[1]=n,t[2]=m,t[3]=h),(0,G.useEffect)(m,h);let g;t[4]===Symbol.for(`react.memo_cache_sentinel`)?(g=e=>{u(t=>{let n=t[e];return n?.checked?{...t,[e]:{...n,checked:!1}}:{...t,[e]:{checked:!0,port:n?.port??``}}})},t[4]=g):g=t[4];let _=g,v;t[5]===Symbol.for(`react.memo_cache_sentinel`)?(v=(e,t)=>{u(n=>({...n,[e]:{checked:n[e]?.checked??!0,port:t}}))},t[5]=v):v=t[5];let y=v,b;t[6]!==s||t[7]!==l?(b=()=>{let e=Object.entries(l).filter(Y);if(e.length===0){p(`Select at least one instance.`);return}let t=[];for(let[n,r]of e){if(r.port.trim()===``){t.push({id:n});continue}let e=q(r.port);if(e===void 0){p(`Port for ${n} must be an integer between 1 and 65535.`);return}t.push({id:n,port:e})}p(void 0),s(t)},t[6]=s,t[7]=l,t[8]=b):b=t[8];let x=b,S;t[9]===Symbol.for(`react.memo_cache_sentinel`)?(S=(0,K.jsx)(A,{children:`Register targets`}),t[9]=S):S=t[9];let C;t[10]===a?C=t[11]:(C=(0,K.jsxs)(P,{children:[S,(0,K.jsxs)(O,{children:[`Select instances to register. Leave port blank to use the target group port (`,a,`).`]})]}),t[10]=a,t[11]=C);let T;t[12]!==a||t[13]!==i||t[14]!==l?(T=i.length===0?(0,K.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No instances available in this VPC.`}):(0,K.jsx)(`div`,{className:`max-h-72 space-y-1 overflow-y-auto`,children:i.map(e=>{let t=e.InstanceId??``,n=l[t],r=n?.checked??!1,i=f(e.Tags);return(0,K.jsxs)(`div`,{className:`flex items-center gap-2 rounded px-1 py-1 text-xs hover:bg-accent`,children:[(0,K.jsx)(`input`,{"aria-label":`Register target ${t}`,checked:r,id:`register-target-${t}`,onChange:()=>_(t),type:`checkbox`}),(0,K.jsxs)(`label`,{className:`flex flex-1 items-center gap-2`,htmlFor:`register-target-${t}`,children:[(0,K.jsx)(`span`,{className:`font-mono`,children:t}),i&&(0,K.jsxs)(`span`,{className:`text-muted-foreground`,children:[`(`,i,`)`]}),(0,K.jsx)(`span`,{className:`text-muted-foreground`,children:e.State?.Name??``})]}),r&&(0,K.jsx)(w,{"aria-label":`Port override for ${t}`,className:`w-24`,onChange:e=>y(t,e.target.value),placeholder:String(a),value:n?.port??``})]},t)})}),t[12]=a,t[13]=i,t[14]=l,t[15]=T):T=t[15];let E;t[16]===d?E=t[17]:(E=d&&(0,K.jsx)(`p`,{className:`text-xs text-destructive`,role:`alert`,children:d}),t[16]=d,t[17]=E);let D;t[18]===o?D=t[19]:(D=(0,K.jsx)(N,{disabled:o,children:`Cancel`}),t[18]=o,t[19]=D);let I=o?`Registering…`:`Register`,L;t[20]!==x||t[21]!==o||t[22]!==I?(L=(0,K.jsx)(j,{disabled:o,onClick:x,children:I}),t[20]=x,t[21]=o,t[22]=I,t[23]=L):L=t[23];let R;t[24]!==D||t[25]!==L?(R=(0,K.jsxs)(M,{children:[D,L]}),t[24]=D,t[25]=L,t[26]=R):R=t[26];let z;t[27]!==E||t[28]!==R||t[29]!==C||t[30]!==T?(z=(0,K.jsxs)(k,{className:`sm:max-w-lg`,children:[C,T,E,R]}),t[27]=E,t[28]=R,t[29]=C,t[30]=T,t[31]=z):z=t[31];let B;return t[32]!==r||t[33]!==n||t[34]!==z?(B=(0,K.jsx)(F,{onOpenChange:r,open:n,children:z}),t[32]=r,t[33]=n,t[34]=z,t[35]=B):B=t[35],B}function Y(e){let[,t]=e;return t.checked&&t!==void 0}var X=5e3,Z=new Set([`healthy`]),Q=new Set([`unhealthy`,`unavailable`]),$=new Set([`initial`,`draining`]);function ee(e){return e&&Z.has(e)?`bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-100`:e&&Q.has(e)?`bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-100`:e&&$.has(e)?`bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-100`:`bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-100`}function te(e){return`${e.Id??``}:${e.Port??``}`}function ne({targetGroupArn:r,vpcId:a,defaultPort:o,isActive:l}){let{data:u}=n(_),{data:f,isLoading:p,error:m}=t({...g(r),refetchInterval:l?X:!1,refetchIntervalInBackground:!1}),h=c(),v=s(),[y,b]=(0,G.useState)(!1),[x,S]=(0,G.useState)(),w=(u.Reservations?.flatMap(e=>e.Instances??[])??[]).filter(e=>e.VpcId===a&&e.State?.Name!==`terminated`),T=f?.TargetHealthDescriptions??[];return(0,K.jsxs)(`div`,{className:`space-y-3`,children:[h.error&&(0,K.jsx)(e,{error:h.error,msg:`Failed to register targets`}),v.error&&(0,K.jsx)(e,{error:v.error,msg:`Failed to deregister target`}),m&&(0,K.jsx)(e,{error:m,msg:`Failed to load target health`}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:p?`Loading target health…`:`${T.length} target${T.length===1?``:`s`}`}),(0,K.jsx)(C,{onClick:()=>b(!0),size:`sm`,children:`Register targets`})]}),T.length===0?(0,K.jsx)(`p`,{className:`text-muted-foreground`,children:`No targets registered.`}):(0,K.jsx)(`div`,{className:`overflow-x-auto rounded-lg border bg-card`,children:(0,K.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,K.jsx)(`thead`,{children:(0,K.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,K.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Target`}),(0,K.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Port`}),(0,K.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`AZ`}),(0,K.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Health`}),(0,K.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Reason`}),(0,K.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Description`}),(0,K.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:(0,K.jsx)(`span`,{className:`sr-only`,children:`Actions`})})]})}),(0,K.jsx)(`tbody`,{children:T.map(e=>{let t=e.Target??{Id:``},n=e.TargetHealth?.State;return(0,K.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,K.jsx)(`td`,{className:`px-4 py-2 font-mono text-xs`,children:t.Id??``}),(0,K.jsx)(`td`,{className:`px-4 py-2`,children:t.Port??``}),(0,K.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:t.AvailabilityZone??``}),(0,K.jsx)(`td`,{className:`px-4 py-2`,children:(0,K.jsx)(`span`,{className:d(`rounded-full px-2 py-0.5 text-xs`,ee(n)),children:n??`unknown`})}),(0,K.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:e.TargetHealth?.Reason??``}),(0,K.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:e.TargetHealth?.Description??``}),(0,K.jsx)(`td`,{className:`px-4 py-2 text-right`,children:(0,K.jsx)(C,{"aria-label":`Deregister ${t.Id}`,onClick:()=>S(t),size:`sm`,variant:`ghost`,children:(0,K.jsx)(i,{className:`size-4`})})})]},te(t))})})]})}),(0,K.jsx)(J,{defaultPort:o,instances:w,isPending:h.isPending,onConfirm:async e=>{try{await h.mutateAsync({targetGroupArn:r,targets:e}),b(!1)}catch{}},onOpenChange:b,open:y}),(0,K.jsx)(I,{description:x?`Deregister ${x.Id}${x.Port?`:${x.Port}`:``} from this target group?`:``,isPending:v.isPending,onConfirm:async()=>{if(x?.Id)try{await v.mutateAsync({targetGroupArn:r,targets:[{id:x.Id,port:x.Port}]})}finally{S(void 0)}},onOpenChange:e=>!e&&S(void 0),open:x!==void 0,title:`Deregister target`})]})}function re({arn:t}){let s=x(),{data:c}=n(m(t)),{data:d}=n(v(t)),{data:f}=n(u([t])),p=a(),h=l(),g=o(),[_,y]=(0,G.useState)(!1),[b,S]=(0,G.useState)(`overview`),w=c.TargetGroups?.[0];if(!w?.TargetGroupArn)return(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(r,{to:`/ec2/describe-target-groups`,children:`Back to target groups`}),(0,K.jsx)(`p`,{className:`text-muted-foreground`,children:`Target group not found.`})]});let O=async()=>{try{await p.mutateAsync(t),s({to:`/ec2/describe-target-groups`})}finally{y(!1)}},k=d.Attributes??[],A=f?.TagDescriptions?.find(e=>e.ResourceArn===t)?.Tags??[];return(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(r,{to:`/ec2/describe-target-groups`,children:`Back to target groups`}),p.error&&(0,K.jsx)(e,{error:p.error,msg:`Failed to delete target group`}),(0,K.jsxs)(`div`,{className:`space-y-6`,children:[(0,K.jsx)(T,{actions:(0,K.jsxs)(C,{onClick:()=>y(!0),size:`sm`,variant:`destructive`,children:[(0,K.jsx)(i,{className:`size-4`}),`Delete`]}),subtitle:`Target Group Details`,title:w.TargetGroupName??w.TargetGroupArn}),(0,K.jsxs)(U,{onValueChange:S,value:b,children:[(0,K.jsxs)(B,{children:[(0,K.jsx)(z,{value:`overview`,children:`Overview`}),(0,K.jsx)(z,{value:`targets`,children:`Targets`}),(0,K.jsx)(z,{value:`health-checks`,children:`Health checks`}),(0,K.jsx)(z,{value:`attributes`,children:`Attributes`}),(0,K.jsx)(z,{value:`tags`,children:`Tags`})]}),(0,K.jsx)(H,{value:`overview`,children:(0,K.jsxs)(E,{children:[(0,K.jsx)(E.Header,{children:`Target group`}),(0,K.jsxs)(E.Content,{children:[(0,K.jsx)(D,{label:`ARN`,value:w.TargetGroupArn}),(0,K.jsx)(D,{label:`Protocol`,value:w.Protocol}),(0,K.jsx)(D,{label:`Port`,value:w.Port?.toString()}),(0,K.jsx)(D,{label:`VPC`,value:w.VpcId}),(0,K.jsx)(D,{label:`Target type`,value:w.TargetType}),(0,K.jsx)(D,{label:`Protocol version`,value:w.ProtocolVersion}),(0,K.jsx)(D,{label:`IP address type`,value:w.IpAddressType})]})]})}),(0,K.jsx)(H,{value:`targets`,children:(0,K.jsx)(ne,{defaultPort:w.Port??80,isActive:b===`targets`,targetGroupArn:w.TargetGroupArn,vpcId:w.VpcId})}),(0,K.jsxs)(H,{value:`health-checks`,children:[(0,K.jsx)(`p`,{className:`mb-3 text-sm text-muted-foreground`,children:`Health-check settings are set at creation time. Editing lands in a future slice (mulga-948).`}),(0,K.jsxs)(E,{children:[(0,K.jsx)(E.Header,{children:`Health check`}),(0,K.jsxs)(E.Content,{children:[(0,K.jsx)(D,{label:`Enabled`,value:w.HealthCheckEnabled===void 0?void 0:String(w.HealthCheckEnabled)}),(0,K.jsx)(D,{label:`Protocol`,value:w.HealthCheckProtocol}),(0,K.jsx)(D,{label:`Path`,value:w.HealthCheckPath}),(0,K.jsx)(D,{label:`Port`,value:w.HealthCheckPort}),(0,K.jsx)(D,{label:`Interval (s)`,value:w.HealthCheckIntervalSeconds?.toString()}),(0,K.jsx)(D,{label:`Timeout (s)`,value:w.HealthCheckTimeoutSeconds?.toString()}),(0,K.jsx)(D,{label:`Healthy threshold`,value:w.HealthyThresholdCount?.toString()}),(0,K.jsx)(D,{label:`Unhealthy threshold`,value:w.UnhealthyThresholdCount?.toString()}),(0,K.jsx)(D,{label:`Matcher (HTTP codes)`,value:w.Matcher?.HttpCode??w.Matcher?.GrpcCode})]})]})]}),(0,K.jsx)(H,{value:`attributes`,children:(0,K.jsx)(V,{attributes:k,error:h.error,isPending:h.isPending,isSuccess:h.isSuccess,onSubmit:e=>{h.mutate({targetGroupArn:t,attributes:e})},specs:R})}),(0,K.jsx)(H,{value:`tags`,children:(0,K.jsx)(L,{error:g.error,isPending:g.isPending,isSuccess:g.isSuccess,onSubmit:e=>g.mutate({resourceArn:t,tags:e,initialKeys:A.map(e=>e.Key??``).filter(e=>e.length>0)}),tags:A})})]})]}),(0,K.jsx)(I,{description:`Are you sure you want to delete target group "${w.TargetGroupName??w.TargetGroupArn}"? This action cannot be undone.`,isPending:p.isPending,onConfirm:O,onOpenChange:y,open:_,title:`Delete Target Group`})]})}function ie(){let e=(0,W.c)(2),{id:t}=b.useParams(),n=decodeURIComponent(t),r;return e[0]===n?r=e[1]:(r=(0,K.jsx)(re,{arn:n}),e[0]=n,e[1]=r),r}export{ie as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_policyArn.js b/spinifex/services/spinifexui/frontend/dist/assets/_policyArn.js index 744a55bea..838cec502 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_policyArn.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_policyArn.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./trash-2.js";import{o as i}from"./iam.js";import{Po as a,Ta as o,b as s,ho as c,ja as l,mo as u,p as d,so as f,uo as p,y as m}from"./index.js";import{t as h}from"./page-heading.js";import{n as g,t as _}from"./detail-row.js";import{t as v}from"./delete-confirmation-dialog.js";var y=a(c()),b=f(),x=u();function S(e){let t=(0,b.c)(4),{document:n}=e,r;try{let e;t[0]===n?e=t[1]:(e=JSON.stringify(JSON.parse(n),null,2),t[0]=n,t[1]=e),r=e}catch{r=n}let i;return t[2]===r?i=t[3]:(i=(0,x.jsx)(`pre`,{className:`overflow-auto rounded-md border bg-muted p-4 font-mono text-sm`,children:r}),t[2]=r,t[3]=i),i}function C(){let{policyArn:a}=d.useParams(),c=decodeURIComponent(a),u=p(),{data:f}=t(m(c)),b=f.Policy,C=i(),[w,T]=(0,y.useState)(!1),{data:E}=t(s(c,b?.DefaultVersionId??`v1`)),D=E?.PolicyVersion?.Document?decodeURIComponent(E.PolicyVersion.Document):null;return b?(0,x.jsxs)(x.Fragment,{children:[(0,x.jsx)(n,{to:`/iam/list-policies`,children:`Back to policies`}),C.error&&(0,x.jsx)(e,{error:C.error,msg:`Failed to delete policy`}),(0,x.jsxs)(`div`,{className:`space-y-6`,children:[(0,x.jsx)(h,{actions:(0,x.jsxs)(o,{onClick:()=>T(!0),size:`sm`,variant:`destructive`,children:[(0,x.jsx)(r,{className:`size-4`}),`Delete`]}),subtitle:`Policy Details`,title:b.PolicyName??``}),(0,x.jsxs)(g,{children:[(0,x.jsx)(g.Header,{children:`Policy Information`}),(0,x.jsxs)(g.Content,{children:[(0,x.jsx)(_,{label:`Policy Name`,value:b.PolicyName}),(0,x.jsx)(_,{label:`Policy ID`,value:b.PolicyId}),(0,x.jsx)(_,{label:`ARN`,value:b.Arn}),(0,x.jsx)(_,{label:`Path`,value:b.Path}),(0,x.jsx)(_,{label:`Description`,value:b.Description??`-`}),(0,x.jsx)(_,{label:`Created`,value:l(b.CreateDate)})]})]}),D&&(0,x.jsxs)(g,{children:[(0,x.jsx)(g.Header,{children:`Policy Document`}),(0,x.jsx)(`div`,{className:`p-4`,children:(0,x.jsx)(S,{document:D})})]})]}),(0,x.jsx)(v,{description:`Are you sure you want to delete the policy "${b.PolicyName}"? This action cannot be undone.`,isPending:C.isPending,onConfirm:async()=>{try{await C.mutateAsync(c),u({to:`/iam/list-policies`})}finally{T(!1)}},onOpenChange:T,open:w,title:`Delete Policy`})]}):(0,x.jsxs)(x.Fragment,{children:[(0,x.jsx)(n,{to:`/iam/list-policies`,children:`Back to policies`}),(0,x.jsx)(`p`,{className:`text-muted-foreground`,children:`Policy not found.`})]})}export{C as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./trash-2.js";import{o as i}from"./iam.js";import{Ga as a,Jo as o,Oo as s,b as c,ko as l,p as u,wo as d,xo as f,y as p,za as m}from"./index.js";import{t as h}from"./page-heading.js";import{n as g,t as _}from"./detail-row.js";import{t as v}from"./delete-confirmation-dialog.js";var y=o(l()),b=f(),x=s();function S(e){let t=(0,b.c)(4),{document:n}=e,r;try{let e;t[0]===n?e=t[1]:(e=JSON.stringify(JSON.parse(n),null,2),t[0]=n,t[1]=e),r=e}catch{r=n}let i;return t[2]===r?i=t[3]:(i=(0,x.jsx)(`pre`,{className:`overflow-auto rounded-md border bg-muted p-4 font-mono text-sm`,children:r}),t[2]=r,t[3]=i),i}function C(){let{policyArn:o}=u.useParams(),s=decodeURIComponent(o),l=d(),{data:f}=t(p(s)),b=f.Policy,C=i(),[w,T]=(0,y.useState)(!1),{data:E}=t(c(s,b?.DefaultVersionId??`v1`)),D=E?.PolicyVersion?.Document?decodeURIComponent(E.PolicyVersion.Document):null;return b?(0,x.jsxs)(x.Fragment,{children:[(0,x.jsx)(n,{to:`/iam/list-policies`,children:`Back to policies`}),C.error&&(0,x.jsx)(e,{error:C.error,msg:`Failed to delete policy`}),(0,x.jsxs)(`div`,{className:`space-y-6`,children:[(0,x.jsx)(h,{actions:(0,x.jsxs)(m,{onClick:()=>T(!0),size:`sm`,variant:`destructive`,children:[(0,x.jsx)(r,{className:`size-4`}),`Delete`]}),subtitle:`Policy Details`,title:b.PolicyName??``}),(0,x.jsxs)(g,{children:[(0,x.jsx)(g.Header,{children:`Policy Information`}),(0,x.jsxs)(g.Content,{children:[(0,x.jsx)(_,{label:`Policy Name`,value:b.PolicyName}),(0,x.jsx)(_,{label:`Policy ID`,value:b.PolicyId}),(0,x.jsx)(_,{label:`ARN`,value:b.Arn}),(0,x.jsx)(_,{label:`Path`,value:b.Path}),(0,x.jsx)(_,{label:`Description`,value:b.Description??`-`}),(0,x.jsx)(_,{label:`Created`,value:a(b.CreateDate)})]})]}),D&&(0,x.jsxs)(g,{children:[(0,x.jsx)(g.Header,{children:`Policy Document`}),(0,x.jsx)(`div`,{className:`p-4`,children:(0,x.jsx)(S,{document:D})})]})]}),(0,x.jsx)(v,{description:`Are you sure you want to delete the policy "${b.PolicyName}"? This action cannot be undone.`,isPending:C.isPending,onConfirm:async()=>{try{await C.mutateAsync(s),l({to:`/iam/list-policies`})}finally{T(!1)}},onOpenChange:T,open:w,title:`Delete Policy`})]}):(0,x.jsxs)(x.Fragment,{children:[(0,x.jsx)(n,{to:`/iam/list-policies`,children:`Back to policies`}),(0,x.jsx)(`p`,{className:`text-muted-foreground`,children:`Policy not found.`})]})}export{C as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/_userName.js b/spinifex/services/spinifexui/frontend/dist/assets/_userName.js index d0cc0f319..155908aff 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/_userName.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/_userName.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./check.js";import{t as i}from"./trash-2.js";import{t as a}from"./triangle-alert.js";import{a as o,c as s,l as c,n as l,s as u,t as d}from"./iam.js";import{Po as f,Ta as p,_ as m,g as h,ho as g,ja as _,m as v,mo as y,so as b,uo as x,v as S,x as C}from"./index.js";import{t as w}from"./page-heading.js";import{t as T}from"./state-badge.js";import{n as E,t as D}from"./detail-row.js";import{a as O,c as k,i as A,l as j,o as M,r as N,s as P,t as F}from"./alert-dialog.js";import{t as I}from"./delete-confirmation-dialog.js";import{t as L}from"./use-copy-to-clipboard.js";var R=f(g()),z=b(),B=y();function V(e){let t=(0,z.c)(27),{onClose:n,accessKeyId:i,secretAccessKey:o}=e,{copied:s,copy:c}=L(),l;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(l=(0,B.jsxs)(P,{children:[(0,B.jsx)(k,{children:(0,B.jsx)(a,{className:`text-destructive`})}),(0,B.jsx)(j,{children:`Save Your Access Key`}),(0,B.jsx)(O,{children:`This is your only chance to view the secret access key. Please copy it now. You won't be able to retrieve it again.`})]}),t[0]=l):l=t[0];let u;t[1]===Symbol.for(`react.memo_cache_sentinel`)?(u=(0,B.jsx)(`span`,{className:`text-muted-foreground`,children:`Access Key ID: `}),t[1]=u):u=t[1];let d;t[2]===i?d=t[3]:(d=(0,B.jsxs)(`div`,{children:[u,i]}),t[2]=i,t[3]=d);let f;t[4]===Symbol.for(`react.memo_cache_sentinel`)?(f=(0,B.jsx)(`span`,{className:`text-muted-foreground`,children:`Secret Access Key: `}),t[4]=f):f=t[4];let m;t[5]===o?m=t[6]:(m=(0,B.jsxs)(`div`,{children:[f,o]}),t[5]=o,t[6]=m);let h;t[7]!==d||t[8]!==m?(h=(0,B.jsxs)(`div`,{className:`space-y-2 rounded-md border p-4 font-mono text-sm`,children:[d,m]}),t[7]=d,t[8]=m,t[9]=h):h=t[9];let g;t[10]!==i||t[11]!==c||t[12]!==o?(g=async()=>await c(`Access Key ID: ${i}\nSecret Access Key: ${o}`),t[10]=i,t[11]=c,t[12]=o,t[13]=g):g=t[13];let _;t[14]===s?_=t[15]:(_=s?(0,B.jsxs)(B.Fragment,{children:[(0,B.jsx)(r,{className:`mr-2 size-4`}),`Copied!`]}):`Copy to Clipboard`,t[14]=s,t[15]=_);let v;t[16]!==g||t[17]!==_?(v=(0,B.jsx)(p,{className:`w-full`,onClick:g,type:`button`,variant:`outline`,children:_}),t[16]=g,t[17]=_,t[18]=v):v=t[18];let y;t[19]!==h||t[20]!==v?(y=(0,B.jsxs)(`div`,{className:`space-y-3`,children:[h,v]}),t[19]=h,t[20]=v,t[21]=y):y=t[21];let b;t[22]===n?b=t[23]:(b=(0,B.jsx)(M,{children:(0,B.jsx)(N,{onClick:n,children:`Close and Continue`})}),t[22]=n,t[23]=b);let x;return t[24]!==y||t[25]!==b?(x=(0,B.jsx)(F,{open:!0,children:(0,B.jsxs)(A,{className:`max-w-2xl`,children:[l,y,b]})}),t[24]=y,t[25]=b,t[26]=x):x=t[26],x}function H(){let{userName:r}=v.useParams(),a=x(),{data:f}=t(C(r)),{data:g}=t(h(r)),{data:y}=t(m(r)),{data:b}=t(S),O=u(),k=l(),A=o(),j=c(),M=d(),N=s(),[P,F]=(0,R.useState)(!1),[L,z]=(0,R.useState)(null),[H,U]=(0,R.useState)(!1),[W,G]=(0,R.useState)(null),[K,q]=(0,R.useState)(null),J=f.User,Y=g.AccessKeyMetadata??[],X=y.AttachedPolicies??[],Z=b.Policies??[],Q=new Set(X.map(e=>e.PolicyArn)),$=Z.filter(e=>e.Arn&&!Q.has(e.Arn)),ee=async()=>{try{await O.mutateAsync(r),a({to:`/iam/list-users`})}finally{F(!1)}},te=async()=>{let e=await k.mutateAsync(r);e.AccessKey&&z({accessKeyId:e.AccessKey.AccessKeyId??``,secretAccessKey:e.AccessKey.SecretAccessKey??``})},ne=async e=>{if(e.AccessKeyId){G(e.AccessKeyId);try{await j.mutateAsync({userName:r,accessKeyId:e.AccessKeyId,status:e.Status===`Active`?`Inactive`:`Active`})}finally{G(null)}}},re=async e=>{G(e);try{await A.mutateAsync({userName:r,accessKeyId:e})}finally{G(null)}},ie=async e=>{await M.mutateAsync({userName:r,policyArn:e}),U(!1)},ae=async e=>{q(e);try{await N.mutateAsync({userName:r,policyArn:e})}finally{q(null)}};return J?(0,B.jsxs)(B.Fragment,{children:[(0,B.jsx)(n,{to:`/iam/list-users`,children:`Back to users`}),O.error&&(0,B.jsx)(e,{error:O.error,msg:`Failed to delete user`}),k.error&&(0,B.jsx)(e,{error:k.error,msg:`Failed to create access key`}),A.error&&(0,B.jsx)(e,{error:A.error,msg:`Failed to delete access key`}),M.error&&(0,B.jsx)(e,{error:M.error,msg:`Failed to attach policy`}),N.error&&(0,B.jsx)(e,{error:N.error,msg:`Failed to detach policy`}),(0,B.jsxs)(`div`,{className:`space-y-6`,children:[(0,B.jsx)(w,{actions:(0,B.jsxs)(p,{onClick:()=>F(!0),size:`sm`,variant:`destructive`,children:[(0,B.jsx)(i,{className:`size-4`}),`Delete`]}),subtitle:`User Details`,title:J.UserName??``}),(0,B.jsxs)(E,{children:[(0,B.jsx)(E.Header,{children:`User Information`}),(0,B.jsxs)(E.Content,{children:[(0,B.jsx)(D,{label:`User Name`,value:J.UserName}),(0,B.jsx)(D,{label:`User ID`,value:J.UserId}),(0,B.jsx)(D,{label:`ARN`,value:J.Arn}),(0,B.jsx)(D,{label:`Path`,value:J.Path}),(0,B.jsx)(D,{label:`Created`,value:_(J.CreateDate)})]})]}),(0,B.jsxs)(E,{children:[(0,B.jsx)(E.Header,{children:(0,B.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,B.jsx)(`span`,{children:`Access Keys`}),(0,B.jsx)(p,{disabled:k.isPending,onClick:te,size:`sm`,children:k.isPending?`Creating...`:`Create Access Key`})]})}),(0,B.jsx)(E.Content,{children:Y.length>0?(0,B.jsx)(`div`,{className:`col-span-2 space-y-3`,children:Y.map(e=>(0,B.jsxs)(`div`,{className:`flex items-center justify-between rounded-md border p-3`,children:[(0,B.jsxs)(`div`,{className:`space-y-1`,children:[(0,B.jsx)(`p`,{className:`font-mono text-sm`,children:e.AccessKeyId}),(0,B.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[`Created `,_(e.CreateDate)]})]}),(0,B.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,B.jsx)(T,{state:e.Status}),(0,B.jsx)(p,{disabled:W===e.AccessKeyId,onClick:async()=>await ne(e),size:`sm`,variant:`outline`,children:e.Status===`Active`?`Deactivate`:`Activate`}),(0,B.jsx)(p,{disabled:W===e.AccessKeyId,onClick:()=>{e.AccessKeyId&&re(e.AccessKeyId)},size:`sm`,variant:`destructive`,children:`Delete`})]})]},e.AccessKeyId))}):(0,B.jsx)(`p`,{className:`col-span-2 text-sm text-muted-foreground`,children:`No access keys.`})})]}),(0,B.jsxs)(E,{children:[(0,B.jsx)(E.Header,{children:(0,B.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,B.jsx)(`span`,{children:`Attached Policies`}),(0,B.jsx)(p,{onClick:()=>U(!H),size:`sm`,children:`Attach Policy`})]})}),(0,B.jsxs)(E.Content,{children:[H&&$.length>0&&(0,B.jsxs)(`div`,{className:`col-span-2 space-y-2 rounded-md border p-3`,children:[(0,B.jsx)(`p`,{className:`text-sm font-medium`,children:`Select a policy to attach:`}),(0,B.jsx)(`div`,{className:`space-y-1`,children:$.map(e=>(0,B.jsxs)(`button`,{className:`flex w-full items-center justify-between rounded-md p-2 text-left text-sm hover:bg-accent`,disabled:M.isPending,onClick:()=>{e.Arn&&ie(e.Arn)},type:`button`,children:[(0,B.jsx)(`span`,{children:e.PolicyName}),(0,B.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:e.Arn})]},e.Arn))})]}),H&&$.length===0&&(0,B.jsx)(`p`,{className:`col-span-2 text-sm text-muted-foreground`,children:`No policies available to attach.`}),X.length>0?(0,B.jsx)(`div`,{className:`col-span-2 space-y-3`,children:X.map(e=>(0,B.jsxs)(`div`,{className:`flex items-center justify-between rounded-md border p-3`,children:[(0,B.jsxs)(`div`,{className:`space-y-1`,children:[(0,B.jsx)(`p`,{className:`text-sm font-medium`,children:e.PolicyName}),(0,B.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e.PolicyArn})]}),(0,B.jsx)(p,{disabled:K===e.PolicyArn,onClick:()=>{e.PolicyArn&&ae(e.PolicyArn)},size:`sm`,variant:`outline`,children:`Detach`})]},e.PolicyArn))}):(0,B.jsx)(`p`,{className:`col-span-2 text-sm text-muted-foreground`,children:`No attached policies.`})]})]})]}),(0,B.jsx)(I,{description:`Are you sure you want to delete the user "${r}"? This action cannot be undone. You must detach all policies and delete all access keys first.`,isPending:O.isPending,onConfirm:ee,onOpenChange:F,open:P,title:`Delete User`}),L&&(0,B.jsx)(V,{accessKeyId:L.accessKeyId,onClose:()=>z(null),secretAccessKey:L.secretAccessKey})]}):(0,B.jsxs)(B.Fragment,{children:[(0,B.jsx)(n,{to:`/iam/list-users`,children:`Back to users`}),(0,B.jsx)(`p`,{className:`text-muted-foreground`,children:`User not found.`})]})}export{H as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./check.js";import{t as i}from"./trash-2.js";import{t as a}from"./triangle-alert.js";import{a as o,c as s,l as c,n as l,s as u,t as d}from"./iam.js";import{Ga as f,Jo as p,Oo as m,_ as h,g,ko as _,m as v,v as y,wo as b,x as ee,xo as x,za as S}from"./index.js";import{t as C}from"./page-heading.js";import{t as w}from"./state-badge.js";import{n as T,t as E}from"./detail-row.js";import{a as D,c as O,i as k,l as A,o as j,r as M,s as N,t as P}from"./alert-dialog.js";import{t as F}from"./delete-confirmation-dialog.js";import{t as I}from"./use-copy-to-clipboard.js";var L=p(_()),R=x(),z=m();function B(e){let t=(0,R.c)(27),{onClose:n,accessKeyId:i,secretAccessKey:o}=e,{copied:s,copy:c}=I(),l;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(l=(0,z.jsxs)(N,{children:[(0,z.jsx)(O,{children:(0,z.jsx)(a,{className:`text-destructive`})}),(0,z.jsx)(A,{children:`Save Your Access Key`}),(0,z.jsx)(D,{children:`This is your only chance to view the secret access key. Please copy it now. You won't be able to retrieve it again.`})]}),t[0]=l):l=t[0];let u;t[1]===Symbol.for(`react.memo_cache_sentinel`)?(u=(0,z.jsx)(`span`,{className:`text-muted-foreground`,children:`Access Key ID: `}),t[1]=u):u=t[1];let d;t[2]===i?d=t[3]:(d=(0,z.jsxs)(`div`,{children:[u,i]}),t[2]=i,t[3]=d);let f;t[4]===Symbol.for(`react.memo_cache_sentinel`)?(f=(0,z.jsx)(`span`,{className:`text-muted-foreground`,children:`Secret Access Key: `}),t[4]=f):f=t[4];let p;t[5]===o?p=t[6]:(p=(0,z.jsxs)(`div`,{children:[f,o]}),t[5]=o,t[6]=p);let m;t[7]!==d||t[8]!==p?(m=(0,z.jsxs)(`div`,{className:`space-y-2 rounded-md border p-4 font-mono text-sm`,children:[d,p]}),t[7]=d,t[8]=p,t[9]=m):m=t[9];let h;t[10]!==i||t[11]!==c||t[12]!==o?(h=async()=>await c(`Access Key ID: ${i}\nSecret Access Key: ${o}`),t[10]=i,t[11]=c,t[12]=o,t[13]=h):h=t[13];let g;t[14]===s?g=t[15]:(g=s?(0,z.jsxs)(z.Fragment,{children:[(0,z.jsx)(r,{className:`mr-2 size-4`}),`Copied!`]}):`Copy to Clipboard`,t[14]=s,t[15]=g);let _;t[16]!==h||t[17]!==g?(_=(0,z.jsx)(S,{className:`w-full`,onClick:h,type:`button`,variant:`outline`,children:g}),t[16]=h,t[17]=g,t[18]=_):_=t[18];let v;t[19]!==m||t[20]!==_?(v=(0,z.jsxs)(`div`,{className:`space-y-3`,children:[m,_]}),t[19]=m,t[20]=_,t[21]=v):v=t[21];let y;t[22]===n?y=t[23]:(y=(0,z.jsx)(j,{children:(0,z.jsx)(M,{onClick:n,children:`Close and Continue`})}),t[22]=n,t[23]=y);let b;return t[24]!==v||t[25]!==y?(b=(0,z.jsx)(P,{open:!0,children:(0,z.jsxs)(k,{className:`max-w-2xl`,children:[l,v,y]})}),t[24]=v,t[25]=y,t[26]=b):b=t[26],b}function V(){let{userName:r}=v.useParams(),a=b(),{data:p}=t(ee(r)),{data:m}=t(g(r)),{data:_}=t(h(r)),{data:x}=t(y),D=u(),O=l(),k=o(),A=c(),j=d(),M=s(),[N,P]=(0,L.useState)(!1),[I,R]=(0,L.useState)(null),[V,H]=(0,L.useState)(!1),[U,W]=(0,L.useState)(null),[G,K]=(0,L.useState)(null),q=p.User,J=m.AccessKeyMetadata??[],Y=_.AttachedPolicies??[],X=x.Policies??[],Z=new Set(Y.map(e=>e.PolicyArn)),Q=X.filter(e=>e.Arn&&!Z.has(e.Arn)),te=async()=>{try{await D.mutateAsync(r),a({to:`/iam/list-users`})}finally{P(!1)}},$=async()=>{let e=await O.mutateAsync(r);e.AccessKey&&R({accessKeyId:e.AccessKey.AccessKeyId??``,secretAccessKey:e.AccessKey.SecretAccessKey??``})},ne=async e=>{if(e.AccessKeyId){W(e.AccessKeyId);try{await A.mutateAsync({userName:r,accessKeyId:e.AccessKeyId,status:e.Status===`Active`?`Inactive`:`Active`})}finally{W(null)}}},re=async e=>{W(e);try{await k.mutateAsync({userName:r,accessKeyId:e})}finally{W(null)}},ie=async e=>{await j.mutateAsync({userName:r,policyArn:e}),H(!1)},ae=async e=>{K(e);try{await M.mutateAsync({userName:r,policyArn:e})}finally{K(null)}};return q?(0,z.jsxs)(z.Fragment,{children:[(0,z.jsx)(n,{to:`/iam/list-users`,children:`Back to users`}),D.error&&(0,z.jsx)(e,{error:D.error,msg:`Failed to delete user`}),O.error&&(0,z.jsx)(e,{error:O.error,msg:`Failed to create access key`}),k.error&&(0,z.jsx)(e,{error:k.error,msg:`Failed to delete access key`}),j.error&&(0,z.jsx)(e,{error:j.error,msg:`Failed to attach policy`}),M.error&&(0,z.jsx)(e,{error:M.error,msg:`Failed to detach policy`}),(0,z.jsxs)(`div`,{className:`space-y-6`,children:[(0,z.jsx)(C,{actions:(0,z.jsxs)(S,{onClick:()=>P(!0),size:`sm`,variant:`destructive`,children:[(0,z.jsx)(i,{className:`size-4`}),`Delete`]}),subtitle:`User Details`,title:q.UserName??``}),(0,z.jsxs)(T,{children:[(0,z.jsx)(T.Header,{children:`User Information`}),(0,z.jsxs)(T.Content,{children:[(0,z.jsx)(E,{label:`User Name`,value:q.UserName}),(0,z.jsx)(E,{label:`User ID`,value:q.UserId}),(0,z.jsx)(E,{label:`ARN`,value:q.Arn}),(0,z.jsx)(E,{label:`Path`,value:q.Path}),(0,z.jsx)(E,{label:`Created`,value:f(q.CreateDate)})]})]}),(0,z.jsxs)(T,{children:[(0,z.jsx)(T.Header,{children:(0,z.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,z.jsx)(`span`,{children:`Access Keys`}),(0,z.jsx)(S,{disabled:O.isPending,onClick:$,size:`sm`,children:O.isPending?`Creating...`:`Create Access Key`})]})}),(0,z.jsx)(T.Content,{children:J.length>0?(0,z.jsx)(`div`,{className:`col-span-2 space-y-3`,children:J.map(e=>(0,z.jsxs)(`div`,{className:`flex items-center justify-between rounded-md border p-3`,children:[(0,z.jsxs)(`div`,{className:`space-y-1`,children:[(0,z.jsx)(`p`,{className:`font-mono text-sm`,children:e.AccessKeyId}),(0,z.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[`Created `,f(e.CreateDate)]})]}),(0,z.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,z.jsx)(w,{state:e.Status}),(0,z.jsx)(S,{disabled:U===e.AccessKeyId,onClick:async()=>await ne(e),size:`sm`,variant:`outline`,children:e.Status===`Active`?`Deactivate`:`Activate`}),(0,z.jsx)(S,{disabled:U===e.AccessKeyId,onClick:()=>{e.AccessKeyId&&re(e.AccessKeyId)},size:`sm`,variant:`destructive`,children:`Delete`})]})]},e.AccessKeyId))}):(0,z.jsx)(`p`,{className:`col-span-2 text-sm text-muted-foreground`,children:`No access keys.`})})]}),(0,z.jsxs)(T,{children:[(0,z.jsx)(T.Header,{children:(0,z.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,z.jsx)(`span`,{children:`Attached Policies`}),(0,z.jsx)(S,{onClick:()=>H(!V),size:`sm`,children:`Attach Policy`})]})}),(0,z.jsxs)(T.Content,{children:[V&&Q.length>0&&(0,z.jsxs)(`div`,{className:`col-span-2 space-y-2 rounded-md border p-3`,children:[(0,z.jsx)(`p`,{className:`text-sm font-medium`,children:`Select a policy to attach:`}),(0,z.jsx)(`div`,{className:`space-y-1`,children:Q.map(e=>(0,z.jsxs)(`button`,{className:`flex w-full items-center justify-between rounded-md p-2 text-left text-sm hover:bg-accent`,disabled:j.isPending,onClick:()=>{e.Arn&&ie(e.Arn)},type:`button`,children:[(0,z.jsx)(`span`,{children:e.PolicyName}),(0,z.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:e.Arn})]},e.Arn))})]}),V&&Q.length===0&&(0,z.jsx)(`p`,{className:`col-span-2 text-sm text-muted-foreground`,children:`No policies available to attach.`}),Y.length>0?(0,z.jsx)(`div`,{className:`col-span-2 space-y-3`,children:Y.map(e=>(0,z.jsxs)(`div`,{className:`flex items-center justify-between rounded-md border p-3`,children:[(0,z.jsxs)(`div`,{className:`space-y-1`,children:[(0,z.jsx)(`p`,{className:`text-sm font-medium`,children:e.PolicyName}),(0,z.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e.PolicyArn})]}),(0,z.jsx)(S,{disabled:G===e.PolicyArn,onClick:()=>{e.PolicyArn&&ae(e.PolicyArn)},size:`sm`,variant:`outline`,children:`Detach`})]},e.PolicyArn))}):(0,z.jsx)(`p`,{className:`col-span-2 text-sm text-muted-foreground`,children:`No attached policies.`})]})]})]}),(0,z.jsx)(F,{description:`Are you sure you want to delete the user "${r}"? This action cannot be undone. You must detach all policies and delete all access keys first.`,isPending:D.isPending,onConfirm:te,onOpenChange:P,open:N,title:`Delete User`}),I&&(0,z.jsx)(B,{accessKeyId:I.accessKeyId,onClose:()=>R(null),secretAccessKey:I.secretAccessKey})]}):(0,z.jsxs)(z.Fragment,{children:[(0,z.jsx)(n,{to:`/iam/list-users`,children:`Back to users`}),(0,z.jsx)(`p`,{className:`text-muted-foreground`,children:`User not found.`})]})}export{V as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/admin.js b/spinifex/services/spinifexui/frontend/dist/assets/admin.js index 281a9cf6c..a98cad8b9 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/admin.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/admin.js @@ -1 +1 @@ -import{Kn as e,fo as t,lr as n}from"./index.js";var r=t({queryKey:[`admin`,`nodes`],queryFn:async()=>{let t=n();if(!t)throw Error(`Not authenticated`);return await e({action:`GetNodes`,credentials:t})},staleTime:1e4}),i=t({queryKey:[`admin`,`vms`],queryFn:async()=>{let t=n();if(!t)throw Error(`Not authenticated`);return await e({action:`GetVMs`,credentials:t})},staleTime:1e4}),a=t({queryKey:[`admin`,`storageStatus`],queryFn:async()=>{let t=n();if(!t)throw Error(`Not authenticated`);return await e({action:`GetStorageStatus`,credentials:t})},staleTime:1e4});export{a as n,i as r,r as t}; \ No newline at end of file +import{Cr as e,Eo as t,or as n}from"./index.js";var r=t({queryKey:[`admin`,`nodes`],queryFn:async()=>{let t=e();if(!t)throw Error(`Not authenticated`);return await n({action:`GetNodes`,credentials:t})},staleTime:1e4}),i=t({queryKey:[`admin`,`vms`],queryFn:async()=>{let t=e();if(!t)throw Error(`Not authenticated`);return await n({action:`GetVMs`,credentials:t})},staleTime:1e4}),a=t({queryKey:[`admin`,`storageStatus`],queryFn:async()=>{let t=e();if(!t)throw Error(`Not authenticated`);return await n({action:`GetStorageStatus`,credentials:t})},staleTime:1e4});export{a as n,i as r,r as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/alert-dialog.js b/spinifex/services/spinifexui/frontend/dist/assets/alert-dialog.js index b892dcd45..24df68f46 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/alert-dialog.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/alert-dialog.js @@ -1 +1 @@ -import{Ci as e,Dr as t,Er as n,Lr as r,Oa as i,Or as a,Po as o,Pr as s,Si as c,Ta as l,_i as u,gi as d,ho as f,kr as p,mo as m,so as h,vi as g}from"./index.js";var _=o(f()),v=m();function y(n){let{children:r,open:i,defaultOpen:o=!1,onOpenChange:s,onOpenChangeComplete:l,actionsRef:u,handle:d,triggerId:f,defaultTriggerId:m=null}=n,h=e(!0),g=!!h,y=a.useStore(d?.store,{open:o,openProp:i,activeTriggerId:m,triggerIdProp:f,modal:!0,disablePointerDismissal:!0,nested:g,role:`alertdialog`});y.useControlledProp(`openProp`,i),y.useControlledProp(`triggerIdProp`,f),y.useSyncedValue(`nested`,g),y.useContextCallback(`onOpenChange`,s),y.useContextCallback(`onOpenChangeComplete`,l);let b=y.useState(`payload`);p({store:y,actionsRef:u,parentContext:h?.store.context,isDrawer:!1,onOpenChange:s,triggerIdProp:f});let x=_.useMemo(()=>({store:y}),[y]);return(0,v.jsx)(t.Provider,{value:!1,children:(0,v.jsx)(c.Provider,{value:x,children:typeof r==`function`?r({payload:b}):r})})}var b=h();function x(e){let t=(0,b.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,v.jsx)(y,{"data-slot":`alert-dialog`,...n}),t[2]=n,t[3]=r),r}function S(e){let t=(0,b.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,v.jsx)(s,{"data-slot":`alert-dialog-portal`,...n}),t[2]=n,t[3]=r),r}function C(e){let t=(0,b.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let a;t[3]===n?a=t[4]:(a=i(`data-closed:fade-out-0 data-open:fade-in-0 data-closed:animate-out data-open:animate-in fixed inset-0 isolate z-50 bg-black/80 duration-100 supports-backdrop-filter:backdrop-blur-xs`,n),t[3]=n,t[4]=a);let o;return t[5]!==r||t[6]!==a?(o=(0,v.jsx)(g,{className:a,"data-slot":`alert-dialog-overlay`,...r}),t[5]=r,t[6]=a,t[7]=o):o=t[7],o}function w(e){let t=(0,b.c)(11),n,a,o;t[0]===e?(n=t[1],a=t[2],o=t[3]):({className:n,size:o,...a}=e,t[0]=e,t[1]=n,t[2]=a,t[3]=o);let s=o===void 0?`default`:o,c;t[4]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,v.jsx)(C,{}),t[4]=c):c=t[4];let l;t[5]===n?l=t[6]:(l=i(`data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 group/alert-dialog-content data-closed:animate-out data-open:animate-in fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-3 rounded-xl bg-background p-4 ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-64 data-[size=default]:sm:max-w-sm`,n),t[5]=n,t[6]=l);let u;return t[7]!==a||t[8]!==s||t[9]!==l?(u=(0,v.jsxs)(S,{children:[c,(0,v.jsx)(r,{className:l,"data-size":s,"data-slot":`alert-dialog-content`,...a})]}),t[7]=a,t[8]=s,t[9]=l,t[10]=u):u=t[10],u}function T(e){let t=(0,b.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let a;t[3]===n?a=t[4]:(a=i(`grid grid-rows-[auto_1fr] place-items-center gap-1 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]`,n),t[3]=n,t[4]=a);let o;return t[5]!==r||t[6]!==a?(o=(0,v.jsx)(`div`,{className:a,"data-slot":`alert-dialog-header`,...r}),t[5]=r,t[6]=a,t[7]=o):o=t[7],o}function E(e){let t=(0,b.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let a;t[3]===n?a=t[4]:(a=i(`flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end`,n),t[3]=n,t[4]=a);let o;return t[5]!==r||t[6]!==a?(o=(0,v.jsx)(`div`,{className:a,"data-slot":`alert-dialog-footer`,...r}),t[5]=r,t[6]=a,t[7]=o):o=t[7],o}function D(e){let t=(0,b.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let a;t[3]===n?a=t[4]:(a=i(`mb-2 inline-flex size-8 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-4`,n),t[3]=n,t[4]=a);let o;return t[5]!==r||t[6]!==a?(o=(0,v.jsx)(`div`,{className:a,"data-slot":`alert-dialog-media`,...r}),t[5]=r,t[6]=a,t[7]=o):o=t[7],o}function O(e){let t=(0,b.c)(8),r,a;t[0]===e?(r=t[1],a=t[2]):({className:r,...a}=e,t[0]=e,t[1]=r,t[2]=a);let o;t[3]===r?o=t[4]:(o=i(`text-sm font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2`,r),t[3]=r,t[4]=o);let s;return t[5]!==a||t[6]!==o?(s=(0,v.jsx)(n,{className:o,"data-slot":`alert-dialog-title`,...a}),t[5]=a,t[6]=o,t[7]=s):s=t[7],s}function k(e){let t=(0,b.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let a;t[3]===n?a=t[4]:(a=i(`text-xs/relaxed text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground`,n),t[3]=n,t[4]=a);let o;return t[5]!==r||t[6]!==a?(o=(0,v.jsx)(d,{className:a,"data-slot":`alert-dialog-description`,...r}),t[5]=r,t[6]=a,t[7]=o):o=t[7],o}function A(e){let t=(0,b.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let a;t[3]===n?a=t[4]:(a=i(n),t[3]=n,t[4]=a);let o;return t[5]!==r||t[6]!==a?(o=(0,v.jsx)(l,{className:a,"data-slot":`alert-dialog-action`,...r}),t[5]=r,t[6]=a,t[7]=o):o=t[7],o}function j(e){let t=(0,b.c)(14),n,r,a,o;t[0]===e?(n=t[1],r=t[2],a=t[3],o=t[4]):({className:n,variant:a,size:o,...r}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=a,t[4]=o);let s=a===void 0?`outline`:a,c=o===void 0?`default`:o,d;t[5]===n?d=t[6]:(d=i(n),t[5]=n,t[6]=d);let f;t[7]!==c||t[8]!==s?(f=(0,v.jsx)(l,{size:c,variant:s}),t[7]=c,t[8]=s,t[9]=f):f=t[9];let p;return t[10]!==r||t[11]!==d||t[12]!==f?(p=(0,v.jsx)(u,{className:d,"data-slot":`alert-dialog-cancel`,render:f,...r}),t[10]=r,t[11]=d,t[12]=f,t[13]=p):p=t[13],p}export{k as a,D as c,w as i,O as l,A as n,E as o,j as r,T as s,x as t}; \ No newline at end of file +import{Ai as e,Br as t,Ha as n,Hr as r,Ii as i,Jo as a,Jr as o,Li as s,Mi as c,Oo as l,Ur as u,Vr as d,Zr as f,ji as p,ko as m,xo as h,za as g}from"./index.js";var _=a(m()),v=l();function y(e){let{children:t,open:n,defaultOpen:a=!1,onOpenChange:o,onOpenChangeComplete:c,actionsRef:l,handle:f,triggerId:p,defaultTriggerId:m=null}=e,h=s(!0),g=!!h,y=r.useStore(f?.store,{open:a,openProp:n,activeTriggerId:m,triggerIdProp:p,modal:!0,disablePointerDismissal:!0,nested:g,role:`alertdialog`});y.useControlledProp(`openProp`,n),y.useControlledProp(`triggerIdProp`,p),y.useSyncedValue(`nested`,g),y.useContextCallback(`onOpenChange`,o),y.useContextCallback(`onOpenChangeComplete`,c);let b=y.useState(`payload`);u({store:y,actionsRef:l,parentContext:h?.store.context,isDrawer:!1,onOpenChange:o,triggerIdProp:p});let x=_.useMemo(()=>({store:y}),[y]);return(0,v.jsx)(d.Provider,{value:!1,children:(0,v.jsx)(i.Provider,{value:x,children:typeof t==`function`?t({payload:b}):t})})}var b=h();function x(e){let t=(0,b.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,v.jsx)(y,{"data-slot":`alert-dialog`,...n}),t[2]=n,t[3]=r),r}function S(e){let t=(0,b.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,v.jsx)(o,{"data-slot":`alert-dialog-portal`,...n}),t[2]=n,t[3]=r),r}function C(e){let t=(0,b.c)(8),r,i;t[0]===e?(r=t[1],i=t[2]):({className:r,...i}=e,t[0]=e,t[1]=r,t[2]=i);let a;t[3]===r?a=t[4]:(a=n(`data-closed:fade-out-0 data-open:fade-in-0 data-closed:animate-out data-open:animate-in fixed inset-0 isolate z-50 bg-black/80 duration-100 supports-backdrop-filter:backdrop-blur-xs`,r),t[3]=r,t[4]=a);let o;return t[5]!==i||t[6]!==a?(o=(0,v.jsx)(c,{className:a,"data-slot":`alert-dialog-overlay`,...i}),t[5]=i,t[6]=a,t[7]=o):o=t[7],o}function w(e){let t=(0,b.c)(11),r,i,a;t[0]===e?(r=t[1],i=t[2],a=t[3]):({className:r,size:a,...i}=e,t[0]=e,t[1]=r,t[2]=i,t[3]=a);let o=a===void 0?`default`:a,s;t[4]===Symbol.for(`react.memo_cache_sentinel`)?(s=(0,v.jsx)(C,{}),t[4]=s):s=t[4];let c;t[5]===r?c=t[6]:(c=n(`data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 group/alert-dialog-content data-closed:animate-out data-open:animate-in fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-3 rounded-xl bg-background p-4 ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-64 data-[size=default]:sm:max-w-sm`,r),t[5]=r,t[6]=c);let l;return t[7]!==i||t[8]!==o||t[9]!==c?(l=(0,v.jsxs)(S,{children:[s,(0,v.jsx)(f,{className:c,"data-size":o,"data-slot":`alert-dialog-content`,...i})]}),t[7]=i,t[8]=o,t[9]=c,t[10]=l):l=t[10],l}function T(e){let t=(0,b.c)(8),r,i;t[0]===e?(r=t[1],i=t[2]):({className:r,...i}=e,t[0]=e,t[1]=r,t[2]=i);let a;t[3]===r?a=t[4]:(a=n(`grid grid-rows-[auto_1fr] place-items-center gap-1 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]`,r),t[3]=r,t[4]=a);let o;return t[5]!==i||t[6]!==a?(o=(0,v.jsx)(`div`,{className:a,"data-slot":`alert-dialog-header`,...i}),t[5]=i,t[6]=a,t[7]=o):o=t[7],o}function E(e){let t=(0,b.c)(8),r,i;t[0]===e?(r=t[1],i=t[2]):({className:r,...i}=e,t[0]=e,t[1]=r,t[2]=i);let a;t[3]===r?a=t[4]:(a=n(`flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end`,r),t[3]=r,t[4]=a);let o;return t[5]!==i||t[6]!==a?(o=(0,v.jsx)(`div`,{className:a,"data-slot":`alert-dialog-footer`,...i}),t[5]=i,t[6]=a,t[7]=o):o=t[7],o}function D(e){let t=(0,b.c)(8),r,i;t[0]===e?(r=t[1],i=t[2]):({className:r,...i}=e,t[0]=e,t[1]=r,t[2]=i);let a;t[3]===r?a=t[4]:(a=n(`mb-2 inline-flex size-8 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-4`,r),t[3]=r,t[4]=a);let o;return t[5]!==i||t[6]!==a?(o=(0,v.jsx)(`div`,{className:a,"data-slot":`alert-dialog-media`,...i}),t[5]=i,t[6]=a,t[7]=o):o=t[7],o}function O(e){let r=(0,b.c)(8),i,a;r[0]===e?(i=r[1],a=r[2]):({className:i,...a}=e,r[0]=e,r[1]=i,r[2]=a);let o;r[3]===i?o=r[4]:(o=n(`text-sm font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2`,i),r[3]=i,r[4]=o);let s;return r[5]!==a||r[6]!==o?(s=(0,v.jsx)(t,{className:o,"data-slot":`alert-dialog-title`,...a}),r[5]=a,r[6]=o,r[7]=s):s=r[7],s}function k(t){let r=(0,b.c)(8),i,a;r[0]===t?(i=r[1],a=r[2]):({className:i,...a}=t,r[0]=t,r[1]=i,r[2]=a);let o;r[3]===i?o=r[4]:(o=n(`text-xs/relaxed text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground`,i),r[3]=i,r[4]=o);let s;return r[5]!==a||r[6]!==o?(s=(0,v.jsx)(e,{className:o,"data-slot":`alert-dialog-description`,...a}),r[5]=a,r[6]=o,r[7]=s):s=r[7],s}function A(e){let t=(0,b.c)(8),r,i;t[0]===e?(r=t[1],i=t[2]):({className:r,...i}=e,t[0]=e,t[1]=r,t[2]=i);let a;t[3]===r?a=t[4]:(a=n(r),t[3]=r,t[4]=a);let o;return t[5]!==i||t[6]!==a?(o=(0,v.jsx)(g,{className:a,"data-slot":`alert-dialog-action`,...i}),t[5]=i,t[6]=a,t[7]=o):o=t[7],o}function j(e){let t=(0,b.c)(14),r,i,a,o;t[0]===e?(r=t[1],i=t[2],a=t[3],o=t[4]):({className:r,variant:a,size:o,...i}=e,t[0]=e,t[1]=r,t[2]=i,t[3]=a,t[4]=o);let s=a===void 0?`outline`:a,c=o===void 0?`default`:o,l;t[5]===r?l=t[6]:(l=n(r),t[5]=r,t[6]=l);let u;t[7]!==c||t[8]!==s?(u=(0,v.jsx)(g,{size:c,variant:s}),t[7]=c,t[8]=s,t[9]=u):u=t[9];let d;return t[10]!==i||t[11]!==l||t[12]!==u?(d=(0,v.jsx)(p,{className:l,"data-slot":`alert-dialog-cancel`,render:u,...i}),t[10]=i,t[11]=l,t[12]=u,t[13]=d):d=t[13],d}export{k as a,D as c,w as i,O as l,A as n,E as o,j as r,T as s,x as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/ami-details.js b/spinifex/services/spinifexui/frontend/dist/assets/ami-details.js index 4eb33a3a4..facf4af24 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/ami-details.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/ami-details.js @@ -1 +1 @@ -import{ja as e,lo as t,mo as n,so as r}from"./index.js";import{n as i,t as a}from"./detail-row.js";var o=r(),s=n();function c(n){let r=(0,o.c)(58),{image:c,showExtendedDetails:u}=n,d=u===void 0?!1:u,f;r[0]===c.CreationDate?f=r[1]:(f=e(c.CreationDate),r[0]=c.CreationDate,r[1]=f);let p=f,m=d?`AMI Information`:`AMI Details`,h;r[2]===m?h=r[3]:(h=(0,s.jsx)(i.Header,{children:m}),r[2]=m,r[3]=h);let g;r[4]!==c.ImageId||r[5]!==d?(g=c.ImageId&&!d?(0,s.jsx)(t,{className:`text-primary hover:underline`,params:{id:c.ImageId},to:`/ec2/describe-images/$id`,children:c.ImageId}):c.ImageId,r[4]=c.ImageId,r[5]=d,r[6]=g):g=r[6];let _;r[7]===g?_=r[8]:(_=(0,s.jsx)(a,{label:`AMI ID`,value:g}),r[7]=g,r[8]=_);let v;r[9]===c.Name?v=r[10]:(v=(0,s.jsx)(a,{label:`AMI Name`,value:c.Name}),r[9]=c.Name,r[10]=v);let y;r[11]===c.Description?y=r[12]:(y=(0,s.jsx)(a,{label:`Description`,value:c.Description}),r[11]=c.Description,r[12]=y);let b;r[13]===c.Architecture?b=r[14]:(b=(0,s.jsx)(a,{label:`Architecture`,value:c.Architecture}),r[13]=c.Architecture,r[14]=b);let x;r[15]===c.VirtualizationType?x=r[16]:(x=(0,s.jsx)(a,{label:`Virtualization Type`,value:c.VirtualizationType}),r[15]=c.VirtualizationType,r[16]=x);let S=c.Platform??`Linux`,C;r[17]===S?C=r[18]:(C=(0,s.jsx)(a,{label:`Platform`,value:S}),r[17]=S,r[18]=C);let w;r[19]===c.PlatformDetails?w=r[20]:(w=(0,s.jsx)(a,{label:`Platform Details`,value:c.PlatformDetails}),r[19]=c.PlatformDetails,r[20]=w);let T;r[21]===c.ImageType?T=r[22]:(T=(0,s.jsx)(a,{label:`Image Type`,value:c.ImageType}),r[21]=c.ImageType,r[22]=T);let E;r[23]===c.RootDeviceType?E=r[24]:(E=(0,s.jsx)(a,{label:`Root Device Type`,value:c.RootDeviceType}),r[23]=c.RootDeviceType,r[24]=E);let D;r[25]===c.RootDeviceName?D=r[26]:(D=(0,s.jsx)(a,{label:`Root Device Name`,value:c.RootDeviceName}),r[25]=c.RootDeviceName,r[26]=D);let O;r[27]===c.OwnerId?O=r[28]:(O=(0,s.jsx)(a,{label:`Owner`,value:c.OwnerId}),r[27]=c.OwnerId,r[28]=O);let k;r[29]===c.State?k=r[30]:(k=(0,s.jsx)(a,{label:`State`,value:c.State}),r[29]=c.State,r[30]=k);let A;r[31]!==p||r[32]!==c.Public||r[33]!==d?(A=d&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a,{label:`Creation Date`,value:p}),(0,s.jsx)(a,{label:`Public`,value:c.Public?`Yes`:`No`})]}),r[31]=p,r[32]=c.Public,r[33]=d,r[34]=A):A=r[34];let j;r[35]!==x||r[36]!==C||r[37]!==w||r[38]!==T||r[39]!==E||r[40]!==D||r[41]!==O||r[42]!==k||r[43]!==A||r[44]!==_||r[45]!==v||r[46]!==y||r[47]!==b?(j=(0,s.jsxs)(i.Content,{children:[_,v,y,b,x,C,w,T,E,D,O,k,A]}),r[35]=x,r[36]=C,r[37]=w,r[38]=T,r[39]=E,r[40]=D,r[41]=O,r[42]=k,r[43]=A,r[44]=_,r[45]=v,r[46]=y,r[47]=b,r[48]=j):j=r[48];let M;r[49]!==j||r[50]!==h?(M=(0,s.jsxs)(i,{children:[h,j]}),r[49]=j,r[50]=h,r[51]=M):M=r[51];let N;r[52]!==c.BlockDeviceMappings||r[53]!==d?(N=d&&c.BlockDeviceMappings&&c.BlockDeviceMappings.length>0&&c.BlockDeviceMappings.map(l),r[52]=c.BlockDeviceMappings,r[53]=d,r[54]=N):N=r[54];let P;return r[55]!==M||r[56]!==N?(P=(0,s.jsxs)(s.Fragment,{children:[M,N]}),r[55]=M,r[56]=N,r[57]=P):P=r[57],P}function l(e){return(0,s.jsxs)(i,{children:[(0,s.jsxs)(i.Header,{children:[`Block Device: `,e.DeviceName]}),(0,s.jsxs)(i.Content,{children:[(0,s.jsx)(a,{label:`Device Name`,value:e.DeviceName}),e.Ebs&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a,{label:`Volume Size`,value:e.Ebs.VolumeSize?`${e.Ebs.VolumeSize} GB`:void 0}),(0,s.jsx)(a,{label:`Volume Type`,value:e.Ebs.VolumeType}),(0,s.jsx)(a,{label:`Delete On Termination`,value:e.Ebs.DeleteOnTermination?`Yes`:`No`}),(0,s.jsx)(a,{label:`Encrypted`,value:e.Ebs.Encrypted?`Yes`:`No`}),e.Ebs.SnapshotId&&(0,s.jsx)(a,{label:`Snapshot ID`,value:(0,s.jsx)(t,{className:`text-primary hover:underline`,params:{id:e.Ebs.SnapshotId},to:`/ec2/describe-snapshots/$id`,children:e.Ebs.SnapshotId})})]}),e.VirtualName&&(0,s.jsx)(a,{label:`Virtual Name`,value:e.VirtualName})]})]},e.DeviceName)}export{c as t}; \ No newline at end of file +import{Co as e,Ga as t,Oo as n,xo as r}from"./index.js";import{n as i,t as a}from"./detail-row.js";var o=r(),s=n();function c(n){let r=(0,o.c)(58),{image:c,showExtendedDetails:u}=n,d=u===void 0?!1:u,f;r[0]===c.CreationDate?f=r[1]:(f=t(c.CreationDate),r[0]=c.CreationDate,r[1]=f);let p=f,m=d?`AMI Information`:`AMI Details`,h;r[2]===m?h=r[3]:(h=(0,s.jsx)(i.Header,{children:m}),r[2]=m,r[3]=h);let g;r[4]!==c.ImageId||r[5]!==d?(g=c.ImageId&&!d?(0,s.jsx)(e,{className:`text-primary hover:underline`,params:{id:c.ImageId},to:`/ec2/describe-images/$id`,children:c.ImageId}):c.ImageId,r[4]=c.ImageId,r[5]=d,r[6]=g):g=r[6];let _;r[7]===g?_=r[8]:(_=(0,s.jsx)(a,{label:`AMI ID`,value:g}),r[7]=g,r[8]=_);let v;r[9]===c.Name?v=r[10]:(v=(0,s.jsx)(a,{label:`AMI Name`,value:c.Name}),r[9]=c.Name,r[10]=v);let y;r[11]===c.Description?y=r[12]:(y=(0,s.jsx)(a,{label:`Description`,value:c.Description}),r[11]=c.Description,r[12]=y);let b;r[13]===c.Architecture?b=r[14]:(b=(0,s.jsx)(a,{label:`Architecture`,value:c.Architecture}),r[13]=c.Architecture,r[14]=b);let x;r[15]===c.VirtualizationType?x=r[16]:(x=(0,s.jsx)(a,{label:`Virtualization Type`,value:c.VirtualizationType}),r[15]=c.VirtualizationType,r[16]=x);let S=c.Platform??`Linux`,C;r[17]===S?C=r[18]:(C=(0,s.jsx)(a,{label:`Platform`,value:S}),r[17]=S,r[18]=C);let w;r[19]===c.PlatformDetails?w=r[20]:(w=(0,s.jsx)(a,{label:`Platform Details`,value:c.PlatformDetails}),r[19]=c.PlatformDetails,r[20]=w);let T;r[21]===c.ImageType?T=r[22]:(T=(0,s.jsx)(a,{label:`Image Type`,value:c.ImageType}),r[21]=c.ImageType,r[22]=T);let E;r[23]===c.RootDeviceType?E=r[24]:(E=(0,s.jsx)(a,{label:`Root Device Type`,value:c.RootDeviceType}),r[23]=c.RootDeviceType,r[24]=E);let D;r[25]===c.RootDeviceName?D=r[26]:(D=(0,s.jsx)(a,{label:`Root Device Name`,value:c.RootDeviceName}),r[25]=c.RootDeviceName,r[26]=D);let O;r[27]===c.OwnerId?O=r[28]:(O=(0,s.jsx)(a,{label:`Owner`,value:c.OwnerId}),r[27]=c.OwnerId,r[28]=O);let k;r[29]===c.State?k=r[30]:(k=(0,s.jsx)(a,{label:`State`,value:c.State}),r[29]=c.State,r[30]=k);let A;r[31]!==p||r[32]!==c.Public||r[33]!==d?(A=d&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a,{label:`Creation Date`,value:p}),(0,s.jsx)(a,{label:`Public`,value:c.Public?`Yes`:`No`})]}),r[31]=p,r[32]=c.Public,r[33]=d,r[34]=A):A=r[34];let j;r[35]!==x||r[36]!==C||r[37]!==w||r[38]!==T||r[39]!==E||r[40]!==D||r[41]!==O||r[42]!==k||r[43]!==A||r[44]!==_||r[45]!==v||r[46]!==y||r[47]!==b?(j=(0,s.jsxs)(i.Content,{children:[_,v,y,b,x,C,w,T,E,D,O,k,A]}),r[35]=x,r[36]=C,r[37]=w,r[38]=T,r[39]=E,r[40]=D,r[41]=O,r[42]=k,r[43]=A,r[44]=_,r[45]=v,r[46]=y,r[47]=b,r[48]=j):j=r[48];let M;r[49]!==j||r[50]!==h?(M=(0,s.jsxs)(i,{children:[h,j]}),r[49]=j,r[50]=h,r[51]=M):M=r[51];let N;r[52]!==c.BlockDeviceMappings||r[53]!==d?(N=d&&c.BlockDeviceMappings&&c.BlockDeviceMappings.length>0&&c.BlockDeviceMappings.map(l),r[52]=c.BlockDeviceMappings,r[53]=d,r[54]=N):N=r[54];let P;return r[55]!==M||r[56]!==N?(P=(0,s.jsxs)(s.Fragment,{children:[M,N]}),r[55]=M,r[56]=N,r[57]=P):P=r[57],P}function l(t){return(0,s.jsxs)(i,{children:[(0,s.jsxs)(i.Header,{children:[`Block Device: `,t.DeviceName]}),(0,s.jsxs)(i.Content,{children:[(0,s.jsx)(a,{label:`Device Name`,value:t.DeviceName}),t.Ebs&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a,{label:`Volume Size`,value:t.Ebs.VolumeSize?`${t.Ebs.VolumeSize} GB`:void 0}),(0,s.jsx)(a,{label:`Volume Type`,value:t.Ebs.VolumeType}),(0,s.jsx)(a,{label:`Delete On Termination`,value:t.Ebs.DeleteOnTermination?`Yes`:`No`}),(0,s.jsx)(a,{label:`Encrypted`,value:t.Ebs.Encrypted?`Yes`:`No`}),t.Ebs.SnapshotId&&(0,s.jsx)(a,{label:`Snapshot ID`,value:(0,s.jsx)(e,{className:`text-primary hover:underline`,params:{id:t.Ebs.SnapshotId},to:`/ec2/describe-snapshots/$id`,children:t.Ebs.SnapshotId})})]}),t.VirtualName&&(0,s.jsx)(a,{label:`Virtual Name`,value:t.VirtualName})]})]},t.DeviceName)}export{c as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/back-link.js b/spinifex/services/spinifexui/frontend/dist/assets/back-link.js index 042afaa6d..3ecdf1f7f 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/back-link.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/back-link.js @@ -1 +1 @@ -import{Xa as e,lo as t,mo as n,so as r}from"./index.js";var i=e(`arrow-left`,[[`path`,{d:`m12 19-7-7 7-7`,key:`1l729n`}],[`path`,{d:`M19 12H5`,key:`x3x0zl`}]]),a=r(),o=n();function s(e){let n=(0,a.c)(7),r,s;n[0]===e?(r=n[1],s=n[2]):({children:r,...s}=e,n[0]=e,n[1]=r,n[2]=s);let c;n[3]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,o.jsx)(i,{className:`size-4`}),n[3]=c):c=n[3];let l;return n[4]!==r||n[5]!==s?(l=(0,o.jsxs)(t,{className:`mb-6 inline-flex items-center gap-2 text-sm`,...s,children:[c,r]}),n[4]=r,n[5]=s,n[6]=l):l=n[6],l}export{s as t}; \ No newline at end of file +import{Co as e,Oo as t,uo as n,xo as r}from"./index.js";var i=n(`arrow-left`,[[`path`,{d:`m12 19-7-7 7-7`,key:`1l729n`}],[`path`,{d:`M19 12H5`,key:`x3x0zl`}]]),a=r(),o=t();function s(t){let n=(0,a.c)(7),r,s;n[0]===t?(r=n[1],s=n[2]):({children:r,...s}=t,n[0]=t,n[1]=r,n[2]=s);let c;n[3]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,o.jsx)(i,{className:`size-4`}),n[3]=c):c=n[3];let l;return n[4]!==r||n[5]!==s?(l=(0,o.jsxs)(e,{className:`mb-6 inline-flex items-center gap-2 text-sm`,...s,children:[c,r]}),n[4]=r,n[5]=s,n[6]=l):l=n[6],l}export{s as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/badge.js b/spinifex/services/spinifexui/frontend/dist/assets/badge.js index 96f059147..3a02afd31 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/badge.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/badge.js @@ -1 +1 @@ -import{Oa as e,Qa as t,Za as n,oo as r,so as i}from"./index.js";var a=i(),o=n(`group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2 py-0.5 text-[0.625rem] font-medium whitespace-nowrap transition-all transition-colors focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-2.5!`,{variants:{variant:{default:`bg-primary text-primary-foreground [a]:hover:bg-primary/80`,secondary:`bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80`,destructive:`bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20`,outline:`border-border bg-input/20 text-foreground dark:bg-input/30 [a]:hover:bg-muted [a]:hover:text-muted-foreground`,ghost:`hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50`,link:`text-primary underline-offset-4 hover:underline`}},defaultVariants:{variant:`default`}});function s(n){let i=(0,a.c)(13),s,c,l,u,d;if(i[0]!==n){let{className:a,variant:f,render:p,...m}=n;s=p,d=f===void 0?`default`:f,u=t,c=`span`,l=r({className:e(o({className:a,variant:d}))},m),i[0]=n,i[1]=s,i[2]=c,i[3]=l,i[4]=u,i[5]=d}else s=i[1],c=i[2],l=i[3],u=i[4],d=i[5];let f;i[6]===d?f=i[7]:(f={slot:`badge`,variant:d},i[6]=d,i[7]=f);let p;return i[8]!==s||i[9]!==c||i[10]!==l||i[11]!==f?(p={defaultTagName:c,props:l,render:s,state:f},i[8]=s,i[9]=c,i[10]=l,i[11]=f,i[12]=p):p=i[12],u(p)}export{s as t}; \ No newline at end of file +import{Ha as e,bo as t,do as n,fo as r,xo as i}from"./index.js";var a=i(),o=n(`group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2 py-0.5 text-[0.625rem] font-medium whitespace-nowrap transition-all transition-colors focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-2.5!`,{variants:{variant:{default:`bg-primary text-primary-foreground [a]:hover:bg-primary/80`,secondary:`bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80`,destructive:`bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20`,outline:`border-border bg-input/20 text-foreground dark:bg-input/30 [a]:hover:bg-muted [a]:hover:text-muted-foreground`,ghost:`hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50`,link:`text-primary underline-offset-4 hover:underline`}},defaultVariants:{variant:`default`}});function s(n){let i=(0,a.c)(13),s,c,l,u,d;if(i[0]!==n){let{className:a,variant:f,render:p,...m}=n;s=p,d=f===void 0?`default`:f,u=r,c=`span`,l=t({className:e(o({className:a,variant:d}))},m),i[0]=n,i[1]=s,i[2]=c,i[3]=l,i[4]=u,i[5]=d}else s=i[1],c=i[2],l=i[3],u=i[4],d=i[5];let f;i[6]===d?f=i[7]:(f={slot:`badge`,variant:d},i[6]=d,i[7]=f);let p;return i[8]!==s||i[9]!==c||i[10]!==l||i[11]!==f?(p={defaultTagName:c,props:l,render:s,state:f},i[8]=s,i[9]=c,i[10]=l,i[11]=f,i[12]=p):p=i[12],u(p)}export{s as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/card.js b/spinifex/services/spinifexui/frontend/dist/assets/card.js index 76accc139..05cc04685 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/card.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/card.js @@ -1 +1 @@ -import{Oa as e,mo as t,so as n}from"./index.js";var r=n(),i=t();function a(t){let n=(0,r.c)(10),a,o,s;n[0]===t?(a=n[1],o=n[2],s=n[3]):({className:a,size:s,...o}=t,n[0]=t,n[1]=a,n[2]=o,n[3]=s);let c=s===void 0?`default`:s,l;n[4]===a?l=n[5]:(l=e(`group/card flex flex-col gap-4 overflow-hidden rounded-lg bg-card py-4 text-xs/relaxed text-card-foreground ring-1 ring-foreground/10 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 *:[img:first-child]:rounded-t-lg *:[img:last-child]:rounded-b-lg`,a),n[4]=a,n[5]=l);let u;return n[6]!==o||n[7]!==c||n[8]!==l?(u=(0,i.jsx)(`div`,{className:l,"data-size":c,"data-slot":`card`,...o}),n[6]=o,n[7]=c,n[8]=l,n[9]=u):u=n[9],u}function o(t){let n=(0,r.c)(8),a,o;n[0]===t?(a=n[1],o=n[2]):({className:a,...o}=t,n[0]=t,n[1]=a,n[2]=o);let s;n[3]===a?s=n[4]:(s=e(`group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-lg px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3`,a),n[3]=a,n[4]=s);let c;return n[5]!==o||n[6]!==s?(c=(0,i.jsx)(`div`,{className:s,"data-slot":`card-header`,...o}),n[5]=o,n[6]=s,n[7]=c):c=n[7],c}function s(t){let n=(0,r.c)(8),a,o;n[0]===t?(a=n[1],o=n[2]):({className:a,...o}=t,n[0]=t,n[1]=a,n[2]=o);let s;n[3]===a?s=n[4]:(s=e(`text-sm font-medium`,a),n[3]=a,n[4]=s);let c;return n[5]!==o||n[6]!==s?(c=(0,i.jsx)(`div`,{className:s,"data-slot":`card-title`,...o}),n[5]=o,n[6]=s,n[7]=c):c=n[7],c}function c(t){let n=(0,r.c)(8),a,o;n[0]===t?(a=n[1],o=n[2]):({className:a,...o}=t,n[0]=t,n[1]=a,n[2]=o);let s;n[3]===a?s=n[4]:(s=e(`col-start-2 row-span-2 row-start-1 self-start justify-self-end`,a),n[3]=a,n[4]=s);let c;return n[5]!==o||n[6]!==s?(c=(0,i.jsx)(`div`,{className:s,"data-slot":`card-action`,...o}),n[5]=o,n[6]=s,n[7]=c):c=n[7],c}function l(t){let n=(0,r.c)(8),a,o;n[0]===t?(a=n[1],o=n[2]):({className:a,...o}=t,n[0]=t,n[1]=a,n[2]=o);let s;n[3]===a?s=n[4]:(s=e(`px-4 group-data-[size=sm]/card:px-3`,a),n[3]=a,n[4]=s);let c;return n[5]!==o||n[6]!==s?(c=(0,i.jsx)(`div`,{className:s,"data-slot":`card-content`,...o}),n[5]=o,n[6]=s,n[7]=c):c=n[7],c}function u(t){let n=(0,r.c)(8),a,o;n[0]===t?(a=n[1],o=n[2]):({className:a,...o}=t,n[0]=t,n[1]=a,n[2]=o);let s;n[3]===a?s=n[4]:(s=e(`flex items-center rounded-b-lg px-4 group-data-[size=sm]/card:px-3 [.border-t]:pt-4 group-data-[size=sm]/card:[.border-t]:pt-3`,a),n[3]=a,n[4]=s);let c;return n[5]!==o||n[6]!==s?(c=(0,i.jsx)(`div`,{className:s,"data-slot":`card-footer`,...o}),n[5]=o,n[6]=s,n[7]=c):c=n[7],c}export{o as a,u as i,c as n,s as o,l as r,a as t}; \ No newline at end of file +import{Ha as e,Oo as t,xo as n}from"./index.js";var r=n(),i=t();function a(t){let n=(0,r.c)(10),a,o,s;n[0]===t?(a=n[1],o=n[2],s=n[3]):({className:a,size:s,...o}=t,n[0]=t,n[1]=a,n[2]=o,n[3]=s);let c=s===void 0?`default`:s,l;n[4]===a?l=n[5]:(l=e(`group/card flex flex-col gap-4 overflow-hidden rounded-lg bg-card py-4 text-xs/relaxed text-card-foreground ring-1 ring-foreground/10 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 *:[img:first-child]:rounded-t-lg *:[img:last-child]:rounded-b-lg`,a),n[4]=a,n[5]=l);let u;return n[6]!==o||n[7]!==c||n[8]!==l?(u=(0,i.jsx)(`div`,{className:l,"data-size":c,"data-slot":`card`,...o}),n[6]=o,n[7]=c,n[8]=l,n[9]=u):u=n[9],u}function o(t){let n=(0,r.c)(8),a,o;n[0]===t?(a=n[1],o=n[2]):({className:a,...o}=t,n[0]=t,n[1]=a,n[2]=o);let s;n[3]===a?s=n[4]:(s=e(`group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-lg px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3`,a),n[3]=a,n[4]=s);let c;return n[5]!==o||n[6]!==s?(c=(0,i.jsx)(`div`,{className:s,"data-slot":`card-header`,...o}),n[5]=o,n[6]=s,n[7]=c):c=n[7],c}function s(t){let n=(0,r.c)(8),a,o;n[0]===t?(a=n[1],o=n[2]):({className:a,...o}=t,n[0]=t,n[1]=a,n[2]=o);let s;n[3]===a?s=n[4]:(s=e(`text-sm font-medium`,a),n[3]=a,n[4]=s);let c;return n[5]!==o||n[6]!==s?(c=(0,i.jsx)(`div`,{className:s,"data-slot":`card-title`,...o}),n[5]=o,n[6]=s,n[7]=c):c=n[7],c}function c(t){let n=(0,r.c)(8),a,o;n[0]===t?(a=n[1],o=n[2]):({className:a,...o}=t,n[0]=t,n[1]=a,n[2]=o);let s;n[3]===a?s=n[4]:(s=e(`col-start-2 row-span-2 row-start-1 self-start justify-self-end`,a),n[3]=a,n[4]=s);let c;return n[5]!==o||n[6]!==s?(c=(0,i.jsx)(`div`,{className:s,"data-slot":`card-action`,...o}),n[5]=o,n[6]=s,n[7]=c):c=n[7],c}function l(t){let n=(0,r.c)(8),a,o;n[0]===t?(a=n[1],o=n[2]):({className:a,...o}=t,n[0]=t,n[1]=a,n[2]=o);let s;n[3]===a?s=n[4]:(s=e(`px-4 group-data-[size=sm]/card:px-3`,a),n[3]=a,n[4]=s);let c;return n[5]!==o||n[6]!==s?(c=(0,i.jsx)(`div`,{className:s,"data-slot":`card-content`,...o}),n[5]=o,n[6]=s,n[7]=c):c=n[7],c}function u(t){let n=(0,r.c)(8),a,o;n[0]===t?(a=n[1],o=n[2]):({className:a,...o}=t,n[0]=t,n[1]=a,n[2]=o);let s;n[3]===a?s=n[4]:(s=e(`flex items-center rounded-b-lg px-4 group-data-[size=sm]/card:px-3 [.border-t]:pt-4 group-data-[size=sm]/card:[.border-t]:pt-3`,a),n[3]=a,n[4]=s);let c;return n[5]!==o||n[6]!==s?(c=(0,i.jsx)(`div`,{className:s,"data-slot":`card-footer`,...o}),n[5]=o,n[6]=s,n[7]=c):c=n[7],c}export{o as a,u as i,c as n,s as o,l as r,a as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/check.js b/spinifex/services/spinifexui/frontend/dist/assets/check.js index b790b4fbd..cf8796197 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/check.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/check.js @@ -1 +1 @@ -import{Xa as e}from"./index.js";var t=e(`check`,[[`path`,{d:`M20 6 9 17l-5-5`,key:`1gmf2c`}]]);export{t}; \ No newline at end of file +import{uo as e}from"./index.js";var t=e(`check`,[[`path`,{d:`M20 6 9 17l-5-5`,key:`1gmf2c`}]]);export{t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/chevron-down.js b/spinifex/services/spinifexui/frontend/dist/assets/chevron-down.js index 2d19e2900..5104df886 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/chevron-down.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/chevron-down.js @@ -1 +1 @@ -import{Xa as e}from"./index.js";var t=e(`chevron-down`,[[`path`,{d:`m6 9 6 6 6-6`,key:`qrunsl`}]]);export{t}; \ No newline at end of file +import{uo as e}from"./index.js";var t=e(`chevron-down`,[[`path`,{d:`m6 9 6 6 6-6`,key:`qrunsl`}]]);export{t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/chevron-right.js b/spinifex/services/spinifexui/frontend/dist/assets/chevron-right.js index e50426e6d..50690ad5f 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/chevron-right.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/chevron-right.js @@ -1 +1 @@ -import{Xa as e}from"./index.js";var t=e(`chevron-right`,[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]]);export{t}; \ No newline at end of file +import{uo as e}from"./index.js";var t=e(`chevron-right`,[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]]);export{t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/cli-command-panel.js b/spinifex/services/spinifexui/frontend/dist/assets/cli-command-panel.js index 904fd3b0e..2dd355c6c 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/cli-command-panel.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/cli-command-panel.js @@ -1,3 +1,3 @@ -import{t as e}from"./check.js";import{t}from"./chevron-down.js";import{t as n}from"./copy.js";import{Oa as r,Po as i,Ta as a,Xa as o,ho as s,mo as c,so as l}from"./index.js";import{t as u}from"./use-copy-to-clipboard.js";var d=o(`square-terminal`,[[`path`,{d:`m7 11 2-2-2-2`,key:`1lz0vl`}],[`path`,{d:`M11 13h4`,key:`1p7l4v`}],[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}]]),f=l(),p=i(s(),1),m=c(),h={bin:`text-tactical-cyan font-semibold`,flag:`text-tactical-amber`,value:`text-foreground`,comment:`text-muted-foreground italic`,variable:`text-tactical-green font-semibold`};function g(e){return e.map(e=>e.parts.map(e=>e.value).join(``)).join(` +import{t as e}from"./check.js";import{t}from"./chevron-down.js";import{t as n}from"./copy.js";import{Ha as r,Jo as i,Oo as a,ko as o,uo as s,xo as c,za as l}from"./index.js";import{t as u}from"./use-copy-to-clipboard.js";var d=s(`square-terminal`,[[`path`,{d:`m7 11 2-2-2-2`,key:`1lz0vl`}],[`path`,{d:`M11 13h4`,key:`1p7l4v`}],[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}]]),f=c(),p=i(o(),1),m=a(),h={bin:`text-tactical-cyan font-semibold`,flag:`text-tactical-amber`,value:`text-foreground`,comment:`text-muted-foreground italic`,variable:`text-tactical-green font-semibold`};function g(e){return e.map(e=>e.parts.map(e=>e.value).join(``)).join(` -`)}function _(i){let o=(0,f.c)(18),{commands:s}=i,[c,l]=(0,p.useState)(!1),{copied:h,copy:_}=u();if(s.length===0)return null;let b;o[0]===Symbol.for(`react.memo_cache_sentinel`)?(b=()=>l(y),o[0]=b):b=o[0];let x,S;o[1]===Symbol.for(`react.memo_cache_sentinel`)?(x=(0,m.jsx)(d,{className:`size-3.5`}),S=(0,m.jsx)(`span`,{children:`AWS CLI`}),o[1]=x,o[2]=S):(x=o[1],S=o[2]);let C=c&&`rotate-180`,w;o[3]===C?w=o[4]:(w=r(`ml-auto size-3.5 transition-transform`,C),o[3]=C,o[4]=w);let T;o[5]===w?T=o[6]:(T=(0,m.jsx)(t,{className:w}),o[5]=w,o[6]=T);let E;o[7]!==c||o[8]!==T?(E=(0,m.jsxs)(`button`,{type:`button`,onClick:b,className:`flex w-full items-center gap-2 px-3 py-2 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground`,"aria-expanded":c,children:[x,S,T]}),o[7]=c,o[8]=T,o[9]=E):E=o[9];let D;o[10]!==s||o[11]!==h||o[12]!==_||o[13]!==c?(D=c&&(0,m.jsxs)(`div`,{className:`border-t border-border`,children:[(0,m.jsxs)(`div`,{className:`flex items-center justify-between border-b border-border px-3 py-1.5`,children:[(0,m.jsx)(`span`,{className:`text-[0.625rem] text-muted-foreground`,children:s.length>1?`${s.length} commands`:`command`}),(0,m.jsxs)(a,{type:`button`,variant:`ghost`,size:`xs`,onClick:async()=>await _(g(s)),children:[h?(0,m.jsx)(e,{className:`size-2.5`}):(0,m.jsx)(n,{className:`size-2.5`}),h?`Copied`:`Copy`]})]}),(0,m.jsx)(`div`,{className:`overflow-x-auto p-3`,children:s.map((e,t)=>(0,m.jsxs)(`div`,{children:[s.length>1&&(0,m.jsx)(`div`,{className:`mb-1 text-[0.625rem] font-medium text-muted-foreground`,children:e.label}),(0,m.jsx)(`pre`,{className:`font-mono text-xs/relaxed`,children:(0,m.jsx)(`code`,{children:e.parts.map(v)})}),tc(y),a[0]=b):b=a[0];let x,S;a[1]===Symbol.for(`react.memo_cache_sentinel`)?(x=(0,m.jsx)(d,{className:`size-3.5`}),S=(0,m.jsx)(`span`,{children:`AWS CLI`}),a[1]=x,a[2]=S):(x=a[1],S=a[2]);let C=s&&`rotate-180`,w;a[3]===C?w=a[4]:(w=r(`ml-auto size-3.5 transition-transform`,C),a[3]=C,a[4]=w);let T;a[5]===w?T=a[6]:(T=(0,m.jsx)(t,{className:w}),a[5]=w,a[6]=T);let E;a[7]!==s||a[8]!==T?(E=(0,m.jsxs)(`button`,{type:`button`,onClick:b,className:`flex w-full items-center gap-2 px-3 py-2 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground`,"aria-expanded":s,children:[x,S,T]}),a[7]=s,a[8]=T,a[9]=E):E=a[9];let D;a[10]!==o||a[11]!==h||a[12]!==_||a[13]!==s?(D=s&&(0,m.jsxs)(`div`,{className:`border-t border-border`,children:[(0,m.jsxs)(`div`,{className:`flex items-center justify-between border-b border-border px-3 py-1.5`,children:[(0,m.jsx)(`span`,{className:`text-[0.625rem] text-muted-foreground`,children:o.length>1?`${o.length} commands`:`command`}),(0,m.jsxs)(l,{type:`button`,variant:`ghost`,size:`xs`,onClick:async()=>await _(g(o)),children:[h?(0,m.jsx)(e,{className:`size-2.5`}):(0,m.jsx)(n,{className:`size-2.5`}),h?`Copied`:`Copy`]})]}),(0,m.jsx)(`div`,{className:`overflow-x-auto p-3`,children:o.map((e,t)=>(0,m.jsxs)(`div`,{children:[o.length>1&&(0,m.jsx)(`div`,{className:`mb-1 text-[0.625rem] font-medium text-muted-foreground`,children:e.label}),(0,m.jsx)(`pre`,{className:`font-mono text-xs/relaxed`,children:(0,m.jsx)(`code`,{children:e.parts.map(v)})}),t{let t=!d,n=r(l,e.nativeEvent);if(a(t,n),n.isCanceled)return;let i=I.current;P.current===`css-animation`&&i!=null&&i.style.removeProperty(`animation-name`),!k&&!j&&(P.current!=null&&P.current!==`css-animation`&&!m&&t&&h(!0),P.current===`css-animation`&&(!_&&t&&v(!0),!m&&t&&h(!0))),p(t),P.current===`none`&&m&&!t&&h(!1)});return S(()=>{u&&P.current===`none`&&!d&&h(!1)},[u,d,n,h]),w.useMemo(()=>({abortControllerRef:N,animationTypeRef:P,disabled:o,handleTrigger:R,height:y,mounted:m,open:d,panelId:O,panelRef:I,runOnceAnimationsFinish:L,setDimensions:x,setHiddenUntilFound:A,setKeepMounted:M,setMounted:h,setOpen:p,setPanelIdState:D,setVisible:v,transitionDimensionRef:F,transitionStatus:g,visible:_,width:b}),[N,P,o,R,y,m,d,O,I,L,x,A,M,h,p,v,F,g,_,b])}var E=w.createContext(void 0);function D(){let e=w.useContext(E);if(e===void 0)throw Error(h(15));return e}var O=function(e){return e.open=`data-open`,e.closed=`data-closed`,e[e.startingStyle=n.startingStyle]=`startingStyle`,e[e.endingStyle=n.endingStyle]=`endingStyle`,e}({}),k=function(e){return e.panelOpen=`data-panel-open`,e}({}),A={[O.open]:``},j={[O.closed]:``},M={open(e){return e?{[k.panelOpen]:``}:null}},N={open(e){return e?A:j},...m},P=y(),F=w.forwardRef(function(n,r){let{render:i,className:a,defaultOpen:o=!1,disabled:s=!1,onOpenChange:c,open:l,style:u,...d}=n,f=t(c),p=T({open:l,defaultOpen:o,onOpenChange:f,disabled:s}),m=w.useMemo(()=>({open:p.open,disabled:p.disabled,transitionStatus:p.transitionStatus}),[p.open,p.disabled,p.transitionStatus]),h=w.useMemo(()=>({...p,onOpenChange:f,state:m}),[p,f,m]),g=e(`div`,n,{state:m,ref:r,props:d,stateAttributesMapping:N});return(0,P.jsx)(E.Provider,{value:h,children:g})}),I={...M,...m},L=w.forwardRef(function(t,n){let{panelId:r,open:i,handleTrigger:a,state:s,disabled:c}=D(),{className:l,disabled:u=c,id:d,render:f,nativeButton:p=!0,style:m,...h}=t,{getButtonProps:g,buttonRef:_}=o({disabled:u,focusableWhenDisabled:!0,native:p}),v=w.useMemo(()=>({"aria-controls":i?r:void 0,"aria-expanded":i,onClick:a}),[r,i,a]);return e(`button`,t,{state:s,ref:[n,_],props:[v,h,g],stateAttributesMapping:I})}),R=function(e){return e.disabled=`data-disabled`,e.orientation=`data-orientation`,e}({});function z(e){let{abortControllerRef:n,animationTypeRef:o,externalRef:s,height:c,hiddenUntilFound:l,keepMounted:u,id:d,mounted:f,onOpenChange:m,open:h,panelRef:_,runOnceAnimationsFinish:y,setDimensions:x,setMounted:C,setOpen:T,setVisible:E,transitionDimensionRef:D,visible:k,width:A}=e,j=w.useRef(!1),M=w.useRef(null),N=w.useRef(h),P=w.useRef(h),F=p(),I=w.useMemo(()=>o.current===`css-animation`?!k:!h&&!f,[h,f,k,o]),L=b(s,_,t(e=>{if(!e)return;if(o.current==null||D.current==null){let t=getComputedStyle(e),n=t.animationName!==`none`&&t.animationName!==``,r=t.transitionDuration!==`0s`&&t.transitionDuration!==``;n&&r||(t.animationName===`none`&&t.transitionDuration!==`0s`?o.current=`css-transition`:t.animationName!==`none`&&t.transitionDuration===`0s`?o.current=`css-animation`:o.current=`none`),e.getAttribute(R.orientation)===`horizontal`||t.transitionProperty.indexOf(`width`)>-1?D.current=`width`:D.current=`height`}if(o.current!==`css-transition`)return;(c===void 0||A===void 0)&&(x({height:e.scrollHeight,width:e.scrollWidth}),P.current&&e.style.setProperty(`transition-duration`,`0s`));let t=-1,n=-1;return t=a.request(()=>{P.current=!1,n=a.request(()=>{setTimeout(()=>{e.style.removeProperty(`transition-duration`)})})}),()=>{a.cancel(t),a.cancel(n)}}));return S(()=>{if(o.current!==`css-transition`)return;let e=_.current;if(!e)return;let t=-1;if(n.current!=null&&(n.current.abort(),n.current=null),h){let n={"justify-content":e.style.justifyContent,"align-items":e.style.alignItems,"align-content":e.style.alignContent,"justify-items":e.style.justifyItems};Object.keys(n).forEach(t=>{e.style.setProperty(t,`initial`,`important`)}),!P.current&&!u&&e.setAttribute(O.startingStyle,``),x({height:e.scrollHeight,width:e.scrollWidth}),t=a.request(()=>{Object.entries(n).forEach(([t,n])=>{n===``?e.style.removeProperty(t):e.style.setProperty(t,n)})})}else{if(e.scrollHeight===0&&e.scrollWidth===0)return;x({height:e.scrollHeight,width:e.scrollWidth});let t=new AbortController;n.current=t;let r=t.signal,i=null,a=O.endingStyle;return i=new MutationObserver(o=>{o.some(e=>e.type===`attributes`&&e.attributeName===a)&&(i?.disconnect(),i=null,y(()=>{x({height:0,width:0}),e.style.removeProperty(`content-visibility`),C(!1),n.current===t&&(n.current=null)},r))}),i.observe(e,{attributes:!0,attributeFilter:[a]}),()=>{i?.disconnect(),F.cancel(),n.current===t&&(t.abort(),n.current=null)}}return()=>{a.cancel(t)}},[n,o,F,l,u,f,h,_,y,x,C]),S(()=>{if(o.current!==`css-animation`)return;let e=_.current;e&&(M.current=e.style.animationName||M.current,e.style.setProperty(`animation-name`,`none`),x({height:e.scrollHeight,width:e.scrollWidth}),!N.current&&!j.current&&e.style.removeProperty(`animation-name`),h?(n.current!=null&&(n.current.abort(),n.current=null),C(!0),E(!0)):(n.current=new AbortController,y(()=>{C(!1),E(!1),n.current=null},n.current.signal)))},[n,o,h,_,y,x,C,E,k]),i(()=>{let e=a.request(()=>{N.current=!1});return()=>a.cancel(e)}),S(()=>{if(!l)return;let e=_.current;if(!e)return;let t=-1,n=-1;return h&&j.current&&(e.style.transitionDuration=`0s`,x({height:e.scrollHeight,width:e.scrollWidth}),t=a.request(()=>{j.current=!1,n=a.request(()=>{setTimeout(()=>{e.style.removeProperty(`transition-duration`)})})})),()=>{a.cancel(t),a.cancel(n)}},[l,h,_,x]),S(()=>{let e=_.current;e&&l&&I&&(e.setAttribute(`hidden`,`until-found`),o.current===`css-transition`&&e.setAttribute(O.startingStyle,``))},[l,I,o,_]),w.useEffect(function(){let e=_.current;if(!e)return;function t(e){j.current=!0,T(!0),m(!0,r(v,e))}return g(e,`beforematch`,t)},[m,_,T]),w.useMemo(()=>({props:{hidden:I,id:d,ref:L}}),[I,d,L])}var B=function(e){return e.collapsiblePanelHeight=`--collapsible-panel-height`,e.collapsiblePanelWidth=`--collapsible-panel-width`,e}({}),V=w.forwardRef(function(t,n){let{className:r,hiddenUntilFound:i,keepMounted:a,render:o,id:s,style:c,...l}=t,{abortControllerRef:u,animationTypeRef:f,height:p,mounted:m,onOpenChange:h,open:g,panelId:_,panelRef:v,runOnceAnimationsFinish:y,setDimensions:b,setHiddenUntilFound:x,setKeepMounted:C,setMounted:T,setPanelIdState:E,setOpen:O,setVisible:k,state:A,transitionDimensionRef:j,visible:M,width:P,transitionStatus:F}=D(),I=i??!1,L=a??!1;S(()=>{if(s)return E(s),()=>{E(void 0)}},[s,E]),S(()=>{x(I)},[x,I]),S(()=>{C(L)},[C,L]);let{props:R}=z({abortControllerRef:u,animationTypeRef:f,externalRef:n,height:p,hiddenUntilFound:I,id:_,keepMounted:L,mounted:m,onOpenChange:h,open:g,panelRef:v,runOnceAnimationsFinish:y,setDimensions:b,setMounted:T,setOpen:O,setVisible:k,transitionDimensionRef:j,visible:M,width:P});d({open:g&&F===`idle`,ref:v,onComplete(){g&&b({height:void 0,width:void 0})}});let V=e(`div`,t,{state:w.useMemo(()=>({...A,transitionStatus:F}),[A,F]),ref:[n,v],props:[R,{style:{[B.collapsiblePanelHeight]:p===void 0?`auto`:`${p}px`,[B.collapsiblePanelWidth]:P===void 0?`auto`:`${P}px`}},l],stateAttributesMapping:N});return L||I||m?V:null}),H=x();function U(e){let t=(0,H.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,P.jsx)(F,{"data-slot":`collapsible`,...n}),t[2]=n,t[3]=r),r}function W(e){let t=(0,H.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,P.jsx)(L,{"data-slot":`collapsible-trigger`,...n}),t[2]=n,t[3]=r),r}function G(e){let t=(0,H.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,P.jsx)(V,{"data-slot":`collapsible-content`,...n}),t[2]=n,t[3]=r),r}export{G as n,W as r,U as t}; \ No newline at end of file +import{$a as e,$i as t,Bi as n,Gi as r,Ia as i,Jo as a,Oo as o,Qi as s,Xa as c,Xi as l,Zi as u,_o as d,aa as f,ea as p,eo as m,ki as h,ko as g,na as _,po as v,qi as y,ra as b,ta as x,xo as S,yo as C}from"./index.js";var w=a(g());function T(r){let{open:a,defaultOpen:o,onOpenChange:s,disabled:c}=r,d=a!==void 0,[f,p]=l({controlled:a,default:o,name:`Collapsible`,state:`open`}),{mounted:h,setMounted:g,transitionStatus:_}=u(f,!0,!0),[v,b]=w.useState(f),[{height:x,width:S},C]=w.useState({height:void 0,width:void 0}),T=i(),[E,D]=w.useState(),O=E??T,[k,A]=w.useState(!1),[j,M]=w.useState(!1),N=w.useRef(null),P=w.useRef(null),F=w.useRef(null),I=w.useRef(null),L=t(I,!1),R=m(e=>{let t=!f,r=n(y,e.nativeEvent);if(s(t,r),r.isCanceled)return;let i=I.current;P.current===`css-animation`&&i!=null&&i.style.removeProperty(`animation-name`),!k&&!j&&(P.current!=null&&P.current!==`css-animation`&&!h&&t&&g(!0),P.current===`css-animation`&&(!v&&t&&b(!0),!h&&t&&g(!0))),p(t),P.current===`none`&&h&&!t&&g(!1)});return e(()=>{d&&P.current===`none`&&!f&&g(!1)},[d,f,a,g]),w.useMemo(()=>({abortControllerRef:N,animationTypeRef:P,disabled:c,handleTrigger:R,height:x,mounted:h,open:f,panelId:O,panelRef:I,runOnceAnimationsFinish:L,setDimensions:C,setHiddenUntilFound:A,setKeepMounted:M,setMounted:g,setOpen:p,setPanelIdState:D,setVisible:b,transitionDimensionRef:F,transitionStatus:_,visible:v,width:S}),[N,P,c,R,x,h,f,O,I,L,C,A,M,g,p,b,F,_,v,S])}var E=w.createContext(void 0);function D(){let e=w.useContext(E);if(e===void 0)throw Error(C(15));return e}var O=function(e){return e.open=`data-open`,e.closed=`data-closed`,e[e.startingStyle=p.startingStyle]=`startingStyle`,e[e.endingStyle=p.endingStyle]=`endingStyle`,e}({}),k=function(e){return e.panelOpen=`data-panel-open`,e}({}),A={[O.open]:``},j={[O.closed]:``},M={open(e){return e?{[k.panelOpen]:``}:null}},N={open(e){return e?A:j},...x},P=o(),F=w.forwardRef(function(e,t){let{render:n,className:r,defaultOpen:i=!1,disabled:a=!1,onOpenChange:o,open:s,style:c,...l}=e,u=m(o),d=T({open:s,defaultOpen:i,onOpenChange:u,disabled:a}),f=w.useMemo(()=>({open:d.open,disabled:d.disabled,transitionStatus:d.transitionStatus}),[d.open,d.disabled,d.transitionStatus]),p=w.useMemo(()=>({...d,onOpenChange:u,state:f}),[d,u,f]),h=v(`div`,e,{state:f,ref:t,props:l,stateAttributesMapping:N});return(0,P.jsx)(E.Provider,{value:p,children:h})}),I={...M,...x},L=w.forwardRef(function(e,t){let{panelId:n,open:r,handleTrigger:i,state:a,disabled:o}=D(),{className:s,disabled:l=o,id:u,render:d,nativeButton:f=!0,style:p,...m}=e,{getButtonProps:h,buttonRef:g}=c({disabled:l,focusableWhenDisabled:!0,native:f}),_=w.useMemo(()=>({"aria-controls":r?n:void 0,"aria-expanded":r,onClick:i}),[n,r,i]);return v(`button`,e,{state:a,ref:[t,g],props:[_,m,h],stateAttributesMapping:I})}),R=function(e){return e.disabled=`data-disabled`,e.orientation=`data-orientation`,e}({});function z(t){let{abortControllerRef:i,animationTypeRef:a,externalRef:o,height:s,hiddenUntilFound:c,keepMounted:l,id:u,mounted:p,onOpenChange:g,open:v,panelRef:y,runOnceAnimationsFinish:x,setDimensions:S,setMounted:C,setOpen:T,setVisible:E,transitionDimensionRef:D,visible:k,width:A}=t,j=w.useRef(!1),M=w.useRef(null),N=w.useRef(v),P=w.useRef(v),F=b(),I=w.useMemo(()=>a.current===`css-animation`?!k:!v&&!p,[v,p,k,a]),L=d(o,y,m(e=>{if(!e)return;if(a.current==null||D.current==null){let t=getComputedStyle(e),n=t.animationName!==`none`&&t.animationName!==``,r=t.transitionDuration!==`0s`&&t.transitionDuration!==``;n&&r||(t.animationName===`none`&&t.transitionDuration!==`0s`?a.current=`css-transition`:t.animationName!==`none`&&t.transitionDuration===`0s`?a.current=`css-animation`:a.current=`none`),e.getAttribute(R.orientation)===`horizontal`||t.transitionProperty.indexOf(`width`)>-1?D.current=`width`:D.current=`height`}if(a.current!==`css-transition`)return;(s===void 0||A===void 0)&&(S({height:e.scrollHeight,width:e.scrollWidth}),P.current&&e.style.setProperty(`transition-duration`,`0s`));let t=-1,n=-1;return t=_.request(()=>{P.current=!1,n=_.request(()=>{setTimeout(()=>{e.style.removeProperty(`transition-duration`)})})}),()=>{_.cancel(t),_.cancel(n)}}));return e(()=>{if(a.current!==`css-transition`)return;let e=y.current;if(!e)return;let t=-1;if(i.current!=null&&(i.current.abort(),i.current=null),v){let n={"justify-content":e.style.justifyContent,"align-items":e.style.alignItems,"align-content":e.style.alignContent,"justify-items":e.style.justifyItems};Object.keys(n).forEach(t=>{e.style.setProperty(t,`initial`,`important`)}),!P.current&&!l&&e.setAttribute(O.startingStyle,``),S({height:e.scrollHeight,width:e.scrollWidth}),t=_.request(()=>{Object.entries(n).forEach(([t,n])=>{n===``?e.style.removeProperty(t):e.style.setProperty(t,n)})})}else{if(e.scrollHeight===0&&e.scrollWidth===0)return;S({height:e.scrollHeight,width:e.scrollWidth});let t=new AbortController;i.current=t;let n=t.signal,r=null,a=O.endingStyle;return r=new MutationObserver(o=>{o.some(e=>e.type===`attributes`&&e.attributeName===a)&&(r?.disconnect(),r=null,x(()=>{S({height:0,width:0}),e.style.removeProperty(`content-visibility`),C(!1),i.current===t&&(i.current=null)},n))}),r.observe(e,{attributes:!0,attributeFilter:[a]}),()=>{r?.disconnect(),F.cancel(),i.current===t&&(t.abort(),i.current=null)}}return()=>{_.cancel(t)}},[i,a,F,c,l,p,v,y,x,S,C]),e(()=>{if(a.current!==`css-animation`)return;let e=y.current;e&&(M.current=e.style.animationName||M.current,e.style.setProperty(`animation-name`,`none`),S({height:e.scrollHeight,width:e.scrollWidth}),!N.current&&!j.current&&e.style.removeProperty(`animation-name`),v?(i.current!=null&&(i.current.abort(),i.current=null),C(!0),E(!0)):(i.current=new AbortController,x(()=>{C(!1),E(!1),i.current=null},i.current.signal)))},[i,a,v,y,x,S,C,E,k]),f(()=>{let e=_.request(()=>{N.current=!1});return()=>_.cancel(e)}),e(()=>{if(!c)return;let e=y.current;if(!e)return;let t=-1,n=-1;return v&&j.current&&(e.style.transitionDuration=`0s`,S({height:e.scrollHeight,width:e.scrollWidth}),t=_.request(()=>{j.current=!1,n=_.request(()=>{setTimeout(()=>{e.style.removeProperty(`transition-duration`)})})})),()=>{_.cancel(t),_.cancel(n)}},[c,v,y,S]),e(()=>{let e=y.current;e&&c&&I&&(e.setAttribute(`hidden`,`until-found`),a.current===`css-transition`&&e.setAttribute(O.startingStyle,``))},[c,I,a,y]),w.useEffect(function(){let e=y.current;if(!e)return;function t(e){j.current=!0,T(!0),g(!0,n(r,e))}return h(e,`beforematch`,t)},[g,y,T]),w.useMemo(()=>({props:{hidden:I,id:u,ref:L}}),[I,u,L])}var B=function(e){return e.collapsiblePanelHeight=`--collapsible-panel-height`,e.collapsiblePanelWidth=`--collapsible-panel-width`,e}({}),V=w.forwardRef(function(t,n){let{className:r,hiddenUntilFound:i,keepMounted:a,render:o,id:c,style:l,...u}=t,{abortControllerRef:d,animationTypeRef:f,height:p,mounted:m,onOpenChange:h,open:g,panelId:_,panelRef:y,runOnceAnimationsFinish:b,setDimensions:x,setHiddenUntilFound:S,setKeepMounted:C,setMounted:T,setPanelIdState:E,setOpen:O,setVisible:k,state:A,transitionDimensionRef:j,visible:M,width:P,transitionStatus:F}=D(),I=i??!1,L=a??!1;e(()=>{if(c)return E(c),()=>{E(void 0)}},[c,E]),e(()=>{S(I)},[S,I]),e(()=>{C(L)},[C,L]);let{props:R}=z({abortControllerRef:d,animationTypeRef:f,externalRef:n,height:p,hiddenUntilFound:I,id:_,keepMounted:L,mounted:m,onOpenChange:h,open:g,panelRef:y,runOnceAnimationsFinish:b,setDimensions:x,setMounted:T,setOpen:O,setVisible:k,transitionDimensionRef:j,visible:M,width:P});s({open:g&&F===`idle`,ref:y,onComplete(){g&&x({height:void 0,width:void 0})}});let V=v(`div`,t,{state:w.useMemo(()=>({...A,transitionStatus:F}),[A,F]),ref:[n,y],props:[R,{style:{[B.collapsiblePanelHeight]:p===void 0?`auto`:`${p}px`,[B.collapsiblePanelWidth]:P===void 0?`auto`:`${P}px`}},u],stateAttributesMapping:N});return L||I||m?V:null}),H=S();function U(e){let t=(0,H.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,P.jsx)(F,{"data-slot":`collapsible`,...n}),t[2]=n,t[3]=r),r}function W(e){let t=(0,H.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,P.jsx)(L,{"data-slot":`collapsible-trigger`,...n}),t[2]=n,t[3]=r),r}function G(e){let t=(0,H.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,P.jsx)(V,{"data-slot":`collapsible-content`,...n}),t[2]=n,t[3]=r),r}export{G as n,W as r,U as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/copy.js b/spinifex/services/spinifexui/frontend/dist/assets/copy.js index dcd328972..a89c2d4ce 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/copy.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/copy.js @@ -1 +1 @@ -import{Xa as e}from"./index.js";var t=e(`copy`,[[`rect`,{width:`14`,height:`14`,x:`8`,y:`8`,rx:`2`,ry:`2`,key:`17jyea`}],[`path`,{d:`M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2`,key:`zix9uf`}]]);export{t}; \ No newline at end of file +import{uo as e}from"./index.js";var t=e(`copy`,[[`rect`,{width:`14`,height:`14`,x:`8`,y:`8`,rx:`2`,ry:`2`,key:`17jyea`}],[`path`,{d:`M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2`,key:`zix9uf`}]]);export{t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/create-bucket.js b/spinifex/services/spinifexui/frontend/dist/assets/create-bucket.js index 473d51775..9aaca60ef 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/create-bucket.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/create-bucket.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./back-link.js";import{t as n}from"./cli-command-panel.js";import{t as r}from"./s3.js";import{Ti as i,gr as a,mo as o,so as s,uo as c,vr as l}from"./index.js";import{t as u}from"./page-heading.js";import{a as d,r as f,t as p}from"./field.js";import{i as m,t as h}from"./zod.js";import{t as g}from"./form-actions.js";var _=s(),v=a({bucketName:l().min(3,`Bucket name must be at least 3 characters`).max(63,`Bucket name must be at most 63 characters`).regex(/^[a-z0-9][a-z0-9.-]*[a-z0-9]$/,`Must start and end with a lowercase letter or number`).regex(/^[a-z0-9.-]+$/,`Only lowercase letters, numbers, hyphens, and periods allowed`).refine(e=>!e.includes(`..`),`Must not contain consecutive periods`).refine(e=>!(e.includes(`.-`)||e.includes(`-.`)),`Must not contain adjacent period and hyphen`)}),y=o();function b(){let a=(0,_.c)(40),o=c(),s=r(),l;a[0]===Symbol.for(`react.memo_cache_sentinel`)?(l={resolver:h(v)},a[0]=l):l=a[0];let{handleSubmit:b,register:S,watch:C,formState:w}=m(l),{errors:T,isSubmitting:E}=w,D;a[1]!==s||a[2]!==o?(D=async e=>{await s.mutateAsync(e),o({to:`/s3/ls`})},a[1]=s,a[2]=o,a[3]=D):D=a[3];let O=D,k,A;a[4]===Symbol.for(`react.memo_cache_sentinel`)?(k=(0,y.jsx)(t,{to:`/s3/ls`,children:`Back to buckets`}),A=(0,y.jsx)(u,{title:`Create Bucket`}),a[4]=k,a[5]=A):(k=a[4],A=a[5]);let j;a[6]===s.error?j=a[7]:(j=s.error&&(0,y.jsx)(e,{error:s.error,msg:`Failed to create bucket`}),a[6]=s.error,a[7]=j);let M;a[8]!==b||a[9]!==O?(M=b(O),a[8]=b,a[9]=O,a[10]=M):M=a[10];let N;a[11]===Symbol.for(`react.memo_cache_sentinel`)?(N=(0,y.jsx)(d,{children:(0,y.jsx)(`label`,{htmlFor:`bucketName`,children:`Bucket Name`})}),a[11]=N):N=a[11];let P=!!T.bucketName,F;a[12]===S?F=a[13]:(F=S(`bucketName`),a[12]=S,a[13]=F);let I;a[14]!==P||a[15]!==F?(I=(0,y.jsx)(i,{"aria-invalid":P,id:`bucketName`,placeholder:`my-bucket`,type:`text`,...F}),a[14]=P,a[15]=F,a[16]=I):I=a[16];let L;a[17]===T.bucketName?L=a[18]:(L=(0,y.jsx)(f,{errors:[T.bucketName]}),a[17]=T.bucketName,a[18]=L);let R;a[19]!==I||a[20]!==L?(R=(0,y.jsxs)(p,{children:[N,I,L]}),a[19]=I,a[20]=L,a[21]=R):R=a[21];let z;a[22]===C?z=a[23]:(z=x(C),a[22]=C,a[23]=z);let B;a[24]===z?B=a[25]:(B=(0,y.jsx)(n,{commands:z}),a[24]=z,a[25]=B);let V;a[26]===o?V=a[27]:(V=async()=>await o({to:`/s3/ls`}),a[26]=o,a[27]=V);let H;a[28]!==s.isPending||a[29]!==E||a[30]!==V?(H=(0,y.jsx)(g,{isPending:s.isPending,isSubmitting:E,onCancel:V,pendingLabel:`Creating…`,submitLabel:`Create Bucket`}),a[28]=s.isPending,a[29]=E,a[30]=V,a[31]=H):H=a[31];let U;a[32]!==R||a[33]!==B||a[34]!==H||a[35]!==M?(U=(0,y.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:M,children:[R,B,H]}),a[32]=R,a[33]=B,a[34]=H,a[35]=M,a[36]=U):U=a[36];let W;return a[37]!==U||a[38]!==j?(W=(0,y.jsxs)(y.Fragment,{children:[k,A,j,U]}),a[37]=U,a[38]=j,a[39]=W):W=a[39],W}function x(e){let t=e(`bucketName`);return[{label:`Create Bucket`,parts:[{type:`bin`,value:`AWS_PROFILE=spinifex aws s3api create-bucket`},{type:`flag`,value:` --bucket`},{type:`value`,value:` ${(typeof t==`string`?t:``)||``}`}]}]}export{b as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./back-link.js";import{t as n}from"./cli-command-panel.js";import{t as r}from"./s3.js";import{Ar as i,Mr as a,Oo as o,wo as s,xo as c,zi as l}from"./index.js";import{t as u}from"./page-heading.js";import{a as d,r as f,t as p}from"./field.js";import{a as m,i as h,t as g}from"./zod.js";import{t as _}from"./form-actions.js";var v=c(),y=i({bucketName:a().min(3,`Bucket name must be at least 3 characters`).max(63,`Bucket name must be at most 63 characters`).regex(/^[a-z0-9][a-z0-9.-]*[a-z0-9]$/,`Must start and end with a lowercase letter or number`).regex(/^[a-z0-9.-]+$/,`Only lowercase letters, numbers, hyphens, and periods allowed`).refine(e=>!e.includes(`..`),`Must not contain consecutive periods`).refine(e=>!(e.includes(`.-`)||e.includes(`-.`)),`Must not contain adjacent period and hyphen`)}),b=o();function x(){let i=(0,v.c)(44),a=s(),o=r(),c;i[0]===Symbol.for(`react.memo_cache_sentinel`)?(c={resolver:g(y)},i[0]=c):c=i[0];let{handleSubmit:x,register:C,control:w,formState:T}=h(c),{errors:E,isSubmitting:D}=T,O;i[1]===w?O=i[2]:(O={control:w},i[1]=w,i[2]=O);let k=m(O),A;i[3]===k?A=i[4]:(A=e=>e?k[e]:void 0,i[3]=k,i[4]=A);let j=A,M;i[5]!==o||i[6]!==a?(M=async e=>{await o.mutateAsync(e),a({to:`/s3/ls`})},i[5]=o,i[6]=a,i[7]=M):M=i[7];let N=M,P,F;i[8]===Symbol.for(`react.memo_cache_sentinel`)?(P=(0,b.jsx)(t,{to:`/s3/ls`,children:`Back to buckets`}),F=(0,b.jsx)(u,{title:`Create Bucket`}),i[8]=P,i[9]=F):(P=i[8],F=i[9]);let I;i[10]===o.error?I=i[11]:(I=o.error&&(0,b.jsx)(e,{error:o.error,msg:`Failed to create bucket`}),i[10]=o.error,i[11]=I);let L;i[12]!==x||i[13]!==N?(L=x(N),i[12]=x,i[13]=N,i[14]=L):L=i[14];let R;i[15]===Symbol.for(`react.memo_cache_sentinel`)?(R=(0,b.jsx)(d,{children:(0,b.jsx)(`label`,{htmlFor:`bucketName`,children:`Bucket Name`})}),i[15]=R):R=i[15];let z=!!E.bucketName,B;i[16]===C?B=i[17]:(B=C(`bucketName`),i[16]=C,i[17]=B);let V;i[18]!==z||i[19]!==B?(V=(0,b.jsx)(l,{"aria-invalid":z,id:`bucketName`,placeholder:`my-bucket`,type:`text`,...B}),i[18]=z,i[19]=B,i[20]=V):V=i[20];let H;i[21]===E.bucketName?H=i[22]:(H=(0,b.jsx)(f,{errors:[E.bucketName]}),i[21]=E.bucketName,i[22]=H);let U;i[23]!==V||i[24]!==H?(U=(0,b.jsxs)(p,{children:[R,V,H]}),i[23]=V,i[24]=H,i[25]=U):U=i[25];let W;i[26]===j?W=i[27]:(W=S(j),i[26]=j,i[27]=W);let G;i[28]===W?G=i[29]:(G=(0,b.jsx)(n,{commands:W}),i[28]=W,i[29]=G);let K;i[30]===a?K=i[31]:(K=async()=>await a({to:`/s3/ls`}),i[30]=a,i[31]=K);let q;i[32]!==o.isPending||i[33]!==D||i[34]!==K?(q=(0,b.jsx)(_,{isPending:o.isPending,isSubmitting:D,onCancel:K,pendingLabel:`Creating…`,submitLabel:`Create Bucket`}),i[32]=o.isPending,i[33]=D,i[34]=K,i[35]=q):q=i[35];let J;i[36]!==U||i[37]!==G||i[38]!==q||i[39]!==L?(J=(0,b.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:L,children:[U,G,q]}),i[36]=U,i[37]=G,i[38]=q,i[39]=L,i[40]=J):J=i[40];let Y;return i[41]!==J||i[42]!==I?(Y=(0,b.jsxs)(b.Fragment,{children:[P,F,I,J]}),i[41]=J,i[42]=I,i[43]=Y):Y=i[43],Y}function S(e){let t=e(`bucketName`);return[{label:`Create Bucket`,parts:[{type:`bin`,value:`AWS_PROFILE=spinifex aws s3api create-bucket`},{type:`flag`,value:` --bucket`},{type:`value`,value:` ${(typeof t==`string`?t:``)||``}`}]}]}export{x as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/create-key-pair.js b/spinifex/services/spinifexui/frontend/dist/assets/create-key-pair.js index 7e8f53aa7..135250529 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/create-key-pair.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/create-key-pair.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./back-link.js";import{t as n}from"./check.js";import{t as r}from"./download.js";import{t as i}from"./cli-command-panel.js";import{t as a}from"./triangle-alert.js";import{s as o}from"./ec2.js";import{Po as s,Ta as c,Ti as l,ho as u,mo as d,so as f,uo as p}from"./index.js";import{t as m}from"./page-heading.js";import{a as h,c as g,i as _,l as v,o as y,r as b,s as x,t as S}from"./alert-dialog.js";import{a as C,r as w,t as T}from"./field.js";import{i as E,t as D}from"./zod.js";import{t as O}from"./use-copy-to-clipboard.js";import{r as k}from"./ec22.js";import{t as A}from"./form-actions.js";var j=s(u()),M=f(),N=d();function P(e){let t=(0,M.c)(38),{open:i,keyName:o,keyMaterial:s}=e,l=p(),{copied:u,copy:d}=O(),f;t[0]!==s||t[1]!==o?(f=()=>{let e=new Blob([s],{type:`text/plain`}),t=URL.createObjectURL(e),n=document.createElement(`a`);n.href=t,n.download=`${o}.pem`,n.click(),URL.revokeObjectURL(t)},t[0]=s,t[1]=o,t[2]=f):f=t[2];let m=f,C;t[3]===l?C=t[4]:(C=()=>{l({to:`/ec2/describe-key-pairs`})},t[3]=l,t[4]=C);let w=C,T,E;t[5]===Symbol.for(`react.memo_cache_sentinel`)?(T=(0,N.jsx)(g,{children:(0,N.jsx)(a,{className:`text-destructive`})}),E=(0,N.jsx)(v,{children:`Save Your Private Key`}),t[5]=T,t[6]=E):(T=t[5],E=t[6]);let D;t[7]===o?D=t[8]:(D=(0,N.jsxs)(x,{children:[T,E,(0,N.jsxs)(h,{children:[`This is your only chance to save the private key file for`,` `,(0,N.jsx)(`strong`,{children:o}),`. Please download or copy it now. You won't be able to retrieve it again.`]})]}),t[7]=o,t[8]=D);let k=`Private key material for ${o}`,A;t[9]!==s||t[10]!==k?(A=(0,N.jsx)(`textarea`,{"aria-label":k,className:`w-full resize-none overflow-y-auto rounded-md border border-input bg-input/20 px-2 py-2 font-mono text-xs`,readOnly:!0,rows:4,value:s}),t[9]=s,t[10]=k,t[11]=A):A=t[11];let j;t[12]!==d||t[13]!==s?(j=async()=>await d(s),t[12]=d,t[13]=s,t[14]=j):j=t[14];let P;t[15]===u?P=t[16]:(P=u?(0,N.jsxs)(N.Fragment,{children:[(0,N.jsx)(n,{className:`mr-2 size-4`}),`Copied!`]}):`Copy to Clipboard`,t[15]=u,t[16]=P);let F;t[17]!==j||t[18]!==P?(F=(0,N.jsx)(c,{className:`flex-1`,onClick:j,type:`button`,variant:`outline`,children:P}),t[17]=j,t[18]=P,t[19]=F):F=t[19];let I;t[20]===Symbol.for(`react.memo_cache_sentinel`)?(I=(0,N.jsx)(r,{className:`mr-2 size-4`}),t[20]=I):I=t[20];let L;t[21]===m?L=t[22]:(L=(0,N.jsxs)(c,{className:`flex-1`,onClick:m,type:`button`,variant:`outline`,children:[I,`Download .pem File`]}),t[21]=m,t[22]=L);let R;t[23]!==F||t[24]!==L?(R=(0,N.jsxs)(`div`,{className:`flex gap-2`,children:[F,L]}),t[23]=F,t[24]=L,t[25]=R):R=t[25];let z;t[26]!==R||t[27]!==A?(z=(0,N.jsxs)(`div`,{className:`space-y-3`,children:[A,R]}),t[26]=R,t[27]=A,t[28]=z):z=t[28];let B;t[29]===w?B=t[30]:(B=(0,N.jsx)(y,{children:(0,N.jsx)(b,{onClick:w,children:`Close and Continue`})}),t[29]=w,t[30]=B);let V;t[31]!==z||t[32]!==B||t[33]!==D?(V=(0,N.jsxs)(_,{className:`max-w-2xl`,children:[D,z,B]}),t[31]=z,t[32]=B,t[33]=D,t[34]=V):V=t[34];let H;return t[35]!==i||t[36]!==V?(H=(0,N.jsx)(S,{open:i,children:V}),t[35]=i,t[36]=V,t[37]=H):H=t[37],H}function F(){let n=(0,M.c)(42),r=p(),a=o(),[s,c]=(0,j.useState)(null),u;n[0]===Symbol.for(`react.memo_cache_sentinel`)?(u={resolver:D(k)},n[0]=u):u=n[0];let{handleSubmit:d,register:f,watch:h,formState:g}=E(u),{errors:_,isSubmitting:v}=g,y;n[1]===a?y=n[2]:(y=async e=>{let t=await a.mutateAsync(e);t.KeyMaterial&&c({keyName:e.keyName,material:t.KeyMaterial})},n[1]=a,n[2]=y);let b=y,x,S;n[3]===Symbol.for(`react.memo_cache_sentinel`)?(x=(0,N.jsx)(t,{to:`/ec2/describe-key-pairs`,children:`Back to key pairs`}),S=(0,N.jsx)(m,{title:`Create Key Pair`}),n[3]=x,n[4]=S):(x=n[3],S=n[4]);let O;n[5]===a.error?O=n[6]:(O=a.error&&(0,N.jsx)(e,{error:a.error,msg:`Failed to create key pair`}),n[5]=a.error,n[6]=O);let F;n[7]!==d||n[8]!==b?(F=d(b),n[7]=d,n[8]=b,n[9]=F):F=n[9];let L;n[10]===Symbol.for(`react.memo_cache_sentinel`)?(L=(0,N.jsx)(C,{children:(0,N.jsx)(`label`,{htmlFor:`keyName`,children:`Key Pair Name`})}),n[10]=L):L=n[10];let R=!!_.keyName,z;n[11]===f?z=n[12]:(z=f(`keyName`),n[11]=f,n[12]=z);let B;n[13]!==R||n[14]!==z?(B=(0,N.jsx)(l,{"aria-invalid":R,id:`keyName`,placeholder:`my-key-pair…`,...z}),n[13]=R,n[14]=z,n[15]=B):B=n[15];let V;n[16]===_.keyName?V=n[17]:(V=(0,N.jsx)(w,{errors:[_.keyName]}),n[16]=_.keyName,n[17]=V);let H;n[18]!==B||n[19]!==V?(H=(0,N.jsxs)(T,{children:[L,B,V]}),n[18]=B,n[19]=V,n[20]=H):H=n[20];let U;n[21]===h?U=n[22]:(U=I(h),n[21]=h,n[22]=U);let W;n[23]===U?W=n[24]:(W=(0,N.jsx)(i,{commands:U}),n[23]=U,n[24]=W);let G;n[25]===r?G=n[26]:(G=async()=>await r({to:`/ec2/describe-key-pairs`}),n[25]=r,n[26]=G);let K;n[27]!==a.isPending||n[28]!==v||n[29]!==G?(K=(0,N.jsx)(A,{isPending:a.isPending,isSubmitting:v,onCancel:G,pendingLabel:`Creating…`,submitLabel:`Create Key Pair`}),n[27]=a.isPending,n[28]=v,n[29]=G,n[30]=K):K=n[30];let q;n[31]!==H||n[32]!==W||n[33]!==K||n[34]!==F?(q=(0,N.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:F,children:[H,W,K]}),n[31]=H,n[32]=W,n[33]=K,n[34]=F,n[35]=q):q=n[35];let J;n[36]===s?J=n[37]:(J=s&&(0,N.jsx)(P,{keyMaterial:s.material,keyName:s.keyName,open:!!s}),n[36]=s,n[37]=J);let Y;return n[38]!==q||n[39]!==J||n[40]!==O?(Y=(0,N.jsxs)(N.Fragment,{children:[x,S,O,q,J]}),n[38]=q,n[39]=J,n[40]=O,n[41]=Y):Y=n[41],Y}function I(e){let t=e(`keyName`);return[{label:`Create Key Pair`,parts:[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 create-key-pair`},{type:`flag`,value:` --key-name`},{type:`value`,value:` ${(typeof t==`string`?t:``)||``}`}]}]}export{F as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./back-link.js";import{t as n}from"./check.js";import{t as r}from"./download.js";import{t as i}from"./cli-command-panel.js";import{t as a}from"./triangle-alert.js";import{s as o}from"./ec2.js";import{Jo as s,Oo as c,ko as l,wo as ee,xo as u,za as d,zi as f}from"./index.js";import{t as p}from"./page-heading.js";import{a as m,c as h,i as g,l as _,o as v,r as y,s as b,t as x}from"./alert-dialog.js";import{a as S,r as C,t as w}from"./field.js";import{a as T,i as E,t as D}from"./zod.js";import{t as O}from"./use-copy-to-clipboard.js";import{r as k}from"./ec22.js";import{t as A}from"./form-actions.js";var j=s(l()),M=u(),N=c();function P(e){let t=(0,M.c)(38),{open:i,keyName:o,keyMaterial:s}=e,c=ee(),{copied:l,copy:u}=O(),f;t[0]!==s||t[1]!==o?(f=()=>{let e=new Blob([s],{type:`text/plain`}),t=URL.createObjectURL(e),n=document.createElement(`a`);n.href=t,n.download=`${o}.pem`,n.click(),URL.revokeObjectURL(t)},t[0]=s,t[1]=o,t[2]=f):f=t[2];let p=f,S;t[3]===c?S=t[4]:(S=()=>{c({to:`/ec2/describe-key-pairs`})},t[3]=c,t[4]=S);let C=S,w,T;t[5]===Symbol.for(`react.memo_cache_sentinel`)?(w=(0,N.jsx)(h,{children:(0,N.jsx)(a,{className:`text-destructive`})}),T=(0,N.jsx)(_,{children:`Save Your Private Key`}),t[5]=w,t[6]=T):(w=t[5],T=t[6]);let E;t[7]===o?E=t[8]:(E=(0,N.jsxs)(b,{children:[w,T,(0,N.jsxs)(m,{children:[`This is your only chance to save the private key file for`,` `,(0,N.jsx)(`strong`,{children:o}),`. Please download or copy it now. You won't be able to retrieve it again.`]})]}),t[7]=o,t[8]=E);let D=`Private key material for ${o}`,k;t[9]!==s||t[10]!==D?(k=(0,N.jsx)(`textarea`,{"aria-label":D,className:`w-full resize-none overflow-y-auto rounded-md border border-input bg-input/20 px-2 py-2 font-mono text-xs`,readOnly:!0,rows:4,value:s}),t[9]=s,t[10]=D,t[11]=k):k=t[11];let A;t[12]!==u||t[13]!==s?(A=async()=>await u(s),t[12]=u,t[13]=s,t[14]=A):A=t[14];let j;t[15]===l?j=t[16]:(j=l?(0,N.jsxs)(N.Fragment,{children:[(0,N.jsx)(n,{className:`mr-2 size-4`}),`Copied!`]}):`Copy to Clipboard`,t[15]=l,t[16]=j);let P;t[17]!==A||t[18]!==j?(P=(0,N.jsx)(d,{className:`flex-1`,onClick:A,type:`button`,variant:`outline`,children:j}),t[17]=A,t[18]=j,t[19]=P):P=t[19];let F;t[20]===Symbol.for(`react.memo_cache_sentinel`)?(F=(0,N.jsx)(r,{className:`mr-2 size-4`}),t[20]=F):F=t[20];let I;t[21]===p?I=t[22]:(I=(0,N.jsxs)(d,{className:`flex-1`,onClick:p,type:`button`,variant:`outline`,children:[F,`Download .pem File`]}),t[21]=p,t[22]=I);let L;t[23]!==P||t[24]!==I?(L=(0,N.jsxs)(`div`,{className:`flex gap-2`,children:[P,I]}),t[23]=P,t[24]=I,t[25]=L):L=t[25];let R;t[26]!==L||t[27]!==k?(R=(0,N.jsxs)(`div`,{className:`space-y-3`,children:[k,L]}),t[26]=L,t[27]=k,t[28]=R):R=t[28];let z;t[29]===C?z=t[30]:(z=(0,N.jsx)(v,{children:(0,N.jsx)(y,{onClick:C,children:`Close and Continue`})}),t[29]=C,t[30]=z);let B;t[31]!==R||t[32]!==z||t[33]!==E?(B=(0,N.jsxs)(g,{className:`max-w-2xl`,children:[E,R,z]}),t[31]=R,t[32]=z,t[33]=E,t[34]=B):B=t[34];let V;return t[35]!==i||t[36]!==B?(V=(0,N.jsx)(x,{open:i,children:B}),t[35]=i,t[36]=B,t[37]=V):V=t[37],V}function F(){let n=(0,M.c)(46),r=ee(),a=o(),[s,c]=(0,j.useState)(null),l;n[0]===Symbol.for(`react.memo_cache_sentinel`)?(l={resolver:D(k)},n[0]=l):l=n[0];let{handleSubmit:u,register:d,control:m,formState:h}=E(l),{errors:g,isSubmitting:_}=h,v;n[1]===m?v=n[2]:(v={control:m},n[1]=m,n[2]=v);let y=T(v),b;n[3]===y?b=n[4]:(b=e=>e?y[e]:void 0,n[3]=y,n[4]=b);let x=b,O;n[5]===a?O=n[6]:(O=async e=>{let t=await a.mutateAsync(e);t.KeyMaterial&&c({keyName:e.keyName,material:t.KeyMaterial})},n[5]=a,n[6]=O);let F=O,L,R;n[7]===Symbol.for(`react.memo_cache_sentinel`)?(L=(0,N.jsx)(t,{to:`/ec2/describe-key-pairs`,children:`Back to key pairs`}),R=(0,N.jsx)(p,{title:`Create Key Pair`}),n[7]=L,n[8]=R):(L=n[7],R=n[8]);let z;n[9]===a.error?z=n[10]:(z=a.error&&(0,N.jsx)(e,{error:a.error,msg:`Failed to create key pair`}),n[9]=a.error,n[10]=z);let B;n[11]!==u||n[12]!==F?(B=u(F),n[11]=u,n[12]=F,n[13]=B):B=n[13];let V;n[14]===Symbol.for(`react.memo_cache_sentinel`)?(V=(0,N.jsx)(S,{children:(0,N.jsx)(`label`,{htmlFor:`keyName`,children:`Key Pair Name`})}),n[14]=V):V=n[14];let H=!!g.keyName,U;n[15]===d?U=n[16]:(U=d(`keyName`),n[15]=d,n[16]=U);let W;n[17]!==H||n[18]!==U?(W=(0,N.jsx)(f,{"aria-invalid":H,id:`keyName`,placeholder:`my-key-pair…`,...U}),n[17]=H,n[18]=U,n[19]=W):W=n[19];let G;n[20]===g.keyName?G=n[21]:(G=(0,N.jsx)(C,{errors:[g.keyName]}),n[20]=g.keyName,n[21]=G);let K;n[22]!==W||n[23]!==G?(K=(0,N.jsxs)(w,{children:[V,W,G]}),n[22]=W,n[23]=G,n[24]=K):K=n[24];let q;n[25]===x?q=n[26]:(q=I(x),n[25]=x,n[26]=q);let J;n[27]===q?J=n[28]:(J=(0,N.jsx)(i,{commands:q}),n[27]=q,n[28]=J);let Y;n[29]===r?Y=n[30]:(Y=async()=>await r({to:`/ec2/describe-key-pairs`}),n[29]=r,n[30]=Y);let X;n[31]!==a.isPending||n[32]!==_||n[33]!==Y?(X=(0,N.jsx)(A,{isPending:a.isPending,isSubmitting:_,onCancel:Y,pendingLabel:`Creating…`,submitLabel:`Create Key Pair`}),n[31]=a.isPending,n[32]=_,n[33]=Y,n[34]=X):X=n[34];let Z;n[35]!==K||n[36]!==J||n[37]!==X||n[38]!==B?(Z=(0,N.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:B,children:[K,J,X]}),n[35]=K,n[36]=J,n[37]=X,n[38]=B,n[39]=Z):Z=n[39];let Q;n[40]===s?Q=n[41]:(Q=s&&(0,N.jsx)(P,{keyMaterial:s.material,keyName:s.keyName,open:!!s}),n[40]=s,n[41]=Q);let $;return n[42]!==Z||n[43]!==Q||n[44]!==z?($=(0,N.jsxs)(N.Fragment,{children:[L,R,z,Z,Q]}),n[42]=Z,n[43]=Q,n[44]=z,n[45]=$):$=n[45],$}function I(e){let t=e(`keyName`);return[{label:`Create Key Pair`,parts:[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 create-key-pair`},{type:`flag`,value:` --key-name`},{type:`value`,value:` ${(typeof t==`string`?t:``)||``}`}]}]}export{F as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/create-load-balancer.js b/spinifex/services/spinifexui/frontend/dist/assets/create-load-balancer.js index 73939ec24..9c08b3f3a 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/create-load-balancer.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/create-load-balancer.js @@ -1,4 +1,4 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{c as r,i,n as a,s as o,t as s}from"./select.js";import{t as c}from"./plus.js";import{t as l}from"./cli-command-panel.js";import{t as u}from"./trash-2.js";import{n as d}from"./elbv2.js";import{$ as f,M as p,Pa as m,Po as h,Ta as g,Ti as _,Y as ee,ho as v,mo as y,rt as te,uo as b}from"./index.js";import{t as ne}from"./page-heading.js";import{a as x,r as S,t as C}from"./field.js";import{i as w,n as T,t as E}from"./zod.js";import{t as re}from"./form-actions.js";import{t as ie}from"./target-group-form.js";import{i as ae,n as D}from"./elbv22.js";var O=h(v(),1),k=y();function A(e){let t=m(e.Tags);return t?`${e.VpcId} (${t})`:`${e.VpcId} (${e.CidrBlock})`}function j(e){let t=m(e.Tags);return`${t?`${e.SubnetId} (${t})`:e.SubnetId} · ${e.CidrBlock}`}function oe(e){let t=new Map;for(let n of e){let e=n.AvailabilityZone??`unknown`,r=t.get(e)??[];r.push(n),t.set(e,r)}return[...t.entries()].toSorted((e,t)=>e[0].localeCompare(t[0])).map(([e,t])=>({az:e,subnets:t}))}function M(){let m=b(),{data:h}=t(te),{data:v}=t(f),{data:y}=t(ee),{data:M}=t(p),N=d(),[P,F]=(0,O.useState)(null),I=h.Vpcs??[],ce=v.Subnets??[],L=y.SecurityGroups??[],R=M.TargetGroups??[],z=w({resolver:E(D),defaultValues:{name:``,scheme:`internet-facing`,vpcId:I[0]?.VpcId??``,subnetIds:[],securityGroupIds:[],tags:[],listener:{protocol:`HTTP`,port:80,targetGroupMode:`new`,existingTargetGroupArn:``}}}),B=w({resolver:E(ae),defaultValues:{name:``,protocol:`HTTP`,port:80,vpcId:I[0]?.VpcId??``,healthCheck:{protocol:`HTTP`,path:`/`,port:`traffic-port`,intervalSeconds:30,timeoutSeconds:5,healthyThresholdCount:5,unhealthyThresholdCount:2,matcher:`200`},tags:[]}}),{handleSubmit:V,register:H,watch:U,control:W,setValue:G,getValues:K,formState:{errors:q,isSubmitting:le}}=z,J=U(`vpcId`),ue=U(`subnetIds`),de=U(`securityGroupIds`),Y=U(`listener.targetGroupMode`),fe=U(`tags`),X=ce.filter(e=>e.VpcId===J),Z=L.filter(e=>e.VpcId===J),Q=R.filter(e=>e.VpcId===J),pe=(e=``)=>{let t=e??``;G(`vpcId`,t,{shouldValidate:!0}),G(`subnetIds`,[],{shouldValidate:!0}),G(`securityGroupIds`,[]),G(`listener.existingTargetGroupArn`,``),B.setValue(`vpcId`,t)},me=e=>{let t=K(`subnetIds`);G(`subnetIds`,t.includes(e)?t.filter(t=>t!==e):[...t,e],{shouldValidate:!0})},he=e=>{let t=K(`securityGroupIds`);G(`securityGroupIds`,t.includes(e)?t.filter(t=>t!==e):[...t,e])},ge=async e=>{F(null);let t;if(e.listener.targetGroupMode===`new`){if(!await B.trigger())return;t=B.getValues()}let n=await N.mutateAsync({lb:{name:e.name,scheme:e.scheme,vpcId:e.vpcId,subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds,tags:e.tags},listener:{protocol:e.listener.protocol,port:e.listener.port,targetGroupMode:e.listener.targetGroupMode,existingTargetGroupArn:e.listener.existingTargetGroupArn,newTargetGroup:t}});F(n),!n.error&&n.loadBalancerArn&&m({to:`/ec2/describe-load-balancers/$id`,params:{id:encodeURIComponent(n.loadBalancerArn)}})},$=oe(X);return(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(n,{to:`/ec2/describe-load-balancers`,children:`Back to load balancers`}),(0,k.jsx)(ne,{title:`Create Load Balancer`}),N.error&&(0,k.jsx)(e,{error:N.error,msg:`Failed to create load balancer`}),P?.error&&(0,k.jsxs)(`div`,{className:`mb-6 max-w-4xl rounded-md border border-destructive bg-destructive/10 p-4`,children:[(0,k.jsxs)(`h2`,{className:`text-sm font-medium text-destructive`,children:[`Wizard failed: `,P.failedStep]}),(0,k.jsx)(`p`,{className:`mt-1 text-sm text-destructive`,children:P.error.message}),P.created.length>0&&(0,k.jsxs)(`div`,{className:`mt-3`,children:[(0,k.jsx)(`p`,{className:`text-xs font-medium text-destructive`,children:`Successfully created resources (clean up manually if needed):`}),(0,k.jsx)(`ul`,{className:`mt-1 list-inside list-disc text-xs text-destructive`,children:P.created.map((e,t)=>(0,k.jsxs)(`li`,{children:[e.type,`: `,e.id??`(created)`]},t))})]})]}),(0,k.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:V(ge),children:[(0,k.jsxs)(C,{children:[(0,k.jsx)(x,{children:(0,k.jsx)(`label`,{htmlFor:`lb-name`,children:`Name`})}),(0,k.jsx)(_,{"aria-invalid":!!q.name,id:`lb-name`,placeholder:`my-load-balancer`,...H(`name`)}),(0,k.jsx)(S,{errors:[q.name]})]}),(0,k.jsxs)(C,{children:[(0,k.jsx)(x,{children:`Scheme`}),(0,k.jsx)(T,{control:W,name:`scheme`,render:({field:e})=>(0,k.jsxs)(`div`,{className:`flex gap-4`,children:[(0,k.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[(0,k.jsx)(`input`,{"aria-label":`Internet-facing`,checked:e.value===`internet-facing`,name:`scheme`,onChange:()=>e.onChange(`internet-facing`),type:`radio`}),`Internet-facing`]}),(0,k.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[(0,k.jsx)(`input`,{"aria-label":`Internal`,checked:e.value===`internal`,name:`scheme`,onChange:()=>e.onChange(`internal`),type:`radio`}),`Internal`]})]})})]}),(0,k.jsxs)(C,{children:[(0,k.jsx)(x,{children:(0,k.jsx)(`label`,{htmlFor:`lb-vpc`,children:`VPC`})}),(0,k.jsx)(T,{control:W,name:`vpcId`,render:({field:e})=>(0,k.jsxs)(s,{onValueChange:e=>pe(e),value:e.value??``,children:[(0,k.jsx)(o,{"aria-invalid":!!q.vpcId,className:`w-full`,id:`lb-vpc`,children:(0,k.jsx)(r,{placeholder:`Select VPC`})}),(0,k.jsx)(a,{children:I.map(e=>(0,k.jsx)(i,{value:e.VpcId??``,children:A(e)},e.VpcId))})]})}),(0,k.jsx)(S,{errors:[q.vpcId]})]}),(0,k.jsxs)(C,{children:[(0,k.jsx)(x,{children:`Subnets (select at least 2)`}),$.length===0?(0,k.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No subnets in the selected VPC.`}):(0,k.jsx)(`div`,{className:`space-y-3`,children:$.map(e=>(0,k.jsxs)(`div`,{children:[(0,k.jsx)(`p`,{className:`mb-1 text-xs font-medium text-muted-foreground`,children:e.az}),(0,k.jsx)(`div`,{className:`space-y-1`,children:e.subnets.map(e=>(0,k.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[(0,k.jsx)(`input`,{"aria-label":`Subnet ${j(e)}`,checked:ue.includes(e.SubnetId??``),onChange:()=>me(e.SubnetId??``),type:`checkbox`}),(0,k.jsx)(`span`,{className:`font-mono`,children:j(e)})]},e.SubnetId))})]},e.az))}),(0,k.jsx)(S,{errors:[q.subnetIds]})]}),(0,k.jsxs)(C,{children:[(0,k.jsx)(x,{children:`Security groups`}),Z.length===0?(0,k.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No security groups in the selected VPC.`}):(0,k.jsx)(`div`,{className:`space-y-1`,children:Z.map(e=>(0,k.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[(0,k.jsx)(`input`,{"aria-label":`Security group ${e.GroupId} (${e.GroupName})`,checked:de.includes(e.GroupId??``),onChange:()=>he(e.GroupId??``),type:`checkbox`}),(0,k.jsxs)(`span`,{className:`font-mono`,children:[e.GroupId,` (`,e.GroupName,`)`]})]},e.GroupId))})]}),(0,k.jsxs)(C,{children:[(0,k.jsx)(x,{children:`Tags`}),(0,k.jsxs)(`div`,{className:`space-y-2`,children:[fe.map((e,t)=>(0,k.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,k.jsx)(_,{placeholder:`Key`,...H(`tags.${t}.key`)}),(0,k.jsx)(_,{placeholder:`Value`,...H(`tags.${t}.value`)}),(0,k.jsx)(g,{onClick:()=>G(`tags`,K(`tags`).filter((e,n)=>n!==t)),size:`icon`,type:`button`,variant:`ghost`,children:(0,k.jsx)(u,{className:`size-3.5`})})]},t)),(0,k.jsxs)(g,{onClick:()=>G(`tags`,[...K(`tags`),{key:``,value:``}]),size:`sm`,type:`button`,variant:`outline`,children:[(0,k.jsx)(c,{className:`size-3.5`}),`Add tag`]})]})]}),(0,k.jsxs)(`div`,{className:`space-y-4 rounded-md border bg-card p-4`,children:[(0,k.jsx)(`h2`,{className:`text-sm font-semibold`,children:`First listener & default target group`}),(0,k.jsxs)(C,{children:[(0,k.jsx)(x,{children:(0,k.jsx)(`label`,{htmlFor:`listener-protocol`,children:`Protocol`})}),(0,k.jsx)(T,{control:W,name:`listener.protocol`,render:({field:e})=>(0,k.jsxs)(s,{onValueChange:e.onChange,value:e.value,children:[(0,k.jsx)(o,{className:`w-full`,id:`listener-protocol`,children:(0,k.jsx)(r,{})}),(0,k.jsx)(a,{children:(0,k.jsx)(i,{value:`HTTP`,children:`HTTP`})})]})})]}),(0,k.jsxs)(C,{children:[(0,k.jsx)(x,{children:(0,k.jsx)(`label`,{htmlFor:`listener-port`,children:`Port`})}),(0,k.jsx)(_,{"aria-invalid":!!q.listener?.port,id:`listener-port`,inputMode:`numeric`,type:`number`,...H(`listener.port`,{valueAsNumber:!0})}),(0,k.jsx)(S,{errors:[q.listener?.port]})]}),(0,k.jsxs)(C,{children:[(0,k.jsx)(x,{children:`Default target group`}),(0,k.jsx)(T,{control:W,name:`listener.targetGroupMode`,render:({field:e})=>(0,k.jsxs)(`div`,{className:`flex gap-4`,children:[(0,k.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[(0,k.jsx)(`input`,{"aria-label":`Create new target group`,checked:e.value===`new`,name:`tg-mode`,onChange:()=>e.onChange(`new`),type:`radio`}),`Create new`]}),(0,k.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[(0,k.jsx)(`input`,{"aria-label":`Use existing target group`,checked:e.value===`existing`,name:`tg-mode`,onChange:()=>e.onChange(`existing`),type:`radio`}),`Use existing`]})]})})]}),Y===`existing`&&(0,k.jsxs)(C,{children:[(0,k.jsx)(x,{children:(0,k.jsx)(`label`,{htmlFor:`tg-existing`,children:`Target group`})}),(0,k.jsx)(T,{control:W,name:`listener.existingTargetGroupArn`,render:({field:e})=>(0,k.jsxs)(s,{onValueChange:e.onChange,value:e.value??``,children:[(0,k.jsx)(o,{"aria-invalid":!!q.listener?.existingTargetGroupArn,className:`w-full`,id:`tg-existing`,children:(0,k.jsx)(r,{placeholder:`Select target group`})}),(0,k.jsx)(a,{children:Q.map(e=>(0,k.jsxs)(i,{value:e.TargetGroupArn??``,children:[e.TargetGroupName,` · `,e.Protocol,`:`,e.Port]},e.TargetGroupArn))})]})}),(0,k.jsx)(S,{errors:[q.listener?.existingTargetGroupArn]}),Q.length===0&&(0,k.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground`,children:`No target groups in this VPC. Choose “Create new” instead.`})]}),Y===`new`&&(0,k.jsx)(`div`,{className:`space-y-4 border-l-2 border-muted pl-4`,children:(0,k.jsx)(ie,{form:B,vpcs:I})})]}),(0,k.jsx)(l,{commands:se(U,B.watch)}),(0,k.jsx)(re,{isPending:N.isPending,isSubmitting:le,onCancel:async()=>await m({to:`/ec2/describe-load-balancers`}),pendingLabel:`Creating…`,submitLabel:`Create Load Balancer`})]})]})}function se(e,t){let n=t=>{let n=e(t);return typeof n==`string`?n:``},r=t=>{let n=e(t);return Array.isArray(n)?n.filter(e=>typeof e==`string`):[]},i=t=>{let n=e(t);return typeof n==`number`&&Number.isFinite(n)?n:void 0},a=n(`name`)||``,o=n(`scheme`)||`internet-facing`,s=r(`subnetIds`),c=r(`securityGroupIds`),l=n(`listener.protocol`)||`HTTP`,u=i(`listener.port`)??80,d=n(`listener.targetGroupMode`),f=n(`listener.existingTargetGroupArn`),p=[],m={type:`comment`,value:`# Create ALB with listener and default target group +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{c as r,i,n as a,s as o,t as s}from"./select.js";import{t as c}from"./plus.js";import{t as l}from"./cli-command-panel.js";import{t as u}from"./trash-2.js";import{n as d}from"./elbv2.js";import{Ja as f,Jo as p,N as m,Oo as h,X as g,et as _,it as v,ko as y,wo as b,za as x,zi as S}from"./index.js";import{t as ee}from"./page-heading.js";import{a as C,r as w,t as T}from"./field.js";import{i as E,n as D,t as O}from"./zod.js";import{t as te}from"./form-actions.js";import{t as ne}from"./target-group-form.js";import{a as re,r as ie}from"./elbv22.js";var k=p(y(),1),A=h();function j(e){let t=f(e.Tags);return t?`${e.VpcId} (${t})`:`${e.VpcId} (${e.CidrBlock})`}function M(e){let t=f(e.Tags);return`${t?`${e.SubnetId} (${t})`:e.SubnetId} · ${e.CidrBlock}`}function ae(e){let t=new Map;for(let n of e){let e=n.AvailabilityZone??`unknown`,r=t.get(e)??[];r.push(n),t.set(e,r)}return[...t.entries()].toSorted((e,t)=>e[0].localeCompare(t[0])).map(([e,t])=>({az:e,subnets:t}))}function N(){let f=b(),{data:p}=t(v),{data:h}=t(_),{data:y}=t(g),{data:N}=t(m),P=d(),[F,I]=(0,k.useState)(null),L=p.Vpcs??[],se=h.Subnets??[],ce=y.SecurityGroups??[],R=N.TargetGroups??[],z=E({resolver:O(ie),defaultValues:{name:``,scheme:`internet-facing`,vpcId:L[0]?.VpcId??``,subnetIds:[],securityGroupIds:[],tags:[],listener:{protocol:`HTTP`,port:80,targetGroupMode:`new`,existingTargetGroupArn:``}}}),B=E({resolver:O(re),defaultValues:{name:``,protocol:`HTTP`,port:80,vpcId:L[0]?.VpcId??``,healthCheck:{protocol:`HTTP`,path:`/`,port:`traffic-port`,intervalSeconds:30,timeoutSeconds:5,healthyThresholdCount:5,unhealthyThresholdCount:2,matcher:`200`},tags:[]}}),{handleSubmit:V,register:H,watch:U,control:W,setValue:G,getValues:K,formState:{errors:q,isSubmitting:le}}=z,J=U(`vpcId`),ue=U(`subnetIds`),de=U(`securityGroupIds`),Y=U(`listener.targetGroupMode`),fe=U(`tags`),X=se.filter(e=>e.VpcId===J),Z=ce.filter(e=>e.VpcId===J),Q=R.filter(e=>e.VpcId===J),pe=(e=``)=>{let t=e??``;G(`vpcId`,t,{shouldValidate:!0}),G(`subnetIds`,[],{shouldValidate:!0}),G(`securityGroupIds`,[]),G(`listener.existingTargetGroupArn`,``),B.setValue(`vpcId`,t)},me=e=>{let t=K(`subnetIds`);G(`subnetIds`,t.includes(e)?t.filter(t=>t!==e):[...t,e],{shouldValidate:!0})},he=e=>{let t=K(`securityGroupIds`);G(`securityGroupIds`,t.includes(e)?t.filter(t=>t!==e):[...t,e])},ge=async e=>{I(null);let t;if(e.listener.targetGroupMode===`new`){if(!await B.trigger())return;t=B.getValues()}let n=await P.mutateAsync({lb:{name:e.name,scheme:e.scheme,vpcId:e.vpcId,subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds,tags:e.tags},listener:{protocol:e.listener.protocol,port:e.listener.port,targetGroupMode:e.listener.targetGroupMode,existingTargetGroupArn:e.listener.existingTargetGroupArn,newTargetGroup:t}});I(n),!n.error&&n.loadBalancerArn&&f({to:`/ec2/describe-load-balancers/$id`,params:{id:encodeURIComponent(n.loadBalancerArn)}})},$=ae(X);return(0,A.jsxs)(A.Fragment,{children:[(0,A.jsx)(n,{to:`/ec2/describe-load-balancers`,children:`Back to load balancers`}),(0,A.jsx)(ee,{title:`Create Load Balancer`}),P.error&&(0,A.jsx)(e,{error:P.error,msg:`Failed to create load balancer`}),F?.error&&(0,A.jsxs)(`div`,{className:`mb-6 max-w-4xl rounded-md border border-destructive bg-destructive/10 p-4`,children:[(0,A.jsxs)(`h2`,{className:`text-sm font-medium text-destructive`,children:[`Wizard failed: `,F.failedStep]}),(0,A.jsx)(`p`,{className:`mt-1 text-sm text-destructive`,children:F.error.message}),F.created.length>0&&(0,A.jsxs)(`div`,{className:`mt-3`,children:[(0,A.jsx)(`p`,{className:`text-xs font-medium text-destructive`,children:`Successfully created resources (clean up manually if needed):`}),(0,A.jsx)(`ul`,{className:`mt-1 list-inside list-disc text-xs text-destructive`,children:F.created.map((e,t)=>(0,A.jsxs)(`li`,{children:[e.type,`: `,e.id??`(created)`]},t))})]})]}),(0,A.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:V(ge),children:[(0,A.jsxs)(T,{children:[(0,A.jsx)(C,{children:(0,A.jsx)(`label`,{htmlFor:`lb-name`,children:`Name`})}),(0,A.jsx)(S,{"aria-invalid":!!q.name,id:`lb-name`,placeholder:`my-load-balancer`,...H(`name`)}),(0,A.jsx)(w,{errors:[q.name]})]}),(0,A.jsxs)(T,{children:[(0,A.jsx)(C,{children:`Scheme`}),(0,A.jsx)(D,{control:W,name:`scheme`,render:({field:e})=>(0,A.jsxs)(`div`,{className:`flex gap-4`,children:[(0,A.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[(0,A.jsx)(`input`,{"aria-label":`Internet-facing`,checked:e.value===`internet-facing`,name:`scheme`,onChange:()=>e.onChange(`internet-facing`),type:`radio`}),`Internet-facing`]}),(0,A.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[(0,A.jsx)(`input`,{"aria-label":`Internal`,checked:e.value===`internal`,name:`scheme`,onChange:()=>e.onChange(`internal`),type:`radio`}),`Internal`]})]})})]}),(0,A.jsxs)(T,{children:[(0,A.jsx)(C,{children:(0,A.jsx)(`label`,{htmlFor:`lb-vpc`,children:`VPC`})}),(0,A.jsx)(D,{control:W,name:`vpcId`,render:({field:e})=>(0,A.jsxs)(s,{onValueChange:e=>pe(e),value:e.value??``,children:[(0,A.jsx)(o,{"aria-invalid":!!q.vpcId,className:`w-full`,id:`lb-vpc`,children:(0,A.jsx)(r,{placeholder:`Select VPC`})}),(0,A.jsx)(a,{children:L.map(e=>(0,A.jsx)(i,{value:e.VpcId??``,children:j(e)},e.VpcId))})]})}),(0,A.jsx)(w,{errors:[q.vpcId]})]}),(0,A.jsxs)(T,{children:[(0,A.jsx)(C,{children:`Subnets (select at least 2)`}),$.length===0?(0,A.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No subnets in the selected VPC.`}):(0,A.jsx)(`div`,{className:`space-y-3`,children:$.map(e=>(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`p`,{className:`mb-1 text-xs font-medium text-muted-foreground`,children:e.az}),(0,A.jsx)(`div`,{className:`space-y-1`,children:e.subnets.map(e=>(0,A.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[(0,A.jsx)(`input`,{"aria-label":`Subnet ${M(e)}`,checked:ue.includes(e.SubnetId??``),onChange:()=>me(e.SubnetId??``),type:`checkbox`}),(0,A.jsx)(`span`,{className:`font-mono`,children:M(e)})]},e.SubnetId))})]},e.az))}),(0,A.jsx)(w,{errors:[q.subnetIds]})]}),(0,A.jsxs)(T,{children:[(0,A.jsx)(C,{children:`Security groups`}),Z.length===0?(0,A.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No security groups in the selected VPC.`}):(0,A.jsx)(`div`,{className:`space-y-1`,children:Z.map(e=>(0,A.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[(0,A.jsx)(`input`,{"aria-label":`Security group ${e.GroupId} (${e.GroupName})`,checked:de.includes(e.GroupId??``),onChange:()=>he(e.GroupId??``),type:`checkbox`}),(0,A.jsxs)(`span`,{className:`font-mono`,children:[e.GroupId,` (`,e.GroupName,`)`]})]},e.GroupId))})]}),(0,A.jsxs)(T,{children:[(0,A.jsx)(C,{children:`Tags`}),(0,A.jsxs)(`div`,{className:`space-y-2`,children:[fe.map((e,t)=>(0,A.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,A.jsx)(S,{placeholder:`Key`,...H(`tags.${t}.key`)}),(0,A.jsx)(S,{placeholder:`Value`,...H(`tags.${t}.value`)}),(0,A.jsx)(x,{onClick:()=>G(`tags`,K(`tags`).filter((e,n)=>n!==t)),size:`icon`,type:`button`,variant:`ghost`,children:(0,A.jsx)(u,{className:`size-3.5`})})]},t)),(0,A.jsxs)(x,{onClick:()=>G(`tags`,[...K(`tags`),{key:``,value:``}]),size:`sm`,type:`button`,variant:`outline`,children:[(0,A.jsx)(c,{className:`size-3.5`}),`Add tag`]})]})]}),(0,A.jsxs)(`div`,{className:`space-y-4 rounded-md border bg-card p-4`,children:[(0,A.jsx)(`h2`,{className:`text-sm font-semibold`,children:`First listener & default target group`}),(0,A.jsxs)(T,{children:[(0,A.jsx)(C,{children:(0,A.jsx)(`label`,{htmlFor:`listener-protocol`,children:`Protocol`})}),(0,A.jsx)(D,{control:W,name:`listener.protocol`,render:({field:e})=>(0,A.jsxs)(s,{onValueChange:e.onChange,value:e.value,children:[(0,A.jsx)(o,{className:`w-full`,id:`listener-protocol`,children:(0,A.jsx)(r,{})}),(0,A.jsx)(a,{children:(0,A.jsx)(i,{value:`HTTP`,children:`HTTP`})})]})})]}),(0,A.jsxs)(T,{children:[(0,A.jsx)(C,{children:(0,A.jsx)(`label`,{htmlFor:`listener-port`,children:`Port`})}),(0,A.jsx)(S,{"aria-invalid":!!q.listener?.port,id:`listener-port`,inputMode:`numeric`,type:`number`,...H(`listener.port`,{valueAsNumber:!0})}),(0,A.jsx)(w,{errors:[q.listener?.port]})]}),(0,A.jsxs)(T,{children:[(0,A.jsx)(C,{children:`Default target group`}),(0,A.jsx)(D,{control:W,name:`listener.targetGroupMode`,render:({field:e})=>(0,A.jsxs)(`div`,{className:`flex gap-4`,children:[(0,A.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[(0,A.jsx)(`input`,{"aria-label":`Create new target group`,checked:e.value===`new`,name:`tg-mode`,onChange:()=>e.onChange(`new`),type:`radio`}),`Create new`]}),(0,A.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[(0,A.jsx)(`input`,{"aria-label":`Use existing target group`,checked:e.value===`existing`,name:`tg-mode`,onChange:()=>e.onChange(`existing`),type:`radio`}),`Use existing`]})]})})]}),Y===`existing`&&(0,A.jsxs)(T,{children:[(0,A.jsx)(C,{children:(0,A.jsx)(`label`,{htmlFor:`tg-existing`,children:`Target group`})}),(0,A.jsx)(D,{control:W,name:`listener.existingTargetGroupArn`,render:({field:e})=>(0,A.jsxs)(s,{onValueChange:e.onChange,value:e.value??``,children:[(0,A.jsx)(o,{"aria-invalid":!!q.listener?.existingTargetGroupArn,className:`w-full`,id:`tg-existing`,children:(0,A.jsx)(r,{placeholder:`Select target group`})}),(0,A.jsx)(a,{children:Q.map(e=>(0,A.jsxs)(i,{value:e.TargetGroupArn??``,children:[e.TargetGroupName,` · `,e.Protocol,`:`,e.Port]},e.TargetGroupArn))})]})}),(0,A.jsx)(w,{errors:[q.listener?.existingTargetGroupArn]}),Q.length===0&&(0,A.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground`,children:`No target groups in this VPC. Choose “Create new” instead.`})]}),Y===`new`&&(0,A.jsx)(`div`,{className:`space-y-4 border-l-2 border-muted pl-4`,children:(0,A.jsx)(ne,{form:B,vpcs:L})})]}),(0,A.jsx)(l,{commands:oe(U,B.watch)}),(0,A.jsx)(te,{isPending:P.isPending,isSubmitting:le,onCancel:async()=>await f({to:`/ec2/describe-load-balancers`}),pendingLabel:`Creating…`,submitLabel:`Create Load Balancer`})]})]})}function oe(e,t){let n=t=>{let n=e(t);return typeof n==`string`?n:``},r=t=>{let n=e(t);return Array.isArray(n)?n.filter(e=>typeof e==`string`):[]},i=t=>{let n=e(t);return typeof n==`number`&&Number.isFinite(n)?n:void 0},a=n(`name`)||``,o=n(`scheme`)||`internet-facing`,s=r(`subnetIds`),c=r(`securityGroupIds`),l=n(`listener.protocol`)||`HTTP`,u=i(`listener.port`)??80,d=n(`listener.targetGroupMode`),f=n(`listener.existingTargetGroupArn`),p=[],m={type:`comment`,value:`# Create ALB with listener and default target group `},h=e=>{let n=t(e);return typeof n==`string`?n:``},g=e=>{let n=t(e);return typeof n==`number`&&Number.isFinite(n)?n:void 0};if(d===`new`){let e=h(`name`)||``,t=g(`port`)??80,n=h(`vpcId`);p.push({label:`Create Target Group`,parts:[m,{type:`variable`,value:`TG_ARN=`},{type:`bin`,value:`$(AWS_PROFILE=spinifex aws elbv2 create-target-group`},{type:`flag`,value:` \\ --name`},{type:`value`,value:` ${e}`},{type:`flag`,value:` \\ @@ -14,4 +14,4 @@ import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";impor --load-balancer-arn`},{type:`variable`,value:` "$LB_ARN"`},{type:`flag`,value:` \\ --protocol`},{type:`value`,value:` ${l}`},{type:`flag`,value:` \\ --port`},{type:`value`,value:` ${u}`},{type:`flag`,value:` \\ - --default-actions`},{type:`value`,value:` Type=forward,TargetGroupArn="$TG_ARN"`}]}),p}var N=M;export{N as component}; \ No newline at end of file + --default-actions`},{type:`value`,value:` Type=forward,TargetGroupArn="$TG_ARN"`}]}),p}var P=N;export{P as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/create-placement-group.js b/spinifex/services/spinifexui/frontend/dist/assets/create-placement-group.js index 87612e9f6..2470b116b 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/create-placement-group.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/create-placement-group.js @@ -1,3 +1,3 @@ -import{t as e}from"./error-banner.js";import{t}from"./back-link.js";import{c as n,i as r,n as i,s as a,t as o}from"./select.js";import{t as s}from"./cli-command-panel.js";import{c}from"./ec2.js";import{Ti as l,mo as u,so as d,uo as f}from"./index.js";import{t as p}from"./page-heading.js";import{a as m,r as h,t as g}from"./field.js";import{i as ee,n as te,t as ne}from"./zod.js";import{i as _}from"./ec22.js";import{t as v}from"./form-actions.js";var y=d(),b=u();function x(){let u=(0,y.c)(52),d=f(),x=c(),S;u[0]===Symbol.for(`react.memo_cache_sentinel`)?(S={resolver:ne(_),defaultValues:{groupName:``,strategy:`spread`}},u[0]=S):S=u[0];let{control:w,handleSubmit:T,register:E,watch:D,formState:O}=ee(S),{errors:k,isSubmitting:A}=O,j;u[1]!==x||u[2]!==d?(j=async e=>{d({to:`/ec2/describe-placement-groups/$id`,params:{id:(await x.mutateAsync(e)).PlacementGroup?.GroupId??``}})},u[1]=x,u[2]=d,u[3]=j):j=u[3];let M=j,N,P;u[4]===Symbol.for(`react.memo_cache_sentinel`)?(N=(0,b.jsx)(t,{to:`/ec2/describe-placement-groups`,children:`Back to placement groups`}),P=(0,b.jsx)(p,{title:`Create Placement Group`}),u[4]=N,u[5]=P):(N=u[4],P=u[5]);let F;u[6]===x.error?F=u[7]:(F=x.error&&(0,b.jsx)(e,{error:x.error,msg:`Failed to create placement group`}),u[6]=x.error,u[7]=F);let I;u[8]!==T||u[9]!==M?(I=T(M),u[8]=T,u[9]=M,u[10]=I):I=u[10];let L;u[11]===Symbol.for(`react.memo_cache_sentinel`)?(L=(0,b.jsx)(m,{children:(0,b.jsx)(`label`,{htmlFor:`groupName`,children:`Group Name`})}),u[11]=L):L=u[11];let R=!!k.groupName,z;u[12]===E?z=u[13]:(z=E(`groupName`),u[12]=E,u[13]=z);let B;u[14]!==R||u[15]!==z?(B=(0,b.jsx)(l,{"aria-invalid":R,id:`groupName`,placeholder:`my-placement-group`,...z}),u[14]=R,u[15]=z,u[16]=B):B=u[16];let V;u[17]===k.groupName?V=u[18]:(V=(0,b.jsx)(h,{errors:[k.groupName]}),u[17]=k.groupName,u[18]=V);let H;u[19]!==B||u[20]!==V?(H=(0,b.jsxs)(g,{children:[L,B,V]}),u[19]=B,u[20]=V,u[21]=H):H=u[21];let U;u[22]===Symbol.for(`react.memo_cache_sentinel`)?(U=(0,b.jsx)(m,{children:(0,b.jsx)(`label`,{htmlFor:`strategy`,children:`Strategy`})}),u[22]=U):U=u[22];let W;u[23]===k.strategy?W=u[24]:(W=e=>{let{field:t}=e;return(0,b.jsxs)(o,{onValueChange:e=>t.onChange(e),value:t.value??``,children:[(0,b.jsx)(a,{"aria-invalid":!!k.strategy,className:`w-full`,id:`strategy`,children:(0,b.jsx)(n,{})}),(0,b.jsxs)(i,{children:[(0,b.jsx)(r,{value:`spread`,children:`spread`}),(0,b.jsx)(r,{value:`cluster`,children:`cluster`})]})]})},u[23]=k.strategy,u[24]=W);let G;u[25]!==w||u[26]!==W?(G=(0,b.jsx)(te,{control:w,name:`strategy`,render:W}),u[25]=w,u[26]=W,u[27]=G):G=u[27];let K;u[28]===k.strategy?K=u[29]:(K=(0,b.jsx)(h,{errors:[k.strategy]}),u[28]=k.strategy,u[29]=K);let q;u[30]!==G||u[31]!==K?(q=(0,b.jsxs)(g,{children:[U,G,K]}),u[30]=G,u[31]=K,u[32]=q):q=u[32];let J;u[33]===D?J=u[34]:(J=C(D),u[33]=D,u[34]=J);let Y;u[35]===J?Y=u[36]:(Y=(0,b.jsx)(s,{commands:J}),u[35]=J,u[36]=Y);let X;u[37]===d?X=u[38]:(X=async()=>await d({to:`/ec2/describe-placement-groups`}),u[37]=d,u[38]=X);let Z;u[39]!==x.isPending||u[40]!==A||u[41]!==X?(Z=(0,b.jsx)(v,{isPending:x.isPending,isSubmitting:A,onCancel:X,pendingLabel:`Creating…`,submitLabel:`Create Placement Group`}),u[39]=x.isPending,u[40]=A,u[41]=X,u[42]=Z):Z=u[42];let Q;u[43]!==H||u[44]!==q||u[45]!==Y||u[46]!==Z||u[47]!==I?(Q=(0,b.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:I,children:[H,q,Y,Z]}),u[43]=H,u[44]=q,u[45]=Y,u[46]=Z,u[47]=I,u[48]=Q):Q=u[48];let $;return u[49]!==Q||u[50]!==F?($=(0,b.jsxs)(b.Fragment,{children:[N,P,F,Q]}),u[49]=Q,u[50]=F,u[51]=$):$=u[51],$}function S(e){return`'${e.replaceAll(`'`,`'"'"'`)}'`}function C(e){let t=e(`groupName`),n=typeof t==`string`?t:``,r=e(`strategy`),i=typeof r==`string`?r:``;return[{label:`Create Placement Group`,parts:[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 create-placement-group`},{type:`flag`,value:` \\ - --group-name`},{type:`value`,value:` ${n?S(n):``}`},{type:`flag`,value:` \\ - --strategy`},{type:`value`,value:` ${i||`spread`}`}]}]}export{x as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./back-link.js";import{c as n,i as r,n as i,s as a,t as ee}from"./select.js";import{t as o}from"./cli-command-panel.js";import{c as s}from"./ec2.js";import{Oo as c,wo as l,xo as u,zi as te}from"./index.js";import{t as ne}from"./page-heading.js";import{a as d,r as f,t as p}from"./field.js";import{a as re,i as ie,n as m,t as h}from"./zod.js";import{i as g}from"./ec22.js";import{t as _}from"./form-actions.js";var v=u(),y=c();function b(){let c=(0,v.c)(56),u=l(),b=s(),x;c[0]===Symbol.for(`react.memo_cache_sentinel`)?(x={resolver:h(g),defaultValues:{groupName:``,strategy:`spread`}},c[0]=x):x=c[0];let{control:S,handleSubmit:C,register:w,formState:oe}=ie(x),{errors:T,isSubmitting:E}=oe,D;c[1]===S?D=c[2]:(D={control:S},c[1]=S,c[2]=D);let O=re(D),k;c[3]===O?k=c[4]:(k=e=>e?O[e]:void 0,c[3]=O,c[4]=k);let A=k,j;c[5]!==b||c[6]!==u?(j=async e=>{u({to:`/ec2/describe-placement-groups/$id`,params:{id:(await b.mutateAsync(e)).PlacementGroup?.GroupId??``}})},c[5]=b,c[6]=u,c[7]=j):j=c[7];let M=j,N,P;c[8]===Symbol.for(`react.memo_cache_sentinel`)?(N=(0,y.jsx)(t,{to:`/ec2/describe-placement-groups`,children:`Back to placement groups`}),P=(0,y.jsx)(ne,{title:`Create Placement Group`}),c[8]=N,c[9]=P):(N=c[8],P=c[9]);let F;c[10]===b.error?F=c[11]:(F=b.error&&(0,y.jsx)(e,{error:b.error,msg:`Failed to create placement group`}),c[10]=b.error,c[11]=F);let I;c[12]!==C||c[13]!==M?(I=C(M),c[12]=C,c[13]=M,c[14]=I):I=c[14];let L;c[15]===Symbol.for(`react.memo_cache_sentinel`)?(L=(0,y.jsx)(d,{children:(0,y.jsx)(`label`,{htmlFor:`groupName`,children:`Group Name`})}),c[15]=L):L=c[15];let R=!!T.groupName,z;c[16]===w?z=c[17]:(z=w(`groupName`),c[16]=w,c[17]=z);let B;c[18]!==R||c[19]!==z?(B=(0,y.jsx)(te,{"aria-invalid":R,id:`groupName`,placeholder:`my-placement-group`,...z}),c[18]=R,c[19]=z,c[20]=B):B=c[20];let V;c[21]===T.groupName?V=c[22]:(V=(0,y.jsx)(f,{errors:[T.groupName]}),c[21]=T.groupName,c[22]=V);let H;c[23]!==B||c[24]!==V?(H=(0,y.jsxs)(p,{children:[L,B,V]}),c[23]=B,c[24]=V,c[25]=H):H=c[25];let U;c[26]===Symbol.for(`react.memo_cache_sentinel`)?(U=(0,y.jsx)(d,{children:(0,y.jsx)(`label`,{htmlFor:`strategy`,children:`Strategy`})}),c[26]=U):U=c[26];let W;c[27]===T.strategy?W=c[28]:(W=e=>{let{field:t}=e;return(0,y.jsxs)(ee,{onValueChange:e=>t.onChange(e),value:t.value??``,children:[(0,y.jsx)(a,{"aria-invalid":!!T.strategy,className:`w-full`,id:`strategy`,children:(0,y.jsx)(n,{})}),(0,y.jsxs)(i,{children:[(0,y.jsx)(r,{value:`spread`,children:`spread`}),(0,y.jsx)(r,{value:`cluster`,children:`cluster`})]})]})},c[27]=T.strategy,c[28]=W);let G;c[29]!==S||c[30]!==W?(G=(0,y.jsx)(m,{control:S,name:`strategy`,render:W}),c[29]=S,c[30]=W,c[31]=G):G=c[31];let K;c[32]===T.strategy?K=c[33]:(K=(0,y.jsx)(f,{errors:[T.strategy]}),c[32]=T.strategy,c[33]=K);let q;c[34]!==G||c[35]!==K?(q=(0,y.jsxs)(p,{children:[U,G,K]}),c[34]=G,c[35]=K,c[36]=q):q=c[36];let J;c[37]===A?J=c[38]:(J=ae(A),c[37]=A,c[38]=J);let Y;c[39]===J?Y=c[40]:(Y=(0,y.jsx)(o,{commands:J}),c[39]=J,c[40]=Y);let X;c[41]===u?X=c[42]:(X=async()=>await u({to:`/ec2/describe-placement-groups`}),c[41]=u,c[42]=X);let Z;c[43]!==b.isPending||c[44]!==E||c[45]!==X?(Z=(0,y.jsx)(_,{isPending:b.isPending,isSubmitting:E,onCancel:X,pendingLabel:`Creating…`,submitLabel:`Create Placement Group`}),c[43]=b.isPending,c[44]=E,c[45]=X,c[46]=Z):Z=c[46];let Q;c[47]!==H||c[48]!==q||c[49]!==Y||c[50]!==Z||c[51]!==I?(Q=(0,y.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:I,children:[H,q,Y,Z]}),c[47]=H,c[48]=q,c[49]=Y,c[50]=Z,c[51]=I,c[52]=Q):Q=c[52];let $;return c[53]!==Q||c[54]!==F?($=(0,y.jsxs)(y.Fragment,{children:[N,P,F,Q]}),c[53]=Q,c[54]=F,c[55]=$):$=c[55],$}function x(e){return`'${e.replaceAll(`'`,`'"'"'`)}'`}function ae(e){let t=e(`groupName`),n=typeof t==`string`?t:``,r=e(`strategy`),i=typeof r==`string`?r:``;return[{label:`Create Placement Group`,parts:[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 create-placement-group`},{type:`flag`,value:` \\ + --group-name`},{type:`value`,value:` ${n?x(n):``}`},{type:`flag`,value:` \\ + --strategy`},{type:`value`,value:` ${i||`spread`}`}]}]}export{b as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/create-policy.js b/spinifex/services/spinifexui/frontend/dist/assets/create-policy.js index a2e1df5ce..79108395d 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/create-policy.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/create-policy.js @@ -1,4 +1,4 @@ -import{t as e}from"./error-banner.js";import{t}from"./back-link.js";import{t as n}from"./cli-command-panel.js";import{r}from"./iam.js";import{Ti as i,mo as a,so as o,uo as s}from"./index.js";import{t as c}from"./page-heading.js";import{a as l,r as u,t as d}from"./field.js";import{t as f}from"./textarea.js";import{i as p,t as m}from"./zod.js";import{t as h}from"./form-actions.js";import{t as g}from"./iam2.js";var ee=o(),_=a(),te=JSON.stringify({Version:`2012-10-17`,Statement:[{Effect:`Allow`,Action:`*`,Resource:`*`}]},null,2);function v(){let a=(0,ee.c)(63),o=s(),v=r(),y;a[0]===Symbol.for(`react.memo_cache_sentinel`)?(y={resolver:m(g),defaultValues:{policyDocument:te}},a[0]=y):y=a[0];let{handleSubmit:b,register:x,watch:S,formState:re}=p(y),{errors:C,isSubmitting:w}=re,T;a[1]!==v||a[2]!==o?(T=async e=>{await v.mutateAsync(e),o({to:`/iam/list-policies`})},a[1]=v,a[2]=o,a[3]=T):T=a[3];let E=T,D,O;a[4]===Symbol.for(`react.memo_cache_sentinel`)?(D=(0,_.jsx)(t,{to:`/iam/list-policies`,children:`Back to policies`}),O=(0,_.jsx)(c,{title:`Create Policy`}),a[4]=D,a[5]=O):(D=a[4],O=a[5]);let k;a[6]===v.error?k=a[7]:(k=v.error&&(0,_.jsx)(e,{error:v.error,msg:`Failed to create policy`}),a[6]=v.error,a[7]=k);let A;a[8]!==b||a[9]!==E?(A=b(E),a[8]=b,a[9]=E,a[10]=A):A=a[10];let j;a[11]===Symbol.for(`react.memo_cache_sentinel`)?(j=(0,_.jsx)(l,{children:(0,_.jsx)(`label`,{htmlFor:`policyName`,children:`Policy Name`})}),a[11]=j):j=a[11];let M=!!C.policyName,N;a[12]===x?N=a[13]:(N=x(`policyName`),a[12]=x,a[13]=N);let P;a[14]!==M||a[15]!==N?(P=(0,_.jsx)(i,{"aria-invalid":M,id:`policyName`,placeholder:`my-policy...`,...N}),a[14]=M,a[15]=N,a[16]=P):P=a[16];let F;a[17]===C.policyName?F=a[18]:(F=(0,_.jsx)(u,{errors:[C.policyName]}),a[17]=C.policyName,a[18]=F);let I;a[19]!==P||a[20]!==F?(I=(0,_.jsxs)(d,{children:[j,P,F]}),a[19]=P,a[20]=F,a[21]=I):I=a[21];let L;a[22]===Symbol.for(`react.memo_cache_sentinel`)?(L=(0,_.jsx)(l,{children:(0,_.jsx)(`label`,{htmlFor:`description`,children:`Description (optional)`})}),a[22]=L):L=a[22];let R;a[23]===x?R=a[24]:(R=x(`description`),a[23]=x,a[24]=R);let z;a[25]===R?z=a[26]:(z=(0,_.jsx)(i,{id:`description`,placeholder:`A brief description of this policy...`,...R}),a[25]=R,a[26]=z);let B;a[27]===C.description?B=a[28]:(B=(0,_.jsx)(u,{errors:[C.description]}),a[27]=C.description,a[28]=B);let V;a[29]!==z||a[30]!==B?(V=(0,_.jsxs)(d,{children:[L,z,B]}),a[29]=z,a[30]=B,a[31]=V):V=a[31];let H;a[32]===Symbol.for(`react.memo_cache_sentinel`)?(H=(0,_.jsx)(l,{children:(0,_.jsx)(`label`,{htmlFor:`policyDocument`,children:`Policy Document (JSON)`})}),a[32]=H):H=a[32];let U=!!C.policyDocument,W;a[33]===x?W=a[34]:(W=x(`policyDocument`),a[33]=x,a[34]=W);let G;a[35]!==U||a[36]!==W?(G=(0,_.jsx)(f,{"aria-invalid":U,className:`font-mono text-sm`,id:`policyDocument`,rows:15,...W}),a[35]=U,a[36]=W,a[37]=G):G=a[37];let K;a[38]===C.policyDocument?K=a[39]:(K=(0,_.jsx)(u,{errors:[C.policyDocument]}),a[38]=C.policyDocument,a[39]=K);let q;a[40]!==G||a[41]!==K?(q=(0,_.jsxs)(d,{children:[H,G,K]}),a[40]=G,a[41]=K,a[42]=q):q=a[42];let J;a[43]===S?J=a[44]:(J=ne(S),a[43]=S,a[44]=J);let Y;a[45]===J?Y=a[46]:(Y=(0,_.jsx)(n,{commands:J}),a[45]=J,a[46]=Y);let X;a[47]===o?X=a[48]:(X=async()=>await o({to:`/iam/list-policies`}),a[47]=o,a[48]=X);let Z;a[49]!==v.isPending||a[50]!==w||a[51]!==X?(Z=(0,_.jsx)(h,{isPending:v.isPending,isSubmitting:w,onCancel:X,pendingLabel:`Creating...`,submitLabel:`Create Policy`}),a[49]=v.isPending,a[50]=w,a[51]=X,a[52]=Z):Z=a[52];let Q;a[53]!==I||a[54]!==V||a[55]!==q||a[56]!==Y||a[57]!==Z||a[58]!==A?(Q=(0,_.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:A,children:[I,V,q,Y,Z]}),a[53]=I,a[54]=V,a[55]=q,a[56]=Y,a[57]=Z,a[58]=A,a[59]=Q):Q=a[59];let $;return a[60]!==Q||a[61]!==k?($=(0,_.jsxs)(_.Fragment,{children:[D,O,k,Q]}),a[60]=Q,a[61]=k,a[62]=$):$=a[62],$}function ne(e){let t=e(`policyName`),n=typeof t==`string`?t:``,r=e(`description`),i=typeof r==`string`?r:``,a=e(`policyDocument`),o=typeof a==`string`?a:``,s=[{type:`bin`,value:`AWS_PROFILE=spinifex aws iam create-policy`},{type:`flag`,value:` \\ +import{t as e}from"./error-banner.js";import{t}from"./back-link.js";import{t as n}from"./cli-command-panel.js";import{r}from"./iam.js";import{Oo as i,wo as a,xo as o,zi as s}from"./index.js";import{t as c}from"./page-heading.js";import{a as l,r as u,t as d}from"./field.js";import{t as ee}from"./textarea.js";import{a as te,i as ne,t as re}from"./zod.js";import{t as ie}from"./form-actions.js";import{t as f}from"./iam2.js";var ae=o(),p=i(),oe=JSON.stringify({Version:`2012-10-17`,Statement:[{Effect:`Allow`,Action:`*`,Resource:`*`}]},null,2);function m(){let i=(0,ae.c)(67),o=a(),m=r(),h;i[0]===Symbol.for(`react.memo_cache_sentinel`)?(h={resolver:re(f),defaultValues:{policyDocument:oe}},i[0]=h):h=i[0];let{handleSubmit:g,register:_,control:v,formState:ce}=ne(h),{errors:y,isSubmitting:b}=ce,x;i[1]===v?x=i[2]:(x={control:v},i[1]=v,i[2]=x);let S=te(x),C;i[3]===S?C=i[4]:(C=e=>e?S[e]:void 0,i[3]=S,i[4]=C);let w=C,T;i[5]!==m||i[6]!==o?(T=async e=>{await m.mutateAsync(e),o({to:`/iam/list-policies`})},i[5]=m,i[6]=o,i[7]=T):T=i[7];let E=T,D,O;i[8]===Symbol.for(`react.memo_cache_sentinel`)?(D=(0,p.jsx)(t,{to:`/iam/list-policies`,children:`Back to policies`}),O=(0,p.jsx)(c,{title:`Create Policy`}),i[8]=D,i[9]=O):(D=i[8],O=i[9]);let k;i[10]===m.error?k=i[11]:(k=m.error&&(0,p.jsx)(e,{error:m.error,msg:`Failed to create policy`}),i[10]=m.error,i[11]=k);let A;i[12]!==g||i[13]!==E?(A=g(E),i[12]=g,i[13]=E,i[14]=A):A=i[14];let j;i[15]===Symbol.for(`react.memo_cache_sentinel`)?(j=(0,p.jsx)(l,{children:(0,p.jsx)(`label`,{htmlFor:`policyName`,children:`Policy Name`})}),i[15]=j):j=i[15];let M=!!y.policyName,N;i[16]===_?N=i[17]:(N=_(`policyName`),i[16]=_,i[17]=N);let P;i[18]!==M||i[19]!==N?(P=(0,p.jsx)(s,{"aria-invalid":M,id:`policyName`,placeholder:`my-policy...`,...N}),i[18]=M,i[19]=N,i[20]=P):P=i[20];let F;i[21]===y.policyName?F=i[22]:(F=(0,p.jsx)(u,{errors:[y.policyName]}),i[21]=y.policyName,i[22]=F);let I;i[23]!==P||i[24]!==F?(I=(0,p.jsxs)(d,{children:[j,P,F]}),i[23]=P,i[24]=F,i[25]=I):I=i[25];let L;i[26]===Symbol.for(`react.memo_cache_sentinel`)?(L=(0,p.jsx)(l,{children:(0,p.jsx)(`label`,{htmlFor:`description`,children:`Description (optional)`})}),i[26]=L):L=i[26];let R;i[27]===_?R=i[28]:(R=_(`description`),i[27]=_,i[28]=R);let z;i[29]===R?z=i[30]:(z=(0,p.jsx)(s,{id:`description`,placeholder:`A brief description of this policy...`,...R}),i[29]=R,i[30]=z);let B;i[31]===y.description?B=i[32]:(B=(0,p.jsx)(u,{errors:[y.description]}),i[31]=y.description,i[32]=B);let V;i[33]!==z||i[34]!==B?(V=(0,p.jsxs)(d,{children:[L,z,B]}),i[33]=z,i[34]=B,i[35]=V):V=i[35];let H;i[36]===Symbol.for(`react.memo_cache_sentinel`)?(H=(0,p.jsx)(l,{children:(0,p.jsx)(`label`,{htmlFor:`policyDocument`,children:`Policy Document (JSON)`})}),i[36]=H):H=i[36];let U=!!y.policyDocument,W;i[37]===_?W=i[38]:(W=_(`policyDocument`),i[37]=_,i[38]=W);let G;i[39]!==U||i[40]!==W?(G=(0,p.jsx)(ee,{"aria-invalid":U,className:`font-mono text-sm`,id:`policyDocument`,rows:15,...W}),i[39]=U,i[40]=W,i[41]=G):G=i[41];let K;i[42]===y.policyDocument?K=i[43]:(K=(0,p.jsx)(u,{errors:[y.policyDocument]}),i[42]=y.policyDocument,i[43]=K);let q;i[44]!==G||i[45]!==K?(q=(0,p.jsxs)(d,{children:[H,G,K]}),i[44]=G,i[45]=K,i[46]=q):q=i[46];let J;i[47]===w?J=i[48]:(J=se(w),i[47]=w,i[48]=J);let Y;i[49]===J?Y=i[50]:(Y=(0,p.jsx)(n,{commands:J}),i[49]=J,i[50]=Y);let X;i[51]===o?X=i[52]:(X=async()=>await o({to:`/iam/list-policies`}),i[51]=o,i[52]=X);let Z;i[53]!==m.isPending||i[54]!==b||i[55]!==X?(Z=(0,p.jsx)(ie,{isPending:m.isPending,isSubmitting:b,onCancel:X,pendingLabel:`Creating...`,submitLabel:`Create Policy`}),i[53]=m.isPending,i[54]=b,i[55]=X,i[56]=Z):Z=i[56];let Q;i[57]!==I||i[58]!==V||i[59]!==q||i[60]!==Y||i[61]!==Z||i[62]!==A?(Q=(0,p.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:A,children:[I,V,q,Y,Z]}),i[57]=I,i[58]=V,i[59]=q,i[60]=Y,i[61]=Z,i[62]=A,i[63]=Q):Q=i[63];let $;return i[64]!==Q||i[65]!==k?($=(0,p.jsxs)(p.Fragment,{children:[D,O,k,Q]}),i[64]=Q,i[65]=k,i[66]=$):$=i[66],$}function se(e){let t=e(`policyName`),n=typeof t==`string`?t:``,r=e(`description`),i=typeof r==`string`?r:``,a=e(`policyDocument`),o=typeof a==`string`?a:``,s=[{type:`bin`,value:`AWS_PROFILE=spinifex aws iam create-policy`},{type:`flag`,value:` \\ --policy-name`},{type:`value`,value:` ${n||``}`}];return i&&s.push({type:`flag`,value:` \\ --description`},{type:`value`,value:` "${i}"`}),s.push({type:`flag`,value:` \\ - --policy-document`},{type:`value`,value:` '${o||``}'`}),[{label:`Create Policy`,parts:s}]}export{v as component}; \ No newline at end of file + --policy-document`},{type:`value`,value:` '${o||``}'`}),[{label:`Create Policy`,parts:s}]}export{m as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/create-security-group.js b/spinifex/services/spinifexui/frontend/dist/assets/create-security-group.js index 3c0983ee0..4585e89d0 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/create-security-group.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/create-security-group.js @@ -1,4 +1,4 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as ee}from"./back-link.js";import{c as n,i as r,n as i,s as a,t as o}from"./select.js";import{t as te}from"./cli-command-panel.js";import{l as ne}from"./ec2.js";import{Pa as s,Ti as re,mo as c,rt as ie,so as l,uo as ae}from"./index.js";import{t as oe}from"./page-heading.js";import{a as u,r as d,t as f}from"./field.js";import{i as se,n as ce,t as le}from"./zod.js";import{a as ue}from"./ec22.js";import{t as de}from"./form-actions.js";var fe=l(),p=c();function m(){let r=(0,fe.c)(69),s=ae(),{data:c}=t(ie),l=ne(),m;r[0]===c.Vpcs?m=r[1]:(m=c.Vpcs??[],r[0]=c.Vpcs,r[1]=m);let h=m,g;r[2]===Symbol.for(`react.memo_cache_sentinel`)?(g=le(ue),r[2]=g):g=r[2];let _=h[0]?.VpcId??``,v;r[3]===_?v=r[4]:(v={resolver:g,defaultValues:{groupName:``,description:``,vpcId:_}},r[3]=_,r[4]=v);let{control:y,handleSubmit:b,register:x,watch:S,formState:he}=se(v),{errors:C,isSubmitting:w}=he,T;r[5]!==l||r[6]!==s?(T=async e=>{let t=(await l.mutateAsync(e)).GroupId;s(t?{to:`/ec2/describe-security-groups/$id`,params:{id:t}}:{to:`/ec2/describe-security-groups`})},r[5]=l,r[6]=s,r[7]=T):T=r[7];let E=T,D,O;r[8]===Symbol.for(`react.memo_cache_sentinel`)?(D=(0,p.jsx)(ee,{to:`/ec2/describe-security-groups`,children:`Back to Security Groups`}),O=(0,p.jsx)(oe,{title:`Create Security Group`}),r[8]=D,r[9]=O):(D=r[8],O=r[9]);let k;r[10]===l.error?k=r[11]:(k=l.error&&(0,p.jsx)(e,{error:l.error,msg:`Failed to create security group`}),r[10]=l.error,r[11]=k);let A;r[12]!==b||r[13]!==E?(A=b(E),r[12]=b,r[13]=E,r[14]=A):A=r[14];let j;r[15]===Symbol.for(`react.memo_cache_sentinel`)?(j=(0,p.jsx)(u,{children:(0,p.jsx)(`label`,{htmlFor:`groupName`,children:`Group Name`})}),r[15]=j):j=r[15];let M=!!C.groupName,N;r[16]===x?N=r[17]:(N=x(`groupName`),r[16]=x,r[17]=N);let P;r[18]!==M||r[19]!==N?(P=(0,p.jsx)(re,{"aria-invalid":M,id:`groupName`,placeholder:`my-security-group`,...N}),r[18]=M,r[19]=N,r[20]=P):P=r[20];let F;r[21]===C.groupName?F=r[22]:(F=(0,p.jsx)(d,{errors:[C.groupName]}),r[21]=C.groupName,r[22]=F);let I;r[23]!==P||r[24]!==F?(I=(0,p.jsxs)(f,{children:[j,P,F]}),r[23]=P,r[24]=F,r[25]=I):I=r[25];let L;r[26]===Symbol.for(`react.memo_cache_sentinel`)?(L=(0,p.jsx)(u,{children:(0,p.jsx)(`label`,{htmlFor:`description`,children:`Description`})}),r[26]=L):L=r[26];let R=!!C.description,z;r[27]===x?z=r[28]:(z=x(`description`),r[27]=x,r[28]=z);let B;r[29]!==R||r[30]!==z?(B=(0,p.jsx)(re,{"aria-invalid":R,id:`description`,placeholder:`My security group description`,...z}),r[29]=R,r[30]=z,r[31]=B):B=r[31];let V;r[32]===C.description?V=r[33]:(V=(0,p.jsx)(d,{errors:[C.description]}),r[32]=C.description,r[33]=V);let H;r[34]!==B||r[35]!==V?(H=(0,p.jsxs)(f,{children:[L,B,V]}),r[34]=B,r[35]=V,r[36]=H):H=r[36];let U;r[37]===Symbol.for(`react.memo_cache_sentinel`)?(U=(0,p.jsx)(u,{children:(0,p.jsx)(`label`,{htmlFor:`vpcId`,children:`VPC`})}),r[37]=U):U=r[37];let W;r[38]!==C.vpcId||r[39]!==h?(W=e=>{let{field:t}=e;return(0,p.jsxs)(o,{onValueChange:e=>t.onChange(e),value:t.value??``,children:[(0,p.jsx)(a,{"aria-invalid":!!C.vpcId,className:`w-full`,id:`vpcId`,children:(0,p.jsx)(n,{})}),(0,p.jsx)(i,{children:h.map(pe)})]})},r[38]=C.vpcId,r[39]=h,r[40]=W):W=r[40];let G;r[41]!==y||r[42]!==W?(G=(0,p.jsx)(ce,{control:y,name:`vpcId`,render:W}),r[41]=y,r[42]=W,r[43]=G):G=r[43];let K;r[44]===C.vpcId?K=r[45]:(K=(0,p.jsx)(d,{errors:[C.vpcId]}),r[44]=C.vpcId,r[45]=K);let q;r[46]!==G||r[47]!==K?(q=(0,p.jsxs)(f,{children:[U,G,K]}),r[46]=G,r[47]=K,r[48]=q):q=r[48];let J;r[49]===S?J=r[50]:(J=me(S),r[49]=S,r[50]=J);let Y;r[51]===J?Y=r[52]:(Y=(0,p.jsx)(te,{commands:J}),r[51]=J,r[52]=Y);let X;r[53]===s?X=r[54]:(X=async()=>await s({to:`/ec2/describe-security-groups`}),r[53]=s,r[54]=X);let Z;r[55]!==l.isPending||r[56]!==w||r[57]!==X?(Z=(0,p.jsx)(de,{isPending:l.isPending,isSubmitting:w,onCancel:X,pendingLabel:`Creating…`,submitLabel:`Create Security Group`}),r[55]=l.isPending,r[56]=w,r[57]=X,r[58]=Z):Z=r[58];let Q;r[59]!==I||r[60]!==H||r[61]!==q||r[62]!==Y||r[63]!==Z||r[64]!==A?(Q=(0,p.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:A,children:[I,H,q,Y,Z]}),r[59]=I,r[60]=H,r[61]=q,r[62]=Y,r[63]=Z,r[64]=A,r[65]=Q):Q=r[65];let $;return r[66]!==Q||r[67]!==k?($=(0,p.jsxs)(p.Fragment,{children:[D,O,k,Q]}),r[66]=Q,r[67]=k,r[68]=$):$=r[68],$}function pe(e){let t=s(e.Tags);return(0,p.jsx)(r,{value:e.VpcId??``,children:t?`${e.VpcId} (${t})`:`${e.VpcId} (${e.CidrBlock})`},e.VpcId)}function me(e){let t=e(`groupName`),ee=typeof t==`string`?t:``,n=e(`description`),r=typeof n==`string`?n:``,i=e(`vpcId`),a=typeof i==`string`?i:``,o=[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 create-security-group`},{type:`flag`,value:` \\ +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as ee}from"./back-link.js";import{c as n,i as r,n as i,s as a,t as o}from"./select.js";import{t as te}from"./cli-command-panel.js";import{l as ne}from"./ec2.js";import{Ja as s,Oo as c,it as re,wo as ie,xo as l,zi as ae}from"./index.js";import{t as oe}from"./page-heading.js";import{a as se,r as ce,t as u}from"./field.js";import{a as le,i as ue,n as de,t as fe}from"./zod.js";import{a as pe}from"./ec22.js";import{t as me}from"./form-actions.js";var he=l(),d=c();function f(){let r=(0,he.c)(73),s=ie(),{data:c}=t(re),l=ne(),f;r[0]===c.Vpcs?f=r[1]:(f=c.Vpcs??[],r[0]=c.Vpcs,r[1]=f);let p=f,m;r[2]===Symbol.for(`react.memo_cache_sentinel`)?(m=fe(pe),r[2]=m):m=r[2];let h=p[0]?.VpcId??``,g;r[3]===h?g=r[4]:(g={resolver:m,defaultValues:{groupName:``,description:``,vpcId:h}},r[3]=h,r[4]=g);let{control:_,handleSubmit:v,register:y,formState:ve}=ue(g),{errors:b,isSubmitting:x}=ve,S;r[5]===_?S=r[6]:(S={control:_},r[5]=_,r[6]=S);let ye=le(S),C;r[7]===ye?C=r[8]:(C=e=>e?ye[e]:void 0,r[7]=ye,r[8]=C);let w=C,T;r[9]!==l||r[10]!==s?(T=async e=>{let t=(await l.mutateAsync(e)).GroupId;s(t?{to:`/ec2/describe-security-groups/$id`,params:{id:t}}:{to:`/ec2/describe-security-groups`})},r[9]=l,r[10]=s,r[11]=T):T=r[11];let E=T,D,O;r[12]===Symbol.for(`react.memo_cache_sentinel`)?(D=(0,d.jsx)(ee,{to:`/ec2/describe-security-groups`,children:`Back to Security Groups`}),O=(0,d.jsx)(oe,{title:`Create Security Group`}),r[12]=D,r[13]=O):(D=r[12],O=r[13]);let k;r[14]===l.error?k=r[15]:(k=l.error&&(0,d.jsx)(e,{error:l.error,msg:`Failed to create security group`}),r[14]=l.error,r[15]=k);let A;r[16]!==v||r[17]!==E?(A=v(E),r[16]=v,r[17]=E,r[18]=A):A=r[18];let j;r[19]===Symbol.for(`react.memo_cache_sentinel`)?(j=(0,d.jsx)(se,{children:(0,d.jsx)(`label`,{htmlFor:`groupName`,children:`Group Name`})}),r[19]=j):j=r[19];let M=!!b.groupName,N;r[20]===y?N=r[21]:(N=y(`groupName`),r[20]=y,r[21]=N);let P;r[22]!==M||r[23]!==N?(P=(0,d.jsx)(ae,{"aria-invalid":M,id:`groupName`,placeholder:`my-security-group`,...N}),r[22]=M,r[23]=N,r[24]=P):P=r[24];let F;r[25]===b.groupName?F=r[26]:(F=(0,d.jsx)(ce,{errors:[b.groupName]}),r[25]=b.groupName,r[26]=F);let I;r[27]!==P||r[28]!==F?(I=(0,d.jsxs)(u,{children:[j,P,F]}),r[27]=P,r[28]=F,r[29]=I):I=r[29];let L;r[30]===Symbol.for(`react.memo_cache_sentinel`)?(L=(0,d.jsx)(se,{children:(0,d.jsx)(`label`,{htmlFor:`description`,children:`Description`})}),r[30]=L):L=r[30];let R=!!b.description,z;r[31]===y?z=r[32]:(z=y(`description`),r[31]=y,r[32]=z);let B;r[33]!==R||r[34]!==z?(B=(0,d.jsx)(ae,{"aria-invalid":R,id:`description`,placeholder:`My security group description`,...z}),r[33]=R,r[34]=z,r[35]=B):B=r[35];let V;r[36]===b.description?V=r[37]:(V=(0,d.jsx)(ce,{errors:[b.description]}),r[36]=b.description,r[37]=V);let H;r[38]!==B||r[39]!==V?(H=(0,d.jsxs)(u,{children:[L,B,V]}),r[38]=B,r[39]=V,r[40]=H):H=r[40];let U;r[41]===Symbol.for(`react.memo_cache_sentinel`)?(U=(0,d.jsx)(se,{children:(0,d.jsx)(`label`,{htmlFor:`vpcId`,children:`VPC`})}),r[41]=U):U=r[41];let W;r[42]!==b.vpcId||r[43]!==p?(W=e=>{let{field:t}=e;return(0,d.jsxs)(o,{onValueChange:e=>t.onChange(e),value:t.value??``,children:[(0,d.jsx)(a,{"aria-invalid":!!b.vpcId,className:`w-full`,id:`vpcId`,children:(0,d.jsx)(n,{})}),(0,d.jsx)(i,{children:p.map(ge)})]})},r[42]=b.vpcId,r[43]=p,r[44]=W):W=r[44];let G;r[45]!==_||r[46]!==W?(G=(0,d.jsx)(de,{control:_,name:`vpcId`,render:W}),r[45]=_,r[46]=W,r[47]=G):G=r[47];let K;r[48]===b.vpcId?K=r[49]:(K=(0,d.jsx)(ce,{errors:[b.vpcId]}),r[48]=b.vpcId,r[49]=K);let q;r[50]!==G||r[51]!==K?(q=(0,d.jsxs)(u,{children:[U,G,K]}),r[50]=G,r[51]=K,r[52]=q):q=r[52];let J;r[53]===w?J=r[54]:(J=_e(w),r[53]=w,r[54]=J);let Y;r[55]===J?Y=r[56]:(Y=(0,d.jsx)(te,{commands:J}),r[55]=J,r[56]=Y);let X;r[57]===s?X=r[58]:(X=async()=>await s({to:`/ec2/describe-security-groups`}),r[57]=s,r[58]=X);let Z;r[59]!==l.isPending||r[60]!==x||r[61]!==X?(Z=(0,d.jsx)(me,{isPending:l.isPending,isSubmitting:x,onCancel:X,pendingLabel:`Creating…`,submitLabel:`Create Security Group`}),r[59]=l.isPending,r[60]=x,r[61]=X,r[62]=Z):Z=r[62];let Q;r[63]!==A||r[64]!==I||r[65]!==H||r[66]!==q||r[67]!==Y||r[68]!==Z?(Q=(0,d.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:A,children:[I,H,q,Y,Z]}),r[63]=A,r[64]=I,r[65]=H,r[66]=q,r[67]=Y,r[68]=Z,r[69]=Q):Q=r[69];let $;return r[70]!==k||r[71]!==Q?($=(0,d.jsxs)(d.Fragment,{children:[D,O,k,Q]}),r[70]=k,r[71]=Q,r[72]=$):$=r[72],$}function ge(e){let t=s(e.Tags);return(0,d.jsx)(r,{value:e.VpcId??``,children:t?`${e.VpcId} (${t})`:`${e.VpcId} (${e.CidrBlock})`},e.VpcId)}function _e(e){let t=e(`groupName`),ee=typeof t==`string`?t:``,n=e(`description`),r=typeof n==`string`?n:``,i=e(`vpcId`),a=typeof i==`string`?i:``,o=[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 create-security-group`},{type:`flag`,value:` \\ --group-name`},{type:`value`,value:` ${ee||``}`},{type:`flag`,value:` \\ --description`},{type:`value`,value:` "${r||``}"`}];return a&&o.push({type:`flag`,value:` \\ - --vpc-id`},{type:`value`,value:` ${a}`}),[{label:`Create Security Group`,parts:o}]}export{m as component}; \ No newline at end of file + --vpc-id`},{type:`value`,value:` ${a}`}),[{label:`Create Security Group`,parts:o}]}export{f as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/create-snapshot.js b/spinifex/services/spinifexui/frontend/dist/assets/create-snapshot.js index 9a719af0e..dbdd5cc22 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/create-snapshot.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/create-snapshot.js @@ -1,3 +1,3 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{c as r,i,n as a,s as o,t as s}from"./select.js";import{t as c}from"./cli-command-panel.js";import{u as l}from"./ec2.js";import{P as u,mo as d,so as f,tt as p,uo as ee}from"./index.js";import{t as te}from"./page-heading.js";import{a as m,r as ne,t as h}from"./field.js";import{t as re}from"./textarea.js";import{i as ie,n as ae,t as g}from"./zod.js";import{o as _}from"./ec22.js";import{t as v}from"./form-actions.js";var oe=f(),y=d();function b(){let i=(0,oe.c)(51),d=ee(),{data:f}=t(p),b=l(),x;i[0]===f.Volumes?x=i[1]:(x=f.Volumes??[],i[0]=f.Volumes,i[1]=x);let S=x,{volumeId:C}=u.useSearch(),w=C??S[0]?.VolumeId??``,T;i[2]===Symbol.for(`react.memo_cache_sentinel`)?(T=g(_),i[2]=T):T=i[2];let E;i[3]===w?E=i[4]:(E={resolver:T,defaultValues:{volumeId:w,description:``}},i[3]=w,i[4]=E);let{control:D,handleSubmit:O,register:k,watch:A,formState:j}=ie(E),{errors:M,isSubmitting:N}=j,P;i[5]!==b||i[6]!==d?(P=async e=>{await b.mutateAsync(e),d({to:`/ec2/describe-snapshots`})},i[5]=b,i[6]=d,i[7]=P):P=i[7];let F=P,I,L;i[8]===Symbol.for(`react.memo_cache_sentinel`)?(I=(0,y.jsx)(n,{to:`/ec2/describe-snapshots`,children:`Back to snapshots`}),L=(0,y.jsx)(te,{title:`Create Snapshot`}),i[8]=I,i[9]=L):(I=i[8],L=i[9]);let R;i[10]===b.error?R=i[11]:(R=b.error&&(0,y.jsx)(e,{error:b.error,msg:`Failed to create snapshot`}),i[10]=b.error,i[11]=R);let z;i[12]!==O||i[13]!==F?(z=O(F),i[12]=O,i[13]=F,i[14]=z):z=i[14];let B;i[15]===Symbol.for(`react.memo_cache_sentinel`)?(B=(0,y.jsx)(m,{children:(0,y.jsx)(`label`,{htmlFor:`volumeId`,children:`Volume`})}),i[15]=B):B=i[15];let V;i[16]!==M.volumeId||i[17]!==S?(V=e=>{let{field:t}=e;return(0,y.jsxs)(s,{onValueChange:e=>t.onChange(e),value:t.value??``,children:[(0,y.jsx)(o,{"aria-invalid":!!M.volumeId,className:`w-full`,id:`volumeId`,children:(0,y.jsx)(r,{})}),(0,y.jsx)(a,{children:S.map(se)})]})},i[16]=M.volumeId,i[17]=S,i[18]=V):V=i[18];let H;i[19]!==D||i[20]!==V?(H=(0,y.jsx)(ae,{control:D,name:`volumeId`,render:V}),i[19]=D,i[20]=V,i[21]=H):H=i[21];let U;i[22]===M.volumeId?U=i[23]:(U=(0,y.jsx)(ne,{errors:[M.volumeId]}),i[22]=M.volumeId,i[23]=U);let W;i[24]!==H||i[25]!==U?(W=(0,y.jsxs)(h,{children:[B,H,U]}),i[24]=H,i[25]=U,i[26]=W):W=i[26];let G;i[27]===Symbol.for(`react.memo_cache_sentinel`)?(G=(0,y.jsx)(m,{children:(0,y.jsx)(`label`,{htmlFor:`description`,children:`Description (optional)`})}),i[27]=G):G=i[27];let K;i[28]===k?K=i[29]:(K=k(`description`),i[28]=k,i[29]=K);let q;i[30]===K?q=i[31]:(q=(0,y.jsxs)(h,{children:[G,(0,y.jsx)(re,{id:`description`,placeholder:`Snapshot description`,...K})]}),i[30]=K,i[31]=q);let J;i[32]===A?J=i[33]:(J=ce(A),i[32]=A,i[33]=J);let Y;i[34]===J?Y=i[35]:(Y=(0,y.jsx)(c,{commands:J}),i[34]=J,i[35]=Y);let X;i[36]===d?X=i[37]:(X=async()=>await d({to:`/ec2/describe-snapshots`}),i[36]=d,i[37]=X);let Z;i[38]!==b.isPending||i[39]!==N||i[40]!==X?(Z=(0,y.jsx)(v,{isPending:b.isPending,isSubmitting:N,onCancel:X,pendingLabel:`Creating…`,submitLabel:`Create Snapshot`}),i[38]=b.isPending,i[39]=N,i[40]=X,i[41]=Z):Z=i[41];let Q;i[42]!==W||i[43]!==q||i[44]!==Y||i[45]!==Z||i[46]!==z?(Q=(0,y.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:z,children:[W,q,Y,Z]}),i[42]=W,i[43]=q,i[44]=Y,i[45]=Z,i[46]=z,i[47]=Q):Q=i[47];let $;return i[48]!==Q||i[49]!==R?($=(0,y.jsxs)(y.Fragment,{children:[I,L,R,Q]}),i[48]=Q,i[49]=R,i[50]=$):$=i[50],$}function se(e){return(0,y.jsxs)(i,{value:e.VolumeId??``,children:[e.VolumeId,` (`,e.Size,` GiB)`]},e.VolumeId)}function ce(e){let t=e(`volumeId`),n=typeof t==`string`?t:``,r=e(`description`),i=typeof r==`string`?r:``,a=[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 create-snapshot`},{type:`flag`,value:` \\ +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{c as r,i,n as a,s as ee,t as o}from"./select.js";import{t as te}from"./cli-command-panel.js";import{u as s}from"./ec2.js";import{F as c,Oo as l,nt as ne,wo as re,xo as u}from"./index.js";import{t as ie}from"./page-heading.js";import{a as d,r as ae,t as f}from"./field.js";import{t as oe}from"./textarea.js";import{a as se,i as ce,n as p,t as le}from"./zod.js";import{o as ue}from"./ec22.js";import{t as m}from"./form-actions.js";var h=u(),g=l();function _(){let i=(0,h.c)(55),l=re(),{data:u}=t(ne),_=s(),y;i[0]===u.Volumes?y=i[1]:(y=u.Volumes??[],i[0]=u.Volumes,i[1]=y);let b=y,{volumeId:fe}=c.useSearch(),x=fe??b[0]?.VolumeId??``,S;i[2]===Symbol.for(`react.memo_cache_sentinel`)?(S=le(ue),i[2]=S):S=i[2];let C;i[3]===x?C=i[4]:(C={resolver:S,defaultValues:{volumeId:x,description:``}},i[3]=x,i[4]=C);let{control:w,handleSubmit:T,register:E,formState:D}=ce(C),{errors:O,isSubmitting:k}=D,A;i[5]===w?A=i[6]:(A={control:w},i[5]=w,i[6]=A);let j=se(A),M;i[7]===j?M=i[8]:(M=e=>e?j[e]:void 0,i[7]=j,i[8]=M);let N=M,P;i[9]!==_||i[10]!==l?(P=async e=>{await _.mutateAsync(e),l({to:`/ec2/describe-snapshots`})},i[9]=_,i[10]=l,i[11]=P):P=i[11];let F=P,I,L;i[12]===Symbol.for(`react.memo_cache_sentinel`)?(I=(0,g.jsx)(n,{to:`/ec2/describe-snapshots`,children:`Back to snapshots`}),L=(0,g.jsx)(ie,{title:`Create Snapshot`}),i[12]=I,i[13]=L):(I=i[12],L=i[13]);let R;i[14]===_.error?R=i[15]:(R=_.error&&(0,g.jsx)(e,{error:_.error,msg:`Failed to create snapshot`}),i[14]=_.error,i[15]=R);let z;i[16]!==T||i[17]!==F?(z=T(F),i[16]=T,i[17]=F,i[18]=z):z=i[18];let B;i[19]===Symbol.for(`react.memo_cache_sentinel`)?(B=(0,g.jsx)(d,{children:(0,g.jsx)(`label`,{htmlFor:`volumeId`,children:`Volume`})}),i[19]=B):B=i[19];let V;i[20]!==O.volumeId||i[21]!==b?(V=e=>{let{field:t}=e;return(0,g.jsxs)(o,{onValueChange:e=>t.onChange(e),value:t.value??``,children:[(0,g.jsx)(ee,{"aria-invalid":!!O.volumeId,className:`w-full`,id:`volumeId`,children:(0,g.jsx)(r,{})}),(0,g.jsx)(a,{children:b.map(de)})]})},i[20]=O.volumeId,i[21]=b,i[22]=V):V=i[22];let H;i[23]!==w||i[24]!==V?(H=(0,g.jsx)(p,{control:w,name:`volumeId`,render:V}),i[23]=w,i[24]=V,i[25]=H):H=i[25];let U;i[26]===O.volumeId?U=i[27]:(U=(0,g.jsx)(ae,{errors:[O.volumeId]}),i[26]=O.volumeId,i[27]=U);let W;i[28]!==H||i[29]!==U?(W=(0,g.jsxs)(f,{children:[B,H,U]}),i[28]=H,i[29]=U,i[30]=W):W=i[30];let G;i[31]===Symbol.for(`react.memo_cache_sentinel`)?(G=(0,g.jsx)(d,{children:(0,g.jsx)(`label`,{htmlFor:`description`,children:`Description (optional)`})}),i[31]=G):G=i[31];let K;i[32]===E?K=i[33]:(K=E(`description`),i[32]=E,i[33]=K);let q;i[34]===K?q=i[35]:(q=(0,g.jsxs)(f,{children:[G,(0,g.jsx)(oe,{id:`description`,placeholder:`Snapshot description`,...K})]}),i[34]=K,i[35]=q);let J;i[36]===N?J=i[37]:(J=v(N),i[36]=N,i[37]=J);let Y;i[38]===J?Y=i[39]:(Y=(0,g.jsx)(te,{commands:J}),i[38]=J,i[39]=Y);let X;i[40]===l?X=i[41]:(X=async()=>await l({to:`/ec2/describe-snapshots`}),i[40]=l,i[41]=X);let Z;i[42]!==_.isPending||i[43]!==k||i[44]!==X?(Z=(0,g.jsx)(m,{isPending:_.isPending,isSubmitting:k,onCancel:X,pendingLabel:`Creating…`,submitLabel:`Create Snapshot`}),i[42]=_.isPending,i[43]=k,i[44]=X,i[45]=Z):Z=i[45];let Q;i[46]!==z||i[47]!==W||i[48]!==q||i[49]!==Y||i[50]!==Z?(Q=(0,g.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:z,children:[W,q,Y,Z]}),i[46]=z,i[47]=W,i[48]=q,i[49]=Y,i[50]=Z,i[51]=Q):Q=i[51];let $;return i[52]!==Q||i[53]!==R?($=(0,g.jsxs)(g.Fragment,{children:[I,L,R,Q]}),i[52]=Q,i[53]=R,i[54]=$):$=i[54],$}function de(e){return(0,g.jsxs)(i,{value:e.VolumeId??``,children:[e.VolumeId,` (`,e.Size,` GiB)`]},e.VolumeId)}function v(e){let t=e(`volumeId`),n=typeof t==`string`?t:``,r=e(`description`),i=typeof r==`string`?r:``,a=[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 create-snapshot`},{type:`flag`,value:` \\ --volume-id`},{type:`value`,value:` ${n||``}`}];return i&&a.push({type:`flag`,value:` \\ - --description`},{type:`value`,value:` "${i}"`}),[{label:`Create Snapshot`,parts:a}]}export{b as component}; \ No newline at end of file + --description`},{type:`value`,value:` "${i}"`}),[{label:`Create Snapshot`,parts:a}]}export{_ as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/create-subnet.js b/spinifex/services/spinifexui/frontend/dist/assets/create-subnet.js index 708bca8d9..a7977eebc 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/create-subnet.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/create-subnet.js @@ -1,4 +1,4 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as ee}from"./back-link.js";import{c as n,i as r,n as i,s as a,t as o}from"./select.js";import{t as te}from"./cli-command-panel.js";import{d as ne}from"./ec2.js";import{L as re,Pa as s,Ti as ie,mo as c,rt as ae,so as l,uo as oe}from"./index.js";import{t as se}from"./page-heading.js";import{a as u,r as ce,t as d}from"./field.js";import{i as le,n as ue,t as de}from"./zod.js";import{s as fe}from"./ec22.js";import{t as pe}from"./form-actions.js";var me=l(),f=c();function p(){let s=(0,me.c)(66),c=oe(),{data:l}=t(ae),{data:p}=t(re),m=ne(),h;s[0]===l.Vpcs?h=s[1]:(h=l.Vpcs??[],s[0]=l.Vpcs,s[1]=h);let g=h,_;s[2]===p.AvailabilityZones?_=s[3]:(_=p.AvailabilityZones??[],s[2]=p.AvailabilityZones,s[3]=_);let v=_,y;s[4]===Symbol.for(`react.memo_cache_sentinel`)?(y=de(fe),s[4]=y):y=s[4];let b=g[0]?.VpcId??``,x;s[5]===b?x=s[6]:(x={resolver:y,defaultValues:{vpcId:b,cidrBlock:`10.0.1.0/24`,availabilityZone:void 0}},s[5]=b,s[6]=x);let{control:S,handleSubmit:C,register:w,watch:T,formState:ve}=le(x),{errors:E,isSubmitting:D}=ve,O;s[7]!==m||s[8]!==c?(O=async e=>{let t=(await m.mutateAsync(e)).Subnet?.SubnetId;c(t?{to:`/ec2/describe-subnets/$id`,params:{id:t}}:{to:`/ec2/describe-subnets`})},s[7]=m,s[8]=c,s[9]=O):O=s[9];let k=O,A,j;s[10]===Symbol.for(`react.memo_cache_sentinel`)?(A=(0,f.jsx)(ee,{to:`/ec2/describe-subnets`,children:`Back to Subnets`}),j=(0,f.jsx)(se,{title:`Create Subnet`}),s[10]=A,s[11]=j):(A=s[10],j=s[11]);let M;s[12]===m.error?M=s[13]:(M=m.error&&(0,f.jsx)(e,{error:m.error,msg:`Failed to create subnet`}),s[12]=m.error,s[13]=M);let N;s[14]!==C||s[15]!==k?(N=C(k),s[14]=C,s[15]=k,s[16]=N):N=s[16];let P;s[17]===Symbol.for(`react.memo_cache_sentinel`)?(P=(0,f.jsx)(u,{children:(0,f.jsx)(`label`,{htmlFor:`vpcId`,children:`VPC`})}),s[17]=P):P=s[17];let F;s[18]!==E.vpcId||s[19]!==g?(F=e=>{let{field:t}=e;return(0,f.jsxs)(o,{onValueChange:e=>t.onChange(e),value:t.value??``,children:[(0,f.jsx)(a,{"aria-invalid":!!E.vpcId,className:`w-full`,id:`vpcId`,children:(0,f.jsx)(n,{})}),(0,f.jsx)(i,{children:g.map(ge)})]})},s[18]=E.vpcId,s[19]=g,s[20]=F):F=s[20];let I;s[21]!==S||s[22]!==F?(I=(0,f.jsx)(ue,{control:S,name:`vpcId`,render:F}),s[21]=S,s[22]=F,s[23]=I):I=s[23];let L;s[24]===E.vpcId?L=s[25]:(L=(0,f.jsx)(ce,{errors:[E.vpcId]}),s[24]=E.vpcId,s[25]=L);let R;s[26]!==I||s[27]!==L?(R=(0,f.jsxs)(d,{children:[P,I,L]}),s[26]=I,s[27]=L,s[28]=R):R=s[28];let z;s[29]===Symbol.for(`react.memo_cache_sentinel`)?(z=(0,f.jsx)(u,{children:(0,f.jsx)(`label`,{htmlFor:`cidrBlock`,children:`CIDR Block`})}),s[29]=z):z=s[29];let B=!!E.cidrBlock,V;s[30]===w?V=s[31]:(V=w(`cidrBlock`),s[30]=w,s[31]=V);let H;s[32]!==B||s[33]!==V?(H=(0,f.jsx)(ie,{"aria-invalid":B,id:`cidrBlock`,placeholder:`10.0.1.0/24`,...V}),s[32]=B,s[33]=V,s[34]=H):H=s[34];let U;s[35]===E.cidrBlock?U=s[36]:(U=(0,f.jsx)(ce,{errors:[E.cidrBlock]}),s[35]=E.cidrBlock,s[36]=U);let W;s[37]!==H||s[38]!==U?(W=(0,f.jsxs)(d,{children:[z,H,U]}),s[37]=H,s[38]=U,s[39]=W):W=s[39];let G;s[40]===Symbol.for(`react.memo_cache_sentinel`)?(G=(0,f.jsx)(u,{children:(0,f.jsx)(`label`,{htmlFor:`availabilityZone`,children:`Availability Zone (optional)`})}),s[40]=G):G=s[40];let K;s[41]===v?K=s[42]:(K=e=>{let{field:t}=e;return(0,f.jsxs)(o,{onValueChange:e=>t.onChange(e===`none`?void 0:e),value:t.value??`none`,children:[(0,f.jsx)(a,{className:`w-full`,id:`availabilityZone`,children:(0,f.jsx)(n,{})}),(0,f.jsxs)(i,{children:[(0,f.jsx)(r,{value:`none`,children:`none`}),v.map(he)]})]})},s[41]=v,s[42]=K);let q;s[43]!==S||s[44]!==K?(q=(0,f.jsxs)(d,{children:[G,(0,f.jsx)(ue,{control:S,name:`availabilityZone`,render:K})]}),s[43]=S,s[44]=K,s[45]=q):q=s[45];let J;s[46]===T?J=s[47]:(J=_e(T),s[46]=T,s[47]=J);let Y;s[48]===J?Y=s[49]:(Y=(0,f.jsx)(te,{commands:J}),s[48]=J,s[49]=Y);let X;s[50]===c?X=s[51]:(X=async()=>await c({to:`/ec2/describe-subnets`}),s[50]=c,s[51]=X);let Z;s[52]!==m.isPending||s[53]!==D||s[54]!==X?(Z=(0,f.jsx)(pe,{isPending:m.isPending,isSubmitting:D,onCancel:X,pendingLabel:`Creating…`,submitLabel:`Create Subnet`}),s[52]=m.isPending,s[53]=D,s[54]=X,s[55]=Z):Z=s[55];let Q;s[56]!==N||s[57]!==R||s[58]!==W||s[59]!==q||s[60]!==Y||s[61]!==Z?(Q=(0,f.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:N,children:[R,W,q,Y,Z]}),s[56]=N,s[57]=R,s[58]=W,s[59]=q,s[60]=Y,s[61]=Z,s[62]=Q):Q=s[62];let $;return s[63]!==Q||s[64]!==M?($=(0,f.jsxs)(f.Fragment,{children:[A,j,M,Q]}),s[63]=Q,s[64]=M,s[65]=$):$=s[65],$}function he(e){return(0,f.jsx)(r,{value:e.ZoneName??``,children:e.ZoneName},e.ZoneName)}function ge(e){let t=s(e.Tags);return(0,f.jsx)(r,{value:e.VpcId??``,children:t?`${e.VpcId} (${t})`:`${e.VpcId} (${e.CidrBlock})`},e.VpcId)}function _e(e){let t=e(`vpcId`),ee=typeof t==`string`?t:``,n=e(`cidrBlock`),r=typeof n==`string`?n:``,i=e(`availabilityZone`),a=typeof i==`string`?i:``,o=[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 create-subnet`},{type:`flag`,value:` \\ +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as ee}from"./back-link.js";import{c as n,i as r,n as i,s as a,t as o}from"./select.js";import{t as te}from"./cli-command-panel.js";import{d as ne}from"./ec2.js";import{Ja as s,Oo as c,R as re,it as ie,wo as ae,xo as l,zi as oe}from"./index.js";import{t as se}from"./page-heading.js";import{a as u,r as ce,t as le}from"./field.js";import{a as ue,i as de,n as fe,t as pe}from"./zod.js";import{s as me}from"./ec22.js";import{t as he}from"./form-actions.js";var ge=l(),d=c();function f(){let s=(0,ge.c)(70),c=ae(),{data:l}=t(ie),{data:f}=t(re),p=ne(),m;s[0]===l.Vpcs?m=s[1]:(m=l.Vpcs??[],s[0]=l.Vpcs,s[1]=m);let h=m,g;s[2]===f.AvailabilityZones?g=s[3]:(g=f.AvailabilityZones??[],s[2]=f.AvailabilityZones,s[3]=g);let be=g,_;s[4]===Symbol.for(`react.memo_cache_sentinel`)?(_=pe(me),s[4]=_):_=s[4];let v=h[0]?.VpcId??``,y;s[5]===v?y=s[6]:(y={resolver:_,defaultValues:{vpcId:v,cidrBlock:`10.0.1.0/24`,availabilityZone:void 0}},s[5]=v,s[6]=y);let{control:b,handleSubmit:x,register:S,formState:xe}=de(y),{errors:C,isSubmitting:Se}=xe,w;s[7]===b?w=s[8]:(w={control:b},s[7]=b,s[8]=w);let T=ue(w),E;s[9]===T?E=s[10]:(E=e=>e?T[e]:void 0,s[9]=T,s[10]=E);let D=E,O;s[11]!==p||s[12]!==c?(O=async e=>{let t=(await p.mutateAsync(e)).Subnet?.SubnetId;c(t?{to:`/ec2/describe-subnets/$id`,params:{id:t}}:{to:`/ec2/describe-subnets`})},s[11]=p,s[12]=c,s[13]=O):O=s[13];let k=O,A,j;s[14]===Symbol.for(`react.memo_cache_sentinel`)?(j=(0,d.jsx)(ee,{to:`/ec2/describe-subnets`,children:`Back to Subnets`}),A=(0,d.jsx)(se,{title:`Create Subnet`}),s[14]=A,s[15]=j):(A=s[14],j=s[15]);let M;s[16]===p.error?M=s[17]:(M=p.error&&(0,d.jsx)(e,{error:p.error,msg:`Failed to create subnet`}),s[16]=p.error,s[17]=M);let N;s[18]!==x||s[19]!==k?(N=x(k),s[18]=x,s[19]=k,s[20]=N):N=s[20];let P;s[21]===Symbol.for(`react.memo_cache_sentinel`)?(P=(0,d.jsx)(u,{children:(0,d.jsx)(`label`,{htmlFor:`vpcId`,children:`VPC`})}),s[21]=P):P=s[21];let F;s[22]!==C.vpcId||s[23]!==h?(F=e=>{let{field:t}=e;return(0,d.jsxs)(o,{onValueChange:e=>t.onChange(e),value:t.value??``,children:[(0,d.jsx)(a,{"aria-invalid":!!C.vpcId,className:`w-full`,id:`vpcId`,children:(0,d.jsx)(n,{})}),(0,d.jsx)(i,{children:h.map(ve)})]})},s[22]=C.vpcId,s[23]=h,s[24]=F):F=s[24];let I;s[25]!==b||s[26]!==F?(I=(0,d.jsx)(fe,{control:b,name:`vpcId`,render:F}),s[25]=b,s[26]=F,s[27]=I):I=s[27];let L;s[28]===C.vpcId?L=s[29]:(L=(0,d.jsx)(ce,{errors:[C.vpcId]}),s[28]=C.vpcId,s[29]=L);let R;s[30]!==I||s[31]!==L?(R=(0,d.jsxs)(le,{children:[P,I,L]}),s[30]=I,s[31]=L,s[32]=R):R=s[32];let z;s[33]===Symbol.for(`react.memo_cache_sentinel`)?(z=(0,d.jsx)(u,{children:(0,d.jsx)(`label`,{htmlFor:`cidrBlock`,children:`CIDR Block`})}),s[33]=z):z=s[33];let B=!!C.cidrBlock,V;s[34]===S?V=s[35]:(V=S(`cidrBlock`),s[34]=S,s[35]=V);let H;s[36]!==B||s[37]!==V?(H=(0,d.jsx)(oe,{"aria-invalid":B,id:`cidrBlock`,placeholder:`10.0.1.0/24`,...V}),s[36]=B,s[37]=V,s[38]=H):H=s[38];let U;s[39]===C.cidrBlock?U=s[40]:(U=(0,d.jsx)(ce,{errors:[C.cidrBlock]}),s[39]=C.cidrBlock,s[40]=U);let W;s[41]!==H||s[42]!==U?(W=(0,d.jsxs)(le,{children:[z,H,U]}),s[41]=H,s[42]=U,s[43]=W):W=s[43];let G;s[44]===Symbol.for(`react.memo_cache_sentinel`)?(G=(0,d.jsx)(u,{children:(0,d.jsx)(`label`,{htmlFor:`availabilityZone`,children:`Availability Zone (optional)`})}),s[44]=G):G=s[44];let K;s[45]===be?K=s[46]:(K=e=>{let{field:t}=e;return(0,d.jsxs)(o,{onValueChange:e=>t.onChange(e===`none`?void 0:e),value:t.value??`none`,children:[(0,d.jsx)(a,{className:`w-full`,id:`availabilityZone`,children:(0,d.jsx)(n,{})}),(0,d.jsxs)(i,{children:[(0,d.jsx)(r,{value:`none`,children:`none`}),be.map(_e)]})]})},s[45]=be,s[46]=K);let q;s[47]!==b||s[48]!==K?(q=(0,d.jsxs)(le,{children:[G,(0,d.jsx)(fe,{control:b,name:`availabilityZone`,render:K})]}),s[47]=b,s[48]=K,s[49]=q):q=s[49];let J;s[50]===D?J=s[51]:(J=ye(D),s[50]=D,s[51]=J);let Y;s[52]===J?Y=s[53]:(Y=(0,d.jsx)(te,{commands:J}),s[52]=J,s[53]=Y);let X;s[54]===c?X=s[55]:(X=async()=>await c({to:`/ec2/describe-subnets`}),s[54]=c,s[55]=X);let Z;s[56]!==p.isPending||s[57]!==Se||s[58]!==X?(Z=(0,d.jsx)(he,{isPending:p.isPending,isSubmitting:Se,onCancel:X,pendingLabel:`Creating…`,submitLabel:`Create Subnet`}),s[56]=p.isPending,s[57]=Se,s[58]=X,s[59]=Z):Z=s[59];let Q;s[60]!==N||s[61]!==R||s[62]!==W||s[63]!==q||s[64]!==Y||s[65]!==Z?(Q=(0,d.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:N,children:[R,W,q,Y,Z]}),s[60]=N,s[61]=R,s[62]=W,s[63]=q,s[64]=Y,s[65]=Z,s[66]=Q):Q=s[66];let $;return s[67]!==M||s[68]!==Q?($=(0,d.jsxs)(d.Fragment,{children:[j,A,M,Q]}),s[67]=M,s[68]=Q,s[69]=$):$=s[69],$}function _e(e){return(0,d.jsx)(r,{value:e.ZoneName??``,children:e.ZoneName},e.ZoneName)}function ve(e){let t=s(e.Tags);return(0,d.jsx)(r,{value:e.VpcId??``,children:t?`${e.VpcId} (${t})`:`${e.VpcId} (${e.CidrBlock})`},e.VpcId)}function ye(e){let t=e(`vpcId`),ee=typeof t==`string`?t:``,n=e(`cidrBlock`),r=typeof n==`string`?n:``,i=e(`availabilityZone`),a=typeof i==`string`?i:``,o=[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 create-subnet`},{type:`flag`,value:` \\ --vpc-id`},{type:`value`,value:` ${ee||``}`},{type:`flag`,value:` \\ --cidr-block`},{type:`value`,value:` ${r||``}`}];return a&&o.push({type:`flag`,value:` \\ - --availability-zone`},{type:`value`,value:` ${a}`}),[{label:`Create Subnet`,parts:o}]}export{p as component}; \ No newline at end of file + --availability-zone`},{type:`value`,value:` ${a}`}),[{label:`Create Subnet`,parts:o}]}export{f as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/create-target-group.js b/spinifex/services/spinifexui/frontend/dist/assets/create-target-group.js index 429e2008e..c37639374 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/create-target-group.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/create-target-group.js @@ -1,4 +1,4 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./cli-command-panel.js";import{i}from"./elbv2.js";import{mo as a,rt as o,uo as s}from"./index.js";import{t as c}from"./page-heading.js";import{i as l,t as u}from"./zod.js";import{t as d}from"./form-actions.js";import{t as f}from"./target-group-form.js";import{i as p}from"./elbv22.js";var m=a();function h(){let a=s(),{data:h}=t(o),_=i(),v=h.Vpcs??[],y=l({resolver:u(p),defaultValues:{name:``,protocol:`HTTP`,port:80,vpcId:v[0]?.VpcId??``,healthCheck:{protocol:`HTTP`,path:`/`,port:`traffic-port`,intervalSeconds:30,timeoutSeconds:5,healthyThresholdCount:5,unhealthyThresholdCount:2,matcher:`200`},tags:[]}}),{handleSubmit:b,watch:x,formState:{isSubmitting:S}}=y;return(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(n,{to:`/ec2/describe-target-groups`,children:`Back to target groups`}),(0,m.jsx)(c,{title:`Create Target Group`}),_.error&&(0,m.jsx)(e,{error:_.error,msg:`Failed to create target group`}),(0,m.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:b(async e=>{try{let t=(await _.mutateAsync(e)).TargetGroups?.[0]?.TargetGroupArn;a(t?{to:`/ec2/describe-target-groups/$id`,params:{id:encodeURIComponent(t)}}:{to:`/ec2/describe-target-groups`})}catch{}}),children:[(0,m.jsx)(f,{form:y,vpcs:v}),(0,m.jsx)(r,{commands:g(x)}),(0,m.jsx)(d,{isPending:_.isPending,isSubmitting:S,onCancel:async()=>await a({to:`/ec2/describe-target-groups`}),pendingLabel:`Creating…`,submitLabel:`Create Target Group`})]})]})}function g(e){let t=t=>{let n=e(t);return typeof n==`string`?n:``},n=t=>{let n=e(t);return typeof n==`number`&&Number.isFinite(n)?n:void 0},r=t(`name`),i=t(`protocol`)||`HTTP`,a=n(`port`),o=t(`vpcId`),s=t(`healthCheck.protocol`)||`HTTP`,c=t(`healthCheck.path`)||`/`,l=t(`healthCheck.port`)||`traffic-port`,u=n(`healthCheck.intervalSeconds`),d=n(`healthCheck.timeoutSeconds`),f=n(`healthCheck.healthyThresholdCount`),p=n(`healthCheck.unhealthyThresholdCount`),m=t(`healthCheck.matcher`)||`200`,h=[{type:`bin`,value:`AWS_PROFILE=spinifex aws elbv2 create-target-group`},{type:`flag`,value:` \\ +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./cli-command-panel.js";import{i}from"./elbv2.js";import{Oo as a,it as o,wo as s}from"./index.js";import{t as c}from"./page-heading.js";import{i as l,t as u}from"./zod.js";import{t as d}from"./form-actions.js";import{t as f}from"./target-group-form.js";import{a as p}from"./elbv22.js";var m=a();function h(){let a=s(),{data:h}=t(o),_=i(),v=h.Vpcs??[],y=l({resolver:u(p),defaultValues:{name:``,protocol:`HTTP`,port:80,vpcId:v[0]?.VpcId??``,healthCheck:{protocol:`HTTP`,path:`/`,port:`traffic-port`,intervalSeconds:30,timeoutSeconds:5,healthyThresholdCount:5,unhealthyThresholdCount:2,matcher:`200`},tags:[]}}),{handleSubmit:b,watch:x,formState:{isSubmitting:S}}=y;return(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(n,{to:`/ec2/describe-target-groups`,children:`Back to target groups`}),(0,m.jsx)(c,{title:`Create Target Group`}),_.error&&(0,m.jsx)(e,{error:_.error,msg:`Failed to create target group`}),(0,m.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:b(async e=>{try{let t=(await _.mutateAsync(e)).TargetGroups?.[0]?.TargetGroupArn;a(t?{to:`/ec2/describe-target-groups/$id`,params:{id:encodeURIComponent(t)}}:{to:`/ec2/describe-target-groups`})}catch{}}),children:[(0,m.jsx)(f,{form:y,vpcs:v}),(0,m.jsx)(r,{commands:g(x)}),(0,m.jsx)(d,{isPending:_.isPending,isSubmitting:S,onCancel:async()=>await a({to:`/ec2/describe-target-groups`}),pendingLabel:`Creating…`,submitLabel:`Create Target Group`})]})]})}function g(e){let t=t=>{let n=e(t);return typeof n==`string`?n:``},n=t=>{let n=e(t);return typeof n==`number`&&Number.isFinite(n)?n:void 0},r=t(`name`),i=t(`protocol`)||`HTTP`,a=n(`port`),o=t(`vpcId`),s=t(`healthCheck.protocol`)||`HTTP`,c=t(`healthCheck.path`)||`/`,l=t(`healthCheck.port`)||`traffic-port`,u=n(`healthCheck.intervalSeconds`),d=n(`healthCheck.timeoutSeconds`),f=n(`healthCheck.healthyThresholdCount`),p=n(`healthCheck.unhealthyThresholdCount`),m=t(`healthCheck.matcher`)||`200`,h=[{type:`bin`,value:`AWS_PROFILE=spinifex aws elbv2 create-target-group`},{type:`flag`,value:` \\ --name`},{type:`value`,value:` ${r||``}`},{type:`flag`,value:` \\ --protocol`},{type:`value`,value:` ${i}`},{type:`flag`,value:` \\ --port`},{type:`value`,value:` ${a??80}`},{type:`flag`,value:` \\ diff --git a/spinifex/services/spinifexui/frontend/dist/assets/create-user.js b/spinifex/services/spinifexui/frontend/dist/assets/create-user.js index 2955a50ce..6feefbfd1 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/create-user.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/create-user.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./back-link.js";import{t as n}from"./cli-command-panel.js";import{i as r}from"./iam.js";import{Ti as i,mo as a,so as o,uo as s}from"./index.js";import{t as c}from"./page-heading.js";import{a as l,r as u,t as d}from"./field.js";import{i as f,t as p}from"./zod.js";import{t as m}from"./form-actions.js";import{n as h}from"./iam2.js";var g=o(),_=a();function v(){let a=(0,g.c)(51),o=s(),v=r(),b;a[0]===Symbol.for(`react.memo_cache_sentinel`)?(b={resolver:p(h)},a[0]=b):b=a[0];let{handleSubmit:x,register:S,watch:C,formState:w}=f(b),{errors:T,isSubmitting:E}=w,D;a[1]!==v||a[2]!==o?(D=async e=>{await v.mutateAsync(e),o({to:`/iam/list-users`})},a[1]=v,a[2]=o,a[3]=D):D=a[3];let O=D,k,A;a[4]===Symbol.for(`react.memo_cache_sentinel`)?(k=(0,_.jsx)(t,{to:`/iam/list-users`,children:`Back to users`}),A=(0,_.jsx)(c,{title:`Create User`}),a[4]=k,a[5]=A):(k=a[4],A=a[5]);let j;a[6]===v.error?j=a[7]:(j=v.error&&(0,_.jsx)(e,{error:v.error,msg:`Failed to create user`}),a[6]=v.error,a[7]=j);let M;a[8]!==x||a[9]!==O?(M=x(O),a[8]=x,a[9]=O,a[10]=M):M=a[10];let N;a[11]===Symbol.for(`react.memo_cache_sentinel`)?(N=(0,_.jsx)(l,{children:(0,_.jsx)(`label`,{htmlFor:`userName`,children:`User Name`})}),a[11]=N):N=a[11];let P=!!T.userName,F;a[12]===S?F=a[13]:(F=S(`userName`),a[12]=S,a[13]=F);let I;a[14]!==P||a[15]!==F?(I=(0,_.jsx)(i,{"aria-invalid":P,id:`userName`,placeholder:`my-user...`,...F}),a[14]=P,a[15]=F,a[16]=I):I=a[16];let L;a[17]===T.userName?L=a[18]:(L=(0,_.jsx)(u,{errors:[T.userName]}),a[17]=T.userName,a[18]=L);let R;a[19]!==I||a[20]!==L?(R=(0,_.jsxs)(d,{children:[N,I,L]}),a[19]=I,a[20]=L,a[21]=R):R=a[21];let z;a[22]===Symbol.for(`react.memo_cache_sentinel`)?(z=(0,_.jsx)(l,{children:(0,_.jsx)(`label`,{htmlFor:`path`,children:`Path (optional)`})}),a[22]=z):z=a[22];let B;a[23]===S?B=a[24]:(B=S(`path`),a[23]=S,a[24]=B);let V;a[25]===B?V=a[26]:(V=(0,_.jsx)(i,{id:`path`,placeholder:`/`,...B}),a[25]=B,a[26]=V);let H;a[27]===T.path?H=a[28]:(H=(0,_.jsx)(u,{errors:[T.path]}),a[27]=T.path,a[28]=H);let U;a[29]!==V||a[30]!==H?(U=(0,_.jsxs)(d,{children:[z,V,H]}),a[29]=V,a[30]=H,a[31]=U):U=a[31];let W;a[32]===C?W=a[33]:(W=y(C),a[32]=C,a[33]=W);let G;a[34]===W?G=a[35]:(G=(0,_.jsx)(n,{commands:W}),a[34]=W,a[35]=G);let K;a[36]===o?K=a[37]:(K=async()=>await o({to:`/iam/list-users`}),a[36]=o,a[37]=K);let q;a[38]!==v.isPending||a[39]!==E||a[40]!==K?(q=(0,_.jsx)(m,{isPending:v.isPending,isSubmitting:E,onCancel:K,pendingLabel:`Creating...`,submitLabel:`Create User`}),a[38]=v.isPending,a[39]=E,a[40]=K,a[41]=q):q=a[41];let J;a[42]!==R||a[43]!==U||a[44]!==G||a[45]!==q||a[46]!==M?(J=(0,_.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:M,children:[R,U,G,q]}),a[42]=R,a[43]=U,a[44]=G,a[45]=q,a[46]=M,a[47]=J):J=a[47];let Y;return a[48]!==J||a[49]!==j?(Y=(0,_.jsxs)(_.Fragment,{children:[k,A,j,J]}),a[48]=J,a[49]=j,a[50]=Y):Y=a[50],Y}function y(e){let t=e(`userName`),n=typeof t==`string`?t:``,r=e(`path`),i=typeof r==`string`?r:``,a=[{type:`bin`,value:`AWS_PROFILE=spinifex aws iam create-user`},{type:`flag`,value:` --user-name`},{type:`value`,value:` ${n||``}`}];return i&&i!==`/`&&a.push({type:`flag`,value:` --path`},{type:`value`,value:` ${i}`}),[{label:`Create User`,parts:a}]}export{v as component}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./back-link.js";import{t as n}from"./cli-command-panel.js";import{i as r}from"./iam.js";import{Oo as i,wo as a,xo as o,zi as s}from"./index.js";import{t as ee}from"./page-heading.js";import{a as c,r as l,t as u}from"./field.js";import{a as d,i as f,t as p}from"./zod.js";import{t as m}from"./form-actions.js";import{n as h}from"./iam2.js";var g=o(),_=i();function v(){let i=(0,g.c)(55),o=a(),v=r(),b;i[0]===Symbol.for(`react.memo_cache_sentinel`)?(b={resolver:p(h)},i[0]=b):b=i[0];let{handleSubmit:x,register:S,control:C,formState:w}=f(b),{errors:T,isSubmitting:E}=w,D;i[1]===C?D=i[2]:(D={control:C},i[1]=C,i[2]=D);let O=d(D),k;i[3]===O?k=i[4]:(k=e=>e?O[e]:void 0,i[3]=O,i[4]=k);let A=k,j;i[5]!==v||i[6]!==o?(j=async e=>{await v.mutateAsync(e),o({to:`/iam/list-users`})},i[5]=v,i[6]=o,i[7]=j):j=i[7];let M=j,N,P;i[8]===Symbol.for(`react.memo_cache_sentinel`)?(N=(0,_.jsx)(t,{to:`/iam/list-users`,children:`Back to users`}),P=(0,_.jsx)(ee,{title:`Create User`}),i[8]=N,i[9]=P):(N=i[8],P=i[9]);let F;i[10]===v.error?F=i[11]:(F=v.error&&(0,_.jsx)(e,{error:v.error,msg:`Failed to create user`}),i[10]=v.error,i[11]=F);let I;i[12]!==x||i[13]!==M?(I=x(M),i[12]=x,i[13]=M,i[14]=I):I=i[14];let L;i[15]===Symbol.for(`react.memo_cache_sentinel`)?(L=(0,_.jsx)(c,{children:(0,_.jsx)(`label`,{htmlFor:`userName`,children:`User Name`})}),i[15]=L):L=i[15];let R=!!T.userName,z;i[16]===S?z=i[17]:(z=S(`userName`),i[16]=S,i[17]=z);let B;i[18]!==R||i[19]!==z?(B=(0,_.jsx)(s,{"aria-invalid":R,id:`userName`,placeholder:`my-user...`,...z}),i[18]=R,i[19]=z,i[20]=B):B=i[20];let V;i[21]===T.userName?V=i[22]:(V=(0,_.jsx)(l,{errors:[T.userName]}),i[21]=T.userName,i[22]=V);let H;i[23]!==B||i[24]!==V?(H=(0,_.jsxs)(u,{children:[L,B,V]}),i[23]=B,i[24]=V,i[25]=H):H=i[25];let U;i[26]===Symbol.for(`react.memo_cache_sentinel`)?(U=(0,_.jsx)(c,{children:(0,_.jsx)(`label`,{htmlFor:`path`,children:`Path (optional)`})}),i[26]=U):U=i[26];let W;i[27]===S?W=i[28]:(W=S(`path`),i[27]=S,i[28]=W);let G;i[29]===W?G=i[30]:(G=(0,_.jsx)(s,{id:`path`,placeholder:`/`,...W}),i[29]=W,i[30]=G);let K;i[31]===T.path?K=i[32]:(K=(0,_.jsx)(l,{errors:[T.path]}),i[31]=T.path,i[32]=K);let q;i[33]!==G||i[34]!==K?(q=(0,_.jsxs)(u,{children:[U,G,K]}),i[33]=G,i[34]=K,i[35]=q):q=i[35];let J;i[36]===A?J=i[37]:(J=y(A),i[36]=A,i[37]=J);let Y;i[38]===J?Y=i[39]:(Y=(0,_.jsx)(n,{commands:J}),i[38]=J,i[39]=Y);let X;i[40]===o?X=i[41]:(X=async()=>await o({to:`/iam/list-users`}),i[40]=o,i[41]=X);let Z;i[42]!==v.isPending||i[43]!==E||i[44]!==X?(Z=(0,_.jsx)(m,{isPending:v.isPending,isSubmitting:E,onCancel:X,pendingLabel:`Creating...`,submitLabel:`Create User`}),i[42]=v.isPending,i[43]=E,i[44]=X,i[45]=Z):Z=i[45];let Q;i[46]!==H||i[47]!==q||i[48]!==Y||i[49]!==Z||i[50]!==I?(Q=(0,_.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:I,children:[H,q,Y,Z]}),i[46]=H,i[47]=q,i[48]=Y,i[49]=Z,i[50]=I,i[51]=Q):Q=i[51];let $;return i[52]!==Q||i[53]!==F?($=(0,_.jsxs)(_.Fragment,{children:[N,P,F,Q]}),i[52]=Q,i[53]=F,i[54]=$):$=i[54],$}function y(e){let t=e(`userName`),n=typeof t==`string`?t:``,r=e(`path`),i=typeof r==`string`?r:``,a=[{type:`bin`,value:`AWS_PROFILE=spinifex aws iam create-user`},{type:`flag`,value:` --user-name`},{type:`value`,value:` ${n||``}`}];return i&&i!==`/`&&a.push({type:`flag`,value:` --path`},{type:`value`,value:` ${i}`}),[{label:`Create User`,parts:a}]}export{v as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/create-volume.js b/spinifex/services/spinifexui/frontend/dist/assets/create-volume.js index e439dbf6a..08983322c 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/create-volume.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/create-volume.js @@ -1,3 +1,3 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{c as r,i,n as ee,s as a,t as te}from"./select.js";import{t as o}from"./cli-command-panel.js";import{f as ne}from"./ec2.js";import{L as re,Ti as ie,mo as s,so as c,uo as l}from"./index.js";import{t as u}from"./page-heading.js";import{a as d,r as f,t as p}from"./field.js";import{i as m,n as h,t as g}from"./zod.js";import{c as ae}from"./ec22.js";import{t as oe}from"./form-actions.js";var se=c(),_=s();function v(){let i=(0,se.c)(57),s=l(),{data:c}=t(re),v=ne(),y;i[0]===c.AvailabilityZones?y=i[1]:(y=c.AvailabilityZones??[],i[0]=c.AvailabilityZones,i[1]=y);let b=y,x=b[0]?.ZoneName??``,S;i[2]===Symbol.for(`react.memo_cache_sentinel`)?(S=g(ae),i[2]=S):S=i[2];let C;i[3]===x?C=i[4]:(C={resolver:S,defaultValues:{size:1,availabilityZone:x}},i[3]=x,i[4]=C);let{control:w,handleSubmit:T,register:E,watch:D,formState:O}=m(C),{errors:k,isSubmitting:A}=O,j;i[5]!==v||i[6]!==s?(j=async e=>{await v.mutateAsync(e),s({to:`/ec2/describe-volumes`})},i[5]=v,i[6]=s,i[7]=j):j=i[7];let M=j,N,P;i[8]===Symbol.for(`react.memo_cache_sentinel`)?(N=(0,_.jsx)(n,{to:`/ec2/describe-volumes`,children:`Back to volumes`}),P=(0,_.jsx)(u,{title:`Create Volume`}),i[8]=N,i[9]=P):(N=i[8],P=i[9]);let F;i[10]===v.error?F=i[11]:(F=v.error&&(0,_.jsx)(e,{error:v.error,msg:`Failed to create volume`}),i[10]=v.error,i[11]=F);let I;i[12]!==T||i[13]!==M?(I=T(M),i[12]=T,i[13]=M,i[14]=I):I=i[14];let L;i[15]===Symbol.for(`react.memo_cache_sentinel`)?(L=(0,_.jsx)(d,{children:(0,_.jsx)(`label`,{htmlFor:`size`,children:`Size (GiB)`})}),i[15]=L):L=i[15];let R=!!k.size,z;i[16]===E?z=i[17]:(z=E(`size`,{valueAsNumber:!0}),i[16]=E,i[17]=z);let B;i[18]!==R||i[19]!==z?(B=(0,_.jsx)(ie,{"aria-invalid":R,id:`size`,max:16384,min:1,type:`number`,...z}),i[18]=R,i[19]=z,i[20]=B):B=i[20];let V;i[21]===k.size?V=i[22]:(V=(0,_.jsx)(f,{errors:[k.size]}),i[21]=k.size,i[22]=V);let H;i[23]!==B||i[24]!==V?(H=(0,_.jsxs)(p,{children:[L,B,V]}),i[23]=B,i[24]=V,i[25]=H):H=i[25];let U;i[26]===Symbol.for(`react.memo_cache_sentinel`)?(U=(0,_.jsx)(d,{children:(0,_.jsx)(`label`,{htmlFor:`availabilityZone`,children:`Availability Zone`})}),i[26]=U):U=i[26];let W;i[27]!==b||i[28]!==k.availabilityZone?(W=e=>{let{field:t}=e;return(0,_.jsxs)(te,{onValueChange:e=>t.onChange(e),value:t.value??``,children:[(0,_.jsx)(a,{"aria-invalid":!!k.availabilityZone,className:`w-full`,id:`availabilityZone`,children:(0,_.jsx)(r,{})}),(0,_.jsx)(ee,{children:b.map(ce)})]})},i[27]=b,i[28]=k.availabilityZone,i[29]=W):W=i[29];let G;i[30]!==w||i[31]!==W?(G=(0,_.jsx)(h,{control:w,name:`availabilityZone`,render:W}),i[30]=w,i[31]=W,i[32]=G):G=i[32];let K;i[33]===k.availabilityZone?K=i[34]:(K=(0,_.jsx)(f,{errors:[k.availabilityZone]}),i[33]=k.availabilityZone,i[34]=K);let q;i[35]!==G||i[36]!==K?(q=(0,_.jsxs)(p,{children:[U,G,K]}),i[35]=G,i[36]=K,i[37]=q):q=i[37];let J;i[38]===D?J=i[39]:(J=le(D),i[38]=D,i[39]=J);let Y;i[40]===J?Y=i[41]:(Y=(0,_.jsx)(o,{commands:J}),i[40]=J,i[41]=Y);let X;i[42]===s?X=i[43]:(X=async()=>await s({to:`/ec2/describe-volumes`}),i[42]=s,i[43]=X);let Z;i[44]!==v.isPending||i[45]!==A||i[46]!==X?(Z=(0,_.jsx)(oe,{isPending:v.isPending,isSubmitting:A,onCancel:X,pendingLabel:`Creating…`,submitLabel:`Create Volume`}),i[44]=v.isPending,i[45]=A,i[46]=X,i[47]=Z):Z=i[47];let Q;i[48]!==H||i[49]!==q||i[50]!==Y||i[51]!==Z||i[52]!==I?(Q=(0,_.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:I,children:[H,q,Y,Z]}),i[48]=H,i[49]=q,i[50]=Y,i[51]=Z,i[52]=I,i[53]=Q):Q=i[53];let $;return i[54]!==Q||i[55]!==F?($=(0,_.jsxs)(_.Fragment,{children:[N,P,F,Q]}),i[54]=Q,i[55]=F,i[56]=$):$=i[56],$}function ce(e){return(0,_.jsx)(i,{value:e.ZoneName??``,children:e.ZoneName},e.ZoneName)}function le(e){let t=e(`size`),n=typeof t==`number`?t:0,r=e(`availabilityZone`),i=typeof r==`string`?r:``;return[{label:`Create Volume`,parts:[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 create-volume`},{type:`flag`,value:` \\ +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{c as r,i,n as ee,s as a,t as te}from"./select.js";import{t as o}from"./cli-command-panel.js";import{f as ne}from"./ec2.js";import{Oo as s,R as re,wo as ie,xo as c,zi as l}from"./index.js";import{t as u}from"./page-heading.js";import{a as d,r as f,t as p}from"./field.js";import{i as m,n as h,t as g}from"./zod.js";import{c as ae}from"./ec22.js";import{t as oe}from"./form-actions.js";var se=c(),_=s();function v(){let i=(0,se.c)(57),s=ie(),{data:c}=t(re),v=ne(),y;i[0]===c.AvailabilityZones?y=i[1]:(y=c.AvailabilityZones??[],i[0]=c.AvailabilityZones,i[1]=y);let b=y,x=b[0]?.ZoneName??``,S;i[2]===Symbol.for(`react.memo_cache_sentinel`)?(S=g(ae),i[2]=S):S=i[2];let C;i[3]===x?C=i[4]:(C={resolver:S,defaultValues:{size:1,availabilityZone:x}},i[3]=x,i[4]=C);let{control:w,handleSubmit:T,register:E,watch:D,formState:O}=m(C),{errors:k,isSubmitting:A}=O,j;i[5]!==v||i[6]!==s?(j=async e=>{await v.mutateAsync(e),s({to:`/ec2/describe-volumes`})},i[5]=v,i[6]=s,i[7]=j):j=i[7];let M=j,N,P;i[8]===Symbol.for(`react.memo_cache_sentinel`)?(N=(0,_.jsx)(n,{to:`/ec2/describe-volumes`,children:`Back to volumes`}),P=(0,_.jsx)(u,{title:`Create Volume`}),i[8]=N,i[9]=P):(N=i[8],P=i[9]);let F;i[10]===v.error?F=i[11]:(F=v.error&&(0,_.jsx)(e,{error:v.error,msg:`Failed to create volume`}),i[10]=v.error,i[11]=F);let I;i[12]!==T||i[13]!==M?(I=T(M),i[12]=T,i[13]=M,i[14]=I):I=i[14];let L;i[15]===Symbol.for(`react.memo_cache_sentinel`)?(L=(0,_.jsx)(d,{children:(0,_.jsx)(`label`,{htmlFor:`size`,children:`Size (GiB)`})}),i[15]=L):L=i[15];let R=!!k.size,z;i[16]===E?z=i[17]:(z=E(`size`,{valueAsNumber:!0}),i[16]=E,i[17]=z);let B;i[18]!==R||i[19]!==z?(B=(0,_.jsx)(l,{"aria-invalid":R,id:`size`,max:16384,min:1,type:`number`,...z}),i[18]=R,i[19]=z,i[20]=B):B=i[20];let V;i[21]===k.size?V=i[22]:(V=(0,_.jsx)(f,{errors:[k.size]}),i[21]=k.size,i[22]=V);let H;i[23]!==B||i[24]!==V?(H=(0,_.jsxs)(p,{children:[L,B,V]}),i[23]=B,i[24]=V,i[25]=H):H=i[25];let U;i[26]===Symbol.for(`react.memo_cache_sentinel`)?(U=(0,_.jsx)(d,{children:(0,_.jsx)(`label`,{htmlFor:`availabilityZone`,children:`Availability Zone`})}),i[26]=U):U=i[26];let W;i[27]!==b||i[28]!==k.availabilityZone?(W=e=>{let{field:t}=e;return(0,_.jsxs)(te,{onValueChange:e=>t.onChange(e),value:t.value??``,children:[(0,_.jsx)(a,{"aria-invalid":!!k.availabilityZone,className:`w-full`,id:`availabilityZone`,children:(0,_.jsx)(r,{})}),(0,_.jsx)(ee,{children:b.map(ce)})]})},i[27]=b,i[28]=k.availabilityZone,i[29]=W):W=i[29];let G;i[30]!==w||i[31]!==W?(G=(0,_.jsx)(h,{control:w,name:`availabilityZone`,render:W}),i[30]=w,i[31]=W,i[32]=G):G=i[32];let K;i[33]===k.availabilityZone?K=i[34]:(K=(0,_.jsx)(f,{errors:[k.availabilityZone]}),i[33]=k.availabilityZone,i[34]=K);let q;i[35]!==G||i[36]!==K?(q=(0,_.jsxs)(p,{children:[U,G,K]}),i[35]=G,i[36]=K,i[37]=q):q=i[37];let J;i[38]===D?J=i[39]:(J=le(D),i[38]=D,i[39]=J);let Y;i[40]===J?Y=i[41]:(Y=(0,_.jsx)(o,{commands:J}),i[40]=J,i[41]=Y);let X;i[42]===s?X=i[43]:(X=async()=>await s({to:`/ec2/describe-volumes`}),i[42]=s,i[43]=X);let Z;i[44]!==v.isPending||i[45]!==A||i[46]!==X?(Z=(0,_.jsx)(oe,{isPending:v.isPending,isSubmitting:A,onCancel:X,pendingLabel:`Creating…`,submitLabel:`Create Volume`}),i[44]=v.isPending,i[45]=A,i[46]=X,i[47]=Z):Z=i[47];let Q;i[48]!==H||i[49]!==q||i[50]!==Y||i[51]!==Z||i[52]!==I?(Q=(0,_.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:I,children:[H,q,Y,Z]}),i[48]=H,i[49]=q,i[50]=Y,i[51]=Z,i[52]=I,i[53]=Q):Q=i[53];let $;return i[54]!==Q||i[55]!==F?($=(0,_.jsxs)(_.Fragment,{children:[N,P,F,Q]}),i[54]=Q,i[55]=F,i[56]=$):$=i[56],$}function ce(e){return(0,_.jsx)(i,{value:e.ZoneName??``,children:e.ZoneName},e.ZoneName)}function le(e){let t=e(`size`),n=typeof t==`number`?t:0,r=e(`availabilityZone`),i=typeof r==`string`?r:``;return[{label:`Create Volume`,parts:[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 create-volume`},{type:`flag`,value:` \\ --size`},{type:`value`,value:` ${n||1}`},{type:`flag`,value:` \\ --availability-zone`},{type:`value`,value:` ${i||``}`}]}]}export{v as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/create-vpc.js b/spinifex/services/spinifexui/frontend/dist/assets/create-vpc.js index d8d3056ee..3564da71a 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/create-vpc.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/create-vpc.js @@ -1,4 +1,4 @@ -import{t as e}from"./error-banner.js";import{t}from"./back-link.js";import{t as n}from"./chevron-down.js";import{t as r}from"./chevron-right.js";import{c as i,i as a,n as o,s,t as c}from"./select.js";import{t as l}from"./cli-command-panel.js";import{N as u,m as d,p as f}from"./ec2.js";import{Po as p,Ta as m,Ti as h,ho as g,mo as _,so as v,uo as y}from"./index.js";import{t as b}from"./page-heading.js";import{a as x,r as S,t as C}from"./field.js";import{i as w,n as T,t as E}from"./zod.js";import{l as D}from"./ec22.js";import{t as O}from"./form-actions.js";var k=v(),A=p(g(),1),j=_();function M(e){let t=(0,k.c)(18),{form:i,type:a,count:o,defaults:s}=e,[c,l]=(0,A.useState)(!1),u=a===`public`?`publicSubnetCidrs`:`privateSubnetCidrs`;if(o===0)return null;let d;t[0]===c?d=t[1]:(d=()=>l(!c),t[0]=c,t[1]=d);let f;t[2]===c?f=t[3]:(f=c?(0,j.jsx)(n,{className:`size-3`}):(0,j.jsx)(r,{className:`size-3`}),t[2]=c,t[3]=f);let p;t[4]!==d||t[5]!==f||t[6]!==a?(p=(0,j.jsxs)(m,{className:`gap-1 px-0 text-xs text-muted-foreground`,onClick:d,type:`button`,variant:`link`,children:[f,`Customize `,a,` subnet CIDR blocks`]}),t[4]=d,t[5]=f,t[6]=a,t[7]=p):p=t[7];let g;t[8]!==o||t[9]!==s||t[10]!==c||t[11]!==u||t[12]!==i||t[13]!==a?(g=c&&(0,j.jsx)(`div`,{className:`mt-2 space-y-2`,children:Array.from({length:o},(e,t)=>(0,j.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,j.jsxs)(`span`,{className:`w-32 text-xs text-muted-foreground`,children:[a===`public`?`Public`:`Private`,` subnet `,t+1]}),(0,j.jsx)(h,{defaultValue:s[t],placeholder:s[t],...i.register(`${u}.${t}`)})]},t))}),t[8]=o,t[9]=s,t[10]=c,t[11]=u,t[12]=i,t[13]=a,t[14]=g):g=t[14];let _;return t[15]!==p||t[16]!==g?(_=(0,j.jsxs)(`div`,{className:`mt-2`,children:[p,g]}),t[15]=p,t[16]=g,t[17]=_):_=t[17],_}function N(e){let t=(0,k.c)(8),{label:n,cidr:r,variant:i}=e,a=`rounded-md border px-3 py-2 text-xs ${i===`public`?`border-emerald-500/30 bg-emerald-500/10`:`border-blue-500/30 bg-blue-500/10`}`,o;t[0]===n?o=t[1]:(o=(0,j.jsx)(`div`,{className:`font-medium`,children:n}),t[0]=n,t[1]=o);let s;t[2]===r?s=t[3]:(s=(0,j.jsx)(`div`,{className:`text-muted-foreground`,children:r}),t[2]=r,t[3]=s);let c;return t[4]!==a||t[5]!==o||t[6]!==s?(c=(0,j.jsxs)(`div`,{className:a,children:[o,s]}),t[4]=a,t[5]=o,t[6]=s,t[7]=c):c=t[7],c}function P(e){let t=(0,k.c)(14),{mode:n,vpcCidr:r,publicSubnets:i,privateSubnets:a,hasIgw:o}=e,s;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(s=(0,j.jsx)(`h3`,{className:`mb-3 text-xs font-semibold tracking-wider text-muted-foreground uppercase`,children:`Preview`}),t[0]=s):s=t[0];let c;t[1]===r?c=t[2]:(c=(0,j.jsxs)(`div`,{className:`mb-3 text-xs font-medium`,children:[`VPC `,(0,j.jsxs)(`span`,{className:`text-muted-foreground`,children:[`(`,r,`)`]})]}),t[1]=r,t[2]=c);let l;t[3]!==o||t[4]!==n||t[5]!==a||t[6]!==i?(l=n===`vpc-and-more`&&(0,j.jsxs)(`div`,{className:`grid gap-4 md:grid-cols-3`,children:[(0,j.jsxs)(`div`,{className:`space-y-2`,children:[(0,j.jsx)(`div`,{className:`text-xs font-medium text-muted-foreground`,children:`Subnets`}),i.map(I),a.map(F),i.length===0&&a.length===0&&(0,j.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`No subnets`})]}),(0,j.jsxs)(`div`,{className:`space-y-2`,children:[(0,j.jsx)(`div`,{className:`text-xs font-medium text-muted-foreground`,children:`Route Tables`}),i.length>0&&(0,j.jsxs)(`div`,{className:`rounded-md border border-foreground/10 bg-background px-3 py-2 text-xs`,children:[(0,j.jsx)(`div`,{className:`font-medium`,children:`Public Route Table`}),(0,j.jsx)(`div`,{className:`mt-1 text-muted-foreground`,children:`0.0.0.0/0 → IGW`}),(0,j.jsx)(`div`,{className:`text-muted-foreground`,children:`local`})]}),a.length>0&&(0,j.jsxs)(`div`,{className:`rounded-md border border-foreground/10 bg-background px-3 py-2 text-xs`,children:[(0,j.jsx)(`div`,{className:`font-medium`,children:`Private Route Table`}),(0,j.jsx)(`div`,{className:`mt-1 text-muted-foreground`,children:`local`})]})]}),(0,j.jsxs)(`div`,{className:`space-y-2`,children:[(0,j.jsx)(`div`,{className:`text-xs font-medium text-muted-foreground`,children:`Network Connections`}),o&&(0,j.jsxs)(`div`,{className:`rounded-md border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-xs`,children:[(0,j.jsx)(`div`,{className:`font-medium`,children:`Internet Gateway`}),(0,j.jsx)(`div`,{className:`text-muted-foreground`,children:`Attached to VPC`})]}),!o&&(0,j.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`No internet gateway`})]})]}),t[3]=o,t[4]=n,t[5]=a,t[6]=i,t[7]=l):l=t[7];let u;t[8]===n?u=t[9]:(u=n===`vpc-only`&&(0,j.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`VPC only — no additional resources will be created.`}),t[8]=n,t[9]=u);let d;return t[10]!==c||t[11]!==l||t[12]!==u?(d=(0,j.jsxs)(`div`,{className:`rounded-lg border bg-muted/30 p-4`,children:[s,(0,j.jsxs)(`div`,{className:`rounded-lg border-2 border-dashed border-foreground/20 p-4`,children:[c,l,u]})]}),t[10]=c,t[11]=l,t[12]=u,t[13]=d):d=t[13],d}function F(e){return(0,j.jsx)(N,{cidr:e.cidr,label:e.label,variant:`private`},e.cidr)}function I(e){return(0,j.jsx)(N,{cidr:e.cidr,label:e.label,variant:`public`},e.cidr)}var L=[0,1],R=[0,1,2];function z(){let n=y(),r=f(),p=d(),[g,_]=(0,A.useState)(null),v=w({resolver:E(D),defaultValues:{mode:`vpc-only`,namePrefix:``,autoGenerateNames:!0,cidrBlock:`10.0.0.0/16`,tenancy:`default`,publicSubnetCount:1,privateSubnetCount:1,publicSubnetCidrs:[],privateSubnetCidrs:[],tags:[]}}),{handleSubmit:k,register:N,watch:F,control:I,formState:{errors:z,isSubmitting:V}}=v,H=F(`mode`),U=F(`cidrBlock`),W=F(`publicSubnetCount`),G=F(`privateSubnetCount`),K=u(U||`10.0.0.0/16`,H===`vpc-and-more`?W:0,H===`vpc-and-more`?G:0),[q,J]=(0,A.useState)(``),Y=async e=>{if(_(null),e.mode===`vpc-only`){let t=e.autoGenerateNames&&e.namePrefix?`${e.namePrefix}-vpc`:e.namePrefix,i=(await r.mutateAsync({cidrBlock:e.cidrBlock,name:t||void 0})).Vpc?.VpcId;n(i?{to:`/ec2/describe-vpcs/$id`,params:{id:i}}:{to:`/ec2/describe-vpcs`});return}J(`Creating VPC and resources...`);let t=await p.mutateAsync(e);_(t),!t.error&&t.vpcId&&n({to:`/ec2/describe-vpcs/$id`,params:{id:t.vpcId}}),J(``)},X=r.error??p.error,Z=r.isPending||p.isPending;return(0,j.jsxs)(j.Fragment,{children:[(0,j.jsx)(t,{to:`/ec2/describe-vpcs`,children:`Back to VPCs`}),(0,j.jsx)(b,{title:`Create VPC`}),X&&(0,j.jsx)(e,{error:X,msg:`Failed to create VPC`}),g?.error&&(0,j.jsxs)(`div`,{className:`mb-6 max-w-4xl rounded-md border border-destructive bg-destructive/10 p-4`,children:[(0,j.jsxs)(`h2`,{className:`text-sm font-medium text-destructive`,children:[`Wizard failed: `,g.failedStep]}),(0,j.jsx)(`p`,{className:`mt-1 text-sm text-destructive`,children:g.error.message}),g.created.length>0&&(0,j.jsxs)(`div`,{className:`mt-3`,children:[(0,j.jsx)(`p`,{className:`text-xs font-medium text-destructive`,children:`Successfully created resources:`}),(0,j.jsx)(`ul`,{className:`mt-1 list-inside list-disc text-xs text-destructive`,children:g.created.map((e,t)=>(0,j.jsxs)(`li`,{children:[e.type,`: `,e.id]},t))})]})]}),q&&(0,j.jsx)(`div`,{className:`mb-4 max-w-4xl text-sm text-muted-foreground`,children:q}),(0,j.jsxs)(`div`,{className:`flex max-w-6xl gap-8`,children:[(0,j.jsxs)(`form`,{className:`min-w-0 flex-1 space-y-6`,onSubmit:k(Y),children:[(0,j.jsxs)(C,{children:[(0,j.jsx)(x,{children:`Resources to create`}),(0,j.jsx)(T,{control:I,name:`mode`,render:({field:e})=>(0,j.jsxs)(`div`,{className:`flex gap-4`,children:[(0,j.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[(0,j.jsx)(`input`,{"aria-label":`VPC only`,checked:e.value===`vpc-only`,name:`mode`,onChange:()=>e.onChange(`vpc-only`),type:`radio`}),`VPC only`]}),(0,j.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[(0,j.jsx)(`input`,{"aria-label":`VPC and more`,checked:e.value===`vpc-and-more`,name:`mode`,onChange:()=>e.onChange(`vpc-and-more`),type:`radio`}),`VPC and more`]})]})})]}),(0,j.jsxs)(C,{children:[(0,j.jsx)(x,{children:(0,j.jsx)(`label`,{htmlFor:`namePrefix`,children:`Name tag auto-generation`})}),(0,j.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,j.jsx)(h,{id:`namePrefix`,placeholder:`project`,...N(`namePrefix`)}),(0,j.jsx)(T,{control:I,name:`autoGenerateNames`,render:({field:e})=>(0,j.jsxs)(`label`,{className:`flex shrink-0 items-center gap-2 text-xs`,children:[(0,j.jsx)(`input`,{"aria-label":`Auto-generate name tags`,checked:e.value,onChange:t=>e.onChange(t.target.checked),type:`checkbox`}),`Auto-generate`]})})]})]}),(0,j.jsxs)(C,{children:[(0,j.jsx)(x,{children:(0,j.jsx)(`label`,{htmlFor:`cidrBlock`,children:`IPv4 CIDR block`})}),(0,j.jsx)(h,{"aria-invalid":!!z.cidrBlock,id:`cidrBlock`,placeholder:`10.0.0.0/16`,...N(`cidrBlock`)}),(0,j.jsx)(S,{errors:[z.cidrBlock]})]}),(0,j.jsxs)(C,{children:[(0,j.jsx)(x,{children:`Tenancy`}),(0,j.jsx)(T,{control:I,name:`tenancy`,render:({field:e})=>(0,j.jsxs)(c,{onValueChange:e.onChange,value:e.value,children:[(0,j.jsx)(s,{id:`tenancy`,children:(0,j.jsx)(i,{})}),(0,j.jsxs)(o,{children:[(0,j.jsx)(a,{value:`default`,children:`default`}),(0,j.jsx)(a,{value:`dedicated`,children:`dedicated`})]})]})})]}),H===`vpc-and-more`&&(0,j.jsxs)(j.Fragment,{children:[(0,j.jsxs)(C,{children:[(0,j.jsx)(x,{children:`Number of public subnets`}),(0,j.jsx)(T,{control:I,name:`publicSubnetCount`,render:({field:e})=>(0,j.jsx)(`div`,{className:`flex gap-1`,children:L.map(t=>(0,j.jsx)(m,{onClick:()=>e.onChange(t),size:`sm`,type:`button`,variant:e.value===t?`default`:`outline`,children:t},t))})}),(0,j.jsx)(M,{count:W,defaults:K.publicSubnets.map(e=>e.cidr),form:v,type:`public`})]}),(0,j.jsxs)(C,{children:[(0,j.jsx)(x,{children:`Number of private subnets`}),(0,j.jsx)(T,{control:I,name:`privateSubnetCount`,render:({field:e})=>(0,j.jsx)(`div`,{className:`flex gap-1`,children:R.map(t=>(0,j.jsx)(m,{onClick:()=>e.onChange(t),size:`sm`,type:`button`,variant:e.value===t?`default`:`outline`,children:t},t))})}),(0,j.jsx)(M,{count:G,defaults:K.privateSubnets.map(e=>e.cidr),form:v,type:`private`})]})]}),(0,j.jsx)(l,{commands:B(F,K)}),(0,j.jsx)(O,{isPending:Z,isSubmitting:V,onCancel:async()=>await n({to:`/ec2/describe-vpcs`}),pendingLabel:`Creating…`,submitLabel:`Create VPC`})]}),(0,j.jsx)(`div`,{className:`hidden min-w-0 flex-1 lg:block`,children:(0,j.jsx)(P,{hasIgw:H===`vpc-and-more`&&W>0,mode:H,privateSubnets:K.privateSubnets,publicSubnets:K.publicSubnets,vpcCidr:U||`10.0.0.0/16`})})]})]})}function B(e,t){let n=e(`mode`),r=typeof n==`string`?n:``,i=e(`cidrBlock`),a=typeof i==`string`?i:``,o=e(`tenancy`),s=typeof o==`string`?o:``;if(r===`vpc-only`){let e=[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 create-vpc`},{type:`flag`,value:` \\ +import{t as e}from"./error-banner.js";import{t}from"./back-link.js";import{t as n}from"./chevron-down.js";import{t as r}from"./chevron-right.js";import{c as i,i as a,n as o,s,t as c}from"./select.js";import{t as l}from"./cli-command-panel.js";import{N as u,m as d,p as f}from"./ec2.js";import{Jo as p,Oo as m,ko as h,wo as g,xo as _,za as v,zi as y}from"./index.js";import{t as b}from"./page-heading.js";import{a as x,r as S,t as C}from"./field.js";import{i as w,n as T,t as E}from"./zod.js";import{l as D}from"./ec22.js";import{t as O}from"./form-actions.js";var k=_(),A=p(h(),1),j=m();function M(e){let t=(0,k.c)(18),{form:i,type:a,count:o,defaults:s}=e,[c,l]=(0,A.useState)(!1),u=a===`public`?`publicSubnetCidrs`:`privateSubnetCidrs`;if(o===0)return null;let d;t[0]===c?d=t[1]:(d=()=>l(!c),t[0]=c,t[1]=d);let f;t[2]===c?f=t[3]:(f=c?(0,j.jsx)(n,{className:`size-3`}):(0,j.jsx)(r,{className:`size-3`}),t[2]=c,t[3]=f);let p;t[4]!==d||t[5]!==f||t[6]!==a?(p=(0,j.jsxs)(v,{className:`gap-1 px-0 text-xs text-muted-foreground`,onClick:d,type:`button`,variant:`link`,children:[f,`Customize `,a,` subnet CIDR blocks`]}),t[4]=d,t[5]=f,t[6]=a,t[7]=p):p=t[7];let m;t[8]!==o||t[9]!==s||t[10]!==c||t[11]!==u||t[12]!==i||t[13]!==a?(m=c&&(0,j.jsx)(`div`,{className:`mt-2 space-y-2`,children:Array.from({length:o},(e,t)=>(0,j.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,j.jsxs)(`span`,{className:`w-32 text-xs text-muted-foreground`,children:[a===`public`?`Public`:`Private`,` subnet `,t+1]}),(0,j.jsx)(y,{defaultValue:s[t],placeholder:s[t],...i.register(`${u}.${t}`)})]},t))}),t[8]=o,t[9]=s,t[10]=c,t[11]=u,t[12]=i,t[13]=a,t[14]=m):m=t[14];let h;return t[15]!==p||t[16]!==m?(h=(0,j.jsxs)(`div`,{className:`mt-2`,children:[p,m]}),t[15]=p,t[16]=m,t[17]=h):h=t[17],h}function N(e){let t=(0,k.c)(8),{label:n,cidr:r,variant:i}=e,a=`rounded-md border px-3 py-2 text-xs ${i===`public`?`border-emerald-500/30 bg-emerald-500/10`:`border-blue-500/30 bg-blue-500/10`}`,o;t[0]===n?o=t[1]:(o=(0,j.jsx)(`div`,{className:`font-medium`,children:n}),t[0]=n,t[1]=o);let s;t[2]===r?s=t[3]:(s=(0,j.jsx)(`div`,{className:`text-muted-foreground`,children:r}),t[2]=r,t[3]=s);let c;return t[4]!==a||t[5]!==o||t[6]!==s?(c=(0,j.jsxs)(`div`,{className:a,children:[o,s]}),t[4]=a,t[5]=o,t[6]=s,t[7]=c):c=t[7],c}function P(e){let t=(0,k.c)(14),{mode:n,vpcCidr:r,publicSubnets:i,privateSubnets:a,hasIgw:o}=e,s;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(s=(0,j.jsx)(`h3`,{className:`mb-3 text-xs font-semibold tracking-wider text-muted-foreground uppercase`,children:`Preview`}),t[0]=s):s=t[0];let c;t[1]===r?c=t[2]:(c=(0,j.jsxs)(`div`,{className:`mb-3 text-xs font-medium`,children:[`VPC `,(0,j.jsxs)(`span`,{className:`text-muted-foreground`,children:[`(`,r,`)`]})]}),t[1]=r,t[2]=c);let l;t[3]!==o||t[4]!==n||t[5]!==a||t[6]!==i?(l=n===`vpc-and-more`&&(0,j.jsxs)(`div`,{className:`grid gap-4 md:grid-cols-3`,children:[(0,j.jsxs)(`div`,{className:`space-y-2`,children:[(0,j.jsx)(`div`,{className:`text-xs font-medium text-muted-foreground`,children:`Subnets`}),i.map(I),a.map(F),i.length===0&&a.length===0&&(0,j.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`No subnets`})]}),(0,j.jsxs)(`div`,{className:`space-y-2`,children:[(0,j.jsx)(`div`,{className:`text-xs font-medium text-muted-foreground`,children:`Route Tables`}),i.length>0&&(0,j.jsxs)(`div`,{className:`rounded-md border border-foreground/10 bg-background px-3 py-2 text-xs`,children:[(0,j.jsx)(`div`,{className:`font-medium`,children:`Public Route Table`}),(0,j.jsx)(`div`,{className:`mt-1 text-muted-foreground`,children:`0.0.0.0/0 → IGW`}),(0,j.jsx)(`div`,{className:`text-muted-foreground`,children:`local`})]}),a.length>0&&(0,j.jsxs)(`div`,{className:`rounded-md border border-foreground/10 bg-background px-3 py-2 text-xs`,children:[(0,j.jsx)(`div`,{className:`font-medium`,children:`Private Route Table`}),(0,j.jsx)(`div`,{className:`mt-1 text-muted-foreground`,children:`local`})]})]}),(0,j.jsxs)(`div`,{className:`space-y-2`,children:[(0,j.jsx)(`div`,{className:`text-xs font-medium text-muted-foreground`,children:`Network Connections`}),o&&(0,j.jsxs)(`div`,{className:`rounded-md border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-xs`,children:[(0,j.jsx)(`div`,{className:`font-medium`,children:`Internet Gateway`}),(0,j.jsx)(`div`,{className:`text-muted-foreground`,children:`Attached to VPC`})]}),!o&&(0,j.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`No internet gateway`})]})]}),t[3]=o,t[4]=n,t[5]=a,t[6]=i,t[7]=l):l=t[7];let u;t[8]===n?u=t[9]:(u=n===`vpc-only`&&(0,j.jsx)(`div`,{className:`text-xs text-muted-foreground`,children:`VPC only — no additional resources will be created.`}),t[8]=n,t[9]=u);let d;return t[10]!==c||t[11]!==l||t[12]!==u?(d=(0,j.jsxs)(`div`,{className:`rounded-lg border bg-muted/30 p-4`,children:[s,(0,j.jsxs)(`div`,{className:`rounded-lg border-2 border-dashed border-foreground/20 p-4`,children:[c,l,u]})]}),t[10]=c,t[11]=l,t[12]=u,t[13]=d):d=t[13],d}function F(e){return(0,j.jsx)(N,{cidr:e.cidr,label:e.label,variant:`private`},e.cidr)}function I(e){return(0,j.jsx)(N,{cidr:e.cidr,label:e.label,variant:`public`},e.cidr)}var L=[0,1],R=[0,1,2];function z(){let n=g(),r=f(),p=d(),[m,h]=(0,A.useState)(null),_=w({resolver:E(D),defaultValues:{mode:`vpc-only`,namePrefix:``,autoGenerateNames:!0,cidrBlock:`10.0.0.0/16`,tenancy:`default`,publicSubnetCount:1,privateSubnetCount:1,publicSubnetCidrs:[],privateSubnetCidrs:[],tags:[]}}),{handleSubmit:k,register:N,watch:F,control:I,formState:{errors:z,isSubmitting:V}}=_,H=F(`mode`),U=F(`cidrBlock`),W=F(`publicSubnetCount`),G=F(`privateSubnetCount`),K=u(U||`10.0.0.0/16`,H===`vpc-and-more`?W:0,H===`vpc-and-more`?G:0),[q,J]=(0,A.useState)(``),Y=async e=>{if(h(null),e.mode===`vpc-only`){let t=e.autoGenerateNames&&e.namePrefix?`${e.namePrefix}-vpc`:e.namePrefix,i=(await r.mutateAsync({cidrBlock:e.cidrBlock,name:t||void 0})).Vpc?.VpcId;n(i?{to:`/ec2/describe-vpcs/$id`,params:{id:i}}:{to:`/ec2/describe-vpcs`});return}J(`Creating VPC and resources...`);let t=await p.mutateAsync(e);h(t),!t.error&&t.vpcId&&n({to:`/ec2/describe-vpcs/$id`,params:{id:t.vpcId}}),J(``)},X=r.error??p.error,Z=r.isPending||p.isPending;return(0,j.jsxs)(j.Fragment,{children:[(0,j.jsx)(t,{to:`/ec2/describe-vpcs`,children:`Back to VPCs`}),(0,j.jsx)(b,{title:`Create VPC`}),X&&(0,j.jsx)(e,{error:X,msg:`Failed to create VPC`}),m?.error&&(0,j.jsxs)(`div`,{className:`mb-6 max-w-4xl rounded-md border border-destructive bg-destructive/10 p-4`,children:[(0,j.jsxs)(`h2`,{className:`text-sm font-medium text-destructive`,children:[`Wizard failed: `,m.failedStep]}),(0,j.jsx)(`p`,{className:`mt-1 text-sm text-destructive`,children:m.error.message}),m.created.length>0&&(0,j.jsxs)(`div`,{className:`mt-3`,children:[(0,j.jsx)(`p`,{className:`text-xs font-medium text-destructive`,children:`Successfully created resources:`}),(0,j.jsx)(`ul`,{className:`mt-1 list-inside list-disc text-xs text-destructive`,children:m.created.map((e,t)=>(0,j.jsxs)(`li`,{children:[e.type,`: `,e.id]},t))})]})]}),q&&(0,j.jsx)(`div`,{className:`mb-4 max-w-4xl text-sm text-muted-foreground`,children:q}),(0,j.jsxs)(`div`,{className:`flex max-w-6xl gap-8`,children:[(0,j.jsxs)(`form`,{className:`min-w-0 flex-1 space-y-6`,onSubmit:k(Y),children:[(0,j.jsxs)(C,{children:[(0,j.jsx)(x,{children:`Resources to create`}),(0,j.jsx)(T,{control:I,name:`mode`,render:({field:e})=>(0,j.jsxs)(`div`,{className:`flex gap-4`,children:[(0,j.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[(0,j.jsx)(`input`,{"aria-label":`VPC only`,checked:e.value===`vpc-only`,name:`mode`,onChange:()=>e.onChange(`vpc-only`),type:`radio`}),`VPC only`]}),(0,j.jsxs)(`label`,{className:`flex items-center gap-2 text-xs`,children:[(0,j.jsx)(`input`,{"aria-label":`VPC and more`,checked:e.value===`vpc-and-more`,name:`mode`,onChange:()=>e.onChange(`vpc-and-more`),type:`radio`}),`VPC and more`]})]})})]}),(0,j.jsxs)(C,{children:[(0,j.jsx)(x,{children:(0,j.jsx)(`label`,{htmlFor:`namePrefix`,children:`Name tag auto-generation`})}),(0,j.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,j.jsx)(y,{id:`namePrefix`,placeholder:`project`,...N(`namePrefix`)}),(0,j.jsx)(T,{control:I,name:`autoGenerateNames`,render:({field:e})=>(0,j.jsxs)(`label`,{className:`flex shrink-0 items-center gap-2 text-xs`,children:[(0,j.jsx)(`input`,{"aria-label":`Auto-generate name tags`,checked:e.value,onChange:t=>e.onChange(t.target.checked),type:`checkbox`}),`Auto-generate`]})})]})]}),(0,j.jsxs)(C,{children:[(0,j.jsx)(x,{children:(0,j.jsx)(`label`,{htmlFor:`cidrBlock`,children:`IPv4 CIDR block`})}),(0,j.jsx)(y,{"aria-invalid":!!z.cidrBlock,id:`cidrBlock`,placeholder:`10.0.0.0/16`,...N(`cidrBlock`)}),(0,j.jsx)(S,{errors:[z.cidrBlock]})]}),(0,j.jsxs)(C,{children:[(0,j.jsx)(x,{children:`Tenancy`}),(0,j.jsx)(T,{control:I,name:`tenancy`,render:({field:e})=>(0,j.jsxs)(c,{onValueChange:e.onChange,value:e.value,children:[(0,j.jsx)(s,{id:`tenancy`,children:(0,j.jsx)(i,{})}),(0,j.jsxs)(o,{children:[(0,j.jsx)(a,{value:`default`,children:`default`}),(0,j.jsx)(a,{value:`dedicated`,children:`dedicated`})]})]})})]}),H===`vpc-and-more`&&(0,j.jsxs)(j.Fragment,{children:[(0,j.jsxs)(C,{children:[(0,j.jsx)(x,{children:`Number of public subnets`}),(0,j.jsx)(T,{control:I,name:`publicSubnetCount`,render:({field:e})=>(0,j.jsx)(`div`,{className:`flex gap-1`,children:L.map(t=>(0,j.jsx)(v,{onClick:()=>e.onChange(t),size:`sm`,type:`button`,variant:e.value===t?`default`:`outline`,children:t},t))})}),(0,j.jsx)(M,{count:W,defaults:K.publicSubnets.map(e=>e.cidr),form:_,type:`public`})]}),(0,j.jsxs)(C,{children:[(0,j.jsx)(x,{children:`Number of private subnets`}),(0,j.jsx)(T,{control:I,name:`privateSubnetCount`,render:({field:e})=>(0,j.jsx)(`div`,{className:`flex gap-1`,children:R.map(t=>(0,j.jsx)(v,{onClick:()=>e.onChange(t),size:`sm`,type:`button`,variant:e.value===t?`default`:`outline`,children:t},t))})}),(0,j.jsx)(M,{count:G,defaults:K.privateSubnets.map(e=>e.cidr),form:_,type:`private`})]})]}),(0,j.jsx)(l,{commands:B(F,K)}),(0,j.jsx)(O,{isPending:Z,isSubmitting:V,onCancel:async()=>await n({to:`/ec2/describe-vpcs`}),pendingLabel:`Creating…`,submitLabel:`Create VPC`})]}),(0,j.jsx)(`div`,{className:`hidden min-w-0 flex-1 lg:block`,children:(0,j.jsx)(P,{hasIgw:H===`vpc-and-more`&&W>0,mode:H,privateSubnets:K.privateSubnets,publicSubnets:K.publicSubnets,vpcCidr:U||`10.0.0.0/16`})})]})]})}function B(e,t){let n=e(`mode`),r=typeof n==`string`?n:``,i=e(`cidrBlock`),a=typeof i==`string`?i:``,o=e(`tenancy`),s=typeof o==`string`?o:``;if(r===`vpc-only`){let e=[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 create-vpc`},{type:`flag`,value:` \\ --cidr-block`},{type:`value`,value:` ${a||`10.0.0.0/16`}`}];return s&&s!==`default`&&e.push({type:`flag`,value:` \\ --instance-tenancy`},{type:`value`,value:` ${s}`}),[{label:`Create VPC`,parts:e}]}let c=[],l=[...t.publicSubnets.map((e,t)=>({...e,name:`PUBLIC_SUBNET_${t+1}`})),...t.privateSubnets.map((e,t)=>({...e,name:`PRIVATE_SUBNET_${t+1}`}))];c.push({label:`Create VPC`,parts:[{type:`comment`,value:`# Create VPC with subnets, internet gateway, and routing diff --git a/spinifex/services/spinifexui/frontend/dist/assets/delete-confirmation-dialog.js b/spinifex/services/spinifexui/frontend/dist/assets/delete-confirmation-dialog.js index 34688c6cb..027c95724 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/delete-confirmation-dialog.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/delete-confirmation-dialog.js @@ -1 +1 @@ -import{mo as e,so as t}from"./index.js";import{a as n,i as r,l as i,n as a,o,r as s,s as c,t as l}from"./alert-dialog.js";var u=t(),d=e();function f(e){let t=(0,u.c)(19),{open:f,onOpenChange:p,title:m,description:h,isPending:g,onConfirm:_,confirmLabel:v,pendingLabel:y}=e,b=v===void 0?`Delete`:v,x=y===void 0?`Deleting…`:y,S;t[0]===m?S=t[1]:(S=(0,d.jsx)(i,{children:m}),t[0]=m,t[1]=S);let C;t[2]===h?C=t[3]:(C=(0,d.jsx)(n,{children:h}),t[2]=h,t[3]=C);let w;t[4]!==S||t[5]!==C?(w=(0,d.jsxs)(c,{children:[S,C]}),t[4]=S,t[5]=C,t[6]=w):w=t[6];let T;t[7]===Symbol.for(`react.memo_cache_sentinel`)?(T=(0,d.jsx)(s,{children:`Cancel`}),t[7]=T):T=t[7];let E=g?x:b,D;t[8]!==g||t[9]!==_||t[10]!==E?(D=(0,d.jsxs)(o,{children:[T,(0,d.jsx)(a,{disabled:g,onClick:_,children:E})]}),t[8]=g,t[9]=_,t[10]=E,t[11]=D):D=t[11];let O;t[12]!==w||t[13]!==D?(O=(0,d.jsxs)(r,{children:[w,D]}),t[12]=w,t[13]=D,t[14]=O):O=t[14];let k;return t[15]!==p||t[16]!==f||t[17]!==O?(k=(0,d.jsx)(l,{onOpenChange:p,open:f,children:O}),t[15]=p,t[16]=f,t[17]=O,t[18]=k):k=t[18],k}export{f as t}; \ No newline at end of file +import{Oo as e,xo as t}from"./index.js";import{a as n,i as r,l as i,n as a,o,r as s,s as c,t as l}from"./alert-dialog.js";var u=t(),d=e();function f(e){let t=(0,u.c)(19),{open:f,onOpenChange:p,title:m,description:h,isPending:g,onConfirm:_,confirmLabel:v,pendingLabel:y}=e,b=v===void 0?`Delete`:v,x=y===void 0?`Deleting…`:y,S;t[0]===m?S=t[1]:(S=(0,d.jsx)(i,{children:m}),t[0]=m,t[1]=S);let C;t[2]===h?C=t[3]:(C=(0,d.jsx)(n,{children:h}),t[2]=h,t[3]=C);let w;t[4]!==S||t[5]!==C?(w=(0,d.jsxs)(c,{children:[S,C]}),t[4]=S,t[5]=C,t[6]=w):w=t[6];let T;t[7]===Symbol.for(`react.memo_cache_sentinel`)?(T=(0,d.jsx)(s,{children:`Cancel`}),t[7]=T):T=t[7];let E=g?x:b,D;t[8]!==g||t[9]!==_||t[10]!==E?(D=(0,d.jsxs)(o,{children:[T,(0,d.jsx)(a,{disabled:g,onClick:_,children:E})]}),t[8]=g,t[9]=_,t[10]=E,t[11]=D):D=t[11];let O;t[12]!==w||t[13]!==D?(O=(0,d.jsxs)(r,{children:[w,D]}),t[12]=w,t[13]=D,t[14]=O):O=t[14];let k;return t[15]!==p||t[16]!==f||t[17]!==O?(k=(0,d.jsx)(l,{onOpenChange:p,open:f,children:O}),t[15]=p,t[16]=f,t[17]=O,t[18]=k):k=t[18],k}export{f as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/describe-images.js b/spinifex/services/spinifexui/frontend/dist/assets/describe-images.js index 4899be18d..ba5888371 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/describe-images.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/describe-images.js @@ -1 +1 @@ -import{t as e}from"./useSuspenseQuery.js";import{mo as t,so as n,z as r}from"./index.js";import{t as i}from"./page-heading.js";import{t as a}from"./state-badge.js";import{t as o}from"./system-managed.js";import{t as s}from"./list-card.js";var c=n(),l=t();function u(){let t=(0,c.c)(3),{data:n}=e(r),a;if(t[0]!==n.Images){let e=(n.Images??[]).filter(f),r;t[2]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,l.jsx)(i,{title:`Images`}),t[2]=r):r=t[2],a=(0,l.jsxs)(l.Fragment,{children:[r,e.length>0?(0,l.jsx)(`div`,{className:`space-y-4`,children:e.map(d)}):(0,l.jsx)(`p`,{className:`text-muted-foreground`,children:`No images found.`})]}),t[0]=n.Images,t[1]=a}else a=t[1];return a}function d(e){return e.ImageId?(0,l.jsx)(s,{badge:(0,l.jsx)(a,{state:e.State}),params:{id:e.ImageId},subtitle:e.ImageId??``,title:e.Name??e.ImageId??``,to:`/ec2/describe-images/$id`},e.ImageId):null}function f(e){return!o(e)}export{u as component}; \ No newline at end of file +import{t as e}from"./useSuspenseQuery.js";import{B as t,Oo as n,xo as r}from"./index.js";import{t as i}from"./page-heading.js";import{t as a}from"./state-badge.js";import{t as o}from"./system-managed.js";import{t as s}from"./list-card.js";var c=r(),l=n();function u(){let n=(0,c.c)(3),{data:r}=e(t),a;if(n[0]!==r.Images){let e=(r.Images??[]).filter(f),t;n[2]===Symbol.for(`react.memo_cache_sentinel`)?(t=(0,l.jsx)(i,{title:`Images`}),n[2]=t):t=n[2],a=(0,l.jsxs)(l.Fragment,{children:[t,e.length>0?(0,l.jsx)(`div`,{className:`space-y-4`,children:e.map(d)}):(0,l.jsx)(`p`,{className:`text-muted-foreground`,children:`No images found.`})]}),n[0]=r.Images,n[1]=a}else a=n[1];return a}function d(e){return e.ImageId?(0,l.jsx)(s,{badge:(0,l.jsx)(a,{state:e.State}),params:{id:e.ImageId},subtitle:e.ImageId??``,title:e.Name??e.ImageId??``,to:`/ec2/describe-images/$id`},e.ImageId):null}function f(e){return!o(e)}export{u as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/describe-instances.js b/spinifex/services/spinifexui/frontend/dist/assets/describe-instances.js index 24a2a9d2a..63aa23abe 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/describe-instances.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/describe-instances.js @@ -1 +1 @@ -import{t as e}from"./useSuspenseQuery.js";import{H as t,Ta as n,lo as r,mo as i,so as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./state-badge.js";import{t as c}from"./list-card.js";var l=a(),u=i(),d={running:0,pending:1,stopping:2,"shutting-down":3,stopped:4,terminated:5};function f(){let i=(0,l.c)(3),{data:a}=e(t),s;if(i[0]!==a.Reservations){let e=(a.Reservations?.flatMap(h)??[]).toSorted(m),t;i[2]===Symbol.for(`react.memo_cache_sentinel`)?(t=(0,u.jsx)(o,{actions:(0,u.jsx)(r,{to:`/ec2/run-instances`,children:(0,u.jsx)(n,{children:`Run Instances`})}),title:`Instances`}),i[2]=t):t=i[2],s=(0,u.jsxs)(u.Fragment,{children:[t,e.length>0?(0,u.jsx)(`div`,{className:`space-y-4`,children:e.map(p)}):(0,u.jsx)(`p`,{className:`text-muted-foreground`,children:`No instances found.`})]}),i[0]=a.Reservations,i[1]=s}else s=i[1];return s}function p(e){return e.InstanceId?(0,u.jsx)(c,{badge:(0,u.jsx)(s,{state:e.State?.Name}),params:{id:e.InstanceId},subtitle:`${e.InstanceType}`,title:e.InstanceId,to:`/ec2/describe-instances/$id`},e.InstanceId):null}function m(e,t){let n=d[e.State?.Name??``]??6,r=d[t.State?.Name??``]??6;return n===r?(e.InstanceId??``).localeCompare(t.InstanceId??``):n-r}function h(e){return e.Instances??[]}export{f as component}; \ No newline at end of file +import{t as e}from"./useSuspenseQuery.js";import{Co as t,Oo as n,U as r,xo as i,za as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./state-badge.js";import{t as c}from"./list-card.js";var l=i(),u=n(),d={running:0,pending:1,stopping:2,"shutting-down":3,stopped:4,terminated:5};function f(){let n=(0,l.c)(3),{data:i}=e(r),s;if(n[0]!==i.Reservations){let e=(i.Reservations?.flatMap(h)??[]).toSorted(m),r;n[2]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,u.jsx)(o,{actions:(0,u.jsx)(t,{to:`/ec2/run-instances`,children:(0,u.jsx)(a,{children:`Run Instances`})}),title:`Instances`}),n[2]=r):r=n[2],s=(0,u.jsxs)(u.Fragment,{children:[r,e.length>0?(0,u.jsx)(`div`,{className:`space-y-4`,children:e.map(p)}):(0,u.jsx)(`p`,{className:`text-muted-foreground`,children:`No instances found.`})]}),n[0]=i.Reservations,n[1]=s}else s=n[1];return s}function p(e){return e.InstanceId?(0,u.jsx)(c,{badge:(0,u.jsx)(s,{state:e.State?.Name}),params:{id:e.InstanceId},subtitle:`${e.InstanceType}`,title:e.InstanceId,to:`/ec2/describe-instances/$id`},e.InstanceId):null}function m(e,t){let n=d[e.State?.Name??``]??6,r=d[t.State?.Name??``]??6;return n===r?(e.InstanceId??``).localeCompare(t.InstanceId??``):n-r}function h(e){return e.Instances??[]}export{f as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/describe-key-pairs.js b/spinifex/services/spinifexui/frontend/dist/assets/describe-key-pairs.js index 7605d0370..02f84c969 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/describe-key-pairs.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/describe-key-pairs.js @@ -1 +1 @@ -import{t as e}from"./useSuspenseQuery.js";import{Ta as t,W as n,lo as r,mo as i,so as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./list-card.js";var c=a(),l=i();function u(){let i=(0,c.c)(4),{data:a}=e(n),s;if(i[0]!==a.KeyPairs){let e=(a.KeyPairs??[]).toSorted(f),n;i[2]===Symbol.for(`react.memo_cache_sentinel`)?(n=(0,l.jsx)(r,{to:`/ec2/import-key-pair`,children:(0,l.jsx)(t,{variant:`outline`,children:`Import Key Pair`})}),i[2]=n):n=i[2];let c;i[3]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,l.jsx)(o,{actions:(0,l.jsxs)(`div`,{className:`flex gap-2`,children:[n,(0,l.jsx)(r,{to:`/ec2/create-key-pair`,children:(0,l.jsx)(t,{children:`Create Key Pair`})})]}),title:`Key Pairs`}),i[3]=c):c=i[3],s=(0,l.jsxs)(l.Fragment,{children:[c,e.length>0?(0,l.jsx)(`div`,{className:`space-y-4`,children:e.map(d)}):(0,l.jsx)(`p`,{className:`text-muted-foreground`,children:`No key pairs found.`})]}),i[0]=a.KeyPairs,i[1]=s}else s=i[1];return s}function d(e){return e.KeyPairId?(0,l.jsx)(s,{params:{id:e.KeyPairId},subtitle:e.KeyPairId??``,title:e.KeyName??``,to:`/ec2/describe-key-pairs/$id`},e.KeyPairId):null}function f(e,t){let n=e.KeyName?.toLowerCase()??``,r=t.KeyName?.toLowerCase()??``;return n.localeCompare(r)}export{u as component}; \ No newline at end of file +import{t as e}from"./useSuspenseQuery.js";import{Co as t,G as n,Oo as r,xo as i,za as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./list-card.js";var c=i(),l=r();function u(){let r=(0,c.c)(4),{data:i}=e(n),s;if(r[0]!==i.KeyPairs){let e=(i.KeyPairs??[]).toSorted(f),n;r[2]===Symbol.for(`react.memo_cache_sentinel`)?(n=(0,l.jsx)(t,{to:`/ec2/import-key-pair`,children:(0,l.jsx)(a,{variant:`outline`,children:`Import Key Pair`})}),r[2]=n):n=r[2];let c;r[3]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,l.jsx)(o,{actions:(0,l.jsxs)(`div`,{className:`flex gap-2`,children:[n,(0,l.jsx)(t,{to:`/ec2/create-key-pair`,children:(0,l.jsx)(a,{children:`Create Key Pair`})})]}),title:`Key Pairs`}),r[3]=c):c=r[3],s=(0,l.jsxs)(l.Fragment,{children:[c,e.length>0?(0,l.jsx)(`div`,{className:`space-y-4`,children:e.map(d)}):(0,l.jsx)(`p`,{className:`text-muted-foreground`,children:`No key pairs found.`})]}),r[0]=i.KeyPairs,r[1]=s}else s=r[1];return s}function d(e){return e.KeyPairId?(0,l.jsx)(s,{params:{id:e.KeyPairId},subtitle:e.KeyPairId??``,title:e.KeyName??``,to:`/ec2/describe-key-pairs/$id`},e.KeyPairId):null}function f(e,t){let n=e.KeyName?.toLowerCase()??``,r=t.KeyName?.toLowerCase()??``;return n.localeCompare(r)}export{u as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/describe-load-balancers.js b/spinifex/services/spinifexui/frontend/dist/assets/describe-load-balancers.js index c80879534..0d3fabe57 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/describe-load-balancers.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/describe-load-balancers.js @@ -1 +1 @@ -import{t as e}from"./useSuspenseQuery.js";import{O as t,Ta as n,ja as r,lo as i,mo as a,so as o,uo as s}from"./index.js";import{t as c}from"./page-heading.js";import{t as l}from"./state-badge.js";var u=o(),d=a();function f(){let a=(0,u.c)(10),o=s(),{data:f}=e(t),m;a[0]===f.LoadBalancers?m=a[1]:(m=f.LoadBalancers??[],a[0]=f.LoadBalancers,a[1]=m);let h=m,g;a[2]===o?g=a[3]:(g=(0,d.jsx)(c,{actions:(0,d.jsx)(n,{onClick:async()=>await o({to:`/ec2/create-load-balancer`}),children:`Create Load Balancer`}),title:`Load Balancers`}),a[2]=o,a[3]=g);let _;a[4]!==h||a[5]!==o?(_=h.length>0?(0,d.jsx)(`div`,{className:`overflow-x-auto rounded-lg border bg-card`,children:(0,d.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,d.jsx)(`thead`,{children:(0,d.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Name`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`DNS Name`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`State`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Type`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Scheme`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`VPC`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Created`})]})}),(0,d.jsx)(`tbody`,{children:h.map(e=>{if(!e.LoadBalancerArn)return null;let t=e.LoadBalancerArn;return(0,d.jsxs)(`tr`,{className:`cursor-pointer border-b transition-colors last:border-0 hover:bg-accent`,onClick:async()=>await o({to:`/ec2/describe-load-balancers/$id`,params:{id:encodeURIComponent(t)}}),children:[(0,d.jsx)(`td`,{className:`px-4 py-2 font-medium`,children:(0,d.jsx)(i,{className:`text-primary hover:underline`,onClick:p,params:{id:encodeURIComponent(t)},to:`/ec2/describe-load-balancers/$id`,children:e.LoadBalancerName??t})}),(0,d.jsx)(`td`,{className:`px-4 py-2 font-mono text-xs`,children:e.DNSName??``}),(0,d.jsx)(`td`,{className:`px-4 py-2`,children:(0,d.jsx)(l,{state:e.State?.Code})}),(0,d.jsx)(`td`,{className:`px-4 py-2`,children:e.Type??``}),(0,d.jsx)(`td`,{className:`px-4 py-2`,children:e.Scheme??``}),(0,d.jsx)(`td`,{className:`px-4 py-2 font-mono text-xs`,children:e.VpcId??``}),(0,d.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:r(e.CreatedTime)})]},t)})})]})}):(0,d.jsx)(`p`,{className:`text-muted-foreground`,children:`No load balancers found.`}),a[4]=h,a[5]=o,a[6]=_):_=a[6];let v;return a[7]!==g||a[8]!==_?(v=(0,d.jsxs)(d.Fragment,{children:[g,_]}),a[7]=g,a[8]=_,a[9]=v):v=a[9],v}function p(e){return e.stopPropagation()}var m=f;export{m as component}; \ No newline at end of file +import{t as e}from"./useSuspenseQuery.js";import{Co as t,Ga as n,O as r,Oo as i,wo as a,xo as o,za as s}from"./index.js";import{t as c}from"./page-heading.js";import{t as l}from"./state-badge.js";var u=o(),d=i();function f(){let i=(0,u.c)(10),o=a(),{data:f}=e(r),m;i[0]===f.LoadBalancers?m=i[1]:(m=f.LoadBalancers??[],i[0]=f.LoadBalancers,i[1]=m);let h=m,g;i[2]===o?g=i[3]:(g=(0,d.jsx)(c,{actions:(0,d.jsx)(s,{onClick:async()=>await o({to:`/ec2/create-load-balancer`}),children:`Create Load Balancer`}),title:`Load Balancers`}),i[2]=o,i[3]=g);let _;i[4]!==h||i[5]!==o?(_=h.length>0?(0,d.jsx)(`div`,{className:`overflow-x-auto rounded-lg border bg-card`,children:(0,d.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,d.jsx)(`thead`,{children:(0,d.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Name`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`DNS Name`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`State`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Type`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Scheme`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`VPC`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Created`})]})}),(0,d.jsx)(`tbody`,{children:h.map(e=>{if(!e.LoadBalancerArn)return null;let r=e.LoadBalancerArn;return(0,d.jsxs)(`tr`,{className:`cursor-pointer border-b transition-colors last:border-0 hover:bg-accent`,onClick:async()=>await o({to:`/ec2/describe-load-balancers/$id`,params:{id:encodeURIComponent(r)}}),children:[(0,d.jsx)(`td`,{className:`px-4 py-2 font-medium`,children:(0,d.jsx)(t,{className:`text-primary hover:underline`,onClick:p,params:{id:encodeURIComponent(r)},to:`/ec2/describe-load-balancers/$id`,children:e.LoadBalancerName??r})}),(0,d.jsx)(`td`,{className:`px-4 py-2 font-mono text-xs`,children:e.DNSName??``}),(0,d.jsx)(`td`,{className:`px-4 py-2`,children:(0,d.jsx)(l,{state:e.State?.Code})}),(0,d.jsx)(`td`,{className:`px-4 py-2`,children:e.Type??``}),(0,d.jsx)(`td`,{className:`px-4 py-2`,children:e.Scheme??``}),(0,d.jsx)(`td`,{className:`px-4 py-2 font-mono text-xs`,children:e.VpcId??``}),(0,d.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:n(e.CreatedTime)})]},r)})})]})}):(0,d.jsx)(`p`,{className:`text-muted-foreground`,children:`No load balancers found.`}),i[4]=h,i[5]=o,i[6]=_):_=i[6];let v;return i[7]!==g||i[8]!==_?(v=(0,d.jsxs)(d.Fragment,{children:[g,_]}),i[7]=g,i[8]=_,i[9]=v):v=i[9],v}function p(e){return e.stopPropagation()}var m=f;export{m as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/describe-placement-groups.js b/spinifex/services/spinifexui/frontend/dist/assets/describe-placement-groups.js index 670f23737..cbb657e27 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/describe-placement-groups.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/describe-placement-groups.js @@ -1 +1 @@ -import{t as e}from"./useSuspenseQuery.js";import{K as t,Ta as n,lo as r,mo as i,so as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./state-badge.js";import{t as c}from"./list-card.js";var l=a(),u=i();function d(){let i=(0,l.c)(5),{data:a}=e(t),s;i[0]===a.PlacementGroups?s=i[1]:(s=a.PlacementGroups??[],i[0]=a.PlacementGroups,i[1]=s);let c=s,d;i[2]===Symbol.for(`react.memo_cache_sentinel`)?(d=(0,u.jsx)(o,{actions:(0,u.jsx)(r,{to:`/ec2/create-placement-group`,children:(0,u.jsx)(n,{children:`Create Placement Group`})}),title:`Placement Groups`}),i[2]=d):d=i[2];let p;return i[3]===c?p=i[4]:(p=(0,u.jsxs)(u.Fragment,{children:[d,c.length>0?(0,u.jsx)(`div`,{className:`space-y-4`,children:c.map(f)}):(0,u.jsx)(`p`,{className:`text-muted-foreground`,children:`No placement groups found.`})]}),i[3]=c,i[4]=p),p}function f(e){return e.GroupId?(0,u.jsx)(c,{badge:(0,u.jsx)(s,{state:e.State}),params:{id:e.GroupId},subtitle:`${e.Strategy} \u2022 ${e.GroupId}`,title:e.GroupName??e.GroupId,to:`/ec2/describe-placement-groups/$id`},e.GroupId):null}export{d as component}; \ No newline at end of file +import{t as e}from"./useSuspenseQuery.js";import{Co as t,Oo as n,q as r,xo as i,za as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./state-badge.js";import{t as c}from"./list-card.js";var l=i(),u=n();function d(){let n=(0,l.c)(5),{data:i}=e(r),s;n[0]===i.PlacementGroups?s=n[1]:(s=i.PlacementGroups??[],n[0]=i.PlacementGroups,n[1]=s);let c=s,d;n[2]===Symbol.for(`react.memo_cache_sentinel`)?(d=(0,u.jsx)(o,{actions:(0,u.jsx)(t,{to:`/ec2/create-placement-group`,children:(0,u.jsx)(a,{children:`Create Placement Group`})}),title:`Placement Groups`}),n[2]=d):d=n[2];let p;return n[3]===c?p=n[4]:(p=(0,u.jsxs)(u.Fragment,{children:[d,c.length>0?(0,u.jsx)(`div`,{className:`space-y-4`,children:c.map(f)}):(0,u.jsx)(`p`,{className:`text-muted-foreground`,children:`No placement groups found.`})]}),n[3]=c,n[4]=p),p}function f(e){return e.GroupId?(0,u.jsx)(c,{badge:(0,u.jsx)(s,{state:e.State}),params:{id:e.GroupId},subtitle:`${e.Strategy} \u2022 ${e.GroupId}`,title:e.GroupName??e.GroupId,to:`/ec2/describe-placement-groups/$id`},e.GroupId):null}export{d as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/describe-security-groups.js b/spinifex/services/spinifexui/frontend/dist/assets/describe-security-groups.js index c9fcde957..1321879c7 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/describe-security-groups.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/describe-security-groups.js @@ -1 +1 @@ -import{t as e}from"./useSuspenseQuery.js";import{Ta as t,Y as n,lo as r,mo as i,so as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./list-card.js";var c=a(),l=i();function u(){let i=(0,c.c)(5),{data:a}=e(n),s;i[0]===a.SecurityGroups?s=i[1]:(s=a.SecurityGroups??[],i[0]=a.SecurityGroups,i[1]=s);let u=s,f;i[2]===Symbol.for(`react.memo_cache_sentinel`)?(f=(0,l.jsx)(o,{actions:(0,l.jsx)(r,{to:`/ec2/create-security-group`,children:(0,l.jsx)(t,{children:`Create Security Group`})}),title:`Security Groups`}),i[2]=f):f=i[2];let p;return i[3]===u?p=i[4]:(p=(0,l.jsxs)(l.Fragment,{children:[f,u.length>0?(0,l.jsx)(`div`,{className:`space-y-4`,children:u.map(d)}):(0,l.jsx)(`p`,{className:`text-muted-foreground`,children:`No security groups found.`})]}),i[3]=u,i[4]=p),p}function d(e){return e.GroupId?(0,l.jsx)(s,{params:{id:e.GroupId},subtitle:e.VpcId??``,title:e.GroupName?`${e.GroupId} (${e.GroupName})`:e.GroupId,to:`/ec2/describe-security-groups/$id`},e.GroupId):null}export{u as component}; \ No newline at end of file +import{t as e}from"./useSuspenseQuery.js";import{Co as t,Oo as n,X as r,xo as i,za as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./list-card.js";var c=i(),l=n();function u(){let n=(0,c.c)(5),{data:i}=e(r),s;n[0]===i.SecurityGroups?s=n[1]:(s=i.SecurityGroups??[],n[0]=i.SecurityGroups,n[1]=s);let u=s,f;n[2]===Symbol.for(`react.memo_cache_sentinel`)?(f=(0,l.jsx)(o,{actions:(0,l.jsx)(t,{to:`/ec2/create-security-group`,children:(0,l.jsx)(a,{children:`Create Security Group`})}),title:`Security Groups`}),n[2]=f):f=n[2];let p;return n[3]===u?p=n[4]:(p=(0,l.jsxs)(l.Fragment,{children:[f,u.length>0?(0,l.jsx)(`div`,{className:`space-y-4`,children:u.map(d)}):(0,l.jsx)(`p`,{className:`text-muted-foreground`,children:`No security groups found.`})]}),n[3]=u,n[4]=p),p}function d(e){return e.GroupId?(0,l.jsx)(s,{params:{id:e.GroupId},subtitle:e.VpcId??``,title:e.GroupName?`${e.GroupId} (${e.GroupName})`:e.GroupId,to:`/ec2/describe-security-groups/$id`},e.GroupId):null}export{u as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/describe-snapshots.js b/spinifex/services/spinifexui/frontend/dist/assets/describe-snapshots.js index 17e4d38ce..966fec749 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/describe-snapshots.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/describe-snapshots.js @@ -1 +1 @@ -import{t as e}from"./useSuspenseQuery.js";import{Ta as t,Z as n,lo as r,mo as i,so as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./state-badge.js";import{t as c}from"./list-card.js";var l=a(),u=i();function d(){let i=(0,l.c)(5),{data:a}=e(n),s;i[0]===a.Snapshots?s=i[1]:(s=a.Snapshots??[],i[0]=a.Snapshots,i[1]=s);let c=s,d;i[2]===Symbol.for(`react.memo_cache_sentinel`)?(d=(0,u.jsx)(o,{actions:(0,u.jsx)(r,{to:`/ec2/create-snapshot`,children:(0,u.jsx)(t,{children:`Create Snapshot`})}),title:`Snapshots`}),i[2]=d):d=i[2];let p;return i[3]===c?p=i[4]:(p=(0,u.jsxs)(u.Fragment,{children:[d,c.length>0?(0,u.jsx)(`div`,{className:`space-y-4`,children:c.map(f)}):(0,u.jsx)(`p`,{className:`text-muted-foreground`,children:`No snapshots found.`})]}),i[3]=c,i[4]=p),p}function f(e){return e.SnapshotId?(0,u.jsx)(c,{badge:(0,u.jsx)(s,{state:e.State}),params:{id:e.SnapshotId},subtitle:`${e.VolumeSize} GiB \u2022 ${e.VolumeId}`,title:e.SnapshotId,to:`/ec2/describe-snapshots/$id`},e.SnapshotId):null}export{d as component}; \ No newline at end of file +import{t as e}from"./useSuspenseQuery.js";import{Co as t,Oo as n,Q as r,xo as i,za as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./state-badge.js";import{t as c}from"./list-card.js";var l=i(),u=n();function d(){let n=(0,l.c)(5),{data:i}=e(r),s;n[0]===i.Snapshots?s=n[1]:(s=i.Snapshots??[],n[0]=i.Snapshots,n[1]=s);let c=s,d;n[2]===Symbol.for(`react.memo_cache_sentinel`)?(d=(0,u.jsx)(o,{actions:(0,u.jsx)(t,{to:`/ec2/create-snapshot`,children:(0,u.jsx)(a,{children:`Create Snapshot`})}),title:`Snapshots`}),n[2]=d):d=n[2];let p;return n[3]===c?p=n[4]:(p=(0,u.jsxs)(u.Fragment,{children:[d,c.length>0?(0,u.jsx)(`div`,{className:`space-y-4`,children:c.map(f)}):(0,u.jsx)(`p`,{className:`text-muted-foreground`,children:`No snapshots found.`})]}),n[3]=c,n[4]=p),p}function f(e){return e.SnapshotId?(0,u.jsx)(c,{badge:(0,u.jsx)(s,{state:e.State}),params:{id:e.SnapshotId},subtitle:`${e.VolumeSize} GiB \u2022 ${e.VolumeId}`,title:e.SnapshotId,to:`/ec2/describe-snapshots/$id`},e.SnapshotId):null}export{d as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/describe-subnets.js b/spinifex/services/spinifexui/frontend/dist/assets/describe-subnets.js index b35a297d3..88382f431 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/describe-subnets.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/describe-subnets.js @@ -1 +1 @@ -import{t as e}from"./useSuspenseQuery.js";import{$ as t,Pa as n,Ta as r,lo as i,mo as a,so as o}from"./index.js";import{t as s}from"./page-heading.js";import{t as c}from"./state-badge.js";import{t as l}from"./list-card.js";var u=o(),d=a();function f(){let n=(0,u.c)(5),{data:a}=e(t),o;n[0]===a.Subnets?o=n[1]:(o=a.Subnets??[],n[0]=a.Subnets,n[1]=o);let c=o,l;n[2]===Symbol.for(`react.memo_cache_sentinel`)?(l=(0,d.jsx)(s,{actions:(0,d.jsx)(i,{to:`/ec2/create-subnet`,children:(0,d.jsx)(r,{children:`Create Subnet`})}),title:`Subnets`}),n[2]=l):l=n[2];let f;return n[3]===c?f=n[4]:(f=(0,d.jsxs)(d.Fragment,{children:[l,c.length>0?(0,d.jsx)(`div`,{className:`space-y-4`,children:c.map(p)}):(0,d.jsx)(`p`,{className:`text-muted-foreground`,children:`No subnets found.`})]}),n[3]=c,n[4]=f),f}function p(e){if(!e.SubnetId)return null;let t=n(e.Tags);return(0,d.jsx)(l,{badge:(0,d.jsx)(c,{state:e.State}),params:{id:e.SubnetId},subtitle:`${e.CidrBlock??``} \u2022 ${e.AvailabilityZone??``}`,title:t?`${e.SubnetId} (${t})`:e.SubnetId,to:`/ec2/describe-subnets/$id`},e.SubnetId)}export{f as component}; \ No newline at end of file +import{t as e}from"./useSuspenseQuery.js";import{Co as t,Ja as n,Oo as r,et as i,xo as a,za as o}from"./index.js";import{t as s}from"./page-heading.js";import{t as c}from"./state-badge.js";import{t as l}from"./list-card.js";var u=a(),d=r();function f(){let n=(0,u.c)(5),{data:r}=e(i),a;n[0]===r.Subnets?a=n[1]:(a=r.Subnets??[],n[0]=r.Subnets,n[1]=a);let c=a,l;n[2]===Symbol.for(`react.memo_cache_sentinel`)?(l=(0,d.jsx)(s,{actions:(0,d.jsx)(t,{to:`/ec2/create-subnet`,children:(0,d.jsx)(o,{children:`Create Subnet`})}),title:`Subnets`}),n[2]=l):l=n[2];let f;return n[3]===c?f=n[4]:(f=(0,d.jsxs)(d.Fragment,{children:[l,c.length>0?(0,d.jsx)(`div`,{className:`space-y-4`,children:c.map(p)}):(0,d.jsx)(`p`,{className:`text-muted-foreground`,children:`No subnets found.`})]}),n[3]=c,n[4]=f),f}function p(e){if(!e.SubnetId)return null;let t=n(e.Tags);return(0,d.jsx)(l,{badge:(0,d.jsx)(c,{state:e.State}),params:{id:e.SubnetId},subtitle:`${e.CidrBlock??``} \u2022 ${e.AvailabilityZone??``}`,title:t?`${e.SubnetId} (${t})`:e.SubnetId,to:`/ec2/describe-subnets/$id`},e.SubnetId)}export{f as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/describe-target-groups.js b/spinifex/services/spinifexui/frontend/dist/assets/describe-target-groups.js index acd62c33e..8c7378402 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/describe-target-groups.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/describe-target-groups.js @@ -1 +1 @@ -import{t as e}from"./useQuery.js";import{t}from"./useSuspenseQuery.js";import{M as n,N as r,Ta as i,lo as a,mo as o,so as s,uo as c}from"./index.js";import{t as l}from"./page-heading.js";var u=s(),d=o();function f(){let e=(0,u.c)(6),r=c(),{data:o}=t(n),s;e[0]===o.TargetGroups?s=e[1]:(s=o.TargetGroups??[],e[0]=o.TargetGroups,e[1]=s);let f=s,h;e[2]===Symbol.for(`react.memo_cache_sentinel`)?(h=(0,d.jsx)(l,{actions:(0,d.jsx)(a,{to:`/ec2/create-target-group`,children:(0,d.jsx)(i,{children:`Create Target Group`})}),title:`Target Groups`}),e[2]=h):h=e[2];let g;return e[3]!==r||e[4]!==f?(g=(0,d.jsxs)(d.Fragment,{children:[h,f.length>0?(0,d.jsx)(`div`,{className:`overflow-x-auto rounded-lg border bg-card`,children:(0,d.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,d.jsx)(`thead`,{children:(0,d.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Name`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Protocol`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Port`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`VPC`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Target Type`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Targets`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Health`})]})}),(0,d.jsx)(`tbody`,{children:f.map(e=>{if(!e.TargetGroupArn)return null;let t=e.TargetGroupArn;return(0,d.jsxs)(`tr`,{className:`cursor-pointer border-b transition-colors last:border-0 hover:bg-accent`,onClick:async()=>await r({to:`/ec2/describe-target-groups/$id`,params:{id:encodeURIComponent(t)}}),children:[(0,d.jsx)(`td`,{className:`px-4 py-2 font-medium`,children:(0,d.jsx)(a,{className:`text-primary hover:underline`,onClick:p,params:{id:encodeURIComponent(t)},to:`/ec2/describe-target-groups/$id`,children:e.TargetGroupName??t})}),(0,d.jsx)(`td`,{className:`px-4 py-2`,children:e.Protocol??``}),(0,d.jsx)(`td`,{className:`px-4 py-2`,children:e.Port??``}),(0,d.jsx)(`td`,{className:`px-4 py-2 font-mono text-xs`,children:e.VpcId??``}),(0,d.jsx)(`td`,{className:`px-4 py-2`,children:e.TargetType??``}),(0,d.jsx)(m,{arn:t})]},t)})})]})}):(0,d.jsx)(`p`,{className:`text-muted-foreground`,children:`No target groups found.`})]}),e[3]=r,e[4]=f,e[5]=g):g=e[5],g}function p(e){return e.stopPropagation()}function m(t){let n=(0,u.c)(13),{arn:i}=t,a;n[0]===i?a=n[1]:(a=r(i),n[0]=i,n[1]=a);let{data:o,isLoading:s}=e(a);if(s){let e;return n[2]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(`td`,{className:`px-4 py-2 text-muted-foreground`,children:`…`}),(0,d.jsx)(`td`,{className:`px-4 py-2 text-muted-foreground`,children:`…`})]}),n[2]=e):e=n[2],e}let c,l;if(n[3]!==o?.TargetHealthDescriptions){c=o?.TargetHealthDescriptions??[];let e={};for(let t of c){let n=t.TargetHealth?.State??`unknown`;e[n]=(e[n]??0)+1}l=Object.entries(e).map(h).join(`, `)||`—`,n[3]=o?.TargetHealthDescriptions,n[4]=c,n[5]=l}else c=n[4],l=n[5];let f=l,p;n[6]===c.length?p=n[7]:(p=(0,d.jsx)(`td`,{className:`px-4 py-2`,children:c.length}),n[6]=c.length,n[7]=p);let m;n[8]===f?m=n[9]:(m=(0,d.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:f}),n[8]=f,n[9]=m);let g;return n[10]!==p||n[11]!==m?(g=(0,d.jsxs)(d.Fragment,{children:[p,m]}),n[10]=p,n[11]=m,n[12]=g):g=n[12],g}function h(e){let[t,n]=e;return`${n} ${t}`}var g=f;export{g as component}; \ No newline at end of file +import{t as e}from"./useQuery.js";import{t}from"./useSuspenseQuery.js";import{Co as n,N as r,Oo as i,P as a,wo as o,xo as s,za as c}from"./index.js";import{t as l}from"./page-heading.js";var u=s(),d=i();function f(){let e=(0,u.c)(6),i=o(),{data:a}=t(r),s;e[0]===a.TargetGroups?s=e[1]:(s=a.TargetGroups??[],e[0]=a.TargetGroups,e[1]=s);let f=s,h;e[2]===Symbol.for(`react.memo_cache_sentinel`)?(h=(0,d.jsx)(l,{actions:(0,d.jsx)(n,{to:`/ec2/create-target-group`,children:(0,d.jsx)(c,{children:`Create Target Group`})}),title:`Target Groups`}),e[2]=h):h=e[2];let g;return e[3]!==i||e[4]!==f?(g=(0,d.jsxs)(d.Fragment,{children:[h,f.length>0?(0,d.jsx)(`div`,{className:`overflow-x-auto rounded-lg border bg-card`,children:(0,d.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,d.jsx)(`thead`,{children:(0,d.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Name`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Protocol`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Port`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`VPC`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Target Type`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Targets`}),(0,d.jsx)(`th`,{className:`px-4 py-2 font-medium`,children:`Health`})]})}),(0,d.jsx)(`tbody`,{children:f.map(e=>{if(!e.TargetGroupArn)return null;let t=e.TargetGroupArn;return(0,d.jsxs)(`tr`,{className:`cursor-pointer border-b transition-colors last:border-0 hover:bg-accent`,onClick:async()=>await i({to:`/ec2/describe-target-groups/$id`,params:{id:encodeURIComponent(t)}}),children:[(0,d.jsx)(`td`,{className:`px-4 py-2 font-medium`,children:(0,d.jsx)(n,{className:`text-primary hover:underline`,onClick:p,params:{id:encodeURIComponent(t)},to:`/ec2/describe-target-groups/$id`,children:e.TargetGroupName??t})}),(0,d.jsx)(`td`,{className:`px-4 py-2`,children:e.Protocol??``}),(0,d.jsx)(`td`,{className:`px-4 py-2`,children:e.Port??``}),(0,d.jsx)(`td`,{className:`px-4 py-2 font-mono text-xs`,children:e.VpcId??``}),(0,d.jsx)(`td`,{className:`px-4 py-2`,children:e.TargetType??``}),(0,d.jsx)(m,{arn:t})]},t)})})]})}):(0,d.jsx)(`p`,{className:`text-muted-foreground`,children:`No target groups found.`})]}),e[3]=i,e[4]=f,e[5]=g):g=e[5],g}function p(e){return e.stopPropagation()}function m(t){let n=(0,u.c)(13),{arn:r}=t,i;n[0]===r?i=n[1]:(i=a(r),n[0]=r,n[1]=i);let{data:o,isLoading:s}=e(i);if(s){let e;return n[2]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(`td`,{className:`px-4 py-2 text-muted-foreground`,children:`…`}),(0,d.jsx)(`td`,{className:`px-4 py-2 text-muted-foreground`,children:`…`})]}),n[2]=e):e=n[2],e}let c,l;if(n[3]!==o?.TargetHealthDescriptions){c=o?.TargetHealthDescriptions??[];let e={};for(let t of c){let n=t.TargetHealth?.State??`unknown`;e[n]=(e[n]??0)+1}l=Object.entries(e).map(h).join(`, `)||`—`,n[3]=o?.TargetHealthDescriptions,n[4]=c,n[5]=l}else c=n[4],l=n[5];let f=l,p;n[6]===c.length?p=n[7]:(p=(0,d.jsx)(`td`,{className:`px-4 py-2`,children:c.length}),n[6]=c.length,n[7]=p);let m;n[8]===f?m=n[9]:(m=(0,d.jsx)(`td`,{className:`px-4 py-2 text-xs`,children:f}),n[8]=f,n[9]=m);let g;return n[10]!==p||n[11]!==m?(g=(0,d.jsxs)(d.Fragment,{children:[p,m]}),n[10]=p,n[11]=m,n[12]=g):g=n[12],g}function h(e){let[t,n]=e;return`${n} ${t}`}var g=f;export{g as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/describe-volumes.js b/spinifex/services/spinifexui/frontend/dist/assets/describe-volumes.js index 6a9e12449..271839d45 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/describe-volumes.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/describe-volumes.js @@ -1 +1 @@ -import{t as e}from"./useSuspenseQuery.js";import{Ta as t,lo as n,mo as r,so as i,tt as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./state-badge.js";import{t as c}from"./list-card.js";var l=i(),u=r();function d(){let r=(0,l.c)(5),{data:i}=e(a),s;r[0]===i.Volumes?s=r[1]:(s=i.Volumes??[],r[0]=i.Volumes,r[1]=s);let c=s,d;r[2]===Symbol.for(`react.memo_cache_sentinel`)?(d=(0,u.jsx)(o,{actions:(0,u.jsx)(n,{to:`/ec2/create-volume`,children:(0,u.jsx)(t,{children:`Create Volume`})}),title:`Volumes`}),r[2]=d):d=r[2];let p;return r[3]===c?p=r[4]:(p=(0,u.jsxs)(u.Fragment,{children:[d,c.length>0?(0,u.jsx)(`div`,{className:`space-y-4`,children:c.map(f)}):(0,u.jsx)(`p`,{className:`text-muted-foreground`,children:`No volumes found.`})]}),r[3]=c,r[4]=p),p}function f(e){return e.VolumeId?(0,u.jsx)(c,{badge:(0,u.jsx)(s,{state:e.State}),params:{id:e.VolumeId},subtitle:`${e.Size} GiB`,title:e.VolumeId,to:`/ec2/describe-volumes/$id`},e.VolumeId):null}export{d as component}; \ No newline at end of file +import{t as e}from"./useSuspenseQuery.js";import{Co as t,Oo as n,nt as r,xo as i,za as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./state-badge.js";import{t as c}from"./list-card.js";var l=i(),u=n();function d(){let n=(0,l.c)(5),{data:i}=e(r),s;n[0]===i.Volumes?s=n[1]:(s=i.Volumes??[],n[0]=i.Volumes,n[1]=s);let c=s,d;n[2]===Symbol.for(`react.memo_cache_sentinel`)?(d=(0,u.jsx)(o,{actions:(0,u.jsx)(t,{to:`/ec2/create-volume`,children:(0,u.jsx)(a,{children:`Create Volume`})}),title:`Volumes`}),n[2]=d):d=n[2];let p;return n[3]===c?p=n[4]:(p=(0,u.jsxs)(u.Fragment,{children:[d,c.length>0?(0,u.jsx)(`div`,{className:`space-y-4`,children:c.map(f)}):(0,u.jsx)(`p`,{className:`text-muted-foreground`,children:`No volumes found.`})]}),n[3]=c,n[4]=p),p}function f(e){return e.VolumeId?(0,u.jsx)(c,{badge:(0,u.jsx)(s,{state:e.State}),params:{id:e.VolumeId},subtitle:`${e.Size} GiB`,title:e.VolumeId,to:`/ec2/describe-volumes/$id`},e.VolumeId):null}export{d as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/describe-vpcs.js b/spinifex/services/spinifexui/frontend/dist/assets/describe-vpcs.js index f963fc82b..76553a344 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/describe-vpcs.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/describe-vpcs.js @@ -1 +1 @@ -import{t as e}from"./useSuspenseQuery.js";import{Pa as t,Ta as n,lo as r,mo as i,rt as a,so as o}from"./index.js";import{t as s}from"./page-heading.js";import{t as c}from"./state-badge.js";import{t as l}from"./list-card.js";var u=o(),d=i();function f(){let t=(0,u.c)(5),{data:i}=e(a),o;t[0]===i.Vpcs?o=t[1]:(o=i.Vpcs??[],t[0]=i.Vpcs,t[1]=o);let c=o,l;t[2]===Symbol.for(`react.memo_cache_sentinel`)?(l=(0,d.jsx)(s,{actions:(0,d.jsx)(r,{to:`/ec2/create-vpc`,children:(0,d.jsx)(n,{children:`Create VPC`})}),title:`VPCs`}),t[2]=l):l=t[2];let f;return t[3]===c?f=t[4]:(f=(0,d.jsxs)(d.Fragment,{children:[l,c.length>0?(0,d.jsx)(`div`,{className:`space-y-4`,children:c.map(p)}):(0,d.jsx)(`p`,{className:`text-muted-foreground`,children:`No VPCs found.`})]}),t[3]=c,t[4]=f),f}function p(e){if(!e.VpcId)return null;let n=t(e.Tags);return(0,d.jsx)(l,{badge:(0,d.jsx)(c,{state:e.State}),params:{id:e.VpcId},subtitle:e.CidrBlock??``,title:n?`${e.VpcId} (${n})`:e.VpcId,to:`/ec2/describe-vpcs/$id`},e.VpcId)}export{f as component}; \ No newline at end of file +import{t as e}from"./useSuspenseQuery.js";import{Co as t,Ja as n,Oo as r,it as i,xo as a,za as o}from"./index.js";import{t as s}from"./page-heading.js";import{t as c}from"./state-badge.js";import{t as l}from"./list-card.js";var u=a(),d=r();function f(){let n=(0,u.c)(5),{data:r}=e(i),a;n[0]===r.Vpcs?a=n[1]:(a=r.Vpcs??[],n[0]=r.Vpcs,n[1]=a);let c=a,l;n[2]===Symbol.for(`react.memo_cache_sentinel`)?(l=(0,d.jsx)(s,{actions:(0,d.jsx)(t,{to:`/ec2/create-vpc`,children:(0,d.jsx)(o,{children:`Create VPC`})}),title:`VPCs`}),n[2]=l):l=n[2];let f;return n[3]===c?f=n[4]:(f=(0,d.jsxs)(d.Fragment,{children:[l,c.length>0?(0,d.jsx)(`div`,{className:`space-y-4`,children:c.map(p)}):(0,d.jsx)(`p`,{className:`text-muted-foreground`,children:`No VPCs found.`})]}),n[3]=c,n[4]=f),f}function p(e){if(!e.VpcId)return null;let t=n(e.Tags);return(0,d.jsx)(l,{badge:(0,d.jsx)(c,{state:e.State}),params:{id:e.VpcId},subtitle:e.CidrBlock??``,title:t?`${e.VpcId} (${t})`:e.VpcId,to:`/ec2/describe-vpcs/$id`},e.VpcId)}export{f as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/detail-row.js b/spinifex/services/spinifexui/frontend/dist/assets/detail-row.js index f87915081..ec873927a 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/detail-row.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/detail-row.js @@ -1 +1 @@ -import{mo as e,so as t}from"./index.js";var n=t(),r=e();function i(e){let t=(0,n.c)(2),{children:i}=e,a;return t[0]===i?a=t[1]:(a=(0,r.jsx)(`div`,{className:`rounded-lg border bg-card`,children:i}),t[0]=i,t[1]=a),a}function a(e){let t=(0,n.c)(2),{children:i}=e,a;return t[0]===i?a=t[1]:(a=(0,r.jsx)(`div`,{className:`border-b p-4`,children:(0,r.jsx)(`h2`,{className:`font-semibold`,children:i})}),t[0]=i,t[1]=a),a}function o(e){let t=(0,n.c)(2),{children:i}=e,a;return t[0]===i?a=t[1]:(a=(0,r.jsx)(`div`,{className:`grid gap-4 p-4 sm:grid-cols-2`,children:i}),t[0]=i,t[1]=a),a}var s=Object.assign(i,{Header:a,Content:o});function c(e){let t=(0,n.c)(9),{label:i,value:a}=e,o;t[0]===i?o=t[1]:(o=(0,r.jsx)(`dt`,{className:`text-sm text-muted-foreground`,children:i}),t[0]=i,t[1]=o);let s;t[2]===a?s=t[3]:(s=a||(0,r.jsx)(`span`,{className:`text-muted-foreground`,children:`—`}),t[2]=a,t[3]=s);let c;t[4]===s?c=t[5]:(c=(0,r.jsx)(`dd`,{className:`mt-1 font-mono text-sm`,children:s}),t[4]=s,t[5]=c);let l;return t[6]!==o||t[7]!==c?(l=(0,r.jsxs)(`div`,{children:[o,c]}),t[6]=o,t[7]=c,t[8]=l):l=t[8],l}export{s as n,c as t}; \ No newline at end of file +import{Oo as e,xo as t}from"./index.js";var n=t(),r=e();function i(e){let t=(0,n.c)(2),{children:i}=e,a;return t[0]===i?a=t[1]:(a=(0,r.jsx)(`div`,{className:`rounded-lg border bg-card`,children:i}),t[0]=i,t[1]=a),a}function a(e){let t=(0,n.c)(2),{children:i}=e,a;return t[0]===i?a=t[1]:(a=(0,r.jsx)(`div`,{className:`border-b p-4`,children:(0,r.jsx)(`h2`,{className:`font-semibold`,children:i})}),t[0]=i,t[1]=a),a}function o(e){let t=(0,n.c)(2),{children:i}=e,a;return t[0]===i?a=t[1]:(a=(0,r.jsx)(`div`,{className:`grid gap-4 p-4 sm:grid-cols-2`,children:i}),t[0]=i,t[1]=a),a}var s=Object.assign(i,{Header:a,Content:o});function c(e){let t=(0,n.c)(9),{label:i,value:a}=e,o;t[0]===i?o=t[1]:(o=(0,r.jsx)(`dt`,{className:`text-sm text-muted-foreground`,children:i}),t[0]=i,t[1]=o);let s;t[2]===a?s=t[3]:(s=a||(0,r.jsx)(`span`,{className:`text-muted-foreground`,children:`—`}),t[2]=a,t[3]=s);let c;t[4]===s?c=t[5]:(c=(0,r.jsx)(`dd`,{className:`mt-1 font-mono text-sm`,children:s}),t[4]=s,t[5]=c);let l;return t[6]!==o||t[7]!==c?(l=(0,r.jsxs)(`div`,{children:[o,c]}),t[6]=o,t[7]=c,t[8]=l):l=t[8],l}export{s as n,c as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/download.js b/spinifex/services/spinifexui/frontend/dist/assets/download.js index 5d603e805..5766fc807 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/download.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/download.js @@ -1 +1 @@ -import{Xa as e}from"./index.js";var t=e(`download`,[[`path`,{d:`M12 15V3`,key:`m9g1x1`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}],[`path`,{d:`m7 10 5 5 5-5`,key:`brsn70`}]]);export{t}; \ No newline at end of file +import{uo as e}from"./index.js";var t=e(`download`,[[`path`,{d:`M12 15V3`,key:`m9g1x1`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}],[`path`,{d:`m7 10 5 5 5-5`,key:`brsn70`}]]);export{t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/ec2.js b/spinifex/services/spinifexui/frontend/dist/assets/ec2.js index 5b419d0ac..43d1114a8 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/ec2.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/ec2.js @@ -1 +1 @@ -import{n as e}from"./error-banner.js";import{$n as t,$t as n,An as r,Cn as i,Dn as a,En as o,Fn as s,Hn as c,In as l,Ln as u,Mn as d,Nn as f,On as p,Qt as ee,Rn as te,Sn as m,Tn as h,Vn as ne,W as g,Zt as re,_n as ie,an as ae,at as _,bn as oe,cn as se,dn as ce,en as le,fn as ue,gn as de,hn as v,in as y,jn as b,kn as x,ln as S,mn as C,nn as w,on as T,pn as E,po as D,qn as O,rn as k,sn as A,so as j,tn as M,un as N,vn as P,wn as F,xn as I,yn as L}from"./index.js";var R=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`AssociateRouteTable`,{}).n(`EC2Client`,`AssociateRouteTableCommand`).sc(re).build(){},z=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`AttachInternetGateway`,{}).n(`EC2Client`,`AttachInternetGatewayCommand`).sc(ee).build(){},B=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`AttachVolume`,{}).n(`EC2Client`,`AttachVolumeCommand`).sc(n).build(){},V=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`AuthorizeSecurityGroupEgress`,{}).n(`EC2Client`,`AuthorizeSecurityGroupEgressCommand`).sc(le).build(){},H=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`AuthorizeSecurityGroupIngress`,{}).n(`EC2Client`,`AuthorizeSecurityGroupIngressCommand`).sc(M).build(){};function fe(e){let{port:t,query:n}=e,{protocol:r,path:i,hostname:a}=e;r&&r.slice(-1)!==`:`&&(r+=`:`),t&&(a+=`:${t}`),i&&i.charAt(0)!==`/`&&(i=`/${i}`);let o=n?c(n):``;o&&o[0]!==`?`&&(o=`?${o}`);let s=``;(e.username!=null||e.password!=null)&&(s=`${e.username??``}:${e.password??``}@`);let l=``;return e.fragment&&(l=`#${e.fragment}`),`${r}//${s}${a}${i}${o}${l}`}var pe=`2016-11-15`;function me(e){return(n,r)=>async r=>{let{input:i}=r;if(!i.PresignedUrl){let n=await e.region(),a=await u(i,{getEndpointParameterInstructions(){return{UseFIPS:{type:`builtInParams`,name:`useFipsEndpoint`},Endpoint:{type:`builtInParams`,name:`endpoint`},Region:{type:`builtInParams`,name:`region`},UseDualStack:{type:`builtInParams`,name:`useDualstackEndpoint`}}}},{...e,region:i.SourceRegion}),o=typeof e.endpoint==`function`?await e.endpoint():te(a),s=new t({...o,protocol:`https`,headers:{host:o.hostname},query:{...Object.entries(i).reduce((e,[t,n])=>(e[t]=String(n??``),e),{}),Action:`CopySnapshot`,Version:pe,DestinationRegion:n}}),c=await new O({credentials:e.credentials,region:i.SourceRegion,service:`ec2`,sha256:e.sha256,uriEscapePath:e.signingEscapePath}).presign(s,{expiresIn:3600});if(r={...r,input:{...r.input,DestinationRegion:n,PresignedUrl:fe(c)}},t.isInstance(r.request)){let{request:e}=r;(e.body??``).includes(`DestinationRegion=`)||(e.body+=`&DestinationRegion=${n}`),(e.body??``).includes(`PresignedUrl=`)||(e.body+=`&PresignedUrl=${ne(r.input.PresignedUrl)}`)}}return n(r)}}var he={step:`serialize`,tags:[`CROSS_REGION_PRESIGNED_URL`],name:`crossRegionPresignedUrlMiddleware`,override:!0,relation:`after`,toMiddleware:`endpointV2Middleware`},ge=e=>({applyToStack:t=>{t.add(me(e),he)}}),_e=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions()),ge(n)]}).s(`AmazonEC2`,`CopySnapshot`,{}).n(`EC2Client`,`CopySnapshotCommand`).sc(w).build(){},ve=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateImage`,{}).n(`EC2Client`,`CreateImageCommand`).sc(k).build(){},ye=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateInternetGateway`,{}).n(`EC2Client`,`CreateInternetGatewayCommand`).sc(y).build(){},be=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateKeyPair`,{}).n(`EC2Client`,`CreateKeyPairCommand`).sc(ae).build(){},xe=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreatePlacementGroup`,{}).n(`EC2Client`,`CreatePlacementGroupCommand`).sc(T).build(){},Se=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateRoute`,{}).n(`EC2Client`,`CreateRouteCommand`).sc(A).build(){},U=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateRouteTable`,{}).n(`EC2Client`,`CreateRouteTableCommand`).sc(se).build(){},Ce=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateSecurityGroup`,{}).n(`EC2Client`,`CreateSecurityGroupCommand`).sc(S).build(){},we=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateSnapshot`,{}).n(`EC2Client`,`CreateSnapshotCommand`).sc(N).build(){},W=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateSubnet`,{}).n(`EC2Client`,`CreateSubnetCommand`).sc(ce).build(){},Te=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateVolume`,{}).n(`EC2Client`,`CreateVolumeCommand`).sc(ue).build(){},G=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateVpc`,{}).n(`EC2Client`,`CreateVpcCommand`).sc(E).build(){},Ee=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DeleteKeyPair`,{}).n(`EC2Client`,`DeleteKeyPairCommand`).sc(C).build(){},De=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DeletePlacementGroup`,{}).n(`EC2Client`,`DeletePlacementGroupCommand`).sc(v).build(){},Oe=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DeleteSecurityGroup`,{}).n(`EC2Client`,`DeleteSecurityGroupCommand`).sc(de).build(){},ke=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DeleteSnapshot`,{}).n(`EC2Client`,`DeleteSnapshotCommand`).sc(ie).build(){},Ae=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DeleteSubnet`,{}).n(`EC2Client`,`DeleteSubnetCommand`).sc(P).build(){},je=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DeleteVolume`,{}).n(`EC2Client`,`DeleteVolumeCommand`).sc(L).build(){},Me=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DeleteVpc`,{}).n(`EC2Client`,`DeleteVpcCommand`).sc(oe).build(){},Ne=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DetachVolume`,{}).n(`EC2Client`,`DetachVolumeCommand`).sc(I).build(){},Pe=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`GetConsoleOutput`,{}).n(`EC2Client`,`GetConsoleOutputCommand`).sc(m).build(){},Fe=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`ImportKeyPair`,{}).n(`EC2Client`,`ImportKeyPairCommand`).sc(i).build(){},Ie=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`ModifyInstanceAttribute`,{}).n(`EC2Client`,`ModifyInstanceAttributeCommand`).sc(F).build(){},Le=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`ModifyVolume`,{}).n(`EC2Client`,`ModifyVolumeCommand`).sc(h).build(){},Re=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`RebootInstances`,{}).n(`EC2Client`,`RebootInstancesCommand`).sc(o).build(){},ze=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`RevokeSecurityGroupEgress`,{}).n(`EC2Client`,`RevokeSecurityGroupEgressCommand`).sc(a).build(){},Be=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`RevokeSecurityGroupIngress`,{}).n(`EC2Client`,`RevokeSecurityGroupIngressCommand`).sc(p).build(){},Ve=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`RunInstances`,{}).n(`EC2Client`,`RunInstancesCommand`).sc(x).build(){},He=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`StartInstances`,{}).n(`EC2Client`,`StartInstancesCommand`).sc(r).build(){},Ue=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`StopInstances`,{}).n(`EC2Client`,`StopInstancesCommand`).sc(b).build(){},We=class extends s.classBuilder().ep(f).m(function(e,t,n,r){return[l(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`TerminateInstances`,{}).n(`EC2Client`,`TerminateInstancesCommand`).sc(d).build(){},K={capacity_block:`capacity-block`,capacity_manager_data_export:`capacity-manager-data-export`,capacity_reservation:`capacity-reservation`,capacity_reservation_fleet:`capacity-reservation-fleet`,carrier_gateway:`carrier-gateway`,client_vpn_endpoint:`client-vpn-endpoint`,coip_pool:`coip-pool`,customer_gateway:`customer-gateway`,declarative_policies_report:`declarative-policies-report`,dedicated_host:`dedicated-host`,dhcp_options:`dhcp-options`,egress_only_internet_gateway:`egress-only-internet-gateway`,elastic_gpu:`elastic-gpu`,elastic_ip:`elastic-ip`,export_image_task:`export-image-task`,export_instance_task:`export-instance-task`,fleet:`fleet`,fpga_image:`fpga-image`,host_reservation:`host-reservation`,image:`image`,image_usage_report:`image-usage-report`,import_image_task:`import-image-task`,import_snapshot_task:`import-snapshot-task`,instance:`instance`,instance_connect_endpoint:`instance-connect-endpoint`,instance_event_window:`instance-event-window`,internet_gateway:`internet-gateway`,ipam:`ipam`,ipam_external_resource_verification_token:`ipam-external-resource-verification-token`,ipam_policy:`ipam-policy`,ipam_pool:`ipam-pool`,ipam_prefix_list_resolver:`ipam-prefix-list-resolver`,ipam_prefix_list_resolver_target:`ipam-prefix-list-resolver-target`,ipam_resource_discovery:`ipam-resource-discovery`,ipam_resource_discovery_association:`ipam-resource-discovery-association`,ipam_scope:`ipam-scope`,ipv4pool_ec2:`ipv4pool-ec2`,ipv6pool_ec2:`ipv6pool-ec2`,key_pair:`key-pair`,launch_template:`launch-template`,local_gateway:`local-gateway`,local_gateway_route_table:`local-gateway-route-table`,local_gateway_route_table_virtual_interface_group_association:`local-gateway-route-table-virtual-interface-group-association`,local_gateway_route_table_vpc_association:`local-gateway-route-table-vpc-association`,local_gateway_virtual_interface:`local-gateway-virtual-interface`,local_gateway_virtual_interface_group:`local-gateway-virtual-interface-group`,mac_modification_task:`mac-modification-task`,natgateway:`natgateway`,network_acl:`network-acl`,network_insights_access_scope:`network-insights-access-scope`,network_insights_access_scope_analysis:`network-insights-access-scope-analysis`,network_insights_analysis:`network-insights-analysis`,network_insights_path:`network-insights-path`,network_interface:`network-interface`,outpost_lag:`outpost-lag`,placement_group:`placement-group`,prefix_list:`prefix-list`,replace_root_volume_task:`replace-root-volume-task`,reserved_instances:`reserved-instances`,route_server:`route-server`,route_server_endpoint:`route-server-endpoint`,route_server_peer:`route-server-peer`,route_table:`route-table`,secondary_interface:`secondary-interface`,secondary_network:`secondary-network`,secondary_subnet:`secondary-subnet`,security_group:`security-group`,security_group_rule:`security-group-rule`,service_link_virtual_interface:`service-link-virtual-interface`,snapshot:`snapshot`,spot_fleet_request:`spot-fleet-request`,spot_instances_request:`spot-instances-request`,subnet:`subnet`,subnet_cidr_reservation:`subnet-cidr-reservation`,traffic_mirror_filter:`traffic-mirror-filter`,traffic_mirror_filter_rule:`traffic-mirror-filter-rule`,traffic_mirror_session:`traffic-mirror-session`,traffic_mirror_target:`traffic-mirror-target`,transit_gateway:`transit-gateway`,transit_gateway_attachment:`transit-gateway-attachment`,transit_gateway_connect_peer:`transit-gateway-connect-peer`,transit_gateway_metering_policy:`transit-gateway-metering-policy`,transit_gateway_multicast_domain:`transit-gateway-multicast-domain`,transit_gateway_policy_table:`transit-gateway-policy-table`,transit_gateway_route_table:`transit-gateway-route-table`,transit_gateway_route_table_announcement:`transit-gateway-route-table-announcement`,verified_access_endpoint:`verified-access-endpoint`,verified_access_endpoint_target:`verified-access-endpoint-target`,verified_access_group:`verified-access-group`,verified_access_instance:`verified-access-instance`,verified_access_policy:`verified-access-policy`,verified_access_trust_provider:`verified-access-trust-provider`,volume:`volume`,vpc:`vpc`,vpc_block_public_access_exclusion:`vpc-block-public-access-exclusion`,vpc_encryption_control:`vpc-encryption-control`,vpc_endpoint:`vpc-endpoint`,vpc_endpoint_connection:`vpc-endpoint-connection`,vpc_endpoint_connection_device_type:`vpc-endpoint-connection-device-type`,vpc_endpoint_service:`vpc-endpoint-service`,vpc_endpoint_service_permission:`vpc-endpoint-service-permission`,vpc_flow_log:`vpc-flow-log`,vpc_peering_connection:`vpc-peering-connection`,vpn_concentrator:`vpn-concentrator`,vpn_connection:`vpn-connection`,vpn_connection_device_type:`vpn-connection-device-type`,vpn_gateway:`vpn-gateway`},q=j();function J(e){let t=e.split(`/`),n=t[0]??``,r=t[1]??`0`,i=Number.parseInt(r,10),a=n.split(`.`).map(e=>Number.parseInt(e,10)),o=a[0]??0,s=a[1]??0,c=a[2]??0,l=a[3]??0;return{network:((o<<24|s<<16|c<<8|l)>>>0&(i===0?0:4294967295<<32-i>>>0))>>>0,prefix:i}}function Y(e){return`${e>>>24&255}.${e>>>16&255}.${e>>>8&255}.${e&255}`}function X(e){return 2**(32-e)}function Ge(e){let t=e+4;return Math.min(t,28)}function Z(e,t,n){let{network:r,prefix:i}=J(e),a=Ge(i),o=X(a),s=X(i)/2,c=[];for(let e=0;e>>0;c.push({cidr:`${Y(t)}/${a}`,label:`Public Subnet ${e+1}`})}let l=[];for(let e=0;e>>0;l.push({cidr:`${Y(t)}/${a}`,label:`Private Subnet ${e+1}`})}return{publicSubnets:c,privateSubnets:l}}function Ke(e,t){let n=J(e),r=J(t),i=n.network+X(n.prefix)-1>>>0,a=r.network+X(r.prefix)-1>>>0;return n.network<=a&&r.network<=i}function qe(e,t){let n=J(e),r=J(t),i=n.network+X(n.prefix)-1>>>0,a=r.network+X(r.prefix)-1>>>0;return r.network>=n.network&&a<=i}function Je(e,t=16,n=28){let r=/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/(\d{1,2})$/.exec(e);if(!r||[Number.parseInt(r[1]??`0`,10),Number.parseInt(r[2]??`0`,10),Number.parseInt(r[3]??`0`,10),Number.parseInt(r[4]??`0`,10)].some(e=>e>255))return!1;let i=Number.parseInt(r[5]??`0`,10);return i>=t&&i<=n}var Ye=/\s+/;function Xe(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:Ze,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`instances`]})}},t[0]=n,t[1]=r),e(r)}async function Ze(e){let t=new He({InstanceIds:[e]});return await _().send(t)}function Qe(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:$e,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`instances`]})}},t[0]=n,t[1]=r),e(r)}async function $e(e){let t=new Ue({InstanceIds:[e]});return await _().send(t)}function et(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:tt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`instances`]})}},t[0]=n,t[1]=r),e(r)}async function tt(e){let t=new We({InstanceIds:[e]});return await _().send(t)}function nt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:rt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`instances`]})}},t[0]=n,t[1]=r),e(r)}async function rt(e){let t=new Re({InstanceIds:[e]});return await _().send(t)}function it(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:at,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`instances`]})}},t[0]=n,t[1]=r),e(r)}async function at(e){let t=new Ve({ImageId:e.imageId,InstanceType:e.instanceType,KeyName:e.keyName,MinCount:e.count,MaxCount:e.count,SubnetId:e.subnetId||void 0,Placement:e.placementGroupName?{GroupName:e.placementGroupName}:void 0,BlockDeviceMappings:ot(e)});return await _().send(t)}function ot(e){let{rootDeviceName:t,rootVolumeSize:n,rootVolumeType:r,rootDeleteOnTermination:i}=e;return n!==void 0||r!==void 0||i!==void 0?[{DeviceName:t,Ebs:{...n!==void 0&&{VolumeSize:n},...r!==void 0&&{VolumeType:r},...i!==void 0&&{DeleteOnTermination:i}}}]:void 0}function st(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:ct,onSuccess:()=>{n.invalidateQueries(g)}},t[0]=n,t[1]=r),e(r)}async function ct(e){let t=new be({KeyName:e.keyName,KeyType:`rsa`}),n=await _().send(t);if(!n.KeyMaterial)throw Error(`Key pair was created but the API returned no private key. The key cannot be recovered — delete it and try again.`);return n}function lt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:ut,onSuccess:()=>{n.invalidateQueries(g)}},t[0]=n,t[1]=r),e(r)}async function ut(e){let t=e.publicKeyMaterial.trim().split(Ye).slice(0,2).join(` `),n=new Fe({KeyName:e.keyName,PublicKeyMaterial:new TextEncoder().encode(t)});return await _().send(n)}function dt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:ft,onSuccess:()=>{n.invalidateQueries(g)}},t[0]=n,t[1]=r),e(r)}async function ft(e){let t=new Ee({KeyPairId:e});return await _().send(t)}function pt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:mt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`volumes`]})}},t[0]=n,t[1]=r),e(r)}async function mt(e){let t=new Te({Size:e.size,AvailabilityZone:e.availabilityZone,VolumeType:`gp3`});return await _().send(t)}function ht(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:gt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`volumes`]})}},t[0]=n,t[1]=r),e(r)}async function gt(e){let t=new Le({VolumeId:e.volumeId,Size:e.size});return await _().send(t)}function _t(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:vt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`volumes`]})}},t[0]=n,t[1]=r),e(r)}async function vt(e){let t=new je({VolumeId:e});return await _().send(t)}function yt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:bt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`snapshots`]})}},t[0]=n,t[1]=r),e(r)}async function bt(e){let t=new we({VolumeId:e.volumeId,Description:e.description||void 0});return await _().send(t)}function xt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:St,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`snapshots`]})}},t[0]=n,t[1]=r),e(r)}async function St(e){let t=new ke({SnapshotId:e});return await _().send(t)}function Ct(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:wt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`snapshots`]})}},t[0]=n,t[1]=r),e(r)}async function wt(e){let t=new _e({SourceSnapshotId:e.sourceSnapshotId,SourceRegion:e.sourceRegion,Description:e.description||void 0});return await _().send(t)}function Tt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:Et,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`volumes`]}),n.invalidateQueries({queryKey:[`ec2`,`instances`]})}},t[0]=n,t[1]=r),e(r)}async function Et(e){let t=new B({VolumeId:e.volumeId,InstanceId:e.instanceId,Device:e.device||void 0});return await _().send(t)}function Dt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:Ot,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`volumes`]}),n.invalidateQueries({queryKey:[`ec2`,`instances`]})}},t[0]=n,t[1]=r),e(r)}async function Ot(e){let t=new Ne({VolumeId:e.volumeId,InstanceId:e.instanceId||void 0,Force:e.force});return await _().send(t)}function kt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:At,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`instances`]})}},t[0]=n,t[1]=r),e(r)}async function At(e){let{instanceId:t,...n}=e,r=new Ie({InstanceId:t,InstanceType:{Value:n.instanceType}});return await _().send(r)}function jt(){let t=(0,q.c)(1),n;return t[0]===Symbol.for(`react.memo_cache_sentinel`)?(n={mutationFn:Mt},t[0]=n):n=t[0],e(n)}async function Mt(e){let t=new Pe({InstanceId:e});return await _().send(t)}function Nt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:Pt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`images`]})}},t[0]=n,t[1]=r),e(r)}async function Pt(e){let t=new ve({InstanceId:e.instanceId,Name:e.name,Description:e.description||void 0});return await _().send(t)}function Ft(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:It,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`vpcs`]})}},t[0]=n,t[1]=r),e(r)}async function It(e){let t=new G({CidrBlock:e.cidrBlock,TagSpecifications:e.name?[{ResourceType:`vpc`,Tags:[{Key:`Name`,Value:e.name}]}]:void 0});return await _().send(t)}function Lt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:Rt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`vpcs`]})}},t[0]=n,t[1]=r),e(r)}async function Rt(e){let t=new Me({VpcId:e});return await _().send(t)}function zt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:Bt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`subnets`]})}},t[0]=n,t[1]=r),e(r)}async function Bt(e){let t=new W({VpcId:e.vpcId,CidrBlock:e.cidrBlock,AvailabilityZone:e.availabilityZone||void 0});return await _().send(t)}function Vt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:Ht,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`subnets`]})}},t[0]=n,t[1]=r),e(r)}async function Ht(e){let t=new Ae({SubnetId:e});return await _().send(t)}function Ut(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:Wt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`placementGroups`]})}},t[0]=n,t[1]=r),e(r)}async function Wt(e){let t=new xe({GroupName:e.groupName,Strategy:e.strategy});return await _().send(t)}function Gt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:Kt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`placementGroups`]})}},t[0]=n,t[1]=r),e(r)}async function Kt(e){let t=new De({GroupName:e});return await _().send(t)}function qt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:Jt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`securityGroups`]})}},t[0]=n,t[1]=r),e(r)}async function Jt(e){let t=new Ce({GroupName:e.groupName,Description:e.description,VpcId:e.vpcId});return await _().send(t)}function Q(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:Yt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`securityGroups`]})}},t[0]=n,t[1]=r),e(r)}async function Yt(e){let t=new Oe({GroupId:e});return await _().send(t)}function Xt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:Zt,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`ec2`,`securityGroups`]}),n.invalidateQueries({queryKey:[`ec2`,`securityGroups`,t.groupId]})}},t[0]=n,t[1]=r),e(r)}async function Zt(e){let t=new H({GroupId:e.groupId,IpPermissions:[{IpProtocol:e.ipProtocol,FromPort:e.fromPort,ToPort:e.toPort,IpRanges:[{CidrIp:e.cidrIp}]}]});return await _().send(t)}function Qt(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:$t,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`ec2`,`securityGroups`]}),n.invalidateQueries({queryKey:[`ec2`,`securityGroups`,t.groupId]})}},t[0]=n,t[1]=r),e(r)}async function $t(e){let t=new V({GroupId:e.groupId,IpPermissions:[{IpProtocol:e.ipProtocol,FromPort:e.fromPort,ToPort:e.toPort,IpRanges:[{CidrIp:e.cidrIp}]}]});return await _().send(t)}function en(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:tn,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`ec2`,`securityGroups`]}),n.invalidateQueries({queryKey:[`ec2`,`securityGroups`,t.groupId]})}},t[0]=n,t[1]=r),e(r)}async function tn(e){let t=new Be({GroupId:e.groupId,IpPermissions:[{IpProtocol:e.ipProtocol,FromPort:e.fromPort,ToPort:e.toPort,IpRanges:[{CidrIp:e.cidrIp}]}]});return await _().send(t)}function nn(){let t=(0,q.c)(2),n=D(),r;return t[0]===n?r=t[1]:(r={mutationFn:rn,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`ec2`,`securityGroups`]}),n.invalidateQueries({queryKey:[`ec2`,`securityGroups`,t.groupId]})}},t[0]=n,t[1]=r),e(r)}async function rn(e){let t=new ze({GroupId:e.groupId,IpPermissions:[{IpProtocol:e.ipProtocol,FromPort:e.fromPort,ToPort:e.toPort,IpRanges:[{CidrIp:e.cidrIp}]}]});return await _().send(t)}function an(e,t){let n=[];return e&&n.push({Key:`Name`,Value:e}),n.push(...t),n}function $(e,t,n){let r=an(t,n);if(r.length!==0)return[{ResourceType:e,Tags:r}]}function on(){let t=D();return e({mutationFn:async e=>{let t=_(),n=[],r=e.autoGenerateNames?e.namePrefix:void 0,i=e.tags.map(e=>({Key:e.key,Value:e.value})),a=`creating VPC`;try{let o=r?`${r}-vpc`:e.namePrefix,s=e.tenancy,c=(await t.send(new G({CidrBlock:e.cidrBlock,InstanceTenancy:s,TagSpecifications:$(K.vpc,o,i)}))).Vpc?.VpcId;if(!c)throw Error(`VPC was created but no VPC ID was returned by the API`);if(n.push({type:`VPC`,id:c}),e.mode===`vpc-only`)return{vpcId:c,created:n};let l=Z(e.cidrBlock,e.publicSubnetCount,e.privateSubnetCount),u=e.publicSubnetCidrs.length>0?e.publicSubnetCidrs:l.publicSubnets.map(e=>e.cidr),d=e.privateSubnetCidrs.length>0?e.privateSubnetCidrs:l.privateSubnets.map(e=>e.cidr);a=`creating public subnets`;let f=[];for(let a=0;a0){a=`creating internet gateway`;let e=r?`${r}-igw`:void 0,o=(await t.send(new ye({TagSpecifications:$(K.internet_gateway,e,i)}))).InternetGateway?.InternetGatewayId;if(!o)throw Error(`Internet gateway was created but no ID was returned`);n.push({type:`Internet Gateway`,id:o}),a=`attaching internet gateway to VPC`,await t.send(new z({InternetGatewayId:o,VpcId:c})),a=`creating public route table`;let s=r?`${r}-rtb-public`:void 0,l=(await t.send(new U({VpcId:c,TagSpecifications:$(K.route_table,s,i)}))).RouteTable?.RouteTableId;if(!l)throw Error(`Public route table was created but no ID was returned`);n.push({type:`Public Route Table`,id:l}),a=`creating default route to internet gateway`,await t.send(new Se({RouteTableId:l,DestinationCidrBlock:`0.0.0.0/0`,GatewayId:o})),a=`associating public subnets with route table`;for(let e of f)await t.send(new R({RouteTableId:l,SubnetId:e}))}if(e.privateSubnetCount>0){a=`creating private route table`;let e=r?`${r}-rtb-private`:void 0,o=(await t.send(new U({VpcId:c,TagSpecifications:$(K.route_table,e,i)}))).RouteTable?.RouteTableId;if(!o)throw Error(`Private route table was created but no ID was returned`);n.push({type:`Private Route Table`,id:o}),a=`associating private subnets with route table`;for(let e of p)await t.send(new R({RouteTableId:o,SubnetId:e}))}return{vpcId:c,created:n}}catch(e){return{vpcId:n.find(e=>e.type===`VPC`)?.id,created:n,error:e instanceof Error?e:Error(String(e)),failedStep:`Failed while ${a}`}}},onSuccess:()=>{t.invalidateQueries({queryKey:[`ec2`,`vpcs`]}),t.invalidateQueries({queryKey:[`ec2`,`subnets`]}),t.invalidateQueries({queryKey:[`ec2`,`internetGateways`]}),t.invalidateQueries({queryKey:[`ec2`,`routeTables`]})}})}export{Xe as A,jt as C,nt as D,ht as E,Ke as F,Je as I,et as M,Z as N,nn as O,qe as P,Dt as S,kt as T,Q as _,Nt as a,_t as b,Ut as c,zt as d,pt as f,Gt as g,dt as h,Ct as i,Qe as j,en as k,qt as l,on as m,Qt as n,it as o,Ft as p,Xt as r,st as s,Tt as t,yt as u,xt as v,lt as w,Lt as x,Vt as y}; \ No newline at end of file +import{n as e}from"./error-banner.js";import{An as t,Bn as n,Cn as r,Dn as i,Do as a,En as o,Fn as s,G as c,Hn as l,In as u,Kn as d,Ln as f,Mn as p,Nn as m,On as ee,Pn as h,Rn as g,Sn as _,Tn as te,Un as ne,Vn as v,_n as re,an as ie,bn as ae,cn as oe,dn as se,fn as ce,gn as le,hn as ue,in as de,jn as y,kn as b,ln as x,mn as S,nn as C,on as w,pn as T,pr as E,qn as D,rn as O,sn as k,sr as A,st as j,un as M,vn as N,wn as P,xn as F,xo as I,yn as L}from"./index.js";var R=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`AssociateRouteTable`,{}).n(`EC2Client`,`AssociateRouteTableCommand`).sc(C).build(){},z=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`AttachInternetGateway`,{}).n(`EC2Client`,`AttachInternetGatewayCommand`).sc(O).build(){},B=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`AttachVolume`,{}).n(`EC2Client`,`AttachVolumeCommand`).sc(de).build(){},V=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`AuthorizeSecurityGroupEgress`,{}).n(`EC2Client`,`AuthorizeSecurityGroupEgressCommand`).sc(ie).build(){},H=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`AuthorizeSecurityGroupIngress`,{}).n(`EC2Client`,`AuthorizeSecurityGroupIngressCommand`).sc(w).build(){};function fe(e){let{port:t,query:n}=e,{protocol:r,path:i,hostname:a}=e;r&&r.slice(-1)!==`:`&&(r+=`:`),t&&(a+=`:${t}`),i&&i.charAt(0)!==`/`&&(i=`/${i}`);let o=n?D(n):``;o&&o[0]!==`?`&&(o=`?${o}`);let s=``;(e.username!=null||e.password!=null)&&(s=`${e.username??``}:${e.password??``}@`);let c=``;return e.fragment&&(c=`#${e.fragment}`),`${r}//${s}${a}${i}${o}${c}`}var pe=`2016-11-15`;function me(e){return(t,n)=>async n=>{let{input:r}=n;if(!r.PresignedUrl){let t=await e.region(),i=await l(r,{getEndpointParameterInstructions(){return{UseFIPS:{type:`builtInParams`,name:`useFipsEndpoint`},Endpoint:{type:`builtInParams`,name:`endpoint`},Region:{type:`builtInParams`,name:`region`},UseDualStack:{type:`builtInParams`,name:`useDualstackEndpoint`}}}},{...e,region:r.SourceRegion}),a=typeof e.endpoint==`function`?await e.endpoint():ne(i),o=new E({...a,protocol:`https`,headers:{host:a.hostname},query:{...Object.entries(r).reduce((e,[t,n])=>(e[t]=String(n??``),e),{}),Action:`CopySnapshot`,Version:pe,DestinationRegion:t}}),s=await new A({credentials:e.credentials,region:r.SourceRegion,service:`ec2`,sha256:e.sha256,uriEscapePath:e.signingEscapePath}).presign(o,{expiresIn:3600});if(n={...n,input:{...n.input,DestinationRegion:t,PresignedUrl:fe(s)}},E.isInstance(n.request)){let{request:e}=n;(e.body??``).includes(`DestinationRegion=`)||(e.body+=`&DestinationRegion=${t}`),(e.body??``).includes(`PresignedUrl=`)||(e.body+=`&PresignedUrl=${d(n.input.PresignedUrl)}`)}}return t(n)}}var he={step:`serialize`,tags:[`CROSS_REGION_PRESIGNED_URL`],name:`crossRegionPresignedUrlMiddleware`,override:!0,relation:`after`,toMiddleware:`endpointV2Middleware`},ge=e=>({applyToStack:t=>{t.add(me(e),he)}}),_e=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions()),ge(n)]}).s(`AmazonEC2`,`CopySnapshot`,{}).n(`EC2Client`,`CopySnapshotCommand`).sc(k).build(){},ve=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateImage`,{}).n(`EC2Client`,`CreateImageCommand`).sc(oe).build(){},ye=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateInternetGateway`,{}).n(`EC2Client`,`CreateInternetGatewayCommand`).sc(x).build(){},be=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateKeyPair`,{}).n(`EC2Client`,`CreateKeyPairCommand`).sc(M).build(){},xe=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreatePlacementGroup`,{}).n(`EC2Client`,`CreatePlacementGroupCommand`).sc(se).build(){},Se=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateRoute`,{}).n(`EC2Client`,`CreateRouteCommand`).sc(ce).build(){},U=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateRouteTable`,{}).n(`EC2Client`,`CreateRouteTableCommand`).sc(T).build(){},Ce=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateSecurityGroup`,{}).n(`EC2Client`,`CreateSecurityGroupCommand`).sc(S).build(){},we=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateSnapshot`,{}).n(`EC2Client`,`CreateSnapshotCommand`).sc(ue).build(){},W=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateSubnet`,{}).n(`EC2Client`,`CreateSubnetCommand`).sc(le).build(){},Te=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateVolume`,{}).n(`EC2Client`,`CreateVolumeCommand`).sc(re).build(){},G=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`CreateVpc`,{}).n(`EC2Client`,`CreateVpcCommand`).sc(N).build(){},Ee=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DeleteKeyPair`,{}).n(`EC2Client`,`DeleteKeyPairCommand`).sc(L).build(){},De=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DeletePlacementGroup`,{}).n(`EC2Client`,`DeletePlacementGroupCommand`).sc(ae).build(){},Oe=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DeleteSecurityGroup`,{}).n(`EC2Client`,`DeleteSecurityGroupCommand`).sc(F).build(){},ke=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DeleteSnapshot`,{}).n(`EC2Client`,`DeleteSnapshotCommand`).sc(_).build(){},Ae=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DeleteSubnet`,{}).n(`EC2Client`,`DeleteSubnetCommand`).sc(r).build(){},je=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DeleteVolume`,{}).n(`EC2Client`,`DeleteVolumeCommand`).sc(P).build(){},Me=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DeleteVpc`,{}).n(`EC2Client`,`DeleteVpcCommand`).sc(te).build(){},Ne=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DetachVolume`,{}).n(`EC2Client`,`DetachVolumeCommand`).sc(o).build(){},Pe=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`GetConsoleOutput`,{}).n(`EC2Client`,`GetConsoleOutputCommand`).sc(i).build(){},Fe=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`ImportKeyPair`,{}).n(`EC2Client`,`ImportKeyPairCommand`).sc(ee).build(){},Ie=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`ModifyInstanceAttribute`,{}).n(`EC2Client`,`ModifyInstanceAttributeCommand`).sc(b).build(){},Le=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`ModifyVolume`,{}).n(`EC2Client`,`ModifyVolumeCommand`).sc(t).build(){},Re=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`RebootInstances`,{}).n(`EC2Client`,`RebootInstancesCommand`).sc(y).build(){},ze=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`RevokeSecurityGroupEgress`,{}).n(`EC2Client`,`RevokeSecurityGroupEgressCommand`).sc(p).build(){},Be=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`RevokeSecurityGroupIngress`,{}).n(`EC2Client`,`RevokeSecurityGroupIngressCommand`).sc(m).build(){},Ve=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`RunInstances`,{}).n(`EC2Client`,`RunInstancesCommand`).sc(h).build(){},He=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`StartInstances`,{}).n(`EC2Client`,`StartInstancesCommand`).sc(s).build(){},Ue=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`StopInstances`,{}).n(`EC2Client`,`StopInstancesCommand`).sc(u).build(){},We=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[v(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`TerminateInstances`,{}).n(`EC2Client`,`TerminateInstancesCommand`).sc(f).build(){},K={capacity_block:`capacity-block`,capacity_manager_data_export:`capacity-manager-data-export`,capacity_reservation:`capacity-reservation`,capacity_reservation_fleet:`capacity-reservation-fleet`,carrier_gateway:`carrier-gateway`,client_vpn_endpoint:`client-vpn-endpoint`,coip_pool:`coip-pool`,customer_gateway:`customer-gateway`,declarative_policies_report:`declarative-policies-report`,dedicated_host:`dedicated-host`,dhcp_options:`dhcp-options`,egress_only_internet_gateway:`egress-only-internet-gateway`,elastic_gpu:`elastic-gpu`,elastic_ip:`elastic-ip`,export_image_task:`export-image-task`,export_instance_task:`export-instance-task`,fleet:`fleet`,fpga_image:`fpga-image`,host_reservation:`host-reservation`,image:`image`,image_usage_report:`image-usage-report`,import_image_task:`import-image-task`,import_snapshot_task:`import-snapshot-task`,instance:`instance`,instance_connect_endpoint:`instance-connect-endpoint`,instance_event_window:`instance-event-window`,internet_gateway:`internet-gateway`,ipam:`ipam`,ipam_external_resource_verification_token:`ipam-external-resource-verification-token`,ipam_policy:`ipam-policy`,ipam_pool:`ipam-pool`,ipam_prefix_list_resolver:`ipam-prefix-list-resolver`,ipam_prefix_list_resolver_target:`ipam-prefix-list-resolver-target`,ipam_resource_discovery:`ipam-resource-discovery`,ipam_resource_discovery_association:`ipam-resource-discovery-association`,ipam_scope:`ipam-scope`,ipv4pool_ec2:`ipv4pool-ec2`,ipv6pool_ec2:`ipv6pool-ec2`,key_pair:`key-pair`,launch_template:`launch-template`,local_gateway:`local-gateway`,local_gateway_route_table:`local-gateway-route-table`,local_gateway_route_table_virtual_interface_group_association:`local-gateway-route-table-virtual-interface-group-association`,local_gateway_route_table_vpc_association:`local-gateway-route-table-vpc-association`,local_gateway_virtual_interface:`local-gateway-virtual-interface`,local_gateway_virtual_interface_group:`local-gateway-virtual-interface-group`,mac_modification_task:`mac-modification-task`,natgateway:`natgateway`,network_acl:`network-acl`,network_insights_access_scope:`network-insights-access-scope`,network_insights_access_scope_analysis:`network-insights-access-scope-analysis`,network_insights_analysis:`network-insights-analysis`,network_insights_path:`network-insights-path`,network_interface:`network-interface`,outpost_lag:`outpost-lag`,placement_group:`placement-group`,prefix_list:`prefix-list`,replace_root_volume_task:`replace-root-volume-task`,reserved_instances:`reserved-instances`,route_server:`route-server`,route_server_endpoint:`route-server-endpoint`,route_server_peer:`route-server-peer`,route_table:`route-table`,secondary_interface:`secondary-interface`,secondary_network:`secondary-network`,secondary_subnet:`secondary-subnet`,security_group:`security-group`,security_group_rule:`security-group-rule`,service_link_virtual_interface:`service-link-virtual-interface`,snapshot:`snapshot`,spot_fleet_request:`spot-fleet-request`,spot_instances_request:`spot-instances-request`,subnet:`subnet`,subnet_cidr_reservation:`subnet-cidr-reservation`,traffic_mirror_filter:`traffic-mirror-filter`,traffic_mirror_filter_rule:`traffic-mirror-filter-rule`,traffic_mirror_session:`traffic-mirror-session`,traffic_mirror_target:`traffic-mirror-target`,transit_gateway:`transit-gateway`,transit_gateway_attachment:`transit-gateway-attachment`,transit_gateway_connect_peer:`transit-gateway-connect-peer`,transit_gateway_metering_policy:`transit-gateway-metering-policy`,transit_gateway_multicast_domain:`transit-gateway-multicast-domain`,transit_gateway_policy_table:`transit-gateway-policy-table`,transit_gateway_route_table:`transit-gateway-route-table`,transit_gateway_route_table_announcement:`transit-gateway-route-table-announcement`,verified_access_endpoint:`verified-access-endpoint`,verified_access_endpoint_target:`verified-access-endpoint-target`,verified_access_group:`verified-access-group`,verified_access_instance:`verified-access-instance`,verified_access_policy:`verified-access-policy`,verified_access_trust_provider:`verified-access-trust-provider`,volume:`volume`,vpc:`vpc`,vpc_block_public_access_exclusion:`vpc-block-public-access-exclusion`,vpc_encryption_control:`vpc-encryption-control`,vpc_endpoint:`vpc-endpoint`,vpc_endpoint_connection:`vpc-endpoint-connection`,vpc_endpoint_connection_device_type:`vpc-endpoint-connection-device-type`,vpc_endpoint_service:`vpc-endpoint-service`,vpc_endpoint_service_permission:`vpc-endpoint-service-permission`,vpc_flow_log:`vpc-flow-log`,vpc_peering_connection:`vpc-peering-connection`,vpn_concentrator:`vpn-concentrator`,vpn_connection:`vpn-connection`,vpn_connection_device_type:`vpn-connection-device-type`,vpn_gateway:`vpn-gateway`},q=I();function J(e){let t=e.split(`/`),n=t[0]??``,r=t[1]??`0`,i=Number.parseInt(r,10),a=n.split(`.`).map(e=>Number.parseInt(e,10)),o=a[0]??0,s=a[1]??0,c=a[2]??0,l=a[3]??0;return{network:((o<<24|s<<16|c<<8|l)>>>0&(i===0?0:4294967295<<32-i>>>0))>>>0,prefix:i}}function Y(e){return`${e>>>24&255}.${e>>>16&255}.${e>>>8&255}.${e&255}`}function X(e){return 2**(32-e)}function Ge(e){let t=e+4;return Math.min(t,28)}function Z(e,t,n){let{network:r,prefix:i}=J(e),a=Ge(i),o=X(a),s=X(i)/2,c=[];for(let e=0;e>>0;c.push({cidr:`${Y(t)}/${a}`,label:`Public Subnet ${e+1}`})}let l=[];for(let e=0;e>>0;l.push({cidr:`${Y(t)}/${a}`,label:`Private Subnet ${e+1}`})}return{publicSubnets:c,privateSubnets:l}}function Ke(e,t){let n=J(e),r=J(t),i=n.network+X(n.prefix)-1>>>0,a=r.network+X(r.prefix)-1>>>0;return n.network<=a&&r.network<=i}function qe(e,t){let n=J(e),r=J(t),i=n.network+X(n.prefix)-1>>>0,a=r.network+X(r.prefix)-1>>>0;return r.network>=n.network&&a<=i}function Je(e,t=16,n=28){let r=/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/(\d{1,2})$/.exec(e);if(!r||[Number.parseInt(r[1]??`0`,10),Number.parseInt(r[2]??`0`,10),Number.parseInt(r[3]??`0`,10),Number.parseInt(r[4]??`0`,10)].some(e=>e>255))return!1;let i=Number.parseInt(r[5]??`0`,10);return i>=t&&i<=n}var Ye=/\s+/;function Xe(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:Ze,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`instances`]})}},t[0]=n,t[1]=r),e(r)}async function Ze(e){let t=new He({InstanceIds:[e]});return await j().send(t)}function Qe(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:$e,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`instances`]})}},t[0]=n,t[1]=r),e(r)}async function $e(e){let t=new Ue({InstanceIds:[e]});return await j().send(t)}function et(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:tt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`instances`]})}},t[0]=n,t[1]=r),e(r)}async function tt(e){let t=new We({InstanceIds:[e]});return await j().send(t)}function nt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:rt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`instances`]})}},t[0]=n,t[1]=r),e(r)}async function rt(e){let t=new Re({InstanceIds:[e]});return await j().send(t)}function it(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:at,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`instances`]})}},t[0]=n,t[1]=r),e(r)}async function at(e){let t=new Ve({ImageId:e.imageId,InstanceType:e.instanceType,KeyName:e.keyName,MinCount:e.count,MaxCount:e.count,SubnetId:e.subnetId||void 0,Placement:e.placementGroupName?{GroupName:e.placementGroupName}:void 0,BlockDeviceMappings:ot(e)});return await j().send(t)}function ot(e){let{rootDeviceName:t,rootVolumeSize:n,rootVolumeType:r,rootDeleteOnTermination:i}=e;return n!==void 0||r!==void 0||i!==void 0?[{DeviceName:t,Ebs:{...n!==void 0&&{VolumeSize:n},...r!==void 0&&{VolumeType:r},...i!==void 0&&{DeleteOnTermination:i}}}]:void 0}function st(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:ct,onSuccess:()=>{n.invalidateQueries(c)}},t[0]=n,t[1]=r),e(r)}async function ct(e){let t=new be({KeyName:e.keyName,KeyType:`rsa`}),n=await j().send(t);if(!n.KeyMaterial)throw Error(`Key pair was created but the API returned no private key. The key cannot be recovered — delete it and try again.`);return n}function lt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:ut,onSuccess:()=>{n.invalidateQueries(c)}},t[0]=n,t[1]=r),e(r)}async function ut(e){let t=e.publicKeyMaterial.trim().split(Ye).slice(0,2).join(` `),n=new Fe({KeyName:e.keyName,PublicKeyMaterial:new TextEncoder().encode(t)});return await j().send(n)}function dt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:ft,onSuccess:()=>{n.invalidateQueries(c)}},t[0]=n,t[1]=r),e(r)}async function ft(e){let t=new Ee({KeyPairId:e});return await j().send(t)}function pt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:mt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`volumes`]})}},t[0]=n,t[1]=r),e(r)}async function mt(e){let t=new Te({Size:e.size,AvailabilityZone:e.availabilityZone,VolumeType:`gp3`});return await j().send(t)}function ht(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:gt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`volumes`]})}},t[0]=n,t[1]=r),e(r)}async function gt(e){let t=new Le({VolumeId:e.volumeId,Size:e.size});return await j().send(t)}function _t(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:vt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`volumes`]})}},t[0]=n,t[1]=r),e(r)}async function vt(e){let t=new je({VolumeId:e});return await j().send(t)}function yt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:bt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`snapshots`]})}},t[0]=n,t[1]=r),e(r)}async function bt(e){let t=new we({VolumeId:e.volumeId,Description:e.description||void 0});return await j().send(t)}function xt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:St,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`snapshots`]})}},t[0]=n,t[1]=r),e(r)}async function St(e){let t=new ke({SnapshotId:e});return await j().send(t)}function Ct(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:wt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`snapshots`]})}},t[0]=n,t[1]=r),e(r)}async function wt(e){let t=new _e({SourceSnapshotId:e.sourceSnapshotId,SourceRegion:e.sourceRegion,Description:e.description||void 0});return await j().send(t)}function Tt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:Et,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`volumes`]}),n.invalidateQueries({queryKey:[`ec2`,`instances`]})}},t[0]=n,t[1]=r),e(r)}async function Et(e){let t=new B({VolumeId:e.volumeId,InstanceId:e.instanceId,Device:e.device||void 0});return await j().send(t)}function Dt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:Ot,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`volumes`]}),n.invalidateQueries({queryKey:[`ec2`,`instances`]})}},t[0]=n,t[1]=r),e(r)}async function Ot(e){let t=new Ne({VolumeId:e.volumeId,InstanceId:e.instanceId||void 0,Force:e.force});return await j().send(t)}function kt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:At,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`instances`]})}},t[0]=n,t[1]=r),e(r)}async function At(e){let{instanceId:t,...n}=e,r=new Ie({InstanceId:t,InstanceType:{Value:n.instanceType}});return await j().send(r)}function jt(){let t=(0,q.c)(1),n;return t[0]===Symbol.for(`react.memo_cache_sentinel`)?(n={mutationFn:Mt},t[0]=n):n=t[0],e(n)}async function Mt(e){let t=new Pe({InstanceId:e});return await j().send(t)}function Nt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:Pt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`images`]})}},t[0]=n,t[1]=r),e(r)}async function Pt(e){let t=new ve({InstanceId:e.instanceId,Name:e.name,Description:e.description||void 0});return await j().send(t)}function Ft(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:It,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`vpcs`]})}},t[0]=n,t[1]=r),e(r)}async function It(e){let t=new G({CidrBlock:e.cidrBlock,TagSpecifications:e.name?[{ResourceType:`vpc`,Tags:[{Key:`Name`,Value:e.name}]}]:void 0});return await j().send(t)}function Lt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:Rt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`vpcs`]})}},t[0]=n,t[1]=r),e(r)}async function Rt(e){let t=new Me({VpcId:e});return await j().send(t)}function zt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:Bt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`subnets`]})}},t[0]=n,t[1]=r),e(r)}async function Bt(e){let t=new W({VpcId:e.vpcId,CidrBlock:e.cidrBlock,AvailabilityZone:e.availabilityZone||void 0});return await j().send(t)}function Vt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:Ht,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`subnets`]})}},t[0]=n,t[1]=r),e(r)}async function Ht(e){let t=new Ae({SubnetId:e});return await j().send(t)}function Ut(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:Wt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`placementGroups`]})}},t[0]=n,t[1]=r),e(r)}async function Wt(e){let t=new xe({GroupName:e.groupName,Strategy:e.strategy});return await j().send(t)}function Gt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:Kt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`placementGroups`]})}},t[0]=n,t[1]=r),e(r)}async function Kt(e){let t=new De({GroupName:e});return await j().send(t)}function qt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:Jt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`securityGroups`]})}},t[0]=n,t[1]=r),e(r)}async function Jt(e){let t=new Ce({GroupName:e.groupName,Description:e.description,VpcId:e.vpcId});return await j().send(t)}function Q(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:Yt,onSuccess:()=>{n.invalidateQueries({queryKey:[`ec2`,`securityGroups`]})}},t[0]=n,t[1]=r),e(r)}async function Yt(e){let t=new Oe({GroupId:e});return await j().send(t)}function Xt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:Zt,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`ec2`,`securityGroups`]}),n.invalidateQueries({queryKey:[`ec2`,`securityGroups`,t.groupId]})}},t[0]=n,t[1]=r),e(r)}async function Zt(e){let t=new H({GroupId:e.groupId,IpPermissions:[{IpProtocol:e.ipProtocol,FromPort:e.fromPort,ToPort:e.toPort,IpRanges:[{CidrIp:e.cidrIp}]}]});return await j().send(t)}function Qt(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:$t,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`ec2`,`securityGroups`]}),n.invalidateQueries({queryKey:[`ec2`,`securityGroups`,t.groupId]})}},t[0]=n,t[1]=r),e(r)}async function $t(e){let t=new V({GroupId:e.groupId,IpPermissions:[{IpProtocol:e.ipProtocol,FromPort:e.fromPort,ToPort:e.toPort,IpRanges:[{CidrIp:e.cidrIp}]}]});return await j().send(t)}function en(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:tn,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`ec2`,`securityGroups`]}),n.invalidateQueries({queryKey:[`ec2`,`securityGroups`,t.groupId]})}},t[0]=n,t[1]=r),e(r)}async function tn(e){let t=new Be({GroupId:e.groupId,IpPermissions:[{IpProtocol:e.ipProtocol,FromPort:e.fromPort,ToPort:e.toPort,IpRanges:[{CidrIp:e.cidrIp}]}]});return await j().send(t)}function nn(){let t=(0,q.c)(2),n=a(),r;return t[0]===n?r=t[1]:(r={mutationFn:rn,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`ec2`,`securityGroups`]}),n.invalidateQueries({queryKey:[`ec2`,`securityGroups`,t.groupId]})}},t[0]=n,t[1]=r),e(r)}async function rn(e){let t=new ze({GroupId:e.groupId,IpPermissions:[{IpProtocol:e.ipProtocol,FromPort:e.fromPort,ToPort:e.toPort,IpRanges:[{CidrIp:e.cidrIp}]}]});return await j().send(t)}function an(e,t){let n=[];return e&&n.push({Key:`Name`,Value:e}),n.push(...t),n}function $(e,t,n){let r=an(t,n);if(r.length!==0)return[{ResourceType:e,Tags:r}]}function on(){let t=a();return e({mutationFn:async e=>{let t=j(),n=[],r=e.autoGenerateNames?e.namePrefix:void 0,i=e.tags.map(e=>({Key:e.key,Value:e.value})),a=`creating VPC`;try{let o=r?`${r}-vpc`:e.namePrefix,s=e.tenancy,c=(await t.send(new G({CidrBlock:e.cidrBlock,InstanceTenancy:s,TagSpecifications:$(K.vpc,o,i)}))).Vpc?.VpcId;if(!c)throw Error(`VPC was created but no VPC ID was returned by the API`);if(n.push({type:`VPC`,id:c}),e.mode===`vpc-only`)return{vpcId:c,created:n};let l=Z(e.cidrBlock,e.publicSubnetCount,e.privateSubnetCount),u=e.publicSubnetCidrs.length>0?e.publicSubnetCidrs:l.publicSubnets.map(e=>e.cidr),d=e.privateSubnetCidrs.length>0?e.privateSubnetCidrs:l.privateSubnets.map(e=>e.cidr);a=`creating public subnets`;let f=[];for(let a=0;a0){a=`creating internet gateway`;let e=r?`${r}-igw`:void 0,o=(await t.send(new ye({TagSpecifications:$(K.internet_gateway,e,i)}))).InternetGateway?.InternetGatewayId;if(!o)throw Error(`Internet gateway was created but no ID was returned`);n.push({type:`Internet Gateway`,id:o}),a=`attaching internet gateway to VPC`,await t.send(new z({InternetGatewayId:o,VpcId:c})),a=`creating public route table`;let s=r?`${r}-rtb-public`:void 0,l=(await t.send(new U({VpcId:c,TagSpecifications:$(K.route_table,s,i)}))).RouteTable?.RouteTableId;if(!l)throw Error(`Public route table was created but no ID was returned`);n.push({type:`Public Route Table`,id:l}),a=`creating default route to internet gateway`,await t.send(new Se({RouteTableId:l,DestinationCidrBlock:`0.0.0.0/0`,GatewayId:o})),a=`associating public subnets with route table`;for(let e of f)await t.send(new R({RouteTableId:l,SubnetId:e}))}if(e.privateSubnetCount>0){a=`creating private route table`;let e=r?`${r}-rtb-private`:void 0,o=(await t.send(new U({VpcId:c,TagSpecifications:$(K.route_table,e,i)}))).RouteTable?.RouteTableId;if(!o)throw Error(`Private route table was created but no ID was returned`);n.push({type:`Private Route Table`,id:o}),a=`associating private subnets with route table`;for(let e of p)await t.send(new R({RouteTableId:o,SubnetId:e}))}return{vpcId:c,created:n}}catch(e){return{vpcId:n.find(e=>e.type===`VPC`)?.id,created:n,error:e instanceof Error?e:Error(String(e)),failedStep:`Failed while ${a}`}}},onSuccess:()=>{t.invalidateQueries({queryKey:[`ec2`,`vpcs`]}),t.invalidateQueries({queryKey:[`ec2`,`subnets`]}),t.invalidateQueries({queryKey:[`ec2`,`internetGateways`]}),t.invalidateQueries({queryKey:[`ec2`,`routeTables`]})}})}export{Xe as A,jt as C,nt as D,ht as E,Ke as F,Je as I,et as M,Z as N,nn as O,qe as P,Dt as S,kt as T,Q as _,Nt as a,_t as b,Ut as c,zt as d,pt as f,Gt as g,dt as h,Ct as i,Qe as j,en as k,qt as l,on as m,Qt as n,it as o,Ft as p,Xt as r,st as s,Tt as t,yt as u,xt as v,lt as w,Lt as x,Vt as y}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/ec22.js b/spinifex/services/spinifexui/frontend/dist/assets/ec22.js index 9cee54e61..3100aea4a 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/ec22.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/ec22.js @@ -1 +1 @@ -import{F as e,I as t,P as n}from"./ec2.js";import{dr as r,fr as i,gr as a,hr as o,mr as s,pr as c,vr as l}from"./index.js";var u=/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}$/,d=l().min(1,`Key name is required`).max(255,`Key name must be 255 characters or less`).regex(/^[\w\s._\-:/()#,@[\]+=&;{}!$*]+$/,`Key name contains invalid characters`),f=[`gp3`],p=a({imageId:l(`Please select an Image`),instanceType:l(`Please select an instance type`),keyName:l(`Please select a key pair`).min(1,`Key pair is required`),subnetId:l().optional(),placementGroupName:l().optional(),count:s(`Instance count must be a whole number`).min(1,`Instance count must be at least 1`),rootDeviceName:l().optional(),rootVolumeSize:o().int(`Volume size must be a whole number`).min(1,`Volume size must be at least 1 GiB`).max(16384,`Volume size must be at most 16384 GiB`).optional(),rootVolumeType:r(f).optional(),rootDeleteOnTermination:c().optional()}),m=a({keyName:d}),h=a({keyName:d,publicKeyMaterial:l().min(1,`Public key is required`).refine(e=>e.trim().length>0,`Public key cannot be empty`)}),g=a({size:o().int(`Size must be a whole number`).min(1,`Size must be at least 1 GiB`).max(16384,`Size must be at most 16384 GiB`),availabilityZone:l().min(1,`Availability zone is required`)}),_=a({size:o().int(`Size must be a whole number`).min(1,`Size must be at least 1 GiB`)}),v=a({volumeId:l().min(1,`Volume is required`),description:l().optional()});a({sourceSnapshotId:l().min(1,`Source snapshot is required`),sourceRegion:l().min(1,`Source region is required`),description:l().optional()}),a({volumeId:l().min(1,`Volume is required`),instanceId:l().min(1,`Instance is required`),device:l().optional()}),a({volumeId:l().min(1,`Volume is required`),instanceId:l().optional(),force:c().optional()}),a({instanceType:l().min(1,`Instance type is required`)}),a({name:l().min(1,`Name is required`),description:l().optional()});var y=a({vpcId:l().min(1,`VPC is required`),cidrBlock:l().min(1,`CIDR block is required`).regex(u,`Must be a valid CIDR block (e.g. 10.0.1.0/24)`),availabilityZone:l().optional()});a({cidrBlock:l().min(1,`CIDR block is required`).regex(u,`Must be a valid CIDR block (e.g. 10.0.0.0/16)`),name:l().optional()});var b=a({key:l().min(1,`Key is required`),value:l()}),x=a({mode:r([`vpc-only`,`vpc-and-more`]),namePrefix:l().optional(),autoGenerateNames:c(),cidrBlock:l().min(1,`CIDR block is required`).regex(u,`Must be a valid CIDR block (e.g. 10.0.0.0/16)`).refine(e=>t(e),`CIDR has invalid octets or prefix length (must be /16 to /28)`),tenancy:r([`default`,`dedicated`]),publicSubnetCount:o().int().min(0).max(1),privateSubnetCount:o().int().min(0).max(2),publicSubnetCidrs:i(l()),privateSubnetCidrs:i(l()),tags:i(b)}).superRefine((r,i)=>{if(r.mode!==`vpc-and-more`)return;let a=[];for(let[e,o]of r.publicSubnetCidrs.entries())t(o,16,28)?(n(r.cidrBlock,o)||i.addIssue({code:`custom`,message:`Subnet CIDR must be within the VPC CIDR range`,path:[`publicSubnetCidrs`,e]}),a.push({cidr:o,field:`publicSubnetCidrs`,index:e})):i.addIssue({code:`custom`,message:`Invalid subnet CIDR format or prefix length`,path:[`publicSubnetCidrs`,e]});for(let[e,o]of r.privateSubnetCidrs.entries())t(o,16,28)?(n(r.cidrBlock,o)||i.addIssue({code:`custom`,message:`Subnet CIDR must be within the VPC CIDR range`,path:[`privateSubnetCidrs`,e]}),a.push({cidr:o,field:`privateSubnetCidrs`,index:e})):i.addIssue({code:`custom`,message:`Invalid subnet CIDR format or prefix length`,path:[`privateSubnetCidrs`,e]});for(let t=0;te.trim().length>0,`Public key cannot be empty`)}),g=r({size:l().int(`Size must be a whole number`).min(1,`Size must be at least 1 GiB`).max(16384,`Size must be at most 16384 GiB`),availabilityZone:o().min(1,`Availability zone is required`)}),_=r({size:l().int(`Size must be a whole number`).min(1,`Size must be at least 1 GiB`)}),v=r({volumeId:o().min(1,`Volume is required`),description:o().optional()});r({sourceSnapshotId:o().min(1,`Source snapshot is required`),sourceRegion:o().min(1,`Source region is required`),description:o().optional()}),r({volumeId:o().min(1,`Volume is required`),instanceId:o().min(1,`Instance is required`),device:o().optional()}),r({volumeId:o().min(1,`Volume is required`),instanceId:o().optional(),force:i().optional()}),r({instanceType:o().min(1,`Instance type is required`)}),r({name:o().min(1,`Name is required`),description:o().optional()});var y=r({vpcId:o().min(1,`VPC is required`),cidrBlock:o().min(1,`CIDR block is required`).regex(u,`Must be a valid CIDR block (e.g. 10.0.1.0/24)`),availabilityZone:o().optional()});r({cidrBlock:o().min(1,`CIDR block is required`).regex(u,`Must be a valid CIDR block (e.g. 10.0.0.0/16)`),name:o().optional()});var b=r({key:o().min(1,`Key is required`),value:o()}),x=r({mode:c([`vpc-only`,`vpc-and-more`]),namePrefix:o().optional(),autoGenerateNames:i(),cidrBlock:o().min(1,`CIDR block is required`).regex(u,`Must be a valid CIDR block (e.g. 10.0.0.0/16)`).refine(e=>t(e),`CIDR has invalid octets or prefix length (must be /16 to /28)`),tenancy:c([`default`,`dedicated`]),publicSubnetCount:l().int().min(0).max(1),privateSubnetCount:l().int().min(0).max(2),publicSubnetCidrs:a(o()),privateSubnetCidrs:a(o()),tags:a(b)}).superRefine((r,i)=>{if(r.mode!==`vpc-and-more`)return;let a=[];for(let[e,o]of r.publicSubnetCidrs.entries())t(o,16,28)?(n(r.cidrBlock,o)||i.addIssue({code:`custom`,message:`Subnet CIDR must be within the VPC CIDR range`,path:[`publicSubnetCidrs`,e]}),a.push({cidr:o,field:`publicSubnetCidrs`,index:e})):i.addIssue({code:`custom`,message:`Invalid subnet CIDR format or prefix length`,path:[`publicSubnetCidrs`,e]});for(let[e,o]of r.privateSubnetCidrs.entries())t(o,16,28)?(n(r.cidrBlock,o)||i.addIssue({code:`custom`,message:`Subnet CIDR must be within the VPC CIDR range`,path:[`privateSubnetCidrs`,e]}),a.push({cidr:o,field:`privateSubnetCidrs`,index:e})):i.addIssue({code:`custom`,message:`Invalid subnet CIDR format or prefix length`,path:[`privateSubnetCidrs`,e]});for(let t=0;t{n.invalidateQueries({queryKey:[`elbv2`,`loadBalancers`]})}},t[0]=n,t[1]=r),e(r)}async function P(e){let t=new C({LoadBalancerArn:e});return await p().send(t)}function F(){let t=(0,M.c)(2),n=m(),r;return t[0]===n?r=t[1]:(r={mutationFn:I,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`loadBalancers`,t.loadBalancerArn,`attributes`]})}},t[0]=n,t[1]=r),e(r)}async function I(e){let t=new O({LoadBalancerArn:e.loadBalancerArn,Attributes:e.attributes.map(re)});return await p().send(t)}function re(e){return{Key:e.key,Value:e.value}}function L(){let t=(0,M.c)(2),n=m(),r;return t[0]===n?r=t[1]:(r={mutationFn:R,onSuccess:()=>{n.invalidateQueries({queryKey:[`elbv2`,`targetGroups`]})}},t[0]=n,t[1]=r),e(r)}async function R(e){let t=e.tags.filter(B).map(z),n=new x({Name:e.name,Protocol:e.protocol,Port:e.port,VpcId:e.vpcId,TargetType:`instance`,HealthCheckProtocol:e.healthCheck.protocol,HealthCheckPath:e.healthCheck.path,HealthCheckPort:e.healthCheck.port,HealthCheckIntervalSeconds:e.healthCheck.intervalSeconds,HealthCheckTimeoutSeconds:e.healthCheck.timeoutSeconds,HealthyThresholdCount:e.healthCheck.healthyThresholdCount,UnhealthyThresholdCount:e.healthCheck.unhealthyThresholdCount,Matcher:{HttpCode:e.healthCheck.matcher},Tags:t.length>0?t:void 0});return await p().send(n)}function z(e){return{Key:e.key,Value:e.value}}function B(e){return e.key.length>0}function V(){let t=(0,M.c)(2),n=m(),r;return t[0]===n?r=t[1]:(r={mutationFn:H,onSuccess:()=>{n.invalidateQueries({queryKey:[`elbv2`,`targetGroups`]})}},t[0]=n,t[1]=r),e(r)}async function H(e){let t=new T({TargetGroupArn:e});return await p().send(t)}function U(){let t=(0,M.c)(2),n=m(),r;return t[0]===n?r=t[1]:(r={mutationFn:W,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`targetGroups`,t.targetGroupArn,`attributes`]})}},t[0]=n,t[1]=r),e(r)}async function W(e){let t=new A({TargetGroupArn:e.targetGroupArn,Attributes:e.attributes.map(G)});return await p().send(t)}function G(e){return{Key:e.key,Value:e.value}}function K(){let t=(0,M.c)(2),n=m(),r;return t[0]===n?r=t[1]:(r={mutationFn:q,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`listeners`,t.loadBalancerArn]})}},t[0]=n,t[1]=r),e(r)}async function q(e){let t=[{Type:`forward`,TargetGroupArn:e.defaultTargetGroupArn}],n=new v({LoadBalancerArn:e.loadBalancerArn,Protocol:e.protocol,Port:e.port,DefaultActions:t});return await p().send(n)}function J(){let t=(0,M.c)(2),n=m(),r;return t[0]===n?r=t[1]:(r={mutationFn:Y,onSuccess:()=>{n.invalidateQueries({queryKey:[`elbv2`,`listeners`]})}},t[0]=n,t[1]=r),e(r)}async function Y(e){let t=new S({ListenerArn:e});return await p().send(t)}function X(){let t=(0,M.c)(2),n=m(),r;return t[0]===n?r=t[1]:(r={mutationFn:ie,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`listeners`,t.loadBalancerArn]})}},t[0]=n,t[1]=r),e(r)}async function ie(e){let t=[{Type:`forward`,TargetGroupArn:e.defaultTargetGroupArn}],n=new D({ListenerArn:e.listenerArn,Protocol:e.protocol,Port:e.port,DefaultActions:t});return await p().send(n)}function ae(){let t=m();return e({mutationFn:async e=>{let t=p(),n=[],r=``;try{let i=e.listener.existingTargetGroupArn;if(e.listener.targetGroupMode===`new`){let a=e.listener.newTargetGroup;if(!a)throw Error(`internal error: new target group requested but no data supplied`);r=`creating target group`;let o=a.tags.filter(e=>e.key.length>0).map(e=>({Key:e.key,Value:e.value}));if(i=(await t.send(new x({Name:a.name,Protocol:a.protocol,Port:a.port,VpcId:a.vpcId,TargetType:`instance`,HealthCheckProtocol:a.healthCheck.protocol,HealthCheckPath:a.healthCheck.path,HealthCheckPort:a.healthCheck.port,HealthCheckIntervalSeconds:a.healthCheck.intervalSeconds,HealthCheckTimeoutSeconds:a.healthCheck.timeoutSeconds,HealthyThresholdCount:a.healthCheck.healthyThresholdCount,UnhealthyThresholdCount:a.healthCheck.unhealthyThresholdCount,Matcher:{HttpCode:a.healthCheck.matcher},Tags:o.length>0?o:void 0}))).TargetGroups?.[0]?.TargetGroupArn,!i)throw Error(`Target group was created but no ARN was returned by the API`);n.push({type:`Target Group`,id:i})}if(!i)throw Error(`Target group selection is required`);r=`creating load balancer`;let a=e.lb.tags.filter(e=>e.key.length>0).map(e=>({Key:e.key,Value:e.value})),o=(await t.send(new y({Name:e.lb.name,Scheme:e.lb.scheme,Type:`application`,IpAddressType:`ipv4`,Subnets:e.lb.subnetIds,SecurityGroups:e.lb.securityGroupIds.length>0?e.lb.securityGroupIds:void 0,Tags:a.length>0?a:void 0}))).LoadBalancers?.[0]?.LoadBalancerArn;if(!o)throw Error(`Load balancer was created but no ARN was returned by the API`);return n.push({type:`Load Balancer`,id:o}),r=`creating listener`,await t.send(new v({LoadBalancerArn:o,Protocol:e.listener.protocol,Port:e.listener.port,DefaultActions:[{Type:`forward`,TargetGroupArn:i}]})),n.push({type:`Listener`,id:void 0}),{loadBalancerArn:o,created:n}}catch(e){return{loadBalancerArn:void 0,created:n,error:e instanceof Error?e:Error(String(e)),failedStep:r}}},onSettled:()=>{t.invalidateQueries({queryKey:[`elbv2`]})}})}function Z(e){return e.map(e=>({Id:e.id,Port:e.port}))}function oe(){let t=(0,M.c)(2),n=m(),r;return t[0]===n?r=t[1]:(r={mutationFn:se,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`targetGroups`,t.targetGroupArn,`health`]})}},t[0]=n,t[1]=r),e(r)}async function se(e){let t=new j({TargetGroupArn:e.targetGroupArn,Targets:Z(e.targets)});return await p().send(t)}function Q(){let t=(0,M.c)(2),n=m(),r;return t[0]===n?r=t[1]:(r={mutationFn:ce,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`targetGroups`,t.targetGroupArn,`health`]})}},t[0]=n,t[1]=r),e(r)}async function ce(e){let t=new E({TargetGroupArn:e.targetGroupArn,Targets:Z(e.targets)});return await p().send(t)}function $(e){return e.map(e=>{switch(e.field){case`host-header`:return{Field:e.field,HostHeaderConfig:{Values:e.values}};case`path-pattern`:return{Field:e.field,PathPatternConfig:{Values:e.values}};case`http-header`:return{Field:e.field,HttpHeaderConfig:{HttpHeaderName:e.httpHeaderName??``,Values:e.values}};case`http-request-method`:return{Field:e.field,HttpRequestMethodConfig:{Values:e.values}};case`source-ip`:return{Field:e.field,SourceIpConfig:{Values:e.values}};case`query-string`:return{Field:e.field,QueryStringConfig:{Values:(e.queryStringPairs??[]).map(e=>({Key:e.key&&e.key.length>0?e.key:void 0,Value:e.value}))}};default:return{Field:e.field,Values:e.values}}})}function le(){let t=(0,M.c)(2),n=m(),r;return t[0]===n?r=t[1]:(r={mutationFn:ue,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`listeners`,t.listenerArn,`rules`]})}},t[0]=n,t[1]=r),e(r)}async function ue(e){let t=[{Type:`forward`,TargetGroupArn:e.forwardTargetGroupArn}],n=new b({ListenerArn:e.listenerArn,Priority:e.priority,Conditions:$(e.conditions),Actions:t});return await p().send(n)}function de(){let t=(0,M.c)(2),n=m(),r;return t[0]===n?r=t[1]:(r={mutationFn:fe,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`listeners`,t.listenerArn,`rules`]})}},t[0]=n,t[1]=r),e(r)}async function fe(e){let t=new k({RuleArn:e.ruleArn,Conditions:e.conditions?$(e.conditions):void 0,Actions:e.forwardTargetGroupArn?[{Type:`forward`,TargetGroupArn:e.forwardTargetGroupArn}]:void 0});return await p().send(t)}function pe(){let t=(0,M.c)(2),n=m(),r;return t[0]===n?r=t[1]:(r={mutationFn:me,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`listeners`,t.listenerArn,`rules`]})}},t[0]=n,t[1]=r),e(r)}async function me(e){let t=new w({RuleArn:e.ruleArn});return await p().send(t)}export{J as a,V as c,F as d,de as f,L as i,Q as l,oe as m,ae as n,N as o,U as p,le as r,pe as s,K as t,X as u}; \ No newline at end of file +import{n as e}from"./error-banner.js";import{$t as t,Bn as n,Bt as r,Do as i,Gt as a,Ht as o,Jt as ee,Kt as s,Lt as c,Qt as l,Rt as u,Ut as d,Vn as f,Vt as te,Wt as ne,Xt as re,Yt as p,Zt as m,ct as h,en as g,qt as _,xo as v,zt as y}from"./index.js";var b=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`AddTags`,{}).n(`ElasticLoadBalancingV2Client`,`AddTagsCommand`).sc(c).build(){},x=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`CreateListener`,{}).n(`ElasticLoadBalancingV2Client`,`CreateListenerCommand`).sc(u).build(){},S=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`CreateLoadBalancer`,{}).n(`ElasticLoadBalancingV2Client`,`CreateLoadBalancerCommand`).sc(y).build(){},C=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`CreateRule`,{}).n(`ElasticLoadBalancingV2Client`,`CreateRuleCommand`).sc(r).build(){},w=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`CreateTargetGroup`,{}).n(`ElasticLoadBalancingV2Client`,`CreateTargetGroupCommand`).sc(te).build(){},T=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DeleteListener`,{}).n(`ElasticLoadBalancingV2Client`,`DeleteListenerCommand`).sc(o).build(){},E=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DeleteLoadBalancer`,{}).n(`ElasticLoadBalancingV2Client`,`DeleteLoadBalancerCommand`).sc(d).build(){},D=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DeleteRule`,{}).n(`ElasticLoadBalancingV2Client`,`DeleteRuleCommand`).sc(ne).build(){},O=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DeleteTargetGroup`,{}).n(`ElasticLoadBalancingV2Client`,`DeleteTargetGroupCommand`).sc(a).build(){},k=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DeregisterTargets`,{}).n(`ElasticLoadBalancingV2Client`,`DeregisterTargetsCommand`).sc(s).build(){},A=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`ModifyListener`,{}).n(`ElasticLoadBalancingV2Client`,`ModifyListenerCommand`).sc(_).build(){},j=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`ModifyLoadBalancerAttributes`,{}).n(`ElasticLoadBalancingV2Client`,`ModifyLoadBalancerAttributesCommand`).sc(ee).build(){},M=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`ModifyRule`,{}).n(`ElasticLoadBalancingV2Client`,`ModifyRuleCommand`).sc(p).build(){},N=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`ModifyTargetGroupAttributes`,{}).n(`ElasticLoadBalancingV2Client`,`ModifyTargetGroupAttributesCommand`).sc(re).build(){},P=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`RegisterTargets`,{}).n(`ElasticLoadBalancingV2Client`,`RegisterTargetsCommand`).sc(m).build(){},F=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`RemoveTags`,{}).n(`ElasticLoadBalancingV2Client`,`RemoveTagsCommand`).sc(l).build(){},I=class extends n.classBuilder().ep(g).m(function(e,t,n,r){return[f(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`SetSecurityGroups`,{}).n(`ElasticLoadBalancingV2Client`,`SetSecurityGroupsCommand`).sc(t).build(){},L=v();function R(){let t=(0,L.c)(2),n=i(),r;return t[0]===n?r=t[1]:(r={mutationFn:z,onSuccess:()=>{n.invalidateQueries({queryKey:[`elbv2`,`loadBalancers`]})}},t[0]=n,t[1]=r),e(r)}async function z(e){let t=new E({LoadBalancerArn:e});return await h().send(t)}function B(){let t=(0,L.c)(2),n=i(),r;return t[0]===n?r=t[1]:(r={mutationFn:V,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`loadBalancers`,t.loadBalancerArn,`attributes`]})}},t[0]=n,t[1]=r),e(r)}async function V(e){let t=new j({LoadBalancerArn:e.loadBalancerArn,Attributes:e.attributes.map(H)});return await h().send(t)}function H(e){return{Key:e.key,Value:e.value}}function U(){let t=(0,L.c)(2),n=i(),r;return t[0]===n?r=t[1]:(r={mutationFn:W,onSuccess:()=>{n.invalidateQueries({queryKey:[`elbv2`,`tags`]})}},t[0]=n,t[1]=r),e(r)}async function W(e){let t=new Set(e.tags.map(K)),n=e.initialKeys.filter(e=>!t.has(e)),r=h();e.tags.length>0&&await r.send(new b({ResourceArns:[e.resourceArn],Tags:e.tags.map(G)})),n.length>0&&await r.send(new F({ResourceArns:[e.resourceArn],TagKeys:n}))}function G(e){return{Key:e.key,Value:e.value}}function K(e){return e.key}function q(){let t=(0,L.c)(2),n=i(),r;return t[0]===n?r=t[1]:(r={mutationFn:J,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`loadBalancers`,t.loadBalancerArn]})}},t[0]=n,t[1]=r),e(r)}async function J(e){let t=new I({LoadBalancerArn:e.loadBalancerArn,SecurityGroups:e.securityGroupIds});return await h().send(t)}function ie(){let t=(0,L.c)(2),n=i(),r;return t[0]===n?r=t[1]:(r={mutationFn:Y,onSuccess:()=>{n.invalidateQueries({queryKey:[`elbv2`,`targetGroups`]})}},t[0]=n,t[1]=r),e(r)}async function Y(e){let t=e.tags.filter(oe).map(ae),n=new w({Name:e.name,Protocol:e.protocol,Port:e.port,VpcId:e.vpcId,TargetType:`instance`,HealthCheckProtocol:e.healthCheck.protocol,HealthCheckPath:e.healthCheck.path,HealthCheckPort:e.healthCheck.port,HealthCheckIntervalSeconds:e.healthCheck.intervalSeconds,HealthCheckTimeoutSeconds:e.healthCheck.timeoutSeconds,HealthyThresholdCount:e.healthCheck.healthyThresholdCount,UnhealthyThresholdCount:e.healthCheck.unhealthyThresholdCount,Matcher:{HttpCode:e.healthCheck.matcher},Tags:t.length>0?t:void 0});return await h().send(n)}function ae(e){return{Key:e.key,Value:e.value}}function oe(e){return e.key.length>0}function se(){let t=(0,L.c)(2),n=i(),r;return t[0]===n?r=t[1]:(r={mutationFn:ce,onSuccess:()=>{n.invalidateQueries({queryKey:[`elbv2`,`targetGroups`]})}},t[0]=n,t[1]=r),e(r)}async function ce(e){let t=new O({TargetGroupArn:e});return await h().send(t)}function le(){let t=(0,L.c)(2),n=i(),r;return t[0]===n?r=t[1]:(r={mutationFn:ue,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`targetGroups`,t.targetGroupArn,`attributes`]})}},t[0]=n,t[1]=r),e(r)}async function ue(e){let t=new N({TargetGroupArn:e.targetGroupArn,Attributes:e.attributes.map(de)});return await h().send(t)}function de(e){return{Key:e.key,Value:e.value}}function X(e,t,n){return e!==`HTTPS`||!t?{}:{Certificates:[{CertificateArn:t}],SslPolicy:n}}function fe(){let t=(0,L.c)(2),n=i(),r;return t[0]===n?r=t[1]:(r={mutationFn:pe,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`listeners`,t.loadBalancerArn]})}},t[0]=n,t[1]=r),e(r)}async function pe(e){let t=[{Type:`forward`,TargetGroupArn:e.defaultTargetGroupArn}],n=new x({LoadBalancerArn:e.loadBalancerArn,Protocol:e.protocol,Port:e.port,DefaultActions:t,...X(e.protocol,e.certificateArn,e.sslPolicy)});return await h().send(n)}function me(){let t=(0,L.c)(2),n=i(),r;return t[0]===n?r=t[1]:(r={mutationFn:he,onSuccess:()=>{n.invalidateQueries({queryKey:[`elbv2`,`listeners`]})}},t[0]=n,t[1]=r),e(r)}async function he(e){let t=new T({ListenerArn:e});return await h().send(t)}function ge(){let t=(0,L.c)(2),n=i(),r;return t[0]===n?r=t[1]:(r={mutationFn:_e,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`listeners`,t.loadBalancerArn]})}},t[0]=n,t[1]=r),e(r)}async function _e(e){let t=[{Type:`forward`,TargetGroupArn:e.defaultTargetGroupArn}],n=new A({ListenerArn:e.listenerArn,Protocol:e.protocol,Port:e.port,DefaultActions:t,...X(e.protocol,e.certificateArn,e.sslPolicy)});return await h().send(n)}function ve(){let t=i();return e({mutationFn:async e=>{let t=h(),n=[],r=``;try{let i=e.listener.existingTargetGroupArn;if(e.listener.targetGroupMode===`new`){let a=e.listener.newTargetGroup;if(!a)throw Error(`internal error: new target group requested but no data supplied`);r=`creating target group`;let o=a.tags.filter(e=>e.key.length>0).map(e=>({Key:e.key,Value:e.value}));if(i=(await t.send(new w({Name:a.name,Protocol:a.protocol,Port:a.port,VpcId:a.vpcId,TargetType:`instance`,HealthCheckProtocol:a.healthCheck.protocol,HealthCheckPath:a.healthCheck.path,HealthCheckPort:a.healthCheck.port,HealthCheckIntervalSeconds:a.healthCheck.intervalSeconds,HealthCheckTimeoutSeconds:a.healthCheck.timeoutSeconds,HealthyThresholdCount:a.healthCheck.healthyThresholdCount,UnhealthyThresholdCount:a.healthCheck.unhealthyThresholdCount,Matcher:{HttpCode:a.healthCheck.matcher},Tags:o.length>0?o:void 0}))).TargetGroups?.[0]?.TargetGroupArn,!i)throw Error(`Target group was created but no ARN was returned by the API`);n.push({type:`Target Group`,id:i})}if(!i)throw Error(`Target group selection is required`);r=`creating load balancer`;let a=e.lb.tags.filter(e=>e.key.length>0).map(e=>({Key:e.key,Value:e.value})),o=(await t.send(new S({Name:e.lb.name,Scheme:e.lb.scheme,Type:`application`,IpAddressType:`ipv4`,Subnets:e.lb.subnetIds,SecurityGroups:e.lb.securityGroupIds.length>0?e.lb.securityGroupIds:void 0,Tags:a.length>0?a:void 0}))).LoadBalancers?.[0]?.LoadBalancerArn;if(!o)throw Error(`Load balancer was created but no ARN was returned by the API`);return n.push({type:`Load Balancer`,id:o}),r=`creating listener`,await t.send(new x({LoadBalancerArn:o,Protocol:e.listener.protocol,Port:e.listener.port,DefaultActions:[{Type:`forward`,TargetGroupArn:i}]})),n.push({type:`Listener`,id:void 0}),{loadBalancerArn:o,created:n}}catch(e){return{loadBalancerArn:void 0,created:n,error:e instanceof Error?e:Error(String(e)),failedStep:r}}},onSettled:()=>{t.invalidateQueries({queryKey:[`elbv2`]})}})}function Z(e){return e.map(e=>({Id:e.id,Port:e.port}))}function ye(){let t=(0,L.c)(2),n=i(),r;return t[0]===n?r=t[1]:(r={mutationFn:be,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`targetGroups`,t.targetGroupArn,`health`]})}},t[0]=n,t[1]=r),e(r)}async function be(e){let t=new P({TargetGroupArn:e.targetGroupArn,Targets:Z(e.targets)});return await h().send(t)}function xe(){let t=(0,L.c)(2),n=i(),r;return t[0]===n?r=t[1]:(r={mutationFn:Se,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`targetGroups`,t.targetGroupArn,`health`]})}},t[0]=n,t[1]=r),e(r)}async function Se(e){let t=new k({TargetGroupArn:e.targetGroupArn,Targets:Z(e.targets)});return await h().send(t)}function Q(e){return e.map(e=>{switch(e.field){case`host-header`:return{Field:e.field,HostHeaderConfig:{Values:e.values}};case`path-pattern`:return{Field:e.field,PathPatternConfig:{Values:e.values}};case`http-header`:return{Field:e.field,HttpHeaderConfig:{HttpHeaderName:e.httpHeaderName??``,Values:e.values}};case`http-request-method`:return{Field:e.field,HttpRequestMethodConfig:{Values:e.values}};case`source-ip`:return{Field:e.field,SourceIpConfig:{Values:e.values}};case`query-string`:return{Field:e.field,QueryStringConfig:{Values:(e.queryStringPairs??[]).map(e=>({Key:e.key&&e.key.length>0?e.key:void 0,Value:e.value}))}};default:return{Field:e.field,Values:e.values}}})}function Ce(){let t=(0,L.c)(2),n=i(),r;return t[0]===n?r=t[1]:(r={mutationFn:$,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`listeners`,t.listenerArn,`rules`]})}},t[0]=n,t[1]=r),e(r)}async function $(e){let t=[{Type:`forward`,TargetGroupArn:e.forwardTargetGroupArn}],n=new C({ListenerArn:e.listenerArn,Priority:e.priority,Conditions:Q(e.conditions),Actions:t});return await h().send(n)}function we(){let t=(0,L.c)(2),n=i(),r;return t[0]===n?r=t[1]:(r={mutationFn:Te,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`listeners`,t.listenerArn,`rules`]})}},t[0]=n,t[1]=r),e(r)}async function Te(e){let t=new M({RuleArn:e.ruleArn,Conditions:e.conditions?Q(e.conditions):void 0,Actions:e.forwardTargetGroupArn?[{Type:`forward`,TargetGroupArn:e.forwardTargetGroupArn}]:void 0});return await h().send(t)}function Ee(){let t=(0,L.c)(2),n=i(),r;return t[0]===n?r=t[1]:(r={mutationFn:De,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`elbv2`,`listeners`,t.listenerArn,`rules`]})}},t[0]=n,t[1]=r),e(r)}async function De(e){let t=new D({RuleArn:e.ruleArn});return await h().send(t)}export{me as a,se as c,B as d,we as f,U as g,q as h,ie as i,xe as l,ye as m,ve as n,R as o,le as p,Ce as r,Ee as s,fe as t,ge as u}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/elbv22.js b/spinifex/services/spinifexui/frontend/dist/assets/elbv22.js index d71672bca..f4b52c928 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/elbv22.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/elbv22.js @@ -1 +1 @@ -import{_r as e,dr as t,fr as n,gr as r,hr as i,vr as a}from"./index.js";var o=/^(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])$/,s=a().min(1,`Name is required`).max(32,`Name must be 32 characters or less`).regex(o,`Name may contain only letters, digits, and hyphens; must start and end with alphanumeric`).refine(e=>!e.startsWith(`internal-`),`Name cannot start with 'internal-'`),c=a().min(1,`Name is required`).max(32,`Name must be 32 characters or less`).regex(o,`Name may contain only letters, digits, and hyphens; must start and end with alphanumeric`),l=i().int(`Port must be a whole number`).min(1,`Port must be at least 1`).max(65535,`Port must be at most 65535`),u=r({key:a().min(1,`Tag key is required`).max(128),value:a().max(256)}),d=r({protocol:t([`HTTP`]),path:a().min(1,`Path is required`).max(1024),port:a().min(1),intervalSeconds:i().int().min(5).max(300),timeoutSeconds:i().int().min(2).max(120),healthyThresholdCount:i().int().min(2).max(10),unhealthyThresholdCount:i().int().min(2).max(10),matcher:a().regex(/^\d{3}(?:[-,]\d{3})*$/,`Matcher must be HTTP codes like 200 or 200-299 or 200,201`)}),f=r({name:c,protocol:t([`HTTP`]),port:l,vpcId:a().min(1,`VPC is required`),healthCheck:d,tags:n(u)}),p=r({protocol:t([`HTTP`]),port:l,defaultTargetGroupArn:a().min(1,`Target group is required`)}),m=/^[!-~]+$/,h=r({field:t([`host-header`,`path-pattern`,`http-header`,`http-request-method`,`source-ip`,`query-string`]),httpHeaderName:a().max(40).optional(),rawValues:a().min(1,`At least one value is required`).max(640,`Too many values`)}).superRefine((e,t)=>{e.field===`http-header`&&!e.httpHeaderName&&t.addIssue({code:`custom`,path:[`httpHeaderName`],message:`Header name is required`});let n=e.rawValues.split(/[\n,]/).map(e=>e.trim()).filter(e=>e.length>0);if(n.length===0||n.length>5){t.addIssue({code:`custom`,path:[`rawValues`],message:`Enter 1 to 5 values, comma or newline separated`});return}for(let e of n)if(!m.test(e)){t.addIssue({code:`custom`,path:[`rawValues`],message:`Value "${e}" contains whitespace or non-ASCII characters`});return}}),g=r({priority:i().int(`Priority must be a whole number`).min(1,`Priority must be at least 1`).max(5e4,`Priority must be at most 50000`),conditions:n(h).min(1,`At least one condition is required`).max(5,`Up to 5 conditions per rule`),forwardTargetGroupArn:a().min(1,`Target group is required`)}),_=r({name:s,scheme:t([`internet-facing`,`internal`]),vpcId:a().min(1,`VPC is required`),subnetIds:n(a()).min(2,`At least 2 subnets are required for an ALB`),securityGroupIds:n(a()),tags:n(u),listener:r({protocol:t([`HTTP`]),port:l,targetGroupMode:t([`new`,`existing`]),existingTargetGroupArn:a().optional()}).refine(e=>e.targetGroupMode===`existing`?!!e.existingTargetGroupArn:!0,{error:`Target group is required`,path:[`existingTargetGroupArn`]})});r({targets:n(r({instanceId:a().min(1,`Instance is required`),port:l.optional()})).min(1,`At least one target is required`)}),e(a(),a());export{f as i,_ as n,g as r,p as t}; \ No newline at end of file +import{Ar as e,Er as t,Mr as n,Tr as r,jr as i,kr as a}from"./index.js";var o=/^(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])$/,s=n().min(1,`Name is required`).max(32,`Name must be 32 characters or less`).regex(o,`Name may contain only letters, digits, and hyphens; must start and end with alphanumeric`).refine(e=>!e.startsWith(`internal-`),`Name cannot start with 'internal-'`),c=n().min(1,`Name is required`).max(32,`Name must be 32 characters or less`).regex(o,`Name may contain only letters, digits, and hyphens; must start and end with alphanumeric`),l=a().int(`Port must be a whole number`).min(1,`Port must be at least 1`).max(65535,`Port must be at most 65535`),u=e({key:n().min(1,`Tag key is required`).max(128),value:n().max(256)}),d=e({protocol:r([`HTTP`]),path:n().min(1,`Path is required`).max(1024),port:n().min(1),intervalSeconds:a().int().min(5).max(300),timeoutSeconds:a().int().min(2).max(120),healthyThresholdCount:a().int().min(2).max(10),unhealthyThresholdCount:a().int().min(2).max(10),matcher:n().regex(/^\d{3}(?:[-,]\d{3})*$/,`Matcher must be HTTP codes like 200 or 200-299 or 200,201`)}),f=e({name:c,protocol:r([`HTTP`]),port:l,vpcId:n().min(1,`VPC is required`),healthCheck:d,tags:t(u)}),p=`ELBSecurityPolicy-2016-08`,m=e({protocol:r([`HTTP`,`HTTPS`]),port:l,defaultTargetGroupArn:n().min(1,`Target group is required`),certificateArn:n().optional(),sslPolicy:n().optional()}).superRefine((e,t)=>{e.protocol===`HTTPS`&&!e.certificateArn&&t.addIssue({code:`custom`,path:[`certificateArn`],message:`A certificate is required for HTTPS`})}),h=/^[!-~]+$/,g=e({field:r([`host-header`,`path-pattern`,`http-header`,`http-request-method`,`source-ip`,`query-string`]),httpHeaderName:n().max(40).optional(),rawValues:n().min(1,`At least one value is required`).max(640,`Too many values`)}).superRefine((e,t)=>{e.field===`http-header`&&!e.httpHeaderName&&t.addIssue({code:`custom`,path:[`httpHeaderName`],message:`Header name is required`});let n=e.rawValues.split(/[\n,]/).map(e=>e.trim()).filter(e=>e.length>0);if(n.length===0||n.length>5){t.addIssue({code:`custom`,path:[`rawValues`],message:`Enter 1 to 5 values, comma or newline separated`});return}for(let e of n)if(!h.test(e)){t.addIssue({code:`custom`,path:[`rawValues`],message:`Value "${e}" contains whitespace or non-ASCII characters`});return}}),_=e({priority:a().int(`Priority must be a whole number`).min(1,`Priority must be at least 1`).max(5e4,`Priority must be at most 50000`),conditions:t(g).min(1,`At least one condition is required`).max(5,`Up to 5 conditions per rule`),forwardTargetGroupArn:n().min(1,`Target group is required`)}),v=e({name:s,scheme:r([`internet-facing`,`internal`]),vpcId:n().min(1,`VPC is required`),subnetIds:t(n()).min(2,`At least 2 subnets are required for an ALB`),securityGroupIds:t(n()),tags:t(u),listener:e({protocol:r([`HTTP`]),port:l,targetGroupMode:r([`new`,`existing`]),existingTargetGroupArn:n().optional()}).refine(e=>e.targetGroupMode===`existing`?!!e.existingTargetGroupArn:!0,{error:`Target group is required`,path:[`existingTargetGroupArn`]})});e({targets:t(e({instanceId:n().min(1,`Instance is required`),port:l.optional()})).min(1,`At least one target is required`)}),i(n(),n());export{f as a,_ as i,m as n,v as r,p as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/error-banner.js b/spinifex/services/spinifexui/frontend/dist/assets/error-banner.js index 6665b414e..274d03f67 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/error-banner.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/error-banner.js @@ -1 +1 @@ -import{Co as e,Do as t,Mo as n,Oo as r,Po as i,go as a,ho as o,mo as s,po as c,so as l,vo as u,xo as d}from"./index.js";var f=class extends n{#e;#t=void 0;#n;#r;constructor(e,t){super(),this.#e=e,this.setOptions(t),this.bindMethods(),this.#i()}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(e){let n=this.options;this.options=this.#e.defaultMutationOptions(e),t(this.options,n)||this.#e.getMutationCache().notify({type:`observerOptionsUpdated`,mutation:this.#n,observer:this}),n?.mutationKey&&this.options.mutationKey&&d(n.mutationKey)!==d(this.options.mutationKey)?this.reset():this.#n?.state.status===`pending`&&this.#n.setOptions(this.options)}onUnsubscribe(){this.hasListeners()||this.#n?.removeObserver(this)}onMutationUpdate(e){this.#i(),this.#a(e)}getCurrentResult(){return this.#t}reset(){this.#n?.removeObserver(this),this.#n=void 0,this.#i(),this.#a()}mutate(e,t){return this.#r=t,this.#n?.removeObserver(this),this.#n=this.#e.getMutationCache().build(this.#e,this.options),this.#n.addObserver(this),this.#n.execute(e)}#i(){let e=this.#n?.state??a();this.#t={...e,isPending:e.status===`pending`,isSuccess:e.status===`success`,isError:e.status===`error`,isIdle:e.status===`idle`,mutate:this.mutate,reset:this.reset}}#a(e){u.batch(()=>{if(this.#r&&this.hasListeners()){let t=this.#t.variables,n=this.#t.context,r={client:this.#e,meta:this.options.meta,mutationKey:this.options.mutationKey};if(e?.type===`success`){try{this.#r.onSuccess?.(e.data,t,n,r)}catch(e){Promise.reject(e)}try{this.#r.onSettled?.(e.data,null,t,n,r)}catch(e){Promise.reject(e)}}else if(e?.type===`error`){try{this.#r.onError?.(e.error,t,n,r)}catch(e){Promise.reject(e)}try{this.#r.onSettled?.(void 0,e.error,t,n,r)}catch(e){Promise.reject(e)}}}this.listeners.forEach(e=>{e(this.#t)})})}},p=i(o(),1);function m(t,n){let i=c(n),[a]=p.useState(()=>new f(i,t));p.useEffect(()=>{a.setOptions(t)},[a,t]);let o=p.useSyncExternalStore(p.useCallback(e=>a.subscribe(u.batchCalls(e)),[a]),()=>a.getCurrentResult(),()=>a.getCurrentResult()),s=p.useCallback((t,n)=>{a.mutate(t,n).catch(e)},[a]);if(o.error&&r(a.options.throwOnError,[o.error]))throw o.error;return{...o,mutate:s,mutateAsync:o.mutate}}var h=l(),g=s();function _(e){let t=(0,h.c)(7),{msg:n,error:r}=e,i;r&&(i=r.name===`Error`?r.message:r.name);let a;t[0]===n?a=t[1]:(a=n&&(0,g.jsx)(`h2`,{className:`text-sm text-destructive`,children:n}),t[0]=n,t[1]=a);let o;t[2]===i?o=t[3]:(o=i&&(0,g.jsx)(`p`,{className:`text-sm text-destructive`,children:i}),t[2]=i,t[3]=o);let s;return t[4]!==a||t[5]!==o?(s=(0,g.jsxs)(`div`,{className:`mb-6 max-w-4xl rounded-md border border-destructive bg-destructive/10 p-4`,children:[a,o]}),t[4]=a,t[5]=o,t[6]=s):s=t[6],s}export{m as n,_ as t}; \ No newline at end of file +import{Ao as e,Do as t,Fo as n,Ho as r,Jo as i,Ko as a,Lo as o,Mo as s,Oo as c,Vo as l,ko as u,xo as d}from"./index.js";var f=class extends a{#e;#t=void 0;#n;#r;constructor(e,t){super(),this.#e=e,this.setOptions(t),this.bindMethods(),this.#i()}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(e){let t=this.options;this.options=this.#e.defaultMutationOptions(e),l(this.options,t)||this.#e.getMutationCache().notify({type:`observerOptionsUpdated`,mutation:this.#n,observer:this}),t?.mutationKey&&this.options.mutationKey&&n(t.mutationKey)!==n(this.options.mutationKey)?this.reset():this.#n?.state.status===`pending`&&this.#n.setOptions(this.options)}onUnsubscribe(){this.hasListeners()||this.#n?.removeObserver(this)}onMutationUpdate(e){this.#i(),this.#a(e)}getCurrentResult(){return this.#t}reset(){this.#n?.removeObserver(this),this.#n=void 0,this.#i(),this.#a()}mutate(e,t){return this.#r=t,this.#n?.removeObserver(this),this.#n=this.#e.getMutationCache().build(this.#e,this.options),this.#n.addObserver(this),this.#n.execute(e)}#i(){let t=this.#n?.state??e();this.#t={...t,isPending:t.status===`pending`,isSuccess:t.status===`success`,isError:t.status===`error`,isIdle:t.status===`idle`,mutate:this.mutate,reset:this.reset}}#a(e){s.batch(()=>{if(this.#r&&this.hasListeners()){let t=this.#t.variables,n=this.#t.context,r={client:this.#e,meta:this.options.meta,mutationKey:this.options.mutationKey};if(e?.type===`success`){try{this.#r.onSuccess?.(e.data,t,n,r)}catch(e){Promise.reject(e)}try{this.#r.onSettled?.(e.data,null,t,n,r)}catch(e){Promise.reject(e)}}else if(e?.type===`error`){try{this.#r.onError?.(e.error,t,n,r)}catch(e){Promise.reject(e)}try{this.#r.onSettled?.(void 0,e.error,t,n,r)}catch(e){Promise.reject(e)}}}this.listeners.forEach(e=>{e(this.#t)})})}},p=i(u(),1);function m(e,n){let i=t(n),[a]=p.useState(()=>new f(i,e));p.useEffect(()=>{a.setOptions(e)},[a,e]);let c=p.useSyncExternalStore(p.useCallback(e=>a.subscribe(s.batchCalls(e)),[a]),()=>a.getCurrentResult(),()=>a.getCurrentResult()),l=p.useCallback((e,t)=>{a.mutate(e,t).catch(o)},[a]);if(c.error&&r(a.options.throwOnError,[c.error]))throw c.error;return{...c,mutate:l,mutateAsync:c.mutate}}var h=d(),g=c();function _(e){let t=(0,h.c)(7),{msg:n,error:r}=e,i;r&&(i=r.name===`Error`?r.message:r.name);let a;t[0]===n?a=t[1]:(a=n&&(0,g.jsx)(`h2`,{className:`text-sm text-destructive`,children:n}),t[0]=n,t[1]=a);let o;t[2]===i?o=t[3]:(o=i&&(0,g.jsx)(`p`,{className:`text-sm text-destructive`,children:i}),t[2]=i,t[3]=o);let s;return t[4]!==a||t[5]!==o?(s=(0,g.jsxs)(`div`,{className:`mb-6 max-w-4xl rounded-md border border-destructive bg-destructive/10 p-4`,children:[a,o]}),t[4]=a,t[5]=o,t[6]=s):s=t[6],s}export{m as n,_ as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/event-streams.js b/spinifex/services/spinifexui/frontend/dist/assets/event-streams.js index 4198859c7..aaa8cd773 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/event-streams.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/event-streams.js @@ -1 +1 @@ -import{Yn as e,Zn as t}from"./index.js";var n=class{marshaller;serializer;deserializer;serdeContext;defaultContentType;constructor({marshaller:e,serializer:t,deserializer:n,serdeContext:r,defaultContentType:i}){this.marshaller=e,this.serializer=t,this.deserializer=n,this.serdeContext=r,this.defaultContentType=i}async serializeEventStream({eventStream:e,requestSchema:t,initialRequest:n}){let r=this.marshaller,i=t.getEventStreamMember(),a=t.getMemberSchema(i),o=this.serializer,s=this.defaultContentType,c=Symbol(`initialRequestMarker`),l={async*[Symbol.asyncIterator](){if(n){let e={":event-type":{type:`string`,value:`initial-request`},":message-type":{type:`string`,value:`event`},":content-type":{type:`string`,value:s}};o.write(t,n);let r=o.flush();yield{[c]:!0,headers:e,body:r}}for await(let t of e)yield t}};return r.serialize(l,e=>{if(e[c])return{headers:e.headers,body:e.body};let t=``;for(let n in e)if(n!==`__type`){t=n;break}let{additionalHeaders:n,body:r,eventType:i,explicitPayloadContentType:o}=this.writeEventBody(t,a,e);return{headers:{":event-type":{type:`string`,value:i},":message-type":{type:`string`,value:`event`},":content-type":{type:`string`,value:o??s},...n},body:r}})}async deserializeEventStream({response:t,responseSchema:n,initialResponseContainer:r}){let i=this.marshaller,a=n.getEventStreamMember(),o=n.getMemberSchema(a).getMemberSchemas(),s=Symbol(`initialResponseMarker`),c=i.deserialize(t.body,async t=>{let r=``;for(let e in t)if(e!==`__type`){r=e;break}let i=t[r].body;if(r===`initial-response`){let e=await this.deserializer.read(n,i);return delete e[a],{[s]:!0,...e}}else if(r in o){let n=o[r];if(n.isStructSchema()){let a={},o=!1;for(let[s,c]of n.structIterator()){let{eventHeader:n,eventPayload:l}=c.getMergedTraits();if(o||=!!(n||l),l)c.isBlobSchema()?a[s]=i:c.isStringSchema()?a[s]=(this.serdeContext?.utf8Encoder??e)(i):c.isStructSchema()&&(a[s]=await this.deserializer.read(c,i));else if(n){let e=t[r].headers[s]?.value;e!=null&&(c.isNumericSchema()?e&&typeof e==`object`&&`bytes`in e?a[s]=BigInt(e.toString()):a[s]=Number(e):a[s]=e)}}if(o)return{[r]:a};if(i.byteLength===0)return{[r]:{}}}return{[r]:await this.deserializer.read(n,i)}}else return{$unknown:t}}),l=c[Symbol.asyncIterator](),u=await l.next();if(u.done)return c;if(u.value?.[s]){if(!n)throw Error(`@smithy::core/protocols - initial-response event encountered in event stream but no response schema given.`);for(let e in u.value)r[e]=u.value[e]}return{async*[Symbol.asyncIterator](){for(u?.value?.[s]||(yield u.value);;){let{done:e,value:t}=await l.next();if(e)break;yield t}}}}writeEventBody(e,n,r){let i=this.serializer,a=e,o=null,s,c=n.getSchema()[4].includes(e),l={};if(c){let t=n.getMemberSchema(e);if(t.isStructSchema()){for(let[n,i]of t.structIterator()){let{eventHeader:t,eventPayload:a}=i.getMergedTraits();if(a)o=n;else if(t){let t=r[e][n],a=`binary`;i.isNumericSchema()?a=(-2)**31<=t&&t<=2**31-1?`integer`:`long`:i.isTimestampSchema()?a=`timestamp`:i.isStringSchema()?a=`string`:i.isBooleanSchema()&&(a=`boolean`),t!=null&&(l[n]={type:a,value:t},delete r[e][n])}}if(o!==null){let n=t.getMemberSchema(o);n.isBlobSchema()?s=`application/octet-stream`:n.isStringSchema()&&(s=`text/plain`),i.write(n,r[e][o])}else i.write(t,r[e])}else if(t.isUnitSchema())i.write(t,{});else throw Error(`@smithy/core/event-streams - non-struct member not supported in event stream union.`)}else{let[t,n]=r[e];a=t,i.write(15,n)}let u=i.flush()??new Uint8Array;return{body:typeof u==`string`?(this.serdeContext?.utf8Decoder??t)(u):u,eventType:a,explicitPayloadContentType:s,additionalHeaders:l}}};export{n as EventStreamSerde}; \ No newline at end of file +import{dr as e,lr as t}from"./index.js";var n=class{marshaller;serializer;deserializer;serdeContext;defaultContentType;constructor({marshaller:e,serializer:t,deserializer:n,serdeContext:r,defaultContentType:i}){this.marshaller=e,this.serializer=t,this.deserializer=n,this.serdeContext=r,this.defaultContentType=i}async serializeEventStream({eventStream:e,requestSchema:t,initialRequest:n}){let r=this.marshaller,i=t.getEventStreamMember(),a=t.getMemberSchema(i),o=this.serializer,s=this.defaultContentType,c=Symbol(`initialRequestMarker`),l={async*[Symbol.asyncIterator](){if(n){let e={":event-type":{type:`string`,value:`initial-request`},":message-type":{type:`string`,value:`event`},":content-type":{type:`string`,value:s}};o.write(t,n);let r=o.flush();yield{[c]:!0,headers:e,body:r}}for await(let t of e)yield t}};return r.serialize(l,e=>{if(e[c])return{headers:e.headers,body:e.body};let t=``;for(let n in e)if(n!==`__type`){t=n;break}let{additionalHeaders:n,body:r,eventType:i,explicitPayloadContentType:o}=this.writeEventBody(t,a,e);return{headers:{":event-type":{type:`string`,value:i},":message-type":{type:`string`,value:`event`},":content-type":{type:`string`,value:o??s},...n},body:r}})}async deserializeEventStream({response:e,responseSchema:n,initialResponseContainer:r}){let i=this.marshaller,a=n.getEventStreamMember(),o=n.getMemberSchema(a).getMemberSchemas(),s=Symbol(`initialResponseMarker`),c=i.deserialize(e.body,async e=>{let r=``;for(let t in e)if(t!==`__type`){r=t;break}let i=e[r].body;if(r===`initial-response`){let e=await this.deserializer.read(n,i);return delete e[a],{[s]:!0,...e}}else if(r in o){let n=o[r];if(n.isStructSchema()){let a={},o=!1;for(let[s,c]of n.structIterator()){let{eventHeader:n,eventPayload:l}=c.getMergedTraits();if(o||=!!(n||l),l)c.isBlobSchema()?a[s]=i:c.isStringSchema()?a[s]=(this.serdeContext?.utf8Encoder??t)(i):c.isStructSchema()&&(a[s]=await this.deserializer.read(c,i));else if(n){let t=e[r].headers[s]?.value;t!=null&&(c.isNumericSchema()?t&&typeof t==`object`&&`bytes`in t?a[s]=BigInt(t.toString()):a[s]=Number(t):a[s]=t)}}if(o)return{[r]:a};if(i.byteLength===0)return{[r]:{}}}return{[r]:await this.deserializer.read(n,i)}}else return{$unknown:e}}),l=c[Symbol.asyncIterator](),u=await l.next();if(u.done)return c;if(u.value?.[s]){if(!n)throw Error(`@smithy::core/protocols - initial-response event encountered in event stream but no response schema given.`);for(let e in u.value)r[e]=u.value[e]}return{async*[Symbol.asyncIterator](){for(u?.value?.[s]||(yield u.value);;){let{done:e,value:t}=await l.next();if(e)break;yield t}}}}writeEventBody(t,n,r){let i=this.serializer,a=t,o=null,s,c=n.getSchema()[4].includes(t),l={};if(c){let e=n.getMemberSchema(t);if(e.isStructSchema()){for(let[n,i]of e.structIterator()){let{eventHeader:e,eventPayload:a}=i.getMergedTraits();if(a)o=n;else if(e){let e=r[t][n],a=`binary`;i.isNumericSchema()?a=(-2)**31<=e&&e<=2**31-1?`integer`:`long`:i.isTimestampSchema()?a=`timestamp`:i.isStringSchema()?a=`string`:i.isBooleanSchema()&&(a=`boolean`),e!=null&&(l[n]={type:a,value:e},delete r[t][n])}}if(o!==null){let n=e.getMemberSchema(o);n.isBlobSchema()?s=`application/octet-stream`:n.isStringSchema()&&(s=`text/plain`),i.write(n,r[t][o])}else i.write(e,r[t])}else if(e.isUnitSchema())i.write(e,{});else throw Error(`@smithy/core/event-streams - non-struct member not supported in event stream union.`)}else{let[e,n]=r[t];a=e,i.write(15,n)}let u=i.flush()??new Uint8Array;return{body:typeof u==`string`?(this.serdeContext?.utf8Decoder??e)(u):u,eventType:a,explicitPayloadContentType:s,additionalHeaders:l}}};export{n as EventStreamSerde}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/field.js b/spinifex/services/spinifexui/frontend/dist/assets/field.js index efe5c7a8c..d50c5fa6f 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/field.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/field.js @@ -1 +1 @@ -import{Oa as e,Za as t,ho as n,mo as r,so as i}from"./index.js";n();var a=i(),o=r();function s(t){let n=(0,a.c)(8),r,i;n[0]===t?(r=n[1],i=n[2]):({className:r,...i}=t,n[0]=t,n[1]=r,n[2]=i);let s;n[3]===r?s=n[4]:(s=e(`group/field-group @container/field-group flex w-full flex-col gap-4 data-[slot=checkbox-group]:gap-3 *:data-[slot=field-group]:gap-4`,r),n[3]=r,n[4]=s);let c;return n[5]!==i||n[6]!==s?(c=(0,o.jsx)(`div`,{className:s,"data-slot":`field-group`,...i}),n[5]=i,n[6]=s,n[7]=c):c=n[7],c}var c=t(`group/field flex w-full gap-2 data-[invalid=true]:text-destructive`,{variants:{orientation:{vertical:`flex-col [&>*]:w-full [&>.sr-only]:w-auto`,horizontal:`flex-row items-center has-[>[data-slot=field-content]]:items-start [&>[data-slot=field-label]]:flex-auto has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px`,responsive:`flex-col @md/field-group:flex-row @md/field-group:items-center @md/field-group:has-[>[data-slot=field-content]]:items-start [&>*]:w-full @md/field-group:[&>*]:w-auto [&>.sr-only]:w-auto @md/field-group:[&>[data-slot=field-label]]:flex-auto @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px`}},defaultVariants:{orientation:`vertical`}});function l(t){let n=(0,a.c)(11),r,i,s;n[0]===t?(r=n[1],i=n[2],s=n[3]):({className:r,orientation:s,...i}=t,n[0]=t,n[1]=r,n[2]=i,n[3]=s);let l=s===void 0?`vertical`:s,u;n[4]!==r||n[5]!==l?(u=e(c({orientation:l}),r),n[4]=r,n[5]=l,n[6]=u):u=n[6];let d;return n[7]!==l||n[8]!==i||n[9]!==u?(d=(0,o.jsx)(`div`,{className:u,"data-orientation":l,"data-slot":`field`,role:`group`,...i}),n[7]=l,n[8]=i,n[9]=u,n[10]=d):d=n[10],d}function u(t){let n=(0,a.c)(8),r,i;n[0]===t?(r=n[1],i=n[2]):({className:r,...i}=t,n[0]=t,n[1]=r,n[2]=i);let s;n[3]===r?s=n[4]:(s=e(`flex w-fit items-center gap-2 text-xs/relaxed leading-snug font-medium group-data-[disabled=true]/field:opacity-50`,r),n[3]=r,n[4]=s);let c;return n[5]!==i||n[6]!==s?(c=(0,o.jsx)(`div`,{className:s,"data-slot":`field-label`,...i}),n[5]=i,n[6]=s,n[7]=c):c=n[7],c}function d(t){let n=(0,a.c)(8),r,i;n[0]===t?(r=n[1],i=n[2]):({className:r,...i}=t,n[0]=t,n[1]=r,n[2]=i);let s;n[3]===r?s=n[4]:(s=e(`text-left text-xs/relaxed leading-normal font-normal text-muted-foreground group-has-data-[orientation=horizontal]/field:text-balance [[data-variant=legend]+&]:-mt-1.5`,`last:mt-0 nth-last-2:-mt-1`,`[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary`,r),n[3]=r,n[4]=s);let c;return n[5]!==i||n[6]!==s?(c=(0,o.jsx)(`p`,{className:s,"data-slot":`field-description`,...i}),n[5]=i,n[6]=s,n[7]=c):c=n[7],c}function f(t){let n=(0,a.c)(15),r,i,s,c;n[0]===t?(r=n[1],i=n[2],s=n[3],c=n[4]):({className:i,children:r,errors:s,...c}=t,n[0]=t,n[1]=r,n[2]=i,n[3]=s,n[4]=c);let l;bb0:{if(r){l=r;break bb0}if(!s?.length){l=null;break bb0}let e;n[5]===s?e=n[6]:(e=[...new Map(s.map(m)).values()],n[5]=s,n[6]=e);let t=e;if(t?.length===1){l=t[0]?.message;break bb0}let i;n[7]===t?i=n[8]:(i=(0,o.jsx)(`ul`,{className:`ml-4 flex list-disc flex-col gap-1`,children:t.map(p)}),n[7]=t,n[8]=i),l=i}let u=l;if(!u)return null;let d;n[9]===i?d=n[10]:(d=e(`text-xs/relaxed font-normal text-destructive`,i),n[9]=i,n[10]=d);let f;return n[11]!==u||n[12]!==c||n[13]!==d?(f=(0,o.jsx)(`div`,{className:d,"data-slot":`field-error`,role:`alert`,...c,children:u}),n[11]=u,n[12]=c,n[13]=d,n[14]=f):f=n[14],f}function p(e){return e?.message&&(0,o.jsx)(`li`,{children:e.message},e.message)}function m(e){return[e?.message,e]}export{u as a,s as i,d as n,f as r,l as t}; \ No newline at end of file +import{Ha as e,Oo as t,do as n,ko as r,xo as i}from"./index.js";r();var a=i(),o=t();function s(t){let n=(0,a.c)(8),r,i;n[0]===t?(r=n[1],i=n[2]):({className:r,...i}=t,n[0]=t,n[1]=r,n[2]=i);let s;n[3]===r?s=n[4]:(s=e(`group/field-group @container/field-group flex w-full flex-col gap-4 data-[slot=checkbox-group]:gap-3 *:data-[slot=field-group]:gap-4`,r),n[3]=r,n[4]=s);let c;return n[5]!==i||n[6]!==s?(c=(0,o.jsx)(`div`,{className:s,"data-slot":`field-group`,...i}),n[5]=i,n[6]=s,n[7]=c):c=n[7],c}var c=n(`group/field flex w-full gap-2 data-[invalid=true]:text-destructive`,{variants:{orientation:{vertical:`flex-col [&>*]:w-full [&>.sr-only]:w-auto`,horizontal:`flex-row items-center has-[>[data-slot=field-content]]:items-start [&>[data-slot=field-label]]:flex-auto has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px`,responsive:`flex-col @md/field-group:flex-row @md/field-group:items-center @md/field-group:has-[>[data-slot=field-content]]:items-start [&>*]:w-full @md/field-group:[&>*]:w-auto [&>.sr-only]:w-auto @md/field-group:[&>[data-slot=field-label]]:flex-auto @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px`}},defaultVariants:{orientation:`vertical`}});function l(t){let n=(0,a.c)(11),r,i,s;n[0]===t?(r=n[1],i=n[2],s=n[3]):({className:r,orientation:s,...i}=t,n[0]=t,n[1]=r,n[2]=i,n[3]=s);let l=s===void 0?`vertical`:s,u;n[4]!==r||n[5]!==l?(u=e(c({orientation:l}),r),n[4]=r,n[5]=l,n[6]=u):u=n[6];let d;return n[7]!==l||n[8]!==i||n[9]!==u?(d=(0,o.jsx)(`div`,{className:u,"data-orientation":l,"data-slot":`field`,role:`group`,...i}),n[7]=l,n[8]=i,n[9]=u,n[10]=d):d=n[10],d}function u(t){let n=(0,a.c)(8),r,i;n[0]===t?(r=n[1],i=n[2]):({className:r,...i}=t,n[0]=t,n[1]=r,n[2]=i);let s;n[3]===r?s=n[4]:(s=e(`flex w-fit items-center gap-2 text-xs/relaxed leading-snug font-medium group-data-[disabled=true]/field:opacity-50`,r),n[3]=r,n[4]=s);let c;return n[5]!==i||n[6]!==s?(c=(0,o.jsx)(`div`,{className:s,"data-slot":`field-label`,...i}),n[5]=i,n[6]=s,n[7]=c):c=n[7],c}function d(t){let n=(0,a.c)(8),r,i;n[0]===t?(r=n[1],i=n[2]):({className:r,...i}=t,n[0]=t,n[1]=r,n[2]=i);let s;n[3]===r?s=n[4]:(s=e(`text-left text-xs/relaxed leading-normal font-normal text-muted-foreground group-has-data-[orientation=horizontal]/field:text-balance [[data-variant=legend]+&]:-mt-1.5`,`last:mt-0 nth-last-2:-mt-1`,`[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary`,r),n[3]=r,n[4]=s);let c;return n[5]!==i||n[6]!==s?(c=(0,o.jsx)(`p`,{className:s,"data-slot":`field-description`,...i}),n[5]=i,n[6]=s,n[7]=c):c=n[7],c}function f(t){let n=(0,a.c)(15),r,i,s,c;n[0]===t?(r=n[1],i=n[2],s=n[3],c=n[4]):({className:i,children:r,errors:s,...c}=t,n[0]=t,n[1]=r,n[2]=i,n[3]=s,n[4]=c);let l;bb0:{if(r){l=r;break bb0}if(!s?.length){l=null;break bb0}let e;n[5]===s?e=n[6]:(e=[...new Map(s.map(m)).values()],n[5]=s,n[6]=e);let t=e;if(t?.length===1){l=t[0]?.message;break bb0}let i;n[7]===t?i=n[8]:(i=(0,o.jsx)(`ul`,{className:`ml-4 flex list-disc flex-col gap-1`,children:t.map(p)}),n[7]=t,n[8]=i),l=i}let u=l;if(!u)return null;let d;n[9]===i?d=n[10]:(d=e(`text-xs/relaxed font-normal text-destructive`,i),n[9]=i,n[10]=d);let f;return n[11]!==u||n[12]!==c||n[13]!==d?(f=(0,o.jsx)(`div`,{className:d,"data-slot":`field-error`,role:`alert`,...c,children:u}),n[11]=u,n[12]=c,n[13]=d,n[14]=f):f=n[14],f}function p(e){return e?.message&&(0,o.jsx)(`li`,{children:e.message},e.message)}function m(e){return[e?.message,e]}export{u as a,s as i,d as n,f as r,l as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/form-actions.js b/spinifex/services/spinifexui/frontend/dist/assets/form-actions.js index 03c08607a..21043b20f 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/form-actions.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/form-actions.js @@ -1 +1 @@ -import{Ta as e,mo as t,so as n}from"./index.js";var r=n(),i=t();function a(t){let n=(0,r.c)(9),{isSubmitting:a,isPending:o,onCancel:s,submitLabel:c,pendingLabel:l}=t,u=a||o,d;n[0]!==u||n[1]!==s?(d=(0,i.jsx)(e,{disabled:u,onClick:s,type:`button`,variant:`outline`,children:`Cancel`}),n[0]=u,n[1]=s,n[2]=d):d=n[2];let f=u?l:c,p;n[3]!==u||n[4]!==f?(p=(0,i.jsx)(e,{disabled:u,type:`submit`,children:f}),n[3]=u,n[4]=f,n[5]=p):p=n[5];let m;return n[6]!==d||n[7]!==p?(m=(0,i.jsxs)(`div`,{className:`flex gap-2`,children:[d,p]}),n[6]=d,n[7]=p,n[8]=m):m=n[8],m}export{a as t}; \ No newline at end of file +import{Oo as e,xo as t,za as n}from"./index.js";var r=t(),i=e();function a(e){let t=(0,r.c)(9),{isSubmitting:a,isPending:o,onCancel:s,submitLabel:c,pendingLabel:l}=e,u=a||o,d;t[0]!==u||t[1]!==s?(d=(0,i.jsx)(n,{disabled:u,onClick:s,type:`button`,variant:`outline`,children:`Cancel`}),t[0]=u,t[1]=s,t[2]=d):d=t[2];let f=u?l:c,p;t[3]!==u||t[4]!==f?(p=(0,i.jsx)(n,{disabled:u,type:`submit`,children:f}),t[3]=u,t[4]=f,t[5]=p):p=t[5];let m;return t[6]!==d||t[7]!==p?(m=(0,i.jsxs)(`div`,{className:`flex gap-2`,children:[d,p]}),t[6]=d,t[7]=p,t[8]=m):m=t[8],m}export{a as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/iam.js b/spinifex/services/spinifexui/frontend/dist/assets/iam.js index 457dc437e..0d86af3db 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/iam.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/iam.js @@ -1 +1 @@ -import{n as e}from"./error-banner.js";import{At as t,Dt as n,Et as r,Fn as i,In as a,Mt as o,Nt as s,Ot as c,Pt as l,Tt as u,jt as d,kt as f,po as p,so as m,st as h}from"./index.js";var g=class extends i.classBuilder().ep(l).m(function(e,t,n,r){return[a(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`AttachUserPolicy`,{}).n(`IAMClient`,`AttachUserPolicyCommand`).sc(u).build(){},_=class extends i.classBuilder().ep(l).m(function(e,t,n,r){return[a(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`CreateAccessKey`,{}).n(`IAMClient`,`CreateAccessKeyCommand`).sc(r).build(){},v=class extends i.classBuilder().ep(l).m(function(e,t,n,r){return[a(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`CreatePolicy`,{}).n(`IAMClient`,`CreatePolicyCommand`).sc(n).build(){},y=class extends i.classBuilder().ep(l).m(function(e,t,n,r){return[a(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`CreateUser`,{}).n(`IAMClient`,`CreateUserCommand`).sc(c).build(){},b=class extends i.classBuilder().ep(l).m(function(e,t,n,r){return[a(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`DeleteAccessKey`,{}).n(`IAMClient`,`DeleteAccessKeyCommand`).sc(f).build(){},x=class extends i.classBuilder().ep(l).m(function(e,t,n,r){return[a(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`DeletePolicy`,{}).n(`IAMClient`,`DeletePolicyCommand`).sc(t).build(){},S=class extends i.classBuilder().ep(l).m(function(e,t,n,r){return[a(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`DeleteUser`,{}).n(`IAMClient`,`DeleteUserCommand`).sc(d).build(){},C=class extends i.classBuilder().ep(l).m(function(e,t,n,r){return[a(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`DetachUserPolicy`,{}).n(`IAMClient`,`DetachUserPolicyCommand`).sc(o).build(){},w=class extends i.classBuilder().ep(l).m(function(e,t,n,r){return[a(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`UpdateAccessKey`,{}).n(`IAMClient`,`UpdateAccessKeyCommand`).sc(s).build(){},T=m();function E(){let t=(0,T.c)(2),n=p(),r;return t[0]===n?r=t[1]:(r={mutationFn:D,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`users`]})}},t[0]=n,t[1]=r),e(r)}async function D(e){let t=new y({UserName:e.userName,Path:e.path||void 0});return await h().send(t)}function O(){let t=(0,T.c)(2),n=p(),r;return t[0]===n?r=t[1]:(r={mutationFn:k,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`users`]})}},t[0]=n,t[1]=r),e(r)}async function k(e){let t=new S({UserName:e});return await h().send(t)}function A(){let t=(0,T.c)(2),n=p(),r;return t[0]===n?r=t[1]:(r={mutationFn:j,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`access-keys`]})}},t[0]=n,t[1]=r),e(r)}async function j(e){let t=new _({UserName:e});return await h().send(t)}function M(){let t=(0,T.c)(2),n=p(),r;return t[0]===n?r=t[1]:(r={mutationFn:N,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`access-keys`]})}},t[0]=n,t[1]=r),e(r)}async function N(e){let{userName:t,accessKeyId:n}=e,r=new b({UserName:t,AccessKeyId:n});return await h().send(r)}function P(){let t=(0,T.c)(2),n=p(),r;return t[0]===n?r=t[1]:(r={mutationFn:F,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`access-keys`]})}},t[0]=n,t[1]=r),e(r)}async function F(e){let{userName:t,accessKeyId:n,status:r}=e,i=new w({UserName:t,AccessKeyId:n,Status:r});return await h().send(i)}function I(){let t=(0,T.c)(2),n=p(),r;return t[0]===n?r=t[1]:(r={mutationFn:L,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`policies`]})}},t[0]=n,t[1]=r),e(r)}async function L(e){let t=new v({PolicyName:e.policyName,Description:e.description||void 0,PolicyDocument:e.policyDocument});return await h().send(t)}function R(){let t=(0,T.c)(2),n=p(),r;return t[0]===n?r=t[1]:(r={mutationFn:z,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`policies`]})}},t[0]=n,t[1]=r),e(r)}async function z(e){let t=new x({PolicyArn:e});return await h().send(t)}function B(){let t=(0,T.c)(2),n=p(),r;return t[0]===n?r=t[1]:(r={mutationFn:V,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`attached-user-policies`]})}},t[0]=n,t[1]=r),e(r)}async function V(e){let{userName:t,policyArn:n}=e,r=new g({UserName:t,PolicyArn:n});return await h().send(r)}function H(){let t=(0,T.c)(2),n=p(),r;return t[0]===n?r=t[1]:(r={mutationFn:U,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`attached-user-policies`]})}},t[0]=n,t[1]=r),e(r)}async function U(e){let{userName:t,policyArn:n}=e,r=new C({UserName:t,PolicyArn:n});return await h().send(r)}export{M as a,H as c,E as i,P as l,A as n,R as o,I as r,O as s,B as t}; \ No newline at end of file +import{n as e}from"./error-banner.js";import{At as t,Bn as n,Do as r,Dt as i,Ft as a,It as o,Mt as s,Nt as c,Ot as l,Pt as u,Vn as d,jt as f,kt as p,lt as m,xo as h}from"./index.js";var g=class extends n.classBuilder().ep(o).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`AttachUserPolicy`,{}).n(`IAMClient`,`AttachUserPolicyCommand`).sc(i).build(){},_=class extends n.classBuilder().ep(o).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`CreateAccessKey`,{}).n(`IAMClient`,`CreateAccessKeyCommand`).sc(l).build(){},v=class extends n.classBuilder().ep(o).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`CreatePolicy`,{}).n(`IAMClient`,`CreatePolicyCommand`).sc(p).build(){},y=class extends n.classBuilder().ep(o).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`CreateUser`,{}).n(`IAMClient`,`CreateUserCommand`).sc(t).build(){},b=class extends n.classBuilder().ep(o).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`DeleteAccessKey`,{}).n(`IAMClient`,`DeleteAccessKeyCommand`).sc(f).build(){},x=class extends n.classBuilder().ep(o).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`DeletePolicy`,{}).n(`IAMClient`,`DeletePolicyCommand`).sc(s).build(){},S=class extends n.classBuilder().ep(o).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`DeleteUser`,{}).n(`IAMClient`,`DeleteUserCommand`).sc(c).build(){},C=class extends n.classBuilder().ep(o).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`DetachUserPolicy`,{}).n(`IAMClient`,`DetachUserPolicyCommand`).sc(u).build(){},w=class extends n.classBuilder().ep(o).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`UpdateAccessKey`,{}).n(`IAMClient`,`UpdateAccessKeyCommand`).sc(a).build(){},T=h();function E(){let t=(0,T.c)(2),n=r(),i;return t[0]===n?i=t[1]:(i={mutationFn:D,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`users`]})}},t[0]=n,t[1]=i),e(i)}async function D(e){let t=new y({UserName:e.userName,Path:e.path||void 0});return await m().send(t)}function O(){let t=(0,T.c)(2),n=r(),i;return t[0]===n?i=t[1]:(i={mutationFn:k,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`users`]})}},t[0]=n,t[1]=i),e(i)}async function k(e){let t=new S({UserName:e});return await m().send(t)}function A(){let t=(0,T.c)(2),n=r(),i;return t[0]===n?i=t[1]:(i={mutationFn:j,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`access-keys`]})}},t[0]=n,t[1]=i),e(i)}async function j(e){let t=new _({UserName:e});return await m().send(t)}function M(){let t=(0,T.c)(2),n=r(),i;return t[0]===n?i=t[1]:(i={mutationFn:N,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`access-keys`]})}},t[0]=n,t[1]=i),e(i)}async function N(e){let{userName:t,accessKeyId:n}=e,r=new b({UserName:t,AccessKeyId:n});return await m().send(r)}function P(){let t=(0,T.c)(2),n=r(),i;return t[0]===n?i=t[1]:(i={mutationFn:F,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`access-keys`]})}},t[0]=n,t[1]=i),e(i)}async function F(e){let{userName:t,accessKeyId:n,status:r}=e,i=new w({UserName:t,AccessKeyId:n,Status:r});return await m().send(i)}function I(){let t=(0,T.c)(2),n=r(),i;return t[0]===n?i=t[1]:(i={mutationFn:L,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`policies`]})}},t[0]=n,t[1]=i),e(i)}async function L(e){let t=new v({PolicyName:e.policyName,Description:e.description||void 0,PolicyDocument:e.policyDocument});return await m().send(t)}function R(){let t=(0,T.c)(2),n=r(),i;return t[0]===n?i=t[1]:(i={mutationFn:z,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`policies`]})}},t[0]=n,t[1]=i),e(i)}async function z(e){let t=new x({PolicyArn:e});return await m().send(t)}function B(){let t=(0,T.c)(2),n=r(),i;return t[0]===n?i=t[1]:(i={mutationFn:V,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`attached-user-policies`]})}},t[0]=n,t[1]=i),e(i)}async function V(e){let{userName:t,policyArn:n}=e,r=new g({UserName:t,PolicyArn:n});return await m().send(r)}function H(){let t=(0,T.c)(2),n=r(),i;return t[0]===n?i=t[1]:(i={mutationFn:U,onSuccess:()=>{n.invalidateQueries({queryKey:[`iam`,`attached-user-policies`]})}},t[0]=n,t[1]=i),e(i)}async function U(e){let{userName:t,policyArn:n}=e,r=new C({UserName:t,PolicyArn:n});return await m().send(r)}export{M as a,H as c,E as i,P as l,A as n,R as o,I as r,O as s,B as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/iam2.js b/spinifex/services/spinifexui/frontend/dist/assets/iam2.js index a724557c4..9c1ae9891 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/iam2.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/iam2.js @@ -1 +1 @@ -import{gr as e,vr as t}from"./index.js";var n=e({userName:t().min(1,`User name is required`).max(64,`User name must be 64 characters or less`).regex(/^[\w+=,.@-]+$/,`User name contains invalid characters`),path:t().optional()}),r=e({policyName:t().min(1,`Policy name is required`).max(128,`Policy name must be 128 characters or less`).regex(/^[\w+=,.@-]+$/,`Policy name contains invalid characters`),description:t().optional(),policyDocument:t().min(1,`Policy document is required`).refine(e=>{try{return JSON.parse(e),!0}catch{return!1}},{message:`Policy document must be valid JSON`})});export{n,r as t}; \ No newline at end of file +import{Ar as e,Mr as t}from"./index.js";var n=e({userName:t().min(1,`User name is required`).max(64,`User name must be 64 characters or less`).regex(/^[\w+=,.@-]+$/,`User name contains invalid characters`),path:t().optional()}),r=e({policyName:t().min(1,`Policy name is required`).max(128,`Policy name must be 128 characters or less`).regex(/^[\w+=,.@-]+$/,`Policy name contains invalid characters`),description:t().optional(),policyDocument:t().min(1,`Policy document is required`).refine(e=>{try{return JSON.parse(e),!0}catch{return!1}},{message:`Policy document must be valid JSON`})});export{n,r as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/import-key-pair.js b/spinifex/services/spinifexui/frontend/dist/assets/import-key-pair.js index a75a428fb..1658432c9 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/import-key-pair.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/import-key-pair.js @@ -1,3 +1,3 @@ -import{t as e}from"./error-banner.js";import{t}from"./back-link.js";import{t as n}from"./cli-command-panel.js";import{w as r}from"./ec2.js";import{Ti as i,mo as a,so as o,uo as s}from"./index.js";import{t as c}from"./page-heading.js";import{a as l,r as u,t as d}from"./field.js";import{t as f}from"./textarea.js";import{i as p,t as m}from"./zod.js";import{u as h}from"./ec22.js";import{t as g}from"./form-actions.js";var _=o(),v=a();function y(){let a=(0,_.c)(53),o=s(),y=r(),x;a[0]===Symbol.for(`react.memo_cache_sentinel`)?(x={resolver:m(h)},a[0]=x):x=a[0];let{handleSubmit:S,register:C,watch:w,formState:T}=p(x),{errors:E,isSubmitting:D}=T,O;a[1]!==y||a[2]!==o?(O=async e=>{await y.mutateAsync(e),o({to:`/ec2/describe-key-pairs`})},a[1]=y,a[2]=o,a[3]=O):O=a[3];let k=O,A,j;a[4]===Symbol.for(`react.memo_cache_sentinel`)?(A=(0,v.jsx)(t,{to:`/ec2/describe-key-pairs`,children:`Back to key pairs`}),j=(0,v.jsx)(c,{title:`Import Key Pair`}),a[4]=A,a[5]=j):(A=a[4],j=a[5]);let M;a[6]===y.error?M=a[7]:(M=y.error&&(0,v.jsx)(e,{error:y.error,msg:`Failed to import key pair`}),a[6]=y.error,a[7]=M);let N;a[8]!==S||a[9]!==k?(N=S(k),a[8]=S,a[9]=k,a[10]=N):N=a[10];let P;a[11]===Symbol.for(`react.memo_cache_sentinel`)?(P=(0,v.jsx)(l,{children:(0,v.jsx)(`label`,{htmlFor:`keyName`,children:`Key Pair Name`})}),a[11]=P):P=a[11];let F=!!E.keyName,I;a[12]===C?I=a[13]:(I=C(`keyName`),a[12]=C,a[13]=I);let L;a[14]!==F||a[15]!==I?(L=(0,v.jsx)(i,{"aria-invalid":F,id:`keyName`,placeholder:`my-key-pair…`,...I}),a[14]=F,a[15]=I,a[16]=L):L=a[16];let R;a[17]===E.keyName?R=a[18]:(R=(0,v.jsx)(u,{errors:[E.keyName]}),a[17]=E.keyName,a[18]=R);let z;a[19]!==L||a[20]!==R?(z=(0,v.jsxs)(d,{children:[P,L,R]}),a[19]=L,a[20]=R,a[21]=z):z=a[21];let B,V;a[22]===Symbol.for(`react.memo_cache_sentinel`)?(B=(0,v.jsx)(l,{children:(0,v.jsx)(`label`,{htmlFor:`publicKeyMaterial`,children:`Public Key`})}),V=(0,v.jsx)(`p`,{className:`text-xs text-muted-foreground`,id:`publicKey-description`,children:`Paste your OpenSSH public key (e.g. the contents of id_rsa.pub)`}),a[22]=B,a[23]=V):(B=a[22],V=a[23]);let H=!!E.publicKeyMaterial,U;a[24]===C?U=a[25]:(U=C(`publicKeyMaterial`),a[24]=C,a[25]=U);let W;a[26]!==H||a[27]!==U?(W=(0,v.jsx)(f,{"aria-invalid":H,id:`publicKeyMaterial`,placeholder:`ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC…`,rows:8,...U}),a[26]=H,a[27]=U,a[28]=W):W=a[28];let G;a[29]===E.publicKeyMaterial?G=a[30]:(G=(0,v.jsx)(u,{errors:[E.publicKeyMaterial]}),a[29]=E.publicKeyMaterial,a[30]=G);let K;a[31]!==W||a[32]!==G?(K=(0,v.jsxs)(d,{children:[B,V,W,G]}),a[31]=W,a[32]=G,a[33]=K):K=a[33];let q;a[34]===w?q=a[35]:(q=b(w),a[34]=w,a[35]=q);let J;a[36]===q?J=a[37]:(J=(0,v.jsx)(n,{commands:q}),a[36]=q,a[37]=J);let Y;a[38]===o?Y=a[39]:(Y=async()=>await o({to:`/ec2/describe-key-pairs`}),a[38]=o,a[39]=Y);let X;a[40]!==y.isPending||a[41]!==D||a[42]!==Y?(X=(0,v.jsx)(g,{isPending:y.isPending,isSubmitting:D,onCancel:Y,pendingLabel:`Importing…`,submitLabel:`Import Key Pair`}),a[40]=y.isPending,a[41]=D,a[42]=Y,a[43]=X):X=a[43];let Z;a[44]!==z||a[45]!==K||a[46]!==J||a[47]!==X||a[48]!==N?(Z=(0,v.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:N,children:[z,K,J,X]}),a[44]=z,a[45]=K,a[46]=J,a[47]=X,a[48]=N,a[49]=Z):Z=a[49];let Q;return a[50]!==Z||a[51]!==M?(Q=(0,v.jsxs)(v.Fragment,{children:[A,j,M,Z]}),a[50]=Z,a[51]=M,a[52]=Q):Q=a[52],Q}function b(e){let t=e(`keyName`);return[{label:`Import Key Pair`,parts:[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 import-key-pair`},{type:`flag`,value:` \\ +import{t as e}from"./error-banner.js";import{t}from"./back-link.js";import{t as ee}from"./cli-command-panel.js";import{w as n}from"./ec2.js";import{Oo as r,wo as te,xo as i,zi as ne}from"./index.js";import{t as a}from"./page-heading.js";import{a as o,r as s,t as c}from"./field.js";import{t as l}from"./textarea.js";import{a as u,i as d,t as f}from"./zod.js";import{u as p}from"./ec22.js";import{t as m}from"./form-actions.js";var h=i(),g=r();function _(){let r=(0,h.c)(57),i=te(),_=n(),v;r[0]===Symbol.for(`react.memo_cache_sentinel`)?(v={resolver:f(p)},r[0]=v):v=r[0];let{handleSubmit:y,register:b,control:x,formState:S}=d(v),{errors:C,isSubmitting:w}=S,T;r[1]===x?T=r[2]:(T={control:x},r[1]=x,r[2]=T);let E=u(T),D;r[3]===E?D=r[4]:(D=e=>e?E[e]:void 0,r[3]=E,r[4]=D);let O=D,k;r[5]!==_||r[6]!==i?(k=async e=>{await _.mutateAsync(e),i({to:`/ec2/describe-key-pairs`})},r[5]=_,r[6]=i,r[7]=k):k=r[7];let A=k,j,M;r[8]===Symbol.for(`react.memo_cache_sentinel`)?(j=(0,g.jsx)(t,{to:`/ec2/describe-key-pairs`,children:`Back to key pairs`}),M=(0,g.jsx)(a,{title:`Import Key Pair`}),r[8]=j,r[9]=M):(j=r[8],M=r[9]);let N;r[10]===_.error?N=r[11]:(N=_.error&&(0,g.jsx)(e,{error:_.error,msg:`Failed to import key pair`}),r[10]=_.error,r[11]=N);let P;r[12]!==y||r[13]!==A?(P=y(A),r[12]=y,r[13]=A,r[14]=P):P=r[14];let F;r[15]===Symbol.for(`react.memo_cache_sentinel`)?(F=(0,g.jsx)(o,{children:(0,g.jsx)(`label`,{htmlFor:`keyName`,children:`Key Pair Name`})}),r[15]=F):F=r[15];let I=!!C.keyName,L;r[16]===b?L=r[17]:(L=b(`keyName`),r[16]=b,r[17]=L);let R;r[18]!==I||r[19]!==L?(R=(0,g.jsx)(ne,{"aria-invalid":I,id:`keyName`,placeholder:`my-key-pair…`,...L}),r[18]=I,r[19]=L,r[20]=R):R=r[20];let z;r[21]===C.keyName?z=r[22]:(z=(0,g.jsx)(s,{errors:[C.keyName]}),r[21]=C.keyName,r[22]=z);let B;r[23]!==R||r[24]!==z?(B=(0,g.jsxs)(c,{children:[F,R,z]}),r[23]=R,r[24]=z,r[25]=B):B=r[25];let V,H;r[26]===Symbol.for(`react.memo_cache_sentinel`)?(V=(0,g.jsx)(o,{children:(0,g.jsx)(`label`,{htmlFor:`publicKeyMaterial`,children:`Public Key`})}),H=(0,g.jsx)(`p`,{className:`text-xs text-muted-foreground`,id:`publicKey-description`,children:`Paste your OpenSSH public key (e.g. the contents of id_rsa.pub)`}),r[26]=V,r[27]=H):(V=r[26],H=r[27]);let U=!!C.publicKeyMaterial,W;r[28]===b?W=r[29]:(W=b(`publicKeyMaterial`),r[28]=b,r[29]=W);let G;r[30]!==U||r[31]!==W?(G=(0,g.jsx)(l,{"aria-invalid":U,id:`publicKeyMaterial`,placeholder:`ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC…`,rows:8,...W}),r[30]=U,r[31]=W,r[32]=G):G=r[32];let K;r[33]===C.publicKeyMaterial?K=r[34]:(K=(0,g.jsx)(s,{errors:[C.publicKeyMaterial]}),r[33]=C.publicKeyMaterial,r[34]=K);let q;r[35]!==G||r[36]!==K?(q=(0,g.jsxs)(c,{children:[V,H,G,K]}),r[35]=G,r[36]=K,r[37]=q):q=r[37];let J;r[38]===O?J=r[39]:(J=re(O),r[38]=O,r[39]=J);let Y;r[40]===J?Y=r[41]:(Y=(0,g.jsx)(ee,{commands:J}),r[40]=J,r[41]=Y);let X;r[42]===i?X=r[43]:(X=async()=>await i({to:`/ec2/describe-key-pairs`}),r[42]=i,r[43]=X);let Z;r[44]!==_.isPending||r[45]!==w||r[46]!==X?(Z=(0,g.jsx)(m,{isPending:_.isPending,isSubmitting:w,onCancel:X,pendingLabel:`Importing…`,submitLabel:`Import Key Pair`}),r[44]=_.isPending,r[45]=w,r[46]=X,r[47]=Z):Z=r[47];let Q;r[48]!==B||r[49]!==q||r[50]!==Y||r[51]!==Z||r[52]!==P?(Q=(0,g.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:P,children:[B,q,Y,Z]}),r[48]=B,r[49]=q,r[50]=Y,r[51]=Z,r[52]=P,r[53]=Q):Q=r[53];let $;return r[54]!==Q||r[55]!==N?($=(0,g.jsxs)(g.Fragment,{children:[j,M,N,Q]}),r[54]=Q,r[55]=N,r[56]=$):$=r[56],$}function re(e){let t=e(`keyName`);return[{label:`Import Key Pair`,parts:[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 import-key-pair`},{type:`flag`,value:` \\ --key-name`},{type:`value`,value:` ${(typeof t==`string`?t:``)||``}`},{type:`flag`,value:` \\ - --public-key-material`},{type:`value`,value:` fileb://path/to/key.pub`}]}]}export{y as component}; \ No newline at end of file + --public-key-material`},{type:`value`,value:` fileb://path/to/key.pub`}]}]}export{_ as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/index.browser.js b/spinifex/services/spinifexui/frontend/dist/assets/index.browser.js new file mode 100644 index 000000000..5c76576ef --- /dev/null +++ b/spinifex/services/spinifexui/frontend/dist/assets/index.browser.js @@ -0,0 +1 @@ +import{er as e,tr as t}from"./index.js";var n=class{marshaller;serializer;deserializer;serdeContext;defaultContentType;constructor({marshaller:e,serializer:t,deserializer:n,serdeContext:r,defaultContentType:i}){this.marshaller=e,this.serializer=t,this.deserializer=n,this.serdeContext=r,this.defaultContentType=i}async serializeEventStream({eventStream:e,requestSchema:t,initialRequest:n}){let r=this.marshaller,i=t.getEventStreamMember(),a=t.getMemberSchema(i),o=this.serializer,s=this.defaultContentType,c=Symbol(`initialRequestMarker`),l={async*[Symbol.asyncIterator](){if(n){let e={":event-type":{type:`string`,value:`initial-request`},":message-type":{type:`string`,value:`event`},":content-type":{type:`string`,value:s}};o.write(t,n);let r=o.flush();yield{[c]:!0,headers:e,body:r}}for await(let t of e)yield t}};return r.serialize(l,e=>{if(e[c])return{headers:e.headers,body:e.body};let t=``;for(let n in e)if(n!==`__type`){t=n;break}let{additionalHeaders:n,body:r,eventType:i,explicitPayloadContentType:o}=this.writeEventBody(t,a,e);return{headers:{":event-type":{type:`string`,value:i},":message-type":{type:`string`,value:`event`},":content-type":{type:`string`,value:o??s},...n},body:r}})}async deserializeEventStream({response:t,responseSchema:n,initialResponseContainer:r}){let i=this.marshaller,a=n.getEventStreamMember(),o=n.getMemberSchema(a).getMemberSchemas(),s=Symbol(`initialResponseMarker`),c=i.deserialize(t.body,async t=>{let r=``;for(let e in t)if(e!==`__type`){r=e;break}let i=t[r].body;if(r===`initial-response`){let e=await this.deserializer.read(n,i);return delete e[a],{[s]:!0,...e}}else if(r in o){let n=o[r];if(n.isStructSchema()){let a={},o=!1;for(let[s,c]of n.structIterator()){let{eventHeader:n,eventPayload:l}=c.getMergedTraits();if(o||=!!(n||l),l)c.isBlobSchema()?a[s]=i:c.isStringSchema()?a[s]=(this.serdeContext?.utf8Encoder??e)(i):c.isStructSchema()&&(a[s]=await this.deserializer.read(c,i));else if(n){let e=t[r].headers[s]?.value;e!=null&&(c.isNumericSchema()?e&&typeof e==`object`&&`bytes`in e?a[s]=BigInt(e.toString()):a[s]=Number(e):a[s]=e)}}if(o)return{[r]:a};if(i.byteLength===0)return{[r]:{}}}return{[r]:await this.deserializer.read(n,i)}}else return{$unknown:t}}),l=c[Symbol.asyncIterator](),u=await l.next();if(u.done)return c;if(u.value?.[s]){if(!n)throw Error(`@smithy::core/protocols - initial-response event encountered in event stream but no response schema given.`);for(let e in u.value)r[e]=u.value[e]}return{async*[Symbol.asyncIterator](){for(u?.value?.[s]||(yield u.value);;){let{done:e,value:t}=await l.next();if(e)break;yield t}}}}writeEventBody(e,n,r){let i=this.serializer,a=e,o=null,s,c=n.getSchema()[4].includes(e),l={};if(c){let t=n.getMemberSchema(e);if(t.isStructSchema()){for(let[n,i]of t.structIterator()){let{eventHeader:t,eventPayload:a}=i.getMergedTraits();if(a)o=n;else if(t){let t=r[e][n],a=`binary`;i.isNumericSchema()?a=(-2)**31<=t&&t<=2**31-1?`integer`:`long`:i.isTimestampSchema()?a=`timestamp`:i.isStringSchema()?a=`string`:i.isBooleanSchema()&&(a=`boolean`),t!=null&&(l[n]={type:a,value:t},delete r[e][n])}}if(o!==null){let n=t.getMemberSchema(o);n.isBlobSchema()?s=`application/octet-stream`:n.isStringSchema()&&(s=`text/plain`),i.write(n,r[e][o])}else i.write(t,r[e])}else if(t.isUnitSchema())i.write(t,{});else throw Error(`@smithy/core/event-streams - non-struct member not supported in event stream union.`)}else{let[t,n]=r[e];a=t,i.write(15,n)}let u=i.flush()??new Uint8Array;return{body:typeof u==`string`?(this.serdeContext?.utf8Decoder??t)(u):u,eventType:a,explicitPayloadContentType:s,additionalHeaders:l}}};export{n as EventStreamSerde}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/index.css b/spinifex/services/spinifexui/frontend/dist/assets/index.css index da0b8c632..adf53fde3 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/index.css +++ b/spinifex/services/spinifexui/frontend/dist/assets/index.css @@ -1,2 +1,2 @@ /*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-pan-x:initial;--tw-pan-y:initial;--tw-pinch-zoom:initial;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-divide-x-reverse:0;--tw-border-style:solid;--tw-divide-y-reverse:0;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-content:""}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-100:#ffe2e2;--color-red-800:#9f0712;--color-red-900:#82181a;--color-amber-500:#f99c00;--color-yellow-100:#fef9c2;--color-yellow-800:#874b00;--color-yellow-900:#733e0a;--color-green-100:#dcfce7;--color-green-600:#00a544;--color-green-800:#016630;--color-green-900:#0d542b;--color-emerald-400:#00d294;--color-emerald-500:#00bb7f;--color-emerald-700:#007956;--color-blue-500:#3080ff;--color-gray-100:#f3f4f6;--color-gray-800:#1e2939;--color-zinc-100:#f4f4f5;--color-zinc-400:#9f9fa9;--color-zinc-500:#71717b;--color-zinc-800:#27272a;--color-black:#000;--spacing:.25rem;--container-xs:20rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--container-2xl:42rem;--container-4xl:56rem;--container-6xl:72rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wider:.05em;--tracking-widest:.1em;--leading-tight:1.25;--leading-snug:1.375;--leading-normal:1.5;--leading-relaxed:1.625;--radius-sm:calc(var(--radius) - 2px);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-xs:4px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}@supports (color:lab(0% 0 0)){:root,:host{--color-red-100:lab(92.243% 10.2865 3.83865);--color-red-800:lab(33.7174% 55.8993 41.0293);--color-red-900:lab(28.5139% 44.5539 29.0463);--color-amber-500:lab(72.7183% 31.8672 97.9407);--color-yellow-100:lab(97.3564% -4.51407 27.344);--color-yellow-800:lab(38.7484% 23.5833 51.4916);--color-yellow-900:lab(32.3865% 21.1273 38.5959);--color-green-100:lab(96.1861% -13.8464 6.52365);--color-green-600:lab(59.0978% -58.6621 41.2579);--color-green-800:lab(37.4616% -36.7971 22.9692);--color-green-900:lab(30.797% -29.6927 17.382);--color-emerald-400:lab(75.0771% -60.7313 19.4147);--color-emerald-500:lab(66.9756% -58.27 19.5419);--color-emerald-700:lab(44.4871% -41.0396 11.0361);--color-blue-500:lab(54.1736% 13.3369 -74.6839);--color-gray-100:lab(96.1596% -.0823438 -1.13575);--color-gray-800:lab(16.1051% -1.18239 -11.7533);--color-zinc-100:lab(96.1634% .0993311 -.364041);--color-zinc-400:lab(65.6464% 1.53497 -5.42429);--color-zinc-500:lab(47.8878% 1.65477 -5.77283);--color-zinc-800:lab(15.7305% .613764 -2.16959)}}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*{overscroll-behavior:none;border-color:var(--border);outline-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){*{outline-color:color-mix(in oklab, var(--ring) 50%, transparent)}}*{scrollbar-width:thin}body{background-color:var(--background);width:100%;min-height:100svh;color:var(--foreground);font-family:var(--font-sans), sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.font-mono{font-family:var(--font-mono), monospace}button:not(:disabled),[role=button]:not(:disabled){cursor:pointer}}@layer components;@layer utilities{.\@container\/card-header{container:card-header/inline-size}.\@container\/field-group{container:field-group/inline-size}.\@container{container-type:inline-size}.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.not-sr-only{clip-path:none;white-space:normal;width:auto;height:auto;margin:0;padding:0;position:static;overflow:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.inset-y-0{inset-block:calc(var(--spacing) * 0)}.top-0{top:calc(var(--spacing) * 0)}.top-1\.5{top:calc(var(--spacing) * 1.5)}.top-1\/2{top:50%}.top-3\.5{top:calc(var(--spacing) * 3.5)}.top-4{top:calc(var(--spacing) * 4)}.right-0{right:calc(var(--spacing) * 0)}.right-1{right:calc(var(--spacing) * 1)}.right-2{right:calc(var(--spacing) * 2)}.right-3{right:calc(var(--spacing) * 3)}.right-4{right:calc(var(--spacing) * 4)}.bottom-0{bottom:calc(var(--spacing) * 0)}.left-0{left:calc(var(--spacing) * 0)}.left-1\/2{left:50%}.isolate{isolation:isolate}.isolation-auto{isolation:auto}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.order-first{order:-9999}.order-last{order:9999}.col-span-2{grid-column:span 2/span 2}.col-start-2{grid-column-start:2}.row-span-2{grid-row:span 2/span 2}.row-start-1{grid-row-start:1}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.-mx-1{margin-inline:calc(var(--spacing) * -1)}.mx-0{margin-inline:calc(var(--spacing) * 0)}.mx-2{margin-inline:calc(var(--spacing) * 2)}.mx-3\.5{margin-inline:calc(var(--spacing) * 3.5)}.mx-auto{margin-inline:auto}.-my-2{margin-block:calc(var(--spacing) * -2)}.my-1{margin-block:calc(var(--spacing) * 1)}.my-2{margin-block:calc(var(--spacing) * 2)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-auto{margin-top:auto}.mr-2{margin-right:calc(var(--spacing) * 2)}.mr-auto{margin-right:auto}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.-ml-1{margin-left:calc(var(--spacing) * -1)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-4{margin-left:calc(var(--spacing) * 4)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.flow-root{display:flow-root}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.inline-grid{display:inline-grid}.inline-table{display:inline-table}.list-item{display:list-item}.table{display:table}.table-caption{display:table-caption}.table-cell{display:table-cell}.table-column{display:table-column}.table-column-group{display:table-column-group}.table-footer-group{display:table-footer-group}.table-header-group{display:table-header-group}.table-row{display:table-row}.table-row-group{display:table-row-group}.field-sizing-content{field-sizing:content}.aspect-square{aspect-ratio:1}.size-2\.5{width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5)}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-3\.5{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-5{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.size-6{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.size-7{width:calc(var(--spacing) * 7);height:calc(var(--spacing) * 7)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.size-12{width:calc(var(--spacing) * 12);height:calc(var(--spacing) * 12)}.size-\[1\.2rem\]{width:1.2rem;height:1.2rem}.size-full{width:100%;height:100%}.h-3{height:calc(var(--spacing) * 3)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-12{height:calc(var(--spacing) * 12)}.h-\[calc\(--spacing\(4\.75\)\)\]{height:calc(calc(var(--spacing) * 4.75))}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.h-svh{height:100svh}.max-h-\(--available-height\){max-height:var(--available-height)}.max-h-72{max-height:calc(var(--spacing) * 72)}.max-h-96{max-height:calc(var(--spacing) * 96)}.max-h-\[min\(calc\(--spacing\(72\)---spacing\(9\)\)\,calc\(var\(--available-height\)---spacing\(9\)\)\)\]{max-height:min(calc(calc(var(--spacing) * 72) - calc(var(--spacing) * 9)), calc(var(--available-height) - calc(var(--spacing) * 9)))}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-7{min-height:calc(var(--spacing) * 7)}.min-h-16{min-height:calc(var(--spacing) * 16)}.min-h-svh{min-height:100svh}.w-\(--anchor-width\){width:var(--anchor-width)}.w-\(--sidebar-width\){width:var(--sidebar-width)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-24{width:calc(var(--spacing) * 24)}.w-32{width:calc(var(--spacing) * 32)}.w-36{width:calc(var(--spacing) * 36)}.w-48{width:calc(var(--spacing) * 48)}.w-auto{width:auto}.w-fit{width:fit-content}.w-full{width:100%}.max-w-\(--available-width\){max-width:var(--available-width)}.max-w-\(--skeleton-width\){max-width:var(--skeleton-width)}.max-w-2xl{max-width:var(--container-2xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-5{min-width:calc(var(--spacing) * 5)}.min-w-16{min-width:calc(var(--spacing) * 16)}.min-w-32{min-width:calc(var(--spacing) * 32)}.min-w-\[calc\(var\(--anchor-width\)\+--spacing\(7\)\)\]{min-width:calc(var(--anchor-width) + calc(var(--spacing) * 7))}.flex-1{flex:1}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.border-collapse{border-collapse:collapse}.origin-\(--transform-origin\){transform-origin:var(--transform-origin)}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-x-px{--tw-translate-x:-1px;translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-px{--tw-translate-x:1px;translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-y-\[calc\(-50\%-2px\)\]{--tw-translate-y:calc(-50% - 2px);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-none{translate:none}.scale-0{--tw-scale-x:0%;--tw-scale-y:0%;--tw-scale-z:0%;scale:var(--tw-scale-x) var(--tw-scale-y)}.scale-100{--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y)}.scale-3d{scale:var(--tw-scale-x) var(--tw-scale-y) var(--tw-scale-z)}.rotate-0{rotate:0deg}.rotate-45{rotate:45deg}.rotate-90{rotate:90deg}.rotate-180{rotate:180deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-pulse{animation:var(--animate-pulse)}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.cursor-text{cursor:text}.touch-pinch-zoom{--tw-pinch-zoom:pinch-zoom;touch-action:var(--tw-pan-x,) var(--tw-pan-y,) var(--tw-pinch-zoom,)}.resize{resize:both}.resize-none{resize:none}.scroll-my-1{scroll-margin-block:calc(var(--spacing) * 1)}.scroll-py-1{scroll-padding-block:calc(var(--spacing) * 1)}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.auto-rows-min{grid-auto-rows:min-content}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-\[minmax\(0\,1fr\)\]{grid-template-columns:minmax(0,1fr)}.grid-rows-\[auto_1fr\]{grid-template-rows:auto 1fr}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-0{gap:calc(var(--spacing) * 0)}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-8{gap:calc(var(--spacing) * 8)}.gap-px{gap:1px}:where(.space-y-0>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 0) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 0) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-reverse>:not(:last-child)){--tw-space-y-reverse:1}:where(.-space-x-2>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing) * -2) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing) * -2) * calc(1 - var(--tw-space-x-reverse)))}:where(.space-x-reverse>:not(:last-child)){--tw-space-x-reverse:1}:where(.divide-x>:not(:last-child)){--tw-divide-x-reverse:0;border-inline-style:var(--tw-border-style);border-inline-start-width:calc(1px * var(--tw-divide-x-reverse));border-inline-end-width:calc(1px * calc(1 - var(--tw-divide-x-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-y-reverse>:not(:last-child)){--tw-divide-y-reverse:1}.self-end{align-self:flex-end}.self-start{align-self:flex-start}.justify-self-end{justify-self:flex-end}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.overscroll-contain{overscroll-behavior:contain}.rounded{border-radius:.25rem}.rounded-\[2px\]{border-radius:2px}.rounded-\[calc\(var\(--radius-sm\)\+2px\)\]{border-radius:calc(var(--radius-sm) + 2px)}.rounded-\[calc\(var\(--radius-sm\)-2px\)\]{border-radius:calc(var(--radius-sm) - 2px)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:calc(var(--radius) + 2px)}.rounded-md{border-radius:var(--radius)}.rounded-none{border-radius:0}.rounded-sm{border-radius:calc(var(--radius) - 2px)}.rounded-xl{border-radius:calc(var(--radius) + 4px)}.rounded-s{border-start-start-radius:.25rem;border-end-start-radius:.25rem}.rounded-ss{border-start-start-radius:.25rem}.rounded-e{border-start-end-radius:.25rem;border-end-end-radius:.25rem}.rounded-se{border-start-end-radius:.25rem}.rounded-ee{border-end-end-radius:.25rem}.rounded-es{border-end-start-radius:.25rem}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-t-lg{border-top-left-radius:calc(var(--radius) + 2px);border-top-right-radius:calc(var(--radius) + 2px)}.rounded-l{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.rounded-tl{border-top-left-radius:.25rem}.rounded-r{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.rounded-tr{border-top-right-radius:.25rem}.rounded-b{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.rounded-b-lg{border-bottom-right-radius:calc(var(--radius) + 2px);border-bottom-left-radius:calc(var(--radius) + 2px)}.rounded-br{border-bottom-right-radius:.25rem}.rounded-bl{border-bottom-left-radius:.25rem}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.border-s{border-inline-start-style:var(--tw-border-style);border-inline-start-width:1px}.border-e{border-inline-end-style:var(--tw-border-style);border-inline-end-width:1px}.border-bs{border-block-start-style:var(--tw-border-style);border-block-start-width:1px}.border-be{border-block-end-style:var(--tw-border-style);border-block-end-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-amber-500\/30{border-color:#f99c004d}@supports (color:color-mix(in lab, red, red)){.border-amber-500\/30{border-color:color-mix(in oklab, var(--color-amber-500) 30%, transparent)}}.border-blue-500\/30{border-color:#3080ff4d}@supports (color:color-mix(in lab, red, red)){.border-blue-500\/30{border-color:color-mix(in oklab, var(--color-blue-500) 30%, transparent)}}.border-border{border-color:var(--border)}.border-destructive{border-color:var(--destructive)}.border-emerald-500{border-color:var(--color-emerald-500)}.border-emerald-500\/30{border-color:#00bb7f4d}@supports (color:color-mix(in lab, red, red)){.border-emerald-500\/30{border-color:color-mix(in oklab, var(--color-emerald-500) 30%, transparent)}}.border-foreground\/10{border-color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.border-foreground\/10{border-color:color-mix(in oklab, var(--foreground) 10%, transparent)}}.border-foreground\/20{border-color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.border-foreground\/20{border-color:color-mix(in oklab, var(--foreground) 20%, transparent)}}.border-input{border-color:var(--input)}.border-muted{border-color:var(--muted)}.border-sidebar-border{border-color:var(--sidebar-border)}.border-transparent{border-color:#0000}.bg-amber-500\/10{background-color:#f99c001a}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/10{background-color:color-mix(in oklab, var(--color-amber-500) 10%, transparent)}}.bg-background{background-color:var(--background)}.bg-black\/80{background-color:#000c}@supports (color:color-mix(in lab, red, red)){.bg-black\/80{background-color:color-mix(in oklab, var(--color-black) 80%, transparent)}}.bg-blue-500\/10{background-color:#3080ff1a}@supports (color:color-mix(in lab, red, red)){.bg-blue-500\/10{background-color:color-mix(in oklab, var(--color-blue-500) 10%, transparent)}}.bg-border,.bg-border\/50{background-color:var(--border)}@supports (color:color-mix(in lab, red, red)){.bg-border\/50{background-color:color-mix(in oklab, var(--border) 50%, transparent)}}.bg-card{background-color:var(--card)}.bg-destructive\/10{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.bg-destructive\/10{background-color:color-mix(in oklab, var(--destructive) 10%, transparent)}}.bg-emerald-500\/10{background-color:#00bb7f1a}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/10{background-color:color-mix(in oklab, var(--color-emerald-500) 10%, transparent)}}.bg-foreground{background-color:var(--foreground)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-green-100{background-color:var(--color-green-100)}.bg-input\/20{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.bg-input\/20{background-color:color-mix(in oklab, var(--input) 20%, transparent)}}.bg-muted{background-color:var(--muted)}.bg-muted-foreground\/10{background-color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.bg-muted-foreground\/10{background-color:color-mix(in oklab, var(--muted-foreground) 10%, transparent)}}.bg-muted\/20{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/20{background-color:color-mix(in oklab, var(--muted) 20%, transparent)}}.bg-muted\/30{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/30{background-color:color-mix(in oklab, var(--muted) 30%, transparent)}}.bg-muted\/50{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/50{background-color:color-mix(in oklab, var(--muted) 50%, transparent)}}.bg-popover{background-color:var(--popover)}.bg-primary{background-color:var(--primary)}.bg-red-100{background-color:var(--color-red-100)}.bg-secondary{background-color:var(--secondary)}.bg-sidebar{background-color:var(--sidebar)}.bg-sidebar-border{background-color:var(--sidebar-border)}.bg-transparent{background-color:#0000}.bg-yellow-100{background-color:var(--color-yellow-100)}.bg-zinc-100{background-color:var(--color-zinc-100)}.bg-clip-padding{background-clip:padding-box}.bg-repeat{background-repeat:repeat}.mask-no-clip{-webkit-mask-clip:no-clip;mask-clip:no-clip}.mask-repeat{-webkit-mask-repeat:repeat;mask-repeat:repeat}.fill-foreground{fill:var(--foreground)}.object-cover{object-fit:cover}.p-0{padding:calc(var(--spacing) * 0)}.p-1{padding:calc(var(--spacing) * 1)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-0{padding-inline:calc(var(--spacing) * 0)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.pt-0{padding-top:calc(var(--spacing) * 0)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pr-4{padding-right:calc(var(--spacing) * 4)}.pr-8{padding-right:calc(var(--spacing) * 8)}.pb-0{padding-bottom:calc(var(--spacing) * 0)}.pb-0\.5{padding-bottom:calc(var(--spacing) * .5)}.pb-1{padding-bottom:calc(var(--spacing) * 1)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pl-2{padding-left:calc(var(--spacing) * 2)}.pl-4{padding-left:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-sm\/relaxed{font-size:var(--text-sm);line-height:var(--leading-relaxed)}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-xs\/relaxed{font-size:var(--text-xs);line-height:var(--leading-relaxed)}.text-\[0\.625rem\]{font-size:.625rem}.text-\[11px\]{font-size:11px}.leading-none{--tw-leading:1;line-height:1}.leading-normal{--tw-leading:var(--leading-normal);line-height:var(--leading-normal)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.text-balance{text-wrap:balance}.text-wrap{text-wrap:wrap}.break-all{word-break:break-all}.text-clip{text-overflow:clip}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-amber-500{color:var(--color-amber-500)}.text-background{color:var(--background)}.text-card-foreground{color:var(--card-foreground)}.text-destructive{color:var(--destructive)}.text-emerald-700{color:var(--color-emerald-700)}.text-foreground{color:var(--foreground)}.text-gray-800{color:var(--color-gray-800)}.text-green-600{color:var(--color-green-600)}.text-green-800{color:var(--color-green-800)}.text-muted-foreground{color:var(--muted-foreground)}.text-popover-foreground{color:var(--popover-foreground)}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.text-red-800{color:var(--color-red-800)}.text-secondary-foreground{color:var(--secondary-foreground)}.text-sidebar-foreground,.text-sidebar-foreground\/70{color:var(--sidebar-foreground)}@supports (color:color-mix(in lab, red, red)){.text-sidebar-foreground\/70{color:color-mix(in oklab, var(--sidebar-foreground) 70%, transparent)}}.text-tactical-amber{color:var(--tactical-amber)}.text-tactical-cyan{color:var(--tactical-cyan)}.text-tactical-green{color:var(--tactical-green)}.text-yellow-800{color:var(--color-yellow-800)}.text-zinc-500{color:var(--color-zinc-500)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.italic{font-style:italic}.not-italic{font-style:normal}.diagonal-fractions{--tw-numeric-fraction:diagonal-fractions;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.lining-nums{--tw-numeric-figure:lining-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.oldstyle-nums{--tw-numeric-figure:oldstyle-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.ordinal{--tw-ordinal:ordinal;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.proportional-nums{--tw-numeric-spacing:proportional-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.slashed-zero{--tw-slashed-zero:slashed-zero;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.stacked-fractions{--tw-numeric-fraction:stacked-fractions;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.normal-nums{font-variant-numeric:normal}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.overline{text-decoration-line:overline}.underline{text-decoration-line:underline}.underline-offset-4{text-underline-offset:4px}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.subpixel-antialiased{-webkit-font-smoothing:auto;-moz-osx-font-smoothing:auto}.opacity-50{opacity:.5}.bg-blend-color{background-blend-mode:color}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_0_0_1px_hsl\(var\(--sidebar-border\)\)\]{--tw-shadow:0 0 0 1px var(--tw-shadow-color,hsl(var(--sidebar-border)));box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-0{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.inset-ring{--tw-inset-ring-shadow:inset 0 0 0 1px var(--tw-inset-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-background{--tw-ring-color:var(--background)}.ring-foreground\/10{--tw-ring-color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.ring-foreground\/10{--tw-ring-color:color-mix(in oklab, var(--foreground) 10%, transparent)}}.ring-sidebar-ring{--tw-ring-color:var(--sidebar-ring)}.outline-hidden{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.outline-hidden{outline-offset:2px;outline:2px solid #0000}}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.drop-shadow{--tw-drop-shadow-size:drop-shadow(0 1px 2px var(--tw-drop-shadow-color,#0000001a)) drop-shadow(0 1px 1px var(--tw-drop-shadow-color,#0000000f));--tw-drop-shadow:drop-shadow(0 1px 2px #0000001a) drop-shadow(0 1px 1px #0000000f);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-grayscale{--tw-backdrop-grayscale:grayscale(100%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-invert{--tw-backdrop-invert:invert(100%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-sepia{--tw-backdrop-sepia:sepia(100%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[left\,right\,width\]{transition-property:left,right,width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[margin\,opacity\]{transition-property:margin,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[width\,height\,padding\]{transition-property:width,height,padding;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[width\]{transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-100{--tw-duration:.1s;transition-duration:.1s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-linear{--tw-ease:linear;transition-timing-function:linear}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}:where(.divide-x-reverse>:not(:last-child)){--tw-divide-x-reverse:1}.ring-inset{--tw-ring-inset:inset}.group-focus-within\/menu-item\:opacity-100:is(:where(.group\/menu-item):focus-within *){opacity:1}@media (hover:hover){.group-hover\/menu-item\:opacity-100:is(:where(.group\/menu-item):hover *){opacity:1}}.group-focus\/dropdown-menu-item\:text-accent-foreground:is(:where(.group\/dropdown-menu-item):focus *){color:var(--accent-foreground)}.group-has-data-\[orientation\=horizontal\]\/field\:text-balance:is(:where(.group\/field):has([data-orientation=horizontal]) *){text-wrap:balance}.group-has-data-\[sidebar\=menu-action\]\/menu-item\:pr-8:is(:where(.group\/menu-item):has([data-sidebar=menu-action]) *){padding-right:calc(var(--spacing) * 8)}.group-has-data-\[size\=lg\]\/avatar-group\:size-10:is(:where(.group\/avatar-group):has([data-size=lg]) *){width:calc(var(--spacing) * 10);height:calc(var(--spacing) * 10)}.group-has-data-\[size\=sm\]\/avatar-group\:size-6:is(:where(.group\/avatar-group):has([data-size=sm]) *){width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.group-has-data-\[slot\=combobox-clear\]\/input-group\:hidden:is(:where(.group\/input-group):has([data-slot=combobox-clear]) *){display:none}.group-has-\[\>input\]\/input-group\:pt-2:is(:where(.group\/input-group):has(>input) *){padding-top:calc(var(--spacing) * 2)}.group-has-\[\>input\]\/input-group\:pb-2:is(:where(.group\/input-group):has(>input) *){padding-bottom:calc(var(--spacing) * 2)}.group-data-empty\/combobox-content\:flex:is(:where(.group\/combobox-content)[data-empty] *){display:flex}.group-data-\[collapsible\=icon\]\:-mt-8:is(:where(.group)[data-collapsible=icon] *){margin-top:calc(var(--spacing) * -8)}.group-data-\[collapsible\=icon\]\:hidden:is(:where(.group)[data-collapsible=icon] *){display:none}.group-data-\[collapsible\=icon\]\:size-8\!:is(:where(.group)[data-collapsible=icon] *){width:calc(var(--spacing) * 8)!important;height:calc(var(--spacing) * 8)!important}.group-data-\[collapsible\=icon\]\:w-\(--sidebar-width-icon\):is(:where(.group)[data-collapsible=icon] *){width:var(--sidebar-width-icon)}.group-data-\[collapsible\=icon\]\:w-\[calc\(var\(--sidebar-width-icon\)\+\(--spacing\(4\)\)\)\]:is(:where(.group)[data-collapsible=icon] *){width:calc(var(--sidebar-width-icon) + (calc(var(--spacing) * 4)))}.group-data-\[collapsible\=icon\]\:w-\[calc\(var\(--sidebar-width-icon\)\+\(--spacing\(4\)\)\+2px\)\]:is(:where(.group)[data-collapsible=icon] *){width:calc(var(--sidebar-width-icon) + (calc(var(--spacing) * 4)) + 2px)}.group-data-\[collapsible\=icon\]\:overflow-hidden:is(:where(.group)[data-collapsible=icon] *){overflow:hidden}.group-data-\[collapsible\=icon\]\:p-0\!:is(:where(.group)[data-collapsible=icon] *){padding:calc(var(--spacing) * 0)!important}.group-data-\[collapsible\=icon\]\:p-2\!:is(:where(.group)[data-collapsible=icon] *){padding:calc(var(--spacing) * 2)!important}.group-data-\[collapsible\=icon\]\:opacity-0:is(:where(.group)[data-collapsible=icon] *){opacity:0}.group-data-\[collapsible\=offExamples\]\:right-\[calc\(var\(--sidebar-width\)\*-1\)\]:is(:where(.group)[data-collapsible=offExamples] *){right:calc(var(--sidebar-width) * -1)}.group-data-\[collapsible\=offExamples\]\:left-\[calc\(var\(--sidebar-width\)\*-1\)\]:is(:where(.group)[data-collapsible=offExamples] *){left:calc(var(--sidebar-width) * -1)}.group-data-\[collapsible\=offExamples\]\:w-0:is(:where(.group)[data-collapsible=offExamples] *){width:calc(var(--spacing) * 0)}.group-data-\[collapsible\=offExamples\]\:translate-x-0:is(:where(.group)[data-collapsible=offExamples] *){--tw-translate-x:calc(var(--spacing) * 0);translate:var(--tw-translate-x) var(--tw-translate-y)}.group-data-\[disabled\=true\]\:pointer-events-none:is(:where(.group)[data-disabled=true] *){pointer-events:none}.group-data-\[disabled\=true\]\:opacity-50:is(:where(.group)[data-disabled=true] *),.group-data-\[disabled\=true\]\/field\:opacity-50:is(:where(.group\/field)[data-disabled=true] *),.group-data-\[disabled\=true\]\/input-group\:opacity-50:is(:where(.group\/input-group)[data-disabled=true] *){opacity:.5}.group-data-\[panel-open\]\:rotate-180:is(:where(.group)[data-panel-open] *){rotate:180deg}.group-data-\[side\=left\]\:-right-4:is(:where(.group)[data-side=left] *){right:calc(var(--spacing) * -4)}.group-data-\[side\=left\]\:border-r:is(:where(.group)[data-side=left] *){border-right-style:var(--tw-border-style);border-right-width:1px}.group-data-\[side\=right\]\:left-0:is(:where(.group)[data-side=right] *){left:calc(var(--spacing) * 0)}.group-data-\[side\=right\]\:rotate-180:is(:where(.group)[data-side=right] *){rotate:180deg}.group-data-\[side\=right\]\:border-l:is(:where(.group)[data-side=right] *){border-left-style:var(--tw-border-style);border-left-width:1px}.group-data-\[size\=default\]\/avatar\:size-2\.5:is(:where(.group\/avatar)[data-size=default] *){width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5)}.group-data-\[size\=lg\]\/avatar\:size-3:is(:where(.group\/avatar)[data-size=lg] *){width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.group-data-\[size\=sm\]\/alert-dialog-content\:grid:is(:where(.group\/alert-dialog-content)[data-size=sm] *){display:grid}.group-data-\[size\=sm\]\/alert-dialog-content\:grid-cols-2:is(:where(.group\/alert-dialog-content)[data-size=sm] *){grid-template-columns:repeat(2,minmax(0,1fr))}.group-data-\[size\=sm\]\/avatar\:size-2:is(:where(.group\/avatar)[data-size=sm] *){width:calc(var(--spacing) * 2);height:calc(var(--spacing) * 2)}.group-data-\[size\=sm\]\/avatar\:text-xs:is(:where(.group\/avatar)[data-size=sm] *){font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.group-data-\[size\=sm\]\/card\:px-3:is(:where(.group\/card)[data-size=sm] *){padding-inline:calc(var(--spacing) * 3)}.group-data-\[variant\=floating\]\:rounded-lg:is(:where(.group)[data-variant=floating] *){border-radius:calc(var(--radius) + 2px)}.group-data-\[variant\=floating\]\:shadow-sm:is(:where(.group)[data-variant=floating] *){--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.group-data-\[variant\=floating\]\:ring-1:is(:where(.group)[data-variant=floating] *){--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.group-data-\[variant\=floating\]\:ring-sidebar-border:is(:where(.group)[data-variant=floating] *){--tw-ring-color:var(--sidebar-border)}.group-data-\[variant\=outline\]\/field-group\:-mb-2:is(:where(.group\/field-group)[data-variant=outline] *){margin-bottom:calc(var(--spacing) * -2)}@media (hover:hover){.peer-hover\/menu-button\:text-sidebar-accent-foreground:is(:where(.peer\/menu-button):hover~*){color:var(--sidebar-accent-foreground)}}.peer-disabled\:cursor-not-allowed:is(:where(.peer):disabled~*){cursor:not-allowed}.peer-disabled\:opacity-50:is(:where(.peer):disabled~*){opacity:.5}.peer-data-active\/menu-button\:text-sidebar-accent-foreground:is(:where(.peer\/menu-button)[data-active]~*){color:var(--sidebar-accent-foreground)}.peer-data-\[size\=default\]\/menu-button\:top-1\.5:is(:where(.peer\/menu-button)[data-size=default]~*){top:calc(var(--spacing) * 1.5)}.peer-data-\[size\=lg\]\/menu-button\:top-2\.5:is(:where(.peer\/menu-button)[data-size=lg]~*){top:calc(var(--spacing) * 2.5)}.peer-data-\[size\=sm\]\/menu-button\:top-1:is(:where(.peer\/menu-button)[data-size=sm]~*){top:calc(var(--spacing) * 1)}.file\:inline-flex::file-selector-button{display:inline-flex}.file\:h-6::file-selector-button{height:calc(var(--spacing) * 6)}.file\:border-0::file-selector-button{border-style:var(--tw-border-style);border-width:0}.file\:bg-transparent::file-selector-button{background-color:#0000}.file\:text-xs\/relaxed::file-selector-button{font-size:var(--text-xs);line-height:var(--leading-relaxed)}.file\:font-medium::file-selector-button{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.file\:text-foreground::file-selector-button{color:var(--foreground)}.placeholder\:text-muted-foreground::placeholder{color:var(--muted-foreground)}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:-inset-2:after{content:var(--tw-content);inset:calc(var(--spacing) * -2)}.after\:inset-0:after{content:var(--tw-content);inset:calc(var(--spacing) * 0)}.after\:inset-y-0:after{content:var(--tw-content);inset-block:calc(var(--spacing) * 0)}.after\:left-1\/2:after{content:var(--tw-content);left:50%}.after\:w-\[2px\]:after{content:var(--tw-content);width:2px}.after\:rounded-full:after{content:var(--tw-content);border-radius:3.40282e38px}.after\:border:after{content:var(--tw-content);border-style:var(--tw-border-style);border-width:1px}.after\:border-border:after{content:var(--tw-content);border-color:var(--border)}.after\:mix-blend-darken:after{content:var(--tw-content);mix-blend-mode:darken}.group-data-\[collapsible\=offExamples\]\:after\:left-full:is(:where(.group)[data-collapsible=offExamples] *):after{content:var(--tw-content);left:100%}.last\:mt-0:last-child{margin-top:calc(var(--spacing) * 0)}.last\:border-0:last-child{border-style:var(--tw-border-style);border-width:0}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.focus-within\:border-ring:focus-within{border-color:var(--ring)}.focus-within\:ring-2:focus-within{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-within\:ring-ring\/30:focus-within{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.focus-within\:ring-ring\/30:focus-within{--tw-ring-color:color-mix(in oklab, var(--ring) 30%, transparent)}}@media (hover:hover){.hover\:bg-accent:hover{background-color:var(--accent)}.hover\:bg-destructive\/20:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-destructive\/20:hover{background-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.hover\:bg-input\/40:hover{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-input\/40:hover{background-color:color-mix(in oklab, var(--input) 40%, transparent)}}.hover\:bg-input\/50:hover{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-input\/50:hover{background-color:color-mix(in oklab, var(--input) 50%, transparent)}}.hover\:bg-muted:hover{background-color:var(--muted)}.hover\:bg-primary\/80:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/80:hover{background-color:color-mix(in oklab, var(--primary) 80%, transparent)}}.hover\:bg-secondary\/80:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab, var(--secondary) 80%, transparent)}}.hover\:bg-sidebar-accent:hover{background-color:var(--sidebar-accent)}.hover\:text-accent-foreground:hover{color:var(--accent-foreground)}.hover\:text-foreground:hover{color:var(--foreground)}.hover\:text-muted-foreground:hover{color:var(--muted-foreground)}.hover\:text-sidebar-accent-foreground:hover{color:var(--sidebar-accent-foreground)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.hover\:shadow-\[0_0_0_1px_hsl\(var\(--sidebar-accent\)\)\]:hover{--tw-shadow:0 0 0 1px var(--tw-shadow-color,hsl(var(--sidebar-accent)));box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hover\:group-data-\[collapsible\=offExamples\]\:bg-sidebar:hover:is(:where(.group)[data-collapsible=offExamples] *){background-color:var(--sidebar)}.hover\:after\:bg-sidebar-border:hover:after{content:var(--tw-content);background-color:var(--sidebar-border)}}.focus\:bg-accent:focus{background-color:var(--accent)}.focus\:text-accent-foreground:focus,:is(.focus\:\*\*\:text-accent-foreground:focus *),:is(.not-data-\[variant\=destructive\]\:focus\:\*\*\:text-accent-foreground:not([data-variant=destructive]):focus *){color:var(--accent-foreground)}.focus-visible\:border-destructive\/40:focus-visible{border-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:border-destructive\/40:focus-visible{border-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.focus-visible\:border-ring:focus-visible{border-color:var(--ring)}.focus-visible\:ring-0:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\:ring-2:focus-visible,.focus-visible\:ring-\[2px\]:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\:ring-\[3px\]:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.focus-visible\:ring-ring\/30:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-ring\/30:focus-visible{--tw-ring-color:color-mix(in oklab, var(--ring) 30%, transparent)}}.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:color-mix(in oklab, var(--ring) 50%, transparent)}}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.active\:bg-sidebar-accent:active{background-color:var(--sidebar-accent)}.active\:text-sidebar-accent-foreground:active{color:var(--sidebar-accent-foreground)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}:where([data-side=left]) .in-data-\[side\=left\]\:cursor-w-resize{cursor:w-resize}:where([data-side=right]) .in-data-\[side\=right\]\:cursor-e-resize{cursor:e-resize}:where([data-slot=combobox-content]) .in-data-\[slot\=combobox-content\]\:focus-within\:border-inherit:focus-within{border-color:inherit}:where([data-slot=combobox-content]) .in-data-\[slot\=combobox-content\]\:focus-within\:ring-0:focus-within{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.has-disabled\:pointer-events-none:has(:disabled){pointer-events:none}.has-disabled\:cursor-not-allowed:has(:disabled){cursor:not-allowed}.has-disabled\:opacity-50:has(:disabled){opacity:.5}.has-aria-invalid\:border-destructive:has([aria-invalid=true]){border-color:var(--destructive)}.has-aria-invalid\:ring-2:has([aria-invalid=true]){--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.has-aria-invalid\:ring-destructive\/20:has([aria-invalid=true]){--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.has-aria-invalid\:ring-destructive\/20:has([aria-invalid=true]){--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.has-data-checked\:bg-primary\/5:has([data-checked]){background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.has-data-checked\:bg-primary\/5:has([data-checked]){background-color:color-mix(in oklab, var(--primary) 5%, transparent)}}.has-data-\[align\=block-end\]\:rounded-md:has([data-align=block-end]),.has-data-\[align\=block-start\]\:rounded-md:has([data-align=block-start]){border-radius:var(--radius)}.has-data-\[icon\=inline-end\]\:pr-1\.5:has([data-icon=inline-end]){padding-right:calc(var(--spacing) * 1.5)}.has-data-\[icon\=inline-end\]\:pr-2:has([data-icon=inline-end]){padding-right:calc(var(--spacing) * 2)}.has-data-\[icon\=inline-start\]\:pl-1\.5:has([data-icon=inline-start]){padding-left:calc(var(--spacing) * 1.5)}.has-data-\[icon\=inline-start\]\:pl-2:has([data-icon=inline-start]){padding-left:calc(var(--spacing) * 2)}.has-data-\[slot\=alert-dialog-media\]\:grid-rows-\[auto_auto_1fr\]:has([data-slot=alert-dialog-media]){grid-template-rows:auto auto 1fr}.has-data-\[slot\=alert-dialog-media\]\:gap-x-4:has([data-slot=alert-dialog-media]){column-gap:calc(var(--spacing) * 4)}.has-data-\[slot\=card-action\]\:grid-cols-\[1fr_auto\]:has([data-slot=card-action]){grid-template-columns:1fr auto}.has-data-\[slot\=card-description\]\:grid-rows-\[auto_auto\]:has([data-slot=card-description]){grid-template-rows:auto auto}.has-data-\[slot\=combobox-chip\]\:px-1:has([data-slot=combobox-chip]){padding-inline:calc(var(--spacing) * 1)}.has-data-\[slot\=combobox-chip-remove\]\:pr-0:has([data-slot=combobox-chip-remove]){padding-right:calc(var(--spacing) * 0)}.has-data-\[variant\=inset\]\:bg-sidebar:has([data-variant=inset]){background-color:var(--sidebar)}.has-\[\[data-slot\=input-group-control\]\:focus-visible\]\:border-ring:has([data-slot=input-group-control]:focus-visible){border-color:var(--ring)}.has-\[\[data-slot\=input-group-control\]\:focus-visible\]\:ring-2:has([data-slot=input-group-control]:focus-visible){--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.has-\[\[data-slot\=input-group-control\]\:focus-visible\]\:ring-ring\/30:has([data-slot=input-group-control]:focus-visible){--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.has-\[\[data-slot\=input-group-control\]\:focus-visible\]\:ring-ring\/30:has([data-slot=input-group-control]:focus-visible){--tw-ring-color:color-mix(in oklab, var(--ring) 30%, transparent)}}.has-\[\[data-slot\]\[aria-invalid\=true\]\]\:border-destructive:has([data-slot][aria-invalid=true]){border-color:var(--destructive)}.has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-2:has([data-slot][aria-invalid=true]){--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/20:has([data-slot][aria-invalid=true]){--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/20:has([data-slot][aria-invalid=true]){--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.has-\[textarea\]\:rounded-md:has(:is(textarea)){border-radius:var(--radius)}.has-\[\>\[data-align\=block-end\]\]\:h-auto:has(>[data-align=block-end]){height:auto}.has-\[\>\[data-align\=block-end\]\]\:flex-col:has(>[data-align=block-end]){flex-direction:column}.has-\[\>\[data-align\=block-start\]\]\:h-auto:has(>[data-align=block-start]){height:auto}.has-\[\>\[data-align\=block-start\]\]\:flex-col:has(>[data-align=block-start]){flex-direction:column}.has-\[\>\[data-slot\=checkbox-group\]\]\:gap-3:has(>[data-slot=checkbox-group]){gap:calc(var(--spacing) * 3)}.has-\[\>\[data-slot\=field-content\]\]\:items-start:has(>[data-slot=field-content]){align-items:flex-start}.has-\[\>\[data-slot\=field\]\]\:w-full:has(>[data-slot=field]){width:100%}.has-\[\>\[data-slot\=field\]\]\:flex-col:has(>[data-slot=field]){flex-direction:column}.has-\[\>\[data-slot\=field\]\]\:rounded-md:has(>[data-slot=field]){border-radius:var(--radius)}.has-\[\>\[data-slot\=field\]\]\:border:has(>[data-slot=field]){border-style:var(--tw-border-style);border-width:1px}.has-\[\>\[data-slot\=radio-group\]\]\:gap-3:has(>[data-slot=radio-group]){gap:calc(var(--spacing) * 3)}.has-\[\>button\]\:mr-\[-0\.275rem\]:has(>button){margin-right:-.275rem}.has-\[\>button\]\:ml-\[-0\.275rem\]:has(>button){margin-left:-.275rem}.has-\[\>img\:first-child\]\:pt-0:has(>img:first-child){padding-top:calc(var(--spacing) * 0)}.has-\[\>kbd\]\:mr-\[-0\.275rem\]:has(>kbd){margin-right:-.275rem}.has-\[\>kbd\]\:ml-\[-0\.275rem\]:has(>kbd){margin-left:-.275rem}.has-\[\>svg\]\:p-0:has(>svg){padding:calc(var(--spacing) * 0)}.has-\[\>textarea\]\:h-auto:has(>textarea){height:auto}.aria-disabled\:pointer-events-none[aria-disabled=true]{pointer-events:none}.aria-disabled\:opacity-50[aria-disabled=true]{opacity:.5}.aria-expanded\:bg-muted[aria-expanded=true]{background-color:var(--muted)}.aria-expanded\:bg-secondary[aria-expanded=true]{background-color:var(--secondary)}.aria-expanded\:text-foreground[aria-expanded=true]{color:var(--foreground)}.aria-expanded\:text-secondary-foreground[aria-expanded=true]{color:var(--secondary-foreground)}.aria-invalid\:border-destructive[aria-invalid=true]{border-color:var(--destructive)}.aria-invalid\:ring-0[aria-invalid=true]{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.aria-invalid\:ring-2[aria-invalid=true],.aria-invalid\:ring-\[2px\][aria-invalid=true]{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.data-active\:bg-sidebar-accent[data-active]{background-color:var(--sidebar-accent)}.data-active\:font-medium[data-active]{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.data-active\:text-sidebar-accent-foreground[data-active]{color:var(--sidebar-accent-foreground)}.data-closed\:overflow-hidden[data-closed]{overflow:hidden}.data-disabled\:pointer-events-none[data-disabled]{pointer-events:none}.data-disabled\:opacity-50[data-disabled]{opacity:.5}.data-empty\:p-0[data-empty]{padding:calc(var(--spacing) * 0)}.data-ending-style\:opacity-0[data-ending-style]{opacity:0}.data-highlighted\:bg-accent[data-highlighted]{background-color:var(--accent)}.data-highlighted\:text-accent-foreground[data-highlighted],:is(.not-data-\[variant\=destructive\]\:data-highlighted\:\*\*\:text-accent-foreground:not([data-variant=destructive])[data-highlighted] *){color:var(--accent-foreground)}.data-inset\:pl-8[data-inset]{padding-left:calc(var(--spacing) * 8)}.data-open\:bg-accent[data-open]{background-color:var(--accent)}.data-open\:text-accent-foreground[data-open]{color:var(--accent-foreground)}.data-open\:opacity-100[data-open]{opacity:1}@media (hover:hover){.data-open\:hover\:bg-sidebar-accent[data-open]:hover{background-color:var(--sidebar-accent)}.data-open\:hover\:text-sidebar-accent-foreground[data-open]:hover{color:var(--sidebar-accent-foreground)}}.data-placeholder\:text-muted-foreground[data-placeholder]{color:var(--muted-foreground)}.data-pressed\:bg-transparent[data-pressed]{background-color:#0000}.data-selected\:border-primary[data-selected]{border-color:var(--primary)}.data-selected\:text-foreground[data-selected]{color:var(--foreground)}.data-starting-style\:opacity-0[data-starting-style]{opacity:0}.data-\[chips\=true\]\:min-w-\(--anchor-width\)[data-chips=true]{min-width:var(--anchor-width)}.data-\[invalid\=true\]\:text-destructive[data-invalid=true]{color:var(--destructive)}.data-\[orientation\=horizontal\]\:h-px[data-orientation=horizontal]{height:1px}.data-\[orientation\=horizontal\]\:w-full[data-orientation=horizontal]{width:100%}.data-\[orientation\=vertical\]\:w-px[data-orientation=vertical]{width:1px}.data-\[orientation\=vertical\]\:self-stretch[data-orientation=vertical]{align-self:stretch}.data-\[side\=bottom\]\:inset-x-0[data-side=bottom]{inset-inline:calc(var(--spacing) * 0)}.data-\[side\=bottom\]\:top-1[data-side=bottom]{top:calc(var(--spacing) * 1)}.data-\[side\=bottom\]\:bottom-0[data-side=bottom]{bottom:calc(var(--spacing) * 0)}.data-\[side\=bottom\]\:h-auto[data-side=bottom]{height:auto}.data-\[side\=bottom\]\:border-t[data-side=bottom]{border-top-style:var(--tw-border-style);border-top-width:1px}.data-\[side\=left\]\:inset-y-0[data-side=left]{inset-block:calc(var(--spacing) * 0)}.data-\[side\=left\]\:top-1\/2\![data-side=left]{top:50%!important}.data-\[side\=left\]\:-right-1[data-side=left]{right:calc(var(--spacing) * -1)}.data-\[side\=left\]\:left-0[data-side=left]{left:calc(var(--spacing) * 0)}.data-\[side\=left\]\:h-full[data-side=left]{height:100%}.data-\[side\=left\]\:w-3\/4[data-side=left]{width:75%}.data-\[side\=left\]\:-translate-y-1\/2[data-side=left]{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.data-\[side\=left\]\:border-r[data-side=left]{border-right-style:var(--tw-border-style);border-right-width:1px}.data-\[side\=right\]\:inset-y-0[data-side=right]{inset-block:calc(var(--spacing) * 0)}.data-\[side\=right\]\:top-1\/2\![data-side=right]{top:50%!important}.data-\[side\=right\]\:right-0[data-side=right]{right:calc(var(--spacing) * 0)}.data-\[side\=right\]\:-left-1[data-side=right]{left:calc(var(--spacing) * -1)}.data-\[side\=right\]\:h-full[data-side=right]{height:100%}.data-\[side\=right\]\:w-3\/4[data-side=right]{width:75%}.data-\[side\=right\]\:-translate-y-1\/2[data-side=right]{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.data-\[side\=right\]\:border-l[data-side=right]{border-left-style:var(--tw-border-style);border-left-width:1px}.data-\[side\=top\]\:inset-x-0[data-side=top]{inset-inline:calc(var(--spacing) * 0)}.data-\[side\=top\]\:top-0[data-side=top]{top:calc(var(--spacing) * 0)}.data-\[side\=top\]\:-bottom-2\.5[data-side=top]{bottom:calc(var(--spacing) * -2.5)}.data-\[side\=top\]\:h-auto[data-side=top]{height:auto}.data-\[side\=top\]\:border-b[data-side=top]{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.data-\[size\=default\]\:h-7[data-size=default]{height:calc(var(--spacing) * 7)}.data-\[size\=default\]\:max-w-xs[data-size=default]{max-width:var(--container-xs)}.data-\[size\=lg\]\:size-10[data-size=lg]{width:calc(var(--spacing) * 10);height:calc(var(--spacing) * 10)}.data-\[size\=md\]\:text-xs[data-size=md]{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.data-\[size\=sm\]\:size-6[data-size=sm]{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.data-\[size\=sm\]\:h-6[data-size=sm]{height:calc(var(--spacing) * 6)}.data-\[size\=sm\]\:max-w-64[data-size=sm]{max-width:calc(var(--spacing) * 64)}.data-\[size\=sm\]\:gap-3[data-size=sm]{gap:calc(var(--spacing) * 3)}.data-\[size\=sm\]\:py-3[data-size=sm]{padding-block:calc(var(--spacing) * 3)}.data-\[size\=sm\]\:text-xs[data-size=sm]{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}:is(.\*\:data-\[slot\=avatar\]\:ring-2>*)[data-slot=avatar]{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}:is(.\*\:data-\[slot\=avatar\]\:ring-background>*)[data-slot=avatar]{--tw-ring-color:var(--background)}.data-\[slot\=checkbox-group\]\:gap-3[data-slot=checkbox-group]{gap:calc(var(--spacing) * 3)}:is(.\*\:data-\[slot\=field\]\:p-2>*)[data-slot=field]{padding:calc(var(--spacing) * 2)}:is(.\*\:data-\[slot\=field-group\]\:gap-4>*)[data-slot=field-group]{gap:calc(var(--spacing) * 4)}:is(.\*\:data-\[slot\=input-group\]\:m-1>*)[data-slot=input-group]{margin:calc(var(--spacing) * 1)}:is(.\*\:data-\[slot\=input-group\]\:mb-0>*)[data-slot=input-group]{margin-bottom:calc(var(--spacing) * 0)}:is(.\*\:data-\[slot\=input-group\]\:h-7>*)[data-slot=input-group]{height:calc(var(--spacing) * 7)}:is(.\*\:data-\[slot\=input-group\]\:border-none>*)[data-slot=input-group]{--tw-border-style:none;border-style:none}:is(.\*\:data-\[slot\=input-group\]\:bg-input\/20>*)[data-slot=input-group]{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){:is(.\*\:data-\[slot\=input-group\]\:bg-input\/20>*)[data-slot=input-group]{background-color:color-mix(in oklab, var(--input) 20%, transparent)}}:is(.\*\:data-\[slot\=input-group\]\:shadow-none>*)[data-slot=input-group]{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}:is(.\*\*\:data-\[slot\=kbd\]\:rounded-\[calc\(var\(--radius-sm\)-2px\)\] *)[data-slot=kbd]{border-radius:calc(var(--radius-sm) - 2px)}:is(.\*\*\:data-\[slot\=kbd\]\:rounded-md *)[data-slot=kbd]{border-radius:var(--radius)}:is(.\*\*\:data-\[slot\=kbd\]\:bg-muted-foreground\/10 *)[data-slot=kbd]{background-color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){:is(.\*\*\:data-\[slot\=kbd\]\:bg-muted-foreground\/10 *)[data-slot=kbd]{background-color:color-mix(in oklab, var(--muted-foreground) 10%, transparent)}}:is(.\*\*\:data-\[slot\=kbd\]\:px-1 *)[data-slot=kbd]{padding-inline:calc(var(--spacing) * 1)}:is(.\*\*\:data-\[slot\=kbd\]\:text-\[0\.625rem\] *)[data-slot=kbd]{font-size:.625rem}:is(.\*\:data-\[slot\=select-value\]\:line-clamp-1>*)[data-slot=select-value]{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}:is(.\*\:data-\[slot\=select-value\]\:flex>*)[data-slot=select-value]{display:flex}:is(.\*\:data-\[slot\=select-value\]\:items-center>*)[data-slot=select-value]{align-items:center}:is(.\*\:data-\[slot\=select-value\]\:gap-1\.5>*)[data-slot=select-value]{gap:calc(var(--spacing) * 1.5)}.data-\[variant\=destructive\]\:text-destructive[data-variant=destructive]{color:var(--destructive)}.data-\[variant\=destructive\]\:focus\:bg-destructive\/10[data-variant=destructive]:focus{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.data-\[variant\=destructive\]\:focus\:bg-destructive\/10[data-variant=destructive]:focus{background-color:color-mix(in oklab, var(--destructive) 10%, transparent)}}.data-\[variant\=destructive\]\:focus\:text-destructive[data-variant=destructive]:focus{color:var(--destructive)}.data-\[variant\=label\]\:text-xs\/relaxed[data-variant=label]{font-size:var(--text-xs);line-height:var(--leading-relaxed)}.data-\[variant\=legend\]\:text-sm[data-variant=legend]{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.nth-last-2\:-mt-1:nth-last-child(2){margin-top:calc(var(--spacing) * -1)}@supports ((-webkit-backdrop-filter:var(--tw)) or (backdrop-filter:var(--tw))){.supports-backdrop-filter\:backdrop-blur-xs{--tw-backdrop-blur:blur(var(--blur-xs));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}}@media (width>=40rem){.sm\:flex{display:flex}.sm\:max-w-lg{max-width:var(--container-lg)}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:justify-end{justify-content:flex-end}.sm\:group-data-\[size\=default\]\/alert-dialog-content\:row-span-2:is(:where(.group\/alert-dialog-content)[data-size=default] *){grid-row:span 2/span 2}.sm\:group-data-\[size\=default\]\/alert-dialog-content\:place-items-start:is(:where(.group\/alert-dialog-content)[data-size=default] *){place-items:start}.sm\:group-data-\[size\=default\]\/alert-dialog-content\:text-left:is(:where(.group\/alert-dialog-content)[data-size=default] *){text-align:left}.sm\:group-data-\[size\=default\]\/alert-dialog-content\:group-has-data-\[slot\=alert-dialog-media\]\/alert-dialog-content\:col-start-2:is(:where(.group\/alert-dialog-content)[data-size=default] *):is(:where(.group\/alert-dialog-content):has([data-slot=alert-dialog-media]) *){grid-column-start:2}.sm\:group-data-\[size\=default\]\/alert-dialog-content\:has-data-\[slot\=alert-dialog-media\]\:grid-rows-\[auto_1fr\]:is(:where(.group\/alert-dialog-content)[data-size=default] *):has([data-slot=alert-dialog-media]){grid-template-rows:auto 1fr}.data-\[side\=left\]\:sm\:max-w-sm[data-side=left],.data-\[side\=right\]\:sm\:max-w-sm[data-side=right],.data-\[size\=default\]\:sm\:max-w-sm[data-size=default]{max-width:var(--container-sm)}}@media (width>=48rem){.md\:block{display:block}.md\:flex{display:flex}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:text-xs\/relaxed{font-size:var(--text-xs);line-height:var(--leading-relaxed)}.md\:text-pretty{text-wrap:pretty}.md\:opacity-0{opacity:0}.md\:peer-data-\[variant\=inset\]\:m-2:is(:where(.peer)[data-variant=inset]~*){margin:calc(var(--spacing) * 2)}.md\:peer-data-\[variant\=inset\]\:ml-0:is(:where(.peer)[data-variant=inset]~*){margin-left:calc(var(--spacing) * 0)}.md\:peer-data-\[variant\=inset\]\:rounded-xl:is(:where(.peer)[data-variant=inset]~*){border-radius:calc(var(--radius) + 4px)}.md\:peer-data-\[variant\=inset\]\:shadow-sm:is(:where(.peer)[data-variant=inset]~*){--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.md\:peer-data-\[variant\=inset\]\:peer-data-\[state\=collapsed\]\:ml-2:is(:where(.peer)[data-variant=inset]~*):is(:where(.peer)[data-state=collapsed]~*){margin-left:calc(var(--spacing) * 2)}.md\:after\:hidden:after{content:var(--tw-content);display:none}}@media (width>=64rem){.lg\:block{display:block}}@media (width>=80rem){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@container field-group (width>=28rem){.\@md\/field-group\:flex-row{flex-direction:row}.\@md\/field-group\:items-center{align-items:center}.\@md\/field-group\:has-\[\>\[data-slot\=field-content\]\]\:items-start:has(>[data-slot=field-content]){align-items:flex-start}}.dark\:scale-0:where(.dark,.dark *){--tw-scale-x:0%;--tw-scale-y:0%;--tw-scale-z:0%;scale:var(--tw-scale-x) var(--tw-scale-y)}.dark\:scale-100:where(.dark,.dark *){--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y)}.dark\:-rotate-90:where(.dark,.dark *){rotate:-90deg}.dark\:rotate-0:where(.dark,.dark *){rotate:0deg}.dark\:bg-destructive\/20:where(.dark,.dark *){background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-destructive\/20:where(.dark,.dark *){background-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.dark\:bg-gray-800:where(.dark,.dark *){background-color:var(--color-gray-800)}.dark\:bg-green-900:where(.dark,.dark *){background-color:var(--color-green-900)}.dark\:bg-input\/30:where(.dark,.dark *){background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-input\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--input) 30%, transparent)}}.dark\:bg-muted\/30:where(.dark,.dark *){background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-muted\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--muted) 30%, transparent)}}.dark\:bg-popover:where(.dark,.dark *){background-color:var(--popover)}.dark\:bg-red-900:where(.dark,.dark *){background-color:var(--color-red-900)}.dark\:bg-transparent:where(.dark,.dark *){background-color:#0000}.dark\:bg-yellow-900:where(.dark,.dark *){background-color:var(--color-yellow-900)}.dark\:bg-zinc-800:where(.dark,.dark *){background-color:var(--color-zinc-800)}.dark\:text-emerald-400:where(.dark,.dark *){color:var(--color-emerald-400)}.dark\:text-gray-100:where(.dark,.dark *){color:var(--color-gray-100)}.dark\:text-green-100:where(.dark,.dark *){color:var(--color-green-100)}.dark\:text-red-100:where(.dark,.dark *){color:var(--color-red-100)}.dark\:text-yellow-100:where(.dark,.dark *){color:var(--color-yellow-100)}.dark\:text-zinc-400:where(.dark,.dark *){color:var(--color-zinc-400)}.dark\:invert:where(.dark,.dark *){--tw-invert:invert(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.dark\:after\:mix-blend-lighten:where(.dark,.dark *):after{content:var(--tw-content);mix-blend-mode:lighten}@media (hover:hover){.dark\:hover\:bg-destructive\/30:where(.dark,.dark *):hover{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:hover\:bg-destructive\/30:where(.dark,.dark *):hover{background-color:color-mix(in oklab, var(--destructive) 30%, transparent)}}.dark\:hover\:bg-input\/50:where(.dark,.dark *):hover{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.dark\:hover\:bg-input\/50:where(.dark,.dark *):hover{background-color:color-mix(in oklab, var(--input) 50%, transparent)}}.dark\:hover\:bg-muted\/50:where(.dark,.dark *):hover{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.dark\:hover\:bg-muted\/50:where(.dark,.dark *):hover{background-color:color-mix(in oklab, var(--muted) 50%, transparent)}}}.dark\:focus-visible\:ring-destructive\/40:where(.dark,.dark *):focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:focus-visible\:ring-destructive\/40:where(.dark,.dark *):focus-visible{--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.dark\:has-aria-invalid\:border-destructive\/50:where(.dark,.dark *):has([aria-invalid=true]){border-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:has-aria-invalid\:border-destructive\/50:where(.dark,.dark *):has([aria-invalid=true]){border-color:color-mix(in oklab, var(--destructive) 50%, transparent)}}.dark\:has-aria-invalid\:ring-destructive\/40:where(.dark,.dark *):has([aria-invalid=true]){--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:has-aria-invalid\:ring-destructive\/40:where(.dark,.dark *):has([aria-invalid=true]){--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.dark\:has-data-checked\:bg-primary\/10:where(.dark,.dark *):has([data-checked]){background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.dark\:has-data-checked\:bg-primary\/10:where(.dark,.dark *):has([data-checked]){background-color:color-mix(in oklab, var(--primary) 10%, transparent)}}.dark\:has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/40:where(.dark,.dark *):has([data-slot][aria-invalid=true]){--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/40:where(.dark,.dark *):has([data-slot][aria-invalid=true]){--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.dark\:aria-invalid\:border-destructive\/50:where(.dark,.dark *)[aria-invalid=true]{border-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:aria-invalid\:border-destructive\/50:where(.dark,.dark *)[aria-invalid=true]{border-color:color-mix(in oklab, var(--destructive) 50%, transparent)}}.dark\:aria-invalid\:ring-destructive\/40:where(.dark,.dark *)[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:aria-invalid\:ring-destructive\/40:where(.dark,.dark *)[aria-invalid=true]{--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.dark\:data-\[variant\=destructive\]\:focus\:bg-destructive\/20:where(.dark,.dark *)[data-variant=destructive]:focus{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:data-\[variant\=destructive\]\:focus\:bg-destructive\/20:where(.dark,.dark *)[data-variant=destructive]:focus{background-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:size-4 svg{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-2\.5 svg:not([class*=size-]){width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5)}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-3 svg:not([class*=size-]){width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-3\.5 svg:not([class*=size-]){width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-4 svg:not([class*=size-]){width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\[\.border-b\]\:pb-2.border-b{padding-bottom:calc(var(--spacing) * 2)}.\[\.border-b\]\:pb-4.border-b{padding-bottom:calc(var(--spacing) * 4)}.group-data-\[size\=sm\]\/card\:\[\.border-b\]\:pb-3:is(:where(.group\/card)[data-size=sm] *).border-b{padding-bottom:calc(var(--spacing) * 3)}.\[\.border-t\]\:pt-2.border-t{padding-top:calc(var(--spacing) * 2)}.\[\.border-t\]\:pt-4.border-t{padding-top:calc(var(--spacing) * 4)}.group-data-\[size\=sm\]\/card\:\[\.border-t\]\:pt-3:is(:where(.group\/card)[data-size=sm] *).border-t{padding-top:calc(var(--spacing) * 3)}:is(.\*\:\[a\]\:underline>*):is(a){text-decoration-line:underline}:is(.\*\:\[a\]\:underline-offset-3>*):is(a){text-underline-offset:3px}@media (hover:hover){.\[a\]\:hover\:bg-destructive\/20:is(a):hover{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.\[a\]\:hover\:bg-destructive\/20:is(a):hover{background-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.\[a\]\:hover\:bg-muted:is(a):hover{background-color:var(--muted)}.\[a\]\:hover\:bg-primary\/80:is(a):hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.\[a\]\:hover\:bg-primary\/80:is(a):hover{background-color:color-mix(in oklab, var(--primary) 80%, transparent)}}.\[a\]\:hover\:bg-secondary\/80:is(a):hover{background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){.\[a\]\:hover\:bg-secondary\/80:is(a):hover{background-color:color-mix(in oklab, var(--secondary) 80%, transparent)}}.\[a\]\:hover\:text-muted-foreground:is(a):hover{color:var(--muted-foreground)}:is(.\*\:\[a\]\:hover\:text-foreground>*):is(a):hover{color:var(--foreground)}}:is(.\*\:\[img\:first-child\]\:rounded-t-lg>*):is(img:first-child){border-top-left-radius:calc(var(--radius) + 2px);border-top-right-radius:calc(var(--radius) + 2px)}:is(.\*\:\[img\:last-child\]\:rounded-b-lg>*):is(img:last-child){border-bottom-right-radius:calc(var(--radius) + 2px);border-bottom-left-radius:calc(var(--radius) + 2px)}:is(.\*\:\[span\]\:last\:flex>*):is(span):last-child{display:flex}:is(.\*\:\[span\]\:last\:items-center>*):is(span):last-child{align-items:center}:is(.\*\:\[span\]\:last\:gap-2>*):is(span):last-child{gap:calc(var(--spacing) * 2)}:is(.data-\[variant\=destructive\]\:\*\:\[svg\]\:text-destructive[data-variant=destructive]>*):is(svg){color:var(--destructive)}:is(.\*\:\[svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-4>*):is(svg:not([class*=size-])){width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\[\&\>\*\]\:w-full>*{width:100%}@container field-group (width>=28rem){.\@md\/field-group\:\[\&\>\*\]\:w-auto>*{width:auto}}.\[\&\>\.sr-only\]\:w-auto>.sr-only{width:auto}.\[\&\>\[data-slot\=field-label\]\]\:flex-auto>[data-slot=field-label]{flex:auto}@container field-group (width>=28rem){.\@md\/field-group\:\[\&\>\[data-slot\=field-label\]\]\:flex-auto>[data-slot=field-label]{flex:auto}}.has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content])>[role=checkbox],.has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content]) [role=radio]{margin-top:1px}@container field-group (width>=28rem){.\@md\/field-group\:has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content])>[role=checkbox],.\@md\/field-group\:has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content]) [role=radio]{margin-top:1px}}.\[\&\>a\]\:underline>a{text-decoration-line:underline}.\[\&\>a\]\:underline-offset-4>a{text-underline-offset:4px}.\[\&\>a\:hover\]\:text-primary>a:hover{color:var(--primary)}.\[\&\>button\]\:hidden>button{display:none}.has-\[\>\[data-align\=block-end\]\]\:\[\&\>input\]\:pt-3:has(>[data-align=block-end])>input{padding-top:calc(var(--spacing) * 3)}.has-\[\>\[data-align\=block-start\]\]\:\[\&\>input\]\:pb-3:has(>[data-align=block-start])>input{padding-bottom:calc(var(--spacing) * 3)}.has-\[\>\[data-align\=inline-end\]\]\:\[\&\>input\]\:pr-1\.5:has(>[data-align=inline-end])>input{padding-right:calc(var(--spacing) * 1.5)}.has-\[\>\[data-align\=inline-start\]\]\:\[\&\>input\]\:pl-1\.5:has(>[data-align=inline-start])>input{padding-left:calc(var(--spacing) * 1.5)}.\[\&\>span\:last-child\]\:truncate>span:last-child{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.\[\&\>svg\]\:pointer-events-none>svg{pointer-events:none}.\[\&\>svg\]\:size-2\.5\!>svg{width:calc(var(--spacing) * 2.5)!important;height:calc(var(--spacing) * 2.5)!important}.\[\&\>svg\]\:size-4>svg{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\[\&\>svg\]\:shrink-0>svg{flex-shrink:0}.\[\&\>svg\]\:text-sidebar-accent-foreground>svg{color:var(--sidebar-accent-foreground)}.group-has-data-\[size\=lg\]\/avatar-group\:\[\&\>svg\]\:size-5:is(:where(.group\/avatar-group):has([data-size=lg]) *)>svg{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.group-has-data-\[size\=sm\]\/avatar-group\:\[\&\>svg\]\:size-3:is(:where(.group\/avatar-group):has([data-size=sm]) *)>svg{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.group-data-\[size\=default\]\/avatar\:\[\&\>svg\]\:size-2:is(:where(.group\/avatar)[data-size=default] *)>svg,.group-data-\[size\=lg\]\/avatar\:\[\&\>svg\]\:size-2:is(:where(.group\/avatar)[data-size=lg] *)>svg{width:calc(var(--spacing) * 2);height:calc(var(--spacing) * 2)}.group-data-\[size\=sm\]\/avatar\:\[\&\>svg\]\:hidden:is(:where(.group\/avatar)[data-size=sm] *)>svg{display:none}.\[\&\>svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-3>svg:not([class*=size-]){width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.\[\&\>svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-3\.5>svg:not([class*=size-]){width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}[data-side=left][data-collapsible=offExamples] .\[\[data-side\=left\]\[data-collapsible\=offExamples\]_\&\]\:-right-2{right:calc(var(--spacing) * -2)}[data-side=left][data-state=collapsed] .\[\[data-side\=left\]\[data-state\=collapsed\]_\&\]\:cursor-e-resize{cursor:e-resize}[data-side=right][data-collapsible=offExamples] .\[\[data-side\=right\]\[data-collapsible\=offExamples\]_\&\]\:-left-2{left:calc(var(--spacing) * -2)}[data-side=right][data-state=collapsed] .\[\[data-side\=right\]\[data-state\=collapsed\]_\&\]\:cursor-w-resize{cursor:w-resize}[data-variant=legend]+.\[\[data-variant\=legend\]\+\&\]\:-mt-1\.5{margin-top:calc(var(--spacing) * -1.5)}}@font-face{font-family:Geist Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/geist-cyrillic-wght-normal.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Geist Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/geist-latin-ext-wght-normal.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Geist Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/geist-latin-wght-normal.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(data:font/woff2;base64,d09GMgABAAAAAAfsABQAAAAAEAwAAAeCAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhwbHhwoP0hWQVJbBmA/U1RBVIFiJyYAdC9qEQgKhGSEAAsgADCGCAE2AiQDOgQgBYlMB4EUDAcbLQ4onoexrSC/2ZyLAa8p8VHB8/x3Vue+V0hVJalMJg2nx/TCrQXxBeqLjQG7FyM1WEa/X1tEXN7cFz9EJEMmMUz3RihWSSKeQCbcIou0izz/C8v+fq3VfajEa9gDD11CImXS7qL/RJFVzC1qiB6KmKeD6TZdQ6IRGv78dL6uSVVCfgni5mzu7kcgQBgAEAQTQRCoL++STTYybkJxNfQxAAIAGu8OdEB9teW2jh4BpgDqFjAeSEByW3zFP0CBBgNMsMCGEDjgggdhiEAUAeIIED7ABTDUEnkIE9Q9ahFgKttcVhApo4ACB4qobHaccgDfEjFO6aaWUhjMLt2SyIvHKoDqoA4CSUwEIYQCEjhAO9R1G6keDeDZGjNo+AhxOjCEGTr1WeIF3kYBiLAOKvkJSMiKX0VdAyQt3SDJClCkxJCHkCzfqyVTriJZLcolS32JZHUekq2TYNkYtCtjYHMQXSxGjXDz2t/yLWXzDzxz+o3zFwDEaN23F+13pyMdQAEaSKAR9vcGq4A4MTSKCElGW+M7UcY7xqkggITb28ZJhlqc9q2twYKTt0NjixBgYvO9BIihEBLYuOFXQzfIQ7dXGUEEEgFDooBfAzqiQbpJrhiWSuKJCRFKYbHCyJKI2G5GiZbNAvgAu5pc3vwx4G+g3aDkhklABiSz0BICXrYghtYhx/cdJ+44rY2oZ0aMNRFz3VZjb6W33F3gzltqtOCV8tTHSpOeXuItfvr5lCdfzFpqtEitvqdcdGGFd28ZqqC0tPbeChGXgrIlnhSWu/eUso4uKWFLugyDzQJhflY4659+WjQ++6x72WUMv9G8mw6QJl7BVxX5fe/kpUsOvnZwee9uQ0cGXYd0o89XB2748sDSnt8d2VphdOTTgceDVvOds0v9P/s7HPq15aGun/6Vllb56f1dl0t1LejqrNkpdRZsG8TOnM5vkBG5oiVyVGnS8LHps5cfNWJs6qKPfaNSxiQNBUm3cKNWROr0GSur7Za31k1vieq7LH11VF+jXdRIasRKflc7jkobm1Z9te1IyZA0pDkhLR98+H37Zf1c/8at+dB7x+7GfVyTfJMPiYztsnl59Y5l4j+0n1RXlpHnF3Tq7HecmNF/CJodEMAikruxiyJaGLvHOdAfoA+oDvpjBm2b91cHGRZMU9n25xEU0A8fgEEAdKI3Q1iDtc034sug5YVMkE2jsE+BIkwSoQ3gxXMqz9tELp48bd0cFKOKS7xYjEuXBnZP5ia7DyiO/X/YI+PQSbt2uSdqAkWL9nQbV1XB94/+uPfdZz8dnXYFBYrcTl2SIR/ybxJNJPz/Gupb0JaZeens2ekC7EKr8t+Ls/P5VJPYJdHKyqfg2nqU6bhlidzcddQV/7MmecTzJ5VPcKXkNKSEogHjYFx6QZ7rQ+FSe8njaiNuOnXS8H2ScQ619c2mC3VTtauL0rRbXd/CkSOP37FY9Zkjz8+GibYUMOEWF+RdrFS8Ecv1SHOpPUPZGEIpjPvFyU5cXKjd6OXqorTqy9GwRd++HVufPGnVsW+aO3vggKZ18jR9sXaTC1PWTEsVUaK0FkNySbTQDqlm2PfDjZcu4aalnSLKjnOoYQ0nUlqqXcGpPu/4VgV/xU2pAqW4BW3qzhQ8/hFKhV2qE3+BKAtDqBXjfgnVdH4y0wg5tbVNRenNdTWOrenWLcupQdmsbq5b+18piTe/xRdp1xbILxNPJGInm2z6hoB21Lal0i+ePTtd7B45+3XhFJ329evskXm7qurUVREotqSluSo/L29d3qDhI4YOQqWhI4YNvBNfsMHeXKemXrxQfKeuPOGRVayA3JtkJKEgbPp+dXUDluddutRYLFoXGXWX6N3WFaGLbQtRSitVYNacTNSdy7AaG/HSaUEANcBoGXNdcZvZsOqQ1icBDv21/gzAoYPHH/WDW0qNR3QTYKEAEHig6o13NXbND06CQPlRtYjGNnSktRc09k1mAMDvAlDKfQjgy6fssInlfzmNAjKkDxoxHOBLdVRAIVt9j4qo+hA1w9T1aNBNTUOTTNUHLbqokE+UAfJXCIGw/IxCSL5GRUJeR40rL/UxTm4Q08H6MbCs70ObuNyIIXrINHQYInF06UUlevTjbQzTh5upiDMzMMogUtEnjPs/Y7jAHCJeB0GBHh04tC6FiB6ZFB1oArUSIoFoqhzCeAN6lHwm0T4C3VVPWvjpSMXReuWesMEcoqrmgtNBGd2noWeV0hNAz9rFeShNJxHGsPa3HXeKTk8b55hahySYHaYKKFFLpCfN8rsoaJn01CR04Gkc+5k7KVTCmClX8Q10HCrUEkVlSX+XO33oQR9609tJ516H497WSobWs5Up6TLaS10/dessIskgJSLiDlWvHVUywpkQ7hdPZqGyiEF0uVQerVcPamT1A3eKXdyI1vG9OoflrSXihZ1qqGE3nhmAgiIbRCQgPLEPtOM3UQwTLYaYYomNlpA44opnjV6jkD6id80OOrzf6BzmMD6eEa1zKyeYG1fzfEf16V6jw9XYOaar1/b2kP/IYX8oR2mcFvv2GtBV3JXgd437AQAA)format("woff2-variations");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-cyrillic-wght-normal.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-greek-wght-normal.woff2)format("woff2-variations");unicode-range:U+370-377,U+37A-37F,U+384-38A,U+38C,U+38E-3A1,U+3A3-3FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-vietnamese-wght-normal.woff2)format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-latin-ext-wght-normal.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-latin-wght-normal.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}:root{--font-sans:"Geist Variable", sans-serif;--font-mono:"JetBrains Mono Variable", monospace;--background:#f4f1ec;--foreground:#1d2930;--card:#f9f8f6;--card-foreground:#1d2930;--popover:#fbfaf9;--popover-foreground:#1d2930;--primary:#305030;--primary-foreground:#f5f3ef;--secondary:#eae5d7;--secondary-foreground:#263740;--muted:#e9e7e2;--muted-foreground:#576b75;--accent:#e7e2da;--accent-foreground:#1d2930;--destructive:#c32222;--destructive-foreground:#fff;--border:#b6c9b6;--input:#dedbd3;--ring:#3e743e;--chart-1:#2e6b2e;--chart-2:#cfa117;--chart-3:#297aa3;--chart-4:#cc8c33;--chart-5:#b82e2e;--radius:.25rem;--sidebar:#f5f3f0;--sidebar-background:#f5f3f0;--sidebar-foreground:#263740;--sidebar-primary:#305030;--sidebar-primary-foreground:#f5f3ef;--sidebar-accent:#e7e2da;--sidebar-accent-foreground:#1d2930;--sidebar-border:#c4d4c4;--sidebar-ring:#3e743e;--tactical-amber:#c2940a;--tactical-amber-dim:#d6b85c;--tactical-green:#267326;--tactical-green-dim:#7ab87a;--tactical-cyan:#24868f;--tactical-cyan-dim:#5eb2ba;--tactical-red:#bd2828;--tactical-olive:#64783a;--scanline-opacity:.015}.dark{--background:#0d1012;--foreground:#e0ddd1;--card:#14181a;--card-foreground:#e0ddd1;--popover:#111517;--popover-foreground:#e0ddd1;--primary:#fa0;--primary-foreground:#0d1012;--secondary:#323922;--secondary-foreground:#c6d2ac;--muted:#202527;--muted-foreground:#819098;--accent:#292f32;--accent-foreground:#ebe8e0;--destructive:#c32222;--destructive-foreground:#fff;--border:#203c32;--input:#292f32;--ring:#ffbf00;--chart-1:#ffbf00;--chart-2:#22c38e;--chart-3:#1aa1e6;--chart-4:#86ac39;--chart-5:#d92626;--sidebar:#111517;--sidebar-background:#111517;--sidebar-foreground:#e0ddd1;--sidebar-primary:#ffbf00;--sidebar-primary-foreground:#0d1012;--sidebar-accent:#292f32;--sidebar-accent-foreground:#ebe8e0;--sidebar-border:#203c32;--sidebar-ring:#ffbf00;--tactical-amber:#ffbf00;--tactical-amber-dim:#a17d12;--tactical-green:#22c38e;--tactical-green-dim:#20604a;--tactical-cyan:#17bfcf;--tactical-cyan-dim:#196066;--tactical-red:#d92626;--tactical-olive:#576b2e;--scanline-opacity:.03}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-pan-x{syntax:"*";inherits:false}@property --tw-pan-y{syntax:"*";inherits:false}@property --tw-pinch-zoom{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@keyframes pulse{50%{opacity:.5}} +@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-pan-x:initial;--tw-pan-y:initial;--tw-pinch-zoom:initial;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-divide-x-reverse:0;--tw-border-style:solid;--tw-divide-y-reverse:0;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-content:""}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-100:#ffe2e2;--color-red-800:#9f0712;--color-red-900:#82181a;--color-amber-500:#f99c00;--color-yellow-100:#fef9c2;--color-yellow-800:#874b00;--color-yellow-900:#733e0a;--color-green-100:#dcfce7;--color-green-600:#00a544;--color-green-800:#016630;--color-green-900:#0d542b;--color-emerald-400:#00d294;--color-emerald-500:#00bb7f;--color-emerald-700:#007956;--color-blue-500:#3080ff;--color-gray-100:#f3f4f6;--color-gray-800:#1e2939;--color-zinc-100:#f4f4f5;--color-zinc-400:#9f9fa9;--color-zinc-500:#71717b;--color-zinc-800:#27272a;--color-black:#000;--spacing:.25rem;--container-xs:20rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--container-2xl:42rem;--container-4xl:56rem;--container-6xl:72rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wider:.05em;--tracking-widest:.1em;--leading-snug:1.375;--leading-normal:1.5;--leading-relaxed:1.625;--radius-sm:calc(var(--radius) - 2px);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-xs:4px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}@supports (color:lab(0% 0 0)){:root,:host{--color-red-100:lab(92.243% 10.2865 3.83865);--color-red-800:lab(33.7174% 55.8993 41.0293);--color-red-900:lab(28.5139% 44.5539 29.0463);--color-amber-500:lab(72.7183% 31.8672 97.9407);--color-yellow-100:lab(97.3564% -4.51407 27.344);--color-yellow-800:lab(38.7484% 23.5833 51.4916);--color-yellow-900:lab(32.3865% 21.1273 38.5959);--color-green-100:lab(96.1861% -13.8464 6.52365);--color-green-600:lab(59.0978% -58.6621 41.2579);--color-green-800:lab(37.4616% -36.7971 22.9692);--color-green-900:lab(30.797% -29.6927 17.382);--color-emerald-400:lab(75.0771% -60.7313 19.4147);--color-emerald-500:lab(66.9756% -58.27 19.5419);--color-emerald-700:lab(44.4871% -41.0396 11.0361);--color-blue-500:lab(54.1736% 13.3369 -74.6839);--color-gray-100:lab(96.1596% -.0823438 -1.13575);--color-gray-800:lab(16.1051% -1.18239 -11.7533);--color-zinc-100:lab(96.1634% .0993311 -.364041);--color-zinc-400:lab(65.6464% 1.53497 -5.42429);--color-zinc-500:lab(47.8878% 1.65477 -5.77283);--color-zinc-800:lab(15.7305% .613764 -2.16959)}}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*{border-color:var(--border);outline-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){*{outline-color:color-mix(in oklab, var(--ring) 50%, transparent)}}*{scrollbar-width:thin}html,body{overscroll-behavior:none}body{background-color:var(--background);width:100%;min-height:100svh;color:var(--foreground);font-family:var(--font-sans), sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.font-mono{font-family:var(--font-mono), monospace}button:not(:disabled),[role=button]:not(:disabled){cursor:pointer}}@layer components;@layer utilities{.\@container\/card-header{container:card-header/inline-size}.\@container\/field-group{container:field-group/inline-size}.\@container{container-type:inline-size}.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.not-sr-only{clip-path:none;white-space:normal;width:auto;height:auto;margin:0;padding:0;position:static;overflow:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.inset-y-0{inset-block:calc(var(--spacing) * 0)}.top-0{top:calc(var(--spacing) * 0)}.top-1\.5{top:calc(var(--spacing) * 1.5)}.top-1\/2{top:50%}.top-3\.5{top:calc(var(--spacing) * 3.5)}.top-4{top:calc(var(--spacing) * 4)}.right-0{right:calc(var(--spacing) * 0)}.right-1{right:calc(var(--spacing) * 1)}.right-2{right:calc(var(--spacing) * 2)}.right-3{right:calc(var(--spacing) * 3)}.right-4{right:calc(var(--spacing) * 4)}.bottom-0{bottom:calc(var(--spacing) * 0)}.left-0{left:calc(var(--spacing) * 0)}.left-1\/2{left:50%}.isolate{isolation:isolate}.isolation-auto{isolation:auto}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.order-first{order:-9999}.order-last{order:9999}.col-span-2{grid-column:span 2/span 2}.col-start-2{grid-column-start:2}.row-span-2{grid-row:span 2/span 2}.row-start-1{grid-row-start:1}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.-mx-1{margin-inline:calc(var(--spacing) * -1)}.mx-0{margin-inline:calc(var(--spacing) * 0)}.mx-2{margin-inline:calc(var(--spacing) * 2)}.mx-3\.5{margin-inline:calc(var(--spacing) * 3.5)}.mx-auto{margin-inline:auto}.-my-2{margin-block:calc(var(--spacing) * -2)}.my-1{margin-block:calc(var(--spacing) * 1)}.my-2{margin-block:calc(var(--spacing) * 2)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-auto{margin-top:auto}.mr-2{margin-right:calc(var(--spacing) * 2)}.mr-auto{margin-right:auto}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.-ml-1{margin-left:calc(var(--spacing) * -1)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-4{margin-left:calc(var(--spacing) * 4)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.flow-root{display:flow-root}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.inline-grid{display:inline-grid}.inline-table{display:inline-table}.list-item{display:list-item}.table{display:table}.table-caption{display:table-caption}.table-cell{display:table-cell}.table-column{display:table-column}.table-column-group{display:table-column-group}.table-footer-group{display:table-footer-group}.table-header-group{display:table-header-group}.table-row{display:table-row}.table-row-group{display:table-row-group}.field-sizing-content{field-sizing:content}.aspect-square{aspect-ratio:1}.size-2\.5{width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5)}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-3\.5{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-5{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.size-6{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.size-7{width:calc(var(--spacing) * 7);height:calc(var(--spacing) * 7)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.size-12{width:calc(var(--spacing) * 12);height:calc(var(--spacing) * 12)}.size-\[1\.2rem\]{width:1.2rem;height:1.2rem}.size-full{width:100%;height:100%}.h-3{height:calc(var(--spacing) * 3)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-12{height:calc(var(--spacing) * 12)}.h-\[calc\(--spacing\(4\.75\)\)\]{height:calc(calc(var(--spacing) * 4.75))}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.h-svh{height:100svh}.max-h-\(--available-height\){max-height:var(--available-height)}.max-h-72{max-height:calc(var(--spacing) * 72)}.max-h-96{max-height:calc(var(--spacing) * 96)}.max-h-\[min\(calc\(--spacing\(72\)---spacing\(9\)\)\,calc\(var\(--available-height\)---spacing\(9\)\)\)\]{max-height:min(calc(calc(var(--spacing) * 72) - calc(var(--spacing) * 9)), calc(var(--available-height) - calc(var(--spacing) * 9)))}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-7{min-height:calc(var(--spacing) * 7)}.min-h-16{min-height:calc(var(--spacing) * 16)}.min-h-svh{min-height:100svh}.w-\(--anchor-width\){width:var(--anchor-width)}.w-\(--sidebar-width\){width:var(--sidebar-width)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-24{width:calc(var(--spacing) * 24)}.w-32{width:calc(var(--spacing) * 32)}.w-36{width:calc(var(--spacing) * 36)}.w-48{width:calc(var(--spacing) * 48)}.w-auto{width:auto}.w-fit{width:fit-content}.w-full{width:100%}.max-w-\(--available-width\){max-width:var(--available-width)}.max-w-\(--skeleton-width\){max-width:var(--skeleton-width)}.max-w-2xl{max-width:var(--container-2xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-5{min-width:calc(var(--spacing) * 5)}.min-w-16{min-width:calc(var(--spacing) * 16)}.min-w-32{min-width:calc(var(--spacing) * 32)}.min-w-\[calc\(var\(--anchor-width\)\+--spacing\(7\)\)\]{min-width:calc(var(--anchor-width) + calc(var(--spacing) * 7))}.flex-1{flex:1}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.border-collapse{border-collapse:collapse}.origin-\(--transform-origin\){transform-origin:var(--transform-origin)}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-x-px{--tw-translate-x:-1px;translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-px{--tw-translate-x:1px;translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-y-\[calc\(-50\%-2px\)\]{--tw-translate-y:calc(-50% - 2px);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-none{translate:none}.scale-0{--tw-scale-x:0%;--tw-scale-y:0%;--tw-scale-z:0%;scale:var(--tw-scale-x) var(--tw-scale-y)}.scale-100{--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y)}.scale-3d{scale:var(--tw-scale-x) var(--tw-scale-y) var(--tw-scale-z)}.rotate-0{rotate:0deg}.rotate-45{rotate:45deg}.rotate-90{rotate:90deg}.rotate-180{rotate:180deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-pulse{animation:var(--animate-pulse)}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.cursor-text{cursor:text}.touch-pinch-zoom{--tw-pinch-zoom:pinch-zoom;touch-action:var(--tw-pan-x,) var(--tw-pan-y,) var(--tw-pinch-zoom,)}.resize{resize:both}.resize-none{resize:none}.scroll-my-1{scroll-margin-block:calc(var(--spacing) * 1)}.scroll-py-1{scroll-padding-block:calc(var(--spacing) * 1)}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.auto-rows-min{grid-auto-rows:min-content}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-\[minmax\(0\,1fr\)\]{grid-template-columns:minmax(0,1fr)}.grid-rows-\[auto_1fr\]{grid-template-rows:auto 1fr}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-0{gap:calc(var(--spacing) * 0)}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-8{gap:calc(var(--spacing) * 8)}.gap-px{gap:1px}:where(.space-y-0>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 0) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 0) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-reverse>:not(:last-child)){--tw-space-y-reverse:1}:where(.-space-x-2>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing) * -2) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing) * -2) * calc(1 - var(--tw-space-x-reverse)))}:where(.space-x-reverse>:not(:last-child)){--tw-space-x-reverse:1}:where(.divide-x>:not(:last-child)){--tw-divide-x-reverse:0;border-inline-style:var(--tw-border-style);border-inline-start-width:calc(1px * var(--tw-divide-x-reverse));border-inline-end-width:calc(1px * calc(1 - var(--tw-divide-x-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-y-reverse>:not(:last-child)){--tw-divide-y-reverse:1}.self-end{align-self:flex-end}.self-start{align-self:flex-start}.justify-self-end{justify-self:flex-end}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.overscroll-contain{overscroll-behavior:contain}.rounded{border-radius:.25rem}.rounded-\[2px\]{border-radius:2px}.rounded-\[calc\(var\(--radius-sm\)\+2px\)\]{border-radius:calc(var(--radius-sm) + 2px)}.rounded-\[calc\(var\(--radius-sm\)-2px\)\]{border-radius:calc(var(--radius-sm) - 2px)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:calc(var(--radius) + 2px)}.rounded-md{border-radius:var(--radius)}.rounded-none{border-radius:0}.rounded-sm{border-radius:calc(var(--radius) - 2px)}.rounded-xl{border-radius:calc(var(--radius) + 4px)}.rounded-s{border-start-start-radius:.25rem;border-end-start-radius:.25rem}.rounded-ss{border-start-start-radius:.25rem}.rounded-e{border-start-end-radius:.25rem;border-end-end-radius:.25rem}.rounded-se{border-start-end-radius:.25rem}.rounded-ee{border-end-end-radius:.25rem}.rounded-es{border-end-start-radius:.25rem}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-t-lg{border-top-left-radius:calc(var(--radius) + 2px);border-top-right-radius:calc(var(--radius) + 2px)}.rounded-l{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.rounded-tl{border-top-left-radius:.25rem}.rounded-r{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.rounded-tr{border-top-right-radius:.25rem}.rounded-b{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.rounded-b-lg{border-bottom-right-radius:calc(var(--radius) + 2px);border-bottom-left-radius:calc(var(--radius) + 2px)}.rounded-br{border-bottom-right-radius:.25rem}.rounded-bl{border-bottom-left-radius:.25rem}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.border-s{border-inline-start-style:var(--tw-border-style);border-inline-start-width:1px}.border-e{border-inline-end-style:var(--tw-border-style);border-inline-end-width:1px}.border-bs{border-block-start-style:var(--tw-border-style);border-block-start-width:1px}.border-be{border-block-end-style:var(--tw-border-style);border-block-end-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-amber-500\/30{border-color:#f99c004d}@supports (color:color-mix(in lab, red, red)){.border-amber-500\/30{border-color:color-mix(in oklab, var(--color-amber-500) 30%, transparent)}}.border-blue-500\/30{border-color:#3080ff4d}@supports (color:color-mix(in lab, red, red)){.border-blue-500\/30{border-color:color-mix(in oklab, var(--color-blue-500) 30%, transparent)}}.border-border{border-color:var(--border)}.border-destructive{border-color:var(--destructive)}.border-emerald-500{border-color:var(--color-emerald-500)}.border-emerald-500\/30{border-color:#00bb7f4d}@supports (color:color-mix(in lab, red, red)){.border-emerald-500\/30{border-color:color-mix(in oklab, var(--color-emerald-500) 30%, transparent)}}.border-foreground\/10{border-color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.border-foreground\/10{border-color:color-mix(in oklab, var(--foreground) 10%, transparent)}}.border-foreground\/20{border-color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.border-foreground\/20{border-color:color-mix(in oklab, var(--foreground) 20%, transparent)}}.border-input{border-color:var(--input)}.border-muted{border-color:var(--muted)}.border-sidebar-border{border-color:var(--sidebar-border)}.border-transparent{border-color:#0000}.bg-amber-500\/10{background-color:#f99c001a}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/10{background-color:color-mix(in oklab, var(--color-amber-500) 10%, transparent)}}.bg-background{background-color:var(--background)}.bg-black\/80{background-color:#000c}@supports (color:color-mix(in lab, red, red)){.bg-black\/80{background-color:color-mix(in oklab, var(--color-black) 80%, transparent)}}.bg-blue-500\/10{background-color:#3080ff1a}@supports (color:color-mix(in lab, red, red)){.bg-blue-500\/10{background-color:color-mix(in oklab, var(--color-blue-500) 10%, transparent)}}.bg-border,.bg-border\/50{background-color:var(--border)}@supports (color:color-mix(in lab, red, red)){.bg-border\/50{background-color:color-mix(in oklab, var(--border) 50%, transparent)}}.bg-card{background-color:var(--card)}.bg-destructive\/10{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.bg-destructive\/10{background-color:color-mix(in oklab, var(--destructive) 10%, transparent)}}.bg-emerald-500\/10{background-color:#00bb7f1a}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/10{background-color:color-mix(in oklab, var(--color-emerald-500) 10%, transparent)}}.bg-foreground{background-color:var(--foreground)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-green-100{background-color:var(--color-green-100)}.bg-input\/20{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.bg-input\/20{background-color:color-mix(in oklab, var(--input) 20%, transparent)}}.bg-muted{background-color:var(--muted)}.bg-muted-foreground\/10{background-color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.bg-muted-foreground\/10{background-color:color-mix(in oklab, var(--muted-foreground) 10%, transparent)}}.bg-muted\/20{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/20{background-color:color-mix(in oklab, var(--muted) 20%, transparent)}}.bg-muted\/30{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/30{background-color:color-mix(in oklab, var(--muted) 30%, transparent)}}.bg-muted\/50{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/50{background-color:color-mix(in oklab, var(--muted) 50%, transparent)}}.bg-popover{background-color:var(--popover)}.bg-primary{background-color:var(--primary)}.bg-red-100{background-color:var(--color-red-100)}.bg-secondary{background-color:var(--secondary)}.bg-sidebar{background-color:var(--sidebar)}.bg-sidebar-border{background-color:var(--sidebar-border)}.bg-transparent{background-color:#0000}.bg-yellow-100{background-color:var(--color-yellow-100)}.bg-zinc-100{background-color:var(--color-zinc-100)}.bg-clip-padding{background-clip:padding-box}.bg-repeat{background-repeat:repeat}.mask-no-clip{-webkit-mask-clip:no-clip;mask-clip:no-clip}.mask-repeat{-webkit-mask-repeat:repeat;mask-repeat:repeat}.fill-foreground{fill:var(--foreground)}.object-cover{object-fit:cover}.p-0{padding:calc(var(--spacing) * 0)}.p-1{padding:calc(var(--spacing) * 1)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-0{padding-inline:calc(var(--spacing) * 0)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.pt-0{padding-top:calc(var(--spacing) * 0)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pr-4{padding-right:calc(var(--spacing) * 4)}.pr-8{padding-right:calc(var(--spacing) * 8)}.pb-0{padding-bottom:calc(var(--spacing) * 0)}.pb-0\.5{padding-bottom:calc(var(--spacing) * .5)}.pb-1{padding-bottom:calc(var(--spacing) * 1)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pl-2{padding-left:calc(var(--spacing) * 2)}.pl-4{padding-left:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-sm\/relaxed{font-size:var(--text-sm);line-height:var(--leading-relaxed)}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-xs\/relaxed{font-size:var(--text-xs);line-height:var(--leading-relaxed)}.text-\[0\.625rem\]{font-size:.625rem}.text-\[11px\]{font-size:11px}.leading-none{--tw-leading:1;line-height:1}.leading-normal{--tw-leading:var(--leading-normal);line-height:var(--leading-normal)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.text-balance{text-wrap:balance}.text-wrap{text-wrap:wrap}.break-all{word-break:break-all}.text-clip{text-overflow:clip}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-amber-500{color:var(--color-amber-500)}.text-background{color:var(--background)}.text-card-foreground{color:var(--card-foreground)}.text-destructive{color:var(--destructive)}.text-emerald-700{color:var(--color-emerald-700)}.text-foreground{color:var(--foreground)}.text-gray-800{color:var(--color-gray-800)}.text-green-600{color:var(--color-green-600)}.text-green-800{color:var(--color-green-800)}.text-muted-foreground{color:var(--muted-foreground)}.text-popover-foreground{color:var(--popover-foreground)}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.text-red-800{color:var(--color-red-800)}.text-secondary-foreground{color:var(--secondary-foreground)}.text-sidebar-foreground,.text-sidebar-foreground\/70{color:var(--sidebar-foreground)}@supports (color:color-mix(in lab, red, red)){.text-sidebar-foreground\/70{color:color-mix(in oklab, var(--sidebar-foreground) 70%, transparent)}}.text-tactical-amber{color:var(--tactical-amber)}.text-tactical-cyan{color:var(--tactical-cyan)}.text-tactical-green{color:var(--tactical-green)}.text-yellow-800{color:var(--color-yellow-800)}.text-zinc-500{color:var(--color-zinc-500)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.italic{font-style:italic}.not-italic{font-style:normal}.diagonal-fractions{--tw-numeric-fraction:diagonal-fractions;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.lining-nums{--tw-numeric-figure:lining-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.oldstyle-nums{--tw-numeric-figure:oldstyle-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.ordinal{--tw-ordinal:ordinal;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.proportional-nums{--tw-numeric-spacing:proportional-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.slashed-zero{--tw-slashed-zero:slashed-zero;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.stacked-fractions{--tw-numeric-fraction:stacked-fractions;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.normal-nums{font-variant-numeric:normal}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.overline{text-decoration-line:overline}.underline{text-decoration-line:underline}.underline-offset-4{text-underline-offset:4px}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.subpixel-antialiased{-webkit-font-smoothing:auto;-moz-osx-font-smoothing:auto}.opacity-50{opacity:.5}.bg-blend-color{background-blend-mode:color}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_0_0_1px_hsl\(var\(--sidebar-border\)\)\]{--tw-shadow:0 0 0 1px var(--tw-shadow-color,hsl(var(--sidebar-border)));box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-0{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.inset-ring{--tw-inset-ring-shadow:inset 0 0 0 1px var(--tw-inset-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-background{--tw-ring-color:var(--background)}.ring-foreground\/10{--tw-ring-color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.ring-foreground\/10{--tw-ring-color:color-mix(in oklab, var(--foreground) 10%, transparent)}}.ring-sidebar-ring{--tw-ring-color:var(--sidebar-ring)}.outline-hidden{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.outline-hidden{outline-offset:2px;outline:2px solid #0000}}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.drop-shadow{--tw-drop-shadow-size:drop-shadow(0 1px 2px var(--tw-drop-shadow-color,#0000001a)) drop-shadow(0 1px 1px var(--tw-drop-shadow-color,#0000000f));--tw-drop-shadow:drop-shadow(0 1px 2px #0000001a) drop-shadow(0 1px 1px #0000000f);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-grayscale{--tw-backdrop-grayscale:grayscale(100%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-invert{--tw-backdrop-invert:invert(100%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-sepia{--tw-backdrop-sepia:sepia(100%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[left\,right\,width\]{transition-property:left,right,width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[margin\,opacity\]{transition-property:margin,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[width\,height\,padding\]{transition-property:width,height,padding;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[width\]{transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-100{--tw-duration:.1s;transition-duration:.1s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-linear{--tw-ease:linear;transition-timing-function:linear}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}:where(.divide-x-reverse>:not(:last-child)){--tw-divide-x-reverse:1}.ring-inset{--tw-ring-inset:inset}.group-focus-within\/menu-item\:opacity-100:is(:where(.group\/menu-item):focus-within *){opacity:1}@media (hover:hover){.group-hover\/menu-item\:opacity-100:is(:where(.group\/menu-item):hover *){opacity:1}}.group-focus\/dropdown-menu-item\:text-accent-foreground:is(:where(.group\/dropdown-menu-item):focus *){color:var(--accent-foreground)}.group-has-data-\[orientation\=horizontal\]\/field\:text-balance:is(:where(.group\/field):has([data-orientation=horizontal]) *){text-wrap:balance}.group-has-data-\[sidebar\=menu-action\]\/menu-item\:pr-8:is(:where(.group\/menu-item):has([data-sidebar=menu-action]) *){padding-right:calc(var(--spacing) * 8)}.group-has-data-\[size\=lg\]\/avatar-group\:size-10:is(:where(.group\/avatar-group):has([data-size=lg]) *){width:calc(var(--spacing) * 10);height:calc(var(--spacing) * 10)}.group-has-data-\[size\=sm\]\/avatar-group\:size-6:is(:where(.group\/avatar-group):has([data-size=sm]) *){width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.group-has-data-\[slot\=combobox-clear\]\/input-group\:hidden:is(:where(.group\/input-group):has([data-slot=combobox-clear]) *){display:none}.group-has-\[\>input\]\/input-group\:pt-2:is(:where(.group\/input-group):has(>input) *){padding-top:calc(var(--spacing) * 2)}.group-has-\[\>input\]\/input-group\:pb-2:is(:where(.group\/input-group):has(>input) *){padding-bottom:calc(var(--spacing) * 2)}.group-data-empty\/combobox-content\:flex:is(:where(.group\/combobox-content)[data-empty] *){display:flex}.group-data-\[collapsible\=icon\]\:-mt-8:is(:where(.group)[data-collapsible=icon] *){margin-top:calc(var(--spacing) * -8)}.group-data-\[collapsible\=icon\]\:hidden:is(:where(.group)[data-collapsible=icon] *){display:none}.group-data-\[collapsible\=icon\]\:size-8\!:is(:where(.group)[data-collapsible=icon] *){width:calc(var(--spacing) * 8)!important;height:calc(var(--spacing) * 8)!important}.group-data-\[collapsible\=icon\]\:w-\(--sidebar-width-icon\):is(:where(.group)[data-collapsible=icon] *){width:var(--sidebar-width-icon)}.group-data-\[collapsible\=icon\]\:w-\[calc\(var\(--sidebar-width-icon\)\+\(--spacing\(4\)\)\)\]:is(:where(.group)[data-collapsible=icon] *){width:calc(var(--sidebar-width-icon) + (calc(var(--spacing) * 4)))}.group-data-\[collapsible\=icon\]\:w-\[calc\(var\(--sidebar-width-icon\)\+\(--spacing\(4\)\)\+2px\)\]:is(:where(.group)[data-collapsible=icon] *){width:calc(var(--sidebar-width-icon) + (calc(var(--spacing) * 4)) + 2px)}.group-data-\[collapsible\=icon\]\:overflow-hidden:is(:where(.group)[data-collapsible=icon] *){overflow:hidden}.group-data-\[collapsible\=icon\]\:p-0\!:is(:where(.group)[data-collapsible=icon] *){padding:calc(var(--spacing) * 0)!important}.group-data-\[collapsible\=icon\]\:p-2\!:is(:where(.group)[data-collapsible=icon] *){padding:calc(var(--spacing) * 2)!important}.group-data-\[collapsible\=icon\]\:opacity-0:is(:where(.group)[data-collapsible=icon] *){opacity:0}.group-data-\[collapsible\=offExamples\]\:right-\[calc\(var\(--sidebar-width\)\*-1\)\]:is(:where(.group)[data-collapsible=offExamples] *){right:calc(var(--sidebar-width) * -1)}.group-data-\[collapsible\=offExamples\]\:left-\[calc\(var\(--sidebar-width\)\*-1\)\]:is(:where(.group)[data-collapsible=offExamples] *){left:calc(var(--sidebar-width) * -1)}.group-data-\[collapsible\=offExamples\]\:w-0:is(:where(.group)[data-collapsible=offExamples] *){width:calc(var(--spacing) * 0)}.group-data-\[collapsible\=offExamples\]\:translate-x-0:is(:where(.group)[data-collapsible=offExamples] *){--tw-translate-x:calc(var(--spacing) * 0);translate:var(--tw-translate-x) var(--tw-translate-y)}.group-data-\[disabled\=true\]\:pointer-events-none:is(:where(.group)[data-disabled=true] *){pointer-events:none}.group-data-\[disabled\=true\]\:opacity-50:is(:where(.group)[data-disabled=true] *),.group-data-\[disabled\=true\]\/field\:opacity-50:is(:where(.group\/field)[data-disabled=true] *),.group-data-\[disabled\=true\]\/input-group\:opacity-50:is(:where(.group\/input-group)[data-disabled=true] *){opacity:.5}.group-data-\[panel-open\]\:rotate-180:is(:where(.group)[data-panel-open] *){rotate:180deg}.group-data-\[side\=left\]\:-right-4:is(:where(.group)[data-side=left] *){right:calc(var(--spacing) * -4)}.group-data-\[side\=left\]\:border-r:is(:where(.group)[data-side=left] *){border-right-style:var(--tw-border-style);border-right-width:1px}.group-data-\[side\=right\]\:left-0:is(:where(.group)[data-side=right] *){left:calc(var(--spacing) * 0)}.group-data-\[side\=right\]\:rotate-180:is(:where(.group)[data-side=right] *){rotate:180deg}.group-data-\[side\=right\]\:border-l:is(:where(.group)[data-side=right] *){border-left-style:var(--tw-border-style);border-left-width:1px}.group-data-\[size\=default\]\/avatar\:size-2\.5:is(:where(.group\/avatar)[data-size=default] *){width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5)}.group-data-\[size\=lg\]\/avatar\:size-3:is(:where(.group\/avatar)[data-size=lg] *){width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.group-data-\[size\=sm\]\/alert-dialog-content\:grid:is(:where(.group\/alert-dialog-content)[data-size=sm] *){display:grid}.group-data-\[size\=sm\]\/alert-dialog-content\:grid-cols-2:is(:where(.group\/alert-dialog-content)[data-size=sm] *){grid-template-columns:repeat(2,minmax(0,1fr))}.group-data-\[size\=sm\]\/avatar\:size-2:is(:where(.group\/avatar)[data-size=sm] *){width:calc(var(--spacing) * 2);height:calc(var(--spacing) * 2)}.group-data-\[size\=sm\]\/avatar\:text-xs:is(:where(.group\/avatar)[data-size=sm] *){font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.group-data-\[size\=sm\]\/card\:px-3:is(:where(.group\/card)[data-size=sm] *){padding-inline:calc(var(--spacing) * 3)}.group-data-\[variant\=floating\]\:rounded-lg:is(:where(.group)[data-variant=floating] *){border-radius:calc(var(--radius) + 2px)}.group-data-\[variant\=floating\]\:shadow-sm:is(:where(.group)[data-variant=floating] *){--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.group-data-\[variant\=floating\]\:ring-1:is(:where(.group)[data-variant=floating] *){--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.group-data-\[variant\=floating\]\:ring-sidebar-border:is(:where(.group)[data-variant=floating] *){--tw-ring-color:var(--sidebar-border)}.group-data-\[variant\=outline\]\/field-group\:-mb-2:is(:where(.group\/field-group)[data-variant=outline] *){margin-bottom:calc(var(--spacing) * -2)}@media (hover:hover){.peer-hover\/menu-button\:text-sidebar-accent-foreground:is(:where(.peer\/menu-button):hover~*){color:var(--sidebar-accent-foreground)}}.peer-disabled\:cursor-not-allowed:is(:where(.peer):disabled~*){cursor:not-allowed}.peer-disabled\:opacity-50:is(:where(.peer):disabled~*){opacity:.5}.peer-data-active\/menu-button\:text-sidebar-accent-foreground:is(:where(.peer\/menu-button)[data-active]~*){color:var(--sidebar-accent-foreground)}.peer-data-\[size\=default\]\/menu-button\:top-1\.5:is(:where(.peer\/menu-button)[data-size=default]~*){top:calc(var(--spacing) * 1.5)}.peer-data-\[size\=lg\]\/menu-button\:top-2\.5:is(:where(.peer\/menu-button)[data-size=lg]~*){top:calc(var(--spacing) * 2.5)}.peer-data-\[size\=sm\]\/menu-button\:top-1:is(:where(.peer\/menu-button)[data-size=sm]~*){top:calc(var(--spacing) * 1)}.file\:inline-flex::file-selector-button{display:inline-flex}.file\:h-6::file-selector-button{height:calc(var(--spacing) * 6)}.file\:border-0::file-selector-button{border-style:var(--tw-border-style);border-width:0}.file\:bg-transparent::file-selector-button{background-color:#0000}.file\:text-xs\/relaxed::file-selector-button{font-size:var(--text-xs);line-height:var(--leading-relaxed)}.file\:font-medium::file-selector-button{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.file\:text-foreground::file-selector-button{color:var(--foreground)}.placeholder\:text-muted-foreground::placeholder{color:var(--muted-foreground)}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:-inset-2:after{content:var(--tw-content);inset:calc(var(--spacing) * -2)}.after\:inset-0:after{content:var(--tw-content);inset:calc(var(--spacing) * 0)}.after\:inset-y-0:after{content:var(--tw-content);inset-block:calc(var(--spacing) * 0)}.after\:left-1\/2:after{content:var(--tw-content);left:50%}.after\:w-\[2px\]:after{content:var(--tw-content);width:2px}.after\:rounded-full:after{content:var(--tw-content);border-radius:3.40282e38px}.after\:border:after{content:var(--tw-content);border-style:var(--tw-border-style);border-width:1px}.after\:border-border:after{content:var(--tw-content);border-color:var(--border)}.after\:mix-blend-darken:after{content:var(--tw-content);mix-blend-mode:darken}.group-data-\[collapsible\=offExamples\]\:after\:left-full:is(:where(.group)[data-collapsible=offExamples] *):after{content:var(--tw-content);left:100%}.last\:mt-0:last-child{margin-top:calc(var(--spacing) * 0)}.last\:border-0:last-child{border-style:var(--tw-border-style);border-width:0}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.focus-within\:border-ring:focus-within{border-color:var(--ring)}.focus-within\:ring-2:focus-within{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-within\:ring-ring\/30:focus-within{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.focus-within\:ring-ring\/30:focus-within{--tw-ring-color:color-mix(in oklab, var(--ring) 30%, transparent)}}@media (hover:hover){.hover\:bg-accent:hover{background-color:var(--accent)}.hover\:bg-destructive\/20:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-destructive\/20:hover{background-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.hover\:bg-input\/40:hover{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-input\/40:hover{background-color:color-mix(in oklab, var(--input) 40%, transparent)}}.hover\:bg-input\/50:hover{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-input\/50:hover{background-color:color-mix(in oklab, var(--input) 50%, transparent)}}.hover\:bg-muted:hover{background-color:var(--muted)}.hover\:bg-primary\/80:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/80:hover{background-color:color-mix(in oklab, var(--primary) 80%, transparent)}}.hover\:bg-secondary\/80:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab, var(--secondary) 80%, transparent)}}.hover\:bg-sidebar-accent:hover{background-color:var(--sidebar-accent)}.hover\:text-accent-foreground:hover{color:var(--accent-foreground)}.hover\:text-foreground:hover{color:var(--foreground)}.hover\:text-muted-foreground:hover{color:var(--muted-foreground)}.hover\:text-sidebar-accent-foreground:hover{color:var(--sidebar-accent-foreground)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.hover\:shadow-\[0_0_0_1px_hsl\(var\(--sidebar-accent\)\)\]:hover{--tw-shadow:0 0 0 1px var(--tw-shadow-color,hsl(var(--sidebar-accent)));box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hover\:group-data-\[collapsible\=offExamples\]\:bg-sidebar:hover:is(:where(.group)[data-collapsible=offExamples] *){background-color:var(--sidebar)}.hover\:after\:bg-sidebar-border:hover:after{content:var(--tw-content);background-color:var(--sidebar-border)}}.focus\:bg-accent:focus{background-color:var(--accent)}.focus\:text-accent-foreground:focus,:is(.focus\:\*\*\:text-accent-foreground:focus *),:is(.not-data-\[variant\=destructive\]\:focus\:\*\*\:text-accent-foreground:not([data-variant=destructive]):focus *){color:var(--accent-foreground)}.focus-visible\:border-destructive\/40:focus-visible{border-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:border-destructive\/40:focus-visible{border-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.focus-visible\:border-ring:focus-visible{border-color:var(--ring)}.focus-visible\:ring-0:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\:ring-2:focus-visible,.focus-visible\:ring-\[2px\]:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\:ring-\[3px\]:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.focus-visible\:ring-ring\/30:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-ring\/30:focus-visible{--tw-ring-color:color-mix(in oklab, var(--ring) 30%, transparent)}}.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:color-mix(in oklab, var(--ring) 50%, transparent)}}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.active\:bg-sidebar-accent:active{background-color:var(--sidebar-accent)}.active\:text-sidebar-accent-foreground:active{color:var(--sidebar-accent-foreground)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}:where([data-side=left]) .in-data-\[side\=left\]\:cursor-w-resize{cursor:w-resize}:where([data-side=right]) .in-data-\[side\=right\]\:cursor-e-resize{cursor:e-resize}:where([data-slot=combobox-content]) .in-data-\[slot\=combobox-content\]\:focus-within\:border-inherit:focus-within{border-color:inherit}:where([data-slot=combobox-content]) .in-data-\[slot\=combobox-content\]\:focus-within\:ring-0:focus-within{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.has-disabled\:pointer-events-none:has(:disabled){pointer-events:none}.has-disabled\:cursor-not-allowed:has(:disabled){cursor:not-allowed}.has-disabled\:opacity-50:has(:disabled){opacity:.5}.has-aria-invalid\:border-destructive:has([aria-invalid=true]){border-color:var(--destructive)}.has-aria-invalid\:ring-2:has([aria-invalid=true]){--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.has-aria-invalid\:ring-destructive\/20:has([aria-invalid=true]){--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.has-aria-invalid\:ring-destructive\/20:has([aria-invalid=true]){--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.has-data-checked\:bg-primary\/5:has([data-checked]){background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.has-data-checked\:bg-primary\/5:has([data-checked]){background-color:color-mix(in oklab, var(--primary) 5%, transparent)}}.has-data-\[align\=block-end\]\:rounded-md:has([data-align=block-end]),.has-data-\[align\=block-start\]\:rounded-md:has([data-align=block-start]){border-radius:var(--radius)}.has-data-\[icon\=inline-end\]\:pr-1\.5:has([data-icon=inline-end]){padding-right:calc(var(--spacing) * 1.5)}.has-data-\[icon\=inline-end\]\:pr-2:has([data-icon=inline-end]){padding-right:calc(var(--spacing) * 2)}.has-data-\[icon\=inline-start\]\:pl-1\.5:has([data-icon=inline-start]){padding-left:calc(var(--spacing) * 1.5)}.has-data-\[icon\=inline-start\]\:pl-2:has([data-icon=inline-start]){padding-left:calc(var(--spacing) * 2)}.has-data-\[slot\=alert-dialog-media\]\:grid-rows-\[auto_auto_1fr\]:has([data-slot=alert-dialog-media]){grid-template-rows:auto auto 1fr}.has-data-\[slot\=alert-dialog-media\]\:gap-x-4:has([data-slot=alert-dialog-media]){column-gap:calc(var(--spacing) * 4)}.has-data-\[slot\=card-action\]\:grid-cols-\[1fr_auto\]:has([data-slot=card-action]){grid-template-columns:1fr auto}.has-data-\[slot\=card-description\]\:grid-rows-\[auto_auto\]:has([data-slot=card-description]){grid-template-rows:auto auto}.has-data-\[slot\=combobox-chip\]\:px-1:has([data-slot=combobox-chip]){padding-inline:calc(var(--spacing) * 1)}.has-data-\[slot\=combobox-chip-remove\]\:pr-0:has([data-slot=combobox-chip-remove]){padding-right:calc(var(--spacing) * 0)}.has-data-\[variant\=inset\]\:bg-sidebar:has([data-variant=inset]){background-color:var(--sidebar)}.has-\[\[data-slot\=input-group-control\]\:focus-visible\]\:border-ring:has([data-slot=input-group-control]:focus-visible){border-color:var(--ring)}.has-\[\[data-slot\=input-group-control\]\:focus-visible\]\:ring-2:has([data-slot=input-group-control]:focus-visible){--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.has-\[\[data-slot\=input-group-control\]\:focus-visible\]\:ring-ring\/30:has([data-slot=input-group-control]:focus-visible){--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.has-\[\[data-slot\=input-group-control\]\:focus-visible\]\:ring-ring\/30:has([data-slot=input-group-control]:focus-visible){--tw-ring-color:color-mix(in oklab, var(--ring) 30%, transparent)}}.has-\[\[data-slot\]\[aria-invalid\=true\]\]\:border-destructive:has([data-slot][aria-invalid=true]){border-color:var(--destructive)}.has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-2:has([data-slot][aria-invalid=true]){--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/20:has([data-slot][aria-invalid=true]){--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/20:has([data-slot][aria-invalid=true]){--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.has-\[textarea\]\:rounded-md:has(:is(textarea)){border-radius:var(--radius)}.has-\[\>\[data-align\=block-end\]\]\:h-auto:has(>[data-align=block-end]){height:auto}.has-\[\>\[data-align\=block-end\]\]\:flex-col:has(>[data-align=block-end]){flex-direction:column}.has-\[\>\[data-align\=block-start\]\]\:h-auto:has(>[data-align=block-start]){height:auto}.has-\[\>\[data-align\=block-start\]\]\:flex-col:has(>[data-align=block-start]){flex-direction:column}.has-\[\>\[data-slot\=checkbox-group\]\]\:gap-3:has(>[data-slot=checkbox-group]){gap:calc(var(--spacing) * 3)}.has-\[\>\[data-slot\=field-content\]\]\:items-start:has(>[data-slot=field-content]){align-items:flex-start}.has-\[\>\[data-slot\=field\]\]\:w-full:has(>[data-slot=field]){width:100%}.has-\[\>\[data-slot\=field\]\]\:flex-col:has(>[data-slot=field]){flex-direction:column}.has-\[\>\[data-slot\=field\]\]\:rounded-md:has(>[data-slot=field]){border-radius:var(--radius)}.has-\[\>\[data-slot\=field\]\]\:border:has(>[data-slot=field]){border-style:var(--tw-border-style);border-width:1px}.has-\[\>\[data-slot\=radio-group\]\]\:gap-3:has(>[data-slot=radio-group]){gap:calc(var(--spacing) * 3)}.has-\[\>button\]\:mr-\[-0\.275rem\]:has(>button){margin-right:-.275rem}.has-\[\>button\]\:ml-\[-0\.275rem\]:has(>button){margin-left:-.275rem}.has-\[\>img\:first-child\]\:pt-0:has(>img:first-child){padding-top:calc(var(--spacing) * 0)}.has-\[\>kbd\]\:mr-\[-0\.275rem\]:has(>kbd){margin-right:-.275rem}.has-\[\>kbd\]\:ml-\[-0\.275rem\]:has(>kbd){margin-left:-.275rem}.has-\[\>svg\]\:p-0:has(>svg){padding:calc(var(--spacing) * 0)}.has-\[\>textarea\]\:h-auto:has(>textarea){height:auto}.aria-disabled\:pointer-events-none[aria-disabled=true]{pointer-events:none}.aria-disabled\:opacity-50[aria-disabled=true]{opacity:.5}.aria-expanded\:bg-muted[aria-expanded=true]{background-color:var(--muted)}.aria-expanded\:bg-secondary[aria-expanded=true]{background-color:var(--secondary)}.aria-expanded\:text-foreground[aria-expanded=true]{color:var(--foreground)}.aria-expanded\:text-secondary-foreground[aria-expanded=true]{color:var(--secondary-foreground)}.aria-invalid\:border-destructive[aria-invalid=true]{border-color:var(--destructive)}.aria-invalid\:ring-0[aria-invalid=true]{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.aria-invalid\:ring-2[aria-invalid=true],.aria-invalid\:ring-\[2px\][aria-invalid=true]{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.data-active\:bg-sidebar-accent[data-active]{background-color:var(--sidebar-accent)}.data-active\:font-medium[data-active]{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.data-active\:text-sidebar-accent-foreground[data-active]{color:var(--sidebar-accent-foreground)}.data-closed\:overflow-hidden[data-closed]{overflow:hidden}.data-disabled\:pointer-events-none[data-disabled]{pointer-events:none}.data-disabled\:opacity-50[data-disabled]{opacity:.5}.data-empty\:p-0[data-empty]{padding:calc(var(--spacing) * 0)}.data-ending-style\:opacity-0[data-ending-style]{opacity:0}.data-highlighted\:bg-accent[data-highlighted]{background-color:var(--accent)}.data-highlighted\:text-accent-foreground[data-highlighted],:is(.not-data-\[variant\=destructive\]\:data-highlighted\:\*\*\:text-accent-foreground:not([data-variant=destructive])[data-highlighted] *){color:var(--accent-foreground)}.data-inset\:pl-8[data-inset]{padding-left:calc(var(--spacing) * 8)}.data-open\:bg-accent[data-open]{background-color:var(--accent)}.data-open\:text-accent-foreground[data-open]{color:var(--accent-foreground)}.data-open\:opacity-100[data-open]{opacity:1}@media (hover:hover){.data-open\:hover\:bg-sidebar-accent[data-open]:hover{background-color:var(--sidebar-accent)}.data-open\:hover\:text-sidebar-accent-foreground[data-open]:hover{color:var(--sidebar-accent-foreground)}}.data-placeholder\:text-muted-foreground[data-placeholder]{color:var(--muted-foreground)}.data-pressed\:bg-transparent[data-pressed]{background-color:#0000}.data-selected\:border-primary[data-selected]{border-color:var(--primary)}.data-selected\:text-foreground[data-selected]{color:var(--foreground)}.data-starting-style\:opacity-0[data-starting-style]{opacity:0}.data-\[chips\=true\]\:min-w-\(--anchor-width\)[data-chips=true]{min-width:var(--anchor-width)}.data-\[invalid\=true\]\:text-destructive[data-invalid=true]{color:var(--destructive)}.data-\[orientation\=horizontal\]\:h-px[data-orientation=horizontal]{height:1px}.data-\[orientation\=horizontal\]\:w-full[data-orientation=horizontal]{width:100%}.data-\[orientation\=vertical\]\:w-px[data-orientation=vertical]{width:1px}.data-\[orientation\=vertical\]\:self-stretch[data-orientation=vertical]{align-self:stretch}.data-\[side\=bottom\]\:inset-x-0[data-side=bottom]{inset-inline:calc(var(--spacing) * 0)}.data-\[side\=bottom\]\:top-1[data-side=bottom]{top:calc(var(--spacing) * 1)}.data-\[side\=bottom\]\:bottom-0[data-side=bottom]{bottom:calc(var(--spacing) * 0)}.data-\[side\=bottom\]\:h-auto[data-side=bottom]{height:auto}.data-\[side\=bottom\]\:border-t[data-side=bottom]{border-top-style:var(--tw-border-style);border-top-width:1px}.data-\[side\=left\]\:inset-y-0[data-side=left]{inset-block:calc(var(--spacing) * 0)}.data-\[side\=left\]\:top-1\/2\![data-side=left]{top:50%!important}.data-\[side\=left\]\:-right-1[data-side=left]{right:calc(var(--spacing) * -1)}.data-\[side\=left\]\:left-0[data-side=left]{left:calc(var(--spacing) * 0)}.data-\[side\=left\]\:h-full[data-side=left]{height:100%}.data-\[side\=left\]\:w-3\/4[data-side=left]{width:75%}.data-\[side\=left\]\:-translate-y-1\/2[data-side=left]{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.data-\[side\=left\]\:border-r[data-side=left]{border-right-style:var(--tw-border-style);border-right-width:1px}.data-\[side\=right\]\:inset-y-0[data-side=right]{inset-block:calc(var(--spacing) * 0)}.data-\[side\=right\]\:top-1\/2\![data-side=right]{top:50%!important}.data-\[side\=right\]\:right-0[data-side=right]{right:calc(var(--spacing) * 0)}.data-\[side\=right\]\:-left-1[data-side=right]{left:calc(var(--spacing) * -1)}.data-\[side\=right\]\:h-full[data-side=right]{height:100%}.data-\[side\=right\]\:w-3\/4[data-side=right]{width:75%}.data-\[side\=right\]\:-translate-y-1\/2[data-side=right]{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.data-\[side\=right\]\:border-l[data-side=right]{border-left-style:var(--tw-border-style);border-left-width:1px}.data-\[side\=top\]\:inset-x-0[data-side=top]{inset-inline:calc(var(--spacing) * 0)}.data-\[side\=top\]\:top-0[data-side=top]{top:calc(var(--spacing) * 0)}.data-\[side\=top\]\:-bottom-2\.5[data-side=top]{bottom:calc(var(--spacing) * -2.5)}.data-\[side\=top\]\:h-auto[data-side=top]{height:auto}.data-\[side\=top\]\:border-b[data-side=top]{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.data-\[size\=default\]\:h-7[data-size=default]{height:calc(var(--spacing) * 7)}.data-\[size\=default\]\:max-w-xs[data-size=default]{max-width:var(--container-xs)}.data-\[size\=lg\]\:size-10[data-size=lg]{width:calc(var(--spacing) * 10);height:calc(var(--spacing) * 10)}.data-\[size\=md\]\:text-xs[data-size=md]{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.data-\[size\=sm\]\:size-6[data-size=sm]{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.data-\[size\=sm\]\:h-6[data-size=sm]{height:calc(var(--spacing) * 6)}.data-\[size\=sm\]\:max-w-64[data-size=sm]{max-width:calc(var(--spacing) * 64)}.data-\[size\=sm\]\:gap-3[data-size=sm]{gap:calc(var(--spacing) * 3)}.data-\[size\=sm\]\:py-3[data-size=sm]{padding-block:calc(var(--spacing) * 3)}.data-\[size\=sm\]\:text-xs[data-size=sm]{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}:is(.\*\:data-\[slot\=avatar\]\:ring-2>*)[data-slot=avatar]{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}:is(.\*\:data-\[slot\=avatar\]\:ring-background>*)[data-slot=avatar]{--tw-ring-color:var(--background)}.data-\[slot\=checkbox-group\]\:gap-3[data-slot=checkbox-group]{gap:calc(var(--spacing) * 3)}:is(.\*\:data-\[slot\=field\]\:p-2>*)[data-slot=field]{padding:calc(var(--spacing) * 2)}:is(.\*\:data-\[slot\=field-group\]\:gap-4>*)[data-slot=field-group]{gap:calc(var(--spacing) * 4)}:is(.\*\:data-\[slot\=input-group\]\:m-1>*)[data-slot=input-group]{margin:calc(var(--spacing) * 1)}:is(.\*\:data-\[slot\=input-group\]\:mb-0>*)[data-slot=input-group]{margin-bottom:calc(var(--spacing) * 0)}:is(.\*\:data-\[slot\=input-group\]\:h-7>*)[data-slot=input-group]{height:calc(var(--spacing) * 7)}:is(.\*\:data-\[slot\=input-group\]\:border-none>*)[data-slot=input-group]{--tw-border-style:none;border-style:none}:is(.\*\:data-\[slot\=input-group\]\:bg-input\/20>*)[data-slot=input-group]{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){:is(.\*\:data-\[slot\=input-group\]\:bg-input\/20>*)[data-slot=input-group]{background-color:color-mix(in oklab, var(--input) 20%, transparent)}}:is(.\*\:data-\[slot\=input-group\]\:shadow-none>*)[data-slot=input-group]{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}:is(.\*\*\:data-\[slot\=kbd\]\:rounded-\[calc\(var\(--radius-sm\)-2px\)\] *)[data-slot=kbd]{border-radius:calc(var(--radius-sm) - 2px)}:is(.\*\*\:data-\[slot\=kbd\]\:rounded-md *)[data-slot=kbd]{border-radius:var(--radius)}:is(.\*\*\:data-\[slot\=kbd\]\:bg-muted-foreground\/10 *)[data-slot=kbd]{background-color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){:is(.\*\*\:data-\[slot\=kbd\]\:bg-muted-foreground\/10 *)[data-slot=kbd]{background-color:color-mix(in oklab, var(--muted-foreground) 10%, transparent)}}:is(.\*\*\:data-\[slot\=kbd\]\:px-1 *)[data-slot=kbd]{padding-inline:calc(var(--spacing) * 1)}:is(.\*\*\:data-\[slot\=kbd\]\:text-\[0\.625rem\] *)[data-slot=kbd]{font-size:.625rem}:is(.\*\:data-\[slot\=select-value\]\:line-clamp-1>*)[data-slot=select-value]{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}:is(.\*\:data-\[slot\=select-value\]\:flex>*)[data-slot=select-value]{display:flex}:is(.\*\:data-\[slot\=select-value\]\:items-center>*)[data-slot=select-value]{align-items:center}:is(.\*\:data-\[slot\=select-value\]\:gap-1\.5>*)[data-slot=select-value]{gap:calc(var(--spacing) * 1.5)}.data-\[variant\=destructive\]\:text-destructive[data-variant=destructive]{color:var(--destructive)}.data-\[variant\=destructive\]\:focus\:bg-destructive\/10[data-variant=destructive]:focus{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.data-\[variant\=destructive\]\:focus\:bg-destructive\/10[data-variant=destructive]:focus{background-color:color-mix(in oklab, var(--destructive) 10%, transparent)}}.data-\[variant\=destructive\]\:focus\:text-destructive[data-variant=destructive]:focus{color:var(--destructive)}.data-\[variant\=label\]\:text-xs\/relaxed[data-variant=label]{font-size:var(--text-xs);line-height:var(--leading-relaxed)}.data-\[variant\=legend\]\:text-sm[data-variant=legend]{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.nth-last-2\:-mt-1:nth-last-child(2){margin-top:calc(var(--spacing) * -1)}@supports ((-webkit-backdrop-filter:var(--tw)) or (backdrop-filter:var(--tw))){.supports-backdrop-filter\:backdrop-blur-xs{--tw-backdrop-blur:blur(var(--blur-xs));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}}@media (width>=40rem){.sm\:flex{display:flex}.sm\:max-w-lg{max-width:var(--container-lg)}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:justify-end{justify-content:flex-end}.sm\:group-data-\[size\=default\]\/alert-dialog-content\:row-span-2:is(:where(.group\/alert-dialog-content)[data-size=default] *){grid-row:span 2/span 2}.sm\:group-data-\[size\=default\]\/alert-dialog-content\:place-items-start:is(:where(.group\/alert-dialog-content)[data-size=default] *){place-items:start}.sm\:group-data-\[size\=default\]\/alert-dialog-content\:text-left:is(:where(.group\/alert-dialog-content)[data-size=default] *){text-align:left}.sm\:group-data-\[size\=default\]\/alert-dialog-content\:group-has-data-\[slot\=alert-dialog-media\]\/alert-dialog-content\:col-start-2:is(:where(.group\/alert-dialog-content)[data-size=default] *):is(:where(.group\/alert-dialog-content):has([data-slot=alert-dialog-media]) *){grid-column-start:2}.sm\:group-data-\[size\=default\]\/alert-dialog-content\:has-data-\[slot\=alert-dialog-media\]\:grid-rows-\[auto_1fr\]:is(:where(.group\/alert-dialog-content)[data-size=default] *):has([data-slot=alert-dialog-media]){grid-template-rows:auto 1fr}.data-\[side\=left\]\:sm\:max-w-sm[data-side=left],.data-\[side\=right\]\:sm\:max-w-sm[data-side=right],.data-\[size\=default\]\:sm\:max-w-sm[data-size=default]{max-width:var(--container-sm)}}@media (width>=48rem){.md\:block{display:block}.md\:flex{display:flex}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:text-xs\/relaxed{font-size:var(--text-xs);line-height:var(--leading-relaxed)}.md\:text-pretty{text-wrap:pretty}.md\:opacity-0{opacity:0}.md\:peer-data-\[variant\=inset\]\:m-2:is(:where(.peer)[data-variant=inset]~*){margin:calc(var(--spacing) * 2)}.md\:peer-data-\[variant\=inset\]\:ml-0:is(:where(.peer)[data-variant=inset]~*){margin-left:calc(var(--spacing) * 0)}.md\:peer-data-\[variant\=inset\]\:rounded-xl:is(:where(.peer)[data-variant=inset]~*){border-radius:calc(var(--radius) + 4px)}.md\:peer-data-\[variant\=inset\]\:shadow-sm:is(:where(.peer)[data-variant=inset]~*){--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.md\:peer-data-\[variant\=inset\]\:peer-data-\[state\=collapsed\]\:ml-2:is(:where(.peer)[data-variant=inset]~*):is(:where(.peer)[data-state=collapsed]~*){margin-left:calc(var(--spacing) * 2)}.md\:after\:hidden:after{content:var(--tw-content);display:none}}@media (width>=64rem){.lg\:block{display:block}}@media (width>=80rem){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@container field-group (width>=28rem){.\@md\/field-group\:flex-row{flex-direction:row}.\@md\/field-group\:items-center{align-items:center}.\@md\/field-group\:has-\[\>\[data-slot\=field-content\]\]\:items-start:has(>[data-slot=field-content]){align-items:flex-start}}.dark\:scale-0:where(.dark,.dark *){--tw-scale-x:0%;--tw-scale-y:0%;--tw-scale-z:0%;scale:var(--tw-scale-x) var(--tw-scale-y)}.dark\:scale-100:where(.dark,.dark *){--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y)}.dark\:-rotate-90:where(.dark,.dark *){rotate:-90deg}.dark\:rotate-0:where(.dark,.dark *){rotate:0deg}.dark\:bg-destructive\/20:where(.dark,.dark *){background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-destructive\/20:where(.dark,.dark *){background-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.dark\:bg-gray-800:where(.dark,.dark *){background-color:var(--color-gray-800)}.dark\:bg-green-900:where(.dark,.dark *){background-color:var(--color-green-900)}.dark\:bg-input\/30:where(.dark,.dark *){background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-input\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--input) 30%, transparent)}}.dark\:bg-muted\/30:where(.dark,.dark *){background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-muted\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--muted) 30%, transparent)}}.dark\:bg-popover:where(.dark,.dark *){background-color:var(--popover)}.dark\:bg-red-900:where(.dark,.dark *){background-color:var(--color-red-900)}.dark\:bg-transparent:where(.dark,.dark *){background-color:#0000}.dark\:bg-yellow-900:where(.dark,.dark *){background-color:var(--color-yellow-900)}.dark\:bg-zinc-800:where(.dark,.dark *){background-color:var(--color-zinc-800)}.dark\:text-emerald-400:where(.dark,.dark *){color:var(--color-emerald-400)}.dark\:text-gray-100:where(.dark,.dark *){color:var(--color-gray-100)}.dark\:text-green-100:where(.dark,.dark *){color:var(--color-green-100)}.dark\:text-red-100:where(.dark,.dark *){color:var(--color-red-100)}.dark\:text-yellow-100:where(.dark,.dark *){color:var(--color-yellow-100)}.dark\:text-zinc-400:where(.dark,.dark *){color:var(--color-zinc-400)}.dark\:invert:where(.dark,.dark *){--tw-invert:invert(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.dark\:after\:mix-blend-lighten:where(.dark,.dark *):after{content:var(--tw-content);mix-blend-mode:lighten}@media (hover:hover){.dark\:hover\:bg-destructive\/30:where(.dark,.dark *):hover{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:hover\:bg-destructive\/30:where(.dark,.dark *):hover{background-color:color-mix(in oklab, var(--destructive) 30%, transparent)}}.dark\:hover\:bg-input\/50:where(.dark,.dark *):hover{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.dark\:hover\:bg-input\/50:where(.dark,.dark *):hover{background-color:color-mix(in oklab, var(--input) 50%, transparent)}}.dark\:hover\:bg-muted\/50:where(.dark,.dark *):hover{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.dark\:hover\:bg-muted\/50:where(.dark,.dark *):hover{background-color:color-mix(in oklab, var(--muted) 50%, transparent)}}}.dark\:focus-visible\:ring-destructive\/40:where(.dark,.dark *):focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:focus-visible\:ring-destructive\/40:where(.dark,.dark *):focus-visible{--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.dark\:has-aria-invalid\:border-destructive\/50:where(.dark,.dark *):has([aria-invalid=true]){border-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:has-aria-invalid\:border-destructive\/50:where(.dark,.dark *):has([aria-invalid=true]){border-color:color-mix(in oklab, var(--destructive) 50%, transparent)}}.dark\:has-aria-invalid\:ring-destructive\/40:where(.dark,.dark *):has([aria-invalid=true]){--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:has-aria-invalid\:ring-destructive\/40:where(.dark,.dark *):has([aria-invalid=true]){--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.dark\:has-data-checked\:bg-primary\/10:where(.dark,.dark *):has([data-checked]){background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.dark\:has-data-checked\:bg-primary\/10:where(.dark,.dark *):has([data-checked]){background-color:color-mix(in oklab, var(--primary) 10%, transparent)}}.dark\:has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/40:where(.dark,.dark *):has([data-slot][aria-invalid=true]){--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/40:where(.dark,.dark *):has([data-slot][aria-invalid=true]){--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.dark\:aria-invalid\:border-destructive\/50:where(.dark,.dark *)[aria-invalid=true]{border-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:aria-invalid\:border-destructive\/50:where(.dark,.dark *)[aria-invalid=true]{border-color:color-mix(in oklab, var(--destructive) 50%, transparent)}}.dark\:aria-invalid\:ring-destructive\/40:where(.dark,.dark *)[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:aria-invalid\:ring-destructive\/40:where(.dark,.dark *)[aria-invalid=true]{--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.dark\:data-\[variant\=destructive\]\:focus\:bg-destructive\/20:where(.dark,.dark *)[data-variant=destructive]:focus{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:data-\[variant\=destructive\]\:focus\:bg-destructive\/20:where(.dark,.dark *)[data-variant=destructive]:focus{background-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:size-4 svg{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-2\.5 svg:not([class*=size-]){width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5)}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-3 svg:not([class*=size-]){width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-3\.5 svg:not([class*=size-]){width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-4 svg:not([class*=size-]){width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\[\.border-b\]\:pb-2.border-b{padding-bottom:calc(var(--spacing) * 2)}.\[\.border-b\]\:pb-4.border-b{padding-bottom:calc(var(--spacing) * 4)}.group-data-\[size\=sm\]\/card\:\[\.border-b\]\:pb-3:is(:where(.group\/card)[data-size=sm] *).border-b{padding-bottom:calc(var(--spacing) * 3)}.\[\.border-t\]\:pt-2.border-t{padding-top:calc(var(--spacing) * 2)}.\[\.border-t\]\:pt-4.border-t{padding-top:calc(var(--spacing) * 4)}.group-data-\[size\=sm\]\/card\:\[\.border-t\]\:pt-3:is(:where(.group\/card)[data-size=sm] *).border-t{padding-top:calc(var(--spacing) * 3)}:is(.\*\:\[a\]\:underline>*):is(a){text-decoration-line:underline}:is(.\*\:\[a\]\:underline-offset-3>*):is(a){text-underline-offset:3px}@media (hover:hover){.\[a\]\:hover\:bg-destructive\/20:is(a):hover{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.\[a\]\:hover\:bg-destructive\/20:is(a):hover{background-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.\[a\]\:hover\:bg-muted:is(a):hover{background-color:var(--muted)}.\[a\]\:hover\:bg-primary\/80:is(a):hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.\[a\]\:hover\:bg-primary\/80:is(a):hover{background-color:color-mix(in oklab, var(--primary) 80%, transparent)}}.\[a\]\:hover\:bg-secondary\/80:is(a):hover{background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){.\[a\]\:hover\:bg-secondary\/80:is(a):hover{background-color:color-mix(in oklab, var(--secondary) 80%, transparent)}}.\[a\]\:hover\:text-muted-foreground:is(a):hover{color:var(--muted-foreground)}:is(.\*\:\[a\]\:hover\:text-foreground>*):is(a):hover{color:var(--foreground)}}:is(.\*\:\[img\:first-child\]\:rounded-t-lg>*):is(img:first-child){border-top-left-radius:calc(var(--radius) + 2px);border-top-right-radius:calc(var(--radius) + 2px)}:is(.\*\:\[img\:last-child\]\:rounded-b-lg>*):is(img:last-child){border-bottom-right-radius:calc(var(--radius) + 2px);border-bottom-left-radius:calc(var(--radius) + 2px)}:is(.\*\:\[span\]\:last\:flex>*):is(span):last-child{display:flex}:is(.\*\:\[span\]\:last\:items-center>*):is(span):last-child{align-items:center}:is(.\*\:\[span\]\:last\:gap-2>*):is(span):last-child{gap:calc(var(--spacing) * 2)}:is(.data-\[variant\=destructive\]\:\*\:\[svg\]\:text-destructive[data-variant=destructive]>*):is(svg){color:var(--destructive)}:is(.\*\:\[svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-4>*):is(svg:not([class*=size-])){width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\[\&\>\*\]\:w-full>*{width:100%}@container field-group (width>=28rem){.\@md\/field-group\:\[\&\>\*\]\:w-auto>*{width:auto}}.\[\&\>\.sr-only\]\:w-auto>.sr-only{width:auto}.\[\&\>\[data-slot\=field-label\]\]\:flex-auto>[data-slot=field-label]{flex:auto}@container field-group (width>=28rem){.\@md\/field-group\:\[\&\>\[data-slot\=field-label\]\]\:flex-auto>[data-slot=field-label]{flex:auto}}.has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content])>[role=checkbox],.has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content]) [role=radio]{margin-top:1px}@container field-group (width>=28rem){.\@md\/field-group\:has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content])>[role=checkbox],.\@md\/field-group\:has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content]) [role=radio]{margin-top:1px}}.\[\&\>a\]\:underline>a{text-decoration-line:underline}.\[\&\>a\]\:underline-offset-4>a{text-underline-offset:4px}.\[\&\>a\:hover\]\:text-primary>a:hover{color:var(--primary)}.\[\&\>button\]\:hidden>button{display:none}.has-\[\>\[data-align\=block-end\]\]\:\[\&\>input\]\:pt-3:has(>[data-align=block-end])>input{padding-top:calc(var(--spacing) * 3)}.has-\[\>\[data-align\=block-start\]\]\:\[\&\>input\]\:pb-3:has(>[data-align=block-start])>input{padding-bottom:calc(var(--spacing) * 3)}.has-\[\>\[data-align\=inline-end\]\]\:\[\&\>input\]\:pr-1\.5:has(>[data-align=inline-end])>input{padding-right:calc(var(--spacing) * 1.5)}.has-\[\>\[data-align\=inline-start\]\]\:\[\&\>input\]\:pl-1\.5:has(>[data-align=inline-start])>input{padding-left:calc(var(--spacing) * 1.5)}.\[\&\>span\:last-child\]\:truncate>span:last-child{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.\[\&\>svg\]\:pointer-events-none>svg{pointer-events:none}.\[\&\>svg\]\:size-2\.5\!>svg{width:calc(var(--spacing) * 2.5)!important;height:calc(var(--spacing) * 2.5)!important}.\[\&\>svg\]\:size-4>svg{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\[\&\>svg\]\:shrink-0>svg{flex-shrink:0}.\[\&\>svg\]\:text-sidebar-accent-foreground>svg{color:var(--sidebar-accent-foreground)}.group-has-data-\[size\=lg\]\/avatar-group\:\[\&\>svg\]\:size-5:is(:where(.group\/avatar-group):has([data-size=lg]) *)>svg{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.group-has-data-\[size\=sm\]\/avatar-group\:\[\&\>svg\]\:size-3:is(:where(.group\/avatar-group):has([data-size=sm]) *)>svg{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.group-data-\[size\=default\]\/avatar\:\[\&\>svg\]\:size-2:is(:where(.group\/avatar)[data-size=default] *)>svg,.group-data-\[size\=lg\]\/avatar\:\[\&\>svg\]\:size-2:is(:where(.group\/avatar)[data-size=lg] *)>svg{width:calc(var(--spacing) * 2);height:calc(var(--spacing) * 2)}.group-data-\[size\=sm\]\/avatar\:\[\&\>svg\]\:hidden:is(:where(.group\/avatar)[data-size=sm] *)>svg{display:none}.\[\&\>svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-3>svg:not([class*=size-]){width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.\[\&\>svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-3\.5>svg:not([class*=size-]){width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}[data-side=left][data-collapsible=offExamples] .\[\[data-side\=left\]\[data-collapsible\=offExamples\]_\&\]\:-right-2{right:calc(var(--spacing) * -2)}[data-side=left][data-state=collapsed] .\[\[data-side\=left\]\[data-state\=collapsed\]_\&\]\:cursor-e-resize{cursor:e-resize}[data-side=right][data-collapsible=offExamples] .\[\[data-side\=right\]\[data-collapsible\=offExamples\]_\&\]\:-left-2{left:calc(var(--spacing) * -2)}[data-side=right][data-state=collapsed] .\[\[data-side\=right\]\[data-state\=collapsed\]_\&\]\:cursor-w-resize{cursor:w-resize}[data-variant=legend]+.\[\[data-variant\=legend\]\+\&\]\:-mt-1\.5{margin-top:calc(var(--spacing) * -1.5)}}@font-face{font-family:Geist Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/geist-cyrillic-wght-normal.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Geist Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/geist-latin-ext-wght-normal.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Geist Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/geist-latin-wght-normal.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(data:font/woff2;base64,d09GMgABAAAAAAfsABQAAAAAEAwAAAeCAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhwbHhwoP0hWQVJbBmA/U1RBVIFiJyYAdC9qEQgKhGSEAAsgADCGCAE2AiQDOgQgBYlMB4EUDAcbLQ4onoexrSC/2ZyLAa8p8VHB8/x3Vue+V0hVJalMJg2nx/TCrQXxBeqLjQG7FyM1WEa/X1tEXN7cFz9EJEMmMUz3RihWSSKeQCbcIou0izz/C8v+fq3VfajEa9gDD11CImXS7qL/RJFVzC1qiB6KmKeD6TZdQ6IRGv78dL6uSVVCfgni5mzu7kcgQBgAEAQTQRCoL++STTYybkJxNfQxAAIAGu8OdEB9teW2jh4BpgDqFjAeSEByW3zFP0CBBgNMsMCGEDjgggdhiEAUAeIIED7ABTDUEnkIE9Q9ahFgKttcVhApo4ACB4qobHaccgDfEjFO6aaWUhjMLt2SyIvHKoDqoA4CSUwEIYQCEjhAO9R1G6keDeDZGjNo+AhxOjCEGTr1WeIF3kYBiLAOKvkJSMiKX0VdAyQt3SDJClCkxJCHkCzfqyVTriJZLcolS32JZHUekq2TYNkYtCtjYHMQXSxGjXDz2t/yLWXzDzxz+o3zFwDEaN23F+13pyMdQAEaSKAR9vcGq4A4MTSKCElGW+M7UcY7xqkggITb28ZJhlqc9q2twYKTt0NjixBgYvO9BIihEBLYuOFXQzfIQ7dXGUEEEgFDooBfAzqiQbpJrhiWSuKJCRFKYbHCyJKI2G5GiZbNAvgAu5pc3vwx4G+g3aDkhklABiSz0BICXrYghtYhx/cdJ+44rY2oZ0aMNRFz3VZjb6W33F3gzltqtOCV8tTHSpOeXuItfvr5lCdfzFpqtEitvqdcdGGFd28ZqqC0tPbeChGXgrIlnhSWu/eUso4uKWFLugyDzQJhflY4659+WjQ++6x72WUMv9G8mw6QJl7BVxX5fe/kpUsOvnZwee9uQ0cGXYd0o89XB2748sDSnt8d2VphdOTTgceDVvOds0v9P/s7HPq15aGun/6Vllb56f1dl0t1LejqrNkpdRZsG8TOnM5vkBG5oiVyVGnS8LHps5cfNWJs6qKPfaNSxiQNBUm3cKNWROr0GSur7Za31k1vieq7LH11VF+jXdRIasRKflc7jkobm1Z9te1IyZA0pDkhLR98+H37Zf1c/8at+dB7x+7GfVyTfJMPiYztsnl59Y5l4j+0n1RXlpHnF3Tq7HecmNF/CJodEMAikruxiyJaGLvHOdAfoA+oDvpjBm2b91cHGRZMU9n25xEU0A8fgEEAdKI3Q1iDtc034sug5YVMkE2jsE+BIkwSoQ3gxXMqz9tELp48bd0cFKOKS7xYjEuXBnZP5ia7DyiO/X/YI+PQSbt2uSdqAkWL9nQbV1XB94/+uPfdZz8dnXYFBYrcTl2SIR/ybxJNJPz/Gupb0JaZeens2ekC7EKr8t+Ls/P5VJPYJdHKyqfg2nqU6bhlidzcddQV/7MmecTzJ5VPcKXkNKSEogHjYFx6QZ7rQ+FSe8njaiNuOnXS8H2ScQ619c2mC3VTtauL0rRbXd/CkSOP37FY9Zkjz8+GibYUMOEWF+RdrFS8Ecv1SHOpPUPZGEIpjPvFyU5cXKjd6OXqorTqy9GwRd++HVufPGnVsW+aO3vggKZ18jR9sXaTC1PWTEsVUaK0FkNySbTQDqlm2PfDjZcu4aalnSLKjnOoYQ0nUlqqXcGpPu/4VgV/xU2pAqW4BW3qzhQ8/hFKhV2qE3+BKAtDqBXjfgnVdH4y0wg5tbVNRenNdTWOrenWLcupQdmsbq5b+18piTe/xRdp1xbILxNPJGInm2z6hoB21Lal0i+ePTtd7B45+3XhFJ329evskXm7qurUVREotqSluSo/L29d3qDhI4YOQqWhI4YNvBNfsMHeXKemXrxQfKeuPOGRVayA3JtkJKEgbPp+dXUDluddutRYLFoXGXWX6N3WFaGLbQtRSitVYNacTNSdy7AaG/HSaUEANcBoGXNdcZvZsOqQ1icBDv21/gzAoYPHH/WDW0qNR3QTYKEAEHig6o13NXbND06CQPlRtYjGNnSktRc09k1mAMDvAlDKfQjgy6fssInlfzmNAjKkDxoxHOBLdVRAIVt9j4qo+hA1w9T1aNBNTUOTTNUHLbqokE+UAfJXCIGw/IxCSL5GRUJeR40rL/UxTm4Q08H6MbCs70ObuNyIIXrINHQYInF06UUlevTjbQzTh5upiDMzMMogUtEnjPs/Y7jAHCJeB0GBHh04tC6FiB6ZFB1oArUSIoFoqhzCeAN6lHwm0T4C3VVPWvjpSMXReuWesMEcoqrmgtNBGd2noWeV0hNAz9rFeShNJxHGsPa3HXeKTk8b55hahySYHaYKKFFLpCfN8rsoaJn01CR04Gkc+5k7KVTCmClX8Q10HCrUEkVlSX+XO33oQR9609tJ516H497WSobWs5Up6TLaS10/dessIskgJSLiDlWvHVUywpkQ7hdPZqGyiEF0uVQerVcPamT1A3eKXdyI1vG9OoflrSXihZ1qqGE3nhmAgiIbRCQgPLEPtOM3UQwTLYaYYomNlpA44opnjV6jkD6id80OOrzf6BzmMD6eEa1zKyeYG1fzfEf16V6jw9XYOaar1/b2kP/IYX8oR2mcFvv2GtBV3JXgd437AQAA)format("woff2-variations");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-cyrillic-wght-normal.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-greek-wght-normal.woff2)format("woff2-variations");unicode-range:U+370-377,U+37A-37F,U+384-38A,U+38C,U+38E-3A1,U+3A3-3FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-vietnamese-wght-normal.woff2)format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-latin-ext-wght-normal.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-latin-wght-normal.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}:root{--font-sans:"Geist Variable", sans-serif;--font-mono:"JetBrains Mono Variable", monospace;--background:#f4f1ec;--foreground:#1d2930;--card:#f9f8f6;--card-foreground:#1d2930;--popover:#fbfaf9;--popover-foreground:#1d2930;--primary:#305030;--primary-foreground:#f5f3ef;--secondary:#eae5d7;--secondary-foreground:#263740;--muted:#e9e7e2;--muted-foreground:#576b75;--accent:#e7e2da;--accent-foreground:#1d2930;--destructive:#c32222;--destructive-foreground:#fff;--border:#b6c9b6;--input:#dedbd3;--ring:#3e743e;--chart-1:#2e6b2e;--chart-2:#cfa117;--chart-3:#297aa3;--chart-4:#cc8c33;--chart-5:#b82e2e;--radius:.25rem;--sidebar:#f5f3f0;--sidebar-background:#f5f3f0;--sidebar-foreground:#263740;--sidebar-primary:#305030;--sidebar-primary-foreground:#f5f3ef;--sidebar-accent:#e7e2da;--sidebar-accent-foreground:#1d2930;--sidebar-border:#c4d4c4;--sidebar-ring:#3e743e;--tactical-amber:#c2940a;--tactical-amber-dim:#d6b85c;--tactical-green:#267326;--tactical-green-dim:#7ab87a;--tactical-cyan:#24868f;--tactical-cyan-dim:#5eb2ba;--tactical-red:#bd2828;--tactical-olive:#64783a;--scanline-opacity:.015}.dark{--background:#0d1012;--foreground:#e0ddd1;--card:#14181a;--card-foreground:#e0ddd1;--popover:#111517;--popover-foreground:#e0ddd1;--primary:#fa0;--primary-foreground:#0d1012;--secondary:#323922;--secondary-foreground:#c6d2ac;--muted:#202527;--muted-foreground:#819098;--accent:#292f32;--accent-foreground:#ebe8e0;--destructive:#c32222;--destructive-foreground:#fff;--border:#203c32;--input:#292f32;--ring:#ffbf00;--chart-1:#ffbf00;--chart-2:#22c38e;--chart-3:#1aa1e6;--chart-4:#86ac39;--chart-5:#d92626;--sidebar:#111517;--sidebar-background:#111517;--sidebar-foreground:#e0ddd1;--sidebar-primary:#ffbf00;--sidebar-primary-foreground:#0d1012;--sidebar-accent:#292f32;--sidebar-accent-foreground:#ebe8e0;--sidebar-border:#203c32;--sidebar-ring:#ffbf00;--tactical-amber:#ffbf00;--tactical-amber-dim:#a17d12;--tactical-green:#22c38e;--tactical-green-dim:#20604a;--tactical-cyan:#17bfcf;--tactical-cyan-dim:#196066;--tactical-red:#d92626;--tactical-olive:#576b2e;--scanline-opacity:.03}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-pan-x{syntax:"*";inherits:false}@property --tw-pan-y{syntax:"*";inherits:false}@property --tw-pinch-zoom{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@keyframes pulse{50%{opacity:.5}} diff --git a/spinifex/services/spinifexui/frontend/dist/assets/index.js b/spinifex/services/spinifexui/frontend/dist/assets/index.js index 99d99e78f..9848dbbb1 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/index.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/index.js @@ -1,15 +1,15 @@ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/login.js","assets/collapsible.js","assets/zod.js","assets/card.js","assets/field.js","assets/_auth.js","assets/useQuery.js","assets/useBaseQuery.js","assets/chevron-down.js","assets/chevron-right.js","assets/page-heading.js","assets/state-badge.js","assets/badge.js","assets/admin.js","assets/nodes.js","assets/service-metrics.js","assets/ls.js","assets/useSuspenseQuery.js","assets/list-card.js","assets/create-bucket.js","assets/s3.js","assets/error-banner.js","assets/back-link.js","assets/cli-command-panel.js","assets/check.js","assets/copy.js","assets/use-copy-to-clipboard.js","assets/form-actions.js","assets/create-user.js","assets/iam.js","assets/iam2.js","assets/create-policy.js","assets/textarea.js","assets/create-vpc.js","assets/ec2.js","assets/select.js","assets/ec22.js","assets/create-volume.js","assets/create-target-group.js","assets/elbv2.js","assets/target-group-form.js","assets/plus.js","assets/trash-2.js","assets/elbv22.js","assets/create-subnet.js","assets/create-snapshot.js","assets/create-security-group.js","assets/create-placement-group.js","assets/create-load-balancer.js","assets/import-key-pair.js","assets/create-key-pair.js","assets/alert-dialog.js","assets/download.js","assets/triangle-alert.js","assets/run-instances.js","assets/_bucket.js","assets/upload-button.js","assets/delete-confirmation-dialog.js","assets/list-users.js","assets/list-policies.js","assets/describe-vpcs.js","assets/describe-volumes.js","assets/describe-target-groups.js","assets/describe-subnets.js","assets/describe-snapshots.js","assets/describe-security-groups.js","assets/describe-placement-groups.js","assets/describe-load-balancers.js","assets/describe-key-pairs.js","assets/describe-instances.js","assets/describe-images.js","assets/system-managed.js","assets/_.js","assets/_userName.js","assets/detail-row.js","assets/_policyArn.js","assets/_id12.js","assets/_id11.js","assets/_id10.js","assets/_id9.js","assets/tabs.js","assets/_id8.js","assets/_id7.js","assets/_id6.js","assets/_id5.js","assets/_id4.js","assets/_id3.js","assets/_id2.js","assets/ami-details.js","assets/_id.js"])))=>i.map(i=>d[i]); -var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;li[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,a)=>(a=n==null?{}:e(i(n)),s(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var l=class{constructor(){this.listeners=new Set,this.subscribe=this.subscribe.bind(this)}subscribe(e){return this.listeners.add(e),this.onSubscribe(),()=>{this.listeners.delete(e),this.onUnsubscribe()}}hasListeners(){return this.listeners.size>0}onSubscribe(){}onUnsubscribe(){}},u=new class extends l{#e;#t;#n;constructor(){super(),this.#n=e=>{if(typeof window<`u`&&window.addEventListener){let t=()=>e();return window.addEventListener(`visibilitychange`,t,!1),()=>{window.removeEventListener(`visibilitychange`,t)}}}}onSubscribe(){this.#t||this.setEventListener(this.#n)}onUnsubscribe(){this.hasListeners()||(this.#t?.(),this.#t=void 0)}setEventListener(e){this.#n=e,this.#t?.(),this.#t=e(e=>{typeof e==`boolean`?this.setFocused(e):this.onFocus()})}setFocused(e){this.#e!==e&&(this.#e=e,this.onFocus())}onFocus(){let e=this.isFocused();this.listeners.forEach(t=>{t(e)})}isFocused(){return typeof this.#e==`boolean`?this.#e:globalThis.document?.visibilityState!==`hidden`}},d={setTimeout:(e,t)=>setTimeout(e,t),clearTimeout:e=>clearTimeout(e),setInterval:(e,t)=>setInterval(e,t),clearInterval:e=>clearInterval(e)},f=new class{#e=d;setTimeoutProvider(e){this.#e=e}setTimeout(e,t){return this.#e.setTimeout(e,t)}clearTimeout(e){this.#e.clearTimeout(e)}setInterval(e,t){return this.#e.setInterval(e,t)}clearInterval(e){this.#e.clearInterval(e)}};function p(e){setTimeout(e,0)}var m=typeof window>`u`||`Deno`in globalThis;function h(){}function g(e,t){return typeof e==`function`?e(t):e}function _(e){return typeof e==`number`&&e>=0&&e!==1/0}function v(e,t){return Math.max(e+(t||0)-Date.now(),0)}function y(e,t){return typeof e==`function`?e(t):e}function b(e,t){return typeof e==`function`?e(t):e}function x(e,t){let{type:n=`all`,exact:r,fetchStatus:i,predicate:a,queryKey:o,stale:s}=e;if(o){if(r){if(t.queryHash!==C(o,t.options))return!1}else if(!T(t.queryKey,o))return!1}if(n!==`all`){let e=t.isActive();if(n===`active`&&!e||n===`inactive`&&e)return!1}return!(typeof s==`boolean`&&t.isStale()!==s||i&&i!==t.state.fetchStatus||a&&!a(t))}function S(e,t){let{exact:n,status:r,predicate:i,mutationKey:a}=e;if(a){if(!t.options.mutationKey)return!1;if(n){if(w(t.options.mutationKey)!==w(a))return!1}else if(!T(t.options.mutationKey,a))return!1}return!(r&&t.state.status!==r||i&&!i(t))}function C(e,t){return(t?.queryKeyHashFn||w)(e)}function w(e){return JSON.stringify(e,(e,t)=>te(t)?Object.keys(t).sort().reduce((e,n)=>(e[n]=t[n],e),{}):t)}function T(e,t){return e===t?!0:typeof e==typeof t&&e&&t&&typeof e==`object`&&typeof t==`object`?Object.keys(t).every(n=>T(e[n],t[n])):!1}var E=Object.prototype.hasOwnProperty;function ee(e,t,n=0){if(e===t)return e;if(n>500)return t;let r=O(e)&&O(t);if(!r&&!(te(e)&&te(t)))return t;let i=(r?e:Object.keys(e)).length,a=r?t:Object.keys(t),o=a.length,s=r?Array(o):{},c=0;for(let l=0;l{f.setTimeout(t,e)})}function k(e,t,n){return typeof n.structuralSharing==`function`?n.structuralSharing(e,t):n.structuralSharing===!1?t:ee(e,t)}function A(e,t,n=0){let r=[...e,t];return n&&r.length>n?r.slice(1):r}function ie(e,t,n=0){let r=[t,...e];return n&&r.length>n?r.slice(0,-1):r}var j=Symbol();function ae(e,t){return!e.queryFn&&t?.initialPromise?()=>t.initialPromise:!e.queryFn||e.queryFn===j?()=>Promise.reject(Error(`Missing queryFn: '${e.queryHash}'`)):e.queryFn}function oe(e,t){return typeof e==`function`?e(...t):!!e}function se(e,t,n){let r=!1,i;return Object.defineProperty(e,`signal`,{enumerable:!0,get:()=>(i??=t(),r?i:(r=!0,i.aborted?n():i.addEventListener(`abort`,n,{once:!0}),i))}),e}var ce=(()=>{let e=()=>m;return{isServer(){return e()},setIsServer(t){e=t}}})();function M(){let e,t,n=new Promise((n,r)=>{e=n,t=r});n.status=`pending`,n.catch(()=>{});function r(e){Object.assign(n,e),delete n.resolve,delete n.reject}return n.resolve=t=>{r({status:`fulfilled`,value:t}),e(t)},n.reject=e=>{r({status:`rejected`,reason:e}),t(e)},n}var le=p;function ue(){let e=[],t=0,n=e=>{e()},r=e=>{e()},i=le,a=r=>{t?e.push(r):i(()=>{n(r)})},o=()=>{let t=e;e=[],t.length&&i(()=>{r(()=>{t.forEach(e=>{n(e)})})})};return{batch:e=>{let n;t++;try{n=e()}finally{t--,t||o()}return n},batchCalls:e=>(...t)=>{a(()=>{e(...t)})},schedule:a,setNotifyFunction:e=>{n=e},setBatchNotifyFunction:e=>{r=e},setScheduler:e=>{i=e}}}var N=ue(),de=new class extends l{#e=!0;#t;#n;constructor(){super(),this.#n=e=>{if(typeof window<`u`&&window.addEventListener){let t=()=>e(!0),n=()=>e(!1);return window.addEventListener(`online`,t,!1),window.addEventListener(`offline`,n,!1),()=>{window.removeEventListener(`online`,t),window.removeEventListener(`offline`,n)}}}}onSubscribe(){this.#t||this.setEventListener(this.#n)}onUnsubscribe(){this.hasListeners()||(this.#t?.(),this.#t=void 0)}setEventListener(e){this.#n=e,this.#t?.(),this.#t=e(this.setOnline.bind(this))}setOnline(e){this.#e!==e&&(this.#e=e,this.listeners.forEach(t=>{t(e)}))}isOnline(){return this.#e}};function fe(e){return Math.min(1e3*2**e,3e4)}function pe(e){return(e??`online`)===`online`?de.isOnline():!0}var me=class extends Error{constructor(e){super(`CancelledError`),this.revert=e?.revert,this.silent=e?.silent}};function he(e){let t=!1,n=0,r,i=M(),a=()=>i.status!==`pending`,o=t=>{if(!a()){let n=new me(t);p(n),e.onCancel?.(n)}},s=()=>{t=!0},c=()=>{t=!1},l=()=>u.isFocused()&&(e.networkMode===`always`||de.isOnline())&&e.canRun(),d=()=>pe(e.networkMode)&&e.canRun(),f=e=>{a()||(r?.(),i.resolve(e))},p=e=>{a()||(r?.(),i.reject(e))},m=()=>new Promise(t=>{r=e=>{(a()||l())&&t(e)},e.onPause?.()}).then(()=>{r=void 0,a()||e.onContinue?.()}),h=()=>{if(a())return;let r,i=n===0?e.initialPromise:void 0;try{r=i??e.fn()}catch(e){r=Promise.reject(e)}Promise.resolve(r).then(f).catch(r=>{if(a())return;let i=e.retry??(ce.isServer()?0:3),o=e.retryDelay??fe,s=typeof o==`function`?o(n,r):o,c=i===!0||typeof i==`number`&&nl()?void 0:m()).then(()=>{t?p(r):h()})})};return{promise:i,status:()=>i.status,cancel:o,continue:()=>(r?.(),i),cancelRetry:s,continueRetry:c,canStart:d,start:()=>(d()?h():m().then(h),i)}}var ge=class{#e;destroy(){this.clearGcTimeout()}scheduleGc(){this.clearGcTimeout(),_(this.gcTime)&&(this.#e=f.setTimeout(()=>{this.optionalRemove()},this.gcTime))}updateGcTime(e){this.gcTime=Math.max(this.gcTime||0,e??(ce.isServer()?1/0:300*1e3))}clearGcTimeout(){this.#e!==void 0&&(f.clearTimeout(this.#e),this.#e=void 0)}};function _e(e){return{onFetch:(t,n)=>{let r=t.options,i=t.fetchOptions?.meta?.fetchMore?.direction,a=t.state.data?.pages||[],o=t.state.data?.pageParams||[],s={pages:[],pageParams:[]},c=0,l=async()=>{let n=!1,l=e=>{se(e,()=>t.signal,()=>n=!0)},u=ae(t.options,t.fetchOptions),d=async(e,r,i)=>{if(n)return Promise.reject(t.signal.reason);if(r==null&&e.pages.length)return Promise.resolve(e);let a=await u((()=>{let e={client:t.client,queryKey:t.queryKey,pageParam:r,direction:i?`backward`:`forward`,meta:t.options.meta};return l(e),e})()),{maxPages:o}=t.options,s=i?ie:A;return{pages:s(e.pages,a,o),pageParams:s(e.pageParams,r,o)}};if(i&&a.length){let e=i===`backward`,t=e?ye:ve,n={pages:a,pageParams:o};s=await d(n,t(r,n),e)}else{let t=e??a.length;do{let e=c===0?o[0]??r.initialPageParam:ve(r,s);if(c>0&&e==null)break;s=await d(s,e),c++}while(ct.options.persister?.(l,{client:t.client,queryKey:t.queryKey,meta:t.options.meta,signal:t.signal},n):t.fetchFn=l}}}function ve(e,{pages:t,pageParams:n}){let r=t.length-1;return t.length>0?e.getNextPageParam(t[r],t,n[r],n):void 0}function ye(e,{pages:t,pageParams:n}){return t.length>0?e.getPreviousPageParam?.(t[0],t,n[0],n):void 0}var be=class extends ge{#e;#t;#n;#r;#i;#a;#o;#s;constructor(e){super(),this.#s=!1,this.#o=e.defaultOptions,this.setOptions(e.options),this.observers=[],this.#i=e.client,this.#r=this.#i.getQueryCache(),this.queryKey=e.queryKey,this.queryHash=e.queryHash,this.#t=Ce(this.options),this.state=e.state??this.#t,this.scheduleGc()}get meta(){return this.options.meta}get queryType(){return this.#e}get promise(){return this.#a?.promise}setOptions(e){if(this.options={...this.#o,...e},e?._type&&(this.#e=e._type),this.updateGcTime(this.options.gcTime),this.state&&this.state.data===void 0){let e=Ce(this.options);e.data!==void 0&&(this.setState(Se(e.data,e.dataUpdatedAt)),this.#t=e)}}optionalRemove(){!this.observers.length&&this.state.fetchStatus===`idle`&&this.#r.remove(this)}setData(e,t){let n=k(this.state.data,e,this.options);return this.#l({data:n,type:`success`,dataUpdatedAt:t?.updatedAt,manual:t?.manual}),n}setState(e){this.#l({type:`setState`,state:e})}cancel(e){let t=this.#a?.promise;return this.#a?.cancel(e),t?t.then(h).catch(h):Promise.resolve()}destroy(){super.destroy(),this.cancel({silent:!0})}get resetState(){return this.#t}reset(){this.destroy(),this.setState(this.resetState)}isActive(){return this.observers.some(e=>b(e.options.enabled,this)!==!1)}isDisabled(){return this.getObserversCount()>0?!this.isActive():this.options.queryFn===j||!this.isFetched()}isFetched(){return this.state.dataUpdateCount+this.state.errorUpdateCount>0}isStatic(){return this.getObserversCount()>0?this.observers.some(e=>y(e.options.staleTime,this)===`static`):!1}isStale(){return this.getObserversCount()>0?this.observers.some(e=>e.getCurrentResult().isStale):this.state.data===void 0||this.state.isInvalidated}isStaleByTime(e=0){return this.state.data===void 0?!0:e===`static`?!1:this.state.isInvalidated?!0:!v(this.state.dataUpdatedAt,e)}onFocus(){this.observers.find(e=>e.shouldFetchOnWindowFocus())?.refetch({cancelRefetch:!1}),this.#a?.continue()}onOnline(){this.observers.find(e=>e.shouldFetchOnReconnect())?.refetch({cancelRefetch:!1}),this.#a?.continue()}addObserver(e){this.observers.includes(e)||(this.observers.push(e),this.clearGcTimeout(),this.#r.notify({type:`observerAdded`,query:this,observer:e}))}removeObserver(e){this.observers.includes(e)&&(this.observers=this.observers.filter(t=>t!==e),this.observers.length||(this.#a&&(this.#s||this.#c()?this.#a.cancel({revert:!0}):this.#a.cancelRetry()),this.scheduleGc()),this.#r.notify({type:`observerRemoved`,query:this,observer:e}))}getObserversCount(){return this.observers.length}#c(){return this.state.fetchStatus===`paused`&&this.state.status===`pending`}invalidate(){this.state.isInvalidated||this.#l({type:`invalidate`})}async fetch(e,t){if(this.state.fetchStatus!==`idle`&&this.#a?.status()!==`rejected`){if(this.state.data!==void 0&&t?.cancelRefetch)this.cancel({silent:!0});else if(this.#a)return this.#a.continueRetry(),this.#a.promise}if(e&&this.setOptions(e),!this.options.queryFn){let e=this.observers.find(e=>e.options.queryFn);e&&this.setOptions(e.options)}let n=new AbortController,r=e=>{Object.defineProperty(e,`signal`,{enumerable:!0,get:()=>(this.#s=!0,n.signal)})},i=()=>{let e=ae(this.options,t),n=(()=>{let e={client:this.#i,queryKey:this.queryKey,meta:this.meta};return r(e),e})();return this.#s=!1,this.options.persister?this.options.persister(e,n,this):e(n)},a=(()=>{let e={fetchOptions:t,options:this.options,queryKey:this.queryKey,client:this.#i,state:this.state,fetchFn:i};return r(e),e})();(this.#e===`infinite`?_e(this.options.pages):this.options.behavior)?.onFetch(a,this),this.#n=this.state,(this.state.fetchStatus===`idle`||this.state.fetchMeta!==a.fetchOptions?.meta)&&this.#l({type:`fetch`,meta:a.fetchOptions?.meta}),this.#a=he({initialPromise:t?.initialPromise,fn:a.fetchFn,onCancel:e=>{e instanceof me&&e.revert&&this.setState({...this.#n,fetchStatus:`idle`}),n.abort()},onFail:(e,t)=>{this.#l({type:`failed`,failureCount:e,error:t})},onPause:()=>{this.#l({type:`pause`})},onContinue:()=>{this.#l({type:`continue`})},retry:a.options.retry,retryDelay:a.options.retryDelay,networkMode:a.options.networkMode,canRun:()=>!0});try{let e=await this.#a.start();if(e===void 0)throw Error(`${this.queryHash} data is undefined`);return this.setData(e),this.#r.config.onSuccess?.(e,this),this.#r.config.onSettled?.(e,this.state.error,this),e}catch(e){if(e instanceof me){if(e.silent)return this.#a.promise;if(e.revert){if(this.state.data===void 0)throw e;return this.state.data}}throw this.#l({type:`error`,error:e}),this.#r.config.onError?.(e,this),this.#r.config.onSettled?.(this.state.data,e,this),e}finally{this.scheduleGc()}}#l(e){let t=t=>{switch(e.type){case`failed`:return{...t,fetchFailureCount:e.failureCount,fetchFailureReason:e.error};case`pause`:return{...t,fetchStatus:`paused`};case`continue`:return{...t,fetchStatus:`fetching`};case`fetch`:return{...t,...xe(t.data,this.options),fetchMeta:e.meta??null};case`success`:let n={...t,...Se(e.data,e.dataUpdatedAt),dataUpdateCount:t.dataUpdateCount+1,...!e.manual&&{fetchStatus:`idle`,fetchFailureCount:0,fetchFailureReason:null}};return this.#n=e.manual?n:void 0,n;case`error`:let r=e.error;return{...t,error:r,errorUpdateCount:t.errorUpdateCount+1,errorUpdatedAt:Date.now(),fetchFailureCount:t.fetchFailureCount+1,fetchFailureReason:r,fetchStatus:`idle`,status:`error`,isInvalidated:!0};case`invalidate`:return{...t,isInvalidated:!0};case`setState`:return{...t,...e.state}}};this.state=t(this.state),N.batch(()=>{this.observers.forEach(e=>{e.onQueryUpdate()}),this.#r.notify({query:this,type:`updated`,action:e})})}};function xe(e,t){return{fetchFailureCount:0,fetchFailureReason:null,fetchStatus:pe(t.networkMode)?`fetching`:`paused`,...e===void 0&&{error:null,status:`pending`}}}function Se(e,t){return{data:e,dataUpdatedAt:t??Date.now(),error:null,isInvalidated:!1,status:`success`}}function Ce(e){let t=typeof e.initialData==`function`?e.initialData():e.initialData,n=t!==void 0,r=n?typeof e.initialDataUpdatedAt==`function`?e.initialDataUpdatedAt():e.initialDataUpdatedAt:0;return{data:t,dataUpdateCount:0,dataUpdatedAt:n?r??Date.now():0,error:null,errorUpdateCount:0,errorUpdatedAt:0,fetchFailureCount:0,fetchFailureReason:null,fetchMeta:null,isInvalidated:!1,status:n?`success`:`pending`,fetchStatus:`idle`}}var we=class extends ge{#e;#t;#n;#r;constructor(e){super(),this.#e=e.client,this.mutationId=e.mutationId,this.#n=e.mutationCache,this.#t=[],this.state=e.state||Te(),this.setOptions(e.options),this.scheduleGc()}setOptions(e){this.options=e,this.updateGcTime(this.options.gcTime)}get meta(){return this.options.meta}addObserver(e){this.#t.includes(e)||(this.#t.push(e),this.clearGcTimeout(),this.#n.notify({type:`observerAdded`,mutation:this,observer:e}))}removeObserver(e){this.#t=this.#t.filter(t=>t!==e),this.scheduleGc(),this.#n.notify({type:`observerRemoved`,mutation:this,observer:e})}optionalRemove(){this.#t.length||(this.state.status===`pending`?this.scheduleGc():this.#n.remove(this))}continue(){return this.#r?.continue()??this.execute(this.state.variables)}async execute(e){let t=()=>{this.#i({type:`continue`})},n={client:this.#e,meta:this.options.meta,mutationKey:this.options.mutationKey};this.#r=he({fn:()=>this.options.mutationFn?this.options.mutationFn(e,n):Promise.reject(Error(`No mutationFn found`)),onFail:(e,t)=>{this.#i({type:`failed`,failureCount:e,error:t})},onPause:()=>{this.#i({type:`pause`})},onContinue:t,retry:this.options.retry??0,retryDelay:this.options.retryDelay,networkMode:this.options.networkMode,canRun:()=>this.#n.canRun(this)});let r=this.state.status===`pending`,i=!this.#r.canStart();try{if(r)t();else{this.#i({type:`pending`,variables:e,isPaused:i}),this.#n.config.onMutate&&await this.#n.config.onMutate(e,this,n);let t=await this.options.onMutate?.(e,n);t!==this.state.context&&this.#i({type:`pending`,context:t,variables:e,isPaused:i})}let a=await this.#r.start();return await this.#n.config.onSuccess?.(a,e,this.state.context,this,n),await this.options.onSuccess?.(a,e,this.state.context,n),await this.#n.config.onSettled?.(a,null,this.state.variables,this.state.context,this,n),await this.options.onSettled?.(a,null,e,this.state.context,n),this.#i({type:`success`,data:a}),a}catch(t){try{await this.#n.config.onError?.(t,e,this.state.context,this,n)}catch(e){Promise.reject(e)}try{await this.options.onError?.(t,e,this.state.context,n)}catch(e){Promise.reject(e)}try{await this.#n.config.onSettled?.(void 0,t,this.state.variables,this.state.context,this,n)}catch(e){Promise.reject(e)}try{await this.options.onSettled?.(void 0,t,e,this.state.context,n)}catch(e){Promise.reject(e)}throw this.#i({type:`error`,error:t}),t}finally{this.#n.runNext(this)}}#i(e){let t=t=>{switch(e.type){case`failed`:return{...t,failureCount:e.failureCount,failureReason:e.error};case`pause`:return{...t,isPaused:!0};case`continue`:return{...t,isPaused:!1};case`pending`:return{...t,context:e.context,data:void 0,failureCount:0,failureReason:null,error:null,isPaused:e.isPaused,status:`pending`,variables:e.variables,submittedAt:Date.now()};case`success`:return{...t,data:e.data,failureCount:0,failureReason:null,error:null,status:`success`,isPaused:!1};case`error`:return{...t,data:void 0,error:e.error,failureCount:t.failureCount+1,failureReason:e.error,isPaused:!1,status:`error`}}};this.state=t(this.state),N.batch(()=>{this.#t.forEach(t=>{t.onMutationUpdate(e)}),this.#n.notify({mutation:this,type:`updated`,action:e})})}};function Te(){return{context:void 0,data:void 0,error:null,failureCount:0,failureReason:null,isPaused:!1,status:`idle`,variables:void 0,submittedAt:0}}var Ee=class extends l{constructor(e={}){super(),this.config=e,this.#e=new Set,this.#t=new Map,this.#n=0}#e;#t;#n;build(e,t,n){let r=new we({client:e,mutationCache:this,mutationId:++this.#n,options:e.defaultMutationOptions(t),state:n});return this.add(r),r}add(e){this.#e.add(e);let t=De(e);if(typeof t==`string`){let n=this.#t.get(t);n?n.push(e):this.#t.set(t,[e])}this.notify({type:`added`,mutation:e})}remove(e){if(this.#e.delete(e)){let t=De(e);if(typeof t==`string`){let n=this.#t.get(t);if(n)if(n.length>1){let t=n.indexOf(e);t!==-1&&n.splice(t,1)}else n[0]===e&&this.#t.delete(t)}}this.notify({type:`removed`,mutation:e})}canRun(e){let t=De(e);if(typeof t==`string`){let n=this.#t.get(t)?.find(e=>e.state.status===`pending`);return!n||n===e}else return!0}runNext(e){let t=De(e);return typeof t==`string`?(this.#t.get(t)?.find(t=>t!==e&&t.state.isPaused))?.continue()??Promise.resolve():Promise.resolve()}clear(){N.batch(()=>{this.#e.forEach(e=>{this.notify({type:`removed`,mutation:e})}),this.#e.clear(),this.#t.clear()})}getAll(){return Array.from(this.#e)}find(e){let t={exact:!0,...e};return this.getAll().find(e=>S(t,e))}findAll(e={}){return this.getAll().filter(t=>S(e,t))}notify(e){N.batch(()=>{this.listeners.forEach(t=>{t(e)})})}resumePausedMutations(){let e=this.getAll().filter(e=>e.state.isPaused);return N.batch(()=>Promise.all(e.map(e=>e.continue().catch(h))))}};function De(e){return e.options.scope?.id}var Oe=class extends l{constructor(e={}){super(),this.config=e,this.#e=new Map}#e;build(e,t,n){let r=t.queryKey,i=t.queryHash??C(r,t),a=this.get(i);return a||(a=new be({client:e,queryKey:r,queryHash:i,options:e.defaultQueryOptions(t),state:n,defaultOptions:e.getQueryDefaults(r)}),this.add(a)),a}add(e){this.#e.has(e.queryHash)||(this.#e.set(e.queryHash,e),this.notify({type:`added`,query:e}))}remove(e){let t=this.#e.get(e.queryHash);t&&(e.destroy(),t===e&&this.#e.delete(e.queryHash),this.notify({type:`removed`,query:e}))}clear(){N.batch(()=>{this.getAll().forEach(e=>{this.remove(e)})})}get(e){return this.#e.get(e)}getAll(){return[...this.#e.values()]}find(e){let t={exact:!0,...e};return this.getAll().find(e=>x(t,e))}findAll(e={}){let t=this.getAll();return Object.keys(e).length>0?t.filter(t=>x(e,t)):t}notify(e){N.batch(()=>{this.listeners.forEach(t=>{t(e)})})}onFocus(){N.batch(()=>{this.getAll().forEach(e=>{e.onFocus()})})}onOnline(){N.batch(()=>{this.getAll().forEach(e=>{e.onOnline()})})}},ke=class{#e;#t;#n;#r;#i;#a;#o;#s;constructor(e={}){this.#e=e.queryCache||new Oe,this.#t=e.mutationCache||new Ee,this.#n=e.defaultOptions||{},this.#r=new Map,this.#i=new Map,this.#a=0}mount(){this.#a++,this.#a===1&&(this.#o=u.subscribe(async e=>{e&&(await this.resumePausedMutations(),this.#e.onFocus())}),this.#s=de.subscribe(async e=>{e&&(await this.resumePausedMutations(),this.#e.onOnline())}))}unmount(){this.#a--,this.#a===0&&(this.#o?.(),this.#o=void 0,this.#s?.(),this.#s=void 0)}isFetching(e){return this.#e.findAll({...e,fetchStatus:`fetching`}).length}isMutating(e){return this.#t.findAll({...e,status:`pending`}).length}getQueryData(e){let t=this.defaultQueryOptions({queryKey:e});return this.#e.get(t.queryHash)?.state.data}ensureQueryData(e){let t=this.defaultQueryOptions(e),n=this.#e.build(this,t),r=n.state.data;return r===void 0?this.fetchQuery(e):(e.revalidateIfStale&&n.isStaleByTime(y(t.staleTime,n))&&this.prefetchQuery(t),Promise.resolve(r))}getQueriesData(e){return this.#e.findAll(e).map(({queryKey:e,state:t})=>[e,t.data])}setQueryData(e,t,n){let r=this.defaultQueryOptions({queryKey:e}),i=this.#e.get(r.queryHash)?.state.data,a=g(t,i);if(a!==void 0)return this.#e.build(this,r).setData(a,{...n,manual:!0})}setQueriesData(e,t,n){return N.batch(()=>this.#e.findAll(e).map(({queryKey:e})=>[e,this.setQueryData(e,t,n)]))}getQueryState(e){let t=this.defaultQueryOptions({queryKey:e});return this.#e.get(t.queryHash)?.state}removeQueries(e){let t=this.#e;N.batch(()=>{t.findAll(e).forEach(e=>{t.remove(e)})})}resetQueries(e,t){let n=this.#e;return N.batch(()=>(n.findAll(e).forEach(e=>{e.reset()}),this.refetchQueries({type:`active`,...e},t)))}cancelQueries(e,t={}){let n={revert:!0,...t},r=N.batch(()=>this.#e.findAll(e).map(e=>e.cancel(n)));return Promise.all(r).then(h).catch(h)}invalidateQueries(e,t={}){return N.batch(()=>(this.#e.findAll(e).forEach(e=>{e.invalidate()}),e?.refetchType===`none`?Promise.resolve():this.refetchQueries({...e,type:e?.refetchType??e?.type??`active`},t)))}refetchQueries(e,t={}){let n={...t,cancelRefetch:t.cancelRefetch??!0},r=N.batch(()=>this.#e.findAll(e).filter(e=>!e.isDisabled()&&!e.isStatic()).map(e=>{let t=e.fetch(void 0,n);return n.throwOnError||(t=t.catch(h)),e.state.fetchStatus===`paused`?Promise.resolve():t}));return Promise.all(r).then(h)}fetchQuery(e){let t=this.defaultQueryOptions(e);t.retry===void 0&&(t.retry=!1);let n=this.#e.build(this,t);return n.isStaleByTime(y(t.staleTime,n))?n.fetch(t):Promise.resolve(n.state.data)}prefetchQuery(e){return this.fetchQuery(e).then(h).catch(h)}fetchInfiniteQuery(e){return e._type=`infinite`,this.fetchQuery(e)}prefetchInfiniteQuery(e){return this.fetchInfiniteQuery(e).then(h).catch(h)}ensureInfiniteQueryData(e){return e._type=`infinite`,this.ensureQueryData(e)}resumePausedMutations(){return de.isOnline()?this.#t.resumePausedMutations():Promise.resolve()}getQueryCache(){return this.#e}getMutationCache(){return this.#t}getDefaultOptions(){return this.#n}setDefaultOptions(e){this.#n=e}setQueryDefaults(e,t){this.#r.set(w(e),{queryKey:e,defaultOptions:t})}getQueryDefaults(e){let t=[...this.#r.values()],n={};return t.forEach(t=>{T(e,t.queryKey)&&Object.assign(n,t.defaultOptions)}),n}setMutationDefaults(e,t){this.#i.set(w(e),{mutationKey:e,defaultOptions:t})}getMutationDefaults(e){let t=[...this.#i.values()],n={};return t.forEach(t=>{T(e,t.mutationKey)&&Object.assign(n,t.defaultOptions)}),n}defaultQueryOptions(e){if(e._defaulted)return e;let t={...this.#n.queries,...this.getQueryDefaults(e.queryKey),...e,_defaulted:!0};return t.queryHash||=C(t.queryKey,t),t.refetchOnReconnect===void 0&&(t.refetchOnReconnect=t.networkMode!==`always`),t.throwOnError===void 0&&(t.throwOnError=!!t.suspense),!t.networkMode&&t.persister&&(t.networkMode=`offlineFirst`),t.queryFn===j&&(t.enabled=!1),t}defaultMutationOptions(e){return e?._defaulted?e:{...this.#n.mutations,...e?.mutationKey&&this.getMutationDefaults(e.mutationKey),...e,_defaulted:!0}}clear(){this.#e.clear(),this.#t.clear()}},Ae=o((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.consumer`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.for(`react.activity`),p=Symbol.iterator;function m(e){return typeof e!=`object`||!e?null:(e=p&&e[p]||e[`@@iterator`],typeof e==`function`?e:null)}var h={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g=Object.assign,_={};function v(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}v.prototype.isReactComponent={},v.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},v.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function y(){}y.prototype=v.prototype;function b(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}var x=b.prototype=new y;x.constructor=b,g(x,v.prototype),x.isPureReactComponent=!0;var S=Array.isArray;function C(){}var w={H:null,A:null,T:null,S:null},T=Object.prototype.hasOwnProperty;function E(e,n,r){var i=r.ref;return{$$typeof:t,type:e,key:n,ref:i===void 0?null:i,props:r}}function ee(e,t){return E(e.type,t,e.props)}function D(e){return typeof e==`object`&&!!e&&e.$$typeof===t}function O(e){var t={"=":`=0`,":":`=2`};return`$`+e.replace(/[=:]/g,function(e){return t[e]})}var te=/\/+/g;function ne(e,t){return typeof e==`object`&&e&&e.key!=null?O(``+e.key):t.toString(36)}function re(e){switch(e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason;default:switch(typeof e.status==`string`?e.then(C,C):(e.status=`pending`,e.then(function(t){e.status===`pending`&&(e.status=`fulfilled`,e.value=t)},function(t){e.status===`pending`&&(e.status=`rejected`,e.reason=t)})),e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason}}throw e}function k(e,r,i,a,o){var s=typeof e;(s===`undefined`||s===`boolean`)&&(e=null);var c=!1;if(e===null)c=!0;else switch(s){case`bigint`:case`string`:case`number`:c=!0;break;case`object`:switch(e.$$typeof){case t:case n:c=!0;break;case d:return c=e._init,k(c(e._payload),r,i,a,o)}}if(c)return o=o(e),c=a===``?`.`+ne(e,0):a,S(o)?(i=``,c!=null&&(i=c.replace(te,`$&/`)+`/`),k(o,r,i,``,function(e){return e})):o!=null&&(D(o)&&(o=ee(o,i+(o.key==null||e&&e.key===o.key?``:(``+o.key).replace(te,`$&/`)+`/`)+c)),r.push(o)),1;c=0;var l=a===``?`.`:a+`:`;if(S(e))for(var u=0;u{t.exports=Ae()})),Me=o((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.fragment`);function r(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.Fragment=n,e.jsx=r,e.jsxs=r})),Ne=o(((e,t)=>{t.exports=Me()})),P=c(je(),1),F=Ne(),Pe=P.createContext(void 0),Fe=e=>{let t=P.useContext(Pe);if(e)return e;if(!t)throw Error(`No QueryClient set, use QueryClientProvider to set one`);return t},Ie=({client:e,children:t})=>(P.useEffect(()=>(e.mount(),()=>{e.unmount()}),[e]),(0,F.jsx)(Pe.Provider,{value:e,children:t}));function Le(e){return e}var Re=P.use,ze=typeof window<`u`?P.useLayoutEffect:P.useEffect;function Be(e){let t=P.useRef({value:e,prev:null}),n=t.current.value;return e!==n&&(t.current={value:e,prev:n}),t.current.prev}function Ve(e,t,n={},r={}){P.useEffect(()=>{if(!e.current||r.disabled||typeof IntersectionObserver!=`function`)return;let i=new IntersectionObserver(([e])=>{t(e)},n);return i.observe(e.current),()=>{i.disconnect()}},[t,n,r.disabled,e])}function He(e){let t=P.useRef(null);return P.useImperativeHandle(e,()=>t.current,[]),t}function Ue(e){return e[e.length-1]}function We(e){return typeof e==`function`}function Ge(e,t){return We(e)?e(t):e}var Ke=Object.prototype.hasOwnProperty,qe=Object.prototype.propertyIsEnumerable;function Je(e){for(let t in e)if(Ke.call(e,t))return!0;return!1}var Ye=()=>Object.create(null),Xe=(e,t)=>Ze(e,t,Ye);function Ze(e,t,n=()=>({}),r=0){if(e===t)return e;if(r>500)return t;let i=t,a=tt(e)&&tt(i);if(!a&&!($e(e)&&$e(i)))return i;let o=a?e:Qe(e);if(!o)return i;let s=a?i:Qe(i);if(!s)return i;let c=o.length,l=s.length,u=a?Array(l):n(),d=0;for(let t=0;ti||!nt(e[o],t[o],n)))return!1;return i===a}return!1}function rt(e){let t,n,r=new Promise((e,r)=>{t=e,n=r});return r.status=`pending`,r.resolve=n=>{r.status=`resolved`,r.value=n,t(n),e?.(n)},r.reject=e=>{r.status=`rejected`,n(e)},r}function it(e){return typeof e?.message==`string`?e.message.startsWith(`Failed to fetch dynamically imported module`)||e.message.startsWith(`error loading dynamically imported module`)||e.message.startsWith(`Importing a module script failed`):!1}function at(e){return!!(e&&typeof e==`object`&&typeof e.then==`function`)}function ot(e){return e.replace(/[\x00-\x1f\x7f]/g,``)}function st(e){let t;try{t=decodeURI(e)}catch{t=e.replaceAll(/%[0-9A-F]{2}/gi,e=>{try{return decodeURI(e)}catch{return e}})}return ot(t)}var ct=[`http:`,`https:`,`mailto:`,`tel:`];function lt(e,t){if(!e)return!1;try{let n=new URL(e);return!t.has(n.protocol)}catch{return!1}}var ut={"&":`\\u0026`,">":`\\u003e`,"<":`\\u003c`,"\u2028":`\\u2028`,"\u2029":`\\u2029`},dt=/[&><\u2028\u2029]/g;function ft(e){return e.replace(dt,e=>ut[e])}function pt(e){if(!e||!/[%\\\x00-\x1f\x7f]/.test(e)&&!e.startsWith(`//`))return{path:e,handledProtocolRelativeURL:!1};let t=/%25|%5C/gi,n=0,r=``,i;for(;(i=t.exec(e))!==null;)r+=st(e.slice(n,i.index))+i[0],n=t.lastIndex;r+=st(n?e.slice(n):e);let a=!1;return r.startsWith(`//`)&&(a=!0,r=`/`+r.replace(/^\/+/,``)),{path:r,handledProtocolRelativeURL:a}}function mt(e){return/\s|[^\u0000-\u007F]/.test(e)?e.replace(/\s|[^\u0000-\u007F]/gu,encodeURIComponent):e}function ht(e,t){if(e===t)return!0;if(e.length!==t.length)return!1;for(let n=0;n{e.next&&(e.prev?(e.prev.next=e.next,e.next.prev=e.prev,e.next=void 0,r&&(r.next=e,e.prev=r)):(e.next.prev=void 0,n=e.next,e.next=void 0,r&&(e.prev=r,r.next=e)),r=e)};return{get(e){let n=t.get(e);if(n)return i(n),n.value},set(a,o){if(t.size>=e&&n){let e=n;t.delete(e.key),e.next&&(n=e.next,e.next.prev=void 0),e===r&&(r=void 0)}let s=t.get(a);if(s)s.value=o,i(s);else{let e={key:a,value:o,prev:r};r&&(r.next=e),r=e,n||=e,t.set(a,e)}},clear(){t.clear(),n=void 0,r=void 0}}}var vt=4,yt=5;function bt(e){let t=e.indexOf(`{`);if(t===-1)return null;let n=e.indexOf(`}`,t);return n===-1||t+1>=e.length?null:[t,n]}function xt(e,t,n=new Uint16Array(6)){let r=e.indexOf(`/`,t),i=r===-1?e.length:r,a=e.substring(t,i);if(!a||!a.includes(`$`))return n[0]=0,n[1]=t,n[2]=t,n[3]=i,n[4]=i,n[5]=i,n;if(a===`$`){let r=e.length;return n[0]=2,n[1]=t,n[2]=t,n[3]=r,n[4]=r,n[5]=r,n}if(a.charCodeAt(0)===36)return n[0]=1,n[1]=t,n[2]=t+1,n[3]=i,n[4]=i,n[5]=i,n;let o=bt(a);if(o){let[r,s]=o,c=a.charCodeAt(r+1);if(c===45){if(r+2!e.parse&&e.caseSensitive===f&&e.prefix===p&&e.suffix===m);if(h)o=h;else{let e=Et(1,n.fullPath??n.from,f,p,m);o=e,e.depth=a,e.parent=i,i.dynamic??=[],i.dynamic.push(e)}break}case 3:{let t=r.substring(u,e[1]),s=r.substring(e[4],d),f=c&&!!(t||s),p=t?f?t:t.toLowerCase():void 0,m=s?f?s:s.toLowerCase():void 0,h=!l&&i.optional?.find(e=>!e.parse&&e.caseSensitive===f&&e.prefix===p&&e.suffix===m);if(h)o=h;else{let e=Et(3,n.fullPath??n.from,f,p,m);o=e,e.parent=i,e.depth=a,i.optional??=[],i.optional.push(e)}break}case 2:{let t=r.substring(u,e[1]),s=r.substring(e[4],d),l=c&&!!(t||s),f=t?l?t:t.toLowerCase():void 0,p=s?l?s:s.toLowerCase():void 0,m=Et(2,n.fullPath??n.from,l,f,p);o=m,m.parent=i,m.depth=a,i.wildcard??=[],i.wildcard.push(m)}}i=o}if(l&&n.children&&!n.isRoot&&n.id&&n.id.charCodeAt(n.id.lastIndexOf(`/`)+1)===95){let e=Tt(n.fullPath??n.from);e.kind=yt,e.parent=i,a++,e.depth=a,i.pathless??=[],i.pathless.push(e),i=e}let u=(n.path||!n.children)&&!n.isRoot;if(u&&r.endsWith(`/`)){let e=Tt(n.fullPath??n.from);e.kind=vt,e.parent=i,a++,e.depth=a,i.index=e,i=e}i.parse=l??null,u&&!i.route&&(i.route=n,i.fullPath=n.fullPath??n.from)}if(n.children)for(let r of n.children)St(e,t,r,s,i,a,o)}function Ct(e,t){if(e.parse&&!t.parse)return-1;if(!e.parse&&t.parse)return 1;if(e.prefix&&t.prefix&&e.prefix!==t.prefix){if(e.prefix.startsWith(t.prefix))return-1;if(t.prefix.startsWith(e.prefix))return 1}if(e.suffix&&t.suffix&&e.suffix!==t.suffix){if(e.suffix.endsWith(t.suffix))return-1;if(t.suffix.endsWith(e.suffix))return 1}return e.prefix&&!t.prefix?-1:!e.prefix&&t.prefix?1:e.suffix&&!t.suffix?-1:!e.suffix&&t.suffix?1:e.caseSensitive&&!t.caseSensitive?-1:!e.caseSensitive&&t.caseSensitive?1:0}function wt(e){if(e.pathless)for(let t of e.pathless)wt(t);if(e.static)for(let t of e.static.values())wt(t);if(e.staticInsensitive)for(let t of e.staticInsensitive.values())wt(t);if(e.dynamic?.length){e.dynamic.sort(Ct);for(let t of e.dynamic)wt(t)}if(e.optional?.length){e.optional.sort(Ct);for(let t of e.optional)wt(t)}if(e.wildcard?.length){e.wildcard.sort(Ct);for(let t of e.wildcard)wt(t)}}function Tt(e){return{kind:0,depth:0,pathless:null,index:null,static:null,staticInsensitive:null,dynamic:null,optional:null,wildcard:null,route:null,fullPath:e,parent:null,parse:null}}function Et(e,t,n,r,i){return{kind:e,depth:0,pathless:null,index:null,static:null,staticInsensitive:null,dynamic:null,optional:null,wildcard:null,route:null,fullPath:t,parent:null,parse:null,caseSensitive:n,prefix:r,suffix:i}}function Dt(e,t){let n=Tt(`/`),r=new Uint16Array(6);for(let t of e)St(!1,r,t,1,n,0);wt(n),t.masksTree=n,t.flatCache=_t(1e3)}function Ot(e,t){e||=`/`;let n=t.flatCache.get(e);if(n)return n;let r=Nt(e,t.masksTree);return t.flatCache.set(e,r),r}function kt(e,t,n,r,i){e||=`/`,r||=`/`;let a=t?`case\0${e}`:e,o=i.singleCache.get(a);return o||(o=Tt(`/`),St(t,new Uint16Array(6),{from:e},1,o,0),i.singleCache.set(a,o)),Nt(r,o,n)}function At(e,t,n=!1){let r=n?e:`nofuzz\0${e}`,i=t.matchCache.get(r);if(i!==void 0)return i;e||=`/`;let a;try{a=Nt(e,t.segmentTree,n)}catch(e){if(e instanceof URIError)a=null;else throw e}return a&&(a.branch=Ft(a.route)),t.matchCache.set(r,a),a}function jt(e){return e===`/`?e:e.replace(/\/{1,}$/,``)}function Mt(e,t=!1,n){let r=Tt(e.fullPath),i=new Uint16Array(6),a={},o={},s=0;return St(t,i,e,1,r,0,e=>{if(n?.(e,s),e.id in a&>(),a[e.id]=e,s!==0&&e.path){let t=jt(e.fullPath);(!o[t]||e.fullPath.endsWith(`/`))&&(o[t]=e)}s++}),wt(r),{processedTree:{segmentTree:r,singleCache:_t(1e3),matchCache:_t(1e3),flatCache:null,masksTree:null},routesById:a,routesByPath:o}}function Nt(e,t,n=!1){let r=e.split(`/`),i=Lt(e,r,t,n);if(!i)return null;let[a]=Pt(e,r,i);return{route:i.node.route,rawParams:a}}function Pt(e,t,n){let r=It(n.node),i=null,a=Object.create(null),o=n.extract?.part??0,s=n.extract?.node??0,c=n.extract?.path??0,l=n.extract?.segment??0;for(;s=0;e--){let n=i.wildcard[e],{prefix:r,suffix:a}=n;if(!(r&&(v||!(n.caseSensitive?y:b??=y.toLowerCase()).startsWith(r)))){if(a){if(v)continue;let e=t.slice(u).join(`/`).slice(-a.length);if((n.caseSensitive?e:e.toLowerCase())!==a)continue}s.push({node:n,index:o,skipped:d,depth:f+1,statics:p,dynamics:m,optionals:h,extract:g,rawParams:_})}}if(i.optional){let e=d|1<=0;n--){let r=i.optional[n];s.push({node:r,index:u,skipped:e,depth:t,statics:p,dynamics:m,optionals:h,extract:g,rawParams:_})}if(!v)for(let e=i.optional.length-1;e>=0;e--){let n=i.optional[e],{prefix:r,suffix:a}=n;if(r||a){let e=n.caseSensitive?y:b??=y.toLowerCase();if(r&&!e.startsWith(r)||a&&!e.endsWith(a))continue}s.push({node:n,index:u+1,skipped:d,depth:t,statics:p,dynamics:m,optionals:h+Rt(o,u),extract:g,rawParams:_})}}if(!v&&i.dynamic&&y)for(let e=i.dynamic.length-1;e>=0;e--){let t=i.dynamic[e],{prefix:n,suffix:r}=t;if(n||r){let e=t.caseSensitive?y:b??=y.toLowerCase();if(n&&!e.startsWith(n)||r&&!e.endsWith(r))continue}s.push({node:t,index:u+1,skipped:d,depth:f+1,statics:p,dynamics:m+Rt(o,u),optionals:h,extract:g,rawParams:_})}if(!v&&i.staticInsensitive){let e=i.staticInsensitive.get(b??=y.toLowerCase());e&&s.push({node:e,index:u+1,skipped:d,depth:f+1,statics:p+Rt(o,u),dynamics:m,optionals:h,extract:g,rawParams:_})}if(!v&&i.static){let e=i.static.get(y);e&&s.push({node:e,index:u+1,skipped:d,depth:f+1,statics:p+Rt(o,u),dynamics:m,optionals:h,extract:g,rawParams:_})}if(i.pathless){let e=f+1;for(let t=i.pathless.length-1;t>=0;t--){let n=i.pathless[t];s.push({node:n,index:u,skipped:d,depth:e,statics:p,dynamics:m,optionals:h,extract:g,rawParams:_})}}}if(l)return l;if(r&&c){let n=c.index;for(let e=0;ee.statics||t.statics===e.statics&&(t.dynamics>e.dynamics||t.dynamics===e.dynamics&&(t.optionals>e.optionals||t.optionals===e.optionals&&((t.node.kind===vt)>(e.node.kind===vt)||t.node.kind===vt==(e.node.kind===vt)&&t.depth>e.depth))):!0}function Ht(e){return Ut(e.filter(e=>e!==void 0).join(`/`))}function Ut(e){return e.replace(/\/{2,}/g,`/`)}function Wt(e){return e===`/`?e:e.replace(/^\/{1,}/,``)}function Gt(e){let t=e.length;return t>1&&e[t-1]===`/`?e.replace(/\/{1,}$/,``):e}function Kt(e){return Gt(Wt(e))}function qt(e,t){return e?.endsWith(`/`)&&e!==`/`&&e!==`${t}/`?e.slice(0,-1):e}function Jt(e,t,n){return qt(e,n)===qt(t,n)}function Yt({base:e,to:t,trailingSlash:n=`never`,cache:r}){let i=t.startsWith(`/`),a=!i&&t===`.`,o;if(r){o=i?t:a?e:e+`\0`+t;let n=r.get(o);if(n)return n}let s;if(a)s=e.split(`/`);else if(i)s=t.split(`/`);else{for(s=e.split(`/`);s.length>1&&Ue(s)===``;)s.pop();let n=t.split(`/`);for(let e=0,t=n.length;e1&&(Ue(s)===``?n===`never`&&s.pop():n===`always`&&s.push(``));let c=Ut(s.join(`/`))||`/`;return o&&r&&r.set(o,c),c}function Xt(e){let t=new Map(e.map(e=>[encodeURIComponent(e),e])),n=Array.from(t.keys()).map(e=>e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)).join(`|`),r=new RegExp(n,`g`);return e=>e.replace(r,e=>t.get(e)??e)}function Zt(e,t,n){let r=t[e];return typeof r==`string`?e===`_splat`?/^[a-zA-Z0-9\-._~!/]*$/.test(r)?r:r.split(`/`).map(e=>$t(e,n)).join(`/`):$t(r,n):r}function Qt({path:e,params:t,decoder:n,...r}){let i=!1,a=Object.create(null);if(!e||e===`/`)return{interpolatedPath:`/`,usedParams:a,isMissingParams:i};if(!e.includes(`$`))return{interpolatedPath:e,usedParams:a,isMissingParams:i};let o=e.length,s=0,c,l=``;for(;s{t=Ge(e,t)||t},persist:()=>{try{e.setItem(nn,JSON.stringify(t))}catch{}}}}var an=rn(),on=e=>e.state.__TSR_key||e.href;function sn(e){let t=[],n;for(;n=e.parentNode;)t.push(`${e.tagName}:nth-child(${Array.prototype.indexOf.call(n.children,e)+1})`),e=n;return`${t.reverse().join(` > `)}`.toLowerCase()}var cn=!1,ln=`window`,un=`data-scroll-restoration-id`;function dn(e,t){if(!an)return;let n=an;if((t??e.options.scrollRestoration??!1)&&(e.isScrollRestoring=!0),e.isScrollRestorationSetup||!n)return;e.isScrollRestorationSetup=!0,cn=!1;let r=e.options.getScrollRestorationKey||on,i=new Map;window.history.scrollRestoration=`manual`;let a=t=>{if(!(cn||!e.isScrollRestoring))if(t.target===document||t.target===window)i.set(ln,{scrollX:window.scrollX||0,scrollY:window.scrollY||0});else{let e=t.target;i.set(e,{scrollX:e.scrollLeft||0,scrollY:e.scrollTop||0})}},o=t=>{if(!e.isScrollRestoring||!t||i.size===0||!n)return;let r=n.state[t]||={};for(let[e,t]of i){let n;if(e===ln)n=ln;else if(e.isConnected){let t=e.getAttribute(un);n=t?`[${un}="${t}"]`:sn(e)}n&&(r[n]=t)}};document.addEventListener(`scroll`,a,!0),e.subscribe(`onBeforeLoad`,e=>{o(e.fromLocation?r(e.fromLocation):void 0),i.clear()}),window.addEventListener(`pagehide`,()=>{o(r(e.stores.resolvedLocation.get()??e.stores.location.get())),n.persist()}),e.subscribe(`onRendered`,t=>{let a=r(t.toLocation),o=e.options.scrollRestorationBehavior,s=e.options.scrollToTopSelectors;if(i.clear(),!e.resetNextScroll){e.resetNextScroll=!0;return}if(!(typeof e.options.scrollRestoration==`function`&&!e.options.scrollRestoration({location:e.latestLocation}))){cn=!0;try{let t=e.isScrollRestoring?n.state[a]:void 0,r=!1;if(t)for(let e in t){let n=t[e];if(!$e(n))continue;let{scrollX:i,scrollY:a}=n;if(!(!Number.isFinite(i)||!Number.isFinite(a))){if(e===ln)window.scrollTo({top:a,left:i,behavior:o}),r=!0;else if(e){let t;try{t=document.querySelector(e)}catch{continue}t&&(t.scrollLeft=i,t.scrollTop=a,r=!0)}}}if(!r){let t=e.history.location.hash.slice(1);if(t){let e=window.history.state?.__hashScrollIntoViewOptions??!0;if(e){let n=document.getElementById(t);n&&n.scrollIntoView(e)}}else{let e={top:0,left:0,behavior:o};if(window.scrollTo(e),s)for(let t of s){if(t===ln)continue;let n=typeof t==`function`?t():document.querySelector(t);n&&n.scrollTo(e)}}}}finally{cn=!1}e.isScrollRestoring&&n.set(e=>(e[a]||={},e))}})}function fn(e,t=String){let n=new URLSearchParams;for(let r in e){let i=e[r];i!==void 0&&n.set(r,t(i))}return n.toString()}function pn(e){return e?e===`false`?!1:e===`true`?!0:e*0==0&&+e+``===e?+e:e:``}function mn(e){let t=new URLSearchParams(e),n=Object.create(null);for(let[e,r]of t.entries()){let t=n[e];t==null?n[e]=pn(r):Array.isArray(t)?t.push(pn(r)):n[e]=[t,pn(r)]}return n}var hn=_n(JSON.parse),gn=vn(JSON.stringify,JSON.parse);function _n(e){return t=>{t[0]===`?`&&(t=t.substring(1));let n=mn(t);for(let t in n){let r=n[t];if(typeof r==`string`)try{n[t]=e(r)}catch{}}return n}}function vn(e,t){let n=typeof t==`function`;function r(r){if(typeof r==`object`&&r)try{return e(r)}catch{}else if(n&&typeof r==`string`)try{return t(r),e(r)}catch{}return r}return e=>{let t=fn(e,r);return t?`?${t}`:``}}var yn=`__root__`;function bn(e){if(e.statusCode=e.statusCode||e.code||307,!e._builtLocation&&!e.reloadDocument&&typeof e.href==`string`)try{new URL(e.href),e.reloadDocument=!0}catch{}let t=new Headers(e.headers);e.href&&t.get(`Location`)===null&&t.set(`Location`,e.href);let n=new Response(null,{status:e.statusCode,headers:t});if(n.options=e,e.throw)throw n;return n}function xn(e){return e instanceof Response&&!!e.options}function Sn(e){return{input:({url:t})=>{for(let n of e)t=wn(n,t);return t},output:({url:t})=>{for(let n=e.length-1;n>=0;n--)t=Tn(e[n],t);return t}}}function Cn(e){let t=Kt(e.basepath),n=`/${t}`,r=`${n}/`,i=e.caseSensitive?n:n.toLowerCase(),a=e.caseSensitive?r:r.toLowerCase();return{input:({url:t})=>{let r=e.caseSensitive?t.pathname:t.pathname.toLowerCase();return r===i?t.pathname=`/`:r.startsWith(a)&&(t.pathname=t.pathname.slice(n.length)),t},output:({url:e})=>(e.pathname=Ht([`/`,t,e.pathname]),e)}}function wn(e,t){let n=e?.input?.({url:t});if(n){if(typeof n==`string`)return new URL(n);if(n instanceof URL)return n}return t}function Tn(e,t){let n=e?.output?.({url:t});if(n){if(typeof n==`string`)return new URL(n);if(n instanceof URL)return n}return t}function En(e,t){let{createMutableStore:n,createReadonlyStore:r,batch:i,init:a}=t,o=new Map,s=new Map,c=new Map,l=n(e.status),u=n(e.loadedAt),d=n(e.isLoading),f=n(e.isTransitioning),p=n(e.location),m=n(e.resolvedLocation),h=n(e.statusCode),g=n(e.redirect),_=n([]),v=n([]),y=n([]),b=r(()=>Dn(o,_.get())),x=r(()=>Dn(s,v.get())),S=r(()=>Dn(c,y.get())),C=r(()=>_.get()[0]),w=r(()=>_.get().some(e=>o.get(e)?.get().status===`pending`)),T=r(()=>({locationHref:p.get().href,resolvedLocationHref:m.get()?.href,status:l.get()})),E=r(()=>({status:l.get(),loadedAt:u.get(),isLoading:d.get(),isTransitioning:f.get(),matches:b.get(),location:p.get(),resolvedLocation:m.get(),statusCode:h.get(),redirect:g.get()})),ee=_t(64);function D(e){let t=ee.get(e);return t||(t=r(()=>{let t=_.get();for(let n of t){let t=o.get(n);if(t&&t.routeId===e)return t.get()}}),ee.set(e,t)),t}let O={status:l,loadedAt:u,isLoading:d,isTransitioning:f,location:p,resolvedLocation:m,statusCode:h,redirect:g,matchesId:_,pendingIds:v,cachedIds:y,matches:b,pendingMatches:x,cachedMatches:S,firstId:C,hasPending:w,matchRouteDeps:T,matchStores:o,pendingMatchStores:s,cachedMatchStores:c,__store:E,getRouteMatchStore:D,setMatches:te,setPending:ne,setCached:re};te(e.matches),a?.(O);function te(e){On(e,o,_,n,i)}function ne(e){On(e,s,v,n,i)}function re(e){On(e,c,y,n,i)}return O}function Dn(e,t){let n=[];for(let r of t){let t=e.get(r);t&&n.push(t.get())}return n}function On(e,t,n,r,i){let a=e.map(e=>e.id),o=new Set(a);i(()=>{for(let e of t.keys())o.has(e)||t.delete(e);for(let n of e){let e=t.get(n.id);if(!e){let e=r(n);e.routeId=n.routeId,t.set(n.id,e);continue}e.routeId=n.routeId,e.get()!==n&&e.set(n)}ht(n.get(),a)||n.set(a)})}var kn=e=>{if(!e.rendered)return e.rendered=!0,e.onReady?.()},An=e=>e.stores.matchesId.get().some(t=>e.stores.matchStores.get(t)?.get()._forcePending),jn=(e,t)=>!!(e.preload&&!e.router.stores.matchStores.has(t)),Mn=(e,t,n=!0)=>{let r={...e.router.options.context??{}},i=n?t:t-1;for(let t=0;t<=i;t++){let n=e.matches[t];if(!n)continue;let i=e.router.getMatch(n.id);i&&Object.assign(r,i.__routeContext,i.__beforeLoadContext)}return r},Nn=(e,t)=>{if(!e.matches.length)return;let n=t.routeId,r=e.matches.findIndex(t=>t.routeId===e.router.routeTree.id),i=r>=0?r:0,a=n?e.matches.findIndex(e=>e.routeId===n):e.firstBadMatchIndex??e.matches.length-1;a<0&&(a=i);for(let t=a;t>=0;t--){let n=e.matches[t];if(e.router.looseRoutesById[n.routeId].options.notFoundComponent)return t}return n?a:i},Pn=(e,t,n)=>{if(!(!xn(n)&&!en(n)))throw xn(n)&&n.redirectHandled&&!n.options.reloadDocument?n:(t&&(t._nonReactive.beforeLoadPromise?.resolve(),t._nonReactive.loaderPromise?.resolve(),t._nonReactive.beforeLoadPromise=void 0,t._nonReactive.loaderPromise=void 0,t._nonReactive.error=n,e.updateMatch(t.id,r=>({...r,status:xn(n)?`redirected`:en(n)?`notFound`:r.status===`pending`?`success`:r.status,context:Mn(e,t.index),isFetching:!1,error:n})),en(n)&&!n.routeId&&(n.routeId=t.routeId),t._nonReactive.loadPromise?.resolve()),xn(n)&&(e.rendered=!0,n.options._fromLocation=e.location,n.redirectHandled=!0,n=e.router.resolveRedirect(n)),n)},Fn=(e,t)=>{let n=e.router.getMatch(t);return!!(!n||n._nonReactive.dehydrated)},In=(e,t,n)=>{let r=Mn(e,n);e.updateMatch(t,e=>({...e,context:r}))},Ln=(e,t,n,r)=>{let{id:i,routeId:a}=e.matches[t],o=e.router.looseRoutesById[a];if(n instanceof Promise)throw n;n.routerCode=r,e.firstBadMatchIndex??=t,Pn(e,e.router.getMatch(i),n);try{o.options.onError?.(n)}catch(t){n=t,Pn(e,e.router.getMatch(i),n)}e.updateMatch(i,e=>(e._nonReactive.beforeLoadPromise?.resolve(),e._nonReactive.beforeLoadPromise=void 0,e._nonReactive.loadPromise?.resolve(),{...e,error:n,status:`error`,isFetching:!1,updatedAt:Date.now(),abortController:new AbortController})),!e.preload&&!xn(n)&&!en(n)&&(e.serialError??=n)},Rn=(e,t,n,r)=>{if(r._nonReactive.pendingTimeout!==void 0)return;let i=n.options.pendingMs??e.router.options.defaultPendingMs;if(e.onReady&&!jn(e,t)&&(n.options.loader||n.options.beforeLoad||Yn(n))&&typeof i==`number`&&i!==1/0&&(n.options.pendingComponent??e.router.options?.defaultPendingComponent)){let t=setTimeout(()=>{kn(e)},i);r._nonReactive.pendingTimeout=t}},zn=(e,t,n)=>{let r=e.router.getMatch(t);if(!r._nonReactive.beforeLoadPromise&&!r._nonReactive.loaderPromise)return;Rn(e,t,n,r);let i=()=>{let n=e.router.getMatch(t);n.preload&&(n.status===`redirected`||n.status===`notFound`)&&Pn(e,n,n.error)};return r._nonReactive.beforeLoadPromise?r._nonReactive.beforeLoadPromise.then(i):i()},Bn=(e,t,n,r)=>{let i=e.router.getMatch(t),a=i._nonReactive.loadPromise;i._nonReactive.loadPromise=rt(()=>{a?.resolve(),a=void 0});let{paramsError:o,searchError:s}=i;o&&Ln(e,n,o,`PARSE_PARAMS`),s&&Ln(e,n,s,`VALIDATE_SEARCH`),Rn(e,t,r,i);let c=new AbortController,l=!1,u=()=>{l||(l=!0,e.updateMatch(t,e=>({...e,isFetching:`beforeLoad`,fetchCount:e.fetchCount+1,abortController:c})))},d=()=>{i._nonReactive.beforeLoadPromise?.resolve(),i._nonReactive.beforeLoadPromise=void 0,e.updateMatch(t,e=>({...e,isFetching:!1}))};if(!r.options.beforeLoad){e.router.batch(()=>{u(),d()});return}i._nonReactive.beforeLoadPromise=rt();let f={...Mn(e,n,!1),...i.__routeContext},{search:p,params:m,cause:h}=i,g=jn(e,t),_={search:p,abortController:c,params:m,preload:g,context:f,location:e.location,navigate:t=>e.router.navigate({...t,_fromLocation:e.location}),buildLocation:e.router.buildLocation,cause:g?`preload`:h,matches:e.matches,routeId:r.id,...e.router.options.additionalContext},v=r=>{if(r===void 0){e.router.batch(()=>{u(),d()});return}(xn(r)||en(r))&&(u(),Ln(e,n,r,`BEFORE_LOAD`)),e.router.batch(()=>{u(),e.updateMatch(t,e=>({...e,__beforeLoadContext:r})),d()})},y;try{if(y=r.options.beforeLoad(_),at(y))return u(),y.catch(t=>{Ln(e,n,t,`BEFORE_LOAD`)}).then(v)}catch(t){u(),Ln(e,n,t,`BEFORE_LOAD`)}v(y)},Vn=(e,t)=>{let{id:n,routeId:r}=e.matches[t],i=e.router.looseRoutesById[r],a=()=>s(),o=()=>Bn(e,n,t,i),s=()=>{if(Fn(e,n))return;let t=zn(e,n,i);return at(t)?t.then(o):o()};return a()},Hn=(e,t,n)=>{let r=e.router.getMatch(t);if(!r||!n.options.head&&!n.options.scripts&&!n.options.headers)return;let i={ssr:e.router.options.ssr,matches:e.matches,match:r,params:r.params,loaderData:r.loaderData};return Promise.all([n.options.head?.(i),n.options.scripts?.(i),n.options.headers?.(i)]).then(([e,t,n])=>({meta:e?.meta,links:e?.links,headScripts:e?.scripts,headers:n,scripts:t,styles:e?.styles}))},Un=(e,t,n,r,i)=>{let a=t[r-1],{params:o,loaderDeps:s,abortController:c,cause:l}=e.router.getMatch(n),u=Mn(e,r),d=jn(e,n);return{params:o,deps:s,preload:!!d,parentMatchPromise:a,abortController:c,context:u,location:e.location,navigate:t=>e.router.navigate({...t,_fromLocation:e.location}),cause:d?`preload`:l,route:i,...e.router.options.additionalContext}},Wn=async(e,t,n,r,i)=>{try{let a=e.router.getMatch(n);try{Jn(i);let o=i.options.loader,s=typeof o==`function`?o:o?.handler,c=s?.(Un(e,t,n,r,i)),l=!!s&&at(c);if((l||i._lazyPromise||i._componentsPromise||i.options.head||i.options.scripts||i.options.headers||a._nonReactive.minPendingPromise)&&e.updateMatch(n,e=>({...e,isFetching:`loader`})),s){let t=l?await c:c;Pn(e,e.router.getMatch(n),t),t!==void 0&&e.updateMatch(n,e=>({...e,loaderData:t}))}i._lazyPromise&&await i._lazyPromise;let u=a._nonReactive.minPendingPromise;u&&await u,i._componentsPromise&&await i._componentsPromise,e.updateMatch(n,t=>({...t,error:void 0,context:Mn(e,r),status:`success`,isFetching:!1,updatedAt:Date.now()}))}catch(t){let o=t;if(o?.name===`AbortError`){if(a.abortController.signal.aborted){a._nonReactive.loaderPromise?.resolve(),a._nonReactive.loaderPromise=void 0;return}e.updateMatch(n,t=>({...t,status:t.status===`pending`?`success`:t.status,isFetching:!1,context:Mn(e,r)}));return}let s=a._nonReactive.minPendingPromise;s&&await s,en(t)&&await i.options.notFoundComponent?.preload?.(),Pn(e,e.router.getMatch(n),t);try{i.options.onError?.(t)}catch(t){o=t,Pn(e,e.router.getMatch(n),t)}!xn(o)&&!en(o)&&await Jn(i,[`errorComponent`]),e.updateMatch(n,t=>({...t,error:o,context:Mn(e,r),status:`error`,isFetching:!1}))}}catch(t){let r=e.router.getMatch(n);r&&(r._nonReactive.loaderPromise=void 0),Pn(e,r,t)}},Gn=async(e,t,n)=>{async function r(r,a,c,l,d){let f=Date.now()-a.updatedAt,p=r?d.options.preloadStaleTime??e.router.options.defaultPreloadStaleTime??3e4:d.options.staleTime??e.router.options.defaultStaleTime??0,m=d.options.shouldReload,h=typeof m==`function`?m(Un(e,t,i,n,d)):m,{status:g,invalid:_}=l,v=f>=p&&(!!e.forceStaleReload||l.cause===`enter`||c!==void 0&&c!==l.id);o=g===`success`&&(_||(h??v)),r&&d.options.preload===!1||(o&&!e.sync&&u?(s=!0,(async()=>{try{await Wn(e,t,i,n,d);let r=e.router.getMatch(i);r._nonReactive.loaderPromise?.resolve(),r._nonReactive.loadPromise?.resolve(),r._nonReactive.loaderPromise=void 0,r._nonReactive.loadPromise=void 0}catch(t){xn(t)&&await e.router.navigate(t.options)}})()):g!==`success`||o?await Wn(e,t,i,n,d):In(e,i,n))}let{id:i,routeId:a}=e.matches[n],o=!1,s=!1,c=e.router.looseRoutesById[a],l=c.options.loader,u=((typeof l==`function`?void 0:l?.staleReloadMode)??e.router.options.defaultStaleReloadMode)!==`blocking`;if(Fn(e,i)){if(!e.router.getMatch(i))return e.matches[n];In(e,i,n)}else{let t=e.router.getMatch(i),o=e.router.stores.matchesId.get()[n],s=(o&&e.router.stores.matchStores.get(o)||null)?.routeId===a?o:e.router.stores.matches.get().find(e=>e.routeId===a)?.id,l=jn(e,i);if(t._nonReactive.loaderPromise){if(t.status===`success`&&!e.sync&&!t.preload&&u)return t;await t._nonReactive.loaderPromise;let n=e.router.getMatch(i),a=n._nonReactive.error||n.error;a&&Pn(e,n,a),n.status===`pending`&&await r(l,t,s,n,c)}else{let n=l&&!e.router.stores.matchStores.has(i),a=e.router.getMatch(i);a._nonReactive.loaderPromise=rt(),n!==a.preload&&e.updateMatch(i,e=>({...e,preload:n})),await r(l,t,s,a,c)}}let d=e.router.getMatch(i);s||(d._nonReactive.loaderPromise?.resolve(),d._nonReactive.loadPromise?.resolve(),d._nonReactive.loadPromise=void 0),clearTimeout(d._nonReactive.pendingTimeout),d._nonReactive.pendingTimeout=void 0,s||(d._nonReactive.loaderPromise=void 0),d._nonReactive.dehydrated=void 0;let f=s?d.isFetching:!1;return f!==d.isFetching||d.invalid!==!1?(e.updateMatch(i,e=>({...e,isFetching:f,invalid:!1})),e.router.getMatch(i)):d};async function Kn(e){let t=e,n=[];An(t.router)&&kn(t);let r;for(let e=0;e({...e,...a?{status:`success`,globalNotFound:!0,error:void 0}:{status:`notFound`,error:l},isFetching:!1})),u=e,await Jn(r,[`notFoundComponent`])}else if(!t.preload){let e=t.matches[0];e.globalNotFound||t.router.getMatch(e.id)?.globalNotFound&&t.updateMatch(e.id,e=>({...e,globalNotFound:!1,error:void 0}))}if(t.serialError&&t.firstBadMatchIndex!==void 0){let e=t.router.looseRoutesById[t.matches[t.firstBadMatchIndex].routeId];await Jn(e,[`errorComponent`])}for(let e=0;e<=u;e++){let{id:n,routeId:r}=t.matches[e],i=t.router.looseRoutesById[r];try{let e=Hn(t,n,i);if(e){let r=await e;t.updateMatch(n,e=>({...e,...r}))}}catch(e){console.error(`Error executing head for route ${r}:`,e)}}let d=kn(t);if(at(d)&&await d,l)throw l;if(t.serialError&&!t.preload&&!t.onReady)throw t.serialError;return t.matches}function qn(e,t){let n=t.map(t=>e.options[t]?.preload?.()).filter(Boolean);if(n.length!==0)return Promise.all(n)}function Jn(e,t=Xn){!e._lazyLoaded&&e._lazyPromise===void 0&&(e.lazyFn?e._lazyPromise=e.lazyFn().then(t=>{let{id:n,...r}=t.options;Object.assign(e.options,r),e._lazyLoaded=!0,e._lazyPromise=void 0}):e._lazyLoaded=!0);let n=()=>e._componentsLoaded?void 0:t===Xn?(()=>{if(e._componentsPromise===void 0){let t=qn(e,Xn);t?e._componentsPromise=t.then(()=>{e._componentsLoaded=!0,e._componentsPromise=void 0}):e._componentsLoaded=!0}return e._componentsPromise})():qn(e,t);return e._lazyPromise?e._lazyPromise.then(n):n()}function Yn(e){for(let t of Xn)if(e.options[t]?.preload)return!0;return!1}var Xn=[`component`,`errorComponent`,`pendingComponent`,`notFoundComponent`],Zn=`__TSR_index`,Qn=`popstate`,$n=`beforeunload`;function er(e){let t=e.getLocation(),n=new Set,r=r=>{t=e.getLocation(),n.forEach(e=>e({location:t,action:r}))},i=n=>{e.notifyOnIndexChange??!0?r(n):t=e.getLocation()},a=async({task:n,navigateOpts:r,...i})=>{if(r?.ignoreBlocker??!1){n();return}let a=e.getBlockers?.()??[],o=i.type===`PUSH`||i.type===`REPLACE`;if(typeof document<`u`&&a.length&&o)for(let n of a){let r=ir(i.path,i.state);if(await n.blockerFn({currentLocation:t,nextLocation:r,action:i.type})){e.onBlocked?.();return}}n()};return{get location(){return t},get length(){return e.getLength()},subscribers:n,subscribe:e=>(n.add(e),()=>{n.delete(e)}),push:(n,i,o)=>{let s=t.state[Zn];i=tr(s+1,i),a({task:()=>{e.pushState(n,i),r({type:`PUSH`})},navigateOpts:o,type:`PUSH`,path:n,state:i})},replace:(n,i,o)=>{let s=t.state[Zn];i=tr(s,i),a({task:()=>{e.replaceState(n,i),r({type:`REPLACE`})},navigateOpts:o,type:`REPLACE`,path:n,state:i})},go:(t,n)=>{a({task:()=>{e.go(t),i({type:`GO`,index:t})},navigateOpts:n,type:`GO`})},back:t=>{a({task:()=>{e.back(t?.ignoreBlocker??!1),i({type:`BACK`})},navigateOpts:t,type:`BACK`})},forward:t=>{a({task:()=>{e.forward(t?.ignoreBlocker??!1),i({type:`FORWARD`})},navigateOpts:t,type:`FORWARD`})},canGoBack:()=>t.state[Zn]!==0,createHref:t=>e.createHref(t),block:t=>{if(!e.setBlockers)return()=>{};let n=e.getBlockers?.()??[];return e.setBlockers([...n,t]),()=>{let n=e.getBlockers?.()??[];e.setBlockers?.(n.filter(e=>e!==t))}},flush:()=>e.flush?.(),destroy:()=>e.destroy?.(),notify:r}}function tr(e,t){t||={};let n=ar();return{...t,key:n,__TSR_key:n,[Zn]:e}}function nr(e){let t=e?.window??(typeof document<`u`?window:void 0),n=t.history.pushState,r=t.history.replaceState,i=[],a=()=>i,o=e=>i=e,s=e?.createHref??(e=>e),c=e?.parseLocation??(()=>ir(`${t.location.pathname}${t.location.search}${t.location.hash}`,t.history.state));if(!t.history.state?.__TSR_key&&!t.history.state?.key){let e=ar();t.history.replaceState({[Zn]:0,key:e,__TSR_key:e},``)}let l=c(),u,d=!1,f=!1,p=!1,m=!1,h=()=>l,g,_,v=()=>{g&&(C._ignoreSubscribers=!0,(g.isPush?t.history.pushState:t.history.replaceState)(g.state,``,g.href),C._ignoreSubscribers=!1,g=void 0,_=void 0,u=void 0)},y=(e,t,n)=>{let r=s(t);_||(u=l),l=ir(t,n),g={href:r,state:n,isPush:g?.isPush||e===`push`},_||=Promise.resolve().then(()=>v())},b=e=>{l=c(),C.notify({type:e})},x=async()=>{if(f){f=!1;return}let e=c(),n=e.state[Zn]-l.state[Zn],r=n===1,i=n===-1,o=!r&&!i||d;d=!1;let s=o?`GO`:i?`BACK`:`FORWARD`,u=o?{type:`GO`,index:n}:{type:i?`BACK`:`FORWARD`};if(p)p=!1;else{let n=a();if(typeof document<`u`&&n.length){for(let r of n)if(await r.blockerFn({currentLocation:l,nextLocation:e,action:s})){f=!0,t.history.go(1),C.notify(u);return}}}l=c(),C.notify(u)},S=e=>{if(m){m=!1;return}let t=!1,n=a();if(typeof document<`u`&&n.length)for(let e of n){let n=e.enableBeforeUnload??!0;if(n===!0){t=!0;break}if(typeof n==`function`&&n()===!0){t=!0;break}}if(t)return e.preventDefault(),e.returnValue=``},C=er({getLocation:h,getLength:()=>t.history.length,pushState:(e,t)=>y(`push`,e,t),replaceState:(e,t)=>y(`replace`,e,t),back:e=>(e&&(p=!0),m=!0,t.history.back()),forward:e=>{e&&(p=!0),m=!0,t.history.forward()},go:e=>{d=!0,t.history.go(e)},createHref:e=>s(e),flush:v,destroy:()=>{t.history.pushState=n,t.history.replaceState=r,t.removeEventListener($n,S,{capture:!0}),t.removeEventListener(Qn,x)},onBlocked:()=>{u&&l!==u&&(l=u)},getBlockers:a,setBlockers:o,notifyOnIndexChange:!1});return t.addEventListener($n,S,{capture:!0}),t.addEventListener(Qn,x),t.history.pushState=function(...e){let r=n.apply(t.history,e);return C._ignoreSubscribers||b(`PUSH`),r},t.history.replaceState=function(...e){let n=r.apply(t.history,e);return C._ignoreSubscribers||b(`REPLACE`),n},C}function rr(e){let t=e.replace(/[\x00-\x1f\x7f]/g,``);return t.startsWith(`//`)&&(t=`/`+t.replace(/^\/+/,``)),t}function ir(e,t){let n=rr(e),r=n.indexOf(`#`),i=n.indexOf(`?`),a=ar();return{href:n,pathname:n.substring(0,r>0?i>0?Math.min(r,i):r:i>0?i:n.length),hash:r>-1?n.substring(r):``,search:i>-1?n.slice(i,r===-1?void 0:r):``,state:t||{[Zn]:0,key:a,__TSR_key:a}}}function ar(){return(Math.random()+1).toString(36).substring(7)}function or(e,t){let n=t,r=e;return{fromLocation:n,toLocation:r,pathChanged:n?.pathname!==r.pathname,hrefChanged:n?.href!==r.href,hashChanged:n?.hash!==r.hash}}var sr=class{constructor(e,t){this.tempLocationKey=`${Math.round(Math.random()*1e7)}`,this.resetNextScroll=!0,this.shouldViewTransition=void 0,this.isViewTransitionTypesSupported=void 0,this.subscribers=new Set,this.isScrollRestoring=!1,this.isScrollRestorationSetup=!1,this.routeBranchCache=new WeakMap,this.startTransition=e=>e(),this.update=e=>{let t=this.options,n=this.basepath??t?.basepath??`/`,r=this.basepath===void 0,i=t?.rewrite;if(this.options={...t,...e},this.isServer=this.options.isServer??typeof document>`u`,this.protocolAllowlist=new Set(this.options.protocolAllowlist),this.options.pathParamsAllowedCharacters&&(this.pathParamsDecoder=Xt(this.options.pathParamsAllowedCharacters)),(!this.history||this.options.history&&this.options.history!==this.history)&&(this.options.history?this.history=this.options.history:this.history=nr()),this.origin=this.options.origin,this.origin||(window?.origin&&window.origin!==`null`?this.origin=window.origin:this.origin=`http://localhost`),this.history&&this.updateLatestLocation(),this.options.routeTree!==this.routeTree){this.routeTree=this.options.routeTree;let e;this.resolvePathCache=_t(1e3),e=this.buildRouteTree(),this.setRoutes(e)}if(!this.stores&&this.latestLocation){let e=this.getStoreConfig(this);this.batch=e.batch,this.stores=En(ur(this.latestLocation),e),dn(this)}let a=!1,o=this.options.basepath??`/`,s=this.options.rewrite;if(r||n!==o||i!==s){this.basepath=o;let e=[],t=Kt(o);t&&t!==`/`&&e.push(Cn({basepath:o})),s&&e.push(s),this.rewrite=e.length===0?void 0:e.length===1?e[0]:Sn(e),this.history&&this.updateLatestLocation(),a=!0}a&&this.stores&&this.stores.location.set(this.latestLocation),typeof window<`u`&&`CSS`in window&&typeof window.CSS?.supports==`function`&&(this.isViewTransitionTypesSupported=window.CSS.supports(`selector(:active-view-transition-type(a))`))},this.updateLatestLocation=()=>{this.latestLocation=this.parseLocation(this.history.location,this.latestLocation)},this.buildRouteTree=()=>{let e=Mt(this.routeTree,this.options.caseSensitive,(e,t)=>{e.init({originalIndex:t})});return this.options.routeMasks&&Dt(this.options.routeMasks,e.processedTree),e},this.subscribe=(e,t)=>{let n={eventType:e,fn:t};return this.subscribers.add(n),()=>{this.subscribers.delete(n)}},this.emit=e=>{this.subscribers.forEach(t=>{t.eventType===e.type&&t.fn(e)})},this.parseLocation=(e,t)=>{let n=({pathname:e,search:n,hash:r,href:i,state:a})=>{if(!this.rewrite&&!/[ \x00-\x1f\x7f\u0080-\uffff]/.test(e)){let i=this.options.parseSearch(n),o=this.options.stringifySearch(i);return{href:e+o+r,publicHref:e+o+r,pathname:pt(e).path,external:!1,searchStr:o,search:Xe(t?.search,i),hash:pt(r.slice(1)).path,state:Ze(t?.state,a)}}let o=new URL(i,this.origin),s=wn(this.rewrite,o),c=this.options.parseSearch(s.search),l=this.options.stringifySearch(c);return s.search=l,{href:s.href.replace(s.origin,``),publicHref:i,pathname:pt(s.pathname).path,external:!!this.rewrite&&s.origin!==this.origin,searchStr:l,search:Xe(t?.search,c),hash:pt(s.hash.slice(1)).path,state:Ze(t?.state,a)}},r=n(e),{__tempLocation:i,__tempKey:a}=r.state;if(i&&(!a||a===this.tempLocationKey)){let e=n(i);return e.state.key=r.state.key,e.state.__TSR_key=r.state.__TSR_key,delete e.state.__tempLocation,{...e,maskedLocation:r}}return r},this.resolvePathWithBase=(e,t)=>Yt({base:e,to:t.includes(`//`)?Ut(t):t,trailingSlash:this.options.trailingSlash,cache:this.resolvePathCache}),this.matchRoutes=(e,t,n)=>typeof e==`string`?this.matchRoutesInternal({pathname:e,search:t},n):this.matchRoutesInternal(e,t),this.getMatchedRoutes=e=>fr({pathname:e,routesById:this.routesById,processedTree:this.processedTree}),this.cancelMatch=e=>{let t=this.getMatch(e);t&&(t.abortController.abort(),clearTimeout(t._nonReactive.pendingTimeout),t._nonReactive.pendingTimeout=void 0)},this.cancelMatches=()=>{this.stores.pendingIds.get().forEach(e=>{this.cancelMatch(e)}),this.stores.matchesId.get().forEach(e=>{if(this.stores.pendingMatchStores.has(e))return;let t=this.stores.matchStores.get(e)?.get();t&&(t.status===`pending`||t.isFetching===`loader`)&&this.cancelMatch(e)})},this.buildLocation=e=>{let t=(t={})=>{let n=t._fromLocation||this.pendingBuiltLocation||this.latestLocation,r=this.matchRoutesLightweight(n);t.from;let i=t.unsafeRelative===`path`?n.pathname:t.from??r.fullPath,a=t.to?`${t.to}`:void 0,o=r.search,s=Object.assign(Object.create(null),r.params),c=a?.charCodeAt(0)===47?`/`:this.resolvePathWithBase(i,`.`),l=a?this.resolvePathWithBase(c,a):c,u=t.params===!1||t.params===null?Object.create(null):(t.params??!0)===!0?s:Object.assign(s,Ge(t.params,s)),d=this.routesByPath[Gt(l)],f;if(d)f=this.getRouteBranch(d);else if(l.includes(`$`))f=[];else{let e=this.getMatchedRoutes(l);f=e.matchedRoutes,this.options.notFoundRoute&&(!e.foundRoute||e.foundRoute.path!==`/`&&e.routeParams[`**`])&&(f=[...f,this.options.notFoundRoute])}if(f.length&&Je(u))for(let e of f){let t=e.options.params?.stringify??e.options.stringifyParams;if(t)try{Object.assign(u,t(u))}catch{}}let p=e.leaveParams?l:pt(Qt({path:l,params:u,decoder:this.pathParamsDecoder,server:this.isServer}).interpolatedPath).path,m=o;if(e._includeValidateSearch&&this.options.search?.strict){let e={};f.forEach(t=>{if(t.options.validateSearch)try{Object.assign(e,dr(t.options.validateSearch,{...e,...m}))}catch{}}),m=e}m=pr({search:m,dest:t,destRoutes:f,_includeValidateSearch:e._includeValidateSearch}),m=Xe(o,m);let h=this.options.stringifySearch(m),g=t.hash===!0?n.hash:t.hash?Ge(t.hash,n.hash):void 0,_=g?`#${g}`:``,v=t.state===!0?n.state:t.state?Ge(t.state,n.state):{};v=Ze(n.state,v);let y=`${p}${h}${_}`,b,x,S=!1;if(this.rewrite){let e=new URL(y,this.origin),t=Tn(this.rewrite,e);b=e.href.replace(e.origin,``),t.origin===this.origin?x=t.pathname+t.search+t.hash:(x=t.href,S=!0)}else b=mt(y),x=b;return{publicHref:x,href:b,pathname:p,search:m,searchStr:h,state:v,hash:g??``,external:S,unmaskOnReload:t.unmaskOnReload}},n=(n={},r)=>{let i=t(n),a=r?t(r):void 0;if(!a){let n=Object.create(null);if(this.options.routeMasks){let o=Ot(i.pathname,this.processedTree);if(o){Object.assign(n,o.rawParams);let{from:i,params:s,...c}=o.route,l=s===!1||s===null?Object.create(null):(s??!0)===!0?n:Object.assign(n,Ge(s,n));r={from:e.from,...c,params:l},a=t(r)}}}return a&&(i.maskedLocation=a),i};return e.mask?n(e,{from:e.from,...e.mask}):n(e)},this.commitLocation=async({viewTransition:e,ignoreBlocker:t,...n})=>{let r=()=>{let e=[`key`,`__TSR_key`,`__TSR_index`,`__hashScrollIntoViewOptions`];e.forEach(e=>{n.state[e]=this.latestLocation.state[e]});let t=nt(n.state,this.latestLocation.state);return e.forEach(e=>{delete n.state[e]}),t},i=Gt(this.latestLocation.href)===Gt(n.href),a=this.commitLocationPromise;if(this.commitLocationPromise=rt(()=>{a?.resolve(),a=void 0}),i&&r())this.load();else{let{maskedLocation:r,hashScrollIntoView:i,...a}=n;r&&(a={...r,state:{...r.state,__tempKey:void 0,__tempLocation:{...a,search:a.searchStr,state:{...a.state,__tempKey:void 0,__tempLocation:void 0,__TSR_key:void 0,key:void 0}}}},(a.unmaskOnReload??this.options.unmaskOnReload??!1)&&(a.state.__tempKey=this.tempLocationKey)),a.state.__hashScrollIntoViewOptions=i??this.options.defaultHashScrollIntoView??!0,this.shouldViewTransition=e,this.history[n.replace?`replace`:`push`](a.publicHref,a.state,{ignoreBlocker:t})}return this.resetNextScroll=n.resetScroll??!0,this.history.subscribers.size||this.load(),this.commitLocationPromise},this.buildAndCommitLocation=({replace:e,resetScroll:t,hashScrollIntoView:n,viewTransition:r,ignoreBlocker:i,href:a,...o}={})=>{if(a){let t=this.history.location.state.__TSR_index,n=ir(a,{__TSR_index:e?t:t+1}),r=new URL(n.pathname,this.origin);o.to=wn(this.rewrite,r).pathname,o.search=this.options.parseSearch(n.search),o.hash=n.hash.slice(1)}let s=this.buildLocation({...o,_includeValidateSearch:!0});this.pendingBuiltLocation=s;let c=this.commitLocation({...s,viewTransition:r,replace:e,resetScroll:t,hashScrollIntoView:n,ignoreBlocker:i});return Promise.resolve().then(()=>{this.pendingBuiltLocation===s&&(this.pendingBuiltLocation=void 0)}),c},this.navigate=async({to:e,reloadDocument:t,href:n,publicHref:r,...i})=>{let a=!1;if(n)try{new URL(`${n}`),a=!0}catch{}if(a&&!t&&(t=!0),t){if(e!==void 0||!n){let t=this.buildLocation({to:e,...i});n??=t.publicHref,r??=t.publicHref}let t=!a&&r?r:n;if(lt(t,this.protocolAllowlist))return Promise.resolve();if(!i.ignoreBlocker){let e=this.history.getBlockers?.()??[];for(let t of e)if(t?.blockerFn&&await t.blockerFn({currentLocation:this.latestLocation,nextLocation:this.latestLocation,action:`PUSH`}))return Promise.resolve()}return i.replace?window.location.replace(t):window.location.href=t,Promise.resolve()}return this.buildAndCommitLocation({...i,href:n,to:e,_isNavigate:!0})},this.beforeLoad=()=>{this.cancelMatches(),this.updateLatestLocation();let e=this.matchRoutes(this.latestLocation),t=this.stores.cachedMatches.get().filter(t=>!e.some(e=>e.id===t.id));this.batch(()=>{this.stores.status.set(`pending`),this.stores.statusCode.set(200),this.stores.isLoading.set(!0),this.stores.location.set(this.latestLocation),this.stores.setPending(e),this.stores.setCached(t)})},this.load=async e=>{let t,n,r,i=this.stores.resolvedLocation.get()??this.stores.location.get();for(r=new Promise(a=>{this.startTransition(async()=>{try{this.beforeLoad();let t=this.latestLocation,n=or(t,this.stores.resolvedLocation.get());this.stores.redirect.get()||this.emit({type:`onBeforeNavigate`,...n}),this.emit({type:`onBeforeLoad`,...n}),await Kn({router:this,sync:e?.sync,forceStaleReload:i.href===t.href,matches:this.stores.pendingMatches.get(),location:t,updateMatch:this.updateMatch,onReady:async()=>{this.startTransition(()=>{this.startViewTransition(async()=>{let e=null,t=null,n=null,r=null;this.batch(()=>{let i=this.stores.pendingMatches.get(),a=i.length,o=this.stores.matches.get();e=a?o.filter(e=>!this.stores.pendingMatchStores.has(e.id)):null;let s=new Set;for(let e of this.stores.pendingMatchStores.values())e.routeId&&s.add(e.routeId);let c=new Set;for(let e of this.stores.matchStores.values())e.routeId&&c.add(e.routeId);t=a?o.filter(e=>!s.has(e.routeId)):null,n=a?i.filter(e=>!c.has(e.routeId)):null,r=a?i.filter(e=>c.has(e.routeId)):o,this.stores.isLoading.set(!1),this.stores.loadedAt.set(Date.now()),a&&(this.stores.setMatches(i),this.stores.setPending([]),this.stores.setCached([...this.stores.cachedMatches.get(),...e.filter(e=>e.status!==`error`&&e.status!==`notFound`&&e.status!==`redirected`)]),this.clearExpiredCache())});for(let[e,i]of[[t,`onLeave`],[n,`onEnter`],[r,`onStay`]])if(e)for(let t of e)this.looseRoutesById[t.routeId].options[i]?.(t)})})}})}catch(e){xn(e)?(t=e,this.navigate({...t.options,replace:!0,ignoreBlocker:!0})):en(e)&&(n=e);let r=t?t.status:n?404:this.stores.matches.get().some(e=>e.status===`error`)?500:200;this.batch(()=>{this.stores.statusCode.set(r),this.stores.redirect.set(t)})}this.latestLoadPromise===r&&(this.commitLocationPromise?.resolve(),this.latestLoadPromise=void 0,this.commitLocationPromise=void 0),a()})}),this.latestLoadPromise=r,await r;this.latestLoadPromise&&r!==this.latestLoadPromise;)await this.latestLoadPromise;let a;this.hasNotFoundMatch()?a=404:this.stores.matches.get().some(e=>e.status===`error`)&&(a=500),a!==void 0&&this.stores.statusCode.set(a)},this.startViewTransition=e=>{let t=this.shouldViewTransition??this.options.defaultViewTransition;if(this.shouldViewTransition=void 0,t&&typeof document<`u`&&`startViewTransition`in document&&typeof document.startViewTransition==`function`){let n;if(typeof t==`object`&&this.isViewTransitionTypesSupported){let r=this.latestLocation,i=this.stores.resolvedLocation.get(),a=typeof t.types==`function`?t.types(or(r,i)):t.types;if(a===!1){e();return}n={update:e,types:a}}else n=e;document.startViewTransition(n)}else e()},this.updateMatch=(e,t)=>{this.startTransition(()=>{let n=this.stores.pendingMatchStores.get(e);if(n){n.set(t);return}let r=this.stores.matchStores.get(e);if(r){r.set(t);return}let i=this.stores.cachedMatchStores.get(e);if(i){let n=t(i.get());n.status===`redirected`?this.stores.cachedMatchStores.delete(e)&&this.stores.cachedIds.set(t=>t.filter(t=>t!==e)):i.set(n)}})},this.getMatch=e=>this.stores.cachedMatchStores.get(e)?.get()??this.stores.pendingMatchStores.get(e)?.get()??this.stores.matchStores.get(e)?.get(),this.invalidate=e=>{let t=t=>e?.filter?.(t)??!0?{...t,invalid:!0,...e?.forcePending||t.status===`error`||t.status===`notFound`?{status:`pending`,error:void 0}:void 0}:t;return this.batch(()=>{this.stores.setMatches(this.stores.matches.get().map(t)),this.stores.setCached(this.stores.cachedMatches.get().map(t)),this.stores.setPending(this.stores.pendingMatches.get().map(t))}),this.shouldViewTransition=!1,this.load({sync:e?.sync})},this.getParsedLocationHref=e=>e.publicHref||`/`,this.resolveRedirect=e=>{let t=e.headers.get(`Location`);if(!e.options.href||e.options._builtLocation){let t=e.options._builtLocation??this.buildLocation(e.options),n=this.getParsedLocationHref(t);e.options.href=n,e.headers.set(`Location`,n)}else if(t)try{let n=new URL(t);if(this.origin&&n.origin===this.origin){let t=n.pathname+n.search+n.hash;e.options.href=t,e.headers.set(`Location`,t)}}catch{}if(e.options.href&&!e.options._builtLocation&<(e.options.href,this.protocolAllowlist))throw Error(`Redirect blocked: unsafe protocol`);return e.headers.get(`Location`)||e.headers.set(`Location`,e.options.href),e},this.clearCache=e=>{let t=e?.filter;t===void 0?this.stores.setCached([]):this.stores.setCached(this.stores.cachedMatches.get().filter(e=>!t(e)))},this.clearExpiredCache=()=>{let e=Date.now();this.clearCache({filter:t=>{let n=this.looseRoutesById[t.routeId];if(!n.options.loader)return!0;let r=(t.preload?n.options.preloadGcTime??this.options.defaultPreloadGcTime:n.options.gcTime??this.options.defaultGcTime)??300*1e3;return t.status===`error`?!0:e-t.updatedAt>=r}})},this.loadRouteChunk=Jn,this.preloadRoute=async e=>{let t=e._builtLocation??this.buildLocation(e),n=this.matchRoutes(t,{throwOnError:!0,preload:!0,dest:e}),r=new Set([...this.stores.matchesId.get(),...this.stores.pendingIds.get()]),i=new Set([...r,...this.stores.cachedIds.get()]),a=n.filter(e=>!i.has(e.id));if(a.length){let e=this.stores.cachedMatches.get();this.stores.setCached([...e,...a])}try{return n=await Kn({router:this,matches:n,location:t,preload:!0,updateMatch:(e,t)=>{r.has(e)?n=n.map(n=>n.id===e?t(n):n):this.updateMatch(e,t)}}),n}catch(e){if(xn(e))return e.options.reloadDocument?void 0:await this.preloadRoute({...e.options,_fromLocation:t});en(e)||console.error(e);return}},this.matchRoute=(e,t)=>{let n={...e,to:e.to?this.resolvePathWithBase(e.from||``,e.to):void 0,params:e.params||{},leaveParams:!0},r=this.buildLocation(n);if(t?.pending&&this.stores.status.get()!==`pending`)return!1;let i=(t?.pending===void 0?!this.stores.isLoading.get():t.pending)?this.latestLocation:this.stores.resolvedLocation.get()||this.stores.location.get(),a=kt(r.pathname,t?.caseSensitive??!1,t?.fuzzy??!1,i.pathname,this.processedTree);return!a||e.params&&!nt(a.rawParams,e.params,{partial:!0})?!1:t?.includeSearch??!0?nt(i.search,r.search,{partial:!0})?a.rawParams:!1:a.rawParams},this.hasNotFoundMatch=()=>this.stores.matches.get().some(e=>e.status===`notFound`||e.globalNotFound),this.getStoreConfig=t,this.update({defaultPreloadDelay:50,defaultPendingMs:1e3,defaultPendingMinMs:500,context:void 0,...e,caseSensitive:e.caseSensitive??!1,notFoundMode:e.notFoundMode??`fuzzy`,stringifySearch:e.stringifySearch??gn,parseSearch:e.parseSearch??hn,protocolAllowlist:e.protocolAllowlist??ct}),typeof document<`u`&&(self.__TSR_ROUTER__=this)}isShell(){return!!this.options.isShell}isPrerendering(){return!!this.options.isPrerendering}get state(){return this.stores.__store.get()}setRoutes({routesById:e,routesByPath:t,processedTree:n}){this.routesById=e,this.routesByPath=t,this.processedTree=n;let r=this.options.notFoundRoute;r&&(r.init({originalIndex:99999999999}),this.routesById[r.id]=r)}getRouteBranch(e){let t=this.routeBranchCache.get(e);return t||(t=Ft(e),this.routeBranchCache.set(e,t)),t}get looseRoutesById(){return this.routesById}getParentContext(e){return e?.id?e.context??this.options.context??void 0:this.options.context??void 0}matchRoutesInternal(e,t){let n=this.getMatchedRoutes(e.pathname),{foundRoute:r,routeParams:i}=n,{matchedRoutes:a}=n,o=!1;(r?r.path!==`/`&&i[`**`]:Gt(e.pathname))&&(this.options.notFoundRoute?a=[...a,this.options.notFoundRoute]:o=!0);let s=o?hr(this.options.notFoundMode,a):void 0,c=Array(a.length),l=new Map;for(let e of this.stores.matchStores.values())e.routeId&&l.set(e.routeId,e.get());for(let n=0;nthis.navigate({...t,_fromLocation:e}),buildLocation:this.buildLocation,cause:n.cause,abortController:n.abortController,preload:!!n.preload,matches:c,routeId:r.id};n.__routeContext=r.options.context(t)??void 0}n.context={...a,...n.__routeContext,...n.__beforeLoadContext}}}return c}matchRoutesLightweight(e){let{matchedRoutes:t,routeParams:n}=this.getMatchedRoutes(e.pathname),r=Ue(t),i={...e.search};for(let e of t)try{Object.assign(i,dr(e.options.validateSearch,i))}catch{}let a=Ue(this.stores.matchesId.get()),o=a&&this.stores.matchStores.get(a)?.get(),s=o&&o.routeId===r.id&&o.pathname===e.pathname,c;if(s)c=o.params;else{let e=Object.assign(Object.create(null),n);for(let n of t)try{gr(n,e)}catch{}c=e}return{matchedRoutes:t,fullPath:r.fullPath,search:i,params:c}}},cr=class extends Error{},lr=class extends Error{};function ur(e){return{loadedAt:0,isLoading:!1,isTransitioning:!1,status:`idle`,resolvedLocation:void 0,location:e,matches:[],statusCode:200}}function dr(e,t){if(e==null)return{};if(`~standard`in e){let n=e[`~standard`].validate(t);if(n instanceof Promise)throw new cr(`Async validation not supported`);if(n.issues)throw new cr(JSON.stringify(n.issues,void 0,2),{cause:n});return n.value}return`parse`in e?e.parse(t):typeof e==`function`?e(t):{}}function fr({pathname:e,routesById:t,processedTree:n}){let r=Object.create(null),i=Gt(e),a,o=At(i,n,!0);return o&&(a=o.route,Object.assign(r,o.rawParams)),{matchedRoutes:o?.branch||[t.__root__],routeParams:r,foundRoute:a}}function pr({search:e,dest:t,destRoutes:n,_includeValidateSearch:r}){return mr(n)(e,t,r??!1)}function mr(e){let t={dest:null,_includeValidateSearch:!1,middlewares:[]};for(let n of e)`search`in n.options?n.options.search?.middlewares&&t.middlewares.push(...n.options.search.middlewares):(n.options.preSearchFilters||n.options.postSearchFilters)&&t.middlewares.push(({search:e,next:t})=>{let r=e;`preSearchFilters`in n.options&&n.options.preSearchFilters&&(r=n.options.preSearchFilters.reduce((e,t)=>t(e),e));let i=t(r);return`postSearchFilters`in n.options&&n.options.postSearchFilters?n.options.postSearchFilters.reduce((e,t)=>t(e),i):i}),n.options.validateSearch&&t.middlewares.push(({search:e,next:r})=>{let i=r(e);if(!t._includeValidateSearch)return i;try{return{...i,...dr(n.options.validateSearch,i)??void 0}}catch{return i}});t.middlewares.push(({search:e})=>{let n=t.dest;return n.search?n.search===!0?e:Ge(n.search,e):{}});let n=(e,t,r)=>{if(e>=r.length)return t;let i=r[e];return i({search:t,next:t=>n(e+1,t,r)})};return function(e,r,i){return t.dest=r,t._includeValidateSearch=i,n(0,e,t.middlewares)}}function hr(e,t){if(e!==`root`)for(let e=t.length-1;e>=0;e--){let n=t[e];if(n.children)return n.id}return yn}function gr(e,t){let n=e.options.params?.parse??e.options.parseParams;if(n){let e=n(t);if(e===!1)throw Error(`Route params.parse returned false for a matched route`);Object.assign(t,e)}}var _r=`Error preloading route! ☝️`;function vr(e,t){if(e)return typeof e==`string`?e:e[t]}function yr(e){return typeof e==`string`?{href:e,crossOrigin:void 0}:e}function br(e){if(e.tag!==`link`)return;let t=e.attrs?.rel,n=e.attrs?.href;if(typeof n==`string`&&(typeof t==`string`?t.split(/\s+/):[]).includes(`stylesheet`))return n}function xr(e,t){let n=br(t);return!!n&&e?.inlineCss?.styles[n]!==void 0}var Sr=class{get to(){return this._to}get id(){return this._id}get path(){return this._path}get fullPath(){return this._fullPath}constructor(e){if(this.init=e=>{this.originalIndex=e.originalIndex;let t=this.options,n=!t?.path&&!t?.id;this.parentRoute=this.options.getParentRoute?.(),n?this._path=yn:this.parentRoute||gt();let r=n?yn:t?.path;r&&r!==`/`&&(r=Wt(r));let i=t?.id||r,a=n?yn:Ht([this.parentRoute.id===`__root__`?``:this.parentRoute.id,i]);r===`__root__`&&(r=`/`),a!==`__root__`&&(a=Ht([`/`,a]));let o=a===`__root__`?`/`:Ht([this.parentRoute.fullPath,r]);this._path=r,this._id=a,this._fullPath=o,this._to=Gt(o)},this.addChildren=e=>this._addFileChildren(e),this._addFileChildren=e=>(Array.isArray(e)&&(this.children=e),typeof e==`object`&&e&&(this.children=Object.values(e)),this),this._addFileTypes=()=>this,this.updateLoader=e=>(Object.assign(this.options,e),this),this.update=e=>(Object.assign(this.options,e),this),this.lazy=e=>(this.lazyFn=e,this),this.redirect=e=>bn({from:this.fullPath,...e}),this.options=e||{},this.isRoot=!e?.getParentRoute,e?.id&&e?.path)throw Error(`Route cannot have both an 'id' and a 'path' option.`)}},Cr=class extends Sr{constructor(e){super(e)}};function wr(e){if(typeof document<`u`&&document.querySelector){let t=e.stores.location.get(),n=t.state.__hashScrollIntoViewOptions??!0;if(n&&t.hash!==``){let e=document.getElementById(t.hash);e&&e.scrollIntoView(n)}}}function Tr(e){let t=e.errorComponent??Dr;return(0,F.jsx)(Er,{getResetKey:e.getResetKey,onCatch:e.onCatch,children:({error:n,reset:r})=>n?P.createElement(t,{error:n,reset:r}):e.children})}var Er=class extends P.Component{constructor(...e){super(...e),this.state={error:null}}static getDerivedStateFromProps(e,t){let n=e.getResetKey();return t.error&&t.resetKey!==n?{resetKey:n,error:null}:{resetKey:n}}static getDerivedStateFromError(e){return{error:e}}reset(){this.setState({error:null})}componentDidCatch(e,t){this.props.onCatch&&this.props.onCatch(e,t)}render(){return this.props.children({error:this.state.error,reset:()=>{this.reset()}})}};function Dr({error:e}){let[t,n]=P.useState(!1);return(0,F.jsxs)(`div`,{style:{padding:`.5rem`,maxWidth:`100%`},children:[(0,F.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`.5rem`},children:[(0,F.jsx)(`strong`,{style:{fontSize:`1rem`},children:`Something went wrong!`}),(0,F.jsx)(`button`,{style:{appearance:`none`,fontSize:`.6em`,border:`1px solid currentColor`,padding:`.1rem .2rem`,fontWeight:`bold`,borderRadius:`.25rem`},onClick:()=>n(e=>!e),children:t?`Hide Error`:`Show Error`})]}),(0,F.jsx)(`div`,{style:{height:`.25rem`}}),t?(0,F.jsx)(`div`,{children:(0,F.jsx)(`pre`,{style:{fontSize:`.7em`,border:`1px solid red`,borderRadius:`.25rem`,padding:`.3rem`,color:`red`,overflow:`auto`},children:e.message?(0,F.jsx)(`code`,{children:e.message}):null})}):null]})}function Or({children:e,fallback:t=null}){return kr()?(0,F.jsx)(P.Fragment,{children:e}):(0,F.jsx)(P.Fragment,{children:t})}function kr(){return P.useSyncExternalStore(Ar,()=>!0,()=>!1)}function Ar(){return()=>{}}var jr=P.createContext(null);function Mr(e){return P.useContext(jr)}var Nr=P.createContext(void 0),Pr=P.createContext(void 0),Fr=(e=>(e[e.None=0]=`None`,e[e.Mutable=1]=`Mutable`,e[e.Watching=2]=`Watching`,e[e.RecursedCheck=4]=`RecursedCheck`,e[e.Recursed=8]=`Recursed`,e[e.Dirty=16]=`Dirty`,e[e.Pending=32]=`Pending`,e))(Fr||{});function Ir({update:e,notify:t,unwatched:n}){return{link:r,unlink:i,propagate:a,checkDirty:o,shallowPropagate:s};function r(e,t,n){let r=t.depsTail;if(r!==void 0&&r.dep===e)return;let i=r===void 0?t.deps:r.nextDep;if(i!==void 0&&i.dep===e){i.version=n,t.depsTail=i;return}let a=e.subsTail;if(a!==void 0&&a.version===n&&a.sub===t)return;let o=t.depsTail=e.subsTail={version:n,dep:e,sub:t,prevDep:r,nextDep:i,prevSub:a,nextSub:void 0};i!==void 0&&(i.prevDep=o),r===void 0?t.deps=o:r.nextDep=o,a===void 0?e.subs=o:a.nextSub=o}function i(e,t=e.sub){let r=e.dep,i=e.prevDep,a=e.nextDep,o=e.nextSub,s=e.prevSub;return a===void 0?t.depsTail=i:a.prevDep=i,i===void 0?t.deps=a:i.nextDep=a,o===void 0?r.subsTail=s:o.prevSub=s,s===void 0?(r.subs=o)===void 0&&n(r):s.nextSub=o,a}function a(e){let n=e.nextSub,r;top:do{let i=e.sub,a=i.flags;if(a&60?a&12?a&4?!(a&48)&&c(e,i)?(i.flags=a|40,a&=1):a=0:i.flags=a&-9|32:a=0:i.flags=a|32,a&2&&t(i),a&1){let t=i.subs;if(t!==void 0){let i=(e=t).nextSub;i!==void 0&&(r={value:n,prev:r},n=i);continue}}if((e=n)!==void 0){n=e.nextSub;continue}for(;r!==void 0;)if(e=r.value,r=r.prev,e!==void 0){n=e.nextSub;continue top}break}while(!0)}function o(t,n){let r,i=0,a=!1;top:do{let o=t.dep,c=o.flags;if(n.flags&16)a=!0;else if((c&17)==17){if(e(o)){let e=o.subs;e.nextSub!==void 0&&s(e),a=!0}}else if((c&33)==33){(t.nextSub!==void 0||t.prevSub!==void 0)&&(r={value:t,prev:r}),t=o.deps,n=o,++i;continue}if(!a){let e=t.nextDep;if(e!==void 0){t=e;continue}}for(;i--;){let i=n.subs,o=i.nextSub!==void 0;if(o?(t=r.value,r=r.prev):t=i,a){if(e(n)){o&&s(i),n=t.sub;continue}a=!1}else n.flags&=-33;n=t.sub;let c=t.nextDep;if(c!==void 0){t=c;continue top}}return a}while(!0)}function s(e){do{let n=e.sub,r=n.flags;(r&48)==32&&(n.flags=r|16,(r&6)==2&&t(n))}while((e=e.nextSub)!==void 0)}function c(e,t){let n=t.depsTail;for(;n!==void 0;){if(n===e)return!0;n=n.prevDep}return!1}}function Lr(e,t,n){let r=typeof e==`object`,i=r?e:void 0;return{next:(r?e.next:e)?.bind(i),error:(r?e.error:t)?.bind(i),complete:(r?e.complete:n)?.bind(i)}}var Rr=[],zr=0,{link:Br,unlink:Vr,propagate:Hr,checkDirty:Ur,shallowPropagate:Wr}=Ir({update(e){return e._update()},notify(e){Rr[Kr++]=e,e.flags&=~Fr.Watching},unwatched(e){e.depsTail!==void 0&&(e.depsTail=void 0,e.flags=Fr.Mutable|Fr.Dirty,Xr(e))}}),Gr=0,Kr=0,qr,Jr=0;function Yr(e){try{++Jr,e()}finally{--Jr||Zr()}}function Xr(e){let t=e.depsTail,n=t===void 0?e.deps:t.nextDep;for(;n!==void 0;)n=Vr(n,e)}function Zr(){if(!(Jr>0)){for(;Gr{i.get(),n.current?t.next?.(i._snapshot):n.current=!0});return{unsubscribe:()=>{r.stop()}}},_update(e){let a=qr,o=t?.compare??Object.is;if(n)qr=i,++zr,i.depsTail=void 0;else if(e===void 0)return!1;n&&(i.flags=Fr.Mutable|Fr.RecursedCheck);try{let t=i._snapshot,a=typeof e==`function`?e(t):e===void 0&&n?r(t):e;return t===void 0||!o(t,a)?(i._snapshot=a,!0):!1}finally{qr=a,n&&(i.flags&=~Fr.RecursedCheck),Xr(i)}}};return n?(i.flags=Fr.Mutable|Fr.Dirty,i.get=function(){let e=i.flags;if(e&Fr.Dirty||e&Fr.Pending&&Ur(i.deps,i)){if(i._update()){let e=i.subs;e!==void 0&&Wr(e)}}else e&Fr.Pending&&(i.flags=e&~Fr.Pending);return qr!==void 0&&Br(i,qr,zr),i._snapshot}):i.set=function(e){if(i._update(e)){let e=i.subs;e!==void 0&&(Hr(e),Wr(e),Zr())}},i}function $r(e){let t=()=>{let t=qr;qr=n,++zr,n.depsTail=void 0,n.flags=Fr.Watching|Fr.RecursedCheck;try{return e()}finally{qr=t,n.flags&=~Fr.RecursedCheck,Xr(n)}},n={deps:void 0,depsTail:void 0,subs:void 0,subsTail:void 0,flags:Fr.Watching|Fr.RecursedCheck,notify(){let e=this.flags;e&Fr.Dirty||e&Fr.Pending&&Ur(this.deps,this)?t():this.flags=Fr.Watching},stop(){this.flags=Fr.None,this.depsTail=void 0,Xr(this)}};return t(),n}var ei=o((e=>{var t=je();function n(e,t){return e===t&&(e!==0||1/e==1/t)||e!==e&&t!==t}var r=typeof Object.is==`function`?Object.is:n,i=t.useState,a=t.useEffect,o=t.useLayoutEffect,s=t.useDebugValue;function c(e,t){var n=t(),r=i({inst:{value:n,getSnapshot:t}}),c=r[0].inst,u=r[1];return o(function(){c.value=n,c.getSnapshot=t,l(c)&&u({inst:c})},[e,n,t]),a(function(){return l(c)&&u({inst:c}),e(function(){l(c)&&u({inst:c})})},[e]),s(n),n}function l(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!r(e,n)}catch{return!0}}function u(e,t){return t()}var d=typeof window>`u`||window.document===void 0||window.document.createElement===void 0?u:c;e.useSyncExternalStore=t.useSyncExternalStore===void 0?d:t.useSyncExternalStore})),ti=o(((e,t)=>{t.exports=ei()})),ni=o((e=>{var t=je(),n=ti();function r(e,t){return e===t&&(e!==0||1/e==1/t)||e!==e&&t!==t}var i=typeof Object.is==`function`?Object.is:r,a=n.useSyncExternalStore,o=t.useRef,s=t.useEffect,c=t.useMemo,l=t.useDebugValue;e.useSyncExternalStoreWithSelector=function(e,t,n,r,u){var d=o(null);if(d.current===null){var f={hasValue:!1,value:null};d.current=f}else f=d.current;d=c(function(){function e(e){if(!a){if(a=!0,o=e,e=r(e),u!==void 0&&f.hasValue){var t=f.value;if(u(t,e))return s=t}return s=e}if(t=s,i(o,e))return t;var n=r(e);return u!==void 0&&u(t,n)?(o=e,t):(o=e,s=n)}var a=!1,o,s,c=n===void 0?null:n;return[function(){return e(t())},c===null?void 0:function(){return e(c())}]},[t,n,r,u]);var p=a(e,d[0],d[1]);return s(function(){f.hasValue=!0,f.value=p},[p]),l(p),p}})),ri=o(((e,t)=>{t.exports=ni()}))();function ii(e,t){return e===t}function ai(e,t,n=ii){let r=(0,P.useCallback)(t=>{if(!e)return()=>{};let{unsubscribe:n}=e.subscribe(t);return n},[e]),i=(0,P.useCallback)(()=>e?.get(),[e]);return(0,ri.useSyncExternalStoreWithSelector)(r,i,i,t,n)}var oi={get:()=>void 0,subscribe:()=>({unsubscribe:()=>{}})};function si(e){let t=Mr(),n=P.useContext(e.from?Pr:Nr),r=e.from??n,i=r?e.from?t.stores.getRouteMatchStore(r):t.stores.matchStores.get(r):void 0,a=P.useRef(void 0);return ai(i??oi,n=>{if((e.shouldThrow??!0)&&!n&>(),n===void 0)return;let r=e.select?e.select(n):n;if(e.structuralSharing??t.options.defaultStructuralSharing){let e=Ze(a.current,r);return a.current=e,e}return r})}function ci(e){return si({from:e.from,strict:e.strict,structuralSharing:e.structuralSharing,select:t=>e.select?e.select(t.loaderData):t.loaderData})}function li(e){let{select:t,...n}=e;return si({...n,select:e=>t?t(e.loaderDeps):e.loaderDeps})}function ui(e){return si({from:e.from,shouldThrow:e.shouldThrow,structuralSharing:e.structuralSharing,strict:e.strict,select:t=>{let n=e.strict===!1?t.params:t._strictParams;return e.select?e.select(n):n}})}function di(e){return si({from:e.from,strict:e.strict,shouldThrow:e.shouldThrow,structuralSharing:e.structuralSharing,select:t=>e.select?e.select(t.search):t.search})}function fi(e){let t=Mr();return P.useCallback(n=>t.navigate({...n,from:n.from??e?.from}),[e?.from,t])}function pi(e){return si({...e,select:t=>e.select?e.select(t.context):t.context})}var mi=o((e=>{var t=je();function n(e){var t=`https://react.dev/errors/`+e;if(1{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=mi()})),gi=c(hi(),1);function _i(e,t){let n=Mr(),r=He(t),{activeProps:i,inactiveProps:a,activeOptions:o,to:s,preload:c,preloadDelay:l,preloadIntentProximity:u,hashScrollIntoView:d,replace:f,startTransition:p,resetScroll:m,viewTransition:h,children:g,target:_,disabled:v,style:y,className:b,onClick:x,onBlur:S,onFocus:C,onMouseEnter:w,onMouseLeave:T,onTouchStart:E,ignoreBlocker:ee,params:D,search:O,hash:te,state:ne,mask:re,reloadDocument:k,unsafeRelative:A,from:ie,_fromLocation:j,...ae}=e,oe=kr(),se=P.useMemo(()=>e,[n,e.from,e._fromLocation,e.hash,e.to,e.search,e.params,e.state,e.mask,e.unsafeRelative]),ce=ai(n.stores.location,e=>e,(e,t)=>e.href===t.href),M=P.useMemo(()=>{let e={_fromLocation:ce,...se};return n.buildLocation(e)},[n,ce,se]),le=M.maskedLocation?M.maskedLocation.publicHref:M.publicHref,ue=M.maskedLocation?M.maskedLocation.external:M.external,N=P.useMemo(()=>Ei(le,ue,n.history,v),[v,ue,le,n.history]),de=P.useMemo(()=>{if(N?.external)return lt(N.href,n.protocolAllowlist)?void 0:N.href;if(!Di(s)&&!(typeof s!=`string`||s.indexOf(`:`)===-1))try{return new URL(s),lt(s,n.protocolAllowlist)?void 0:s}catch{}},[s,N,n.protocolAllowlist]),fe=P.useMemo(()=>{if(de)return!1;if(o?.exact){if(!Jt(ce.pathname,M.pathname,n.basepath))return!1}else{let e=qt(ce.pathname,n.basepath),t=qt(M.pathname,n.basepath);if(!(e.startsWith(t)&&(e.length===t.length||e[t.length]===`/`)))return!1}return(o?.includeSearch??!0)&&!nt(ce.search,M.search,{partial:!o?.exact,ignoreUndefined:!o?.explicitUndefined})?!1:o?.includeHash?oe&&ce.hash===M.hash:!0},[o?.exact,o?.explicitUndefined,o?.includeHash,o?.includeSearch,ce,de,oe,M.hash,M.pathname,M.search,n.basepath]),pe=fe?Ge(i,{})??yi:vi,me=fe?vi:Ge(a,{})??vi,he=[b,pe.className,me.className].filter(Boolean).join(` `),ge=(y||pe.style||me.style)&&{...y,...pe.style,...me.style},[_e,ve]=P.useState(!1),ye=P.useRef(!1),be=e.reloadDocument||de?!1:c??n.options.defaultPreload,xe=l??n.options.defaultPreloadDelay??0,Se=P.useCallback(()=>{n.preloadRoute({...se,_builtLocation:M}).catch(e=>{console.warn(e),console.warn(_r)})},[n,se,M]);Ve(r,P.useCallback(e=>{e?.isIntersecting&&Se()},[Se]),wi,{disabled:!!v||be!==`viewport`}),P.useEffect(()=>{ye.current||!v&&be===`render`&&(Se(),ye.current=!0)},[v,Se,be]);let Ce=e=>{let t=e.currentTarget.getAttribute(`target`),r=_===void 0?t:_;if(!v&&!ki(e)&&!e.defaultPrevented&&(!r||r===`_self`)&&e.button===0){e.preventDefault(),(0,gi.flushSync)(()=>{ve(!0)});let t=n.subscribe(`onResolved`,()=>{t(),ve(!1)});n.navigate({...se,replace:f,resetScroll:m,hashScrollIntoView:d,startTransition:p,viewTransition:h,ignoreBlocker:ee})}};if(de)return{...ae,ref:r,href:de,...g&&{children:g},..._&&{target:_},...v&&{disabled:v},...y&&{style:y},...b&&{className:b},...x&&{onClick:x},...S&&{onBlur:S},...C&&{onFocus:C},...w&&{onMouseEnter:w},...T&&{onMouseLeave:T},...E&&{onTouchStart:E}};let we=e=>{if(v||be!==`intent`)return;if(!xe){Se();return}let t=e.currentTarget;if(Ci.has(t))return;let n=setTimeout(()=>{Ci.delete(t),Se()},xe);Ci.set(t,n)},Te=e=>{v||be!==`intent`||Se()},Ee=e=>{if(v||!be||!xe)return;let t=e.currentTarget,n=Ci.get(t);n&&(clearTimeout(n),Ci.delete(t))};return{...ae,...pe,...me,href:N?.href,ref:r,onClick:Ti([x,Ce]),onBlur:Ti([S,Ee]),onFocus:Ti([C,we]),onMouseEnter:Ti([w,we]),onMouseLeave:Ti([T,Ee]),onTouchStart:Ti([E,Te]),disabled:!!v,target:_,...ge&&{style:ge},...he&&{className:he},...v&&bi,...fe&&xi,...oe&&_e&&Si}}var vi={},yi={className:`active`},bi={role:`link`,"aria-disabled":!0},xi={"data-status":`active`,"aria-current":`page`},Si={"data-transitioning":`transitioning`},Ci=new WeakMap,wi={rootMargin:`100px`},Ti=e=>t=>{for(let n of e)if(n){if(t.defaultPrevented)return;n(t)}};function Ei(e,t,n,r){if(!r)return t?{href:e,external:!0}:{href:n.createHref(e)||`/`,external:!1}}function Di(e){if(typeof e!=`string`)return!1;let t=e.charCodeAt(0);return t===47?e.charCodeAt(1)!==47:t===46}var Oi=P.forwardRef((e,t)=>{let{_asChild:n,...r}=e,{type:i,...a}=_i(r,t),o=typeof r.children==`function`?r.children({isActive:a[`data-status`]===`active`}):r.children;if(!n){let{disabled:e,...t}=a;return P.createElement(`a`,t,o)}return P.createElement(n,a,o)});function ki(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}var Ai=class extends Sr{constructor(e){super(e),this.useMatch=e=>si({select:e?.select,from:this.id,structuralSharing:e?.structuralSharing}),this.useRouteContext=e=>pi({...e,from:this.id}),this.useSearch=e=>di({select:e?.select,structuralSharing:e?.structuralSharing,from:this.id}),this.useParams=e=>ui({select:e?.select,structuralSharing:e?.structuralSharing,from:this.id}),this.useLoaderDeps=e=>li({...e,from:this.id}),this.useLoaderData=e=>ci({...e,from:this.id}),this.useNavigate=()=>fi({from:this.fullPath}),this.Link=P.forwardRef((e,t)=>(0,F.jsx)(Oi,{ref:t,from:this.fullPath,...e}))}};function ji(e){return new Ai(e)}function Mi(){return e=>Pi(e)}var Ni=class extends Cr{constructor(e){super(e),this.useMatch=e=>si({select:e?.select,from:this.id,structuralSharing:e?.structuralSharing}),this.useRouteContext=e=>pi({...e,from:this.id}),this.useSearch=e=>di({select:e?.select,structuralSharing:e?.structuralSharing,from:this.id}),this.useParams=e=>ui({select:e?.select,structuralSharing:e?.structuralSharing,from:this.id}),this.useLoaderDeps=e=>li({...e,from:this.id}),this.useLoaderData=e=>ci({...e,from:this.id}),this.useNavigate=()=>fi({from:this.fullPath}),this.Link=P.forwardRef((e,t)=>(0,F.jsx)(Oi,{ref:t,from:this.fullPath,...e}))}};function Pi(e){return new Ni(e)}function I(e){return new Fi(e,{silent:!0}).createRoute}var Fi=class{constructor(e,t){this.path=e,this.createRoute=e=>{let t=ji(e);return t.isRoot=!1,t},this.silent=t?.silent}};function L(e,t){let n,r,i,a,o=()=>(n||=e().then(e=>{n=void 0,r=e[t??`default`]}).catch(e=>{if(i=e,it(i)&&i instanceof Error&&typeof window<`u`&&typeof sessionStorage<`u`){let e=`tanstack_router_reload:${i.message}`;sessionStorage.getItem(e)||(sessionStorage.setItem(e,`1`),a=!0)}}),n),s=function(e){if(a)throw window.location.reload(),new Promise(()=>{});if(i)throw i;if(!r)if(Re)Re(o());else throw o();return P.createElement(r,e)};return s.preload=o,s}function Ii(e){let t=Mr(),n=`not-found-${ai(t.stores.location,e=>e.pathname)}-${ai(t.stores.status,e=>e)}`;return(0,F.jsx)(Tr,{getResetKey:()=>n,onCatch:(t,n)=>{if(en(t))e.onCatch?.(t,n);else throw t},errorComponent:({error:t})=>{if(en(t))return e.fallback?.(t);throw t},children:e.children})}function Li(){return(0,F.jsx)(`p`,{children:`Not Found`})}function Ri(e){return(0,F.jsx)(F.Fragment,{children:e.children})}function zi(e,t,n){return t.options.notFoundComponent?(0,F.jsx)(t.options.notFoundComponent,{...n}):e.options.defaultNotFoundComponent?(0,F.jsx)(e.options.defaultNotFoundComponent,{...n}):(0,F.jsx)(Li,{})}var Bi=P.memo(function({matchId:e}){let t=Mr(),n=t.stores.matchStores.get(e);n||gt();let r=ai(t.stores.loadedAt,e=>e),i=ai(n,e=>e);return(0,F.jsx)(Vi,{router:t,matchId:e,resetKey:r,matchState:P.useMemo(()=>{let e=i.routeId,n=t.routesById[e].parentRoute?.id;return{routeId:e,ssr:i.ssr,_displayPending:i._displayPending,parentRouteId:n}},[i._displayPending,i.routeId,i.ssr,t.routesById])})});function Vi({router:e,matchId:t,resetKey:n,matchState:r}){let i=e.routesById[r.routeId],a=i.options.pendingComponent??e.options.defaultPendingComponent,o=a?(0,F.jsx)(a,{}):null,s=i.options.errorComponent??e.options.defaultErrorComponent,c=i.options.onCatch??e.options.defaultOnCatch,l=i.isRoot?i.options.notFoundComponent??e.options.notFoundRoute?.options.component:i.options.notFoundComponent,u=r.ssr===!1||r.ssr===`data-only`,d=(!i.isRoot||i.options.wrapInSuspense||u)&&(i.options.wrapInSuspense??a??(i.options.errorComponent?.preload||u))?P.Suspense:Ri,f=s?Tr:Ri,p=l?Ii:Ri;return(0,F.jsxs)(i.isRoot?i.options.shellComponent??Ri:Ri,{children:[(0,F.jsx)(Nr.Provider,{value:t,children:(0,F.jsx)(d,{fallback:o,children:(0,F.jsx)(f,{getResetKey:()=>n,errorComponent:s||Dr,onCatch:(e,t)=>{if(en(e))throw e.routeId??=r.routeId,e;c?.(e,t)},children:(0,F.jsx)(p,{fallback:e=>{if(e.routeId??=r.routeId,!l||e.routeId&&e.routeId!==r.routeId||!e.routeId&&!i.isRoot)throw e;return P.createElement(l,e)},children:u||r._displayPending?(0,F.jsx)(Or,{fallback:o,children:(0,F.jsx)(Ui,{matchId:t})}):(0,F.jsx)(Ui,{matchId:t})})})})}),r.parentRouteId===`__root__`?(0,F.jsxs)(F.Fragment,{children:[(0,F.jsx)(Hi,{resetKey:n}),(e.options.scrollRestoration,null)]}):null]})}function Hi({resetKey:e}){let t=Mr(),n=P.useRef(void 0);return ze(()=>{let e=t.latestLocation.href;(n.current===void 0||n.current!==e)&&(t.emit({type:`onRendered`,...or(t.stores.location.get(),t.stores.resolvedLocation.get())}),n.current=e)},[t.latestLocation.state.__TSR_key,e,t]),null}var Ui=P.memo(function({matchId:e}){let t=Mr(),n=(e,n)=>t.getMatch(e.id)?._nonReactive[n]??e._nonReactive[n],r=t.stores.matchStores.get(e);r||gt();let i=ai(r,e=>e),a=i.routeId,o=t.routesById[a],s=P.useMemo(()=>{let e=(t.routesById[a].options.remountDeps??t.options.defaultRemountDeps)?.({routeId:a,loaderDeps:i.loaderDeps,params:i._strictParams,search:i._strictSearch});return e?JSON.stringify(e):void 0},[a,i.loaderDeps,i._strictParams,i._strictSearch,t.options.defaultRemountDeps,t.routesById]),c=P.useMemo(()=>{let e=o.options.component??t.options.defaultComponent;return e?(0,F.jsx)(e,{},s):(0,F.jsx)(Wi,{})},[s,o.options.component,t.options.defaultComponent]);if(i._displayPending)throw n(i,`displayPendingPromise`);if(i._forcePending)throw n(i,`minPendingPromise`);if(i.status===`pending`){let e=o.options.pendingMinMs??t.options.defaultPendingMinMs;if(e){let n=t.getMatch(i.id);if(n&&!n._nonReactive.minPendingPromise){let t=rt();n._nonReactive.minPendingPromise=t,setTimeout(()=>{t.resolve(),n._nonReactive.minPendingPromise=void 0},e)}}throw n(i,`loadPromise`)}if(i.status===`notFound`)return en(i.error)||gt(),zi(t,o,i.error);if(i.status===`redirected`)throw xn(i.error)||gt(),n(i,`loadPromise`);if(i.status===`error`)throw i.error;return c}),Wi=P.memo(function(){let e=Mr(),t=P.useContext(Nr),n,r=!1,i;{let a=t?e.stores.matchStores.get(t):void 0;[n,r]=ai(a,e=>[e?.routeId,e?.globalNotFound??!1]),i=ai(e.stores.matchesId,e=>e[e.findIndex(e=>e===t)+1])}let a=n?e.routesById[n]:void 0,o=e.options.defaultPendingComponent?(0,F.jsx)(e.options.defaultPendingComponent,{}):null;if(r)return a||gt(),zi(e,a,void 0);if(!i)return null;let s=(0,F.jsx)(Bi,{matchId:i});return n===`__root__`?(0,F.jsx)(P.Suspense,{fallback:o,children:s}):s});function Gi(){let e=Mr(),t=P.useRef({router:e,mounted:!1}),[n,r]=P.useState(!1),i=ai(e.stores.isLoading,e=>e),a=ai(e.stores.hasPending,e=>e),o=Be(i),s=i||n||a,c=Be(s),l=i||a,u=Be(l);return e.startTransition=e=>{r(!0),P.startTransition(()=>{e(),r(!1)})},P.useEffect(()=>{let t=e.history.subscribe(e.load),n=e.buildLocation({to:e.latestLocation.pathname,search:!0,params:!0,hash:!0,state:!0,_includeValidateSearch:!0});return Gt(e.latestLocation.publicHref)!==Gt(n.publicHref)&&e.commitLocation({...n,replace:!0}),()=>{t()}},[e,e.history]),ze(()=>{typeof window<`u`&&e.ssr||t.current.router===e&&t.current.mounted||(t.current={router:e,mounted:!0},(async()=>{try{await e.load()}catch(e){console.error(e)}})())},[e]),ze(()=>{o&&!i&&e.emit({type:`onLoad`,...or(e.stores.location.get(),e.stores.resolvedLocation.get())})},[o,e,i]),ze(()=>{u&&!l&&e.emit({type:`onBeforeRouteMount`,...or(e.stores.location.get(),e.stores.resolvedLocation.get())})},[l,u,e]),ze(()=>{if(c&&!s){let t=or(e.stores.location.get(),e.stores.resolvedLocation.get());e.emit({type:`onResolved`,...t}),Yr(()=>{e.stores.status.set(`idle`),e.stores.resolvedLocation.set(e.stores.location.get())}),t.hrefChanged&&wr(e)}},[s,c,e]),null}function Ki(){let e=Mr(),t=e.routesById.__root__.options.pendingComponent??e.options.defaultPendingComponent,n=t?(0,F.jsx)(t,{}):null,r=(0,F.jsxs)(typeof document<`u`&&e.ssr?Ri:P.Suspense,{fallback:n,children:[(0,F.jsx)(Gi,{}),(0,F.jsx)(qi,{})]});return e.options.InnerWrap?(0,F.jsx)(e.options.InnerWrap,{children:r}):r}function qi(){let e=Mr(),t=ai(e.stores.firstId,e=>e),n=ai(e.stores.loadedAt,e=>e),r=t?(0,F.jsx)(Bi,{matchId:t}):null;return(0,F.jsx)(Nr.Provider,{value:t,children:e.options.disableGlobalCatchBoundary?r:(0,F.jsx)(Tr,{getResetKey:()=>n,errorComponent:Dr,onCatch:void 0,children:r})})}var Ji=e=>({createMutableStore:Qr,createReadonlyStore:Qr,batch:Yr}),Yi=e=>new Xi(e),Xi=class extends sr{constructor(e){super(e,Ji)}};function Zi({router:e,children:t,...n}){Je(n)&&e.update({...e.options,...n,context:{...e.options.context,...n.context}});let r=(0,F.jsx)(jr.Provider,{value:e,children:t});return e.options.Wrap?(0,F.jsx)(e.options.Wrap,{children:r}):r}function Qi({router:e,...t}){return(0,F.jsx)(Zi,{router:e,...t,children:(0,F.jsx)(Ki,{})})}function $i(e){let t=Mr(),n=(0,P.useRef)(void 0);return ai(t.stores.location,r=>{let i=e?.select?e.select(r):r;if(e?.structuralSharing??t.options.defaultStructuralSharing){let e=Ze(n.current,i);return n.current=e,e}return i})}function ea(e){let{attrs:t,children:n,nonce:r}=e;switch(e.tag){case`title`:return(0,F.jsx)(`title`,{...t,suppressHydrationWarning:!0,children:n});case`meta`:return(0,F.jsx)(`meta`,{...t,suppressHydrationWarning:!0});case`link`:return(0,F.jsx)(`link`,{...t,precedence:t?.precedence??(t?.rel===`stylesheet`?`default`:void 0),nonce:r,suppressHydrationWarning:!0});case`style`:return e.inlineCss,(0,F.jsx)(`style`,{...t,dangerouslySetInnerHTML:{__html:n},nonce:r});case`script`:return(0,F.jsx)(ta,{attrs:t,children:n});default:return null}}function ta({attrs:e,children:t}){Mr();let n=kr(),r=typeof e?.type==`string`&&e.type!==``&&e.type!==`text/javascript`&&e.type!==`module`;if(P.useEffect(()=>{if(!r){if(e?.src){let t=(()=>{try{let t=document.baseURI||window.location.href;return new URL(e.src,t).href}catch{return e.src}})();if(Array.from(document.querySelectorAll(`script[src]`)).find(e=>e.src===t))return;let n=document.createElement(`script`);for(let[t,r]of Object.entries(e))t!==`suppressHydrationWarning`&&r!==void 0&&r!==!1&&n.setAttribute(t,typeof r==`boolean`?``:String(r));return document.head.appendChild(n),()=>{n.parentNode&&n.parentNode.removeChild(n)}}if(typeof t==`string`){let n=typeof e?.type==`string`?e.type:`text/javascript`,r=typeof e?.nonce==`string`?e.nonce:void 0;if(Array.from(document.querySelectorAll(`script:not([src])`)).find(e=>{if(!(e instanceof HTMLScriptElement))return!1;let i=e.getAttribute(`type`)??`text/javascript`,a=e.getAttribute(`nonce`)??void 0;return e.textContent===t&&i===n&&a===r}))return;let i=document.createElement(`script`);if(i.textContent=t,e)for(let[t,n]of Object.entries(e))t!==`suppressHydrationWarning`&&n!==void 0&&n!==!1&&i.setAttribute(t,typeof n==`boolean`?``:String(n));return document.head.appendChild(i),()=>{i.parentNode&&i.parentNode.removeChild(i)}}}},[e,t,r]),r&&typeof t==`string`)return(0,F.jsx)(`script`,{...e,suppressHydrationWarning:!0,dangerouslySetInnerHTML:{__html:t}});if(!n){if(e?.src)return(0,F.jsx)(`script`,{...e,suppressHydrationWarning:!0});if(typeof t==`string`)return(0,F.jsx)(`script`,{...e,dangerouslySetInnerHTML:{__html:t},suppressHydrationWarning:!0})}return null}var na=e=>{let t=Mr(),n=t.options.ssr?.nonce,r=ai(t.stores.matches,e=>e.map(e=>e.meta).filter(Boolean),nt),i=P.useMemo(()=>{let e=[],t={},i;for(let a=r.length-1;a>=0;a--){let o=r[a];for(let r=o.length-1;r>=0;r--){let a=o[r];if(a)if(a.title)i||={tag:`title`,children:a.title};else if(`script:ld+json`in a)try{let t=JSON.stringify(a[`script:ld+json`]);e.push({tag:`script`,attrs:{type:`application/ld+json`},children:ft(t)})}catch{}else{let r=a.name??a.property;if(r){if(t[r])continue;t[r]=!0}e.push({tag:`meta`,attrs:{...a,nonce:n}})}}}return i&&e.push(i),n&&e.push({tag:`meta`,attrs:{property:`csp-nonce`,content:n}}),e.reverse(),e},[r,n]),a=ai(t.stores.matches,r=>{let i=r.map(e=>e.links).filter(Boolean).flat(1).map(e=>({tag:`link`,attrs:{...e,nonce:n}})),a=t.ssr?.manifest,o=r.map(e=>a?.routes[e.routeId]?.assets??[]).filter(Boolean).flat(1).flatMap(t=>t.tag===`link`?xr(a,t)?[]:[{tag:`link`,attrs:{...t.attrs,crossOrigin:vr(e,`stylesheet`)??t.attrs?.crossOrigin,suppressHydrationWarning:!0,nonce:n}}]:t.tag===`style`?[{tag:`style`,attrs:{...t.attrs,nonce:n},children:t.children,...t.inlineCss?{inlineCss:!0}:{}}]:[]);return[...i,...o]},nt),o=ai(t.stores.matches,r=>{let i=[];return r.map(e=>t.looseRoutesById[e.routeId]).forEach(r=>t.ssr?.manifest?.routes[r.id]?.preloads?.filter(Boolean).forEach(t=>{let r=yr(t);i.push({tag:`link`,attrs:{rel:`modulepreload`,href:r.href,crossOrigin:vr(e,`modulepreload`)??r.crossOrigin,nonce:n}})})),i},nt),s=ai(t.stores.matches,e=>e.map(e=>e.styles).flat(1).filter(Boolean).map(({children:e,...t})=>({tag:`style`,attrs:{...t,nonce:n},children:e})),nt),c=ai(t.stores.matches,e=>e.map(e=>e.headScripts).flat(1).filter(Boolean).map(({children:e,...t})=>({tag:`script`,attrs:{...t,nonce:n},children:e})),nt);return ra([...i,...o,...a,...s,...c],e=>JSON.stringify(e))};function ra(e,t){let n=new Set;return e.filter(e=>{let r=t(e);return n.has(r)?!1:(n.add(r),!0)})}function ia(e){let t=na(e.assetCrossOrigin),n=Mr().options.ssr?.nonce;return(0,F.jsx)(F.Fragment,{children:t.map(e=>(0,P.createElement)(ea,{...e,key:`tsr-meta-${JSON.stringify(e)}`,nonce:n}))})}var aa=o((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(e.unstable_now=void 0,typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=!1,_=typeof setTimeout==`function`?setTimeout:null,v=typeof clearTimeout==`function`?clearTimeout:null,y=typeof setImmediate<`u`?setImmediate:null;function b(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function x(e){if(h=!1,b(e),!m)if(n(c)!==null)m=!0,S||(S=!0,D());else{var t=n(l);t!==null&&ne(x,t.startTime-e)}}var S=!1,C=-1,w=5,T=-1;function E(){return g?!0:!(e.unstable_now()-Tt&&E());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=t);if(t=e.unstable_now(),typeof s==`function`){d.callback=s,b(t),i=!0;break b}d===n(c)&&r(c),b(t)}else r(c);d=n(c)}if(d!==null)i=!0;else{var u=n(l);u!==null&&ne(x,u.startTime-t),i=!1}}break a}finally{d=null,f=a,p=!1}i=void 0}}finally{i?D():S=!1}}}var D;if(typeof y==`function`)D=function(){y(ee)};else if(typeof MessageChannel<`u`){var O=new MessageChannel,te=O.port2;O.port1.onmessage=ee,D=function(){te.postMessage(null)}}else D=function(){_(ee,0)};function ne(t,n){C=_(function(){t(e.unstable_now())},n)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(e){e.callback=null},e.unstable_forceFrameRate=function(e){0>e||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(v(C),C=-1):h=!0,ne(x,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,S||(S=!0,D()))),r},e.unstable_shouldYield=E,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),oa=o(((e,t)=>{t.exports=aa()})),sa=o((e=>{var t=oa(),n=je(),r=hi();function i(e){var t=`https://react.dev/errors/`+e;if(1ae||(e.current=j[ae],j[ae]=null,ae--)}function ce(e,t){ae++,j[ae]=e.current,e.current=t}var M=oe(null),le=oe(null),ue=oe(null),N=oe(null);function de(e,t){switch(ce(ue,t),ce(le,e),ce(M,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?tf(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=tf(t),e=nf(t,e);else switch(e){case`svg`:e=1;break;case`math`:e=2;break;default:e=0}}se(M),ce(M,e)}function fe(){se(M),se(le),se(ue)}function pe(e){e.memoizedState!==null&&ce(N,e);var t=M.current,n=nf(t,e.type);t!==n&&(ce(le,e),ce(M,n))}function me(e){le.current===e&&(se(M),se(le)),N.current===e&&(se(N),fp._currentValue=ie)}var he,ge;function _e(e){if(he===void 0)try{throw Error()}catch(e){var t=e.stack.trim().match(/\n( *(at )?)/);he=t&&t[1]||``,ge=-1()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;li[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,a)=>(a=n==null?{}:e(i(n)),s(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var l=class{constructor(){this.listeners=new Set,this.subscribe=this.subscribe.bind(this)}subscribe(e){return this.listeners.add(e),this.onSubscribe(),()=>{this.listeners.delete(e),this.onUnsubscribe()}}hasListeners(){return this.listeners.size>0}onSubscribe(){}onUnsubscribe(){}},u=new class extends l{#e;#t;#n;constructor(){super(),this.#n=e=>{if(typeof window<`u`&&window.addEventListener){let t=()=>e();return window.addEventListener(`visibilitychange`,t,!1),()=>{window.removeEventListener(`visibilitychange`,t)}}}}onSubscribe(){this.#t||this.setEventListener(this.#n)}onUnsubscribe(){this.hasListeners()||(this.#t?.(),this.#t=void 0)}setEventListener(e){this.#n=e,this.#t?.(),this.#t=e(e=>{typeof e==`boolean`?this.setFocused(e):this.onFocus()})}setFocused(e){this.#e!==e&&(this.#e=e,this.onFocus())}onFocus(){let e=this.isFocused();this.listeners.forEach(t=>{t(e)})}isFocused(){return typeof this.#e==`boolean`?this.#e:globalThis.document?.visibilityState!==`hidden`}},d={setTimeout:(e,t)=>setTimeout(e,t),clearTimeout:e=>clearTimeout(e),setInterval:(e,t)=>setInterval(e,t),clearInterval:e=>clearInterval(e)},f=new class{#e=d;setTimeoutProvider(e){this.#e=e}setTimeout(e,t){return this.#e.setTimeout(e,t)}clearTimeout(e){this.#e.clearTimeout(e)}setInterval(e,t){return this.#e.setInterval(e,t)}clearInterval(e){this.#e.clearInterval(e)}};function p(e){setTimeout(e,0)}var m=typeof window>`u`||`Deno`in globalThis;function h(){}function g(e,t){return typeof e==`function`?e(t):e}function _(e){return typeof e==`number`&&e>=0&&e!==1/0}function v(e,t){return Math.max(e+(t||0)-Date.now(),0)}function y(e,t){return typeof e==`function`?e(t):e}function b(e,t){return typeof e==`function`?e(t):e}function x(e,t){let{type:n=`all`,exact:r,fetchStatus:i,predicate:a,queryKey:o,stale:s}=e;if(o){if(r){if(t.queryHash!==C(o,t.options))return!1}else if(!T(t.queryKey,o))return!1}if(n!==`all`){let e=t.isActive();if(n===`active`&&!e||n===`inactive`&&e)return!1}return!(typeof s==`boolean`&&t.isStale()!==s||i&&i!==t.state.fetchStatus||a&&!a(t))}function S(e,t){let{exact:n,status:r,predicate:i,mutationKey:a}=e;if(a){if(!t.options.mutationKey)return!1;if(n){if(w(t.options.mutationKey)!==w(a))return!1}else if(!T(t.options.mutationKey,a))return!1}return!(r&&t.state.status!==r||i&&!i(t))}function C(e,t){return(t?.queryKeyHashFn||w)(e)}function w(e){return JSON.stringify(e,(e,t)=>te(t)?Object.keys(t).sort().reduce((e,n)=>(e[n]=t[n],e),{}):t)}function T(e,t){return e===t?!0:typeof e==typeof t&&e&&t&&typeof e==`object`&&typeof t==`object`?Object.keys(t).every(n=>T(e[n],t[n])):!1}var E=Object.prototype.hasOwnProperty;function ee(e,t,n=0){if(e===t)return e;if(n>500)return t;let r=O(e)&&O(t);if(!r&&!(te(e)&&te(t)))return t;let i=(r?e:Object.keys(e)).length,a=r?t:Object.keys(t),o=a.length,s=r?Array(o):{},c=0;for(let l=0;l{f.setTimeout(t,e)})}function k(e,t,n){return typeof n.structuralSharing==`function`?n.structuralSharing(e,t):n.structuralSharing===!1?t:ee(e,t)}function A(e,t,n=0){let r=[...e,t];return n&&r.length>n?r.slice(1):r}function ie(e,t,n=0){let r=[t,...e];return n&&r.length>n?r.slice(0,-1):r}var j=Symbol();function ae(e,t){return!e.queryFn&&t?.initialPromise?()=>t.initialPromise:!e.queryFn||e.queryFn===j?()=>Promise.reject(Error(`Missing queryFn: '${e.queryHash}'`)):e.queryFn}function oe(e,t){return typeof e==`function`?e(...t):!!e}function se(e,t,n){let r=!1,i;return Object.defineProperty(e,`signal`,{enumerable:!0,get:()=>(i??=t(),r?i:(r=!0,i.aborted?n():i.addEventListener(`abort`,n,{once:!0}),i))}),e}var ce=(()=>{let e=()=>m;return{isServer(){return e()},setIsServer(t){e=t}}})();function M(){let e,t,n=new Promise((n,r)=>{e=n,t=r});n.status=`pending`,n.catch(()=>{});function r(e){Object.assign(n,e),delete n.resolve,delete n.reject}return n.resolve=t=>{r({status:`fulfilled`,value:t}),e(t)},n.reject=e=>{r({status:`rejected`,reason:e}),t(e)},n}var le=p;function ue(){let e=[],t=0,n=e=>{e()},r=e=>{e()},i=le,a=r=>{t?e.push(r):i(()=>{n(r)})},o=()=>{let t=e;e=[],t.length&&i(()=>{r(()=>{t.forEach(e=>{n(e)})})})};return{batch:e=>{let n;t++;try{n=e()}finally{t--,t||o()}return n},batchCalls:e=>(...t)=>{a(()=>{e(...t)})},schedule:a,setNotifyFunction:e=>{n=e},setBatchNotifyFunction:e=>{r=e},setScheduler:e=>{i=e}}}var N=ue(),de=new class extends l{#e=!0;#t;#n;constructor(){super(),this.#n=e=>{if(typeof window<`u`&&window.addEventListener){let t=()=>e(!0),n=()=>e(!1);return window.addEventListener(`online`,t,!1),window.addEventListener(`offline`,n,!1),()=>{window.removeEventListener(`online`,t),window.removeEventListener(`offline`,n)}}}}onSubscribe(){this.#t||this.setEventListener(this.#n)}onUnsubscribe(){this.hasListeners()||(this.#t?.(),this.#t=void 0)}setEventListener(e){this.#n=e,this.#t?.(),this.#t=e(this.setOnline.bind(this))}setOnline(e){this.#e!==e&&(this.#e=e,this.listeners.forEach(t=>{t(e)}))}isOnline(){return this.#e}};function fe(e){return Math.min(1e3*2**e,3e4)}function pe(e){return(e??`online`)===`online`?de.isOnline():!0}var me=class extends Error{constructor(e){super(`CancelledError`),this.revert=e?.revert,this.silent=e?.silent}};function he(e){let t=!1,n=0,r,i=M(),a=()=>i.status!==`pending`,o=t=>{if(!a()){let n=new me(t);p(n),e.onCancel?.(n)}},s=()=>{t=!0},c=()=>{t=!1},l=()=>u.isFocused()&&(e.networkMode===`always`||de.isOnline())&&e.canRun(),d=()=>pe(e.networkMode)&&e.canRun(),f=e=>{a()||(r?.(),i.resolve(e))},p=e=>{a()||(r?.(),i.reject(e))},m=()=>new Promise(t=>{r=e=>{(a()||l())&&t(e)},e.onPause?.()}).then(()=>{r=void 0,a()||e.onContinue?.()}),h=()=>{if(a())return;let r,i=n===0?e.initialPromise:void 0;try{r=i??e.fn()}catch(e){r=Promise.reject(e)}Promise.resolve(r).then(f).catch(r=>{if(a())return;let i=e.retry??(ce.isServer()?0:3),o=e.retryDelay??fe,s=typeof o==`function`?o(n,r):o,c=i===!0||typeof i==`number`&&nl()?void 0:m()).then(()=>{t?p(r):h()})})};return{promise:i,status:()=>i.status,cancel:o,continue:()=>(r?.(),i),cancelRetry:s,continueRetry:c,canStart:d,start:()=>(d()?h():m().then(h),i)}}var ge=class{#e;destroy(){this.clearGcTimeout()}scheduleGc(){this.clearGcTimeout(),_(this.gcTime)&&(this.#e=f.setTimeout(()=>{this.optionalRemove()},this.gcTime))}updateGcTime(e){this.gcTime=Math.max(this.gcTime||0,e??(ce.isServer()?1/0:300*1e3))}clearGcTimeout(){this.#e!==void 0&&(f.clearTimeout(this.#e),this.#e=void 0)}};function _e(e){return{onFetch:(t,n)=>{let r=t.options,i=t.fetchOptions?.meta?.fetchMore?.direction,a=t.state.data?.pages||[],o=t.state.data?.pageParams||[],s={pages:[],pageParams:[]},c=0,l=async()=>{let n=!1,l=e=>{se(e,()=>t.signal,()=>n=!0)},u=ae(t.options,t.fetchOptions),d=async(e,r,i)=>{if(n)return Promise.reject(t.signal.reason);if(r==null&&e.pages.length)return Promise.resolve(e);let a=await u((()=>{let e={client:t.client,queryKey:t.queryKey,pageParam:r,direction:i?`backward`:`forward`,meta:t.options.meta};return l(e),e})()),{maxPages:o}=t.options,s=i?ie:A;return{pages:s(e.pages,a,o),pageParams:s(e.pageParams,r,o)}};if(i&&a.length){let e=i===`backward`,t=e?ye:ve,n={pages:a,pageParams:o};s=await d(n,t(r,n),e)}else{let t=e??a.length;do{let e=c===0?o[0]??r.initialPageParam:ve(r,s);if(c>0&&e==null)break;s=await d(s,e),c++}while(ct.options.persister?.(l,{client:t.client,queryKey:t.queryKey,meta:t.options.meta,signal:t.signal},n):t.fetchFn=l}}}function ve(e,{pages:t,pageParams:n}){let r=t.length-1;return t.length>0?e.getNextPageParam(t[r],t,n[r],n):void 0}function ye(e,{pages:t,pageParams:n}){return t.length>0?e.getPreviousPageParam?.(t[0],t,n[0],n):void 0}var be=class extends ge{#e;#t;#n;#r;#i;#a;#o;#s;constructor(e){super(),this.#s=!1,this.#o=e.defaultOptions,this.setOptions(e.options),this.observers=[],this.#i=e.client,this.#r=this.#i.getQueryCache(),this.queryKey=e.queryKey,this.queryHash=e.queryHash,this.#t=Ce(this.options),this.state=e.state??this.#t,this.scheduleGc()}get meta(){return this.options.meta}get queryType(){return this.#e}get promise(){return this.#a?.promise}setOptions(e){if(this.options={...this.#o,...e},e?._type&&(this.#e=e._type),this.updateGcTime(this.options.gcTime),this.state&&this.state.data===void 0){let e=Ce(this.options);e.data!==void 0&&(this.setState(Se(e.data,e.dataUpdatedAt)),this.#t=e)}}optionalRemove(){!this.observers.length&&this.state.fetchStatus===`idle`&&this.#r.remove(this)}setData(e,t){let n=k(this.state.data,e,this.options);return this.#l({data:n,type:`success`,dataUpdatedAt:t?.updatedAt,manual:t?.manual}),n}setState(e){this.#l({type:`setState`,state:e})}cancel(e){let t=this.#a?.promise;return this.#a?.cancel(e),t?t.then(h).catch(h):Promise.resolve()}destroy(){super.destroy(),this.cancel({silent:!0})}get resetState(){return this.#t}reset(){this.destroy(),this.setState(this.resetState)}isActive(){return this.observers.some(e=>b(e.options.enabled,this)!==!1)}isDisabled(){return this.getObserversCount()>0?!this.isActive():this.options.queryFn===j||!this.isFetched()}isFetched(){return this.state.dataUpdateCount+this.state.errorUpdateCount>0}isStatic(){return this.getObserversCount()>0?this.observers.some(e=>y(e.options.staleTime,this)===`static`):!1}isStale(){return this.getObserversCount()>0?this.observers.some(e=>e.getCurrentResult().isStale):this.state.data===void 0||this.state.isInvalidated}isStaleByTime(e=0){return this.state.data===void 0?!0:e===`static`?!1:this.state.isInvalidated?!0:!v(this.state.dataUpdatedAt,e)}onFocus(){this.observers.find(e=>e.shouldFetchOnWindowFocus())?.refetch({cancelRefetch:!1}),this.#a?.continue()}onOnline(){this.observers.find(e=>e.shouldFetchOnReconnect())?.refetch({cancelRefetch:!1}),this.#a?.continue()}addObserver(e){this.observers.includes(e)||(this.observers.push(e),this.clearGcTimeout(),this.#r.notify({type:`observerAdded`,query:this,observer:e}))}removeObserver(e){this.observers.includes(e)&&(this.observers=this.observers.filter(t=>t!==e),this.observers.length||(this.#a&&(this.#s||this.#c()?this.#a.cancel({revert:!0}):this.#a.cancelRetry()),this.scheduleGc()),this.#r.notify({type:`observerRemoved`,query:this,observer:e}))}getObserversCount(){return this.observers.length}#c(){return this.state.fetchStatus===`paused`&&this.state.status===`pending`}invalidate(){this.state.isInvalidated||this.#l({type:`invalidate`})}async fetch(e,t){if(this.state.fetchStatus!==`idle`&&this.#a?.status()!==`rejected`){if(this.state.data!==void 0&&t?.cancelRefetch)this.cancel({silent:!0});else if(this.#a)return this.#a.continueRetry(),this.#a.promise}if(e&&this.setOptions(e),!this.options.queryFn){let e=this.observers.find(e=>e.options.queryFn);e&&this.setOptions(e.options)}let n=new AbortController,r=e=>{Object.defineProperty(e,`signal`,{enumerable:!0,get:()=>(this.#s=!0,n.signal)})},i=()=>{let e=ae(this.options,t),n=(()=>{let e={client:this.#i,queryKey:this.queryKey,meta:this.meta};return r(e),e})();return this.#s=!1,this.options.persister?this.options.persister(e,n,this):e(n)},a=(()=>{let e={fetchOptions:t,options:this.options,queryKey:this.queryKey,client:this.#i,state:this.state,fetchFn:i};return r(e),e})();(this.#e===`infinite`?_e(this.options.pages):this.options.behavior)?.onFetch(a,this),this.#n=this.state,(this.state.fetchStatus===`idle`||this.state.fetchMeta!==a.fetchOptions?.meta)&&this.#l({type:`fetch`,meta:a.fetchOptions?.meta}),this.#a=he({initialPromise:t?.initialPromise,fn:a.fetchFn,onCancel:e=>{e instanceof me&&e.revert&&this.setState({...this.#n,fetchStatus:`idle`}),n.abort()},onFail:(e,t)=>{this.#l({type:`failed`,failureCount:e,error:t})},onPause:()=>{this.#l({type:`pause`})},onContinue:()=>{this.#l({type:`continue`})},retry:a.options.retry,retryDelay:a.options.retryDelay,networkMode:a.options.networkMode,canRun:()=>!0});try{let e=await this.#a.start();if(e===void 0)throw Error(`${this.queryHash} data is undefined`);return this.setData(e),this.#r.config.onSuccess?.(e,this),this.#r.config.onSettled?.(e,this.state.error,this),e}catch(e){if(e instanceof me){if(e.silent)return this.#a.promise;if(e.revert){if(this.state.data===void 0)throw e;return this.state.data}}throw this.#l({type:`error`,error:e}),this.#r.config.onError?.(e,this),this.#r.config.onSettled?.(this.state.data,e,this),e}finally{this.scheduleGc()}}#l(e){let t=t=>{switch(e.type){case`failed`:return{...t,fetchFailureCount:e.failureCount,fetchFailureReason:e.error};case`pause`:return{...t,fetchStatus:`paused`};case`continue`:return{...t,fetchStatus:`fetching`};case`fetch`:return{...t,...xe(t.data,this.options),fetchMeta:e.meta??null};case`success`:let n={...t,...Se(e.data,e.dataUpdatedAt),dataUpdateCount:t.dataUpdateCount+1,...!e.manual&&{fetchStatus:`idle`,fetchFailureCount:0,fetchFailureReason:null}};return this.#n=e.manual?n:void 0,n;case`error`:let r=e.error;return{...t,error:r,errorUpdateCount:t.errorUpdateCount+1,errorUpdatedAt:Date.now(),fetchFailureCount:t.fetchFailureCount+1,fetchFailureReason:r,fetchStatus:`idle`,status:`error`,isInvalidated:!0};case`invalidate`:return{...t,isInvalidated:!0};case`setState`:return{...t,...e.state}}};this.state=t(this.state),N.batch(()=>{this.observers.forEach(e=>{e.onQueryUpdate()}),this.#r.notify({query:this,type:`updated`,action:e})})}};function xe(e,t){return{fetchFailureCount:0,fetchFailureReason:null,fetchStatus:pe(t.networkMode)?`fetching`:`paused`,...e===void 0&&{error:null,status:`pending`}}}function Se(e,t){return{data:e,dataUpdatedAt:t??Date.now(),error:null,isInvalidated:!1,status:`success`}}function Ce(e){let t=typeof e.initialData==`function`?e.initialData():e.initialData,n=t!==void 0,r=n?typeof e.initialDataUpdatedAt==`function`?e.initialDataUpdatedAt():e.initialDataUpdatedAt:0;return{data:t,dataUpdateCount:0,dataUpdatedAt:n?r??Date.now():0,error:null,errorUpdateCount:0,errorUpdatedAt:0,fetchFailureCount:0,fetchFailureReason:null,fetchMeta:null,isInvalidated:!1,status:n?`success`:`pending`,fetchStatus:`idle`}}var we=class extends ge{#e;#t;#n;#r;constructor(e){super(),this.#e=e.client,this.mutationId=e.mutationId,this.#n=e.mutationCache,this.#t=[],this.state=e.state||Te(),this.setOptions(e.options),this.scheduleGc()}setOptions(e){this.options=e,this.updateGcTime(this.options.gcTime)}get meta(){return this.options.meta}addObserver(e){this.#t.includes(e)||(this.#t.push(e),this.clearGcTimeout(),this.#n.notify({type:`observerAdded`,mutation:this,observer:e}))}removeObserver(e){this.#t=this.#t.filter(t=>t!==e),this.scheduleGc(),this.#n.notify({type:`observerRemoved`,mutation:this,observer:e})}optionalRemove(){this.#t.length||(this.state.status===`pending`?this.scheduleGc():this.#n.remove(this))}continue(){return this.#r?.continue()??this.execute(this.state.variables)}async execute(e){let t=()=>{this.#i({type:`continue`})},n={client:this.#e,meta:this.options.meta,mutationKey:this.options.mutationKey};this.#r=he({fn:()=>this.options.mutationFn?this.options.mutationFn(e,n):Promise.reject(Error(`No mutationFn found`)),onFail:(e,t)=>{this.#i({type:`failed`,failureCount:e,error:t})},onPause:()=>{this.#i({type:`pause`})},onContinue:t,retry:this.options.retry??0,retryDelay:this.options.retryDelay,networkMode:this.options.networkMode,canRun:()=>this.#n.canRun(this)});let r=this.state.status===`pending`,i=!this.#r.canStart();try{if(r)t();else{this.#i({type:`pending`,variables:e,isPaused:i}),this.#n.config.onMutate&&await this.#n.config.onMutate(e,this,n);let t=await this.options.onMutate?.(e,n);t!==this.state.context&&this.#i({type:`pending`,context:t,variables:e,isPaused:i})}let a=await this.#r.start();return await this.#n.config.onSuccess?.(a,e,this.state.context,this,n),await this.options.onSuccess?.(a,e,this.state.context,n),await this.#n.config.onSettled?.(a,null,this.state.variables,this.state.context,this,n),await this.options.onSettled?.(a,null,e,this.state.context,n),this.#i({type:`success`,data:a}),a}catch(t){try{await this.#n.config.onError?.(t,e,this.state.context,this,n)}catch(e){Promise.reject(e)}try{await this.options.onError?.(t,e,this.state.context,n)}catch(e){Promise.reject(e)}try{await this.#n.config.onSettled?.(void 0,t,this.state.variables,this.state.context,this,n)}catch(e){Promise.reject(e)}try{await this.options.onSettled?.(void 0,t,e,this.state.context,n)}catch(e){Promise.reject(e)}throw this.#i({type:`error`,error:t}),t}finally{this.#n.runNext(this)}}#i(e){let t=t=>{switch(e.type){case`failed`:return{...t,failureCount:e.failureCount,failureReason:e.error};case`pause`:return{...t,isPaused:!0};case`continue`:return{...t,isPaused:!1};case`pending`:return{...t,context:e.context,data:void 0,failureCount:0,failureReason:null,error:null,isPaused:e.isPaused,status:`pending`,variables:e.variables,submittedAt:Date.now()};case`success`:return{...t,data:e.data,failureCount:0,failureReason:null,error:null,status:`success`,isPaused:!1};case`error`:return{...t,data:void 0,error:e.error,failureCount:t.failureCount+1,failureReason:e.error,isPaused:!1,status:`error`}}};this.state=t(this.state),N.batch(()=>{this.#t.forEach(t=>{t.onMutationUpdate(e)}),this.#n.notify({mutation:this,type:`updated`,action:e})})}};function Te(){return{context:void 0,data:void 0,error:null,failureCount:0,failureReason:null,isPaused:!1,status:`idle`,variables:void 0,submittedAt:0}}var Ee=class extends l{constructor(e={}){super(),this.config=e,this.#e=new Set,this.#t=new Map,this.#n=0}#e;#t;#n;build(e,t,n){let r=new we({client:e,mutationCache:this,mutationId:++this.#n,options:e.defaultMutationOptions(t),state:n});return this.add(r),r}add(e){this.#e.add(e);let t=De(e);if(typeof t==`string`){let n=this.#t.get(t);n?n.push(e):this.#t.set(t,[e])}this.notify({type:`added`,mutation:e})}remove(e){if(this.#e.delete(e)){let t=De(e);if(typeof t==`string`){let n=this.#t.get(t);if(n)if(n.length>1){let t=n.indexOf(e);t!==-1&&n.splice(t,1)}else n[0]===e&&this.#t.delete(t)}}this.notify({type:`removed`,mutation:e})}canRun(e){let t=De(e);if(typeof t==`string`){let n=this.#t.get(t)?.find(e=>e.state.status===`pending`);return!n||n===e}else return!0}runNext(e){let t=De(e);return typeof t==`string`?(this.#t.get(t)?.find(t=>t!==e&&t.state.isPaused))?.continue()??Promise.resolve():Promise.resolve()}clear(){N.batch(()=>{this.#e.forEach(e=>{this.notify({type:`removed`,mutation:e})}),this.#e.clear(),this.#t.clear()})}getAll(){return Array.from(this.#e)}find(e){let t={exact:!0,...e};return this.getAll().find(e=>S(t,e))}findAll(e={}){return this.getAll().filter(t=>S(e,t))}notify(e){N.batch(()=>{this.listeners.forEach(t=>{t(e)})})}resumePausedMutations(){let e=this.getAll().filter(e=>e.state.isPaused);return N.batch(()=>Promise.all(e.map(e=>e.continue().catch(h))))}};function De(e){return e.options.scope?.id}var Oe=class extends l{constructor(e={}){super(),this.config=e,this.#e=new Map}#e;build(e,t,n){let r=t.queryKey,i=t.queryHash??C(r,t),a=this.get(i);return a||(a=new be({client:e,queryKey:r,queryHash:i,options:e.defaultQueryOptions(t),state:n,defaultOptions:e.getQueryDefaults(r)}),this.add(a)),a}add(e){this.#e.has(e.queryHash)||(this.#e.set(e.queryHash,e),this.notify({type:`added`,query:e}))}remove(e){let t=this.#e.get(e.queryHash);t&&(e.destroy(),t===e&&this.#e.delete(e.queryHash),this.notify({type:`removed`,query:e}))}clear(){N.batch(()=>{this.getAll().forEach(e=>{this.remove(e)})})}get(e){return this.#e.get(e)}getAll(){return[...this.#e.values()]}find(e){let t={exact:!0,...e};return this.getAll().find(e=>x(t,e))}findAll(e={}){let t=this.getAll();return Object.keys(e).length>0?t.filter(t=>x(e,t)):t}notify(e){N.batch(()=>{this.listeners.forEach(t=>{t(e)})})}onFocus(){N.batch(()=>{this.getAll().forEach(e=>{e.onFocus()})})}onOnline(){N.batch(()=>{this.getAll().forEach(e=>{e.onOnline()})})}},ke=class{#e;#t;#n;#r;#i;#a;#o;#s;constructor(e={}){this.#e=e.queryCache||new Oe,this.#t=e.mutationCache||new Ee,this.#n=e.defaultOptions||{},this.#r=new Map,this.#i=new Map,this.#a=0}mount(){this.#a++,this.#a===1&&(this.#o=u.subscribe(async e=>{e&&(await this.resumePausedMutations(),this.#e.onFocus())}),this.#s=de.subscribe(async e=>{e&&(await this.resumePausedMutations(),this.#e.onOnline())}))}unmount(){this.#a--,this.#a===0&&(this.#o?.(),this.#o=void 0,this.#s?.(),this.#s=void 0)}isFetching(e){return this.#e.findAll({...e,fetchStatus:`fetching`}).length}isMutating(e){return this.#t.findAll({...e,status:`pending`}).length}getQueryData(e){let t=this.defaultQueryOptions({queryKey:e});return this.#e.get(t.queryHash)?.state.data}ensureQueryData(e){let t=this.defaultQueryOptions(e),n=this.#e.build(this,t),r=n.state.data;return r===void 0?this.fetchQuery(e):(e.revalidateIfStale&&n.isStaleByTime(y(t.staleTime,n))&&this.prefetchQuery(t),Promise.resolve(r))}getQueriesData(e){return this.#e.findAll(e).map(({queryKey:e,state:t})=>[e,t.data])}setQueryData(e,t,n){let r=this.defaultQueryOptions({queryKey:e}),i=this.#e.get(r.queryHash)?.state.data,a=g(t,i);if(a!==void 0)return this.#e.build(this,r).setData(a,{...n,manual:!0})}setQueriesData(e,t,n){return N.batch(()=>this.#e.findAll(e).map(({queryKey:e})=>[e,this.setQueryData(e,t,n)]))}getQueryState(e){let t=this.defaultQueryOptions({queryKey:e});return this.#e.get(t.queryHash)?.state}removeQueries(e){let t=this.#e;N.batch(()=>{t.findAll(e).forEach(e=>{t.remove(e)})})}resetQueries(e,t){let n=this.#e;return N.batch(()=>(n.findAll(e).forEach(e=>{e.reset()}),this.refetchQueries({type:`active`,...e},t)))}cancelQueries(e,t={}){let n={revert:!0,...t},r=N.batch(()=>this.#e.findAll(e).map(e=>e.cancel(n)));return Promise.all(r).then(h).catch(h)}invalidateQueries(e,t={}){return N.batch(()=>(this.#e.findAll(e).forEach(e=>{e.invalidate()}),e?.refetchType===`none`?Promise.resolve():this.refetchQueries({...e,type:e?.refetchType??e?.type??`active`},t)))}refetchQueries(e,t={}){let n={...t,cancelRefetch:t.cancelRefetch??!0},r=N.batch(()=>this.#e.findAll(e).filter(e=>!e.isDisabled()&&!e.isStatic()).map(e=>{let t=e.fetch(void 0,n);return n.throwOnError||(t=t.catch(h)),e.state.fetchStatus===`paused`?Promise.resolve():t}));return Promise.all(r).then(h)}fetchQuery(e){let t=this.defaultQueryOptions(e);t.retry===void 0&&(t.retry=!1);let n=this.#e.build(this,t);return n.isStaleByTime(y(t.staleTime,n))?n.fetch(t):Promise.resolve(n.state.data)}prefetchQuery(e){return this.fetchQuery(e).then(h).catch(h)}fetchInfiniteQuery(e){return e._type=`infinite`,this.fetchQuery(e)}prefetchInfiniteQuery(e){return this.fetchInfiniteQuery(e).then(h).catch(h)}ensureInfiniteQueryData(e){return e._type=`infinite`,this.ensureQueryData(e)}resumePausedMutations(){return de.isOnline()?this.#t.resumePausedMutations():Promise.resolve()}getQueryCache(){return this.#e}getMutationCache(){return this.#t}getDefaultOptions(){return this.#n}setDefaultOptions(e){this.#n=e}setQueryDefaults(e,t){this.#r.set(w(e),{queryKey:e,defaultOptions:t})}getQueryDefaults(e){let t=[...this.#r.values()],n={};return t.forEach(t=>{T(e,t.queryKey)&&Object.assign(n,t.defaultOptions)}),n}setMutationDefaults(e,t){this.#i.set(w(e),{mutationKey:e,defaultOptions:t})}getMutationDefaults(e){let t=[...this.#i.values()],n={};return t.forEach(t=>{T(e,t.mutationKey)&&Object.assign(n,t.defaultOptions)}),n}defaultQueryOptions(e){if(e._defaulted)return e;let t={...this.#n.queries,...this.getQueryDefaults(e.queryKey),...e,_defaulted:!0};return t.queryHash||=C(t.queryKey,t),t.refetchOnReconnect===void 0&&(t.refetchOnReconnect=t.networkMode!==`always`),t.throwOnError===void 0&&(t.throwOnError=!!t.suspense),!t.networkMode&&t.persister&&(t.networkMode=`offlineFirst`),t.queryFn===j&&(t.enabled=!1),t}defaultMutationOptions(e){return e?._defaulted?e:{...this.#n.mutations,...e?.mutationKey&&this.getMutationDefaults(e.mutationKey),...e,_defaulted:!0}}clear(){this.#e.clear(),this.#t.clear()}},Ae=o((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.consumer`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.for(`react.activity`),p=Symbol.iterator;function m(e){return typeof e!=`object`||!e?null:(e=p&&e[p]||e[`@@iterator`],typeof e==`function`?e:null)}var h={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g=Object.assign,_={};function v(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}v.prototype.isReactComponent={},v.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},v.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function y(){}y.prototype=v.prototype;function b(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}var x=b.prototype=new y;x.constructor=b,g(x,v.prototype),x.isPureReactComponent=!0;var S=Array.isArray;function C(){}var w={H:null,A:null,T:null,S:null},T=Object.prototype.hasOwnProperty;function E(e,n,r){var i=r.ref;return{$$typeof:t,type:e,key:n,ref:i===void 0?null:i,props:r}}function ee(e,t){return E(e.type,t,e.props)}function D(e){return typeof e==`object`&&!!e&&e.$$typeof===t}function O(e){var t={"=":`=0`,":":`=2`};return`$`+e.replace(/[=:]/g,function(e){return t[e]})}var te=/\/+/g;function ne(e,t){return typeof e==`object`&&e&&e.key!=null?O(``+e.key):t.toString(36)}function re(e){switch(e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason;default:switch(typeof e.status==`string`?e.then(C,C):(e.status=`pending`,e.then(function(t){e.status===`pending`&&(e.status=`fulfilled`,e.value=t)},function(t){e.status===`pending`&&(e.status=`rejected`,e.reason=t)})),e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason}}throw e}function k(e,r,i,a,o){var s=typeof e;(s===`undefined`||s===`boolean`)&&(e=null);var c=!1;if(e===null)c=!0;else switch(s){case`bigint`:case`string`:case`number`:c=!0;break;case`object`:switch(e.$$typeof){case t:case n:c=!0;break;case d:return c=e._init,k(c(e._payload),r,i,a,o)}}if(c)return o=o(e),c=a===``?`.`+ne(e,0):a,S(o)?(i=``,c!=null&&(i=c.replace(te,`$&/`)+`/`),k(o,r,i,``,function(e){return e})):o!=null&&(D(o)&&(o=ee(o,i+(o.key==null||e&&e.key===o.key?``:(``+o.key).replace(te,`$&/`)+`/`)+c)),r.push(o)),1;c=0;var l=a===``?`.`:a+`:`;if(S(e))for(var u=0;u{t.exports=Ae()})),Me=o((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.fragment`);function r(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.Fragment=n,e.jsx=r,e.jsxs=r})),Ne=o(((e,t)=>{t.exports=Me()})),P=c(je(),1),F=Ne(),Pe=P.createContext(void 0),Fe=e=>{let t=P.useContext(Pe);if(e)return e;if(!t)throw Error(`No QueryClient set, use QueryClientProvider to set one`);return t},Ie=({client:e,children:t})=>(P.useEffect(()=>(e.mount(),()=>{e.unmount()}),[e]),(0,F.jsx)(Pe.Provider,{value:e,children:t}));function Le(e){return e}var Re=P.use,ze=typeof window<`u`?P.useLayoutEffect:P.useEffect;function Be(e){let t=P.useRef({value:e,prev:null}),n=t.current.value;return e!==n&&(t.current={value:e,prev:n}),t.current.prev}function Ve(e,t,n={},r={}){P.useEffect(()=>{if(!e.current||r.disabled||typeof IntersectionObserver!=`function`)return;let i=new IntersectionObserver(([e])=>{t(e)},n);return i.observe(e.current),()=>{i.disconnect()}},[t,n,r.disabled,e])}function He(e){let t=P.useRef(null);return P.useImperativeHandle(e,()=>t.current,[]),t}function Ue(e){return e[e.length-1]}function We(e){return typeof e==`function`}function Ge(e,t){return We(e)?e(t):e}var Ke=Object.prototype.hasOwnProperty,qe=Object.prototype.propertyIsEnumerable;function Je(e){for(let t in e)if(Ke.call(e,t))return!0;return!1}var Ye=()=>Object.create(null),Xe=(e,t)=>Ze(e,t,Ye);function Ze(e,t,n=()=>({}),r=0){if(e===t)return e;if(r>500)return t;let i=t,a=tt(e)&&tt(i);if(!a&&!($e(e)&&$e(i)))return i;let o=a?e:Qe(e);if(!o)return i;let s=a?i:Qe(i);if(!s)return i;let c=o.length,l=s.length,u=a?Array(l):n(),d=0;for(let t=0;ti||!nt(e[o],t[o],n)))return!1;return i===a}return!1}function rt(e){let t,n,r=new Promise((e,r)=>{t=e,n=r});return r.status=`pending`,r.resolve=n=>{r.status=`resolved`,r.value=n,t(n),e?.(n)},r.reject=e=>{r.status=`rejected`,n(e)},r}function it(e){return typeof e?.message==`string`?e.message.startsWith(`Failed to fetch dynamically imported module`)||e.message.startsWith(`error loading dynamically imported module`)||e.message.startsWith(`Importing a module script failed`):!1}function at(e){return!!(e&&typeof e==`object`&&typeof e.then==`function`)}function ot(e){return e.replace(/[\x00-\x1f\x7f]/g,``)}function st(e){let t;try{t=decodeURI(e)}catch{t=e.replaceAll(/%[0-9A-F]{2}/gi,e=>{try{return decodeURI(e)}catch{return e}})}return ot(t)}var ct=[`http:`,`https:`,`mailto:`,`tel:`];function lt(e,t){if(!e)return!1;try{let n=new URL(e);return!t.has(n.protocol)}catch{return!1}}var ut={"&":`\\u0026`,">":`\\u003e`,"<":`\\u003c`,"\u2028":`\\u2028`,"\u2029":`\\u2029`},dt=/[&><\u2028\u2029]/g;function ft(e){return e.replace(dt,e=>ut[e])}function pt(e){if(!e||!/[%\\\x00-\x1f\x7f]/.test(e)&&!e.startsWith(`//`))return{path:e,handledProtocolRelativeURL:!1};let t=/%25|%5C/gi,n=0,r=``,i;for(;(i=t.exec(e))!==null;)r+=st(e.slice(n,i.index))+i[0],n=t.lastIndex;r+=st(n?e.slice(n):e);let a=!1;return r.startsWith(`//`)&&(a=!0,r=`/`+r.replace(/^\/+/,``)),{path:r,handledProtocolRelativeURL:a}}function mt(e){return/\s|[^\u0000-\u007F]/.test(e)?e.replace(/\s|[^\u0000-\u007F]/gu,encodeURIComponent):e}function ht(e,t){if(e===t)return!0;if(e.length!==t.length)return!1;for(let n=0;n{e.next&&(e.prev?(e.prev.next=e.next,e.next.prev=e.prev,e.next=void 0,r&&(r.next=e,e.prev=r)):(e.next.prev=void 0,n=e.next,e.next=void 0,r&&(e.prev=r,r.next=e)),r=e)};return{get(e){let n=t.get(e);if(n)return i(n),n.value},set(a,o){if(t.size>=e&&n){let e=n;t.delete(e.key),e.next&&(n=e.next,e.next.prev=void 0),e===r&&(r=void 0)}let s=t.get(a);if(s)s.value=o,i(s);else{let e={key:a,value:o,prev:r};r&&(r.next=e),r=e,n||=e,t.set(a,e)}},clear(){t.clear(),n=void 0,r=void 0}}}var vt=4,yt=5;function bt(e){let t=e.indexOf(`{`);if(t===-1)return null;let n=e.indexOf(`}`,t);return n===-1||t+1>=e.length?null:[t,n]}function xt(e,t,n=new Uint16Array(6)){let r=e.indexOf(`/`,t),i=r===-1?e.length:r,a=e.substring(t,i);if(!a||!a.includes(`$`))return n[0]=0,n[1]=t,n[2]=t,n[3]=i,n[4]=i,n[5]=i,n;if(a===`$`){let r=e.length;return n[0]=2,n[1]=t,n[2]=t,n[3]=r,n[4]=r,n[5]=r,n}if(a.charCodeAt(0)===36)return n[0]=1,n[1]=t,n[2]=t+1,n[3]=i,n[4]=i,n[5]=i,n;let o=bt(a);if(o){let[r,s]=o,c=a.charCodeAt(r+1);if(c===45){if(r+2!e.parse&&e.caseSensitive===f&&e.prefix===p&&e.suffix===m);if(h)o=h;else{let e=Et(1,n.fullPath??n.from,f,p,m);o=e,e.depth=a,e.parent=i,i.dynamic??=[],i.dynamic.push(e)}break}case 3:{let t=r.substring(u,e[1]),s=r.substring(e[4],d),f=c&&!!(t||s),p=t?f?t:t.toLowerCase():void 0,m=s?f?s:s.toLowerCase():void 0,h=!l&&i.optional?.find(e=>!e.parse&&e.caseSensitive===f&&e.prefix===p&&e.suffix===m);if(h)o=h;else{let e=Et(3,n.fullPath??n.from,f,p,m);o=e,e.parent=i,e.depth=a,i.optional??=[],i.optional.push(e)}break}case 2:{let t=r.substring(u,e[1]),s=r.substring(e[4],d),l=c&&!!(t||s),f=t?l?t:t.toLowerCase():void 0,p=s?l?s:s.toLowerCase():void 0,m=Et(2,n.fullPath??n.from,l,f,p);o=m,m.parent=i,m.depth=a,i.wildcard??=[],i.wildcard.push(m)}}i=o}if(l&&n.children&&!n.isRoot&&n.id&&n.id.charCodeAt(n.id.lastIndexOf(`/`)+1)===95){let e=Tt(n.fullPath??n.from);e.kind=yt,e.parent=i,a++,e.depth=a,i.pathless??=[],i.pathless.push(e),i=e}let u=(n.path||!n.children)&&!n.isRoot;if(u&&r.endsWith(`/`)){let e=Tt(n.fullPath??n.from);e.kind=vt,e.parent=i,a++,e.depth=a,i.index=e,i=e}i.parse=l??null,u&&!i.route&&(i.route=n,i.fullPath=n.fullPath??n.from)}if(n.children)for(let r of n.children)St(e,t,r,s,i,a,o)}function Ct(e,t){if(e.parse&&!t.parse)return-1;if(!e.parse&&t.parse)return 1;if(e.prefix&&t.prefix&&e.prefix!==t.prefix){if(e.prefix.startsWith(t.prefix))return-1;if(t.prefix.startsWith(e.prefix))return 1}if(e.suffix&&t.suffix&&e.suffix!==t.suffix){if(e.suffix.endsWith(t.suffix))return-1;if(t.suffix.endsWith(e.suffix))return 1}return e.prefix&&!t.prefix?-1:!e.prefix&&t.prefix?1:e.suffix&&!t.suffix?-1:!e.suffix&&t.suffix?1:e.caseSensitive&&!t.caseSensitive?-1:!e.caseSensitive&&t.caseSensitive?1:0}function wt(e){if(e.pathless)for(let t of e.pathless)wt(t);if(e.static)for(let t of e.static.values())wt(t);if(e.staticInsensitive)for(let t of e.staticInsensitive.values())wt(t);if(e.dynamic?.length){e.dynamic.sort(Ct);for(let t of e.dynamic)wt(t)}if(e.optional?.length){e.optional.sort(Ct);for(let t of e.optional)wt(t)}if(e.wildcard?.length){e.wildcard.sort(Ct);for(let t of e.wildcard)wt(t)}}function Tt(e){return{kind:0,depth:0,pathless:null,index:null,static:null,staticInsensitive:null,dynamic:null,optional:null,wildcard:null,route:null,fullPath:e,parent:null,parse:null}}function Et(e,t,n,r,i){return{kind:e,depth:0,pathless:null,index:null,static:null,staticInsensitive:null,dynamic:null,optional:null,wildcard:null,route:null,fullPath:t,parent:null,parse:null,caseSensitive:n,prefix:r,suffix:i}}function Dt(e,t){let n=Tt(`/`),r=new Uint16Array(6);for(let t of e)St(!1,r,t,1,n,0);wt(n),t.masksTree=n,t.flatCache=_t(1e3)}function Ot(e,t){e||=`/`;let n=t.flatCache.get(e);if(n)return n;let r=Nt(e,t.masksTree);return t.flatCache.set(e,r),r}function kt(e,t,n,r,i){e||=`/`,r||=`/`;let a=t?`case\0${e}`:e,o=i.singleCache.get(a);return o||(o=Tt(`/`),St(t,new Uint16Array(6),{from:e},1,o,0),i.singleCache.set(a,o)),Nt(r,o,n)}function At(e,t,n=!1){let r=n?e:`nofuzz\0${e}`,i=t.matchCache.get(r);if(i!==void 0)return i;e||=`/`;let a;try{a=Nt(e,t.segmentTree,n)}catch(e){if(e instanceof URIError)a=null;else throw e}return a&&(a.branch=Ft(a.route)),t.matchCache.set(r,a),a}function jt(e){return e===`/`?e:e.replace(/\/{1,}$/,``)}function Mt(e,t=!1,n){let r=Tt(e.fullPath),i=new Uint16Array(6),a={},o={},s=0;return St(t,i,e,1,r,0,e=>{if(n?.(e,s),e.id in a&>(),a[e.id]=e,s!==0&&e.path){let t=jt(e.fullPath);(!o[t]||e.fullPath.endsWith(`/`))&&(o[t]=e)}s++}),wt(r),{processedTree:{segmentTree:r,singleCache:_t(1e3),matchCache:_t(1e3),flatCache:null,masksTree:null},routesById:a,routesByPath:o}}function Nt(e,t,n=!1){let r=e.split(`/`),i=Lt(e,r,t,n);if(!i)return null;let[a]=Pt(e,r,i);return{route:i.node.route,rawParams:a}}function Pt(e,t,n){let r=It(n.node),i=null,a=Object.create(null),o=n.extract?.part??0,s=n.extract?.node??0,c=n.extract?.path??0,l=n.extract?.segment??0;for(;s=0;e--){let n=i.wildcard[e],{prefix:r,suffix:a}=n;if(!(r&&(v||!(n.caseSensitive?y:b??=y.toLowerCase()).startsWith(r)))){if(a){if(v)continue;let e=t.slice(u).join(`/`).slice(-a.length);if((n.caseSensitive?e:e.toLowerCase())!==a)continue}s.push({node:n,index:o,skipped:d,depth:f+1,statics:p,dynamics:m,optionals:h,extract:g,rawParams:_})}}if(i.optional){let e=d|1<=0;n--){let r=i.optional[n];s.push({node:r,index:u,skipped:e,depth:t,statics:p,dynamics:m,optionals:h,extract:g,rawParams:_})}if(!v)for(let e=i.optional.length-1;e>=0;e--){let n=i.optional[e],{prefix:r,suffix:a}=n;if(r||a){let e=n.caseSensitive?y:b??=y.toLowerCase();if(r&&!e.startsWith(r)||a&&!e.endsWith(a))continue}s.push({node:n,index:u+1,skipped:d,depth:t,statics:p,dynamics:m,optionals:h+Rt(o,u),extract:g,rawParams:_})}}if(!v&&i.dynamic&&y)for(let e=i.dynamic.length-1;e>=0;e--){let t=i.dynamic[e],{prefix:n,suffix:r}=t;if(n||r){let e=t.caseSensitive?y:b??=y.toLowerCase();if(n&&!e.startsWith(n)||r&&!e.endsWith(r))continue}s.push({node:t,index:u+1,skipped:d,depth:f+1,statics:p,dynamics:m+Rt(o,u),optionals:h,extract:g,rawParams:_})}if(!v&&i.staticInsensitive){let e=i.staticInsensitive.get(b??=y.toLowerCase());e&&s.push({node:e,index:u+1,skipped:d,depth:f+1,statics:p+Rt(o,u),dynamics:m,optionals:h,extract:g,rawParams:_})}if(!v&&i.static){let e=i.static.get(y);e&&s.push({node:e,index:u+1,skipped:d,depth:f+1,statics:p+Rt(o,u),dynamics:m,optionals:h,extract:g,rawParams:_})}if(i.pathless){let e=f+1;for(let t=i.pathless.length-1;t>=0;t--){let n=i.pathless[t];s.push({node:n,index:u,skipped:d,depth:e,statics:p,dynamics:m,optionals:h,extract:g,rawParams:_})}}}if(l)return l;if(r&&c){let n=c.index;for(let e=0;ee.statics||t.statics===e.statics&&(t.dynamics>e.dynamics||t.dynamics===e.dynamics&&(t.optionals>e.optionals||t.optionals===e.optionals&&((t.node.kind===vt)>(e.node.kind===vt)||t.node.kind===vt==(e.node.kind===vt)&&t.depth>e.depth))):!0}function Ht(e){return Ut(e.filter(e=>e!==void 0).join(`/`))}function Ut(e){return e.replace(/\/{2,}/g,`/`)}function Wt(e){return e===`/`?e:e.replace(/^\/{1,}/,``)}function Gt(e){let t=e.length;return t>1&&e[t-1]===`/`?e.replace(/\/{1,}$/,``):e}function Kt(e){return Gt(Wt(e))}function qt(e,t){return e?.endsWith(`/`)&&e!==`/`&&e!==`${t}/`?e.slice(0,-1):e}function Jt(e,t,n){return qt(e,n)===qt(t,n)}function Yt({base:e,to:t,trailingSlash:n=`never`,cache:r}){let i=t.startsWith(`/`),a=!i&&t===`.`,o;if(r){o=i?t:a?e:e+`\0`+t;let n=r.get(o);if(n)return n}let s;if(a)s=e.split(`/`);else if(i)s=t.split(`/`);else{for(s=e.split(`/`);s.length>1&&Ue(s)===``;)s.pop();let n=t.split(`/`);for(let e=0,t=n.length;e1&&(Ue(s)===``?n===`never`&&s.pop():n===`always`&&s.push(``));let c=Ut(s.join(`/`))||`/`;return o&&r&&r.set(o,c),c}function Xt(e){let t=new Map(e.map(e=>[encodeURIComponent(e),e])),n=Array.from(t.keys()).map(e=>e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)).join(`|`),r=new RegExp(n,`g`);return e=>e.replace(r,e=>t.get(e)??e)}function Zt(e,t,n){let r=t[e];return typeof r==`string`?e===`_splat`?/^[a-zA-Z0-9\-._~!/]*$/.test(r)?r:r.split(`/`).map(e=>$t(e,n)).join(`/`):$t(r,n):r}function Qt({path:e,params:t,decoder:n,...r}){let i=!1,a=Object.create(null);if(!e||e===`/`)return{interpolatedPath:`/`,usedParams:a,isMissingParams:i};if(!e.includes(`$`))return{interpolatedPath:e,usedParams:a,isMissingParams:i};let o=e.length,s=0,c,l=``;for(;s{t=Ge(e,t)||t},persist:()=>{try{e.setItem(nn,JSON.stringify(t))}catch{}}}}var an=rn(),on=e=>e.state.__TSR_key||e.href;function sn(e){let t=[],n;for(;n=e.parentNode;)t.push(`${e.tagName}:nth-child(${Array.prototype.indexOf.call(n.children,e)+1})`),e=n;return`${t.reverse().join(` > `)}`.toLowerCase()}var cn=!1,ln=`window`,un=`data-scroll-restoration-id`;function dn(e,t){if(!an)return;let n=an;if((t??e.options.scrollRestoration??!1)&&(e.isScrollRestoring=!0),e.isScrollRestorationSetup||!n)return;e.isScrollRestorationSetup=!0,cn=!1;let r=e.options.getScrollRestorationKey||on,i=new Map;window.history.scrollRestoration=`manual`;let a=t=>{if(!(cn||!e.isScrollRestoring))if(t.target===document||t.target===window)i.set(ln,{scrollX:window.scrollX||0,scrollY:window.scrollY||0});else{let e=t.target;i.set(e,{scrollX:e.scrollLeft||0,scrollY:e.scrollTop||0})}},o=t=>{if(!e.isScrollRestoring||!t||i.size===0||!n)return;let r=n.state[t]||={};for(let[e,t]of i){let n;if(e===ln)n=ln;else if(e.isConnected){let t=e.getAttribute(un);n=t?`[${un}="${t}"]`:sn(e)}n&&(r[n]=t)}};document.addEventListener(`scroll`,a,!0),e.subscribe(`onBeforeLoad`,e=>{o(e.fromLocation?r(e.fromLocation):void 0),i.clear()}),window.addEventListener(`pagehide`,()=>{o(r(e.stores.resolvedLocation.get()??e.stores.location.get())),n.persist()}),e.subscribe(`onRendered`,t=>{let a=r(t.toLocation),o=e.options.scrollRestorationBehavior,s=e.options.scrollToTopSelectors;if(i.clear(),!e.resetNextScroll){e.resetNextScroll=!0;return}if(!(typeof e.options.scrollRestoration==`function`&&!e.options.scrollRestoration({location:e.latestLocation}))){cn=!0;try{let t=e.isScrollRestoring?n.state[a]:void 0,r=!1;if(t)for(let e in t){let n=t[e];if(!$e(n))continue;let{scrollX:i,scrollY:a}=n;if(!(!Number.isFinite(i)||!Number.isFinite(a))){if(e===ln)window.scrollTo({top:a,left:i,behavior:o}),r=!0;else if(e){let t;try{t=document.querySelector(e)}catch{continue}t&&(t.scrollLeft=i,t.scrollTop=a,r=!0)}}}if(!r){let t=e.history.location.hash.slice(1);if(t){let e=window.history.state?.__hashScrollIntoViewOptions??!0;if(e){let n=document.getElementById(t);n&&n.scrollIntoView(e)}}else{let e={top:0,left:0,behavior:o};if(window.scrollTo(e),s)for(let t of s){if(t===ln)continue;let n=typeof t==`function`?t():document.querySelector(t);n&&n.scrollTo(e)}}}}finally{cn=!1}e.isScrollRestoring&&n.set(e=>(e[a]||={},e))}})}function fn(e,t=String){let n=new URLSearchParams;for(let r in e){let i=e[r];i!==void 0&&n.set(r,t(i))}return n.toString()}function pn(e){return e?e===`false`?!1:e===`true`?!0:e*0==0&&+e+``===e?+e:e:``}function mn(e){let t=new URLSearchParams(e),n=Object.create(null);for(let[e,r]of t.entries()){let t=n[e];t==null?n[e]=pn(r):Array.isArray(t)?t.push(pn(r)):n[e]=[t,pn(r)]}return n}var hn=_n(JSON.parse),gn=vn(JSON.stringify,JSON.parse);function _n(e){return t=>{t[0]===`?`&&(t=t.substring(1));let n=mn(t);for(let t in n){let r=n[t];if(typeof r==`string`)try{n[t]=e(r)}catch{}}return n}}function vn(e,t){let n=typeof t==`function`;function r(r){if(typeof r==`object`&&r)try{return e(r)}catch{}else if(n&&typeof r==`string`)try{return t(r),e(r)}catch{}return r}return e=>{let t=fn(e,r);return t?`?${t}`:``}}var yn=`__root__`;function bn(e){if(e.statusCode=e.statusCode||e.code||307,!e._builtLocation&&!e.reloadDocument&&typeof e.href==`string`)try{new URL(e.href),e.reloadDocument=!0}catch{}let t=new Headers(e.headers);e.href&&t.get(`Location`)===null&&t.set(`Location`,e.href);let n=new Response(null,{status:e.statusCode,headers:t});if(n.options=e,e.throw)throw n;return n}function xn(e){return e instanceof Response&&!!e.options}function Sn(e){return{input:({url:t})=>{for(let n of e)t=wn(n,t);return t},output:({url:t})=>{for(let n=e.length-1;n>=0;n--)t=Tn(e[n],t);return t}}}function Cn(e){let t=Kt(e.basepath),n=`/${t}`,r=`${n}/`,i=e.caseSensitive?n:n.toLowerCase(),a=e.caseSensitive?r:r.toLowerCase();return{input:({url:t})=>{let r=e.caseSensitive?t.pathname:t.pathname.toLowerCase();return r===i?t.pathname=`/`:r.startsWith(a)&&(t.pathname=t.pathname.slice(n.length)),t},output:({url:e})=>(e.pathname=Ht([`/`,t,e.pathname]),e)}}function wn(e,t){let n=e?.input?.({url:t});if(n){if(typeof n==`string`)return new URL(n);if(n instanceof URL)return n}return t}function Tn(e,t){let n=e?.output?.({url:t});if(n){if(typeof n==`string`)return new URL(n);if(n instanceof URL)return n}return t}function En(e,t){let{createMutableStore:n,createReadonlyStore:r,batch:i,init:a}=t,o=new Map,s=new Map,c=new Map,l=n(e.status),u=n(e.loadedAt),d=n(e.isLoading),f=n(e.isTransitioning),p=n(e.location),m=n(e.resolvedLocation),h=n(e.statusCode),g=n(e.redirect),_=n([]),v=n([]),y=n([]),b=r(()=>Dn(o,_.get())),x=r(()=>Dn(s,v.get())),S=r(()=>Dn(c,y.get())),C=r(()=>_.get()[0]),w=r(()=>_.get().some(e=>o.get(e)?.get().status===`pending`)),T=r(()=>({locationHref:p.get().href,resolvedLocationHref:m.get()?.href,status:l.get()})),E=r(()=>({status:l.get(),loadedAt:u.get(),isLoading:d.get(),isTransitioning:f.get(),matches:b.get(),location:p.get(),resolvedLocation:m.get(),statusCode:h.get(),redirect:g.get()})),ee=_t(64);function D(e){let t=ee.get(e);return t||(t=r(()=>{let t=_.get();for(let n of t){let t=o.get(n);if(t&&t.routeId===e)return t.get()}}),ee.set(e,t)),t}let O={status:l,loadedAt:u,isLoading:d,isTransitioning:f,location:p,resolvedLocation:m,statusCode:h,redirect:g,matchesId:_,pendingIds:v,cachedIds:y,matches:b,pendingMatches:x,cachedMatches:S,firstId:C,hasPending:w,matchRouteDeps:T,matchStores:o,pendingMatchStores:s,cachedMatchStores:c,__store:E,getRouteMatchStore:D,setMatches:te,setPending:ne,setCached:re};te(e.matches),a?.(O);function te(e){On(e,o,_,n,i)}function ne(e){On(e,s,v,n,i)}function re(e){On(e,c,y,n,i)}return O}function Dn(e,t){let n=[];for(let r of t){let t=e.get(r);t&&n.push(t.get())}return n}function On(e,t,n,r,i){let a=e.map(e=>e.id),o=new Set(a);i(()=>{for(let e of t.keys())o.has(e)||t.delete(e);for(let n of e){let e=t.get(n.id);if(!e){let e=r(n);e.routeId=n.routeId,t.set(n.id,e);continue}e.routeId=n.routeId,e.get()!==n&&e.set(n)}ht(n.get(),a)||n.set(a)})}var kn=e=>{if(!e.rendered)return e.rendered=!0,e.onReady?.()},An=e=>e.stores.matchesId.get().some(t=>e.stores.matchStores.get(t)?.get()._forcePending),jn=(e,t)=>!!(e.preload&&!e.router.stores.matchStores.has(t)),Mn=(e,t,n=!0)=>{let r={...e.router.options.context??{}},i=n?t:t-1;for(let t=0;t<=i;t++){let n=e.matches[t];if(!n)continue;let i=e.router.getMatch(n.id);i&&Object.assign(r,i.__routeContext,i.__beforeLoadContext)}return r},Nn=(e,t)=>{if(!e.matches.length)return;let n=t.routeId,r=e.matches.findIndex(t=>t.routeId===e.router.routeTree.id),i=r>=0?r:0,a=n?e.matches.findIndex(e=>e.routeId===n):e.firstBadMatchIndex??e.matches.length-1;a<0&&(a=i);for(let t=a;t>=0;t--){let n=e.matches[t];if(e.router.looseRoutesById[n.routeId].options.notFoundComponent)return t}return n?a:i},Pn=(e,t,n)=>{if(!(!xn(n)&&!en(n)))throw xn(n)&&n.redirectHandled&&!n.options.reloadDocument?n:(t&&(t._nonReactive.beforeLoadPromise?.resolve(),t._nonReactive.loaderPromise?.resolve(),t._nonReactive.beforeLoadPromise=void 0,t._nonReactive.loaderPromise=void 0,t._nonReactive.error=n,e.updateMatch(t.id,r=>({...r,status:xn(n)?`redirected`:en(n)?`notFound`:r.status===`pending`?`success`:r.status,context:Mn(e,t.index),isFetching:!1,error:n})),en(n)&&!n.routeId&&(n.routeId=t.routeId),t._nonReactive.loadPromise?.resolve()),xn(n)&&(e.rendered=!0,n.options._fromLocation=e.location,n.redirectHandled=!0,n=e.router.resolveRedirect(n)),n)},Fn=(e,t)=>{let n=e.router.getMatch(t);return!!(!n||n._nonReactive.dehydrated)},In=(e,t,n)=>{let r=Mn(e,n);e.updateMatch(t,e=>({...e,context:r}))},Ln=(e,t,n,r)=>{let{id:i,routeId:a}=e.matches[t],o=e.router.looseRoutesById[a];if(n instanceof Promise)throw n;n.routerCode=r,e.firstBadMatchIndex??=t,Pn(e,e.router.getMatch(i),n);try{o.options.onError?.(n)}catch(t){n=t,Pn(e,e.router.getMatch(i),n)}e.updateMatch(i,e=>(e._nonReactive.beforeLoadPromise?.resolve(),e._nonReactive.beforeLoadPromise=void 0,e._nonReactive.loadPromise?.resolve(),{...e,error:n,status:`error`,isFetching:!1,updatedAt:Date.now(),abortController:new AbortController})),!e.preload&&!xn(n)&&!en(n)&&(e.serialError??=n)},Rn=(e,t,n,r)=>{if(r._nonReactive.pendingTimeout!==void 0)return;let i=n.options.pendingMs??e.router.options.defaultPendingMs;if(e.onReady&&!jn(e,t)&&(n.options.loader||n.options.beforeLoad||Yn(n))&&typeof i==`number`&&i!==1/0&&(n.options.pendingComponent??e.router.options?.defaultPendingComponent)){let t=setTimeout(()=>{kn(e)},i);r._nonReactive.pendingTimeout=t}},zn=(e,t,n)=>{let r=e.router.getMatch(t);if(!r._nonReactive.beforeLoadPromise&&!r._nonReactive.loaderPromise)return;Rn(e,t,n,r);let i=()=>{let n=e.router.getMatch(t);n.preload&&(n.status===`redirected`||n.status===`notFound`)&&Pn(e,n,n.error)};return r._nonReactive.beforeLoadPromise?r._nonReactive.beforeLoadPromise.then(i):i()},Bn=(e,t,n,r)=>{let i=e.router.getMatch(t),a=i._nonReactive.loadPromise;i._nonReactive.loadPromise=rt(()=>{a?.resolve(),a=void 0});let{paramsError:o,searchError:s}=i;o&&Ln(e,n,o,`PARSE_PARAMS`),s&&Ln(e,n,s,`VALIDATE_SEARCH`),Rn(e,t,r,i);let c=new AbortController,l=!1,u=()=>{l||(l=!0,e.updateMatch(t,e=>({...e,isFetching:`beforeLoad`,fetchCount:e.fetchCount+1,abortController:c})))},d=()=>{i._nonReactive.beforeLoadPromise?.resolve(),i._nonReactive.beforeLoadPromise=void 0,e.updateMatch(t,e=>({...e,isFetching:!1}))};if(!r.options.beforeLoad){e.router.batch(()=>{u(),d()});return}i._nonReactive.beforeLoadPromise=rt();let f={...Mn(e,n,!1),...i.__routeContext},{search:p,params:m,cause:h}=i,g=jn(e,t),_={search:p,abortController:c,params:m,preload:g,context:f,location:e.location,navigate:t=>e.router.navigate({...t,_fromLocation:e.location}),buildLocation:e.router.buildLocation,cause:g?`preload`:h,matches:e.matches,routeId:r.id,...e.router.options.additionalContext},v=r=>{if(r===void 0){e.router.batch(()=>{u(),d()});return}(xn(r)||en(r))&&(u(),Ln(e,n,r,`BEFORE_LOAD`)),e.router.batch(()=>{u(),e.updateMatch(t,e=>({...e,__beforeLoadContext:r})),d()})},y;try{if(y=r.options.beforeLoad(_),at(y))return u(),y.catch(t=>{Ln(e,n,t,`BEFORE_LOAD`)}).then(v)}catch(t){u(),Ln(e,n,t,`BEFORE_LOAD`)}v(y)},Vn=(e,t)=>{let{id:n,routeId:r}=e.matches[t],i=e.router.looseRoutesById[r],a=()=>s(),o=()=>Bn(e,n,t,i),s=()=>{if(Fn(e,n))return;let t=zn(e,n,i);return at(t)?t.then(o):o()};return a()},Hn=(e,t,n)=>{let r=e.router.getMatch(t);if(!r||!n.options.head&&!n.options.scripts&&!n.options.headers)return;let i={ssr:e.router.options.ssr,matches:e.matches,match:r,params:r.params,loaderData:r.loaderData};return Promise.all([n.options.head?.(i),n.options.scripts?.(i),n.options.headers?.(i)]).then(([e,t,n])=>({meta:e?.meta,links:e?.links,headScripts:e?.scripts,headers:n,scripts:t,styles:e?.styles}))},Un=(e,t,n,r,i)=>{let a=t[r-1],{params:o,loaderDeps:s,abortController:c,cause:l}=e.router.getMatch(n),u=Mn(e,r),d=jn(e,n);return{params:o,deps:s,preload:!!d,parentMatchPromise:a,abortController:c,context:u,location:e.location,navigate:t=>e.router.navigate({...t,_fromLocation:e.location}),cause:d?`preload`:l,route:i,...e.router.options.additionalContext}},Wn=async(e,t,n,r,i)=>{try{let a=e.router.getMatch(n);try{Jn(i);let o=i.options.loader,s=typeof o==`function`?o:o?.handler,c=s?.(Un(e,t,n,r,i)),l=!!s&&at(c);if((l||i._lazyPromise||i._componentsPromise||i.options.head||i.options.scripts||i.options.headers||a._nonReactive.minPendingPromise)&&e.updateMatch(n,e=>({...e,isFetching:`loader`})),s){let t=l?await c:c;Pn(e,e.router.getMatch(n),t),t!==void 0&&e.updateMatch(n,e=>({...e,loaderData:t}))}i._lazyPromise&&await i._lazyPromise;let u=a._nonReactive.minPendingPromise;u&&await u,i._componentsPromise&&await i._componentsPromise,e.updateMatch(n,t=>({...t,error:void 0,context:Mn(e,r),status:`success`,isFetching:!1,updatedAt:Date.now()}))}catch(t){let o=t;if(o?.name===`AbortError`){if(a.abortController.signal.aborted){a._nonReactive.loaderPromise?.resolve(),a._nonReactive.loaderPromise=void 0;return}e.updateMatch(n,t=>({...t,status:t.status===`pending`?`success`:t.status,isFetching:!1,context:Mn(e,r)}));return}let s=a._nonReactive.minPendingPromise;s&&await s,en(t)&&await i.options.notFoundComponent?.preload?.(),Pn(e,e.router.getMatch(n),t);try{i.options.onError?.(t)}catch(t){o=t,Pn(e,e.router.getMatch(n),t)}!xn(o)&&!en(o)&&await Jn(i,[`errorComponent`]),e.updateMatch(n,t=>({...t,error:o,context:Mn(e,r),status:`error`,isFetching:!1}))}}catch(t){let r=e.router.getMatch(n);r&&(r._nonReactive.loaderPromise=void 0),Pn(e,r,t)}},Gn=async(e,t,n)=>{async function r(r,a,c,l,d){let f=Date.now()-a.updatedAt,p=r?d.options.preloadStaleTime??e.router.options.defaultPreloadStaleTime??3e4:d.options.staleTime??e.router.options.defaultStaleTime??0,m=d.options.shouldReload,h=typeof m==`function`?m(Un(e,t,i,n,d)):m,{status:g,invalid:_}=l,v=f>=p&&(!!e.forceStaleReload||l.cause===`enter`||c!==void 0&&c!==l.id);o=g===`success`&&(_||(h??v)),r&&d.options.preload===!1||(o&&!e.sync&&u?(s=!0,(async()=>{try{await Wn(e,t,i,n,d);let r=e.router.getMatch(i);r._nonReactive.loaderPromise?.resolve(),r._nonReactive.loadPromise?.resolve(),r._nonReactive.loaderPromise=void 0,r._nonReactive.loadPromise=void 0}catch(t){xn(t)&&await e.router.navigate(t.options)}})()):g!==`success`||o?await Wn(e,t,i,n,d):In(e,i,n))}let{id:i,routeId:a}=e.matches[n],o=!1,s=!1,c=e.router.looseRoutesById[a],l=c.options.loader,u=((typeof l==`function`?void 0:l?.staleReloadMode)??e.router.options.defaultStaleReloadMode)!==`blocking`;if(Fn(e,i)){if(!e.router.getMatch(i))return e.matches[n];In(e,i,n)}else{let t=e.router.getMatch(i),o=e.router.stores.matchesId.get()[n],s=(o&&e.router.stores.matchStores.get(o)||null)?.routeId===a?o:e.router.stores.matches.get().find(e=>e.routeId===a)?.id,l=jn(e,i);if(t._nonReactive.loaderPromise){if(t.status===`success`&&!e.sync&&!t.preload&&u)return t;await t._nonReactive.loaderPromise;let n=e.router.getMatch(i),a=n._nonReactive.error||n.error;a&&Pn(e,n,a),n.status===`pending`&&await r(l,t,s,n,c)}else{let n=l&&!e.router.stores.matchStores.has(i),a=e.router.getMatch(i);a._nonReactive.loaderPromise=rt(),n!==a.preload&&e.updateMatch(i,e=>({...e,preload:n})),await r(l,t,s,a,c)}}let d=e.router.getMatch(i);s||(d._nonReactive.loaderPromise?.resolve(),d._nonReactive.loadPromise?.resolve(),d._nonReactive.loadPromise=void 0),clearTimeout(d._nonReactive.pendingTimeout),d._nonReactive.pendingTimeout=void 0,s||(d._nonReactive.loaderPromise=void 0),d._nonReactive.dehydrated=void 0;let f=s?d.isFetching:!1;return f!==d.isFetching||d.invalid!==!1?(e.updateMatch(i,e=>({...e,isFetching:f,invalid:!1})),e.router.getMatch(i)):d};async function Kn(e){let t=e,n=[];An(t.router)&&kn(t);let r;for(let e=0;e({...e,...a?{status:`success`,globalNotFound:!0,error:void 0}:{status:`notFound`,error:l},isFetching:!1})),u=e,await Jn(r,[`notFoundComponent`])}else if(!t.preload){let e=t.matches[0];e.globalNotFound||t.router.getMatch(e.id)?.globalNotFound&&t.updateMatch(e.id,e=>({...e,globalNotFound:!1,error:void 0}))}if(t.serialError&&t.firstBadMatchIndex!==void 0){let e=t.router.looseRoutesById[t.matches[t.firstBadMatchIndex].routeId];await Jn(e,[`errorComponent`])}for(let e=0;e<=u;e++){let{id:n,routeId:r}=t.matches[e],i=t.router.looseRoutesById[r];try{let e=Hn(t,n,i);if(e){let r=await e;t.updateMatch(n,e=>({...e,...r}))}}catch(e){console.error(`Error executing head for route ${r}:`,e)}}let d=kn(t);if(at(d)&&await d,l)throw l;if(t.serialError&&!t.preload&&!t.onReady)throw t.serialError;return t.matches}function qn(e,t){let n=t.map(t=>e.options[t]?.preload?.()).filter(Boolean);if(n.length!==0)return Promise.all(n)}function Jn(e,t=Xn){!e._lazyLoaded&&e._lazyPromise===void 0&&(e.lazyFn?e._lazyPromise=e.lazyFn().then(t=>{let{id:n,...r}=t.options;Object.assign(e.options,r),e._lazyLoaded=!0,e._lazyPromise=void 0}):e._lazyLoaded=!0);let n=()=>e._componentsLoaded?void 0:t===Xn?(()=>{if(e._componentsPromise===void 0){let t=qn(e,Xn);t?e._componentsPromise=t.then(()=>{e._componentsLoaded=!0,e._componentsPromise=void 0}):e._componentsLoaded=!0}return e._componentsPromise})():qn(e,t);return e._lazyPromise?e._lazyPromise.then(n):n()}function Yn(e){for(let t of Xn)if(e.options[t]?.preload)return!0;return!1}var Xn=[`component`,`errorComponent`,`pendingComponent`,`notFoundComponent`],Zn=`__TSR_index`,Qn=`popstate`,$n=`beforeunload`;function er(e){let t=e.getLocation(),n=new Set,r=r=>{t=e.getLocation(),n.forEach(e=>e({location:t,action:r}))},i=n=>{e.notifyOnIndexChange??!0?r(n):t=e.getLocation()},a=async({task:n,navigateOpts:r,...i})=>{if(r?.ignoreBlocker??!1){n();return}let a=e.getBlockers?.()??[],o=i.type===`PUSH`||i.type===`REPLACE`;if(typeof document<`u`&&a.length&&o)for(let n of a){let r=ir(i.path,i.state);if(await n.blockerFn({currentLocation:t,nextLocation:r,action:i.type})){e.onBlocked?.();return}}n()};return{get location(){return t},get length(){return e.getLength()},subscribers:n,subscribe:e=>(n.add(e),()=>{n.delete(e)}),push:(n,i,o)=>{let s=t.state[Zn];i=tr(s+1,i),a({task:()=>{e.pushState(n,i),r({type:`PUSH`})},navigateOpts:o,type:`PUSH`,path:n,state:i})},replace:(n,i,o)=>{let s=t.state[Zn];i=tr(s,i),a({task:()=>{e.replaceState(n,i),r({type:`REPLACE`})},navigateOpts:o,type:`REPLACE`,path:n,state:i})},go:(t,n)=>{a({task:()=>{e.go(t),i({type:`GO`,index:t})},navigateOpts:n,type:`GO`})},back:t=>{a({task:()=>{e.back(t?.ignoreBlocker??!1),i({type:`BACK`})},navigateOpts:t,type:`BACK`})},forward:t=>{a({task:()=>{e.forward(t?.ignoreBlocker??!1),i({type:`FORWARD`})},navigateOpts:t,type:`FORWARD`})},canGoBack:()=>t.state[Zn]!==0,createHref:t=>e.createHref(t),block:t=>{if(!e.setBlockers)return()=>{};let n=e.getBlockers?.()??[];return e.setBlockers([...n,t]),()=>{let n=e.getBlockers?.()??[];e.setBlockers?.(n.filter(e=>e!==t))}},flush:()=>e.flush?.(),destroy:()=>e.destroy?.(),notify:r}}function tr(e,t){t||={};let n=ar();return{...t,key:n,__TSR_key:n,[Zn]:e}}function nr(e){let t=e?.window??(typeof document<`u`?window:void 0),n=t.history.pushState,r=t.history.replaceState,i=[],a=()=>i,o=e=>i=e,s=e?.createHref??(e=>e),c=e?.parseLocation??(()=>ir(`${t.location.pathname}${t.location.search}${t.location.hash}`,t.history.state));if(!t.history.state?.__TSR_key&&!t.history.state?.key){let e=ar();t.history.replaceState({[Zn]:0,key:e,__TSR_key:e},``)}let l=c(),u,d=!1,f=!1,p=!1,m=!1,h=()=>l,g,_,v=()=>{g&&(C._ignoreSubscribers=!0,(g.isPush?t.history.pushState:t.history.replaceState)(g.state,``,g.href),C._ignoreSubscribers=!1,g=void 0,_=void 0,u=void 0)},y=(e,t,n)=>{let r=s(t);_||(u=l),l=ir(t,n),g={href:r,state:n,isPush:g?.isPush||e===`push`},_||=Promise.resolve().then(()=>v())},b=e=>{l=c(),C.notify({type:e})},x=async()=>{if(f){f=!1;return}let e=c(),n=e.state[Zn]-l.state[Zn],r=n===1,i=n===-1,o=!r&&!i||d;d=!1;let s=o?`GO`:i?`BACK`:`FORWARD`,u=o?{type:`GO`,index:n}:{type:i?`BACK`:`FORWARD`};if(p)p=!1;else{let n=a();if(typeof document<`u`&&n.length){for(let r of n)if(await r.blockerFn({currentLocation:l,nextLocation:e,action:s})){f=!0,t.history.go(1),C.notify(u);return}}}l=c(),C.notify(u)},S=e=>{if(m){m=!1;return}let t=!1,n=a();if(typeof document<`u`&&n.length)for(let e of n){let n=e.enableBeforeUnload??!0;if(n===!0){t=!0;break}if(typeof n==`function`&&n()===!0){t=!0;break}}if(t)return e.preventDefault(),e.returnValue=``},C=er({getLocation:h,getLength:()=>t.history.length,pushState:(e,t)=>y(`push`,e,t),replaceState:(e,t)=>y(`replace`,e,t),back:e=>(e&&(p=!0),m=!0,t.history.back()),forward:e=>{e&&(p=!0),m=!0,t.history.forward()},go:e=>{d=!0,t.history.go(e)},createHref:e=>s(e),flush:v,destroy:()=>{t.history.pushState=n,t.history.replaceState=r,t.removeEventListener($n,S,{capture:!0}),t.removeEventListener(Qn,x)},onBlocked:()=>{u&&l!==u&&(l=u)},getBlockers:a,setBlockers:o,notifyOnIndexChange:!1});return t.addEventListener($n,S,{capture:!0}),t.addEventListener(Qn,x),t.history.pushState=function(...e){let r=n.apply(t.history,e);return C._ignoreSubscribers||b(`PUSH`),r},t.history.replaceState=function(...e){let n=r.apply(t.history,e);return C._ignoreSubscribers||b(`REPLACE`),n},C}function rr(e){let t=e.replace(/[\x00-\x1f\x7f]/g,``);return t.startsWith(`//`)&&(t=`/`+t.replace(/^\/+/,``)),t}function ir(e,t){let n=rr(e),r=n.indexOf(`#`),i=n.indexOf(`?`),a=ar();return{href:n,pathname:n.substring(0,r>0?i>0?Math.min(r,i):r:i>0?i:n.length),hash:r>-1?n.substring(r):``,search:i>-1?n.slice(i,r===-1?void 0:r):``,state:t||{[Zn]:0,key:a,__TSR_key:a}}}function ar(){return(Math.random()+1).toString(36).substring(7)}function or(e,t){let n=t,r=e;return{fromLocation:n,toLocation:r,pathChanged:n?.pathname!==r.pathname,hrefChanged:n?.href!==r.href,hashChanged:n?.hash!==r.hash}}var sr=class{constructor(e,t){this.tempLocationKey=`${Math.round(Math.random()*1e7)}`,this.resetNextScroll=!0,this.shouldViewTransition=void 0,this.isViewTransitionTypesSupported=void 0,this.subscribers=new Set,this.isScrollRestoring=!1,this.isScrollRestorationSetup=!1,this.routeBranchCache=new WeakMap,this.startTransition=e=>e(),this.update=e=>{let t=this.options,n=this.basepath??t?.basepath??`/`,r=this.basepath===void 0,i=t?.rewrite;if(this.options={...t,...e},this.isServer=this.options.isServer??typeof document>`u`,this.protocolAllowlist=new Set(this.options.protocolAllowlist),this.options.pathParamsAllowedCharacters&&(this.pathParamsDecoder=Xt(this.options.pathParamsAllowedCharacters)),(!this.history||this.options.history&&this.options.history!==this.history)&&(this.options.history?this.history=this.options.history:this.history=nr()),this.origin=this.options.origin,this.origin||(window?.origin&&window.origin!==`null`?this.origin=window.origin:this.origin=`http://localhost`),this.history&&this.updateLatestLocation(),this.options.routeTree!==this.routeTree){this.routeTree=this.options.routeTree;let e;this.resolvePathCache=_t(1e3),e=this.buildRouteTree(),this.setRoutes(e)}if(!this.stores&&this.latestLocation){let e=this.getStoreConfig(this);this.batch=e.batch,this.stores=En(ur(this.latestLocation),e),dn(this)}let a=!1,o=this.options.basepath??`/`,s=this.options.rewrite;if(r||n!==o||i!==s){this.basepath=o;let e=[],t=Kt(o);t&&t!==`/`&&e.push(Cn({basepath:o})),s&&e.push(s),this.rewrite=e.length===0?void 0:e.length===1?e[0]:Sn(e),this.history&&this.updateLatestLocation(),a=!0}a&&this.stores&&this.stores.location.set(this.latestLocation),typeof window<`u`&&`CSS`in window&&typeof window.CSS?.supports==`function`&&(this.isViewTransitionTypesSupported=window.CSS.supports(`selector(:active-view-transition-type(a))`))},this.updateLatestLocation=()=>{this.latestLocation=this.parseLocation(this.history.location,this.latestLocation)},this.buildRouteTree=()=>{let e=Mt(this.routeTree,this.options.caseSensitive,(e,t)=>{e.init({originalIndex:t})});return this.options.routeMasks&&Dt(this.options.routeMasks,e.processedTree),e},this.subscribe=(e,t)=>{let n={eventType:e,fn:t};return this.subscribers.add(n),()=>{this.subscribers.delete(n)}},this.emit=e=>{this.subscribers.forEach(t=>{t.eventType===e.type&&t.fn(e)})},this.parseLocation=(e,t)=>{let n=({pathname:e,search:n,hash:r,href:i,state:a})=>{if(!this.rewrite&&!/[ \x00-\x1f\x7f\u0080-\uffff]/.test(e)){let i=this.options.parseSearch(n),o=this.options.stringifySearch(i);return{href:e+o+r,publicHref:e+o+r,pathname:pt(e).path,external:!1,searchStr:o,search:Xe(t?.search,i),hash:pt(r.slice(1)).path,state:Ze(t?.state,a)}}let o=new URL(i,this.origin),s=wn(this.rewrite,o),c=this.options.parseSearch(s.search),l=this.options.stringifySearch(c);return s.search=l,{href:s.href.replace(s.origin,``),publicHref:i,pathname:pt(s.pathname).path,external:!!this.rewrite&&s.origin!==this.origin,searchStr:l,search:Xe(t?.search,c),hash:pt(s.hash.slice(1)).path,state:Ze(t?.state,a)}},r=n(e),{__tempLocation:i,__tempKey:a}=r.state;if(i&&(!a||a===this.tempLocationKey)){let e=n(i);return e.state.key=r.state.key,e.state.__TSR_key=r.state.__TSR_key,delete e.state.__tempLocation,{...e,maskedLocation:r}}return r},this.resolvePathWithBase=(e,t)=>Yt({base:e,to:t.includes(`//`)?Ut(t):t,trailingSlash:this.options.trailingSlash,cache:this.resolvePathCache}),this.matchRoutes=(e,t,n)=>typeof e==`string`?this.matchRoutesInternal({pathname:e,search:t},n):this.matchRoutesInternal(e,t),this.getMatchedRoutes=e=>fr({pathname:e,routesById:this.routesById,processedTree:this.processedTree}),this.cancelMatch=e=>{let t=this.getMatch(e);t&&(t.abortController.abort(),clearTimeout(t._nonReactive.pendingTimeout),t._nonReactive.pendingTimeout=void 0)},this.cancelMatches=()=>{this.stores.pendingIds.get().forEach(e=>{this.cancelMatch(e)}),this.stores.matchesId.get().forEach(e=>{if(this.stores.pendingMatchStores.has(e))return;let t=this.stores.matchStores.get(e)?.get();t&&(t.status===`pending`||t.isFetching===`loader`)&&this.cancelMatch(e)})},this.buildLocation=e=>{let t=(t={})=>{let n=t._fromLocation||this.pendingBuiltLocation||this.latestLocation,r=this.matchRoutesLightweight(n);t.from;let i=t.unsafeRelative===`path`?n.pathname:t.from??r.fullPath,a=t.to?`${t.to}`:void 0,o=r.search,s=Object.assign(Object.create(null),r.params),c=a?.charCodeAt(0)===47?`/`:this.resolvePathWithBase(i,`.`),l=a?this.resolvePathWithBase(c,a):c,u=t.params===!1||t.params===null?Object.create(null):(t.params??!0)===!0?s:Object.assign(s,Ge(t.params,s)),d=this.routesByPath[Gt(l)],f;if(d)f=this.getRouteBranch(d);else if(l.includes(`$`))f=[];else{let e=this.getMatchedRoutes(l);f=e.matchedRoutes,this.options.notFoundRoute&&(!e.foundRoute||e.foundRoute.path!==`/`&&e.routeParams[`**`])&&(f=[...f,this.options.notFoundRoute])}if(f.length&&Je(u))for(let e of f){let t=e.options.params?.stringify??e.options.stringifyParams;if(t)try{Object.assign(u,t(u))}catch{}}let p=e.leaveParams?l:pt(Qt({path:l,params:u,decoder:this.pathParamsDecoder,server:this.isServer}).interpolatedPath).path,m=o;if(e._includeValidateSearch&&this.options.search?.strict){let e={};f.forEach(t=>{if(t.options.validateSearch)try{Object.assign(e,dr(t.options.validateSearch,{...e,...m}))}catch{}}),m=e}m=pr({search:m,dest:t,destRoutes:f,_includeValidateSearch:e._includeValidateSearch}),m=Xe(o,m);let h=this.options.stringifySearch(m),g=t.hash===!0?n.hash:t.hash?Ge(t.hash,n.hash):void 0,_=g?`#${g}`:``,v=t.state===!0?n.state:t.state?Ge(t.state,n.state):{};v=Ze(n.state,v);let y=`${p}${h}${_}`,b,x,S=!1;if(this.rewrite){let e=new URL(y,this.origin),t=Tn(this.rewrite,e);b=e.href.replace(e.origin,``),t.origin===this.origin?x=t.pathname+t.search+t.hash:(x=t.href,S=!0)}else b=mt(y),x=b;return{publicHref:x,href:b,pathname:p,search:m,searchStr:h,state:v,hash:g??``,external:S,unmaskOnReload:t.unmaskOnReload}},n=(n={},r)=>{let i=t(n),a=r?t(r):void 0;if(!a){let n=Object.create(null);if(this.options.routeMasks){let o=Ot(i.pathname,this.processedTree);if(o){Object.assign(n,o.rawParams);let{from:i,params:s,...c}=o.route,l=s===!1||s===null?Object.create(null):(s??!0)===!0?n:Object.assign(n,Ge(s,n));r={from:e.from,...c,params:l},a=t(r)}}}return a&&(i.maskedLocation=a),i};return e.mask?n(e,{from:e.from,...e.mask}):n(e)},this.commitLocation=async({viewTransition:e,ignoreBlocker:t,...n})=>{let r=()=>{let e=[`key`,`__TSR_key`,`__TSR_index`,`__hashScrollIntoViewOptions`];e.forEach(e=>{n.state[e]=this.latestLocation.state[e]});let t=nt(n.state,this.latestLocation.state);return e.forEach(e=>{delete n.state[e]}),t},i=Gt(this.latestLocation.href)===Gt(n.href),a=this.commitLocationPromise;if(this.commitLocationPromise=rt(()=>{a?.resolve(),a=void 0}),i&&r())this.load();else{let{maskedLocation:r,hashScrollIntoView:i,...a}=n;r&&(a={...r,state:{...r.state,__tempKey:void 0,__tempLocation:{...a,search:a.searchStr,state:{...a.state,__tempKey:void 0,__tempLocation:void 0,__TSR_key:void 0,key:void 0}}}},(a.unmaskOnReload??this.options.unmaskOnReload??!1)&&(a.state.__tempKey=this.tempLocationKey)),a.state.__hashScrollIntoViewOptions=i??this.options.defaultHashScrollIntoView??!0,this.shouldViewTransition=e,this.history[n.replace?`replace`:`push`](a.publicHref,a.state,{ignoreBlocker:t})}return this.resetNextScroll=n.resetScroll??!0,this.history.subscribers.size||this.load(),this.commitLocationPromise},this.buildAndCommitLocation=({replace:e,resetScroll:t,hashScrollIntoView:n,viewTransition:r,ignoreBlocker:i,href:a,...o}={})=>{if(a){let t=this.history.location.state.__TSR_index,n=ir(a,{__TSR_index:e?t:t+1}),r=new URL(n.pathname,this.origin);o.to=wn(this.rewrite,r).pathname,o.search=this.options.parseSearch(n.search),o.hash=n.hash.slice(1)}let s=this.buildLocation({...o,_includeValidateSearch:!0});this.pendingBuiltLocation=s;let c=this.commitLocation({...s,viewTransition:r,replace:e,resetScroll:t,hashScrollIntoView:n,ignoreBlocker:i});return Promise.resolve().then(()=>{this.pendingBuiltLocation===s&&(this.pendingBuiltLocation=void 0)}),c},this.navigate=async({to:e,reloadDocument:t,href:n,publicHref:r,...i})=>{let a=!1;if(n)try{new URL(`${n}`),a=!0}catch{}if(a&&!t&&(t=!0),t){if(e!==void 0||!n){let t=this.buildLocation({to:e,...i});n??=t.publicHref,r??=t.publicHref}let t=!a&&r?r:n;if(lt(t,this.protocolAllowlist))return Promise.resolve();if(!i.ignoreBlocker){let e=this.history.getBlockers?.()??[];for(let t of e)if(t?.blockerFn&&await t.blockerFn({currentLocation:this.latestLocation,nextLocation:this.latestLocation,action:`PUSH`}))return Promise.resolve()}return i.replace?window.location.replace(t):window.location.href=t,Promise.resolve()}return this.buildAndCommitLocation({...i,href:n,to:e,_isNavigate:!0})},this.beforeLoad=()=>{this.cancelMatches(),this.updateLatestLocation();let e=this.matchRoutes(this.latestLocation),t=this.stores.cachedMatches.get().filter(t=>!e.some(e=>e.id===t.id));this.batch(()=>{this.stores.status.set(`pending`),this.stores.statusCode.set(200),this.stores.isLoading.set(!0),this.stores.location.set(this.latestLocation),this.stores.setPending(e),this.stores.setCached(t)})},this.load=async e=>{let t,n,r,i=this.stores.resolvedLocation.get()??this.stores.location.get();for(r=new Promise(a=>{this.startTransition(async()=>{try{this.beforeLoad();let t=this.latestLocation,n=or(t,this.stores.resolvedLocation.get());this.stores.redirect.get()||this.emit({type:`onBeforeNavigate`,...n}),this.emit({type:`onBeforeLoad`,...n}),await Kn({router:this,sync:e?.sync,forceStaleReload:i.href===t.href,matches:this.stores.pendingMatches.get(),location:t,updateMatch:this.updateMatch,onReady:async()=>{this.startTransition(()=>{this.startViewTransition(async()=>{let e=null,t=null,n=null,r=null;this.batch(()=>{let i=this.stores.pendingMatches.get(),a=i.length,o=this.stores.matches.get();e=a?o.filter(e=>!this.stores.pendingMatchStores.has(e.id)):null;let s=new Set;for(let e of this.stores.pendingMatchStores.values())e.routeId&&s.add(e.routeId);let c=new Set;for(let e of this.stores.matchStores.values())e.routeId&&c.add(e.routeId);t=a?o.filter(e=>!s.has(e.routeId)):null,n=a?i.filter(e=>!c.has(e.routeId)):null,r=a?i.filter(e=>c.has(e.routeId)):o,this.stores.isLoading.set(!1),this.stores.loadedAt.set(Date.now()),a&&(this.stores.setMatches(i),this.stores.setPending([]),this.stores.setCached([...this.stores.cachedMatches.get(),...e.filter(e=>e.status!==`error`&&e.status!==`notFound`&&e.status!==`redirected`)]),this.clearExpiredCache())});for(let[e,i]of[[t,`onLeave`],[n,`onEnter`],[r,`onStay`]])if(e)for(let t of e)this.looseRoutesById[t.routeId].options[i]?.(t)})})}})}catch(e){xn(e)?(t=e,this.navigate({...t.options,replace:!0,ignoreBlocker:!0})):en(e)&&(n=e);let r=t?t.status:n?404:this.stores.matches.get().some(e=>e.status===`error`)?500:200;this.batch(()=>{this.stores.statusCode.set(r),this.stores.redirect.set(t)})}this.latestLoadPromise===r&&(this.commitLocationPromise?.resolve(),this.latestLoadPromise=void 0,this.commitLocationPromise=void 0),a()})}),this.latestLoadPromise=r,await r;this.latestLoadPromise&&r!==this.latestLoadPromise;)await this.latestLoadPromise;let a;this.hasNotFoundMatch()?a=404:this.stores.matches.get().some(e=>e.status===`error`)&&(a=500),a!==void 0&&this.stores.statusCode.set(a)},this.startViewTransition=e=>{let t=this.shouldViewTransition??this.options.defaultViewTransition;if(this.shouldViewTransition=void 0,t&&typeof document<`u`&&`startViewTransition`in document&&typeof document.startViewTransition==`function`){let n;if(typeof t==`object`&&this.isViewTransitionTypesSupported){let r=this.latestLocation,i=this.stores.resolvedLocation.get(),a=typeof t.types==`function`?t.types(or(r,i)):t.types;if(a===!1){e();return}n={update:e,types:a}}else n=e;document.startViewTransition(n)}else e()},this.updateMatch=(e,t)=>{this.startTransition(()=>{let n=this.stores.pendingMatchStores.get(e);if(n){n.set(t);return}let r=this.stores.matchStores.get(e);if(r){r.set(t);return}let i=this.stores.cachedMatchStores.get(e);if(i){let n=t(i.get());n.status===`redirected`?this.stores.cachedMatchStores.delete(e)&&this.stores.cachedIds.set(t=>t.filter(t=>t!==e)):i.set(n)}})},this.getMatch=e=>this.stores.cachedMatchStores.get(e)?.get()??this.stores.pendingMatchStores.get(e)?.get()??this.stores.matchStores.get(e)?.get(),this.invalidate=e=>{let t=t=>e?.filter?.(t)??!0?{...t,invalid:!0,...e?.forcePending||t.status===`error`||t.status===`notFound`?{status:`pending`,error:void 0}:void 0}:t;return this.batch(()=>{this.stores.setMatches(this.stores.matches.get().map(t)),this.stores.setCached(this.stores.cachedMatches.get().map(t)),this.stores.setPending(this.stores.pendingMatches.get().map(t))}),this.shouldViewTransition=!1,this.load({sync:e?.sync})},this.getParsedLocationHref=e=>e.publicHref||`/`,this.resolveRedirect=e=>{let t=e.headers.get(`Location`);if(!e.options.href||e.options._builtLocation){let t=e.options._builtLocation??this.buildLocation(e.options),n=this.getParsedLocationHref(t);e.options.href=n,e.headers.set(`Location`,n)}else if(t)try{let n=new URL(t);if(this.origin&&n.origin===this.origin){let t=n.pathname+n.search+n.hash;e.options.href=t,e.headers.set(`Location`,t)}}catch{}if(e.options.href&&!e.options._builtLocation&<(e.options.href,this.protocolAllowlist))throw Error(`Redirect blocked: unsafe protocol`);return e.headers.get(`Location`)||e.headers.set(`Location`,e.options.href),e},this.clearCache=e=>{let t=e?.filter;t===void 0?this.stores.setCached([]):this.stores.setCached(this.stores.cachedMatches.get().filter(e=>!t(e)))},this.clearExpiredCache=()=>{let e=Date.now();this.clearCache({filter:t=>{let n=this.looseRoutesById[t.routeId];if(!n.options.loader)return!0;let r=(t.preload?n.options.preloadGcTime??this.options.defaultPreloadGcTime:n.options.gcTime??this.options.defaultGcTime)??300*1e3;return t.status===`error`?!0:e-t.updatedAt>=r}})},this.loadRouteChunk=Jn,this.preloadRoute=async e=>{let t=e._builtLocation??this.buildLocation(e),n=this.matchRoutes(t,{throwOnError:!0,preload:!0,dest:e}),r=new Set([...this.stores.matchesId.get(),...this.stores.pendingIds.get()]),i=new Set([...r,...this.stores.cachedIds.get()]),a=n.filter(e=>!i.has(e.id));if(a.length){let e=this.stores.cachedMatches.get();this.stores.setCached([...e,...a])}try{return n=await Kn({router:this,matches:n,location:t,preload:!0,updateMatch:(e,t)=>{r.has(e)?n=n.map(n=>n.id===e?t(n):n):this.updateMatch(e,t)}}),n}catch(e){if(xn(e))return e.options.reloadDocument?void 0:await this.preloadRoute({...e.options,_fromLocation:t});en(e)||console.error(e);return}},this.matchRoute=(e,t)=>{let n={...e,to:e.to?this.resolvePathWithBase(e.from||``,e.to):void 0,params:e.params||{},leaveParams:!0},r=this.buildLocation(n);if(t?.pending&&this.stores.status.get()!==`pending`)return!1;let i=(t?.pending===void 0?!this.stores.isLoading.get():t.pending)?this.latestLocation:this.stores.resolvedLocation.get()||this.stores.location.get(),a=kt(r.pathname,t?.caseSensitive??!1,t?.fuzzy??!1,i.pathname,this.processedTree);return!a||e.params&&!nt(a.rawParams,e.params,{partial:!0})?!1:t?.includeSearch??!0?nt(i.search,r.search,{partial:!0})?a.rawParams:!1:a.rawParams},this.hasNotFoundMatch=()=>this.stores.matches.get().some(e=>e.status===`notFound`||e.globalNotFound),this.getStoreConfig=t,this.update({defaultPreloadDelay:50,defaultPendingMs:1e3,defaultPendingMinMs:500,context:void 0,...e,caseSensitive:e.caseSensitive??!1,notFoundMode:e.notFoundMode??`fuzzy`,stringifySearch:e.stringifySearch??gn,parseSearch:e.parseSearch??hn,protocolAllowlist:e.protocolAllowlist??ct}),typeof document<`u`&&(self.__TSR_ROUTER__=this)}isShell(){return!!this.options.isShell}isPrerendering(){return!!this.options.isPrerendering}get state(){return this.stores.__store.get()}setRoutes({routesById:e,routesByPath:t,processedTree:n}){this.routesById=e,this.routesByPath=t,this.processedTree=n;let r=this.options.notFoundRoute;r&&(r.init({originalIndex:99999999999}),this.routesById[r.id]=r)}getRouteBranch(e){let t=this.routeBranchCache.get(e);return t||(t=Ft(e),this.routeBranchCache.set(e,t)),t}get looseRoutesById(){return this.routesById}getParentContext(e){return e?.id?e.context??this.options.context??void 0:this.options.context??void 0}matchRoutesInternal(e,t){let n=this.getMatchedRoutes(e.pathname),{foundRoute:r,routeParams:i}=n,{matchedRoutes:a}=n,o=!1;(r?r.path!==`/`&&i[`**`]:Gt(e.pathname))&&(this.options.notFoundRoute?a=[...a,this.options.notFoundRoute]:o=!0);let s=o?hr(this.options.notFoundMode,a):void 0,c=Array(a.length),l=new Map;for(let e of this.stores.matchStores.values())e.routeId&&l.set(e.routeId,e.get());for(let n=0;nthis.navigate({...t,_fromLocation:e}),buildLocation:this.buildLocation,cause:n.cause,abortController:n.abortController,preload:!!n.preload,matches:c,routeId:r.id};n.__routeContext=r.options.context(t)??void 0}n.context={...a,...n.__routeContext,...n.__beforeLoadContext}}}return c}matchRoutesLightweight(e){let{matchedRoutes:t,routeParams:n}=this.getMatchedRoutes(e.pathname),r=Ue(t),i={...e.search};for(let e of t)try{Object.assign(i,dr(e.options.validateSearch,i))}catch{}let a=Ue(this.stores.matchesId.get()),o=a&&this.stores.matchStores.get(a)?.get(),s=o&&o.routeId===r.id&&o.pathname===e.pathname,c;if(s)c=o.params;else{let e=Object.assign(Object.create(null),n);for(let n of t)try{gr(n,e)}catch{}c=e}return{matchedRoutes:t,fullPath:r.fullPath,search:i,params:c}}},cr=class extends Error{},lr=class extends Error{};function ur(e){return{loadedAt:0,isLoading:!1,isTransitioning:!1,status:`idle`,resolvedLocation:void 0,location:e,matches:[],statusCode:200}}function dr(e,t){if(e==null)return{};if(`~standard`in e){let n=e[`~standard`].validate(t);if(n instanceof Promise)throw new cr(`Async validation not supported`);if(n.issues)throw new cr(JSON.stringify(n.issues,void 0,2),{cause:n});return n.value}return`parse`in e?e.parse(t):typeof e==`function`?e(t):{}}function fr({pathname:e,routesById:t,processedTree:n}){let r=Object.create(null),i=Gt(e),a,o=At(i,n,!0);return o&&(a=o.route,Object.assign(r,o.rawParams)),{matchedRoutes:o?.branch||[t.__root__],routeParams:r,foundRoute:a}}function pr({search:e,dest:t,destRoutes:n,_includeValidateSearch:r}){return mr(n)(e,t,r??!1)}function mr(e){let t={dest:null,_includeValidateSearch:!1,middlewares:[]};for(let n of e)`search`in n.options?n.options.search?.middlewares&&t.middlewares.push(...n.options.search.middlewares):(n.options.preSearchFilters||n.options.postSearchFilters)&&t.middlewares.push(({search:e,next:t})=>{let r=e;`preSearchFilters`in n.options&&n.options.preSearchFilters&&(r=n.options.preSearchFilters.reduce((e,t)=>t(e),e));let i=t(r);return`postSearchFilters`in n.options&&n.options.postSearchFilters?n.options.postSearchFilters.reduce((e,t)=>t(e),i):i}),n.options.validateSearch&&t.middlewares.push(({search:e,next:r})=>{let i=r(e);if(!t._includeValidateSearch)return i;try{return{...i,...dr(n.options.validateSearch,i)??void 0}}catch{return i}});t.middlewares.push(({search:e})=>{let n=t.dest;return n.search?n.search===!0?e:Ge(n.search,e):{}});let n=(e,t,r)=>{if(e>=r.length)return t;let i=r[e];return i({search:t,next:t=>n(e+1,t,r)})};return function(e,r,i){return t.dest=r,t._includeValidateSearch=i,n(0,e,t.middlewares)}}function hr(e,t){if(e!==`root`)for(let e=t.length-1;e>=0;e--){let n=t[e];if(n.children)return n.id}return yn}function gr(e,t){let n=e.options.params?.parse??e.options.parseParams;if(n){let e=n(t);if(e===!1)throw Error(`Route params.parse returned false for a matched route`);Object.assign(t,e)}}var _r=`Error preloading route! ☝️`;function vr(e,t){if(e)return typeof e==`string`?e:e[t]}function yr(e){return typeof e==`string`?{href:e,crossOrigin:void 0}:e}function br(e){if(e.tag!==`link`)return;let t=e.attrs?.rel,n=e.attrs?.href;if(typeof n==`string`&&(typeof t==`string`?t.split(/\s+/):[]).includes(`stylesheet`))return n}function xr(e,t){let n=br(t);return!!n&&e?.inlineCss?.styles[n]!==void 0}var Sr=class{get to(){return this._to}get id(){return this._id}get path(){return this._path}get fullPath(){return this._fullPath}constructor(e){if(this.init=e=>{this.originalIndex=e.originalIndex;let t=this.options,n=!t?.path&&!t?.id;this.parentRoute=this.options.getParentRoute?.(),n?this._path=yn:this.parentRoute||gt();let r=n?yn:t?.path;r&&r!==`/`&&(r=Wt(r));let i=t?.id||r,a=n?yn:Ht([this.parentRoute.id===`__root__`?``:this.parentRoute.id,i]);r===`__root__`&&(r=`/`),a!==`__root__`&&(a=Ht([`/`,a]));let o=a===`__root__`?`/`:Ht([this.parentRoute.fullPath,r]);this._path=r,this._id=a,this._fullPath=o,this._to=Gt(o)},this.addChildren=e=>this._addFileChildren(e),this._addFileChildren=e=>(Array.isArray(e)&&(this.children=e),typeof e==`object`&&e&&(this.children=Object.values(e)),this),this._addFileTypes=()=>this,this.updateLoader=e=>(Object.assign(this.options,e),this),this.update=e=>(Object.assign(this.options,e),this),this.lazy=e=>(this.lazyFn=e,this),this.redirect=e=>bn({from:this.fullPath,...e}),this.options=e||{},this.isRoot=!e?.getParentRoute,e?.id&&e?.path)throw Error(`Route cannot have both an 'id' and a 'path' option.`)}},Cr=class extends Sr{constructor(e){super(e)}};function wr(e){if(typeof document<`u`&&document.querySelector){let t=e.stores.location.get(),n=t.state.__hashScrollIntoViewOptions??!0;if(n&&t.hash!==``){let e=document.getElementById(t.hash);e&&e.scrollIntoView(n)}}}function Tr(e){let t=e.errorComponent??Dr;return(0,F.jsx)(Er,{getResetKey:e.getResetKey,onCatch:e.onCatch,children:({error:n,reset:r})=>n?P.createElement(t,{error:n,reset:r}):e.children})}var Er=class extends P.Component{constructor(...e){super(...e),this.state={error:null}}static getDerivedStateFromProps(e,t){let n=e.getResetKey();return t.error&&t.resetKey!==n?{resetKey:n,error:null}:{resetKey:n}}static getDerivedStateFromError(e){return{error:e}}reset(){this.setState({error:null})}componentDidCatch(e,t){this.props.onCatch&&this.props.onCatch(e,t)}render(){return this.props.children({error:this.state.error,reset:()=>{this.reset()}})}};function Dr({error:e}){let[t,n]=P.useState(!1);return(0,F.jsxs)(`div`,{style:{padding:`.5rem`,maxWidth:`100%`},children:[(0,F.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`.5rem`},children:[(0,F.jsx)(`strong`,{style:{fontSize:`1rem`},children:`Something went wrong!`}),(0,F.jsx)(`button`,{style:{appearance:`none`,fontSize:`.6em`,border:`1px solid currentColor`,padding:`.1rem .2rem`,fontWeight:`bold`,borderRadius:`.25rem`},onClick:()=>n(e=>!e),children:t?`Hide Error`:`Show Error`})]}),(0,F.jsx)(`div`,{style:{height:`.25rem`}}),t?(0,F.jsx)(`div`,{children:(0,F.jsx)(`pre`,{style:{fontSize:`.7em`,border:`1px solid red`,borderRadius:`.25rem`,padding:`.3rem`,color:`red`,overflow:`auto`},children:e.message?(0,F.jsx)(`code`,{children:e.message}):null})}):null]})}function Or({children:e,fallback:t=null}){return kr()?(0,F.jsx)(P.Fragment,{children:e}):(0,F.jsx)(P.Fragment,{children:t})}function kr(){return P.useSyncExternalStore(Ar,()=>!0,()=>!1)}function Ar(){return()=>{}}var jr=P.createContext(null);function Mr(e){return P.useContext(jr)}var Nr=P.createContext(void 0),Pr=P.createContext(void 0),Fr=(e=>(e[e.None=0]=`None`,e[e.Mutable=1]=`Mutable`,e[e.Watching=2]=`Watching`,e[e.RecursedCheck=4]=`RecursedCheck`,e[e.Recursed=8]=`Recursed`,e[e.Dirty=16]=`Dirty`,e[e.Pending=32]=`Pending`,e))(Fr||{});function Ir({update:e,notify:t,unwatched:n}){return{link:r,unlink:i,propagate:a,checkDirty:o,shallowPropagate:s};function r(e,t,n){let r=t.depsTail;if(r!==void 0&&r.dep===e)return;let i=r===void 0?t.deps:r.nextDep;if(i!==void 0&&i.dep===e){i.version=n,t.depsTail=i;return}let a=e.subsTail;if(a!==void 0&&a.version===n&&a.sub===t)return;let o=t.depsTail=e.subsTail={version:n,dep:e,sub:t,prevDep:r,nextDep:i,prevSub:a,nextSub:void 0};i!==void 0&&(i.prevDep=o),r===void 0?t.deps=o:r.nextDep=o,a===void 0?e.subs=o:a.nextSub=o}function i(e,t=e.sub){let r=e.dep,i=e.prevDep,a=e.nextDep,o=e.nextSub,s=e.prevSub;return a===void 0?t.depsTail=i:a.prevDep=i,i===void 0?t.deps=a:i.nextDep=a,o===void 0?r.subsTail=s:o.prevSub=s,s===void 0?(r.subs=o)===void 0&&n(r):s.nextSub=o,a}function a(e){let n=e.nextSub,r;top:do{let i=e.sub,a=i.flags;if(a&60?a&12?a&4?!(a&48)&&c(e,i)?(i.flags=a|40,a&=1):a=0:i.flags=a&-9|32:a=0:i.flags=a|32,a&2&&t(i),a&1){let t=i.subs;if(t!==void 0){let i=(e=t).nextSub;i!==void 0&&(r={value:n,prev:r},n=i);continue}}if((e=n)!==void 0){n=e.nextSub;continue}for(;r!==void 0;)if(e=r.value,r=r.prev,e!==void 0){n=e.nextSub;continue top}break}while(!0)}function o(t,n){let r,i=0,a=!1;top:do{let o=t.dep,c=o.flags;if(n.flags&16)a=!0;else if((c&17)==17){if(e(o)){let e=o.subs;e.nextSub!==void 0&&s(e),a=!0}}else if((c&33)==33){(t.nextSub!==void 0||t.prevSub!==void 0)&&(r={value:t,prev:r}),t=o.deps,n=o,++i;continue}if(!a){let e=t.nextDep;if(e!==void 0){t=e;continue}}for(;i--;){let i=n.subs,o=i.nextSub!==void 0;if(o?(t=r.value,r=r.prev):t=i,a){if(e(n)){o&&s(i),n=t.sub;continue}a=!1}else n.flags&=-33;n=t.sub;let c=t.nextDep;if(c!==void 0){t=c;continue top}}return a}while(!0)}function s(e){do{let n=e.sub,r=n.flags;(r&48)==32&&(n.flags=r|16,(r&6)==2&&t(n))}while((e=e.nextSub)!==void 0)}function c(e,t){let n=t.depsTail;for(;n!==void 0;){if(n===e)return!0;n=n.prevDep}return!1}}function Lr(e,t,n){let r=typeof e==`object`,i=r?e:void 0;return{next:(r?e.next:e)?.bind(i),error:(r?e.error:t)?.bind(i),complete:(r?e.complete:n)?.bind(i)}}var Rr=[],zr=0,{link:Br,unlink:Vr,propagate:Hr,checkDirty:Ur,shallowPropagate:Wr}=Ir({update(e){return e._update()},notify(e){Rr[Kr++]=e,e.flags&=~Fr.Watching},unwatched(e){e.depsTail!==void 0&&(e.depsTail=void 0,e.flags=Fr.Mutable|Fr.Dirty,Xr(e))}}),Gr=0,Kr=0,qr,Jr=0;function Yr(e){try{++Jr,e()}finally{--Jr||Zr()}}function Xr(e){let t=e.depsTail,n=t===void 0?e.deps:t.nextDep;for(;n!==void 0;)n=Vr(n,e)}function Zr(){if(!(Jr>0)){for(;Gr{i.get(),n.current?t.next?.(i._snapshot):n.current=!0});return{unsubscribe:()=>{r.stop()}}},_update(e){let a=qr,o=t?.compare??Object.is;if(n)qr=i,++zr,i.depsTail=void 0;else if(e===void 0)return!1;n&&(i.flags=Fr.Mutable|Fr.RecursedCheck);try{let t=i._snapshot,a=typeof e==`function`?e(t):e===void 0&&n?r(t):e;return t===void 0||!o(t,a)?(i._snapshot=a,!0):!1}finally{qr=a,n&&(i.flags&=~Fr.RecursedCheck),Xr(i)}}};return n?(i.flags=Fr.Mutable|Fr.Dirty,i.get=function(){let e=i.flags;if(e&Fr.Dirty||e&Fr.Pending&&Ur(i.deps,i)){if(i._update()){let e=i.subs;e!==void 0&&Wr(e)}}else e&Fr.Pending&&(i.flags=e&~Fr.Pending);return qr!==void 0&&Br(i,qr,zr),i._snapshot}):i.set=function(e){if(i._update(e)){let e=i.subs;e!==void 0&&(Hr(e),Wr(e),Zr())}},i}function $r(e){let t=()=>{let t=qr;qr=n,++zr,n.depsTail=void 0,n.flags=Fr.Watching|Fr.RecursedCheck;try{return e()}finally{qr=t,n.flags&=~Fr.RecursedCheck,Xr(n)}},n={deps:void 0,depsTail:void 0,subs:void 0,subsTail:void 0,flags:Fr.Watching|Fr.RecursedCheck,notify(){let e=this.flags;e&Fr.Dirty||e&Fr.Pending&&Ur(this.deps,this)?t():this.flags=Fr.Watching},stop(){this.flags=Fr.None,this.depsTail=void 0,Xr(this)}};return t(),n}var ei=o((e=>{var t=je();function n(e,t){return e===t&&(e!==0||1/e==1/t)||e!==e&&t!==t}var r=typeof Object.is==`function`?Object.is:n,i=t.useState,a=t.useEffect,o=t.useLayoutEffect,s=t.useDebugValue;function c(e,t){var n=t(),r=i({inst:{value:n,getSnapshot:t}}),c=r[0].inst,u=r[1];return o(function(){c.value=n,c.getSnapshot=t,l(c)&&u({inst:c})},[e,n,t]),a(function(){return l(c)&&u({inst:c}),e(function(){l(c)&&u({inst:c})})},[e]),s(n),n}function l(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!r(e,n)}catch{return!0}}function u(e,t){return t()}var d=typeof window>`u`||window.document===void 0||window.document.createElement===void 0?u:c;e.useSyncExternalStore=t.useSyncExternalStore===void 0?d:t.useSyncExternalStore})),ti=o(((e,t)=>{t.exports=ei()})),ni=o((e=>{var t=je(),n=ti();function r(e,t){return e===t&&(e!==0||1/e==1/t)||e!==e&&t!==t}var i=typeof Object.is==`function`?Object.is:r,a=n.useSyncExternalStore,o=t.useRef,s=t.useEffect,c=t.useMemo,l=t.useDebugValue;e.useSyncExternalStoreWithSelector=function(e,t,n,r,u){var d=o(null);if(d.current===null){var f={hasValue:!1,value:null};d.current=f}else f=d.current;d=c(function(){function e(e){if(!a){if(a=!0,o=e,e=r(e),u!==void 0&&f.hasValue){var t=f.value;if(u(t,e))return s=t}return s=e}if(t=s,i(o,e))return t;var n=r(e);return u!==void 0&&u(t,n)?(o=e,t):(o=e,s=n)}var a=!1,o,s,c=n===void 0?null:n;return[function(){return e(t())},c===null?void 0:function(){return e(c())}]},[t,n,r,u]);var p=a(e,d[0],d[1]);return s(function(){f.hasValue=!0,f.value=p},[p]),l(p),p}})),ri=o(((e,t)=>{t.exports=ni()}))();function ii(e,t){return e===t}function ai(e,t,n=ii){let r=(0,P.useCallback)(t=>{if(!e)return()=>{};let{unsubscribe:n}=e.subscribe(t);return n},[e]),i=(0,P.useCallback)(()=>e?.get(),[e]);return(0,ri.useSyncExternalStoreWithSelector)(r,i,i,t,n)}var oi={get:()=>void 0,subscribe:()=>({unsubscribe:()=>{}})};function si(e){let t=Mr(),n=P.useContext(e.from?Pr:Nr),r=e.from??n,i=r?e.from?t.stores.getRouteMatchStore(r):t.stores.matchStores.get(r):void 0,a=P.useRef(void 0);return ai(i??oi,n=>{if((e.shouldThrow??!0)&&!n&>(),n===void 0)return;let r=e.select?e.select(n):n;if(e.structuralSharing??t.options.defaultStructuralSharing){let e=Ze(a.current,r);return a.current=e,e}return r})}function ci(e){return si({from:e.from,strict:e.strict,structuralSharing:e.structuralSharing,select:t=>e.select?e.select(t.loaderData):t.loaderData})}function li(e){let{select:t,...n}=e;return si({...n,select:e=>t?t(e.loaderDeps):e.loaderDeps})}function ui(e){return si({from:e.from,shouldThrow:e.shouldThrow,structuralSharing:e.structuralSharing,strict:e.strict,select:t=>{let n=e.strict===!1?t.params:t._strictParams;return e.select?e.select(n):n}})}function di(e){return si({from:e.from,strict:e.strict,shouldThrow:e.shouldThrow,structuralSharing:e.structuralSharing,select:t=>e.select?e.select(t.search):t.search})}function fi(e){let t=Mr();return P.useCallback(n=>t.navigate({...n,from:n.from??e?.from}),[e?.from,t])}function pi(e){return si({...e,select:t=>e.select?e.select(t.context):t.context})}var mi=o((e=>{var t=je();function n(e){var t=`https://react.dev/errors/`+e;if(1{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=mi()})),gi=c(hi(),1);function _i(e,t){let n=Mr(),r=He(t),{activeProps:i,inactiveProps:a,activeOptions:o,to:s,preload:c,preloadDelay:l,preloadIntentProximity:u,hashScrollIntoView:d,replace:f,startTransition:p,resetScroll:m,viewTransition:h,children:g,target:_,disabled:v,style:y,className:b,onClick:x,onBlur:S,onFocus:C,onMouseEnter:w,onMouseLeave:T,onTouchStart:E,ignoreBlocker:ee,params:D,search:O,hash:te,state:ne,mask:re,reloadDocument:k,unsafeRelative:A,from:ie,_fromLocation:j,...ae}=e,oe=kr(),se=P.useMemo(()=>e,[n,e.from,e._fromLocation,e.hash,e.to,e.search,e.params,e.state,e.mask,e.unsafeRelative]),ce=ai(n.stores.location,e=>e,(e,t)=>e.href===t.href),M=P.useMemo(()=>{let e={_fromLocation:ce,...se};return n.buildLocation(e)},[n,ce,se]),le=M.maskedLocation?M.maskedLocation.publicHref:M.publicHref,ue=M.maskedLocation?M.maskedLocation.external:M.external,N=P.useMemo(()=>Ei(le,ue,n.history,v),[v,ue,le,n.history]),de=P.useMemo(()=>{if(N?.external)return lt(N.href,n.protocolAllowlist)?void 0:N.href;if(!Di(s)&&!(typeof s!=`string`||s.indexOf(`:`)===-1))try{return new URL(s),lt(s,n.protocolAllowlist)?void 0:s}catch{}},[s,N,n.protocolAllowlist]),fe=P.useMemo(()=>{if(de)return!1;if(o?.exact){if(!Jt(ce.pathname,M.pathname,n.basepath))return!1}else{let e=qt(ce.pathname,n.basepath),t=qt(M.pathname,n.basepath);if(!(e.startsWith(t)&&(e.length===t.length||e[t.length]===`/`)))return!1}return(o?.includeSearch??!0)&&!nt(ce.search,M.search,{partial:!o?.exact,ignoreUndefined:!o?.explicitUndefined})?!1:o?.includeHash?oe&&ce.hash===M.hash:!0},[o?.exact,o?.explicitUndefined,o?.includeHash,o?.includeSearch,ce,de,oe,M.hash,M.pathname,M.search,n.basepath]),pe=fe?Ge(i,{})??yi:vi,me=fe?vi:Ge(a,{})??vi,he=[b,pe.className,me.className].filter(Boolean).join(` `),ge=(y||pe.style||me.style)&&{...y,...pe.style,...me.style},[_e,ve]=P.useState(!1),ye=P.useRef(!1),be=e.reloadDocument||de?!1:c??n.options.defaultPreload,xe=l??n.options.defaultPreloadDelay??0,Se=P.useCallback(()=>{n.preloadRoute({...se,_builtLocation:M}).catch(e=>{console.warn(e),console.warn(_r)})},[n,se,M]);Ve(r,P.useCallback(e=>{e?.isIntersecting&&Se()},[Se]),wi,{disabled:!!v||be!==`viewport`}),P.useEffect(()=>{ye.current||!v&&be===`render`&&(Se(),ye.current=!0)},[v,Se,be]);let Ce=e=>{let t=e.currentTarget.getAttribute(`target`),r=_===void 0?t:_;if(!v&&!ki(e)&&!e.defaultPrevented&&(!r||r===`_self`)&&e.button===0){e.preventDefault(),(0,gi.flushSync)(()=>{ve(!0)});let t=n.subscribe(`onResolved`,()=>{t(),ve(!1)});n.navigate({...se,replace:f,resetScroll:m,hashScrollIntoView:d,startTransition:p,viewTransition:h,ignoreBlocker:ee})}};if(de)return{...ae,ref:r,href:de,...g&&{children:g},..._&&{target:_},...v&&{disabled:v},...y&&{style:y},...b&&{className:b},...x&&{onClick:x},...S&&{onBlur:S},...C&&{onFocus:C},...w&&{onMouseEnter:w},...T&&{onMouseLeave:T},...E&&{onTouchStart:E}};let we=e=>{if(v||be!==`intent`)return;if(!xe){Se();return}let t=e.currentTarget;if(Ci.has(t))return;let n=setTimeout(()=>{Ci.delete(t),Se()},xe);Ci.set(t,n)},Te=e=>{v||be!==`intent`||Se()},Ee=e=>{if(v||!be||!xe)return;let t=e.currentTarget,n=Ci.get(t);n&&(clearTimeout(n),Ci.delete(t))};return{...ae,...pe,...me,href:N?.href,ref:r,onClick:Ti([x,Ce]),onBlur:Ti([S,Ee]),onFocus:Ti([C,we]),onMouseEnter:Ti([w,we]),onMouseLeave:Ti([T,Ee]),onTouchStart:Ti([E,Te]),disabled:!!v,target:_,...ge&&{style:ge},...he&&{className:he},...v&&bi,...fe&&xi,...oe&&_e&&Si}}var vi={},yi={className:`active`},bi={role:`link`,"aria-disabled":!0},xi={"data-status":`active`,"aria-current":`page`},Si={"data-transitioning":`transitioning`},Ci=new WeakMap,wi={rootMargin:`100px`},Ti=e=>t=>{for(let n of e)if(n){if(t.defaultPrevented)return;n(t)}};function Ei(e,t,n,r){if(!r)return t?{href:e,external:!0}:{href:n.createHref(e)||`/`,external:!1}}function Di(e){if(typeof e!=`string`)return!1;let t=e.charCodeAt(0);return t===47?e.charCodeAt(1)!==47:t===46}var Oi=P.forwardRef((e,t)=>{let{_asChild:n,...r}=e,{type:i,...a}=_i(r,t),o=typeof r.children==`function`?r.children({isActive:a[`data-status`]===`active`}):r.children;if(!n){let{disabled:e,...t}=a;return P.createElement(`a`,t,o)}return P.createElement(n,a,o)});function ki(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}var Ai=class extends Sr{constructor(e){super(e),this.useMatch=e=>si({select:e?.select,from:this.id,structuralSharing:e?.structuralSharing}),this.useRouteContext=e=>pi({...e,from:this.id}),this.useSearch=e=>di({select:e?.select,structuralSharing:e?.structuralSharing,from:this.id}),this.useParams=e=>ui({select:e?.select,structuralSharing:e?.structuralSharing,from:this.id}),this.useLoaderDeps=e=>li({...e,from:this.id}),this.useLoaderData=e=>ci({...e,from:this.id}),this.useNavigate=()=>fi({from:this.fullPath}),this.Link=P.forwardRef((e,t)=>(0,F.jsx)(Oi,{ref:t,from:this.fullPath,...e}))}};function ji(e){return new Ai(e)}function Mi(){return e=>Pi(e)}var Ni=class extends Cr{constructor(e){super(e),this.useMatch=e=>si({select:e?.select,from:this.id,structuralSharing:e?.structuralSharing}),this.useRouteContext=e=>pi({...e,from:this.id}),this.useSearch=e=>di({select:e?.select,structuralSharing:e?.structuralSharing,from:this.id}),this.useParams=e=>ui({select:e?.select,structuralSharing:e?.structuralSharing,from:this.id}),this.useLoaderDeps=e=>li({...e,from:this.id}),this.useLoaderData=e=>ci({...e,from:this.id}),this.useNavigate=()=>fi({from:this.fullPath}),this.Link=P.forwardRef((e,t)=>(0,F.jsx)(Oi,{ref:t,from:this.fullPath,...e}))}};function Pi(e){return new Ni(e)}function I(e){return new Fi(e,{silent:!0}).createRoute}var Fi=class{constructor(e,t){this.path=e,this.createRoute=e=>{let t=ji(e);return t.isRoot=!1,t},this.silent=t?.silent}};function L(e,t){let n,r,i,a,o=()=>(n||=e().then(e=>{n=void 0,r=e[t??`default`]}).catch(e=>{if(i=e,it(i)&&i instanceof Error&&typeof window<`u`&&typeof sessionStorage<`u`){let e=`tanstack_router_reload:${i.message}`;sessionStorage.getItem(e)||(sessionStorage.setItem(e,`1`),a=!0)}}),n),s=function(e){if(a)throw window.location.reload(),new Promise(()=>{});if(i)throw i;if(!r)if(Re)Re(o());else throw o();return P.createElement(r,e)};return s.preload=o,s}function Ii(e){let t=Mr(),n=`not-found-${ai(t.stores.location,e=>e.pathname)}-${ai(t.stores.status,e=>e)}`;return(0,F.jsx)(Tr,{getResetKey:()=>n,onCatch:(t,n)=>{if(en(t))e.onCatch?.(t,n);else throw t},errorComponent:({error:t})=>{if(en(t))return e.fallback?.(t);throw t},children:e.children})}function Li(){return(0,F.jsx)(`p`,{children:`Not Found`})}function Ri(e){return(0,F.jsx)(F.Fragment,{children:e.children})}function zi(e,t,n){return t.options.notFoundComponent?(0,F.jsx)(t.options.notFoundComponent,{...n}):e.options.defaultNotFoundComponent?(0,F.jsx)(e.options.defaultNotFoundComponent,{...n}):(0,F.jsx)(Li,{})}var Bi=P.memo(function({matchId:e}){let t=Mr(),n=t.stores.matchStores.get(e);n||gt();let r=ai(t.stores.loadedAt,e=>e),i=ai(n,e=>e);return(0,F.jsx)(Vi,{router:t,matchId:e,resetKey:r,matchState:P.useMemo(()=>{let e=i.routeId,n=t.routesById[e].parentRoute?.id;return{routeId:e,ssr:i.ssr,_displayPending:i._displayPending,parentRouteId:n}},[i._displayPending,i.routeId,i.ssr,t.routesById])})});function Vi({router:e,matchId:t,resetKey:n,matchState:r}){let i=e.routesById[r.routeId],a=i.options.pendingComponent??e.options.defaultPendingComponent,o=a?(0,F.jsx)(a,{}):null,s=i.options.errorComponent??e.options.defaultErrorComponent,c=i.options.onCatch??e.options.defaultOnCatch,l=i.isRoot?i.options.notFoundComponent??e.options.notFoundRoute?.options.component:i.options.notFoundComponent,u=r.ssr===!1||r.ssr===`data-only`,d=(!i.isRoot||i.options.wrapInSuspense||u)&&(i.options.wrapInSuspense??a??(i.options.errorComponent?.preload||u))?P.Suspense:Ri,f=s?Tr:Ri,p=l?Ii:Ri;return(0,F.jsxs)(i.isRoot?i.options.shellComponent??Ri:Ri,{children:[(0,F.jsx)(Nr.Provider,{value:t,children:(0,F.jsx)(d,{fallback:o,children:(0,F.jsx)(f,{getResetKey:()=>n,errorComponent:s||Dr,onCatch:(e,t)=>{if(en(e))throw e.routeId??=r.routeId,e;c?.(e,t)},children:(0,F.jsx)(p,{fallback:e=>{if(e.routeId??=r.routeId,!l||e.routeId&&e.routeId!==r.routeId||!e.routeId&&!i.isRoot)throw e;return P.createElement(l,e)},children:u||r._displayPending?(0,F.jsx)(Or,{fallback:o,children:(0,F.jsx)(Ui,{matchId:t})}):(0,F.jsx)(Ui,{matchId:t})})})})}),r.parentRouteId===`__root__`?(0,F.jsxs)(F.Fragment,{children:[(0,F.jsx)(Hi,{resetKey:n}),(e.options.scrollRestoration,null)]}):null]})}function Hi({resetKey:e}){let t=Mr(),n=P.useRef(void 0);return ze(()=>{let e=t.latestLocation.href;(n.current===void 0||n.current!==e)&&(t.emit({type:`onRendered`,...or(t.stores.location.get(),t.stores.resolvedLocation.get())}),n.current=e)},[t.latestLocation.state.__TSR_key,e,t]),null}var Ui=P.memo(function({matchId:e}){let t=Mr(),n=(e,n)=>t.getMatch(e.id)?._nonReactive[n]??e._nonReactive[n],r=t.stores.matchStores.get(e);r||gt();let i=ai(r,e=>e),a=i.routeId,o=t.routesById[a],s=P.useMemo(()=>{let e=(t.routesById[a].options.remountDeps??t.options.defaultRemountDeps)?.({routeId:a,loaderDeps:i.loaderDeps,params:i._strictParams,search:i._strictSearch});return e?JSON.stringify(e):void 0},[a,i.loaderDeps,i._strictParams,i._strictSearch,t.options.defaultRemountDeps,t.routesById]),c=P.useMemo(()=>{let e=o.options.component??t.options.defaultComponent;return e?(0,F.jsx)(e,{},s):(0,F.jsx)(Wi,{})},[s,o.options.component,t.options.defaultComponent]);if(i._displayPending)throw n(i,`displayPendingPromise`);if(i._forcePending)throw n(i,`minPendingPromise`);if(i.status===`pending`){let e=o.options.pendingMinMs??t.options.defaultPendingMinMs;if(e){let n=t.getMatch(i.id);if(n&&!n._nonReactive.minPendingPromise){let t=rt();n._nonReactive.minPendingPromise=t,setTimeout(()=>{t.resolve(),n._nonReactive.minPendingPromise=void 0},e)}}throw n(i,`loadPromise`)}if(i.status===`notFound`)return en(i.error)||gt(),zi(t,o,i.error);if(i.status===`redirected`)throw xn(i.error)||gt(),n(i,`loadPromise`);if(i.status===`error`)throw i.error;return c}),Wi=P.memo(function(){let e=Mr(),t=P.useContext(Nr),n,r=!1,i;{let a=t?e.stores.matchStores.get(t):void 0;[n,r]=ai(a,e=>[e?.routeId,e?.globalNotFound??!1]),i=ai(e.stores.matchesId,e=>e[e.findIndex(e=>e===t)+1])}let a=n?e.routesById[n]:void 0,o=e.options.defaultPendingComponent?(0,F.jsx)(e.options.defaultPendingComponent,{}):null;if(r)return a||gt(),zi(e,a,void 0);if(!i)return null;let s=(0,F.jsx)(Bi,{matchId:i});return n===`__root__`?(0,F.jsx)(P.Suspense,{fallback:o,children:s}):s});function Gi(){let e=Mr(),t=P.useRef({router:e,mounted:!1}),[n,r]=P.useState(!1),i=ai(e.stores.isLoading,e=>e),a=ai(e.stores.hasPending,e=>e),o=Be(i),s=i||n||a,c=Be(s),l=i||a,u=Be(l);return e.startTransition=e=>{r(!0),P.startTransition(()=>{e(),r(!1)})},P.useEffect(()=>{let t=e.history.subscribe(e.load),n=e.buildLocation({to:e.latestLocation.pathname,search:!0,params:!0,hash:!0,state:!0,_includeValidateSearch:!0});return Gt(e.latestLocation.publicHref)!==Gt(n.publicHref)&&e.commitLocation({...n,replace:!0}),()=>{t()}},[e,e.history]),ze(()=>{typeof window<`u`&&e.ssr||t.current.router===e&&t.current.mounted||(t.current={router:e,mounted:!0},(async()=>{try{await e.load()}catch(e){console.error(e)}})())},[e]),ze(()=>{o&&!i&&e.emit({type:`onLoad`,...or(e.stores.location.get(),e.stores.resolvedLocation.get())})},[o,e,i]),ze(()=>{u&&!l&&e.emit({type:`onBeforeRouteMount`,...or(e.stores.location.get(),e.stores.resolvedLocation.get())})},[l,u,e]),ze(()=>{if(c&&!s){let t=or(e.stores.location.get(),e.stores.resolvedLocation.get());e.emit({type:`onResolved`,...t}),Yr(()=>{e.stores.status.set(`idle`),e.stores.resolvedLocation.set(e.stores.location.get())}),t.hrefChanged&&wr(e)}},[s,c,e]),null}function Ki(){let e=Mr(),t=e.routesById.__root__.options.pendingComponent??e.options.defaultPendingComponent,n=t?(0,F.jsx)(t,{}):null,r=(0,F.jsxs)(typeof document<`u`&&e.ssr?Ri:P.Suspense,{fallback:n,children:[(0,F.jsx)(Gi,{}),(0,F.jsx)(qi,{})]});return e.options.InnerWrap?(0,F.jsx)(e.options.InnerWrap,{children:r}):r}function qi(){let e=Mr(),t=ai(e.stores.firstId,e=>e),n=ai(e.stores.loadedAt,e=>e),r=t?(0,F.jsx)(Bi,{matchId:t}):null;return(0,F.jsx)(Nr.Provider,{value:t,children:e.options.disableGlobalCatchBoundary?r:(0,F.jsx)(Tr,{getResetKey:()=>n,errorComponent:Dr,onCatch:void 0,children:r})})}var Ji=e=>({createMutableStore:Qr,createReadonlyStore:Qr,batch:Yr}),Yi=e=>new Xi(e),Xi=class extends sr{constructor(e){super(e,Ji)}};function Zi({router:e,children:t,...n}){Je(n)&&e.update({...e.options,...n,context:{...e.options.context,...n.context}});let r=(0,F.jsx)(jr.Provider,{value:e,children:t});return e.options.Wrap?(0,F.jsx)(e.options.Wrap,{children:r}):r}function Qi({router:e,...t}){return(0,F.jsx)(Zi,{router:e,...t,children:(0,F.jsx)(Ki,{})})}function $i(e){let t=Mr(),n=(0,P.useRef)(void 0);return ai(t.stores.location,r=>{let i=e?.select?e.select(r):r;if(e?.structuralSharing??t.options.defaultStructuralSharing){let e=Ze(n.current,i);return n.current=e,e}return i})}function ea(e){let{attrs:t,children:n,nonce:r}=e;switch(e.tag){case`title`:return(0,F.jsx)(`title`,{...t,suppressHydrationWarning:!0,children:n});case`meta`:return(0,F.jsx)(`meta`,{...t,suppressHydrationWarning:!0});case`link`:return(0,F.jsx)(`link`,{...t,precedence:t?.precedence??(t?.rel===`stylesheet`?`default`:void 0),nonce:r,suppressHydrationWarning:!0});case`style`:return e.inlineCss,(0,F.jsx)(`style`,{...t,dangerouslySetInnerHTML:{__html:n},nonce:r});case`script`:return(0,F.jsx)(ta,{attrs:t,children:n});default:return null}}function ta({attrs:e,children:t}){Mr();let n=kr(),r=typeof e?.type==`string`&&e.type!==``&&e.type!==`text/javascript`&&e.type!==`module`;if(P.useEffect(()=>{if(!r){if(e?.src){let t=(()=>{try{let t=document.baseURI||window.location.href;return new URL(e.src,t).href}catch{return e.src}})();if(Array.from(document.querySelectorAll(`script[src]`)).find(e=>e.src===t))return;let n=document.createElement(`script`);for(let[t,r]of Object.entries(e))t!==`suppressHydrationWarning`&&r!==void 0&&r!==!1&&n.setAttribute(t,typeof r==`boolean`?``:String(r));return document.head.appendChild(n),()=>{n.parentNode&&n.parentNode.removeChild(n)}}if(typeof t==`string`){let n=typeof e?.type==`string`?e.type:`text/javascript`,r=typeof e?.nonce==`string`?e.nonce:void 0;if(Array.from(document.querySelectorAll(`script:not([src])`)).find(e=>{if(!(e instanceof HTMLScriptElement))return!1;let i=e.getAttribute(`type`)??`text/javascript`,a=e.getAttribute(`nonce`)??void 0;return e.textContent===t&&i===n&&a===r}))return;let i=document.createElement(`script`);if(i.textContent=t,e)for(let[t,n]of Object.entries(e))t!==`suppressHydrationWarning`&&n!==void 0&&n!==!1&&i.setAttribute(t,typeof n==`boolean`?``:String(n));return document.head.appendChild(i),()=>{i.parentNode&&i.parentNode.removeChild(i)}}}},[e,t,r]),r&&typeof t==`string`)return(0,F.jsx)(`script`,{...e,suppressHydrationWarning:!0,dangerouslySetInnerHTML:{__html:t}});if(!n){if(e?.src)return(0,F.jsx)(`script`,{...e,suppressHydrationWarning:!0});if(typeof t==`string`)return(0,F.jsx)(`script`,{...e,dangerouslySetInnerHTML:{__html:t},suppressHydrationWarning:!0})}return null}var na=e=>{let t=Mr(),n=t.options.ssr?.nonce,r=ai(t.stores.matches,e=>e.map(e=>e.meta).filter(Boolean),nt),i=P.useMemo(()=>{let e=[],t={},i;for(let a=r.length-1;a>=0;a--){let o=r[a];for(let r=o.length-1;r>=0;r--){let a=o[r];if(a)if(a.title)i||={tag:`title`,children:a.title};else if(`script:ld+json`in a)try{let t=JSON.stringify(a[`script:ld+json`]);e.push({tag:`script`,attrs:{type:`application/ld+json`},children:ft(t)})}catch{}else{let r=a.name??a.property;if(r){if(t[r])continue;t[r]=!0}e.push({tag:`meta`,attrs:{...a,nonce:n}})}}}return i&&e.push(i),n&&e.push({tag:`meta`,attrs:{property:`csp-nonce`,content:n}}),e.reverse(),e},[r,n]),a=ai(t.stores.matches,r=>{let i=r.map(e=>e.links).filter(Boolean).flat(1).map(e=>({tag:`link`,attrs:{...e,nonce:n}})),a=t.ssr?.manifest,o=r.map(e=>a?.routes[e.routeId]?.assets??[]).filter(Boolean).flat(1).flatMap(t=>t.tag===`link`?xr(a,t)?[]:[{tag:`link`,attrs:{...t.attrs,crossOrigin:vr(e,`stylesheet`)??t.attrs?.crossOrigin,suppressHydrationWarning:!0,nonce:n}}]:t.tag===`style`?[{tag:`style`,attrs:{...t.attrs,nonce:n},children:t.children,...t.inlineCss?{inlineCss:!0}:{}}]:[]);return[...i,...o]},nt),o=ai(t.stores.matches,r=>{let i=[];return r.map(e=>t.looseRoutesById[e.routeId]).forEach(r=>t.ssr?.manifest?.routes[r.id]?.preloads?.filter(Boolean).forEach(t=>{let r=yr(t);i.push({tag:`link`,attrs:{rel:`modulepreload`,href:r.href,crossOrigin:vr(e,`modulepreload`)??r.crossOrigin,nonce:n}})})),i},nt),s=ai(t.stores.matches,e=>e.map(e=>e.styles).flat(1).filter(Boolean).map(({children:e,...t})=>({tag:`style`,attrs:{...t,nonce:n},children:e})),nt),c=ai(t.stores.matches,e=>e.map(e=>e.headScripts).flat(1).filter(Boolean).map(({children:e,...t})=>({tag:`script`,attrs:{...t,nonce:n},children:e})),nt);return ra([...i,...o,...a,...s,...c],e=>JSON.stringify(e))};function ra(e,t){let n=new Set;return e.filter(e=>{let r=t(e);return n.has(r)?!1:(n.add(r),!0)})}function ia(e){let t=na(e.assetCrossOrigin),n=Mr().options.ssr?.nonce;return(0,F.jsx)(F.Fragment,{children:t.map(e=>(0,P.createElement)(ea,{...e,key:`tsr-meta-${JSON.stringify(e)}`,nonce:n}))})}var aa=o((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(e.unstable_now=void 0,typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=!1,_=typeof setTimeout==`function`?setTimeout:null,v=typeof clearTimeout==`function`?clearTimeout:null,y=typeof setImmediate<`u`?setImmediate:null;function b(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function x(e){if(h=!1,b(e),!m)if(n(c)!==null)m=!0,S||(S=!0,D());else{var t=n(l);t!==null&&ne(x,t.startTime-e)}}var S=!1,C=-1,w=5,T=-1;function E(){return g?!0:!(e.unstable_now()-Tt&&E());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=t);if(t=e.unstable_now(),typeof s==`function`){d.callback=s,b(t),i=!0;break b}d===n(c)&&r(c),b(t)}else r(c);d=n(c)}if(d!==null)i=!0;else{var u=n(l);u!==null&&ne(x,u.startTime-t),i=!1}}break a}finally{d=null,f=a,p=!1}i=void 0}}finally{i?D():S=!1}}}var D;if(typeof y==`function`)D=function(){y(ee)};else if(typeof MessageChannel<`u`){var O=new MessageChannel,te=O.port2;O.port1.onmessage=ee,D=function(){te.postMessage(null)}}else D=function(){_(ee,0)};function ne(t,n){C=_(function(){t(e.unstable_now())},n)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(e){e.callback=null},e.unstable_forceFrameRate=function(e){0>e||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(v(C),C=-1):h=!0,ne(x,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,S||(S=!0,D()))),r},e.unstable_shouldYield=E,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),eee=o(((e,t)=>{t.exports=aa()})),oa=o((e=>{var t=eee(),n=je(),r=hi();function i(e){var t=`https://react.dev/errors/`+e;if(1ae||(e.current=j[ae],j[ae]=null,ae--)}function ce(e,t){ae++,j[ae]=e.current,e.current=t}var M=oe(null),le=oe(null),ue=oe(null),N=oe(null);function de(e,t){switch(ce(ue,t),ce(le,e),ce(M,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?ef(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=ef(t),e=tf(t,e);else switch(e){case`svg`:e=1;break;case`math`:e=2;break;default:e=0}}se(M),ce(M,e)}function fe(){se(M),se(le),se(ue)}function pe(e){e.memoizedState!==null&&ce(N,e);var t=M.current,n=tf(t,e.type);t!==n&&(ce(le,e),ce(M,n))}function me(e){le.current===e&&(se(M),se(le)),N.current===e&&(se(N),dp._currentValue=ie)}var he,ge;function _e(e){if(he===void 0)try{throw Error()}catch(e){var t=e.stack.trim().match(/\n( *(at )?)/);he=t&&t[1]||``,ge=-1)`:-1i||c[r]!==l[i]){var u=` `+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(``)&&(u=u.replace(``,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{ve=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?_e(n):``}function be(e,t){switch(e.tag){case 26:case 27:case 5:return _e(e.type);case 16:return _e(`Lazy`);case 13:return e.child!==t&&t!==null?_e(`Suspense Fallback`):_e(`Suspense`);case 19:return _e(`SuspenseList`);case 0:case 15:return ye(e.type,!1);case 11:return ye(e.type.render,!1);case 1:return ye(e.type,!0);case 31:return _e(`Activity`);default:return``}}function xe(e){try{var t=``,n=null;do t+=be(e,n),n=e,e=e.return;while(e);return t}catch(e){return` Error generating stack: `+e.message+` -`+e.stack}}var Se=Object.prototype.hasOwnProperty,Ce=t.unstable_scheduleCallback,we=t.unstable_cancelCallback,Te=t.unstable_shouldYield,Ee=t.unstable_requestPaint,De=t.unstable_now,Oe=t.unstable_getCurrentPriorityLevel,ke=t.unstable_ImmediatePriority,Ae=t.unstable_UserBlockingPriority,Me=t.unstable_NormalPriority,Ne=t.unstable_LowPriority,P=t.unstable_IdlePriority,F=t.log,Pe=t.unstable_setDisableYieldValue,Fe=null,Ie=null;function Le(e){if(typeof F==`function`&&Pe(e),Ie&&typeof Ie.setStrictMode==`function`)try{Ie.setStrictMode(Fe,e)}catch{}}var Re=Math.clz32?Math.clz32:Ve,ze=Math.log,Be=Math.LN2;function Ve(e){return e>>>=0,e===0?32:31-(ze(e)/Be|0)|0}var He=256,Ue=262144,We=4194304;function Ge(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Ke(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=Ge(n))):i=Ge(o):i=Ge(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=Ge(n))):i=Ge(o)):i=Ge(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function qe(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Je(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Ye(){var e=We;return We<<=1,!(We&62914560)&&(We=4194304),e}function Xe(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function Ze(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Qe(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0`u`||window.document===void 0||window.document.createElement===void 0),dn=!1;if(un)try{var fn={};Object.defineProperty(fn,`passive`,{get:function(){dn=!0}}),window.addEventListener(`test`,fn,fn),window.removeEventListener(`test`,fn,fn)}catch{dn=!1}var pn=null,mn=null,hn=null;function gn(){if(hn)return hn;var e,t=mn,n=t.length,r,i=`value`in pn?pn.value:pn.textContent,a=i.length;for(e=0;e=Jn),Zn=` `,Qn=!1;function $n(e,t){switch(e){case`keyup`:return Kn.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function er(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var tr=!1;function nr(e,t){switch(e){case`compositionend`:return er(t);case`keypress`:return t.which===32?(Qn=!0,Zn):null;case`textInput`:return e=t.data,e===Zn&&Qn?null:e;default:return null}}function rr(e,t){if(tr)return e===`compositionend`||!qn&&$n(e,t)?(e=gn(),hn=mn=pn=null,tr=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=Tr(n)}}function Dr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Dr(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Or(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Lt(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=Lt(e.document)}return t}function kr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}var Ar=un&&`documentMode`in document&&11>=document.documentMode,jr=null,Mr=null,Nr=null,Pr=!1;function Fr(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Pr||jr==null||jr!==Lt(r)||(r=jr,`selectionStart`in r&&kr(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Nr&&wr(Nr,r)||(Nr=r,r=zd(Mr,`onSelect`),0>=o,i-=o,Oi=1<<32-Re(t)+i|n<m?(h=d,d=null):h=d.sibling;var g=p(i,d,s[m],c);if(g===null){d===null&&(d=h);break}e&&d&&g.alternate===null&&t(i,d),a=o(g,a,m),u===null?l=g:u.sibling=g,u=g,d=h}if(m===s.length)return n(i,d),L&&Ai(i,m),l;if(d===null){for(;mh?(g=m,m=null):g=m.sibling;var y=p(a,m,v.value,l);if(y===null){m===null&&(m=g);break}e&&m&&y.alternate===null&&t(a,m),s=o(y,s,h),d===null?u=y:d.sibling=y,d=y,m=g}if(v.done)return n(a,m),L&&Ai(a,h),u;if(m===null){for(;!v.done;h++,v=c.next())v=f(a,v.value,l),v!==null&&(s=o(v,s,h),d===null?u=v:d.sibling=v,d=v);return L&&Ai(a,h),u}for(m=r(m);!v.done;h++,v=c.next())v=_(m,a,h,v.value,l),v!==null&&(e&&v.alternate!==null&&m.delete(v.key===null?h:v.key),s=o(v,s,h),d===null?u=v:d.sibling=v,d=v);return e&&m.forEach(function(e){return t(a,e)}),L&&Ai(a,h),u}function x(e,r,o,c){if(typeof o==`object`&&o&&o.type===g&&o.key===null&&(o=o.props.children),typeof o==`object`&&o){switch(o.$$typeof){case m:a:{for(var l=o.key;r!==null;){if(r.key===l){if(l=o.type,l===g){if(r.tag===7){n(e,r.sibling),c=a(r,o.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===T&&Aa(l)===r.type){n(e,r.sibling),c=a(r,o.props),La(c,o),c.return=e,e=c;break a}n(e,r);break}else t(e,r);r=r.sibling}o.type===g?(c=mi(o.props.children,e.mode,c,o.key),c.return=e,e=c):(c=pi(o.type,o.key,o.props,null,e.mode,c),La(c,o),c.return=e,e=c)}return s(e);case h:a:{for(l=o.key;r!==null;){if(r.key===l)if(r.tag===4&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),c=a(r,o.children||[]),c.return=e,e=c;break a}else{n(e,r);break}else t(e,r);r=r.sibling}c=vi(o,e.mode,c),c.return=e,e=c}return s(e);case T:return o=Aa(o),x(e,r,o,c)}if(re(o))return v(e,r,o,c);if(O(o)){if(l=O(o),typeof l!=`function`)throw Error(i(150));return o=l.call(o),y(e,r,o,c)}if(typeof o.then==`function`)return x(e,r,Ia(o),c);if(o.$$typeof===b)return x(e,r,ra(e,o),c);Ra(e,o)}return typeof o==`string`&&o!==``||typeof o==`number`||typeof o==`bigint`?(o=``+o,r!==null&&r.tag===6?(n(e,r.sibling),c=a(r,o),c.return=e,e=c):(n(e,r),c=gi(o,e.mode,c),c.return=e,e=c),s(e)):n(e,r)}return function(e,t,n,r){try{Fa=0;var i=x(e,t,n,r);return Pa=null,i}catch(t){if(t===wa||t===Ea)throw t;var a=li(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var Ba=za(!0),Va=za(!1),Ha=!1;function Ua(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Wa(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ga(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Ka(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,Gl&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=oi(e),ai(e,null,n),t}return ni(e,r,t,n),oi(e)}function qa(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,et(e,n)}}function Ja(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var Ya=!1;function Xa(){if(Ya){var e=ha;if(e!==null)throw e}}function Za(e,t,n,r){Ya=!1;var i=e.updateQueue;Ha=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var p=s.lane&-536870913,m=p!==s.lane;if(m?(Jl&p)===p:(r&p)===p){p!==0&&p===ma&&(Ya=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var h=e,g=s;p=t;var _=n;switch(g.tag){case 1:if(h=g.payload,typeof h==`function`){d=h.call(_,d,p);break a}d=h;break a;case 3:h.flags=h.flags&-65537|128;case 0:if(h=g.payload,p=typeof h==`function`?h.call(_,d,p):h,p==null)break a;d=f({},d,p);break a;case 2:Ha=!0}}p=s.callback,p!==null&&(e.flags|=64,m&&(e.flags|=8192),m=i.callbacks,m===null?i.callbacks=[p]:m.push(p))}else m={lane:p,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=m,c=d):u=u.next=m,o|=p;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;m=s,s=m.next,m.next=null,i.lastBaseUpdate=m,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),nu|=o,e.lanes=o,e.memoizedState=d}}function Qa(e,t){if(typeof e!=`function`)throw Error(i(191,e));e.call(t)}function $a(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;ea?a:8;var o=k.T,s={};k.T=s,Bs(e,!1,t,n);try{var c=i(),l=k.S;l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`?zs(e,t,va(c,r),wu(e)):zs(e,t,r,wu(e))}catch(n){zs(e,t,{then:function(){},status:`rejected`,reason:n},wu())}finally{A.p=a,o!==null&&s.types!==null&&(o.types=s.types),k.T=o}}function ks(){}function As(e,t,n,r){if(e.tag!==5)throw Error(i(476));var a=js(e).queue;Os(e,a,t,ie,n===null?ks:function(){return Ms(e),n(r)})}function js(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:ie,baseState:ie,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Vo,lastRenderedState:ie},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Vo,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function Ms(e){var t=js(e);t.next===null&&(t=e.alternate.memoizedState),zs(e,t.next.queue,{},wu())}function Ns(){return na(fp)}function Ps(){return Io().memoizedState}function Fs(){return Io().memoizedState}function Is(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=wu();e=Ga(n);var r=Ka(t,e,n);r!==null&&(Eu(r,t,n),qa(r,t,n)),t={cache:ua()},e.payload=t;return}t=t.return}}function Ls(e,t,n){var r=wu();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},Vs(e)?Hs(t,n):(n=ri(e,t,n,r),n!==null&&(Eu(n,e,r),Us(n,t,r)))}function Rs(e,t,n){zs(e,t,n,wu())}function zs(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(Vs(e))Hs(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,Cr(s,o))return ni(e,t,i,0),Kl===null&&ti(),!1}catch{}if(n=ri(e,t,i,r),n!==null)return Eu(n,e,r),Us(n,t,r),!0}return!1}function Bs(e,t,n,r){if(r={lane:2,revertLane:Cd(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},Vs(e)){if(t)throw Error(i(479))}else t=ri(e,n,r,2),t!==null&&Eu(t,e,2)}function Vs(e){var t=e.alternate;return e===go||t!==null&&t===go}function Hs(e,t){bo=yo=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Us(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,et(e,n)}}var Ws={readContext:na,use:zo,useCallback:Eo,useContext:Eo,useEffect:Eo,useImperativeHandle:Eo,useLayoutEffect:Eo,useInsertionEffect:Eo,useMemo:Eo,useReducer:Eo,useRef:Eo,useState:Eo,useDebugValue:Eo,useDeferredValue:Eo,useTransition:Eo,useSyncExternalStore:Eo,useId:Eo,useHostTransitionStatus:Eo,useFormState:Eo,useActionState:Eo,useOptimistic:Eo,useMemoCache:Eo,useCacheRefresh:Eo};Ws.useEffectEvent=Eo;var Gs={readContext:na,use:zo,useCallback:function(e,t){return Fo().memoizedState=[e,t===void 0?null:t],e},useContext:na,useEffect:hs,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),ps(4194308,4,xs.bind(null,t,e),n)},useLayoutEffect:function(e,t){return ps(4194308,4,e,t)},useInsertionEffect:function(e,t){ps(4,2,e,t)},useMemo:function(e,t){var n=Fo();t=t===void 0?null:t;var r=e();if(xo){Le(!0);try{e()}finally{Le(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=Fo();if(n!==void 0){var i=n(t);if(xo){Le(!0);try{n(t)}finally{Le(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=Ls.bind(null,go,e),[r.memoizedState,e]},useRef:function(e){var t=Fo();return e={current:e},t.memoizedState=e},useState:function(e){e=Zo(e);var t=e.queue,n=Rs.bind(null,go,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:Cs,useDeferredValue:function(e,t){return Es(Fo(),e,t)},useTransition:function(){var e=Zo(!1);return e=Os.bind(null,go,e.queue,!0,!1),Fo().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=go,a=Fo();if(L){if(n===void 0)throw Error(i(407));n=n()}else{if(n=t(),Kl===null)throw Error(i(349));Jl&127||Ko(r,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,hs(Jo.bind(null,r,o,e),[e]),r.flags|=2048,ds(9,{destroy:void 0},qo.bind(null,r,o,n,t),null),n},useId:function(){var e=Fo(),t=Kl.identifierPrefix;if(L){var n=ki,r=Oi;n=(r&~(1<<32-Re(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=So++,0<\/script>`,o=o.removeChild(o.firstChild);break;case`select`:o=typeof r.is==`string`?s.createElement(`select`,{is:r.is}):s.createElement(`select`),r.multiple?o.multiple=!0:r.size&&(o.size=r.size);break;default:o=typeof r.is==`string`?s.createElement(a,{is:r.is}):s.createElement(a)}}o[st]=t,o[ct]=r;a:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)o.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break a;for(;s.sibling===null;){if(s.return===null||s.return===t)break a;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=o;a:switch(Jd(o,a,r),a){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&Lc(t)}}return Hc(t),Rc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Lc(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(i(166));if(e=ue.current,Hi(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,a=I,a!==null)switch(a.tag){case 27:case 5:r=a.memoizedProps}e[st]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||Gd(e.nodeValue,n)),e||zi(t,!0)}else e=ef(e).createTextNode(r),e[st]=t,t.stateNode=e}return Hc(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=Hi(t),n!==null){if(e===null){if(!r)throw Error(i(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(i(557));e[st]=t}else Ui(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Hc(t),e=!1}else n=Wi(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?(fo(t),t):(fo(t),null);if(t.flags&128)throw Error(i(558))}return Hc(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(a=Hi(t),r!==null&&r.dehydrated!==null){if(e===null){if(!a)throw Error(i(318));if(a=t.memoizedState,a=a===null?null:a.dehydrated,!a)throw Error(i(317));a[st]=t}else Ui(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Hc(t),a=!1}else a=Wi(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=a),a=!0;if(!a)return t.flags&256?(fo(t),t):(fo(t),null)}return fo(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,a=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(a=r.alternate.memoizedState.cachePool.pool),o=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(o=r.memoizedState.cachePool.pool),o!==a&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),Bc(t,t.updateQueue),Hc(t),null);case 4:return fe(),e===null&&Fd(t.stateNode.containerInfo),Hc(t),null;case 10:return Xi(t.type),Hc(t),null;case 19:if(se(po),r=t.memoizedState,r===null)return Hc(t),null;if(a=(t.flags&128)!=0,o=r.rendering,o===null)if(a)Vc(r,!1);else{if(tu!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(o=mo(e),o!==null){for(t.flags|=128,Vc(r,!1),e=o.updateQueue,t.updateQueue=e,Bc(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)fi(n,e),n=n.sibling;return ce(po,po.current&1|2),L&&Ai(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&De()>fu&&(t.flags|=128,a=!0,Vc(r,!1),t.lanes=4194304)}else{if(!a)if(e=mo(o),e!==null){if(t.flags|=128,a=!0,e=e.updateQueue,t.updateQueue=e,Bc(t,e),Vc(r,!0),r.tail===null&&r.tailMode===`hidden`&&!o.alternate&&!L)return Hc(t),null}else 2*De()-r.renderingStartTime>fu&&n!==536870912&&(t.flags|=128,a=!0,Vc(r,!1),t.lanes=4194304);r.isBackwards?(o.sibling=t.child,t.child=o):(e=r.last,e===null?t.child=o:e.sibling=o,r.last=o)}return r.tail===null?(Hc(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=De(),e.sibling=null,n=po.current,ce(po,a?n&1|2:n&1),L&&Ai(t,r.treeForkCount),e);case 22:case 23:return fo(t),io(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(Hc(t),t.subtreeFlags&6&&(t.flags|=8192)):Hc(t),n=t.updateQueue,n!==null&&Bc(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&se(ba),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),Xi(la),Hc(t),null;case 25:return null;case 30:return null}throw Error(i(156,t.tag))}function Wc(e,t){switch(Ni(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Xi(la),fe(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return me(t),null;case 31:if(t.memoizedState!==null){if(fo(t),t.alternate===null)throw Error(i(340));Ui()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(fo(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(i(340));Ui()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return se(po),null;case 4:return fe(),null;case 10:return Xi(t.type),null;case 22:case 23:return fo(t),io(),e!==null&&se(ba),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Xi(la),null;case 25:return null;default:return null}}function Gc(e,t){switch(Ni(t),t.tag){case 3:Xi(la),fe();break;case 26:case 27:case 5:me(t);break;case 4:fe();break;case 31:t.memoizedState!==null&&fo(t);break;case 13:fo(t);break;case 19:se(po);break;case 10:Xi(t.type);break;case 22:case 23:fo(t),io(),e!==null&&se(ba);break;case 24:Xi(la)}}function Kc(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){nd(t,t.return,e)}}function qc(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){nd(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){nd(t,t.return,e)}}function Jc(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{$a(t,n)}catch(t){nd(e,e.return,t)}}}function Yc(e,t,n){n.props=Qs(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){nd(e,t,n)}}function Xc(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){nd(e,t,n)}}function Zc(e,t){var n=e.ref,r=e.refCleanup;if(n!==null)if(typeof r==`function`)try{r()}catch(n){nd(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){nd(e,t,n)}else n.current=null}function Qc(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){nd(e,e.return,t)}}function $c(e,t,n){try{var r=e.stateNode;Yd(r,e.type,n,t),r[ct]=t}catch(t){nd(e,e.return,t)}}function el(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&ff(e.type)||e.tag===4}function tl(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||el(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&ff(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function nl(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=en));else if(r!==4&&(r===27&&ff(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for(nl(e,t,n),e=e.sibling;e!==null;)nl(e,t,n),e=e.sibling}function rl(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&ff(e.type)&&(n=e.stateNode),e=e.child,e!==null))for(rl(e,t,n),e=e.sibling;e!==null;)rl(e,t,n),e=e.sibling}function il(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);Jd(t,r,n),t[st]=e,t[ct]=n}catch(t){nd(e,e.return,t)}}var al=!1,ol=!1,sl=!1,cl=typeof WeakSet==`function`?WeakSet:Set,ll=null;function ul(e,t){if(e=e.containerInfo,Qd=xp,e=Or(e),kr(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var a=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||a!==0&&f.nodeType!==3||(c=s+a),f!==o||r!==0&&f.nodeType!==3||(l=s+r),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===a&&(c=s),p===o&&++d===r&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for($d={focusedElem:e,selectionRange:n},xp=!1,ll=t;ll!==null;)if(t=ll,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,ll=e;else for(;ll!==null;){switch(t=ll,o=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n title`))),Jd(o,r,n),o[st]=e,bt(o),r=o;break a;case`link`:var s=tp(`link`,`href`,a).get(r+(n.href||``));if(s){for(var c=0;cg&&(o=g,g=h,h=o);var _=Er(s,h),v=Er(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;sn?32:n,k.T=null,n=bu,bu=null;var o=gu,s=vu;if(hu=0,_u=gu=null,vu=0,Gl&6)throw Error(i(331));var c=Gl;if(Gl|=4,Bl(o.current),Ml(o,o.current,s,n),Gl=c,gd(0,!1),Ie&&typeof Ie.onPostCommitFiberRoot==`function`)try{Ie.onPostCommitFiberRoot(Fe,o)}catch{}return!0}finally{A.p=a,k.T=r,Qu(e,t)}}function td(e,t,n){t=bi(n,t),t=ic(e.stateNode,t,2),e=Ka(e,t,2),e!==null&&(Ze(e,2),hd(e))}function nd(e,t,n){if(e.tag===3)td(e,e,n);else for(;t!==null;){if(t.tag===3){td(t,e,n);break}else if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(mu===null||!mu.has(r))){e=bi(n,e),n=ac(2),r=Ka(t,n,2),r!==null&&(oc(n,r,t,e),Ze(r,2),hd(r));break}}t=t.return}}function rd(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new Wl;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||($l=!0,i.add(n),e=id.bind(null,e,t,n),t.then(e,e))}function id(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,Kl===e&&(Jl&n)===n&&(tu===4||tu===3&&(Jl&62914560)===Jl&&300>De()-uu?!(Gl&2)&&Nu(e,0):iu|=n,ou===Jl&&(ou=0)),hd(e)}function ad(e,t){t===0&&(t=Ye()),e=ii(e,t),e!==null&&(Ze(e,t),hd(e))}function od(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),ad(e,n)}function sd(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(i(314))}r!==null&&r.delete(t),ad(e,n)}function cd(e,t){return Ce(e,t)}var ld=null,ud=null,dd=!1,fd=!1,pd=!1,md=0;function hd(e){e!==ud&&e.next===null&&(ud===null?ld=ud=e:ud=ud.next=e),fd=!0,dd||(dd=!0,Sd())}function gd(e,t){if(!pd&&fd){pd=!0;do for(var n=!1,r=ld;r!==null;){if(!t)if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-Re(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,xd(r,a))}else a=Jl,a=Ke(r,r===Kl?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||qe(r,a)||(n=!0,xd(r,a));r=r.next}while(n);pd=!1}}function _d(){vd()}function vd(){fd=dd=!1;var e=0;md!==0&&of()&&(e=md);for(var t=De(),n=null,r=ld;r!==null;){var i=r.next,a=yd(r,t);a===0?(r.next=null,n===null?ld=i:n.next=i,i===null&&(ud=n)):(n=r,(e!==0||a&3)&&(fd=!0)),r=i}hu!==0&&hu!==5||gd(e,!1),md!==0&&(md=0)}function yd(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0s)break;var u=c.transferSize,d=c.initiatorType;u&&Xd(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function Ff(e,t,n){var r=Pf;if(r&&typeof t==`string`&&t){var i=zt(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),kf.has(i)||(kf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Jd(t,`link`,e),bt(t),r.head.appendChild(t)))}}function If(e){jf.D(e),Ff(`dns-prefetch`,e,null)}function Lf(e,t){jf.C(e,t),Ff(`preconnect`,e,t)}function Rf(e,t,n){jf.L(e,t,n);var r=Pf;if(r&&e&&t){var i=`link[rel="preload"][as="`+zt(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+zt(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+zt(n.imageSizes)+`"]`)):i+=`[href="`+zt(e)+`"]`;var a=i;switch(t){case`style`:a=Wf(e);break;case`script`:a=Jf(e)}Of.has(a)||(e=f({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),Of.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(Gf(a))||t===`script`&&r.querySelector(Yf(a))||(t=r.createElement(`link`),Jd(t,`link`,e),bt(t),r.head.appendChild(t)))}}function zf(e,t){jf.m(e,t);var n=Pf;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+zt(r)+`"][href="`+zt(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=Jf(e)}if(!Of.has(a)&&(e=f({rel:`modulepreload`,href:e},t),Of.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Yf(a)))return}r=n.createElement(`link`),Jd(r,`link`,e),bt(r),n.head.appendChild(r)}}}function Bf(e,t,n){jf.S(e,t,n);var r=Pf;if(r&&e){var i=yt(r).hoistableStyles,a=Wf(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(Gf(a)))s.loading=5;else{e=f({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=Of.get(a))&&Qf(e,n);var c=o=r.createElement(`link`);bt(c),Jd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,Zf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Vf(e,t){jf.X(e,t);var n=Pf;if(n&&e){var r=yt(n).hoistableScripts,i=Jf(e),a=r.get(i);a||(a=n.querySelector(Yf(i)),a||(e=f({src:e,async:!0},t),(t=Of.get(i))&&$f(e,t),a=n.createElement(`script`),bt(a),Jd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Hf(e,t){jf.M(e,t);var n=Pf;if(n&&e){var r=yt(n).hoistableScripts,i=Jf(e),a=r.get(i);a||(a=n.querySelector(Yf(i)),a||(e=f({src:e,async:!0,type:`module`},t),(t=Of.get(i))&&$f(e,t),a=n.createElement(`script`),bt(a),Jd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Uf(e,t,n,r){var a=(a=ue.current)?Af(a):null;if(!a)throw Error(i(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Wf(n.href),n=yt(a).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Wf(n.href);var o=yt(a).hoistableStyles,s=o.get(e);if(s||(a=a.ownerDocument||a,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=a.querySelector(Gf(e)))&&!o._p&&(s.instance=o,s.state.loading=5),Of.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},Of.set(e,n),o||qf(a,e,n,s.state))),t&&r===null)throw Error(i(528,``));return s}if(t&&r!==null)throw Error(i(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=Jf(n),n=yt(a).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(i(444,e))}}function Wf(e){return`href="`+zt(e)+`"`}function Gf(e){return`link[rel="stylesheet"][`+e+`]`}function Kf(e){return f({},e,{"data-precedence":e.precedence,precedence:null})}function qf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Jd(t,`link`,n),bt(t),e.head.appendChild(t))}function Jf(e){return`[src="`+zt(e)+`"]`}function Yf(e){return`script[async]`+e}function Xf(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+zt(n.href)+`"]`);if(r)return t.instance=r,bt(r),r;var a=f({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),bt(r),Jd(r,`style`,a),Zf(r,n.precedence,e),t.instance=r;case`stylesheet`:a=Wf(n.href);var o=e.querySelector(Gf(a));if(o)return t.state.loading|=4,t.instance=o,bt(o),o;r=Kf(n),(a=Of.get(a))&&Qf(r,a),o=(e.ownerDocument||e).createElement(`link`),bt(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),Jd(o,`link`,r),t.state.loading|=4,Zf(o,n.precedence,e),t.instance=o;case`script`:return o=Jf(n.src),(a=e.querySelector(Yf(o)))?(t.instance=a,bt(a),a):(r=n,(a=Of.get(o))&&(r=f({},n),$f(r,a)),e=e.ownerDocument||e,a=e.createElement(`script`),bt(a),Jd(a,`link`,r),e.head.appendChild(a),t.instance=a);case`void`:return null;default:throw Error(i(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,Zf(r,n.precedence,e));return t.instance}function Zf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function rp(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function ip(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function ap(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Wf(r.href),a=t.querySelector(Gf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=cp.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,bt(a);return}a=t.ownerDocument||t,r=Kf(r),(i=Of.get(i))&&Qf(r,i),a=a.createElement(`link`),bt(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Jd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=cp.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var op=0;function sp(e,t){return e.stylesheets&&e.count===0&&up(e,e.stylesheets),0op?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function cp(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)up(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var lp=null;function up(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,lp=new Map,t.forEach(dp,e),lp=null,cp.call(e))}function dp(e,t){if(!(t.state.loading&4)){var n=lp.get(e);if(n)var r=n.get(null);else{n=new Map,lp.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=sa()})),la=o((e=>{var t=je().__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;e.c=function(e){return t.H.useMemoCache(e)}})),ua=o(((e,t)=>{t.exports=la()})),da=c(ca(),1),fa=ua(),pa=(0,P.createContext)(void 0);function ma(e,t){try{let t=localStorage.getItem(e);if(t===`light`||t===`dark`||t===`system`)return t}catch{}return t}function ha(e){let t=(0,fa.c)(14),{children:n,defaultTheme:r,storageKey:i}=e,a=r===void 0?`dark`:r,o=i===void 0?`ui-theme`:i,s;t[0]!==a||t[1]!==o?(s=()=>ma(o,a),t[0]=a,t[1]=o,t[2]=s):s=t[2];let[c,l]=(0,P.useState)(s),u,d;t[3]===c?(u=t[4],d=t[5]):(u=()=>{let e=window.document.documentElement;if(e.classList.remove(`light`,`dark`),c===`system`){let t=window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`;e.classList.add(t);return}e.classList.add(c)},d=[c],t[3]=c,t[4]=u,t[5]=d),(0,P.useEffect)(u,d);let f;t[6]===o?f=t[7]:(f=e=>{try{localStorage.setItem(o,e)}catch{}l(e)},t[6]=o,t[7]=f);let p;t[8]!==f||t[9]!==c?(p={theme:c,setTheme:f},t[8]=f,t[9]=c,t[10]=p):p=t[10];let m=p,h;return t[11]!==n||t[12]!==m?(h=(0,F.jsx)(pa.Provider,{value:m,children:n}),t[11]=n,t[12]=m,t[13]=h):h=t[13],h}function ga(){let e=(0,P.useContext)(pa);if(e===void 0)throw Error(`useTheme must be used within a ThemeProvider`);return e}function _a(e,t){if(e&&!t)return e;if(!e&&t)return t;if(e||t)return{...e,...t}}var va={};function ya(e,t,n,r,i){if(!n&&!r&&!i&&!e)return xa(t);let a=xa(e);return t&&(a=Sa(a,t)),n&&(a=Sa(a,n)),r&&(a=Sa(a,r)),i&&(a=Sa(a,i)),a}function ba(e){if(e.length===0)return va;if(e.length===1)return xa(e[0]);let t=xa(e[0]);for(let n=1;n=65&&i<=90&&(typeof t==`function`||t===void 0)}function Ea(e){return typeof e==`function`}function Da(e,t){return Ea(e)?e(t):e??va}function Oa(e,t){return t?e?(...n)=>{let r=n[0];if(Ma(r)){let i=r;Aa(i);let a=t(...n);return i.baseUIHandlerPrevented||e?.(...n),a}let i=t(...n);return e?.(...n),i}:ka(t):e}function ka(e){return e&&((...t)=>{let n=t[0];return Ma(n)&&Aa(n),e(...t)})}function Aa(e){return e.preventBaseUIHandler=()=>{e.baseUIHandlerPrevented=!0},e}function ja(e,t){return t?e?t+` `+e:t:e}function Ma(e){return typeof e==`object`&&!!e&&`nativeEvent`in e}function Na(e,t){return function(n,...r){let i=new URL(e);return i.searchParams.set(`code`,n.toString()),r.forEach(e=>i.searchParams.append(`args[]`,e)),`${t} error #${n}; visit ${i} for the full message.`}}var Pa=Na(`https://base-ui.com/production-error`,`Base UI`),Fa={};function Ia(e,t){let n=P.useRef(Fa);return n.current===Fa&&(n.current=e(t)),n}function La(e,t,n,r){let i=Ia(za).current;return Ba(i,e,t,n,r)&&Ha(i,[e,t,n,r]),i.callback}function Ra(e){let t=Ia(za).current;return Va(t,e)&&Ha(t,e),t.callback}function za(){return{callback:null,cleanup:null,refs:[]}}function Ba(e,t,n,r,i){return e.refs[0]!==t||e.refs[1]!==n||e.refs[2]!==r||e.refs[3]!==i}function Va(e,t){return e.refs.length!==t.length||e.refs.some((e,n)=>e!==t[n])}function Ha(e,t){if(e.refs=t,t.every(e=>e==null)){e.callback=null;return}e.callback=n=>{if(e.cleanup&&=(e.cleanup(),null),n!=null){let r=Array(t.length).fill(null);for(let e=0;e{for(let e=0;e=e}function Ga(e){if(!P.isValidElement(e))return null;let t=e,n=t.props;return(Wa(19)?n?.ref:t.ref)??null}function Ka(){}var qa=Object.freeze([]),Ja=Object.freeze({});function Ya(e,t){let n={};for(let r in e){let i=e[r];if(t?.hasOwnProperty(r)){let e=t[r](i);e!=null&&Object.assign(n,e);continue}i===!0?n[`data-${r.toLowerCase()}`]=``:i&&(n[`data-${r.toLowerCase()}`]=i.toString())}return n}function Xa(e,t){return typeof e==`function`?e(t):e}function Za(e,t){return typeof e==`function`?e(t):e}function Qa(e,t,n={}){let r=t.render,i=$a(t,n);return n.enabled===!1?null:no(e,r,i,n.state??Ja)}function $a(e,t={}){let{className:n,style:r,render:i}=e,{state:a=Ja,ref:o,props:s,stateAttributesMapping:c,enabled:l=!0}=t,u=l?Xa(n,a):void 0,d=l?Za(r,a):void 0,f=l?Ya(a,c):Ja,p=l&&s?eo(s):void 0,m=l?_a(f,p)??{}:Ja;return typeof document<`u`&&(l?Array.isArray(o)?m.ref=Ra([m.ref,Ga(i),...o]):m.ref=La(m.ref,Ga(i),o):La(null,null)),l?(u!==void 0&&(m.className=ja(m.className,u)),d!==void 0&&(m.style=_a(m.style,d)),m):Ja}function eo(e){return Array.isArray(e)?ba(e):ya(void 0,e)}var to=Symbol.for(`react.lazy`);function no(e,t,n,r){if(t){if(typeof t==`function`)return t(n,r);let e=ya(n,t.props);e.ref=n.ref;let i=t;return i?.$$typeof===to&&(i=P.Children.toArray(t)[0]),P.cloneElement(i,e)}if(e&&typeof e==`string`)return ro(e,n);throw Error(Pa(8))}function ro(e,t){return e===`button`?(0,P.createElement)(`button`,{type:`button`,...t,key:t.key}):e===`img`?(0,P.createElement)(`img`,{alt:``,...t,key:t.key}):P.createElement(e,t)}function io(e){return Qa(e.defaultTagName??`div`,e,e)}function ao(e){var t,n,r=``;if(typeof e==`string`||typeof e==`number`)r+=e;else if(typeof e==`object`)if(Array.isArray(e)){var i=e.length;for(t=0;ttypeof e==`boolean`?`${e}`:e===0?`0`:e,co=oo,lo=(e,t)=>n=>{if(t?.variants==null)return co(e,n?.class,n?.className);let{variants:r,defaultVariants:i}=t,a=Object.keys(r).map(e=>{let t=n?.[e],a=i?.[e];if(t===null)return null;let o=so(t)||so(a);return r[e][o]}),o=n&&Object.entries(n).reduce((e,t)=>{let[n,r]=t;return r===void 0||(e[n]=r),e},{});return co(e,a,t?.compoundVariants?.reduce((e,t)=>{let{class:n,className:r,...a}=t;return Object.entries(a).every(e=>{let[t,n]=e;return Array.isArray(n)?n.includes({...i,...o}[t]):{...i,...o}[t]===n})?[...e,n,r]:e},[]),n?.class,n?.className)},uo=(...e)=>e.filter((e,t,n)=>!!e&&e.trim()!==``&&n.indexOf(e)===t).join(` `).trim(),fo=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase(),po=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,t,n)=>n?n.toUpperCase():t.toLowerCase()),mo=e=>{let t=po(e);return t.charAt(0).toUpperCase()+t.slice(1)},ho={xmlns:`http://www.w3.org/2000/svg`,width:24,height:24,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:2,strokeLinecap:`round`,strokeLinejoin:`round`},go=e=>{for(let t in e)if(t.startsWith(`aria-`)||t===`role`||t===`title`)return!0;return!1},_o=(0,P.createContext)({}),vo=()=>(0,P.useContext)(_o),yo=(0,P.forwardRef)(({color:e,size:t,strokeWidth:n,absoluteStrokeWidth:r,className:i=``,children:a,iconNode:o,...s},c)=>{let{size:l=24,strokeWidth:u=2,absoluteStrokeWidth:d=!1,color:f=`currentColor`,className:p=``}=vo()??{},m=r??d?Number(n??u)*24/Number(t??l):n??u;return(0,P.createElement)(`svg`,{ref:c,...ho,width:t??l??ho.width,height:t??l??ho.height,stroke:e??f,strokeWidth:m,className:uo(`lucide`,p,i),...!a&&!go(s)&&{"aria-hidden":`true`},...s},[...o.map(([e,t])=>(0,P.createElement)(e,t)),...Array.isArray(a)?a:[a]])}),bo=(e,t)=>{let n=(0,P.forwardRef)(({className:n,...r},i)=>(0,P.createElement)(yo,{ref:i,iconNode:t,className:uo(`lucide-${fo(mo(e))}`,`lucide-${e}`,n),...r}));return n.displayName=mo(e),n},xo=bo(`activity`,[[`path`,{d:`M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2`,key:`169zse`}]]),So=bo(`book-open`,[[`path`,{d:`M12 7v14`,key:`1akyts`}],[`path`,{d:`M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z`,key:`ruj8y`}]]),Co=bo(`camera`,[[`path`,{d:`M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z`,key:`18u6gg`}],[`circle`,{cx:`12`,cy:`13`,r:`3`,key:`1vg3eu`}]]),wo=bo(`circle-alert`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`line`,{x1:`12`,x2:`12`,y1:`8`,y2:`12`,key:`1pkeuh`}],[`line`,{x1:`12`,x2:`12.01`,y1:`16`,y2:`16`,key:`4dfq90`}]]),To=bo(`crosshair`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`line`,{x1:`22`,x2:`18`,y1:`12`,y2:`12`,key:`l9bcsi`}],[`line`,{x1:`6`,x2:`2`,y1:`12`,y2:`12`,key:`13hhkx`}],[`line`,{x1:`12`,x2:`12`,y1:`6`,y2:`2`,key:`10w3f3`}],[`line`,{x1:`12`,x2:`12`,y1:`22`,y2:`18`,key:`15g9kq`}]]),Eo=bo(`hard-drive`,[[`path`,{d:`M10 16h.01`,key:`1bzywj`}],[`path`,{d:`M2.212 11.577a2 2 0 0 0-.212.896V18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-5.527a2 2 0 0 0-.212-.896L18.55 5.11A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z`,key:`18tbho`}],[`path`,{d:`M21.946 12.013H2.054`,key:`zqlbp7`}],[`path`,{d:`M6 16h.01`,key:`1pmjb7`}]]),Do=bo(`house`,[[`path`,{d:`M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8`,key:`5wwlr5`}],[`path`,{d:`M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z`,key:`r6nss1`}]]),Oo=bo(`image`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}],[`circle`,{cx:`9`,cy:`9`,r:`2`,key:`af1f0g`}],[`path`,{d:`m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21`,key:`1xmnt7`}]]),ko=bo(`key`,[[`path`,{d:`m15.5 7.5 2.3 2.3a1 1 0 0 0 1.4 0l2.1-2.1a1 1 0 0 0 0-1.4L19 4`,key:`g0fldk`}],[`path`,{d:`m21 2-9.6 9.6`,key:`1j0ho8`}],[`circle`,{cx:`7.5`,cy:`15.5`,r:`5.5`,key:`yqb3hr`}]]),Ao=bo(`layers`,[[`path`,{d:`M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z`,key:`zw3jo`}],[`path`,{d:`M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12`,key:`1wduqc`}],[`path`,{d:`M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17`,key:`kqbvx6`}]]),jo=bo(`layout-grid`,[[`rect`,{width:`7`,height:`7`,x:`3`,y:`3`,rx:`1`,key:`1g98yp`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`3`,rx:`1`,key:`6d4xhi`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`14`,rx:`1`,key:`nxv5o0`}],[`rect`,{width:`7`,height:`7`,x:`3`,y:`14`,rx:`1`,key:`1bb6yr`}]]),Mo=bo(`log-out`,[[`path`,{d:`m16 17 5-5-5-5`,key:`1bji2h`}],[`path`,{d:`M21 12H9`,key:`dn1m92`}],[`path`,{d:`M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4`,key:`1uf3rs`}]]),No=bo(`moon`,[[`path`,{d:`M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401`,key:`kfwtm`}]]),Po=bo(`network`,[[`rect`,{x:`16`,y:`16`,width:`6`,height:`6`,rx:`1`,key:`4q2zg0`}],[`rect`,{x:`2`,y:`16`,width:`6`,height:`6`,rx:`1`,key:`8cvhb9`}],[`rect`,{x:`9`,y:`2`,width:`6`,height:`6`,rx:`1`,key:`1egb70`}],[`path`,{d:`M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3`,key:`1jsf9p`}],[`path`,{d:`M12 12V8`,key:`2874zd`}]]),Fo=bo(`panel-left`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`M9 3v18`,key:`fh3hqa`}]]),Io=bo(`server`,[[`rect`,{width:`20`,height:`8`,x:`2`,y:`2`,rx:`2`,ry:`2`,key:`ngkwjq`}],[`rect`,{width:`20`,height:`8`,x:`2`,y:`14`,rx:`2`,ry:`2`,key:`iecqi9`}],[`line`,{x1:`6`,x2:`6.01`,y1:`6`,y2:`6`,key:`16zg32`}],[`line`,{x1:`6`,x2:`6.01`,y1:`18`,y2:`18`,key:`nzw8ys`}]]),Lo=bo(`shield-check`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),Ro=bo(`shield`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}]]),zo=bo(`sun`,[[`circle`,{cx:`12`,cy:`12`,r:`4`,key:`4exip2`}],[`path`,{d:`M12 2v2`,key:`tus03m`}],[`path`,{d:`M12 20v2`,key:`1lh1kg`}],[`path`,{d:`m4.93 4.93 1.41 1.41`,key:`149t6j`}],[`path`,{d:`m17.66 17.66 1.41 1.41`,key:`ptbguv`}],[`path`,{d:`M2 12h2`,key:`1t8f8n`}],[`path`,{d:`M20 12h2`,key:`1q8mjw`}],[`path`,{d:`m6.34 17.66-1.41 1.41`,key:`1m8zz5`}],[`path`,{d:`m19.07 4.93-1.41 1.41`,key:`1shlcs`}]]),Bo=bo(`users`,[[`path`,{d:`M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2`,key:`1yyitq`}],[`path`,{d:`M16 3.128a4 4 0 0 1 0 7.744`,key:`16gr8j`}],[`path`,{d:`M22 21v-2a4 4 0 0 0-3-3.87`,key:`kshegd`}],[`circle`,{cx:`9`,cy:`7`,r:`4`,key:`nufk8`}]]),Vo=bo(`waypoints`,[[`path`,{d:`m10.586 5.414-5.172 5.172`,key:`4mc350`}],[`path`,{d:`m18.586 13.414-5.172 5.172`,key:`8c96vv`}],[`path`,{d:`M6 12h12`,key:`8npq4p`}],[`circle`,{cx:`12`,cy:`20`,r:`2`,key:`144qzu`}],[`circle`,{cx:`12`,cy:`4`,r:`2`,key:`muu5ef`}],[`circle`,{cx:`20`,cy:`12`,r:`2`,key:`1xzzfp`}],[`circle`,{cx:`4`,cy:`12`,r:`2`,key:`1hvhnz`}]]),Ho=bo(`x`,[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]]);function Uo(){return typeof window<`u`}function Wo(e){return qo(e)?(e.nodeName||``).toLowerCase():`#document`}function Go(e){var t;return(e==null||(t=e.ownerDocument)==null?void 0:t.defaultView)||window}function Ko(e){return((qo(e)?e.ownerDocument:e.document)||window.document)?.documentElement}function qo(e){return Uo()?e instanceof Node||e instanceof Go(e).Node:!1}function Jo(e){return Uo()?e instanceof Element||e instanceof Go(e).Element:!1}function Yo(e){return Uo()?e instanceof HTMLElement||e instanceof Go(e).HTMLElement:!1}function Xo(e){return!Uo()||typeof ShadowRoot>`u`?!1:e instanceof ShadowRoot||e instanceof Go(e).ShadowRoot}function Zo(e){let{overflow:t,overflowX:n,overflowY:r,display:i}=cs(e);return/auto|scroll|overlay|hidden|clip/.test(t+r+n)&&i!==`inline`&&i!==`contents`}function Qo(e){return/^(table|td|th)$/.test(Wo(e))}function $o(e){try{if(e.matches(`:popover-open`))return!0}catch{}try{return e.matches(`:modal`)}catch{return!1}}var es=/transform|translate|scale|rotate|perspective|filter/,ts=/paint|layout|strict|content/,ns=e=>!!e&&e!==`none`,rs;function is(e){let t=Jo(e)?cs(e):e;return ns(t.transform)||ns(t.translate)||ns(t.scale)||ns(t.rotate)||ns(t.perspective)||!os()&&(ns(t.backdropFilter)||ns(t.filter))||es.test(t.willChange||``)||ts.test(t.contain||``)}function as(e){let t=us(e);for(;Yo(t)&&!ss(t);){if(is(t))return t;if($o(t))return null;t=us(t)}return null}function os(){return rs??=typeof CSS<`u`&&CSS.supports&&CSS.supports(`-webkit-backdrop-filter`,`none`),rs}function ss(e){return/^(html|body|#document)$/.test(Wo(e))}function cs(e){return Go(e).getComputedStyle(e)}function ls(e){return Jo(e)?{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}:{scrollLeft:e.scrollX,scrollTop:e.scrollY}}function us(e){if(Wo(e)===`html`)return e;let t=e.assignedSlot||e.parentNode||Xo(e)&&e.host||Ko(e);return Xo(t)?t.host:t}function ds(e){let t=us(e);return ss(t)?e.ownerDocument?e.ownerDocument.body:e.body:Yo(t)&&Zo(t)?t:ds(t)}function fs(e,t,n){t===void 0&&(t=[]),n===void 0&&(n=!0);let r=ds(e),i=r===e.ownerDocument?.body,a=Go(r);if(i){let e=ps(a);return t.concat(a,a.visualViewport||[],Zo(r)?r:[],e&&n?fs(e):[])}else return t.concat(r,fs(r,[],n))}function ps(e){return e.parent&&Object.getPrototypeOf(e.parent)?e.frameElement:null}var ms=P[`useInsertionEffect${Math.random().toFixed(1)}`.slice(0,-3)],hs=ms&&ms!==P.useLayoutEffect?ms:e=>e();function gs(e){let t=Ia(_s).current;return t.next=e,hs(t.effect),t.trampoline}function _s(){let e={next:void 0,callback:vs,trampoline:(...t)=>e.callback?.(...t),effect:()=>{e.callback=e.next}};return e}function vs(){}var ys={...P},bs=typeof document<`u`?P.useLayoutEffect:()=>{},xs=P.createContext(void 0);function Ss(e=!1){let t=P.useContext(xs);if(t===void 0&&!e)throw Error(Pa(16));return t}function Cs(e){let{focusableWhenDisabled:t,disabled:n,composite:r=!1,tabIndex:i=0,isNativeButton:a}=e,o=r&&t!==!1,s=r&&t===!1;return{props:P.useMemo(()=>{let e={onKeyDown(e){n&&t&&e.key!==`Tab`&&e.preventDefault()}};return r||(e.tabIndex=i,!a&&n&&(e.tabIndex=t?i:-1)),(a&&(t||o)||!a&&n)&&(e[`aria-disabled`]=n),a&&(!t||s)&&(e.disabled=n),e},[r,n,t,o,s,a,i])}}function ws(e={}){let{disabled:t=!1,focusableWhenDisabled:n,tabIndex:r=0,native:i=!0,composite:a}=e,o=P.useRef(null),s=Ss(!0),c=a??s!==void 0,{props:l}=Cs({focusableWhenDisabled:n,disabled:t,composite:c,tabIndex:r,isNativeButton:i}),u=P.useCallback(()=>{let e=o.current;Ts(e)&&c&&t&&l.disabled===void 0&&e.disabled&&(e.disabled=!1)},[t,l.disabled,c]);return bs(u,[u]),{getButtonProps:P.useCallback((e={})=>{let{onClick:n,onMouseDown:r,onKeyUp:a,onKeyDown:o,onPointerDown:s,...u}=e;return ya({type:i?`button`:void 0,onClick(e){if(t){e.preventDefault();return}n?.(e)},onMouseDown(e){t||r?.(e)},onKeyDown(e){if(t||(Aa(e),o?.(e),e.baseUIHandlerPrevented))return;let r=e.target===e.currentTarget,a=e.currentTarget,s=Ts(a),l=!i&&Es(a),u=r&&(i?s:!l),d=e.key===`Enter`,f=e.key===` `,p=a.getAttribute(`role`),m=p?.startsWith(`menuitem`)||p===`option`||p===`gridcell`;if(r&&c&&f){if(e.defaultPrevented&&m)return;e.preventDefault(),l||i&&s?(a.click(),e.preventBaseUIHandler()):u&&(n?.(e),e.preventBaseUIHandler());return}u&&(!i&&(f||d)&&e.preventDefault(),!i&&d&&n?.(e))},onKeyUp(e){if(!t){if(Aa(e),a?.(e),e.target===e.currentTarget&&i&&c&&Ts(e.currentTarget)&&e.key===` `){e.preventDefault();return}e.baseUIHandlerPrevented||e.target===e.currentTarget&&!i&&!c&&e.key===` `&&n?.(e)}},onPointerDown(e){if(t){e.preventDefault();return}s?.(e)}},i?void 0:{role:`button`},l,u)},[t,l,c,i]),buttonRef:gs(e=>{o.current=e,u()})}}function Ts(e){return Yo(e)&&e.tagName===`BUTTON`}function Es(e){return!!(e?.tagName===`A`&&e?.href)}var Ds=P.forwardRef(function(e,t){let{render:n,className:r,disabled:i=!1,focusableWhenDisabled:a=!1,nativeButton:o=!0,style:s,...c}=e,{getButtonProps:l,buttonRef:u}=ws({disabled:i,focusableWhenDisabled:a,native:o});return Qa(`button`,e,{state:{disabled:i},ref:[t,u],props:[c,l]})}),Os=(e,t)=>{let n=Array(e.length+t.length);for(let t=0;t({classGroupId:e,validator:t}),As=(e=new Map,t=null,n)=>({nextPart:e,validators:t,classGroupId:n}),js=`-`,Ms=[],Ns=`arbitrary..`,Ps=e=>{let t=Ls(e),{conflictingClassGroups:n,conflictingClassGroupModifiers:r}=e;return{getClassGroupId:e=>{if(e.startsWith(`[`)&&e.endsWith(`]`))return Is(e);let n=e.split(js);return Fs(n,+(n[0]===``&&n.length>1),t)},getConflictingClassGroupIds:(e,t)=>{if(t){let t=r[e],i=n[e];return t?i?Os(i,t):t:i||Ms}return n[e]||Ms}}},Fs=(e,t,n)=>{if(e.length-t===0)return n.classGroupId;let r=e[t],i=n.nextPart.get(r);if(i){let n=Fs(e,t+1,i);if(n)return n}let a=n.validators;if(a===null)return;let o=t===0?e.join(js):e.slice(t).join(js),s=a.length;for(let e=0;ee.slice(1,-1).indexOf(`:`)===-1?void 0:(()=>{let t=e.slice(1,-1),n=t.indexOf(`:`),r=t.slice(0,n);return r?Ns+r:void 0})(),Ls=e=>{let{theme:t,classGroups:n}=e;return Rs(n,t)},Rs=(e,t)=>{let n=As();for(let r in e){let i=e[r];zs(i,n,r,t)}return n},zs=(e,t,n,r)=>{let i=e.length;for(let a=0;a{if(typeof e==`string`){Vs(e,t,n);return}if(typeof e==`function`){Hs(e,t,n,r);return}Us(e,t,n,r)},Vs=(e,t,n)=>{let r=e===``?t:Ws(t,e);r.classGroupId=n},Hs=(e,t,n,r)=>{if(Gs(e)){zs(e(r),t,n,r);return}t.validators===null&&(t.validators=[]),t.validators.push(ks(n,e))},Us=(e,t,n,r)=>{let i=Object.entries(e),a=i.length;for(let e=0;e{let n=e,r=t.split(js),i=r.length;for(let e=0;e`isThemeGetter`in e&&e.isThemeGetter===!0,Ks=e=>{if(e<1)return{get:()=>void 0,set:()=>{}};let t=0,n=Object.create(null),r=Object.create(null),i=(i,a)=>{n[i]=a,t++,t>e&&(t=0,r=n,n=Object.create(null))};return{get(e){let t=n[e];if(t!==void 0)return t;if((t=r[e])!==void 0)return i(e,t),t},set(e,t){e in n?n[e]=t:i(e,t)}}},qs=`!`,Js=`:`,Ys=[],Xs=(e,t,n,r,i)=>({modifiers:e,hasImportantModifier:t,baseClassName:n,maybePostfixModifierPosition:r,isExternal:i}),Zs=e=>{let{prefix:t,experimentalParseClassName:n}=e,r=e=>{let t=[],n=0,r=0,i=0,a,o=e.length;for(let s=0;si?a-i:void 0;return Xs(t,l,c,u)};if(t){let e=t+Js,n=r;r=t=>t.startsWith(e)?n(t.slice(e.length)):Xs(Ys,!1,t,void 0,!0)}if(n){let e=r;r=t=>n({className:t,parseClassName:e})}return r},Qs=e=>{let t=new Map;return e.orderSensitiveModifiers.forEach((e,n)=>{t.set(e,1e6+n)}),e=>{let n=[],r=[];for(let i=0;i0&&(r.sort(),n.push(...r),r=[]),n.push(a)):r.push(a)}return r.length>0&&(r.sort(),n.push(...r)),n}},$s=e=>({cache:Ks(e.cacheSize),parseClassName:Zs(e),sortModifiers:Qs(e),postfixLookupClassGroupIds:ec(e),...Ps(e)}),ec=e=>{let t=Object.create(null),n=e.postfixLookupClassGroups;if(n)for(let e=0;e{let{parseClassName:n,getClassGroupId:r,getConflictingClassGroupIds:i,sortModifiers:a,postfixLookupClassGroupIds:o}=t,s=[],c=e.trim().split(tc),l=``;for(let e=c.length-1;e>=0;--e){let t=c[e],{isExternal:u,modifiers:d,hasImportantModifier:f,baseClassName:p,maybePostfixModifierPosition:m}=n(t);if(u){l=t+(l.length>0?` `+l:l);continue}let h=!!m,g;if(h){g=r(p.substring(0,m));let e=g&&o[g]?r(p):void 0;e&&e!==g&&(g=e,h=!1)}else g=r(p);if(!g){if(!h){l=t+(l.length>0?` `+l:l);continue}if(g=r(p),!g){l=t+(l.length>0?` `+l:l);continue}h=!1}let _=d.length===0?``:d.length===1?d[0]:a(d).join(`:`),v=f?_+qs:_,y=v+g;if(s.indexOf(y)>-1)continue;s.push(y);let b=i(g,h);for(let e=0;e0?` `+l:l)}return l},rc=(...e)=>{let t=0,n,r,i=``;for(;t{if(typeof e==`string`)return e;let t,n=``;for(let r=0;r{let n,r,i,a,o=o=>(n=$s(t.reduce((e,t)=>t(e),e())),r=n.cache.get,i=n.cache.set,a=s,s(o)),s=e=>{let t=r(e);if(t)return t;let a=nc(e,n);return i(e,a),a};return a=o,(...e)=>a(rc(...e))},oc=[],sc=e=>{let t=t=>t[e]||oc;return t.isThemeGetter=!0,t},cc=/^\[(?:(\w[\w-]*):)?(.+)\]$/i,lc=/^\((?:(\w[\w-]*):)?(.+)\)$/i,uc=/^\d+(?:\.\d+)?\/\d+(?:\.\d+)?$/,dc=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,fc=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,pc=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,mc=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,hc=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,gc=e=>uc.test(e),_c=e=>!!e&&!Number.isNaN(Number(e)),vc=e=>!!e&&Number.isInteger(Number(e)),yc=e=>e.endsWith(`%`)&&_c(e.slice(0,-1)),bc=e=>dc.test(e),xc=()=>!0,Sc=e=>fc.test(e)&&!pc.test(e),Cc=()=>!1,wc=e=>mc.test(e),Tc=e=>hc.test(e),Ec=e=>!R(e)&&!z(e),Dc=e=>e.startsWith(`@container`)&&(e[10]===`/`&&e[11]!==void 0||e[11]===`s`&&e[16]!==void 0&&e.startsWith(`-size/`,10)||e[11]===`n`&&e[18]!==void 0&&e.startsWith(`-normal/`,10)),Oc=e=>Uc(e,qc,Cc),R=e=>cc.test(e),kc=e=>Uc(e,Jc,Sc),Ac=e=>Uc(e,Yc,_c),jc=e=>Uc(e,Zc,xc),Mc=e=>Uc(e,Xc,Cc),Nc=e=>Uc(e,Gc,Cc),Pc=e=>Uc(e,Kc,Tc),Fc=e=>Uc(e,Qc,wc),z=e=>lc.test(e),Ic=e=>Wc(e,Jc),Lc=e=>Wc(e,Xc),Rc=e=>Wc(e,Gc),zc=e=>Wc(e,qc),Bc=e=>Wc(e,Kc),Vc=e=>Wc(e,Qc,!0),Hc=e=>Wc(e,Zc,!0),Uc=(e,t,n)=>{let r=cc.exec(e);return r?r[1]?t(r[1]):n(r[2]):!1},Wc=(e,t,n=!1)=>{let r=lc.exec(e);return r?r[1]?t(r[1]):n:!1},Gc=e=>e===`position`||e===`percentage`,Kc=e=>e===`image`||e===`url`,qc=e=>e===`length`||e===`size`||e===`bg-size`,Jc=e=>e===`length`,Yc=e=>e===`number`,Xc=e=>e===`family-name`,Zc=e=>e===`number`||e===`weight`,Qc=e=>e===`shadow`,$c=ac(()=>{let e=sc(`color`),t=sc(`font`),n=sc(`text`),r=sc(`font-weight`),i=sc(`tracking`),a=sc(`leading`),o=sc(`breakpoint`),s=sc(`container`),c=sc(`spacing`),l=sc(`radius`),u=sc(`shadow`),d=sc(`inset-shadow`),f=sc(`text-shadow`),p=sc(`drop-shadow`),m=sc(`blur`),h=sc(`perspective`),g=sc(`aspect`),_=sc(`ease`),v=sc(`animate`),y=()=>[`auto`,`avoid`,`all`,`avoid-page`,`page`,`left`,`right`,`column`],b=()=>[`center`,`top`,`bottom`,`left`,`right`,`top-left`,`left-top`,`top-right`,`right-top`,`bottom-right`,`right-bottom`,`bottom-left`,`left-bottom`],x=()=>[...b(),z,R],S=()=>[`auto`,`hidden`,`clip`,`visible`,`scroll`],C=()=>[`auto`,`contain`,`none`],w=()=>[z,R,c],T=()=>[gc,`full`,`auto`,...w()],E=()=>[vc,`none`,`subgrid`,z,R],ee=()=>[`auto`,{span:[`full`,vc,z,R]},vc,z,R],D=()=>[vc,`auto`,z,R],O=()=>[`auto`,`min`,`max`,`fr`,z,R],te=()=>[`start`,`end`,`center`,`between`,`around`,`evenly`,`stretch`,`baseline`,`center-safe`,`end-safe`],ne=()=>[`start`,`end`,`center`,`stretch`,`center-safe`,`end-safe`],re=()=>[`auto`,...w()],k=()=>[gc,`auto`,`full`,`dvw`,`dvh`,`lvw`,`lvh`,`svw`,`svh`,`min`,`max`,`fit`,...w()],A=()=>[gc,`screen`,`full`,`dvw`,`lvw`,`svw`,`min`,`max`,`fit`,...w()],ie=()=>[gc,`screen`,`full`,`lh`,`dvh`,`lvh`,`svh`,`min`,`max`,`fit`,...w()],j=()=>[e,z,R],ae=()=>[...b(),Rc,Nc,{position:[z,R]}],oe=()=>[`no-repeat`,{repeat:[``,`x`,`y`,`space`,`round`]}],se=()=>[`auto`,`cover`,`contain`,zc,Oc,{size:[z,R]}],ce=()=>[yc,Ic,kc],M=()=>[``,`none`,`full`,l,z,R],le=()=>[``,_c,Ic,kc],ue=()=>[`solid`,`dashed`,`dotted`,`double`],N=()=>[`normal`,`multiply`,`screen`,`overlay`,`darken`,`lighten`,`color-dodge`,`color-burn`,`hard-light`,`soft-light`,`difference`,`exclusion`,`hue`,`saturation`,`color`,`luminosity`],de=()=>[_c,yc,Rc,Nc],fe=()=>[``,`none`,m,z,R],pe=()=>[`none`,_c,z,R],me=()=>[`none`,_c,z,R],he=()=>[_c,z,R],ge=()=>[gc,`full`,...w()];return{cacheSize:500,theme:{animate:[`spin`,`ping`,`pulse`,`bounce`],aspect:[`video`],blur:[bc],breakpoint:[bc],color:[xc],container:[bc],"drop-shadow":[bc],ease:[`in`,`out`,`in-out`],font:[Ec],"font-weight":[`thin`,`extralight`,`light`,`normal`,`medium`,`semibold`,`bold`,`extrabold`,`black`],"inset-shadow":[bc],leading:[`none`,`tight`,`snug`,`normal`,`relaxed`,`loose`],perspective:[`dramatic`,`near`,`normal`,`midrange`,`distant`,`none`],radius:[bc],shadow:[bc],spacing:[`px`,_c],text:[bc],"text-shadow":[bc],tracking:[`tighter`,`tight`,`normal`,`wide`,`wider`,`widest`]},classGroups:{aspect:[{aspect:[`auto`,`square`,gc,R,z,g]}],container:[`container`],"container-type":[{"@container":[``,`normal`,`size`,z,R]}],"container-named":[Dc],columns:[{columns:[_c,R,z,s]}],"break-after":[{"break-after":y()}],"break-before":[{"break-before":y()}],"break-inside":[{"break-inside":[`auto`,`avoid`,`avoid-page`,`avoid-column`]}],"box-decoration":[{"box-decoration":[`slice`,`clone`]}],box:[{box:[`border`,`content`]}],display:[`block`,`inline-block`,`inline`,`flex`,`inline-flex`,`table`,`inline-table`,`table-caption`,`table-cell`,`table-column`,`table-column-group`,`table-footer-group`,`table-header-group`,`table-row-group`,`table-row`,`flow-root`,`grid`,`inline-grid`,`contents`,`list-item`,`hidden`],sr:[`sr-only`,`not-sr-only`],float:[{float:[`right`,`left`,`none`,`start`,`end`]}],clear:[{clear:[`left`,`right`,`both`,`none`,`start`,`end`]}],isolation:[`isolate`,`isolation-auto`],"object-fit":[{object:[`contain`,`cover`,`fill`,`none`,`scale-down`]}],"object-position":[{object:x()}],overflow:[{overflow:S()}],"overflow-x":[{"overflow-x":S()}],"overflow-y":[{"overflow-y":S()}],overscroll:[{overscroll:C()}],"overscroll-x":[{"overscroll-x":C()}],"overscroll-y":[{"overscroll-y":C()}],position:[`static`,`fixed`,`absolute`,`relative`,`sticky`],inset:[{inset:T()}],"inset-x":[{"inset-x":T()}],"inset-y":[{"inset-y":T()}],start:[{"inset-s":T(),start:T()}],end:[{"inset-e":T(),end:T()}],"inset-bs":[{"inset-bs":T()}],"inset-be":[{"inset-be":T()}],top:[{top:T()}],right:[{right:T()}],bottom:[{bottom:T()}],left:[{left:T()}],visibility:[`visible`,`invisible`,`collapse`],z:[{z:[vc,`auto`,z,R]}],basis:[{basis:[gc,`full`,`auto`,s,...w()]}],"flex-direction":[{flex:[`row`,`row-reverse`,`col`,`col-reverse`]}],"flex-wrap":[{flex:[`nowrap`,`wrap`,`wrap-reverse`]}],flex:[{flex:[_c,gc,`auto`,`initial`,`none`,R]}],grow:[{grow:[``,_c,z,R]}],shrink:[{shrink:[``,_c,z,R]}],order:[{order:[vc,`first`,`last`,`none`,z,R]}],"grid-cols":[{"grid-cols":E()}],"col-start-end":[{col:ee()}],"col-start":[{"col-start":D()}],"col-end":[{"col-end":D()}],"grid-rows":[{"grid-rows":E()}],"row-start-end":[{row:ee()}],"row-start":[{"row-start":D()}],"row-end":[{"row-end":D()}],"grid-flow":[{"grid-flow":[`row`,`col`,`dense`,`row-dense`,`col-dense`]}],"auto-cols":[{"auto-cols":O()}],"auto-rows":[{"auto-rows":O()}],gap:[{gap:w()}],"gap-x":[{"gap-x":w()}],"gap-y":[{"gap-y":w()}],"justify-content":[{justify:[...te(),`normal`]}],"justify-items":[{"justify-items":[...ne(),`normal`]}],"justify-self":[{"justify-self":[`auto`,...ne()]}],"align-content":[{content:[`normal`,...te()]}],"align-items":[{items:[...ne(),{baseline:[``,`last`]}]}],"align-self":[{self:[`auto`,...ne(),{baseline:[``,`last`]}]}],"place-content":[{"place-content":te()}],"place-items":[{"place-items":[...ne(),`baseline`]}],"place-self":[{"place-self":[`auto`,...ne()]}],p:[{p:w()}],px:[{px:w()}],py:[{py:w()}],ps:[{ps:w()}],pe:[{pe:w()}],pbs:[{pbs:w()}],pbe:[{pbe:w()}],pt:[{pt:w()}],pr:[{pr:w()}],pb:[{pb:w()}],pl:[{pl:w()}],m:[{m:re()}],mx:[{mx:re()}],my:[{my:re()}],ms:[{ms:re()}],me:[{me:re()}],mbs:[{mbs:re()}],mbe:[{mbe:re()}],mt:[{mt:re()}],mr:[{mr:re()}],mb:[{mb:re()}],ml:[{ml:re()}],"space-x":[{"space-x":w()}],"space-x-reverse":[`space-x-reverse`],"space-y":[{"space-y":w()}],"space-y-reverse":[`space-y-reverse`],size:[{size:k()}],"inline-size":[{inline:[`auto`,...A()]}],"min-inline-size":[{"min-inline":[`auto`,...A()]}],"max-inline-size":[{"max-inline":[`none`,...A()]}],"block-size":[{block:[`auto`,...ie()]}],"min-block-size":[{"min-block":[`auto`,...ie()]}],"max-block-size":[{"max-block":[`none`,...ie()]}],w:[{w:[s,`screen`,...k()]}],"min-w":[{"min-w":[s,`screen`,`none`,...k()]}],"max-w":[{"max-w":[s,`screen`,`none`,`prose`,{screen:[o]},...k()]}],h:[{h:[`screen`,`lh`,...k()]}],"min-h":[{"min-h":[`screen`,`lh`,`none`,...k()]}],"max-h":[{"max-h":[`screen`,`lh`,...k()]}],"font-size":[{text:[`base`,n,Ic,kc]}],"font-smoothing":[`antialiased`,`subpixel-antialiased`],"font-style":[`italic`,`not-italic`],"font-weight":[{font:[r,Hc,jc]}],"font-stretch":[{"font-stretch":[`ultra-condensed`,`extra-condensed`,`condensed`,`semi-condensed`,`normal`,`semi-expanded`,`expanded`,`extra-expanded`,`ultra-expanded`,yc,R]}],"font-family":[{font:[Lc,Mc,t]}],"font-features":[{"font-features":[R]}],"fvn-normal":[`normal-nums`],"fvn-ordinal":[`ordinal`],"fvn-slashed-zero":[`slashed-zero`],"fvn-figure":[`lining-nums`,`oldstyle-nums`],"fvn-spacing":[`proportional-nums`,`tabular-nums`],"fvn-fraction":[`diagonal-fractions`,`stacked-fractions`],tracking:[{tracking:[i,z,R]}],"line-clamp":[{"line-clamp":[_c,`none`,z,Ac]}],leading:[{leading:[a,...w()]}],"list-image":[{"list-image":[`none`,z,R]}],"list-style-position":[{list:[`inside`,`outside`]}],"list-style-type":[{list:[`disc`,`decimal`,`none`,z,R]}],"text-alignment":[{text:[`left`,`center`,`right`,`justify`,`start`,`end`]}],"placeholder-color":[{placeholder:j()}],"text-color":[{text:j()}],"text-decoration":[`underline`,`overline`,`line-through`,`no-underline`],"text-decoration-style":[{decoration:[...ue(),`wavy`]}],"text-decoration-thickness":[{decoration:[_c,`from-font`,`auto`,z,kc]}],"text-decoration-color":[{decoration:j()}],"underline-offset":[{"underline-offset":[_c,`auto`,z,R]}],"text-transform":[`uppercase`,`lowercase`,`capitalize`,`normal-case`],"text-overflow":[`truncate`,`text-ellipsis`,`text-clip`],"text-wrap":[{text:[`wrap`,`nowrap`,`balance`,`pretty`]}],indent:[{indent:w()}],"tab-size":[{tab:[vc,z,R]}],"vertical-align":[{align:[`baseline`,`top`,`middle`,`bottom`,`text-top`,`text-bottom`,`sub`,`super`,z,R]}],whitespace:[{whitespace:[`normal`,`nowrap`,`pre`,`pre-line`,`pre-wrap`,`break-spaces`]}],break:[{break:[`normal`,`words`,`all`,`keep`]}],wrap:[{wrap:[`break-word`,`anywhere`,`normal`]}],hyphens:[{hyphens:[`none`,`manual`,`auto`]}],content:[{content:[`none`,z,R]}],"bg-attachment":[{bg:[`fixed`,`local`,`scroll`]}],"bg-clip":[{"bg-clip":[`border`,`padding`,`content`,`text`]}],"bg-origin":[{"bg-origin":[`border`,`padding`,`content`]}],"bg-position":[{bg:ae()}],"bg-repeat":[{bg:oe()}],"bg-size":[{bg:se()}],"bg-image":[{bg:[`none`,{linear:[{to:[`t`,`tr`,`r`,`br`,`b`,`bl`,`l`,`tl`]},vc,z,R],radial:[``,z,R],conic:[vc,z,R]},Bc,Pc]}],"bg-color":[{bg:j()}],"gradient-from-pos":[{from:ce()}],"gradient-via-pos":[{via:ce()}],"gradient-to-pos":[{to:ce()}],"gradient-from":[{from:j()}],"gradient-via":[{via:j()}],"gradient-to":[{to:j()}],rounded:[{rounded:M()}],"rounded-s":[{"rounded-s":M()}],"rounded-e":[{"rounded-e":M()}],"rounded-t":[{"rounded-t":M()}],"rounded-r":[{"rounded-r":M()}],"rounded-b":[{"rounded-b":M()}],"rounded-l":[{"rounded-l":M()}],"rounded-ss":[{"rounded-ss":M()}],"rounded-se":[{"rounded-se":M()}],"rounded-ee":[{"rounded-ee":M()}],"rounded-es":[{"rounded-es":M()}],"rounded-tl":[{"rounded-tl":M()}],"rounded-tr":[{"rounded-tr":M()}],"rounded-br":[{"rounded-br":M()}],"rounded-bl":[{"rounded-bl":M()}],"border-w":[{border:le()}],"border-w-x":[{"border-x":le()}],"border-w-y":[{"border-y":le()}],"border-w-s":[{"border-s":le()}],"border-w-e":[{"border-e":le()}],"border-w-bs":[{"border-bs":le()}],"border-w-be":[{"border-be":le()}],"border-w-t":[{"border-t":le()}],"border-w-r":[{"border-r":le()}],"border-w-b":[{"border-b":le()}],"border-w-l":[{"border-l":le()}],"divide-x":[{"divide-x":le()}],"divide-x-reverse":[`divide-x-reverse`],"divide-y":[{"divide-y":le()}],"divide-y-reverse":[`divide-y-reverse`],"border-style":[{border:[...ue(),`hidden`,`none`]}],"divide-style":[{divide:[...ue(),`hidden`,`none`]}],"border-color":[{border:j()}],"border-color-x":[{"border-x":j()}],"border-color-y":[{"border-y":j()}],"border-color-s":[{"border-s":j()}],"border-color-e":[{"border-e":j()}],"border-color-bs":[{"border-bs":j()}],"border-color-be":[{"border-be":j()}],"border-color-t":[{"border-t":j()}],"border-color-r":[{"border-r":j()}],"border-color-b":[{"border-b":j()}],"border-color-l":[{"border-l":j()}],"divide-color":[{divide:j()}],"outline-style":[{outline:[...ue(),`none`,`hidden`]}],"outline-offset":[{"outline-offset":[_c,z,R]}],"outline-w":[{outline:[``,_c,Ic,kc]}],"outline-color":[{outline:j()}],shadow:[{shadow:[``,`none`,u,Vc,Fc]}],"shadow-color":[{shadow:j()}],"inset-shadow":[{"inset-shadow":[`none`,d,Vc,Fc]}],"inset-shadow-color":[{"inset-shadow":j()}],"ring-w":[{ring:le()}],"ring-w-inset":[`ring-inset`],"ring-color":[{ring:j()}],"ring-offset-w":[{"ring-offset":[_c,kc]}],"ring-offset-color":[{"ring-offset":j()}],"inset-ring-w":[{"inset-ring":le()}],"inset-ring-color":[{"inset-ring":j()}],"text-shadow":[{"text-shadow":[`none`,f,Vc,Fc]}],"text-shadow-color":[{"text-shadow":j()}],opacity:[{opacity:[_c,z,R]}],"mix-blend":[{"mix-blend":[...N(),`plus-darker`,`plus-lighter`]}],"bg-blend":[{"bg-blend":N()}],"mask-clip":[{"mask-clip":[`border`,`padding`,`content`,`fill`,`stroke`,`view`]},`mask-no-clip`],"mask-composite":[{mask:[`add`,`subtract`,`intersect`,`exclude`]}],"mask-image-linear-pos":[{"mask-linear":[_c]}],"mask-image-linear-from-pos":[{"mask-linear-from":de()}],"mask-image-linear-to-pos":[{"mask-linear-to":de()}],"mask-image-linear-from-color":[{"mask-linear-from":j()}],"mask-image-linear-to-color":[{"mask-linear-to":j()}],"mask-image-t-from-pos":[{"mask-t-from":de()}],"mask-image-t-to-pos":[{"mask-t-to":de()}],"mask-image-t-from-color":[{"mask-t-from":j()}],"mask-image-t-to-color":[{"mask-t-to":j()}],"mask-image-r-from-pos":[{"mask-r-from":de()}],"mask-image-r-to-pos":[{"mask-r-to":de()}],"mask-image-r-from-color":[{"mask-r-from":j()}],"mask-image-r-to-color":[{"mask-r-to":j()}],"mask-image-b-from-pos":[{"mask-b-from":de()}],"mask-image-b-to-pos":[{"mask-b-to":de()}],"mask-image-b-from-color":[{"mask-b-from":j()}],"mask-image-b-to-color":[{"mask-b-to":j()}],"mask-image-l-from-pos":[{"mask-l-from":de()}],"mask-image-l-to-pos":[{"mask-l-to":de()}],"mask-image-l-from-color":[{"mask-l-from":j()}],"mask-image-l-to-color":[{"mask-l-to":j()}],"mask-image-x-from-pos":[{"mask-x-from":de()}],"mask-image-x-to-pos":[{"mask-x-to":de()}],"mask-image-x-from-color":[{"mask-x-from":j()}],"mask-image-x-to-color":[{"mask-x-to":j()}],"mask-image-y-from-pos":[{"mask-y-from":de()}],"mask-image-y-to-pos":[{"mask-y-to":de()}],"mask-image-y-from-color":[{"mask-y-from":j()}],"mask-image-y-to-color":[{"mask-y-to":j()}],"mask-image-radial":[{"mask-radial":[z,R]}],"mask-image-radial-from-pos":[{"mask-radial-from":de()}],"mask-image-radial-to-pos":[{"mask-radial-to":de()}],"mask-image-radial-from-color":[{"mask-radial-from":j()}],"mask-image-radial-to-color":[{"mask-radial-to":j()}],"mask-image-radial-shape":[{"mask-radial":[`circle`,`ellipse`]}],"mask-image-radial-size":[{"mask-radial":[{closest:[`side`,`corner`],farthest:[`side`,`corner`]}]}],"mask-image-radial-pos":[{"mask-radial-at":b()}],"mask-image-conic-pos":[{"mask-conic":[_c]}],"mask-image-conic-from-pos":[{"mask-conic-from":de()}],"mask-image-conic-to-pos":[{"mask-conic-to":de()}],"mask-image-conic-from-color":[{"mask-conic-from":j()}],"mask-image-conic-to-color":[{"mask-conic-to":j()}],"mask-mode":[{mask:[`alpha`,`luminance`,`match`]}],"mask-origin":[{"mask-origin":[`border`,`padding`,`content`,`fill`,`stroke`,`view`]}],"mask-position":[{mask:ae()}],"mask-repeat":[{mask:oe()}],"mask-size":[{mask:se()}],"mask-type":[{"mask-type":[`alpha`,`luminance`]}],"mask-image":[{mask:[`none`,z,R]}],filter:[{filter:[``,`none`,z,R]}],blur:[{blur:fe()}],brightness:[{brightness:[_c,z,R]}],contrast:[{contrast:[_c,z,R]}],"drop-shadow":[{"drop-shadow":[``,`none`,p,Vc,Fc]}],"drop-shadow-color":[{"drop-shadow":j()}],grayscale:[{grayscale:[``,_c,z,R]}],"hue-rotate":[{"hue-rotate":[_c,z,R]}],invert:[{invert:[``,_c,z,R]}],saturate:[{saturate:[_c,z,R]}],sepia:[{sepia:[``,_c,z,R]}],"backdrop-filter":[{"backdrop-filter":[``,`none`,z,R]}],"backdrop-blur":[{"backdrop-blur":fe()}],"backdrop-brightness":[{"backdrop-brightness":[_c,z,R]}],"backdrop-contrast":[{"backdrop-contrast":[_c,z,R]}],"backdrop-grayscale":[{"backdrop-grayscale":[``,_c,z,R]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[_c,z,R]}],"backdrop-invert":[{"backdrop-invert":[``,_c,z,R]}],"backdrop-opacity":[{"backdrop-opacity":[_c,z,R]}],"backdrop-saturate":[{"backdrop-saturate":[_c,z,R]}],"backdrop-sepia":[{"backdrop-sepia":[``,_c,z,R]}],"border-collapse":[{border:[`collapse`,`separate`]}],"border-spacing":[{"border-spacing":w()}],"border-spacing-x":[{"border-spacing-x":w()}],"border-spacing-y":[{"border-spacing-y":w()}],"table-layout":[{table:[`auto`,`fixed`]}],caption:[{caption:[`top`,`bottom`]}],transition:[{transition:[``,`all`,`colors`,`opacity`,`shadow`,`transform`,`none`,z,R]}],"transition-behavior":[{transition:[`normal`,`discrete`]}],duration:[{duration:[_c,`initial`,z,R]}],ease:[{ease:[`linear`,`initial`,_,z,R]}],delay:[{delay:[_c,z,R]}],animate:[{animate:[`none`,v,z,R]}],backface:[{backface:[`hidden`,`visible`]}],perspective:[{perspective:[h,z,R]}],"perspective-origin":[{"perspective-origin":x()}],rotate:[{rotate:pe()}],"rotate-x":[{"rotate-x":pe()}],"rotate-y":[{"rotate-y":pe()}],"rotate-z":[{"rotate-z":pe()}],scale:[{scale:me()}],"scale-x":[{"scale-x":me()}],"scale-y":[{"scale-y":me()}],"scale-z":[{"scale-z":me()}],"scale-3d":[`scale-3d`],skew:[{skew:he()}],"skew-x":[{"skew-x":he()}],"skew-y":[{"skew-y":he()}],transform:[{transform:[z,R,``,`none`,`gpu`,`cpu`]}],"transform-origin":[{origin:x()}],"transform-style":[{transform:[`3d`,`flat`]}],translate:[{translate:ge()}],"translate-x":[{"translate-x":ge()}],"translate-y":[{"translate-y":ge()}],"translate-z":[{"translate-z":ge()}],"translate-none":[`translate-none`],zoom:[{zoom:[vc,z,R]}],accent:[{accent:j()}],appearance:[{appearance:[`none`,`auto`]}],"caret-color":[{caret:j()}],"color-scheme":[{scheme:[`normal`,`dark`,`light`,`light-dark`,`only-dark`,`only-light`]}],cursor:[{cursor:[`auto`,`default`,`pointer`,`wait`,`text`,`move`,`help`,`not-allowed`,`none`,`context-menu`,`progress`,`cell`,`crosshair`,`vertical-text`,`alias`,`copy`,`no-drop`,`grab`,`grabbing`,`all-scroll`,`col-resize`,`row-resize`,`n-resize`,`e-resize`,`s-resize`,`w-resize`,`ne-resize`,`nw-resize`,`se-resize`,`sw-resize`,`ew-resize`,`ns-resize`,`nesw-resize`,`nwse-resize`,`zoom-in`,`zoom-out`,z,R]}],"field-sizing":[{"field-sizing":[`fixed`,`content`]}],"pointer-events":[{"pointer-events":[`auto`,`none`]}],resize:[{resize:[`none`,``,`y`,`x`]}],"scroll-behavior":[{scroll:[`auto`,`smooth`]}],"scrollbar-thumb-color":[{"scrollbar-thumb":j()}],"scrollbar-track-color":[{"scrollbar-track":j()}],"scrollbar-gutter":[{"scrollbar-gutter":[`auto`,`stable`,`both`]}],"scrollbar-w":[{scrollbar:[`auto`,`thin`,`none`]}],"scroll-m":[{"scroll-m":w()}],"scroll-mx":[{"scroll-mx":w()}],"scroll-my":[{"scroll-my":w()}],"scroll-ms":[{"scroll-ms":w()}],"scroll-me":[{"scroll-me":w()}],"scroll-mbs":[{"scroll-mbs":w()}],"scroll-mbe":[{"scroll-mbe":w()}],"scroll-mt":[{"scroll-mt":w()}],"scroll-mr":[{"scroll-mr":w()}],"scroll-mb":[{"scroll-mb":w()}],"scroll-ml":[{"scroll-ml":w()}],"scroll-p":[{"scroll-p":w()}],"scroll-px":[{"scroll-px":w()}],"scroll-py":[{"scroll-py":w()}],"scroll-ps":[{"scroll-ps":w()}],"scroll-pe":[{"scroll-pe":w()}],"scroll-pbs":[{"scroll-pbs":w()}],"scroll-pbe":[{"scroll-pbe":w()}],"scroll-pt":[{"scroll-pt":w()}],"scroll-pr":[{"scroll-pr":w()}],"scroll-pb":[{"scroll-pb":w()}],"scroll-pl":[{"scroll-pl":w()}],"snap-align":[{snap:[`start`,`end`,`center`,`align-none`]}],"snap-stop":[{snap:[`normal`,`always`]}],"snap-type":[{snap:[`none`,`x`,`y`,`both`]}],"snap-strictness":[{snap:[`mandatory`,`proximity`]}],touch:[{touch:[`auto`,`none`,`manipulation`]}],"touch-x":[{"touch-pan":[`x`,`left`,`right`]}],"touch-y":[{"touch-pan":[`y`,`up`,`down`]}],"touch-pz":[`touch-pinch-zoom`],select:[{select:[`none`,`text`,`all`,`auto`]}],"will-change":[{"will-change":[`auto`,`scroll`,`contents`,`transform`,z,R]}],fill:[{fill:[`none`,...j()]}],"stroke-w":[{stroke:[_c,Ic,kc,Ac]}],stroke:[{stroke:[`none`,...j()]}],"forced-color-adjust":[{"forced-color-adjust":[`auto`,`none`]}]},conflictingClassGroups:{"container-named":[`container-type`],overflow:[`overflow-x`,`overflow-y`],overscroll:[`overscroll-x`,`overscroll-y`],inset:[`inset-x`,`inset-y`,`inset-bs`,`inset-be`,`start`,`end`,`top`,`right`,`bottom`,`left`],"inset-x":[`right`,`left`],"inset-y":[`top`,`bottom`],flex:[`basis`,`grow`,`shrink`],gap:[`gap-x`,`gap-y`],p:[`px`,`py`,`ps`,`pe`,`pbs`,`pbe`,`pt`,`pr`,`pb`,`pl`],px:[`pr`,`pl`],py:[`pt`,`pb`],m:[`mx`,`my`,`ms`,`me`,`mbs`,`mbe`,`mt`,`mr`,`mb`,`ml`],mx:[`mr`,`ml`],my:[`mt`,`mb`],size:[`w`,`h`],"font-size":[`leading`],"fvn-normal":[`fvn-ordinal`,`fvn-slashed-zero`,`fvn-figure`,`fvn-spacing`,`fvn-fraction`],"fvn-ordinal":[`fvn-normal`],"fvn-slashed-zero":[`fvn-normal`],"fvn-figure":[`fvn-normal`],"fvn-spacing":[`fvn-normal`],"fvn-fraction":[`fvn-normal`],"line-clamp":[`display`,`overflow`],rounded:[`rounded-s`,`rounded-e`,`rounded-t`,`rounded-r`,`rounded-b`,`rounded-l`,`rounded-ss`,`rounded-se`,`rounded-ee`,`rounded-es`,`rounded-tl`,`rounded-tr`,`rounded-br`,`rounded-bl`],"rounded-s":[`rounded-ss`,`rounded-es`],"rounded-e":[`rounded-se`,`rounded-ee`],"rounded-t":[`rounded-tl`,`rounded-tr`],"rounded-r":[`rounded-tr`,`rounded-br`],"rounded-b":[`rounded-br`,`rounded-bl`],"rounded-l":[`rounded-tl`,`rounded-bl`],"border-spacing":[`border-spacing-x`,`border-spacing-y`],"border-w":[`border-w-x`,`border-w-y`,`border-w-s`,`border-w-e`,`border-w-bs`,`border-w-be`,`border-w-t`,`border-w-r`,`border-w-b`,`border-w-l`],"border-w-x":[`border-w-r`,`border-w-l`],"border-w-y":[`border-w-t`,`border-w-b`],"border-color":[`border-color-x`,`border-color-y`,`border-color-s`,`border-color-e`,`border-color-bs`,`border-color-be`,`border-color-t`,`border-color-r`,`border-color-b`,`border-color-l`],"border-color-x":[`border-color-r`,`border-color-l`],"border-color-y":[`border-color-t`,`border-color-b`],translate:[`translate-x`,`translate-y`,`translate-none`],"translate-none":[`translate`,`translate-x`,`translate-y`,`translate-z`],"scroll-m":[`scroll-mx`,`scroll-my`,`scroll-ms`,`scroll-me`,`scroll-mbs`,`scroll-mbe`,`scroll-mt`,`scroll-mr`,`scroll-mb`,`scroll-ml`],"scroll-mx":[`scroll-mr`,`scroll-ml`],"scroll-my":[`scroll-mt`,`scroll-mb`],"scroll-p":[`scroll-px`,`scroll-py`,`scroll-ps`,`scroll-pe`,`scroll-pbs`,`scroll-pbe`,`scroll-pt`,`scroll-pr`,`scroll-pb`,`scroll-pl`],"scroll-px":[`scroll-pr`,`scroll-pl`],"scroll-py":[`scroll-pt`,`scroll-pb`],touch:[`touch-x`,`touch-y`,`touch-pz`],"touch-x":[`touch`],"touch-y":[`touch`],"touch-pz":[`touch`]},conflictingClassGroupModifiers:{"font-size":[`leading`]},postfixLookupClassGroups:[`container-type`],orderSensitiveModifiers:[`*`,`**`,`after`,`backdrop`,`before`,`details-content`,`file`,`first-letter`,`first-line`,`marker`,`placeholder`,`selection`]}});function el(...e){return $c(oo(e))}var tl=new Intl.DateTimeFormat(void 0,{year:`numeric`,month:`long`,day:`numeric`,hour:`2-digit`,minute:`2-digit`,second:`2-digit`});function nl(e){return e?tl.format(new Date(e)):`Unknown`}function rl(e){return`${Math.round(e/1024)} GiB`}var il=[`B`,`KB`,`MB`,`GB`,`TB`];function al(e){if(e===0)return`0 B`;let t=Math.floor(Math.log(e)/Math.log(1024));return`${(e/1024**t).toFixed(2)} ${il[t]}`}function ol(e){return e?.find(e=>e.Key===`Name`)?.Value}var sl=/\/$/;function cl(e){return e.replace(sl,``)}function ll(e){return e&&(e.endsWith(`/`)?e:`${e}/`)}function ul(e,t){return e.startsWith(t)?e:`${t}${e}`}function dl(e,t){return e.startsWith(t)?e.slice(t.length):e}var fl=lo(`group/button inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-xs/relaxed font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-[2px] focus-visible:ring-ring/30 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-[2px] aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`,{variants:{variant:{default:`bg-primary text-primary-foreground hover:bg-primary/80`,outline:`border-border hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-input/30`,secondary:`bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground`,ghost:`hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50`,destructive:`bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40`,link:`text-primary underline-offset-4 hover:underline`},size:{default:`h-7 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5`,xs:`h-5 gap-1 rounded-sm px-2 text-[0.625rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-2.5`,sm:`h-6 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3`,lg:`h-8 gap-1 px-2.5 text-xs/relaxed has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-4`,icon:`size-7 [&_svg:not([class*='size-'])]:size-3.5`,"icon-xs":`size-5 rounded-sm [&_svg:not([class*='size-'])]:size-2.5`,"icon-sm":`size-6 [&_svg:not([class*='size-'])]:size-3`,"icon-lg":`size-8 [&_svg:not([class*='size-'])]:size-4`}},defaultVariants:{variant:`default`,size:`default`}});function pl(e){let t=(0,fa.c)(12),n,r,i,a;t[0]===e?(n=t[1],r=t[2],i=t[3],a=t[4]):({className:n,variant:i,size:a,...r}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i,t[4]=a);let o=i===void 0?`default`:i,s=a===void 0?`default`:a,c;t[5]!==n||t[6]!==s||t[7]!==o?(c=el(fl({variant:o,size:s,className:n})),t[5]=n,t[6]=s,t[7]=o,t[8]=c):c=t[8];let l;return t[9]!==r||t[10]!==c?(l=(0,F.jsx)(Ds,{className:c,"data-slot":`button`,...r}),t[9]=r,t[10]=c,t[11]=l):l=t[11],l}var ml=function(e){return e.disabled=`data-disabled`,e.valid=`data-valid`,e.invalid=`data-invalid`,e.touched=`data-touched`,e.dirty=`data-dirty`,e.filled=`data-filled`,e.focused=`data-focused`,e}({}),hl={badInput:!1,customError:!1,patternMismatch:!1,rangeOverflow:!1,rangeUnderflow:!1,stepMismatch:!1,tooLong:!1,tooShort:!1,typeMismatch:!1,valid:null,valueMissing:!1},gl={valid:null,touched:!1,dirty:!1,filled:!1,focused:!1},_l={disabled:!1,...gl},vl={valid(e){return e===null?null:e?{[ml.valid]:``}:{[ml.invalid]:``}}},yl=P.createContext({invalid:void 0,name:void 0,validityData:{state:hl,errors:[],error:``,value:``,initialValue:null},setValidityData:Ka,disabled:void 0,touched:gl.touched,setTouched:Ka,dirty:gl.dirty,setDirty:Ka,filled:gl.filled,setFilled:Ka,focused:gl.focused,setFocused:Ka,validate:()=>null,validationMode:`onSubmit`,validationDebounceTime:0,shouldValidateOnChange:()=>!1,state:_l,markedDirtyRef:{current:!1},registerFieldControl:Ka,validation:{getValidationProps:(e=Ja)=>e,getInputValidationProps:(e=Ja)=>e,inputRef:{current:null},commit:async()=>{}}});function bl(e=!0){let t=P.useContext(yl);if(t.setValidityData===Ka&&!e)throw Error(Pa(28));return t}var xl=0;function Sl(e,t=`mui`){let[n,r]=P.useState(e),i=e||n;return P.useEffect(()=>{n??(xl+=1,r(`${t}-${xl}`))},[n,t]),i}var Cl=ys.useId;function wl(e,t){if(Cl!==void 0){let n=Cl();return e??(t?`${t}-${n}`:n)}return Sl(e,t)}function Tl(e){return wl(e,`base-ui`)}var El=P.createContext({controlId:void 0,registerControlId:Ka,labelId:void 0,setLabelId:Ka,messageIds:[],setMessageIds:Ka,getDescriptionProps:e=>e});function Dl(){return P.useContext(El)}function Ol(e={}){let{id:t,implicit:n=!1,controlRef:r}=e,{controlId:i,registerControlId:a}=Dl(),o=Tl(t),s=n?i:void 0,c=Ia(()=>Symbol(`labelable-control`)),l=P.useRef(!1),u=P.useRef(t!=null),d=gs(()=>{!l.current||a===Ka||(l.current=!1,a(c.current,void 0))});return bs(()=>{if(a===Ka)return;let e;if(n){let n=r?.current;e=Jo(n)&&n.closest(`label`)!=null?t??null:s??o}else if(t!=null)u.current=!0,e=t;else if(u.current)e=o;else{d();return}if(e===void 0){d();return}l.current=!0,a(c.current,e)},[t,r,s,a,n,o,c,d]),P.useEffect(()=>d,[d]),i??o}function kl(e){return e?.ownerDocument||document}var Al=typeof navigator<`u`,jl=Bl(),Ml=Hl(),Nl=Vl(),Pl=typeof CSS>`u`||!CSS.supports?!1:CSS.supports(`-webkit-backdrop-filter:none`),Fl=jl.platform===`MacIntel`&&jl.maxTouchPoints>1?!0:/iP(hone|ad|od)|iOS/.test(jl.platform);Al&&/firefox/i.test(Nl);var Il=Al&&/apple/i.test(navigator.vendor);Al&&/Edg/i.test(Nl);var Ll=Al&&/android/i.test(Ml)||/android/i.test(Nl),Rl=Al&&Ml.toLowerCase().startsWith(`mac`)&&!navigator.maxTouchPoints,zl=Nl.includes(`jsdom/`);function Bl(){if(!Al)return{platform:``,maxTouchPoints:-1};let e=navigator.userAgentData;return e?.platform?{platform:e.platform,maxTouchPoints:navigator.maxTouchPoints}:{platform:navigator.platform??``,maxTouchPoints:navigator.maxTouchPoints??-1}}function Vl(){if(!Al)return``;let e=navigator.userAgentData;return e&&Array.isArray(e.brands)?e.brands.map(({brand:e,version:t})=>`${e}/${t}`).join(` `):navigator.userAgent}function Hl(){if(!Al)return``;let e=navigator.userAgentData;return e?.platform?e.platform:navigator.platform??``}var Ul=`data-base-ui-focusable`,Wl=`input:not([type='hidden']):not([disabled]),[contenteditable]:not([contenteditable='false']),textarea:not([disabled])`,Gl=`ArrowLeft`,Kl=`ArrowRight`,ql=`ArrowUp`,Jl=`ArrowDown`;function Yl(e){let t=e.activeElement;for(;t?.shadowRoot?.activeElement!=null;)t=t.shadowRoot.activeElement;return t}function Xl(e,t){if(!e||!t)return!1;let n=t.getRootNode?.();if(e.contains(t))return!0;if(n&&Xo(n)){let n=t;for(;n;){if(e===n)return!0;n=n.parentNode||n.host}}return!1}function Zl(e){return`composedPath`in e?e.composedPath()[0]:e.target}function Ql(e,t){if(!Jo(e))return!1;let n=e;if(t.hasElement(n))return!n.hasAttribute(`data-trigger-disabled`);for(let[,e]of t.entries())if(Xl(e,n))return!e.hasAttribute(`data-trigger-disabled`);return!1}function $l(e,t){if(t==null)return!1;if(`composedPath`in e)return e.composedPath().includes(t);let n=e;return n.target!=null&&t.contains(n.target)}function eu(e){return e.matches(`html,body`)}function tu(e){return Yo(e)&&e.matches(`input:not([type='hidden']):not([disabled]),[contenteditable]:not([contenteditable='false']),textarea:not([disabled])`)}function nu(e){return e?.closest(`button,a[href],[role="button"],select,[tabindex]:not([tabindex="-1"]),${Wl}`)!=null}function ru(e){return e?e.getAttribute(`role`)===`combobox`&&tu(e):!1}function iu(e){if(!e||zl)return!0;try{return e.matches(`:focus-visible`)}catch{return!0}}function au(e){return e?e.hasAttribute(`data-base-ui-focusable`)?e:e.querySelector(`[data-base-ui-focusable]`)||e:null}function ou(e,t,n=!0){return e.filter(e=>e.parentId===t).flatMap(t=>[...!n||t.context?.open?[t]:[],...ou(e,t.id,n)])}function su(e,t){let n=[],r=e.find(e=>e.id===t)?.parentId;for(;r;){let t=e.find(e=>e.id===r);r=t?.parentId,t&&(n=n.concat(t))}return n}function cu(e){e.preventDefault(),e.stopPropagation()}function lu(e){return`nativeEvent`in e}function uu(e){return e.pointerType===``&&e.isTrusted?!0:Ll&&e.pointerType?e.type===`click`&&e.buttons===1:e.detail===0&&!e.pointerType}function du(e){return zl?!1:!Ll&&e.width===0&&e.height===0||Ll&&e.width===1&&e.height===1&&e.pressure===0&&e.detail===0&&e.pointerType===`mouse`||e.width<1&&e.height<1&&e.pressure===0&&e.detail===0&&e.pointerType===`touch`}function fu(e,t){let n=[`mouse`,`pen`];return t||n.push(``,void 0),n.includes(e)}function pu(e){let t=e.type;return t===`click`||t===`mousedown`||t===`keydown`||t===`keyup`}var mu=[`top`,`right`,`bottom`,`left`],hu=Math.min,gu=Math.max,_u=Math.round,vu=Math.floor,yu=e=>({x:e,y:e}),bu={left:`right`,right:`left`,bottom:`top`,top:`bottom`};function xu(e,t,n){return gu(e,hu(t,n))}function Su(e,t){return typeof e==`function`?e(t):e}function Cu(e){return e.split(`-`)[0]}function wu(e){return e.split(`-`)[1]}function Tu(e){return e===`x`?`y`:`x`}function Eu(e){return e===`y`?`height`:`width`}function Du(e){let t=e[0];return t===`t`||t===`b`?`y`:`x`}function Ou(e){return Tu(Du(e))}function ku(e,t,n){n===void 0&&(n=!1);let r=wu(e),i=Ou(e),a=Eu(i),o=i===`x`?r===(n?`end`:`start`)?`right`:`left`:r===`start`?`bottom`:`top`;return t.reference[a]>t.floating[a]&&(o=Ru(o)),[o,Ru(o)]}function Au(e){let t=Ru(e);return[ju(e),t,ju(t)]}function ju(e){return e.includes(`start`)?e.replace(`start`,`end`):e.replace(`end`,`start`)}var Mu=[`left`,`right`],Nu=[`right`,`left`],Pu=[`top`,`bottom`],Fu=[`bottom`,`top`];function Iu(e,t,n){switch(e){case`top`:case`bottom`:return n?t?Nu:Mu:t?Mu:Nu;case`left`:case`right`:return t?Pu:Fu;default:return[]}}function Lu(e,t,n,r){let i=wu(e),a=Iu(Cu(e),n===`start`,r);return i&&(a=a.map(e=>e+`-`+i),t&&(a=a.concat(a.map(ju)))),a}function Ru(e){let t=Cu(e);return bu[t]+e.slice(t.length)}function zu(e){return{top:0,right:0,bottom:0,left:0,...e}}function Bu(e){return typeof e==`number`?{top:e,right:e,bottom:e,left:e}:zu(e)}function Vu(e){let{x:t,y:n,width:r,height:i}=e;return{width:r,height:i,top:n,left:t,right:t+r,bottom:n+i,x:t,y:n}}function Hu(e,t,n){return Math.floor(e/t)!==n}function Uu(e,t){return t<0||t>=e.length}function Wu(e,t){return Ku(e.current,{disabledIndices:t})}function Gu(e,t){return Ku(e.current,{decrement:!0,startingIndex:e.current.length,disabledIndices:t})}function Ku(e,{startingIndex:t=-1,decrement:n=!1,disabledIndices:r,amount:i=1}={}){let a=t;do a+=n?-i:i;while(a>=0&&a<=e.length-1&&Zu(e,a,r));return a}function qu(e,{event:t,orientation:n,loopFocus:r,onLoop:i,rtl:a,cols:o,disabledIndices:s,minIndex:c,maxIndex:l,prevIndex:u,stopEvent:d=!1}){let f=u,p;if(t.key===`ArrowUp`?p=`up`:t.key===`ArrowDown`&&(p=`down`),p){let n=[],a=[],m=!1,h=0;{let t=null,r=-1;e.forEach((e,i)=>{if(e==null)return;h+=1;let o=e.closest(`[role="row"]`);o&&(m=!0),(o!==t||r===-1)&&(t=o,r+=1,n[r]=[]),n[r].push(i),a[i]=r})}let g=!1,_=0;if(m)for(let e of n){let t=e.length;t>_&&(_=t),t!==o&&(g=!0)}let v=g&&h{if(!g||u===-1)return;let c=a[u];if(c==null)return;let l=n[c].indexOf(u),d=o===`up`?-1:1;for(let o=c+d,f=0;f=n.length){if(!r||v)return;if(o=o<0?n.length-1:0,i){let e=Math.min(l,n[o].length-1);o=a[i(t,u,n[o][e]??n[o][0])]??o}}let c=n[o];for(let t=Math.min(l,c.length-1);t>=0;--t){let n=c[t];if(!Zu(e,n,s))return n}}},x=t=>{if(!v||u===-1)return;let n=u%y,i=t===`up`?-y:y,a=l-l%y,o=vu(l/y)+1;for(let t=u-n+i,c=0;cl){if(!r)return;t=t<0?a:0}let i=Math.min(t+y-1,l);for(let r=Math.min(t+n,i);r>=t;--r)if(!Zu(e,r,s))return r}};d&&cu(t);let S=b(p)??x(p);if(S!==void 0)f=S;else if(u===-1)f=p===`up`?l:c;else if(f=Ku(e,{startingIndex:u,amount:y,decrement:p===`up`,disabledIndices:s}),r){if(p===`up`&&(u-ye?r:r-y,i&&(f=i(t,u,f))}p===`down`&&u+y>l&&(f=Ku(e,{startingIndex:u%y-y,amount:y,disabledIndices:s}),i&&(f=i(t,u,f)))}Uu(e,f)&&(f=u)}if(n===`both`){let n=vu(u/o);t.key===(a?`ArrowLeft`:`ArrowRight`)&&(d&&cu(t),u%o===o-1?r&&(f=Ku(e,{startingIndex:u-u%o-1,disabledIndices:s}),i&&(f=i(t,u,f))):(f=Ku(e,{startingIndex:u,disabledIndices:s}),r&&Hu(f,o,n)&&(f=Ku(e,{startingIndex:u-u%o-1,disabledIndices:s}),i&&(f=i(t,u,f)))),Hu(f,o,n)&&(f=u)),t.key===(a?`ArrowRight`:`ArrowLeft`)&&(d&&cu(t),u%o===0?r&&(f=Ku(e,{startingIndex:u+(o-u%o),decrement:!0,disabledIndices:s}),i&&(f=i(t,u,f))):(f=Ku(e,{startingIndex:u,decrement:!0,disabledIndices:s}),r&&Hu(f,o,n)&&(f=Ku(e,{startingIndex:u+(o-u%o),decrement:!0,disabledIndices:s}),i&&(f=i(t,u,f)))),Hu(f,o,n)&&(f=u));let c=vu(l/o)===n;Uu(e,f)&&(r&&c?(f=t.key===(a?`ArrowRight`:`ArrowLeft`)?l:Ku(e,{startingIndex:u-u%o-1,disabledIndices:s}),i&&(f=i(t,u,f))):f=u)}return f}function Ju(e,t,n){let r=[],i=0;return e.forEach(({width:e,height:a},o)=>{let s=!1;for(n&&(i=0);!s;){let n=[];for(let r=0;rr[e]==null)?(n.forEach(e=>{r[e]=o}),s=!0):i+=1}}),[...r]}function Yu(e,t,n,r,i){if(e===-1)return-1;let a=n.indexOf(e),o=t[e];switch(i){case`tl`:return a;case`tr`:return o?a+o.width-1:a;case`bl`:return o?a+(o.height-1)*r:a;case`br`:return n.lastIndexOf(e);default:return-1}}function Xu(e,t){return t.flatMap((t,n)=>e.includes(t)?[n]:[])}function Zu(e,t,n){if(typeof n==`function`?n(t):n?.includes(t)??!1)return!0;let r=e[t];return r?$u(r)?!n&&(r.hasAttribute(`disabled`)||r.getAttribute(`aria-disabled`)===`true`):!0:!1}function Qu(e){return e.visibility===`hidden`||e.visibility===`collapse`}function $u(e,t=e?cs(e):null){return!e||!e.isConnected||!t||Qu(t)?!1:typeof e.checkVisibility==`function`?e.checkVisibility():t.display!==`none`&&t.display!==`contents`}var ed=`a[href],button,input,select,textarea,summary,details,iframe,object,embed,[tabindex],[contenteditable]:not([contenteditable="false"]),audio[controls],video[controls]`;function td(e){let t=e.assignedSlot;if(t)return t;if(e.parentElement)return e.parentElement;let n=e.getRootNode();return Xo(n)?n.host:null}function nd(e){for(let t of Array.from(e.children))if(Wo(t)===`summary`)return t;return null}function rd(e,t){let n=nd(t);return!!n&&(e===n||Xl(n,e))}function id(e){let t=e?Wo(e):``;return e!=null&&e.matches(ed)&&(t!==`summary`||e.parentElement!=null&&Wo(e.parentElement)===`details`&&nd(e.parentElement)===e)&&(t!==`details`||nd(e)==null)&&(t!==`input`||e.type!==`hidden`)}function ad(e){if(!id(e)||!e.isConnected||e.matches(`:disabled`))return!1;for(let t=e;t;t=td(t)){let n=t!==e,r=Wo(t)===`slot`;if(t.hasAttribute(`inert`)||n&&Wo(t)===`details`&&!t.open&&!rd(e,t)||t.hasAttribute(`hidden`)||!r&&!od(t,n))return!1}return!0}function od(e,t){let n=cs(e);return t?n.display!==`none`:$u(e,n)}function sd(e){let t=e.tabIndex;if(t<0){let t=Wo(e);if(t===`details`||t===`audio`||t===`video`||Yo(e)&&e.isContentEditable)return 0}return t}function cd(e){if(Wo(e)!==`input`)return null;let t=e;return t.type===`radio`&&t.name!==``?t:null}function ld(e,t){let n=cd(e);if(!n)return!0;let r=t.find(e=>{let t=cd(e);return t?.name===n.name&&t.form===n.form&&t.checked});return r?r===n:t.find(e=>{let t=cd(e);return t?.name===n.name&&t.form===n.form})===n}function ud(e){if(Yo(e)&&Wo(e)===`slot`){let t=e.assignedElements({flatten:!0});if(t.length>0)return t}return Yo(e)&&e.shadowRoot?Array.from(e.shadowRoot.children):Array.from(e.children)}function dd(e,t){ud(e).forEach(e=>{id(e)&&t.push(e),dd(e,t)})}function fd(e,t,n){ud(e).forEach(e=>{Yo(e)&&e.matches(t)&&n.push(e),fd(e,t,n)})}function pd(e){return ad(e)&&sd(e)>=0}function md(e){let t=[];return dd(e,t),t.filter(ad)}function hd(e){let t=md(e);return t.filter(e=>sd(e)>=0&&ld(e,t))}function gd(e,t){let n=hd(e),r=n.length;if(r===0)return;let i=Yl(kl(e)),a=n.indexOf(i);return n[a===-1?t===1?0:r-1:a+t]}function _d(e){return gd(kl(e).body,1)||e}function vd(e){return gd(kl(e).body,-1)||e}function yd(e,t){let n=t||e.currentTarget,r=e.relatedTarget;return!r||!Xl(n,r)}function bd(e){hd(e).forEach(e=>{e.dataset.tabindex=e.getAttribute(`tabindex`)||``,e.setAttribute(`tabindex`,`-1`)})}function xd(e){let t=[];fd(e,`[data-tabindex]`,t),t.forEach(e=>{let t=e.dataset.tabindex;delete e.dataset.tabindex,t?e.setAttribute(`tabindex`,t):e.removeAttribute(`tabindex`)})}var Sd=[];function Cd(e){P.useEffect(e,Sd)}var wd=0,Td=class e{static create(){return new e}currentId=wd;start(e,t){this.clear(),this.currentId=setTimeout(()=>{this.currentId=wd,t()},e)}isStarted(){return this.currentId!==wd}clear=()=>{this.currentId!==wd&&(clearTimeout(this.currentId),this.currentId=wd)};disposeEffect=()=>this.clear};function Ed(){let e=Ia(Td.create).current;return Cd(e.disposeEffect),e}var Dd=null;globalThis.requestAnimationFrame;var Od=new class{callbacks=[];callbacksCount=0;nextId=1;startId=1;isScheduled=!1;tick=e=>{this.isScheduled=!1;let t=this.callbacks,n=this.callbacksCount;if(this.callbacks=[],this.callbacksCount=0,this.startId=this.nextId,n>0)for(let n=0;n=this.callbacks.length||(this.callbacks[t]=null,--this.callbacksCount)}},kd=class e{static create(){return new e}static request(e){return Od.request(e)}static cancel(e){return Od.cancel(e)}currentId=Dd;request(e){this.cancel(),this.currentId=Od.request(()=>{this.currentId=Dd,e()})}cancel=()=>{this.currentId!==Dd&&(Od.cancel(this.currentId),this.currentId=Dd)};disposeEffect=()=>this.cancel};function Ad(){let e=Ia(kd.create).current;return Cd(e.disposeEffect),e}function jd(e){return e==null?e:`current`in e?e.current:e}var Md=function(e){return e.startingStyle=`data-starting-style`,e.endingStyle=`data-ending-style`,e}({}),Nd={[Md.startingStyle]:``},Pd={[Md.endingStyle]:``},Fd={transitionStatus(e){return e===`starting`?Nd:e===`ending`?Pd:null}};function Id(e,t=!1,n=!0){let r=Ad();return gs((i,a=null)=>{r.cancel();let o=jd(e);if(o==null)return;let s=o,c=()=>{gi.flushSync(i)};if(typeof s.getAnimations!=`function`||globalThis.BASE_UI_ANIMATIONS_DISABLED){i();return}function l(){Promise.all(s.getAnimations().map(e=>e.finished)).then(()=>{a?.aborted||c()}).catch(()=>{if(n){a?.aborted||c();return}let e=s.getAnimations();!a?.aborted&&e.length>0&&e.some(e=>e.pending||e.playState!==`finished`)&&l()})}if(t){let e=Md.startingStyle;if(!s.hasAttribute(e)){r.request(l);return}let t=new MutationObserver(()=>{s.hasAttribute(e)||(t.disconnect(),l())});t.observe(s,{attributes:!0,attributeFilter:[e]}),a?.addEventListener(`abort`,()=>t.disconnect(),{once:!0});return}r.request(l)})}function Ld(e){let{enabled:t=!0,open:n,ref:r,onComplete:i}=e,a=gs(i),o=Id(r,n,!1);P.useEffect(()=>{if(!t)return;let e=new AbortController;return o(a,e.signal),()=>{e.abort()}},[t,n,a,o])}function Rd(e,t=!1,n=!1){let[r,i]=P.useState(e&&t?`idle`:void 0),[a,o]=P.useState(e);return e&&!a&&(o(!0),i(`starting`)),!e&&a&&r!==`ending`&&!n&&i(`ending`),!e&&!a&&r===`ending`&&i(void 0),bs(()=>{if(!e&&a&&r!==`ending`&&n){let e=kd.request(()=>{i(`ending`)});return()=>{kd.cancel(e)}}},[e,a,r,n]),bs(()=>{if(!e||t)return;let n=kd.request(()=>{i(void 0)});return()=>{kd.cancel(n)}},[t,e]),bs(()=>{if(!e||!t)return;e&&a&&r!==`idle`&&i(`starting`);let n=kd.request(()=>{i(`idle`)});return()=>{kd.cancel(n)}},[t,e,a,r]),{mounted:a,setMounted:o,transitionStatus:r}}function zd({controlled:e,default:t,name:n,state:r=`value`}){let{current:i}=P.useRef(e!==void 0),[a,o]=P.useState(t);return[i?e:a,P.useCallback(e=>{i||o(e)},[])]}function Bd(e,t){let{enabled:n=!0,getValue:r,id:i,value:a}=t,{registerFieldControl:o}=bl(),s=P.useRef(null);s.current||=Symbol(),bs(()=>{let t=s.current;if(!(!t||!n))return o(t,{controlRef:e,getValue:r,id:i,value:a}),()=>{o(t,void 0)}},[e,n,r,i,o,a])}var Vd=`none`,Hd=`trigger-press`,Ud=`trigger-hover`,Wd=`trigger-focus`,Gd=`outside-press`,Kd=`item-press`,qd=`close-press`,Jd=`focus-out`,Yd=`escape-key`,Xd=`list-navigation`,Zd=`cancel-open`,Qd=`disabled`,$d=`imperative-action`,ef=`window-resize`;function tf(e,t,n,r){let i=!1,a=!1,o=r??Ja;return{reason:e,event:t??new Event(`base-ui`),cancel(){i=!0},allowPropagation(){a=!0},get isCanceled(){return i},get isPropagationAllowed(){return a},trigger:n,...o}}var nf=P.forwardRef(function(e,t){let{render:n,className:r,id:i,name:a,value:o,disabled:s=!1,onValueChange:c,defaultValue:l,autoFocus:u=!1,style:d,...f}=e,{state:p,name:m,disabled:h,setTouched:g,setDirty:_,validityData:v,setFocused:y,setFilled:b,validationMode:x,validation:S}=bl(),C=h||s,w=m??a,T={...p,disabled:C},{labelId:E}=Dl(),ee=Ol({id:i});bs(()=>{let e=o!=null;S.inputRef.current?.value||e&&o!==``?b(!0):e&&o===``&&b(!1)},[S.inputRef,b,o]);let D=P.useRef(null);bs(()=>{u&&D.current===Yl(kl(D.current))&&y(!0)},[u,y]);let[O]=zd({controlled:o,default:l,name:`FieldControl`,state:`value`}),te=o!==void 0,ne=te?O:void 0,re=gs(()=>S.inputRef.current?.value);return Bd(S.inputRef,{id:ee,value:ne,getValue:re}),Qa(`input`,e,{ref:[t,D],state:T,props:[{id:ee,disabled:C,name:w,ref:S.inputRef,"aria-labelledby":E,autoFocus:u,...te?{value:ne}:{defaultValue:l},onChange(e){let t=e.currentTarget.value;c?.(t,tf(Vd,e.nativeEvent)),_(t!==v.initialValue),b(t!==``)},onFocus(){y(!0)},onBlur(e){g(!0),y(!1),x===`onBlur`&&S.commit(e.currentTarget.value)},onKeyDown(e){e.currentTarget.tagName===`INPUT`&&e.key===`Enter`&&(g(!0),S.commit(e.currentTarget.value))}},S.getInputValidationProps(),f],stateAttributesMapping:vl})}),rf=P.forwardRef(function(e,t){return(0,F.jsx)(nf,{ref:t,...e})});function af(e){let t=(0,fa.c)(10),n,r,i;t[0]===e?(n=t[1],r=t[2],i=t[3]):({className:n,type:i,...r}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i);let a;t[4]===n?a=t[5]:(a=el(`h-7 w-full min-w-0 rounded-md border border-input bg-input/20 px-2 py-0.5 text-sm transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-xs/relaxed file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 md:text-xs/relaxed dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40`,n),t[4]=n,t[5]=a);let o;return t[6]!==r||t[7]!==a||t[8]!==i?(o=(0,F.jsx)(rf,{className:a,"data-slot":`input`,type:i,...r}),t[6]=r,t[7]=a,t[8]=i,t[9]=o):o=t[9],o}var of=P.forwardRef(function(e,t){let{className:n,render:r,orientation:i=`horizontal`,style:a,...o}=e;return Qa(`div`,e,{state:{orientation:i},ref:t,props:[{role:`separator`,"aria-orientation":i},o]})});function sf(e){let t=(0,fa.c)(10),n,r,i;t[0]===e?(n=t[1],r=t[2],i=t[3]):({className:n,orientation:i,...r}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i);let a=i===void 0?`horizontal`:i,o;t[4]===n?o=t[5]:(o=el(`shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px data-[orientation=vertical]:self-stretch`,n),t[4]=n,t[5]=o);let s;return t[6]!==a||t[7]!==r||t[8]!==o?(s=(0,F.jsx)(of,{className:o,"data-slot":`separator`,orientation:a,...r}),t[6]=a,t[7]=r,t[8]=o,t[9]=s):s=t[9],s}var cf=P.createContext(void 0);function lf(e){let t=P.useContext(cf);if(e===!1&&t===void 0)throw Error(Pa(27));return t}var uf=function(e){return e.open=`data-open`,e.closed=`data-closed`,e[e.startingStyle=Md.startingStyle]=`startingStyle`,e[e.endingStyle=Md.endingStyle]=`endingStyle`,e.anchorHidden=`data-anchor-hidden`,e.side=`data-side`,e.align=`data-align`,e}({}),df=function(e){return e.popupOpen=`data-popup-open`,e.pressed=`data-pressed`,e}({}),ff={[df.popupOpen]:``},pf={[df.popupOpen]:``,[df.pressed]:``},mf={[uf.open]:``},hf={[uf.closed]:``},gf={[uf.anchorHidden]:``},_f={open(e){return e?ff:null}},vf={open(e){return e?pf:null}},yf={open(e){return e?mf:hf},anchorHidden(e){return e?gf:null}},bf={...yf,...Fd},xf=P.forwardRef(function(e,t){let{render:n,className:r,style:i,forceRender:a=!1,...o}=e,{store:s}=lf(),c=s.useState(`open`),l=s.useState(`nested`),u=s.useState(`mounted`);return Qa(`div`,e,{state:{open:c,transitionStatus:s.useState(`transitionStatus`)},ref:[s.context.backdropRef,t],stateAttributesMapping:bf,props:[{role:`presentation`,hidden:!u,style:{userSelect:`none`,WebkitUserSelect:`none`}},o],enabled:a||!l})}),Sf=P.forwardRef(function(e,t){let{render:n,className:r,disabled:i=!1,nativeButton:a=!0,style:o,...s}=e,{store:c}=lf(),l=c.useState(`open`);function u(e){l&&c.setOpen(!1,tf(qd,e.nativeEvent))}let{getButtonProps:d,buttonRef:f}=ws({disabled:i,native:a});return Qa(`button`,e,{state:{disabled:i},ref:[t,f],props:[{onClick:u},s,d]})}),Cf=P.forwardRef(function(e,t){let{render:n,className:r,style:i,id:a,...o}=e,{store:s}=lf(),c=Tl(a);return s.useSyncedValueWithCleanup(`descriptionElementId`,c),Qa(`p`,e,{ref:t,props:[{id:c},o]})});function wf(e,t){return t!=null&&!fu(t)?0:typeof e==`function`?e():e}function Tf(e,t,n){let r=wf(e,n);return typeof r==`number`?r:r?.[t]}function Ef(e){return typeof e==`function`?e():e}function Df(e,t){return t||e===`click`||e===`mousedown`}var Of=P.createContext({hasProvider:!1,timeoutMs:0,delayRef:{current:0},initialDelayRef:{current:0},timeout:new Td,currentIdRef:{current:null},currentContextRef:{current:null}});function kf(e){let{children:t,delay:n,timeoutMs:r=0}=e,i=P.useRef(n),a=P.useRef(n),o=P.useRef(null),s=P.useRef(null),c=Ed();return(0,F.jsx)(Of.Provider,{value:P.useMemo(()=>({hasProvider:!0,delayRef:i,initialDelayRef:a,currentIdRef:o,timeoutMs:r,currentContextRef:s,timeout:c}),[r,c]),children:t})}function Af(e,t={open:!1}){let n=`rootStore`in e?e.rootStore:e,r=n.useState(`floatingId`),{open:i}=t,{currentIdRef:a,delayRef:o,timeoutMs:s,initialDelayRef:c,currentContextRef:l,hasProvider:u,timeout:d}=P.useContext(Of),[f,p]=P.useState(!1);return bs(()=>{function e(){p(!1),l.current?.setIsInstantPhase(!1),a.current=null,l.current=null,o.current=c.current}if(a.current&&!i&&a.current===r){if(p(!1),s){let t=r;return d.start(s,()=>{n.select(`open`)||a.current&&a.current!==t||e()}),()=>{d.clear()}}e()}},[i,r,a,o,s,c,l,d,n]),bs(()=>{if(!i)return;let e=l.current,t=a.current;d.clear(),l.current={onOpenChange:n.setOpen,setIsInstantPhase:p},a.current=r,o.current={open:0,close:Tf(c.current,`close`)},t!==null&&t!==r?(p(!0),e?.setIsInstantPhase(!0),e?.onOpenChange(!1,tf(Vd))):(p(!1),e?.setIsInstantPhase(!1))},[i,r,n,a,o,s,c,l,d]),bs(()=>()=>{l.current=null},[l]),P.useMemo(()=>({hasProvider:u,delayRef:o,isInstantPhase:f}),[u,o,f])}function jf(e,t,n,r){return e.addEventListener(t,n,r),()=>{e.removeEventListener(t,n,r)}}function Mf(...e){return()=>{for(let t=0;t{t.current=t.next}};return t}var Ff={clipPath:`inset(50%)`,overflow:`hidden`,whiteSpace:`nowrap`,border:0,padding:0,width:1,height:1,margin:-1},If={...Ff,position:`fixed`,top:0,left:0},Lf={...Ff,position:`absolute`},Rf=P.forwardRef(function(e,t){let[n,r]=P.useState();bs(()=>{Il&&r(`button`)},[]);let i={tabIndex:0,role:n};return(0,F.jsx)(`span`,{...e,ref:t,style:If,"aria-hidden":n?void 0:!0,...i,"data-base-ui-focus-guard":``})});function zf(e){return`data-base-ui-${e}`}var Bf=0;function Vf(e,t={}){let{preventScroll:n=!1,cancelPrevious:r=!0,sync:i=!1}=t;r&&cancelAnimationFrame(Bf);let a=()=>e?.focus({preventScroll:n});if(i)return a(),Ka;let o=requestAnimationFrame(a);return Bf=o,()=>{Bf===o&&(cancelAnimationFrame(o),Bf=0)}}var Hf={inert:new WeakMap,"aria-hidden":new WeakMap},Uf=`data-base-ui-inert`,Wf={inert:new WeakSet,"aria-hidden":new WeakSet},Gf=new WeakMap,Kf=0;function qf(e){return Wf[e]}function Jf(e){return e?Xo(e)?e.host:Jf(e.parentNode):null}var Yf=(e,t)=>t.map(t=>{if(e.contains(t))return t;let n=Jf(t);return e.contains(n)?n:null}).filter(e=>e!=null),Xf=e=>{let t=new Set;return e.forEach(e=>{let n=e;for(;n&&!t.has(n);)t.add(n),n=n.parentNode}),t},Zf=(e,t,n)=>{let r=[],i=e=>{!e||n.has(e)||Array.from(e.children).forEach(e=>{Wo(e)!==`script`&&(t.has(e)?i(e):r.push(e))})};return i(e),r};function Qf(e,t,n,r,{mark:i=!0,markerIgnoreElements:a=[]}){let o=r?`inert`:n?`aria-hidden`:null,s=null,c=null,l=Yf(t,e),u=i?Yf(t,a):[],d=new Set(u),f=i?Zf(t,Xf(l),new Set(l)).filter(e=>!d.has(e)):[],p=[],m=[];if(o){let e=Hf[o],n=qf(o);c=n,s=e;let r=Yf(t,Array.from(t.querySelectorAll(`[aria-live]`))),i=l.concat(r);Zf(t,Xf(i),new Set(i)).forEach(t=>{let r=t.getAttribute(o),i=r!==null&&r!==`false`,a=(e.get(t)||0)+1;e.set(t,a),p.push(t),a===1&&i&&n.add(t),i||t.setAttribute(o,o===`inert`?``:`true`)})}return i&&f.forEach(e=>{let t=(Gf.get(e)||0)+1;Gf.set(e,t),m.push(e),t===1&&e.setAttribute(Uf,``)}),Kf+=1,()=>{s&&p.forEach(e=>{let t=(s.get(e)||0)-1;s.set(e,t),t||(!c?.has(e)&&o&&e.removeAttribute(o),c?.delete(e))}),i&&m.forEach(e=>{let t=(Gf.get(e)||0)-1;Gf.set(e,t),t||e.removeAttribute(Uf)}),--Kf,Kf||(Hf.inert=new WeakMap,Hf[`aria-hidden`]=new WeakMap,Wf.inert=new WeakSet,Wf[`aria-hidden`]=new WeakSet,Gf=new WeakMap)}}function $f(e,t={}){let{ariaHidden:n=!1,inert:r=!1,mark:i=!0,markerIgnoreElements:a=[]}=t,o=kl(e[0]).body;return Qf(e,o,n,r,{mark:i,markerIgnoreElements:a})}var ep={style:{transition:`none`}},tp={fallbackAxisSide:`none`},np={fallbackAxisSide:`end`},rp={clipPath:`inset(50%)`,position:`fixed`,top:0,left:0},ip=P.createContext(null),ap=()=>P.useContext(ip),op=zf(`portal`);function sp(e={}){let{ref:t,container:n,componentProps:r=Ja,elementProps:i}=e,a=wl(),o=ap()?.portalNode,[s,c]=P.useState(null),[l,u]=P.useState(null),d=gs(e=>{e!==null&&u(e)}),f=P.useRef(null);bs(()=>{if(n===null){f.current&&(f.current=null,u(null),c(null));return}if(a==null)return;let e=(n&&(qo(n)?n:n.current))??o??document.body;if(e==null){f.current&&(f.current=null,u(null),c(null));return}f.current!==e&&(f.current=e,u(null),c(e))},[n,o,a]);let p=Qa(`div`,r,{ref:[t,d],props:[{id:a,[op]:``},i]});return{portalNode:l,portalSubtree:s&&p?gi.createPortal(p,s):null}}var cp=P.forwardRef(function(e,t){let{children:n,container:r,className:i,render:a,renderGuards:o,style:s,...c}=e,{portalNode:l,portalSubtree:u}=sp({container:r,ref:t,componentProps:e,elementProps:c}),d=P.useRef(null),f=P.useRef(null),p=P.useRef(null),m=P.useRef(null),[h,g]=P.useState(null),_=P.useRef(!1),v=h?.modal,y=h?.open,b=typeof o==`boolean`?o:!!h&&!h.modal&&h.open&&!!l;P.useEffect(()=>{if(!l||v)return;function e(e){l&&e.relatedTarget&&yd(e)&&(e.type===`focusin`?_.current&&=(xd(l),!1):(bd(l),_.current=!0))}return Mf(jf(l,`focusin`,e,!0),jf(l,`focusout`,e,!0))},[l,v]),P.useEffect(()=>{!l||y!==!1||(xd(l),_.current=!1)},[y,l]);let x=P.useMemo(()=>({beforeOutsideRef:d,afterOutsideRef:f,beforeInsideRef:p,afterInsideRef:m,portalNode:l,setFocusManagerState:g}),[l]);return(0,F.jsxs)(P.Fragment,{children:[u,(0,F.jsxs)(ip.Provider,{value:x,children:[b&&l&&(0,F.jsx)(Rf,{"data-type":`outside`,ref:d,onFocus:e=>{yd(e,l)?p.current?.focus():vd(h?h.domReference:null)?.focus()}}),b&&l&&(0,F.jsx)(`span`,{"aria-owns":l.id,style:rp}),l&&gi.createPortal(n,l),b&&l&&(0,F.jsx)(Rf,{"data-type":`outside`,ref:f,onFocus:e=>{yd(e,l)?m.current?.focus():(_d(h?h.domReference:null)?.focus(),h?.closeOnFocusOut&&h?.onOpenChange(!1,tf(`focus-out`,e.nativeEvent)))}})]})]})});function lp(){let e=new Map;return{emit(t,n){e.get(t)?.forEach(e=>e(n))},on(t,n){e.has(t)||e.set(t,new Set),e.get(t).add(n)},off(t,n){e.get(t)?.delete(n)}}}var up=P.createContext(null),dp=P.createContext(null),fp=()=>P.useContext(up)?.id||null,pp=e=>{let t=P.useContext(dp);return e??t};function mp(e,t){let n=Go(Zl(e));return e instanceof n.KeyboardEvent?`keyboard`:e instanceof n.FocusEvent?t||`keyboard`:`pointerType`in e?e.pointerType||`keyboard`:`touches`in e?`touch`:e instanceof n.MouseEvent?t||(e.detail===0?`keyboard`:`mouse`):``}var hp=20,gp=[];function _p(){gp=gp.filter(e=>e.deref()?.isConnected)}function vp(e){_p(),e&&Wo(e)!==`body`&&(gp.push(new WeakRef(e)),gp.length>hp&&(gp=gp.slice(-hp)))}function yp(){return _p(),gp[gp.length-1]?.deref()}function bp(e){return e?pd(e)?e:hd(e)[0]||e:null}function xp(e,t){if(e.hasAttribute(`tabindex`)&&!e.hasAttribute(`data-tabindex`)||!t.current.includes(`floating`)&&!e.getAttribute(`role`)?.includes(`dialog`))return;let n=md(e).filter(e=>{let t=e.getAttribute(`data-tabindex`)||``;return pd(e)||e.hasAttribute(`data-tabindex`)&&!t.startsWith(`-`)}),r=e.getAttribute(`tabindex`);t.current.includes(`floating`)||n.length===0?r!==`0`&&e.setAttribute(`tabindex`,`0`):(r!==`-1`||e.hasAttribute(`data-tabindex`)&&e.getAttribute(`data-tabindex`)!==`-1`)&&(e.setAttribute(`tabindex`,`-1`),e.setAttribute(`data-tabindex`,`-1`))}function Sp(e){let{context:t,children:n,disabled:r=!1,initialFocus:i=!0,returnFocus:a=!0,restoreFocus:o=!1,modal:s=!0,closeOnFocusOut:c=!0,openInteractionType:l=``,nextFocusableElement:u,previousFocusableElement:d,beforeContentFocusGuardRef:f,externalTree:p,getInsideElements:m}=e,h=`rootStore`in t?t.rootStore:t,g=h.useState(`open`),_=h.useState(`domReferenceElement`),v=h.useState(`floatingElement`),{events:y,dataRef:b}=h.context,x=gs(()=>b.current.floatingContext?.nodeId),S=i===!1,C=ru(_)&&S,w=P.useRef([`content`]),T=Nf(i),E=Nf(a),ee=Nf(l),D=pp(p),O=ap(),te=P.useRef(!1),ne=P.useRef(!1),re=P.useRef(!1),k=P.useRef(null),A=P.useRef(``),ie=P.useRef(``),j=P.useRef(null),ae=P.useRef(null),oe=La(j,f,O?.beforeInsideRef),se=La(ae,O?.afterInsideRef),ce=Ed(),M=Ed(),le=Ad(),ue=O!=null,N=au(v),de=gs((e=N)=>e?hd(e):[]),fe=gs(()=>m?.().filter(e=>e!=null)??[]);P.useEffect(()=>{if(r||!s)return;function e(e){e.key===`Tab`&&Xl(N,Yl(kl(N)))&&de().length===0&&!C&&cu(e)}return jf(kl(N),`keydown`,e)},[r,_,N,s,w,C,de]),P.useEffect(()=>{if(r||!g)return;let e=kl(N);function t(){re.current=!1}function n(e){let t=Zl(e),n=fe();re.current=!(Xl(v,t)||Xl(_,t)||Xl(O?.portalNode,t)||n.some(e=>e===t||Xl(e,t))),ie.current=e.pointerType||`keyboard`,t?.closest(`[data-base-ui-click-trigger]`)&&(ne.current=!0)}function i(){ie.current=`keyboard`}return Mf(jf(e,`pointerdown`,n,!0),jf(e,`pointerup`,t,!0),jf(e,`pointercancel`,t,!0),jf(e,`keydown`,i,!0))},[r,v,_,N,g,O,fe]),P.useEffect(()=>{if(r||!c)return;let e=kl(N);function t(){ne.current=!0,M.start(0,()=>{ne.current=!1})}function n(e){let t=Zl(e);pd(t)&&(k.current=t)}function i(t){let n=t.relatedTarget,r=t.currentTarget,i=Zl(t);queueMicrotask(()=>{let a=x(),c=h.context.triggerElements,l=fe(),f=n?.hasAttribute(zf(`focus-guard`))&&[j.current,ae.current,O?.beforeInsideRef.current,O?.afterInsideRef.current,O?.beforeOutsideRef.current,O?.afterOutsideRef.current,jd(d),jd(u)].includes(n),p=!(Xl(_,n)||Xl(v,n)||Xl(n,v)||Xl(O?.portalNode,n)||l.some(e=>e===n||Xl(e,n))||n!=null&&c.hasElement(n)||c.hasMatchingElement(e=>Xl(e,n))||f||D&&(ou(D.nodesRef.current,a).find(e=>Xl(e.context?.elements.floating,n)||Xl(e.context?.elements.domReference,n))||su(D.nodesRef.current,a).find(e=>[e.context?.elements.floating,au(e.context?.elements.floating)].includes(n)||e.context?.elements.domReference===n)));if(r===_&&N&&xp(N,w),o&&r!==_&&!$u(i)&&Yl(e)===e.body){if(Yo(N)&&(N.focus(),o===`popup`)){le.request(()=>{N.focus()});return}let e=de(),t=k.current,n=(t&&e.includes(t)?t:null)||e[e.length-1]||N;Yo(n)&&n.focus()}if(b.current.insideReactTree){b.current.insideReactTree=!1;return}(C||!s)&&n&&p&&!ne.current&&(C||n!==yp())&&(te.current=!0,h.setOpen(!1,tf(Jd,t)))})}function a(){re.current||(b.current.insideReactTree=!0,ce.start(0,()=>{b.current.insideReactTree=!1}))}let l=Yo(_)?_:null;if(!(!v&&!l))return Mf(l&&jf(l,`focusout`,i),l&&jf(l,`pointerdown`,t),v&&jf(v,`focusin`,n),v&&jf(v,`focusout`,i),v&&O&&jf(v,`focusout`,a,!0))},[r,_,v,N,s,D,O,h,c,o,de,C,x,w,b,ce,M,le,u,d,fe]),P.useEffect(()=>{if(r||!v||!g)return;let e=Array.from(O?.portalNode?.querySelectorAll(`[${zf(`portal`)}]`)||[]),t=(D?su(D.nodesRef.current,x()):[]).find(e=>ru(e.context?.elements.domReference||null))?.context?.elements.domReference,n=$f([v,...e,j.current,ae.current,O?.beforeOutsideRef.current,O?.afterOutsideRef.current,...fe(),t,jd(d),jd(u),C?_:null].filter(e=>e!=null),{ariaHidden:s||C,mark:!1}),i=$f([v,...e].filter(e=>e!=null));return()=>{i(),n()}},[g,r,_,v,s,w,O,C,D,x,u,d,fe]),bs(()=>{if(!g||r||!Yo(N))return;let e=Yl(kl(N));queueMicrotask(()=>{let t=T.current,n=typeof t==`function`?t(ee.current||``):t;if(n===void 0||n===!1||Xl(N,e))return;let r=null,i=()=>(r??=de(N),r[0]||N),a;a=n===!0||n===null?i():jd(n),a||=i(),Vf(a,{preventScroll:a===N})})},[r,g,N,S,de,T,ee]),bs(()=>{if(r||!N)return;let e=kl(N);vp(Yl(e));function t(e){if(e.open||(A.current=mp(e.nativeEvent,ie.current)),e.reason===`trigger-hover`&&e.nativeEvent.type===`mouseleave`&&(te.current=!0),e.reason===`outside-press`)if(e.nested)te.current=!1;else if(uu(e.nativeEvent)||du(e.nativeEvent))te.current=!1;else{let e=!1;kl(N).createElement(`div`).focus({get preventScroll(){return e=!0,!1}}),e?te.current=!1:te.current=!0}}y.on(`openchange`,t);function n(){let e=E.current,t=typeof e==`function`?e(A.current):e;if(t===void 0||t===!1)return null;if(t===null&&(t=!0),typeof t==`boolean`){let e=_||yp();return e&&e.isConnected?e:null}let n=_||yp();return jd(t)||n||null}return()=>{y.off(`openchange`,t);let r=Yl(e),i=fe(),a=Xl(v,r)||i.some(e=>e===r||Xl(e,r))||D&&ou(D.nodesRef.current,x(),!1).some(e=>Xl(e.context?.elements.floating,r)),o=E.current,s=n();queueMicrotask(()=>{let t=bp(s),n=typeof o!=`boolean`;o&&!te.current&&Yo(t)&&(!(!n&&t!==r&&r!==e.body)||a)&&t.focus({preventScroll:!0}),te.current=!1})}},[r,v,N,E,b,y,D,_,x,fe]),bs(()=>{if(!Pl||g||!v)return;let e=Yl(kl(v));!Yo(e)||!tu(e)||Xl(v,e)&&e.blur()},[g,v]),bs(()=>{if(!(r||!O))return O.setFocusManagerState({modal:s,closeOnFocusOut:c,open:g,onOpenChange:h.setOpen,domReference:_}),()=>{O.setFocusManagerState(null)}},[r,O,s,g,h,c,_]),bs(()=>{if(!(r||!N))return xp(N,w),()=>{queueMicrotask(_p)}},[r,N,w]);let pe=!r&&(s?!C:!0)&&(ue||s);return(0,F.jsxs)(P.Fragment,{children:[pe&&(0,F.jsx)(Rf,{"data-type":`inside`,ref:oe,onFocus:e=>{if(s){let e=de();Vf(e[e.length-1])}else O?.portalNode&&(te.current=!1,yd(e,O.portalNode)?_d(_)?.focus():jd(d??O.beforeOutsideRef)?.focus())}}),n,pe&&(0,F.jsx)(Rf,{"data-type":`inside`,ref:se,onFocus:e=>{s?Vf(de()[0]):O?.portalNode&&(c&&(te.current=!0),yd(e,O.portalNode)?vd(_)?.focus():jd(u??O.afterOutsideRef)?.focus())}})]})}function Cp(e,t){let n=null,r=null,i=!1;return{contextElement:e||void 0,getBoundingClientRect(){let a=e?.getBoundingClientRect()||{width:0,height:0,x:0,y:0},o=t.axis===`x`||t.axis===`both`,s=t.axis===`y`||t.axis===`both`,c=[`mouseenter`,`mousemove`].includes(t.dataRef.current.openEvent?.type||``)&&t.pointerType!==`touch`,l=a.width,u=a.height,d=a.x,f=a.y;return n==null&&t.x&&o&&(n=a.x-t.x),r==null&&t.y&&s&&(r=a.y-t.y),d-=n||0,f-=r||0,l=0,u=0,!i||c?(l=t.axis===`y`?a.width:0,u=t.axis===`x`?a.height:0,d=o&&t.x!=null?t.x:d,f=s&&t.y!=null?t.y:f):i&&!c&&(u=t.axis===`x`?a.height:u,l=t.axis===`y`?a.width:l),i=!0,{width:l,height:u,x:d,y:f,top:f,right:d+l,bottom:f+u,left:d}}}}function wp(e){return e!=null&&e.clientX!=null}function Tp(e,t={}){let n=`rootStore`in e?e.rootStore:e,r=n.useState(`open`),i=n.useState(`floatingElement`),a=n.useState(`domReferenceElement`),o=n.context.dataRef,{enabled:s=!0,axis:c=`both`}=t,l=P.useRef(!1),u=P.useRef(null),[d,f]=P.useState(),[p,m]=P.useState([]),h=gs((e,t,r)=>{l.current||o.current.openEvent&&!wp(o.current.openEvent)||n.set(`positionReference`,Cp(r??a,{x:e,y:t,axis:c,dataRef:o,pointerType:d}))}),g=gs(e=>{r?u.current||m([]):h(e.clientX,e.clientY,e.currentTarget)}),_=fu(d)?i:r,v=P.useCallback(()=>{if(!_||!s)return;let e=Go(i);function t(e){Xl(i,Zl(e))?(u.current?.(),u.current=null):h(e.clientX,e.clientY)}if(!o.current.openEvent||wp(o.current.openEvent))return u.current=jf(e,`mousemove`,t),()=>{u.current?.(),u.current=null};n.set(`positionReference`,a)},[_,s,i,o,a,n,h]);P.useEffect(()=>v(),[v,p]),P.useEffect(()=>{s&&!i&&(l.current=!1)},[s,i]),P.useEffect(()=>{!s&&r&&(l.current=!0)},[s,r]);let y=P.useMemo(()=>{function e(e){f(e.pointerType)}return{onPointerDown:e,onPointerEnter:e,onMouseMove:g,onMouseEnter:g}},[g]);return P.useMemo(()=>s?{reference:y,trigger:y}:{},[s,y])}var Ep={intentional:`onClick`,sloppy:`onPointerDown`};function Dp(){return!1}function Op(e){return{escapeKey:typeof e==`boolean`?e:e?.escapeKey??!1,outsidePress:typeof e==`boolean`?e:e?.outsidePress??!0}}function kp(e,t={}){let n=`rootStore`in e?e.rootStore:e,r=n.useState(`open`),i=n.useState(`floatingElement`),{dataRef:a}=n.context,{enabled:o=!0,escapeKey:s=!0,outsidePress:c=!0,outsidePressEvent:l=`sloppy`,referencePress:u=Dp,referencePressEvent:d=`sloppy`,bubbles:f,externalTree:p}=t,m=pp(p),h=gs(typeof c==`function`?c:()=>!1),g=typeof c==`function`?h:c,_=g!==!1,v=gs(()=>l),y=P.useRef(!1),b=P.useRef(!1),x=P.useRef(!1),{escapeKey:S,outsidePress:C}=Op(f),w=P.useRef(null),T=Ed(),E=Ed(),ee=gs(()=>{E.clear(),a.current.insideReactTree=!1}),D=P.useRef(!1),O=P.useRef(``),te=gs(u),ne=gs(e=>{if(!r||!o||!s||e.key!==`Escape`||D.current)return;let t=a.current.floatingContext?.nodeId,i=m?ou(m.nodesRef.current,t):[];if(!S&&i.length>0){let e=!0;if(i.forEach(t=>{t.context?.open&&!t.context.dataRef.current.__escapeKeyBubbles&&(e=!1)}),!e)return}let c=tf(Yd,lu(e)?e.nativeEvent:e);n.setOpen(!1,c),!S&&!c.isPropagationAllowed&&e.stopPropagation()}),re=gs(()=>{a.current.insideReactTree=!0,E.start(0,ee)});P.useEffect(()=>{if(!r||!o)return;a.current.__escapeKeyBubbles=S,a.current.__outsidePressBubbles=C;let e=new Td,t=new Td;function c(){e.clear(),D.current=!0}function l(){e.start(os()?5:0,()=>{D.current=!1})}function u(){x.current=!0,t.start(0,()=>{x.current=!1})}function d(){y.current=!1,b.current=!1}function f(){let e=O.current,t=e===`pen`||!e?`mouse`:e,n=v(),r=typeof n==`function`?n():n;return typeof r==`string`?r:r[t]}function p(e){let t=f();return t===`intentional`&&e.type!==`click`||t===`sloppy`&&e.type===`click`}function h(e){let t=a.current.floatingContext?.nodeId,r=m&&ou(m.nodesRef.current,t).some(t=>$l(e,t.context?.elements.floating));return $l(e,n.select(`floatingElement`))||$l(e,n.select(`domReferenceElement`))||r}function E(e){if(p(e)){ee();return}if(a.current.insideReactTree){ee();return}let r=Zl(e),i=`[${zf(`inert`)}]`,o=Jo(r)?r.getRootNode():null,s=Array.from((Xo(o)?o:kl(n.select(`floatingElement`))).querySelectorAll(i)),c=n.context.triggerElements;if(r&&(c.hasElement(r)||c.hasMatchingElement(e=>Xl(e,r))))return;let l=Jo(r)?r:null;for(;l&&!ss(l);){let e=us(l);if(ss(e)||!Jo(e))break;l=e}if(s.length&&Jo(r)&&!eu(r)&&!Xl(r,n.select(`floatingElement`))&&s.every(e=>!Xl(l,e)))return;if(Yo(r)&&!(`touches`in e)){let t=ss(r),n=cs(r),i=/auto|scroll/,a=t||i.test(n.overflowX),o=t||i.test(n.overflowY),s=a&&r.clientWidth>0&&r.scrollWidth>r.clientWidth,c=o&&r.clientHeight>0&&r.scrollHeight>r.clientHeight,l=n.direction===`rtl`,u=c&&(l?e.offsetX<=r.offsetWidth-r.clientWidth:e.offsetX>r.clientWidth),d=s&&e.offsetY>r.clientHeight;if(u||d)return}if(h(e))return;if(f()===`intentional`&&x.current){t.clear(),x.current=!1;return}if(typeof g==`function`&&!g(e))return;let u=a.current.floatingContext?.nodeId,d=m?ou(m.nodesRef.current,u):[];if(d.length>0){let e=!0;if(d.forEach(t=>{t.context?.open&&!t.context.dataRef.current.__outsidePressBubbles&&(e=!1)}),!e)return}n.setOpen(!1,tf(Gd,e)),ee()}function te(e){f()!==`sloppy`||e.pointerType===`touch`||!n.select(`open`)||!o||$l(e,n.select(`floatingElement`))||$l(e,n.select(`domReferenceElement`))||E(e)}function re(e){if(f()!==`sloppy`||!n.select(`open`)||!o||$l(e,n.select(`floatingElement`))||$l(e,n.select(`domReferenceElement`)))return;let t=e.touches[0];t&&(w.current={startTime:Date.now(),startX:t.clientX,startY:t.clientY,dismissOnTouchEnd:!1,dismissOnMouseDown:!0},T.start(1e3,()=>{w.current&&(w.current.dismissOnTouchEnd=!1,w.current.dismissOnMouseDown=!1)}))}function k(e,t){let n=Zl(e);if(!n)return;let r=jf(n,e.type,()=>{t(e),r()})}function A(e){O.current=`touch`,k(e,re)}function ie(e){T.clear(),e.type===`pointerdown`&&(O.current=e.pointerType),!(e.type===`mousedown`&&w.current&&!w.current.dismissOnMouseDown)&&k(e,e=>{e.type===`pointerdown`?te(e):E(e)})}function j(e){if(!y.current)return;let n=b.current;if(d(),f()===`intentional`){if(e.type===`pointercancel`){n&&u();return}if(!h(e)){if(n){u();return}typeof g==`function`&&!g(e)||(t.clear(),x.current=!0,ee())}}}function ae(e){if(f()!==`sloppy`||!w.current||$l(e,n.select(`floatingElement`))||$l(e,n.select(`domReferenceElement`)))return;let t=e.touches[0];if(!t)return;let r=Math.abs(t.clientX-w.current.startX),i=Math.abs(t.clientY-w.current.startY),a=Math.sqrt(r*r+i*i);a>5&&(w.current.dismissOnTouchEnd=!0),a>10&&(E(e),T.clear(),w.current=null)}function oe(e){k(e,ae)}function se(e){f()!==`sloppy`||!w.current||$l(e,n.select(`floatingElement`))||$l(e,n.select(`domReferenceElement`))||(w.current.dismissOnTouchEnd&&E(e),T.clear(),w.current=null)}function ce(e){k(e,se)}let M=kl(i),le=Mf(s&&Mf(jf(M,`keydown`,ne),jf(M,`compositionstart`,c),jf(M,`compositionend`,l)),_&&Mf(jf(M,`click`,ie,!0),jf(M,`pointerdown`,ie,!0),jf(M,`pointerup`,j,!0),jf(M,`pointercancel`,j,!0),jf(M,`mousedown`,ie,!0),jf(M,`mouseup`,j,!0),jf(M,`touchstart`,A,!0),jf(M,`touchmove`,oe,!0),jf(M,`touchend`,ce,!0)));return()=>{le(),e.clear(),t.clear(),d(),x.current=!1}},[a,i,s,_,g,r,o,S,C,ne,ee,v,m,n,T]),P.useEffect(ee,[g,ee]);let k=P.useMemo(()=>({onKeyDown:ne,[Ep[d]]:e=>{te()&&n.setOpen(!1,tf(Hd,e.nativeEvent))},...d!==`intentional`&&{onClick(e){te()&&n.setOpen(!1,tf(`trigger-press`,e.nativeEvent))}}}),[ne,n,d,te]),A=gs(e=>{if(!r||!o||e.button!==0)return;let t=Zl(e.nativeEvent);Xl(n.select(`floatingElement`),t)&&(y.current||(y.current=!0,b.current=!1))}),ie=gs(e=>{!r||!o||(e.defaultPrevented||e.nativeEvent.defaultPrevented)&&y.current&&(b.current=!0)}),j=P.useMemo(()=>({onKeyDown:ne,onPointerDown:ie,onMouseDown:ie,onClickCapture:re,onMouseDownCapture(e){re(),A(e)},onPointerDownCapture(e){re(),A(e)},onMouseUpCapture:re,onTouchEndCapture:re,onTouchMoveCapture:re}),[ne,re,A,ie]);return P.useMemo(()=>o?{reference:k,floating:j,trigger:k}:{},[o,k,j])}function Ap(e,t,n){let{reference:r,floating:i}=e,a=Du(t),o=Ou(t),s=Eu(o),c=Cu(t),l=a===`y`,u=r.x+r.width/2-i.width/2,d=r.y+r.height/2-i.height/2,f=r[s]/2-i[s]/2,p;switch(c){case`top`:p={x:u,y:r.y-i.height};break;case`bottom`:p={x:u,y:r.y+r.height};break;case`right`:p={x:r.x+r.width,y:d};break;case`left`:p={x:r.x-i.width,y:d};break;default:p={x:r.x,y:r.y}}switch(wu(t)){case`start`:p[o]-=f*(n&&l?-1:1);break;case`end`:p[o]+=f*(n&&l?-1:1);break}return p}async function jp(e,t){t===void 0&&(t={});let{x:n,y:r,platform:i,rects:a,elements:o,strategy:s}=e,{boundary:c=`clippingAncestors`,rootBoundary:l=`viewport`,elementContext:u=`floating`,altBoundary:d=!1,padding:f=0}=Su(t,e),p=Bu(f),m=o[d?u===`floating`?`reference`:`floating`:u],h=Vu(await i.getClippingRect({element:await(i.isElement==null?void 0:i.isElement(m))??!0?m:m.contextElement||await(i.getDocumentElement==null?void 0:i.getDocumentElement(o.floating)),boundary:c,rootBoundary:l,strategy:s})),g=u===`floating`?{x:n,y:r,width:a.floating.width,height:a.floating.height}:a.reference,_=await(i.getOffsetParent==null?void 0:i.getOffsetParent(o.floating)),v=await(i.isElement==null?void 0:i.isElement(_))&&await(i.getScale==null?void 0:i.getScale(_))||{x:1,y:1},y=Vu(i.convertOffsetParentRelativeRectToViewportRelativeRect?await i.convertOffsetParentRelativeRectToViewportRelativeRect({elements:o,rect:g,offsetParent:_,strategy:s}):g);return{top:(h.top-y.top+p.top)/v.y,bottom:(y.bottom-h.bottom+p.bottom)/v.y,left:(h.left-y.left+p.left)/v.x,right:(y.right-h.right+p.right)/v.x}}var Mp=50,Np=async(e,t,n)=>{let{placement:r=`bottom`,strategy:i=`absolute`,middleware:a=[],platform:o}=n,s=o.detectOverflow?o:{...o,detectOverflow:jp},c=await(o.isRTL==null?void 0:o.isRTL(t)),l=await o.getElementRects({reference:e,floating:t,strategy:i}),{x:u,y:d}=Ap(l,r,c),f=r,p=0,m={};for(let n=0;ne<=0)){let e=(i.flip?.index||0)+1,t=S[e];if(t&&(!(u===`alignment`&&_!==Du(t))||T.every(e=>Du(e.placement)===_?e.overflows[0]>0:!0)))return{data:{index:e,overflows:T},reset:{placement:t}};let n=T.filter(e=>e.overflows[0]<=0).sort((e,t)=>e.overflows[1]-t.overflows[1])[0]?.placement;if(!n)switch(f){case`bestFit`:{let e=T.filter(e=>{if(x){let t=Du(e.placement);return t===_||t===`y`}return!0}).map(e=>[e.placement,e.overflows.filter(e=>e>0).reduce((e,t)=>e+t,0)]).sort((e,t)=>e[1]-t[1])[0]?.[0];e&&(n=e);break}case`initialPlacement`:n=o;break}if(r!==n)return{reset:{placement:n}}}return{}}}};function Fp(e,t){return{top:e.top-t.height,right:e.right-t.width,bottom:e.bottom-t.height,left:e.left-t.width}}function Ip(e){return mu.some(t=>e[t]>=0)}var Lp=function(e){return e===void 0&&(e={}),{name:`hide`,options:e,async fn(t){let{rects:n,platform:r}=t,{strategy:i=`referenceHidden`,...a}=Su(e,t);switch(i){case`referenceHidden`:{let e=Fp(await r.detectOverflow(t,{...a,elementContext:`reference`}),n.reference);return{data:{referenceHiddenOffsets:e,referenceHidden:Ip(e)}}}case`escaped`:{let e=Fp(await r.detectOverflow(t,{...a,altBoundary:!0}),n.floating);return{data:{escapedOffsets:e,escaped:Ip(e)}}}default:return{}}}}},Rp=new Set([`left`,`top`]);async function zp(e,t){let{placement:n,platform:r,elements:i}=e,a=await(r.isRTL==null?void 0:r.isRTL(i.floating)),o=Cu(n),s=wu(n),c=Du(n)===`y`,l=Rp.has(o)?-1:1,u=a&&c?-1:1,d=Su(t,e),{mainAxis:f,crossAxis:p,alignmentAxis:m}=typeof d==`number`?{mainAxis:d,crossAxis:0,alignmentAxis:null}:{mainAxis:d.mainAxis||0,crossAxis:d.crossAxis||0,alignmentAxis:d.alignmentAxis};return s&&typeof m==`number`&&(p=s===`end`?m*-1:m),c?{x:p*u,y:f*l}:{x:f*l,y:p*u}}var Bp=function(e){return e===void 0&&(e=0),{name:`offset`,options:e,async fn(t){var n;let{x:r,y:i,placement:a,middlewareData:o}=t,s=await zp(t,e);return a===o.offset?.placement&&(n=o.arrow)!=null&&n.alignmentOffset?{}:{x:r+s.x,y:i+s.y,data:{...s,placement:a}}}}},Vp=function(e){return e===void 0&&(e={}),{name:`shift`,options:e,async fn(t){let{x:n,y:r,placement:i,platform:a}=t,{mainAxis:o=!0,crossAxis:s=!1,limiter:c={fn:e=>{let{x:t,y:n}=e;return{x:t,y:n}}},...l}=Su(e,t),u={x:n,y:r},d=await a.detectOverflow(t,l),f=Du(Cu(i)),p=Tu(f),m=u[p],h=u[f];if(o){let e=p===`y`?`top`:`left`,t=p===`y`?`bottom`:`right`,n=m+d[e],r=m-d[t];m=xu(n,m,r)}if(s){let e=f===`y`?`top`:`left`,t=f===`y`?`bottom`:`right`,n=h+d[e],r=h-d[t];h=xu(n,h,r)}let g=c.fn({...t,[p]:m,[f]:h});return{...g,data:{x:g.x-n,y:g.y-r,enabled:{[p]:o,[f]:s}}}}}},Hp=function(e){return e===void 0&&(e={}),{options:e,fn(t){let{x:n,y:r,placement:i,rects:a,middlewareData:o}=t,{offset:s=0,mainAxis:c=!0,crossAxis:l=!0}=Su(e,t),u={x:n,y:r},d=Du(i),f=Tu(d),p=u[f],m=u[d],h=Su(s,t),g=typeof h==`number`?{mainAxis:h,crossAxis:0}:{mainAxis:0,crossAxis:0,...h};if(c){let e=f===`y`?`height`:`width`,t=a.reference[f]-a.floating[e]+g.mainAxis,n=a.reference[f]+a.reference[e]-g.mainAxis;pn&&(p=n)}if(l){let e=f===`y`?`width`:`height`,t=Rp.has(Cu(i)),n=a.reference[d]-a.floating[e]+(t&&o.offset?.[d]||0)+(t?0:g.crossAxis),r=a.reference[d]+a.reference[e]+(t?0:o.offset?.[d]||0)-(t?g.crossAxis:0);mr&&(m=r)}return{[f]:p,[d]:m}}}},Up=function(e){return e===void 0&&(e={}),{name:`size`,options:e,async fn(t){var n,r;let{placement:i,rects:a,platform:o,elements:s}=t,{apply:c=()=>{},...l}=Su(e,t),u=await o.detectOverflow(t,l),d=Cu(i),f=wu(i),p=Du(i)===`y`,{width:m,height:h}=a.floating,g,_;d===`top`||d===`bottom`?(g=d,_=f===(await(o.isRTL==null?void 0:o.isRTL(s.floating))?`start`:`end`)?`left`:`right`):(_=d,g=f===`end`?`top`:`bottom`);let v=h-u.top-u.bottom,y=m-u.left-u.right,b=hu(h-u[g],v),x=hu(m-u[_],y),S=!t.middlewareData.shift,C=b,w=x;if((n=t.middlewareData.shift)!=null&&n.enabled.x&&(w=y),(r=t.middlewareData.shift)!=null&&r.enabled.y&&(C=v),S&&!f){let e=gu(u.left,0),t=gu(u.right,0),n=gu(u.top,0),r=gu(u.bottom,0);p?w=m-2*(e!==0||t!==0?e+t:gu(u.left,u.right)):C=h-2*(n!==0||r!==0?n+r:gu(u.top,u.bottom))}await c({...t,availableWidth:w,availableHeight:C});let T=await o.getDimensions(s.floating);return m!==T.width||h!==T.height?{reset:{rects:!0}}:{}}}};function Wp(e){let t=cs(e),n=parseFloat(t.width)||0,r=parseFloat(t.height)||0,i=Yo(e),a=i?e.offsetWidth:n,o=i?e.offsetHeight:r,s=_u(n)!==a||_u(r)!==o;return s&&(n=a,r=o),{width:n,height:r,$:s}}function Gp(e){return Jo(e)?e:e.contextElement}function Kp(e){let t=Gp(e);if(!Yo(t))return yu(1);let n=t.getBoundingClientRect(),{width:r,height:i,$:a}=Wp(t),o=(a?_u(n.width):n.width)/r,s=(a?_u(n.height):n.height)/i;return(!o||!Number.isFinite(o))&&(o=1),(!s||!Number.isFinite(s))&&(s=1),{x:o,y:s}}var qp=yu(0);function Jp(e){let t=Go(e);return!os()||!t.visualViewport?qp:{x:t.visualViewport.offsetLeft,y:t.visualViewport.offsetTop}}function Yp(e,t,n){return t===void 0&&(t=!1),!n||t&&n!==Go(e)?!1:t}function Xp(e,t,n,r){t===void 0&&(t=!1),n===void 0&&(n=!1);let i=e.getBoundingClientRect(),a=Gp(e),o=yu(1);t&&(r?Jo(r)&&(o=Kp(r)):o=Kp(e));let s=Yp(a,n,r)?Jp(a):yu(0),c=(i.left+s.x)/o.x,l=(i.top+s.y)/o.y,u=i.width/o.x,d=i.height/o.y;if(a){let e=Go(a),t=r&&Jo(r)?Go(r):r,n=e,i=ps(n);for(;i&&r&&t!==n;){let e=Kp(i),t=i.getBoundingClientRect(),r=cs(i),a=t.left+(i.clientLeft+parseFloat(r.paddingLeft))*e.x,o=t.top+(i.clientTop+parseFloat(r.paddingTop))*e.y;c*=e.x,l*=e.y,u*=e.x,d*=e.y,c+=a,l+=o,n=Go(i),i=ps(n)}}return Vu({width:u,height:d,x:c,y:l})}function Zp(e,t){let n=ls(e).scrollLeft;return t?t.left+n:Xp(Ko(e)).left+n}function Qp(e,t){let n=e.getBoundingClientRect();return{x:n.left+t.scrollLeft-Zp(e,n),y:n.top+t.scrollTop}}function $p(e){let{elements:t,rect:n,offsetParent:r,strategy:i}=e,a=i===`fixed`,o=Ko(r),s=t?$o(t.floating):!1;if(r===o||s&&a)return n;let c={scrollLeft:0,scrollTop:0},l=yu(1),u=yu(0),d=Yo(r);if((d||!d&&!a)&&((Wo(r)!==`body`||Zo(o))&&(c=ls(r)),d)){let e=Xp(r);l=Kp(r),u.x=e.x+r.clientLeft,u.y=e.y+r.clientTop}let f=o&&!d&&!a?Qp(o,c):yu(0);return{width:n.width*l.x,height:n.height*l.y,x:n.x*l.x-c.scrollLeft*l.x+u.x+f.x,y:n.y*l.y-c.scrollTop*l.y+u.y+f.y}}function em(e){return Array.from(e.getClientRects())}function tm(e){let t=Ko(e),n=ls(e),r=e.ownerDocument.body,i=gu(t.scrollWidth,t.clientWidth,r.scrollWidth,r.clientWidth),a=gu(t.scrollHeight,t.clientHeight,r.scrollHeight,r.clientHeight),o=-n.scrollLeft+Zp(e),s=-n.scrollTop;return cs(r).direction===`rtl`&&(o+=gu(t.clientWidth,r.clientWidth)-i),{width:i,height:a,x:o,y:s}}var nm=25;function eee(e,t){let n=Go(e),r=Ko(e),i=n.visualViewport,a=r.clientWidth,o=r.clientHeight,s=0,c=0;if(i){a=i.width,o=i.height;let e=os();(!e||e&&t===`fixed`)&&(s=i.offsetLeft,c=i.offsetTop)}let l=Zp(r);if(l<=0){let e=r.ownerDocument,t=e.body,n=getComputedStyle(t),i=e.compatMode===`CSS1Compat`&&parseFloat(n.marginLeft)+parseFloat(n.marginRight)||0,o=Math.abs(r.clientWidth-t.clientWidth-i);o<=nm&&(a-=o)}else l<=nm&&(a+=l);return{width:a,height:o,x:s,y:c}}function rm(e,t){let n=Xp(e,!0,t===`fixed`),r=n.top+e.clientTop,i=n.left+e.clientLeft,a=Yo(e)?Kp(e):yu(1);return{width:e.clientWidth*a.x,height:e.clientHeight*a.y,x:i*a.x,y:r*a.y}}function im(e,t,n){let r;if(t===`viewport`)r=eee(e,n);else if(t===`document`)r=tm(Ko(e));else if(Jo(t))r=rm(t,n);else{let n=Jp(e);r={x:t.x-n.x,y:t.y-n.y,width:t.width,height:t.height}}return Vu(r)}function am(e,t){let n=us(e);return n===t||!Jo(n)||ss(n)?!1:cs(n).position===`fixed`||am(n,t)}function om(e,t){let n=t.get(e);if(n)return n;let r=fs(e,[],!1).filter(e=>Jo(e)&&Wo(e)!==`body`),i=null,a=cs(e).position===`fixed`,o=a?us(e):e;for(;Jo(o)&&!ss(o);){let t=cs(o),n=is(o);!n&&t.position===`fixed`&&(i=null),(a?!n&&!i:!n&&t.position===`static`&&i&&(i.position===`absolute`||i.position===`fixed`)||Zo(o)&&!n&&am(e,o))?r=r.filter(e=>e!==o):i=t,o=us(o)}return t.set(e,r),r}function sm(e){let{element:t,boundary:n,rootBoundary:r,strategy:i}=e,a=[...n===`clippingAncestors`?$o(t)?[]:om(t,this._c):[].concat(n),r],o=im(t,a[0],i),s=o.top,c=o.right,l=o.bottom,u=o.left;for(let e=1;e{o(!1,1e-7)},1e3)}n===1&&!gm(l,e.getBoundingClientRect())&&o(),y=!1}try{n=new IntersectionObserver(b,{...v,root:i.ownerDocument})}catch{n=new IntersectionObserver(b,v)}n.observe(e)}return o(!0),a}function vm(e,t,n,r){r===void 0&&(r={});let{ancestorScroll:i=!0,ancestorResize:a=!0,elementResize:o=typeof ResizeObserver==`function`,layoutShift:s=typeof IntersectionObserver==`function`,animationFrame:c=!1}=r,l=Gp(e),u=i||a?[...l?fs(l):[],...t?fs(t):[]]:[];u.forEach(e=>{i&&e.addEventListener(`scroll`,n,{passive:!0}),a&&e.addEventListener(`resize`,n)});let d=l&&s?_m(l,n):null,f=-1,p=null;o&&(p=new ResizeObserver(e=>{let[r]=e;r&&r.target===l&&p&&t&&(p.unobserve(t),cancelAnimationFrame(f),f=requestAnimationFrame(()=>{var e;(e=p)==null||e.observe(t)})),n()}),l&&!c&&p.observe(l),t&&p.observe(t));let m,h=c?Xp(e):null;c&&g();function g(){let t=Xp(e);h&&!gm(h,t)&&n(),h=t,m=requestAnimationFrame(g)}return n(),()=>{var e;u.forEach(e=>{i&&e.removeEventListener(`scroll`,n),a&&e.removeEventListener(`resize`,n)}),d?.(),(e=p)==null||e.disconnect(),p=null,c&&cancelAnimationFrame(m)}}var ym=Bp,bm=Vp,xm=Pp,Sm=Up,Cm=Lp,wm=Hp,Tm=(e,t,n)=>{let r=new Map,i={platform:hm,...n},a={...i.platform,_c:r};return Np(e,t,{...i,platform:a})},Em=typeof document<`u`?P.useLayoutEffect:function(){};function Dm(e,t){if(e===t)return!0;if(typeof e!=typeof t)return!1;if(typeof e==`function`&&e.toString()===t.toString())return!0;let n,r,i;if(e&&t&&typeof e==`object`){if(Array.isArray(e)){if(n=e.length,n!==t.length)return!1;for(r=n;r--!==0;)if(!Dm(e[r],t[r]))return!1;return!0}if(i=Object.keys(e),n=i.length,n!==Object.keys(t).length)return!1;for(r=n;r--!==0;)if(!{}.hasOwnProperty.call(t,i[r]))return!1;for(r=n;r--!==0;){let n=i[r];if(!(n===`_owner`&&e.$$typeof)&&!Dm(e[n],t[n]))return!1}return!0}return e!==e&&t!==t}function Om(e){return typeof window>`u`?1:(e.ownerDocument.defaultView||window).devicePixelRatio||1}function km(e,t){let n=Om(e);return Math.round(t*n)/n}function Am(e){let t=P.useRef(e);return Em(()=>{t.current=e}),t}function tee(e){e===void 0&&(e={});let{placement:t=`bottom`,strategy:n=`absolute`,middleware:r=[],platform:i,elements:{reference:a,floating:o}={},transform:s=!0,whileElementsMounted:c,open:l}=e,[u,d]=P.useState({x:0,y:0,strategy:n,placement:t,middlewareData:{},isPositioned:!1}),[f,p]=P.useState(r);Dm(f,r)||p(r);let[m,h]=P.useState(null),[g,_]=P.useState(null),v=P.useCallback(e=>{e!==S.current&&(S.current=e,h(e))},[]),y=P.useCallback(e=>{e!==C.current&&(C.current=e,_(e))},[]),b=a||m,x=o||g,S=P.useRef(null),C=P.useRef(null),w=P.useRef(u),T=c!=null,E=Am(c),ee=Am(i),D=Am(l),O=P.useCallback(()=>{if(!S.current||!C.current)return;let e={placement:t,strategy:n,middleware:f};ee.current&&(e.platform=ee.current),Tm(S.current,C.current,e).then(e=>{let t={...e,isPositioned:D.current!==!1};te.current&&!Dm(w.current,t)&&(w.current=t,gi.flushSync(()=>{d(t)}))})},[f,t,n,ee,D]);Em(()=>{l===!1&&w.current.isPositioned&&(w.current.isPositioned=!1,d(e=>({...e,isPositioned:!1})))},[l]);let te=P.useRef(!1);Em(()=>(te.current=!0,()=>{te.current=!1}),[]),Em(()=>{if(b&&(S.current=b),x&&(C.current=x),b&&x){if(E.current)return E.current(b,x,O);O()}},[b,x,O,E,T]);let ne=P.useMemo(()=>({reference:S,floating:C,setReference:v,setFloating:y}),[v,y]),re=P.useMemo(()=>({reference:b,floating:x}),[b,x]),k=P.useMemo(()=>{let e={position:n,left:0,top:0};if(!re.floating)return e;let t=km(re.floating,u.x),r=km(re.floating,u.y);return s?{...e,transform:`translate(`+t+`px, `+r+`px)`,...Om(re.floating)>=1.5&&{willChange:`transform`}}:{position:n,left:t,top:r}},[n,s,re.floating,u.x,u.y]);return P.useMemo(()=>({...u,update:O,refs:ne,elements:re,floatingStyles:k}),[u,O,ne,re,k])}var nee=(e,t)=>{let n=ym(e);return{name:n.name,fn:n.fn,options:[e,t]}},ree=(e,t)=>{let n=bm(e);return{name:n.name,fn:n.fn,options:[e,t]}},iee=(e,t)=>({fn:wm(e).fn,options:[e,t]}),aee=(e,t)=>{let n=xm(e);return{name:n.name,fn:n.fn,options:[e,t]}},oee=(e,t)=>{let n=Sm(e);return{name:n.name,fn:n.fn,options:[e,t]}},see=(e,t)=>{let n=Cm(e);return{name:n.name,fn:n.fn,options:[e,t]}},jm=(e,t,n,r,i,a,...o)=>{if(o.length>0)throw Error(Pa(1));let s;if(e&&t&&n&&r&&i&&a)s=(o,s,c,l)=>a(e(o,s,c,l),t(o,s,c,l),n(o,s,c,l),r(o,s,c,l),i(o,s,c,l),s,c,l);else if(e&&t&&n&&r&&i)s=(a,o,s,c)=>i(e(a,o,s,c),t(a,o,s,c),n(a,o,s,c),r(a,o,s,c),o,s,c);else if(e&&t&&n&&r)s=(i,a,o,s)=>r(e(i,a,o,s),t(i,a,o,s),n(i,a,o,s),a,o,s);else if(e&&t&&n)s=(r,i,a,o)=>n(e(r,i,a,o),t(r,i,a,o),i,a,o);else if(e&&t)s=(n,r,i,a)=>t(e(n,r,i,a),r,i,a);else if(e)s=e;else throw Error(`Missing arguments`);return s},Mm=[],Nm=void 0;function Pm(){return Nm}function Fm(e){Mm.push(e)}function Im(e){let t=(t,n)=>{let r=Ia(Rm).current,i;try{Nm=r;for(let e of Mm)e.before(r);i=e(t,n);for(let e of Mm)e.after(r);r.didInitialize=!0}finally{Nm=void 0}return i};return t.displayName=e.displayName||e.name,t}function Lm(e){return P.forwardRef(Im(e))}function Rm(){return{didInitialize:!1}}var zm=ti(),Bm=Wa(19)?Um:Wm;function Vm(e,t,n,r,i){return Bm(e,t,n,r,i)}function Hm(e,t,n,r,i){let a=P.useCallback(()=>t(e.getSnapshot(),n,r,i),[e,t,n,r,i]);return(0,zm.useSyncExternalStore)(e.subscribe,a,a)}Fm({before(e){e.syncIndex=0,e.didInitialize||(e.syncTick=1,e.syncHooks=[],e.didChangeStore=!0,e.getSnapshot=()=>{let t=!1;for(let n=0;n0&&(e.didChangeStore&&(e.didChangeStore=!1,e.subscribe=t=>{let n=new Set;for(let t of e.syncHooks)n.add(t.store);let r=[];for(let e of n)r.push(e.subscribe(t));return()=>{for(let e of r)e()}}),(0,zm.useSyncExternalStore)(e.subscribe,e.getSnapshot,e.getSnapshot))}});function Um(e,t,n,r,i){let a=Pm();if(!a)return Hm(e,t,n,r,i);let o=a.syncIndex;a.syncIndex+=1;let s;return a.didInitialize?(s=a.syncHooks[o],(s.store!==e||s.selector!==t||!Object.is(s.a1,n)||!Object.is(s.a2,r)||!Object.is(s.a3,i))&&(s.store!==e&&(a.didChangeStore=!0),s.store=e,s.selector=t,s.a1=n,s.a2=r,s.a3=i,s.didChange=!0)):(s={store:e,selector:t,a1:n,a2:r,a3:i,value:t(e.getSnapshot(),n,r,i),didChange:!1},a.syncHooks.push(s)),s.value}function Wm(e,t,n,r,i){return(0,ri.useSyncExternalStoreWithSelector)(e.subscribe,e.getSnapshot,e.getSnapshot,e=>t(e,n,r,i))}var Gm=class{constructor(e){this.state=e,this.listeners=new Set,this.updateTick=0}subscribe=e=>(this.listeners.add(e),()=>{this.listeners.delete(e)});getSnapshot=()=>this.state;setState(e){if(this.state===e)return;this.state=e,this.updateTick+=1;let t=this.updateTick;for(let n of this.listeners){if(t!==this.updateTick)return;n(e)}}update(e){for(let t in e)if(!Object.is(this.state[t],e[t])){this.setState({...this.state,...e});return}}set(e,t){Object.is(this.state[e],t)||this.setState({...this.state,[e]:t})}notifyAll(){let e={...this.state};this.setState(e)}use(e,t,n,r){return Vm(this,e,t,n,r)}},Km=class extends Gm{constructor(e,t={},n){super(e),this.context=t,this.selectors=n}useSyncedValue(e,t){P.useDebugValue(e),bs(()=>{this.state[e]!==t&&this.set(e,t)},[e,t])}useSyncedValueWithCleanup(e,t){let n=this;bs(()=>(n.state[e]!==t&&n.set(e,t),()=>{n.set(e,void 0)}),[n,e,t])}useSyncedValues(e){let t=this;bs(()=>{t.update(e)},[t,...Object.values(e)])}useControlledProp(e,t){P.useDebugValue(e);let n=t!==void 0;bs(()=>{n&&!Object.is(this.state[e],t)&&super.setState({...this.state,[e]:t})},[e,t,n])}select(e,t,n,r){let i=this.selectors[e];return i(this.state,t,n,r)}useState(e,t,n,r){return P.useDebugValue(e),Vm(this,this.selectors[e],t,n,r)}useContextCallback(e,t){P.useDebugValue(e);let n=gs(t??Ka);this.context[e]=n}useStateSetter(e){let t=P.useRef(void 0);return t.current===void 0&&(t.current=t=>{this.set(e,t)}),t.current}observe(e,t){let n;n=typeof e==`function`?e:this.selectors[e];let r=n(this.state);return t(r,r,this),this.subscribe(e=>{let i=n(e);if(!Object.is(r,i)){let e=r;r=i,t(i,e,this)}})}},qm={open:jm(e=>e.open),transitionStatus:jm(e=>e.transitionStatus),domReferenceElement:jm(e=>e.domReferenceElement),referenceElement:jm(e=>e.positionReference??e.referenceElement),floatingElement:jm(e=>e.floatingElement),floatingId:jm(e=>e.floatingId)},Jm=class extends Km{constructor(e){let{syncOnly:t,nested:n,onOpenChange:r,triggerElements:i,...a}=e;super({...a,positionReference:a.referenceElement,domReferenceElement:a.referenceElement},{onOpenChange:r,dataRef:{current:{}},events:lp(),nested:n,triggerElements:i},qm),this.syncOnly=t}syncOpenEvent=(e,t)=>{(!e||!this.state.open||t!=null&&pu(t))&&(this.context.dataRef.current.openEvent=e?t:void 0)};dispatchOpenChange=(e,t)=>{this.syncOpenEvent(e,t.event);let n={open:e,reason:t.reason,nativeEvent:t.event,nested:this.context.nested,triggerElement:t.trigger};this.context.events.emit(`openchange`,n)};setOpen=(e,t)=>{if(this.syncOnly){this.context.onOpenChange?.(e,t);return}this.dispatchOpenChange(e,t),this.context.onOpenChange?.(e,t)}};function Ym(e,t){let n=P.useRef(null),r=P.useRef(null);return P.useCallback(i=>{if(e!==void 0){if(n.current!==null){let e=n.current,i=r.current,a=t.context.triggerElements.getById(e);i&&a===i&&t.context.triggerElements.delete(e),n.current=null,r.current=null}i!==null&&(n.current=e,r.current=i,t.context.triggerElements.add(e,i))}},[t,e])}function Xm(e,t,n,r){let i=n.useState(`isMountedByTrigger`,e),a=Ym(e,n),o=gs(t=>{if(a(t),!t||!n.select(`open`))return;let i=n.select(`activeTriggerId`);if(i===e){n.update({activeTriggerElement:t,...r});return}i??n.update({activeTriggerId:e,activeTriggerElement:t,...r})});return bs(()=>{i&&n.update({activeTriggerElement:t.current,...r})},[i,n,t,...Object.values(r)]),{registerTrigger:o,isMountedByThisTrigger:i}}function Zm(e){let t=e.useState(`open`);bs(()=>{if(t&&!e.select(`activeTriggerId`)&&e.context.triggerElements.size===1){let t=e.context.triggerElements.entries().next();if(!t.done){let[n,r]=t.value;e.update({activeTriggerId:n,activeTriggerElement:r})}}},[t,e])}function Qm(e,t,n){let{mounted:r,setMounted:i,transitionStatus:a}=Rd(e);t.useSyncedValues({mounted:r,transitionStatus:a});let o=gs(()=>{i(!1),t.update({activeTriggerId:null,activeTriggerElement:null,mounted:!1}),n?.(),t.context.onOpenChangeComplete?.(!1)});return Ld({enabled:!t.useState(`preventUnmountingOnClose`),open:e,ref:t.context.popupRef,onComplete(){e||o()}}),{forceUnmount:o,transitionStatus:a}}var $m=class{constructor(){this.elementsSet=new Set,this.idMap=new Map}add(e,t){let n=this.idMap.get(e);n!==t&&(n!==void 0&&this.elementsSet.delete(n),this.elementsSet.add(t),this.idMap.set(e,t))}delete(e){let t=this.idMap.get(e);t&&(this.elementsSet.delete(t),this.idMap.delete(e))}hasElement(e){return this.elementsSet.has(e)}hasMatchingElement(e){for(let t of this.elementsSet)if(e(t))return!0;return!1}getById(e){return this.idMap.get(e)}entries(){return this.idMap.entries()}elements(){return this.elementsSet.values()}get size(){return this.idMap.size}};function eh(){return new Jm({open:!1,transitionStatus:void 0,floatingElement:null,referenceElement:null,triggerElements:new $m,floatingId:``,syncOnly:!1,nested:!1,onOpenChange:void 0})}function th(){return{open:!1,openProp:void 0,mounted:!1,transitionStatus:void 0,floatingRootContext:eh(),preventUnmountingOnClose:!1,payload:void 0,activeTriggerId:null,activeTriggerElement:null,triggerIdProp:void 0,popupElement:null,positionerElement:null,activeTriggerProps:Ja,inactiveTriggerProps:Ja,popupProps:Ja}}var nh=jm(e=>e.triggerIdProp??e.activeTriggerId),rh={open:jm(e=>e.openProp??e.open),mounted:jm(e=>e.mounted),transitionStatus:jm(e=>e.transitionStatus),floatingRootContext:jm(e=>e.floatingRootContext),preventUnmountingOnClose:jm(e=>e.preventUnmountingOnClose),payload:jm(e=>e.payload),activeTriggerId:nh,activeTriggerElement:jm(e=>e.mounted?e.activeTriggerElement:null),isTriggerActive:jm((e,t)=>t!==void 0&&nh(e)===t),isOpenedByTrigger:jm((e,t)=>t!==void 0&&nh(e)===t&&e.open),isMountedByTrigger:jm((e,t)=>t!==void 0&&nh(e)===t&&e.mounted),triggerProps:jm((e,t)=>t?e.activeTriggerProps:e.inactiveTriggerProps),popupProps:jm(e=>e.popupProps),popupElement:jm(e=>e.popupElement),positionerElement:jm(e=>e.positionerElement)};function ih(e){let{open:t=!1,onOpenChange:n,elements:r={}}=e,i=wl(),a=fp()!=null,o=Ia(()=>new Jm({open:t,transitionStatus:void 0,onOpenChange:n,referenceElement:r.reference??null,floatingElement:r.floating??null,triggerElements:new $m,floatingId:i,syncOnly:!1,nested:a})).current;return bs(()=>{let e={open:t,floatingId:i};r.reference!==void 0&&(e.referenceElement=r.reference,e.domReferenceElement=Jo(r.reference)?r.reference:null),r.floating!==void 0&&(e.floatingElement=r.floating),o.update(e)},[t,i,r.reference,r.floating,o]),o.context.onOpenChange=n,o.context.nested=a,o}function ah(e={}){let{nodeId:t,externalTree:n}=e,r=ih(e),i=e.rootContext||r,a={reference:i.useState(`referenceElement`),floating:i.useState(`floatingElement`),domReference:i.useState(`domReferenceElement`)},[o,s]=P.useState(null),c=P.useRef(null),l=pp(n);bs(()=>{a.domReference&&(c.current=a.domReference)},[a.domReference]);let u=tee({...e,elements:{...a,...o&&{reference:o}}}),d=P.useCallback(e=>{let t=Jo(e)?{getBoundingClientRect:()=>e.getBoundingClientRect(),getClientRects:()=>e.getClientRects(),contextElement:e}:e;s(t),u.refs.setReference(t)},[u.refs]),[f,p]=P.useState(void 0),[m,h]=P.useState(null);i.useSyncedValue(`referenceElement`,f??null);let g=Jo(f)?f:null;i.useSyncedValue(`domReferenceElement`,f===void 0?a.domReference:g),i.useSyncedValue(`floatingElement`,m);let _=P.useCallback(e=>{(Jo(e)||e===null)&&(c.current=e,p(e)),(Jo(u.refs.reference.current)||u.refs.reference.current===null||e!==null&&!Jo(e))&&u.refs.setReference(e)},[u.refs,p]),v=P.useCallback(e=>{h(e),u.refs.setFloating(e)},[u.refs]),y=P.useMemo(()=>({...u.refs,setReference:_,setFloating:v,setPositionReference:d,domReference:c}),[u.refs,_,v,d]),b=P.useMemo(()=>({...u.elements,domReference:a.domReference}),[u.elements,a.domReference]),x=i.useState(`open`),S=i.useState(`floatingId`),C=P.useMemo(()=>({...u,dataRef:i.context.dataRef,open:x,onOpenChange:i.setOpen,events:i.context.events,floatingId:S,refs:y,elements:b,nodeId:t,rootStore:i}),[u,y,b,t,i,x,S]);return bs(()=>{i.context.dataRef.current.floatingContext=C;let e=l?.nodesRef.current.find(e=>e.id===t);e&&(e.context=C)}),P.useMemo(()=>({...u,context:C,refs:y,elements:b,rootStore:i}),[u,y,b,C,i])}function oh(e){let{popupStore:t,treatPopupAsFloatingElement:n=!1,onOpenChange:r}=e,i=wl(),a=fp()!=null,o=t.useState(`open`),s=t.useState(`activeTriggerElement`),c=t.useState(n?`popupElement`:`positionerElement`),l=t.context.triggerElements,u=Ia(()=>new Jm({open:o,transitionStatus:void 0,referenceElement:s,floatingElement:c,triggerElements:l,onOpenChange:r,floatingId:i,syncOnly:!0,nested:a})).current;return bs(()=>{let e={open:o,floatingId:i,referenceElement:s,floatingElement:c};Jo(s)&&(e.domReferenceElement=s),u.state.positionReference===u.state.referenceElement&&(e.positionReference=s),u.update(e)},[o,i,s,c,u]),u.context.onOpenChange=r,u.context.nested=a,u}var sh=Rl&&Il;function cee(e,t={}){let n=`rootStore`in e?e.rootStore:e,{events:r,dataRef:i}=n.context,{enabled:a=!0,delay:o}=t,s=P.useRef(!1),c=P.useRef(null),l=Ed(),u=P.useRef(!0);P.useEffect(()=>{let e=n.select(`domReferenceElement`);if(!a)return;let t=Go(e);function r(){let e=n.select(`domReferenceElement`);!n.select(`open`)&&Yo(e)&&e===Yl(kl(e))&&(s.current=!0)}function i(){u.current=!0}function o(){u.current=!1}return Mf(jf(t,`blur`,r),sh&&jf(t,`keydown`,i,!0),sh&&jf(t,`pointerdown`,o,!0))},[n,a]),P.useEffect(()=>{if(!a)return;function e(e){if(e.reason===`trigger-press`||e.reason===`escape-key`){let e=n.select(`domReferenceElement`);Jo(e)&&(c.current=e,s.current=!0)}}return r.on(`openchange`,e),()=>{r.off(`openchange`,e)}},[r,a,n]);let d=P.useMemo(()=>({onMouseLeave(){s.current=!1,c.current=null},onFocus(e){let t=e.currentTarget;if(s.current){if(c.current===t)return;s.current=!1,c.current=null}let r=Zl(e.nativeEvent);if(Jo(r)){if(sh&&!e.relatedTarget){if(!u.current&&!tu(r))return}else if(!iu(r))return}let i=Ql(e.relatedTarget,n.context.triggerElements),{nativeEvent:a,currentTarget:d}=e,f=typeof o==`function`?o():o;if(n.select(`open`)&&i||f===0||f===void 0){n.setOpen(!0,tf(Wd,a,d));return}l.start(f,()=>{s.current||n.setOpen(!0,tf(Wd,a,d))})},onBlur(e){s.current=!1,c.current=null;let t=e.relatedTarget,r=e.nativeEvent,a=Jo(t)&&t.hasAttribute(zf(`focus-guard`))&&t.getAttribute(`data-type`)===`outside`;l.start(0,()=>{let e=n.select(`domReferenceElement`),o=Yl(kl(e));!t&&o===e||Xl(i.current.floatingContext?.refs.floating.current,o)||Xl(e,o)||a||Ql(t??o,n.context.triggerElements)||n.setOpen(!1,tf(Wd,r))})}}),[i,n,l,o]);return P.useMemo(()=>a?{reference:d,trigger:d}:{},[a,d])}var lee=class e{constructor(){this.pointerType=void 0,this.interactedInside=!1,this.handler=void 0,this.blockMouseMove=!0,this.performedPointerEventsMutation=!1,this.pointerEventsScopeElement=null,this.pointerEventsReferenceElement=null,this.pointerEventsFloatingElement=null,this.restTimeoutPending=!1,this.openChangeTimeout=new Td,this.restTimeout=new Td,this.handleCloseOptions=void 0}static create(){return new e}dispose=()=>{this.openChangeTimeout.clear(),this.restTimeout.clear()};disposeEffect=()=>this.dispose},ch=new WeakMap;function lh(e){if(!e.performedPointerEventsMutation)return;let t=e.pointerEventsScopeElement;t&&ch.get(t)===e&&(e.pointerEventsScopeElement?.style.removeProperty(`pointer-events`),e.pointerEventsReferenceElement?.style.removeProperty(`pointer-events`),e.pointerEventsFloatingElement?.style.removeProperty(`pointer-events`),ch.delete(t)),e.performedPointerEventsMutation=!1,e.pointerEventsScopeElement=null,e.pointerEventsReferenceElement=null,e.pointerEventsFloatingElement=null}function uh(e,t){let{scopeElement:n,referenceElement:r,floatingElement:i}=t,a=ch.get(n);a&&a!==e&&lh(a),lh(e),e.performedPointerEventsMutation=!0,e.pointerEventsScopeElement=n,e.pointerEventsReferenceElement=r,e.pointerEventsFloatingElement=i,ch.set(n,e),n.style.pointerEvents=`none`,r.style.pointerEvents=`auto`,i.style.pointerEvents=`auto`}function dh(e){let t=Ia(lee.create).current,n=e.context.dataRef.current;return n.hoverInteractionState||=t,Cd(n.hoverInteractionState.disposeEffect),n.hoverInteractionState}function uee(e,t={}){let n=`rootStore`in e?e.rootStore:e,r=n.useState(`open`),i=n.useState(`floatingElement`),a=n.useState(`domReferenceElement`),{dataRef:o}=n.context,{enabled:s=!0,closeDelay:c=0,nodeId:l}=t,u=dh(n),d=pp(),f=fp(),p=gs(()=>Df(o.current.openEvent?.type,u.interactedInside)),m=gs(()=>{let e=o.current.openEvent?.type;return e?.includes(`mouse`)&&e!==`mousedown`}),h=gs(e=>Ql(e,n.context.triggerElements)),g=P.useCallback(e=>{let t=Tf(c,`close`,u.pointerType),r=()=>{n.setOpen(!1,tf(Ud,e)),d?.events.emit(`floating.closed`,e)};t?u.openChangeTimeout.start(t,r):(u.openChangeTimeout.clear(),r())},[c,n,u,d]),_=gs(()=>{lh(u)}),v=gs(e=>{let t=Zl(e);if(!nu(t)){u.interactedInside=!1;return}u.interactedInside=t?.closest(`[aria-haspopup]`)!=null});bs(()=>{r||(u.pointerType=void 0,u.restTimeoutPending=!1,u.interactedInside=!1,_())},[r,u,_]),P.useEffect(()=>_,[_]),bs(()=>{if(s&&r&&u.handleCloseOptions?.blockPointerEvents&&m()&&Jo(a)&&i){let e=a,t=i,n=kl(i),r=d?.nodesRef.current.find(e=>e.id===f)?.context?.elements.floating;return r&&(r.style.pointerEvents=``),uh(u,{scopeElement:u.handleCloseOptions?.getScope?.()??u.pointerEventsScopeElement??r??e.closest(`[data-rootownerid]`)??n.body,referenceElement:e,floatingElement:t}),()=>{_()}}},[s,r,a,i,u,m,d,f,_]);let y=Ed();P.useEffect(()=>{if(!s)return;function e(){u.openChangeTimeout.clear(),y.clear(),d?.events.off(`floating.closed`,r),_()}function t(e){if(d&&f&&ou(d.nodesRef.current,f).length>0){d.events.on(`floating.closed`,r);return}if(h(e.relatedTarget))return;let t=o.current.floatingContext?.nodeId??l,n=e.relatedTarget;if(!(d&&t&&Jo(n)&&ou(d.nodesRef.current,t,!1).some(e=>Xl(e.context?.elements.floating,n)))){if(u.handler){u.handler(e);return}_(),p()||g(e)}}function r(e){!d||!f||ou(d.nodesRef.current,f).length>0||y.start(0,()=>{d.events.off(`floating.closed`,r),n.setOpen(!1,tf(Ud,e)),d.events.emit(`floating.closed`,e)})}let a=i;return Mf(a&&jf(a,`mouseenter`,e),a&&jf(a,`mouseleave`,t),a&&jf(a,`pointerdown`,v,!0),()=>{d?.events.off(`floating.closed`,r)})},[s,i,n,o,l,p,h,g,_,v,u,d,f,y])}var dee={current:null};function fee(e,t={}){let n=`rootStore`in e?e.rootStore:e,{dataRef:r,events:i}=n.context,{enabled:a=!0,delay:o=0,handleClose:s=null,mouseOnly:c=!1,restMs:l=0,move:u=!0,triggerElementRef:d=dee,externalTree:f,isActiveTrigger:p=!0,getHandleCloseContext:m,isClosing:h}=t,g=pp(f),_=dh(n),v=P.useRef(!1),y=Nf(s),b=Nf(o),x=Nf(l),S=Nf(a),C=Nf(h);p&&(_.handleCloseOptions=y.current?.__options);let w=gs(()=>Df(r.current.openEvent?.type,_.interactedInside)),T=gs(e=>Ql(e,n.context.triggerElements)),E=gs((e,t,r)=>{let i=n.context.triggerElements;if(i.hasElement(t))return!e||!Xl(e,t);if(!Jo(r))return!1;let a=r;return i.hasMatchingElement(e=>Xl(e,a))&&(!e||!Xl(e,a))}),ee=gs((e,t=!0)=>{let r=Tf(b.current,`close`,_.pointerType);r?_.openChangeTimeout.start(r,()=>{n.setOpen(!1,tf(Ud,e)),g?.events.emit(`floating.closed`,e)}):t&&(_.openChangeTimeout.clear(),n.setOpen(!1,tf(Ud,e)),g?.events.emit(`floating.closed`,e))}),D=gs(()=>{_.handler&&=(kl(n.select(`domReferenceElement`)).removeEventListener(`mousemove`,_.handler),void 0)}),O=gs(()=>{lh(_)});return P.useEffect(()=>D,[D]),P.useEffect(()=>{if(!a)return;function e(e){e.open?v.current=!1:(v.current=e.reason===Ud,D(),_.openChangeTimeout.clear(),_.restTimeout.clear(),_.blockMouseMove=!0,_.restTimeoutPending=!1)}return i.on(`openchange`,e),()=>{i.off(`openchange`,e)}},[a,i,_,D]),P.useEffect(()=>{if(!a)return;let e=d.current??(p?n.select(`domReferenceElement`):null);if(!Jo(e))return;function t(e){if(_.openChangeTimeout.clear(),_.blockMouseMove=!1,c&&!fu(_.pointerType))return;let t=Ef(x.current),r=Tf(b.current,`open`,_.pointerType),i=Zl(e),a=e.currentTarget??null,o=n.select(`domReferenceElement`),s=a;if(Jo(i)&&!n.context.triggerElements.hasElement(i)){for(let e of n.context.triggerElements.elements())if(Xl(e,i)){s=e;break}}Jo(a)&&Jo(o)&&!n.context.triggerElements.hasElement(a)&&Xl(a,o)&&(s=o);let l=s==null?!1:E(o,s,i),u=n.select(`open`),d=C.current?.()??n.select(`transitionStatus`)===`ending`,f=!u&&d&&v.current,p=!l&&Jo(s)&&Jo(o)&&Xl(o,s)&&f,m=t>0&&!r,h=l&&(u||f)||p,g=!u||l;if(h){n.setOpen(!0,tf(Ud,e,s));return}m||(r?_.openChangeTimeout.start(r,()=>{g&&n.setOpen(!0,tf(Ud,e,s))}):g&&n.setOpen(!0,tf(Ud,e,s)))}function i(e){if(w()){O();return}D();let t=kl(n.select(`domReferenceElement`));_.restTimeout.clear(),_.restTimeoutPending=!1;let i=r.current.floatingContext??m?.();if(!T(e.relatedTarget)){if(y.current&&i){n.select(`open`)||_.openChangeTimeout.clear();let r=d.current;_.handler=y.current({...i,tree:g,x:e.clientX,y:e.clientY,onClose(){O(),D(),S.current&&!w()&&r===n.select(`domReferenceElement`)&&ee(e,!0)}}),t.addEventListener(`mousemove`,_.handler),_.handler(e);return}(_.pointerType!==`touch`||!Xl(n.select(`floatingElement`),e.relatedTarget))&&ee(e)}}return u?Mf(jf(e,`mousemove`,t,{once:!0}),jf(e,`mouseenter`,t),jf(e,`mouseleave`,i)):Mf(jf(e,`mouseenter`,t),jf(e,`mouseleave`,i))},[D,O,r,b,ee,n,a,y,_,p,E,w,T,c,u,x,d,g,S,m,C]),P.useMemo(()=>{if(!a)return;function e(e){_.pointerType=e.pointerType}return{onPointerDown:e,onPointerEnter:e,onMouseMove(e){let{nativeEvent:t}=e,r=e.currentTarget,i=n.select(`domReferenceElement`),a=n.select(`open`),o=E(i,r,e.target);if(c&&!fu(_.pointerType))return;if(a&&o&&_.handleCloseOptions?.blockPointerEvents){let e=n.select(`floatingElement`);e&&uh(_,{scopeElement:_.handleCloseOptions?.getScope?.()??r.ownerDocument.body,referenceElement:r,floatingElement:e})}let s=Ef(x.current);if(a&&!o||s===0||!o&&_.restTimeoutPending&&e.movementX**2+e.movementY**2<2)return;_.restTimeout.clear();function l(){if(_.restTimeoutPending=!1,w())return;let e=n.select(`open`);!_.blockMouseMove&&(!e||o)&&n.setOpen(!0,tf(Ud,t,r))}_.pointerType===`touch`?gi.flushSync(()=>{l()}):o&&a?l():(_.restTimeoutPending=!0,_.restTimeout.start(s,l))}}},[a,_,w,E,c,n,x])}function fh(e=[]){let t=e.map(e=>e?.reference),n=e.map(e=>e?.floating),r=e.map(e=>e?.item),i=e.map(e=>e?.trigger),a=P.useCallback(t=>ph(t,e,`reference`),t),o=P.useCallback(t=>ph(t,e,`floating`),n),s=P.useCallback(t=>ph(t,e,`item`),r),c=P.useCallback(t=>ph(t,e,`trigger`),i);return P.useMemo(()=>({getReferenceProps:a,getFloatingProps:o,getItemProps:s,getTriggerProps:c}),[a,o,s,c])}function ph(e,t,n){let r=new Map,i=n===`item`,a={};n===`floating`&&(a.tabIndex=-1,a[Ul]=``);for(let t in e)i&&e&&(t===`active`||t===`selected`)||(a[t]=e[t]);for(let o=0;or.get(i)?.map(t=>t(...e)).find(e=>e!==void 0))):e[i]=a)}}var pee=new Map([[`select`,`listbox`],[`combobox`,`listbox`],[`label`,!1]]);function mee(e,t={}){let n=`rootStore`in e?e.rootStore:e,r=n.useState(`open`),i=n.useState(`floatingId`),a=n.useState(`domReferenceElement`),o=n.useState(`floatingElement`),{role:s=`dialog`}=t,c=wl(),l=a?.id||c,u=P.useMemo(()=>au(o)?.id||i,[o,i]),d=pee.get(s)??s,f=fp()!=null,p=P.useMemo(()=>d===`tooltip`||s===`label`?Ja:{"aria-haspopup":d===`alertdialog`?`dialog`:d,"aria-expanded":`false`,...d===`listbox`&&{role:`combobox`},...d===`menu`&&f&&{role:`menuitem`},...s===`select`&&{"aria-autocomplete":`none`},...s===`combobox`&&{"aria-autocomplete":`list`}},[d,f,s]),m=P.useMemo(()=>d===`tooltip`||s===`label`?{[`aria-${s===`label`?`labelledby`:`describedby`}`]:r?u:void 0}:{...p,"aria-expanded":r?`true`:`false`,"aria-controls":r?u:void 0,...d===`menu`&&{id:l}},[d,u,r,l,s,p]),h=P.useMemo(()=>{let e={id:u,...d&&{role:d}};return d===`tooltip`||s===`label`?e:{...e,...d===`menu`&&{"aria-labelledby":l}}},[d,u,l,s]),g=P.useCallback(({active:e,selected:t})=>{let n={role:`option`,...e&&{id:`${u}-fui-option`}};switch(s){case`select`:case`combobox`:return{...n,"aria-selected":t};default:}return{}},[u,s]);return P.useMemo(()=>({reference:m,floating:h,item:g,trigger:p}),[m,h,p,g])}var hh=.1,gh=hh*hh,_h=.5;function vh(e,t,n,r,i,a){return r>=t!=a>=t&&e<=(i-n)*(t-r)/(a-r)+n}function yh(e,t,n,r,i,a,o,s,c,l){let u=!1;return vh(e,t,n,r,i,a)&&(u=!u),vh(e,t,i,a,o,s)&&(u=!u),vh(e,t,o,s,c,l)&&(u=!u),vh(e,t,c,l,n,r)&&(u=!u),u}function bh(e,t,n){return e>=n.x&&e<=n.x+n.width&&t>=n.y&&t<=n.y+n.height}function xh(e,t,n,r,i,a){return e>=Math.min(n,i)&&e<=Math.max(n,i)&&t>=Math.min(r,a)&&t<=Math.max(r,a)}function Sh(e={}){let{blockPointerEvents:t=!1}=e,n=new Td,r=({x:e,y:t,placement:r,elements:i,onClose:a,nodeId:o,tree:s})=>{let c=r?.split(`-`)[0],l=!1,u=null,d=null,f=typeof performance<`u`?performance.now():0;function p(e,t){let n=performance.now(),r=n-f;if(u===null||d===null||r===0)return u=e,d=t,f=n,!1;let i=e-u,a=t-d,o=i*i+a*a,s=r*r*gh;return u=e,d=t,f=n,o0)}function b(){y()||m()}if(y())return;let x=a.getBoundingClientRect(),S=u.getBoundingClientRect(),C=e>S.right-S.width/2,w=t>S.bottom-S.height/2,T=S.width>x.width,E=S.height>x.height,ee=(T?x:S).left,D=(T?x:S).right,O=(E?x:S).top,te=(E?x:S).bottom;if(c===`top`&&t>=x.bottom-1||c===`bottom`&&t<=x.top+1||c===`left`&&e>=x.right-1||c===`right`&&e<=x.left+1){b();return}let ne=!1;switch(c){case`top`:ne=xh(d,f,ee,x.top+1,D,S.bottom-1);break;case`bottom`:ne=xh(d,f,ee,S.top+1,D,x.bottom-1);break;case`left`:ne=xh(d,f,S.right-1,te,x.left+1,O);break;case`right`:ne=xh(d,f,x.right-1,te,S.left+1,O);break;default:}if(ne)return;if(l&&!bh(d,f,x)){b();return}if(!g&&p(d,f)){b();return}let re=!1;switch(c){case`top`:{let n=T?_h/2:_h*4,r=T||C?e+n:e-n,i=T?e-n:C?e+n:e-n,a=t+_h+1,o=C||T?S.bottom-_h:S.top,s=C?T?S.bottom-_h:S.top:S.bottom-_h;re=yh(d,f,r,a,i,a,S.left,o,S.right,s);break}case`bottom`:{let n=T?_h/2:_h*4,r=T||C?e+n:e-n,i=T?e-n:C?e+n:e-n,a=t-_h,o=C||T?S.top+_h:S.bottom,s=C?T?S.top+_h:S.bottom:S.top+_h;re=yh(d,f,r,a,i,a,S.left,o,S.right,s);break}case`left`:{let n=E?_h/2:_h*4,r=E||w?t+n:t-n,i=E?t-n:w?t+n:t-n,a=e+_h+1,o=w||E?S.right-_h:S.left,s=w?E?S.right-_h:S.left:S.right-_h;re=yh(d,f,o,S.top,s,S.bottom,a,r,a,i);break}case`right`:{let n=E?_h/2:_h*4,r=E||w?t+n:t-n,i=E?t-n:w?t+n:t-n,a=e-_h,o=w||E?S.left+_h:S.right,s=w?E?S.left+_h:S.right:S.left+_h;re=yh(d,f,a,r,a,i,o,S.top,s,S.bottom);break}default:}re?l||n.start(40,b):b()}};return r.__options={...e,blockPointerEvents:t},r}var Ch=function(e){return e.nestedDialogs=`--nested-dialogs`,e}({}),wh=function(e){return e[e.open=uf.open]=`open`,e[e.closed=uf.closed]=`closed`,e[e.startingStyle=uf.startingStyle]=`startingStyle`,e[e.endingStyle=uf.endingStyle]=`endingStyle`,e.nested=`data-nested`,e.nestedDialogOpen=`data-nested-dialog-open`,e}({}),Th=P.createContext(void 0);function Eh(){let e=P.useContext(Th);if(e===void 0)throw Error(Pa(26));return e}var Dh=`ArrowUp`,Oh=`ArrowDown`,kh=`ArrowLeft`,Ah=`ArrowRight`,jh=`Home`,Mh=new Set([kh,Ah]),Nh=new Set([kh,Ah,jh,`End`]),Ph=new Set([Dh,Oh]),Fh=new Set([Dh,Oh,jh,`End`]),Ih=new Set([...Mh,...Ph]),Lh=new Set([...Ih,jh,`End`]),Rh=new Set([Dh,Oh,kh,Ah,jh,`End`]),zh=new Set([`Shift`,`Control`,`Alt`,`Meta`]);function Bh(e){return Yo(e)&&e.tagName===`INPUT`}function Vh(e){return!!(Bh(e)&&e.selectionStart!=null||Yo(e)&&e.tagName===`TEXTAREA`)}function Hh(e,t,n,r){if(!e||!t||!t.scrollTo)return;let i=e.scrollLeft,a=e.scrollTop,o=e.clientWidthe.scrollLeft+e.clientWidth-a.scrollPaddingRight?i=r+t.offsetWidth+o.scrollMarginRight-e.clientWidth+a.scrollPaddingRight:r-o.scrollMarginLefte.scrollLeft+e.clientWidth-a.scrollPaddingRight&&(i=r+t.offsetWidth+o.scrollMarginRight-e.clientWidth+a.scrollPaddingRight))}if(s&&r!==`horizontal`){let n=Uh(e,t,`top`),r=Wh(e),i=Wh(t);n-i.scrollMarginTope.scrollTop+e.clientHeight-r.scrollPaddingBottom&&(a=n+t.offsetHeight+i.scrollMarginBottom-e.clientHeight+r.scrollPaddingBottom)}e.scrollTo({left:i,top:a,behavior:`auto`})}function Uh(e,t,n){let r=n===`left`?`offsetLeft`:`offsetTop`,i=0;for(;t.offsetParent&&(i+=t[r],t.offsetParent!==e);)t=t.offsetParent;return i}function Wh(e){let t=getComputedStyle(e);return{scrollMarginTop:parseFloat(t.scrollMarginTop)||0,scrollMarginRight:parseFloat(t.scrollMarginRight)||0,scrollMarginBottom:parseFloat(t.scrollMarginBottom)||0,scrollMarginLeft:parseFloat(t.scrollMarginLeft)||0,scrollPaddingTop:parseFloat(t.scrollPaddingTop)||0,scrollPaddingRight:parseFloat(t.scrollPaddingRight)||0,scrollPaddingBottom:parseFloat(t.scrollPaddingBottom)||0,scrollPaddingLeft:parseFloat(t.scrollPaddingLeft)||0}}var Gh={...yf,...Fd,nestedDialogOpen(e){return e?{[wh.nestedDialogOpen]:``}:null}},Kh=P.forwardRef(function(e,t){let{className:n,finalFocus:r,initialFocus:i,render:a,style:o,...s}=e,{store:c}=lf(),l=c.useState(`descriptionElementId`),u=c.useState(`disablePointerDismissal`),d=c.useState(`floatingRootContext`),f=c.useState(`popupProps`),p=c.useState(`modal`),m=c.useState(`mounted`),h=c.useState(`nested`),g=c.useState(`nestedOpenDialogCount`),_=c.useState(`open`),v=c.useState(`openMethod`),y=c.useState(`titleElementId`),b=c.useState(`transitionStatus`),x=c.useState(`role`);Eh(),Ld({open:_,ref:c.context.popupRef,onComplete(){_&&c.context.onOpenChangeComplete?.(!0)}});function S(e){return e===`touch`?c.context.popupRef.current:!0}let C=i===void 0?S:i,w=Qa(`div`,e,{state:{open:_,nested:h,transitionStatus:b,nestedDialogOpen:g>0},props:[f,{"aria-labelledby":y??void 0,"aria-describedby":l??void 0,role:x,tabIndex:-1,hidden:!m,onKeyDown(e){Rh.has(e.key)&&e.stopPropagation()},style:{[Ch.nestedDialogs]:g}},s],ref:[t,c.context.popupRef,c.useStateSetter(`popupElement`)],stateAttributesMapping:Gh});return(0,F.jsx)(Sp,{context:d,openInteractionType:v,disabled:!m,closeOnFocusOut:!u,initialFocus:C,returnFocus:r,modal:p!==!1,restoreFocus:`popup`,children:w})});function qh(e){return Wa(19)?e:e?`true`:void 0}var Jh=P.forwardRef(function(e,t){let{cutout:n,...r}=e,i;if(n){let e=n.getBoundingClientRect();i=`polygon(0% 0%,100% 0%,100% 100%,0% 100%,0% 0%,${e.left}px ${e.top}px,${e.left}px ${e.bottom}px,${e.right}px ${e.bottom}px,${e.right}px ${e.top}px,${e.left}px ${e.top}px)`}return(0,F.jsx)(`div`,{ref:t,role:`presentation`,"data-base-ui-inert":``,...r,style:{position:`fixed`,inset:0,userSelect:`none`,WebkitUserSelect:`none`,clipPath:i}})}),Yh=P.forwardRef(function(e,t){let{keepMounted:n=!1,...r}=e,{store:i}=lf(),a=i.useState(`mounted`),o=i.useState(`modal`),s=i.useState(`open`);return a||n?(0,F.jsx)(Th.Provider,{value:n,children:(0,F.jsxs)(cp,{ref:t,...r,children:[a&&o===!0&&(0,F.jsx)(Jh,{ref:i.context.internalBackdropRef,inert:qh(!s)}),e.children]})}):null});function Xh(e){let t=P.useRef(!0);t.current&&(t.current=!1,e())}var Zh={},Qh={},$h=``;function eg(e){if(typeof document>`u`)return!1;let t=kl(e);return Go(t).innerWidth-t.documentElement.clientWidth>0}function tg(e){if(!(typeof CSS<`u`&&CSS.supports&&CSS.supports(`scrollbar-gutter`,`stable`))||typeof document>`u`)return!1;let t=kl(e),n=t.documentElement,r=t.body,i=Zo(n)?n:r,a=i.style.overflowY,o=n.style.scrollbarGutter;n.style.scrollbarGutter=`stable`,i.style.overflowY=`scroll`;let s=i.offsetWidth;i.style.overflowY=`hidden`;let c=i.offsetWidth;return i.style.overflowY=a,n.style.scrollbarGutter=o,s===c}function ng(e){let t=kl(e),n=t.documentElement,r=t.body,i=Zo(n)?n:r,a={overflowY:i.style.overflowY,overflowX:i.style.overflowX};return Object.assign(i.style,{overflowY:`hidden`,overflowX:`hidden`}),()=>{Object.assign(i.style,a)}}function rg(e){let t=kl(e),n=t.documentElement,r=t.body,i=Go(n),a=0,o=0,s=!1,c=kd.create();if(Pl&&(i.visualViewport?.scale??1)!==1)return()=>{};function l(){let t=i.getComputedStyle(n),c=i.getComputedStyle(r),l=(t.scrollbarGutter||``).includes(`both-edges`)?`stable both-edges`:`stable`;a=n.scrollTop,o=n.scrollLeft,Zh={scrollbarGutter:n.style.scrollbarGutter,overflowY:n.style.overflowY,overflowX:n.style.overflowX},$h=n.style.scrollBehavior,Qh={position:r.style.position,height:r.style.height,width:r.style.width,boxSizing:r.style.boxSizing,overflowY:r.style.overflowY,overflowX:r.style.overflowX,scrollBehavior:r.style.scrollBehavior};let u=n.scrollHeight>n.clientHeight,d=n.scrollWidth>n.clientWidth,f=t.overflowY===`scroll`||c.overflowY===`scroll`,p=t.overflowX===`scroll`||c.overflowX===`scroll`,m=Math.max(0,i.innerWidth-r.clientWidth),h=Math.max(0,i.innerHeight-r.clientHeight),g=parseFloat(c.marginTop)+parseFloat(c.marginBottom),_=parseFloat(c.marginLeft)+parseFloat(c.marginRight),v=Zo(n)?n:r;if(s=tg(e),s){n.style.scrollbarGutter=l,v.style.overflowY=`hidden`,v.style.overflowX=`hidden`;return}Object.assign(n.style,{scrollbarGutter:l,overflowY:`hidden`,overflowX:`hidden`}),(u||f)&&(n.style.overflowY=`scroll`),(d||p)&&(n.style.overflowX=`scroll`),Object.assign(r.style,{position:`relative`,height:g||h?`calc(100dvh - ${g+h}px)`:`100dvh`,width:_||m?`calc(100vw - ${_+m}px)`:`100vw`,boxSizing:`border-box`,overflow:`hidden`,scrollBehavior:`unset`}),r.scrollTop=a,r.scrollLeft=o,n.setAttribute(`data-base-ui-scroll-locked`,``),n.style.scrollBehavior=`unset`}function u(){Object.assign(n.style,Zh),Object.assign(r.style,Qh),s||(n.scrollTop=a,n.scrollLeft=o,n.removeAttribute(`data-base-ui-scroll-locked`),n.style.scrollBehavior=$h)}function d(){u(),c.request(l)}l();let f=jf(i,`resize`,d);return()=>{c.cancel(),u(),typeof i.removeEventListener==`function`&&f()}}var ig=new class{lockCount=0;restore=null;timeoutLock=Td.create();timeoutUnlock=Td.create();acquire(e){return this.lockCount+=1,this.lockCount===1&&this.restore===null&&this.timeoutLock.start(0,()=>this.lock(e)),this.release}release=()=>{--this.lockCount,this.lockCount===0&&this.restore&&this.timeoutUnlock.start(0,this.unlock)};unlock=()=>{this.lockCount===0&&this.restore&&(this.restore?.(),this.restore=null)};lock(e){if(this.lockCount===0||this.restore!==null)return;let t=kl(e).documentElement,n=Go(t).getComputedStyle(t).overflowY;if(n===`hidden`||n===`clip`){this.restore=Ka;return}let r=Fl||!eg(e);this.restore=r?ng(e):rg(e)}};function ag(e=!0,t=null){bs(()=>{if(e)return ig.acquire(t)},[e,t])}function og(e){let t=P.useRef(``),n=P.useCallback(n=>{n.defaultPrevented||(t.current=n.pointerType,e(n,n.pointerType))},[e]);return{onClick:P.useCallback(n=>{if(n.detail===0){e(n,`keyboard`);return}`pointerType`in n?e(n,n.pointerType):e(n,t.current),t.current=``},[e]),onPointerDown:n}}function sg(e,t){let n=P.useRef(e),r=gs(t);bs(()=>{n.current!==e&&r(n.current)},[e,r]),bs(()=>{n.current=e},[e])}function cg(e){let[t,n]=P.useState(null),r=gs((t,r)=>{e||n(r||(Fl?`touch`:``))});sg(e,t=>{t&&!e&&n(null)});let{onClick:i,onPointerDown:a}=og(r);return P.useMemo(()=>({openMethod:t,triggerProps:{onClick:i,onPointerDown:a}}),[t,i,a])}function lg(e){let{store:t,parentContext:n,actionsRef:r,isDrawer:i}=e,a=t.useState(`open`),o=t.useState(`disablePointerDismissal`),s=t.useState(`modal`),c=t.useState(`popupElement`),{openMethod:l,triggerProps:u}=cg(a);Zm(t);let{forceUnmount:d}=Qm(a,t),f=P.useCallback(()=>{t.setOpen(!1,tf($d))},[t]);P.useImperativeHandle(r,()=>({unmount:d,close:f}),[d,f]);let p=oh({popupStore:t,onOpenChange:t.setOpen,treatPopupAsFloatingElement:!0}),[m,h]=P.useState(0),[g,_]=P.useState(0),v=m===0,y=mee(p),b=kp(p,{outsidePressEvent(){return t.context.internalBackdropRef.current||t.context.backdropRef.current?`intentional`:{mouse:s===`trap-focus`?`sloppy`:`intentional`,touch:`sloppy`}},outsidePress(e){if(!t.context.outsidePressEnabledRef.current||`button`in e&&e.button!==0||`touches`in e&&e.touches.length!==1)return!1;let n=Zl(e);if(v&&!o){let e=n;return s&&(t.context.internalBackdropRef.current||t.context.backdropRef.current)?t.context.internalBackdropRef.current===e||t.context.backdropRef.current===e||Xl(e,c)&&!e?.hasAttribute(`data-base-ui-portal`):!0}return!1},escapeKey:v});ag(a&&s===!0,c);let{getReferenceProps:x,getFloatingProps:S,getTriggerProps:C}=fh([y,b]);t.useContextCallback(`onNestedDialogOpen`,(e,t)=>{h(e),_(t)}),t.useContextCallback(`onNestedDialogClose`,()=>{h(0),_(0)}),P.useEffect(()=>(n?.onNestedDialogOpen&&a&&n.onNestedDialogOpen(m+1,g+ +!!i),n?.onNestedDialogClose&&!a&&n.onNestedDialogClose(),()=>{n?.onNestedDialogClose&&a&&n.onNestedDialogClose()}),[i,a,m,g,n]);let w=P.useMemo(()=>x(u),[x,u]),T=P.useMemo(()=>C(u),[C,u]),E=P.useMemo(()=>S(),[S]);t.useSyncedValues({openMethod:l,activeTriggerProps:w,inactiveTriggerProps:T,popupProps:E,floatingRootContext:p,nestedOpenDialogCount:m,nestedOpenDrawerCount:g})}var ug={...rh,modal:jm(e=>e.modal),nested:jm(e=>e.nested),nestedOpenDialogCount:jm(e=>e.nestedOpenDialogCount),nestedOpenDrawerCount:jm(e=>e.nestedOpenDrawerCount),disablePointerDismissal:jm(e=>e.disablePointerDismissal),openMethod:jm(e=>e.openMethod),descriptionElementId:jm(e=>e.descriptionElementId),titleElementId:jm(e=>e.titleElementId),viewportElement:jm(e=>e.viewportElement),role:jm(e=>e.role)},dg=class e extends Km{constructor(e){super(fg(e),{popupRef:P.createRef(),backdropRef:P.createRef(),internalBackdropRef:P.createRef(),outsidePressEnabledRef:{current:!0},triggerElements:new $m,onOpenChange:void 0,onOpenChangeComplete:void 0},ug)}setOpen=(e,t)=>{if(t.preventUnmountOnClose=()=>{this.set(`preventUnmountingOnClose`,!0)},!e&&t.trigger==null&&this.state.activeTriggerId!=null&&(t.trigger=this.state.activeTriggerElement??void 0),this.context.onOpenChange?.(e,t),t.isCanceled)return;this.state.floatingRootContext.dispatchOpenChange(e,t);let n={open:e},r=t.trigger?.id??null;(r||e)&&(n.activeTriggerId=r,n.activeTriggerElement=t.trigger??null),this.update(n)};static useStore(t,n){let r=Ia(()=>new e(n)).current;return t??r}};function fg(e={}){return{...th(),modal:!0,disablePointerDismissal:!1,popupElement:null,viewportElement:null,descriptionElementId:void 0,titleElementId:void 0,openMethod:null,nested:!1,nestedOpenDialogCount:0,nestedOpenDrawerCount:0,role:`dialog`,...e}}var pg=P.createContext(!1);function mg(e){let{children:t,open:n,defaultOpen:r=!1,onOpenChange:i,onOpenChangeComplete:a,disablePointerDismissal:o=!1,modal:s=!0,actionsRef:c,handle:l,triggerId:u,defaultTriggerId:d=null}=e,f=lf(!0),p=P.useContext(pg),m=!!f,h=dg.useStore(l?.store,{open:r,openProp:n,activeTriggerId:d,triggerIdProp:u,modal:s,disablePointerDismissal:o,nested:m});Xh(()=>{n===void 0&&h.state.open===!1&&r===!0&&h.update({open:!0,activeTriggerId:d})}),h.useControlledProp(`openProp`,n),h.useControlledProp(`triggerIdProp`,u),h.useSyncedValues({disablePointerDismissal:o,nested:m,modal:s}),h.useContextCallback(`onOpenChange`,i),h.useContextCallback(`onOpenChangeComplete`,a);let g=h.useState(`payload`);lg({store:h,actionsRef:c,parentContext:f?.store.context,isDrawer:p,onOpenChange:i,triggerIdProp:u});let _=P.useMemo(()=>({store:h}),[h]);return(0,F.jsx)(pg.Provider,{value:!1,children:(0,F.jsx)(cf.Provider,{value:_,children:typeof t==`function`?t({payload:g}):t})})}var hg=P.forwardRef(function(e,t){let{render:n,className:r,style:i,id:a,...o}=e,{store:s}=lf(),c=Tl(a);return s.useSyncedValueWithCleanup(`titleElementId`,c),Qa(`h2`,e,{ref:t,props:[{id:c},o]})});function gg(e){let t=(0,fa.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,F.jsx)(mg,{"data-slot":`sheet`,...n}),t[2]=n,t[3]=r),r}function _g(e){let t=(0,fa.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,F.jsx)(Yh,{"data-slot":`sheet-portal`,...n}),t[2]=n,t[3]=r),r}function vg(e){let t=(0,fa.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=el(`data-closed:fade-out-0 data-open:fade-in-0 data-closed:animate-out data-open:animate-in fixed inset-0 z-50 bg-black/80 duration-100 data-ending-style:opacity-0 data-starting-style:opacity-0 supports-backdrop-filter:backdrop-blur-xs`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(xf,{className:i,"data-slot":`sheet-overlay`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function yg(e){let t=(0,fa.c)(17),n,r,i,a,o;t[0]===e?(n=t[1],r=t[2],i=t[3],a=t[4],o=t[5]):({className:r,children:n,side:a,showCloseButton:o,...i}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i,t[4]=a,t[5]=o);let s=a===void 0?`right`:a,c=o===void 0?!0:o,l;t[6]===Symbol.for(`react.memo_cache_sentinel`)?(l=(0,F.jsx)(vg,{}),t[6]=l):l=t[6];let u;t[7]===r?u=t[8]:(u=el(`data-[side=right]:data-closed:slide-out-to-right-10 data-[side=right]:data-open:slide-in-from-right-10 data-[side=left]:data-closed:slide-out-to-left-10 data-[side=left]:data-open:slide-in-from-left-10 data-[side=top]:data-closed:slide-out-to-top-10 data-[side=top]:data-open:slide-in-from-top-10 data-closed:fade-out-0 data-open:fade-in-0 data-[side=bottom]:data-closed:slide-out-to-bottom-10 data-[side=bottom]:data-open:slide-in-from-bottom-10 data-closed:animate-out data-open:animate-in fixed z-50 flex flex-col bg-background bg-clip-padding text-xs/relaxed shadow-lg transition duration-200 ease-in-out data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm`,r),t[7]=r,t[8]=u);let d;t[9]===c?d=t[10]:(d=c&&(0,F.jsxs)(Sf,{"data-slot":`sheet-close`,render:(0,F.jsx)(pl,{className:`absolute top-4 right-4`,size:`icon-sm`,variant:`ghost`}),children:[(0,F.jsx)(Ho,{}),(0,F.jsx)(`span`,{className:`sr-only`,children:`Close`})]}),t[9]=c,t[10]=d);let f;return t[11]!==n||t[12]!==i||t[13]!==s||t[14]!==u||t[15]!==d?(f=(0,F.jsxs)(_g,{children:[l,(0,F.jsxs)(Kh,{className:u,"data-side":s,"data-slot":`sheet-content`,...i,children:[n,d]})]}),t[11]=n,t[12]=i,t[13]=s,t[14]=u,t[15]=d,t[16]=f):f=t[16],f}function hee(e){let t=(0,fa.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=el(`flex flex-col gap-1.5 p-6`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(`div`,{className:i,"data-slot":`sheet-header`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function gee(e){let t=(0,fa.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=el(`text-sm font-medium text-foreground`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(hg,{className:i,"data-slot":`sheet-title`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function _ee(e){let t=(0,fa.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=el(`text-xs/relaxed text-muted-foreground`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(Cf,{className:i,"data-slot":`sheet-description`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}var bg=P.createContext(void 0);function xg(e){let t=P.useContext(bg);if(t===void 0&&!e)throw Error(Pa(72));return t}var vee={...rh,disabled:jm(e=>e.disabled),instantType:jm(e=>e.instantType),isInstantPhase:jm(e=>e.isInstantPhase),trackCursorAxis:jm(e=>e.trackCursorAxis),disableHoverablePopup:jm(e=>e.disableHoverablePopup),lastOpenChangeReason:jm(e=>e.openChangeReason),closeOnClick:jm(e=>e.closeOnClick),closeDelay:jm(e=>e.closeDelay),hasViewport:jm(e=>e.hasViewport)},yee=class e extends Km{constructor(e){super({...bee(),...e},{popupRef:P.createRef(),onOpenChange:void 0,onOpenChangeComplete:void 0,triggerElements:new $m},vee)}setOpen=(e,t)=>{let n=t.reason,r=n===Ud,i=e&&n===`trigger-focus`,a=!e&&(n===`trigger-press`||n===`escape-key`);if(t.preventUnmountOnClose=()=>{this.set(`preventUnmountingOnClose`,!0)},this.context.onOpenChange?.(e,t),t.isCanceled)return;this.state.floatingRootContext.dispatchOpenChange(e,t);let o=()=>{let r={open:e,openChangeReason:n};i?r.instantType=`focus`:a?r.instantType=`dismiss`:n===`trigger-hover`&&(r.instantType=void 0);let o=t.trigger?.id??null;(o||e)&&(r.activeTriggerId=o,r.activeTriggerElement=t.trigger??null),this.update(r)};r?gi.flushSync(o):o()};static useStore(t,n){let r=Ia(()=>new e(n)).current,i=t??r,a=oh({popupStore:i,onOpenChange:i.setOpen});return i.state.floatingRootContext=a,i}};function bee(){return{...th(),disabled:!1,instantType:void 0,isInstantPhase:!1,trackCursorAxis:`none`,disableHoverablePopup:!1,openChangeReason:null,closeOnClick:!0,closeDelay:0,hasViewport:!1}}var xee=Im(function(e){let{disabled:t=!1,defaultOpen:n=!1,open:r,disableHoverablePopup:i=!1,trackCursorAxis:a=`none`,actionsRef:o,onOpenChange:s,onOpenChangeComplete:c,handle:l,triggerId:u,defaultTriggerId:d=null,children:f}=e,p=yee.useStore(l?.store,{open:n,openProp:r,activeTriggerId:d,triggerIdProp:u});Xh(()=>{r===void 0&&p.state.open===!1&&n===!0&&p.update({open:!0,activeTriggerId:d})}),p.useControlledProp(`openProp`,r),p.useControlledProp(`triggerIdProp`,u),p.useContextCallback(`onOpenChange`,s),p.useContextCallback(`onOpenChangeComplete`,c);let m=p.useState(`open`),h=!t&&m,g=p.useState(`activeTriggerId`),_=p.useState(`payload`);p.useSyncedValues({trackCursorAxis:a,disableHoverablePopup:i}),bs(()=>{m&&t&&p.setOpen(!1,tf(Qd))},[m,t,p]),p.useSyncedValue(`disabled`,t),Zm(p);let{forceUnmount:v,transitionStatus:y}=Qm(h,p),b=p.select(`floatingRootContext`),x=p.useState(`isInstantPhase`),S=p.useState(`instantType`),C=p.useState(`lastOpenChangeReason`),w=P.useRef(null);bs(()=>{y===`ending`&&C===`none`||y!==`ending`&&x?(S!==`delay`&&(w.current=S),p.set(`instantType`,`delay`)):w.current!==null&&(p.set(`instantType`,w.current),w.current=null)},[y,x,C,S,p]),bs(()=>{h&&(g??p.set(`payload`,void 0))},[p,g,h]);let T=P.useCallback(()=>{p.setOpen(!1,tf($d))},[p]);P.useImperativeHandle(o,()=>({unmount:v,close:T}),[v,T]);let{getReferenceProps:E,getFloatingProps:ee,getTriggerProps:D}=fh([kp(b,{enabled:!t,referencePress:()=>p.select(`closeOnClick`)}),Tp(b,{enabled:!t&&a!==`none`,axis:a===`none`?void 0:a})]),O=P.useMemo(()=>E(),[E]),te=P.useMemo(()=>D(),[D]),ne=P.useMemo(()=>ee(),[ee]);return p.useSyncedValues({activeTriggerProps:O,inactiveTriggerProps:te,popupProps:ne}),(0,F.jsx)(bg.Provider,{value:p,children:typeof f==`function`?f({payload:_}):f})}),Sg=P.createContext(void 0);function See(){return P.useContext(Sg)}var Cee=function(e){return e[e.popupOpen=df.popupOpen]=`popupOpen`,e.triggerDisabled=`data-trigger-disabled`,e}({}),wee=Lm(function(e,t){let{className:n,render:r,handle:i,payload:a,disabled:o,delay:s,closeOnClick:c=!0,closeDelay:l,id:u,style:d,...f}=e,p=xg(!0),m=i?.store??p;if(!m)throw Error(Pa(82));let h=Tl(u),g=m.useState(`isTriggerActive`,h),_=m.useState(`isOpenedByTrigger`,h),v=m.useState(`floatingRootContext`),y=P.useRef(null),b=s??600,x=l??0,{registerTrigger:S,isMountedByThisTrigger:C}=Xm(h,y,m,{payload:a,closeOnClick:c,closeDelay:x}),w=See(),{delayRef:T,isInstantPhase:E,hasProvider:ee}=Af(v,{open:_});m.useSyncedValue(`isInstantPhase`,E);let D=m.useState(`disabled`),O=o??D,te=m.useState(`trackCursorAxis`),ne=m.useState(`disableHoverablePopup`),re=fee(v,{enabled:!O,mouseOnly:!0,move:!1,handleClose:!ne&&te!==`both`?Sh():null,restMs(){let e=w?.delay,t=typeof T.current==`object`?T.current.open:void 0,n=b;return ee&&(n=t===0?0:s??e??b),n},delay(){let e=typeof T.current==`object`?T.current.close:void 0,t=x;return l==null&&ee&&(t=e),{close:t}},triggerElementRef:y,isActiveTrigger:g,isClosing:()=>m.select(`transitionStatus`)===`ending`}),k=cee(v,{enabled:!O}).reference,A={open:_},ie=m.useState(`triggerProps`,C);return Qa(`button`,e,{state:A,ref:[t,S,y],props:[re,k,ie,{onPointerDown(){m.set(`closeOnClick`,c)},id:h,[Cee.triggerDisabled]:O?``:void 0},f],stateAttributesMapping:_f})}),Cg=P.createContext(void 0);function Tee(){let e=P.useContext(Cg);if(e===void 0)throw Error(Pa(70));return e}var Eee=P.forwardRef(function(e,t){let{children:n,container:r,className:i,render:a,style:o,...s}=e,{portalNode:c,portalSubtree:l}=sp({container:r,ref:t,componentProps:e,elementProps:s});return!l&&!c?null:(0,F.jsxs)(P.Fragment,{children:[l,c&&gi.createPortal(n,c)]})}),Dee=P.forwardRef(function(e,t){let{keepMounted:n=!1,...r}=e;return xg().useState(`mounted`)||n?(0,F.jsx)(Cg.Provider,{value:n,children:(0,F.jsx)(Eee,{ref:t,...r})}):null}),wg=P.createContext(void 0);function Tg(){let e=P.useContext(wg);if(e===void 0)throw Error(Pa(71));return e}var Oee=P.createContext(void 0);function Eg(){return P.useContext(Oee)?.direction??`ltr`}var kee=e=>({name:`arrow`,options:e,async fn(t){let{x:n,y:r,placement:i,rects:a,platform:o,elements:s,middlewareData:c}=t,{element:l,padding:u=0,offsetParent:d=`real`}=Su(e,t)||{};if(l==null)return{};let f=Bu(u),p={x:n,y:r},m=Ou(i),h=Eu(m),g=await o.getDimensions(l),_=m===`y`,v=_?`top`:`left`,y=_?`bottom`:`right`,b=_?`clientHeight`:`clientWidth`,x=a.reference[h]+a.reference[m]-p[m]-a.floating[h],S=p[m]-a.reference[m],C=d===`real`?await o.getOffsetParent?.(l):s.floating,w=s.floating[b]||a.floating[h];(!w||!await o.isElement?.(C))&&(w=s.floating[b]||a.floating[h]);let T=x/2-S/2,E=w/2-g[h]/2-1,ee=Math.min(f[v],E),D=Math.min(f[y],E),O=ee,te=w-g[h]-D,ne=w/2-g[h]/2+T,re=xu(O,ne,te),k=!c.arrow&&wu(i)!=null&&ne!==re&&a.reference[h]/2-(ne({...kee(e),options:[e,t]}),jee={name:`hide`,async fn(e){let{width:t,height:n,x:r,y:i}=e.rects.reference,a=t===0&&n===0&&r===0&&i===0;return{data:{referenceHidden:(await see().fn(e)).data?.referenceHidden||a}}}},Dg={sideX:`left`,sideY:`top`},Mee={name:`adaptiveOrigin`,async fn(e){let{x:t,y:n,rects:{floating:r},elements:{floating:i},platform:a,strategy:o,placement:s}=e,c=Go(i),l=c.getComputedStyle(i);if(!(l.transitionDuration!==`0s`&&l.transitionDuration!==``))return{x:t,y:n,data:Dg};let u=await a.getOffsetParent?.(i),d={width:0,height:0};if(o===`fixed`&&c?.visualViewport)d={width:c.visualViewport.width,height:c.visualViewport.height};else if(u===c){let e=kl(i);d={width:e.documentElement.clientWidth,height:e.documentElement.clientHeight}}else await a.isElement?.(u)&&(d=await a.getDimensions(u));let f=Cu(s),p=t,m=n;f===`left`&&(p=d.width-(t+r.width)),f===`top`&&(m=d.height-(n+r.height));let h=f===`left`?`right`:Dg.sideX,g=f===`top`?`bottom`:Dg.sideY;return{x:p,y:m,data:{sideX:h,sideY:g}}}};function Og(e,t,n){let r=e===`inline-start`||e===`inline-end`;return{top:`top`,right:r?n?`inline-start`:`inline-end`:`right`,bottom:`bottom`,left:r?n?`inline-end`:`inline-start`:`left`}[t]}function kg(e,t,n){let{rects:r,placement:i}=e;return{side:Og(t,Cu(i),n),align:wu(i)||`center`,anchor:{width:r.reference.width,height:r.reference.height},positioner:{width:r.floating.width,height:r.floating.height}}}function Ag(e){let{anchor:t,positionMethod:n=`absolute`,side:r=`bottom`,sideOffset:i=0,align:a=`center`,alignOffset:o=0,collisionBoundary:s,collisionPadding:c=5,sticky:l=!1,arrowPadding:u=5,disableAnchorTracking:d=!1,keepMounted:f=!1,floatingRootContext:p,mounted:m,collisionAvoidance:h,shiftCrossAxis:g=!1,nodeId:_,adaptiveOrigin:v,lazyFlip:y=!1,externalTree:b}=e,[x,S]=P.useState(null);!m&&x!==null&&S(null);let C=h.side||`flip`,w=h.align||`flip`,T=h.fallbackAxisSide||`end`,E=typeof t==`function`?t:void 0,ee=gs(E),D=E?ee:t,O=Nf(t),te=Nf(m),ne=Eg()===`rtl`,re=x||{top:`top`,right:`right`,bottom:`bottom`,left:`left`,"inline-end":ne?`left`:`right`,"inline-start":ne?`right`:`left`}[r],k=a===`center`?re:`${re}-${a}`,A=c,ie=+(r===`bottom`),j=+(r===`top`),ae=+(r===`right`),oe=+(r===`left`);typeof A==`number`?A={top:A+ie,right:A+oe,bottom:A+j,left:A+ae}:A&&={top:(A.top||0)+ie,right:(A.right||0)+oe,bottom:(A.bottom||0)+j,left:(A.left||0)+ae};let se={boundary:s===`clipping-ancestors`?`clippingAncestors`:s,padding:A},ce=P.useRef(null),M=Nf(i),le=Nf(o),ue=[nee(e=>{let t=kg(e,r,ne),n=typeof M.current==`function`?M.current(t):M.current,i=typeof le.current==`function`?le.current(t):le.current;return{mainAxis:n,crossAxis:i,alignmentAxis:i}},[typeof i==`function`?0:i,typeof o==`function`?0:o,ne,r])],N=w===`none`&&C!==`shift`,de=!N&&(l||g||C===`shift`),fe=C===`none`?null:aee({...se,padding:{top:A.top+1,right:A.right+1,bottom:A.bottom+1,left:A.left+1},mainAxis:!g&&C===`flip`,crossAxis:w===`flip`?`alignment`:!1,fallbackAxisSideDirection:T}),pe=N?null:ree(e=>{let t=kl(e.elements.floating).documentElement;return{...se,rootBoundary:g?{x:0,y:0,width:t.clientWidth,height:t.clientHeight}:void 0,mainAxis:w!==`none`,crossAxis:de,limiter:l||g?void 0:iee(e=>{if(!ce.current)return{};let{width:t,height:n}=ce.current.getBoundingClientRect(),r=Du(Cu(e.placement)),i=r===`y`?t:n,a=r===`y`?A.left+A.right:A.top+A.bottom;return{offset:i/2+a/2}})}},[se,l,g,A,w]);C===`shift`||w===`shift`||a===`center`?ue.push(pe,fe):ue.push(fe,pe),ue.push(oee({...se,apply({elements:{floating:e},availableWidth:t,availableHeight:n,rects:r}){if(!te.current)return;let i=e.style;i.setProperty(`--available-width`,`${t}px`),i.setProperty(`--available-height`,`${n}px`);let a=Go(e).devicePixelRatio||1,{x:o,y:s,width:c,height:l}=r.reference,u=(Math.round((o+c)*a)-Math.round(o*a))/a,d=(Math.round((s+l)*a)-Math.round(s*a))/a;i.setProperty(`--anchor-width`,`${u}px`),i.setProperty(`--anchor-height`,`${d}px`)}}),Aee(()=>({element:ce.current||kl(ce.current).createElement(`div`),padding:u,offsetParent:`floating`}),[u]),{name:`transformOrigin`,fn(e){let{elements:t,middlewareData:n,placement:a,rects:o,y:s}=e,c=Cu(a),l=Du(c),u=ce.current,d=n.arrow?.x||0,f=n.arrow?.y||0,p=u?.clientWidth||0,m=u?.clientHeight||0,h=d+p/2,g=f+m/2,_=Math.abs(n.shift?.y||0),v=o.reference.height/2,y=typeof i==`function`?i(kg(e,r,ne)):i,b=_>y,x={top:`${h}px calc(100% + ${y}px)`,bottom:`${h}px ${-y}px`,left:`calc(100% + ${y}px) ${g}px`,right:`${-y}px ${g}px`}[c],S=`${h}px ${o.reference.y+v-s}px`;return t.floating.style.setProperty(`--transform-origin`,de&&l===`y`&&b?S:x),{}}},jee,v),bs(()=>{!m&&p&&p.update({referenceElement:null,floatingElement:null,domReferenceElement:null,positionReference:null})},[m,p]);let me=P.useMemo(()=>({elementResize:!d&&typeof ResizeObserver<`u`,layoutShift:!d&&typeof IntersectionObserver<`u`}),[d]),{refs:he,elements:ge,x:_e,y:ve,middlewareData:ye,update:be,placement:xe,context:Se,isPositioned:Ce,floatingStyles:we}=ah({rootContext:p,open:f?m:void 0,placement:k,middleware:ue,strategy:n,whileElementsMounted:f?void 0:(...e)=>vm(...e,me),nodeId:_,externalTree:b}),{sideX:Te,sideY:Ee}=ye.adaptiveOrigin||Dg,De=Ce?n:`fixed`,Oe=P.useMemo(()=>{let e=v?{position:De,[Te]:_e,[Ee]:ve}:{position:De,...we};return Ce||(e.opacity=0),e},[v,De,Te,_e,Ee,ve,we,Ce]),ke=P.useRef(null);bs(()=>{if(!m)return;let e=O.current,t=typeof e==`function`?e():e,n=(jg(t)?t.current:t)||null;n!==ke.current&&(he.setPositionReference(n),ke.current=n)},[m,he,D,O]),P.useEffect(()=>{if(!m)return;let e=O.current;typeof e!=`function`&&jg(e)&&e.current!==ke.current&&(he.setPositionReference(e.current),ke.current=e.current)},[m,he,D,O]),P.useEffect(()=>{if(f&&m&&ge.domReference&&ge.floating)return vm(ge.domReference,ge.floating,be,me)},[f,m,ge,be,me]);let Ae=Cu(xe),je=Og(r,Ae,ne),Me=wu(xe)||`center`,Ne=!!ye.hide?.referenceHidden;bs(()=>{y&&m&&Ce&&S(Ae)},[y,m,Ce,Ae]);let F=P.useMemo(()=>({position:`absolute`,top:ye.arrow?.y,left:ye.arrow?.x}),[ye.arrow]),Pe=ye.arrow?.centerOffset!==0;return P.useMemo(()=>({positionerStyles:Oe,arrowStyles:F,arrowRef:ce,arrowUncentered:Pe,side:je,align:Me,physicalSide:Ae,anchorHidden:Ne,refs:he,context:Se,isPositioned:Ce,update:be}),[Oe,F,ce,Pe,je,Me,Ae,Ne,he,Se,Ce,be])}function jg(e){return e!=null&&`current`in e}function Mg(e){return e===`starting`?ep:Ja}function Ng(e,t,{styles:n,transitionStatus:r,props:i,refs:a,hidden:o,inert:s=!1}){let c={...n};return s&&(c.pointerEvents=`none`),Qa(`div`,e,{state:t,ref:a,props:[{role:`presentation`,hidden:o,style:c},Mg(r),i],stateAttributesMapping:yf})}var Nee=P.forwardRef(function(e,t){let{render:n,className:r,anchor:i,positionMethod:a=`absolute`,side:o=`top`,align:s=`center`,sideOffset:c=0,alignOffset:l=0,collisionBoundary:u=`clipping-ancestors`,collisionPadding:d=5,arrowPadding:f=5,sticky:p=!1,disableAnchorTracking:m=!1,collisionAvoidance:h=np,style:g,..._}=e,v=xg(),y=Tee(),b=v.useState(`open`),x=v.useState(`mounted`),S=v.useState(`trackCursorAxis`),C=v.useState(`disableHoverablePopup`),w=v.useState(`floatingRootContext`),T=v.useState(`instantType`),E=v.useState(`transitionStatus`),ee=Ag({anchor:i,positionMethod:a,floatingRootContext:w,mounted:x,side:o,sideOffset:c,align:s,alignOffset:l,collisionBoundary:u,collisionPadding:d,sticky:p,arrowPadding:f,disableAnchorTracking:m,keepMounted:y,collisionAvoidance:h,adaptiveOrigin:v.useState(`hasViewport`)?Mee:void 0}),D=Ng(e,P.useMemo(()=>({open:b,side:ee.side,align:ee.align,anchorHidden:ee.anchorHidden,instant:S===`none`?T:`tracking-cursor`}),[b,ee.side,ee.align,ee.anchorHidden,S,T]),{styles:ee.positionerStyles,transitionStatus:E,props:_,refs:[t,v.useStateSetter(`positionerElement`)],hidden:!x,inert:!b||S===`both`||C});return(0,F.jsx)(wg.Provider,{value:ee,children:D})}),Pee={...yf,...Fd},Fee=P.forwardRef(function(e,t){let{className:n,render:r,style:i,...a}=e,o=xg(),{side:s,align:c}=Tg(),l=o.useState(`open`),u=o.useState(`instantType`),d=o.useState(`transitionStatus`),f=o.useState(`popupProps`),p=o.useState(`floatingRootContext`);Ld({open:l,ref:o.context.popupRef,onComplete(){l&&o.context.onOpenChangeComplete?.(!0)}});let m=o.useState(`disabled`),h=o.useState(`closeDelay`);return uee(p,{enabled:!m,closeDelay:h}),Qa(`div`,e,{state:{open:l,side:s,align:c,instant:u,transitionStatus:d},ref:[t,o.context.popupRef,o.useStateSetter(`popupElement`)],props:[f,Mg(d),a],stateAttributesMapping:Pee})}),Iee=P.forwardRef(function(e,t){let{className:n,render:r,style:i,...a}=e,o=xg(),s=o.useState(`open`),c=o.useState(`instantType`),{arrowRef:l,side:u,align:d,arrowUncentered:f,arrowStyles:p}=Tg();return Qa(`div`,e,{state:{open:s,side:u,align:d,uncentered:f,instant:c},ref:[t,l],props:[{style:p,"aria-hidden":!0},a],stateAttributesMapping:yf})}),Lee=function(e){let{delay:t,closeDelay:n,timeout:r=400}=e,i=P.useMemo(()=>({delay:t,closeDelay:n}),[t,n]),a=P.useMemo(()=>({open:t,close:n}),[t,n]);return(0,F.jsx)(Sg.Provider,{value:i,children:(0,F.jsx)(kf,{delay:a,timeoutMs:r,children:e.children})})};function Ree(e){let t=(0,fa.c)(6),n,r;t[0]===e?(n=t[1],r=t[2]):({delay:r,...n}=e,t[0]=e,t[1]=n,t[2]=r);let i=r===void 0?0:r,a;return t[3]!==i||t[4]!==n?(a=(0,F.jsx)(Lee,{"data-slot":`tooltip-provider`,delay:i,...n}),t[3]=i,t[4]=n,t[5]=a):a=t[5],a}function zee(e){let t=(0,fa.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,F.jsx)(Ree,{children:(0,F.jsx)(xee,{"data-slot":`tooltip`,...n})}),t[2]=n,t[3]=r),r}function Bee(e){let t=(0,fa.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,F.jsx)(wee,{"data-slot":`tooltip-trigger`,...n}),t[2]=n,t[3]=r),r}function Vee(e){let t=(0,fa.c)(21),n,r,i,a,o,s,c;t[0]===e?(n=t[1],r=t[2],i=t[3],a=t[4],o=t[5],s=t[6],c=t[7]):({className:r,side:a,sideOffset:o,align:s,alignOffset:c,children:n,...i}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i,t[4]=a,t[5]=o,t[6]=s,t[7]=c);let l=a===void 0?`top`:a,u=o===void 0?4:o,d=s===void 0?`center`:s,f=c===void 0?0:c,p;t[8]===r?p=t[9]:(p=el(`data-open:fade-in-0 data-open:zoom-in-95 data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-closed:fade-out-0 data-closed:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=delayed-open]:animate-in data-closed:animate-out data-open:animate-in z-50 w-fit max-w-xs origin-(--transform-origin) rounded-md bg-foreground px-3 py-1.5 text-xs text-background **:data-[slot=kbd]:rounded-md`,r),t[8]=r,t[9]=p);let m;t[10]===Symbol.for(`react.memo_cache_sentinel`)?(m=(0,F.jsx)(Iee,{className:`z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5`}),t[10]=m):m=t[10];let h;t[11]!==n||t[12]!==i||t[13]!==p?(h=(0,F.jsxs)(Fee,{className:p,"data-slot":`tooltip-content`,...i,children:[n,m]}),t[11]=n,t[12]=i,t[13]=p,t[14]=h):h=t[14];let g;return t[15]!==d||t[16]!==f||t[17]!==l||t[18]!==u||t[19]!==h?(g=(0,F.jsx)(Dee,{children:(0,F.jsx)(Nee,{align:d,alignOffset:f,className:`isolate z-50`,side:l,sideOffset:u,children:h})}),t[15]=d,t[16]=f,t[17]=l,t[18]=u,t[19]=h,t[20]=g):g=t[20],g}var Pg=window.matchMedia(`(max-width: 767px)`);function Hee(e){return Pg.addEventListener(`change`,e),()=>Pg.removeEventListener(`change`,e)}function Uee(){return Pg.matches}function Wee(){return(0,P.useSyncExternalStore)(Hee,Uee)}var Gee=`sidebar_state`,Kee=3600*24*7,Fg=`12rem`,Ig=`16rem`,Lg=`3rem`,Rg=`b`,zg=P.createContext(null);function Bg(){let e=P.useContext(zg);if(!e)throw Error(`useSidebar must be used within a SidebarProvider.`);return e}function Vg(e){let t=(0,fa.c)(36),n,r,i,a,o,s,c;t[0]===e?(n=t[1],r=t[2],i=t[3],a=t[4],o=t[5],s=t[6],c=t[7]):({defaultOpen:c,open:i,onOpenChange:o,className:r,style:s,children:n,...a}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i,t[4]=a,t[5]=o,t[6]=s,t[7]=c);let l=c===void 0?!0:c,u=Wee(),[d,f]=P.useState(!1),[p,m]=P.useState(l),h=i??p,g;t[8]!==h||t[9]!==o?(g=e=>{let t=typeof e==`function`?e(h):e;o?o(t):m(t),document.cookie=`${Gee}=${t}; path=/; max-age=${Kee}`},t[8]=h,t[9]=o,t[10]=g):g=t[10];let _=g,v;t[11]!==u||t[12]!==_?(v=()=>u?f(Ug):_(Hg),t[11]=u,t[12]=_,t[13]=v):v=t[13];let y=v,b,x;t[14]===y?(b=t[15],x=t[16]):(b=()=>{let e=e=>{e.key===Rg&&(e.metaKey||e.ctrlKey)&&(e.preventDefault(),y())};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},x=[y],t[14]=y,t[15]=b,t[16]=x),P.useEffect(b,x);let S=h?`expanded`:`collapsed`,C;t[17]!==u||t[18]!==h||t[19]!==d||t[20]!==_||t[21]!==S||t[22]!==y?(C={state:S,open:h,setOpen:_,isMobile:u,openMobile:d,setOpenMobile:f,toggleSidebar:y},t[17]=u,t[18]=h,t[19]=d,t[20]=_,t[21]=S,t[22]=y,t[23]=C):C=t[23];let w=C,T;t[24]===r?T=t[25]:(T=el(`group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar`,r),t[24]=r,t[25]=T);let E;t[26]===s?E=t[27]:(E={"--sidebar-width":Fg,"--sidebar-width-icon":Lg,...s},t[26]=s,t[27]=E);let ee=E,D;t[28]!==n||t[29]!==a||t[30]!==T||t[31]!==ee?(D=(0,F.jsx)(`div`,{className:T,"data-slot":`sidebar-wrapper`,style:ee,...a,children:n}),t[28]=n,t[29]=a,t[30]=T,t[31]=ee,t[32]=D):D=t[32];let O;return t[33]!==w||t[34]!==D?(O=(0,F.jsx)(zg.Provider,{value:w,children:D}),t[33]=w,t[34]=D,t[35]=O):O=t[35],O}function Hg(e){return!e}function Ug(e){return!e}function Wg(e){let t=(0,fa.c)(46),n,r,i,a,o,s;t[0]===e?(n=t[1],r=t[2],i=t[3],a=t[4],o=t[5],s=t[6]):({side:a,variant:o,collapsible:s,className:r,children:n,...i}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i,t[4]=a,t[5]=o,t[6]=s);let c=a===void 0?`left`:a,l=o===void 0?`sidebar`:o,u=s===void 0?`offExamples`:s,{isMobile:d,state:f,openMobile:p,setOpenMobile:m}=Bg();if(u===`none`){let e;t[7]===r?e=t[8]:(e=el(`flex h-full w-(--sidebar-width) flex-col bg-sidebar text-sidebar-foreground`,r),t[7]=r,t[8]=e);let a;return t[9]!==n||t[10]!==i||t[11]!==e?(a=(0,F.jsx)(`div`,{className:e,"data-slot":`sidebar`,...i,children:n}),t[9]=n,t[10]=i,t[11]=e,t[12]=a):a=t[12],a}if(d){let e;t[13]===Symbol.for(`react.memo_cache_sentinel`)?(e={"--sidebar-width":Ig},t[13]=e):e=t[13];let r=e,a;t[14]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,F.jsxs)(hee,{className:`sr-only`,children:[(0,F.jsx)(gee,{children:`Sidebar`}),(0,F.jsx)(_ee,{children:`Displays the mobile sidebar.`})]}),t[14]=a):a=t[14];let o;t[15]===n?o=t[16]:(o=(0,F.jsx)(`div`,{className:`flex h-full w-full flex-col`,children:n}),t[15]=n,t[16]=o);let s;t[17]!==c||t[18]!==o?(s=(0,F.jsxs)(yg,{className:`w-(--sidebar-width) bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden`,"data-mobile":`true`,"data-sidebar":`sidebar`,"data-slot":`sidebar`,side:c,style:r,children:[a,o]}),t[17]=c,t[18]=o,t[19]=s):s=t[19];let l;return t[20]!==p||t[21]!==i||t[22]!==m||t[23]!==s?(l=(0,F.jsx)(gg,{onOpenChange:m,open:p,...i,children:s}),t[20]=p,t[21]=i,t[22]=m,t[23]=s,t[24]=l):l=t[24],l}let h=f===`collapsed`?u:``,g=l===`floating`||l===`inset`?`group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]`:`group-data-[collapsible=icon]:w-(--sidebar-width-icon)`,_;t[25]===g?_=t[26]:(_=el(`relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear`,`group-data-[collapsible=offExamples]:w-0`,`group-data-[side=right]:rotate-180`,g),t[25]=g,t[26]=_);let v;t[27]===_?v=t[28]:(v=(0,F.jsx)(`div`,{className:_,"data-slot":`sidebar-gap`}),t[27]=_,t[28]=v);let y=c===`left`?`left-0 group-data-[collapsible=offExamples]:left-[calc(var(--sidebar-width)*-1)]`:`right-0 group-data-[collapsible=offExamples]:right-[calc(var(--sidebar-width)*-1)]`,b=l===`floating`||l===`inset`?`p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]`:`group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l`,x;t[29]!==r||t[30]!==y||t[31]!==b?(x=el(`fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex`,y,b,r),t[29]=r,t[30]=y,t[31]=b,t[32]=x):x=t[32];let S;t[33]===n?S=t[34]:(S=(0,F.jsx)(`div`,{className:`flex size-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:shadow-sm group-data-[variant=floating]:ring-1 group-data-[variant=floating]:ring-sidebar-border`,"data-sidebar":`sidebar`,"data-slot":`sidebar-inner`,children:n}),t[33]=n,t[34]=S);let C;t[35]!==i||t[36]!==x||t[37]!==S?(C=(0,F.jsx)(`div`,{className:x,"data-slot":`sidebar-container`,...i,children:S}),t[35]=i,t[36]=x,t[37]=S,t[38]=C):C=t[38];let w;return t[39]!==c||t[40]!==f||t[41]!==C||t[42]!==h||t[43]!==v||t[44]!==l?(w=(0,F.jsxs)(`div`,{className:`group peer hidden text-sidebar-foreground md:block`,"data-collapsible":h,"data-side":c,"data-slot":`sidebar`,"data-state":f,"data-variant":l,children:[v,C]}),t[39]=c,t[40]=f,t[41]=C,t[42]=h,t[43]=v,t[44]=l,t[45]=w):w=t[45],w}function Gg(e){let t=(0,fa.c)(15),n,r,i;t[0]===e?(n=t[1],r=t[2],i=t[3]):({className:n,onClick:r,...i}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i);let{toggleSidebar:a}=Bg(),o;t[4]===n?o=t[5]:(o=el(n),t[4]=n,t[5]=o);let s;t[6]!==r||t[7]!==a?(s=e=>{r?.(e),a()},t[6]=r,t[7]=a,t[8]=s):s=t[8];let c,l;t[9]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,F.jsx)(Fo,{}),l=(0,F.jsx)(`span`,{className:`sr-only`,children:`Toggle Sidebar`}),t[9]=c,t[10]=l):(c=t[9],l=t[10]);let u;return t[11]!==i||t[12]!==o||t[13]!==s?(u=(0,F.jsxs)(pl,{className:o,"data-sidebar":`trigger`,"data-slot":`sidebar-trigger`,onClick:s,size:`icon-lg`,variant:`ghost`,...i,children:[c,l]}),t[11]=i,t[12]=o,t[13]=s,t[14]=u):u=t[14],u}function Kg(e){let t=(0,fa.c)(9),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let{toggleSidebar:i}=Bg(),a;t[3]===n?a=t[4]:(a=el(`absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border sm:flex`,`in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize`,`[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize`,`group-data-[collapsible=offExamples]:translate-x-0 group-data-[collapsible=offExamples]:after:left-full hover:group-data-[collapsible=offExamples]:bg-sidebar`,`[[data-side=left][data-collapsible=offExamples]_&]:-right-2`,`[[data-side=right][data-collapsible=offExamples]_&]:-left-2`,n),t[3]=n,t[4]=a);let o;return t[5]!==r||t[6]!==a||t[7]!==i?(o=(0,F.jsx)(`button`,{"aria-label":`Toggle Sidebar`,className:a,"data-sidebar":`rail`,"data-slot":`sidebar-rail`,onClick:i,tabIndex:-1,title:`Toggle Sidebar`,...r}),t[5]=r,t[6]=a,t[7]=i,t[8]=o):o=t[8],o}function qg(e){let t=(0,fa.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=el(`flex flex-col gap-2 p-2`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(`div`,{className:i,"data-sidebar":`header`,"data-slot":`sidebar-header`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Jg(e){let t=(0,fa.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=el(`flex flex-col gap-2 p-2`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(`div`,{className:i,"data-sidebar":`footer`,"data-slot":`sidebar-footer`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Yg(e){let t=(0,fa.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=el(`mx-2 w-auto bg-sidebar-border`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(sf,{className:i,"data-sidebar":`separator`,"data-slot":`sidebar-separator`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Xg(e){let t=(0,fa.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=el(`no-scrollbar flex min-h-0 flex-1 flex-col gap-0 overflow-auto group-data-[collapsible=icon]:overflow-hidden`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(`div`,{className:i,"data-sidebar":`content`,"data-slot":`sidebar-content`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Zg(e){let t=(0,fa.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=el(`relative flex w-full min-w-0 flex-col px-2 py-1`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(`div`,{className:i,"data-sidebar":`group`,"data-slot":`sidebar-group`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Qg(e){let t=(0,fa.c)(10),n,r,i,a;if(t[0]!==e){let{className:o,render:s,...c}=e;n=s,a=io,r=`div`,i=ya({className:el(`flex h-8 shrink-0 items-center rounded-md px-2 text-xs text-sidebar-foreground/70 ring-sidebar-ring outline-hidden transition-[margin,opacity] duration-200 ease-linear group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0 focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0`,o)},c),t[0]=e,t[1]=n,t[2]=r,t[3]=i,t[4]=a}else n=t[1],r=t[2],i=t[3],a=t[4];let o;t[5]===Symbol.for(`react.memo_cache_sentinel`)?(o={slot:`sidebar-group-label`,sidebar:`group-label`},t[5]=o):o=t[5];let s;return t[6]!==n||t[7]!==r||t[8]!==i?(s={defaultTagName:r,props:i,render:n,state:o},t[6]=n,t[7]=r,t[8]=i,t[9]=s):s=t[9],a(s)}function $g(e){let t=(0,fa.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=el(`flex w-full min-w-0 flex-col gap-px`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(`ul`,{className:i,"data-sidebar":`menu`,"data-slot":`sidebar-menu`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function e_(e){let t=(0,fa.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=el(`group/menu-item relative`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(`li`,{className:i,"data-sidebar":`menu-item`,"data-slot":`sidebar-menu-item`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}var t_=lo(`peer/menu-button group/menu-button flex w-full items-center gap-2 overflow-hidden rounded-[calc(var(--radius-sm)+2px)] p-2 text-left text-xs ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-active:bg-sidebar-accent data-active:font-medium data-active:text-sidebar-accent-foreground data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate`,{variants:{variant:{default:`hover:bg-sidebar-accent hover:text-sidebar-accent-foreground`,outline:`bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]`},size:{default:`h-8 text-xs`,sm:`h-7 text-xs`,lg:`h-12 text-xs group-data-[collapsible=icon]:p-0!`}},defaultVariants:{variant:`default`,size:`default`}});function n_(e){let t=(0,fa.c)(15),{render:n,isActive:r,variant:i,size:a,tooltip:o,className:s,...c}=e,l=r===void 0?!1:r,u=i===void 0?`default`:i,d=a===void 0?`default`:a,{isMobile:f,state:p}=Bg(),m=ya({className:el(t_({variant:u,size:d}),s)},c),h=o?Bee:n,g;t[0]!==l||t[1]!==d?(g={slot:`sidebar-menu-button`,sidebar:`menu-button`,size:d,active:l},t[0]=l,t[1]=d,t[2]=g):g=t[2];let _;t[3]!==m||t[4]!==h||t[5]!==g?(_={defaultTagName:`button`,props:m,render:h,state:g},t[3]=m,t[4]=h,t[5]=g,t[6]=_):_=t[6];let v=io(_);if(!o)return v;let y;t[7]===o?y=t[8]:(y=typeof o==`string`?{children:o}:o,t[7]=o,t[8]=y);let b=y,x=p!==`collapsed`||f,S;t[9]!==x||t[10]!==b?(S=(0,F.jsx)(Vee,{align:`center`,hidden:x,side:`right`,...b}),t[9]=x,t[10]=b,t[11]=S):S=t[11];let C;return t[12]!==v||t[13]!==S?(C=(0,F.jsxs)(zee,{children:[v,S]}),t[12]=v,t[13]=S,t[14]=C):C=t[14],C}var r_;function B(e,t,n){function r(n,r){if(n._zod||Object.defineProperty(n,`_zod`,{value:{def:r,constr:o,traits:new Set},enumerable:!1}),n._zod.traits.has(e))return;n._zod.traits.add(e),t(n,r);let i=o.prototype,a=Object.keys(i);for(let e=0;en?.Parent&&t instanceof n.Parent?!0:t?._zod?.traits?.has(e)}),Object.defineProperty(o,`name`,{value:e}),o}var i_=class extends Error{constructor(){super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`)}},a_=class extends Error{constructor(e){super(`Encountered unidirectional transform during encode: ${e}`),this.name=`ZodEncodeError`}};(r_=globalThis).__zod_globalConfig??(r_.__zod_globalConfig={});var o_=globalThis.__zod_globalConfig;function s_(e){return e&&Object.assign(o_,e),o_}function c_(e){let t=Object.values(e).filter(e=>typeof e==`number`);return Object.entries(e).filter(([e,n])=>t.indexOf(+e)===-1).map(([e,t])=>t)}function l_(e,t){return typeof t==`bigint`?t.toString():t}function u_(e){return{get value(){{let t=e();return Object.defineProperty(this,`value`,{value:t}),t}throw Error(`cached value already set`)}}}function d_(e){return e==null}function f_(e){let t=+!!e.startsWith(`^`),n=e.endsWith(`$`)?e.length-1:e.length;return e.slice(t,n)}function p_(e,t){let n=e/t,r=Math.round(n),i=2**-52*Math.max(Math.abs(n),1);return Math.abs(n-r){};function x_(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}var S_=u_(()=>{if(o_.jitless||typeof navigator<`u`&&navigator?.userAgent?.includes(`Cloudflare`))return!1;try{return Function(``),!0}catch{return!1}});function C_(e){if(x_(e)===!1)return!1;let t=e.constructor;if(t===void 0||typeof t!=`function`)return!0;let n=t.prototype;return!(x_(n)===!1||Object.prototype.hasOwnProperty.call(n,`isPrototypeOf`)===!1)}function w_(e){return C_(e)?{...e}:Array.isArray(e)?[...e]:e instanceof Map?new Map(e):e instanceof Set?new Set(e):e}var T_=new Set([`string`,`number`,`symbol`]);function E_(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function D_(e,t,n){let r=new e._zod.constr(t??e._zod.def);return(!t||n?.parent)&&(r._zod.parent=e),r}function V(e){let t=e;if(!t)return{};if(typeof t==`string`)return{error:()=>t};if(t?.message!==void 0){if(t?.error!==void 0)throw Error("Cannot specify both `message` and `error` params");t.error=t.message}return delete t.message,typeof t.error==`string`?{...t,error:()=>t.error}:t}function O_(e){return Object.keys(e).filter(t=>e[t]._zod.optin===`optional`&&e[t]._zod.optout===`optional`)}var k_={safeint:[-(2**53-1),2**53-1],int32:[-2147483648,2147483647],uint32:[0,4294967295],float32:[-34028234663852886e22,34028234663852886e22],float64:[-Number.MAX_VALUE,Number.MAX_VALUE]};function A_(e,t){let n=e._zod.def,r=n.checks;if(r&&r.length>0)throw Error(`.pick() cannot be used on object schemas containing refinements`);return D_(e,__(e._zod.def,{get shape(){let e={};for(let r in t){if(!(r in n.shape))throw Error(`Unrecognized key: "${r}"`);t[r]&&(e[r]=n.shape[r])}return g_(this,`shape`,e),e},checks:[]}))}function j_(e,t){let n=e._zod.def,r=n.checks;if(r&&r.length>0)throw Error(`.omit() cannot be used on object schemas containing refinements`);return D_(e,__(e._zod.def,{get shape(){let r={...e._zod.def.shape};for(let e in t){if(!(e in n.shape))throw Error(`Unrecognized key: "${e}"`);t[e]&&delete r[e]}return g_(this,`shape`,r),r},checks:[]}))}function M_(e,t){if(!C_(t))throw Error(`Invalid input to extend: expected a plain object`);let n=e._zod.def.checks;if(n&&n.length>0){let n=e._zod.def.shape;for(let e in t)if(Object.getOwnPropertyDescriptor(n,e)!==void 0)throw Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead.")}return D_(e,__(e._zod.def,{get shape(){let n={...e._zod.def.shape,...t};return g_(this,`shape`,n),n}}))}function N_(e,t){if(!C_(t))throw Error(`Invalid input to safeExtend: expected a plain object`);return D_(e,__(e._zod.def,{get shape(){let n={...e._zod.def.shape,...t};return g_(this,`shape`,n),n}}))}function P_(e,t){if(e._zod.def.checks?.length)throw Error(`.merge() cannot be used on object schemas containing refinements. Use .safeExtend() instead.`);return D_(e,__(e._zod.def,{get shape(){let n={...e._zod.def.shape,...t._zod.def.shape};return g_(this,`shape`,n),n},get catchall(){return t._zod.def.catchall},checks:t._zod.def.checks??[]}))}function F_(e,t,n){let r=t._zod.def.checks;if(r&&r.length>0)throw Error(`.partial() cannot be used on object schemas containing refinements`);return D_(t,__(t._zod.def,{get shape(){let r=t._zod.def.shape,i={...r};if(n)for(let t in n){if(!(t in r))throw Error(`Unrecognized key: "${t}"`);n[t]&&(i[t]=e?new e({type:`optional`,innerType:r[t]}):r[t])}else for(let t in r)i[t]=e?new e({type:`optional`,innerType:r[t]}):r[t];return g_(this,`shape`,i),i},checks:[]}))}function I_(e,t,n){return D_(t,__(t._zod.def,{get shape(){let r=t._zod.def.shape,i={...r};if(n)for(let t in n){if(!(t in i))throw Error(`Unrecognized key: "${t}"`);n[t]&&(i[t]=new e({type:`nonoptional`,innerType:r[t]}))}else for(let t in r)i[t]=new e({type:`nonoptional`,innerType:r[t]});return g_(this,`shape`,i),i}}))}function L_(e,t=0){if(e.aborted===!0)return!0;for(let n=t;n{var n;return(n=t).path??(n.path=[]),t.path.unshift(e),t})}function B_(e){return typeof e==`string`?e:e?.message}function V_(e,t,n){let r=e.message?e.message:B_(e.inst?._zod.def?.error?.(e))??B_(t?.error?.(e))??B_(n.customError?.(e))??B_(n.localeError?.(e))??`Invalid input`,{inst:i,continue:a,input:o,...s}=e;return s.path??=[],s.message=r,t?.reportInput&&(s.input=o),s}function H_(e){return Array.isArray(e)?`array`:typeof e==`string`?`string`:`unknown`}function U_(...e){let[t,n,r]=e;return typeof t==`string`?{message:t,code:`custom`,input:n,inst:r}:{...t}}var W_=(e,t)=>{e.name=`$ZodError`,Object.defineProperty(e,`_zod`,{value:e._zod,enumerable:!1}),Object.defineProperty(e,`issues`,{value:t,enumerable:!1}),e.message=JSON.stringify(t,l_,2),Object.defineProperty(e,`toString`,{value:()=>e.message,enumerable:!1})},G_=B(`$ZodError`,W_),K_=B(`$ZodError`,W_,{Parent:Error});function q_(e,t=e=>e.message){let n={},r=[];for(let i of e.issues)i.path.length>0?(n[i.path[0]]=n[i.path[0]]||[],n[i.path[0]].push(t(i))):r.push(t(i));return{formErrors:r,fieldErrors:n}}function J_(e,t=e=>e.message){let n={_errors:[]},r=(e,i=[])=>{for(let a of e.issues)if(a.code===`invalid_union`&&a.errors.length)a.errors.map(e=>r({issues:e},[...i,...a.path]));else if(a.code===`invalid_key`)r({issues:a.issues},[...i,...a.path]);else if(a.code===`invalid_element`)r({issues:a.issues},[...i,...a.path]);else{let e=[...i,...a.path];if(e.length===0)n._errors.push(t(a));else{let r=n,i=0;for(;i(t,n,r,i)=>{let a=r?{...r,async:!1}:{async:!1},o=t._zod.run({value:n,issues:[]},a);if(o instanceof Promise)throw new i_;if(o.issues.length){let t=new(i?.Err??e)(o.issues.map(e=>V_(e,a,s_())));throw b_(t,i?.callee),t}return o.value},X_=Y_(K_),Z_=e=>async(t,n,r,i)=>{let a=r?{...r,async:!0}:{async:!0},o=t._zod.run({value:n,issues:[]},a);if(o instanceof Promise&&(o=await o),o.issues.length){let t=new(i?.Err??e)(o.issues.map(e=>V_(e,a,s_())));throw b_(t,i?.callee),t}return o.value},Q_=Z_(K_),$_=e=>(t,n,r)=>{let i=r?{...r,async:!1}:{async:!1},a=t._zod.run({value:n,issues:[]},i);if(a instanceof Promise)throw new i_;return a.issues.length?{success:!1,error:new(e??G_)(a.issues.map(e=>V_(e,i,s_())))}:{success:!0,data:a.value}},ev=$_(K_),tv=e=>async(t,n,r)=>{let i=r?{...r,async:!0}:{async:!0},a=t._zod.run({value:n,issues:[]},i);return a instanceof Promise&&(a=await a),a.issues.length?{success:!1,error:new e(a.issues.map(e=>V_(e,i,s_())))}:{success:!0,data:a.value}},nv=tv(K_),rv=e=>(t,n,r)=>{let i=r?{...r,direction:`backward`}:{direction:`backward`};return Y_(e)(t,n,i)},iv=e=>(t,n,r)=>Y_(e)(t,n,r),av=e=>async(t,n,r)=>{let i=r?{...r,direction:`backward`}:{direction:`backward`};return Z_(e)(t,n,i)},ov=e=>async(t,n,r)=>Z_(e)(t,n,r),sv=e=>(t,n,r)=>{let i=r?{...r,direction:`backward`}:{direction:`backward`};return $_(e)(t,n,i)},cv=e=>(t,n,r)=>$_(e)(t,n,r),lv=e=>async(t,n,r)=>{let i=r?{...r,direction:`backward`}:{direction:`backward`};return tv(e)(t,n,i)},uv=e=>async(t,n,r)=>tv(e)(t,n,r),dv=/^[cC][0-9a-z]{6,}$/,fv=/^[0-9a-z]+$/,pv=/^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/,mv=/^[0-9a-vA-V]{20}$/,hv=/^[A-Za-z0-9]{27}$/,gv=/^[a-zA-Z0-9_-]{21}$/,_v=/^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/,vv=/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/,yv=e=>e?RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${e}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`):/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/,bv=/^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/,xv=`^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`;function Sv(){return new RegExp(xv,`u`)}var Cv=/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,wv=/^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/,Tv=/^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/,Ev=/^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/,Dv=/^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/,Ov=/^[A-Za-z0-9_-]*$/,kv=/^https?$/,Av=/^\+[1-9]\d{6,14}$/,jv=`(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`,Mv=RegExp(`^${jv}$`);function Nv(e){let t=`(?:[01]\\d|2[0-3]):[0-5]\\d`;return typeof e.precision==`number`?e.precision===-1?`${t}`:e.precision===0?`${t}:[0-5]\\d`:`${t}:[0-5]\\d\\.\\d{${e.precision}}`:`${t}(?::[0-5]\\d(?:\\.\\d+)?)?`}function Pv(e){return RegExp(`^${Nv(e)}$`)}function Fv(e){let t=Nv({precision:e.precision}),n=[`Z`];e.local&&n.push(``),e.offset&&n.push(`([+-](?:[01]\\d|2[0-3]):[0-5]\\d)`);let r=`${t}(?:${n.join(`|`)})`;return RegExp(`^${jv}T(?:${r})$`)}var Iv=e=>{let t=e?`[\\s\\S]{${e?.minimum??0},${e?.maximum??``}}`:`[\\s\\S]*`;return RegExp(`^${t}$`)},Lv=/^-?\d+$/,Rv=/^-?\d+(?:\.\d+)?$/,zv=/^(?:true|false)$/i,Bv=/^[^A-Z]*$/,Vv=/^[^a-z]*$/,Hv=B(`$ZodCheck`,(e,t)=>{var n;e._zod??={},e._zod.def=t,(n=e._zod).onattach??(n.onattach=[])}),Uv={number:`number`,bigint:`bigint`,object:`date`},Wv=B(`$ZodCheckLessThan`,(e,t)=>{Hv.init(e,t);let n=Uv[typeof t.value];e._zod.onattach.push(e=>{let n=e._zod.bag,r=(t.inclusive?n.maximum:n.exclusiveMaximum)??1/0;t.value{(t.inclusive?r.value<=t.value:r.value{Hv.init(e,t);let n=Uv[typeof t.value];e._zod.onattach.push(e=>{let n=e._zod.bag,r=(t.inclusive?n.minimum:n.exclusiveMinimum)??-1/0;t.value>r&&(t.inclusive?n.minimum=t.value:n.exclusiveMinimum=t.value)}),e._zod.check=r=>{(t.inclusive?r.value>=t.value:r.value>t.value)||r.issues.push({origin:n,code:`too_small`,minimum:typeof t.value==`object`?t.value.getTime():t.value,input:r.value,inclusive:t.inclusive,inst:e,continue:!t.abort})}}),Kv=B(`$ZodCheckMultipleOf`,(e,t)=>{Hv.init(e,t),e._zod.onattach.push(e=>{var n;(n=e._zod.bag).multipleOf??(n.multipleOf=t.value)}),e._zod.check=n=>{if(typeof n.value!=typeof t.value)throw Error(`Cannot mix number and bigint in multiple_of check.`);(typeof n.value==`bigint`?n.value%t.value===BigInt(0):p_(n.value,t.value)===0)||n.issues.push({origin:typeof n.value,code:`not_multiple_of`,divisor:t.value,input:n.value,inst:e,continue:!t.abort})}}),qv=B(`$ZodCheckNumberFormat`,(e,t)=>{Hv.init(e,t),t.format=t.format||`float64`;let n=t.format?.includes(`int`),r=n?`int`:`number`,[i,a]=k_[t.format];e._zod.onattach.push(e=>{let r=e._zod.bag;r.format=t.format,r.minimum=i,r.maximum=a,n&&(r.pattern=Lv)}),e._zod.check=o=>{let s=o.value;if(n){if(!Number.isInteger(s)){o.issues.push({expected:r,format:t.format,code:`invalid_type`,continue:!1,input:s,inst:e});return}if(!Number.isSafeInteger(s)){s>0?o.issues.push({input:s,code:`too_big`,maximum:2**53-1,note:`Integers must be within the safe integer range.`,inst:e,origin:r,inclusive:!0,continue:!t.abort}):o.issues.push({input:s,code:`too_small`,minimum:-(2**53-1),note:`Integers must be within the safe integer range.`,inst:e,origin:r,inclusive:!0,continue:!t.abort});return}}sa&&o.issues.push({origin:`number`,input:s,code:`too_big`,maximum:a,inclusive:!0,inst:e,continue:!t.abort})}}),Jv=B(`$ZodCheckMaxLength`,(e,t)=>{var n;Hv.init(e,t),(n=e._zod.def).when??(n.when=e=>{let t=e.value;return!d_(t)&&t.length!==void 0}),e._zod.onattach.push(e=>{let n=e._zod.bag.maximum??1/0;t.maximum{let r=n.value;if(r.length<=t.maximum)return;let i=H_(r);n.issues.push({origin:i,code:`too_big`,maximum:t.maximum,inclusive:!0,input:r,inst:e,continue:!t.abort})}}),Yv=B(`$ZodCheckMinLength`,(e,t)=>{var n;Hv.init(e,t),(n=e._zod.def).when??(n.when=e=>{let t=e.value;return!d_(t)&&t.length!==void 0}),e._zod.onattach.push(e=>{let n=e._zod.bag.minimum??-1/0;t.minimum>n&&(e._zod.bag.minimum=t.minimum)}),e._zod.check=n=>{let r=n.value;if(r.length>=t.minimum)return;let i=H_(r);n.issues.push({origin:i,code:`too_small`,minimum:t.minimum,inclusive:!0,input:r,inst:e,continue:!t.abort})}}),Xv=B(`$ZodCheckLengthEquals`,(e,t)=>{var n;Hv.init(e,t),(n=e._zod.def).when??(n.when=e=>{let t=e.value;return!d_(t)&&t.length!==void 0}),e._zod.onattach.push(e=>{let n=e._zod.bag;n.minimum=t.length,n.maximum=t.length,n.length=t.length}),e._zod.check=n=>{let r=n.value,i=r.length;if(i===t.length)return;let a=H_(r),o=i>t.length;n.issues.push({origin:a,...o?{code:`too_big`,maximum:t.length}:{code:`too_small`,minimum:t.length},inclusive:!0,exact:!0,input:n.value,inst:e,continue:!t.abort})}}),Zv=B(`$ZodCheckStringFormat`,(e,t)=>{var n,r;Hv.init(e,t),e._zod.onattach.push(e=>{let n=e._zod.bag;n.format=t.format,t.pattern&&(n.patterns??=new Set,n.patterns.add(t.pattern))}),t.pattern?(n=e._zod).check??(n.check=n=>{t.pattern.lastIndex=0,!t.pattern.test(n.value)&&n.issues.push({origin:`string`,code:`invalid_format`,format:t.format,input:n.value,...t.pattern?{pattern:t.pattern.toString()}:{},inst:e,continue:!t.abort})}):(r=e._zod).check??(r.check=()=>{})}),Qv=B(`$ZodCheckRegex`,(e,t)=>{Zv.init(e,t),e._zod.check=n=>{t.pattern.lastIndex=0,!t.pattern.test(n.value)&&n.issues.push({origin:`string`,code:`invalid_format`,format:`regex`,input:n.value,pattern:t.pattern.toString(),inst:e,continue:!t.abort})}}),$v=B(`$ZodCheckLowerCase`,(e,t)=>{t.pattern??=Bv,Zv.init(e,t)}),ey=B(`$ZodCheckUpperCase`,(e,t)=>{t.pattern??=Vv,Zv.init(e,t)}),ty=B(`$ZodCheckIncludes`,(e,t)=>{Hv.init(e,t);let n=E_(t.includes),r=new RegExp(typeof t.position==`number`?`^.{${t.position}}${n}`:n);t.pattern=r,e._zod.onattach.push(e=>{let t=e._zod.bag;t.patterns??=new Set,t.patterns.add(r)}),e._zod.check=n=>{n.value.includes(t.includes,t.position)||n.issues.push({origin:`string`,code:`invalid_format`,format:`includes`,includes:t.includes,input:n.value,inst:e,continue:!t.abort})}}),ny=B(`$ZodCheckStartsWith`,(e,t)=>{Hv.init(e,t);let n=RegExp(`^${E_(t.prefix)}.*`);t.pattern??=n,e._zod.onattach.push(e=>{let t=e._zod.bag;t.patterns??=new Set,t.patterns.add(n)}),e._zod.check=n=>{n.value.startsWith(t.prefix)||n.issues.push({origin:`string`,code:`invalid_format`,format:`starts_with`,prefix:t.prefix,input:n.value,inst:e,continue:!t.abort})}}),ry=B(`$ZodCheckEndsWith`,(e,t)=>{Hv.init(e,t);let n=RegExp(`.*${E_(t.suffix)}$`);t.pattern??=n,e._zod.onattach.push(e=>{let t=e._zod.bag;t.patterns??=new Set,t.patterns.add(n)}),e._zod.check=n=>{n.value.endsWith(t.suffix)||n.issues.push({origin:`string`,code:`invalid_format`,format:`ends_with`,suffix:t.suffix,input:n.value,inst:e,continue:!t.abort})}}),iy=B(`$ZodCheckOverwrite`,(e,t)=>{Hv.init(e,t),e._zod.check=e=>{e.value=t.tx(e.value)}}),ay=class{constructor(e=[]){this.content=[],this.indent=0,this&&(this.args=e)}indented(e){this.indent+=1,e(this),--this.indent}write(e){if(typeof e==`function`){e(this,{execution:`sync`}),e(this,{execution:`async`});return}let t=e.split(` +`+e.stack}}var Se=Object.prototype.hasOwnProperty,Ce=t.unstable_scheduleCallback,we=t.unstable_cancelCallback,Te=t.unstable_shouldYield,Ee=t.unstable_requestPaint,De=t.unstable_now,Oe=t.unstable_getCurrentPriorityLevel,ke=t.unstable_ImmediatePriority,Ae=t.unstable_UserBlockingPriority,Me=t.unstable_NormalPriority,Ne=t.unstable_LowPriority,P=t.unstable_IdlePriority,F=t.log,Pe=t.unstable_setDisableYieldValue,Fe=null,Ie=null;function Le(e){if(typeof F==`function`&&Pe(e),Ie&&typeof Ie.setStrictMode==`function`)try{Ie.setStrictMode(Fe,e)}catch{}}var Re=Math.clz32?Math.clz32:Ve,ze=Math.log,Be=Math.LN2;function Ve(e){return e>>>=0,e===0?32:31-(ze(e)/Be|0)|0}var He=256,Ue=262144,We=4194304;function Ge(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Ke(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=Ge(n))):i=Ge(o):i=Ge(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=Ge(n))):i=Ge(o)):i=Ge(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function qe(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Je(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Ye(){var e=We;return We<<=1,!(We&62914560)&&(We=4194304),e}function Xe(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function Ze(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Qe(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0`u`||window.document===void 0||window.document.createElement===void 0),dn=!1;if(un)try{var fn={};Object.defineProperty(fn,`passive`,{get:function(){dn=!0}}),window.addEventListener(`test`,fn,fn),window.removeEventListener(`test`,fn,fn)}catch{dn=!1}var pn=null,mn=null,hn=null;function gn(){if(hn)return hn;var e,t=mn,n=t.length,r,i=`value`in pn?pn.value:pn.textContent,a=i.length;for(e=0;e=Jn),Zn=` `,Qn=!1;function $n(e,t){switch(e){case`keyup`:return Kn.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function er(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var tr=!1;function nr(e,t){switch(e){case`compositionend`:return er(t);case`keypress`:return t.which===32?(Qn=!0,Zn):null;case`textInput`:return e=t.data,e===Zn&&Qn?null:e;default:return null}}function rr(e,t){if(tr)return e===`compositionend`||!qn&&$n(e,t)?(e=gn(),hn=mn=pn=null,tr=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=Tr(n)}}function Dr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Dr(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Or(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Lt(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=Lt(e.document)}return t}function kr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}var Ar=un&&`documentMode`in document&&11>=document.documentMode,jr=null,Mr=null,Nr=null,Pr=!1;function Fr(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Pr||jr==null||jr!==Lt(r)||(r=jr,`selectionStart`in r&&kr(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Nr&&wr(Nr,r)||(Nr=r,r=Rd(Mr,`onSelect`),0>=o,i-=o,Oi=1<<32-Re(t)+i|n<m?(h=d,d=null):h=d.sibling;var g=p(i,d,s[m],c);if(g===null){d===null&&(d=h);break}e&&d&&g.alternate===null&&t(i,d),a=o(g,a,m),u===null?l=g:u.sibling=g,u=g,d=h}if(m===s.length)return n(i,d),L&&Ai(i,m),l;if(d===null){for(;mh?(g=m,m=null):g=m.sibling;var y=p(a,m,v.value,l);if(y===null){m===null&&(m=g);break}e&&m&&y.alternate===null&&t(a,m),s=o(y,s,h),d===null?u=y:d.sibling=y,d=y,m=g}if(v.done)return n(a,m),L&&Ai(a,h),u;if(m===null){for(;!v.done;h++,v=c.next())v=f(a,v.value,l),v!==null&&(s=o(v,s,h),d===null?u=v:d.sibling=v,d=v);return L&&Ai(a,h),u}for(m=r(m);!v.done;h++,v=c.next())v=_(m,a,h,v.value,l),v!==null&&(e&&v.alternate!==null&&m.delete(v.key===null?h:v.key),s=o(v,s,h),d===null?u=v:d.sibling=v,d=v);return e&&m.forEach(function(e){return t(a,e)}),L&&Ai(a,h),u}function x(e,r,o,c){if(typeof o==`object`&&o&&o.type===g&&o.key===null&&(o=o.props.children),typeof o==`object`&&o){switch(o.$$typeof){case m:a:{for(var l=o.key;r!==null;){if(r.key===l){if(l=o.type,l===g){if(r.tag===7){n(e,r.sibling),c=a(r,o.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===T&&ka(l)===r.type){n(e,r.sibling),c=a(r,o.props),Ia(c,o),c.return=e,e=c;break a}n(e,r);break}else t(e,r);r=r.sibling}o.type===g?(c=mi(o.props.children,e.mode,c,o.key),c.return=e,e=c):(c=pi(o.type,o.key,o.props,null,e.mode,c),Ia(c,o),c.return=e,e=c)}return s(e);case h:a:{for(l=o.key;r!==null;){if(r.key===l)if(r.tag===4&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),c=a(r,o.children||[]),c.return=e,e=c;break a}else{n(e,r);break}else t(e,r);r=r.sibling}c=vi(o,e.mode,c),c.return=e,e=c}return s(e);case T:return o=ka(o),x(e,r,o,c)}if(re(o))return v(e,r,o,c);if(O(o)){if(l=O(o),typeof l!=`function`)throw Error(i(150));return o=l.call(o),y(e,r,o,c)}if(typeof o.then==`function`)return x(e,r,Fa(o),c);if(o.$$typeof===b)return x(e,r,ra(e,o),c);La(e,o)}return typeof o==`string`&&o!==``||typeof o==`number`||typeof o==`bigint`?(o=``+o,r!==null&&r.tag===6?(n(e,r.sibling),c=a(r,o),c.return=e,e=c):(n(e,r),c=gi(o,e.mode,c),c.return=e,e=c),s(e)):n(e,r)}return function(e,t,n,r){try{Pa=0;var i=x(e,t,n,r);return Na=null,i}catch(t){if(t===Ca||t===Ta)throw t;var a=li(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var za=Ra(!0),Ba=Ra(!1),Va=!1;function Ha(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Ua(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Wa(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Ga(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,Wl&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=oi(e),ai(e,null,n),t}return ni(e,r,t,n),oi(e)}function Ka(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,et(e,n)}}function qa(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var Ja=!1;function Ya(){if(Ja){var e=ma;if(e!==null)throw e}}function Xa(e,t,n,r){Ja=!1;var i=e.updateQueue;Va=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var p=s.lane&-536870913,m=p!==s.lane;if(m?(ql&p)===p:(r&p)===p){p!==0&&p===pa&&(Ja=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var h=e,g=s;p=t;var _=n;switch(g.tag){case 1:if(h=g.payload,typeof h==`function`){d=h.call(_,d,p);break a}d=h;break a;case 3:h.flags=h.flags&-65537|128;case 0:if(h=g.payload,p=typeof h==`function`?h.call(_,d,p):h,p==null)break a;d=f({},d,p);break a;case 2:Va=!0}}p=s.callback,p!==null&&(e.flags|=64,m&&(e.flags|=8192),m=i.callbacks,m===null?i.callbacks=[p]:m.push(p))}else m={lane:p,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=m,c=d):u=u.next=m,o|=p;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;m=s,s=m.next,m.next=null,i.lastBaseUpdate=m,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),tu|=o,e.lanes=o,e.memoizedState=d}}function Za(e,t){if(typeof e!=`function`)throw Error(i(191,e));e.call(t)}function Qa(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;ea?a:8;var o=k.T,s={};k.T=s,zs(e,!1,t,n);try{var c=i(),l=k.S;l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`?Rs(e,t,_a(c,r),Cu(e)):Rs(e,t,r,Cu(e))}catch(n){Rs(e,t,{then:function(){},status:`rejected`,reason:n},Cu())}finally{A.p=a,o!==null&&s.types!==null&&(o.types=s.types),k.T=o}}function Os(){}function ks(e,t,n,r){if(e.tag!==5)throw Error(i(476));var a=As(e).queue;Ds(e,a,t,ie,n===null?Os:function(){return js(e),n(r)})}function As(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:ie,baseState:ie,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Bo,lastRenderedState:ie},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Bo,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function js(e){var t=As(e);t.next===null&&(t=e.alternate.memoizedState),Rs(e,t.next.queue,{},Cu())}function Ms(){return na(dp)}function Ns(){return Fo().memoizedState}function Ps(){return Fo().memoizedState}function Fs(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=Cu();e=Wa(n);var r=Ga(t,e,n);r!==null&&(Tu(r,t,n),Ka(r,t,n)),t={cache:la()},e.payload=t;return}t=t.return}}function Is(e,t,n){var r=Cu();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},Bs(e)?Vs(t,n):(n=ri(e,t,n,r),n!==null&&(Tu(n,e,r),Hs(n,t,r)))}function Ls(e,t,n){Rs(e,t,n,Cu())}function Rs(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(Bs(e))Vs(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,Cr(s,o))return ni(e,t,i,0),Gl===null&&ti(),!1}catch{}if(n=ri(e,t,i,r),n!==null)return Tu(n,e,r),Hs(n,t,r),!0}return!1}function zs(e,t,n,r){if(r={lane:2,revertLane:Sd(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},Bs(e)){if(t)throw Error(i(479))}else t=ri(e,n,r,2),t!==null&&Tu(t,e,2)}function Bs(e){var t=e.alternate;return e===ho||t!==null&&t===ho}function Vs(e,t){yo=vo=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Hs(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,et(e,n)}}var Us={readContext:na,use:Ro,useCallback:To,useContext:To,useEffect:To,useImperativeHandle:To,useLayoutEffect:To,useInsertionEffect:To,useMemo:To,useReducer:To,useRef:To,useState:To,useDebugValue:To,useDeferredValue:To,useTransition:To,useSyncExternalStore:To,useId:To,useHostTransitionStatus:To,useFormState:To,useActionState:To,useOptimistic:To,useMemoCache:To,useCacheRefresh:To};Us.useEffectEvent=To;var Ws={readContext:na,use:Ro,useCallback:function(e,t){return Po().memoizedState=[e,t===void 0?null:t],e},useContext:na,useEffect:ms,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),fs(4194308,4,bs.bind(null,t,e),n)},useLayoutEffect:function(e,t){return fs(4194308,4,e,t)},useInsertionEffect:function(e,t){fs(4,2,e,t)},useMemo:function(e,t){var n=Po();t=t===void 0?null:t;var r=e();if(bo){Le(!0);try{e()}finally{Le(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=Po();if(n!==void 0){var i=n(t);if(bo){Le(!0);try{n(t)}finally{Le(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=Is.bind(null,ho,e),[r.memoizedState,e]},useRef:function(e){var t=Po();return e={current:e},t.memoizedState=e},useState:function(e){e=Xo(e);var t=e.queue,n=Ls.bind(null,ho,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:Ss,useDeferredValue:function(e,t){return Ts(Po(),e,t)},useTransition:function(){var e=Xo(!1);return e=Ds.bind(null,ho,e.queue,!0,!1),Po().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=ho,a=Po();if(L){if(n===void 0)throw Error(i(407));n=n()}else{if(n=t(),Gl===null)throw Error(i(349));ql&127||Go(r,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,ms(qo.bind(null,r,o,e),[e]),r.flags|=2048,us(9,{destroy:void 0},Ko.bind(null,r,o,n,t),null),n},useId:function(){var e=Po(),t=Gl.identifierPrefix;if(L){var n=ki,r=Oi;n=(r&~(1<<32-Re(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=xo++,0<\/script>`,o=o.removeChild(o.firstChild);break;case`select`:o=typeof r.is==`string`?s.createElement(`select`,{is:r.is}):s.createElement(`select`),r.multiple?o.multiple=!0:r.size&&(o.size=r.size);break;default:o=typeof r.is==`string`?s.createElement(a,{is:r.is}):s.createElement(a)}}o[st]=t,o[ct]=r;a:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)o.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break a;for(;s.sibling===null;){if(s.return===null||s.return===t)break a;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=o;a:switch(qd(o,a,r),a){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&Ic(t)}}return Vc(t),Lc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Ic(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(i(166));if(e=ue.current,Hi(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,a=I,a!==null)switch(a.tag){case 27:case 5:r=a.memoizedProps}e[st]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||Wd(e.nodeValue,n)),e||zi(t,!0)}else e=$d(e).createTextNode(r),e[st]=t,t.stateNode=e}return Vc(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=Hi(t),n!==null){if(e===null){if(!r)throw Error(i(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(i(557));e[st]=t}else Ui(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Vc(t),e=!1}else n=Wi(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?(uo(t),t):(uo(t),null);if(t.flags&128)throw Error(i(558))}return Vc(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(a=Hi(t),r!==null&&r.dehydrated!==null){if(e===null){if(!a)throw Error(i(318));if(a=t.memoizedState,a=a===null?null:a.dehydrated,!a)throw Error(i(317));a[st]=t}else Ui(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Vc(t),a=!1}else a=Wi(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=a),a=!0;if(!a)return t.flags&256?(uo(t),t):(uo(t),null)}return uo(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,a=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(a=r.alternate.memoizedState.cachePool.pool),o=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(o=r.memoizedState.cachePool.pool),o!==a&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),zc(t,t.updateQueue),Vc(t),null);case 4:return fe(),e===null&&Pd(t.stateNode.containerInfo),Vc(t),null;case 10:return Xi(t.type),Vc(t),null;case 19:if(se(fo),r=t.memoizedState,r===null)return Vc(t),null;if(a=(t.flags&128)!=0,o=r.rendering,o===null)if(a)Bc(r,!1);else{if(eu!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(o=po(e),o!==null){for(t.flags|=128,Bc(r,!1),e=o.updateQueue,t.updateQueue=e,zc(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)fi(n,e),n=n.sibling;return ce(fo,fo.current&1|2),L&&Ai(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&De()>du&&(t.flags|=128,a=!0,Bc(r,!1),t.lanes=4194304)}else{if(!a)if(e=po(o),e!==null){if(t.flags|=128,a=!0,e=e.updateQueue,t.updateQueue=e,zc(t,e),Bc(r,!0),r.tail===null&&r.tailMode===`hidden`&&!o.alternate&&!L)return Vc(t),null}else 2*De()-r.renderingStartTime>du&&n!==536870912&&(t.flags|=128,a=!0,Bc(r,!1),t.lanes=4194304);r.isBackwards?(o.sibling=t.child,t.child=o):(e=r.last,e===null?t.child=o:e.sibling=o,r.last=o)}return r.tail===null?(Vc(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=De(),e.sibling=null,n=fo.current,ce(fo,a?n&1|2:n&1),L&&Ai(t,r.treeForkCount),e);case 22:case 23:return uo(t),ro(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(Vc(t),t.subtreeFlags&6&&(t.flags|=8192)):Vc(t),n=t.updateQueue,n!==null&&zc(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&se(ya),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),Xi(ca),Vc(t),null;case 25:return null;case 30:return null}throw Error(i(156,t.tag))}function Uc(e,t){switch(Ni(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Xi(ca),fe(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return me(t),null;case 31:if(t.memoizedState!==null){if(uo(t),t.alternate===null)throw Error(i(340));Ui()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(uo(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(i(340));Ui()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return se(fo),null;case 4:return fe(),null;case 10:return Xi(t.type),null;case 22:case 23:return uo(t),ro(),e!==null&&se(ya),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Xi(ca),null;case 25:return null;default:return null}}function Wc(e,t){switch(Ni(t),t.tag){case 3:Xi(ca),fe();break;case 26:case 27:case 5:me(t);break;case 4:fe();break;case 31:t.memoizedState!==null&&uo(t);break;case 13:uo(t);break;case 19:se(fo);break;case 10:Xi(t.type);break;case 22:case 23:uo(t),ro(),e!==null&&se(ya);break;case 24:Xi(ca)}}function Gc(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){td(t,t.return,e)}}function Kc(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){td(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){td(t,t.return,e)}}function qc(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{Qa(t,n)}catch(t){td(e,e.return,t)}}}function Jc(e,t,n){n.props=Zs(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){td(e,t,n)}}function Yc(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){td(e,t,n)}}function Xc(e,t){var n=e.ref,r=e.refCleanup;if(n!==null)if(typeof r==`function`)try{r()}catch(n){td(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){td(e,t,n)}else n.current=null}function Zc(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){td(e,e.return,t)}}function Qc(e,t,n){try{var r=e.stateNode;Jd(r,e.type,n,t),r[ct]=t}catch(t){td(e,e.return,t)}}function $c(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&df(e.type)||e.tag===4}function el(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||$c(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&df(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function tl(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=en));else if(r!==4&&(r===27&&df(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for(tl(e,t,n),e=e.sibling;e!==null;)tl(e,t,n),e=e.sibling}function nl(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&df(e.type)&&(n=e.stateNode),e=e.child,e!==null))for(nl(e,t,n),e=e.sibling;e!==null;)nl(e,t,n),e=e.sibling}function rl(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);qd(t,r,n),t[st]=e,t[ct]=n}catch(t){td(e,e.return,t)}}var il=!1,al=!1,ol=!1,sl=typeof WeakSet==`function`?WeakSet:Set,cl=null;function ll(e,t){if(e=e.containerInfo,Zd=bp,e=Or(e),kr(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var a=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||a!==0&&f.nodeType!==3||(c=s+a),f!==o||r!==0&&f.nodeType!==3||(l=s+r),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===a&&(c=s),p===o&&++d===r&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(Qd={focusedElem:e,selectionRange:n},bp=!1,cl=t;cl!==null;)if(t=cl,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,cl=e;else for(;cl!==null;){switch(t=cl,o=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n title`))),qd(o,r,n),o[st]=e,bt(o),r=o;break a;case`link`:var s=ep(`link`,`href`,a).get(r+(n.href||``));if(s){for(var c=0;cg&&(o=g,g=h,h=o);var _=Er(s,h),v=Er(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;sn?32:n,k.T=null,n=yu,yu=null;var o=hu,s=_u;if(mu=0,gu=hu=null,_u=0,Wl&6)throw Error(i(331));var c=Wl;if(Wl|=4,zl(o.current),jl(o,o.current,s,n),Wl=c,hd(0,!1),Ie&&typeof Ie.onPostCommitFiberRoot==`function`)try{Ie.onPostCommitFiberRoot(Fe,o)}catch{}return!0}finally{A.p=a,k.T=r,Zu(e,t)}}function ed(e,t,n){t=bi(n,t),t=rc(e.stateNode,t,2),e=Ga(e,t,2),e!==null&&(Ze(e,2),md(e))}function td(e,t,n){if(e.tag===3)ed(e,e,n);else for(;t!==null;){if(t.tag===3){ed(t,e,n);break}else if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(pu===null||!pu.has(r))){e=bi(n,e),n=ic(2),r=Ga(t,n,2),r!==null&&(ac(n,r,t,e),Ze(r,2),md(r));break}}t=t.return}}function nd(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new Ul;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||(Ql=!0,i.add(n),e=rd.bind(null,e,t,n),t.then(e,e))}function rd(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,Gl===e&&(ql&n)===n&&(eu===4||eu===3&&(ql&62914560)===ql&&300>De()-lu?!(Wl&2)&&Mu(e,0):ru|=n,au===ql&&(au=0)),md(e)}function id(e,t){t===0&&(t=Ye()),e=ii(e,t),e!==null&&(Ze(e,t),md(e))}function ad(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),id(e,n)}function od(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(i(314))}r!==null&&r.delete(t),id(e,n)}function sd(e,t){return Ce(e,t)}var cd=null,ld=null,ud=!1,dd=!1,fd=!1,pd=0;function md(e){e!==ld&&e.next===null&&(ld===null?cd=ld=e:ld=ld.next=e),dd=!0,ud||(ud=!0,xd())}function hd(e,t){if(!fd&&dd){fd=!0;do for(var n=!1,r=cd;r!==null;){if(!t)if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-Re(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,bd(r,a))}else a=ql,a=Ke(r,r===Gl?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||qe(r,a)||(n=!0,bd(r,a));r=r.next}while(n);fd=!1}}function gd(){_d()}function _d(){dd=ud=!1;var e=0;pd!==0&&af()&&(e=pd);for(var t=De(),n=null,r=cd;r!==null;){var i=r.next,a=vd(r,t);a===0?(r.next=null,n===null?cd=i:n.next=i,i===null&&(ld=n)):(n=r,(e!==0||a&3)&&(dd=!0)),r=i}mu!==0&&mu!==5||hd(e,!1),pd!==0&&(pd=0)}function vd(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0s)break;var u=c.transferSize,d=c.initiatorType;u&&Yd(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function Pf(e,t,n){var r=Nf;if(r&&typeof t==`string`&&t){var i=zt(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),Of.has(i)||(Of.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),qd(t,`link`,e),bt(t),r.head.appendChild(t)))}}function Ff(e){Af.D(e),Pf(`dns-prefetch`,e,null)}function If(e,t){Af.C(e,t),Pf(`preconnect`,e,t)}function Lf(e,t,n){Af.L(e,t,n);var r=Nf;if(r&&e&&t){var i=`link[rel="preload"][as="`+zt(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+zt(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+zt(n.imageSizes)+`"]`)):i+=`[href="`+zt(e)+`"]`;var a=i;switch(t){case`style`:a=Uf(e);break;case`script`:a=qf(e)}Df.has(a)||(e=f({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),Df.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(Wf(a))||t===`script`&&r.querySelector(Jf(a))||(t=r.createElement(`link`),qd(t,`link`,e),bt(t),r.head.appendChild(t)))}}function Rf(e,t){Af.m(e,t);var n=Nf;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+zt(r)+`"][href="`+zt(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=qf(e)}if(!Df.has(a)&&(e=f({rel:`modulepreload`,href:e},t),Df.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Jf(a)))return}r=n.createElement(`link`),qd(r,`link`,e),bt(r),n.head.appendChild(r)}}}function zf(e,t,n){Af.S(e,t,n);var r=Nf;if(r&&e){var i=yt(r).hoistableStyles,a=Uf(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(Wf(a)))s.loading=5;else{e=f({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=Df.get(a))&&Zf(e,n);var c=o=r.createElement(`link`);bt(c),qd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,Xf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Bf(e,t){Af.X(e,t);var n=Nf;if(n&&e){var r=yt(n).hoistableScripts,i=qf(e),a=r.get(i);a||(a=n.querySelector(Jf(i)),a||(e=f({src:e,async:!0},t),(t=Df.get(i))&&Qf(e,t),a=n.createElement(`script`),bt(a),qd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Vf(e,t){Af.M(e,t);var n=Nf;if(n&&e){var r=yt(n).hoistableScripts,i=qf(e),a=r.get(i);a||(a=n.querySelector(Jf(i)),a||(e=f({src:e,async:!0,type:`module`},t),(t=Df.get(i))&&Qf(e,t),a=n.createElement(`script`),bt(a),qd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Hf(e,t,n,r){var a=(a=ue.current)?kf(a):null;if(!a)throw Error(i(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Uf(n.href),n=yt(a).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Uf(n.href);var o=yt(a).hoistableStyles,s=o.get(e);if(s||(a=a.ownerDocument||a,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=a.querySelector(Wf(e)))&&!o._p&&(s.instance=o,s.state.loading=5),Df.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},Df.set(e,n),o||Kf(a,e,n,s.state))),t&&r===null)throw Error(i(528,``));return s}if(t&&r!==null)throw Error(i(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=qf(n),n=yt(a).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(i(444,e))}}function Uf(e){return`href="`+zt(e)+`"`}function Wf(e){return`link[rel="stylesheet"][`+e+`]`}function Gf(e){return f({},e,{"data-precedence":e.precedence,precedence:null})}function Kf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),qd(t,`link`,n),bt(t),e.head.appendChild(t))}function qf(e){return`[src="`+zt(e)+`"]`}function Jf(e){return`script[async]`+e}function Yf(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+zt(n.href)+`"]`);if(r)return t.instance=r,bt(r),r;var a=f({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),bt(r),qd(r,`style`,a),Xf(r,n.precedence,e),t.instance=r;case`stylesheet`:a=Uf(n.href);var o=e.querySelector(Wf(a));if(o)return t.state.loading|=4,t.instance=o,bt(o),o;r=Gf(n),(a=Df.get(a))&&Zf(r,a),o=(e.ownerDocument||e).createElement(`link`),bt(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),qd(o,`link`,r),t.state.loading|=4,Xf(o,n.precedence,e),t.instance=o;case`script`:return o=qf(n.src),(a=e.querySelector(Jf(o)))?(t.instance=a,bt(a),a):(r=n,(a=Df.get(o))&&(r=f({},n),Qf(r,a)),e=e.ownerDocument||e,a=e.createElement(`script`),bt(a),qd(a,`link`,r),e.head.appendChild(a),t.instance=a);case`void`:return null;default:throw Error(i(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,Xf(r,n.precedence,e));return t.instance}function Xf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function np(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function rp(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function ip(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Uf(r.href),a=t.querySelector(Wf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=sp.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,bt(a);return}a=t.ownerDocument||t,r=Gf(r),(i=Df.get(i))&&Zf(r,i),a=a.createElement(`link`),bt(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),qd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=sp.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var ap=0;function op(e,t){return e.stylesheets&&e.count===0&&lp(e,e.stylesheets),0ap?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function sp(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)lp(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var cp=null;function lp(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,cp=new Map,t.forEach(up,e),cp=null,sp.call(e))}function up(e,t){if(!(t.state.loading&4)){var n=cp.get(e);if(n)var r=n.get(null);else{n=new Map,cp.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=oa()})),ca=o((e=>{var t=je().__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;e.c=function(e){return t.H.useMemoCache(e)}})),la=o(((e,t)=>{t.exports=ca()})),ua=c(sa(),1),da=la(),fa=(0,P.createContext)(void 0);function pa(e,t){try{let t=localStorage.getItem(e);if(t===`light`||t===`dark`||t===`system`)return t}catch{}return t}function ma(e){let t=(0,da.c)(14),{children:n,defaultTheme:r,storageKey:i}=e,a=r===void 0?`dark`:r,o=i===void 0?`ui-theme`:i,s;t[0]!==a||t[1]!==o?(s=()=>pa(o,a),t[0]=a,t[1]=o,t[2]=s):s=t[2];let[c,l]=(0,P.useState)(s),u,d;t[3]===c?(u=t[4],d=t[5]):(u=()=>{let e=window.document.documentElement;if(e.classList.remove(`light`,`dark`),c===`system`){let t=window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`;e.classList.add(t);return}e.classList.add(c)},d=[c],t[3]=c,t[4]=u,t[5]=d),(0,P.useEffect)(u,d);let f;t[6]===o?f=t[7]:(f=e=>{try{localStorage.setItem(o,e)}catch{}l(e)},t[6]=o,t[7]=f);let p;t[8]!==f||t[9]!==c?(p={theme:c,setTheme:f},t[8]=f,t[9]=c,t[10]=p):p=t[10];let m=p,h;return t[11]!==n||t[12]!==m?(h=(0,F.jsx)(fa.Provider,{value:m,children:n}),t[11]=n,t[12]=m,t[13]=h):h=t[13],h}function ha(){let e=(0,P.useContext)(fa);if(e===void 0)throw Error(`useTheme must be used within a ThemeProvider`);return e}function ga(e,t){if(e&&!t)return e;if(!e&&t)return t;if(e||t)return{...e,...t}}var _a={};function va(e,t,n,r,i){if(!n&&!r&&!i&&!e)return ba(t);let a=ba(e);return t&&(a=xa(a,t)),n&&(a=xa(a,n)),r&&(a=xa(a,r)),i&&(a=xa(a,i)),a}function ya(e){if(e.length===0)return _a;if(e.length===1)return ba(e[0]);let t=ba(e[0]);for(let n=1;n=65&&i<=90&&(typeof t==`function`||t===void 0)}function Ta(e){return typeof e==`function`}function Ea(e,t){return Ta(e)?e(t):e??_a}function Da(e,t){return t?e?(...n)=>{let r=n[0];if(ja(r)){let i=r;ka(i);let a=t(...n);return i.baseUIHandlerPrevented||e?.(...n),a}let i=t(...n);return e?.(...n),i}:Oa(t):e}function Oa(e){return e&&((...t)=>{let n=t[0];return ja(n)&&ka(n),e(...t)})}function ka(e){return e.preventBaseUIHandler=()=>{e.baseUIHandlerPrevented=!0},e}function Aa(e,t){return t?e?t+` `+e:t:e}function ja(e){return typeof e==`object`&&!!e&&`nativeEvent`in e}function Ma(e,t){return function(n,...r){let i=new URL(e);return i.searchParams.set(`code`,n.toString()),r.forEach(e=>i.searchParams.append(`args[]`,e)),`${t} error #${n}; visit ${i} for the full message.`}}var Na=Ma(`https://base-ui.com/production-error`,`Base UI`),Pa={};function Fa(e,t){let n=P.useRef(Pa);return n.current===Pa&&(n.current=e(t)),n}function Ia(e,t,n,r){let i=Fa(Ra).current;return za(i,e,t,n,r)&&Va(i,[e,t,n,r]),i.callback}function La(e){let t=Fa(Ra).current;return Ba(t,e)&&Va(t,e),t.callback}function Ra(){return{callback:null,cleanup:null,refs:[]}}function za(e,t,n,r,i){return e.refs[0]!==t||e.refs[1]!==n||e.refs[2]!==r||e.refs[3]!==i}function Ba(e,t){return e.refs.length!==t.length||e.refs.some((e,n)=>e!==t[n])}function Va(e,t){if(e.refs=t,t.every(e=>e==null)){e.callback=null;return}e.callback=n=>{if(e.cleanup&&=(e.cleanup(),null),n!=null){let r=Array(t.length).fill(null);for(let e=0;e{for(let e=0;e=e}function Wa(e){if(!P.isValidElement(e))return null;let t=e,n=t.props;return(Ua(19)?n?.ref:t.ref)??null}function Ga(){}var Ka=Object.freeze([]),qa=Object.freeze({});function Ja(e,t){let n={};for(let r in e){let i=e[r];if(t?.hasOwnProperty(r)){let e=t[r](i);e!=null&&Object.assign(n,e);continue}i===!0?n[`data-${r.toLowerCase()}`]=``:i&&(n[`data-${r.toLowerCase()}`]=i.toString())}return n}function Ya(e,t){return typeof e==`function`?e(t):e}function Xa(e,t){return typeof e==`function`?e(t):e}function Za(e,t,n={}){let r=t.render,i=Qa(t,n);return n.enabled===!1?null:to(e,r,i,n.state??qa)}function Qa(e,t={}){let{className:n,style:r,render:i}=e,{state:a=qa,ref:o,props:s,stateAttributesMapping:c,enabled:l=!0}=t,u=l?Ya(n,a):void 0,d=l?Xa(r,a):void 0,f=l?Ja(a,c):qa,p=l&&s?$a(s):void 0,m=l?ga(f,p)??{}:qa;return typeof document<`u`&&(l?Array.isArray(o)?m.ref=La([m.ref,Wa(i),...o]):m.ref=Ia(m.ref,Wa(i),o):Ia(null,null)),l?(u!==void 0&&(m.className=Aa(m.className,u)),d!==void 0&&(m.style=ga(m.style,d)),m):qa}function $a(e){return Array.isArray(e)?ya(e):va(void 0,e)}var eo=Symbol.for(`react.lazy`);function to(e,t,n,r){if(t){if(typeof t==`function`)return t(n,r);let e=va(n,t.props);e.ref=n.ref;let i=t;return i?.$$typeof===eo&&(i=P.Children.toArray(t)[0]),P.cloneElement(i,e)}if(e&&typeof e==`string`)return no(e,n);throw Error(Na(8))}function no(e,t){return e===`button`?(0,P.createElement)(`button`,{type:`button`,...t,key:t.key}):e===`img`?(0,P.createElement)(`img`,{alt:``,...t,key:t.key}):P.createElement(e,t)}function ro(e){return Za(e.defaultTagName??`div`,e,e)}function io(e){var t,n,r=``;if(typeof e==`string`||typeof e==`number`)r+=e;else if(typeof e==`object`)if(Array.isArray(e)){var i=e.length;for(t=0;ttypeof e==`boolean`?`${e}`:e===0?`0`:e,so=ao,co=(e,t)=>n=>{if(t?.variants==null)return so(e,n?.class,n?.className);let{variants:r,defaultVariants:i}=t,a=Object.keys(r).map(e=>{let t=n?.[e],a=i?.[e];if(t===null)return null;let o=oo(t)||oo(a);return r[e][o]}),o=n&&Object.entries(n).reduce((e,t)=>{let[n,r]=t;return r===void 0||(e[n]=r),e},{});return so(e,a,t?.compoundVariants?.reduce((e,t)=>{let{class:n,className:r,...a}=t;return Object.entries(a).every(e=>{let[t,n]=e;return Array.isArray(n)?n.includes({...i,...o}[t]):{...i,...o}[t]===n})?[...e,n,r]:e},[]),n?.class,n?.className)},lo=(...e)=>e.filter((e,t,n)=>!!e&&e.trim()!==``&&n.indexOf(e)===t).join(` `).trim(),uo=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase(),fo=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,t,n)=>n?n.toUpperCase():t.toLowerCase()),po=e=>{let t=fo(e);return t.charAt(0).toUpperCase()+t.slice(1)},mo={xmlns:`http://www.w3.org/2000/svg`,width:24,height:24,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:2,strokeLinecap:`round`,strokeLinejoin:`round`},ho=e=>{for(let t in e)if(t.startsWith(`aria-`)||t===`role`||t===`title`)return!0;return!1},go=(0,P.createContext)({}),_o=()=>(0,P.useContext)(go),vo=(0,P.forwardRef)(({color:e,size:t,strokeWidth:n,absoluteStrokeWidth:r,className:i=``,children:a,iconNode:o,...s},c)=>{let{size:l=24,strokeWidth:u=2,absoluteStrokeWidth:d=!1,color:f=`currentColor`,className:p=``}=_o()??{},m=r??d?Number(n??u)*24/Number(t??l):n??u;return(0,P.createElement)(`svg`,{ref:c,...mo,width:t??l??mo.width,height:t??l??mo.height,stroke:e??f,strokeWidth:m,className:lo(`lucide`,p,i),...!a&&!ho(s)&&{"aria-hidden":`true`},...s},[...o.map(([e,t])=>(0,P.createElement)(e,t)),...Array.isArray(a)?a:[a]])}),yo=(e,t)=>{let n=(0,P.forwardRef)(({className:n,...r},i)=>(0,P.createElement)(vo,{ref:i,iconNode:t,className:lo(`lucide-${uo(po(e))}`,`lucide-${e}`,n),...r}));return n.displayName=po(e),n},bo=yo(`activity`,[[`path`,{d:`M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2`,key:`169zse`}]]),xo=yo(`book-open`,[[`path`,{d:`M12 7v14`,key:`1akyts`}],[`path`,{d:`M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z`,key:`ruj8y`}]]),So=yo(`camera`,[[`path`,{d:`M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z`,key:`18u6gg`}],[`circle`,{cx:`12`,cy:`13`,r:`3`,key:`1vg3eu`}]]),Co=yo(`circle-alert`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`line`,{x1:`12`,x2:`12`,y1:`8`,y2:`12`,key:`1pkeuh`}],[`line`,{x1:`12`,x2:`12.01`,y1:`16`,y2:`16`,key:`4dfq90`}]]),wo=yo(`crosshair`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`line`,{x1:`22`,x2:`18`,y1:`12`,y2:`12`,key:`l9bcsi`}],[`line`,{x1:`6`,x2:`2`,y1:`12`,y2:`12`,key:`13hhkx`}],[`line`,{x1:`12`,x2:`12`,y1:`6`,y2:`2`,key:`10w3f3`}],[`line`,{x1:`12`,x2:`12`,y1:`22`,y2:`18`,key:`15g9kq`}]]),To=yo(`hard-drive`,[[`path`,{d:`M10 16h.01`,key:`1bzywj`}],[`path`,{d:`M2.212 11.577a2 2 0 0 0-.212.896V18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-5.527a2 2 0 0 0-.212-.896L18.55 5.11A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z`,key:`18tbho`}],[`path`,{d:`M21.946 12.013H2.054`,key:`zqlbp7`}],[`path`,{d:`M6 16h.01`,key:`1pmjb7`}]]),Eo=yo(`house`,[[`path`,{d:`M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8`,key:`5wwlr5`}],[`path`,{d:`M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z`,key:`r6nss1`}]]),Do=yo(`image`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}],[`circle`,{cx:`9`,cy:`9`,r:`2`,key:`af1f0g`}],[`path`,{d:`m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21`,key:`1xmnt7`}]]),Oo=yo(`key`,[[`path`,{d:`m15.5 7.5 2.3 2.3a1 1 0 0 0 1.4 0l2.1-2.1a1 1 0 0 0 0-1.4L19 4`,key:`g0fldk`}],[`path`,{d:`m21 2-9.6 9.6`,key:`1j0ho8`}],[`circle`,{cx:`7.5`,cy:`15.5`,r:`5.5`,key:`yqb3hr`}]]),ko=yo(`layers`,[[`path`,{d:`M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z`,key:`zw3jo`}],[`path`,{d:`M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12`,key:`1wduqc`}],[`path`,{d:`M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17`,key:`kqbvx6`}]]),Ao=yo(`layout-grid`,[[`rect`,{width:`7`,height:`7`,x:`3`,y:`3`,rx:`1`,key:`1g98yp`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`3`,rx:`1`,key:`6d4xhi`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`14`,rx:`1`,key:`nxv5o0`}],[`rect`,{width:`7`,height:`7`,x:`3`,y:`14`,rx:`1`,key:`1bb6yr`}]]),jo=yo(`log-out`,[[`path`,{d:`m16 17 5-5-5-5`,key:`1bji2h`}],[`path`,{d:`M21 12H9`,key:`dn1m92`}],[`path`,{d:`M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4`,key:`1uf3rs`}]]),Mo=yo(`moon`,[[`path`,{d:`M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401`,key:`kfwtm`}]]),No=yo(`network`,[[`rect`,{x:`16`,y:`16`,width:`6`,height:`6`,rx:`1`,key:`4q2zg0`}],[`rect`,{x:`2`,y:`16`,width:`6`,height:`6`,rx:`1`,key:`8cvhb9`}],[`rect`,{x:`9`,y:`2`,width:`6`,height:`6`,rx:`1`,key:`1egb70`}],[`path`,{d:`M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3`,key:`1jsf9p`}],[`path`,{d:`M12 12V8`,key:`2874zd`}]]),Po=yo(`panel-left`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`M9 3v18`,key:`fh3hqa`}]]),Fo=yo(`server`,[[`rect`,{width:`20`,height:`8`,x:`2`,y:`2`,rx:`2`,ry:`2`,key:`ngkwjq`}],[`rect`,{width:`20`,height:`8`,x:`2`,y:`14`,rx:`2`,ry:`2`,key:`iecqi9`}],[`line`,{x1:`6`,x2:`6.01`,y1:`6`,y2:`6`,key:`16zg32`}],[`line`,{x1:`6`,x2:`6.01`,y1:`18`,y2:`18`,key:`nzw8ys`}]]),Io=yo(`shield-check`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),Lo=yo(`shield`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}]]),Ro=yo(`sun`,[[`circle`,{cx:`12`,cy:`12`,r:`4`,key:`4exip2`}],[`path`,{d:`M12 2v2`,key:`tus03m`}],[`path`,{d:`M12 20v2`,key:`1lh1kg`}],[`path`,{d:`m4.93 4.93 1.41 1.41`,key:`149t6j`}],[`path`,{d:`m17.66 17.66 1.41 1.41`,key:`ptbguv`}],[`path`,{d:`M2 12h2`,key:`1t8f8n`}],[`path`,{d:`M20 12h2`,key:`1q8mjw`}],[`path`,{d:`m6.34 17.66-1.41 1.41`,key:`1m8zz5`}],[`path`,{d:`m19.07 4.93-1.41 1.41`,key:`1shlcs`}]]),zo=yo(`users`,[[`path`,{d:`M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2`,key:`1yyitq`}],[`path`,{d:`M16 3.128a4 4 0 0 1 0 7.744`,key:`16gr8j`}],[`path`,{d:`M22 21v-2a4 4 0 0 0-3-3.87`,key:`kshegd`}],[`circle`,{cx:`9`,cy:`7`,r:`4`,key:`nufk8`}]]),Bo=yo(`waypoints`,[[`path`,{d:`m10.586 5.414-5.172 5.172`,key:`4mc350`}],[`path`,{d:`m18.586 13.414-5.172 5.172`,key:`8c96vv`}],[`path`,{d:`M6 12h12`,key:`8npq4p`}],[`circle`,{cx:`12`,cy:`20`,r:`2`,key:`144qzu`}],[`circle`,{cx:`12`,cy:`4`,r:`2`,key:`muu5ef`}],[`circle`,{cx:`20`,cy:`12`,r:`2`,key:`1xzzfp`}],[`circle`,{cx:`4`,cy:`12`,r:`2`,key:`1hvhnz`}]]),Vo=yo(`x`,[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]]);function Ho(){return typeof window<`u`}function Uo(e){return Ko(e)?(e.nodeName||``).toLowerCase():`#document`}function Wo(e){var t;return(e==null||(t=e.ownerDocument)==null?void 0:t.defaultView)||window}function Go(e){return((Ko(e)?e.ownerDocument:e.document)||window.document)?.documentElement}function Ko(e){return Ho()?e instanceof Node||e instanceof Wo(e).Node:!1}function qo(e){return Ho()?e instanceof Element||e instanceof Wo(e).Element:!1}function Jo(e){return Ho()?e instanceof HTMLElement||e instanceof Wo(e).HTMLElement:!1}function Yo(e){return!Ho()||typeof ShadowRoot>`u`?!1:e instanceof ShadowRoot||e instanceof Wo(e).ShadowRoot}function Xo(e){let{overflow:t,overflowX:n,overflowY:r,display:i}=ss(e);return/auto|scroll|overlay|hidden|clip/.test(t+r+n)&&i!==`inline`&&i!==`contents`}function Zo(e){return/^(table|td|th)$/.test(Uo(e))}function Qo(e){try{if(e.matches(`:popover-open`))return!0}catch{}try{return e.matches(`:modal`)}catch{return!1}}var $o=/transform|translate|scale|rotate|perspective|filter/,es=/paint|layout|strict|content/,ts=e=>!!e&&e!==`none`,ns;function rs(e){let t=qo(e)?ss(e):e;return ts(t.transform)||ts(t.translate)||ts(t.scale)||ts(t.rotate)||ts(t.perspective)||!as()&&(ts(t.backdropFilter)||ts(t.filter))||$o.test(t.willChange||``)||es.test(t.contain||``)}function is(e){let t=ls(e);for(;Jo(t)&&!os(t);){if(rs(t))return t;if(Qo(t))return null;t=ls(t)}return null}function as(){return ns??=typeof CSS<`u`&&CSS.supports&&CSS.supports(`-webkit-backdrop-filter`,`none`),ns}function os(e){return/^(html|body|#document)$/.test(Uo(e))}function ss(e){return Wo(e).getComputedStyle(e)}function cs(e){return qo(e)?{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}:{scrollLeft:e.scrollX,scrollTop:e.scrollY}}function ls(e){if(Uo(e)===`html`)return e;let t=e.assignedSlot||e.parentNode||Yo(e)&&e.host||Go(e);return Yo(t)?t.host:t}function us(e){let t=ls(e);return os(t)?e.ownerDocument?e.ownerDocument.body:e.body:Jo(t)&&Xo(t)?t:us(t)}function ds(e,t,n){t===void 0&&(t=[]),n===void 0&&(n=!0);let r=us(e),i=r===e.ownerDocument?.body,a=Wo(r);if(i){let e=fs(a);return t.concat(a,a.visualViewport||[],Xo(r)?r:[],e&&n?ds(e):[])}else return t.concat(r,ds(r,[],n))}function fs(e){return e.parent&&Object.getPrototypeOf(e.parent)?e.frameElement:null}var ps=P[`useInsertionEffect${Math.random().toFixed(1)}`.slice(0,-3)],ms=ps&&ps!==P.useLayoutEffect?ps:e=>e();function hs(e){let t=Fa(gs).current;return t.next=e,ms(t.effect),t.trampoline}function gs(){let e={next:void 0,callback:_s,trampoline:(...t)=>e.callback?.(...t),effect:()=>{e.callback=e.next}};return e}function _s(){}var vs={...P},ys=typeof document<`u`?P.useLayoutEffect:()=>{},bs=P.createContext(void 0);function xs(e=!1){let t=P.useContext(bs);if(t===void 0&&!e)throw Error(Na(16));return t}function Ss(e){let{focusableWhenDisabled:t,disabled:n,composite:r=!1,tabIndex:i=0,isNativeButton:a}=e,o=r&&t!==!1,s=r&&t===!1;return{props:P.useMemo(()=>{let e={onKeyDown(e){n&&t&&e.key!==`Tab`&&e.preventDefault()}};return r||(e.tabIndex=i,!a&&n&&(e.tabIndex=t?i:-1)),(a&&(t||o)||!a&&n)&&(e[`aria-disabled`]=n),a&&(!t||s)&&(e.disabled=n),e},[r,n,t,o,s,a,i])}}function Cs(e={}){let{disabled:t=!1,focusableWhenDisabled:n,tabIndex:r=0,native:i=!0,composite:a}=e,o=P.useRef(null),s=xs(!0),c=a??s!==void 0,{props:l}=Ss({focusableWhenDisabled:n,disabled:t,composite:c,tabIndex:r,isNativeButton:i}),u=P.useCallback(()=>{let e=o.current;ws(e)&&c&&t&&l.disabled===void 0&&e.disabled&&(e.disabled=!1)},[t,l.disabled,c]);return ys(u,[u]),{getButtonProps:P.useCallback((e={})=>{let{onClick:n,onMouseDown:r,onKeyUp:a,onKeyDown:o,onPointerDown:s,...u}=e;return va({type:i?`button`:void 0,onClick(e){if(t){e.preventDefault();return}n?.(e)},onMouseDown(e){t||r?.(e)},onKeyDown(e){if(t||(ka(e),o?.(e),e.baseUIHandlerPrevented))return;let r=e.target===e.currentTarget,a=e.currentTarget,s=ws(a),l=!i&&Ts(a),u=r&&(i?s:!l),d=e.key===`Enter`,f=e.key===` `,p=a.getAttribute(`role`),m=p?.startsWith(`menuitem`)||p===`option`||p===`gridcell`;if(r&&c&&f){if(e.defaultPrevented&&m)return;e.preventDefault(),l||i&&s?(a.click(),e.preventBaseUIHandler()):u&&(n?.(e),e.preventBaseUIHandler());return}u&&(!i&&(f||d)&&e.preventDefault(),!i&&d&&n?.(e))},onKeyUp(e){if(!t){if(ka(e),a?.(e),e.target===e.currentTarget&&i&&c&&ws(e.currentTarget)&&e.key===` `){e.preventDefault();return}e.baseUIHandlerPrevented||e.target===e.currentTarget&&!i&&!c&&e.key===` `&&n?.(e)}},onPointerDown(e){if(t){e.preventDefault();return}s?.(e)}},i?void 0:{role:`button`},l,u)},[t,l,c,i]),buttonRef:hs(e=>{o.current=e,u()})}}function ws(e){return Jo(e)&&e.tagName===`BUTTON`}function Ts(e){return!!(e?.tagName===`A`&&e?.href)}var Es=P.forwardRef(function(e,t){let{render:n,className:r,disabled:i=!1,focusableWhenDisabled:a=!1,nativeButton:o=!0,style:s,...c}=e,{getButtonProps:l,buttonRef:u}=Cs({disabled:i,focusableWhenDisabled:a,native:o});return Za(`button`,e,{state:{disabled:i},ref:[t,u],props:[c,l]})}),Ds=(e,t)=>{let n=Array(e.length+t.length);for(let t=0;t({classGroupId:e,validator:t}),ks=(e=new Map,t=null,n)=>({nextPart:e,validators:t,classGroupId:n}),As=`-`,js=[],Ms=`arbitrary..`,Ns=e=>{let t=Is(e),{conflictingClassGroups:n,conflictingClassGroupModifiers:r}=e;return{getClassGroupId:e=>{if(e.startsWith(`[`)&&e.endsWith(`]`))return Fs(e);let n=e.split(As);return Ps(n,+(n[0]===``&&n.length>1),t)},getConflictingClassGroupIds:(e,t)=>{if(t){let t=r[e],i=n[e];return t?i?Ds(i,t):t:i||js}return n[e]||js}}},Ps=(e,t,n)=>{if(e.length-t===0)return n.classGroupId;let r=e[t],i=n.nextPart.get(r);if(i){let n=Ps(e,t+1,i);if(n)return n}let a=n.validators;if(a===null)return;let o=t===0?e.join(As):e.slice(t).join(As),s=a.length;for(let e=0;ee.slice(1,-1).indexOf(`:`)===-1?void 0:(()=>{let t=e.slice(1,-1),n=t.indexOf(`:`),r=t.slice(0,n);return r?Ms+r:void 0})(),Is=e=>{let{theme:t,classGroups:n}=e;return Ls(n,t)},Ls=(e,t)=>{let n=ks();for(let r in e){let i=e[r];Rs(i,n,r,t)}return n},Rs=(e,t,n,r)=>{let i=e.length;for(let a=0;a{if(typeof e==`string`){Bs(e,t,n);return}if(typeof e==`function`){Vs(e,t,n,r);return}Hs(e,t,n,r)},Bs=(e,t,n)=>{let r=e===``?t:Us(t,e);r.classGroupId=n},Vs=(e,t,n,r)=>{if(Ws(e)){Rs(e(r),t,n,r);return}t.validators===null&&(t.validators=[]),t.validators.push(Os(n,e))},Hs=(e,t,n,r)=>{let i=Object.entries(e),a=i.length;for(let e=0;e{let n=e,r=t.split(As),i=r.length;for(let e=0;e`isThemeGetter`in e&&e.isThemeGetter===!0,Gs=e=>{if(e<1)return{get:()=>void 0,set:()=>{}};let t=0,n=Object.create(null),r=Object.create(null),i=(i,a)=>{n[i]=a,t++,t>e&&(t=0,r=n,n=Object.create(null))};return{get(e){let t=n[e];if(t!==void 0)return t;if((t=r[e])!==void 0)return i(e,t),t},set(e,t){e in n?n[e]=t:i(e,t)}}},Ks=`!`,qs=`:`,Js=[],Ys=(e,t,n,r,i)=>({modifiers:e,hasImportantModifier:t,baseClassName:n,maybePostfixModifierPosition:r,isExternal:i}),Xs=e=>{let{prefix:t,experimentalParseClassName:n}=e,r=e=>{let t=[],n=0,r=0,i=0,a,o=e.length;for(let s=0;si?a-i:void 0;return Ys(t,l,c,u)};if(t){let e=t+qs,n=r;r=t=>t.startsWith(e)?n(t.slice(e.length)):Ys(Js,!1,t,void 0,!0)}if(n){let e=r;r=t=>n({className:t,parseClassName:e})}return r},Zs=e=>{let t=new Map;return e.orderSensitiveModifiers.forEach((e,n)=>{t.set(e,1e6+n)}),e=>{let n=[],r=[];for(let i=0;i0&&(r.sort(),n.push(...r),r=[]),n.push(a)):r.push(a)}return r.length>0&&(r.sort(),n.push(...r)),n}},Qs=e=>({cache:Gs(e.cacheSize),parseClassName:Xs(e),sortModifiers:Zs(e),postfixLookupClassGroupIds:$s(e),...Ns(e)}),$s=e=>{let t=Object.create(null),n=e.postfixLookupClassGroups;if(n)for(let e=0;e{let{parseClassName:n,getClassGroupId:r,getConflictingClassGroupIds:i,sortModifiers:a,postfixLookupClassGroupIds:o}=t,s=[],c=e.trim().split(ec),l=``;for(let e=c.length-1;e>=0;--e){let t=c[e],{isExternal:u,modifiers:d,hasImportantModifier:f,baseClassName:p,maybePostfixModifierPosition:m}=n(t);if(u){l=t+(l.length>0?` `+l:l);continue}let h=!!m,g;if(h){g=r(p.substring(0,m));let e=g&&o[g]?r(p):void 0;e&&e!==g&&(g=e,h=!1)}else g=r(p);if(!g){if(!h){l=t+(l.length>0?` `+l:l);continue}if(g=r(p),!g){l=t+(l.length>0?` `+l:l);continue}h=!1}let _=d.length===0?``:d.length===1?d[0]:a(d).join(`:`),v=f?_+Ks:_,y=v+g;if(s.indexOf(y)>-1)continue;s.push(y);let b=i(g,h);for(let e=0;e0?` `+l:l)}return l},nc=(...e)=>{let t=0,n,r,i=``;for(;t{if(typeof e==`string`)return e;let t,n=``;for(let r=0;r{let n,r,i,a,o=o=>(n=Qs(t.reduce((e,t)=>t(e),e())),r=n.cache.get,i=n.cache.set,a=s,s(o)),s=e=>{let t=r(e);if(t)return t;let a=tc(e,n);return i(e,a),a};return a=o,(...e)=>a(nc(...e))},ac=[],oc=e=>{let t=t=>t[e]||ac;return t.isThemeGetter=!0,t},sc=/^\[(?:(\w[\w-]*):)?(.+)\]$/i,cc=/^\((?:(\w[\w-]*):)?(.+)\)$/i,lc=/^\d+(?:\.\d+)?\/\d+(?:\.\d+)?$/,uc=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,dc=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,fc=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,pc=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,mc=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,hc=e=>lc.test(e),gc=e=>!!e&&!Number.isNaN(Number(e)),_c=e=>!!e&&Number.isInteger(Number(e)),vc=e=>e.endsWith(`%`)&&gc(e.slice(0,-1)),yc=e=>uc.test(e),bc=()=>!0,xc=e=>dc.test(e)&&!fc.test(e),Sc=()=>!1,Cc=e=>pc.test(e),wc=e=>mc.test(e),Tc=e=>!R(e)&&!z(e),Ec=e=>e.startsWith(`@container`)&&(e[10]===`/`&&e[11]!==void 0||e[11]===`s`&&e[16]!==void 0&&e.startsWith(`-size/`,10)||e[11]===`n`&&e[18]!==void 0&&e.startsWith(`-normal/`,10)),Dc=e=>Hc(e,Kc,Sc),R=e=>sc.test(e),Oc=e=>Hc(e,qc,xc),kc=e=>Hc(e,Jc,gc),Ac=e=>Hc(e,Xc,bc),jc=e=>Hc(e,Yc,Sc),Mc=e=>Hc(e,Wc,Sc),Nc=e=>Hc(e,Gc,wc),Pc=e=>Hc(e,Zc,Cc),z=e=>cc.test(e),Fc=e=>Uc(e,qc),Ic=e=>Uc(e,Yc),Lc=e=>Uc(e,Wc),Rc=e=>Uc(e,Kc),zc=e=>Uc(e,Gc),Bc=e=>Uc(e,Zc,!0),Vc=e=>Uc(e,Xc,!0),Hc=(e,t,n)=>{let r=sc.exec(e);return r?r[1]?t(r[1]):n(r[2]):!1},Uc=(e,t,n=!1)=>{let r=cc.exec(e);return r?r[1]?t(r[1]):n:!1},Wc=e=>e===`position`||e===`percentage`,Gc=e=>e===`image`||e===`url`,Kc=e=>e===`length`||e===`size`||e===`bg-size`,qc=e=>e===`length`,Jc=e=>e===`number`,Yc=e=>e===`family-name`,Xc=e=>e===`number`||e===`weight`,Zc=e=>e===`shadow`,Qc=ic(()=>{let e=oc(`color`),t=oc(`font`),n=oc(`text`),r=oc(`font-weight`),i=oc(`tracking`),a=oc(`leading`),o=oc(`breakpoint`),s=oc(`container`),c=oc(`spacing`),l=oc(`radius`),u=oc(`shadow`),d=oc(`inset-shadow`),f=oc(`text-shadow`),p=oc(`drop-shadow`),m=oc(`blur`),h=oc(`perspective`),g=oc(`aspect`),_=oc(`ease`),v=oc(`animate`),y=()=>[`auto`,`avoid`,`all`,`avoid-page`,`page`,`left`,`right`,`column`],b=()=>[`center`,`top`,`bottom`,`left`,`right`,`top-left`,`left-top`,`top-right`,`right-top`,`bottom-right`,`right-bottom`,`bottom-left`,`left-bottom`],x=()=>[...b(),z,R],S=()=>[`auto`,`hidden`,`clip`,`visible`,`scroll`],C=()=>[`auto`,`contain`,`none`],w=()=>[z,R,c],T=()=>[hc,`full`,`auto`,...w()],E=()=>[_c,`none`,`subgrid`,z,R],ee=()=>[`auto`,{span:[`full`,_c,z,R]},_c,z,R],D=()=>[_c,`auto`,z,R],O=()=>[`auto`,`min`,`max`,`fr`,z,R],te=()=>[`start`,`end`,`center`,`between`,`around`,`evenly`,`stretch`,`baseline`,`center-safe`,`end-safe`],ne=()=>[`start`,`end`,`center`,`stretch`,`center-safe`,`end-safe`],re=()=>[`auto`,...w()],k=()=>[hc,`auto`,`full`,`dvw`,`dvh`,`lvw`,`lvh`,`svw`,`svh`,`min`,`max`,`fit`,...w()],A=()=>[hc,`screen`,`full`,`dvw`,`lvw`,`svw`,`min`,`max`,`fit`,...w()],ie=()=>[hc,`screen`,`full`,`lh`,`dvh`,`lvh`,`svh`,`min`,`max`,`fit`,...w()],j=()=>[e,z,R],ae=()=>[...b(),Lc,Mc,{position:[z,R]}],oe=()=>[`no-repeat`,{repeat:[``,`x`,`y`,`space`,`round`]}],se=()=>[`auto`,`cover`,`contain`,Rc,Dc,{size:[z,R]}],ce=()=>[vc,Fc,Oc],M=()=>[``,`none`,`full`,l,z,R],le=()=>[``,gc,Fc,Oc],ue=()=>[`solid`,`dashed`,`dotted`,`double`],N=()=>[`normal`,`multiply`,`screen`,`overlay`,`darken`,`lighten`,`color-dodge`,`color-burn`,`hard-light`,`soft-light`,`difference`,`exclusion`,`hue`,`saturation`,`color`,`luminosity`],de=()=>[gc,vc,Lc,Mc],fe=()=>[``,`none`,m,z,R],pe=()=>[`none`,gc,z,R],me=()=>[`none`,gc,z,R],he=()=>[gc,z,R],ge=()=>[hc,`full`,...w()];return{cacheSize:500,theme:{animate:[`spin`,`ping`,`pulse`,`bounce`],aspect:[`video`],blur:[yc],breakpoint:[yc],color:[bc],container:[yc],"drop-shadow":[yc],ease:[`in`,`out`,`in-out`],font:[Tc],"font-weight":[`thin`,`extralight`,`light`,`normal`,`medium`,`semibold`,`bold`,`extrabold`,`black`],"inset-shadow":[yc],leading:[`none`,`tight`,`snug`,`normal`,`relaxed`,`loose`],perspective:[`dramatic`,`near`,`normal`,`midrange`,`distant`,`none`],radius:[yc],shadow:[yc],spacing:[`px`,gc],text:[yc],"text-shadow":[yc],tracking:[`tighter`,`tight`,`normal`,`wide`,`wider`,`widest`]},classGroups:{aspect:[{aspect:[`auto`,`square`,hc,R,z,g]}],container:[`container`],"container-type":[{"@container":[``,`normal`,`size`,z,R]}],"container-named":[Ec],columns:[{columns:[gc,R,z,s]}],"break-after":[{"break-after":y()}],"break-before":[{"break-before":y()}],"break-inside":[{"break-inside":[`auto`,`avoid`,`avoid-page`,`avoid-column`]}],"box-decoration":[{"box-decoration":[`slice`,`clone`]}],box:[{box:[`border`,`content`]}],display:[`block`,`inline-block`,`inline`,`flex`,`inline-flex`,`table`,`inline-table`,`table-caption`,`table-cell`,`table-column`,`table-column-group`,`table-footer-group`,`table-header-group`,`table-row-group`,`table-row`,`flow-root`,`grid`,`inline-grid`,`contents`,`list-item`,`hidden`],sr:[`sr-only`,`not-sr-only`],float:[{float:[`right`,`left`,`none`,`start`,`end`]}],clear:[{clear:[`left`,`right`,`both`,`none`,`start`,`end`]}],isolation:[`isolate`,`isolation-auto`],"object-fit":[{object:[`contain`,`cover`,`fill`,`none`,`scale-down`]}],"object-position":[{object:x()}],overflow:[{overflow:S()}],"overflow-x":[{"overflow-x":S()}],"overflow-y":[{"overflow-y":S()}],overscroll:[{overscroll:C()}],"overscroll-x":[{"overscroll-x":C()}],"overscroll-y":[{"overscroll-y":C()}],position:[`static`,`fixed`,`absolute`,`relative`,`sticky`],inset:[{inset:T()}],"inset-x":[{"inset-x":T()}],"inset-y":[{"inset-y":T()}],start:[{"inset-s":T(),start:T()}],end:[{"inset-e":T(),end:T()}],"inset-bs":[{"inset-bs":T()}],"inset-be":[{"inset-be":T()}],top:[{top:T()}],right:[{right:T()}],bottom:[{bottom:T()}],left:[{left:T()}],visibility:[`visible`,`invisible`,`collapse`],z:[{z:[_c,`auto`,z,R]}],basis:[{basis:[hc,`full`,`auto`,s,...w()]}],"flex-direction":[{flex:[`row`,`row-reverse`,`col`,`col-reverse`]}],"flex-wrap":[{flex:[`nowrap`,`wrap`,`wrap-reverse`]}],flex:[{flex:[gc,hc,`auto`,`initial`,`none`,R]}],grow:[{grow:[``,gc,z,R]}],shrink:[{shrink:[``,gc,z,R]}],order:[{order:[_c,`first`,`last`,`none`,z,R]}],"grid-cols":[{"grid-cols":E()}],"col-start-end":[{col:ee()}],"col-start":[{"col-start":D()}],"col-end":[{"col-end":D()}],"grid-rows":[{"grid-rows":E()}],"row-start-end":[{row:ee()}],"row-start":[{"row-start":D()}],"row-end":[{"row-end":D()}],"grid-flow":[{"grid-flow":[`row`,`col`,`dense`,`row-dense`,`col-dense`]}],"auto-cols":[{"auto-cols":O()}],"auto-rows":[{"auto-rows":O()}],gap:[{gap:w()}],"gap-x":[{"gap-x":w()}],"gap-y":[{"gap-y":w()}],"justify-content":[{justify:[...te(),`normal`]}],"justify-items":[{"justify-items":[...ne(),`normal`]}],"justify-self":[{"justify-self":[`auto`,...ne()]}],"align-content":[{content:[`normal`,...te()]}],"align-items":[{items:[...ne(),{baseline:[``,`last`]}]}],"align-self":[{self:[`auto`,...ne(),{baseline:[``,`last`]}]}],"place-content":[{"place-content":te()}],"place-items":[{"place-items":[...ne(),`baseline`]}],"place-self":[{"place-self":[`auto`,...ne()]}],p:[{p:w()}],px:[{px:w()}],py:[{py:w()}],ps:[{ps:w()}],pe:[{pe:w()}],pbs:[{pbs:w()}],pbe:[{pbe:w()}],pt:[{pt:w()}],pr:[{pr:w()}],pb:[{pb:w()}],pl:[{pl:w()}],m:[{m:re()}],mx:[{mx:re()}],my:[{my:re()}],ms:[{ms:re()}],me:[{me:re()}],mbs:[{mbs:re()}],mbe:[{mbe:re()}],mt:[{mt:re()}],mr:[{mr:re()}],mb:[{mb:re()}],ml:[{ml:re()}],"space-x":[{"space-x":w()}],"space-x-reverse":[`space-x-reverse`],"space-y":[{"space-y":w()}],"space-y-reverse":[`space-y-reverse`],size:[{size:k()}],"inline-size":[{inline:[`auto`,...A()]}],"min-inline-size":[{"min-inline":[`auto`,...A()]}],"max-inline-size":[{"max-inline":[`none`,...A()]}],"block-size":[{block:[`auto`,...ie()]}],"min-block-size":[{"min-block":[`auto`,...ie()]}],"max-block-size":[{"max-block":[`none`,...ie()]}],w:[{w:[s,`screen`,...k()]}],"min-w":[{"min-w":[s,`screen`,`none`,...k()]}],"max-w":[{"max-w":[s,`screen`,`none`,`prose`,{screen:[o]},...k()]}],h:[{h:[`screen`,`lh`,...k()]}],"min-h":[{"min-h":[`screen`,`lh`,`none`,...k()]}],"max-h":[{"max-h":[`screen`,`lh`,...k()]}],"font-size":[{text:[`base`,n,Fc,Oc]}],"font-smoothing":[`antialiased`,`subpixel-antialiased`],"font-style":[`italic`,`not-italic`],"font-weight":[{font:[r,Vc,Ac]}],"font-stretch":[{"font-stretch":[`ultra-condensed`,`extra-condensed`,`condensed`,`semi-condensed`,`normal`,`semi-expanded`,`expanded`,`extra-expanded`,`ultra-expanded`,vc,R]}],"font-family":[{font:[Ic,jc,t]}],"font-features":[{"font-features":[R]}],"fvn-normal":[`normal-nums`],"fvn-ordinal":[`ordinal`],"fvn-slashed-zero":[`slashed-zero`],"fvn-figure":[`lining-nums`,`oldstyle-nums`],"fvn-spacing":[`proportional-nums`,`tabular-nums`],"fvn-fraction":[`diagonal-fractions`,`stacked-fractions`],tracking:[{tracking:[i,z,R]}],"line-clamp":[{"line-clamp":[gc,`none`,z,kc]}],leading:[{leading:[a,...w()]}],"list-image":[{"list-image":[`none`,z,R]}],"list-style-position":[{list:[`inside`,`outside`]}],"list-style-type":[{list:[`disc`,`decimal`,`none`,z,R]}],"text-alignment":[{text:[`left`,`center`,`right`,`justify`,`start`,`end`]}],"placeholder-color":[{placeholder:j()}],"text-color":[{text:j()}],"text-decoration":[`underline`,`overline`,`line-through`,`no-underline`],"text-decoration-style":[{decoration:[...ue(),`wavy`]}],"text-decoration-thickness":[{decoration:[gc,`from-font`,`auto`,z,Oc]}],"text-decoration-color":[{decoration:j()}],"underline-offset":[{"underline-offset":[gc,`auto`,z,R]}],"text-transform":[`uppercase`,`lowercase`,`capitalize`,`normal-case`],"text-overflow":[`truncate`,`text-ellipsis`,`text-clip`],"text-wrap":[{text:[`wrap`,`nowrap`,`balance`,`pretty`]}],indent:[{indent:w()}],"tab-size":[{tab:[_c,z,R]}],"vertical-align":[{align:[`baseline`,`top`,`middle`,`bottom`,`text-top`,`text-bottom`,`sub`,`super`,z,R]}],whitespace:[{whitespace:[`normal`,`nowrap`,`pre`,`pre-line`,`pre-wrap`,`break-spaces`]}],break:[{break:[`normal`,`words`,`all`,`keep`]}],wrap:[{wrap:[`break-word`,`anywhere`,`normal`]}],hyphens:[{hyphens:[`none`,`manual`,`auto`]}],content:[{content:[`none`,z,R]}],"bg-attachment":[{bg:[`fixed`,`local`,`scroll`]}],"bg-clip":[{"bg-clip":[`border`,`padding`,`content`,`text`]}],"bg-origin":[{"bg-origin":[`border`,`padding`,`content`]}],"bg-position":[{bg:ae()}],"bg-repeat":[{bg:oe()}],"bg-size":[{bg:se()}],"bg-image":[{bg:[`none`,{linear:[{to:[`t`,`tr`,`r`,`br`,`b`,`bl`,`l`,`tl`]},_c,z,R],radial:[``,z,R],conic:[_c,z,R]},zc,Nc]}],"bg-color":[{bg:j()}],"gradient-from-pos":[{from:ce()}],"gradient-via-pos":[{via:ce()}],"gradient-to-pos":[{to:ce()}],"gradient-from":[{from:j()}],"gradient-via":[{via:j()}],"gradient-to":[{to:j()}],rounded:[{rounded:M()}],"rounded-s":[{"rounded-s":M()}],"rounded-e":[{"rounded-e":M()}],"rounded-t":[{"rounded-t":M()}],"rounded-r":[{"rounded-r":M()}],"rounded-b":[{"rounded-b":M()}],"rounded-l":[{"rounded-l":M()}],"rounded-ss":[{"rounded-ss":M()}],"rounded-se":[{"rounded-se":M()}],"rounded-ee":[{"rounded-ee":M()}],"rounded-es":[{"rounded-es":M()}],"rounded-tl":[{"rounded-tl":M()}],"rounded-tr":[{"rounded-tr":M()}],"rounded-br":[{"rounded-br":M()}],"rounded-bl":[{"rounded-bl":M()}],"border-w":[{border:le()}],"border-w-x":[{"border-x":le()}],"border-w-y":[{"border-y":le()}],"border-w-s":[{"border-s":le()}],"border-w-e":[{"border-e":le()}],"border-w-bs":[{"border-bs":le()}],"border-w-be":[{"border-be":le()}],"border-w-t":[{"border-t":le()}],"border-w-r":[{"border-r":le()}],"border-w-b":[{"border-b":le()}],"border-w-l":[{"border-l":le()}],"divide-x":[{"divide-x":le()}],"divide-x-reverse":[`divide-x-reverse`],"divide-y":[{"divide-y":le()}],"divide-y-reverse":[`divide-y-reverse`],"border-style":[{border:[...ue(),`hidden`,`none`]}],"divide-style":[{divide:[...ue(),`hidden`,`none`]}],"border-color":[{border:j()}],"border-color-x":[{"border-x":j()}],"border-color-y":[{"border-y":j()}],"border-color-s":[{"border-s":j()}],"border-color-e":[{"border-e":j()}],"border-color-bs":[{"border-bs":j()}],"border-color-be":[{"border-be":j()}],"border-color-t":[{"border-t":j()}],"border-color-r":[{"border-r":j()}],"border-color-b":[{"border-b":j()}],"border-color-l":[{"border-l":j()}],"divide-color":[{divide:j()}],"outline-style":[{outline:[...ue(),`none`,`hidden`]}],"outline-offset":[{"outline-offset":[gc,z,R]}],"outline-w":[{outline:[``,gc,Fc,Oc]}],"outline-color":[{outline:j()}],shadow:[{shadow:[``,`none`,u,Bc,Pc]}],"shadow-color":[{shadow:j()}],"inset-shadow":[{"inset-shadow":[`none`,d,Bc,Pc]}],"inset-shadow-color":[{"inset-shadow":j()}],"ring-w":[{ring:le()}],"ring-w-inset":[`ring-inset`],"ring-color":[{ring:j()}],"ring-offset-w":[{"ring-offset":[gc,Oc]}],"ring-offset-color":[{"ring-offset":j()}],"inset-ring-w":[{"inset-ring":le()}],"inset-ring-color":[{"inset-ring":j()}],"text-shadow":[{"text-shadow":[`none`,f,Bc,Pc]}],"text-shadow-color":[{"text-shadow":j()}],opacity:[{opacity:[gc,z,R]}],"mix-blend":[{"mix-blend":[...N(),`plus-darker`,`plus-lighter`]}],"bg-blend":[{"bg-blend":N()}],"mask-clip":[{"mask-clip":[`border`,`padding`,`content`,`fill`,`stroke`,`view`]},`mask-no-clip`],"mask-composite":[{mask:[`add`,`subtract`,`intersect`,`exclude`]}],"mask-image-linear-pos":[{"mask-linear":[gc]}],"mask-image-linear-from-pos":[{"mask-linear-from":de()}],"mask-image-linear-to-pos":[{"mask-linear-to":de()}],"mask-image-linear-from-color":[{"mask-linear-from":j()}],"mask-image-linear-to-color":[{"mask-linear-to":j()}],"mask-image-t-from-pos":[{"mask-t-from":de()}],"mask-image-t-to-pos":[{"mask-t-to":de()}],"mask-image-t-from-color":[{"mask-t-from":j()}],"mask-image-t-to-color":[{"mask-t-to":j()}],"mask-image-r-from-pos":[{"mask-r-from":de()}],"mask-image-r-to-pos":[{"mask-r-to":de()}],"mask-image-r-from-color":[{"mask-r-from":j()}],"mask-image-r-to-color":[{"mask-r-to":j()}],"mask-image-b-from-pos":[{"mask-b-from":de()}],"mask-image-b-to-pos":[{"mask-b-to":de()}],"mask-image-b-from-color":[{"mask-b-from":j()}],"mask-image-b-to-color":[{"mask-b-to":j()}],"mask-image-l-from-pos":[{"mask-l-from":de()}],"mask-image-l-to-pos":[{"mask-l-to":de()}],"mask-image-l-from-color":[{"mask-l-from":j()}],"mask-image-l-to-color":[{"mask-l-to":j()}],"mask-image-x-from-pos":[{"mask-x-from":de()}],"mask-image-x-to-pos":[{"mask-x-to":de()}],"mask-image-x-from-color":[{"mask-x-from":j()}],"mask-image-x-to-color":[{"mask-x-to":j()}],"mask-image-y-from-pos":[{"mask-y-from":de()}],"mask-image-y-to-pos":[{"mask-y-to":de()}],"mask-image-y-from-color":[{"mask-y-from":j()}],"mask-image-y-to-color":[{"mask-y-to":j()}],"mask-image-radial":[{"mask-radial":[z,R]}],"mask-image-radial-from-pos":[{"mask-radial-from":de()}],"mask-image-radial-to-pos":[{"mask-radial-to":de()}],"mask-image-radial-from-color":[{"mask-radial-from":j()}],"mask-image-radial-to-color":[{"mask-radial-to":j()}],"mask-image-radial-shape":[{"mask-radial":[`circle`,`ellipse`]}],"mask-image-radial-size":[{"mask-radial":[{closest:[`side`,`corner`],farthest:[`side`,`corner`]}]}],"mask-image-radial-pos":[{"mask-radial-at":b()}],"mask-image-conic-pos":[{"mask-conic":[gc]}],"mask-image-conic-from-pos":[{"mask-conic-from":de()}],"mask-image-conic-to-pos":[{"mask-conic-to":de()}],"mask-image-conic-from-color":[{"mask-conic-from":j()}],"mask-image-conic-to-color":[{"mask-conic-to":j()}],"mask-mode":[{mask:[`alpha`,`luminance`,`match`]}],"mask-origin":[{"mask-origin":[`border`,`padding`,`content`,`fill`,`stroke`,`view`]}],"mask-position":[{mask:ae()}],"mask-repeat":[{mask:oe()}],"mask-size":[{mask:se()}],"mask-type":[{"mask-type":[`alpha`,`luminance`]}],"mask-image":[{mask:[`none`,z,R]}],filter:[{filter:[``,`none`,z,R]}],blur:[{blur:fe()}],brightness:[{brightness:[gc,z,R]}],contrast:[{contrast:[gc,z,R]}],"drop-shadow":[{"drop-shadow":[``,`none`,p,Bc,Pc]}],"drop-shadow-color":[{"drop-shadow":j()}],grayscale:[{grayscale:[``,gc,z,R]}],"hue-rotate":[{"hue-rotate":[gc,z,R]}],invert:[{invert:[``,gc,z,R]}],saturate:[{saturate:[gc,z,R]}],sepia:[{sepia:[``,gc,z,R]}],"backdrop-filter":[{"backdrop-filter":[``,`none`,z,R]}],"backdrop-blur":[{"backdrop-blur":fe()}],"backdrop-brightness":[{"backdrop-brightness":[gc,z,R]}],"backdrop-contrast":[{"backdrop-contrast":[gc,z,R]}],"backdrop-grayscale":[{"backdrop-grayscale":[``,gc,z,R]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[gc,z,R]}],"backdrop-invert":[{"backdrop-invert":[``,gc,z,R]}],"backdrop-opacity":[{"backdrop-opacity":[gc,z,R]}],"backdrop-saturate":[{"backdrop-saturate":[gc,z,R]}],"backdrop-sepia":[{"backdrop-sepia":[``,gc,z,R]}],"border-collapse":[{border:[`collapse`,`separate`]}],"border-spacing":[{"border-spacing":w()}],"border-spacing-x":[{"border-spacing-x":w()}],"border-spacing-y":[{"border-spacing-y":w()}],"table-layout":[{table:[`auto`,`fixed`]}],caption:[{caption:[`top`,`bottom`]}],transition:[{transition:[``,`all`,`colors`,`opacity`,`shadow`,`transform`,`none`,z,R]}],"transition-behavior":[{transition:[`normal`,`discrete`]}],duration:[{duration:[gc,`initial`,z,R]}],ease:[{ease:[`linear`,`initial`,_,z,R]}],delay:[{delay:[gc,z,R]}],animate:[{animate:[`none`,v,z,R]}],backface:[{backface:[`hidden`,`visible`]}],perspective:[{perspective:[h,z,R]}],"perspective-origin":[{"perspective-origin":x()}],rotate:[{rotate:pe()}],"rotate-x":[{"rotate-x":pe()}],"rotate-y":[{"rotate-y":pe()}],"rotate-z":[{"rotate-z":pe()}],scale:[{scale:me()}],"scale-x":[{"scale-x":me()}],"scale-y":[{"scale-y":me()}],"scale-z":[{"scale-z":me()}],"scale-3d":[`scale-3d`],skew:[{skew:he()}],"skew-x":[{"skew-x":he()}],"skew-y":[{"skew-y":he()}],transform:[{transform:[z,R,``,`none`,`gpu`,`cpu`]}],"transform-origin":[{origin:x()}],"transform-style":[{transform:[`3d`,`flat`]}],translate:[{translate:ge()}],"translate-x":[{"translate-x":ge()}],"translate-y":[{"translate-y":ge()}],"translate-z":[{"translate-z":ge()}],"translate-none":[`translate-none`],zoom:[{zoom:[_c,z,R]}],accent:[{accent:j()}],appearance:[{appearance:[`none`,`auto`]}],"caret-color":[{caret:j()}],"color-scheme":[{scheme:[`normal`,`dark`,`light`,`light-dark`,`only-dark`,`only-light`]}],cursor:[{cursor:[`auto`,`default`,`pointer`,`wait`,`text`,`move`,`help`,`not-allowed`,`none`,`context-menu`,`progress`,`cell`,`crosshair`,`vertical-text`,`alias`,`copy`,`no-drop`,`grab`,`grabbing`,`all-scroll`,`col-resize`,`row-resize`,`n-resize`,`e-resize`,`s-resize`,`w-resize`,`ne-resize`,`nw-resize`,`se-resize`,`sw-resize`,`ew-resize`,`ns-resize`,`nesw-resize`,`nwse-resize`,`zoom-in`,`zoom-out`,z,R]}],"field-sizing":[{"field-sizing":[`fixed`,`content`]}],"pointer-events":[{"pointer-events":[`auto`,`none`]}],resize:[{resize:[`none`,``,`y`,`x`]}],"scroll-behavior":[{scroll:[`auto`,`smooth`]}],"scrollbar-thumb-color":[{"scrollbar-thumb":j()}],"scrollbar-track-color":[{"scrollbar-track":j()}],"scrollbar-gutter":[{"scrollbar-gutter":[`auto`,`stable`,`both`]}],"scrollbar-w":[{scrollbar:[`auto`,`thin`,`none`]}],"scroll-m":[{"scroll-m":w()}],"scroll-mx":[{"scroll-mx":w()}],"scroll-my":[{"scroll-my":w()}],"scroll-ms":[{"scroll-ms":w()}],"scroll-me":[{"scroll-me":w()}],"scroll-mbs":[{"scroll-mbs":w()}],"scroll-mbe":[{"scroll-mbe":w()}],"scroll-mt":[{"scroll-mt":w()}],"scroll-mr":[{"scroll-mr":w()}],"scroll-mb":[{"scroll-mb":w()}],"scroll-ml":[{"scroll-ml":w()}],"scroll-p":[{"scroll-p":w()}],"scroll-px":[{"scroll-px":w()}],"scroll-py":[{"scroll-py":w()}],"scroll-ps":[{"scroll-ps":w()}],"scroll-pe":[{"scroll-pe":w()}],"scroll-pbs":[{"scroll-pbs":w()}],"scroll-pbe":[{"scroll-pbe":w()}],"scroll-pt":[{"scroll-pt":w()}],"scroll-pr":[{"scroll-pr":w()}],"scroll-pb":[{"scroll-pb":w()}],"scroll-pl":[{"scroll-pl":w()}],"snap-align":[{snap:[`start`,`end`,`center`,`align-none`]}],"snap-stop":[{snap:[`normal`,`always`]}],"snap-type":[{snap:[`none`,`x`,`y`,`both`]}],"snap-strictness":[{snap:[`mandatory`,`proximity`]}],touch:[{touch:[`auto`,`none`,`manipulation`]}],"touch-x":[{"touch-pan":[`x`,`left`,`right`]}],"touch-y":[{"touch-pan":[`y`,`up`,`down`]}],"touch-pz":[`touch-pinch-zoom`],select:[{select:[`none`,`text`,`all`,`auto`]}],"will-change":[{"will-change":[`auto`,`scroll`,`contents`,`transform`,z,R]}],fill:[{fill:[`none`,...j()]}],"stroke-w":[{stroke:[gc,Fc,Oc,kc]}],stroke:[{stroke:[`none`,...j()]}],"forced-color-adjust":[{"forced-color-adjust":[`auto`,`none`]}]},conflictingClassGroups:{"container-named":[`container-type`],overflow:[`overflow-x`,`overflow-y`],overscroll:[`overscroll-x`,`overscroll-y`],inset:[`inset-x`,`inset-y`,`inset-bs`,`inset-be`,`start`,`end`,`top`,`right`,`bottom`,`left`],"inset-x":[`right`,`left`],"inset-y":[`top`,`bottom`],flex:[`basis`,`grow`,`shrink`],gap:[`gap-x`,`gap-y`],p:[`px`,`py`,`ps`,`pe`,`pbs`,`pbe`,`pt`,`pr`,`pb`,`pl`],px:[`pr`,`pl`],py:[`pt`,`pb`],m:[`mx`,`my`,`ms`,`me`,`mbs`,`mbe`,`mt`,`mr`,`mb`,`ml`],mx:[`mr`,`ml`],my:[`mt`,`mb`],size:[`w`,`h`],"font-size":[`leading`],"fvn-normal":[`fvn-ordinal`,`fvn-slashed-zero`,`fvn-figure`,`fvn-spacing`,`fvn-fraction`],"fvn-ordinal":[`fvn-normal`],"fvn-slashed-zero":[`fvn-normal`],"fvn-figure":[`fvn-normal`],"fvn-spacing":[`fvn-normal`],"fvn-fraction":[`fvn-normal`],"line-clamp":[`display`,`overflow`],rounded:[`rounded-s`,`rounded-e`,`rounded-t`,`rounded-r`,`rounded-b`,`rounded-l`,`rounded-ss`,`rounded-se`,`rounded-ee`,`rounded-es`,`rounded-tl`,`rounded-tr`,`rounded-br`,`rounded-bl`],"rounded-s":[`rounded-ss`,`rounded-es`],"rounded-e":[`rounded-se`,`rounded-ee`],"rounded-t":[`rounded-tl`,`rounded-tr`],"rounded-r":[`rounded-tr`,`rounded-br`],"rounded-b":[`rounded-br`,`rounded-bl`],"rounded-l":[`rounded-tl`,`rounded-bl`],"border-spacing":[`border-spacing-x`,`border-spacing-y`],"border-w":[`border-w-x`,`border-w-y`,`border-w-s`,`border-w-e`,`border-w-bs`,`border-w-be`,`border-w-t`,`border-w-r`,`border-w-b`,`border-w-l`],"border-w-x":[`border-w-r`,`border-w-l`],"border-w-y":[`border-w-t`,`border-w-b`],"border-color":[`border-color-x`,`border-color-y`,`border-color-s`,`border-color-e`,`border-color-bs`,`border-color-be`,`border-color-t`,`border-color-r`,`border-color-b`,`border-color-l`],"border-color-x":[`border-color-r`,`border-color-l`],"border-color-y":[`border-color-t`,`border-color-b`],translate:[`translate-x`,`translate-y`,`translate-none`],"translate-none":[`translate`,`translate-x`,`translate-y`,`translate-z`],"scroll-m":[`scroll-mx`,`scroll-my`,`scroll-ms`,`scroll-me`,`scroll-mbs`,`scroll-mbe`,`scroll-mt`,`scroll-mr`,`scroll-mb`,`scroll-ml`],"scroll-mx":[`scroll-mr`,`scroll-ml`],"scroll-my":[`scroll-mt`,`scroll-mb`],"scroll-p":[`scroll-px`,`scroll-py`,`scroll-ps`,`scroll-pe`,`scroll-pbs`,`scroll-pbe`,`scroll-pt`,`scroll-pr`,`scroll-pb`,`scroll-pl`],"scroll-px":[`scroll-pr`,`scroll-pl`],"scroll-py":[`scroll-pt`,`scroll-pb`],touch:[`touch-x`,`touch-y`,`touch-pz`],"touch-x":[`touch`],"touch-y":[`touch`],"touch-pz":[`touch`]},conflictingClassGroupModifiers:{"font-size":[`leading`]},postfixLookupClassGroups:[`container-type`],orderSensitiveModifiers:[`*`,`**`,`after`,`backdrop`,`before`,`details-content`,`file`,`first-letter`,`first-line`,`marker`,`placeholder`,`selection`]}});function $c(...e){return Qc(ao(e))}var el=new Intl.DateTimeFormat(void 0,{year:`numeric`,month:`long`,day:`numeric`,hour:`2-digit`,minute:`2-digit`,second:`2-digit`});function tl(e){return e?el.format(new Date(e)):`Unknown`}function nl(e){return`${Math.round(e/1024)} GiB`}var rl=[`B`,`KB`,`MB`,`GB`,`TB`];function il(e){if(e===0)return`0 B`;let t=Math.floor(Math.log(e)/Math.log(1024));return`${(e/1024**t).toFixed(2)} ${rl[t]}`}function al(e){return e?.find(e=>e.Key===`Name`)?.Value}var ol=/\/$/;function sl(e){return e.replace(ol,``)}function cl(e){return e&&(e.endsWith(`/`)?e:`${e}/`)}function ll(e,t){return e.startsWith(t)?e:`${t}${e}`}function ul(e,t){return e.startsWith(t)?e.slice(t.length):e}var dl=co(`group/button inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-xs/relaxed font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-[2px] focus-visible:ring-ring/30 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-[2px] aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`,{variants:{variant:{default:`bg-primary text-primary-foreground hover:bg-primary/80`,outline:`border-border hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-input/30`,secondary:`bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground`,ghost:`hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50`,destructive:`bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40`,link:`text-primary underline-offset-4 hover:underline`},size:{default:`h-7 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5`,xs:`h-5 gap-1 rounded-sm px-2 text-[0.625rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-2.5`,sm:`h-6 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3`,lg:`h-8 gap-1 px-2.5 text-xs/relaxed has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-4`,icon:`size-7 [&_svg:not([class*='size-'])]:size-3.5`,"icon-xs":`size-5 rounded-sm [&_svg:not([class*='size-'])]:size-2.5`,"icon-sm":`size-6 [&_svg:not([class*='size-'])]:size-3`,"icon-lg":`size-8 [&_svg:not([class*='size-'])]:size-4`}},defaultVariants:{variant:`default`,size:`default`}});function fl(e){let t=(0,da.c)(12),n,r,i,a;t[0]===e?(n=t[1],r=t[2],i=t[3],a=t[4]):({className:n,variant:i,size:a,...r}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i,t[4]=a);let o=i===void 0?`default`:i,s=a===void 0?`default`:a,c;t[5]!==n||t[6]!==s||t[7]!==o?(c=$c(dl({variant:o,size:s,className:n})),t[5]=n,t[6]=s,t[7]=o,t[8]=c):c=t[8];let l;return t[9]!==r||t[10]!==c?(l=(0,F.jsx)(Es,{className:c,"data-slot":`button`,...r}),t[9]=r,t[10]=c,t[11]=l):l=t[11],l}var pl=function(e){return e.disabled=`data-disabled`,e.valid=`data-valid`,e.invalid=`data-invalid`,e.touched=`data-touched`,e.dirty=`data-dirty`,e.filled=`data-filled`,e.focused=`data-focused`,e}({}),ml={badInput:!1,customError:!1,patternMismatch:!1,rangeOverflow:!1,rangeUnderflow:!1,stepMismatch:!1,tooLong:!1,tooShort:!1,typeMismatch:!1,valid:null,valueMissing:!1},hl={valid:null,touched:!1,dirty:!1,filled:!1,focused:!1},gl={disabled:!1,...hl},_l={valid(e){return e===null?null:e?{[pl.valid]:``}:{[pl.invalid]:``}}},vl=P.createContext({invalid:void 0,name:void 0,validityData:{state:ml,errors:[],error:``,value:``,initialValue:null},setValidityData:Ga,disabled:void 0,touched:hl.touched,setTouched:Ga,dirty:hl.dirty,setDirty:Ga,filled:hl.filled,setFilled:Ga,focused:hl.focused,setFocused:Ga,validate:()=>null,validationMode:`onSubmit`,validationDebounceTime:0,shouldValidateOnChange:()=>!1,state:gl,markedDirtyRef:{current:!1},registerFieldControl:Ga,validation:{getValidationProps:(e=qa)=>e,getInputValidationProps:(e=qa)=>e,inputRef:{current:null},commit:async()=>{}}});function yl(e=!0){let t=P.useContext(vl);if(t.setValidityData===Ga&&!e)throw Error(Na(28));return t}var bl=0;function xl(e,t=`mui`){let[n,r]=P.useState(e),i=e||n;return P.useEffect(()=>{n??(bl+=1,r(`${t}-${bl}`))},[n,t]),i}var Sl=vs.useId;function Cl(e,t){if(Sl!==void 0){let n=Sl();return e??(t?`${t}-${n}`:n)}return xl(e,t)}function wl(e){return Cl(e,`base-ui`)}var Tl=P.createContext({controlId:void 0,registerControlId:Ga,labelId:void 0,setLabelId:Ga,messageIds:[],setMessageIds:Ga,getDescriptionProps:e=>e});function El(){return P.useContext(Tl)}function Dl(e={}){let{id:t,implicit:n=!1,controlRef:r}=e,{controlId:i,registerControlId:a}=El(),o=wl(t),s=n?i:void 0,c=Fa(()=>Symbol(`labelable-control`)),l=P.useRef(!1),u=P.useRef(t!=null),d=hs(()=>{!l.current||a===Ga||(l.current=!1,a(c.current,void 0))});return ys(()=>{if(a===Ga)return;let e;if(n){let n=r?.current;e=qo(n)&&n.closest(`label`)!=null?t??null:s??o}else if(t!=null)u.current=!0,e=t;else if(u.current)e=o;else{d();return}if(e===void 0){d();return}l.current=!0,a(c.current,e)},[t,r,s,a,n,o,c,d]),P.useEffect(()=>d,[d]),i??o}function Ol(e){return e?.ownerDocument||document}var kl=typeof navigator<`u`,Al=zl(),jl=Vl(),Ml=Bl(),Nl=typeof CSS>`u`||!CSS.supports?!1:CSS.supports(`-webkit-backdrop-filter:none`),Pl=Al.platform===`MacIntel`&&Al.maxTouchPoints>1?!0:/iP(hone|ad|od)|iOS/.test(Al.platform);kl&&/firefox/i.test(Ml);var Fl=kl&&/apple/i.test(navigator.vendor);kl&&/Edg/i.test(Ml);var Il=kl&&/android/i.test(jl)||/android/i.test(Ml),Ll=kl&&jl.toLowerCase().startsWith(`mac`)&&!navigator.maxTouchPoints,Rl=Ml.includes(`jsdom/`);function zl(){if(!kl)return{platform:``,maxTouchPoints:-1};let e=navigator.userAgentData;return e?.platform?{platform:e.platform,maxTouchPoints:navigator.maxTouchPoints}:{platform:navigator.platform??``,maxTouchPoints:navigator.maxTouchPoints??-1}}function Bl(){if(!kl)return``;let e=navigator.userAgentData;return e&&Array.isArray(e.brands)?e.brands.map(({brand:e,version:t})=>`${e}/${t}`).join(` `):navigator.userAgent}function Vl(){if(!kl)return``;let e=navigator.userAgentData;return e?.platform?e.platform:navigator.platform??``}var Hl=`data-base-ui-focusable`,Ul=`input:not([type='hidden']):not([disabled]),[contenteditable]:not([contenteditable='false']),textarea:not([disabled])`,Wl=`ArrowLeft`,Gl=`ArrowRight`,Kl=`ArrowUp`,ql=`ArrowDown`;function Jl(e){let t=e.activeElement;for(;t?.shadowRoot?.activeElement!=null;)t=t.shadowRoot.activeElement;return t}function Yl(e,t){if(!e||!t)return!1;let n=t.getRootNode?.();if(e.contains(t))return!0;if(n&&Yo(n)){let n=t;for(;n;){if(e===n)return!0;n=n.parentNode||n.host}}return!1}function Xl(e){return`composedPath`in e?e.composedPath()[0]:e.target}function Zl(e,t){if(!qo(e))return!1;let n=e;if(t.hasElement(n))return!n.hasAttribute(`data-trigger-disabled`);for(let[,e]of t.entries())if(Yl(e,n))return!e.hasAttribute(`data-trigger-disabled`);return!1}function Ql(e,t){if(t==null)return!1;if(`composedPath`in e)return e.composedPath().includes(t);let n=e;return n.target!=null&&t.contains(n.target)}function $l(e){return e.matches(`html,body`)}function eu(e){return Jo(e)&&e.matches(`input:not([type='hidden']):not([disabled]),[contenteditable]:not([contenteditable='false']),textarea:not([disabled])`)}function tu(e){return e?.closest(`button,a[href],[role="button"],select,[tabindex]:not([tabindex="-1"]),${Ul}`)!=null}function nu(e){return e?e.getAttribute(`role`)===`combobox`&&eu(e):!1}function ru(e){if(!e||Rl)return!0;try{return e.matches(`:focus-visible`)}catch{return!0}}function iu(e){return e?e.hasAttribute(`data-base-ui-focusable`)?e:e.querySelector(`[data-base-ui-focusable]`)||e:null}function au(e,t,n=!0){return e.filter(e=>e.parentId===t).flatMap(t=>[...!n||t.context?.open?[t]:[],...au(e,t.id,n)])}function ou(e,t){let n=[],r=e.find(e=>e.id===t)?.parentId;for(;r;){let t=e.find(e=>e.id===r);r=t?.parentId,t&&(n=n.concat(t))}return n}function su(e){e.preventDefault(),e.stopPropagation()}function cu(e){return`nativeEvent`in e}function lu(e){return e.pointerType===``&&e.isTrusted?!0:Il&&e.pointerType?e.type===`click`&&e.buttons===1:e.detail===0&&!e.pointerType}function uu(e){return Rl?!1:!Il&&e.width===0&&e.height===0||Il&&e.width===1&&e.height===1&&e.pressure===0&&e.detail===0&&e.pointerType===`mouse`||e.width<1&&e.height<1&&e.pressure===0&&e.detail===0&&e.pointerType===`touch`}function du(e,t){let n=[`mouse`,`pen`];return t||n.push(``,void 0),n.includes(e)}function fu(e){let t=e.type;return t===`click`||t===`mousedown`||t===`keydown`||t===`keyup`}var pu=[`top`,`right`,`bottom`,`left`],mu=Math.min,hu=Math.max,gu=Math.round,_u=Math.floor,vu=e=>({x:e,y:e}),yu={left:`right`,right:`left`,bottom:`top`,top:`bottom`};function bu(e,t,n){return hu(e,mu(t,n))}function xu(e,t){return typeof e==`function`?e(t):e}function Su(e){return e.split(`-`)[0]}function Cu(e){return e.split(`-`)[1]}function wu(e){return e===`x`?`y`:`x`}function Tu(e){return e===`y`?`height`:`width`}function Eu(e){let t=e[0];return t===`t`||t===`b`?`y`:`x`}function Du(e){return wu(Eu(e))}function Ou(e,t,n){n===void 0&&(n=!1);let r=Cu(e),i=Du(e),a=Tu(i),o=i===`x`?r===(n?`end`:`start`)?`right`:`left`:r===`start`?`bottom`:`top`;return t.reference[a]>t.floating[a]&&(o=Lu(o)),[o,Lu(o)]}function ku(e){let t=Lu(e);return[Au(e),t,Au(t)]}function Au(e){return e.includes(`start`)?e.replace(`start`,`end`):e.replace(`end`,`start`)}var ju=[`left`,`right`],Mu=[`right`,`left`],Nu=[`top`,`bottom`],Pu=[`bottom`,`top`];function Fu(e,t,n){switch(e){case`top`:case`bottom`:return n?t?Mu:ju:t?ju:Mu;case`left`:case`right`:return t?Nu:Pu;default:return[]}}function Iu(e,t,n,r){let i=Cu(e),a=Fu(Su(e),n===`start`,r);return i&&(a=a.map(e=>e+`-`+i),t&&(a=a.concat(a.map(Au)))),a}function Lu(e){let t=Su(e);return yu[t]+e.slice(t.length)}function Ru(e){return{top:0,right:0,bottom:0,left:0,...e}}function zu(e){return typeof e==`number`?{top:e,right:e,bottom:e,left:e}:Ru(e)}function Bu(e){let{x:t,y:n,width:r,height:i}=e;return{width:r,height:i,top:n,left:t,right:t+r,bottom:n+i,x:t,y:n}}function Vu(e,t,n){return Math.floor(e/t)!==n}function Hu(e,t){return t<0||t>=e.length}function Uu(e,t){return Gu(e.current,{disabledIndices:t})}function Wu(e,t){return Gu(e.current,{decrement:!0,startingIndex:e.current.length,disabledIndices:t})}function Gu(e,{startingIndex:t=-1,decrement:n=!1,disabledIndices:r,amount:i=1}={}){let a=t;do a+=n?-i:i;while(a>=0&&a<=e.length-1&&Xu(e,a,r));return a}function Ku(e,{event:t,orientation:n,loopFocus:r,onLoop:i,rtl:a,cols:o,disabledIndices:s,minIndex:c,maxIndex:l,prevIndex:u,stopEvent:d=!1}){let f=u,p;if(t.key===`ArrowUp`?p=`up`:t.key===`ArrowDown`&&(p=`down`),p){let n=[],a=[],m=!1,h=0;{let t=null,r=-1;e.forEach((e,i)=>{if(e==null)return;h+=1;let o=e.closest(`[role="row"]`);o&&(m=!0),(o!==t||r===-1)&&(t=o,r+=1,n[r]=[]),n[r].push(i),a[i]=r})}let g=!1,_=0;if(m)for(let e of n){let t=e.length;t>_&&(_=t),t!==o&&(g=!0)}let v=g&&h{if(!g||u===-1)return;let c=a[u];if(c==null)return;let l=n[c].indexOf(u),d=o===`up`?-1:1;for(let o=c+d,f=0;f=n.length){if(!r||v)return;if(o=o<0?n.length-1:0,i){let e=Math.min(l,n[o].length-1);o=a[i(t,u,n[o][e]??n[o][0])]??o}}let c=n[o];for(let t=Math.min(l,c.length-1);t>=0;--t){let n=c[t];if(!Xu(e,n,s))return n}}},x=t=>{if(!v||u===-1)return;let n=u%y,i=t===`up`?-y:y,a=l-l%y,o=_u(l/y)+1;for(let t=u-n+i,c=0;cl){if(!r)return;t=t<0?a:0}let i=Math.min(t+y-1,l);for(let r=Math.min(t+n,i);r>=t;--r)if(!Xu(e,r,s))return r}};d&&su(t);let S=b(p)??x(p);if(S!==void 0)f=S;else if(u===-1)f=p===`up`?l:c;else if(f=Gu(e,{startingIndex:u,amount:y,decrement:p===`up`,disabledIndices:s}),r){if(p===`up`&&(u-ye?r:r-y,i&&(f=i(t,u,f))}p===`down`&&u+y>l&&(f=Gu(e,{startingIndex:u%y-y,amount:y,disabledIndices:s}),i&&(f=i(t,u,f)))}Hu(e,f)&&(f=u)}if(n===`both`){let n=_u(u/o);t.key===(a?`ArrowLeft`:`ArrowRight`)&&(d&&su(t),u%o===o-1?r&&(f=Gu(e,{startingIndex:u-u%o-1,disabledIndices:s}),i&&(f=i(t,u,f))):(f=Gu(e,{startingIndex:u,disabledIndices:s}),r&&Vu(f,o,n)&&(f=Gu(e,{startingIndex:u-u%o-1,disabledIndices:s}),i&&(f=i(t,u,f)))),Vu(f,o,n)&&(f=u)),t.key===(a?`ArrowRight`:`ArrowLeft`)&&(d&&su(t),u%o===0?r&&(f=Gu(e,{startingIndex:u+(o-u%o),decrement:!0,disabledIndices:s}),i&&(f=i(t,u,f))):(f=Gu(e,{startingIndex:u,decrement:!0,disabledIndices:s}),r&&Vu(f,o,n)&&(f=Gu(e,{startingIndex:u+(o-u%o),decrement:!0,disabledIndices:s}),i&&(f=i(t,u,f)))),Vu(f,o,n)&&(f=u));let c=_u(l/o)===n;Hu(e,f)&&(r&&c?(f=t.key===(a?`ArrowRight`:`ArrowLeft`)?l:Gu(e,{startingIndex:u-u%o-1,disabledIndices:s}),i&&(f=i(t,u,f))):f=u)}return f}function qu(e,t,n){let r=[],i=0;return e.forEach(({width:e,height:a},o)=>{let s=!1;for(n&&(i=0);!s;){let n=[];for(let r=0;rr[e]==null)?(n.forEach(e=>{r[e]=o}),s=!0):i+=1}}),[...r]}function Ju(e,t,n,r,i){if(e===-1)return-1;let a=n.indexOf(e),o=t[e];switch(i){case`tl`:return a;case`tr`:return o?a+o.width-1:a;case`bl`:return o?a+(o.height-1)*r:a;case`br`:return n.lastIndexOf(e);default:return-1}}function Yu(e,t){return t.flatMap((t,n)=>e.includes(t)?[n]:[])}function Xu(e,t,n){if(typeof n==`function`?n(t):n?.includes(t)??!1)return!0;let r=e[t];return r?Qu(r)?!n&&(r.hasAttribute(`disabled`)||r.getAttribute(`aria-disabled`)===`true`):!0:!1}function Zu(e){return e.visibility===`hidden`||e.visibility===`collapse`}function Qu(e,t=e?ss(e):null){return!e||!e.isConnected||!t||Zu(t)?!1:typeof e.checkVisibility==`function`?e.checkVisibility():t.display!==`none`&&t.display!==`contents`}var $u=`a[href],button,input,select,textarea,summary,details,iframe,object,embed,[tabindex],[contenteditable]:not([contenteditable="false"]),audio[controls],video[controls]`;function ed(e){let t=e.assignedSlot;if(t)return t;if(e.parentElement)return e.parentElement;let n=e.getRootNode();return Yo(n)?n.host:null}function td(e){for(let t of Array.from(e.children))if(Uo(t)===`summary`)return t;return null}function nd(e,t){let n=td(t);return!!n&&(e===n||Yl(n,e))}function rd(e){let t=e?Uo(e):``;return e!=null&&e.matches($u)&&(t!==`summary`||e.parentElement!=null&&Uo(e.parentElement)===`details`&&td(e.parentElement)===e)&&(t!==`details`||td(e)==null)&&(t!==`input`||e.type!==`hidden`)}function id(e){if(!rd(e)||!e.isConnected||e.matches(`:disabled`))return!1;for(let t=e;t;t=ed(t)){let n=t!==e,r=Uo(t)===`slot`;if(t.hasAttribute(`inert`)||n&&Uo(t)===`details`&&!t.open&&!nd(e,t)||t.hasAttribute(`hidden`)||!r&&!ad(t,n))return!1}return!0}function ad(e,t){let n=ss(e);return t?n.display!==`none`:Qu(e,n)}function od(e){let t=e.tabIndex;if(t<0){let t=Uo(e);if(t===`details`||t===`audio`||t===`video`||Jo(e)&&e.isContentEditable)return 0}return t}function sd(e){if(Uo(e)!==`input`)return null;let t=e;return t.type===`radio`&&t.name!==``?t:null}function cd(e,t){let n=sd(e);if(!n)return!0;let r=t.find(e=>{let t=sd(e);return t?.name===n.name&&t.form===n.form&&t.checked});return r?r===n:t.find(e=>{let t=sd(e);return t?.name===n.name&&t.form===n.form})===n}function ld(e){if(Jo(e)&&Uo(e)===`slot`){let t=e.assignedElements({flatten:!0});if(t.length>0)return t}return Jo(e)&&e.shadowRoot?Array.from(e.shadowRoot.children):Array.from(e.children)}function ud(e,t){ld(e).forEach(e=>{rd(e)&&t.push(e),ud(e,t)})}function dd(e,t,n){ld(e).forEach(e=>{Jo(e)&&e.matches(t)&&n.push(e),dd(e,t,n)})}function fd(e){return id(e)&&od(e)>=0}function pd(e){let t=[];return ud(e,t),t.filter(id)}function md(e){let t=pd(e);return t.filter(e=>od(e)>=0&&cd(e,t))}function hd(e,t){let n=md(e),r=n.length;if(r===0)return;let i=Jl(Ol(e)),a=n.indexOf(i);return n[a===-1?t===1?0:r-1:a+t]}function gd(e){return hd(Ol(e).body,1)||e}function _d(e){return hd(Ol(e).body,-1)||e}function vd(e,t){let n=t||e.currentTarget,r=e.relatedTarget;return!r||!Yl(n,r)}function yd(e){md(e).forEach(e=>{e.dataset.tabindex=e.getAttribute(`tabindex`)||``,e.setAttribute(`tabindex`,`-1`)})}function bd(e){let t=[];dd(e,`[data-tabindex]`,t),t.forEach(e=>{let t=e.dataset.tabindex;delete e.dataset.tabindex,t?e.setAttribute(`tabindex`,t):e.removeAttribute(`tabindex`)})}var xd=[];function Sd(e){P.useEffect(e,xd)}var Cd=0,wd=class e{static create(){return new e}currentId=Cd;start(e,t){this.clear(),this.currentId=setTimeout(()=>{this.currentId=Cd,t()},e)}isStarted(){return this.currentId!==Cd}clear=()=>{this.currentId!==Cd&&(clearTimeout(this.currentId),this.currentId=Cd)};disposeEffect=()=>this.clear};function Td(){let e=Fa(wd.create).current;return Sd(e.disposeEffect),e}var Ed=null;globalThis.requestAnimationFrame;var Dd=new class{callbacks=[];callbacksCount=0;nextId=1;startId=1;isScheduled=!1;tick=e=>{this.isScheduled=!1;let t=this.callbacks,n=this.callbacksCount;if(this.callbacks=[],this.callbacksCount=0,this.startId=this.nextId,n>0)for(let n=0;n=this.callbacks.length||(this.callbacks[t]=null,--this.callbacksCount)}},Od=class e{static create(){return new e}static request(e){return Dd.request(e)}static cancel(e){return Dd.cancel(e)}currentId=Ed;request(e){this.cancel(),this.currentId=Dd.request(()=>{this.currentId=Ed,e()})}cancel=()=>{this.currentId!==Ed&&(Dd.cancel(this.currentId),this.currentId=Ed)};disposeEffect=()=>this.cancel};function kd(){let e=Fa(Od.create).current;return Sd(e.disposeEffect),e}function Ad(e){return e==null?e:`current`in e?e.current:e}var jd=function(e){return e.startingStyle=`data-starting-style`,e.endingStyle=`data-ending-style`,e}({}),Md={[jd.startingStyle]:``},Nd={[jd.endingStyle]:``},Pd={transitionStatus(e){return e===`starting`?Md:e===`ending`?Nd:null}};function Fd(e,t=!1,n=!0){let r=kd();return hs((i,a=null)=>{r.cancel();let o=Ad(e);if(o==null)return;let s=o,c=()=>{gi.flushSync(i)};if(typeof s.getAnimations!=`function`||globalThis.BASE_UI_ANIMATIONS_DISABLED){i();return}function l(){Promise.all(s.getAnimations().map(e=>e.finished)).then(()=>{a?.aborted||c()}).catch(()=>{if(n){a?.aborted||c();return}let e=s.getAnimations();!a?.aborted&&e.length>0&&e.some(e=>e.pending||e.playState!==`finished`)&&l()})}if(t){let e=jd.startingStyle;if(!s.hasAttribute(e)){r.request(l);return}let t=new MutationObserver(()=>{s.hasAttribute(e)||(t.disconnect(),l())});t.observe(s,{attributes:!0,attributeFilter:[e]}),a?.addEventListener(`abort`,()=>t.disconnect(),{once:!0});return}r.request(l)})}function Id(e){let{enabled:t=!0,open:n,ref:r,onComplete:i}=e,a=hs(i),o=Fd(r,n,!1);P.useEffect(()=>{if(!t)return;let e=new AbortController;return o(a,e.signal),()=>{e.abort()}},[t,n,a,o])}function Ld(e,t=!1,n=!1){let[r,i]=P.useState(e&&t?`idle`:void 0),[a,o]=P.useState(e);return e&&!a&&(o(!0),i(`starting`)),!e&&a&&r!==`ending`&&!n&&i(`ending`),!e&&!a&&r===`ending`&&i(void 0),ys(()=>{if(!e&&a&&r!==`ending`&&n){let e=Od.request(()=>{i(`ending`)});return()=>{Od.cancel(e)}}},[e,a,r,n]),ys(()=>{if(!e||t)return;let n=Od.request(()=>{i(void 0)});return()=>{Od.cancel(n)}},[t,e]),ys(()=>{if(!e||!t)return;e&&a&&r!==`idle`&&i(`starting`);let n=Od.request(()=>{i(`idle`)});return()=>{Od.cancel(n)}},[t,e,a,r]),{mounted:a,setMounted:o,transitionStatus:r}}function Rd({controlled:e,default:t,name:n,state:r=`value`}){let{current:i}=P.useRef(e!==void 0),[a,o]=P.useState(t);return[i?e:a,P.useCallback(e=>{i||o(e)},[])]}function zd(e,t){let{enabled:n=!0,getValue:r,id:i,value:a}=t,{registerFieldControl:o}=yl(),s=P.useRef(null);s.current||=Symbol(),ys(()=>{let t=s.current;if(!(!t||!n))return o(t,{controlRef:e,getValue:r,id:i,value:a}),()=>{o(t,void 0)}},[e,n,r,i,o,a])}var Bd=`none`,Vd=`trigger-press`,Hd=`trigger-hover`,Ud=`trigger-focus`,Wd=`outside-press`,Gd=`item-press`,Kd=`close-press`,qd=`focus-out`,Jd=`escape-key`,Yd=`list-navigation`,Xd=`cancel-open`,Zd=`disabled`,Qd=`imperative-action`,$d=`window-resize`;function ef(e,t,n,r){let i=!1,a=!1,o=r??qa;return{reason:e,event:t??new Event(`base-ui`),cancel(){i=!0},allowPropagation(){a=!0},get isCanceled(){return i},get isPropagationAllowed(){return a},trigger:n,...o}}var tf=P.forwardRef(function(e,t){let{render:n,className:r,id:i,name:a,value:o,disabled:s=!1,onValueChange:c,defaultValue:l,autoFocus:u=!1,style:d,...f}=e,{state:p,name:m,disabled:h,setTouched:g,setDirty:_,validityData:v,setFocused:y,setFilled:b,validationMode:x,validation:S}=yl(),C=h||s,w=m??a,T={...p,disabled:C},{labelId:E}=El(),ee=Dl({id:i});ys(()=>{let e=o!=null;S.inputRef.current?.value||e&&o!==``?b(!0):e&&o===``&&b(!1)},[S.inputRef,b,o]);let D=P.useRef(null);ys(()=>{u&&D.current===Jl(Ol(D.current))&&y(!0)},[u,y]);let[O]=Rd({controlled:o,default:l,name:`FieldControl`,state:`value`}),te=o!==void 0,ne=te?O:void 0,re=hs(()=>S.inputRef.current?.value);return zd(S.inputRef,{id:ee,value:ne,getValue:re}),Za(`input`,e,{ref:[t,D],state:T,props:[{id:ee,disabled:C,name:w,ref:S.inputRef,"aria-labelledby":E,autoFocus:u,...te?{value:ne}:{defaultValue:l},onChange(e){let t=e.currentTarget.value;c?.(t,ef(Bd,e.nativeEvent)),_(t!==v.initialValue),b(t!==``)},onFocus(){y(!0)},onBlur(e){g(!0),y(!1),x===`onBlur`&&S.commit(e.currentTarget.value)},onKeyDown(e){e.currentTarget.tagName===`INPUT`&&e.key===`Enter`&&(g(!0),S.commit(e.currentTarget.value))}},S.getInputValidationProps(),f],stateAttributesMapping:_l})}),nf=P.forwardRef(function(e,t){return(0,F.jsx)(tf,{ref:t,...e})});function rf(e){let t=(0,da.c)(10),n,r,i;t[0]===e?(n=t[1],r=t[2],i=t[3]):({className:n,type:i,...r}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i);let a;t[4]===n?a=t[5]:(a=$c(`h-7 w-full min-w-0 rounded-md border border-input bg-input/20 px-2 py-0.5 text-sm transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-xs/relaxed file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 md:text-xs/relaxed dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40`,n),t[4]=n,t[5]=a);let o;return t[6]!==r||t[7]!==a||t[8]!==i?(o=(0,F.jsx)(nf,{className:a,"data-slot":`input`,type:i,...r}),t[6]=r,t[7]=a,t[8]=i,t[9]=o):o=t[9],o}var af=P.forwardRef(function(e,t){let{className:n,render:r,orientation:i=`horizontal`,style:a,...o}=e;return Za(`div`,e,{state:{orientation:i},ref:t,props:[{role:`separator`,"aria-orientation":i},o]})});function of(e){let t=(0,da.c)(10),n,r,i;t[0]===e?(n=t[1],r=t[2],i=t[3]):({className:n,orientation:i,...r}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i);let a=i===void 0?`horizontal`:i,o;t[4]===n?o=t[5]:(o=$c(`shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px data-[orientation=vertical]:self-stretch`,n),t[4]=n,t[5]=o);let s;return t[6]!==a||t[7]!==r||t[8]!==o?(s=(0,F.jsx)(af,{className:o,"data-slot":`separator`,orientation:a,...r}),t[6]=a,t[7]=r,t[8]=o,t[9]=s):s=t[9],s}var sf=P.createContext(void 0);function cf(e){let t=P.useContext(sf);if(e===!1&&t===void 0)throw Error(Na(27));return t}var lf=function(e){return e.open=`data-open`,e.closed=`data-closed`,e[e.startingStyle=jd.startingStyle]=`startingStyle`,e[e.endingStyle=jd.endingStyle]=`endingStyle`,e.anchorHidden=`data-anchor-hidden`,e.side=`data-side`,e.align=`data-align`,e}({}),uf=function(e){return e.popupOpen=`data-popup-open`,e.pressed=`data-pressed`,e}({}),df={[uf.popupOpen]:``},ff={[uf.popupOpen]:``,[uf.pressed]:``},pf={[lf.open]:``},mf={[lf.closed]:``},hf={[lf.anchorHidden]:``},gf={open(e){return e?df:null}},_f={open(e){return e?ff:null}},vf={open(e){return e?pf:mf},anchorHidden(e){return e?hf:null}},yf={...vf,...Pd},bf=P.forwardRef(function(e,t){let{render:n,className:r,style:i,forceRender:a=!1,...o}=e,{store:s}=cf(),c=s.useState(`open`),l=s.useState(`nested`),u=s.useState(`mounted`);return Za(`div`,e,{state:{open:c,transitionStatus:s.useState(`transitionStatus`)},ref:[s.context.backdropRef,t],stateAttributesMapping:yf,props:[{role:`presentation`,hidden:!u,style:{userSelect:`none`,WebkitUserSelect:`none`}},o],enabled:a||!l})}),xf=P.forwardRef(function(e,t){let{render:n,className:r,disabled:i=!1,nativeButton:a=!0,style:o,...s}=e,{store:c}=cf(),l=c.useState(`open`);function u(e){l&&c.setOpen(!1,ef(Kd,e.nativeEvent))}let{getButtonProps:d,buttonRef:f}=Cs({disabled:i,native:a});return Za(`button`,e,{state:{disabled:i},ref:[t,f],props:[{onClick:u},s,d]})}),Sf=P.forwardRef(function(e,t){let{render:n,className:r,style:i,id:a,...o}=e,{store:s}=cf(),c=wl(a);return s.useSyncedValueWithCleanup(`descriptionElementId`,c),Za(`p`,e,{ref:t,props:[{id:c},o]})});function Cf(e,t){return t!=null&&!du(t)?0:typeof e==`function`?e():e}function wf(e,t,n){let r=Cf(e,n);return typeof r==`number`?r:r?.[t]}function Tf(e){return typeof e==`function`?e():e}function Ef(e,t){return t||e===`click`||e===`mousedown`}var Df=P.createContext({hasProvider:!1,timeoutMs:0,delayRef:{current:0},initialDelayRef:{current:0},timeout:new wd,currentIdRef:{current:null},currentContextRef:{current:null}});function Of(e){let{children:t,delay:n,timeoutMs:r=0}=e,i=P.useRef(n),a=P.useRef(n),o=P.useRef(null),s=P.useRef(null),c=Td();return(0,F.jsx)(Df.Provider,{value:P.useMemo(()=>({hasProvider:!0,delayRef:i,initialDelayRef:a,currentIdRef:o,timeoutMs:r,currentContextRef:s,timeout:c}),[r,c]),children:t})}function kf(e,t={open:!1}){let n=`rootStore`in e?e.rootStore:e,r=n.useState(`floatingId`),{open:i}=t,{currentIdRef:a,delayRef:o,timeoutMs:s,initialDelayRef:c,currentContextRef:l,hasProvider:u,timeout:d}=P.useContext(Df),[f,p]=P.useState(!1);return ys(()=>{function e(){p(!1),l.current?.setIsInstantPhase(!1),a.current=null,l.current=null,o.current=c.current}if(a.current&&!i&&a.current===r){if(p(!1),s){let t=r;return d.start(s,()=>{n.select(`open`)||a.current&&a.current!==t||e()}),()=>{d.clear()}}e()}},[i,r,a,o,s,c,l,d,n]),ys(()=>{if(!i)return;let e=l.current,t=a.current;d.clear(),l.current={onOpenChange:n.setOpen,setIsInstantPhase:p},a.current=r,o.current={open:0,close:wf(c.current,`close`)},t!==null&&t!==r?(p(!0),e?.setIsInstantPhase(!0),e?.onOpenChange(!1,ef(Bd))):(p(!1),e?.setIsInstantPhase(!1))},[i,r,n,a,o,s,c,l,d]),ys(()=>()=>{l.current=null},[l]),P.useMemo(()=>({hasProvider:u,delayRef:o,isInstantPhase:f}),[u,o,f])}function Af(e,t,n,r){return e.addEventListener(t,n,r),()=>{e.removeEventListener(t,n,r)}}function jf(...e){return()=>{for(let t=0;t{t.current=t.next}};return t}var Pf={clipPath:`inset(50%)`,overflow:`hidden`,whiteSpace:`nowrap`,border:0,padding:0,width:1,height:1,margin:-1},Ff={...Pf,position:`fixed`,top:0,left:0},If={...Pf,position:`absolute`},Lf=P.forwardRef(function(e,t){let[n,r]=P.useState();ys(()=>{Fl&&r(`button`)},[]);let i={tabIndex:0,role:n};return(0,F.jsx)(`span`,{...e,ref:t,style:Ff,"aria-hidden":n?void 0:!0,...i,"data-base-ui-focus-guard":``})});function Rf(e){return`data-base-ui-${e}`}var zf=0;function Bf(e,t={}){let{preventScroll:n=!1,cancelPrevious:r=!0,sync:i=!1}=t;r&&cancelAnimationFrame(zf);let a=()=>e?.focus({preventScroll:n});if(i)return a(),Ga;let o=requestAnimationFrame(a);return zf=o,()=>{zf===o&&(cancelAnimationFrame(o),zf=0)}}var Vf={inert:new WeakMap,"aria-hidden":new WeakMap},Hf=`data-base-ui-inert`,Uf={inert:new WeakSet,"aria-hidden":new WeakSet},Wf=new WeakMap,Gf=0;function Kf(e){return Uf[e]}function qf(e){return e?Yo(e)?e.host:qf(e.parentNode):null}var Jf=(e,t)=>t.map(t=>{if(e.contains(t))return t;let n=qf(t);return e.contains(n)?n:null}).filter(e=>e!=null),Yf=e=>{let t=new Set;return e.forEach(e=>{let n=e;for(;n&&!t.has(n);)t.add(n),n=n.parentNode}),t},Xf=(e,t,n)=>{let r=[],i=e=>{!e||n.has(e)||Array.from(e.children).forEach(e=>{Uo(e)!==`script`&&(t.has(e)?i(e):r.push(e))})};return i(e),r};function Zf(e,t,n,r,{mark:i=!0,markerIgnoreElements:a=[]}){let o=r?`inert`:n?`aria-hidden`:null,s=null,c=null,l=Jf(t,e),u=i?Jf(t,a):[],d=new Set(u),f=i?Xf(t,Yf(l),new Set(l)).filter(e=>!d.has(e)):[],p=[],m=[];if(o){let e=Vf[o],n=Kf(o);c=n,s=e;let r=Jf(t,Array.from(t.querySelectorAll(`[aria-live]`))),i=l.concat(r);Xf(t,Yf(i),new Set(i)).forEach(t=>{let r=t.getAttribute(o),i=r!==null&&r!==`false`,a=(e.get(t)||0)+1;e.set(t,a),p.push(t),a===1&&i&&n.add(t),i||t.setAttribute(o,o===`inert`?``:`true`)})}return i&&f.forEach(e=>{let t=(Wf.get(e)||0)+1;Wf.set(e,t),m.push(e),t===1&&e.setAttribute(Hf,``)}),Gf+=1,()=>{s&&p.forEach(e=>{let t=(s.get(e)||0)-1;s.set(e,t),t||(!c?.has(e)&&o&&e.removeAttribute(o),c?.delete(e))}),i&&m.forEach(e=>{let t=(Wf.get(e)||0)-1;Wf.set(e,t),t||e.removeAttribute(Hf)}),--Gf,Gf||(Vf.inert=new WeakMap,Vf[`aria-hidden`]=new WeakMap,Uf.inert=new WeakSet,Uf[`aria-hidden`]=new WeakSet,Wf=new WeakMap)}}function Qf(e,t={}){let{ariaHidden:n=!1,inert:r=!1,mark:i=!0,markerIgnoreElements:a=[]}=t,o=Ol(e[0]).body;return Zf(e,o,n,r,{mark:i,markerIgnoreElements:a})}var $f={style:{transition:`none`}},ep={fallbackAxisSide:`none`},tp={fallbackAxisSide:`end`},np={clipPath:`inset(50%)`,position:`fixed`,top:0,left:0},rp=P.createContext(null),ip=()=>P.useContext(rp),ap=Rf(`portal`);function op(e={}){let{ref:t,container:n,componentProps:r=qa,elementProps:i}=e,a=Cl(),o=ip()?.portalNode,[s,c]=P.useState(null),[l,u]=P.useState(null),d=hs(e=>{e!==null&&u(e)}),f=P.useRef(null);ys(()=>{if(n===null){f.current&&(f.current=null,u(null),c(null));return}if(a==null)return;let e=(n&&(Ko(n)?n:n.current))??o??document.body;if(e==null){f.current&&(f.current=null,u(null),c(null));return}f.current!==e&&(f.current=e,u(null),c(e))},[n,o,a]);let p=Za(`div`,r,{ref:[t,d],props:[{id:a,[ap]:``},i]});return{portalNode:l,portalSubtree:s&&p?gi.createPortal(p,s):null}}var sp=P.forwardRef(function(e,t){let{children:n,container:r,className:i,render:a,renderGuards:o,style:s,...c}=e,{portalNode:l,portalSubtree:u}=op({container:r,ref:t,componentProps:e,elementProps:c}),d=P.useRef(null),f=P.useRef(null),p=P.useRef(null),m=P.useRef(null),[h,g]=P.useState(null),_=P.useRef(!1),v=h?.modal,y=h?.open,b=typeof o==`boolean`?o:!!h&&!h.modal&&h.open&&!!l;P.useEffect(()=>{if(!l||v)return;function e(e){l&&e.relatedTarget&&vd(e)&&(e.type===`focusin`?_.current&&=(bd(l),!1):(yd(l),_.current=!0))}return jf(Af(l,`focusin`,e,!0),Af(l,`focusout`,e,!0))},[l,v]),P.useEffect(()=>{!l||y!==!1||(bd(l),_.current=!1)},[y,l]);let x=P.useMemo(()=>({beforeOutsideRef:d,afterOutsideRef:f,beforeInsideRef:p,afterInsideRef:m,portalNode:l,setFocusManagerState:g}),[l]);return(0,F.jsxs)(P.Fragment,{children:[u,(0,F.jsxs)(rp.Provider,{value:x,children:[b&&l&&(0,F.jsx)(Lf,{"data-type":`outside`,ref:d,onFocus:e=>{vd(e,l)?p.current?.focus():_d(h?h.domReference:null)?.focus()}}),b&&l&&(0,F.jsx)(`span`,{"aria-owns":l.id,style:np}),l&&gi.createPortal(n,l),b&&l&&(0,F.jsx)(Lf,{"data-type":`outside`,ref:f,onFocus:e=>{vd(e,l)?m.current?.focus():(gd(h?h.domReference:null)?.focus(),h?.closeOnFocusOut&&h?.onOpenChange(!1,ef(`focus-out`,e.nativeEvent)))}})]})]})});function cp(){let e=new Map;return{emit(t,n){e.get(t)?.forEach(e=>e(n))},on(t,n){e.has(t)||e.set(t,new Set),e.get(t).add(n)},off(t,n){e.get(t)?.delete(n)}}}var lp=P.createContext(null),up=P.createContext(null),dp=()=>P.useContext(lp)?.id||null,fp=e=>{let t=P.useContext(up);return e??t};function pp(e,t){let n=Wo(Xl(e));return e instanceof n.KeyboardEvent?`keyboard`:e instanceof n.FocusEvent?t||`keyboard`:`pointerType`in e?e.pointerType||`keyboard`:`touches`in e?`touch`:e instanceof n.MouseEvent?t||(e.detail===0?`keyboard`:`mouse`):``}var mp=20,hp=[];function gp(){hp=hp.filter(e=>e.deref()?.isConnected)}function _p(e){gp(),e&&Uo(e)!==`body`&&(hp.push(new WeakRef(e)),hp.length>mp&&(hp=hp.slice(-mp)))}function vp(){return gp(),hp[hp.length-1]?.deref()}function yp(e){return e?fd(e)?e:md(e)[0]||e:null}function bp(e,t){if(e.hasAttribute(`tabindex`)&&!e.hasAttribute(`data-tabindex`)||!t.current.includes(`floating`)&&!e.getAttribute(`role`)?.includes(`dialog`))return;let n=pd(e).filter(e=>{let t=e.getAttribute(`data-tabindex`)||``;return fd(e)||e.hasAttribute(`data-tabindex`)&&!t.startsWith(`-`)}),r=e.getAttribute(`tabindex`);t.current.includes(`floating`)||n.length===0?r!==`0`&&e.setAttribute(`tabindex`,`0`):(r!==`-1`||e.hasAttribute(`data-tabindex`)&&e.getAttribute(`data-tabindex`)!==`-1`)&&(e.setAttribute(`tabindex`,`-1`),e.setAttribute(`data-tabindex`,`-1`))}function xp(e){let{context:t,children:n,disabled:r=!1,initialFocus:i=!0,returnFocus:a=!0,restoreFocus:o=!1,modal:s=!0,closeOnFocusOut:c=!0,openInteractionType:l=``,nextFocusableElement:u,previousFocusableElement:d,beforeContentFocusGuardRef:f,externalTree:p,getInsideElements:m}=e,h=`rootStore`in t?t.rootStore:t,g=h.useState(`open`),_=h.useState(`domReferenceElement`),v=h.useState(`floatingElement`),{events:y,dataRef:b}=h.context,x=hs(()=>b.current.floatingContext?.nodeId),S=i===!1,C=nu(_)&&S,w=P.useRef([`content`]),T=Mf(i),E=Mf(a),ee=Mf(l),D=fp(p),O=ip(),te=P.useRef(!1),ne=P.useRef(!1),re=P.useRef(!1),k=P.useRef(null),A=P.useRef(``),ie=P.useRef(``),j=P.useRef(null),ae=P.useRef(null),oe=Ia(j,f,O?.beforeInsideRef),se=Ia(ae,O?.afterInsideRef),ce=Td(),M=Td(),le=kd(),ue=O!=null,N=iu(v),de=hs((e=N)=>e?md(e):[]),fe=hs(()=>m?.().filter(e=>e!=null)??[]);P.useEffect(()=>{if(r||!s)return;function e(e){e.key===`Tab`&&Yl(N,Jl(Ol(N)))&&de().length===0&&!C&&su(e)}return Af(Ol(N),`keydown`,e)},[r,_,N,s,w,C,de]),P.useEffect(()=>{if(r||!g)return;let e=Ol(N);function t(){re.current=!1}function n(e){let t=Xl(e),n=fe();re.current=!(Yl(v,t)||Yl(_,t)||Yl(O?.portalNode,t)||n.some(e=>e===t||Yl(e,t))),ie.current=e.pointerType||`keyboard`,t?.closest(`[data-base-ui-click-trigger]`)&&(ne.current=!0)}function i(){ie.current=`keyboard`}return jf(Af(e,`pointerdown`,n,!0),Af(e,`pointerup`,t,!0),Af(e,`pointercancel`,t,!0),Af(e,`keydown`,i,!0))},[r,v,_,N,g,O,fe]),P.useEffect(()=>{if(r||!c)return;let e=Ol(N);function t(){ne.current=!0,M.start(0,()=>{ne.current=!1})}function n(e){let t=Xl(e);fd(t)&&(k.current=t)}function i(t){let n=t.relatedTarget,r=t.currentTarget,i=Xl(t);queueMicrotask(()=>{let a=x(),c=h.context.triggerElements,l=fe(),f=n?.hasAttribute(Rf(`focus-guard`))&&[j.current,ae.current,O?.beforeInsideRef.current,O?.afterInsideRef.current,O?.beforeOutsideRef.current,O?.afterOutsideRef.current,Ad(d),Ad(u)].includes(n),p=!(Yl(_,n)||Yl(v,n)||Yl(n,v)||Yl(O?.portalNode,n)||l.some(e=>e===n||Yl(e,n))||n!=null&&c.hasElement(n)||c.hasMatchingElement(e=>Yl(e,n))||f||D&&(au(D.nodesRef.current,a).find(e=>Yl(e.context?.elements.floating,n)||Yl(e.context?.elements.domReference,n))||ou(D.nodesRef.current,a).find(e=>[e.context?.elements.floating,iu(e.context?.elements.floating)].includes(n)||e.context?.elements.domReference===n)));if(r===_&&N&&bp(N,w),o&&r!==_&&!Qu(i)&&Jl(e)===e.body){if(Jo(N)&&(N.focus(),o===`popup`)){le.request(()=>{N.focus()});return}let e=de(),t=k.current,n=(t&&e.includes(t)?t:null)||e[e.length-1]||N;Jo(n)&&n.focus()}if(b.current.insideReactTree){b.current.insideReactTree=!1;return}(C||!s)&&n&&p&&!ne.current&&(C||n!==vp())&&(te.current=!0,h.setOpen(!1,ef(qd,t)))})}function a(){re.current||(b.current.insideReactTree=!0,ce.start(0,()=>{b.current.insideReactTree=!1}))}let l=Jo(_)?_:null;if(!(!v&&!l))return jf(l&&Af(l,`focusout`,i),l&&Af(l,`pointerdown`,t),v&&Af(v,`focusin`,n),v&&Af(v,`focusout`,i),v&&O&&Af(v,`focusout`,a,!0))},[r,_,v,N,s,D,O,h,c,o,de,C,x,w,b,ce,M,le,u,d,fe]),P.useEffect(()=>{if(r||!v||!g)return;let e=Array.from(O?.portalNode?.querySelectorAll(`[${Rf(`portal`)}]`)||[]),t=(D?ou(D.nodesRef.current,x()):[]).find(e=>nu(e.context?.elements.domReference||null))?.context?.elements.domReference,n=Qf([v,...e,j.current,ae.current,O?.beforeOutsideRef.current,O?.afterOutsideRef.current,...fe(),t,Ad(d),Ad(u),C?_:null].filter(e=>e!=null),{ariaHidden:s||C,mark:!1}),i=Qf([v,...e].filter(e=>e!=null));return()=>{i(),n()}},[g,r,_,v,s,w,O,C,D,x,u,d,fe]),ys(()=>{if(!g||r||!Jo(N))return;let e=Jl(Ol(N));queueMicrotask(()=>{let t=T.current,n=typeof t==`function`?t(ee.current||``):t;if(n===void 0||n===!1||Yl(N,e))return;let r=null,i=()=>(r??=de(N),r[0]||N),a;a=n===!0||n===null?i():Ad(n),a||=i(),Bf(a,{preventScroll:a===N})})},[r,g,N,S,de,T,ee]),ys(()=>{if(r||!N)return;let e=Ol(N);_p(Jl(e));function t(e){if(e.open||(A.current=pp(e.nativeEvent,ie.current)),e.reason===`trigger-hover`&&e.nativeEvent.type===`mouseleave`&&(te.current=!0),e.reason===`outside-press`)if(e.nested)te.current=!1;else if(lu(e.nativeEvent)||uu(e.nativeEvent))te.current=!1;else{let e=!1;Ol(N).createElement(`div`).focus({get preventScroll(){return e=!0,!1}}),e?te.current=!1:te.current=!0}}y.on(`openchange`,t);function n(){let e=E.current,t=typeof e==`function`?e(A.current):e;if(t===void 0||t===!1)return null;if(t===null&&(t=!0),typeof t==`boolean`){let e=_||vp();return e&&e.isConnected?e:null}let n=_||vp();return Ad(t)||n||null}return()=>{y.off(`openchange`,t);let r=Jl(e),i=fe(),a=Yl(v,r)||i.some(e=>e===r||Yl(e,r))||D&&au(D.nodesRef.current,x(),!1).some(e=>Yl(e.context?.elements.floating,r)),o=E.current,s=n();queueMicrotask(()=>{let t=yp(s),n=typeof o!=`boolean`;o&&!te.current&&Jo(t)&&(!(!n&&t!==r&&r!==e.body)||a)&&t.focus({preventScroll:!0}),te.current=!1})}},[r,v,N,E,b,y,D,_,x,fe]),ys(()=>{if(!Nl||g||!v)return;let e=Jl(Ol(v));!Jo(e)||!eu(e)||Yl(v,e)&&e.blur()},[g,v]),ys(()=>{if(!(r||!O))return O.setFocusManagerState({modal:s,closeOnFocusOut:c,open:g,onOpenChange:h.setOpen,domReference:_}),()=>{O.setFocusManagerState(null)}},[r,O,s,g,h,c,_]),ys(()=>{if(!(r||!N))return bp(N,w),()=>{queueMicrotask(gp)}},[r,N,w]);let pe=!r&&(s?!C:!0)&&(ue||s);return(0,F.jsxs)(P.Fragment,{children:[pe&&(0,F.jsx)(Lf,{"data-type":`inside`,ref:oe,onFocus:e=>{if(s){let e=de();Bf(e[e.length-1])}else O?.portalNode&&(te.current=!1,vd(e,O.portalNode)?gd(_)?.focus():Ad(d??O.beforeOutsideRef)?.focus())}}),n,pe&&(0,F.jsx)(Lf,{"data-type":`inside`,ref:se,onFocus:e=>{s?Bf(de()[0]):O?.portalNode&&(c&&(te.current=!0),vd(e,O.portalNode)?_d(_)?.focus():Ad(u??O.afterOutsideRef)?.focus())}})]})}function Sp(e,t){let n=null,r=null,i=!1;return{contextElement:e||void 0,getBoundingClientRect(){let a=e?.getBoundingClientRect()||{width:0,height:0,x:0,y:0},o=t.axis===`x`||t.axis===`both`,s=t.axis===`y`||t.axis===`both`,c=[`mouseenter`,`mousemove`].includes(t.dataRef.current.openEvent?.type||``)&&t.pointerType!==`touch`,l=a.width,u=a.height,d=a.x,f=a.y;return n==null&&t.x&&o&&(n=a.x-t.x),r==null&&t.y&&s&&(r=a.y-t.y),d-=n||0,f-=r||0,l=0,u=0,!i||c?(l=t.axis===`y`?a.width:0,u=t.axis===`x`?a.height:0,d=o&&t.x!=null?t.x:d,f=s&&t.y!=null?t.y:f):i&&!c&&(u=t.axis===`x`?a.height:u,l=t.axis===`y`?a.width:l),i=!0,{width:l,height:u,x:d,y:f,top:f,right:d+l,bottom:f+u,left:d}}}}function Cp(e){return e!=null&&e.clientX!=null}function wp(e,t={}){let n=`rootStore`in e?e.rootStore:e,r=n.useState(`open`),i=n.useState(`floatingElement`),a=n.useState(`domReferenceElement`),o=n.context.dataRef,{enabled:s=!0,axis:c=`both`}=t,l=P.useRef(!1),u=P.useRef(null),[d,f]=P.useState(),[p,m]=P.useState([]),h=hs((e,t,r)=>{l.current||o.current.openEvent&&!Cp(o.current.openEvent)||n.set(`positionReference`,Sp(r??a,{x:e,y:t,axis:c,dataRef:o,pointerType:d}))}),g=hs(e=>{r?u.current||m([]):h(e.clientX,e.clientY,e.currentTarget)}),_=du(d)?i:r,v=P.useCallback(()=>{if(!_||!s)return;let e=Wo(i);function t(e){Yl(i,Xl(e))?(u.current?.(),u.current=null):h(e.clientX,e.clientY)}if(!o.current.openEvent||Cp(o.current.openEvent))return u.current=Af(e,`mousemove`,t),()=>{u.current?.(),u.current=null};n.set(`positionReference`,a)},[_,s,i,o,a,n,h]);P.useEffect(()=>v(),[v,p]),P.useEffect(()=>{s&&!i&&(l.current=!1)},[s,i]),P.useEffect(()=>{!s&&r&&(l.current=!0)},[s,r]);let y=P.useMemo(()=>{function e(e){f(e.pointerType)}return{onPointerDown:e,onPointerEnter:e,onMouseMove:g,onMouseEnter:g}},[g]);return P.useMemo(()=>s?{reference:y,trigger:y}:{},[s,y])}var Tp={intentional:`onClick`,sloppy:`onPointerDown`};function Ep(){return!1}function Dp(e){return{escapeKey:typeof e==`boolean`?e:e?.escapeKey??!1,outsidePress:typeof e==`boolean`?e:e?.outsidePress??!0}}function Op(e,t={}){let n=`rootStore`in e?e.rootStore:e,r=n.useState(`open`),i=n.useState(`floatingElement`),{dataRef:a}=n.context,{enabled:o=!0,escapeKey:s=!0,outsidePress:c=!0,outsidePressEvent:l=`sloppy`,referencePress:u=Ep,referencePressEvent:d=`sloppy`,bubbles:f,externalTree:p}=t,m=fp(p),h=hs(typeof c==`function`?c:()=>!1),g=typeof c==`function`?h:c,_=g!==!1,v=hs(()=>l),y=P.useRef(!1),b=P.useRef(!1),x=P.useRef(!1),{escapeKey:S,outsidePress:C}=Dp(f),w=P.useRef(null),T=Td(),E=Td(),ee=hs(()=>{E.clear(),a.current.insideReactTree=!1}),D=P.useRef(!1),O=P.useRef(``),te=hs(u),ne=hs(e=>{if(!r||!o||!s||e.key!==`Escape`||D.current)return;let t=a.current.floatingContext?.nodeId,i=m?au(m.nodesRef.current,t):[];if(!S&&i.length>0){let e=!0;if(i.forEach(t=>{t.context?.open&&!t.context.dataRef.current.__escapeKeyBubbles&&(e=!1)}),!e)return}let c=ef(Jd,cu(e)?e.nativeEvent:e);n.setOpen(!1,c),!S&&!c.isPropagationAllowed&&e.stopPropagation()}),re=hs(()=>{a.current.insideReactTree=!0,E.start(0,ee)});P.useEffect(()=>{if(!r||!o)return;a.current.__escapeKeyBubbles=S,a.current.__outsidePressBubbles=C;let e=new wd,t=new wd;function c(){e.clear(),D.current=!0}function l(){e.start(as()?5:0,()=>{D.current=!1})}function u(){x.current=!0,t.start(0,()=>{x.current=!1})}function d(){y.current=!1,b.current=!1}function f(){let e=O.current,t=e===`pen`||!e?`mouse`:e,n=v(),r=typeof n==`function`?n():n;return typeof r==`string`?r:r[t]}function p(e){let t=f();return t===`intentional`&&e.type!==`click`||t===`sloppy`&&e.type===`click`}function h(e){let t=a.current.floatingContext?.nodeId,r=m&&au(m.nodesRef.current,t).some(t=>Ql(e,t.context?.elements.floating));return Ql(e,n.select(`floatingElement`))||Ql(e,n.select(`domReferenceElement`))||r}function E(e){if(p(e)){ee();return}if(a.current.insideReactTree){ee();return}let r=Xl(e),i=`[${Rf(`inert`)}]`,o=qo(r)?r.getRootNode():null,s=Array.from((Yo(o)?o:Ol(n.select(`floatingElement`))).querySelectorAll(i)),c=n.context.triggerElements;if(r&&(c.hasElement(r)||c.hasMatchingElement(e=>Yl(e,r))))return;let l=qo(r)?r:null;for(;l&&!os(l);){let e=ls(l);if(os(e)||!qo(e))break;l=e}if(s.length&&qo(r)&&!$l(r)&&!Yl(r,n.select(`floatingElement`))&&s.every(e=>!Yl(l,e)))return;if(Jo(r)&&!(`touches`in e)){let t=os(r),n=ss(r),i=/auto|scroll/,a=t||i.test(n.overflowX),o=t||i.test(n.overflowY),s=a&&r.clientWidth>0&&r.scrollWidth>r.clientWidth,c=o&&r.clientHeight>0&&r.scrollHeight>r.clientHeight,l=n.direction===`rtl`,u=c&&(l?e.offsetX<=r.offsetWidth-r.clientWidth:e.offsetX>r.clientWidth),d=s&&e.offsetY>r.clientHeight;if(u||d)return}if(h(e))return;if(f()===`intentional`&&x.current){t.clear(),x.current=!1;return}if(typeof g==`function`&&!g(e))return;let u=a.current.floatingContext?.nodeId,d=m?au(m.nodesRef.current,u):[];if(d.length>0){let e=!0;if(d.forEach(t=>{t.context?.open&&!t.context.dataRef.current.__outsidePressBubbles&&(e=!1)}),!e)return}n.setOpen(!1,ef(Wd,e)),ee()}function te(e){f()!==`sloppy`||e.pointerType===`touch`||!n.select(`open`)||!o||Ql(e,n.select(`floatingElement`))||Ql(e,n.select(`domReferenceElement`))||E(e)}function re(e){if(f()!==`sloppy`||!n.select(`open`)||!o||Ql(e,n.select(`floatingElement`))||Ql(e,n.select(`domReferenceElement`)))return;let t=e.touches[0];t&&(w.current={startTime:Date.now(),startX:t.clientX,startY:t.clientY,dismissOnTouchEnd:!1,dismissOnMouseDown:!0},T.start(1e3,()=>{w.current&&(w.current.dismissOnTouchEnd=!1,w.current.dismissOnMouseDown=!1)}))}function k(e,t){let n=Xl(e);if(!n)return;let r=Af(n,e.type,()=>{t(e),r()})}function A(e){O.current=`touch`,k(e,re)}function ie(e){T.clear(),e.type===`pointerdown`&&(O.current=e.pointerType),!(e.type===`mousedown`&&w.current&&!w.current.dismissOnMouseDown)&&k(e,e=>{e.type===`pointerdown`?te(e):E(e)})}function j(e){if(!y.current)return;let n=b.current;if(d(),f()===`intentional`){if(e.type===`pointercancel`){n&&u();return}if(!h(e)){if(n){u();return}typeof g==`function`&&!g(e)||(t.clear(),x.current=!0,ee())}}}function ae(e){if(f()!==`sloppy`||!w.current||Ql(e,n.select(`floatingElement`))||Ql(e,n.select(`domReferenceElement`)))return;let t=e.touches[0];if(!t)return;let r=Math.abs(t.clientX-w.current.startX),i=Math.abs(t.clientY-w.current.startY),a=Math.sqrt(r*r+i*i);a>5&&(w.current.dismissOnTouchEnd=!0),a>10&&(E(e),T.clear(),w.current=null)}function oe(e){k(e,ae)}function se(e){f()!==`sloppy`||!w.current||Ql(e,n.select(`floatingElement`))||Ql(e,n.select(`domReferenceElement`))||(w.current.dismissOnTouchEnd&&E(e),T.clear(),w.current=null)}function ce(e){k(e,se)}let M=Ol(i),le=jf(s&&jf(Af(M,`keydown`,ne),Af(M,`compositionstart`,c),Af(M,`compositionend`,l)),_&&jf(Af(M,`click`,ie,!0),Af(M,`pointerdown`,ie,!0),Af(M,`pointerup`,j,!0),Af(M,`pointercancel`,j,!0),Af(M,`mousedown`,ie,!0),Af(M,`mouseup`,j,!0),Af(M,`touchstart`,A,!0),Af(M,`touchmove`,oe,!0),Af(M,`touchend`,ce,!0)));return()=>{le(),e.clear(),t.clear(),d(),x.current=!1}},[a,i,s,_,g,r,o,S,C,ne,ee,v,m,n,T]),P.useEffect(ee,[g,ee]);let k=P.useMemo(()=>({onKeyDown:ne,[Tp[d]]:e=>{te()&&n.setOpen(!1,ef(Vd,e.nativeEvent))},...d!==`intentional`&&{onClick(e){te()&&n.setOpen(!1,ef(`trigger-press`,e.nativeEvent))}}}),[ne,n,d,te]),A=hs(e=>{if(!r||!o||e.button!==0)return;let t=Xl(e.nativeEvent);Yl(n.select(`floatingElement`),t)&&(y.current||(y.current=!0,b.current=!1))}),ie=hs(e=>{!r||!o||(e.defaultPrevented||e.nativeEvent.defaultPrevented)&&y.current&&(b.current=!0)}),j=P.useMemo(()=>({onKeyDown:ne,onPointerDown:ie,onMouseDown:ie,onClickCapture:re,onMouseDownCapture(e){re(),A(e)},onPointerDownCapture(e){re(),A(e)},onMouseUpCapture:re,onTouchEndCapture:re,onTouchMoveCapture:re}),[ne,re,A,ie]);return P.useMemo(()=>o?{reference:k,floating:j,trigger:k}:{},[o,k,j])}function kp(e,t,n){let{reference:r,floating:i}=e,a=Eu(t),o=Du(t),s=Tu(o),c=Su(t),l=a===`y`,u=r.x+r.width/2-i.width/2,d=r.y+r.height/2-i.height/2,f=r[s]/2-i[s]/2,p;switch(c){case`top`:p={x:u,y:r.y-i.height};break;case`bottom`:p={x:u,y:r.y+r.height};break;case`right`:p={x:r.x+r.width,y:d};break;case`left`:p={x:r.x-i.width,y:d};break;default:p={x:r.x,y:r.y}}switch(Cu(t)){case`start`:p[o]-=f*(n&&l?-1:1);break;case`end`:p[o]+=f*(n&&l?-1:1);break}return p}async function Ap(e,t){t===void 0&&(t={});let{x:n,y:r,platform:i,rects:a,elements:o,strategy:s}=e,{boundary:c=`clippingAncestors`,rootBoundary:l=`viewport`,elementContext:u=`floating`,altBoundary:d=!1,padding:f=0}=xu(t,e),p=zu(f),m=o[d?u===`floating`?`reference`:`floating`:u],h=Bu(await i.getClippingRect({element:await(i.isElement==null?void 0:i.isElement(m))??!0?m:m.contextElement||await(i.getDocumentElement==null?void 0:i.getDocumentElement(o.floating)),boundary:c,rootBoundary:l,strategy:s})),g=u===`floating`?{x:n,y:r,width:a.floating.width,height:a.floating.height}:a.reference,_=await(i.getOffsetParent==null?void 0:i.getOffsetParent(o.floating)),v=await(i.isElement==null?void 0:i.isElement(_))&&await(i.getScale==null?void 0:i.getScale(_))||{x:1,y:1},y=Bu(i.convertOffsetParentRelativeRectToViewportRelativeRect?await i.convertOffsetParentRelativeRectToViewportRelativeRect({elements:o,rect:g,offsetParent:_,strategy:s}):g);return{top:(h.top-y.top+p.top)/v.y,bottom:(y.bottom-h.bottom+p.bottom)/v.y,left:(h.left-y.left+p.left)/v.x,right:(y.right-h.right+p.right)/v.x}}var jp=50,Mp=async(e,t,n)=>{let{placement:r=`bottom`,strategy:i=`absolute`,middleware:a=[],platform:o}=n,s=o.detectOverflow?o:{...o,detectOverflow:Ap},c=await(o.isRTL==null?void 0:o.isRTL(t)),l=await o.getElementRects({reference:e,floating:t,strategy:i}),{x:u,y:d}=kp(l,r,c),f=r,p=0,m={};for(let n=0;ne<=0)){let e=(i.flip?.index||0)+1,t=S[e];if(t&&(!(u===`alignment`&&_!==Eu(t))||T.every(e=>Eu(e.placement)===_?e.overflows[0]>0:!0)))return{data:{index:e,overflows:T},reset:{placement:t}};let n=T.filter(e=>e.overflows[0]<=0).sort((e,t)=>e.overflows[1]-t.overflows[1])[0]?.placement;if(!n)switch(f){case`bestFit`:{let e=T.filter(e=>{if(x){let t=Eu(e.placement);return t===_||t===`y`}return!0}).map(e=>[e.placement,e.overflows.filter(e=>e>0).reduce((e,t)=>e+t,0)]).sort((e,t)=>e[1]-t[1])[0]?.[0];e&&(n=e);break}case`initialPlacement`:n=o;break}if(r!==n)return{reset:{placement:n}}}return{}}}};function Pp(e,t){return{top:e.top-t.height,right:e.right-t.width,bottom:e.bottom-t.height,left:e.left-t.width}}function Fp(e){return pu.some(t=>e[t]>=0)}var Ip=function(e){return e===void 0&&(e={}),{name:`hide`,options:e,async fn(t){let{rects:n,platform:r}=t,{strategy:i=`referenceHidden`,...a}=xu(e,t);switch(i){case`referenceHidden`:{let e=Pp(await r.detectOverflow(t,{...a,elementContext:`reference`}),n.reference);return{data:{referenceHiddenOffsets:e,referenceHidden:Fp(e)}}}case`escaped`:{let e=Pp(await r.detectOverflow(t,{...a,altBoundary:!0}),n.floating);return{data:{escapedOffsets:e,escaped:Fp(e)}}}default:return{}}}}},Lp=new Set([`left`,`top`]);async function Rp(e,t){let{placement:n,platform:r,elements:i}=e,a=await(r.isRTL==null?void 0:r.isRTL(i.floating)),o=Su(n),s=Cu(n),c=Eu(n)===`y`,l=Lp.has(o)?-1:1,u=a&&c?-1:1,d=xu(t,e),{mainAxis:f,crossAxis:p,alignmentAxis:m}=typeof d==`number`?{mainAxis:d,crossAxis:0,alignmentAxis:null}:{mainAxis:d.mainAxis||0,crossAxis:d.crossAxis||0,alignmentAxis:d.alignmentAxis};return s&&typeof m==`number`&&(p=s===`end`?m*-1:m),c?{x:p*u,y:f*l}:{x:f*l,y:p*u}}var zp=function(e){return e===void 0&&(e=0),{name:`offset`,options:e,async fn(t){var n;let{x:r,y:i,placement:a,middlewareData:o}=t,s=await Rp(t,e);return a===o.offset?.placement&&(n=o.arrow)!=null&&n.alignmentOffset?{}:{x:r+s.x,y:i+s.y,data:{...s,placement:a}}}}},Bp=function(e){return e===void 0&&(e={}),{name:`shift`,options:e,async fn(t){let{x:n,y:r,placement:i,platform:a}=t,{mainAxis:o=!0,crossAxis:s=!1,limiter:c={fn:e=>{let{x:t,y:n}=e;return{x:t,y:n}}},...l}=xu(e,t),u={x:n,y:r},d=await a.detectOverflow(t,l),f=Eu(Su(i)),p=wu(f),m=u[p],h=u[f];if(o){let e=p===`y`?`top`:`left`,t=p===`y`?`bottom`:`right`,n=m+d[e],r=m-d[t];m=bu(n,m,r)}if(s){let e=f===`y`?`top`:`left`,t=f===`y`?`bottom`:`right`,n=h+d[e],r=h-d[t];h=bu(n,h,r)}let g=c.fn({...t,[p]:m,[f]:h});return{...g,data:{x:g.x-n,y:g.y-r,enabled:{[p]:o,[f]:s}}}}}},Vp=function(e){return e===void 0&&(e={}),{options:e,fn(t){let{x:n,y:r,placement:i,rects:a,middlewareData:o}=t,{offset:s=0,mainAxis:c=!0,crossAxis:l=!0}=xu(e,t),u={x:n,y:r},d=Eu(i),f=wu(d),p=u[f],m=u[d],h=xu(s,t),g=typeof h==`number`?{mainAxis:h,crossAxis:0}:{mainAxis:0,crossAxis:0,...h};if(c){let e=f===`y`?`height`:`width`,t=a.reference[f]-a.floating[e]+g.mainAxis,n=a.reference[f]+a.reference[e]-g.mainAxis;pn&&(p=n)}if(l){let e=f===`y`?`width`:`height`,t=Lp.has(Su(i)),n=a.reference[d]-a.floating[e]+(t&&o.offset?.[d]||0)+(t?0:g.crossAxis),r=a.reference[d]+a.reference[e]+(t?0:o.offset?.[d]||0)-(t?g.crossAxis:0);mr&&(m=r)}return{[f]:p,[d]:m}}}},Hp=function(e){return e===void 0&&(e={}),{name:`size`,options:e,async fn(t){var n,r;let{placement:i,rects:a,platform:o,elements:s}=t,{apply:c=()=>{},...l}=xu(e,t),u=await o.detectOverflow(t,l),d=Su(i),f=Cu(i),p=Eu(i)===`y`,{width:m,height:h}=a.floating,g,_;d===`top`||d===`bottom`?(g=d,_=f===(await(o.isRTL==null?void 0:o.isRTL(s.floating))?`start`:`end`)?`left`:`right`):(_=d,g=f===`end`?`top`:`bottom`);let v=h-u.top-u.bottom,y=m-u.left-u.right,b=mu(h-u[g],v),x=mu(m-u[_],y),S=!t.middlewareData.shift,C=b,w=x;if((n=t.middlewareData.shift)!=null&&n.enabled.x&&(w=y),(r=t.middlewareData.shift)!=null&&r.enabled.y&&(C=v),S&&!f){let e=hu(u.left,0),t=hu(u.right,0),n=hu(u.top,0),r=hu(u.bottom,0);p?w=m-2*(e!==0||t!==0?e+t:hu(u.left,u.right)):C=h-2*(n!==0||r!==0?n+r:hu(u.top,u.bottom))}await c({...t,availableWidth:w,availableHeight:C});let T=await o.getDimensions(s.floating);return m!==T.width||h!==T.height?{reset:{rects:!0}}:{}}}};function Up(e){let t=ss(e),n=parseFloat(t.width)||0,r=parseFloat(t.height)||0,i=Jo(e),a=i?e.offsetWidth:n,o=i?e.offsetHeight:r,s=gu(n)!==a||gu(r)!==o;return s&&(n=a,r=o),{width:n,height:r,$:s}}function Wp(e){return qo(e)?e:e.contextElement}function Gp(e){let t=Wp(e);if(!Jo(t))return vu(1);let n=t.getBoundingClientRect(),{width:r,height:i,$:a}=Up(t),o=(a?gu(n.width):n.width)/r,s=(a?gu(n.height):n.height)/i;return(!o||!Number.isFinite(o))&&(o=1),(!s||!Number.isFinite(s))&&(s=1),{x:o,y:s}}var Kp=vu(0);function qp(e){let t=Wo(e);return!as()||!t.visualViewport?Kp:{x:t.visualViewport.offsetLeft,y:t.visualViewport.offsetTop}}function Jp(e,t,n){return t===void 0&&(t=!1),!n||t&&n!==Wo(e)?!1:t}function Yp(e,t,n,r){t===void 0&&(t=!1),n===void 0&&(n=!1);let i=e.getBoundingClientRect(),a=Wp(e),o=vu(1);t&&(r?qo(r)&&(o=Gp(r)):o=Gp(e));let s=Jp(a,n,r)?qp(a):vu(0),c=(i.left+s.x)/o.x,l=(i.top+s.y)/o.y,u=i.width/o.x,d=i.height/o.y;if(a){let e=Wo(a),t=r&&qo(r)?Wo(r):r,n=e,i=fs(n);for(;i&&r&&t!==n;){let e=Gp(i),t=i.getBoundingClientRect(),r=ss(i),a=t.left+(i.clientLeft+parseFloat(r.paddingLeft))*e.x,o=t.top+(i.clientTop+parseFloat(r.paddingTop))*e.y;c*=e.x,l*=e.y,u*=e.x,d*=e.y,c+=a,l+=o,n=Wo(i),i=fs(n)}}return Bu({width:u,height:d,x:c,y:l})}function Xp(e,t){let n=cs(e).scrollLeft;return t?t.left+n:Yp(Go(e)).left+n}function Zp(e,t){let n=e.getBoundingClientRect();return{x:n.left+t.scrollLeft-Xp(e,n),y:n.top+t.scrollTop}}function Qp(e){let{elements:t,rect:n,offsetParent:r,strategy:i}=e,a=i===`fixed`,o=Go(r),s=t?Qo(t.floating):!1;if(r===o||s&&a)return n;let c={scrollLeft:0,scrollTop:0},l=vu(1),u=vu(0),d=Jo(r);if((d||!d&&!a)&&((Uo(r)!==`body`||Xo(o))&&(c=cs(r)),d)){let e=Yp(r);l=Gp(r),u.x=e.x+r.clientLeft,u.y=e.y+r.clientTop}let f=o&&!d&&!a?Zp(o,c):vu(0);return{width:n.width*l.x,height:n.height*l.y,x:n.x*l.x-c.scrollLeft*l.x+u.x+f.x,y:n.y*l.y-c.scrollTop*l.y+u.y+f.y}}function tee(e){return Array.from(e.getClientRects())}function nee(e){let t=Go(e),n=cs(e),r=e.ownerDocument.body,i=hu(t.scrollWidth,t.clientWidth,r.scrollWidth,r.clientWidth),a=hu(t.scrollHeight,t.clientHeight,r.scrollHeight,r.clientHeight),o=-n.scrollLeft+Xp(e),s=-n.scrollTop;return ss(r).direction===`rtl`&&(o+=hu(t.clientWidth,r.clientWidth)-i),{width:i,height:a,x:o,y:s}}var $p=25;function ree(e,t){let n=Wo(e),r=Go(e),i=n.visualViewport,a=r.clientWidth,o=r.clientHeight,s=0,c=0;if(i){a=i.width,o=i.height;let e=as();(!e||e&&t===`fixed`)&&(s=i.offsetLeft,c=i.offsetTop)}let l=Xp(r);if(l<=0){let e=r.ownerDocument,t=e.body,n=getComputedStyle(t),i=e.compatMode===`CSS1Compat`&&parseFloat(n.marginLeft)+parseFloat(n.marginRight)||0,o=Math.abs(r.clientWidth-t.clientWidth-i);o<=$p&&(a-=o)}else l<=$p&&(a+=l);return{width:a,height:o,x:s,y:c}}function iee(e,t){let n=Yp(e,!0,t===`fixed`),r=n.top+e.clientTop,i=n.left+e.clientLeft,a=Jo(e)?Gp(e):vu(1);return{width:e.clientWidth*a.x,height:e.clientHeight*a.y,x:i*a.x,y:r*a.y}}function em(e,t,n){let r;if(t===`viewport`)r=ree(e,n);else if(t===`document`)r=nee(Go(e));else if(qo(t))r=iee(t,n);else{let n=qp(e);r={x:t.x-n.x,y:t.y-n.y,width:t.width,height:t.height}}return Bu(r)}function tm(e,t){let n=ls(e);return n===t||!qo(n)||os(n)?!1:ss(n).position===`fixed`||tm(n,t)}function aee(e,t){let n=t.get(e);if(n)return n;let r=ds(e,[],!1).filter(e=>qo(e)&&Uo(e)!==`body`),i=null,a=ss(e).position===`fixed`,o=a?ls(e):e;for(;qo(o)&&!os(o);){let t=ss(o),n=rs(o);!n&&t.position===`fixed`&&(i=null),(a?!n&&!i:!n&&t.position===`static`&&i&&(i.position===`absolute`||i.position===`fixed`)||Xo(o)&&!n&&tm(e,o))?r=r.filter(e=>e!==o):i=t,o=ls(o)}return t.set(e,r),r}function oee(e){let{element:t,boundary:n,rootBoundary:r,strategy:i}=e,a=[...n===`clippingAncestors`?Qo(t)?[]:aee(t,this._c):[].concat(n),r],o=em(t,a[0],i),s=o.top,c=o.right,l=o.bottom,u=o.left;for(let e=1;e{o(!1,1e-7)},1e3)}n===1&&!om(l,e.getBoundingClientRect())&&o(),y=!1}try{n=new IntersectionObserver(b,{...v,root:i.ownerDocument})}catch{n=new IntersectionObserver(b,v)}n.observe(e)}return o(!0),a}function sm(e,t,n,r){r===void 0&&(r={});let{ancestorScroll:i=!0,ancestorResize:a=!0,elementResize:o=typeof ResizeObserver==`function`,layoutShift:s=typeof IntersectionObserver==`function`,animationFrame:c=!1}=r,l=Wp(e),u=i||a?[...l?ds(l):[],...t?ds(t):[]]:[];u.forEach(e=>{i&&e.addEventListener(`scroll`,n,{passive:!0}),a&&e.addEventListener(`resize`,n)});let d=l&&s?dee(l,n):null,f=-1,p=null;o&&(p=new ResizeObserver(e=>{let[r]=e;r&&r.target===l&&p&&t&&(p.unobserve(t),cancelAnimationFrame(f),f=requestAnimationFrame(()=>{var e;(e=p)==null||e.observe(t)})),n()}),l&&!c&&p.observe(l),t&&p.observe(t));let m,h=c?Yp(e):null;c&&g();function g(){let t=Yp(e);h&&!om(h,t)&&n(),h=t,m=requestAnimationFrame(g)}return n(),()=>{var e;u.forEach(e=>{i&&e.removeEventListener(`scroll`,n),a&&e.removeEventListener(`resize`,n)}),d?.(),(e=p)==null||e.disconnect(),p=null,c&&cancelAnimationFrame(m)}}var fee=zp,cm=Bp,lm=Np,um=Hp,dm=Ip,fm=Vp,pm=(e,t,n)=>{let r=new Map,i={platform:am,...n},a={...i.platform,_c:r};return Mp(e,t,{...i,platform:a})},mm=typeof document<`u`?P.useLayoutEffect:function(){};function hm(e,t){if(e===t)return!0;if(typeof e!=typeof t)return!1;if(typeof e==`function`&&e.toString()===t.toString())return!0;let n,r,i;if(e&&t&&typeof e==`object`){if(Array.isArray(e)){if(n=e.length,n!==t.length)return!1;for(r=n;r--!==0;)if(!hm(e[r],t[r]))return!1;return!0}if(i=Object.keys(e),n=i.length,n!==Object.keys(t).length)return!1;for(r=n;r--!==0;)if(!{}.hasOwnProperty.call(t,i[r]))return!1;for(r=n;r--!==0;){let n=i[r];if(!(n===`_owner`&&e.$$typeof)&&!hm(e[n],t[n]))return!1}return!0}return e!==e&&t!==t}function gm(e){return typeof window>`u`?1:(e.ownerDocument.defaultView||window).devicePixelRatio||1}function _m(e,t){let n=gm(e);return Math.round(t*n)/n}function vm(e){let t=P.useRef(e);return mm(()=>{t.current=e}),t}function pee(e){e===void 0&&(e={});let{placement:t=`bottom`,strategy:n=`absolute`,middleware:r=[],platform:i,elements:{reference:a,floating:o}={},transform:s=!0,whileElementsMounted:c,open:l}=e,[u,d]=P.useState({x:0,y:0,strategy:n,placement:t,middlewareData:{},isPositioned:!1}),[f,p]=P.useState(r);hm(f,r)||p(r);let[m,h]=P.useState(null),[g,_]=P.useState(null),v=P.useCallback(e=>{e!==S.current&&(S.current=e,h(e))},[]),y=P.useCallback(e=>{e!==C.current&&(C.current=e,_(e))},[]),b=a||m,x=o||g,S=P.useRef(null),C=P.useRef(null),w=P.useRef(u),T=c!=null,E=vm(c),ee=vm(i),D=vm(l),O=P.useCallback(()=>{if(!S.current||!C.current)return;let e={placement:t,strategy:n,middleware:f};ee.current&&(e.platform=ee.current),pm(S.current,C.current,e).then(e=>{let t={...e,isPositioned:D.current!==!1};te.current&&!hm(w.current,t)&&(w.current=t,gi.flushSync(()=>{d(t)}))})},[f,t,n,ee,D]);mm(()=>{l===!1&&w.current.isPositioned&&(w.current.isPositioned=!1,d(e=>({...e,isPositioned:!1})))},[l]);let te=P.useRef(!1);mm(()=>(te.current=!0,()=>{te.current=!1}),[]),mm(()=>{if(b&&(S.current=b),x&&(C.current=x),b&&x){if(E.current)return E.current(b,x,O);O()}},[b,x,O,E,T]);let ne=P.useMemo(()=>({reference:S,floating:C,setReference:v,setFloating:y}),[v,y]),re=P.useMemo(()=>({reference:b,floating:x}),[b,x]),k=P.useMemo(()=>{let e={position:n,left:0,top:0};if(!re.floating)return e;let t=_m(re.floating,u.x),r=_m(re.floating,u.y);return s?{...e,transform:`translate(`+t+`px, `+r+`px)`,...gm(re.floating)>=1.5&&{willChange:`transform`}}:{position:n,left:t,top:r}},[n,s,re.floating,u.x,u.y]);return P.useMemo(()=>({...u,update:O,refs:ne,elements:re,floatingStyles:k}),[u,O,ne,re,k])}var mee=(e,t)=>{let n=fee(e);return{name:n.name,fn:n.fn,options:[e,t]}},hee=(e,t)=>{let n=cm(e);return{name:n.name,fn:n.fn,options:[e,t]}},gee=(e,t)=>({fn:fm(e).fn,options:[e,t]}),_ee=(e,t)=>{let n=lm(e);return{name:n.name,fn:n.fn,options:[e,t]}},vee=(e,t)=>{let n=um(e);return{name:n.name,fn:n.fn,options:[e,t]}},yee=(e,t)=>{let n=dm(e);return{name:n.name,fn:n.fn,options:[e,t]}},ym=(e,t,n,r,i,a,...o)=>{if(o.length>0)throw Error(Na(1));let s;if(e&&t&&n&&r&&i&&a)s=(o,s,c,l)=>a(e(o,s,c,l),t(o,s,c,l),n(o,s,c,l),r(o,s,c,l),i(o,s,c,l),s,c,l);else if(e&&t&&n&&r&&i)s=(a,o,s,c)=>i(e(a,o,s,c),t(a,o,s,c),n(a,o,s,c),r(a,o,s,c),o,s,c);else if(e&&t&&n&&r)s=(i,a,o,s)=>r(e(i,a,o,s),t(i,a,o,s),n(i,a,o,s),a,o,s);else if(e&&t&&n)s=(r,i,a,o)=>n(e(r,i,a,o),t(r,i,a,o),i,a,o);else if(e&&t)s=(n,r,i,a)=>t(e(n,r,i,a),r,i,a);else if(e)s=e;else throw Error(`Missing arguments`);return s},bm=[],xm=void 0;function bee(){return xm}function xee(e){bm.push(e)}function Sm(e){let t=(t,n)=>{let r=Fa(Cee).current,i;try{xm=r;for(let e of bm)e.before(r);i=e(t,n);for(let e of bm)e.after(r);r.didInitialize=!0}finally{xm=void 0}return i};return t.displayName=e.displayName||e.name,t}function See(e){return P.forwardRef(Sm(e))}function Cee(){return{didInitialize:!1}}var Cm=ti(),wee=Ua(19)?Eee:Dee;function wm(e,t,n,r,i){return wee(e,t,n,r,i)}function Tee(e,t,n,r,i){let a=P.useCallback(()=>t(e.getSnapshot(),n,r,i),[e,t,n,r,i]);return(0,Cm.useSyncExternalStore)(e.subscribe,a,a)}xee({before(e){e.syncIndex=0,e.didInitialize||(e.syncTick=1,e.syncHooks=[],e.didChangeStore=!0,e.getSnapshot=()=>{let t=!1;for(let n=0;n0&&(e.didChangeStore&&(e.didChangeStore=!1,e.subscribe=t=>{let n=new Set;for(let t of e.syncHooks)n.add(t.store);let r=[];for(let e of n)r.push(e.subscribe(t));return()=>{for(let e of r)e()}}),(0,Cm.useSyncExternalStore)(e.subscribe,e.getSnapshot,e.getSnapshot))}});function Eee(e,t,n,r,i){let a=bee();if(!a)return Tee(e,t,n,r,i);let o=a.syncIndex;a.syncIndex+=1;let s;return a.didInitialize?(s=a.syncHooks[o],(s.store!==e||s.selector!==t||!Object.is(s.a1,n)||!Object.is(s.a2,r)||!Object.is(s.a3,i))&&(s.store!==e&&(a.didChangeStore=!0),s.store=e,s.selector=t,s.a1=n,s.a2=r,s.a3=i,s.didChange=!0)):(s={store:e,selector:t,a1:n,a2:r,a3:i,value:t(e.getSnapshot(),n,r,i),didChange:!1},a.syncHooks.push(s)),s.value}function Dee(e,t,n,r,i){return(0,ri.useSyncExternalStoreWithSelector)(e.subscribe,e.getSnapshot,e.getSnapshot,e=>t(e,n,r,i))}var Tm=class{constructor(e){this.state=e,this.listeners=new Set,this.updateTick=0}subscribe=e=>(this.listeners.add(e),()=>{this.listeners.delete(e)});getSnapshot=()=>this.state;setState(e){if(this.state===e)return;this.state=e,this.updateTick+=1;let t=this.updateTick;for(let n of this.listeners){if(t!==this.updateTick)return;n(e)}}update(e){for(let t in e)if(!Object.is(this.state[t],e[t])){this.setState({...this.state,...e});return}}set(e,t){Object.is(this.state[e],t)||this.setState({...this.state,[e]:t})}notifyAll(){let e={...this.state};this.setState(e)}use(e,t,n,r){return wm(this,e,t,n,r)}},Em=class extends Tm{constructor(e,t={},n){super(e),this.context=t,this.selectors=n}useSyncedValue(e,t){P.useDebugValue(e),ys(()=>{this.state[e]!==t&&this.set(e,t)},[e,t])}useSyncedValueWithCleanup(e,t){let n=this;ys(()=>(n.state[e]!==t&&n.set(e,t),()=>{n.set(e,void 0)}),[n,e,t])}useSyncedValues(e){let t=this;ys(()=>{t.update(e)},[t,...Object.values(e)])}useControlledProp(e,t){P.useDebugValue(e);let n=t!==void 0;ys(()=>{n&&!Object.is(this.state[e],t)&&super.setState({...this.state,[e]:t})},[e,t,n])}select(e,t,n,r){let i=this.selectors[e];return i(this.state,t,n,r)}useState(e,t,n,r){return P.useDebugValue(e),wm(this,this.selectors[e],t,n,r)}useContextCallback(e,t){P.useDebugValue(e);let n=hs(t??Ga);this.context[e]=n}useStateSetter(e){let t=P.useRef(void 0);return t.current===void 0&&(t.current=t=>{this.set(e,t)}),t.current}observe(e,t){let n;n=typeof e==`function`?e:this.selectors[e];let r=n(this.state);return t(r,r,this),this.subscribe(e=>{let i=n(e);if(!Object.is(r,i)){let e=r;r=i,t(i,e,this)}})}},Oee={open:ym(e=>e.open),transitionStatus:ym(e=>e.transitionStatus),domReferenceElement:ym(e=>e.domReferenceElement),referenceElement:ym(e=>e.positionReference??e.referenceElement),floatingElement:ym(e=>e.floatingElement),floatingId:ym(e=>e.floatingId)},Dm=class extends Em{constructor(e){let{syncOnly:t,nested:n,onOpenChange:r,triggerElements:i,...a}=e;super({...a,positionReference:a.referenceElement,domReferenceElement:a.referenceElement},{onOpenChange:r,dataRef:{current:{}},events:cp(),nested:n,triggerElements:i},Oee),this.syncOnly=t}syncOpenEvent=(e,t)=>{(!e||!this.state.open||t!=null&&fu(t))&&(this.context.dataRef.current.openEvent=e?t:void 0)};dispatchOpenChange=(e,t)=>{this.syncOpenEvent(e,t.event);let n={open:e,reason:t.reason,nativeEvent:t.event,nested:this.context.nested,triggerElement:t.trigger};this.context.events.emit(`openchange`,n)};setOpen=(e,t)=>{if(this.syncOnly){this.context.onOpenChange?.(e,t);return}this.dispatchOpenChange(e,t),this.context.onOpenChange?.(e,t)}};function kee(e,t){let n=P.useRef(null),r=P.useRef(null);return P.useCallback(i=>{if(e!==void 0){if(n.current!==null){let e=n.current,i=r.current,a=t.context.triggerElements.getById(e);i&&a===i&&t.context.triggerElements.delete(e),n.current=null,r.current=null}i!==null&&(n.current=e,r.current=i,t.context.triggerElements.add(e,i))}},[t,e])}function Aee(e,t,n,r){let i=n.useState(`isMountedByTrigger`,e),a=kee(e,n),o=hs(t=>{if(a(t),!t||!n.select(`open`))return;let i=n.select(`activeTriggerId`);if(i===e){n.update({activeTriggerElement:t,...r});return}i??n.update({activeTriggerId:e,activeTriggerElement:t,...r})});return ys(()=>{i&&n.update({activeTriggerElement:t.current,...r})},[i,n,t,...Object.values(r)]),{registerTrigger:o,isMountedByThisTrigger:i}}function Om(e){let t=e.useState(`open`);ys(()=>{if(t&&!e.select(`activeTriggerId`)&&e.context.triggerElements.size===1){let t=e.context.triggerElements.entries().next();if(!t.done){let[n,r]=t.value;e.update({activeTriggerId:n,activeTriggerElement:r})}}},[t,e])}function km(e,t,n){let{mounted:r,setMounted:i,transitionStatus:a}=Ld(e);t.useSyncedValues({mounted:r,transitionStatus:a});let o=hs(()=>{i(!1),t.update({activeTriggerId:null,activeTriggerElement:null,mounted:!1}),n?.(),t.context.onOpenChangeComplete?.(!1)});return Id({enabled:!t.useState(`preventUnmountingOnClose`),open:e,ref:t.context.popupRef,onComplete(){e||o()}}),{forceUnmount:o,transitionStatus:a}}var Am=class{constructor(){this.elementsSet=new Set,this.idMap=new Map}add(e,t){let n=this.idMap.get(e);n!==t&&(n!==void 0&&this.elementsSet.delete(n),this.elementsSet.add(t),this.idMap.set(e,t))}delete(e){let t=this.idMap.get(e);t&&(this.elementsSet.delete(t),this.idMap.delete(e))}hasElement(e){return this.elementsSet.has(e)}hasMatchingElement(e){for(let t of this.elementsSet)if(e(t))return!0;return!1}getById(e){return this.idMap.get(e)}entries(){return this.idMap.entries()}elements(){return this.elementsSet.values()}get size(){return this.idMap.size}};function jee(){return new Dm({open:!1,transitionStatus:void 0,floatingElement:null,referenceElement:null,triggerElements:new Am,floatingId:``,syncOnly:!1,nested:!1,onOpenChange:void 0})}function jm(){return{open:!1,openProp:void 0,mounted:!1,transitionStatus:void 0,floatingRootContext:jee(),preventUnmountingOnClose:!1,payload:void 0,activeTriggerId:null,activeTriggerElement:null,triggerIdProp:void 0,popupElement:null,positionerElement:null,activeTriggerProps:qa,inactiveTriggerProps:qa,popupProps:qa}}var Mm=ym(e=>e.triggerIdProp??e.activeTriggerId),Nm={open:ym(e=>e.openProp??e.open),mounted:ym(e=>e.mounted),transitionStatus:ym(e=>e.transitionStatus),floatingRootContext:ym(e=>e.floatingRootContext),preventUnmountingOnClose:ym(e=>e.preventUnmountingOnClose),payload:ym(e=>e.payload),activeTriggerId:Mm,activeTriggerElement:ym(e=>e.mounted?e.activeTriggerElement:null),isTriggerActive:ym((e,t)=>t!==void 0&&Mm(e)===t),isOpenedByTrigger:ym((e,t)=>t!==void 0&&Mm(e)===t&&e.open),isMountedByTrigger:ym((e,t)=>t!==void 0&&Mm(e)===t&&e.mounted),triggerProps:ym((e,t)=>t?e.activeTriggerProps:e.inactiveTriggerProps),popupProps:ym(e=>e.popupProps),popupElement:ym(e=>e.popupElement),positionerElement:ym(e=>e.positionerElement)};function Pm(e){let{open:t=!1,onOpenChange:n,elements:r={}}=e,i=Cl(),a=dp()!=null,o=Fa(()=>new Dm({open:t,transitionStatus:void 0,onOpenChange:n,referenceElement:r.reference??null,floatingElement:r.floating??null,triggerElements:new Am,floatingId:i,syncOnly:!1,nested:a})).current;return ys(()=>{let e={open:t,floatingId:i};r.reference!==void 0&&(e.referenceElement=r.reference,e.domReferenceElement=qo(r.reference)?r.reference:null),r.floating!==void 0&&(e.floatingElement=r.floating),o.update(e)},[t,i,r.reference,r.floating,o]),o.context.onOpenChange=n,o.context.nested=a,o}function Mee(e={}){let{nodeId:t,externalTree:n}=e,r=Pm(e),i=e.rootContext||r,a={reference:i.useState(`referenceElement`),floating:i.useState(`floatingElement`),domReference:i.useState(`domReferenceElement`)},[o,s]=P.useState(null),c=P.useRef(null),l=fp(n);ys(()=>{a.domReference&&(c.current=a.domReference)},[a.domReference]);let u=pee({...e,elements:{...a,...o&&{reference:o}}}),d=P.useCallback(e=>{let t=qo(e)?{getBoundingClientRect:()=>e.getBoundingClientRect(),getClientRects:()=>e.getClientRects(),contextElement:e}:e;s(t),u.refs.setReference(t)},[u.refs]),[f,p]=P.useState(void 0),[m,h]=P.useState(null);i.useSyncedValue(`referenceElement`,f??null);let g=qo(f)?f:null;i.useSyncedValue(`domReferenceElement`,f===void 0?a.domReference:g),i.useSyncedValue(`floatingElement`,m);let _=P.useCallback(e=>{(qo(e)||e===null)&&(c.current=e,p(e)),(qo(u.refs.reference.current)||u.refs.reference.current===null||e!==null&&!qo(e))&&u.refs.setReference(e)},[u.refs,p]),v=P.useCallback(e=>{h(e),u.refs.setFloating(e)},[u.refs]),y=P.useMemo(()=>({...u.refs,setReference:_,setFloating:v,setPositionReference:d,domReference:c}),[u.refs,_,v,d]),b=P.useMemo(()=>({...u.elements,domReference:a.domReference}),[u.elements,a.domReference]),x=i.useState(`open`),S=i.useState(`floatingId`),C=P.useMemo(()=>({...u,dataRef:i.context.dataRef,open:x,onOpenChange:i.setOpen,events:i.context.events,floatingId:S,refs:y,elements:b,nodeId:t,rootStore:i}),[u,y,b,t,i,x,S]);return ys(()=>{i.context.dataRef.current.floatingContext=C;let e=l?.nodesRef.current.find(e=>e.id===t);e&&(e.context=C)}),P.useMemo(()=>({...u,context:C,refs:y,elements:b,rootStore:i}),[u,y,b,C,i])}function Fm(e){let{popupStore:t,treatPopupAsFloatingElement:n=!1,onOpenChange:r}=e,i=Cl(),a=dp()!=null,o=t.useState(`open`),s=t.useState(`activeTriggerElement`),c=t.useState(n?`popupElement`:`positionerElement`),l=t.context.triggerElements,u=Fa(()=>new Dm({open:o,transitionStatus:void 0,referenceElement:s,floatingElement:c,triggerElements:l,onOpenChange:r,floatingId:i,syncOnly:!0,nested:a})).current;return ys(()=>{let e={open:o,floatingId:i,referenceElement:s,floatingElement:c};qo(s)&&(e.domReferenceElement=s),u.state.positionReference===u.state.referenceElement&&(e.positionReference=s),u.update(e)},[o,i,s,c,u]),u.context.onOpenChange=r,u.context.nested=a,u}var Im=Ll&&Fl;function Nee(e,t={}){let n=`rootStore`in e?e.rootStore:e,{events:r,dataRef:i}=n.context,{enabled:a=!0,delay:o}=t,s=P.useRef(!1),c=P.useRef(null),l=Td(),u=P.useRef(!0);P.useEffect(()=>{let e=n.select(`domReferenceElement`);if(!a)return;let t=Wo(e);function r(){let e=n.select(`domReferenceElement`);!n.select(`open`)&&Jo(e)&&e===Jl(Ol(e))&&(s.current=!0)}function i(){u.current=!0}function o(){u.current=!1}return jf(Af(t,`blur`,r),Im&&Af(t,`keydown`,i,!0),Im&&Af(t,`pointerdown`,o,!0))},[n,a]),P.useEffect(()=>{if(!a)return;function e(e){if(e.reason===`trigger-press`||e.reason===`escape-key`){let e=n.select(`domReferenceElement`);qo(e)&&(c.current=e,s.current=!0)}}return r.on(`openchange`,e),()=>{r.off(`openchange`,e)}},[r,a,n]);let d=P.useMemo(()=>({onMouseLeave(){s.current=!1,c.current=null},onFocus(e){let t=e.currentTarget;if(s.current){if(c.current===t)return;s.current=!1,c.current=null}let r=Xl(e.nativeEvent);if(qo(r)){if(Im&&!e.relatedTarget){if(!u.current&&!eu(r))return}else if(!ru(r))return}let i=Zl(e.relatedTarget,n.context.triggerElements),{nativeEvent:a,currentTarget:d}=e,f=typeof o==`function`?o():o;if(n.select(`open`)&&i||f===0||f===void 0){n.setOpen(!0,ef(Ud,a,d));return}l.start(f,()=>{s.current||n.setOpen(!0,ef(Ud,a,d))})},onBlur(e){s.current=!1,c.current=null;let t=e.relatedTarget,r=e.nativeEvent,a=qo(t)&&t.hasAttribute(Rf(`focus-guard`))&&t.getAttribute(`data-type`)===`outside`;l.start(0,()=>{let e=n.select(`domReferenceElement`),o=Jl(Ol(e));!t&&o===e||Yl(i.current.floatingContext?.refs.floating.current,o)||Yl(e,o)||a||Zl(t??o,n.context.triggerElements)||n.setOpen(!1,ef(Ud,r))})}}),[i,n,l,o]);return P.useMemo(()=>a?{reference:d,trigger:d}:{},[a,d])}var Pee=class e{constructor(){this.pointerType=void 0,this.interactedInside=!1,this.handler=void 0,this.blockMouseMove=!0,this.performedPointerEventsMutation=!1,this.pointerEventsScopeElement=null,this.pointerEventsReferenceElement=null,this.pointerEventsFloatingElement=null,this.restTimeoutPending=!1,this.openChangeTimeout=new wd,this.restTimeout=new wd,this.handleCloseOptions=void 0}static create(){return new e}dispose=()=>{this.openChangeTimeout.clear(),this.restTimeout.clear()};disposeEffect=()=>this.dispose},Lm=new WeakMap;function Rm(e){if(!e.performedPointerEventsMutation)return;let t=e.pointerEventsScopeElement;t&&Lm.get(t)===e&&(e.pointerEventsScopeElement?.style.removeProperty(`pointer-events`),e.pointerEventsReferenceElement?.style.removeProperty(`pointer-events`),e.pointerEventsFloatingElement?.style.removeProperty(`pointer-events`),Lm.delete(t)),e.performedPointerEventsMutation=!1,e.pointerEventsScopeElement=null,e.pointerEventsReferenceElement=null,e.pointerEventsFloatingElement=null}function zm(e,t){let{scopeElement:n,referenceElement:r,floatingElement:i}=t,a=Lm.get(n);a&&a!==e&&Rm(a),Rm(e),e.performedPointerEventsMutation=!0,e.pointerEventsScopeElement=n,e.pointerEventsReferenceElement=r,e.pointerEventsFloatingElement=i,Lm.set(n,e),n.style.pointerEvents=`none`,r.style.pointerEvents=`auto`,i.style.pointerEvents=`auto`}function Bm(e){let t=Fa(Pee.create).current,n=e.context.dataRef.current;return n.hoverInteractionState||=t,Sd(n.hoverInteractionState.disposeEffect),n.hoverInteractionState}function Fee(e,t={}){let n=`rootStore`in e?e.rootStore:e,r=n.useState(`open`),i=n.useState(`floatingElement`),a=n.useState(`domReferenceElement`),{dataRef:o}=n.context,{enabled:s=!0,closeDelay:c=0,nodeId:l}=t,u=Bm(n),d=fp(),f=dp(),p=hs(()=>Ef(o.current.openEvent?.type,u.interactedInside)),m=hs(()=>{let e=o.current.openEvent?.type;return e?.includes(`mouse`)&&e!==`mousedown`}),h=hs(e=>Zl(e,n.context.triggerElements)),g=P.useCallback(e=>{let t=wf(c,`close`,u.pointerType),r=()=>{n.setOpen(!1,ef(Hd,e)),d?.events.emit(`floating.closed`,e)};t?u.openChangeTimeout.start(t,r):(u.openChangeTimeout.clear(),r())},[c,n,u,d]),_=hs(()=>{Rm(u)}),v=hs(e=>{let t=Xl(e);if(!tu(t)){u.interactedInside=!1;return}u.interactedInside=t?.closest(`[aria-haspopup]`)!=null});ys(()=>{r||(u.pointerType=void 0,u.restTimeoutPending=!1,u.interactedInside=!1,_())},[r,u,_]),P.useEffect(()=>_,[_]),ys(()=>{if(s&&r&&u.handleCloseOptions?.blockPointerEvents&&m()&&qo(a)&&i){let e=a,t=i,n=Ol(i),r=d?.nodesRef.current.find(e=>e.id===f)?.context?.elements.floating;return r&&(r.style.pointerEvents=``),zm(u,{scopeElement:u.handleCloseOptions?.getScope?.()??u.pointerEventsScopeElement??r??e.closest(`[data-rootownerid]`)??n.body,referenceElement:e,floatingElement:t}),()=>{_()}}},[s,r,a,i,u,m,d,f,_]);let y=Td();P.useEffect(()=>{if(!s)return;function e(){u.openChangeTimeout.clear(),y.clear(),d?.events.off(`floating.closed`,r),_()}function t(e){if(d&&f&&au(d.nodesRef.current,f).length>0){d.events.on(`floating.closed`,r);return}if(h(e.relatedTarget))return;let t=o.current.floatingContext?.nodeId??l,n=e.relatedTarget;if(!(d&&t&&qo(n)&&au(d.nodesRef.current,t,!1).some(e=>Yl(e.context?.elements.floating,n)))){if(u.handler){u.handler(e);return}_(),p()||g(e)}}function r(e){!d||!f||au(d.nodesRef.current,f).length>0||y.start(0,()=>{d.events.off(`floating.closed`,r),n.setOpen(!1,ef(Hd,e)),d.events.emit(`floating.closed`,e)})}let a=i;return jf(a&&Af(a,`mouseenter`,e),a&&Af(a,`mouseleave`,t),a&&Af(a,`pointerdown`,v,!0),()=>{d?.events.off(`floating.closed`,r)})},[s,i,n,o,l,p,h,g,_,v,u,d,f,y])}var Iee={current:null};function Lee(e,t={}){let n=`rootStore`in e?e.rootStore:e,{dataRef:r,events:i}=n.context,{enabled:a=!0,delay:o=0,handleClose:s=null,mouseOnly:c=!1,restMs:l=0,move:u=!0,triggerElementRef:d=Iee,externalTree:f,isActiveTrigger:p=!0,getHandleCloseContext:m,isClosing:h}=t,g=fp(f),_=Bm(n),v=P.useRef(!1),y=Mf(s),b=Mf(o),x=Mf(l),S=Mf(a),C=Mf(h);p&&(_.handleCloseOptions=y.current?.__options);let w=hs(()=>Ef(r.current.openEvent?.type,_.interactedInside)),T=hs(e=>Zl(e,n.context.triggerElements)),E=hs((e,t,r)=>{let i=n.context.triggerElements;if(i.hasElement(t))return!e||!Yl(e,t);if(!qo(r))return!1;let a=r;return i.hasMatchingElement(e=>Yl(e,a))&&(!e||!Yl(e,a))}),ee=hs((e,t=!0)=>{let r=wf(b.current,`close`,_.pointerType);r?_.openChangeTimeout.start(r,()=>{n.setOpen(!1,ef(Hd,e)),g?.events.emit(`floating.closed`,e)}):t&&(_.openChangeTimeout.clear(),n.setOpen(!1,ef(Hd,e)),g?.events.emit(`floating.closed`,e))}),D=hs(()=>{_.handler&&=(Ol(n.select(`domReferenceElement`)).removeEventListener(`mousemove`,_.handler),void 0)}),O=hs(()=>{Rm(_)});return P.useEffect(()=>D,[D]),P.useEffect(()=>{if(!a)return;function e(e){e.open?v.current=!1:(v.current=e.reason===Hd,D(),_.openChangeTimeout.clear(),_.restTimeout.clear(),_.blockMouseMove=!0,_.restTimeoutPending=!1)}return i.on(`openchange`,e),()=>{i.off(`openchange`,e)}},[a,i,_,D]),P.useEffect(()=>{if(!a)return;let e=d.current??(p?n.select(`domReferenceElement`):null);if(!qo(e))return;function t(e){if(_.openChangeTimeout.clear(),_.blockMouseMove=!1,c&&!du(_.pointerType))return;let t=Tf(x.current),r=wf(b.current,`open`,_.pointerType),i=Xl(e),a=e.currentTarget??null,o=n.select(`domReferenceElement`),s=a;if(qo(i)&&!n.context.triggerElements.hasElement(i)){for(let e of n.context.triggerElements.elements())if(Yl(e,i)){s=e;break}}qo(a)&&qo(o)&&!n.context.triggerElements.hasElement(a)&&Yl(a,o)&&(s=o);let l=s==null?!1:E(o,s,i),u=n.select(`open`),d=C.current?.()??n.select(`transitionStatus`)===`ending`,f=!u&&d&&v.current,p=!l&&qo(s)&&qo(o)&&Yl(o,s)&&f,m=t>0&&!r,h=l&&(u||f)||p,g=!u||l;if(h){n.setOpen(!0,ef(Hd,e,s));return}m||(r?_.openChangeTimeout.start(r,()=>{g&&n.setOpen(!0,ef(Hd,e,s))}):g&&n.setOpen(!0,ef(Hd,e,s)))}function i(e){if(w()){O();return}D();let t=Ol(n.select(`domReferenceElement`));_.restTimeout.clear(),_.restTimeoutPending=!1;let i=r.current.floatingContext??m?.();if(!T(e.relatedTarget)){if(y.current&&i){n.select(`open`)||_.openChangeTimeout.clear();let r=d.current;_.handler=y.current({...i,tree:g,x:e.clientX,y:e.clientY,onClose(){O(),D(),S.current&&!w()&&r===n.select(`domReferenceElement`)&&ee(e,!0)}}),t.addEventListener(`mousemove`,_.handler),_.handler(e);return}(_.pointerType!==`touch`||!Yl(n.select(`floatingElement`),e.relatedTarget))&&ee(e)}}return u?jf(Af(e,`mousemove`,t,{once:!0}),Af(e,`mouseenter`,t),Af(e,`mouseleave`,i)):jf(Af(e,`mouseenter`,t),Af(e,`mouseleave`,i))},[D,O,r,b,ee,n,a,y,_,p,E,w,T,c,u,x,d,g,S,m,C]),P.useMemo(()=>{if(!a)return;function e(e){_.pointerType=e.pointerType}return{onPointerDown:e,onPointerEnter:e,onMouseMove(e){let{nativeEvent:t}=e,r=e.currentTarget,i=n.select(`domReferenceElement`),a=n.select(`open`),o=E(i,r,e.target);if(c&&!du(_.pointerType))return;if(a&&o&&_.handleCloseOptions?.blockPointerEvents){let e=n.select(`floatingElement`);e&&zm(_,{scopeElement:_.handleCloseOptions?.getScope?.()??r.ownerDocument.body,referenceElement:r,floatingElement:e})}let s=Tf(x.current);if(a&&!o||s===0||!o&&_.restTimeoutPending&&e.movementX**2+e.movementY**2<2)return;_.restTimeout.clear();function l(){if(_.restTimeoutPending=!1,w())return;let e=n.select(`open`);!_.blockMouseMove&&(!e||o)&&n.setOpen(!0,ef(Hd,t,r))}_.pointerType===`touch`?gi.flushSync(()=>{l()}):o&&a?l():(_.restTimeoutPending=!0,_.restTimeout.start(s,l))}}},[a,_,w,E,c,n,x])}function Vm(e=[]){let t=e.map(e=>e?.reference),n=e.map(e=>e?.floating),r=e.map(e=>e?.item),i=e.map(e=>e?.trigger),a=P.useCallback(t=>Hm(t,e,`reference`),t),o=P.useCallback(t=>Hm(t,e,`floating`),n),s=P.useCallback(t=>Hm(t,e,`item`),r),c=P.useCallback(t=>Hm(t,e,`trigger`),i);return P.useMemo(()=>({getReferenceProps:a,getFloatingProps:o,getItemProps:s,getTriggerProps:c}),[a,o,s,c])}function Hm(e,t,n){let r=new Map,i=n===`item`,a={};n===`floating`&&(a.tabIndex=-1,a[Hl]=``);for(let t in e)i&&e&&(t===`active`||t===`selected`)||(a[t]=e[t]);for(let o=0;or.get(i)?.map(t=>t(...e)).find(e=>e!==void 0))):e[i]=a)}}var Ree=new Map([[`select`,`listbox`],[`combobox`,`listbox`],[`label`,!1]]);function zee(e,t={}){let n=`rootStore`in e?e.rootStore:e,r=n.useState(`open`),i=n.useState(`floatingId`),a=n.useState(`domReferenceElement`),o=n.useState(`floatingElement`),{role:s=`dialog`}=t,c=Cl(),l=a?.id||c,u=P.useMemo(()=>iu(o)?.id||i,[o,i]),d=Ree.get(s)??s,f=dp()!=null,p=P.useMemo(()=>d===`tooltip`||s===`label`?qa:{"aria-haspopup":d===`alertdialog`?`dialog`:d,"aria-expanded":`false`,...d===`listbox`&&{role:`combobox`},...d===`menu`&&f&&{role:`menuitem`},...s===`select`&&{"aria-autocomplete":`none`},...s===`combobox`&&{"aria-autocomplete":`list`}},[d,f,s]),m=P.useMemo(()=>d===`tooltip`||s===`label`?{[`aria-${s===`label`?`labelledby`:`describedby`}`]:r?u:void 0}:{...p,"aria-expanded":r?`true`:`false`,"aria-controls":r?u:void 0,...d===`menu`&&{id:l}},[d,u,r,l,s,p]),h=P.useMemo(()=>{let e={id:u,...d&&{role:d}};return d===`tooltip`||s===`label`?e:{...e,...d===`menu`&&{"aria-labelledby":l}}},[d,u,l,s]),g=P.useCallback(({active:e,selected:t})=>{let n={role:`option`,...e&&{id:`${u}-fui-option`}};switch(s){case`select`:case`combobox`:return{...n,"aria-selected":t};default:}return{}},[u,s]);return P.useMemo(()=>({reference:m,floating:h,item:g,trigger:p}),[m,h,p,g])}var Wm=.1,Bee=Wm*Wm,Gm=.5;function Km(e,t,n,r,i,a){return r>=t!=a>=t&&e<=(i-n)*(t-r)/(a-r)+n}function qm(e,t,n,r,i,a,o,s,c,l){let u=!1;return Km(e,t,n,r,i,a)&&(u=!u),Km(e,t,i,a,o,s)&&(u=!u),Km(e,t,o,s,c,l)&&(u=!u),Km(e,t,c,l,n,r)&&(u=!u),u}function Vee(e,t,n){return e>=n.x&&e<=n.x+n.width&&t>=n.y&&t<=n.y+n.height}function Jm(e,t,n,r,i,a){return e>=Math.min(n,i)&&e<=Math.max(n,i)&&t>=Math.min(r,a)&&t<=Math.max(r,a)}function Hee(e={}){let{blockPointerEvents:t=!1}=e,n=new wd,r=({x:e,y:t,placement:r,elements:i,onClose:a,nodeId:o,tree:s})=>{let c=r?.split(`-`)[0],l=!1,u=null,d=null,f=typeof performance<`u`?performance.now():0;function p(e,t){let n=performance.now(),r=n-f;if(u===null||d===null||r===0)return u=e,d=t,f=n,!1;let i=e-u,a=t-d,o=i*i+a*a,s=r*r*Bee;return u=e,d=t,f=n,o0)}function b(){y()||m()}if(y())return;let x=a.getBoundingClientRect(),S=u.getBoundingClientRect(),C=e>S.right-S.width/2,w=t>S.bottom-S.height/2,T=S.width>x.width,E=S.height>x.height,ee=(T?x:S).left,D=(T?x:S).right,O=(E?x:S).top,te=(E?x:S).bottom;if(c===`top`&&t>=x.bottom-1||c===`bottom`&&t<=x.top+1||c===`left`&&e>=x.right-1||c===`right`&&e<=x.left+1){b();return}let ne=!1;switch(c){case`top`:ne=Jm(d,f,ee,x.top+1,D,S.bottom-1);break;case`bottom`:ne=Jm(d,f,ee,S.top+1,D,x.bottom-1);break;case`left`:ne=Jm(d,f,S.right-1,te,x.left+1,O);break;case`right`:ne=Jm(d,f,x.right-1,te,S.left+1,O);break;default:}if(ne)return;if(l&&!Vee(d,f,x)){b();return}if(!g&&p(d,f)){b();return}let re=!1;switch(c){case`top`:{let n=T?Gm/2:Gm*4,r=T||C?e+n:e-n,i=T?e-n:C?e+n:e-n,a=t+Gm+1,o=C||T?S.bottom-Gm:S.top,s=C?T?S.bottom-Gm:S.top:S.bottom-Gm;re=qm(d,f,r,a,i,a,S.left,o,S.right,s);break}case`bottom`:{let n=T?Gm/2:Gm*4,r=T||C?e+n:e-n,i=T?e-n:C?e+n:e-n,a=t-Gm,o=C||T?S.top+Gm:S.bottom,s=C?T?S.top+Gm:S.bottom:S.top+Gm;re=qm(d,f,r,a,i,a,S.left,o,S.right,s);break}case`left`:{let n=E?Gm/2:Gm*4,r=E||w?t+n:t-n,i=E?t-n:w?t+n:t-n,a=e+Gm+1,o=w||E?S.right-Gm:S.left,s=w?E?S.right-Gm:S.left:S.right-Gm;re=qm(d,f,o,S.top,s,S.bottom,a,r,a,i);break}case`right`:{let n=E?Gm/2:Gm*4,r=E||w?t+n:t-n,i=E?t-n:w?t+n:t-n,a=e-Gm,o=w||E?S.left+Gm:S.right,s=w?E?S.left+Gm:S.right:S.left+Gm;re=qm(d,f,a,r,a,i,o,S.top,s,S.bottom);break}default:}re?l||n.start(40,b):b()}};return r.__options={...e,blockPointerEvents:t},r}var Uee=function(e){return e.nestedDialogs=`--nested-dialogs`,e}({}),Wee=function(e){return e[e.open=lf.open]=`open`,e[e.closed=lf.closed]=`closed`,e[e.startingStyle=lf.startingStyle]=`startingStyle`,e[e.endingStyle=lf.endingStyle]=`endingStyle`,e.nested=`data-nested`,e.nestedDialogOpen=`data-nested-dialog-open`,e}({}),Ym=P.createContext(void 0);function Gee(){let e=P.useContext(Ym);if(e===void 0)throw Error(Na(26));return e}var Xm=`ArrowUp`,Zm=`ArrowDown`,Qm=`ArrowLeft`,$m=`ArrowRight`,eh=`Home`,th=new Set([Qm,$m]),Kee=new Set([Qm,$m,eh,`End`]),nh=new Set([Xm,Zm]),qee=new Set([Xm,Zm,eh,`End`]),rh=new Set([...th,...nh]),Jee=new Set([...rh,eh,`End`]),ih=new Set([Xm,Zm,Qm,$m,eh,`End`]),Yee=new Set([`Shift`,`Control`,`Alt`,`Meta`]);function Xee(e){return Jo(e)&&e.tagName===`INPUT`}function Zee(e){return!!(Xee(e)&&e.selectionStart!=null||Jo(e)&&e.tagName===`TEXTAREA`)}function Qee(e,t,n,r){if(!e||!t||!t.scrollTo)return;let i=e.scrollLeft,a=e.scrollTop,o=e.clientWidthe.scrollLeft+e.clientWidth-a.scrollPaddingRight?i=r+t.offsetWidth+o.scrollMarginRight-e.clientWidth+a.scrollPaddingRight:r-o.scrollMarginLefte.scrollLeft+e.clientWidth-a.scrollPaddingRight&&(i=r+t.offsetWidth+o.scrollMarginRight-e.clientWidth+a.scrollPaddingRight))}if(s&&r!==`horizontal`){let n=ah(e,t,`top`),r=oh(e),i=oh(t);n-i.scrollMarginTope.scrollTop+e.clientHeight-r.scrollPaddingBottom&&(a=n+t.offsetHeight+i.scrollMarginBottom-e.clientHeight+r.scrollPaddingBottom)}e.scrollTo({left:i,top:a,behavior:`auto`})}function ah(e,t,n){let r=n===`left`?`offsetLeft`:`offsetTop`,i=0;for(;t.offsetParent&&(i+=t[r],t.offsetParent!==e);)t=t.offsetParent;return i}function oh(e){let t=getComputedStyle(e);return{scrollMarginTop:parseFloat(t.scrollMarginTop)||0,scrollMarginRight:parseFloat(t.scrollMarginRight)||0,scrollMarginBottom:parseFloat(t.scrollMarginBottom)||0,scrollMarginLeft:parseFloat(t.scrollMarginLeft)||0,scrollPaddingTop:parseFloat(t.scrollPaddingTop)||0,scrollPaddingRight:parseFloat(t.scrollPaddingRight)||0,scrollPaddingBottom:parseFloat(t.scrollPaddingBottom)||0,scrollPaddingLeft:parseFloat(t.scrollPaddingLeft)||0}}var $ee={...vf,...Pd,nestedDialogOpen(e){return e?{[Wee.nestedDialogOpen]:``}:null}},sh=P.forwardRef(function(e,t){let{className:n,finalFocus:r,initialFocus:i,render:a,style:o,...s}=e,{store:c}=cf(),l=c.useState(`descriptionElementId`),u=c.useState(`disablePointerDismissal`),d=c.useState(`floatingRootContext`),f=c.useState(`popupProps`),p=c.useState(`modal`),m=c.useState(`mounted`),h=c.useState(`nested`),g=c.useState(`nestedOpenDialogCount`),_=c.useState(`open`),v=c.useState(`openMethod`),y=c.useState(`titleElementId`),b=c.useState(`transitionStatus`),x=c.useState(`role`);Gee(),Id({open:_,ref:c.context.popupRef,onComplete(){_&&c.context.onOpenChangeComplete?.(!0)}});function S(e){return e===`touch`?c.context.popupRef.current:!0}let C=i===void 0?S:i,w=Za(`div`,e,{state:{open:_,nested:h,transitionStatus:b,nestedDialogOpen:g>0},props:[f,{"aria-labelledby":y??void 0,"aria-describedby":l??void 0,role:x,tabIndex:-1,hidden:!m,onKeyDown(e){ih.has(e.key)&&e.stopPropagation()},style:{[Uee.nestedDialogs]:g}},s],ref:[t,c.context.popupRef,c.useStateSetter(`popupElement`)],stateAttributesMapping:$ee});return(0,F.jsx)(xp,{context:d,openInteractionType:v,disabled:!m,closeOnFocusOut:!u,initialFocus:C,returnFocus:r,modal:p!==!1,restoreFocus:`popup`,children:w})});function ch(e){return Ua(19)?e:e?`true`:void 0}var lh=P.forwardRef(function(e,t){let{cutout:n,...r}=e,i;if(n){let e=n.getBoundingClientRect();i=`polygon(0% 0%,100% 0%,100% 100%,0% 100%,0% 0%,${e.left}px ${e.top}px,${e.left}px ${e.bottom}px,${e.right}px ${e.bottom}px,${e.right}px ${e.top}px,${e.left}px ${e.top}px)`}return(0,F.jsx)(`div`,{ref:t,role:`presentation`,"data-base-ui-inert":``,...r,style:{position:`fixed`,inset:0,userSelect:`none`,WebkitUserSelect:`none`,clipPath:i}})}),uh=P.forwardRef(function(e,t){let{keepMounted:n=!1,...r}=e,{store:i}=cf(),a=i.useState(`mounted`),o=i.useState(`modal`),s=i.useState(`open`);return a||n?(0,F.jsx)(Ym.Provider,{value:n,children:(0,F.jsxs)(sp,{ref:t,...r,children:[a&&o===!0&&(0,F.jsx)(lh,{ref:i.context.internalBackdropRef,inert:ch(!s)}),e.children]})}):null});function dh(e){let t=P.useRef(!0);t.current&&(t.current=!1,e())}var fh={},ph={},mh=``;function ete(e){if(typeof document>`u`)return!1;let t=Ol(e);return Wo(t).innerWidth-t.documentElement.clientWidth>0}function tte(e){if(!(typeof CSS<`u`&&CSS.supports&&CSS.supports(`scrollbar-gutter`,`stable`))||typeof document>`u`)return!1;let t=Ol(e),n=t.documentElement,r=t.body,i=Xo(n)?n:r,a=i.style.overflowY,o=n.style.scrollbarGutter;n.style.scrollbarGutter=`stable`,i.style.overflowY=`scroll`;let s=i.offsetWidth;i.style.overflowY=`hidden`;let c=i.offsetWidth;return i.style.overflowY=a,n.style.scrollbarGutter=o,s===c}function nte(e){let t=Ol(e),n=t.documentElement,r=t.body,i=Xo(n)?n:r,a={overflowY:i.style.overflowY,overflowX:i.style.overflowX};return Object.assign(i.style,{overflowY:`hidden`,overflowX:`hidden`}),()=>{Object.assign(i.style,a)}}function rte(e){let t=Ol(e),n=t.documentElement,r=t.body,i=Wo(n),a=0,o=0,s=!1,c=Od.create();if(Nl&&(i.visualViewport?.scale??1)!==1)return()=>{};function l(){let t=i.getComputedStyle(n),c=i.getComputedStyle(r),l=(t.scrollbarGutter||``).includes(`both-edges`)?`stable both-edges`:`stable`;a=n.scrollTop,o=n.scrollLeft,fh={scrollbarGutter:n.style.scrollbarGutter,overflowY:n.style.overflowY,overflowX:n.style.overflowX},mh=n.style.scrollBehavior,ph={position:r.style.position,height:r.style.height,width:r.style.width,boxSizing:r.style.boxSizing,overflowY:r.style.overflowY,overflowX:r.style.overflowX,scrollBehavior:r.style.scrollBehavior};let u=n.scrollHeight>n.clientHeight,d=n.scrollWidth>n.clientWidth,f=t.overflowY===`scroll`||c.overflowY===`scroll`,p=t.overflowX===`scroll`||c.overflowX===`scroll`,m=Math.max(0,i.innerWidth-r.clientWidth),h=Math.max(0,i.innerHeight-r.clientHeight),g=parseFloat(c.marginTop)+parseFloat(c.marginBottom),_=parseFloat(c.marginLeft)+parseFloat(c.marginRight),v=Xo(n)?n:r;if(s=tte(e),s){n.style.scrollbarGutter=l,v.style.overflowY=`hidden`,v.style.overflowX=`hidden`;return}Object.assign(n.style,{scrollbarGutter:l,overflowY:`hidden`,overflowX:`hidden`}),(u||f)&&(n.style.overflowY=`scroll`),(d||p)&&(n.style.overflowX=`scroll`),Object.assign(r.style,{position:`relative`,height:g||h?`calc(100dvh - ${g+h}px)`:`100dvh`,width:_||m?`calc(100vw - ${_+m}px)`:`100vw`,boxSizing:`border-box`,overflow:`hidden`,scrollBehavior:`unset`}),r.scrollTop=a,r.scrollLeft=o,n.setAttribute(`data-base-ui-scroll-locked`,``),n.style.scrollBehavior=`unset`}function u(){Object.assign(n.style,fh),Object.assign(r.style,ph),s||(n.scrollTop=a,n.scrollLeft=o,n.removeAttribute(`data-base-ui-scroll-locked`),n.style.scrollBehavior=mh)}function d(){u(),c.request(l)}l();let f=Af(i,`resize`,d);return()=>{c.cancel(),u(),typeof i.removeEventListener==`function`&&f()}}var ite=new class{lockCount=0;restore=null;timeoutLock=wd.create();timeoutUnlock=wd.create();acquire(e){return this.lockCount+=1,this.lockCount===1&&this.restore===null&&this.timeoutLock.start(0,()=>this.lock(e)),this.release}release=()=>{--this.lockCount,this.lockCount===0&&this.restore&&this.timeoutUnlock.start(0,this.unlock)};unlock=()=>{this.lockCount===0&&this.restore&&(this.restore?.(),this.restore=null)};lock(e){if(this.lockCount===0||this.restore!==null)return;let t=Ol(e).documentElement,n=Wo(t).getComputedStyle(t).overflowY;if(n===`hidden`||n===`clip`){this.restore=Ga;return}let r=Pl||!ete(e);this.restore=r?nte(e):rte(e)}};function hh(e=!0,t=null){ys(()=>{if(e)return ite.acquire(t)},[e,t])}function gh(e){let t=P.useRef(``),n=P.useCallback(n=>{n.defaultPrevented||(t.current=n.pointerType,e(n,n.pointerType))},[e]);return{onClick:P.useCallback(n=>{if(n.detail===0){e(n,`keyboard`);return}`pointerType`in n?e(n,n.pointerType):e(n,t.current),t.current=``},[e]),onPointerDown:n}}function _h(e,t){let n=P.useRef(e),r=hs(t);ys(()=>{n.current!==e&&r(n.current)},[e,r]),ys(()=>{n.current=e},[e])}function vh(e){let[t,n]=P.useState(null),r=hs((t,r)=>{e||n(r||(Pl?`touch`:``))});_h(e,t=>{t&&!e&&n(null)});let{onClick:i,onPointerDown:a}=gh(r);return P.useMemo(()=>({openMethod:t,triggerProps:{onClick:i,onPointerDown:a}}),[t,i,a])}function yh(e){let{store:t,parentContext:n,actionsRef:r,isDrawer:i}=e,a=t.useState(`open`),o=t.useState(`disablePointerDismissal`),s=t.useState(`modal`),c=t.useState(`popupElement`),{openMethod:l,triggerProps:u}=vh(a);Om(t);let{forceUnmount:d}=km(a,t),f=P.useCallback(()=>{t.setOpen(!1,ef(Qd))},[t]);P.useImperativeHandle(r,()=>({unmount:d,close:f}),[d,f]);let p=Fm({popupStore:t,onOpenChange:t.setOpen,treatPopupAsFloatingElement:!0}),[m,h]=P.useState(0),[g,_]=P.useState(0),v=m===0,y=zee(p),b=Op(p,{outsidePressEvent(){return t.context.internalBackdropRef.current||t.context.backdropRef.current?`intentional`:{mouse:s===`trap-focus`?`sloppy`:`intentional`,touch:`sloppy`}},outsidePress(e){if(!t.context.outsidePressEnabledRef.current||`button`in e&&e.button!==0||`touches`in e&&e.touches.length!==1)return!1;let n=Xl(e);if(v&&!o){let e=n;return s&&(t.context.internalBackdropRef.current||t.context.backdropRef.current)?t.context.internalBackdropRef.current===e||t.context.backdropRef.current===e||Yl(e,c)&&!e?.hasAttribute(`data-base-ui-portal`):!0}return!1},escapeKey:v});hh(a&&s===!0,c);let{getReferenceProps:x,getFloatingProps:S,getTriggerProps:C}=Vm([y,b]);t.useContextCallback(`onNestedDialogOpen`,(e,t)=>{h(e),_(t)}),t.useContextCallback(`onNestedDialogClose`,()=>{h(0),_(0)}),P.useEffect(()=>(n?.onNestedDialogOpen&&a&&n.onNestedDialogOpen(m+1,g+ +!!i),n?.onNestedDialogClose&&!a&&n.onNestedDialogClose(),()=>{n?.onNestedDialogClose&&a&&n.onNestedDialogClose()}),[i,a,m,g,n]);let w=P.useMemo(()=>x(u),[x,u]),T=P.useMemo(()=>C(u),[C,u]),E=P.useMemo(()=>S(),[S]);t.useSyncedValues({openMethod:l,activeTriggerProps:w,inactiveTriggerProps:T,popupProps:E,floatingRootContext:p,nestedOpenDialogCount:m,nestedOpenDrawerCount:g})}var ate={...Nm,modal:ym(e=>e.modal),nested:ym(e=>e.nested),nestedOpenDialogCount:ym(e=>e.nestedOpenDialogCount),nestedOpenDrawerCount:ym(e=>e.nestedOpenDrawerCount),disablePointerDismissal:ym(e=>e.disablePointerDismissal),openMethod:ym(e=>e.openMethod),descriptionElementId:ym(e=>e.descriptionElementId),titleElementId:ym(e=>e.titleElementId),viewportElement:ym(e=>e.viewportElement),role:ym(e=>e.role)},bh=class e extends Em{constructor(e){super(ote(e),{popupRef:P.createRef(),backdropRef:P.createRef(),internalBackdropRef:P.createRef(),outsidePressEnabledRef:{current:!0},triggerElements:new Am,onOpenChange:void 0,onOpenChangeComplete:void 0},ate)}setOpen=(e,t)=>{if(t.preventUnmountOnClose=()=>{this.set(`preventUnmountingOnClose`,!0)},!e&&t.trigger==null&&this.state.activeTriggerId!=null&&(t.trigger=this.state.activeTriggerElement??void 0),this.context.onOpenChange?.(e,t),t.isCanceled)return;this.state.floatingRootContext.dispatchOpenChange(e,t);let n={open:e},r=t.trigger?.id??null;(r||e)&&(n.activeTriggerId=r,n.activeTriggerElement=t.trigger??null),this.update(n)};static useStore(t,n){let r=Fa(()=>new e(n)).current;return t??r}};function ote(e={}){return{...jm(),modal:!0,disablePointerDismissal:!1,popupElement:null,viewportElement:null,descriptionElementId:void 0,titleElementId:void 0,openMethod:null,nested:!1,nestedOpenDialogCount:0,nestedOpenDrawerCount:0,role:`dialog`,...e}}var xh=P.createContext(!1);function ste(e){let{children:t,open:n,defaultOpen:r=!1,onOpenChange:i,onOpenChangeComplete:a,disablePointerDismissal:o=!1,modal:s=!0,actionsRef:c,handle:l,triggerId:u,defaultTriggerId:d=null}=e,f=cf(!0),p=P.useContext(xh),m=!!f,h=bh.useStore(l?.store,{open:r,openProp:n,activeTriggerId:d,triggerIdProp:u,modal:s,disablePointerDismissal:o,nested:m});dh(()=>{n===void 0&&h.state.open===!1&&r===!0&&h.update({open:!0,activeTriggerId:d})}),h.useControlledProp(`openProp`,n),h.useControlledProp(`triggerIdProp`,u),h.useSyncedValues({disablePointerDismissal:o,nested:m,modal:s}),h.useContextCallback(`onOpenChange`,i),h.useContextCallback(`onOpenChangeComplete`,a);let g=h.useState(`payload`);yh({store:h,actionsRef:c,parentContext:f?.store.context,isDrawer:p,onOpenChange:i,triggerIdProp:u});let _=P.useMemo(()=>({store:h}),[h]);return(0,F.jsx)(xh.Provider,{value:!1,children:(0,F.jsx)(sf.Provider,{value:_,children:typeof t==`function`?t({payload:g}):t})})}var Sh=P.forwardRef(function(e,t){let{render:n,className:r,style:i,id:a,...o}=e,{store:s}=cf(),c=wl(a);return s.useSyncedValueWithCleanup(`titleElementId`,c),Za(`h2`,e,{ref:t,props:[{id:c},o]})});function cte(e){let t=(0,da.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,F.jsx)(ste,{"data-slot":`sheet`,...n}),t[2]=n,t[3]=r),r}function lte(e){let t=(0,da.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,F.jsx)(uh,{"data-slot":`sheet-portal`,...n}),t[2]=n,t[3]=r),r}function ute(e){let t=(0,da.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=$c(`data-closed:fade-out-0 data-open:fade-in-0 data-closed:animate-out data-open:animate-in fixed inset-0 z-50 bg-black/80 duration-100 data-ending-style:opacity-0 data-starting-style:opacity-0 supports-backdrop-filter:backdrop-blur-xs`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(bf,{className:i,"data-slot":`sheet-overlay`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Ch(e){let t=(0,da.c)(17),n,r,i,a,o;t[0]===e?(n=t[1],r=t[2],i=t[3],a=t[4],o=t[5]):({className:r,children:n,side:a,showCloseButton:o,...i}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i,t[4]=a,t[5]=o);let s=a===void 0?`right`:a,c=o===void 0?!0:o,l;t[6]===Symbol.for(`react.memo_cache_sentinel`)?(l=(0,F.jsx)(ute,{}),t[6]=l):l=t[6];let u;t[7]===r?u=t[8]:(u=$c(`data-[side=right]:data-closed:slide-out-to-right-10 data-[side=right]:data-open:slide-in-from-right-10 data-[side=left]:data-closed:slide-out-to-left-10 data-[side=left]:data-open:slide-in-from-left-10 data-[side=top]:data-closed:slide-out-to-top-10 data-[side=top]:data-open:slide-in-from-top-10 data-closed:fade-out-0 data-open:fade-in-0 data-[side=bottom]:data-closed:slide-out-to-bottom-10 data-[side=bottom]:data-open:slide-in-from-bottom-10 data-closed:animate-out data-open:animate-in fixed z-50 flex flex-col bg-background bg-clip-padding text-xs/relaxed shadow-lg transition duration-200 ease-in-out data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm`,r),t[7]=r,t[8]=u);let d;t[9]===c?d=t[10]:(d=c&&(0,F.jsxs)(xf,{"data-slot":`sheet-close`,render:(0,F.jsx)(fl,{className:`absolute top-4 right-4`,size:`icon-sm`,variant:`ghost`}),children:[(0,F.jsx)(Vo,{}),(0,F.jsx)(`span`,{className:`sr-only`,children:`Close`})]}),t[9]=c,t[10]=d);let f;return t[11]!==n||t[12]!==i||t[13]!==s||t[14]!==u||t[15]!==d?(f=(0,F.jsxs)(lte,{children:[l,(0,F.jsxs)(sh,{className:u,"data-side":s,"data-slot":`sheet-content`,...i,children:[n,d]})]}),t[11]=n,t[12]=i,t[13]=s,t[14]=u,t[15]=d,t[16]=f):f=t[16],f}function wh(e){let t=(0,da.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=$c(`flex flex-col gap-1.5 p-6`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(`div`,{className:i,"data-slot":`sheet-header`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Th(e){let t=(0,da.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=$c(`text-sm font-medium text-foreground`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(Sh,{className:i,"data-slot":`sheet-title`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Eh(e){let t=(0,da.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=$c(`text-xs/relaxed text-muted-foreground`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(Sf,{className:i,"data-slot":`sheet-description`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}var Dh=P.createContext(void 0);function Oh(e){let t=P.useContext(Dh);if(t===void 0&&!e)throw Error(Na(72));return t}var kh={...Nm,disabled:ym(e=>e.disabled),instantType:ym(e=>e.instantType),isInstantPhase:ym(e=>e.isInstantPhase),trackCursorAxis:ym(e=>e.trackCursorAxis),disableHoverablePopup:ym(e=>e.disableHoverablePopup),lastOpenChangeReason:ym(e=>e.openChangeReason),closeOnClick:ym(e=>e.closeOnClick),closeDelay:ym(e=>e.closeDelay),hasViewport:ym(e=>e.hasViewport)},Ah=class e extends Em{constructor(e){super({...jh(),...e},{popupRef:P.createRef(),onOpenChange:void 0,onOpenChangeComplete:void 0,triggerElements:new Am},kh)}setOpen=(e,t)=>{let n=t.reason,r=n===Hd,i=e&&n===`trigger-focus`,a=!e&&(n===`trigger-press`||n===`escape-key`);if(t.preventUnmountOnClose=()=>{this.set(`preventUnmountingOnClose`,!0)},this.context.onOpenChange?.(e,t),t.isCanceled)return;this.state.floatingRootContext.dispatchOpenChange(e,t);let o=()=>{let r={open:e,openChangeReason:n};i?r.instantType=`focus`:a?r.instantType=`dismiss`:n===`trigger-hover`&&(r.instantType=void 0);let o=t.trigger?.id??null;(o||e)&&(r.activeTriggerId=o,r.activeTriggerElement=t.trigger??null),this.update(r)};r?gi.flushSync(o):o()};static useStore(t,n){let r=Fa(()=>new e(n)).current,i=t??r,a=Fm({popupStore:i,onOpenChange:i.setOpen});return i.state.floatingRootContext=a,i}};function jh(){return{...jm(),disabled:!1,instantType:void 0,isInstantPhase:!1,trackCursorAxis:`none`,disableHoverablePopup:!1,openChangeReason:null,closeOnClick:!0,closeDelay:0,hasViewport:!1}}var Mh=Sm(function(e){let{disabled:t=!1,defaultOpen:n=!1,open:r,disableHoverablePopup:i=!1,trackCursorAxis:a=`none`,actionsRef:o,onOpenChange:s,onOpenChangeComplete:c,handle:l,triggerId:u,defaultTriggerId:d=null,children:f}=e,p=Ah.useStore(l?.store,{open:n,openProp:r,activeTriggerId:d,triggerIdProp:u});dh(()=>{r===void 0&&p.state.open===!1&&n===!0&&p.update({open:!0,activeTriggerId:d})}),p.useControlledProp(`openProp`,r),p.useControlledProp(`triggerIdProp`,u),p.useContextCallback(`onOpenChange`,s),p.useContextCallback(`onOpenChangeComplete`,c);let m=p.useState(`open`),h=!t&&m,g=p.useState(`activeTriggerId`),_=p.useState(`payload`);p.useSyncedValues({trackCursorAxis:a,disableHoverablePopup:i}),ys(()=>{m&&t&&p.setOpen(!1,ef(Zd))},[m,t,p]),p.useSyncedValue(`disabled`,t),Om(p);let{forceUnmount:v,transitionStatus:y}=km(h,p),b=p.select(`floatingRootContext`),x=p.useState(`isInstantPhase`),S=p.useState(`instantType`),C=p.useState(`lastOpenChangeReason`),w=P.useRef(null);ys(()=>{y===`ending`&&C===`none`||y!==`ending`&&x?(S!==`delay`&&(w.current=S),p.set(`instantType`,`delay`)):w.current!==null&&(p.set(`instantType`,w.current),w.current=null)},[y,x,C,S,p]),ys(()=>{h&&(g??p.set(`payload`,void 0))},[p,g,h]);let T=P.useCallback(()=>{p.setOpen(!1,ef(Qd))},[p]);P.useImperativeHandle(o,()=>({unmount:v,close:T}),[v,T]);let{getReferenceProps:E,getFloatingProps:ee,getTriggerProps:D}=Vm([Op(b,{enabled:!t,referencePress:()=>p.select(`closeOnClick`)}),wp(b,{enabled:!t&&a!==`none`,axis:a===`none`?void 0:a})]),O=P.useMemo(()=>E(),[E]),te=P.useMemo(()=>D(),[D]),ne=P.useMemo(()=>ee(),[ee]);return p.useSyncedValues({activeTriggerProps:O,inactiveTriggerProps:te,popupProps:ne}),(0,F.jsx)(Dh.Provider,{value:p,children:typeof f==`function`?f({payload:_}):f})}),Nh=P.createContext(void 0);function Ph(){return P.useContext(Nh)}var Fh=function(e){return e[e.popupOpen=uf.popupOpen]=`popupOpen`,e.triggerDisabled=`data-trigger-disabled`,e}({}),Ih=See(function(e,t){let{className:n,render:r,handle:i,payload:a,disabled:o,delay:s,closeOnClick:c=!0,closeDelay:l,id:u,style:d,...f}=e,p=Oh(!0),m=i?.store??p;if(!m)throw Error(Na(82));let h=wl(u),g=m.useState(`isTriggerActive`,h),_=m.useState(`isOpenedByTrigger`,h),v=m.useState(`floatingRootContext`),y=P.useRef(null),b=s??600,x=l??0,{registerTrigger:S,isMountedByThisTrigger:C}=Aee(h,y,m,{payload:a,closeOnClick:c,closeDelay:x}),w=Ph(),{delayRef:T,isInstantPhase:E,hasProvider:ee}=kf(v,{open:_});m.useSyncedValue(`isInstantPhase`,E);let D=m.useState(`disabled`),O=o??D,te=m.useState(`trackCursorAxis`),ne=m.useState(`disableHoverablePopup`),re=Lee(v,{enabled:!O,mouseOnly:!0,move:!1,handleClose:!ne&&te!==`both`?Hee():null,restMs(){let e=w?.delay,t=typeof T.current==`object`?T.current.open:void 0,n=b;return ee&&(n=t===0?0:s??e??b),n},delay(){let e=typeof T.current==`object`?T.current.close:void 0,t=x;return l==null&&ee&&(t=e),{close:t}},triggerElementRef:y,isActiveTrigger:g,isClosing:()=>m.select(`transitionStatus`)===`ending`}),k=Nee(v,{enabled:!O}).reference,A={open:_},ie=m.useState(`triggerProps`,C);return Za(`button`,e,{state:A,ref:[t,S,y],props:[re,k,ie,{onPointerDown(){m.set(`closeOnClick`,c)},id:h,[Fh.triggerDisabled]:O?``:void 0},f],stateAttributesMapping:gf})}),Lh=P.createContext(void 0);function Rh(){let e=P.useContext(Lh);if(e===void 0)throw Error(Na(70));return e}var zh=P.forwardRef(function(e,t){let{children:n,container:r,className:i,render:a,style:o,...s}=e,{portalNode:c,portalSubtree:l}=op({container:r,ref:t,componentProps:e,elementProps:s});return!l&&!c?null:(0,F.jsxs)(P.Fragment,{children:[l,c&&gi.createPortal(n,c)]})}),Bh=P.forwardRef(function(e,t){let{keepMounted:n=!1,...r}=e;return Oh().useState(`mounted`)||n?(0,F.jsx)(Lh.Provider,{value:n,children:(0,F.jsx)(zh,{ref:t,...r})}):null}),Vh=P.createContext(void 0);function Hh(){let e=P.useContext(Vh);if(e===void 0)throw Error(Na(71));return e}var Uh=P.createContext(void 0);function Wh(){return P.useContext(Uh)?.direction??`ltr`}var Gh=e=>({name:`arrow`,options:e,async fn(t){let{x:n,y:r,placement:i,rects:a,platform:o,elements:s,middlewareData:c}=t,{element:l,padding:u=0,offsetParent:d=`real`}=xu(e,t)||{};if(l==null)return{};let f=zu(u),p={x:n,y:r},m=Du(i),h=Tu(m),g=await o.getDimensions(l),_=m===`y`,v=_?`top`:`left`,y=_?`bottom`:`right`,b=_?`clientHeight`:`clientWidth`,x=a.reference[h]+a.reference[m]-p[m]-a.floating[h],S=p[m]-a.reference[m],C=d===`real`?await o.getOffsetParent?.(l):s.floating,w=s.floating[b]||a.floating[h];(!w||!await o.isElement?.(C))&&(w=s.floating[b]||a.floating[h]);let T=x/2-S/2,E=w/2-g[h]/2-1,ee=Math.min(f[v],E),D=Math.min(f[y],E),O=ee,te=w-g[h]-D,ne=w/2-g[h]/2+T,re=bu(O,ne,te),k=!c.arrow&&Cu(i)!=null&&ne!==re&&a.reference[h]/2-(ne({...Gh(e),options:[e,t]}),qh={name:`hide`,async fn(e){let{width:t,height:n,x:r,y:i}=e.rects.reference,a=t===0&&n===0&&r===0&&i===0;return{data:{referenceHidden:(await yee().fn(e)).data?.referenceHidden||a}}}},Jh={sideX:`left`,sideY:`top`},Yh={name:`adaptiveOrigin`,async fn(e){let{x:t,y:n,rects:{floating:r},elements:{floating:i},platform:a,strategy:o,placement:s}=e,c=Wo(i),l=c.getComputedStyle(i);if(!(l.transitionDuration!==`0s`&&l.transitionDuration!==``))return{x:t,y:n,data:Jh};let u=await a.getOffsetParent?.(i),d={width:0,height:0};if(o===`fixed`&&c?.visualViewport)d={width:c.visualViewport.width,height:c.visualViewport.height};else if(u===c){let e=Ol(i);d={width:e.documentElement.clientWidth,height:e.documentElement.clientHeight}}else await a.isElement?.(u)&&(d=await a.getDimensions(u));let f=Su(s),p=t,m=n;f===`left`&&(p=d.width-(t+r.width)),f===`top`&&(m=d.height-(n+r.height));let h=f===`left`?`right`:Jh.sideX,g=f===`top`?`bottom`:Jh.sideY;return{x:p,y:m,data:{sideX:h,sideY:g}}}};function Xh(e,t,n){let r=e===`inline-start`||e===`inline-end`;return{top:`top`,right:r?n?`inline-start`:`inline-end`:`right`,bottom:`bottom`,left:r?n?`inline-end`:`inline-start`:`left`}[t]}function Zh(e,t,n){let{rects:r,placement:i}=e;return{side:Xh(t,Su(i),n),align:Cu(i)||`center`,anchor:{width:r.reference.width,height:r.reference.height},positioner:{width:r.floating.width,height:r.floating.height}}}function Qh(e){let{anchor:t,positionMethod:n=`absolute`,side:r=`bottom`,sideOffset:i=0,align:a=`center`,alignOffset:o=0,collisionBoundary:s,collisionPadding:c=5,sticky:l=!1,arrowPadding:u=5,disableAnchorTracking:d=!1,keepMounted:f=!1,floatingRootContext:p,mounted:m,collisionAvoidance:h,shiftCrossAxis:g=!1,nodeId:_,adaptiveOrigin:v,lazyFlip:y=!1,externalTree:b}=e,[x,S]=P.useState(null);!m&&x!==null&&S(null);let C=h.side||`flip`,w=h.align||`flip`,T=h.fallbackAxisSide||`end`,E=typeof t==`function`?t:void 0,ee=hs(E),D=E?ee:t,O=Mf(t),te=Mf(m),ne=Wh()===`rtl`,re=x||{top:`top`,right:`right`,bottom:`bottom`,left:`left`,"inline-end":ne?`left`:`right`,"inline-start":ne?`right`:`left`}[r],k=a===`center`?re:`${re}-${a}`,A=c,ie=+(r===`bottom`),j=+(r===`top`),ae=+(r===`right`),oe=+(r===`left`);typeof A==`number`?A={top:A+ie,right:A+oe,bottom:A+j,left:A+ae}:A&&={top:(A.top||0)+ie,right:(A.right||0)+oe,bottom:(A.bottom||0)+j,left:(A.left||0)+ae};let se={boundary:s===`clipping-ancestors`?`clippingAncestors`:s,padding:A},ce=P.useRef(null),M=Mf(i),le=Mf(o),ue=[mee(e=>{let t=Zh(e,r,ne),n=typeof M.current==`function`?M.current(t):M.current,i=typeof le.current==`function`?le.current(t):le.current;return{mainAxis:n,crossAxis:i,alignmentAxis:i}},[typeof i==`function`?0:i,typeof o==`function`?0:o,ne,r])],N=w===`none`&&C!==`shift`,de=!N&&(l||g||C===`shift`),fe=C===`none`?null:_ee({...se,padding:{top:A.top+1,right:A.right+1,bottom:A.bottom+1,left:A.left+1},mainAxis:!g&&C===`flip`,crossAxis:w===`flip`?`alignment`:!1,fallbackAxisSideDirection:T}),pe=N?null:hee(e=>{let t=Ol(e.elements.floating).documentElement;return{...se,rootBoundary:g?{x:0,y:0,width:t.clientWidth,height:t.clientHeight}:void 0,mainAxis:w!==`none`,crossAxis:de,limiter:l||g?void 0:gee(e=>{if(!ce.current)return{};let{width:t,height:n}=ce.current.getBoundingClientRect(),r=Eu(Su(e.placement)),i=r===`y`?t:n,a=r===`y`?A.left+A.right:A.top+A.bottom;return{offset:i/2+a/2}})}},[se,l,g,A,w]);C===`shift`||w===`shift`||a===`center`?ue.push(pe,fe):ue.push(fe,pe),ue.push(vee({...se,apply({elements:{floating:e},availableWidth:t,availableHeight:n,rects:r}){if(!te.current)return;let i=e.style;i.setProperty(`--available-width`,`${t}px`),i.setProperty(`--available-height`,`${n}px`);let a=Wo(e).devicePixelRatio||1,{x:o,y:s,width:c,height:l}=r.reference,u=(Math.round((o+c)*a)-Math.round(o*a))/a,d=(Math.round((s+l)*a)-Math.round(s*a))/a;i.setProperty(`--anchor-width`,`${u}px`),i.setProperty(`--anchor-height`,`${d}px`)}}),Kh(()=>({element:ce.current||Ol(ce.current).createElement(`div`),padding:u,offsetParent:`floating`}),[u]),{name:`transformOrigin`,fn(e){let{elements:t,middlewareData:n,placement:a,rects:o,y:s}=e,c=Su(a),l=Eu(c),u=ce.current,d=n.arrow?.x||0,f=n.arrow?.y||0,p=u?.clientWidth||0,m=u?.clientHeight||0,h=d+p/2,g=f+m/2,_=Math.abs(n.shift?.y||0),v=o.reference.height/2,y=typeof i==`function`?i(Zh(e,r,ne)):i,b=_>y,x={top:`${h}px calc(100% + ${y}px)`,bottom:`${h}px ${-y}px`,left:`calc(100% + ${y}px) ${g}px`,right:`${-y}px ${g}px`}[c],S=`${h}px ${o.reference.y+v-s}px`;return t.floating.style.setProperty(`--transform-origin`,de&&l===`y`&&b?S:x),{}}},qh,v),ys(()=>{!m&&p&&p.update({referenceElement:null,floatingElement:null,domReferenceElement:null,positionReference:null})},[m,p]);let me=P.useMemo(()=>({elementResize:!d&&typeof ResizeObserver<`u`,layoutShift:!d&&typeof IntersectionObserver<`u`}),[d]),{refs:he,elements:ge,x:_e,y:ve,middlewareData:ye,update:be,placement:xe,context:Se,isPositioned:Ce,floatingStyles:we}=Mee({rootContext:p,open:f?m:void 0,placement:k,middleware:ue,strategy:n,whileElementsMounted:f?void 0:(...e)=>sm(...e,me),nodeId:_,externalTree:b}),{sideX:Te,sideY:Ee}=ye.adaptiveOrigin||Jh,De=Ce?n:`fixed`,Oe=P.useMemo(()=>{let e=v?{position:De,[Te]:_e,[Ee]:ve}:{position:De,...we};return Ce||(e.opacity=0),e},[v,De,Te,_e,Ee,ve,we,Ce]),ke=P.useRef(null);ys(()=>{if(!m)return;let e=O.current,t=typeof e==`function`?e():e,n=($h(t)?t.current:t)||null;n!==ke.current&&(he.setPositionReference(n),ke.current=n)},[m,he,D,O]),P.useEffect(()=>{if(!m)return;let e=O.current;typeof e!=`function`&&$h(e)&&e.current!==ke.current&&(he.setPositionReference(e.current),ke.current=e.current)},[m,he,D,O]),P.useEffect(()=>{if(f&&m&&ge.domReference&&ge.floating)return sm(ge.domReference,ge.floating,be,me)},[f,m,ge,be,me]);let Ae=Su(xe),je=Xh(r,Ae,ne),Me=Cu(xe)||`center`,Ne=!!ye.hide?.referenceHidden;ys(()=>{y&&m&&Ce&&S(Ae)},[y,m,Ce,Ae]);let F=P.useMemo(()=>({position:`absolute`,top:ye.arrow?.y,left:ye.arrow?.x}),[ye.arrow]),Pe=ye.arrow?.centerOffset!==0;return P.useMemo(()=>({positionerStyles:Oe,arrowStyles:F,arrowRef:ce,arrowUncentered:Pe,side:je,align:Me,physicalSide:Ae,anchorHidden:Ne,refs:he,context:Se,isPositioned:Ce,update:be}),[Oe,F,ce,Pe,je,Me,Ae,Ne,he,Se,Ce,be])}function $h(e){return e!=null&&`current`in e}function eg(e){return e===`starting`?$f:qa}function tg(e,t,{styles:n,transitionStatus:r,props:i,refs:a,hidden:o,inert:s=!1}){let c={...n};return s&&(c.pointerEvents=`none`),Za(`div`,e,{state:t,ref:a,props:[{role:`presentation`,hidden:o,style:c},eg(r),i],stateAttributesMapping:vf})}var dte=P.forwardRef(function(e,t){let{render:n,className:r,anchor:i,positionMethod:a=`absolute`,side:o=`top`,align:s=`center`,sideOffset:c=0,alignOffset:l=0,collisionBoundary:u=`clipping-ancestors`,collisionPadding:d=5,arrowPadding:f=5,sticky:p=!1,disableAnchorTracking:m=!1,collisionAvoidance:h=tp,style:g,..._}=e,v=Oh(),y=Rh(),b=v.useState(`open`),x=v.useState(`mounted`),S=v.useState(`trackCursorAxis`),C=v.useState(`disableHoverablePopup`),w=v.useState(`floatingRootContext`),T=v.useState(`instantType`),E=v.useState(`transitionStatus`),ee=Qh({anchor:i,positionMethod:a,floatingRootContext:w,mounted:x,side:o,sideOffset:c,align:s,alignOffset:l,collisionBoundary:u,collisionPadding:d,sticky:p,arrowPadding:f,disableAnchorTracking:m,keepMounted:y,collisionAvoidance:h,adaptiveOrigin:v.useState(`hasViewport`)?Yh:void 0}),D=tg(e,P.useMemo(()=>({open:b,side:ee.side,align:ee.align,anchorHidden:ee.anchorHidden,instant:S===`none`?T:`tracking-cursor`}),[b,ee.side,ee.align,ee.anchorHidden,S,T]),{styles:ee.positionerStyles,transitionStatus:E,props:_,refs:[t,v.useStateSetter(`positionerElement`)],hidden:!x,inert:!b||S===`both`||C});return(0,F.jsx)(Vh.Provider,{value:ee,children:D})}),fte={...vf,...Pd},pte=P.forwardRef(function(e,t){let{className:n,render:r,style:i,...a}=e,o=Oh(),{side:s,align:c}=Hh(),l=o.useState(`open`),u=o.useState(`instantType`),d=o.useState(`transitionStatus`),f=o.useState(`popupProps`),p=o.useState(`floatingRootContext`);Id({open:l,ref:o.context.popupRef,onComplete(){l&&o.context.onOpenChangeComplete?.(!0)}});let m=o.useState(`disabled`),h=o.useState(`closeDelay`);return Fee(p,{enabled:!m,closeDelay:h}),Za(`div`,e,{state:{open:l,side:s,align:c,instant:u,transitionStatus:d},ref:[t,o.context.popupRef,o.useStateSetter(`popupElement`)],props:[f,eg(d),a],stateAttributesMapping:fte})}),mte=P.forwardRef(function(e,t){let{className:n,render:r,style:i,...a}=e,o=Oh(),s=o.useState(`open`),c=o.useState(`instantType`),{arrowRef:l,side:u,align:d,arrowUncentered:f,arrowStyles:p}=Hh();return Za(`div`,e,{state:{open:s,side:u,align:d,uncentered:f,instant:c},ref:[t,l],props:[{style:p,"aria-hidden":!0},a],stateAttributesMapping:vf})}),hte=function(e){let{delay:t,closeDelay:n,timeout:r=400}=e,i=P.useMemo(()=>({delay:t,closeDelay:n}),[t,n]),a=P.useMemo(()=>({open:t,close:n}),[t,n]);return(0,F.jsx)(Nh.Provider,{value:i,children:(0,F.jsx)(Of,{delay:a,timeoutMs:r,children:e.children})})};function gte(e){let t=(0,da.c)(6),n,r;t[0]===e?(n=t[1],r=t[2]):({delay:r,...n}=e,t[0]=e,t[1]=n,t[2]=r);let i=r===void 0?0:r,a;return t[3]!==i||t[4]!==n?(a=(0,F.jsx)(hte,{"data-slot":`tooltip-provider`,delay:i,...n}),t[3]=i,t[4]=n,t[5]=a):a=t[5],a}function _te(e){let t=(0,da.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,F.jsx)(gte,{children:(0,F.jsx)(Mh,{"data-slot":`tooltip`,...n})}),t[2]=n,t[3]=r),r}function vte(e){let t=(0,da.c)(4),n;t[0]===e?n=t[1]:({...n}=e,t[0]=e,t[1]=n);let r;return t[2]===n?r=t[3]:(r=(0,F.jsx)(Ih,{"data-slot":`tooltip-trigger`,...n}),t[2]=n,t[3]=r),r}function yte(e){let t=(0,da.c)(21),n,r,i,a,o,s,c;t[0]===e?(n=t[1],r=t[2],i=t[3],a=t[4],o=t[5],s=t[6],c=t[7]):({className:r,side:a,sideOffset:o,align:s,alignOffset:c,children:n,...i}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i,t[4]=a,t[5]=o,t[6]=s,t[7]=c);let l=a===void 0?`top`:a,u=o===void 0?4:o,d=s===void 0?`center`:s,f=c===void 0?0:c,p;t[8]===r?p=t[9]:(p=$c(`data-open:fade-in-0 data-open:zoom-in-95 data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-closed:fade-out-0 data-closed:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=delayed-open]:animate-in data-closed:animate-out data-open:animate-in z-50 w-fit max-w-xs origin-(--transform-origin) rounded-md bg-foreground px-3 py-1.5 text-xs text-background **:data-[slot=kbd]:rounded-md`,r),t[8]=r,t[9]=p);let m;t[10]===Symbol.for(`react.memo_cache_sentinel`)?(m=(0,F.jsx)(mte,{className:`z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5`}),t[10]=m):m=t[10];let h;t[11]!==n||t[12]!==i||t[13]!==p?(h=(0,F.jsxs)(pte,{className:p,"data-slot":`tooltip-content`,...i,children:[n,m]}),t[11]=n,t[12]=i,t[13]=p,t[14]=h):h=t[14];let g;return t[15]!==d||t[16]!==f||t[17]!==l||t[18]!==u||t[19]!==h?(g=(0,F.jsx)(Bh,{children:(0,F.jsx)(dte,{align:d,alignOffset:f,className:`isolate z-50`,side:l,sideOffset:u,children:h})}),t[15]=d,t[16]=f,t[17]=l,t[18]=u,t[19]=h,t[20]=g):g=t[20],g}var ng=window.matchMedia(`(max-width: 767px)`);function bte(e){return ng.addEventListener(`change`,e),()=>ng.removeEventListener(`change`,e)}function xte(){return ng.matches}function Ste(){return(0,P.useSyncExternalStore)(bte,xte)}var Cte=`sidebar_state`,wte=3600*24*7,Tte=`12rem`,Ete=`16rem`,Dte=`3rem`,Ote=`b`,rg=P.createContext(null);function ig(){let e=P.useContext(rg);if(!e)throw Error(`useSidebar must be used within a SidebarProvider.`);return e}function kte(e){let t=(0,da.c)(36),n,r,i,a,o,s,c;t[0]===e?(n=t[1],r=t[2],i=t[3],a=t[4],o=t[5],s=t[6],c=t[7]):({defaultOpen:c,open:i,onOpenChange:o,className:r,style:s,children:n,...a}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i,t[4]=a,t[5]=o,t[6]=s,t[7]=c);let l=c===void 0?!0:c,u=Ste(),[d,f]=P.useState(!1),[p,m]=P.useState(l),h=i??p,g;t[8]!==h||t[9]!==o?(g=e=>{let t=typeof e==`function`?e(h):e;o?o(t):m(t),document.cookie=`${Cte}=${t}; path=/; max-age=${wte}`},t[8]=h,t[9]=o,t[10]=g):g=t[10];let _=g,v;t[11]!==u||t[12]!==_?(v=()=>u?f(jte):_(Ate),t[11]=u,t[12]=_,t[13]=v):v=t[13];let y=v,b,x;t[14]===y?(b=t[15],x=t[16]):(b=()=>{let e=e=>{e.key===Ote&&(e.metaKey||e.ctrlKey)&&(e.preventDefault(),y())};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},x=[y],t[14]=y,t[15]=b,t[16]=x),P.useEffect(b,x);let S=h?`expanded`:`collapsed`,C;t[17]!==u||t[18]!==h||t[19]!==d||t[20]!==_||t[21]!==S||t[22]!==y?(C={state:S,open:h,setOpen:_,isMobile:u,openMobile:d,setOpenMobile:f,toggleSidebar:y},t[17]=u,t[18]=h,t[19]=d,t[20]=_,t[21]=S,t[22]=y,t[23]=C):C=t[23];let w=C,T;t[24]===r?T=t[25]:(T=$c(`group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar`,r),t[24]=r,t[25]=T);let E;t[26]===s?E=t[27]:(E={"--sidebar-width":Tte,"--sidebar-width-icon":Dte,...s},t[26]=s,t[27]=E);let ee=E,D;t[28]!==n||t[29]!==a||t[30]!==T||t[31]!==ee?(D=(0,F.jsx)(`div`,{className:T,"data-slot":`sidebar-wrapper`,style:ee,...a,children:n}),t[28]=n,t[29]=a,t[30]=T,t[31]=ee,t[32]=D):D=t[32];let O;return t[33]!==w||t[34]!==D?(O=(0,F.jsx)(rg.Provider,{value:w,children:D}),t[33]=w,t[34]=D,t[35]=O):O=t[35],O}function Ate(e){return!e}function jte(e){return!e}function Mte(e){let t=(0,da.c)(46),n,r,i,a,o,s;t[0]===e?(n=t[1],r=t[2],i=t[3],a=t[4],o=t[5],s=t[6]):({side:a,variant:o,collapsible:s,className:r,children:n,...i}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i,t[4]=a,t[5]=o,t[6]=s);let c=a===void 0?`left`:a,l=o===void 0?`sidebar`:o,u=s===void 0?`offExamples`:s,{isMobile:d,state:f,openMobile:p,setOpenMobile:m}=ig();if(u===`none`){let e;t[7]===r?e=t[8]:(e=$c(`flex h-full w-(--sidebar-width) flex-col bg-sidebar text-sidebar-foreground`,r),t[7]=r,t[8]=e);let a;return t[9]!==n||t[10]!==i||t[11]!==e?(a=(0,F.jsx)(`div`,{className:e,"data-slot":`sidebar`,...i,children:n}),t[9]=n,t[10]=i,t[11]=e,t[12]=a):a=t[12],a}if(d){let e;t[13]===Symbol.for(`react.memo_cache_sentinel`)?(e={"--sidebar-width":Ete},t[13]=e):e=t[13];let r=e,a;t[14]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,F.jsxs)(wh,{className:`sr-only`,children:[(0,F.jsx)(Th,{children:`Sidebar`}),(0,F.jsx)(Eh,{children:`Displays the mobile sidebar.`})]}),t[14]=a):a=t[14];let o;t[15]===n?o=t[16]:(o=(0,F.jsx)(`div`,{className:`flex h-full w-full flex-col`,children:n}),t[15]=n,t[16]=o);let s;t[17]!==c||t[18]!==o?(s=(0,F.jsxs)(Ch,{className:`w-(--sidebar-width) bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden`,"data-mobile":`true`,"data-sidebar":`sidebar`,"data-slot":`sidebar`,side:c,style:r,children:[a,o]}),t[17]=c,t[18]=o,t[19]=s):s=t[19];let l;return t[20]!==p||t[21]!==i||t[22]!==m||t[23]!==s?(l=(0,F.jsx)(cte,{onOpenChange:m,open:p,...i,children:s}),t[20]=p,t[21]=i,t[22]=m,t[23]=s,t[24]=l):l=t[24],l}let h=f===`collapsed`?u:``,g=l===`floating`||l===`inset`?`group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]`:`group-data-[collapsible=icon]:w-(--sidebar-width-icon)`,_;t[25]===g?_=t[26]:(_=$c(`relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear`,`group-data-[collapsible=offExamples]:w-0`,`group-data-[side=right]:rotate-180`,g),t[25]=g,t[26]=_);let v;t[27]===_?v=t[28]:(v=(0,F.jsx)(`div`,{className:_,"data-slot":`sidebar-gap`}),t[27]=_,t[28]=v);let y=c===`left`?`left-0 group-data-[collapsible=offExamples]:left-[calc(var(--sidebar-width)*-1)]`:`right-0 group-data-[collapsible=offExamples]:right-[calc(var(--sidebar-width)*-1)]`,b=l===`floating`||l===`inset`?`p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]`:`group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l`,x;t[29]!==r||t[30]!==y||t[31]!==b?(x=$c(`fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex`,y,b,r),t[29]=r,t[30]=y,t[31]=b,t[32]=x):x=t[32];let S;t[33]===n?S=t[34]:(S=(0,F.jsx)(`div`,{className:`flex size-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:shadow-sm group-data-[variant=floating]:ring-1 group-data-[variant=floating]:ring-sidebar-border`,"data-sidebar":`sidebar`,"data-slot":`sidebar-inner`,children:n}),t[33]=n,t[34]=S);let C;t[35]!==i||t[36]!==x||t[37]!==S?(C=(0,F.jsx)(`div`,{className:x,"data-slot":`sidebar-container`,...i,children:S}),t[35]=i,t[36]=x,t[37]=S,t[38]=C):C=t[38];let w;return t[39]!==c||t[40]!==f||t[41]!==C||t[42]!==h||t[43]!==v||t[44]!==l?(w=(0,F.jsxs)(`div`,{className:`group peer hidden text-sidebar-foreground md:block`,"data-collapsible":h,"data-side":c,"data-slot":`sidebar`,"data-state":f,"data-variant":l,children:[v,C]}),t[39]=c,t[40]=f,t[41]=C,t[42]=h,t[43]=v,t[44]=l,t[45]=w):w=t[45],w}function Nte(e){let t=(0,da.c)(15),n,r,i;t[0]===e?(n=t[1],r=t[2],i=t[3]):({className:n,onClick:r,...i}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i);let{toggleSidebar:a}=ig(),o;t[4]===n?o=t[5]:(o=$c(n),t[4]=n,t[5]=o);let s;t[6]!==r||t[7]!==a?(s=e=>{r?.(e),a()},t[6]=r,t[7]=a,t[8]=s):s=t[8];let c,l;t[9]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,F.jsx)(Po,{}),l=(0,F.jsx)(`span`,{className:`sr-only`,children:`Toggle Sidebar`}),t[9]=c,t[10]=l):(c=t[9],l=t[10]);let u;return t[11]!==i||t[12]!==o||t[13]!==s?(u=(0,F.jsxs)(fl,{className:o,"data-sidebar":`trigger`,"data-slot":`sidebar-trigger`,onClick:s,size:`icon-lg`,variant:`ghost`,...i,children:[c,l]}),t[11]=i,t[12]=o,t[13]=s,t[14]=u):u=t[14],u}function Pte(e){let t=(0,da.c)(9),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let{toggleSidebar:i}=ig(),a;t[3]===n?a=t[4]:(a=$c(`absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border sm:flex`,`in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize`,`[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize`,`group-data-[collapsible=offExamples]:translate-x-0 group-data-[collapsible=offExamples]:after:left-full hover:group-data-[collapsible=offExamples]:bg-sidebar`,`[[data-side=left][data-collapsible=offExamples]_&]:-right-2`,`[[data-side=right][data-collapsible=offExamples]_&]:-left-2`,n),t[3]=n,t[4]=a);let o;return t[5]!==r||t[6]!==a||t[7]!==i?(o=(0,F.jsx)(`button`,{"aria-label":`Toggle Sidebar`,className:a,"data-sidebar":`rail`,"data-slot":`sidebar-rail`,onClick:i,tabIndex:-1,title:`Toggle Sidebar`,...r}),t[5]=r,t[6]=a,t[7]=i,t[8]=o):o=t[8],o}function Fte(e){let t=(0,da.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=$c(`flex flex-col gap-2 p-2`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(`div`,{className:i,"data-sidebar":`header`,"data-slot":`sidebar-header`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Ite(e){let t=(0,da.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=$c(`flex flex-col gap-2 p-2`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(`div`,{className:i,"data-sidebar":`footer`,"data-slot":`sidebar-footer`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Lte(e){let t=(0,da.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=$c(`mx-2 w-auto bg-sidebar-border`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(of,{className:i,"data-sidebar":`separator`,"data-slot":`sidebar-separator`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Rte(e){let t=(0,da.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=$c(`no-scrollbar flex min-h-0 flex-1 flex-col gap-0 overflow-auto group-data-[collapsible=icon]:overflow-hidden`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(`div`,{className:i,"data-sidebar":`content`,"data-slot":`sidebar-content`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function ag(e){let t=(0,da.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=$c(`relative flex w-full min-w-0 flex-col px-2 py-1`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(`div`,{className:i,"data-sidebar":`group`,"data-slot":`sidebar-group`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function og(e){let t=(0,da.c)(10),n,r,i,a;if(t[0]!==e){let{className:o,render:s,...c}=e;n=s,a=ro,r=`div`,i=va({className:$c(`flex h-8 shrink-0 items-center rounded-md px-2 text-xs text-sidebar-foreground/70 ring-sidebar-ring outline-hidden transition-[margin,opacity] duration-200 ease-linear group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0 focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0`,o)},c),t[0]=e,t[1]=n,t[2]=r,t[3]=i,t[4]=a}else n=t[1],r=t[2],i=t[3],a=t[4];let o;t[5]===Symbol.for(`react.memo_cache_sentinel`)?(o={slot:`sidebar-group-label`,sidebar:`group-label`},t[5]=o):o=t[5];let s;return t[6]!==n||t[7]!==r||t[8]!==i?(s={defaultTagName:r,props:i,render:n,state:o},t[6]=n,t[7]=r,t[8]=i,t[9]=s):s=t[9],a(s)}function sg(e){let t=(0,da.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=$c(`flex w-full min-w-0 flex-col gap-px`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(`ul`,{className:i,"data-sidebar":`menu`,"data-slot":`sidebar-menu`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function cg(e){let t=(0,da.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=$c(`group/menu-item relative`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,F.jsx)(`li`,{className:i,"data-sidebar":`menu-item`,"data-slot":`sidebar-menu-item`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}var zte=co(`peer/menu-button group/menu-button flex w-full items-center gap-2 overflow-hidden rounded-[calc(var(--radius-sm)+2px)] p-2 text-left text-xs ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-active:bg-sidebar-accent data-active:font-medium data-active:text-sidebar-accent-foreground data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate`,{variants:{variant:{default:`hover:bg-sidebar-accent hover:text-sidebar-accent-foreground`,outline:`bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]`},size:{default:`h-8 text-xs`,sm:`h-7 text-xs`,lg:`h-12 text-xs group-data-[collapsible=icon]:p-0!`}},defaultVariants:{variant:`default`,size:`default`}});function lg(e){let t=(0,da.c)(15),{render:n,isActive:r,variant:i,size:a,tooltip:o,className:s,...c}=e,l=r===void 0?!1:r,u=i===void 0?`default`:i,d=a===void 0?`default`:a,{isMobile:f,state:p}=ig(),m=va({className:$c(zte({variant:u,size:d}),s)},c),h=o?vte:n,g;t[0]!==l||t[1]!==d?(g={slot:`sidebar-menu-button`,sidebar:`menu-button`,size:d,active:l},t[0]=l,t[1]=d,t[2]=g):g=t[2];let _;t[3]!==m||t[4]!==h||t[5]!==g?(_={defaultTagName:`button`,props:m,render:h,state:g},t[3]=m,t[4]=h,t[5]=g,t[6]=_):_=t[6];let v=ro(_);if(!o)return v;let y;t[7]===o?y=t[8]:(y=typeof o==`string`?{children:o}:o,t[7]=o,t[8]=y);let b=y,x=p!==`collapsed`||f,S;t[9]!==x||t[10]!==b?(S=(0,F.jsx)(yte,{align:`center`,hidden:x,side:`right`,...b}),t[9]=x,t[10]=b,t[11]=S):S=t[11];let C;return t[12]!==v||t[13]!==S?(C=(0,F.jsxs)(_te,{children:[v,S]}),t[12]=v,t[13]=S,t[14]=C):C=t[14],C}var ug;function B(e,t,n){function r(n,r){if(n._zod||Object.defineProperty(n,`_zod`,{value:{def:r,constr:o,traits:new Set},enumerable:!1}),n._zod.traits.has(e))return;n._zod.traits.add(e),t(n,r);let i=o.prototype,a=Object.keys(i);for(let e=0;en?.Parent&&t instanceof n.Parent?!0:t?._zod?.traits?.has(e)}),Object.defineProperty(o,`name`,{value:e}),o}var dg=class extends Error{constructor(){super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`)}},fg=class extends Error{constructor(e){super(`Encountered unidirectional transform during encode: ${e}`),this.name=`ZodEncodeError`}};(ug=globalThis).__zod_globalConfig??(ug.__zod_globalConfig={});var pg=globalThis.__zod_globalConfig;function mg(e){return e&&Object.assign(pg,e),pg}function hg(e){let t=Object.values(e).filter(e=>typeof e==`number`);return Object.entries(e).filter(([e,n])=>t.indexOf(+e)===-1).map(([e,t])=>t)}function gg(e,t){return typeof t==`bigint`?t.toString():t}function _g(e){return{get value(){{let t=e();return Object.defineProperty(this,`value`,{value:t}),t}throw Error(`cached value already set`)}}}function vg(e){return e==null}function yg(e){let t=+!!e.startsWith(`^`),n=e.endsWith(`$`)?e.length-1:e.length;return e.slice(t,n)}function Bte(e,t){let n=e/t,r=Math.round(n),i=2**-52*Math.max(Math.abs(n),1);return Math.abs(n-r){};function Eg(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}var Hte=_g(()=>{if(pg.jitless||typeof navigator<`u`&&navigator?.userAgent?.includes(`Cloudflare`))return!1;try{return Function(``),!0}catch{return!1}});function Dg(e){if(Eg(e)===!1)return!1;let t=e.constructor;if(t===void 0||typeof t!=`function`)return!0;let n=t.prototype;return!(Eg(n)===!1||Object.prototype.hasOwnProperty.call(n,`isPrototypeOf`)===!1)}function Og(e){return Dg(e)?{...e}:Array.isArray(e)?[...e]:e instanceof Map?new Map(e):e instanceof Set?new Set(e):e}var Ute=new Set([`string`,`number`,`symbol`]);function kg(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function Ag(e,t,n){let r=new e._zod.constr(t??e._zod.def);return(!t||n?.parent)&&(r._zod.parent=e),r}function V(e){let t=e;if(!t)return{};if(typeof t==`string`)return{error:()=>t};if(t?.message!==void 0){if(t?.error!==void 0)throw Error("Cannot specify both `message` and `error` params");t.error=t.message}return delete t.message,typeof t.error==`string`?{...t,error:()=>t.error}:t}function Wte(e){return Object.keys(e).filter(t=>e[t]._zod.optin===`optional`&&e[t]._zod.optout===`optional`)}var Gte={safeint:[-(2**53-1),2**53-1],int32:[-2147483648,2147483647],uint32:[0,4294967295],float32:[-34028234663852886e22,34028234663852886e22],float64:[-Number.MAX_VALUE,Number.MAX_VALUE]};function Kte(e,t){let n=e._zod.def,r=n.checks;if(r&&r.length>0)throw Error(`.pick() cannot be used on object schemas containing refinements`);return Ag(e,Cg(e._zod.def,{get shape(){let e={};for(let r in t){if(!(r in n.shape))throw Error(`Unrecognized key: "${r}"`);t[r]&&(e[r]=n.shape[r])}return Sg(this,`shape`,e),e},checks:[]}))}function qte(e,t){let n=e._zod.def,r=n.checks;if(r&&r.length>0)throw Error(`.omit() cannot be used on object schemas containing refinements`);return Ag(e,Cg(e._zod.def,{get shape(){let r={...e._zod.def.shape};for(let e in t){if(!(e in n.shape))throw Error(`Unrecognized key: "${e}"`);t[e]&&delete r[e]}return Sg(this,`shape`,r),r},checks:[]}))}function Jte(e,t){if(!Dg(t))throw Error(`Invalid input to extend: expected a plain object`);let n=e._zod.def.checks;if(n&&n.length>0){let n=e._zod.def.shape;for(let e in t)if(Object.getOwnPropertyDescriptor(n,e)!==void 0)throw Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead.")}return Ag(e,Cg(e._zod.def,{get shape(){let n={...e._zod.def.shape,...t};return Sg(this,`shape`,n),n}}))}function Yte(e,t){if(!Dg(t))throw Error(`Invalid input to safeExtend: expected a plain object`);return Ag(e,Cg(e._zod.def,{get shape(){let n={...e._zod.def.shape,...t};return Sg(this,`shape`,n),n}}))}function Xte(e,t){if(e._zod.def.checks?.length)throw Error(`.merge() cannot be used on object schemas containing refinements. Use .safeExtend() instead.`);return Ag(e,Cg(e._zod.def,{get shape(){let n={...e._zod.def.shape,...t._zod.def.shape};return Sg(this,`shape`,n),n},get catchall(){return t._zod.def.catchall},checks:t._zod.def.checks??[]}))}function Zte(e,t,n){let r=t._zod.def.checks;if(r&&r.length>0)throw Error(`.partial() cannot be used on object schemas containing refinements`);return Ag(t,Cg(t._zod.def,{get shape(){let r=t._zod.def.shape,i={...r};if(n)for(let t in n){if(!(t in r))throw Error(`Unrecognized key: "${t}"`);n[t]&&(i[t]=e?new e({type:`optional`,innerType:r[t]}):r[t])}else for(let t in r)i[t]=e?new e({type:`optional`,innerType:r[t]}):r[t];return Sg(this,`shape`,i),i},checks:[]}))}function Qte(e,t,n){return Ag(t,Cg(t._zod.def,{get shape(){let r=t._zod.def.shape,i={...r};if(n)for(let t in n){if(!(t in i))throw Error(`Unrecognized key: "${t}"`);n[t]&&(i[t]=new e({type:`nonoptional`,innerType:r[t]}))}else for(let t in r)i[t]=new e({type:`nonoptional`,innerType:r[t]});return Sg(this,`shape`,i),i}}))}function jg(e,t=0){if(e.aborted===!0)return!0;for(let n=t;n{var n;return(n=t).path??(n.path=[]),t.path.unshift(e),t})}function Ng(e){return typeof e==`string`?e:e?.message}function Pg(e,t,n){let r=e.message?e.message:Ng(e.inst?._zod.def?.error?.(e))??Ng(t?.error?.(e))??Ng(n.customError?.(e))??Ng(n.localeError?.(e))??`Invalid input`,{inst:i,continue:a,input:o,...s}=e;return s.path??=[],s.message=r,t?.reportInput&&(s.input=o),s}function Fg(e){return Array.isArray(e)?`array`:typeof e==`string`?`string`:`unknown`}function Ig(...e){let[t,n,r]=e;return typeof t==`string`?{message:t,code:`custom`,input:n,inst:r}:{...t}}var Lg=(e,t)=>{e.name=`$ZodError`,Object.defineProperty(e,`_zod`,{value:e._zod,enumerable:!1}),Object.defineProperty(e,`issues`,{value:t,enumerable:!1}),e.message=JSON.stringify(t,gg,2),Object.defineProperty(e,`toString`,{value:()=>e.message,enumerable:!1})},Rg=B(`$ZodError`,Lg),zg=B(`$ZodError`,Lg,{Parent:Error});function ene(e,t=e=>e.message){let n={},r=[];for(let i of e.issues)i.path.length>0?(n[i.path[0]]=n[i.path[0]]||[],n[i.path[0]].push(t(i))):r.push(t(i));return{formErrors:r,fieldErrors:n}}function tne(e,t=e=>e.message){let n={_errors:[]},r=(e,i=[])=>{for(let a of e.issues)if(a.code===`invalid_union`&&a.errors.length)a.errors.map(e=>r({issues:e},[...i,...a.path]));else if(a.code===`invalid_key`)r({issues:a.issues},[...i,...a.path]);else if(a.code===`invalid_element`)r({issues:a.issues},[...i,...a.path]);else{let e=[...i,...a.path];if(e.length===0)n._errors.push(t(a));else{let r=n,i=0;for(;i(t,n,r,i)=>{let a=r?{...r,async:!1}:{async:!1},o=t._zod.run({value:n,issues:[]},a);if(o instanceof Promise)throw new dg;if(o.issues.length){let t=new(i?.Err??e)(o.issues.map(e=>Pg(e,a,mg())));throw Tg(t,i?.callee),t}return o.value},nne=Bg(zg),Vg=e=>async(t,n,r,i)=>{let a=r?{...r,async:!0}:{async:!0},o=t._zod.run({value:n,issues:[]},a);if(o instanceof Promise&&(o=await o),o.issues.length){let t=new(i?.Err??e)(o.issues.map(e=>Pg(e,a,mg())));throw Tg(t,i?.callee),t}return o.value},rne=Vg(zg),Hg=e=>(t,n,r)=>{let i=r?{...r,async:!1}:{async:!1},a=t._zod.run({value:n,issues:[]},i);if(a instanceof Promise)throw new dg;return a.issues.length?{success:!1,error:new(e??Rg)(a.issues.map(e=>Pg(e,i,mg())))}:{success:!0,data:a.value}},ine=Hg(zg),Ug=e=>async(t,n,r)=>{let i=r?{...r,async:!0}:{async:!0},a=t._zod.run({value:n,issues:[]},i);return a instanceof Promise&&(a=await a),a.issues.length?{success:!1,error:new e(a.issues.map(e=>Pg(e,i,mg())))}:{success:!0,data:a.value}},ane=Ug(zg),one=e=>(t,n,r)=>{let i=r?{...r,direction:`backward`}:{direction:`backward`};return Bg(e)(t,n,i)},sne=e=>(t,n,r)=>Bg(e)(t,n,r),cne=e=>async(t,n,r)=>{let i=r?{...r,direction:`backward`}:{direction:`backward`};return Vg(e)(t,n,i)},lne=e=>async(t,n,r)=>Vg(e)(t,n,r),une=e=>(t,n,r)=>{let i=r?{...r,direction:`backward`}:{direction:`backward`};return Hg(e)(t,n,i)},dne=e=>(t,n,r)=>Hg(e)(t,n,r),fne=e=>async(t,n,r)=>{let i=r?{...r,direction:`backward`}:{direction:`backward`};return Ug(e)(t,n,i)},pne=e=>async(t,n,r)=>Ug(e)(t,n,r),mne=/^[cC][0-9a-z]{6,}$/,Wg=/^[0-9a-z]+$/,Gg=/^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/,Kg=/^[0-9a-vA-V]{20}$/,qg=/^[A-Za-z0-9]{27}$/,Jg=/^[a-zA-Z0-9_-]{21}$/,Yg=/^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/,Xg=/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/,Zg=e=>e?RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${e}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`):/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/,Qg=/^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/,$g=`^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`;function e_(){return new RegExp($g,`u`)}var t_=/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,n_=/^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/,r_=/^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/,i_=/^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/,a_=/^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/,o_=/^[A-Za-z0-9_-]*$/,s_=/^https?$/,c_=/^\+[1-9]\d{6,14}$/,l_=`(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`,u_=RegExp(`^${l_}$`);function d_(e){let t=`(?:[01]\\d|2[0-3]):[0-5]\\d`;return typeof e.precision==`number`?e.precision===-1?`${t}`:e.precision===0?`${t}:[0-5]\\d`:`${t}:[0-5]\\d\\.\\d{${e.precision}}`:`${t}(?::[0-5]\\d(?:\\.\\d+)?)?`}function f_(e){return RegExp(`^${d_(e)}$`)}function p_(e){let t=d_({precision:e.precision}),n=[`Z`];e.local&&n.push(``),e.offset&&n.push(`([+-](?:[01]\\d|2[0-3]):[0-5]\\d)`);let r=`${t}(?:${n.join(`|`)})`;return RegExp(`^${l_}T(?:${r})$`)}var m_=e=>{let t=e?`[\\s\\S]{${e?.minimum??0},${e?.maximum??``}}`:`[\\s\\S]*`;return RegExp(`^${t}$`)},h_=/^-?\d+$/,g_=/^-?\d+(?:\.\d+)?$/,__=/^(?:true|false)$/i,v_=/^[^A-Z]*$/,y_=/^[^a-z]*$/,b_=B(`$ZodCheck`,(e,t)=>{var n;e._zod??={},e._zod.def=t,(n=e._zod).onattach??(n.onattach=[])}),x_={number:`number`,bigint:`bigint`,object:`date`},S_=B(`$ZodCheckLessThan`,(e,t)=>{b_.init(e,t);let n=x_[typeof t.value];e._zod.onattach.push(e=>{let n=e._zod.bag,r=(t.inclusive?n.maximum:n.exclusiveMaximum)??1/0;t.value{(t.inclusive?r.value<=t.value:r.value{b_.init(e,t);let n=x_[typeof t.value];e._zod.onattach.push(e=>{let n=e._zod.bag,r=(t.inclusive?n.minimum:n.exclusiveMinimum)??-1/0;t.value>r&&(t.inclusive?n.minimum=t.value:n.exclusiveMinimum=t.value)}),e._zod.check=r=>{(t.inclusive?r.value>=t.value:r.value>t.value)||r.issues.push({origin:n,code:`too_small`,minimum:typeof t.value==`object`?t.value.getTime():t.value,input:r.value,inclusive:t.inclusive,inst:e,continue:!t.abort})}}),w_=B(`$ZodCheckMultipleOf`,(e,t)=>{b_.init(e,t),e._zod.onattach.push(e=>{var n;(n=e._zod.bag).multipleOf??(n.multipleOf=t.value)}),e._zod.check=n=>{if(typeof n.value!=typeof t.value)throw Error(`Cannot mix number and bigint in multiple_of check.`);(typeof n.value==`bigint`?n.value%t.value===BigInt(0):Bte(n.value,t.value)===0)||n.issues.push({origin:typeof n.value,code:`not_multiple_of`,divisor:t.value,input:n.value,inst:e,continue:!t.abort})}}),T_=B(`$ZodCheckNumberFormat`,(e,t)=>{b_.init(e,t),t.format=t.format||`float64`;let n=t.format?.includes(`int`),r=n?`int`:`number`,[i,a]=Gte[t.format];e._zod.onattach.push(e=>{let r=e._zod.bag;r.format=t.format,r.minimum=i,r.maximum=a,n&&(r.pattern=h_)}),e._zod.check=o=>{let s=o.value;if(n){if(!Number.isInteger(s)){o.issues.push({expected:r,format:t.format,code:`invalid_type`,continue:!1,input:s,inst:e});return}if(!Number.isSafeInteger(s)){s>0?o.issues.push({input:s,code:`too_big`,maximum:2**53-1,note:`Integers must be within the safe integer range.`,inst:e,origin:r,inclusive:!0,continue:!t.abort}):o.issues.push({input:s,code:`too_small`,minimum:-(2**53-1),note:`Integers must be within the safe integer range.`,inst:e,origin:r,inclusive:!0,continue:!t.abort});return}}sa&&o.issues.push({origin:`number`,input:s,code:`too_big`,maximum:a,inclusive:!0,inst:e,continue:!t.abort})}}),E_=B(`$ZodCheckMaxLength`,(e,t)=>{var n;b_.init(e,t),(n=e._zod.def).when??(n.when=e=>{let t=e.value;return!vg(t)&&t.length!==void 0}),e._zod.onattach.push(e=>{let n=e._zod.bag.maximum??1/0;t.maximum{let r=n.value;if(r.length<=t.maximum)return;let i=Fg(r);n.issues.push({origin:i,code:`too_big`,maximum:t.maximum,inclusive:!0,input:r,inst:e,continue:!t.abort})}}),D_=B(`$ZodCheckMinLength`,(e,t)=>{var n;b_.init(e,t),(n=e._zod.def).when??(n.when=e=>{let t=e.value;return!vg(t)&&t.length!==void 0}),e._zod.onattach.push(e=>{let n=e._zod.bag.minimum??-1/0;t.minimum>n&&(e._zod.bag.minimum=t.minimum)}),e._zod.check=n=>{let r=n.value;if(r.length>=t.minimum)return;let i=Fg(r);n.issues.push({origin:i,code:`too_small`,minimum:t.minimum,inclusive:!0,input:r,inst:e,continue:!t.abort})}}),O_=B(`$ZodCheckLengthEquals`,(e,t)=>{var n;b_.init(e,t),(n=e._zod.def).when??(n.when=e=>{let t=e.value;return!vg(t)&&t.length!==void 0}),e._zod.onattach.push(e=>{let n=e._zod.bag;n.minimum=t.length,n.maximum=t.length,n.length=t.length}),e._zod.check=n=>{let r=n.value,i=r.length;if(i===t.length)return;let a=Fg(r),o=i>t.length;n.issues.push({origin:a,...o?{code:`too_big`,maximum:t.length}:{code:`too_small`,minimum:t.length},inclusive:!0,exact:!0,input:n.value,inst:e,continue:!t.abort})}}),k_=B(`$ZodCheckStringFormat`,(e,t)=>{var n,r;b_.init(e,t),e._zod.onattach.push(e=>{let n=e._zod.bag;n.format=t.format,t.pattern&&(n.patterns??=new Set,n.patterns.add(t.pattern))}),t.pattern?(n=e._zod).check??(n.check=n=>{t.pattern.lastIndex=0,!t.pattern.test(n.value)&&n.issues.push({origin:`string`,code:`invalid_format`,format:t.format,input:n.value,...t.pattern?{pattern:t.pattern.toString()}:{},inst:e,continue:!t.abort})}):(r=e._zod).check??(r.check=()=>{})}),A_=B(`$ZodCheckRegex`,(e,t)=>{k_.init(e,t),e._zod.check=n=>{t.pattern.lastIndex=0,!t.pattern.test(n.value)&&n.issues.push({origin:`string`,code:`invalid_format`,format:`regex`,input:n.value,pattern:t.pattern.toString(),inst:e,continue:!t.abort})}}),j_=B(`$ZodCheckLowerCase`,(e,t)=>{t.pattern??=v_,k_.init(e,t)}),M_=B(`$ZodCheckUpperCase`,(e,t)=>{t.pattern??=y_,k_.init(e,t)}),N_=B(`$ZodCheckIncludes`,(e,t)=>{b_.init(e,t);let n=kg(t.includes),r=new RegExp(typeof t.position==`number`?`^.{${t.position}}${n}`:n);t.pattern=r,e._zod.onattach.push(e=>{let t=e._zod.bag;t.patterns??=new Set,t.patterns.add(r)}),e._zod.check=n=>{n.value.includes(t.includes,t.position)||n.issues.push({origin:`string`,code:`invalid_format`,format:`includes`,includes:t.includes,input:n.value,inst:e,continue:!t.abort})}}),P_=B(`$ZodCheckStartsWith`,(e,t)=>{b_.init(e,t);let n=RegExp(`^${kg(t.prefix)}.*`);t.pattern??=n,e._zod.onattach.push(e=>{let t=e._zod.bag;t.patterns??=new Set,t.patterns.add(n)}),e._zod.check=n=>{n.value.startsWith(t.prefix)||n.issues.push({origin:`string`,code:`invalid_format`,format:`starts_with`,prefix:t.prefix,input:n.value,inst:e,continue:!t.abort})}}),F_=B(`$ZodCheckEndsWith`,(e,t)=>{b_.init(e,t);let n=RegExp(`.*${kg(t.suffix)}$`);t.pattern??=n,e._zod.onattach.push(e=>{let t=e._zod.bag;t.patterns??=new Set,t.patterns.add(n)}),e._zod.check=n=>{n.value.endsWith(t.suffix)||n.issues.push({origin:`string`,code:`invalid_format`,format:`ends_with`,suffix:t.suffix,input:n.value,inst:e,continue:!t.abort})}}),I_=B(`$ZodCheckOverwrite`,(e,t)=>{b_.init(e,t),e._zod.check=e=>{e.value=t.tx(e.value)}}),L_=class{constructor(e=[]){this.content=[],this.indent=0,this&&(this.args=e)}indented(e){this.indent+=1,e(this),--this.indent}write(e){if(typeof e==`function`){e(this,{execution:`sync`}),e(this,{execution:`async`});return}let t=e.split(` `).filter(e=>e),n=Math.min(...t.map(e=>e.length-e.trimStart().length)),r=t.map(e=>e.slice(n)).map(e=>` `.repeat(this.indent*2)+e);for(let e of r)this.content.push(e)}compile(){let e=Function,t=this?.args,n=[...(this?.content??[``]).map(e=>` ${e}`)];return new e(...t,n.join(` -`))}},oy={major:4,minor:4,patch:3},sy=B(`$ZodType`,(e,t)=>{var n;e??={},e._zod.def=t,e._zod.bag=e._zod.bag||{},e._zod.version=oy;let r=[...e._zod.def.checks??[]];e._zod.traits.has(`$ZodCheck`)&&r.unshift(e);for(let t of r)for(let n of t._zod.onattach)n(e);if(r.length===0)(n=e._zod).deferred??(n.deferred=[]),e._zod.deferred?.push(()=>{e._zod.run=e._zod.parse});else{let t=(e,t,n)=>{let r=L_(e),i;for(let a of t){if(a._zod.def.when){if(R_(e)||!a._zod.def.when(e))continue}else if(r)continue;let t=e.issues.length,o=a._zod.check(e);if(o instanceof Promise&&n?.async===!1)throw new i_;if(i||o instanceof Promise)i=(i??Promise.resolve()).then(async()=>{await o,e.issues.length!==t&&(r||=L_(e,t))});else{if(e.issues.length===t)continue;r||=L_(e,t)}}return i?i.then(()=>e):e},n=(n,i,a)=>{if(L_(n))return n.aborted=!0,n;let o=t(i,r,a);if(o instanceof Promise){if(a.async===!1)throw new i_;return o.then(t=>e._zod.parse(t,a))}return e._zod.parse(o,a)};e._zod.run=(i,a)=>{if(a.skipChecks)return e._zod.parse(i,a);if(a.direction===`backward`){let t=e._zod.parse({value:i.value,issues:[]},{...a,skipChecks:!0});return t instanceof Promise?t.then(e=>n(e,i,a)):n(t,i,a)}let o=e._zod.parse(i,a);if(o instanceof Promise){if(a.async===!1)throw new i_;return o.then(e=>t(e,r,a))}return t(o,r,a)}}h_(e,`~standard`,()=>({validate:t=>{try{let n=ev(e,t);return n.success?{value:n.data}:{issues:n.error?.issues}}catch{return nv(e,t).then(e=>e.success?{value:e.data}:{issues:e.error?.issues})}},vendor:`zod`,version:1}))}),cy=B(`$ZodString`,(e,t)=>{sy.init(e,t),e._zod.pattern=[...e?._zod.bag?.patterns??[]].pop()??Iv(e._zod.bag),e._zod.parse=(n,r)=>{if(t.coerce)try{n.value=String(n.value)}catch{}return typeof n.value==`string`||n.issues.push({expected:`string`,code:`invalid_type`,input:n.value,inst:e}),n}}),ly=B(`$ZodStringFormat`,(e,t)=>{Zv.init(e,t),cy.init(e,t)}),uy=B(`$ZodGUID`,(e,t)=>{t.pattern??=vv,ly.init(e,t)}),dy=B(`$ZodUUID`,(e,t)=>{if(t.version){let e={v1:1,v2:2,v3:3,v4:4,v5:5,v6:6,v7:7,v8:8}[t.version];if(e===void 0)throw Error(`Invalid UUID version: "${t.version}"`);t.pattern??=yv(e)}else t.pattern??=yv();ly.init(e,t)}),fy=B(`$ZodEmail`,(e,t)=>{t.pattern??=bv,ly.init(e,t)}),py=B(`$ZodURL`,(e,t)=>{ly.init(e,t),e._zod.check=n=>{try{let r=n.value.trim();if(!t.normalize&&t.protocol?.source===kv.source&&!/^https?:\/\//i.test(r)){n.issues.push({code:`invalid_format`,format:`url`,note:`Invalid URL format`,input:n.value,inst:e,continue:!t.abort});return}let i=new URL(r);t.hostname&&(t.hostname.lastIndex=0,t.hostname.test(i.hostname)||n.issues.push({code:`invalid_format`,format:`url`,note:`Invalid hostname`,pattern:t.hostname.source,input:n.value,inst:e,continue:!t.abort})),t.protocol&&(t.protocol.lastIndex=0,t.protocol.test(i.protocol.endsWith(`:`)?i.protocol.slice(0,-1):i.protocol)||n.issues.push({code:`invalid_format`,format:`url`,note:`Invalid protocol`,pattern:t.protocol.source,input:n.value,inst:e,continue:!t.abort})),t.normalize?n.value=i.href:n.value=r;return}catch{n.issues.push({code:`invalid_format`,format:`url`,input:n.value,inst:e,continue:!t.abort})}}}),my=B(`$ZodEmoji`,(e,t)=>{t.pattern??=Sv(),ly.init(e,t)}),hy=B(`$ZodNanoID`,(e,t)=>{t.pattern??=gv,ly.init(e,t)}),gy=B(`$ZodCUID`,(e,t)=>{t.pattern??=dv,ly.init(e,t)}),_y=B(`$ZodCUID2`,(e,t)=>{t.pattern??=fv,ly.init(e,t)}),vy=B(`$ZodULID`,(e,t)=>{t.pattern??=pv,ly.init(e,t)}),yy=B(`$ZodXID`,(e,t)=>{t.pattern??=mv,ly.init(e,t)}),by=B(`$ZodKSUID`,(e,t)=>{t.pattern??=hv,ly.init(e,t)}),xy=B(`$ZodISODateTime`,(e,t)=>{t.pattern??=Fv(t),ly.init(e,t)}),Sy=B(`$ZodISODate`,(e,t)=>{t.pattern??=Mv,ly.init(e,t)}),Cy=B(`$ZodISOTime`,(e,t)=>{t.pattern??=Pv(t),ly.init(e,t)}),wy=B(`$ZodISODuration`,(e,t)=>{t.pattern??=_v,ly.init(e,t)}),Ty=B(`$ZodIPv4`,(e,t)=>{t.pattern??=Cv,ly.init(e,t),e._zod.bag.format=`ipv4`}),Ey=B(`$ZodIPv6`,(e,t)=>{t.pattern??=wv,ly.init(e,t),e._zod.bag.format=`ipv6`,e._zod.check=n=>{try{new URL(`http://[${n.value}]`)}catch{n.issues.push({code:`invalid_format`,format:`ipv6`,input:n.value,inst:e,continue:!t.abort})}}}),Dy=B(`$ZodCIDRv4`,(e,t)=>{t.pattern??=Tv,ly.init(e,t)}),Oy=B(`$ZodCIDRv6`,(e,t)=>{t.pattern??=Ev,ly.init(e,t),e._zod.check=n=>{let r=n.value.split(`/`);try{if(r.length!==2)throw Error();let[e,t]=r;if(!t)throw Error();let n=Number(t);if(`${n}`!==t||n<0||n>128)throw Error();new URL(`http://[${e}]`)}catch{n.issues.push({code:`invalid_format`,format:`cidrv6`,input:n.value,inst:e,continue:!t.abort})}}});function ky(e){if(e===``)return!0;if(/\s/.test(e)||e.length%4!=0)return!1;try{return atob(e),!0}catch{return!1}}var Ay=B(`$ZodBase64`,(e,t)=>{t.pattern??=Dv,ly.init(e,t),e._zod.bag.contentEncoding=`base64`,e._zod.check=n=>{ky(n.value)||n.issues.push({code:`invalid_format`,format:`base64`,input:n.value,inst:e,continue:!t.abort})}});function jy(e){if(!Ov.test(e))return!1;let t=e.replace(/[-_]/g,e=>e===`-`?`+`:`/`);return ky(t.padEnd(Math.ceil(t.length/4)*4,`=`))}var My=B(`$ZodBase64URL`,(e,t)=>{t.pattern??=Ov,ly.init(e,t),e._zod.bag.contentEncoding=`base64url`,e._zod.check=n=>{jy(n.value)||n.issues.push({code:`invalid_format`,format:`base64url`,input:n.value,inst:e,continue:!t.abort})}}),Ny=B(`$ZodE164`,(e,t)=>{t.pattern??=Av,ly.init(e,t)});function Py(e,t=null){try{let n=e.split(`.`);if(n.length!==3)return!1;let[r]=n;if(!r)return!1;let i=JSON.parse(atob(r));return!(`typ`in i&&i?.typ!==`JWT`||!i.alg||t&&(!(`alg`in i)||i.alg!==t))}catch{return!1}}var Fy=B(`$ZodJWT`,(e,t)=>{ly.init(e,t),e._zod.check=n=>{Py(n.value,t.alg)||n.issues.push({code:`invalid_format`,format:`jwt`,input:n.value,inst:e,continue:!t.abort})}}),Iy=B(`$ZodNumber`,(e,t)=>{sy.init(e,t),e._zod.pattern=e._zod.bag.pattern??Rv,e._zod.parse=(n,r)=>{if(t.coerce)try{n.value=Number(n.value)}catch{}let i=n.value;if(typeof i==`number`&&!Number.isNaN(i)&&Number.isFinite(i))return n;let a=typeof i==`number`?Number.isNaN(i)?`NaN`:Number.isFinite(i)?void 0:`Infinity`:void 0;return n.issues.push({expected:`number`,code:`invalid_type`,input:i,inst:e,...a?{received:a}:{}}),n}}),Ly=B(`$ZodNumberFormat`,(e,t)=>{qv.init(e,t),Iy.init(e,t)}),Ry=B(`$ZodBoolean`,(e,t)=>{sy.init(e,t),e._zod.pattern=zv,e._zod.parse=(n,r)=>{if(t.coerce)try{n.value=!!n.value}catch{}let i=n.value;return typeof i==`boolean`||n.issues.push({expected:`boolean`,code:`invalid_type`,input:i,inst:e}),n}}),zy=B(`$ZodUnknown`,(e,t)=>{sy.init(e,t),e._zod.parse=e=>e}),By=B(`$ZodNever`,(e,t)=>{sy.init(e,t),e._zod.parse=(t,n)=>(t.issues.push({expected:`never`,code:`invalid_type`,input:t.value,inst:e}),t)});function Vy(e,t,n){e.issues.length&&t.issues.push(...z_(n,e.issues)),t.value[n]=e.value}var qee=B(`$ZodArray`,(e,t)=>{sy.init(e,t),e._zod.parse=(n,r)=>{let i=n.value;if(!Array.isArray(i))return n.issues.push({expected:`array`,code:`invalid_type`,input:i,inst:e}),n;n.value=Array(i.length);let a=[];for(let e=0;eVy(t,n,e))):Vy(s,n,e)}return a.length?Promise.all(a).then(()=>n):n}});function Hy(e,t,n,r,i,a){let o=n in r;if(e.issues.length){if(i&&a&&!o)return;t.issues.push(...z_(n,e.issues))}if(!o&&!i){e.issues.length||t.issues.push({code:`invalid_type`,expected:`nonoptional`,input:void 0,path:[n]});return}e.value===void 0?o&&(t.value[n]=void 0):t.value[n]=e.value}function Uy(e){let t=Object.keys(e.shape);for(let n of t)if(!e.shape?.[n]?._zod?.traits?.has(`$ZodType`))throw Error(`Invalid element at key "${n}": expected a Zod schema`);let n=O_(e.shape);return{...e,keys:t,keySet:new Set(t),numKeys:t.length,optionalKeys:new Set(n)}}function Wy(e,t,n,r,i,a){let o=[],s=i.keySet,c=i.catchall._zod,l=c.def.type,u=c.optin===`optional`,d=c.optout===`optional`;for(let i in t){if(i===`__proto__`||s.has(i))continue;if(l===`never`){o.push(i);continue}let a=c.run({value:t[i],issues:[]},r);a instanceof Promise?e.push(a.then(e=>Hy(e,n,i,t,u,d))):Hy(a,n,i,t,u,d)}return o.length&&n.issues.push({code:`unrecognized_keys`,keys:o,input:t,inst:a}),e.length?Promise.all(e).then(()=>n):n}var Jee=B(`$ZodObject`,(e,t)=>{if(sy.init(e,t),!Object.getOwnPropertyDescriptor(t,`shape`)?.get){let e=t.shape;Object.defineProperty(t,`shape`,{get:()=>{let n={...e};return Object.defineProperty(t,`shape`,{value:n}),n}})}let n=u_(()=>Uy(t));h_(e._zod,`propValues`,()=>{let e=t.shape,n={};for(let t in e){let r=e[t]._zod;if(r.values){n[t]??(n[t]=new Set);for(let e of r.values)n[t].add(e)}}return n});let r=x_,i=t.catchall,a;e._zod.parse=(t,o)=>{a??=n.value;let s=t.value;if(!r(s))return t.issues.push({expected:`object`,code:`invalid_type`,input:s,inst:e}),t;t.value={};let c=[],l=a.shape;for(let e of a.keys){let n=l[e],r=n._zod.optin===`optional`,i=n._zod.optout===`optional`,a=n._zod.run({value:s[e],issues:[]},o);a instanceof Promise?c.push(a.then(n=>Hy(n,t,e,s,r,i))):Hy(a,t,e,s,r,i)}return i?Wy(c,s,t,o,n.value,e):c.length?Promise.all(c).then(()=>t):t}}),Yee=B(`$ZodObjectJIT`,(e,t)=>{Jee.init(e,t);let n=e._zod.parse,r=u_(()=>Uy(t)),i=e=>{let t=new ay([`shape`,`payload`,`ctx`]),n=r.value,i=e=>{let t=v_(e);return`shape[${t}]._zod.run({ value: input[${t}], issues: [] }, ctx)`};t.write(`const input = payload.value;`);let a=Object.create(null),o=0;for(let e of n.keys)a[e]=`key_${o++}`;t.write(`const newResult = {};`);for(let r of n.keys){let n=a[r],o=v_(r),s=e[r],c=s?._zod?.optin===`optional`,l=s?._zod?.optout===`optional`;t.write(`const ${n} = ${i(r)};`),c&&l?t.write(` +`))}},R_={major:4,minor:4,patch:3},z_=B(`$ZodType`,(e,t)=>{var n;e??={},e._zod.def=t,e._zod.bag=e._zod.bag||{},e._zod.version=R_;let r=[...e._zod.def.checks??[]];e._zod.traits.has(`$ZodCheck`)&&r.unshift(e);for(let t of r)for(let n of t._zod.onattach)n(e);if(r.length===0)(n=e._zod).deferred??(n.deferred=[]),e._zod.deferred?.push(()=>{e._zod.run=e._zod.parse});else{let t=(e,t,n)=>{let r=jg(e),i;for(let a of t){if(a._zod.def.when){if($te(e)||!a._zod.def.when(e))continue}else if(r)continue;let t=e.issues.length,o=a._zod.check(e);if(o instanceof Promise&&n?.async===!1)throw new dg;if(i||o instanceof Promise)i=(i??Promise.resolve()).then(async()=>{await o,e.issues.length!==t&&(r||=jg(e,t))});else{if(e.issues.length===t)continue;r||=jg(e,t)}}return i?i.then(()=>e):e},n=(n,i,a)=>{if(jg(n))return n.aborted=!0,n;let o=t(i,r,a);if(o instanceof Promise){if(a.async===!1)throw new dg;return o.then(t=>e._zod.parse(t,a))}return e._zod.parse(o,a)};e._zod.run=(i,a)=>{if(a.skipChecks)return e._zod.parse(i,a);if(a.direction===`backward`){let t=e._zod.parse({value:i.value,issues:[]},{...a,skipChecks:!0});return t instanceof Promise?t.then(e=>n(e,i,a)):n(t,i,a)}let o=e._zod.parse(i,a);if(o instanceof Promise){if(a.async===!1)throw new dg;return o.then(e=>t(e,r,a))}return t(o,r,a)}}xg(e,`~standard`,()=>({validate:t=>{try{let n=ine(e,t);return n.success?{value:n.data}:{issues:n.error?.issues}}catch{return ane(e,t).then(e=>e.success?{value:e.data}:{issues:e.error?.issues})}},vendor:`zod`,version:1}))}),B_=B(`$ZodString`,(e,t)=>{z_.init(e,t),e._zod.pattern=[...e?._zod.bag?.patterns??[]].pop()??m_(e._zod.bag),e._zod.parse=(n,r)=>{if(t.coerce)try{n.value=String(n.value)}catch{}return typeof n.value==`string`||n.issues.push({expected:`string`,code:`invalid_type`,input:n.value,inst:e}),n}}),V_=B(`$ZodStringFormat`,(e,t)=>{k_.init(e,t),B_.init(e,t)}),H_=B(`$ZodGUID`,(e,t)=>{t.pattern??=Xg,V_.init(e,t)}),U_=B(`$ZodUUID`,(e,t)=>{if(t.version){let e={v1:1,v2:2,v3:3,v4:4,v5:5,v6:6,v7:7,v8:8}[t.version];if(e===void 0)throw Error(`Invalid UUID version: "${t.version}"`);t.pattern??=Zg(e)}else t.pattern??=Zg();V_.init(e,t)}),W_=B(`$ZodEmail`,(e,t)=>{t.pattern??=Qg,V_.init(e,t)}),G_=B(`$ZodURL`,(e,t)=>{V_.init(e,t),e._zod.check=n=>{try{let r=n.value.trim();if(!t.normalize&&t.protocol?.source===s_.source&&!/^https?:\/\//i.test(r)){n.issues.push({code:`invalid_format`,format:`url`,note:`Invalid URL format`,input:n.value,inst:e,continue:!t.abort});return}let i=new URL(r);t.hostname&&(t.hostname.lastIndex=0,t.hostname.test(i.hostname)||n.issues.push({code:`invalid_format`,format:`url`,note:`Invalid hostname`,pattern:t.hostname.source,input:n.value,inst:e,continue:!t.abort})),t.protocol&&(t.protocol.lastIndex=0,t.protocol.test(i.protocol.endsWith(`:`)?i.protocol.slice(0,-1):i.protocol)||n.issues.push({code:`invalid_format`,format:`url`,note:`Invalid protocol`,pattern:t.protocol.source,input:n.value,inst:e,continue:!t.abort})),t.normalize?n.value=i.href:n.value=r;return}catch{n.issues.push({code:`invalid_format`,format:`url`,input:n.value,inst:e,continue:!t.abort})}}}),K_=B(`$ZodEmoji`,(e,t)=>{t.pattern??=e_(),V_.init(e,t)}),q_=B(`$ZodNanoID`,(e,t)=>{t.pattern??=Jg,V_.init(e,t)}),J_=B(`$ZodCUID`,(e,t)=>{t.pattern??=mne,V_.init(e,t)}),Y_=B(`$ZodCUID2`,(e,t)=>{t.pattern??=Wg,V_.init(e,t)}),X_=B(`$ZodULID`,(e,t)=>{t.pattern??=Gg,V_.init(e,t)}),Z_=B(`$ZodXID`,(e,t)=>{t.pattern??=Kg,V_.init(e,t)}),Q_=B(`$ZodKSUID`,(e,t)=>{t.pattern??=qg,V_.init(e,t)}),$_=B(`$ZodISODateTime`,(e,t)=>{t.pattern??=p_(t),V_.init(e,t)}),ev=B(`$ZodISODate`,(e,t)=>{t.pattern??=u_,V_.init(e,t)}),tv=B(`$ZodISOTime`,(e,t)=>{t.pattern??=f_(t),V_.init(e,t)}),nv=B(`$ZodISODuration`,(e,t)=>{t.pattern??=Yg,V_.init(e,t)}),rv=B(`$ZodIPv4`,(e,t)=>{t.pattern??=t_,V_.init(e,t),e._zod.bag.format=`ipv4`}),iv=B(`$ZodIPv6`,(e,t)=>{t.pattern??=n_,V_.init(e,t),e._zod.bag.format=`ipv6`,e._zod.check=n=>{try{new URL(`http://[${n.value}]`)}catch{n.issues.push({code:`invalid_format`,format:`ipv6`,input:n.value,inst:e,continue:!t.abort})}}}),av=B(`$ZodCIDRv4`,(e,t)=>{t.pattern??=r_,V_.init(e,t)}),ov=B(`$ZodCIDRv6`,(e,t)=>{t.pattern??=i_,V_.init(e,t),e._zod.check=n=>{let r=n.value.split(`/`);try{if(r.length!==2)throw Error();let[e,t]=r;if(!t)throw Error();let n=Number(t);if(`${n}`!==t||n<0||n>128)throw Error();new URL(`http://[${e}]`)}catch{n.issues.push({code:`invalid_format`,format:`cidrv6`,input:n.value,inst:e,continue:!t.abort})}}});function sv(e){if(e===``)return!0;if(/\s/.test(e)||e.length%4!=0)return!1;try{return atob(e),!0}catch{return!1}}var cv=B(`$ZodBase64`,(e,t)=>{t.pattern??=a_,V_.init(e,t),e._zod.bag.contentEncoding=`base64`,e._zod.check=n=>{sv(n.value)||n.issues.push({code:`invalid_format`,format:`base64`,input:n.value,inst:e,continue:!t.abort})}});function lv(e){if(!o_.test(e))return!1;let t=e.replace(/[-_]/g,e=>e===`-`?`+`:`/`);return sv(t.padEnd(Math.ceil(t.length/4)*4,`=`))}var uv=B(`$ZodBase64URL`,(e,t)=>{t.pattern??=o_,V_.init(e,t),e._zod.bag.contentEncoding=`base64url`,e._zod.check=n=>{lv(n.value)||n.issues.push({code:`invalid_format`,format:`base64url`,input:n.value,inst:e,continue:!t.abort})}}),dv=B(`$ZodE164`,(e,t)=>{t.pattern??=c_,V_.init(e,t)});function fv(e,t=null){try{let n=e.split(`.`);if(n.length!==3)return!1;let[r]=n;if(!r)return!1;let i=JSON.parse(atob(r));return!(`typ`in i&&i?.typ!==`JWT`||!i.alg||t&&(!(`alg`in i)||i.alg!==t))}catch{return!1}}var pv=B(`$ZodJWT`,(e,t)=>{V_.init(e,t),e._zod.check=n=>{fv(n.value,t.alg)||n.issues.push({code:`invalid_format`,format:`jwt`,input:n.value,inst:e,continue:!t.abort})}}),mv=B(`$ZodNumber`,(e,t)=>{z_.init(e,t),e._zod.pattern=e._zod.bag.pattern??g_,e._zod.parse=(n,r)=>{if(t.coerce)try{n.value=Number(n.value)}catch{}let i=n.value;if(typeof i==`number`&&!Number.isNaN(i)&&Number.isFinite(i))return n;let a=typeof i==`number`?Number.isNaN(i)?`NaN`:Number.isFinite(i)?void 0:`Infinity`:void 0;return n.issues.push({expected:`number`,code:`invalid_type`,input:i,inst:e,...a?{received:a}:{}}),n}}),hv=B(`$ZodNumberFormat`,(e,t)=>{T_.init(e,t),mv.init(e,t)}),gv=B(`$ZodBoolean`,(e,t)=>{z_.init(e,t),e._zod.pattern=__,e._zod.parse=(n,r)=>{if(t.coerce)try{n.value=!!n.value}catch{}let i=n.value;return typeof i==`boolean`||n.issues.push({expected:`boolean`,code:`invalid_type`,input:i,inst:e}),n}}),_v=B(`$ZodUnknown`,(e,t)=>{z_.init(e,t),e._zod.parse=e=>e}),vv=B(`$ZodNever`,(e,t)=>{z_.init(e,t),e._zod.parse=(t,n)=>(t.issues.push({expected:`never`,code:`invalid_type`,input:t.value,inst:e}),t)});function yv(e,t,n){e.issues.length&&t.issues.push(...Mg(n,e.issues)),t.value[n]=e.value}var bv=B(`$ZodArray`,(e,t)=>{z_.init(e,t),e._zod.parse=(n,r)=>{let i=n.value;if(!Array.isArray(i))return n.issues.push({expected:`array`,code:`invalid_type`,input:i,inst:e}),n;n.value=Array(i.length);let a=[];for(let e=0;eyv(t,n,e))):yv(s,n,e)}return a.length?Promise.all(a).then(()=>n):n}});function xv(e,t,n,r,i,a){let o=n in r;if(e.issues.length){if(i&&a&&!o)return;t.issues.push(...Mg(n,e.issues))}if(!o&&!i){e.issues.length||t.issues.push({code:`invalid_type`,expected:`nonoptional`,input:void 0,path:[n]});return}e.value===void 0?o&&(t.value[n]=void 0):t.value[n]=e.value}function Sv(e){let t=Object.keys(e.shape);for(let n of t)if(!e.shape?.[n]?._zod?.traits?.has(`$ZodType`))throw Error(`Invalid element at key "${n}": expected a Zod schema`);let n=Wte(e.shape);return{...e,keys:t,keySet:new Set(t),numKeys:t.length,optionalKeys:new Set(n)}}function Cv(e,t,n,r,i,a){let o=[],s=i.keySet,c=i.catchall._zod,l=c.def.type,u=c.optin===`optional`,d=c.optout===`optional`;for(let i in t){if(i===`__proto__`||s.has(i))continue;if(l===`never`){o.push(i);continue}let a=c.run({value:t[i],issues:[]},r);a instanceof Promise?e.push(a.then(e=>xv(e,n,i,t,u,d))):xv(a,n,i,t,u,d)}return o.length&&n.issues.push({code:`unrecognized_keys`,keys:o,input:t,inst:a}),e.length?Promise.all(e).then(()=>n):n}var wv=B(`$ZodObject`,(e,t)=>{if(z_.init(e,t),!Object.getOwnPropertyDescriptor(t,`shape`)?.get){let e=t.shape;Object.defineProperty(t,`shape`,{get:()=>{let n={...e};return Object.defineProperty(t,`shape`,{value:n}),n}})}let n=_g(()=>Sv(t));xg(e._zod,`propValues`,()=>{let e=t.shape,n={};for(let t in e){let r=e[t]._zod;if(r.values){n[t]??(n[t]=new Set);for(let e of r.values)n[t].add(e)}}return n});let r=Eg,i=t.catchall,a;e._zod.parse=(t,o)=>{a??=n.value;let s=t.value;if(!r(s))return t.issues.push({expected:`object`,code:`invalid_type`,input:s,inst:e}),t;t.value={};let c=[],l=a.shape;for(let e of a.keys){let n=l[e],r=n._zod.optin===`optional`,i=n._zod.optout===`optional`,a=n._zod.run({value:s[e],issues:[]},o);a instanceof Promise?c.push(a.then(n=>xv(n,t,e,s,r,i))):xv(a,t,e,s,r,i)}return i?Cv(c,s,t,o,n.value,e):c.length?Promise.all(c).then(()=>t):t}}),Tv=B(`$ZodObjectJIT`,(e,t)=>{wv.init(e,t);let n=e._zod.parse,r=_g(()=>Sv(t)),i=e=>{let t=new L_([`shape`,`payload`,`ctx`]),n=r.value,i=e=>{let t=wg(e);return`shape[${t}]._zod.run({ value: input[${t}], issues: [] }, ctx)`};t.write(`const input = payload.value;`);let a=Object.create(null),o=0;for(let e of n.keys)a[e]=`key_${o++}`;t.write(`const newResult = {};`);for(let r of n.keys){let n=a[r],o=wg(r),s=e[r],c=s?._zod?.optin===`optional`,l=s?._zod?.optout===`optional`;t.write(`const ${n} = ${i(r)};`),c&&l?t.write(` if (${n}.issues.length) { if (${o} in input) { payload.issues = payload.issues.concat(${n}.issues.map(iss => ({ @@ -68,25 +68,40 @@ Error generating stack: `+e.message+` } } - `)}t.write(`payload.value = newResult;`),t.write(`return payload;`);let s=t.compile();return(t,n)=>s(e,t,n)},a,o=x_,s=!o_.jitless,c=s&&S_.value,l=t.catchall,u;e._zod.parse=(d,f)=>{u??=r.value;let p=d.value;return o(p)?s&&c&&f?.async===!1&&f.jitless!==!0?(a||=i(t.shape),d=a(d,f),l?Wy([],p,d,f,u,e):d):n(d,f):(d.issues.push({expected:`object`,code:`invalid_type`,input:p,inst:e}),d)}});function Gy(e,t,n,r){for(let n of e)if(n.issues.length===0)return t.value=n.value,t;let i=e.filter(e=>!L_(e));return i.length===1?(t.value=i[0].value,i[0]):(t.issues.push({code:`invalid_union`,input:t.value,inst:n,errors:e.map(e=>e.issues.map(e=>V_(e,r,s_())))}),t)}var Xee=B(`$ZodUnion`,(e,t)=>{sy.init(e,t),h_(e._zod,`optin`,()=>t.options.some(e=>e._zod.optin===`optional`)?`optional`:void 0),h_(e._zod,`optout`,()=>t.options.some(e=>e._zod.optout===`optional`)?`optional`:void 0),h_(e._zod,`values`,()=>{if(t.options.every(e=>e._zod.values))return new Set(t.options.flatMap(e=>Array.from(e._zod.values)))}),h_(e._zod,`pattern`,()=>{if(t.options.every(e=>e._zod.pattern)){let e=t.options.map(e=>e._zod.pattern);return RegExp(`^(${e.map(e=>f_(e.source)).join(`|`)})$`)}});let n=t.options.length===1?t.options[0]._zod.run:null;e._zod.parse=(r,i)=>{if(n)return n(r,i);let a=!1,o=[];for(let e of t.options){let t=e._zod.run({value:r.value,issues:[]},i);if(t instanceof Promise)o.push(t),a=!0;else{if(t.issues.length===0)return t;o.push(t)}}return a?Promise.all(o).then(t=>Gy(t,r,e,i)):Gy(o,r,e,i)}}),Zee=B(`$ZodIntersection`,(e,t)=>{sy.init(e,t),e._zod.parse=(e,n)=>{let r=e.value,i=t.left._zod.run({value:r,issues:[]},n),a=t.right._zod.run({value:r,issues:[]},n);return i instanceof Promise||a instanceof Promise?Promise.all([i,a]).then(([t,n])=>qy(e,t,n)):qy(e,i,a)}});function Ky(e,t){if(e===t||e instanceof Date&&t instanceof Date&&+e==+t)return{valid:!0,data:e};if(C_(e)&&C_(t)){let n=Object.keys(t),r=Object.keys(e).filter(e=>n.indexOf(e)!==-1),i={...e,...t};for(let n of r){let r=Ky(e[n],t[n]);if(!r.valid)return{valid:!1,mergeErrorPath:[n,...r.mergeErrorPath]};i[n]=r.data}return{valid:!0,data:i}}if(Array.isArray(e)&&Array.isArray(t)){if(e.length!==t.length)return{valid:!1,mergeErrorPath:[]};let n=[];for(let r=0;re.l&&e.r).map(([e])=>e);if(a.length&&i&&e.issues.push({...i,keys:a}),L_(e))return e;let o=Ky(t.value,n.value);if(!o.valid)throw Error(`Unmergable intersection. Error path: ${JSON.stringify(o.mergeErrorPath)}`);return e.value=o.data,e}var Qee=B(`$ZodRecord`,(e,t)=>{sy.init(e,t),e._zod.parse=(n,r)=>{let i=n.value;if(!C_(i))return n.issues.push({expected:`record`,code:`invalid_type`,input:i,inst:e}),n;let a=[],o=t.keyType._zod.values;if(o){n.value={};let s=new Set;for(let c of o)if(typeof c==`string`||typeof c==`number`||typeof c==`symbol`){s.add(typeof c==`number`?c.toString():c);let o=t.keyType._zod.run({value:c,issues:[]},r);if(o instanceof Promise)throw Error(`Async schemas not supported in object keys currently`);if(o.issues.length){n.issues.push({code:`invalid_key`,origin:`record`,issues:o.issues.map(e=>V_(e,r,s_())),input:c,path:[c],inst:e});continue}let l=o.value,u=t.valueType._zod.run({value:i[c],issues:[]},r);u instanceof Promise?a.push(u.then(e=>{e.issues.length&&n.issues.push(...z_(c,e.issues)),n.value[l]=e.value})):(u.issues.length&&n.issues.push(...z_(c,u.issues)),n.value[l]=u.value)}let c;for(let e in i)s.has(e)||(c??=[],c.push(e));c&&c.length>0&&n.issues.push({code:`unrecognized_keys`,input:i,inst:e,keys:c})}else{n.value={};for(let o of Reflect.ownKeys(i)){if(o===`__proto__`||!Object.prototype.propertyIsEnumerable.call(i,o))continue;let s=t.keyType._zod.run({value:o,issues:[]},r);if(s instanceof Promise)throw Error(`Async schemas not supported in object keys currently`);if(typeof o==`string`&&Rv.test(o)&&s.issues.length){let e=t.keyType._zod.run({value:Number(o),issues:[]},r);if(e instanceof Promise)throw Error(`Async schemas not supported in object keys currently`);e.issues.length===0&&(s=e)}if(s.issues.length){t.mode===`loose`?n.value[o]=i[o]:n.issues.push({code:`invalid_key`,origin:`record`,issues:s.issues.map(e=>V_(e,r,s_())),input:o,path:[o],inst:e});continue}let c=t.valueType._zod.run({value:i[o],issues:[]},r);c instanceof Promise?a.push(c.then(e=>{e.issues.length&&n.issues.push(...z_(o,e.issues)),n.value[s.value]=e.value})):(c.issues.length&&n.issues.push(...z_(o,c.issues)),n.value[s.value]=c.value)}}return a.length?Promise.all(a).then(()=>n):n}}),$ee=B(`$ZodEnum`,(e,t)=>{sy.init(e,t);let n=c_(t.entries),r=new Set(n);e._zod.values=r,e._zod.pattern=RegExp(`^(${n.filter(e=>T_.has(typeof e)).map(e=>typeof e==`string`?E_(e):e.toString()).join(`|`)})$`),e._zod.parse=(t,i)=>{let a=t.value;return r.has(a)||t.issues.push({code:`invalid_value`,values:n,input:a,inst:e}),t}}),ete=B(`$ZodTransform`,(e,t)=>{sy.init(e,t),e._zod.optin=`optional`,e._zod.parse=(n,r)=>{if(r.direction===`backward`)throw new a_(e.constructor.name);let i=t.transform(n.value,n);if(r.async)return(i instanceof Promise?i:Promise.resolve(i)).then(e=>(n.value=e,n.fallback=!0,n));if(i instanceof Promise)throw new i_;return n.value=i,n.fallback=!0,n}});function Jy(e,t){return t===void 0&&(e.issues.length||e.fallback)?{issues:[],value:void 0}:e}var Yy=B(`$ZodOptional`,(e,t)=>{sy.init(e,t),e._zod.optin=`optional`,e._zod.optout=`optional`,h_(e._zod,`values`,()=>t.innerType._zod.values?new Set([...t.innerType._zod.values,void 0]):void 0),h_(e._zod,`pattern`,()=>{let e=t.innerType._zod.pattern;return e?RegExp(`^(${f_(e.source)})?$`):void 0}),e._zod.parse=(e,n)=>{if(t.innerType._zod.optin===`optional`){let r=e.value,i=t.innerType._zod.run(e,n);return i instanceof Promise?i.then(e=>Jy(e,r)):Jy(i,r)}return e.value===void 0?e:t.innerType._zod.run(e,n)}}),tte=B(`$ZodExactOptional`,(e,t)=>{Yy.init(e,t),h_(e._zod,`values`,()=>t.innerType._zod.values),h_(e._zod,`pattern`,()=>t.innerType._zod.pattern),e._zod.parse=(e,n)=>t.innerType._zod.run(e,n)}),nte=B(`$ZodNullable`,(e,t)=>{sy.init(e,t),h_(e._zod,`optin`,()=>t.innerType._zod.optin),h_(e._zod,`optout`,()=>t.innerType._zod.optout),h_(e._zod,`pattern`,()=>{let e=t.innerType._zod.pattern;return e?RegExp(`^(${f_(e.source)}|null)$`):void 0}),h_(e._zod,`values`,()=>t.innerType._zod.values?new Set([...t.innerType._zod.values,null]):void 0),e._zod.parse=(e,n)=>e.value===null?e:t.innerType._zod.run(e,n)}),rte=B(`$ZodDefault`,(e,t)=>{sy.init(e,t),e._zod.optin=`optional`,h_(e._zod,`values`,()=>t.innerType._zod.values),e._zod.parse=(e,n)=>{if(n.direction===`backward`)return t.innerType._zod.run(e,n);if(e.value===void 0)return e.value=t.defaultValue,e;let r=t.innerType._zod.run(e,n);return r instanceof Promise?r.then(e=>Xy(e,t)):Xy(r,t)}});function Xy(e,t){return e.value===void 0&&(e.value=t.defaultValue),e}var ite=B(`$ZodPrefault`,(e,t)=>{sy.init(e,t),e._zod.optin=`optional`,h_(e._zod,`values`,()=>t.innerType._zod.values),e._zod.parse=(e,n)=>(n.direction===`backward`||e.value===void 0&&(e.value=t.defaultValue),t.innerType._zod.run(e,n))}),ate=B(`$ZodNonOptional`,(e,t)=>{sy.init(e,t),h_(e._zod,`values`,()=>{let e=t.innerType._zod.values;return e?new Set([...e].filter(e=>e!==void 0)):void 0}),e._zod.parse=(n,r)=>{let i=t.innerType._zod.run(n,r);return i instanceof Promise?i.then(t=>Zy(t,e)):Zy(i,e)}});function Zy(e,t){return!e.issues.length&&e.value===void 0&&e.issues.push({code:`invalid_type`,expected:`nonoptional`,input:e.value,inst:t}),e}var ote=B(`$ZodCatch`,(e,t)=>{sy.init(e,t),e._zod.optin=`optional`,h_(e._zod,`optout`,()=>t.innerType._zod.optout),h_(e._zod,`values`,()=>t.innerType._zod.values),e._zod.parse=(e,n)=>{if(n.direction===`backward`)return t.innerType._zod.run(e,n);let r=t.innerType._zod.run(e,n);return r instanceof Promise?r.then(r=>(e.value=r.value,r.issues.length&&(e.value=t.catchValue({...e,error:{issues:r.issues.map(e=>V_(e,n,s_()))},input:e.value}),e.issues=[],e.fallback=!0),e)):(e.value=r.value,r.issues.length&&(e.value=t.catchValue({...e,error:{issues:r.issues.map(e=>V_(e,n,s_()))},input:e.value}),e.issues=[],e.fallback=!0),e)}}),ste=B(`$ZodPipe`,(e,t)=>{sy.init(e,t),h_(e._zod,`values`,()=>t.in._zod.values),h_(e._zod,`optin`,()=>t.in._zod.optin),h_(e._zod,`optout`,()=>t.out._zod.optout),h_(e._zod,`propValues`,()=>t.in._zod.propValues),e._zod.parse=(e,n)=>{if(n.direction===`backward`){let r=t.out._zod.run(e,n);return r instanceof Promise?r.then(e=>Qy(e,t.in,n)):Qy(r,t.in,n)}let r=t.in._zod.run(e,n);return r instanceof Promise?r.then(e=>Qy(e,t.out,n)):Qy(r,t.out,n)}});function Qy(e,t,n){return e.issues.length?(e.aborted=!0,e):t._zod.run({value:e.value,issues:e.issues,fallback:e.fallback},n)}var cte=B(`$ZodReadonly`,(e,t)=>{sy.init(e,t),h_(e._zod,`propValues`,()=>t.innerType._zod.propValues),h_(e._zod,`values`,()=>t.innerType._zod.values),h_(e._zod,`optin`,()=>t.innerType?._zod?.optin),h_(e._zod,`optout`,()=>t.innerType?._zod?.optout),e._zod.parse=(e,n)=>{if(n.direction===`backward`)return t.innerType._zod.run(e,n);let r=t.innerType._zod.run(e,n);return r instanceof Promise?r.then($y):$y(r)}});function $y(e){return e.value=Object.freeze(e.value),e}var lte=B(`$ZodCustom`,(e,t)=>{Hv.init(e,t),sy.init(e,t),e._zod.parse=(e,t)=>e,e._zod.check=n=>{let r=n.value,i=t.fn(r);if(i instanceof Promise)return i.then(t=>eb(t,n,r,e));eb(i,n,r,e)}});function eb(e,t,n,r){if(!e){let e={code:`custom`,input:n,inst:r,path:[...r._zod.def.path??[]],continue:!r._zod.def.abort};r._zod.def.params&&(e.params=r._zod.def.params),t.issues.push(U_(e))}}var tb,ute=class{constructor(){this._map=new WeakMap,this._idmap=new Map}add(e,...t){let n=t[0];return this._map.set(e,n),n&&typeof n==`object`&&`id`in n&&this._idmap.set(n.id,e),this}clear(){return this._map=new WeakMap,this._idmap=new Map,this}remove(e){let t=this._map.get(e);return t&&typeof t==`object`&&`id`in t&&this._idmap.delete(t.id),this._map.delete(e),this}get(e){let t=e._zod.parent;if(t){let n={...this.get(t)??{}};delete n.id;let r={...n,...this._map.get(e)};return Object.keys(r).length?r:void 0}return this._map.get(e)}has(e){return this._map.has(e)}};function dte(){return new ute}(tb=globalThis).__zod_globalRegistry??(tb.__zod_globalRegistry=dte());var nb=globalThis.__zod_globalRegistry;function fte(e,t){return new e({type:`string`,...V(t)})}function pte(e,t){return new e({type:`string`,format:`email`,check:`string_format`,abort:!1,...V(t)})}function rb(e,t){return new e({type:`string`,format:`guid`,check:`string_format`,abort:!1,...V(t)})}function mte(e,t){return new e({type:`string`,format:`uuid`,check:`string_format`,abort:!1,...V(t)})}function hte(e,t){return new e({type:`string`,format:`uuid`,check:`string_format`,abort:!1,version:`v4`,...V(t)})}function gte(e,t){return new e({type:`string`,format:`uuid`,check:`string_format`,abort:!1,version:`v6`,...V(t)})}function _te(e,t){return new e({type:`string`,format:`uuid`,check:`string_format`,abort:!1,version:`v7`,...V(t)})}function vte(e,t){return new e({type:`string`,format:`url`,check:`string_format`,abort:!1,...V(t)})}function yte(e,t){return new e({type:`string`,format:`emoji`,check:`string_format`,abort:!1,...V(t)})}function bte(e,t){return new e({type:`string`,format:`nanoid`,check:`string_format`,abort:!1,...V(t)})}function xte(e,t){return new e({type:`string`,format:`cuid`,check:`string_format`,abort:!1,...V(t)})}function Ste(e,t){return new e({type:`string`,format:`cuid2`,check:`string_format`,abort:!1,...V(t)})}function Cte(e,t){return new e({type:`string`,format:`ulid`,check:`string_format`,abort:!1,...V(t)})}function wte(e,t){return new e({type:`string`,format:`xid`,check:`string_format`,abort:!1,...V(t)})}function Tte(e,t){return new e({type:`string`,format:`ksuid`,check:`string_format`,abort:!1,...V(t)})}function Ete(e,t){return new e({type:`string`,format:`ipv4`,check:`string_format`,abort:!1,...V(t)})}function Dte(e,t){return new e({type:`string`,format:`ipv6`,check:`string_format`,abort:!1,...V(t)})}function Ote(e,t){return new e({type:`string`,format:`cidrv4`,check:`string_format`,abort:!1,...V(t)})}function kte(e,t){return new e({type:`string`,format:`cidrv6`,check:`string_format`,abort:!1,...V(t)})}function Ate(e,t){return new e({type:`string`,format:`base64`,check:`string_format`,abort:!1,...V(t)})}function jte(e,t){return new e({type:`string`,format:`base64url`,check:`string_format`,abort:!1,...V(t)})}function Mte(e,t){return new e({type:`string`,format:`e164`,check:`string_format`,abort:!1,...V(t)})}function Nte(e,t){return new e({type:`string`,format:`jwt`,check:`string_format`,abort:!1,...V(t)})}function Pte(e,t){return new e({type:`string`,format:`datetime`,check:`string_format`,offset:!1,local:!1,precision:null,...V(t)})}function Fte(e,t){return new e({type:`string`,format:`date`,check:`string_format`,...V(t)})}function Ite(e,t){return new e({type:`string`,format:`time`,check:`string_format`,precision:null,...V(t)})}function Lte(e,t){return new e({type:`string`,format:`duration`,check:`string_format`,...V(t)})}function Rte(e,t){return new e({type:`number`,checks:[],...V(t)})}function zte(e,t){return new e({type:`number`,check:`number_format`,abort:!1,format:`safeint`,...V(t)})}function Bte(e,t){return new e({type:`boolean`,...V(t)})}function Vte(e){return new e({type:`unknown`})}function Hte(e,t){return new e({type:`never`,...V(t)})}function ib(e,t){return new Wv({check:`less_than`,...V(t),value:e,inclusive:!1})}function ab(e,t){return new Wv({check:`less_than`,...V(t),value:e,inclusive:!0})}function ob(e,t){return new Gv({check:`greater_than`,...V(t),value:e,inclusive:!1})}function sb(e,t){return new Gv({check:`greater_than`,...V(t),value:e,inclusive:!0})}function cb(e,t){return new Kv({check:`multiple_of`,...V(t),value:e})}function lb(e,t){return new Jv({check:`max_length`,...V(t),maximum:e})}function ub(e,t){return new Yv({check:`min_length`,...V(t),minimum:e})}function db(e,t){return new Xv({check:`length_equals`,...V(t),length:e})}function Ute(e,t){return new Qv({check:`string_format`,format:`regex`,...V(t),pattern:e})}function Wte(e){return new $v({check:`string_format`,format:`lowercase`,...V(e)})}function Gte(e){return new ey({check:`string_format`,format:`uppercase`,...V(e)})}function Kte(e,t){return new ty({check:`string_format`,format:`includes`,...V(t),includes:e})}function qte(e,t){return new ny({check:`string_format`,format:`starts_with`,...V(t),prefix:e})}function Jte(e,t){return new ry({check:`string_format`,format:`ends_with`,...V(t),suffix:e})}function fb(e){return new iy({check:`overwrite`,tx:e})}function Yte(e){return fb(t=>t.normalize(e))}function Xte(){return fb(e=>e.trim())}function Zte(){return fb(e=>e.toLowerCase())}function Qte(){return fb(e=>e.toUpperCase())}function $te(){return fb(e=>y_(e))}function ene(e,t,n){return new e({type:`array`,element:t,...V(n)})}function tne(e,t,n){return new e({type:`custom`,check:`custom`,fn:t,...V(n)})}function nne(e,t){let n=rne(t=>(t.addIssue=e=>{if(typeof e==`string`)t.issues.push(U_(e,t.value,n._zod.def));else{let r=e;r.fatal&&(r.continue=!1),r.code??=`custom`,r.input??=t.value,r.inst??=n,r.continue??=!n._zod.def.abort,t.issues.push(U_(r))}},e(t.value,t)),t);return n}function rne(e,t){let n=new Hv({check:`custom`,...V(t)});return n._zod.check=e,n}function pb(e){let t=e?.target??`draft-2020-12`;return t===`draft-4`&&(t=`draft-04`),t===`draft-7`&&(t=`draft-07`),{processors:e.processors??{},metadataRegistry:e?.metadata??nb,target:t,unrepresentable:e?.unrepresentable??`throw`,override:e?.override??(()=>{}),io:e?.io??`output`,counter:0,seen:new Map,cycles:e?.cycles??`ref`,reused:e?.reused??`inline`,external:e?.external??void 0}}function mb(e,t,n={path:[],schemaPath:[]}){var r;let i=e._zod.def,a=t.seen.get(e);if(a)return a.count++,n.schemaPath.includes(e)&&(a.cycle=n.path),a.schema;let o={schema:{},count:1,cycle:void 0,path:n.path};t.seen.set(e,o);let s=e._zod.toJSONSchema?.();if(s)o.schema=s;else{let r={...n,schemaPath:[...n.schemaPath,e],path:n.path};if(e._zod.processJSONSchema)e._zod.processJSONSchema(t,o.schema,r);else{let n=o.schema,a=t.processors[i.type];if(!a)throw Error(`[toJSONSchema]: Non-representable type encountered: ${i.type}`);a(e,t,n,r)}let a=e._zod.parent;a&&(o.ref||=a,mb(a,t,r),t.seen.get(a).isParent=!0)}let c=t.metadataRegistry.get(e);return c&&Object.assign(o.schema,c),t.io===`input`&&_b(e)&&(delete o.schema.examples,delete o.schema.default),t.io===`input`&&`_prefault`in o.schema&&((r=o.schema).default??(r.default=o.schema._prefault)),delete o.schema._prefault,t.seen.get(e).schema}function hb(e,t){let n=e.seen.get(t);if(!n)throw Error(`Unprocessed schema. This is a bug in Zod.`);let r=new Map;for(let t of e.seen.entries()){let n=e.metadataRegistry.get(t[0])?.id;if(n){let e=r.get(n);if(e&&e!==t[0])throw Error(`Duplicate schema id "${n}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`);r.set(n,t[0])}}let i=t=>{let r=e.target===`draft-2020-12`?`$defs`:`definitions`;if(e.external){let n=e.external.registry.get(t[0])?.id,i=e.external.uri??(e=>e);if(n)return{ref:i(n)};let a=t[1].defId??t[1].schema.id??`schema${e.counter++}`;return t[1].defId=a,{defId:a,ref:`${i(`__shared`)}#/${r}/${a}`}}if(t[1]===n)return{ref:`#`};let i=`#/${r}/`,a=t[1].schema.id??`__schema${e.counter++}`;return{defId:a,ref:i+a}},a=e=>{if(e[1].schema.$ref)return;let t=e[1],{ref:n,defId:r}=i(e);t.def={...t.schema},r&&(t.defId=r);let a=t.schema;for(let e in a)delete a[e];a.$ref=n};if(e.cycles===`throw`)for(let t of e.seen.entries()){let e=t[1];if(e.cycle)throw Error(`Cycle detected: #/${e.cycle?.join(`/`)}/ + `)}t.write(`payload.value = newResult;`),t.write(`return payload;`);let s=t.compile();return(t,n)=>s(e,t,n)},a,o=Eg,s=!pg.jitless,c=s&&Hte.value,l=t.catchall,u;e._zod.parse=(d,f)=>{u??=r.value;let p=d.value;return o(p)?s&&c&&f?.async===!1&&f.jitless!==!0?(a||=i(t.shape),d=a(d,f),l?Cv([],p,d,f,u,e):d):n(d,f):(d.issues.push({expected:`object`,code:`invalid_type`,input:p,inst:e}),d)}});function Ev(e,t,n,r){for(let n of e)if(n.issues.length===0)return t.value=n.value,t;let i=e.filter(e=>!jg(e));return i.length===1?(t.value=i[0].value,i[0]):(t.issues.push({code:`invalid_union`,input:t.value,inst:n,errors:e.map(e=>e.issues.map(e=>Pg(e,r,mg())))}),t)}var Dv=B(`$ZodUnion`,(e,t)=>{z_.init(e,t),xg(e._zod,`optin`,()=>t.options.some(e=>e._zod.optin===`optional`)?`optional`:void 0),xg(e._zod,`optout`,()=>t.options.some(e=>e._zod.optout===`optional`)?`optional`:void 0),xg(e._zod,`values`,()=>{if(t.options.every(e=>e._zod.values))return new Set(t.options.flatMap(e=>Array.from(e._zod.values)))}),xg(e._zod,`pattern`,()=>{if(t.options.every(e=>e._zod.pattern)){let e=t.options.map(e=>e._zod.pattern);return RegExp(`^(${e.map(e=>yg(e.source)).join(`|`)})$`)}});let n=t.options.length===1?t.options[0]._zod.run:null;e._zod.parse=(r,i)=>{if(n)return n(r,i);let a=!1,o=[];for(let e of t.options){let t=e._zod.run({value:r.value,issues:[]},i);if(t instanceof Promise)o.push(t),a=!0;else{if(t.issues.length===0)return t;o.push(t)}}return a?Promise.all(o).then(t=>Ev(t,r,e,i)):Ev(o,r,e,i)}}),Ov=B(`$ZodIntersection`,(e,t)=>{z_.init(e,t),e._zod.parse=(e,n)=>{let r=e.value,i=t.left._zod.run({value:r,issues:[]},n),a=t.right._zod.run({value:r,issues:[]},n);return i instanceof Promise||a instanceof Promise?Promise.all([i,a]).then(([t,n])=>Av(e,t,n)):Av(e,i,a)}});function kv(e,t){if(e===t||e instanceof Date&&t instanceof Date&&+e==+t)return{valid:!0,data:e};if(Dg(e)&&Dg(t)){let n=Object.keys(t),r=Object.keys(e).filter(e=>n.indexOf(e)!==-1),i={...e,...t};for(let n of r){let r=kv(e[n],t[n]);if(!r.valid)return{valid:!1,mergeErrorPath:[n,...r.mergeErrorPath]};i[n]=r.data}return{valid:!0,data:i}}if(Array.isArray(e)&&Array.isArray(t)){if(e.length!==t.length)return{valid:!1,mergeErrorPath:[]};let n=[];for(let r=0;re.l&&e.r).map(([e])=>e);if(a.length&&i&&e.issues.push({...i,keys:a}),jg(e))return e;let o=kv(t.value,n.value);if(!o.valid)throw Error(`Unmergable intersection. Error path: ${JSON.stringify(o.mergeErrorPath)}`);return e.value=o.data,e}var jv=B(`$ZodRecord`,(e,t)=>{z_.init(e,t),e._zod.parse=(n,r)=>{let i=n.value;if(!Dg(i))return n.issues.push({expected:`record`,code:`invalid_type`,input:i,inst:e}),n;let a=[],o=t.keyType._zod.values;if(o){n.value={};let s=new Set;for(let c of o)if(typeof c==`string`||typeof c==`number`||typeof c==`symbol`){s.add(typeof c==`number`?c.toString():c);let o=t.keyType._zod.run({value:c,issues:[]},r);if(o instanceof Promise)throw Error(`Async schemas not supported in object keys currently`);if(o.issues.length){n.issues.push({code:`invalid_key`,origin:`record`,issues:o.issues.map(e=>Pg(e,r,mg())),input:c,path:[c],inst:e});continue}let l=o.value,u=t.valueType._zod.run({value:i[c],issues:[]},r);u instanceof Promise?a.push(u.then(e=>{e.issues.length&&n.issues.push(...Mg(c,e.issues)),n.value[l]=e.value})):(u.issues.length&&n.issues.push(...Mg(c,u.issues)),n.value[l]=u.value)}let c;for(let e in i)s.has(e)||(c??=[],c.push(e));c&&c.length>0&&n.issues.push({code:`unrecognized_keys`,input:i,inst:e,keys:c})}else{n.value={};for(let o of Reflect.ownKeys(i)){if(o===`__proto__`||!Object.prototype.propertyIsEnumerable.call(i,o))continue;let s=t.keyType._zod.run({value:o,issues:[]},r);if(s instanceof Promise)throw Error(`Async schemas not supported in object keys currently`);if(typeof o==`string`&&g_.test(o)&&s.issues.length){let e=t.keyType._zod.run({value:Number(o),issues:[]},r);if(e instanceof Promise)throw Error(`Async schemas not supported in object keys currently`);e.issues.length===0&&(s=e)}if(s.issues.length){t.mode===`loose`?n.value[o]=i[o]:n.issues.push({code:`invalid_key`,origin:`record`,issues:s.issues.map(e=>Pg(e,r,mg())),input:o,path:[o],inst:e});continue}let c=t.valueType._zod.run({value:i[o],issues:[]},r);c instanceof Promise?a.push(c.then(e=>{e.issues.length&&n.issues.push(...Mg(o,e.issues)),n.value[s.value]=e.value})):(c.issues.length&&n.issues.push(...Mg(o,c.issues)),n.value[s.value]=c.value)}}return a.length?Promise.all(a).then(()=>n):n}}),Mv=B(`$ZodEnum`,(e,t)=>{z_.init(e,t);let n=hg(t.entries),r=new Set(n);e._zod.values=r,e._zod.pattern=RegExp(`^(${n.filter(e=>Ute.has(typeof e)).map(e=>typeof e==`string`?kg(e):e.toString()).join(`|`)})$`),e._zod.parse=(t,i)=>{let a=t.value;return r.has(a)||t.issues.push({code:`invalid_value`,values:n,input:a,inst:e}),t}}),Nv=B(`$ZodTransform`,(e,t)=>{z_.init(e,t),e._zod.optin=`optional`,e._zod.parse=(n,r)=>{if(r.direction===`backward`)throw new fg(e.constructor.name);let i=t.transform(n.value,n);if(r.async)return(i instanceof Promise?i:Promise.resolve(i)).then(e=>(n.value=e,n.fallback=!0,n));if(i instanceof Promise)throw new dg;return n.value=i,n.fallback=!0,n}});function Pv(e,t){return t===void 0&&(e.issues.length||e.fallback)?{issues:[],value:void 0}:e}var Fv=B(`$ZodOptional`,(e,t)=>{z_.init(e,t),e._zod.optin=`optional`,e._zod.optout=`optional`,xg(e._zod,`values`,()=>t.innerType._zod.values?new Set([...t.innerType._zod.values,void 0]):void 0),xg(e._zod,`pattern`,()=>{let e=t.innerType._zod.pattern;return e?RegExp(`^(${yg(e.source)})?$`):void 0}),e._zod.parse=(e,n)=>{if(t.innerType._zod.optin===`optional`){let r=e.value,i=t.innerType._zod.run(e,n);return i instanceof Promise?i.then(e=>Pv(e,r)):Pv(i,r)}return e.value===void 0?e:t.innerType._zod.run(e,n)}}),Iv=B(`$ZodExactOptional`,(e,t)=>{Fv.init(e,t),xg(e._zod,`values`,()=>t.innerType._zod.values),xg(e._zod,`pattern`,()=>t.innerType._zod.pattern),e._zod.parse=(e,n)=>t.innerType._zod.run(e,n)}),Lv=B(`$ZodNullable`,(e,t)=>{z_.init(e,t),xg(e._zod,`optin`,()=>t.innerType._zod.optin),xg(e._zod,`optout`,()=>t.innerType._zod.optout),xg(e._zod,`pattern`,()=>{let e=t.innerType._zod.pattern;return e?RegExp(`^(${yg(e.source)}|null)$`):void 0}),xg(e._zod,`values`,()=>t.innerType._zod.values?new Set([...t.innerType._zod.values,null]):void 0),e._zod.parse=(e,n)=>e.value===null?e:t.innerType._zod.run(e,n)}),Rv=B(`$ZodDefault`,(e,t)=>{z_.init(e,t),e._zod.optin=`optional`,xg(e._zod,`values`,()=>t.innerType._zod.values),e._zod.parse=(e,n)=>{if(n.direction===`backward`)return t.innerType._zod.run(e,n);if(e.value===void 0)return e.value=t.defaultValue,e;let r=t.innerType._zod.run(e,n);return r instanceof Promise?r.then(e=>zv(e,t)):zv(r,t)}});function zv(e,t){return e.value===void 0&&(e.value=t.defaultValue),e}var Bv=B(`$ZodPrefault`,(e,t)=>{z_.init(e,t),e._zod.optin=`optional`,xg(e._zod,`values`,()=>t.innerType._zod.values),e._zod.parse=(e,n)=>(n.direction===`backward`||e.value===void 0&&(e.value=t.defaultValue),t.innerType._zod.run(e,n))}),Vv=B(`$ZodNonOptional`,(e,t)=>{z_.init(e,t),xg(e._zod,`values`,()=>{let e=t.innerType._zod.values;return e?new Set([...e].filter(e=>e!==void 0)):void 0}),e._zod.parse=(n,r)=>{let i=t.innerType._zod.run(n,r);return i instanceof Promise?i.then(t=>Hv(t,e)):Hv(i,e)}});function Hv(e,t){return!e.issues.length&&e.value===void 0&&e.issues.push({code:`invalid_type`,expected:`nonoptional`,input:e.value,inst:t}),e}var Uv=B(`$ZodCatch`,(e,t)=>{z_.init(e,t),e._zod.optin=`optional`,xg(e._zod,`optout`,()=>t.innerType._zod.optout),xg(e._zod,`values`,()=>t.innerType._zod.values),e._zod.parse=(e,n)=>{if(n.direction===`backward`)return t.innerType._zod.run(e,n);let r=t.innerType._zod.run(e,n);return r instanceof Promise?r.then(r=>(e.value=r.value,r.issues.length&&(e.value=t.catchValue({...e,error:{issues:r.issues.map(e=>Pg(e,n,mg()))},input:e.value}),e.issues=[],e.fallback=!0),e)):(e.value=r.value,r.issues.length&&(e.value=t.catchValue({...e,error:{issues:r.issues.map(e=>Pg(e,n,mg()))},input:e.value}),e.issues=[],e.fallback=!0),e)}}),Wv=B(`$ZodPipe`,(e,t)=>{z_.init(e,t),xg(e._zod,`values`,()=>t.in._zod.values),xg(e._zod,`optin`,()=>t.in._zod.optin),xg(e._zod,`optout`,()=>t.out._zod.optout),xg(e._zod,`propValues`,()=>t.in._zod.propValues),e._zod.parse=(e,n)=>{if(n.direction===`backward`){let r=t.out._zod.run(e,n);return r instanceof Promise?r.then(e=>Gv(e,t.in,n)):Gv(r,t.in,n)}let r=t.in._zod.run(e,n);return r instanceof Promise?r.then(e=>Gv(e,t.out,n)):Gv(r,t.out,n)}});function Gv(e,t,n){return e.issues.length?(e.aborted=!0,e):t._zod.run({value:e.value,issues:e.issues,fallback:e.fallback},n)}var Kv=B(`$ZodReadonly`,(e,t)=>{z_.init(e,t),xg(e._zod,`propValues`,()=>t.innerType._zod.propValues),xg(e._zod,`values`,()=>t.innerType._zod.values),xg(e._zod,`optin`,()=>t.innerType?._zod?.optin),xg(e._zod,`optout`,()=>t.innerType?._zod?.optout),e._zod.parse=(e,n)=>{if(n.direction===`backward`)return t.innerType._zod.run(e,n);let r=t.innerType._zod.run(e,n);return r instanceof Promise?r.then(qv):qv(r)}});function qv(e){return e.value=Object.freeze(e.value),e}var Jv=B(`$ZodCustom`,(e,t)=>{b_.init(e,t),z_.init(e,t),e._zod.parse=(e,t)=>e,e._zod.check=n=>{let r=n.value,i=t.fn(r);if(i instanceof Promise)return i.then(t=>Yv(t,n,r,e));Yv(i,n,r,e)}});function Yv(e,t,n,r){if(!e){let e={code:`custom`,input:n,inst:r,path:[...r._zod.def.path??[]],continue:!r._zod.def.abort};r._zod.def.params&&(e.params=r._zod.def.params),t.issues.push(Ig(e))}}var Xv,Zv=class{constructor(){this._map=new WeakMap,this._idmap=new Map}add(e,...t){let n=t[0];return this._map.set(e,n),n&&typeof n==`object`&&`id`in n&&this._idmap.set(n.id,e),this}clear(){return this._map=new WeakMap,this._idmap=new Map,this}remove(e){let t=this._map.get(e);return t&&typeof t==`object`&&`id`in t&&this._idmap.delete(t.id),this._map.delete(e),this}get(e){let t=e._zod.parent;if(t){let n={...this.get(t)??{}};delete n.id;let r={...n,...this._map.get(e)};return Object.keys(r).length?r:void 0}return this._map.get(e)}has(e){return this._map.has(e)}};function Qv(){return new Zv}(Xv=globalThis).__zod_globalRegistry??(Xv.__zod_globalRegistry=Qv());var $v=globalThis.__zod_globalRegistry;function ey(e,t){return new e({type:`string`,...V(t)})}function ty(e,t){return new e({type:`string`,format:`email`,check:`string_format`,abort:!1,...V(t)})}function ny(e,t){return new e({type:`string`,format:`guid`,check:`string_format`,abort:!1,...V(t)})}function ry(e,t){return new e({type:`string`,format:`uuid`,check:`string_format`,abort:!1,...V(t)})}function iy(e,t){return new e({type:`string`,format:`uuid`,check:`string_format`,abort:!1,version:`v4`,...V(t)})}function ay(e,t){return new e({type:`string`,format:`uuid`,check:`string_format`,abort:!1,version:`v6`,...V(t)})}function oy(e,t){return new e({type:`string`,format:`uuid`,check:`string_format`,abort:!1,version:`v7`,...V(t)})}function sy(e,t){return new e({type:`string`,format:`url`,check:`string_format`,abort:!1,...V(t)})}function cy(e,t){return new e({type:`string`,format:`emoji`,check:`string_format`,abort:!1,...V(t)})}function ly(e,t){return new e({type:`string`,format:`nanoid`,check:`string_format`,abort:!1,...V(t)})}function uy(e,t){return new e({type:`string`,format:`cuid`,check:`string_format`,abort:!1,...V(t)})}function dy(e,t){return new e({type:`string`,format:`cuid2`,check:`string_format`,abort:!1,...V(t)})}function fy(e,t){return new e({type:`string`,format:`ulid`,check:`string_format`,abort:!1,...V(t)})}function py(e,t){return new e({type:`string`,format:`xid`,check:`string_format`,abort:!1,...V(t)})}function my(e,t){return new e({type:`string`,format:`ksuid`,check:`string_format`,abort:!1,...V(t)})}function hy(e,t){return new e({type:`string`,format:`ipv4`,check:`string_format`,abort:!1,...V(t)})}function gy(e,t){return new e({type:`string`,format:`ipv6`,check:`string_format`,abort:!1,...V(t)})}function _y(e,t){return new e({type:`string`,format:`cidrv4`,check:`string_format`,abort:!1,...V(t)})}function vy(e,t){return new e({type:`string`,format:`cidrv6`,check:`string_format`,abort:!1,...V(t)})}function yy(e,t){return new e({type:`string`,format:`base64`,check:`string_format`,abort:!1,...V(t)})}function by(e,t){return new e({type:`string`,format:`base64url`,check:`string_format`,abort:!1,...V(t)})}function xy(e,t){return new e({type:`string`,format:`e164`,check:`string_format`,abort:!1,...V(t)})}function Sy(e,t){return new e({type:`string`,format:`jwt`,check:`string_format`,abort:!1,...V(t)})}function Cy(e,t){return new e({type:`string`,format:`datetime`,check:`string_format`,offset:!1,local:!1,precision:null,...V(t)})}function wy(e,t){return new e({type:`string`,format:`date`,check:`string_format`,...V(t)})}function Ty(e,t){return new e({type:`string`,format:`time`,check:`string_format`,precision:null,...V(t)})}function Ey(e,t){return new e({type:`string`,format:`duration`,check:`string_format`,...V(t)})}function Dy(e,t){return new e({type:`number`,checks:[],...V(t)})}function Oy(e,t){return new e({type:`number`,check:`number_format`,abort:!1,format:`safeint`,...V(t)})}function ky(e,t){return new e({type:`boolean`,...V(t)})}function Ay(e){return new e({type:`unknown`})}function hne(e,t){return new e({type:`never`,...V(t)})}function jy(e,t){return new S_({check:`less_than`,...V(t),value:e,inclusive:!1})}function My(e,t){return new S_({check:`less_than`,...V(t),value:e,inclusive:!0})}function Ny(e,t){return new C_({check:`greater_than`,...V(t),value:e,inclusive:!1})}function Py(e,t){return new C_({check:`greater_than`,...V(t),value:e,inclusive:!0})}function Fy(e,t){return new w_({check:`multiple_of`,...V(t),value:e})}function Iy(e,t){return new E_({check:`max_length`,...V(t),maximum:e})}function Ly(e,t){return new D_({check:`min_length`,...V(t),minimum:e})}function Ry(e,t){return new O_({check:`length_equals`,...V(t),length:e})}function gne(e,t){return new A_({check:`string_format`,format:`regex`,...V(t),pattern:e})}function _ne(e){return new j_({check:`string_format`,format:`lowercase`,...V(e)})}function vne(e){return new M_({check:`string_format`,format:`uppercase`,...V(e)})}function yne(e,t){return new N_({check:`string_format`,format:`includes`,...V(t),includes:e})}function bne(e,t){return new P_({check:`string_format`,format:`starts_with`,...V(t),prefix:e})}function xne(e,t){return new F_({check:`string_format`,format:`ends_with`,...V(t),suffix:e})}function zy(e){return new I_({check:`overwrite`,tx:e})}function Sne(e){return zy(t=>t.normalize(e))}function Cne(){return zy(e=>e.trim())}function wne(){return zy(e=>e.toLowerCase())}function Tne(){return zy(e=>e.toUpperCase())}function Ene(){return zy(e=>Vte(e))}function Dne(e,t,n){return new e({type:`array`,element:t,...V(n)})}function One(e,t,n){return new e({type:`custom`,check:`custom`,fn:t,...V(n)})}function kne(e,t){let n=Ane(t=>(t.addIssue=e=>{if(typeof e==`string`)t.issues.push(Ig(e,t.value,n._zod.def));else{let r=e;r.fatal&&(r.continue=!1),r.code??=`custom`,r.input??=t.value,r.inst??=n,r.continue??=!n._zod.def.abort,t.issues.push(Ig(r))}},e(t.value,t)),t);return n}function Ane(e,t){let n=new b_({check:`custom`,...V(t)});return n._zod.check=e,n}function By(e){let t=e?.target??`draft-2020-12`;return t===`draft-4`&&(t=`draft-04`),t===`draft-7`&&(t=`draft-07`),{processors:e.processors??{},metadataRegistry:e?.metadata??$v,target:t,unrepresentable:e?.unrepresentable??`throw`,override:e?.override??(()=>{}),io:e?.io??`output`,counter:0,seen:new Map,cycles:e?.cycles??`ref`,reused:e?.reused??`inline`,external:e?.external??void 0}}function Vy(e,t,n={path:[],schemaPath:[]}){var r;let i=e._zod.def,a=t.seen.get(e);if(a)return a.count++,n.schemaPath.includes(e)&&(a.cycle=n.path),a.schema;let o={schema:{},count:1,cycle:void 0,path:n.path};t.seen.set(e,o);let s=e._zod.toJSONSchema?.();if(s)o.schema=s;else{let r={...n,schemaPath:[...n.schemaPath,e],path:n.path};if(e._zod.processJSONSchema)e._zod.processJSONSchema(t,o.schema,r);else{let n=o.schema,a=t.processors[i.type];if(!a)throw Error(`[toJSONSchema]: Non-representable type encountered: ${i.type}`);a(e,t,n,r)}let a=e._zod.parent;a&&(o.ref||=a,Vy(a,t,r),t.seen.get(a).isParent=!0)}let c=t.metadataRegistry.get(e);return c&&Object.assign(o.schema,c),t.io===`input`&&Wy(e)&&(delete o.schema.examples,delete o.schema.default),t.io===`input`&&`_prefault`in o.schema&&((r=o.schema).default??(r.default=o.schema._prefault)),delete o.schema._prefault,t.seen.get(e).schema}function Hy(e,t){let n=e.seen.get(t);if(!n)throw Error(`Unprocessed schema. This is a bug in Zod.`);let r=new Map;for(let t of e.seen.entries()){let n=e.metadataRegistry.get(t[0])?.id;if(n){let e=r.get(n);if(e&&e!==t[0])throw Error(`Duplicate schema id "${n}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`);r.set(n,t[0])}}let i=t=>{let r=e.target===`draft-2020-12`?`$defs`:`definitions`;if(e.external){let n=e.external.registry.get(t[0])?.id,i=e.external.uri??(e=>e);if(n)return{ref:i(n)};let a=t[1].defId??t[1].schema.id??`schema${e.counter++}`;return t[1].defId=a,{defId:a,ref:`${i(`__shared`)}#/${r}/${a}`}}if(t[1]===n)return{ref:`#`};let i=`#/${r}/`,a=t[1].schema.id??`__schema${e.counter++}`;return{defId:a,ref:i+a}},a=e=>{if(e[1].schema.$ref)return;let t=e[1],{ref:n,defId:r}=i(e);t.def={...t.schema},r&&(t.defId=r);let a=t.schema;for(let e in a)delete a[e];a.$ref=n};if(e.cycles===`throw`)for(let t of e.seen.entries()){let e=t[1];if(e.cycle)throw Error(`Cycle detected: #/${e.cycle?.join(`/`)}/ -Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.`)}for(let n of e.seen.entries()){let r=n[1];if(t===n[0]){a(n);continue}if(e.external){let r=e.external.registry.get(n[0])?.id;if(t!==n[0]&&r){a(n);continue}}if(e.metadataRegistry.get(n[0])?.id){a(n);continue}if(r.cycle){a(n);continue}if(r.count>1&&e.reused===`ref`){a(n);continue}}}function gb(e,t){let n=e.seen.get(t);if(!n)throw Error(`Unprocessed schema. This is a bug in Zod.`);let r=t=>{let n=e.seen.get(t);if(n.ref===null)return;let i=n.def??n.schema,a={...i},o=n.ref;if(n.ref=null,o){r(o);let n=e.seen.get(o),s=n.schema;if(s.$ref&&(e.target===`draft-07`||e.target===`draft-04`||e.target===`openapi-3.0`)?(i.allOf=i.allOf??[],i.allOf.push(s)):Object.assign(i,s),Object.assign(i,a),t._zod.parent===o)for(let e in i)e===`$ref`||e===`allOf`||e in a||delete i[e];if(s.$ref&&n.def)for(let e in i)e===`$ref`||e===`allOf`||e in n.def&&JSON.stringify(i[e])===JSON.stringify(n.def[e])&&delete i[e]}let s=t._zod.parent;if(s&&s!==o){r(s);let t=e.seen.get(s);if(t?.schema.$ref&&(i.$ref=t.schema.$ref,t.def))for(let e in i)e===`$ref`||e===`allOf`||e in t.def&&JSON.stringify(i[e])===JSON.stringify(t.def[e])&&delete i[e]}e.override({zodSchema:t,jsonSchema:i,path:n.path??[]})};for(let t of[...e.seen.entries()].reverse())r(t[0]);let i={};if(e.target===`draft-2020-12`?i.$schema=`https://json-schema.org/draft/2020-12/schema`:e.target===`draft-07`?i.$schema=`http://json-schema.org/draft-07/schema#`:e.target===`draft-04`?i.$schema=`http://json-schema.org/draft-04/schema#`:e.target,e.external?.uri){let n=e.external.registry.get(t)?.id;if(!n)throw Error("Schema is missing an `id` property");i.$id=e.external.uri(n)}Object.assign(i,n.def??n.schema);let a=e.metadataRegistry.get(t)?.id;a!==void 0&&i.id===a&&delete i.id;let o=e.external?.defs??{};for(let t of e.seen.entries()){let e=t[1];e.def&&e.defId&&(e.def.id===e.defId&&delete e.def.id,o[e.defId]=e.def)}e.external||Object.keys(o).length>0&&(e.target===`draft-2020-12`?i.$defs=o:i.definitions=o);try{let n=JSON.parse(JSON.stringify(i));return Object.defineProperty(n,`~standard`,{value:{...t[`~standard`],jsonSchema:{input:vb(t,`input`,e.processors),output:vb(t,`output`,e.processors)}},enumerable:!1,writable:!1}),n}catch{throw Error(`Error converting schema to JSON.`)}}function _b(e,t){let n=t??{seen:new Set};if(n.seen.has(e))return!1;n.seen.add(e);let r=e._zod.def;if(r.type===`transform`)return!0;if(r.type===`array`)return _b(r.element,n);if(r.type===`set`)return _b(r.valueType,n);if(r.type===`lazy`)return _b(r.getter(),n);if(r.type===`promise`||r.type===`optional`||r.type===`nonoptional`||r.type===`nullable`||r.type===`readonly`||r.type===`default`||r.type===`prefault`)return _b(r.innerType,n);if(r.type===`intersection`)return _b(r.left,n)||_b(r.right,n);if(r.type===`record`||r.type===`map`)return _b(r.keyType,n)||_b(r.valueType,n);if(r.type===`pipe`)return e._zod.traits.has(`$ZodCodec`)?!0:_b(r.in,n)||_b(r.out,n);if(r.type===`object`){for(let e in r.shape)if(_b(r.shape[e],n))return!0;return!1}if(r.type===`union`){for(let e of r.options)if(_b(e,n))return!0;return!1}if(r.type===`tuple`){for(let e of r.items)if(_b(e,n))return!0;return!!(r.rest&&_b(r.rest,n))}return!1}var ine=(e,t={})=>n=>{let r=pb({...n,processors:t});return mb(e,r),hb(r,e),gb(r,e)},vb=(e,t,n={})=>r=>{let{libraryOptions:i,target:a}=r??{},o=pb({...i??{},target:a,io:t,processors:n});return mb(e,o),hb(o,e),gb(o,e)},ane={guid:`uuid`,url:`uri`,datetime:`date-time`,json_string:`json-string`,regex:``},one=(e,t,n,r)=>{let i=n;i.type=`string`;let{minimum:a,maximum:o,format:s,patterns:c,contentEncoding:l}=e._zod.bag;if(typeof a==`number`&&(i.minLength=a),typeof o==`number`&&(i.maxLength=o),s&&(i.format=ane[s]??s,i.format===``&&delete i.format,s===`time`&&delete i.format),l&&(i.contentEncoding=l),c&&c.size>0){let e=[...c];e.length===1?i.pattern=e[0].source:e.length>1&&(i.allOf=[...e.map(e=>({...t.target===`draft-07`||t.target===`draft-04`||t.target===`openapi-3.0`?{type:`string`}:{},pattern:e.source}))])}},sne=(e,t,n,r)=>{let i=n,{minimum:a,maximum:o,format:s,multipleOf:c,exclusiveMaximum:l,exclusiveMinimum:u}=e._zod.bag;typeof s==`string`&&s.includes(`int`)?i.type=`integer`:i.type=`number`;let d=typeof u==`number`&&u>=(a??-1/0),f=typeof l==`number`&&l<=(o??1/0),p=t.target===`draft-04`||t.target===`openapi-3.0`;d?p?(i.minimum=u,i.exclusiveMinimum=!0):i.exclusiveMinimum=u:typeof a==`number`&&(i.minimum=a),f?p?(i.maximum=l,i.exclusiveMaximum=!0):i.exclusiveMaximum=l:typeof o==`number`&&(i.maximum=o),typeof c==`number`&&(i.multipleOf=c)},cne=(e,t,n,r)=>{n.type=`boolean`},lne=(e,t,n,r)=>{n.not={}},une=(e,t,n,r)=>{let i=e._zod.def,a=c_(i.entries);a.every(e=>typeof e==`number`)&&(n.type=`number`),a.every(e=>typeof e==`string`)&&(n.type=`string`),n.enum=a},dne=(e,t,n,r)=>{if(t.unrepresentable===`throw`)throw Error(`Custom types cannot be represented in JSON Schema`)},fne=(e,t,n,r)=>{if(t.unrepresentable===`throw`)throw Error(`Transforms cannot be represented in JSON Schema`)},pne=(e,t,n,r)=>{let i=n,a=e._zod.def,{minimum:o,maximum:s}=e._zod.bag;typeof o==`number`&&(i.minItems=o),typeof s==`number`&&(i.maxItems=s),i.type=`array`,i.items=mb(a.element,t,{...r,path:[...r.path,`items`]})},mne=(e,t,n,r)=>{let i=n,a=e._zod.def;i.type=`object`,i.properties={};let o=a.shape;for(let e in o)i.properties[e]=mb(o[e],t,{...r,path:[...r.path,`properties`,e]});let s=new Set(Object.keys(o)),c=new Set([...s].filter(e=>{let n=a.shape[e]._zod;return t.io===`input`?n.optin===void 0:n.optout===void 0}));c.size>0&&(i.required=Array.from(c)),a.catchall?._zod.def.type===`never`?i.additionalProperties=!1:a.catchall?a.catchall&&(i.additionalProperties=mb(a.catchall,t,{...r,path:[...r.path,`additionalProperties`]})):t.io===`output`&&(i.additionalProperties=!1)},hne=(e,t,n,r)=>{let i=e._zod.def,a=i.inclusive===!1,o=i.options.map((e,n)=>mb(e,t,{...r,path:[...r.path,a?`oneOf`:`anyOf`,n]}));a?n.oneOf=o:n.anyOf=o},gne=(e,t,n,r)=>{let i=e._zod.def,a=mb(i.left,t,{...r,path:[...r.path,`allOf`,0]}),o=mb(i.right,t,{...r,path:[...r.path,`allOf`,1]}),s=e=>`allOf`in e&&Object.keys(e).length===1;n.allOf=[...s(a)?a.allOf:[a],...s(o)?o.allOf:[o]]},_ne=(e,t,n,r)=>{let i=n,a=e._zod.def;i.type=`object`;let o=a.keyType,s=o._zod.bag?.patterns;if(a.mode===`loose`&&s&&s.size>0){let e=mb(a.valueType,t,{...r,path:[...r.path,`patternProperties`,`*`]});i.patternProperties={};for(let t of s)i.patternProperties[t.source]=e}else (t.target===`draft-07`||t.target===`draft-2020-12`)&&(i.propertyNames=mb(a.keyType,t,{...r,path:[...r.path,`propertyNames`]})),i.additionalProperties=mb(a.valueType,t,{...r,path:[...r.path,`additionalProperties`]});let c=o._zod.values;if(c){let e=[...c].filter(e=>typeof e==`string`||typeof e==`number`);e.length>0&&(i.required=e)}},vne=(e,t,n,r)=>{let i=e._zod.def,a=mb(i.innerType,t,r),o=t.seen.get(e);t.target===`openapi-3.0`?(o.ref=i.innerType,n.nullable=!0):n.anyOf=[a,{type:`null`}]},yne=(e,t,n,r)=>{let i=e._zod.def;mb(i.innerType,t,r);let a=t.seen.get(e);a.ref=i.innerType},bne=(e,t,n,r)=>{let i=e._zod.def;mb(i.innerType,t,r);let a=t.seen.get(e);a.ref=i.innerType,n.default=JSON.parse(JSON.stringify(i.defaultValue))},xne=(e,t,n,r)=>{let i=e._zod.def;mb(i.innerType,t,r);let a=t.seen.get(e);a.ref=i.innerType,t.io===`input`&&(n._prefault=JSON.parse(JSON.stringify(i.defaultValue)))},Sne=(e,t,n,r)=>{let i=e._zod.def;mb(i.innerType,t,r);let a=t.seen.get(e);a.ref=i.innerType;let o;try{o=i.catchValue(void 0)}catch{throw Error(`Dynamic catch values are not supported in JSON Schema`)}n.default=o},Cne=(e,t,n,r)=>{let i=e._zod.def,a=i.in._zod.traits.has(`$ZodTransform`),o=t.io===`input`?a?i.out:i.in:i.out;mb(o,t,r);let s=t.seen.get(e);s.ref=o},wne=(e,t,n,r)=>{let i=e._zod.def;mb(i.innerType,t,r);let a=t.seen.get(e);a.ref=i.innerType,n.readOnly=!0},yb=(e,t,n,r)=>{let i=e._zod.def;mb(i.innerType,t,r);let a=t.seen.get(e);a.ref=i.innerType},Tne=B(`ZodISODateTime`,(e,t)=>{xy.init(e,t),Eb.init(e,t)});function Ene(e){return Pte(Tne,e)}var Dne=B(`ZodISODate`,(e,t)=>{Sy.init(e,t),Eb.init(e,t)});function One(e){return Fte(Dne,e)}var kne=B(`ZodISOTime`,(e,t)=>{Cy.init(e,t),Eb.init(e,t)});function Ane(e){return Ite(kne,e)}var jne=B(`ZodISODuration`,(e,t)=>{wy.init(e,t),Eb.init(e,t)});function Mne(e){return Lte(jne,e)}var bb=B(`ZodError`,(e,t)=>{G_.init(e,t),e.name=`ZodError`,Object.defineProperties(e,{format:{value:t=>J_(e,t)},flatten:{value:t=>q_(e,t)},addIssue:{value:t=>{e.issues.push(t),e.message=JSON.stringify(e.issues,l_,2)}},addIssues:{value:t=>{e.issues.push(...t),e.message=JSON.stringify(e.issues,l_,2)}},isEmpty:{get(){return e.issues.length===0}}})},{Parent:Error}),Nne=Y_(bb),Pne=Z_(bb),Fne=$_(bb),Ine=tv(bb),Lne=rv(bb),Rne=iv(bb),zne=av(bb),Bne=ov(bb),Vne=sv(bb),Hne=cv(bb),Une=lv(bb),Wne=uv(bb),xb=new WeakMap;function Sb(e,t,n){let r=Object.getPrototypeOf(e),i=xb.get(r);if(i||(i=new Set,xb.set(r,i)),!i.has(t)){i.add(t);for(let e in n){let t=n[e];Object.defineProperty(r,e,{configurable:!0,enumerable:!1,get(){let n=t.bind(this);return Object.defineProperty(this,e,{configurable:!0,writable:!0,enumerable:!0,value:n}),n},set(t){Object.defineProperty(this,e,{configurable:!0,writable:!0,enumerable:!0,value:t})}})}}}var Cb=B(`ZodType`,(e,t)=>(sy.init(e,t),Object.assign(e[`~standard`],{jsonSchema:{input:vb(e,`input`),output:vb(e,`output`)}}),e.toJSONSchema=ine(e,{}),e.def=t,e.type=t.type,Object.defineProperty(e,`_def`,{value:t}),e.parse=(t,n)=>Nne(e,t,n,{callee:e.parse}),e.safeParse=(t,n)=>Fne(e,t,n),e.parseAsync=async(t,n)=>Pne(e,t,n,{callee:e.parseAsync}),e.safeParseAsync=async(t,n)=>Ine(e,t,n),e.spa=e.safeParseAsync,e.encode=(t,n)=>Lne(e,t,n),e.decode=(t,n)=>Rne(e,t,n),e.encodeAsync=async(t,n)=>zne(e,t,n),e.decodeAsync=async(t,n)=>Bne(e,t,n),e.safeEncode=(t,n)=>Vne(e,t,n),e.safeDecode=(t,n)=>Hne(e,t,n),e.safeEncodeAsync=async(t,n)=>Une(e,t,n),e.safeDecodeAsync=async(t,n)=>Wne(e,t,n),Sb(e,`ZodType`,{check(...e){let t=this.def;return this.clone(__(t,{checks:[...t.checks??[],...e.map(e=>typeof e==`function`?{_zod:{check:e,def:{check:`custom`},onattach:[]}}:e)]}),{parent:!0})},with(...e){return this.check(...e)},clone(e,t){return D_(this,e,t)},brand(){return this},register(e,t){return e.add(this,t),this},refine(e,t){return this.check(ax(e,t))},superRefine(e,t){return this.check(ox(e,t))},overwrite(e){return this.check(fb(e))},optional(){return Vb(this)},exactOptional(){return Ub(this)},nullable(){return Gb(this)},nullish(){return Vb(Gb(this))},nonoptional(e){return Zb(this,e)},array(){return Mb(this)},or(e){return yre([this,e])},and(e){return xre(this,e)},transform(e){return tx(this,zb(e))},default(e){return qb(this,e)},prefault(e){return Yb(this,e)},catch(e){return $b(this,e)},pipe(e){return tx(this,e)},readonly(){return rx(this)},describe(e){let t=this.clone();return nb.add(t,{description:e}),t},meta(...e){if(e.length===0)return nb.get(this);let t=this.clone();return nb.add(t,e[0]),t},isOptional(){return this.safeParse(void 0).success},isNullable(){return this.safeParse(null).success},apply(e){return e(this)}}),Object.defineProperty(e,`description`,{get(){return nb.get(e)?.description},configurable:!0}),e)),wb=B(`_ZodString`,(e,t)=>{cy.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>one(e,t,n,r);let n=e._zod.bag;e.format=n.format??null,e.minLength=n.minimum??null,e.maxLength=n.maximum??null,Sb(e,`_ZodString`,{regex(...e){return this.check(Ute(...e))},includes(...e){return this.check(Kte(...e))},startsWith(...e){return this.check(qte(...e))},endsWith(...e){return this.check(Jte(...e))},min(...e){return this.check(ub(...e))},max(...e){return this.check(lb(...e))},length(...e){return this.check(db(...e))},nonempty(...e){return this.check(ub(1,...e))},lowercase(e){return this.check(Wte(e))},uppercase(e){return this.check(Gte(e))},trim(){return this.check(Xte())},normalize(...e){return this.check(Yte(...e))},toLowerCase(){return this.check(Zte())},toUpperCase(){return this.check(Qte())},slugify(){return this.check($te())}})}),Gne=B(`ZodString`,(e,t)=>{cy.init(e,t),wb.init(e,t),e.email=t=>e.check(pte(Kne,t)),e.url=t=>e.check(vte(qne,t)),e.jwt=t=>e.check(Nte(cre,t)),e.emoji=t=>e.check(yte(Jne,t)),e.guid=t=>e.check(rb(Db,t)),e.uuid=t=>e.check(mte(Ob,t)),e.uuidv4=t=>e.check(hte(Ob,t)),e.uuidv6=t=>e.check(gte(Ob,t)),e.uuidv7=t=>e.check(_te(Ob,t)),e.nanoid=t=>e.check(bte(Yne,t)),e.guid=t=>e.check(rb(Db,t)),e.cuid=t=>e.check(xte(Xne,t)),e.cuid2=t=>e.check(Ste(Zne,t)),e.ulid=t=>e.check(Cte(Qne,t)),e.base64=t=>e.check(Ate(are,t)),e.base64url=t=>e.check(jte(ore,t)),e.xid=t=>e.check(wte($ne,t)),e.ksuid=t=>e.check(Tte(ere,t)),e.ipv4=t=>e.check(Ete(tre,t)),e.ipv6=t=>e.check(Dte(nre,t)),e.cidrv4=t=>e.check(Ote(rre,t)),e.cidrv6=t=>e.check(kte(ire,t)),e.e164=t=>e.check(Mte(sre,t)),e.datetime=t=>e.check(Ene(t)),e.date=t=>e.check(One(t)),e.time=t=>e.check(Ane(t)),e.duration=t=>e.check(Mne(t))});function Tb(e){return fte(Gne,e)}var Eb=B(`ZodStringFormat`,(e,t)=>{ly.init(e,t),wb.init(e,t)}),Kne=B(`ZodEmail`,(e,t)=>{fy.init(e,t),Eb.init(e,t)}),Db=B(`ZodGUID`,(e,t)=>{uy.init(e,t),Eb.init(e,t)}),Ob=B(`ZodUUID`,(e,t)=>{dy.init(e,t),Eb.init(e,t)}),qne=B(`ZodURL`,(e,t)=>{py.init(e,t),Eb.init(e,t)}),Jne=B(`ZodEmoji`,(e,t)=>{my.init(e,t),Eb.init(e,t)}),Yne=B(`ZodNanoID`,(e,t)=>{hy.init(e,t),Eb.init(e,t)}),Xne=B(`ZodCUID`,(e,t)=>{gy.init(e,t),Eb.init(e,t)}),Zne=B(`ZodCUID2`,(e,t)=>{_y.init(e,t),Eb.init(e,t)}),Qne=B(`ZodULID`,(e,t)=>{vy.init(e,t),Eb.init(e,t)}),$ne=B(`ZodXID`,(e,t)=>{yy.init(e,t),Eb.init(e,t)}),ere=B(`ZodKSUID`,(e,t)=>{by.init(e,t),Eb.init(e,t)}),tre=B(`ZodIPv4`,(e,t)=>{Ty.init(e,t),Eb.init(e,t)}),nre=B(`ZodIPv6`,(e,t)=>{Ey.init(e,t),Eb.init(e,t)}),rre=B(`ZodCIDRv4`,(e,t)=>{Dy.init(e,t),Eb.init(e,t)}),ire=B(`ZodCIDRv6`,(e,t)=>{Oy.init(e,t),Eb.init(e,t)}),are=B(`ZodBase64`,(e,t)=>{Ay.init(e,t),Eb.init(e,t)}),ore=B(`ZodBase64URL`,(e,t)=>{My.init(e,t),Eb.init(e,t)}),sre=B(`ZodE164`,(e,t)=>{Ny.init(e,t),Eb.init(e,t)}),cre=B(`ZodJWT`,(e,t)=>{Fy.init(e,t),Eb.init(e,t)}),kb=B(`ZodNumber`,(e,t)=>{Iy.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>sne(e,t,n,r),Sb(e,`ZodNumber`,{gt(e,t){return this.check(ob(e,t))},gte(e,t){return this.check(sb(e,t))},min(e,t){return this.check(sb(e,t))},lt(e,t){return this.check(ib(e,t))},lte(e,t){return this.check(ab(e,t))},max(e,t){return this.check(ab(e,t))},int(e){return this.check(Ab(e))},safe(e){return this.check(Ab(e))},positive(e){return this.check(ob(0,e))},nonnegative(e){return this.check(sb(0,e))},negative(e){return this.check(ib(0,e))},nonpositive(e){return this.check(ab(0,e))},multipleOf(e,t){return this.check(cb(e,t))},step(e,t){return this.check(cb(e,t))},finite(){return this}});let n=e._zod.bag;e.minValue=Math.max(n.minimum??-1/0,n.exclusiveMinimum??-1/0)??null,e.maxValue=Math.min(n.maximum??1/0,n.exclusiveMaximum??1/0)??null,e.isInt=(n.format??``).includes(`int`)||Number.isSafeInteger(n.multipleOf??.5),e.isFinite=!0,e.format=n.format??null});function lre(e){return Rte(kb,e)}var ure=B(`ZodNumberFormat`,(e,t)=>{Ly.init(e,t),kb.init(e,t)});function Ab(e){return zte(ure,e)}var dre=B(`ZodBoolean`,(e,t)=>{Ry.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>cne(e,t,n,r)});function fre(e){return Bte(dre,e)}var pre=B(`ZodUnknown`,(e,t)=>{zy.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(e,t,n)=>void 0});function jb(){return Vte(pre)}var mre=B(`ZodNever`,(e,t)=>{By.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>lne(e,t,n,r)});function hre(e){return Hte(mre,e)}var gre=B(`ZodArray`,(e,t)=>{qee.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>pne(e,t,n,r),e.element=t.element,Sb(e,`ZodArray`,{min(e,t){return this.check(ub(e,t))},nonempty(e){return this.check(ub(1,e))},max(e,t){return this.check(lb(e,t))},length(e,t){return this.check(db(e,t))},unwrap(){return this.element}})});function Mb(e,t){return ene(gre,e,t)}var _re=B(`ZodObject`,(e,t)=>{Yee.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>mne(e,t,n,r),h_(e,`shape`,()=>t.shape),Sb(e,`ZodObject`,{keyof(){return Lb(Object.keys(this._zod.def.shape))},catchall(e){return this.clone({...this._zod.def,catchall:e})},passthrough(){return this.clone({...this._zod.def,catchall:jb()})},loose(){return this.clone({...this._zod.def,catchall:jb()})},strict(){return this.clone({...this._zod.def,catchall:hre()})},strip(){return this.clone({...this._zod.def,catchall:void 0})},extend(e){return M_(this,e)},safeExtend(e){return N_(this,e)},merge(e){return P_(this,e)},pick(e){return A_(this,e)},omit(e){return j_(this,e)},partial(...e){return F_(Bb,this,e[0])},required(...e){return I_(Xb,this,e[0])}})});function Nb(e,t){return new _re({type:`object`,shape:e??{},...V(t)})}var vre=B(`ZodUnion`,(e,t)=>{Xee.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>hne(e,t,n,r),e.options=t.options});function yre(e,t){return new vre({type:`union`,options:e,...V(t)})}var bre=B(`ZodIntersection`,(e,t)=>{Zee.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>gne(e,t,n,r)});function xre(e,t){return new bre({type:`intersection`,left:e,right:t})}var Pb=B(`ZodRecord`,(e,t)=>{Qee.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>_ne(e,t,n,r),e.keyType=t.keyType,e.valueType=t.valueType});function Fb(e,t,n){return!t||!t._zod?new Pb({type:`record`,keyType:Tb(),valueType:e,...V(t)}):new Pb({type:`record`,keyType:e,valueType:t,...V(n)})}var Ib=B(`ZodEnum`,(e,t)=>{$ee.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>une(e,t,n,r),e.enum=t.entries,e.options=Object.values(t.entries);let n=new Set(Object.keys(t.entries));e.extract=(e,r)=>{let i={};for(let r of e)if(n.has(r))i[r]=t.entries[r];else throw Error(`Key ${r} not found in enum`);return new Ib({...t,checks:[],...V(r),entries:i})},e.exclude=(e,r)=>{let i={...t.entries};for(let t of e)if(n.has(t))delete i[t];else throw Error(`Key ${t} not found in enum`);return new Ib({...t,checks:[],...V(r),entries:i})}});function Lb(e,t){return new Ib({type:`enum`,entries:Array.isArray(e)?Object.fromEntries(e.map(e=>[e,e])):e,...V(t)})}var Rb=B(`ZodTransform`,(e,t)=>{ete.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>fne(e,t,n,r),e._zod.parse=(n,r)=>{if(r.direction===`backward`)throw new a_(e.constructor.name);n.addIssue=r=>{if(typeof r==`string`)n.issues.push(U_(r,n.value,t));else{let t=r;t.fatal&&(t.continue=!1),t.code??=`custom`,t.input??=n.value,t.inst??=e,n.issues.push(U_(t))}};let i=t.transform(n.value,n);return i instanceof Promise?i.then(e=>(n.value=e,n.fallback=!0,n)):(n.value=i,n.fallback=!0,n)}});function zb(e){return new Rb({type:`transform`,transform:e})}var Bb=B(`ZodOptional`,(e,t)=>{Yy.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>yb(e,t,n,r),e.unwrap=()=>e._zod.def.innerType});function Vb(e){return new Bb({type:`optional`,innerType:e})}var Hb=B(`ZodExactOptional`,(e,t)=>{tte.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>yb(e,t,n,r),e.unwrap=()=>e._zod.def.innerType});function Ub(e){return new Hb({type:`optional`,innerType:e})}var Wb=B(`ZodNullable`,(e,t)=>{nte.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>vne(e,t,n,r),e.unwrap=()=>e._zod.def.innerType});function Gb(e){return new Wb({type:`nullable`,innerType:e})}var Kb=B(`ZodDefault`,(e,t)=>{rte.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>bne(e,t,n,r),e.unwrap=()=>e._zod.def.innerType,e.removeDefault=e.unwrap});function qb(e,t){return new Kb({type:`default`,innerType:e,get defaultValue(){return typeof t==`function`?t():w_(t)}})}var Jb=B(`ZodPrefault`,(e,t)=>{ite.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>xne(e,t,n,r),e.unwrap=()=>e._zod.def.innerType});function Yb(e,t){return new Jb({type:`prefault`,innerType:e,get defaultValue(){return typeof t==`function`?t():w_(t)}})}var Xb=B(`ZodNonOptional`,(e,t)=>{ate.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>yne(e,t,n,r),e.unwrap=()=>e._zod.def.innerType});function Zb(e,t){return new Xb({type:`nonoptional`,innerType:e,...V(t)})}var Qb=B(`ZodCatch`,(e,t)=>{ote.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Sne(e,t,n,r),e.unwrap=()=>e._zod.def.innerType,e.removeCatch=e.unwrap});function $b(e,t){return new Qb({type:`catch`,innerType:e,catchValue:typeof t==`function`?t:()=>t})}var ex=B(`ZodPipe`,(e,t)=>{ste.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Cne(e,t,n,r),e.in=t.in,e.out=t.out});function tx(e,t){return new ex({type:`pipe`,in:e,out:t})}var nx=B(`ZodReadonly`,(e,t)=>{cte.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>wne(e,t,n,r),e.unwrap=()=>e._zod.def.innerType});function rx(e){return new nx({type:`readonly`,innerType:e})}var ix=B(`ZodCustom`,(e,t)=>{lte.init(e,t),Cb.init(e,t),e._zod.processJSONSchema=(t,n,r)=>dne(e,t,n,r)});function ax(e,t={}){return tne(ix,e,t)}function ox(e,t){return nne(e,t)}var sx=`spinifex:v1:aws-credentials`,cx=Nb({accessKeyId:Tb().min(16,`Access Key ID must be at least 16 characters`),secretAccessKey:Tb().min(1,`Secret Access Key is required`)}),lx;function ux(){if(lx!==void 0)return lx;try{let e=localStorage.getItem(sx);if(!e)return lx=null,null;let t=JSON.parse(e),n=cx.safeParse(t);return lx=n.success?n.data:null,lx}catch{return lx=null,null}}function dx(e){try{localStorage.setItem(sx,JSON.stringify(e)),lx=e}catch{lx=e}}function fx(){try{localStorage.removeItem(sx)}catch{}lx=null}var px=e=>new TextEncoder().encode(e),mx=typeof Buffer<`u`&&Buffer.from?function(e){return Buffer.from(e,`utf8`)}:px;function hx(e){return e instanceof Uint8Array?e:typeof e==`string`?mx(e):ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength/Uint8Array.BYTES_PER_ELEMENT):new Uint8Array(e)}function gx(e){return typeof e==`string`?e.length===0:e.byteLength===0}function _x(e){return new Uint8Array([(e&4278190080)>>24,(e&16711680)>>16,(e&65280)>>8,e&255])}function vx(e){if(!Uint32Array.from){for(var t=new Uint32Array(e.length),n=0;n0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw TypeError(t?`Object is not iterable.`:`Symbol.iterator is not defined.`)}var Ox=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),kx=[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225],Ax=2**53-1,jx=function(){function e(){this.state=Int32Array.from(kx),this.temp=new Int32Array(64),this.buffer=new Uint8Array(64),this.bufferLength=0,this.bytesHashed=0,this.finished=!1}return e.prototype.update=function(e){if(this.finished)throw Error(`Attempted to update an already finished hash.`);var t=0,n=e.byteLength;if(this.bytesHashed+=n,this.bytesHashed*8>Ax)throw Error(`Cannot hash more than 2^53 - 1 bits`);for(;n>0;)this.buffer[this.bufferLength++]=e[t++],n--,this.bufferLength===64&&(this.hashBuffer(),this.bufferLength=0)},e.prototype.digest=function(){if(!this.finished){var e=this.bytesHashed*8,t=new DataView(this.buffer.buffer,this.buffer.byteOffset,this.buffer.byteLength),n=this.bufferLength;if(t.setUint8(this.bufferLength++,128),n%64>=56){for(var r=this.bufferLength;r<64;r++)t.setUint8(r,0);this.hashBuffer(),this.bufferLength=0}for(var r=this.bufferLength;r<56;r++)t.setUint8(r,0);t.setUint32(56,Math.floor(e/4294967296),!0),t.setUint32(60,e),this.hashBuffer(),this.finished=!0}for(var i=new Uint8Array(32),r=0;r<8;r++)i[r*4]=this.state[r]>>>24&255,i[r*4+1]=this.state[r]>>>16&255,i[r*4+2]=this.state[r]>>>8&255,i[r*4+3]=this.state[r]>>>0&255;return i},e.prototype.hashBuffer=function(){for(var e=this,t=e.buffer,n=e.state,r=n[0],i=n[1],a=n[2],o=n[3],s=n[4],c=n[5],l=n[6],u=n[7],d=0;d<64;d++){if(d<16)this.temp[d]=(t[d*4]&255)<<24|(t[d*4+1]&255)<<16|(t[d*4+2]&255)<<8|t[d*4+3]&255;else{var f=this.temp[d-2],p=(f>>>17|f<<15)^(f>>>19|f<<13)^f>>>10;f=this.temp[d-15];var m=(f>>>7|f<<25)^(f>>>18|f<<14)^f>>>3;this.temp[d]=(p+this.temp[d-7]|0)+(m+this.temp[d-16]|0)}var h=(((s>>>6|s<<26)^(s>>>11|s<<21)^(s>>>25|s<<7))+(s&c^~s&l)|0)+(u+(Ox[d]+this.temp[d]|0)|0)|0,g=((r>>>2|r<<30)^(r>>>13|r<<19)^(r>>>22|r<<10))+(r&i^r&a^i&a)|0;u=l,l=c,c=s,s=o+h|0,o=a,a=i,i=r,r=h+g|0}n[0]+=r,n[1]+=i,n[2]+=a,n[3]+=o,n[4]+=s,n[5]+=c,n[6]+=l,n[7]+=u},e}(),Mx=function(){function e(e){this.secret=e,this.hash=new jx,this.reset()}return e.prototype.update=function(e){if(!(gx(e)||this.error))try{this.hash.update(hx(e))}catch(e){this.error=e}},e.prototype.digestSync=function(){if(this.error)throw this.error;return this.outer?(this.outer.finished||this.outer.update(this.hash.digest()),this.outer.digest()):this.hash.digest()},e.prototype.digest=function(){return Tx(this,void 0,void 0,function(){return Ex(this,function(e){return[2,this.digestSync()]})})},e.prototype.reset=function(){if(this.hash=new jx,this.secret){this.outer=new jx;var e=Nx(this.secret),t=new Uint8Array(64);t.set(e);for(var n=0;n<64;n++)e[n]^=54,t[n]^=92;this.hash.update(e),this.outer.update(t);for(var n=0;n64){var n=new jx;n.update(t),t=n.digest()}var r=new Uint8Array(64);return r.set(t),r}var Px=[`decrypt`,`digest`,`encrypt`,`exportKey`,`generateKey`,`importKey`,`sign`,`verify`];function Fx(e){if(Ix(e)&&typeof e.crypto.subtle==`object`){var t=e.crypto.subtle;return Lx(t)}return!1}function Ix(e){return typeof e==`object`&&typeof e.crypto==`object`?typeof e.crypto.getRandomValues==`function`:!1}function Lx(e){return e&&Px.every(function(t){return typeof e[t]==`function`})}var Rx=function(){function e(e){Fx(Cx())?this.hash=new wx(e):this.hash=new Mx(e)}return e.prototype.update=function(e,t){this.hash.update(hx(e))},e.prototype.digest=function(){return this.hash.digest()},e.prototype.reset=function(){this.hash.reset()},e}(),zx=e=>({setHttpHandler(t){e.httpHandler=t},httpHandler(){return e.httpHandler},updateHttpClientConfig(t,n){e.httpHandler?.updateHttpClientConfig(t,n)},httpHandlerConfigs(){return e.httpHandler.httpHandlerConfigs()}}),Bx=e=>({httpHandler:e.httpHandler()}),Vx;(function(e){e.HTTP=`http`,e.HTTPS=`https`})(Vx||={});var Hx;(function(e){e.MD5=`md5`,e.CRC32=`crc32`,e.CRC32C=`crc32c`,e.SHA1=`sha1`,e.SHA256=`sha256`})(Hx||={});var Ux=`__smithy_context`,Wx=class e{method;protocol;hostname;port;path;query;headers;username;password;fragment;body;constructor(e){this.method=e.method||`GET`,this.hostname=e.hostname||`localhost`,this.port=e.port,this.query=e.query||{},this.headers=e.headers||{},this.body=e.body,this.protocol=e.protocol?e.protocol.slice(-1)===`:`?e.protocol:`${e.protocol}:`:`https:`,this.path=e.path?e.path.charAt(0)===`/`?e.path:`/${e.path}`:`/`,this.username=e.username,this.password=e.password,this.fragment=e.fragment}static clone(t){let n=new e({...t,headers:{...t.headers}});return n.query&&=Gx(n.query),n}static isInstance(e){if(!e)return!1;let t=e;return`method`in t&&`protocol`in t&&`hostname`in t&&`path`in t&&typeof t.query==`object`&&typeof t.headers==`object`}clone(){return e.clone(this)}};function Gx(e){return Object.keys(e).reduce((t,n)=>{let r=e[n];return{...t,[n]:Array.isArray(r)?[...r]:r}},{})}var Kx=class{statusCode;reason;headers;body;constructor(e){this.statusCode=e.statusCode,this.reason=e.reason,this.headers=e.headers||{},this.body=e.body}static isInstance(e){if(!e)return!1;let t=e;return typeof t.statusCode==`number`&&typeof t.headers==`object`}},qx={},Jx={};for(let e=0;e<256;e++){let t=e.toString(16).toLowerCase();t.length===1&&(t=`0${t}`),qx[e]=t,Jx[t]=e}function Yx(e){if(e.length%2!=0)throw Error(`Hex encoded strings must have an even number length`);let t=new Uint8Array(e.length/2);for(let n=0;nnew TextEncoder().encode(e),Qx=e=>typeof e==`string`?Zx(e):ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength/Uint8Array.BYTES_PER_ELEMENT):new Uint8Array(e),$x=e=>{if(typeof e==`string`)return e;if(typeof e!=`object`||typeof e.byteOffset!=`number`||typeof e.byteLength!=`number`)throw Error(`@smithy/util-utf8: toUtf8 encoder function only accepts string | Uint8Array.`);return new TextDecoder(`utf-8`).decode(e)},eS=`X-Amz-Algorithm`,tS=`X-Amz-Credential`,nS=`X-Amz-Date`,rS=`X-Amz-SignedHeaders`,iS=`X-Amz-Expires`,aS=`X-Amz-Signature`,oS=`X-Amz-Security-Token`,sS=`authorization`,cS=nS.toLowerCase(),lS=[sS,cS,`date`];aS.toLowerCase();var uS=`x-amz-content-sha256`,dS=oS.toLowerCase(),fS={authorization:!0,"cache-control":!0,connection:!0,expect:!0,from:!0,"keep-alive":!0,"max-forwards":!0,pragma:!0,referer:!0,te:!0,trailer:!0,"transfer-encoding":!0,upgrade:!0,"user-agent":!0,"x-amzn-trace-id":!0},pS=/^proxy-/,mS=/^sec-/,hS=`AWS4-HMAC-SHA256`,gS=`AWS4-HMAC-SHA256-PAYLOAD`,_S=`UNSIGNED-PAYLOAD`,vS=`aws4_request`,yS={},bS=[],xS=(e,t,n)=>`${e}/${t}/${n}/${vS}`,SS=async(e,t,n,r,i)=>{let a=`${n}:${r}:${i}:${Xx(await CS(e,t.secretAccessKey,t.accessKeyId))}:${t.sessionToken}`;if(a in yS)return yS[a];for(bS.push(a);bS.length>50;)delete yS[bS.shift()];let o=`AWS4${t.secretAccessKey}`;for(let t of[n,r,i,vS])o=await CS(e,o,t);return yS[a]=o},CS=(e,t,n)=>{let r=new e(t);return r.update(Qx(n)),r.digest()},wS=({headers:e},t,n)=>{let r={};for(let i of Object.keys(e).sort()){if(e[i]==null)continue;let a=i.toLowerCase();(a in fS||t?.has(a)||pS.test(a)||mS.test(a))&&(!n||n&&!n.has(a))||(r[a]=e[i].trim().replace(/\s+/g,` `))}return r},TS=e=>typeof ArrayBuffer==`function`&&e instanceof ArrayBuffer||Object.prototype.toString.call(e)===`[object ArrayBuffer]`,ES=async({headers:e,body:t},n)=>{for(let t of Object.keys(e))if(t.toLowerCase()===`x-amz-content-sha256`)return e[t];if(t==null)return`e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`;if(typeof t==`string`||ArrayBuffer.isView(t)||TS(t)){let e=new n;return e.update(Qx(t)),Xx(await e.digest())}return _S},DS=class{format(e){let t=[];for(let n of Object.keys(e)){let r=Zx(n);t.push(Uint8Array.from([r.byteLength]),r,this.formatHeaderValue(e[n]))}let n=new Uint8Array(t.reduce((e,t)=>e+t.byteLength,0)),r=0;for(let e of t)n.set(e,r),r+=e.byteLength;return n}formatHeaderValue(e){switch(e.type){case`boolean`:return Uint8Array.from([+!e.value]);case`byte`:return Uint8Array.from([2,e.value]);case`short`:let t=new DataView(new ArrayBuffer(3));return t.setUint8(0,3),t.setInt16(1,e.value,!1),new Uint8Array(t.buffer);case`integer`:let n=new DataView(new ArrayBuffer(5));return n.setUint8(0,4),n.setInt32(1,e.value,!1),new Uint8Array(n.buffer);case`long`:let r=new Uint8Array(9);return r[0]=5,r.set(e.value.bytes,1),r;case`binary`:let i=new DataView(new ArrayBuffer(3+e.value.byteLength));i.setUint8(0,6),i.setUint16(1,e.value.byteLength,!1);let a=new Uint8Array(i.buffer);return a.set(e.value,3),a;case`string`:let o=Zx(e.value),s=new DataView(new ArrayBuffer(3+o.byteLength));s.setUint8(0,7),s.setUint16(1,o.byteLength,!1);let c=new Uint8Array(s.buffer);return c.set(o,3),c;case`timestamp`:let l=new Uint8Array(9);return l[0]=8,l.set(AS.fromNumber(e.value.valueOf()).bytes,1),l;case`uuid`:if(!kS.test(e.value))throw Error(`Invalid UUID received: ${e.value}`);let u=new Uint8Array(17);return u[0]=9,u.set(Yx(e.value.replace(/\-/g,``)),1),u}}},OS;(function(e){e[e.boolTrue=0]=`boolTrue`,e[e.boolFalse=1]=`boolFalse`,e[e.byte=2]=`byte`,e[e.short=3]=`short`,e[e.integer=4]=`integer`,e[e.long=5]=`long`,e[e.byteArray=6]=`byteArray`,e[e.string=7]=`string`,e[e.timestamp=8]=`timestamp`,e[e.uuid=9]=`uuid`})(OS||={});var kS=/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/,AS=class e{bytes;constructor(e){if(this.bytes=e,e.byteLength!==8)throw Error(`Int64 buffers must be exactly 8 bytes`)}static fromNumber(t){if(t>0x8000000000000000||t<-0x8000000000000000)throw Error(`${t} is too large (or, if negative, too small) to represent as an Int64`);let n=new Uint8Array(8);for(let e=7,r=Math.abs(Math.round(t));e>-1&&r>0;e--,r/=256)n[e]=r;return t<0&&jS(n),new e(n)}valueOf(){let e=this.bytes.slice(0),t=e[0]&128;return t&&jS(e),parseInt(Xx(e),16)*(t?-1:1)}toString(){return String(this.valueOf())}};function jS(e){for(let t=0;t<8;t++)e[t]^=255;for(let t=7;t>-1&&(e[t]++,e[t]===0);t--);}var MS=(e,t)=>{e=e.toLowerCase();for(let n of Object.keys(t))if(e===n.toLowerCase())return!0;return!1},NS=(e,t={})=>{let{headers:n,query:r={}}=Wx.clone(e);for(let e of Object.keys(n)){let i=e.toLowerCase();(i.slice(0,6)===`x-amz-`&&!t.unhoistableHeaders?.has(i)||t.hoistableHeaders?.has(i))&&(r[e]=n[e],delete n[e])}return{...e,headers:n,query:r}},PS=e=>{e=Wx.clone(e);for(let t of Object.keys(e.headers))lS.indexOf(t.toLowerCase())>-1&&delete e.headers[t];return e},FS=e=>e.__smithy_context||={},IS=e=>{if(typeof e==`function`)return e;let t=Promise.resolve(e);return()=>t},LS=e=>encodeURIComponent(e).replace(/[!'()*]/g,RS),RS=e=>`%${e.charCodeAt(0).toString(16).toUpperCase()}`,zS=({query:e={}})=>{let t=[],n={};for(let r of Object.keys(e)){if(r.toLowerCase()===`x-amz-signature`)continue;let i=LS(r);t.push(i);let a=e[r];typeof a==`string`?n[i]=`${i}=${LS(a)}`:Array.isArray(a)&&(n[i]=a.slice(0).reduce((e,t)=>e.concat([`${i}=${LS(t)}`]),[]).sort().join(`&`))}return t.sort().map(e=>n[e]).filter(e=>e).join(`&`)},BS=e=>VS(e).toISOString().replace(/\.\d{3}Z$/,`Z`),VS=e=>typeof e==`number`?new Date(e*1e3):typeof e==`string`?Number(e)?new Date(Number(e)*1e3):new Date(e):e,HS=class{service;regionProvider;credentialProvider;sha256;uriEscapePath;applyChecksum;constructor({applyChecksum:e,credentials:t,region:n,service:r,sha256:i,uriEscapePath:a=!0}){this.service=r,this.sha256=i,this.uriEscapePath=a,this.applyChecksum=typeof e==`boolean`?e:!0,this.regionProvider=IS(n),this.credentialProvider=IS(t)}createCanonicalRequest(e,t,n){let r=Object.keys(t).sort();return`${e.method} +Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.`)}for(let n of e.seen.entries()){let r=n[1];if(t===n[0]){a(n);continue}if(e.external){let r=e.external.registry.get(n[0])?.id;if(t!==n[0]&&r){a(n);continue}}if(e.metadataRegistry.get(n[0])?.id){a(n);continue}if(r.cycle){a(n);continue}if(r.count>1&&e.reused===`ref`){a(n);continue}}}function Uy(e,t){let n=e.seen.get(t);if(!n)throw Error(`Unprocessed schema. This is a bug in Zod.`);let r=t=>{let n=e.seen.get(t);if(n.ref===null)return;let i=n.def??n.schema,a={...i},o=n.ref;if(n.ref=null,o){r(o);let n=e.seen.get(o),s=n.schema;if(s.$ref&&(e.target===`draft-07`||e.target===`draft-04`||e.target===`openapi-3.0`)?(i.allOf=i.allOf??[],i.allOf.push(s)):Object.assign(i,s),Object.assign(i,a),t._zod.parent===o)for(let e in i)e===`$ref`||e===`allOf`||e in a||delete i[e];if(s.$ref&&n.def)for(let e in i)e===`$ref`||e===`allOf`||e in n.def&&JSON.stringify(i[e])===JSON.stringify(n.def[e])&&delete i[e]}let s=t._zod.parent;if(s&&s!==o){r(s);let t=e.seen.get(s);if(t?.schema.$ref&&(i.$ref=t.schema.$ref,t.def))for(let e in i)e===`$ref`||e===`allOf`||e in t.def&&JSON.stringify(i[e])===JSON.stringify(t.def[e])&&delete i[e]}e.override({zodSchema:t,jsonSchema:i,path:n.path??[]})};for(let t of[...e.seen.entries()].reverse())r(t[0]);let i={};if(e.target===`draft-2020-12`?i.$schema=`https://json-schema.org/draft/2020-12/schema`:e.target===`draft-07`?i.$schema=`http://json-schema.org/draft-07/schema#`:e.target===`draft-04`?i.$schema=`http://json-schema.org/draft-04/schema#`:e.target,e.external?.uri){let n=e.external.registry.get(t)?.id;if(!n)throw Error("Schema is missing an `id` property");i.$id=e.external.uri(n)}Object.assign(i,n.def??n.schema);let a=e.metadataRegistry.get(t)?.id;a!==void 0&&i.id===a&&delete i.id;let o=e.external?.defs??{};for(let t of e.seen.entries()){let e=t[1];e.def&&e.defId&&(e.def.id===e.defId&&delete e.def.id,o[e.defId]=e.def)}e.external||Object.keys(o).length>0&&(e.target===`draft-2020-12`?i.$defs=o:i.definitions=o);try{let n=JSON.parse(JSON.stringify(i));return Object.defineProperty(n,`~standard`,{value:{...t[`~standard`],jsonSchema:{input:Gy(t,`input`,e.processors),output:Gy(t,`output`,e.processors)}},enumerable:!1,writable:!1}),n}catch{throw Error(`Error converting schema to JSON.`)}}function Wy(e,t){let n=t??{seen:new Set};if(n.seen.has(e))return!1;n.seen.add(e);let r=e._zod.def;if(r.type===`transform`)return!0;if(r.type===`array`)return Wy(r.element,n);if(r.type===`set`)return Wy(r.valueType,n);if(r.type===`lazy`)return Wy(r.getter(),n);if(r.type===`promise`||r.type===`optional`||r.type===`nonoptional`||r.type===`nullable`||r.type===`readonly`||r.type===`default`||r.type===`prefault`)return Wy(r.innerType,n);if(r.type===`intersection`)return Wy(r.left,n)||Wy(r.right,n);if(r.type===`record`||r.type===`map`)return Wy(r.keyType,n)||Wy(r.valueType,n);if(r.type===`pipe`)return e._zod.traits.has(`$ZodCodec`)?!0:Wy(r.in,n)||Wy(r.out,n);if(r.type===`object`){for(let e in r.shape)if(Wy(r.shape[e],n))return!0;return!1}if(r.type===`union`){for(let e of r.options)if(Wy(e,n))return!0;return!1}if(r.type===`tuple`){for(let e of r.items)if(Wy(e,n))return!0;return!!(r.rest&&Wy(r.rest,n))}return!1}var jne=(e,t={})=>n=>{let r=By({...n,processors:t});return Vy(e,r),Hy(r,e),Uy(r,e)},Gy=(e,t,n={})=>r=>{let{libraryOptions:i,target:a}=r??{},o=By({...i??{},target:a,io:t,processors:n});return Vy(e,o),Hy(o,e),Uy(o,e)},Mne={guid:`uuid`,url:`uri`,datetime:`date-time`,json_string:`json-string`,regex:``},Nne=(e,t,n,r)=>{let i=n;i.type=`string`;let{minimum:a,maximum:o,format:s,patterns:c,contentEncoding:l}=e._zod.bag;if(typeof a==`number`&&(i.minLength=a),typeof o==`number`&&(i.maxLength=o),s&&(i.format=Mne[s]??s,i.format===``&&delete i.format,s===`time`&&delete i.format),l&&(i.contentEncoding=l),c&&c.size>0){let e=[...c];e.length===1?i.pattern=e[0].source:e.length>1&&(i.allOf=[...e.map(e=>({...t.target===`draft-07`||t.target===`draft-04`||t.target===`openapi-3.0`?{type:`string`}:{},pattern:e.source}))])}},Pne=(e,t,n,r)=>{let i=n,{minimum:a,maximum:o,format:s,multipleOf:c,exclusiveMaximum:l,exclusiveMinimum:u}=e._zod.bag;typeof s==`string`&&s.includes(`int`)?i.type=`integer`:i.type=`number`;let d=typeof u==`number`&&u>=(a??-1/0),f=typeof l==`number`&&l<=(o??1/0),p=t.target===`draft-04`||t.target===`openapi-3.0`;d?p?(i.minimum=u,i.exclusiveMinimum=!0):i.exclusiveMinimum=u:typeof a==`number`&&(i.minimum=a),f?p?(i.maximum=l,i.exclusiveMaximum=!0):i.exclusiveMaximum=l:typeof o==`number`&&(i.maximum=o),typeof c==`number`&&(i.multipleOf=c)},Fne=(e,t,n,r)=>{n.type=`boolean`},Ine=(e,t,n,r)=>{n.not={}},Lne=(e,t,n,r)=>{let i=e._zod.def,a=hg(i.entries);a.every(e=>typeof e==`number`)&&(n.type=`number`),a.every(e=>typeof e==`string`)&&(n.type=`string`),n.enum=a},Rne=(e,t,n,r)=>{if(t.unrepresentable===`throw`)throw Error(`Custom types cannot be represented in JSON Schema`)},zne=(e,t,n,r)=>{if(t.unrepresentable===`throw`)throw Error(`Transforms cannot be represented in JSON Schema`)},Bne=(e,t,n,r)=>{let i=n,a=e._zod.def,{minimum:o,maximum:s}=e._zod.bag;typeof o==`number`&&(i.minItems=o),typeof s==`number`&&(i.maxItems=s),i.type=`array`,i.items=Vy(a.element,t,{...r,path:[...r.path,`items`]})},Vne=(e,t,n,r)=>{let i=n,a=e._zod.def;i.type=`object`,i.properties={};let o=a.shape;for(let e in o)i.properties[e]=Vy(o[e],t,{...r,path:[...r.path,`properties`,e]});let s=new Set(Object.keys(o)),c=new Set([...s].filter(e=>{let n=a.shape[e]._zod;return t.io===`input`?n.optin===void 0:n.optout===void 0}));c.size>0&&(i.required=Array.from(c)),a.catchall?._zod.def.type===`never`?i.additionalProperties=!1:a.catchall?a.catchall&&(i.additionalProperties=Vy(a.catchall,t,{...r,path:[...r.path,`additionalProperties`]})):t.io===`output`&&(i.additionalProperties=!1)},Hne=(e,t,n,r)=>{let i=e._zod.def,a=i.inclusive===!1,o=i.options.map((e,n)=>Vy(e,t,{...r,path:[...r.path,a?`oneOf`:`anyOf`,n]}));a?n.oneOf=o:n.anyOf=o},Une=(e,t,n,r)=>{let i=e._zod.def,a=Vy(i.left,t,{...r,path:[...r.path,`allOf`,0]}),o=Vy(i.right,t,{...r,path:[...r.path,`allOf`,1]}),s=e=>`allOf`in e&&Object.keys(e).length===1;n.allOf=[...s(a)?a.allOf:[a],...s(o)?o.allOf:[o]]},Wne=(e,t,n,r)=>{let i=n,a=e._zod.def;i.type=`object`;let o=a.keyType,s=o._zod.bag?.patterns;if(a.mode===`loose`&&s&&s.size>0){let e=Vy(a.valueType,t,{...r,path:[...r.path,`patternProperties`,`*`]});i.patternProperties={};for(let t of s)i.patternProperties[t.source]=e}else (t.target===`draft-07`||t.target===`draft-2020-12`)&&(i.propertyNames=Vy(a.keyType,t,{...r,path:[...r.path,`propertyNames`]})),i.additionalProperties=Vy(a.valueType,t,{...r,path:[...r.path,`additionalProperties`]});let c=o._zod.values;if(c){let e=[...c].filter(e=>typeof e==`string`||typeof e==`number`);e.length>0&&(i.required=e)}},Gne=(e,t,n,r)=>{let i=e._zod.def,a=Vy(i.innerType,t,r),o=t.seen.get(e);t.target===`openapi-3.0`?(o.ref=i.innerType,n.nullable=!0):n.anyOf=[a,{type:`null`}]},Kne=(e,t,n,r)=>{let i=e._zod.def;Vy(i.innerType,t,r);let a=t.seen.get(e);a.ref=i.innerType},qne=(e,t,n,r)=>{let i=e._zod.def;Vy(i.innerType,t,r);let a=t.seen.get(e);a.ref=i.innerType,n.default=JSON.parse(JSON.stringify(i.defaultValue))},Jne=(e,t,n,r)=>{let i=e._zod.def;Vy(i.innerType,t,r);let a=t.seen.get(e);a.ref=i.innerType,t.io===`input`&&(n._prefault=JSON.parse(JSON.stringify(i.defaultValue)))},Yne=(e,t,n,r)=>{let i=e._zod.def;Vy(i.innerType,t,r);let a=t.seen.get(e);a.ref=i.innerType;let o;try{o=i.catchValue(void 0)}catch{throw Error(`Dynamic catch values are not supported in JSON Schema`)}n.default=o},Xne=(e,t,n,r)=>{let i=e._zod.def,a=i.in._zod.traits.has(`$ZodTransform`),o=t.io===`input`?a?i.out:i.in:i.out;Vy(o,t,r);let s=t.seen.get(e);s.ref=o},Zne=(e,t,n,r)=>{let i=e._zod.def;Vy(i.innerType,t,r);let a=t.seen.get(e);a.ref=i.innerType,n.readOnly=!0},Ky=(e,t,n,r)=>{let i=e._zod.def;Vy(i.innerType,t,r);let a=t.seen.get(e);a.ref=i.innerType},Qne=B(`ZodISODateTime`,(e,t)=>{$_.init(e,t),$y.init(e,t)});function $ne(e){return Cy(Qne,e)}var ere=B(`ZodISODate`,(e,t)=>{ev.init(e,t),$y.init(e,t)});function tre(e){return wy(ere,e)}var nre=B(`ZodISOTime`,(e,t)=>{tv.init(e,t),$y.init(e,t)});function rre(e){return Ty(nre,e)}var ire=B(`ZodISODuration`,(e,t)=>{nv.init(e,t),$y.init(e,t)});function are(e){return Ey(ire,e)}var qy=B(`ZodError`,(e,t)=>{Rg.init(e,t),e.name=`ZodError`,Object.defineProperties(e,{format:{value:t=>tne(e,t)},flatten:{value:t=>ene(e,t)},addIssue:{value:t=>{e.issues.push(t),e.message=JSON.stringify(e.issues,gg,2)}},addIssues:{value:t=>{e.issues.push(...t),e.message=JSON.stringify(e.issues,gg,2)}},isEmpty:{get(){return e.issues.length===0}}})},{Parent:Error}),ore=Bg(qy),sre=Vg(qy),cre=Hg(qy),lre=Ug(qy),ure=one(qy),dre=sne(qy),fre=cne(qy),pre=lne(qy),mre=une(qy),hre=dne(qy),gre=fne(qy),_re=pne(qy),Jy=new WeakMap;function Yy(e,t,n){let r=Object.getPrototypeOf(e),i=Jy.get(r);if(i||(i=new Set,Jy.set(r,i)),!i.has(t)){i.add(t);for(let e in n){let t=n[e];Object.defineProperty(r,e,{configurable:!0,enumerable:!1,get(){let n=t.bind(this);return Object.defineProperty(this,e,{configurable:!0,writable:!0,enumerable:!0,value:n}),n},set(t){Object.defineProperty(this,e,{configurable:!0,writable:!0,enumerable:!0,value:t})}})}}}var Xy=B(`ZodType`,(e,t)=>(z_.init(e,t),Object.assign(e[`~standard`],{jsonSchema:{input:Gy(e,`input`),output:Gy(e,`output`)}}),e.toJSONSchema=jne(e,{}),e.def=t,e.type=t.type,Object.defineProperty(e,`_def`,{value:t}),e.parse=(t,n)=>ore(e,t,n,{callee:e.parse}),e.safeParse=(t,n)=>cre(e,t,n),e.parseAsync=async(t,n)=>sre(e,t,n,{callee:e.parseAsync}),e.safeParseAsync=async(t,n)=>lre(e,t,n),e.spa=e.safeParseAsync,e.encode=(t,n)=>ure(e,t,n),e.decode=(t,n)=>dre(e,t,n),e.encodeAsync=async(t,n)=>fre(e,t,n),e.decodeAsync=async(t,n)=>pre(e,t,n),e.safeEncode=(t,n)=>mre(e,t,n),e.safeDecode=(t,n)=>hre(e,t,n),e.safeEncodeAsync=async(t,n)=>gre(e,t,n),e.safeDecodeAsync=async(t,n)=>_re(e,t,n),Yy(e,`ZodType`,{check(...e){let t=this.def;return this.clone(Cg(t,{checks:[...t.checks??[],...e.map(e=>typeof e==`function`?{_zod:{check:e,def:{check:`custom`},onattach:[]}}:e)]}),{parent:!0})},with(...e){return this.check(...e)},clone(e,t){return Ag(this,e,t)},brand(){return this},register(e,t){return e.add(this,t),this},refine(e,t){return this.check(fie(e,t))},superRefine(e,t){return this.check(pie(e,t))},overwrite(e){return this.check(zy(e))},optional(){return db(this)},exactOptional(){return $re(this)},nullable(){return fb(this)},nullish(){return db(fb(this))},nonoptional(e){return aie(this,e)},array(){return ab(this)},or(e){return Kre([this,e])},and(e){return Jre(this,e)},transform(e){return mb(this,Zre(e))},default(e){return nie(this,e)},prefault(e){return iie(this,e)},catch(e){return sie(this,e)},pipe(e){return mb(this,e)},readonly(){return uie(this)},describe(e){let t=this.clone();return $v.add(t,{description:e}),t},meta(...e){if(e.length===0)return $v.get(this);let t=this.clone();return $v.add(t,e[0]),t},isOptional(){return this.safeParse(void 0).success},isNullable(){return this.safeParse(null).success},apply(e){return e(this)}}),Object.defineProperty(e,`description`,{get(){return $v.get(e)?.description},configurable:!0}),e)),Zy=B(`_ZodString`,(e,t)=>{B_.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Nne(e,t,n,r);let n=e._zod.bag;e.format=n.format??null,e.minLength=n.minimum??null,e.maxLength=n.maximum??null,Yy(e,`_ZodString`,{regex(...e){return this.check(gne(...e))},includes(...e){return this.check(yne(...e))},startsWith(...e){return this.check(bne(...e))},endsWith(...e){return this.check(xne(...e))},min(...e){return this.check(Ly(...e))},max(...e){return this.check(Iy(...e))},length(...e){return this.check(Ry(...e))},nonempty(...e){return this.check(Ly(1,...e))},lowercase(e){return this.check(_ne(e))},uppercase(e){return this.check(vne(e))},trim(){return this.check(Cne())},normalize(...e){return this.check(Sne(...e))},toLowerCase(){return this.check(wne())},toUpperCase(){return this.check(Tne())},slugify(){return this.check(Ene())}})}),vre=B(`ZodString`,(e,t)=>{B_.init(e,t),Zy.init(e,t),e.email=t=>e.check(ty(yre,t)),e.url=t=>e.check(sy(bre,t)),e.jwt=t=>e.check(Sy(Fre,t)),e.emoji=t=>e.check(cy(xre,t)),e.guid=t=>e.check(ny(eb,t)),e.uuid=t=>e.check(ry(tb,t)),e.uuidv4=t=>e.check(iy(tb,t)),e.uuidv6=t=>e.check(ay(tb,t)),e.uuidv7=t=>e.check(oy(tb,t)),e.nanoid=t=>e.check(ly(Sre,t)),e.guid=t=>e.check(ny(eb,t)),e.cuid=t=>e.check(uy(Cre,t)),e.cuid2=t=>e.check(dy(wre,t)),e.ulid=t=>e.check(fy(Tre,t)),e.base64=t=>e.check(yy(Mre,t)),e.base64url=t=>e.check(by(Nre,t)),e.xid=t=>e.check(py(Ere,t)),e.ksuid=t=>e.check(my(Dre,t)),e.ipv4=t=>e.check(hy(Ore,t)),e.ipv6=t=>e.check(gy(kre,t)),e.cidrv4=t=>e.check(_y(Are,t)),e.cidrv6=t=>e.check(vy(jre,t)),e.e164=t=>e.check(xy(Pre,t)),e.datetime=t=>e.check($ne(t)),e.date=t=>e.check(tre(t)),e.time=t=>e.check(rre(t)),e.duration=t=>e.check(are(t))});function Qy(e){return ey(vre,e)}var $y=B(`ZodStringFormat`,(e,t)=>{V_.init(e,t),Zy.init(e,t)}),yre=B(`ZodEmail`,(e,t)=>{W_.init(e,t),$y.init(e,t)}),eb=B(`ZodGUID`,(e,t)=>{H_.init(e,t),$y.init(e,t)}),tb=B(`ZodUUID`,(e,t)=>{U_.init(e,t),$y.init(e,t)}),bre=B(`ZodURL`,(e,t)=>{G_.init(e,t),$y.init(e,t)}),xre=B(`ZodEmoji`,(e,t)=>{K_.init(e,t),$y.init(e,t)}),Sre=B(`ZodNanoID`,(e,t)=>{q_.init(e,t),$y.init(e,t)}),Cre=B(`ZodCUID`,(e,t)=>{J_.init(e,t),$y.init(e,t)}),wre=B(`ZodCUID2`,(e,t)=>{Y_.init(e,t),$y.init(e,t)}),Tre=B(`ZodULID`,(e,t)=>{X_.init(e,t),$y.init(e,t)}),Ere=B(`ZodXID`,(e,t)=>{Z_.init(e,t),$y.init(e,t)}),Dre=B(`ZodKSUID`,(e,t)=>{Q_.init(e,t),$y.init(e,t)}),Ore=B(`ZodIPv4`,(e,t)=>{rv.init(e,t),$y.init(e,t)}),kre=B(`ZodIPv6`,(e,t)=>{iv.init(e,t),$y.init(e,t)}),Are=B(`ZodCIDRv4`,(e,t)=>{av.init(e,t),$y.init(e,t)}),jre=B(`ZodCIDRv6`,(e,t)=>{ov.init(e,t),$y.init(e,t)}),Mre=B(`ZodBase64`,(e,t)=>{cv.init(e,t),$y.init(e,t)}),Nre=B(`ZodBase64URL`,(e,t)=>{uv.init(e,t),$y.init(e,t)}),Pre=B(`ZodE164`,(e,t)=>{dv.init(e,t),$y.init(e,t)}),Fre=B(`ZodJWT`,(e,t)=>{pv.init(e,t),$y.init(e,t)}),nb=B(`ZodNumber`,(e,t)=>{mv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Pne(e,t,n,r),Yy(e,`ZodNumber`,{gt(e,t){return this.check(Ny(e,t))},gte(e,t){return this.check(Py(e,t))},min(e,t){return this.check(Py(e,t))},lt(e,t){return this.check(jy(e,t))},lte(e,t){return this.check(My(e,t))},max(e,t){return this.check(My(e,t))},int(e){return this.check(rb(e))},safe(e){return this.check(rb(e))},positive(e){return this.check(Ny(0,e))},nonnegative(e){return this.check(Py(0,e))},negative(e){return this.check(jy(0,e))},nonpositive(e){return this.check(My(0,e))},multipleOf(e,t){return this.check(Fy(e,t))},step(e,t){return this.check(Fy(e,t))},finite(){return this}});let n=e._zod.bag;e.minValue=Math.max(n.minimum??-1/0,n.exclusiveMinimum??-1/0)??null,e.maxValue=Math.min(n.maximum??1/0,n.exclusiveMaximum??1/0)??null,e.isInt=(n.format??``).includes(`int`)||Number.isSafeInteger(n.multipleOf??.5),e.isFinite=!0,e.format=n.format??null});function Ire(e){return Dy(nb,e)}var Lre=B(`ZodNumberFormat`,(e,t)=>{hv.init(e,t),nb.init(e,t)});function rb(e){return Oy(Lre,e)}var Rre=B(`ZodBoolean`,(e,t)=>{gv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Fne(e,t,n,r)});function zre(e){return ky(Rre,e)}var Bre=B(`ZodUnknown`,(e,t)=>{_v.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(e,t,n)=>void 0});function ib(){return Ay(Bre)}var Vre=B(`ZodNever`,(e,t)=>{vv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Ine(e,t,n,r)});function Hre(e){return hne(Vre,e)}var Ure=B(`ZodArray`,(e,t)=>{bv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Bne(e,t,n,r),e.element=t.element,Yy(e,`ZodArray`,{min(e,t){return this.check(Ly(e,t))},nonempty(e){return this.check(Ly(1,e))},max(e,t){return this.check(Iy(e,t))},length(e,t){return this.check(Ry(e,t))},unwrap(){return this.element}})});function ab(e,t){return Dne(Ure,e,t)}var Wre=B(`ZodObject`,(e,t)=>{Tv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Vne(e,t,n,r),xg(e,`shape`,()=>t.shape),Yy(e,`ZodObject`,{keyof(){return lb(Object.keys(this._zod.def.shape))},catchall(e){return this.clone({...this._zod.def,catchall:e})},passthrough(){return this.clone({...this._zod.def,catchall:ib()})},loose(){return this.clone({...this._zod.def,catchall:ib()})},strict(){return this.clone({...this._zod.def,catchall:Hre()})},strip(){return this.clone({...this._zod.def,catchall:void 0})},extend(e){return Jte(this,e)},safeExtend(e){return Yte(this,e)},merge(e){return Xte(this,e)},pick(e){return Kte(this,e)},omit(e){return qte(this,e)},partial(...e){return Zte(ub,this,e[0])},required(...e){return Qte(pb,this,e[0])}})});function ob(e,t){return new Wre({type:`object`,shape:e??{},...V(t)})}var Gre=B(`ZodUnion`,(e,t)=>{Dv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Hne(e,t,n,r),e.options=t.options});function Kre(e,t){return new Gre({type:`union`,options:e,...V(t)})}var qre=B(`ZodIntersection`,(e,t)=>{Ov.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Une(e,t,n,r)});function Jre(e,t){return new qre({type:`intersection`,left:e,right:t})}var sb=B(`ZodRecord`,(e,t)=>{jv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Wne(e,t,n,r),e.keyType=t.keyType,e.valueType=t.valueType});function Yre(e,t,n){return!t||!t._zod?new sb({type:`record`,keyType:Qy(),valueType:e,...V(t)}):new sb({type:`record`,keyType:e,valueType:t,...V(n)})}var cb=B(`ZodEnum`,(e,t)=>{Mv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Lne(e,t,n,r),e.enum=t.entries,e.options=Object.values(t.entries);let n=new Set(Object.keys(t.entries));e.extract=(e,r)=>{let i={};for(let r of e)if(n.has(r))i[r]=t.entries[r];else throw Error(`Key ${r} not found in enum`);return new cb({...t,checks:[],...V(r),entries:i})},e.exclude=(e,r)=>{let i={...t.entries};for(let t of e)if(n.has(t))delete i[t];else throw Error(`Key ${t} not found in enum`);return new cb({...t,checks:[],...V(r),entries:i})}});function lb(e,t){return new cb({type:`enum`,entries:Array.isArray(e)?Object.fromEntries(e.map(e=>[e,e])):e,...V(t)})}var Xre=B(`ZodTransform`,(e,t)=>{Nv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>zne(e,t,n,r),e._zod.parse=(n,r)=>{if(r.direction===`backward`)throw new fg(e.constructor.name);n.addIssue=r=>{if(typeof r==`string`)n.issues.push(Ig(r,n.value,t));else{let t=r;t.fatal&&(t.continue=!1),t.code??=`custom`,t.input??=n.value,t.inst??=e,n.issues.push(Ig(t))}};let i=t.transform(n.value,n);return i instanceof Promise?i.then(e=>(n.value=e,n.fallback=!0,n)):(n.value=i,n.fallback=!0,n)}});function Zre(e){return new Xre({type:`transform`,transform:e})}var ub=B(`ZodOptional`,(e,t)=>{Fv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Ky(e,t,n,r),e.unwrap=()=>e._zod.def.innerType});function db(e){return new ub({type:`optional`,innerType:e})}var Qre=B(`ZodExactOptional`,(e,t)=>{Iv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Ky(e,t,n,r),e.unwrap=()=>e._zod.def.innerType});function $re(e){return new Qre({type:`optional`,innerType:e})}var eie=B(`ZodNullable`,(e,t)=>{Lv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Gne(e,t,n,r),e.unwrap=()=>e._zod.def.innerType});function fb(e){return new eie({type:`nullable`,innerType:e})}var tie=B(`ZodDefault`,(e,t)=>{Rv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>qne(e,t,n,r),e.unwrap=()=>e._zod.def.innerType,e.removeDefault=e.unwrap});function nie(e,t){return new tie({type:`default`,innerType:e,get defaultValue(){return typeof t==`function`?t():Og(t)}})}var rie=B(`ZodPrefault`,(e,t)=>{Bv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Jne(e,t,n,r),e.unwrap=()=>e._zod.def.innerType});function iie(e,t){return new rie({type:`prefault`,innerType:e,get defaultValue(){return typeof t==`function`?t():Og(t)}})}var pb=B(`ZodNonOptional`,(e,t)=>{Vv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Kne(e,t,n,r),e.unwrap=()=>e._zod.def.innerType});function aie(e,t){return new pb({type:`nonoptional`,innerType:e,...V(t)})}var oie=B(`ZodCatch`,(e,t)=>{Uv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Yne(e,t,n,r),e.unwrap=()=>e._zod.def.innerType,e.removeCatch=e.unwrap});function sie(e,t){return new oie({type:`catch`,innerType:e,catchValue:typeof t==`function`?t:()=>t})}var cie=B(`ZodPipe`,(e,t)=>{Wv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Xne(e,t,n,r),e.in=t.in,e.out=t.out});function mb(e,t){return new cie({type:`pipe`,in:e,out:t})}var lie=B(`ZodReadonly`,(e,t)=>{Kv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Zne(e,t,n,r),e.unwrap=()=>e._zod.def.innerType});function uie(e){return new lie({type:`readonly`,innerType:e})}var die=B(`ZodCustom`,(e,t)=>{Jv.init(e,t),Xy.init(e,t),e._zod.processJSONSchema=(t,n,r)=>Rne(e,t,n,r)});function fie(e,t={}){return One(die,e,t)}function pie(e,t){return kne(e,t)}var hb=`spinifex:v1:aws-credentials`,gb=ob({accessKeyId:Qy().min(16,`Access Key ID must be at least 16 characters`),secretAccessKey:Qy().min(1,`Secret Access Key is required`)}),_b;function vb(){if(_b!==void 0)return _b;try{let e=localStorage.getItem(hb);if(!e)return _b=null,null;let t=JSON.parse(e),n=gb.safeParse(t);return _b=n.success?n.data:null,_b}catch{return _b=null,null}}function mie(e){try{localStorage.setItem(hb,JSON.stringify(e)),_b=e}catch{_b=e}}function yb(){try{localStorage.removeItem(hb)}catch{}_b=null}var bb=e=>new TextEncoder().encode(e),hie=typeof Buffer<`u`&&Buffer.from?function(e){return Buffer.from(e,`utf8`)}:bb;function xb(e){return e instanceof Uint8Array?e:typeof e==`string`?hie(e):ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength/Uint8Array.BYTES_PER_ELEMENT):new Uint8Array(e)}function Sb(e){return typeof e==`string`?e.length===0:e.byteLength===0}function Cb(e){return new Uint8Array([(e&4278190080)>>24,(e&16711680)>>16,(e&65280)>>8,e&255])}function wb(e){if(!Uint32Array.from){for(var t=new Uint32Array(e.length),n=0;n0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw TypeError(t?`Object is not iterable.`:`Symbol.iterator is not defined.`)}var yie=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),bie=[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225],xie=2**53-1,jb=function(){function e(){this.state=Int32Array.from(bie),this.temp=new Int32Array(64),this.buffer=new Uint8Array(64),this.bufferLength=0,this.bytesHashed=0,this.finished=!1}return e.prototype.update=function(e){if(this.finished)throw Error(`Attempted to update an already finished hash.`);var t=0,n=e.byteLength;if(this.bytesHashed+=n,this.bytesHashed*8>xie)throw Error(`Cannot hash more than 2^53 - 1 bits`);for(;n>0;)this.buffer[this.bufferLength++]=e[t++],n--,this.bufferLength===64&&(this.hashBuffer(),this.bufferLength=0)},e.prototype.digest=function(){if(!this.finished){var e=this.bytesHashed*8,t=new DataView(this.buffer.buffer,this.buffer.byteOffset,this.buffer.byteLength),n=this.bufferLength;if(t.setUint8(this.bufferLength++,128),n%64>=56){for(var r=this.bufferLength;r<64;r++)t.setUint8(r,0);this.hashBuffer(),this.bufferLength=0}for(var r=this.bufferLength;r<56;r++)t.setUint8(r,0);t.setUint32(56,Math.floor(e/4294967296),!0),t.setUint32(60,e),this.hashBuffer(),this.finished=!0}for(var i=new Uint8Array(32),r=0;r<8;r++)i[r*4]=this.state[r]>>>24&255,i[r*4+1]=this.state[r]>>>16&255,i[r*4+2]=this.state[r]>>>8&255,i[r*4+3]=this.state[r]>>>0&255;return i},e.prototype.hashBuffer=function(){for(var e=this,t=e.buffer,n=e.state,r=n[0],i=n[1],a=n[2],o=n[3],s=n[4],c=n[5],l=n[6],u=n[7],d=0;d<64;d++){if(d<16)this.temp[d]=(t[d*4]&255)<<24|(t[d*4+1]&255)<<16|(t[d*4+2]&255)<<8|t[d*4+3]&255;else{var f=this.temp[d-2],p=(f>>>17|f<<15)^(f>>>19|f<<13)^f>>>10;f=this.temp[d-15];var m=(f>>>7|f<<25)^(f>>>18|f<<14)^f>>>3;this.temp[d]=(p+this.temp[d-7]|0)+(m+this.temp[d-16]|0)}var h=(((s>>>6|s<<26)^(s>>>11|s<<21)^(s>>>25|s<<7))+(s&c^~s&l)|0)+(u+(yie[d]+this.temp[d]|0)|0)|0,g=((r>>>2|r<<30)^(r>>>13|r<<19)^(r>>>22|r<<10))+(r&i^r&a^i&a)|0;u=l,l=c,c=s,s=o+h|0,o=a,a=i,i=r,r=h+g|0}n[0]+=r,n[1]+=i,n[2]+=a,n[3]+=o,n[4]+=s,n[5]+=c,n[6]+=l,n[7]+=u},e}(),Sie=function(){function e(e){this.secret=e,this.hash=new jb,this.reset()}return e.prototype.update=function(e){if(!(Sb(e)||this.error))try{this.hash.update(xb(e))}catch(e){this.error=e}},e.prototype.digestSync=function(){if(this.error)throw this.error;return this.outer?(this.outer.finished||this.outer.update(this.hash.digest()),this.outer.digest()):this.hash.digest()},e.prototype.digest=function(){return Ob(this,void 0,void 0,function(){return kb(this,function(e){return[2,this.digestSync()]})})},e.prototype.reset=function(){if(this.hash=new jb,this.secret){this.outer=new jb;var e=Cie(this.secret),t=new Uint8Array(64);t.set(e);for(var n=0;n<64;n++)e[n]^=54,t[n]^=92;this.hash.update(e),this.outer.update(t);for(var n=0;n64){var n=new jb;n.update(t),t=n.digest()}var r=new Uint8Array(64);return r.set(t),r}var wie=[`decrypt`,`digest`,`encrypt`,`exportKey`,`generateKey`,`importKey`,`sign`,`verify`];function Mb(e){if(Tie(e)&&typeof e.crypto.subtle==`object`){var t=e.crypto.subtle;return Eie(t)}return!1}function Tie(e){return typeof e==`object`&&typeof e.crypto==`object`?typeof e.crypto.getRandomValues==`function`:!1}function Eie(e){return e&&wie.every(function(t){return typeof e[t]==`function`})}var Nb=function(){function e(e){Mb(Db())?this.hash=new vie(e):this.hash=new Sie(e)}return e.prototype.update=function(e,t){this.hash.update(xb(e))},e.prototype.digest=function(){return this.hash.digest()},e.prototype.reset=function(){this.hash.reset()},e}(),Pb=e=>({setHttpHandler(t){e.httpHandler=t},httpHandler(){return e.httpHandler},updateHttpClientConfig(t,n){e.httpHandler?.updateHttpClientConfig(t,n)},httpHandlerConfigs(){return e.httpHandler.httpHandlerConfigs()}}),Fb=e=>({httpHandler:e.httpHandler()}),Ib;(function(e){e.HTTP=`http`,e.HTTPS=`https`})(Ib||={});var Lb;(function(e){e.MD5=`md5`,e.CRC32=`crc32`,e.CRC32C=`crc32c`,e.SHA1=`sha1`,e.SHA256=`sha256`})(Lb||={});var Die=`__smithy_context`,Rb=class e{method;protocol;hostname;port;path;query;headers;username;password;fragment;body;constructor(e){this.method=e.method||`GET`,this.hostname=e.hostname||`localhost`,this.port=e.port,this.query=e.query||{},this.headers=e.headers||{},this.body=e.body,this.protocol=e.protocol?e.protocol.slice(-1)===`:`?e.protocol:`${e.protocol}:`:`https:`,this.path=e.path?e.path.charAt(0)===`/`?e.path:`/${e.path}`:`/`,this.username=e.username,this.password=e.password,this.fragment=e.fragment}static clone(t){let n=new e({...t,headers:{...t.headers}});return n.query&&=Oie(n.query),n}static isInstance(e){if(!e)return!1;let t=e;return`method`in t&&`protocol`in t&&`hostname`in t&&`path`in t&&typeof t.query==`object`&&typeof t.headers==`object`}clone(){return e.clone(this)}};function Oie(e){return Object.keys(e).reduce((t,n)=>{let r=e[n];return{...t,[n]:Array.isArray(r)?[...r]:r}},{})}var zb=class{statusCode;reason;headers;body;constructor(e){this.statusCode=e.statusCode,this.reason=e.reason,this.headers=e.headers||{},this.body=e.body}static isInstance(e){if(!e)return!1;let t=e;return typeof t.statusCode==`number`&&typeof t.headers==`object`}},Bb={},Vb={};for(let e=0;e<256;e++){let t=e.toString(16).toLowerCase();t.length===1&&(t=`0${t}`),Bb[e]=t,Vb[t]=e}function Hb(e){if(e.length%2!=0)throw Error(`Hex encoded strings must have an even number length`);let t=new Uint8Array(e.length/2);for(let n=0;nnew TextEncoder().encode(e),Gb=e=>typeof e==`string`?Wb(e):ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength/Uint8Array.BYTES_PER_ELEMENT):new Uint8Array(e),Kb=e=>{if(typeof e==`string`)return e;if(typeof e!=`object`||typeof e.byteOffset!=`number`||typeof e.byteLength!=`number`)throw Error(`@smithy/util-utf8: toUtf8 encoder function only accepts string | Uint8Array.`);return new TextDecoder(`utf-8`).decode(e)},kie=`X-Amz-Algorithm`,Aie=`X-Amz-Credential`,qb=`X-Amz-Date`,jie=`X-Amz-SignedHeaders`,Mie=`X-Amz-Expires`,Jb=`X-Amz-Signature`,Yb=`X-Amz-Security-Token`,Xb=`authorization`,Zb=qb.toLowerCase(),Nie=[Xb,Zb,`date`];Jb.toLowerCase();var Pie=`x-amz-content-sha256`,Fie=Yb.toLowerCase(),Iie={authorization:!0,"cache-control":!0,connection:!0,expect:!0,from:!0,"keep-alive":!0,"max-forwards":!0,pragma:!0,referer:!0,te:!0,trailer:!0,"transfer-encoding":!0,upgrade:!0,"user-agent":!0,"x-amzn-trace-id":!0},Lie=/^proxy-/,Rie=/^sec-/,Qb=`AWS4-HMAC-SHA256`,zie=`AWS4-HMAC-SHA256-PAYLOAD`,Bie=`UNSIGNED-PAYLOAD`,$b=`aws4_request`,ex={},tx=[],nx=(e,t,n)=>`${e}/${t}/${n}/${$b}`,Vie=async(e,t,n,r,i)=>{let a=`${n}:${r}:${i}:${Ub(await rx(e,t.secretAccessKey,t.accessKeyId))}:${t.sessionToken}`;if(a in ex)return ex[a];for(tx.push(a);tx.length>50;)delete ex[tx.shift()];let o=`AWS4${t.secretAccessKey}`;for(let t of[n,r,i,$b])o=await rx(e,o,t);return ex[a]=o},rx=(e,t,n)=>{let r=new e(t);return r.update(Gb(n)),r.digest()},ix=({headers:e},t,n)=>{let r={};for(let i of Object.keys(e).sort()){if(e[i]==null)continue;let a=i.toLowerCase();(a in Iie||t?.has(a)||Lie.test(a)||Rie.test(a))&&(!n||n&&!n.has(a))||(r[a]=e[i].trim().replace(/\s+/g,` `))}return r},ax=e=>typeof ArrayBuffer==`function`&&e instanceof ArrayBuffer||Object.prototype.toString.call(e)===`[object ArrayBuffer]`,ox=async({headers:e,body:t},n)=>{for(let t of Object.keys(e))if(t.toLowerCase()===`x-amz-content-sha256`)return e[t];if(t==null)return`e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`;if(typeof t==`string`||ArrayBuffer.isView(t)||ax(t)){let e=new n;return e.update(Gb(t)),Ub(await e.digest())}return Bie},Hie=class{format(e){let t=[];for(let n of Object.keys(e)){let r=Wb(n);t.push(Uint8Array.from([r.byteLength]),r,this.formatHeaderValue(e[n]))}let n=new Uint8Array(t.reduce((e,t)=>e+t.byteLength,0)),r=0;for(let e of t)n.set(e,r),r+=e.byteLength;return n}formatHeaderValue(e){switch(e.type){case`boolean`:return Uint8Array.from([+!e.value]);case`byte`:return Uint8Array.from([2,e.value]);case`short`:let t=new DataView(new ArrayBuffer(3));return t.setUint8(0,3),t.setInt16(1,e.value,!1),new Uint8Array(t.buffer);case`integer`:let n=new DataView(new ArrayBuffer(5));return n.setUint8(0,4),n.setInt32(1,e.value,!1),new Uint8Array(n.buffer);case`long`:let r=new Uint8Array(9);return r[0]=5,r.set(e.value.bytes,1),r;case`binary`:let i=new DataView(new ArrayBuffer(3+e.value.byteLength));i.setUint8(0,6),i.setUint16(1,e.value.byteLength,!1);let a=new Uint8Array(i.buffer);return a.set(e.value,3),a;case`string`:let o=Wb(e.value),s=new DataView(new ArrayBuffer(3+o.byteLength));s.setUint8(0,7),s.setUint16(1,o.byteLength,!1);let c=new Uint8Array(s.buffer);return c.set(o,3),c;case`timestamp`:let l=new Uint8Array(9);return l[0]=8,l.set(Gie.fromNumber(e.value.valueOf()).bytes,1),l;case`uuid`:if(!Wie.test(e.value))throw Error(`Invalid UUID received: ${e.value}`);let u=new Uint8Array(17);return u[0]=9,u.set(Hb(e.value.replace(/\-/g,``)),1),u}}},Uie;(function(e){e[e.boolTrue=0]=`boolTrue`,e[e.boolFalse=1]=`boolFalse`,e[e.byte=2]=`byte`,e[e.short=3]=`short`,e[e.integer=4]=`integer`,e[e.long=5]=`long`,e[e.byteArray=6]=`byteArray`,e[e.string=7]=`string`,e[e.timestamp=8]=`timestamp`,e[e.uuid=9]=`uuid`})(Uie||={});var Wie=/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/,Gie=class e{bytes;constructor(e){if(this.bytes=e,e.byteLength!==8)throw Error(`Int64 buffers must be exactly 8 bytes`)}static fromNumber(t){if(t>0x8000000000000000||t<-0x8000000000000000)throw Error(`${t} is too large (or, if negative, too small) to represent as an Int64`);let n=new Uint8Array(8);for(let e=7,r=Math.abs(Math.round(t));e>-1&&r>0;e--,r/=256)n[e]=r;return t<0&&sx(n),new e(n)}valueOf(){let e=this.bytes.slice(0),t=e[0]&128;return t&&sx(e),parseInt(Ub(e),16)*(t?-1:1)}toString(){return String(this.valueOf())}};function sx(e){for(let t=0;t<8;t++)e[t]^=255;for(let t=7;t>-1&&(e[t]++,e[t]===0);t--);}var Kie=(e,t)=>{e=e.toLowerCase();for(let n of Object.keys(t))if(e===n.toLowerCase())return!0;return!1},qie=(e,t={})=>{let{headers:n,query:r={}}=Rb.clone(e);for(let e of Object.keys(n)){let i=e.toLowerCase();(i.slice(0,6)===`x-amz-`&&!t.unhoistableHeaders?.has(i)||t.hoistableHeaders?.has(i))&&(r[e]=n[e],delete n[e])}return{...e,headers:n,query:r}},cx=e=>{e=Rb.clone(e);for(let t of Object.keys(e.headers))Nie.indexOf(t.toLowerCase())>-1&&delete e.headers[t];return e},lx=e=>e.__smithy_context||={},ux=e=>{if(typeof e==`function`)return e;let t=Promise.resolve(e);return()=>t},dx=e=>encodeURIComponent(e).replace(/[!'()*]/g,Jie),Jie=e=>`%${e.charCodeAt(0).toString(16).toUpperCase()}`,Yie=({query:e={}})=>{let t=[],n={};for(let r of Object.keys(e)){if(r.toLowerCase()===`x-amz-signature`)continue;let i=dx(r);t.push(i);let a=e[r];typeof a==`string`?n[i]=`${i}=${dx(a)}`:Array.isArray(a)&&(n[i]=a.slice(0).reduce((e,t)=>e.concat([`${i}=${dx(t)}`]),[]).sort().join(`&`))}return t.sort().map(e=>n[e]).filter(e=>e).join(`&`)},Xie=e=>Zie(e).toISOString().replace(/\.\d{3}Z$/,`Z`),Zie=e=>typeof e==`number`?new Date(e*1e3):typeof e==`string`?Number(e)?new Date(Number(e)*1e3):new Date(e):e,Qie=class{service;regionProvider;credentialProvider;sha256;uriEscapePath;applyChecksum;constructor({applyChecksum:e,credentials:t,region:n,service:r,sha256:i,uriEscapePath:a=!0}){this.service=r,this.sha256=i,this.uriEscapePath=a,this.applyChecksum=typeof e==`boolean`?e:!0,this.regionProvider=ux(n),this.credentialProvider=ux(t)}createCanonicalRequest(e,t,n){let r=Object.keys(t).sort();return`${e.method} ${this.getCanonicalPath(e)} -${zS(e)} +${Yie(e)} ${r.map(e=>`${e}:${t[e]}`).join(` `)} ${r.join(`;`)} -${n}`}async createStringToSign(e,t,n,r){let i=new this.sha256;return i.update(Qx(n)),`${r} +${n}`}async createStringToSign(e,t,n,r){let i=new this.sha256;return i.update(Gb(n)),`${r} ${e} ${t} -${Xx(await i.digest())}`}getCanonicalPath({path:e}){if(this.uriEscapePath){let t=[];for(let n of e.split(`/`))n?.length!==0&&n!==`.`&&(n===`..`?t.pop():t.push(n));return LS(`${e?.startsWith(`/`)?`/`:``}${t.join(`/`)}${t.length>0&&e?.endsWith(`/`)?`/`:``}`).replace(/%2F/g,`/`)}return e}validateResolvedCredentials(e){if(typeof e!=`object`||typeof e.accessKeyId!=`string`||typeof e.secretAccessKey!=`string`)throw Error(`Resolved credential object is not valid`)}formatDate(e){let t=BS(e).replace(/[\-:]/g,``);return{longDate:t,shortDate:t.slice(0,8)}}getCanonicalHeaderList(e){return Object.keys(e).sort().join(`;`)}},US=class extends HS{headerFormatter=new DS;constructor({applyChecksum:e,credentials:t,region:n,service:r,sha256:i,uriEscapePath:a=!0}){super({applyChecksum:e,credentials:t,region:n,service:r,sha256:i,uriEscapePath:a})}async presign(e,t={}){let{signingDate:n=new Date,expiresIn:r=3600,unsignableHeaders:i,unhoistableHeaders:a,signableHeaders:o,hoistableHeaders:s,signingRegion:c,signingService:l}=t,u=await this.credentialProvider();this.validateResolvedCredentials(u);let d=c??await this.regionProvider(),{longDate:f,shortDate:p}=this.formatDate(n);if(r>604800)return Promise.reject(`Signature version 4 presigned URLs must have an expiration date less than one week in the future`);let m=xS(p,d,l??this.service),h=NS(PS(e),{unhoistableHeaders:a,hoistableHeaders:s});u.sessionToken&&(h.query[oS]=u.sessionToken),h.query[eS]=hS,h.query[tS]=`${u.accessKeyId}/${m}`,h.query[nS]=f,h.query[iS]=r.toString(10);let g=wS(h,i,o);return h.query[rS]=this.getCanonicalHeaderList(g),h.query[aS]=await this.getSignature(f,m,this.getSigningKey(u,d,p,l),this.createCanonicalRequest(h,g,await ES(e,this.sha256))),h}async sign(e,t){return typeof e==`string`?this.signString(e,t):e.headers&&e.payload?this.signEvent(e,t):e.message?this.signMessage(e,t):this.signRequest(e,t)}async signEvent({headers:e,payload:t},{signingDate:n=new Date,priorSignature:r,signingRegion:i,signingService:a,eventStreamCredentials:o}){let s=i??await this.regionProvider(),{shortDate:c,longDate:l}=this.formatDate(n),u=xS(c,s,a??this.service),d=await ES({headers:{},body:t},this.sha256),f=new this.sha256;f.update(e);let p=[gS,l,u,r,Xx(await f.digest()),d].join(` -`);return this.signString(p,{signingDate:n,signingRegion:s,signingService:a,eventStreamCredentials:o})}async signMessage(e,{signingDate:t=new Date,signingRegion:n,signingService:r,eventStreamCredentials:i}){return this.signEvent({headers:this.headerFormatter.format(e.message.headers),payload:e.message.body},{signingDate:t,signingRegion:n,signingService:r,priorSignature:e.priorSignature,eventStreamCredentials:i}).then(t=>({message:e.message,signature:t}))}async signString(e,{signingDate:t=new Date,signingRegion:n,signingService:r,eventStreamCredentials:i}={}){let a=i??await this.credentialProvider();this.validateResolvedCredentials(a);let o=n??await this.regionProvider(),{shortDate:s}=this.formatDate(t),c=new this.sha256(await this.getSigningKey(a,o,s,r));return c.update(Qx(e)),Xx(await c.digest())}async signRequest(e,{signingDate:t=new Date,signableHeaders:n,unsignableHeaders:r,signingRegion:i,signingService:a}={}){let o=await this.credentialProvider();this.validateResolvedCredentials(o);let s=i??await this.regionProvider(),c=PS(e),{longDate:l,shortDate:u}=this.formatDate(t),d=xS(u,s,a??this.service);c.headers[cS]=l,o.sessionToken&&(c.headers[dS]=o.sessionToken);let f=await ES(c,this.sha256);!MS(`x-amz-content-sha256`,c.headers)&&this.applyChecksum&&(c.headers[uS]=f);let p=wS(c,r,n),m=await this.getSignature(l,d,this.getSigningKey(o,s,u,a),this.createCanonicalRequest(c,p,f));return c.headers[sS]=`${hS} Credential=${o.accessKeyId}/${d}, SignedHeaders=${this.getCanonicalHeaderList(p)}, Signature=${m}`,c}async getSignature(e,t,n,r){let i=await this.createStringToSign(e,t,r,hS),a=new this.sha256(await n);return a.update(Qx(i)),Xx(await a.digest())}getSigningKey(e,t,n,r){return SS(this.sha256,e,n,t,r||this.service)}},WS={SignatureV4a:null},GS=`ap-southeast-2`,KS=9999;async function qS({action:e,credentials:t,service:n=`spinifex`}){let r=window.location.protocol.replace(`:`,``),i=`Action=${e}`,a=new Wx({method:`POST`,protocol:r,hostname:`localhost`,port:KS,path:`/`,headers:{host:`localhost:${KS}`,"content-type":`application/x-www-form-urlencoded`},body:i}),o=await new US({credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey},region:GS,service:n,sha256:Rx}).sign(a),s={};for(let[e,t]of Object.entries(o.headers))typeof t==`string`&&(s[e]=t);let c=`${window.location.protocol}//${window.location.host}/proxy/awsgw/`,l=await fetch(c,{method:`POST`,headers:s,body:i});if(!l.ok){let t=await l.text().catch(()=>``);throw Error(`${e} failed: ${l.status}${t?` - ${t}`:``}`)}return await l.json()}var JS=`000000000001`,YS=(0,P.createContext)(void 0);function XS({children:e}){let[t,n]=(0,P.useState)({isAdmin:!1,accountId:null,userName:null,version:null,license:null,loading:!0});return(0,P.useEffect)(()=>{async function e(){let e=ux();if(!e){n(e=>({...e,loading:!1}));return}try{let t=await qS({action:`GetCallerIdentity`,credentials:e}),r=t.account_id===JS,i=null;if(r)try{i=await qS({action:`GetVersion`,credentials:e})}catch{}n({isAdmin:r,accountId:t.account_id,userName:t.user_name,version:i,license:i?.license??null,loading:!1})}catch{n(e=>({...e,loading:!1}))}}e()},[]),(0,F.jsx)(YS,{value:t,children:e})}function ZS(){let e=(0,P.useContext)(YS);if(e===void 0)throw Error(`useAdmin must be used within an AdminProvider`);return e}function QS(){let e=(0,fa.c)(8),{theme:t,setTheme:n}=ga(),r;e[0]!==n||e[1]!==t?(r=()=>{n(t===`light`?`dark`:t===`dark`?`light`:`dark`)},e[0]=n,e[1]=t,e[2]=r):r=e[2];let i=r,a,o,s;e[3]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,F.jsx)(zo,{className:`size-[1.2rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90`}),o=(0,F.jsx)(No,{className:`absolute size-[1.2rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0`}),s=(0,F.jsx)(`span`,{className:`sr-only`,children:`Toggle theme`}),e[3]=a,e[4]=o,e[5]=s):(a=e[3],o=e[4],s=e[5]);let c;return e[6]===i?c=e[7]:(c=(0,F.jsxs)(pl,{className:`rounded-full`,onClick:i,size:`icon-sm`,variant:`ghost`,children:[a,o,s]}),e[6]=i,e[7]=c),c}function $S(){let e=(0,fa.c)(7),{isAdmin:t,license:n}=ZS(),r=t&&n===`open-source`,i,a;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(i=el(`z-50 flex h-10 shrink-0 items-center gap-2 border-b border-sidebar-border bg-sidebar px-4 text-sidebar-foreground`,`sticky top-0`),a=(0,F.jsx)(Gg,{className:`-ml-1`}),e[0]=i,e[1]=a):(i=e[0],a=e[1]);let o;e[2]===r?o=e[3]:(o=r&&(0,F.jsx)(`a`,{href:`https://mulgadc.com/purchase`,target:`_blank`,rel:`noopener noreferrer`,className:el(fl({variant:`outline`,size:`sm`})),children:`Upgrade`}),e[2]=r,e[3]=o);let s;e[4]===Symbol.for(`react.memo_cache_sentinel`)?(s=(0,F.jsx)(QS,{}),e[4]=s):s=e[4];let c;return e[5]===o?c=e[6]:(c=(0,F.jsxs)(`header`,{className:i,children:[a,(0,F.jsxs)(`div`,{className:`flex w-full items-center justify-end gap-2`,children:[o,s]})]}),e[5]=o,e[6]=c),c}function eC(){let e=(0,fa.c)(3),t,n;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(t=(0,F.jsx)(`h1`,{className:`text-4xl font-bold`,children:`404`}),n=(0,F.jsx)(`p`,{className:`text-muted-foreground`,children:`Page not found`}),e[0]=t,e[1]=n):(t=e[0],n=e[1]);let r;return e[2]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,F.jsxs)(`div`,{className:`flex flex-1 flex-col items-center justify-center gap-4`,children:[t,n,(0,F.jsx)(Oi,{to:`/`,children:(0,F.jsx)(pl,{variant:`outline`,children:`Go back home`})})]}),e[2]=r):r=e[2],r}function tC(e){return e}var nC=e=>t=>async n=>{if(!Wx.isInstance(n.request))return t(n);let{request:r}=n,{handlerProtocol:i=``}=e.requestHandler.metadata||{};if(i.indexOf(`h2`)>=0&&!r.headers[`:authority`])delete r.headers.host,r.headers[`:authority`]=r.hostname+(r.port?`:`+r.port:``);else if(!r.headers.host){let e=r.hostname;r.port!=null&&(e+=`:${r.port}`),r.headers.host=e}return t(n)},rC={name:`hostHeaderMiddleware`,step:`build`,priority:`low`,tags:[`HOST`],override:!0},iC=e=>({applyToStack:t=>{t.add(nC(e),rC)}}),aC=()=>(e,t)=>async n=>{try{let r=await e(n),{clientName:i,commandName:a,logger:o,dynamoDbDocumentClientOptions:s={}}=t,{overrideInputFilterSensitiveLog:c,overrideOutputFilterSensitiveLog:l}=s,u=c??t.inputFilterSensitiveLog,d=l??t.outputFilterSensitiveLog,{$metadata:f,...p}=r.output;return o?.info?.({clientName:i,commandName:a,input:u(n.input),output:d(p),metadata:f}),r}catch(e){let{clientName:r,commandName:i,logger:a,dynamoDbDocumentClientOptions:o={}}=t,{overrideInputFilterSensitiveLog:s}=o,c=s??t.inputFilterSensitiveLog;throw a?.error?.({clientName:r,commandName:i,input:c(n.input),error:e,metadata:e.$metadata}),e}},oC={name:`loggerMiddleware`,tags:[`LOGGER`],step:`initialize`,override:!0},sC=e=>({applyToStack:e=>{e.add(aC(),oC)}}),cC={step:`build`,tags:[`RECURSION_DETECTION`],name:`recursionDetectionMiddleware`,override:!0,priority:`low`},lC=()=>e=>async t=>e(t),uC=e=>({applyToStack:e=>{e.add(lC(),cC)}}),dC=(e,t)=>{if(!t||t.length===0)return e;let n=[];for(let r of t)for(let t of e)t.schemeId.split(`#`)[1]===r&&n.push(t);for(let t of e)n.find(({schemeId:e})=>e===t.schemeId)||n.push(t);return n};function fC(e){let t=new Map;for(let n of e)t.set(n.schemeId,n);return t}var pC=(e,t)=>(n,r)=>async i=>{let a=dC(e.httpAuthSchemeProvider(await t.httpAuthSchemeParametersProvider(e,r,i.input)),e.authSchemePreference?await e.authSchemePreference():[]),o=fC(e.httpAuthSchemes),s=FS(r),c=[];for(let n of a){let i=o.get(n.schemeId);if(!i){c.push(`HttpAuthScheme \`${n.schemeId}\` was not enabled for this service.`);continue}let a=i.identityProvider(await t.identityProviderConfigProvider(e));if(!a){c.push(`HttpAuthScheme \`${n.schemeId}\` did not have an IdentityProvider configured.`);continue}let{identityProperties:l={},signingProperties:u={}}=n.propertiesExtractor?.(e,r)||{};n.identityProperties=Object.assign(n.identityProperties||{},l),n.signingProperties=Object.assign(n.signingProperties||{},u),s.selectedHttpAuthScheme={httpAuthOption:n,identity:await a(n.identityProperties),signer:i.signer};break}if(!s.selectedHttpAuthScheme)throw Error(c.join(` -`));return n(i)},mC={step:`serialize`,tags:[`HTTP_AUTH_SCHEME`],name:`httpAuthSchemeMiddleware`,override:!0,relation:`before`,toMiddleware:`endpointV2Middleware`},hC=(e,{httpAuthSchemeParametersProvider:t,identityProviderConfigProvider:n})=>({applyToStack:r=>{r.addRelativeTo(pC(e,{httpAuthSchemeParametersProvider:t,identityProviderConfigProvider:n}),mC)}}),gC=e=>e=>{throw e},_C=(e,t)=>{},vC=e=>(e,t)=>async n=>{if(!Wx.isInstance(n.request))return e(n);let r=FS(t).selectedHttpAuthScheme;if(!r)throw Error(`No HttpAuthScheme was selected: unable to sign request`);let{httpAuthOption:{signingProperties:i={}},identity:a,signer:o}=r,s=await e({...n,request:await o.sign(n.request,a,i)}).catch((o.errorHandler||gC)(i));return(o.successHandler||_C)(s.response,i),s},yC={step:`finalizeRequest`,tags:[`HTTP_SIGNING`],name:`httpSigningMiddleware`,aliases:[`apiKeyMiddleware`,`tokenMiddleware`,`awsAuthMiddleware`],override:!0,relation:`after`,toMiddleware:`retryMiddleware`},bC=e=>({applyToStack:t=>{t.addRelativeTo(vC(e),yC)}}),xC=e=>{if(typeof e==`function`)return e;let t=Promise.resolve(e);return()=>t},SC=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`,CC=Object.entries(SC).reduce((e,[t,n])=>(e[n]=Number(t),e),{}),wC=SC.split(``),TC=e=>{let t=e.length/4*3;e.slice(-2)===`==`?t-=2:e.slice(-1)===`=`&&t--;let n=new ArrayBuffer(t),r=new DataView(n);for(let t=0;t>=6;let a=t/4*3;n>>=i%8;let o=Math.floor(i/8);for(let e=0;e>t)}}return new Uint8Array(n)};function EC(e){let t;t=typeof e==`string`?Zx(e):e;let n=typeof t==`object`&&typeof t.length==`number`,r=typeof t==`object`&&typeof t.byteOffset==`number`&&typeof t.byteLength==`number`;if(!n&&!r)throw Error(`@smithy/util-base64: toBase64 encoder function only accepts string | Uint8Array.`);let i=``;for(let e=0;e>t]}i+=`==`.slice(0,4-a)}return i}var DC=class e extends Uint8Array{static fromString(t,n=`utf-8`){if(typeof t==`string`)return n===`base64`?e.mutate(TC(t)):e.mutate(Zx(t));throw Error(`Unsupported conversion from ${typeof t} to Uint8ArrayBlobAdapter.`)}static mutate(t){return Object.setPrototypeOf(t,e.prototype),t}transformToString(e=`utf-8`){return e===`base64`?EC(this):$x(this)}},OC=e=>typeof ReadableStream==`function`&&(e?.constructor?.name===ReadableStream.name||e instanceof ReadableStream),kC=(e,t)=>{let{base64Encoder:n,bodyLengthChecker:r,checksumAlgorithmFn:i,checksumLocationName:a,streamHasher:o}=t,s=n!==void 0&&r!==void 0&&i!==void 0&&a!==void 0&&o!==void 0,c=s?o(i,e):void 0,l=e.getReader();return new ReadableStream({async pull(e){let{value:t,done:i}=await l.read();if(i){if(e.enqueue(`0\r -`),s){let t=n(await c);e.enqueue(`${a}:${t}\r\n`),e.enqueue(`\r -`)}e.close()}else e.enqueue(`${(r(t)||0).toString(16)}\r\n${t}\r\n`)}})};function AC(e){let t=[];for(let n of Object.keys(e).sort()){let r=e[n];if(n=LS(n),Array.isArray(r))for(let e=0,i=r.length;e{e&&setTimeout(()=>{let t=Error(`Request did not complete within ${e} ms`);t.name=`TimeoutError`,n(t)},e)})}var NC={supported:void 0},PC=class e{config;configProvider;static create(t){return typeof t?.handle==`function`?t:new e(t)}constructor(e){typeof e==`function`?this.configProvider=e().then(e=>e||{}):(this.config=e??{},this.configProvider=Promise.resolve(this.config)),NC.supported===void 0&&(NC.supported=typeof Request<`u`&&`keepalive`in jC(`https://[::1]`))}destroy(){}async handle(e,{abortSignal:t,requestTimeout:n}={}){this.config||=await this.configProvider;let r=n??this.config.requestTimeout,i=this.config.keepAlive===!0,a=this.config.credentials;if(t?.aborted){let e=FC(t);return Promise.reject(e)}let o=e.path,s=AC(e.query||{});s&&(o+=`?${s}`),e.fragment&&(o+=`#${e.fragment}`);let c=``;(e.username!=null||e.password!=null)&&(c=`${e.username??``}:${e.password??``}@`);let{port:l,method:u}=e,d=`${e.protocol}//${c}${e.hostname}${l?`:${l}`:``}${o}`,f=u===`GET`||u===`HEAD`?void 0:e.body,p={body:f,headers:new Headers(e.headers),method:u,credentials:a};this.config?.cache&&(p.cache=this.config.cache),f&&(p.duplex=`half`),typeof AbortController<`u`&&(p.signal=t),NC.supported&&(p.keepalive=i),typeof this.config.requestInit==`function`&&Object.assign(p,this.config.requestInit(e));let m=()=>{},h=jC(d,p),g=[fetch(h).then(e=>{let t=e.headers,n={};for(let e of t.entries())n[e[0]]=e[1];return e.body==null?e.blob().then(t=>({response:new Kx({headers:n,reason:e.statusText,statusCode:e.status,body:t})})):{response:new Kx({headers:n,reason:e.statusText,statusCode:e.status,body:e.body})}}),MC(r)];return t&&g.push(new Promise((e,n)=>{let r=()=>{n(FC(t))};if(typeof t.addEventListener==`function`){let e=t;e.addEventListener(`abort`,r,{once:!0}),m=()=>e.removeEventListener(`abort`,r)}else t.onabort=r})),Promise.race(g).finally(m)}updateHttpClientConfig(e,t){this.config=void 0,this.configProvider=this.configProvider.then(n=>(n[e]=t,n))}httpHandlerConfigs(){return this.config??{}}};function FC(e){let t=e&&typeof e==`object`&&`reason`in e?e.reason:void 0;if(t){if(t instanceof Error){let e=Error(`Request aborted`);return e.name=`AbortError`,e.cause=t,e}let e=Error(String(t));return e.name=`AbortError`,e}let n=Error(`Request aborted`);return n.name=`AbortError`,n}var IC=async e=>typeof Blob==`function`&&e instanceof Blob||e.constructor?.name===`Blob`?Blob.prototype.arrayBuffer===void 0?LC(e):new Uint8Array(await e.arrayBuffer()):RC(e);async function LC(e){let t=TC(await zC(e));return new Uint8Array(t)}async function RC(e){let t=[],n=e.getReader(),r=!1,i=0;for(;!r;){let{done:e,value:a}=await n.read();a&&(t.push(a),i+=a.length),r=e}let a=new Uint8Array(i),o=0;for(let e of t)a.set(e,o),o+=e.length;return a}function zC(e){return new Promise((t,n)=>{let r=new FileReader;r.onloadend=()=>{if(r.readyState!==2)return n(Error(`Reader aborted too early`));let e=r.result??``,i=e.indexOf(`,`),a=i>-1?i+1:e.length;t(e.substring(a))},r.onabort=()=>n(Error(`Read aborted`)),r.onerror=()=>n(r.error),r.readAsDataURL(e)})}var BC=`The stream has already been transformed.`,VC=e=>{if(!HC(e)&&!OC(e)){let t=e?.__proto__?.constructor?.name||e;throw Error(`Unexpected stream implementation, expect Blob or ReadableStream, got ${t}`)}let t=!1,n=async()=>{if(t)throw Error(BC);return t=!0,await IC(e)},r=e=>{if(typeof e.stream!=`function`)throw Error(`Cannot transform payload Blob to web stream. Please make sure the Blob.stream() is polyfilled. -If you are using React Native, this API is not yet supported, see: https://react-native.canny.io/feature-requests/p/fetch-streaming-body`);return e.stream()};return Object.assign(e,{transformToByteArray:n,transformToString:async e=>{let t=await n();if(e===`base64`)return EC(t);if(e===`hex`)return Xx(t);if(e===void 0||e===`utf8`||e===`utf-8`)return $x(t);if(typeof TextDecoder==`function`)return new TextDecoder(e).decode(t);throw Error(`TextDecoder is not available, please make sure polyfill is provided.`)},transformToWebStream:()=>{if(t)throw Error(BC);if(t=!0,HC(e))return r(e);if(OC(e))return e;throw Error(`Cannot transform payload to web stream, got ${e}`)}})},HC=e=>typeof Blob==`function`&&e instanceof Blob,UC=async(e=new Uint8Array,t)=>{if(e instanceof Uint8Array)return DC.mutate(e);if(!e)return DC.mutate(new Uint8Array);let n=t.streamCollector(e);return DC.mutate(await n)};function WC(e){return encodeURIComponent(e).replace(/[!'()*]/g,function(e){return`%`+e.charCodeAt(0).toString(16).toUpperCase()})}var GC=e=>typeof e==`function`?e():e,KC=(e,t,n,r,i)=>({name:t,namespace:e,traits:n,input:r,output:i}),qC=e=>(t,n)=>async r=>{let{response:i}=await t(r),{operationSchema:a}=FS(n),[,o,s,c,l,u]=a??[];try{return{response:i,output:await e.protocol.deserializeResponse(KC(o,s,c,l,u),{...e,...n},i)}}catch(e){if(Object.defineProperty(e,`$response`,{value:i,enumerable:!1,writable:!1,configurable:!1}),!(`$metadata`in e)){let t=`Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.`;try{e.message+=` - `+t}catch{!n.logger||n.logger?.constructor?.name===`NoOpLogger`?console.warn(t):n.logger?.warn?.(t)}e.$responseBodyText!==void 0&&e.$response&&(e.$response.body=e.$responseBodyText);try{if(Kx.isInstance(i)){let{headers:t={}}=i,n=Object.entries(t);e.$metadata={httpStatusCode:i.statusCode,requestId:JC(/^x-[\w-]+-request-?id$/,n),extendedRequestId:JC(/^x-[\w-]+-id-2$/,n),cfId:JC(/^x-[\w-]+-cf-id$/,n)}}}catch{}}throw e}},JC=(e,t)=>(t.find(([t])=>t.match(e))||[void 0,void 0])[1];function YC(e){let t={};if(e=e.replace(/^\?/,``),e)for(let n of e.split(`&`)){let[e,r=null]=n.split(`=`);e=decodeURIComponent(e),r&&=decodeURIComponent(r),e in t?Array.isArray(t[e])?t[e].push(r):t[e]=[t[e],r]:t[e]=r}return t}var XC=e=>{if(typeof e==`string`)return XC(new URL(e));let{hostname:t,pathname:n,port:r,protocol:i,search:a}=e,o;return a&&(o=YC(a)),{hostname:t,port:r?parseInt(r):void 0,protocol:i,path:n,query:o}},ZC=e=>{if(typeof e==`object`){if(`url`in e){let t=XC(e.url);if(e.headers){t.headers={};for(let n in e.headers)t.headers[n.toLowerCase()]=e.headers[n].join(`, `)}return t}return e}return XC(e)},QC=e=>(t,n)=>async r=>{let{operationSchema:i}=FS(n),[,a,o,s,c,l]=i??[],u=n.endpointV2?async()=>ZC(n.endpointV2):e.endpoint,d=await e.protocol.serializeRequest(KC(a,o,s,c,l),r.input,{...e,...n,endpoint:u});return t({...r,request:d})},$C={name:`deserializerMiddleware`,step:`deserialize`,tags:[`DESERIALIZER`],override:!0},ew={name:`serializerMiddleware`,step:`serialize`,tags:[`SERIALIZER`],override:!0};function tw(e){return{applyToStack:t=>{t.add(QC(e),ew),t.add(qC(e),$C),e.protocol.setSerdeContext(e)}}}var nw=[];function rw(e){if(typeof e==`object`)return e;if(e|=0,nw[e])return nw[e];let t={},n=0;for(let r of[`httpLabel`,`idempotent`,`idempotencyToken`,`sensitive`,`httpPayload`,`httpResponseCode`,`httpQueryParams`])(e>>n++&1)==1&&(t[r]=1);return nw[e]=t}var iw={it:Symbol.for(`@smithy/nor-struct-it`),ns:Symbol.for(`@smithy/ns`)},aw=[],ow={},sw=class e{ref;memberName;static symbol=Symbol.for(`@smithy/nor`);symbol=e.symbol;name;schema;_isMemberSchema;traits;memberTraits;normalizedTraits;constructor(t,n){this.ref=t,this.memberName=n;let r=[],i=t,a=t;for(this._isMemberSchema=!1;lw(i);)r.push(i[1]),i=i[0],a=GC(i),this._isMemberSchema=!0;if(r.length>0){this.memberTraits={};for(let e=r.length-1;e>=0;--e){let t=r[e];Object.assign(this.memberTraits,rw(t))}}else this.memberTraits=0;if(a instanceof e){let e=this.memberTraits;Object.assign(this,a),this.memberTraits=Object.assign({},e,a.getMemberTraits(),this.getMemberTraits()),this.normalizedTraits=void 0,this.memberName=n??a.memberName;return}if(this.schema=GC(a),uw(this.schema)?(this.name=`${this.schema[1]}#${this.schema[2]}`,this.traits=this.schema[3]):(this.name=this.memberName??String(a),this.traits=0),this._isMemberSchema&&!n)throw Error(`@smithy/core/schema - NormalizedSchema member init ${this.getName(!0)} missing member name.`)}static[Symbol.hasInstance](e){let t=this.prototype.isPrototypeOf(e);return!t&&typeof e==`object`&&e?e.symbol===this.symbol:t}static of(t){let n=typeof t==`function`||typeof t==`object`&&!!t;if(typeof t==`number`){if(aw[t])return aw[t]}else if(typeof t==`string`){if(ow[t])return ow[t]}else if(n&&t[iw.ns])return t[iw.ns];let r=GC(t);if(r instanceof e)return r;if(lw(r)){let[n,i]=r;if(n instanceof e)return Object.assign(n.getMergedTraits(),rw(i)),n;throw Error(`@smithy/core/schema - may not init unwrapped member schema=${JSON.stringify(t,null,2)}.`)}let i=new e(r);return n?t[iw.ns]=i:typeof r==`string`?ow[r]=i:typeof r==`number`?aw[r]=i:i}getSchema(){let e=this.schema;return Array.isArray(e)&&e[0]===0?e[4]:e}getName(e=!1){let{name:t}=this;return!e&&t&&t.includes(`#`)?t.split(`#`)[1]:t||void 0}getMemberName(){return this.memberName}isMemberSchema(){return this._isMemberSchema}isListSchema(){let e=this.getSchema();return typeof e==`number`?e>=64&&e<128:e[0]===1}isMapSchema(){let e=this.getSchema();return typeof e==`number`?e>=128&&e<=255:e[0]===2}isStructSchema(){let e=this.getSchema();if(typeof e!=`object`)return!1;let t=e[0];return t===3||t===-3||t===4}isUnionSchema(){let e=this.getSchema();return typeof e==`object`?e[0]===4:!1}isBlobSchema(){let e=this.getSchema();return e===21||e===42}isTimestampSchema(){let e=this.getSchema();return typeof e==`number`&&e>=4&&e<=7}isUnitSchema(){return this.getSchema()===`unit`}isDocumentSchema(){return this.getSchema()===15}isStringSchema(){return this.getSchema()===0}isBooleanSchema(){return this.getSchema()===2}isNumericSchema(){return this.getSchema()===1}isBigIntegerSchema(){return this.getSchema()===17}isBigDecimalSchema(){return this.getSchema()===19}isStreaming(){let{streaming:e}=this.getMergedTraits();return!!e||this.getSchema()===42}isIdempotencyToken(){return!!this.getMergedTraits().idempotencyToken}getMergedTraits(){return this.normalizedTraits??={...this.getOwnTraits(),...this.getMemberTraits()}}getMemberTraits(){return rw(this.memberTraits)}getOwnTraits(){return rw(this.traits)}getKeySchema(){let[e,t]=[this.isDocumentSchema(),this.isMapSchema()];if(!e&&!t)throw Error(`@smithy/core/schema - cannot get key for non-map: ${this.getName(!0)}`);let n=this.getSchema();return cw([e?15:n[4]??0,0],`key`)}getValueSchema(){let e=this.getSchema(),[t,n,r]=[this.isDocumentSchema(),this.isMapSchema(),this.isListSchema()],i=typeof e==`number`?63&e:e&&typeof e==`object`&&(n||r)?e[3+e[0]]:t?15:void 0;if(i!=null)return cw([i,0],n?`value`:`member`);throw Error(`@smithy/core/schema - ${this.getName(!0)} has no value member.`)}getMemberSchema(e){let t=this.getSchema();if(this.isStructSchema()&&t[4].includes(e)){let n=t[4].indexOf(e),r=t[5][n];return cw(lw(r)?r:[r,0],e)}if(this.isDocumentSchema())return cw([15,0],e);throw Error(`@smithy/core/schema - ${this.getName(!0)} has no member=${e}.`)}getMemberSchemas(){let e={};try{for(let[t,n]of this.structIterator())e[t]=n}catch{}return e}getEventStreamMember(){if(this.isStructSchema()){for(let[e,t]of this.structIterator())if(t.isStreaming()&&t.isStructSchema())return e}return``}*structIterator(){if(this.isUnitSchema())return;if(!this.isStructSchema())throw Error(`@smithy/core/schema - cannot iterate non-struct schema.`);let e=this.getSchema(),t=e[4].length,n=e[iw.it];if(n&&t===n.length){yield*n;return}n=Array(t);for(let r=0;rArray.isArray(e)&&e.length===2,uw=e=>Array.isArray(e)&&e.length>=5,dw=class e{namespace;schemas;exceptions;static registries=new Map;constructor(e,t=new Map,n=new Map){this.namespace=e,this.schemas=t,this.exceptions=n}static for(t){return e.registries.has(t)||e.registries.set(t,new e(t)),e.registries.get(t)}copyFrom(e){let{schemas:t,exceptions:n}=this;for(let[n,r]of e.schemas)t.has(n)||t.set(n,r);for(let[t,r]of e.exceptions)n.has(t)||n.set(t,r)}register(t,n){let r=this.normalizeShapeId(t);for(let t of[this,e.for(r.split(`#`)[0])])t.schemas.set(r,n)}getSchema(e){let t=this.normalizeShapeId(e);if(!this.schemas.has(t))throw Error(`@smithy/core/schema - schema not found for ${t}`);return this.schemas.get(t)}registerError(t,n){let r=t,i=r[1];for(let t of[this,e.for(i)])t.schemas.set(i+`#`+r[2],r),t.exceptions.set(r,n)}getErrorCtor(t){let n=t;return this.exceptions.has(n)?this.exceptions.get(n):e.for(n[1]).exceptions.get(n)}getBaseException(){for(let e of this.exceptions.keys())if(Array.isArray(e)){let[,t,n]=e,r=t+`#`+n;if(r.startsWith(`smithy.ts.sdk.synthetic.`)&&r.endsWith(`ServiceException`))return e}}find(e){for(let t of this.schemas.values())if(e(t))return t}clear(){this.schemas.clear(),this.exceptions.clear()}normalizeShapeId(e){return e.includes(`#`)?e:this.namespace+`#`+e}},fw=e=>{if(e!=null){if(typeof e==`string`){let t=parseFloat(e);if(!Number.isNaN(t))return String(t)!==String(e)&&Ew.warn(Tw(`Expected number but observed string: ${e}`)),t}if(typeof e==`number`)return e;throw TypeError(`Expected number, got ${typeof e}: ${e}`)}},pw=Math.ceil(2**127*(2-2**-23)),mw=e=>{let t=fw(e);if(t!==void 0&&!Number.isNaN(t)&&t!==1/0&&t!==-1/0&&Math.abs(t)>pw)throw TypeError(`Expected 32-bit float, got ${e}`);return t},hw=e=>{if(e!=null){if(Number.isInteger(e)&&!Number.isNaN(e))return e;throw TypeError(`Expected integer, got ${typeof e}: ${e}`)}},gw=e=>vw(e,16),_w=e=>vw(e,8),vw=(e,t)=>{let n=hw(e);if(n!==void 0&&yw(n,t)!==n)throw TypeError(`Expected ${t}-bit integer, got ${e}`);return n},yw=(e,t)=>{switch(t){case 32:return Int32Array.of(e)[0];case 16:return Int16Array.of(e)[0];case 8:return Int8Array.of(e)[0]}},bw=e=>mw(typeof e==`string`?Sw(e):e),xw=/(-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?)|(-?Infinity)|(NaN)/g,Sw=e=>{let t=e.match(xw);if(t===null||t[0].length!==e.length)throw TypeError(`Expected real number, got implicit NaN`);return parseFloat(e)},Cw=e=>gw(typeof e==`string`?Sw(e):e),ww=e=>_w(typeof e==`string`?Sw(e):e),Tw=e=>String(TypeError(e).stack||e).split(` +${Ub(await i.digest())}`}getCanonicalPath({path:e}){if(this.uriEscapePath){let t=[];for(let n of e.split(`/`))n?.length!==0&&n!==`.`&&(n===`..`?t.pop():t.push(n));return dx(`${e?.startsWith(`/`)?`/`:``}${t.join(`/`)}${t.length>0&&e?.endsWith(`/`)?`/`:``}`).replace(/%2F/g,`/`)}return e}validateResolvedCredentials(e){if(typeof e!=`object`||typeof e.accessKeyId!=`string`||typeof e.secretAccessKey!=`string`)throw Error(`Resolved credential object is not valid`)}formatDate(e){let t=Xie(e).replace(/[\-:]/g,``);return{longDate:t,shortDate:t.slice(0,8)}}getCanonicalHeaderList(e){return Object.keys(e).sort().join(`;`)}},fx=class extends Qie{headerFormatter=new Hie;constructor({applyChecksum:e,credentials:t,region:n,service:r,sha256:i,uriEscapePath:a=!0}){super({applyChecksum:e,credentials:t,region:n,service:r,sha256:i,uriEscapePath:a})}async presign(e,t={}){let{signingDate:n=new Date,expiresIn:r=3600,unsignableHeaders:i,unhoistableHeaders:a,signableHeaders:o,hoistableHeaders:s,signingRegion:c,signingService:l}=t,u=await this.credentialProvider();this.validateResolvedCredentials(u);let d=c??await this.regionProvider(),{longDate:f,shortDate:p}=this.formatDate(n);if(r>604800)return Promise.reject(`Signature version 4 presigned URLs must have an expiration date less than one week in the future`);let m=nx(p,d,l??this.service),h=qie(cx(e),{unhoistableHeaders:a,hoistableHeaders:s});u.sessionToken&&(h.query[Yb]=u.sessionToken),h.query[kie]=Qb,h.query[Aie]=`${u.accessKeyId}/${m}`,h.query[qb]=f,h.query[Mie]=r.toString(10);let g=ix(h,i,o);return h.query[jie]=this.getCanonicalHeaderList(g),h.query[Jb]=await this.getSignature(f,m,this.getSigningKey(u,d,p,l),this.createCanonicalRequest(h,g,await ox(e,this.sha256))),h}async sign(e,t){return typeof e==`string`?this.signString(e,t):e.headers&&e.payload?this.signEvent(e,t):e.message?this.signMessage(e,t):this.signRequest(e,t)}async signEvent({headers:e,payload:t},{signingDate:n=new Date,priorSignature:r,signingRegion:i,signingService:a,eventStreamCredentials:o}){let s=i??await this.regionProvider(),{shortDate:c,longDate:l}=this.formatDate(n),u=nx(c,s,a??this.service),d=await ox({headers:{},body:t},this.sha256),f=new this.sha256;f.update(e);let p=[zie,l,u,r,Ub(await f.digest()),d].join(` +`);return this.signString(p,{signingDate:n,signingRegion:s,signingService:a,eventStreamCredentials:o})}async signMessage(e,{signingDate:t=new Date,signingRegion:n,signingService:r,eventStreamCredentials:i}){return this.signEvent({headers:this.headerFormatter.format(e.message.headers),payload:e.message.body},{signingDate:t,signingRegion:n,signingService:r,priorSignature:e.priorSignature,eventStreamCredentials:i}).then(t=>({message:e.message,signature:t}))}async signString(e,{signingDate:t=new Date,signingRegion:n,signingService:r,eventStreamCredentials:i}={}){let a=i??await this.credentialProvider();this.validateResolvedCredentials(a);let o=n??await this.regionProvider(),{shortDate:s}=this.formatDate(t),c=new this.sha256(await this.getSigningKey(a,o,s,r));return c.update(Gb(e)),Ub(await c.digest())}async signRequest(e,{signingDate:t=new Date,signableHeaders:n,unsignableHeaders:r,signingRegion:i,signingService:a}={}){let o=await this.credentialProvider();this.validateResolvedCredentials(o);let s=i??await this.regionProvider(),c=cx(e),{longDate:l,shortDate:u}=this.formatDate(t),d=nx(u,s,a??this.service);c.headers[Zb]=l,o.sessionToken&&(c.headers[Fie]=o.sessionToken);let f=await ox(c,this.sha256);!Kie(`x-amz-content-sha256`,c.headers)&&this.applyChecksum&&(c.headers[Pie]=f);let p=ix(c,r,n),m=await this.getSignature(l,d,this.getSigningKey(o,s,u,a),this.createCanonicalRequest(c,p,f));return c.headers[Xb]=`${Qb} Credential=${o.accessKeyId}/${d}, SignedHeaders=${this.getCanonicalHeaderList(p)}, Signature=${m}`,c}async getSignature(e,t,n,r){let i=await this.createStringToSign(e,t,r,Qb),a=new this.sha256(await n);return a.update(Gb(i)),Ub(await a.digest())}getSigningKey(e,t,n,r){return Vie(this.sha256,e,n,t,r||this.service)}},px={SignatureV4a:null},$ie=`ap-southeast-2`,mx=9999;async function hx({action:e,credentials:t,service:n=`spinifex`}){let r=window.location.protocol.replace(`:`,``),i=`Action=${e}`,a=new Rb({method:`POST`,protocol:r,hostname:`localhost`,port:mx,path:`/`,headers:{host:`localhost:${mx}`,"content-type":`application/x-www-form-urlencoded`},body:i}),o=await new fx({credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey},region:$ie,service:n,sha256:Nb}).sign(a),s={};for(let[e,t]of Object.entries(o.headers))typeof t==`string`&&(s[e]=t);let c=`${window.location.protocol}//${window.location.host}/proxy/awsgw/`,l=await fetch(c,{method:`POST`,headers:s,body:i});if(!l.ok){let t=await l.text().catch(()=>``);throw Error(`${e} failed: ${l.status}${t?` - ${t}`:``}`)}return await l.json()}var eae=`000000000001`,gx=(0,P.createContext)(void 0);function tae({children:e}){let[t,n]=(0,P.useState)({isAdmin:!1,accountId:null,userName:null,version:null,license:null,loading:!0});return(0,P.useEffect)(()=>{async function e(){let e=vb();if(!e){n(e=>({...e,loading:!1}));return}try{let t=await hx({action:`GetCallerIdentity`,credentials:e}),r=t.account_id===eae,i=null;if(r)try{i=await hx({action:`GetVersion`,credentials:e})}catch{}n({isAdmin:r,accountId:t.account_id,userName:t.user_name,version:i,license:i?.license??null,loading:!1})}catch{n(e=>({...e,loading:!1}))}}e()},[]),(0,F.jsx)(gx,{value:t,children:e})}function _x(){let e=(0,P.useContext)(gx);if(e===void 0)throw Error(`useAdmin must be used within an AdminProvider`);return e}function nae(){let e=(0,da.c)(8),{theme:t,setTheme:n}=ha(),r;e[0]!==n||e[1]!==t?(r=()=>{n(t===`light`?`dark`:t===`dark`?`light`:`dark`)},e[0]=n,e[1]=t,e[2]=r):r=e[2];let i=r,a,o,s;e[3]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,F.jsx)(Ro,{className:`size-[1.2rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90`}),o=(0,F.jsx)(Mo,{className:`absolute size-[1.2rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0`}),s=(0,F.jsx)(`span`,{className:`sr-only`,children:`Toggle theme`}),e[3]=a,e[4]=o,e[5]=s):(a=e[3],o=e[4],s=e[5]);let c;return e[6]===i?c=e[7]:(c=(0,F.jsxs)(fl,{className:`rounded-full`,onClick:i,size:`icon-sm`,variant:`ghost`,children:[a,o,s]}),e[6]=i,e[7]=c),c}function vx(){let e=(0,da.c)(7),{isAdmin:t,license:n}=_x(),r=t&&n===`open-source`,i,a;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(i=$c(`z-50 flex h-10 shrink-0 items-center gap-2 border-b border-sidebar-border bg-sidebar px-4 text-sidebar-foreground`,`sticky top-0`),a=(0,F.jsx)(Nte,{className:`-ml-1`}),e[0]=i,e[1]=a):(i=e[0],a=e[1]);let o;e[2]===r?o=e[3]:(o=r&&(0,F.jsx)(`a`,{href:`https://mulgadc.com/purchase`,target:`_blank`,rel:`noopener noreferrer`,className:$c(dl({variant:`outline`,size:`sm`})),children:`Upgrade`}),e[2]=r,e[3]=o);let s;e[4]===Symbol.for(`react.memo_cache_sentinel`)?(s=(0,F.jsx)(nae,{}),e[4]=s):s=e[4];let c;return e[5]===o?c=e[6]:(c=(0,F.jsxs)(`header`,{className:i,children:[a,(0,F.jsxs)(`div`,{className:`flex w-full items-center justify-end gap-2`,children:[o,s]})]}),e[5]=o,e[6]=c),c}function rae(){let e=(0,da.c)(3),t,n;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(t=(0,F.jsx)(`h1`,{className:`text-4xl font-bold`,children:`404`}),n=(0,F.jsx)(`p`,{className:`text-muted-foreground`,children:`Page not found`}),e[0]=t,e[1]=n):(t=e[0],n=e[1]);let r;return e[2]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,F.jsxs)(`div`,{className:`flex flex-1 flex-col items-center justify-center gap-4`,children:[t,n,(0,F.jsx)(Oi,{to:`/`,children:(0,F.jsx)(fl,{variant:`outline`,children:`Go back home`})})]}),e[2]=r):r=e[2],r}function iae(e,t,n){return e.$source||={},e.$source[t]=n,e}var aae=e=>e?.body instanceof ReadableStream,yx=(e,t)=>{let n=[];if(e&&n.push(e),t)for(let e of t)n.push(e);return n},bx=(e,t)=>`${e||`anonymous`}${t&&t.length>0?` (a.k.a. ${t.join(`,`)})`:``}`,xx=()=>{let e=[],t=[],n=!1,r=new Set,i=e=>e.sort((e,t)=>Sx[t.step]-Sx[e.step]||Cx[t.priority||`normal`]-Cx[e.priority||`normal`]),a=n=>{let i=!1,a=e=>{let t=yx(e.name,e.aliases);if(t.includes(n)){i=!0;for(let e of t)r.delete(e);return!1}return!0};return e=e.filter(a),t=t.filter(a),i},o=n=>{let i=!1,a=e=>{if(e.middleware===n){i=!0;for(let t of yx(e.name,e.aliases))r.delete(t);return!1}return!0};return e=e.filter(a),t=t.filter(a),i},s=n=>(e.forEach(e=>{n.add(e.middleware,{...e})}),t.forEach(e=>{n.addRelativeTo(e.middleware,{...e})}),n.identifyOnResolve?.(u.identifyOnResolve()),n),c=e=>{let t=[];return e.before.forEach(e=>{e.before.length===0&&e.after.length===0?t.push(e):t.push(...c(e))}),t.push(e),e.after.reverse().forEach(e=>{e.before.length===0&&e.after.length===0?t.push(e):t.push(...c(e))}),t},l=(n=!1)=>{let r=[],a=[],o={};return e.forEach(e=>{let t={...e,before:[],after:[]};for(let e of yx(t.name,t.aliases))o[e]=t;r.push(t)}),t.forEach(e=>{let t={...e,before:[],after:[]};for(let e of yx(t.name,t.aliases))o[e]=t;a.push(t)}),a.forEach(e=>{if(e.toMiddleware){let t=o[e.toMiddleware];if(t===void 0){if(n)return;throw Error(`${e.toMiddleware} is not found when adding ${bx(e.name,e.aliases)} middleware ${e.relation} ${e.toMiddleware}`)}e.relation===`after`&&t.after.push(e),e.relation===`before`&&t.before.push(e)}}),i(r).map(c).reduce((e,t)=>(e.push(...t),e),[])},u={add:(t,n={})=>{let{name:i,override:a,aliases:o}=n,s={step:`initialize`,priority:`normal`,middleware:t,...n},c=yx(i,o);if(c.length>0){if(c.some(e=>r.has(e))){if(!a)throw Error(`Duplicate middleware name '${bx(i,o)}'`);for(let t of c){let n=e.findIndex(e=>e.name===t||e.aliases?.some(e=>e===t));if(n===-1)continue;let r=e[n];if(r.step!==s.step||s.priority!==r.priority)throw Error(`"${bx(r.name,r.aliases)}" middleware with ${r.priority} priority in ${r.step} step cannot be overridden by "${bx(i,o)}" middleware with ${s.priority} priority in ${s.step} step.`);e.splice(n,1)}}for(let e of c)r.add(e)}e.push(s)},addRelativeTo:(e,n)=>{let{name:i,override:a,aliases:o}=n,s={middleware:e,...n},c=yx(i,o);if(c.length>0){if(c.some(e=>r.has(e))){if(!a)throw Error(`Duplicate middleware name '${bx(i,o)}'`);for(let e of c){let n=t.findIndex(t=>t.name===e||t.aliases?.some(t=>t===e));if(n===-1)continue;let r=t[n];if(r.toMiddleware!==s.toMiddleware||r.relation!==s.relation)throw Error(`"${bx(r.name,r.aliases)}" middleware ${r.relation} "${r.toMiddleware}" middleware cannot be overridden by "${bx(i,o)}" middleware ${s.relation} "${s.toMiddleware}" middleware.`);t.splice(n,1)}}for(let e of c)r.add(e)}t.push(s)},clone:()=>s(xx()),use:e=>{e.applyToStack(u)},remove:e=>typeof e==`string`?a(e):o(e),removeByTag:n=>{let i=!1,a=e=>{let{tags:t,name:a,aliases:o}=e;if(t&&t.includes(n)){let e=yx(a,o);for(let t of e)r.delete(t);return i=!0,!1}return!0};return e=e.filter(a),t=t.filter(a),i},concat:e=>{let t=s(xx());return t.use(e),t.identifyOnResolve(n||t.identifyOnResolve()||(e.identifyOnResolve?.()??!1)),t},applyToStack:s,identify:()=>l(!0).map(e=>{let t=e.step??e.relation+` `+e.toMiddleware;return bx(e.name,e.aliases)+` - `+t}),identifyOnResolve(e){return typeof e==`boolean`&&(n=e),n},resolve:(e,t)=>{for(let n of l().map(e=>e.middleware).reverse())e=n(e,t);return n&&console.log(u.identify()),e}};return u},Sx={initialize:5,serialize:4,build:3,finalizeRequest:2,deserialize:1},Cx={high:3,normal:2,low:1},wx;(function(e){e.HTTP=`http`,e.HTTPS=`https`})(wx||={});var Tx;(function(e){e.MD5=`md5`,e.CRC32=`crc32`,e.CRC32C=`crc32c`,e.SHA1=`sha1`,e.SHA256=`sha256`})(Tx||={});var oae=`__smithy_context`,Ex=e=>e.__smithy_context||={},Dx=class e{method;protocol;hostname;port;path;query;headers;username;password;fragment;body;constructor(e){this.method=e.method||`GET`,this.hostname=e.hostname||`localhost`,this.port=e.port,this.query=e.query||{},this.headers=e.headers||{},this.body=e.body,this.protocol=e.protocol?e.protocol.slice(-1)===`:`?e.protocol:`${e.protocol}:`:`https:`,this.path=e.path?e.path.charAt(0)===`/`?e.path:`/${e.path}`:`/`,this.username=e.username,this.password=e.password,this.fragment=e.fragment}static clone(t){let n=new e({...t,headers:{...t.headers}});return n.query&&=sae(n.query),n}static isInstance(e){if(!e)return!1;let t=e;return`method`in t&&`protocol`in t&&`hostname`in t&&`path`in t&&typeof t.query==`object`&&typeof t.headers==`object`}clone(){return e.clone(this)}};function sae(e){return Object.keys(e).reduce((t,n)=>{let r=e[n];return{...t,[n]:Array.isArray(r)?[...r]:r}},{})}var Ox=class{statusCode;reason;headers;body;constructor(e){this.statusCode=e.statusCode,this.reason=e.reason,this.headers=e.headers||{},this.body=e.body}static isInstance(e){if(!e)return!1;let t=e;return typeof t.statusCode==`number`&&typeof t.headers==`object`}},cae=RegExp(`^(?!.*-$)(?!-)[a-zA-Z0-9-]{1,63}$`),kx=(e,t=!1)=>{if(!t)return cae.test(e);let n=e.split(`.`);for(let e of n)if(!kx(e))return!1;return!0},Ax=e=>{if(typeof e==`function`)return e;let t=Promise.resolve(e);return()=>t};function lae(e){let t={};if(e=e.replace(/^\?/,``),e)for(let n of e.split(`&`)){let[e,r=null]=n.split(`=`);e=decodeURIComponent(e),r&&=decodeURIComponent(r),e in t?Array.isArray(t[e])?t[e].push(r):t[e]=[t[e],r]:t[e]=r}return t}var jx=e=>{if(typeof e==`string`)return jx(new URL(e));let{hostname:t,pathname:n,port:r,protocol:i,search:a}=e,o;return a&&(o=lae(a)),{hostname:t,port:r?parseInt(r):void 0,protocol:i,path:n,query:o}},Mx=e=>{if(typeof e==`object`){if(`url`in e){let t=jx(e.url);if(e.headers){t.headers={};for(let n in e.headers)t.headers[n.toLowerCase()]=e.headers[n].join(`, `)}return t}return e}return jx(e)},uae=e=>()=>Promise.reject(e),dae=class{config;middlewareStack=xx();initConfig;handlers;constructor(e){this.config=e;let{protocol:t,protocolSettings:n}=e;n&&typeof t==`function`&&(e.protocol=new t(n))}send(e,t,n){let r=typeof t==`function`?void 0:t,i=typeof t==`function`?t:n,a=r===void 0&&this.config.cacheMiddleware===!0,o;if(a){this.handlers||=new WeakMap;let t=this.handlers;t.has(e.constructor)?o=t.get(e.constructor):(o=e.resolveMiddleware(this.middlewareStack,this.config,r),t.set(e.constructor,o))}else delete this.handlers,o=e.resolveMiddleware(this.middlewareStack,this.config,r);if(i)o(e).then(e=>i(null,e.output),e=>i(e)).catch(()=>{});else return o(e).then(e=>e.output)}destroy(){this.config?.requestHandler?.destroy?.(),delete this.handlers}},Nx=e=>typeof e==`function`?e():e,Px=(e,t,n,r,i)=>({name:t,namespace:e,traits:n,input:r,output:i}),fae=e=>(t,n)=>async r=>{let{response:i}=await t(r),{operationSchema:a}=Ex(n),[,o,s,c,l,u]=a??[];try{return{response:i,output:await e.protocol.deserializeResponse(Px(o,s,c,l,u),{...e,...n},i)}}catch(e){if(Object.defineProperty(e,`$response`,{value:i,enumerable:!1,writable:!1,configurable:!1}),!(`$metadata`in e)){let t=`Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.`;try{e.message+=` + `+t}catch{!n.logger||n.logger?.constructor?.name===`NoOpLogger`?console.warn(t):n.logger?.warn?.(t)}e.$responseBodyText!==void 0&&e.$response&&(e.$response.body=e.$responseBodyText);try{if(Ox.isInstance(i)){let{headers:t={},statusCode:n}=i,r=Object.entries(t);e.$metadata={httpStatusCode:n,requestId:Fx(/^x-[\w-]+-request-?id$/,r),extendedRequestId:Fx(/^x-[\w-]+-id-2$/,r),cfId:Fx(/^x-[\w-]+-cf-id$/,r)}}}catch{}}throw e}},Fx=(e,t)=>(t.find(([t])=>t.match(e))||[void 0,void 0])[1],pae=e=>(t,n)=>async r=>{let{operationSchema:i}=Ex(n),[,a,o,s,c,l]=i??[],u=n.endpointV2?async()=>Mx(n.endpointV2):e.endpoint,d=await e.protocol.serializeRequest(Px(a,o,s,c,l),r.input,{...e,...n,endpoint:u});return t({...r,request:d})},mae={name:`deserializerMiddleware`,step:`deserialize`,tags:[`DESERIALIZER`],override:!0},hae={name:`serializerMiddleware`,step:`serialize`,tags:[`SERIALIZER`],override:!0};function gae(e){return{applyToStack:t=>{t.add(pae(e),hae),t.add(fae(e),mae),e.protocol.setSerdeContext(e)}}}var Ix=[];function Lx(e){if(typeof e==`object`)return e;if(e|=0,Ix[e])return Ix[e];let t={},n=0;for(let r of[`httpLabel`,`idempotent`,`idempotencyToken`,`sensitive`,`httpPayload`,`httpResponseCode`,`httpQueryParams`])(e>>n++&1)==1&&(t[r]=1);return Ix[e]=t}var Rx={it:Symbol.for(`@smithy/nor-struct-it`),ns:Symbol.for(`@smithy/ns`)},zx=[],Bx={},Vx=class e{ref;memberName;static symbol=Symbol.for(`@smithy/nor`);symbol=e.symbol;name;schema;_isMemberSchema;traits;memberTraits;normalizedTraits;constructor(t,n){this.ref=t,this.memberName=n;let r=[],i=t,a=t;for(this._isMemberSchema=!1;Ux(i);)r.push(i[1]),i=i[0],a=Nx(i),this._isMemberSchema=!0;if(r.length>0){this.memberTraits={};for(let e=r.length-1;e>=0;--e){let t=r[e];Object.assign(this.memberTraits,Lx(t))}}else this.memberTraits=0;if(a instanceof e){let e=this.memberTraits;Object.assign(this,a),this.memberTraits=Object.assign({},e,a.getMemberTraits(),this.getMemberTraits()),this.normalizedTraits=void 0,this.memberName=n??a.memberName;return}if(this.schema=Nx(a),_ae(this.schema)?(this.name=`${this.schema[1]}#${this.schema[2]}`,this.traits=this.schema[3]):(this.name=this.memberName??String(a),this.traits=0),this._isMemberSchema&&!n)throw Error(`@smithy/core/schema - NormalizedSchema member init ${this.getName(!0)} missing member name.`)}static[Symbol.hasInstance](e){let t=this.prototype.isPrototypeOf(e);return!t&&typeof e==`object`&&e?e.symbol===this.symbol:t}static of(t){let n=typeof t==`function`||typeof t==`object`&&!!t;if(typeof t==`number`){if(zx[t])return zx[t]}else if(typeof t==`string`){if(Bx[t])return Bx[t]}else if(n&&t[Rx.ns])return t[Rx.ns];let r=Nx(t);if(r instanceof e)return r;if(Ux(r)){let[n,i]=r;if(n instanceof e)return Object.assign(n.getMergedTraits(),Lx(i)),n;throw Error(`@smithy/core/schema - may not init unwrapped member schema=${JSON.stringify(t,null,2)}.`)}let i=new e(r);return n?t[Rx.ns]=i:typeof r==`string`?Bx[r]=i:typeof r==`number`?zx[r]=i:i}getSchema(){let e=this.schema;return Array.isArray(e)&&e[0]===0?e[4]:e}getName(e=!1){let{name:t}=this;return!e&&t&&t.includes(`#`)?t.split(`#`)[1]:t||void 0}getMemberName(){return this.memberName}isMemberSchema(){return this._isMemberSchema}isListSchema(){let e=this.getSchema();return typeof e==`number`?e>=64&&e<128:e[0]===1}isMapSchema(){let e=this.getSchema();return typeof e==`number`?e>=128&&e<=255:e[0]===2}isStructSchema(){let e=this.getSchema();if(typeof e!=`object`)return!1;let t=e[0];return t===3||t===-3||t===4}isUnionSchema(){let e=this.getSchema();return typeof e==`object`?e[0]===4:!1}isBlobSchema(){let e=this.getSchema();return e===21||e===42}isTimestampSchema(){let e=this.getSchema();return typeof e==`number`&&e>=4&&e<=7}isUnitSchema(){return this.getSchema()===`unit`}isDocumentSchema(){return this.getSchema()===15}isStringSchema(){return this.getSchema()===0}isBooleanSchema(){return this.getSchema()===2}isNumericSchema(){return this.getSchema()===1}isBigIntegerSchema(){return this.getSchema()===17}isBigDecimalSchema(){return this.getSchema()===19}isStreaming(){let{streaming:e}=this.getMergedTraits();return!!e||this.getSchema()===42}isIdempotencyToken(){return!!this.getMergedTraits().idempotencyToken}getMergedTraits(){return this.normalizedTraits??={...this.getOwnTraits(),...this.getMemberTraits()}}getMemberTraits(){return Lx(this.memberTraits)}getOwnTraits(){return Lx(this.traits)}getKeySchema(){let[e,t]=[this.isDocumentSchema(),this.isMapSchema()];if(!e&&!t)throw Error(`@smithy/core/schema - cannot get key for non-map: ${this.getName(!0)}`);let n=this.getSchema();return Hx([e?15:n[4]??0,0],`key`)}getValueSchema(){let e=this.getSchema(),[t,n,r]=[this.isDocumentSchema(),this.isMapSchema(),this.isListSchema()],i=typeof e==`number`?63&e:e&&typeof e==`object`&&(n||r)?e[3+e[0]]:t?15:void 0;if(i!=null)return Hx([i,0],n?`value`:`member`);throw Error(`@smithy/core/schema - ${this.getName(!0)} has no value member.`)}getMemberSchema(e){let t=this.getSchema();if(this.isStructSchema()&&t[4].includes(e)){let n=t[4].indexOf(e),r=t[5][n];return Hx(Ux(r)?r:[r,0],e)}if(this.isDocumentSchema())return Hx([15,0],e);throw Error(`@smithy/core/schema - ${this.getName(!0)} has no member=${e}.`)}getMemberSchemas(){let e={};try{for(let[t,n]of this.structIterator())e[t]=n}catch{}return e}getEventStreamMember(){if(this.isStructSchema()){for(let[e,t]of this.structIterator())if(t.isStreaming()&&t.isStructSchema())return e}return``}*structIterator(){if(this.isUnitSchema())return;if(!this.isStructSchema())throw Error(`@smithy/core/schema - cannot iterate non-struct schema.`);let e=this.getSchema(),t=e[4].length,n=e[Rx.it];if(n&&t===n.length){yield*n;return}n=Array(t);for(let r=0;rArray.isArray(e)&&e.length===2,_ae=e=>Array.isArray(e)&&e.length>=5,Wx=class e{namespace;schemas;exceptions;static registries=new Map;constructor(e,t=new Map,n=new Map){this.namespace=e,this.schemas=t,this.exceptions=n}static for(t){return e.registries.has(t)||e.registries.set(t,new e(t)),e.registries.get(t)}copyFrom(e){let{schemas:t,exceptions:n}=this;for(let[n,r]of e.schemas)t.has(n)||t.set(n,r);for(let[t,r]of e.exceptions)n.has(t)||n.set(t,r)}register(t,n){let r=this.normalizeShapeId(t);for(let t of[this,e.for(r.split(`#`)[0])])t.schemas.set(r,n)}getSchema(e){let t=this.normalizeShapeId(e);if(!this.schemas.has(t)){if(!e.includes(`#`)){let t=`#`+e,n=[];for(let[e,r]of this.schemas.entries())e.endsWith(t)&&n.push(r);if(n.length===1)return n[0]}throw Error(`@smithy/core/schema - schema not found for ${t}`)}return this.schemas.get(t)}registerError(t,n){let r=t,i=r[1];for(let t of[this,e.for(i)])t.schemas.set(i+`#`+r[2],r),t.exceptions.set(r,n)}getErrorCtor(t){let n=t;return this.exceptions.has(n)?this.exceptions.get(n):e.for(n[1]).exceptions.get(n)}getBaseException(){for(let e of this.exceptions.keys())if(Array.isArray(e)){let[,t,n]=e,r=t+`#`+n;if(r.startsWith(`smithy.ts.sdk.synthetic.`)&&r.endsWith(`ServiceException`))return e}}find(e){for(let t of this.schemas.values())if(e(t))return t}clear(){this.schemas.clear(),this.exceptions.clear()}normalizeShapeId(e){return e.includes(`#`)?e:this.namespace+`#`+e}},vae=class e extends Error{$fault;$response;$retryable;$metadata;constructor(e){super(e.message),Object.setPrototypeOf(this,Object.getPrototypeOf(this).constructor.prototype),this.name=e.name,this.$fault=e.$fault,this.$metadata=e.$metadata}static isInstance(t){if(!t)return!1;let n=t;return e.prototype.isPrototypeOf(n)||!!n.$fault&&!!n.$metadata&&(n.$fault===`client`||n.$fault===`server`)}static[Symbol.hasInstance](t){if(!t)return!1;let n=t;return this===e?e.isInstance(t):e.isInstance(t)?n.name&&this.name?this.prototype.isPrototypeOf(t)||n.name===this.name:this.prototype.isPrototypeOf(t):!1}},Gx=(e,t={})=>(Object.entries(t).filter(([,e])=>e!==void 0).forEach(([t,n])=>{(e[t]==null||e[t]===``)&&(e[t]=n)}),e.message=e.message||e.Message||`UnknownError`,delete e.Message,e),yae=e=>{switch(e){case`standard`:return{retryMode:`standard`,connectionTimeout:3100};case`in-region`:return{retryMode:`standard`,connectionTimeout:1100};case`cross-region`:return{retryMode:`standard`,connectionTimeout:3100};case`mobile`:return{retryMode:`standard`,connectionTimeout:3e4};default:return{}}},Kx=Object.values(Tx),bae=e=>{let t=[];for(let n in Tx){let r=Tx[n];e[r]!==void 0&&t.push({algorithmId:()=>r,checksumConstructor:()=>e[r]})}for(let[n,r]of Object.entries(e.checksumAlgorithms??{}))t.push({algorithmId:()=>n,checksumConstructor:()=>r});return{addChecksumAlgorithm(n){e.checksumAlgorithms=e.checksumAlgorithms??{};let r=n.algorithmId(),i=n.checksumConstructor();Kx.includes(r)?e.checksumAlgorithms[r.toUpperCase()]=i:e.checksumAlgorithms[r]=i,t.push(n)},checksumAlgorithms(){return t}}},xae=e=>{let t={};return e.checksumAlgorithms().forEach(e=>{let n=e.algorithmId();Kx.includes(n)&&(t[n]=e.checksumConstructor())}),t},Sae=e=>({setRetryStrategy(t){e.retryStrategy=t},retryStrategy(){return e.retryStrategy}}),Cae=e=>{let t={};return t.retryStrategy=e.retryStrategy(),t},wae=e=>Object.assign(bae(e),Sae(e)),Tae=e=>Object.assign(xae(e),Cae(e)),qx=class{trace(){}debug(){}info(){}warn(){}error(){}},Jx=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`,Yx=Object.entries(Jx).reduce((e,[t,n])=>(e[n]=Number(t),e),{}),Eae=Jx.split(``),Xx=e=>{let t=e.length/4*3;e.slice(-2)===`==`?t-=2:e.slice(-1)===`=`&&t--;let n=new ArrayBuffer(t),r=new DataView(n);for(let t=0;t>=6;let a=t/4*3;n>>=i%8;let o=Math.floor(i/8);for(let e=0;e>t)}}return new Uint8Array(n)},Zx=e=>new TextEncoder().encode(e);function Qx(e){let t;t=typeof e==`string`?Zx(e):e;let n=typeof t==`object`&&typeof t.length==`number`,r=typeof t==`object`&&typeof t.byteOffset==`number`&&typeof t.byteLength==`number`;if(!n&&!r)throw Error(`@smithy/util-base64: toBase64 encoder function only accepts string | Uint8Array.`);let i=``;for(let e=0;e>t]}i+=`==`.slice(0,4-a)}return i}function Dae(e,t,n,r){return class i extends Uint8Array{static fromString(e,n=`utf-8`){if(typeof e==`string`)return n===`base64`?i.mutate(r(e)):i.mutate(t(e));throw Error(`Unsupported conversion from ${typeof e} to Uint8ArrayBlobAdapter.`)}static mutate(e){return Object.setPrototypeOf(e,i.prototype),e}transformToString(t=`utf-8`){return t===`base64`?n(this):e(this)}}}var $x=e=>{if(typeof e==`string`)return e;if(typeof e!=`object`||typeof e.byteOffset!=`number`||typeof e.byteLength!=`number`)throw Error(`@smithy/util-utf8: toUtf8 encoder function only accepts string | Uint8Array.`);return new TextDecoder(`utf-8`).decode(e)},eS=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,`0`));function Oae(e){return typeof crypto<`u`&&typeof crypto.randomUUID==`function`?()=>crypto.randomUUID():()=>{let t=new Uint8Array(16);return e(t),t[6]=t[6]&15|64,t[8]=t[8]&63|128,eS[t[0]]+eS[t[1]]+eS[t[2]]+eS[t[3]]+`-`+eS[t[4]]+eS[t[5]]+`-`+eS[t[6]]+eS[t[7]]+`-`+eS[t[8]]+eS[t[9]]+`-`+eS[t[10]]+eS[t[11]]+eS[t[12]]+eS[t[13]]+eS[t[14]]+eS[t[15]]}}var tS=e=>{if(e!=null){if(typeof e==`string`){let t=parseFloat(e);if(!Number.isNaN(t))return String(t)!==String(e)&&Bae.warn(zae(`Expected number but observed string: ${e}`)),t}if(typeof e==`number`)return e;throw TypeError(`Expected number, got ${typeof e}: ${e}`)}},kae=Math.ceil(2**127*(2-2**-23)),Aae=e=>{let t=tS(e);if(t!==void 0&&!Number.isNaN(t)&&t!==1/0&&t!==-1/0&&Math.abs(t)>kae)throw TypeError(`Expected 32-bit float, got ${e}`);return t},jae=e=>{if(e!=null){if(Number.isInteger(e)&&!Number.isNaN(e))return e;throw TypeError(`Expected integer, got ${typeof e}: ${e}`)}},Mae=e=>nS(e,16),Nae=e=>nS(e,8),nS=(e,t)=>{let n=jae(e);if(n!==void 0&&Pae(n,t)!==n)throw TypeError(`Expected ${t}-bit integer, got ${e}`);return n},Pae=(e,t)=>{switch(t){case 32:return Int32Array.of(e)[0];case 16:return Int16Array.of(e)[0];case 8:return Int8Array.of(e)[0]}},Fae=e=>tS(typeof e==`string`?rS(e):e),Iae=e=>Aae(typeof e==`string`?rS(e):e),Lae=/(-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?)|(-?Infinity)|(NaN)/g,rS=e=>{let t=e.match(Lae);if(t===null||t[0].length!==e.length)throw TypeError(`Expected real number, got implicit NaN`);return parseFloat(e)},iS=e=>Mae(typeof e==`string`?rS(e):e),Rae=e=>Nae(typeof e==`string`?rS(e):e),zae=e=>String(TypeError(e).stack||e).split(` `).slice(0,5).filter(e=>!e.includes(`stackTraceWarning`)).join(` -`),Ew={warn:console.warn},Dw=[`Sun`,`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`],Ow=[`Jan`,`Feb`,`Mar`,`Apr`,`May`,`Jun`,`Jul`,`Aug`,`Sep`,`Oct`,`Nov`,`Dec`];function kw(e){let t=e.getUTCFullYear(),n=e.getUTCMonth(),r=e.getUTCDay(),i=e.getUTCDate(),a=e.getUTCHours(),o=e.getUTCMinutes(),s=e.getUTCSeconds(),c=i<10?`0${i}`:`${i}`,l=a<10?`0${a}`:`${a}`,u=o<10?`0${o}`:`${o}`,d=s<10?`0${s}`:`${s}`;return`${Dw[r]}, ${c} ${Ow[n]} ${t} ${l}:${u}:${d} GMT`}var Aw=new RegExp(/^(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d{2}) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d{1,2}):(\d{2}):(\d{2})(?:\.(\d+))? GMT$/),jw=new RegExp(/^(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (\d{2})-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d{2}) (\d{1,2}):(\d{2}):(\d{2})(?:\.(\d+))? GMT$/),Mw=new RegExp(/^(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ( [1-9]|\d{2}) (\d{1,2}):(\d{2}):(\d{2})(?:\.(\d+))? (\d{4})$/),Nw=e=>{if(e==null)return;if(typeof e!=`string`)throw TypeError(`RFC-7231 date-times must be expressed as strings`);let t=Aw.exec(e);if(t){let[e,n,r,i,a,o,s,c]=t;return Pw(Cw(Ww(i)),Rw(r),Hw(n,`day`,1,31),{hours:a,minutes:o,seconds:s,fractionalMilliseconds:c})}if(t=jw.exec(e),t){let[e,n,r,i,a,o,s,c]=t;return Lw(Pw(Fw(i),Rw(r),Hw(n,`day`,1,31),{hours:a,minutes:o,seconds:s,fractionalMilliseconds:c}))}if(t=Mw.exec(e),t){let[e,n,r,i,a,o,s,c]=t;return Pw(Cw(Ww(c)),Rw(n),Hw(r.trimLeft(),`day`,1,31),{hours:i,minutes:a,seconds:o,fractionalMilliseconds:s})}throw TypeError(`Invalid RFC-7231 date-time value`)},Pw=(e,t,n,r)=>{let i=t-1;return Bw(e,i,n),new Date(Date.UTC(e,i,n,Hw(r.hours,`hour`,0,23),Hw(r.minutes,`minute`,0,59),Hw(r.seconds,`seconds`,0,60),Uw(r.fractionalMilliseconds)))},Fw=e=>{let t=new Date().getUTCFullYear(),n=Math.floor(t/100)*100+Cw(Ww(e));return ne.getTime()-new Date().getTime()>Iw?new Date(Date.UTC(e.getUTCFullYear()-100,e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds(),e.getUTCMilliseconds())):e,Rw=e=>{let t=Ow.indexOf(e);if(t<0)throw TypeError(`Invalid month: ${e}`);return t+1},zw=[31,28,31,30,31,30,31,31,30,31,30,31],Bw=(e,t,n)=>{let r=zw[t];if(t===1&&Vw(e)&&(r=29),n>r)throw TypeError(`Invalid day for ${Ow[t]} in ${e}: ${n}`)},Vw=e=>e%4==0&&(e%100!=0||e%400==0),Hw=(e,t,n,r)=>{let i=ww(Ww(e));if(ir)throw TypeError(`${t} must be between ${n} and ${r}, inclusive`);return i},Uw=e=>e==null?0:bw(`0.`+e)*1e3,Ww=e=>{let t=0;for(;tt.toString(16).padStart(2,`0`)),qw=()=>{if(Gw)return Gw();let e=new Uint8Array(16);return crypto.getRandomValues(e),e[6]=e[6]&15|64,e[8]=e[8]&63|128,Kw[e[0]]+Kw[e[1]]+Kw[e[2]]+Kw[e[3]]+`-`+Kw[e[4]]+Kw[e[5]]+`-`+Kw[e[6]]+Kw[e[7]]+`-`+Kw[e[8]]+Kw[e[9]]+`-`+Kw[e[10]]+Kw[e[11]]+Kw[e[12]]+Kw[e[13]]+Kw[e[14]]+Kw[e[15]]},Jw=function(e){return Object.assign(new String(e),{deserializeJSON(){return JSON.parse(String(e))},toString(){return String(e)},toJSON(){return String(e)}})};Jw.from=e=>e&&typeof e==`object`&&(e instanceof Jw||`deserializeJSON`in e)?e:typeof e==`string`||Object.getPrototypeOf(e)===String.prototype?Jw(String(e)):Jw(JSON.stringify(e)),Jw.fromObject=Jw.from;function Yw(e){return(e.includes(`,`)||e.includes(`"`))&&(e=`"${e.replace(/"/g,`\\"`)}"`),e}var Xw=`(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)(?:[ne|u?r]?s?day)?`,Zw=`(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)`,Qw=`(\\d?\\d):(\\d{2}):(\\d{2})(?:\\.(\\d+))?`,$w=`(\\d?\\d)`,eT=`(\\d{4})`,tT=new RegExp(/^(\d{4})-(\d\d)-(\d\d)[tT](\d\d):(\d\d):(\d\d)(\.(\d+))?(([-+]\d\d:\d\d)|[zZ])$/),nT=RegExp(`^${Xw}, ${$w} ${Zw} ${eT} ${Qw} GMT$`),rT=RegExp(`^${Xw}, ${$w}-${Zw}-(\\d\\d) ${Qw} GMT$`),iT=RegExp(`^${Xw} ${Zw} ( [1-9]|\\d\\d) ${Qw} ${eT}$`),aT=[`Jan`,`Feb`,`Mar`,`Apr`,`May`,`Jun`,`Jul`,`Aug`,`Sep`,`Oct`,`Nov`,`Dec`],oT=e=>{if(e==null)return;let t=NaN;if(typeof e==`number`)t=e;else if(typeof e==`string`){if(!/^-?\d*\.?\d+$/.test(e))throw TypeError(`parseEpochTimestamp - numeric string invalid.`);t=Number.parseFloat(e)}else typeof e==`object`&&e.tag===1&&(t=e.value);if(isNaN(t)||Math.abs(t)===1/0)throw TypeError(`Epoch timestamps must be valid finite numbers.`);return new Date(Math.round(t*1e3))},sT=e=>{if(e==null)return;if(typeof e!=`string`)throw TypeError(`RFC3339 timestamps must be strings`);let t=tT.exec(e);if(!t)throw TypeError(`Invalid RFC3339 timestamp format ${e}`);let[,n,r,i,a,o,s,,c,l]=t;lT(r,1,12),lT(i,1,31),lT(a,0,23),lT(o,0,59),lT(s,0,60);let u=new Date(Date.UTC(Number(n),Number(r)-1,Number(i),Number(a),Number(o),Number(s),Number(c)?Math.round(parseFloat(`0.${c}`)*1e3):0));if(u.setUTCFullYear(Number(n)),l.toUpperCase()!=`Z`){let[,e,t,n]=/([+-])(\d\d):(\d\d)/.exec(l)||[void 0,`+`,0,0],r=e===`-`?1:-1;u.setTime(u.getTime()+r*(Number(t)*60*60*1e3+Number(n)*60*1e3))}return u},cT=e=>{if(e==null)return;if(typeof e!=`string`)throw TypeError(`RFC7231 timestamps must be strings.`);let t,n,r,i,a,o,s,c;if((c=nT.exec(e))?[,t,n,r,i,a,o,s]=c:(c=rT.exec(e))?([,t,n,r,i,a,o,s]=c,r=(Number(r)+1900).toString()):(c=iT.exec(e))&&([,n,t,i,a,o,s,r]=c),r&&o){let e=Date.UTC(Number(r),aT.indexOf(n),Number(t),Number(i),Number(a),Number(o),s?Math.round(parseFloat(`0.${s}`)*1e3):0);lT(t,1,31),lT(i,0,23),lT(a,0,59),lT(o,0,60);let c=new Date(e);return c.setUTCFullYear(Number(r)),c}throw TypeError(`Invalid RFC7231 date-time value ${e}.`)};function lT(e,t,n){let r=Number(e);if(rn)throw Error(`Value ${r} out of range [${t}, ${n}]`)}function uT(e,t,n){if(n<=0||!Number.isInteger(n))throw Error(`Invalid number of delimiters (`+n+`) for splitEvery.`);let r=e.split(t);if(n===1)return r;let i=[],a=``;for(let e=0;e{let t=e.length,n=[],r=!1,i,a=0;for(let o=0;o{e=e.trim();let t=e.length;return t<2?e:(e[0]===`"`&&e[t-1]===`"`&&(e=e.slice(1,t-1)),e.replace(/\\"/g,`"`))})},fT=/^-?\d*(\.\d+)?$/,pT=class e{string;type;constructor(e,t){if(this.string=e,this.type=t,!fT.test(e))throw Error(`@smithy/core/serde - NumericValue must only contain [0-9], at most one decimal point ".", and an optional negation prefix "-".`)}toString(){return this.string}static[Symbol.hasInstance](t){if(!t||typeof t!=`object`)return!1;let n=t;return e.prototype.isPrototypeOf(t)||n.type===`bigDecimal`&&fT.test(n.string)}},mT=class{serdeContext;setSerdeContext(e){this.serdeContext=e}},hT=`modulepreload`,gT=function(e){return`/`+e},_T={},vT=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}r=o(t.map(t=>{if(t=gT(t,n),t in _T)return;_T[t]=!0;let r=t.endsWith(`.css`),i=r?`[rel="stylesheet"]`:``;if(n)for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}else if(document.querySelector(`link[href="${t}"]${i}`))return;let o=document.createElement(`link`);if(o.rel=r?`stylesheet`:hT,r||(o.as=`script`),o.crossOrigin=``,o.href=t,a&&o.setAttribute(`nonce`,a),document.head.appendChild(o),r)return new Promise((e,n)=>{o.addEventListener(`load`,e),o.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},yT=class extends mT{options;compositeErrorRegistry;constructor(e){super(),this.options=e,this.compositeErrorRegistry=dw.for(e.defaultNamespace);for(let t of e.errorTypeRegistries??[])this.compositeErrorRegistry.copyFrom(t)}getRequestType(){return Wx}getResponseType(){return Kx}setSerdeContext(e){this.serdeContext=e,this.serializer.setSerdeContext(e),this.deserializer.setSerdeContext(e),this.getPayloadCodec()&&this.getPayloadCodec().setSerdeContext(e)}updateServiceEndpoint(e,t){if(`url`in t){e.protocol=t.url.protocol,e.hostname=t.url.hostname,e.port=t.url.port?Number(t.url.port):void 0,e.path=t.url.pathname,e.fragment=t.url.hash||void 0,e.username=t.url.username||void 0,e.password=t.url.password||void 0,e.query||={};for(let[n,r]of t.url.searchParams.entries())e.query[n]=r;if(t.headers)for(let n in t.headers)e.headers[n]=t.headers[n].join(`, `);return e}else{if(e.protocol=t.protocol,e.hostname=t.hostname,e.port=t.port?Number(t.port):void 0,e.path=t.path,e.query={...t.query},t.headers)for(let n in t.headers)e.headers[n]=t.headers[n];return e}}setHostPrefix(e,t,n){if(this.serdeContext?.disableHostPrefix)return;let r=sw.of(t.input),i=rw(t.traits??{});if(i.endpoint){let t=i.endpoint?.[0];if(typeof t==`string`){for(let[e,i]of r.structIterator()){if(!i.getMergedTraits().hostLabel)continue;let r=n[e];if(typeof r!=`string`)throw Error(`@smithy/core/schema - ${e} in input must be a string as hostLabel.`);t=t.replace(`{${e}}`,r)}e.hostname=t+e.hostname}}}deserializeMetadata(e){return{httpStatusCode:e.statusCode,requestId:e.headers[`x-amzn-requestid`]??e.headers[`x-amzn-request-id`]??e.headers[`x-amz-request-id`],extendedRequestId:e.headers[`x-amz-id-2`],cfId:e.headers[`x-amz-cf-id`]}}async serializeEventStream({eventStream:e,requestSchema:t,initialRequest:n}){return(await this.loadEventStreamCapability()).serializeEventStream({eventStream:e,requestSchema:t,initialRequest:n})}async deserializeEventStream({response:e,responseSchema:t,initialResponseContainer:n}){return(await this.loadEventStreamCapability()).deserializeEventStream({response:e,responseSchema:t,initialResponseContainer:n})}async loadEventStreamCapability(){let{EventStreamSerde:e}=await vT(async()=>{let{EventStreamSerde:e}=await import(`./event-streams.js`);return{EventStreamSerde:e}},[]);return new e({marshaller:this.getEventStreamMarshaller(),serializer:this.serializer,deserializer:this.deserializer,serdeContext:this.serdeContext,defaultContentType:this.getDefaultContentType()})}getDefaultContentType(){throw Error(`@smithy/core/protocols - ${this.constructor.name} getDefaultContentType() implementation missing.`)}async deserializeHttpMessage(e,t,n,r,i){return[]}getEventStreamMarshaller(){let e=this.serdeContext;if(!e.eventStreamMarshaller)throw Error(`@smithy/core - HttpProtocol: eventStreamMarshaller missing in serdeContext.`);return e.eventStreamMarshaller}},bT=class extends yT{async serializeRequest(e,t,n){let r=t&&typeof t==`object`?t:{},i=this.serializer,a={},o={},s=await n.endpoint(),c=sw.of(e?.input),l=[],u=[],d=!1,f,p=new Wx({protocol:``,hostname:``,port:void 0,path:``,fragment:void 0,query:a,headers:o,body:void 0});if(s){this.updateServiceEndpoint(p,s),this.setHostPrefix(p,e,r);let t=rw(e.traits);if(t.http){p.method=t.http[0];let[e,n]=t.http[1].split(`?`);p.path==`/`?p.path=e:p.path+=e;let r=new URLSearchParams(n??``);for(let[e,t]of r)a[e]=t}}for(let[e,t]of c.structIterator()){let n=t.getMergedTraits()??{},s=r[e];if(s==null&&!t.isIdempotencyToken()){if(n.httpLabel&&(p.path.includes(`{${e}+}`)||p.path.includes(`{${e}}`)))throw Error(`No value provided for input HTTP label: ${e}.`);continue}if(n.httpPayload)t.isStreaming()?t.isStructSchema()?r[e]&&(f=await this.serializeEventStream({eventStream:r[e],requestSchema:c})):f=s:(i.write(t,s),f=i.flush());else if(n.httpLabel){i.write(t,s);let n=i.flush();p.path.includes(`{${e}+}`)?p.path=p.path.replace(`{${e}+}`,n.split(`/`).map(WC).join(`/`)):p.path.includes(`{${e}}`)&&(p.path=p.path.replace(`{${e}}`,WC(n)))}else if(n.httpHeader)i.write(t,s),o[n.httpHeader.toLowerCase()]=String(i.flush());else if(typeof n.httpPrefixHeaders==`string`)for(let e in s){let r=s[e],a=n.httpPrefixHeaders+e;i.write([t.getValueSchema(),{httpHeader:a}],r),o[a.toLowerCase()]=i.flush()}else n.httpQuery||n.httpQueryParams?this.serializeQuery(t,s,a):(d=!0,l.push(e),u.push(t))}if(d&&r){let[e,t]=(c.getName(!0)??`#Unknown`).split(`#`),n=c.getSchema()[6],a=[3,e,t,c.getMergedTraits(),l,u,void 0];n?a[6]=n:a.pop(),i.write(a,r),f=i.flush()}return p.headers=o,p.query=a,p.body=f,p}serializeQuery(e,t,n){let r=this.serializer,i=e.getMergedTraits();if(i.httpQueryParams){for(let r in t)if(!(r in n)){let a=t[r],o=e.getValueSchema();Object.assign(o.getMergedTraits(),{...i,httpQuery:r,httpQueryParams:void 0}),this.serializeQuery(o,a,n)}return}if(e.isListSchema()){let a=!!e.getMergedTraits().sparse,o=[];for(let n of t){r.write([e.getValueSchema(),i],n);let t=r.flush();(a||t!==void 0)&&o.push(t)}n[i.httpQuery]=o}else r.write([e,i],t),n[i.httpQuery]=r.flush()}async deserializeResponse(e,t,n){let r=this.deserializer,i=sw.of(e.output),a={};if(n.statusCode>=300){let i=await UC(n.body,t);throw i.byteLength>0&&Object.assign(a,await r.read(15,i)),await this.handleError(e,t,n,a,this.deserializeMetadata(n)),Error(`@smithy/core/protocols - HTTP Protocol error handler failed to throw.`)}for(let e in n.headers){let t=n.headers[e];delete n.headers[e],n.headers[e.toLowerCase()]=t}let o=await this.deserializeHttpMessage(i,t,n,a);if(o.length){let e=await UC(n.body,t);if(e.byteLength>0){let t=await r.read(i,e);for(let e of o)t[e]!=null&&(a[e]=t[e])}}else o.discardResponseBody&&await UC(n.body,t);return a.$metadata=this.deserializeMetadata(n),a}async deserializeHttpMessage(e,t,n,r,i){let a;a=r instanceof Set?i:r;let o=!0,s=this.deserializer,c=sw.of(e),l=[];for(let[e,r]of c.structIterator()){let i=r.getMemberTraits();if(i.httpPayload){if(o=!1,r.isStreaming())r.isStructSchema()?a[e]=await this.deserializeEventStream({response:n,responseSchema:c}):a[e]=VC(n.body);else if(n.body){let i=await UC(n.body,t);i.byteLength>0&&(a[e]=await s.read(r,i))}}else if(i.httpHeader){let t=String(i.httpHeader).toLowerCase(),o=n.headers[t];if(o!=null)if(r.isListSchema()){let n=r.getValueSchema();n.getMergedTraits().httpHeader=t;let i;i=n.isTimestampSchema()&&n.getSchema()===4?uT(o,`,`,2):dT(o);let c=[];for(let e of i)c.push(await s.read(n,e.trim()));a[e]=c}else a[e]=await s.read(r,o)}else if(i.httpPrefixHeaders!==void 0){a[e]={};for(let t in n.headers)if(t.startsWith(i.httpPrefixHeaders)){let o=n.headers[t],c=r.getValueSchema();c.getMergedTraits().httpHeader=t,a[e][t.slice(i.httpPrefixHeaders.length)]=await s.read(c,o)}}else i.httpResponseCode?a[e]=n.statusCode:l.push(e)}return l.discardResponseBody=o,l}},xT=class extends yT{async serializeRequest(e,t,n){let r=this.serializer,i={},a={},o=await n.endpoint(),s=sw.of(e?.input),c=s.getSchema(),l,u=t&&typeof t==`object`?t:{},d=new Wx({protocol:``,hostname:``,port:void 0,path:`/`,fragment:void 0,query:i,headers:a,body:void 0});if(o&&(this.updateServiceEndpoint(d,o),this.setHostPrefix(d,e,u)),u){let e=s.getEventStreamMember();if(e){if(u[e]){let t={};for(let[n,i]of s.structIterator())n!==e&&u[n]&&(r.write(i,u[n]),t[n]=r.flush());l=await this.serializeEventStream({eventStream:u[e],requestSchema:s,initialRequest:t})}}else r.write(c,u),l=r.flush()}return d.headers=Object.assign(d.headers,a),d.query=i,d.body=l,d.method=`POST`,d}async deserializeResponse(e,t,n){let r=this.deserializer,i=sw.of(e.output),a={};if(n.statusCode>=300){let i=await UC(n.body,t);throw i.byteLength>0&&Object.assign(a,await r.read(15,i)),await this.handleError(e,t,n,a,this.deserializeMetadata(n)),Error(`@smithy/core/protocols - RPC Protocol error handler failed to throw.`)}for(let e in n.headers){let t=n.headers[e];delete n.headers[e],n.headers[e.toLowerCase()]=t}let o=i.getEventStreamMember();if(o)a[o]=await this.deserializeEventStream({response:n,responseSchema:i,initialResponseContainer:a});else{let e=await UC(n.body,t);e.byteLength>0&&Object.assign(a,await r.read(i,e))}return a.$metadata=this.deserializeMetadata(n),a}};function ST(e,t){if(t.timestampFormat.useTrait&&e.isTimestampSchema()&&(e.getSchema()===5||e.getSchema()===6||e.getSchema()===7))return e.getSchema();let{httpLabel:n,httpPrefixHeaders:r,httpHeader:i,httpQuery:a}=e.getMergedTraits();return(t.httpBindings?typeof r==`string`||i?6:a||n?5:void 0:void 0)??t.timestampFormat.default}var CT=class extends mT{settings;constructor(e){super(),this.settings=e}read(e,t){let n=sw.of(e);if(n.isListSchema())return dT(t).map(e=>this.read(n.getValueSchema(),e));if(n.isBlobSchema())return(this.serdeContext?.base64Decoder??TC)(t);if(n.isTimestampSchema())switch(ST(n,this.settings)){case 5:return sT(t);case 6:return cT(t);case 7:return oT(t);default:return console.warn(`Missing timestamp format, parsing value with Date constructor:`,t),new Date(t)}if(n.isStringSchema()){let e=n.getMergedTraits().mediaType,r=t;if(e)return n.getMergedTraits().httpHeader&&(r=this.base64ToUtf8(r)),(e===`application/json`||e.endsWith(`+json`))&&(r=Jw.from(r)),r}return n.isNumericSchema()?Number(t):n.isBigIntegerSchema()?BigInt(t):n.isBigDecimalSchema()?new pT(t,`bigDecimal`):n.isBooleanSchema()?String(t).toLowerCase()===`true`:t}base64ToUtf8(e){return(this.serdeContext?.utf8Encoder??$x)((this.serdeContext?.base64Decoder??TC)(e))}},wT=class extends mT{codecDeserializer;stringDeserializer;constructor(e,t){super(),this.codecDeserializer=e,this.stringDeserializer=new CT(t)}setSerdeContext(e){this.stringDeserializer.setSerdeContext(e),this.codecDeserializer.setSerdeContext(e),this.serdeContext=e}read(e,t){let n=sw.of(e),r=n.getMergedTraits(),i=this.serdeContext?.utf8Encoder??$x;if(r.httpHeader||r.httpResponseCode)return this.stringDeserializer.read(n,i(t));if(r.httpPayload){if(n.isBlobSchema()){let e=this.serdeContext?.utf8Decoder??Zx;return typeof t==`string`?e(t):t}else if(n.isStringSchema())return`byteLength`in t?i(t):t}return this.codecDeserializer.read(n,t)}},TT=class extends mT{settings;stringBuffer=``;constructor(e){super(),this.settings=e}write(e,t){let n=sw.of(e);switch(typeof t){case`object`:if(t===null){this.stringBuffer=`null`;return}if(n.isTimestampSchema()){if(!(t instanceof Date))throw Error(`@smithy/core/protocols - received non-Date value ${t} when schema expected Date in ${n.getName(!0)}`);switch(ST(n,this.settings)){case 5:this.stringBuffer=t.toISOString().replace(`.000Z`,`Z`);break;case 6:this.stringBuffer=kw(t);break;case 7:this.stringBuffer=String(t.getTime()/1e3);break;default:console.warn(`Missing timestamp format, using epoch seconds`,t),this.stringBuffer=String(t.getTime()/1e3)}return}if(n.isBlobSchema()&&`byteLength`in t){this.stringBuffer=(this.serdeContext?.base64Encoder??EC)(t);return}if(n.isListSchema()&&Array.isArray(t)){let e=``;for(let r of t){this.write([n.getValueSchema(),n.getMergedTraits()],r);let t=this.flush(),i=n.getValueSchema().isTimestampSchema()?t:Yw(t);e!==``&&(e+=`, `),e+=i}this.stringBuffer=e;return}this.stringBuffer=JSON.stringify(t,null,2);break;case`string`:let e=n.getMergedTraits().mediaType,r=t;if(e&&((e===`application/json`||e.endsWith(`+json`))&&(r=Jw.from(r)),n.getMergedTraits().httpHeader)){this.stringBuffer=(this.serdeContext?.base64Encoder??EC)(r.toString());return}this.stringBuffer=t;break;default:n.isIdempotencyToken()?this.stringBuffer=qw():this.stringBuffer=String(t)}}flush(){let e=this.stringBuffer;return this.stringBuffer=``,e}},ET=class{codecSerializer;stringSerializer;buffer;constructor(e,t,n=new TT(t)){this.codecSerializer=e,this.stringSerializer=n}setSerdeContext(e){this.codecSerializer.setSerdeContext(e),this.stringSerializer.setSerdeContext(e)}write(e,t){let n=sw.of(e),r=n.getMergedTraits();if(r.httpHeader||r.httpLabel||r.httpQuery){this.stringSerializer.write(n,t),this.buffer=this.stringSerializer.flush();return}return this.codecSerializer.write(n,t)}flush(){if(this.buffer!==void 0){let e=this.buffer;return this.buffer=void 0,e}return this.codecSerializer.flush()}};function DT(e,t,n){e.__smithy_context?e.__smithy_context.features||(e.__smithy_context.features={}):e.__smithy_context={features:{}},e.__smithy_context.features[t]=n}var OT=class{authSchemes=new Map;constructor(e){for(let t in e){let n=e[t];n!==void 0&&this.authSchemes.set(t,n)}}getIdentityProvider(e){return this.authSchemes.get(e)}},kT=(e=>function(t){return AT(t)&&t.expiration.getTime()-Date.now()e.expiration!==void 0,jT=(e,t,n)=>{if(e===void 0)return;let r=typeof e==`function`?e:async()=>Promise.resolve(e),i,a,o,s=!1,c=async e=>{a||=r(e);try{i=await a,o=!0,s=!1}finally{a=void 0}return i};return t===void 0?async e=>((!o||e?.forceRefresh)&&(i=await c(e)),i):async e=>((!o||e?.forceRefresh)&&(i=await c(e)),s?i:n(i)?(t(i)&&await c(e),i):(s=!0,i))};function MT(e){return e===void 0?!0:typeof e==`string`&&e.length<=50}function NT(e){let t=xC(e.userAgentAppId??void 0),{customUserAgent:n}=e;return Object.assign(e,{customUserAgent:typeof n==`string`?[[n]]:n,userAgentAppId:async()=>{let n=await t();if(!MT(n)){let t=e.logger?.constructor?.name===`NoOpLogger`||!e.logger?console:e.logger;typeof n==`string`?n.length>50&&t?.warn(`The provided userAgentAppId exceeds the maximum length of 50 characters.`):t?.warn(`userAgentAppId must be a string or undefined.`)}return n}})}var PT=class e{nodes;root;conditions;results;constructor(e,t,n,r){this.nodes=e,this.root=t,this.conditions=n,this.results=r}static from(t,n,r,i){return new e(t,n,r,i)}},FT=class{capacity;data=new Map;parameters=[];constructor({size:e,params:t}){this.capacity=e??50,t&&(this.parameters=t)}get(e,t){let n=this.hash(e);if(n===!1)return t();if(!this.data.has(n)){if(this.data.size>this.capacity+10){let e=this.data.keys(),t=0;for(;;){let{value:n,done:r}=e.next();if(this.data.delete(n),r||++t>10)break}}this.data.set(n,t())}return this.data.get(n)}size(){return this.data.size}hash(e){let t=``,{parameters:n}=this;if(n.length===0)return!1;for(let r of n){let n=String(e[r]??``);if(n.includes(`|;`))return!1;t+=n+`|;`}return t}},IT=class extends Error{constructor(e){super(e),this.name=`EndpointError`}},LT=`endpoints`;function RT(e){return typeof e!=`object`||!e?e:`ref`in e?`$${RT(e.ref)}`:`fn`in e?`${e.fn}(${(e.argv||[]).map(RT).join(`, `)})`:JSON.stringify(e,null,2)}var zT={},BT=(e,t)=>e===t;function VT(...e){for(let t of e)if(t!=null)return t}var HT=e=>{let t=e.split(`.`),n=[];for(let r of t){let t=r.indexOf(`[`);if(t!==-1){if(r.indexOf(`]`)!==r.length-1)throw new IT(`Path: '${e}' does not end with ']'`);let i=r.slice(t+1,-1);if(Number.isNaN(parseInt(i)))throw new IT(`Invalid array index: '${i}' in path: '${e}'`);t!==0&&n.push(r.slice(0,t)),n.push(i)}else n.push(r)}return n},UT=(e,t)=>HT(t).reduce((n,r)=>{if(typeof n!=`object`)throw new IT(`Index '${r}' in '${t}' not found in '${JSON.stringify(e)}'`);if(Array.isArray(n)){let e=parseInt(r);return n[e<0?n.length+e:e]}return n[r]},e),WT=e=>e!=null,GT=RegExp(`^(?!.*-$)(?!-)[a-zA-Z0-9-]{1,63}$`),KT=(e,t=!1)=>{if(!t)return GT.test(e);let n=e.split(`.`);for(let e of n)if(!KT(e))return!1;return!0};function qT(e,t,n){return e?t:n}var JT=e=>!e,YT=RegExp(`^(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}$`),XT=e=>YT.test(e)||e.startsWith(`[`)&&e.endsWith(`]`),ZT={[Vx.HTTP]:80,[Vx.HTTPS]:443},QT=e=>{let t=(()=>{try{if(e instanceof URL)return e;if(typeof e==`object`&&`hostname`in e){let{hostname:t,port:n,protocol:r=``,path:i=``,query:a={}}=e,o=new URL(`${r}//${t}${n?`:${n}`:``}${i}`);return o.search=Object.entries(a).map(([e,t])=>`${e}=${t}`).join(`&`),o}return new URL(e)}catch{return null}})();if(!t)return console.error(`Unable to parse ${JSON.stringify(e)} as a whatwg URL.`),null;let n=t.href,{host:r,hostname:i,pathname:a,protocol:o,search:s}=t;if(s)return null;let c=o.slice(0,-1);if(!Object.values(Vx).includes(c))return null;let l=XT(i);return{scheme:c,authority:`${r}${n.includes(`${r}:${ZT[c]}`)||typeof e==`string`&&e.includes(`${r}:${ZT[c]}`)?`:${ZT[c]}`:``}`,path:a,normalizedPath:a.endsWith(`/`)?a:`${a}/`,isIp:l}};function $T(e,t,n){if(n===1)return[e];if(e===``)return[``];let r=e.split(t);return n===0?r:r.slice(0,n-1).concat(r.slice(1).join(t))}var eE={booleanEquals:BT,coalesce:VT,getAttr:UT,isSet:WT,isValidHostLabel:KT,ite:qT,not:JT,parseURL:QT,split:$T,stringEquals:(e,t)=>e===t,substring:(e,t,n,r)=>e==null||t>=n||e.lengthencodeURIComponent(e).replace(/[!*'()]/g,e=>`%${e.charCodeAt(0).toString(16).toUpperCase()}`)},tE=(e,t)=>{let n=[],{referenceRecord:r,endpointParams:i}=t,a=0;for(;at.referenceRecord[e]??t.endpointParams[e],rE=(e,t,n)=>{if(typeof e==`string`)return tE(e,n);if(e.fn)return aE.callFunction(e,n);if(e.ref)return nE(e,n);throw new IT(`'${t}': ${String(e)} is not a string, function or reference.`)},iE=({fn:e,argv:t},n)=>{let r=Array(t.length);for(let e=0;e{let{assign:n}=e;if(n&&n in t.referenceRecord)throw new IT(`'${n}' is already defined in Reference Record.`);let r=iE(e,t);t.logger?.debug?.(`${LT} evaluateCondition: ${RT(e)} = ${RT(r)}`);let i=r===``?!0:!!r;return n==null?{result:i}:{result:i,toAssign:{name:n,value:r}}},sE=(e,t)=>Object.entries(e??{}).reduce((e,[n,r])=>(e[n]=r.map(e=>{let r=rE(e,`Header value entry`,t);if(typeof r!=`string`)throw new IT(`Header '${n}' value '${r}' is not a string`);return r}),e),{}),cE=(e,t)=>Object.entries(e).reduce((e,[n,r])=>(e[n]=uE.getEndpointProperty(r,t),e),{}),lE=(e,t)=>{if(Array.isArray(e))return e.map(e=>lE(e,t));switch(typeof e){case`string`:return tE(e,t);case`object`:if(e===null)throw new IT(`Unexpected endpoint property: ${e}`);return uE.getEndpointProperties(e,t);case`boolean`:return e;default:throw new IT(`Unexpected endpoint property type: ${typeof e}`)}},uE={getEndpointProperty:lE,getEndpointProperties:cE},dE=(e,t)=>{let n=rE(e,`Endpoint URL`,t);if(typeof n==`string`)try{return new URL(n)}catch(e){throw console.error(`Failed to construct URL with ${n}`,e),e}throw new IT(`Endpoint URL must be a string, got ${typeof n}`)},fE=1e8,pE=(e,t)=>{let{nodes:n,root:r,results:i,conditions:a}=e,o=r,s={},c={referenceRecord:s,endpointParams:t.endpointParams,logger:t.logger};for(;o!==1&&o!==-1&&o=0===f.result?r:i}if(o>=fE){let e=i[o-fE];if(e[0]===-1){let[,t]=e;throw new IT(rE(t,`Error`,c))}let[t,n,r]=e;return{url:dE(t,c),properties:cE(n,c),headers:sE(r??{},c)}}throw new IT(`No matching endpoint.`)},mE=(e,t=!1)=>{if(t){for(let t of e.split(`.`))if(!mE(t))return!1;return!0}return!(!KT(e)||e.length<3||e.length>63||e!==e.toLowerCase()||XT(e))},hE=`:`,gE=`/`,_E=e=>{let t=e.split(hE);if(t.length<6)return null;let[n,r,i,a,o,...s]=t;return n!==`arn`||r===``||i===``||s.join(hE)===``?null:{partition:r,service:i,region:a,accountId:o,resourceId:s.map(e=>e.split(gE)).flat()}},vE={partitions:[{id:`aws`,outputs:{dnsSuffix:`amazonaws.com`,dualStackDnsSuffix:`api.aws`,implicitGlobalRegion:`us-east-1`,name:`aws`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^(us|eu|ap|sa|ca|me|af|il|mx)\\-\\w+\\-\\d+$`,regions:{"af-south-1":{description:`Africa (Cape Town)`},"ap-east-1":{description:`Asia Pacific (Hong Kong)`},"ap-east-2":{description:`Asia Pacific (Taipei)`},"ap-northeast-1":{description:`Asia Pacific (Tokyo)`},"ap-northeast-2":{description:`Asia Pacific (Seoul)`},"ap-northeast-3":{description:`Asia Pacific (Osaka)`},"ap-south-1":{description:`Asia Pacific (Mumbai)`},"ap-south-2":{description:`Asia Pacific (Hyderabad)`},"ap-southeast-1":{description:`Asia Pacific (Singapore)`},"ap-southeast-2":{description:`Asia Pacific (Sydney)`},"ap-southeast-3":{description:`Asia Pacific (Jakarta)`},"ap-southeast-4":{description:`Asia Pacific (Melbourne)`},"ap-southeast-5":{description:`Asia Pacific (Malaysia)`},"ap-southeast-6":{description:`Asia Pacific (New Zealand)`},"ap-southeast-7":{description:`Asia Pacific (Thailand)`},"aws-global":{description:`aws global region`},"ca-central-1":{description:`Canada (Central)`},"ca-west-1":{description:`Canada West (Calgary)`},"eu-central-1":{description:`Europe (Frankfurt)`},"eu-central-2":{description:`Europe (Zurich)`},"eu-north-1":{description:`Europe (Stockholm)`},"eu-south-1":{description:`Europe (Milan)`},"eu-south-2":{description:`Europe (Spain)`},"eu-west-1":{description:`Europe (Ireland)`},"eu-west-2":{description:`Europe (London)`},"eu-west-3":{description:`Europe (Paris)`},"il-central-1":{description:`Israel (Tel Aviv)`},"me-central-1":{description:`Middle East (UAE)`},"me-south-1":{description:`Middle East (Bahrain)`},"mx-central-1":{description:`Mexico (Central)`},"sa-east-1":{description:`South America (Sao Paulo)`},"us-east-1":{description:`US East (N. Virginia)`},"us-east-2":{description:`US East (Ohio)`},"us-west-1":{description:`US West (N. California)`},"us-west-2":{description:`US West (Oregon)`}}},{id:`aws-cn`,outputs:{dnsSuffix:`amazonaws.com.cn`,dualStackDnsSuffix:`api.amazonwebservices.com.cn`,implicitGlobalRegion:`cn-northwest-1`,name:`aws-cn`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^cn\\-\\w+\\-\\d+$`,regions:{"aws-cn-global":{description:`aws-cn global region`},"cn-north-1":{description:`China (Beijing)`},"cn-northwest-1":{description:`China (Ningxia)`}}},{id:`aws-eusc`,outputs:{dnsSuffix:`amazonaws.eu`,dualStackDnsSuffix:`api.amazonwebservices.eu`,implicitGlobalRegion:`eusc-de-east-1`,name:`aws-eusc`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^eusc\\-(de)\\-\\w+\\-\\d+$`,regions:{"eusc-de-east-1":{description:`AWS European Sovereign Cloud (Germany)`}}},{id:`aws-iso`,outputs:{dnsSuffix:`c2s.ic.gov`,dualStackDnsSuffix:`api.aws.ic.gov`,implicitGlobalRegion:`us-iso-east-1`,name:`aws-iso`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^us\\-iso\\-\\w+\\-\\d+$`,regions:{"aws-iso-global":{description:`aws-iso global region`},"us-iso-east-1":{description:`US ISO East`},"us-iso-west-1":{description:`US ISO WEST`}}},{id:`aws-iso-b`,outputs:{dnsSuffix:`sc2s.sgov.gov`,dualStackDnsSuffix:`api.aws.scloud`,implicitGlobalRegion:`us-isob-east-1`,name:`aws-iso-b`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^us\\-isob\\-\\w+\\-\\d+$`,regions:{"aws-iso-b-global":{description:`aws-iso-b global region`},"us-isob-east-1":{description:`US ISOB East (Ohio)`},"us-isob-west-1":{description:`US ISOB West`}}},{id:`aws-iso-e`,outputs:{dnsSuffix:`cloud.adc-e.uk`,dualStackDnsSuffix:`api.cloud-aws.adc-e.uk`,implicitGlobalRegion:`eu-isoe-west-1`,name:`aws-iso-e`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^eu\\-isoe\\-\\w+\\-\\d+$`,regions:{"aws-iso-e-global":{description:`aws-iso-e global region`},"eu-isoe-west-1":{description:`EU ISOE West`}}},{id:`aws-iso-f`,outputs:{dnsSuffix:`csp.hci.ic.gov`,dualStackDnsSuffix:`api.aws.hci.ic.gov`,implicitGlobalRegion:`us-isof-south-1`,name:`aws-iso-f`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^us\\-isof\\-\\w+\\-\\d+$`,regions:{"aws-iso-f-global":{description:`aws-iso-f global region`},"us-isof-east-1":{description:`US ISOF EAST`},"us-isof-south-1":{description:`US ISOF SOUTH`}}},{id:`aws-us-gov`,outputs:{dnsSuffix:`amazonaws.com`,dualStackDnsSuffix:`api.aws`,implicitGlobalRegion:`us-gov-west-1`,name:`aws-us-gov`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^us\\-gov\\-\\w+\\-\\d+$`,regions:{"aws-us-gov-global":{description:`aws-us-gov global region`},"us-gov-east-1":{description:`AWS GovCloud (US-East)`},"us-gov-west-1":{description:`AWS GovCloud (US-West)`}}}],version:`1.1`},yE=``,bE=e=>{let{partitions:t}=vE;for(let n of t){let{regions:t,outputs:r}=n;for(let[n,i]of Object.entries(t))if(n===e)return{...r,...i}}for(let n of t){let{regionRegex:t,outputs:r}=n;if(new RegExp(t).test(e))return{...r}}let n=t.find(e=>e.id===`aws`);if(!n)throw Error(`Provided region was not found in the partition array or regex, and default partition with id 'aws' doesn't exist.`);return{...n.outputs}},xE=()=>yE,SE={isVirtualHostableS3Bucket:mE,parseArn:_E,partition:bE};zT.aws=SE;function CE(e,t,n){return e.$source||={},e.$source[t]=n,e}var wE;(function(e){e.STANDARD=`standard`,e.ADAPTIVE=`adaptive`})(wE||={});var TE=wE.STANDARD,EE=[`BandwidthLimitExceeded`,`EC2ThrottledException`,`LimitExceededException`,`PriorRequestNotComplete`,`ProvisionedThroughputExceededException`,`RequestLimitExceeded`,`RequestThrottled`,`RequestThrottledException`,`SlowDown`,`ThrottledException`,`Throttling`,`ThrottlingException`,`TooManyRequestsException`,`TransactionInProgressException`],DE=[`TimeoutError`,`RequestTimeout`,`RequestTimeoutException`],OE=[500,502,503,504],kE=[`ECONNRESET`,`ECONNREFUSED`,`EPIPE`,`ETIMEDOUT`],AE=[`EHOSTUNREACH`,`ENETUNREACH`,`ENOTFOUND`],jE=e=>e?.$retryable!==void 0,ME=e=>e.$metadata?.clockSkewCorrected,NE=e=>{let t=new Set([`Failed to fetch`,`NetworkError when attempting to fetch resource`,`The Internet connection appears to be offline`,`Load failed`,`Network request failed`]);return e&&e instanceof TypeError?t.has(e.message):!1},PE=e=>e.$metadata?.httpStatusCode===429||EE.includes(e.name)||e.$retryable?.throttling==1,FE=(e,t=0)=>jE(e)||ME(e)||e.name===`InvalidSignatureException`&&e.message?.includes(`Signature expired`)||DE.includes(e.name)||kE.includes(e?.code||``)||AE.includes(e?.code||``)||OE.includes(e.$metadata?.httpStatusCode||0)||NE(e)||LE(e)||e.cause!==void 0&&t<=10&&FE(e.cause,t+1),IE=e=>{if(e.$metadata?.httpStatusCode!==void 0){let t=e.$metadata.httpStatusCode;return 500<=t&&t<=599&&!FE(e)}return!1};function LE(e){return e.code===`ERR_HTTP2_STREAM_ERROR`&&e.message.includes(`NGHTTP2_REFUSED_STREAM`)}var RE=class e{static setTimeoutFn=setTimeout;beta;minCapacity;minFillRate;scaleConstant;smooth;enabled=!1;availableTokens=0;lastMaxRate=0;measuredTxRate=0;requestCount=0;fillRate;lastThrottleTime;lastTimestamp=0;lastTxRateBucket;maxCapacity;timeWindow=0;constructor(e){this.beta=e?.beta??.7,this.minCapacity=e?.minCapacity??1,this.minFillRate=e?.minFillRate??.5,this.scaleConstant=e?.scaleConstant??.4,this.smooth=e?.smooth??.8,this.lastThrottleTime=this.getCurrentTimeInSeconds(),this.lastTxRateBucket=Math.floor(this.getCurrentTimeInSeconds()),this.fillRate=this.minFillRate,this.maxCapacity=this.minCapacity}async getSendToken(){return this.acquireTokenBucket(1)}updateClientSendingRate(e){let t;this.updateMeasuredRate();let n=e;if(n?.errorType===`THROTTLING`||PE(n?.error??e)){let e=this.enabled?Math.min(this.measuredTxRate,this.fillRate):this.measuredTxRate;this.lastMaxRate=e,this.calculateTimeWindow(),this.lastThrottleTime=this.getCurrentTimeInSeconds(),t=this.cubicThrottle(e),this.enableTokenBucket()}else this.calculateTimeWindow(),t=this.cubicSuccess(this.getCurrentTimeInSeconds());let r=Math.min(t,2*this.measuredTxRate);this.updateTokenBucketRate(r)}getCurrentTimeInSeconds(){return Date.now()/1e3}async acquireTokenBucket(t){if(this.enabled){for(this.refillTokenBucket();t>this.availableTokens;){let n=(t-this.availableTokens)/this.fillRate*1e3;await new Promise(t=>e.setTimeoutFn(t,n)),this.refillTokenBucket()}this.availableTokens-=t}}refillTokenBucket(){let e=this.getCurrentTimeInSeconds();if(!this.lastTimestamp){this.lastTimestamp=e;return}let t=(e-this.lastTimestamp)*this.fillRate;this.availableTokens=Math.min(this.maxCapacity,this.availableTokens+t),this.lastTimestamp=e}calculateTimeWindow(){this.timeWindow=this.getPrecise((this.lastMaxRate*(1-this.beta)/this.scaleConstant)**(1/3))}cubicThrottle(e){return this.getPrecise(e*this.beta)}cubicSuccess(e){return this.getPrecise(this.scaleConstant*(e-this.lastThrottleTime-this.timeWindow)**3+this.lastMaxRate)}enableTokenBucket(){this.enabled=!0}updateTokenBucketRate(e){this.refillTokenBucket(),this.fillRate=Math.max(e,this.minFillRate),this.maxCapacity=Math.max(e,this.minCapacity),this.availableTokens=Math.min(this.availableTokens,this.maxCapacity)}updateMeasuredRate(){let e=this.getCurrentTimeInSeconds(),t=Math.floor(e*2)/2;if(this.requestCount++,t>this.lastTxRateBucket){let e=this.requestCount/(t-this.lastTxRateBucket);this.measuredTxRate=this.getPrecise(e*this.smooth+this.measuredTxRate*(1-this.smooth)),this.requestCount=0,this.lastTxRateBucket=t}}getPrecise(e){return parseFloat(e.toFixed(8))}},zE=20*1e3,BE=`amz-sdk-invocation-id`,VE=`amz-sdk-request`,HE=class e{static v2026=typeof process<`u`&&{}?.SMITHY_NEW_RETRIES_2026===`true`;static delay(){return e.v2026?50:100}static throttlingDelay(){return e.v2026?1e3:500}static cost(){return e.v2026?14:5}static throttlingCost(){return e.v2026?5:10}static modifiedCostType(){return e.v2026?`THROTTLING`:`TRANSIENT`}},UE=class{x=HE.delay();computeNextBackoffDelay(e){let t=Math.random()*Math.min(this.x*2**e,zE);return Math.floor(t)}setDelayBase(e){this.x=e}},WE=class{delay;count;cost;longPoll;constructor(e,t,n,r){this.delay=e,this.count=t,this.cost=n,this.longPoll=r}getRetryCount(){return this.count}getRetryDelay(){return Math.min(zE,this.delay)}getRetryCost(){return this.cost}isLongPoll(){return this.longPoll}},GE={incompatible:1,attempts:2,capacity:3},KE=class{mode=wE.STANDARD;capacity=500;retryBackoffStrategy;maxAttemptsProvider;baseDelay;constructor(e){typeof e==`number`?this.maxAttemptsProvider=async()=>e:typeof e==`function`?this.maxAttemptsProvider=e:e&&typeof e==`object`&&(this.maxAttemptsProvider=async()=>e.maxAttempts,this.baseDelay=e.baseDelay,this.retryBackoffStrategy=e.backoff),this.maxAttemptsProvider??=async()=>3,this.baseDelay??=HE.delay(),this.retryBackoffStrategy??=new UE}async acquireInitialRetryToken(e){return new WE(HE.delay(),0,void 0,HE.v2026&&e.includes(`:longpoll`))}async refreshRetryTokenForRetry(e,t){let n=await this.getMaxAttempts(),r=this.retryCode(e,t,n),i=r===0,a=e.isLongPoll?.();if(i||a){let n=t.errorType;this.retryBackoffStrategy.setDelayBase(n===`THROTTLING`?HE.throttlingDelay():this.baseDelay);let o=this.retryBackoffStrategy.computeNextBackoffDelay(e.getRetryCount()),s=o;if(t.retryAfterHint instanceof Date&&(s=Math.max(o,Math.min(t.retryAfterHint.getTime()-Date.now(),o+5e3))),i){let t=this.getCapacityCost(n);return this.capacity-=t,new WE(s,e.getRetryCount()+1,t,e.isLongPoll?.()??!1)}else throw Object.assign(Error(`No retry token available`),{$backoff:HE.v2026&&r===GE.capacity&&a?s:0})}throw Error(`No retry token available`)}recordSuccess(e){this.capacity=Math.min(500,this.capacity+(e.getRetryCost()??1))}getCapacity(){return this.capacity}async maxAttempts(){return this.maxAttemptsProvider()}async getMaxAttempts(){try{return await this.maxAttemptsProvider()}catch{return console.warn(`Max attempts provider could not resolve. Using default of 3`),3}}retryCode(e,t,n){let r=e.getRetryCount()+1,i=this.isRetryableError(t.errorType)?0:GE.incompatible,a=r=this.getCapacityCost(t.errorType)?0:GE.capacity;return i||a||o}getCapacityCost(e){return e===HE.modifiedCostType()?HE.throttlingCost():HE.cost()}isRetryableError(e){return e===`THROTTLING`||e===`TRANSIENT`}},qE=class{mode=wE.ADAPTIVE;rateLimiter;standardRetryStrategy;constructor(e,t){let{rateLimiter:n}=t??{};this.rateLimiter=n??new RE,this.standardRetryStrategy=t?new KE({maxAttempts:typeof e==`number`?e:3,...t}):new KE(e)}async acquireInitialRetryToken(e){let t=await this.standardRetryStrategy.acquireInitialRetryToken(e);return await this.rateLimiter.getSendToken(),t}async refreshRetryTokenForRetry(e,t){this.rateLimiter.updateClientSendingRate(t);let n=await this.standardRetryStrategy.refreshRetryTokenForRetry(e,t);return await this.rateLimiter.getSendToken(),n}recordSuccess(e){this.rateLimiter.updateClientSendingRate({}),this.standardRetryStrategy.recordSuccess(e)}async maxAttemptsProvider(){return this.standardRetryStrategy.maxAttempts()}};HE.v2026||=typeof process==`object`&&{}?.AWS_NEW_RETRIES_2026===`true`;function JE(e,t,n){e.__aws_sdk_context?e.__aws_sdk_context.features||(e.__aws_sdk_context.features={}):e.__aws_sdk_context={features:{}},e.__aws_sdk_context.features[t]=n}var YE=/\d{12}\.ddb/;async function XE(e,t,n){if(n.request?.headers?.[`smithy-protocol`]===`rpc-v2-cbor`&&JE(e,`PROTOCOL_RPC_V2_CBOR`,`M`),typeof t.retryStrategy==`function`){let n=await t.retryStrategy();if(typeof n.mode==`string`)switch(n.mode){case wE.ADAPTIVE:JE(e,`RETRY_MODE_ADAPTIVE`,`F`);break;case wE.STANDARD:JE(e,`RETRY_MODE_STANDARD`,`E`);break}}if(typeof t.accountIdEndpointMode==`function`){let n=e.endpointV2;switch(String(n?.url?.hostname).match(YE)&&JE(e,`ACCOUNT_ID_ENDPOINT`,`O`),await t.accountIdEndpointMode?.()){case`disabled`:JE(e,`ACCOUNT_ID_MODE_DISABLED`,`Q`);break;case`preferred`:JE(e,`ACCOUNT_ID_MODE_PREFERRED`,`P`);break;case`required`:JE(e,`ACCOUNT_ID_MODE_REQUIRED`,`R`);break}}let r=e.__smithy_context?.selectedHttpAuthScheme?.identity;if(r?.$source){let t=r;t.accountId&&JE(e,`RESOLVED_ACCOUNT_ID`,`T`);for(let[n,r]of Object.entries(t.$source??{}))JE(e,n,r)}}var ZE=`user-agent`,QE=`x-amz-user-agent`,$E=/[^!$%&'*+\-.^_`|~\w]/g,eD=/[^!$%&'*+\-.^_`|~\w#]/g,tD=1024;function Sre(e){let t=``;for(let n in e){let r=e[n];if(t.length+r.length+1<=tD){t.length?t+=`,`+r:t+=r;continue}break}return t}var Cre=e=>(t,n)=>async r=>{let{request:i}=r;if(!Wx.isInstance(i))return t(r);let{headers:a}=i,o=n?.userAgent?.map(nD)||[],s=(await e.defaultUserAgentProvider()).map(nD);await XE(n,e,r);let c=n;s.push(`m/${Sre(Object.assign({},n.__smithy_context?.features,c.__aws_sdk_context?.features))}`);let l=e?.customUserAgent?.map(nD)||[],u=await e.userAgentAppId();u&&s.push(nD([`app`,`${u}`]));let d=xE(),f=(d?[d]:[]).concat([...s,...o,...l]).join(` `),p=[...s.filter(e=>e.startsWith(`aws-sdk-`)),...l].join(` `);return e.runtime===`browser`?a[QE]=f:(p&&(a[QE]=a[`x-amz-user-agent`]?`${a[ZE]} ${p}`:p),a[ZE]=f),t({...r,request:i})},nD=e=>{let t=e[0].split(`/`).map(e=>e.replace($E,`-`)).join(`/`),n=e[1]?.replace(eD,`-`),r=t.indexOf(`/`),i=t.substring(0,r),a=t.substring(r+1);return i===`api`&&(a=a.toLowerCase()),[i,a,n].filter(e=>e&&e.length>0).reduce((e,t,n)=>{switch(n){case 0:return t;case 1:return`${e}/${t}`;default:return`${e}#${t}`}},``)},wre={name:`getUserAgentMiddleware`,step:`build`,priority:`low`,tags:[`SET_USER_AGENT`,`USER_AGENT`],override:!0},rD=e=>({applyToStack:t=>{t.add(Cre(e),wre)}}),iD=new Set,Tre=(e,t=KT)=>{if(!iD.has(e)&&!t(e))if(e===`*`)console.warn(`@smithy/config-resolver WARN - Please use the caller region instead of "*". See "sigv4a" in https://github.com/aws/aws-sdk-js-v3/blob/main/supplemental-docs/CLIENTS.md.`);else throw Error(`Region not accepted: region="${e}" is not a valid hostname component.`);else iD.add(e)},aD=e=>typeof e==`string`&&(e.startsWith(`fips-`)||e.endsWith(`-fips`)),Ere=e=>aD(e)?[`fips-aws-global`,`aws-fips`].includes(e)?`us-east-1`:e.replace(/fips-(dkr-|prod-)?|-fips/,``):e,oD=e=>{let{region:t,useFipsEndpoint:n}=e;if(!t)throw Error(`Region is missing`);return Object.assign(e,{region:async()=>{let e=Ere(typeof t==`function`?await t():t);return Tre(e),e},useFipsEndpoint:async()=>aD(typeof t==`string`?t:await t())?!0:typeof n==`function`?n():Promise.resolve(!!n)})},sD=`content-length`;function Dre(e){return t=>async n=>{let r=n.request;if(Wx.isInstance(r)){let{body:t,headers:n}=r;if(t&&Object.keys(n).map(e=>e.toLowerCase()).indexOf(sD)===-1)try{let n=e(t);r.headers={...r.headers,[sD]:String(n)}}catch{}}return t({...n,request:r})}}var Ore={step:`build`,tags:[`SET_CONTENT_LENGTH`,`CONTENT_LENGTH`],name:`contentLengthMiddleware`,override:!0},cD=e=>({applyToStack:t=>{t.add(Dre(e.bodyLengthChecker),Ore)}}),kre=async e=>{let t=e?.Bucket||``;if(typeof e.Bucket==`string`&&(e.Bucket=t.replace(/#/g,`%23`).replace(/\?/g,`%3F`)),Pre(t)){if(e.ForcePathStyle===!0)throw Error(`Path-style addressing cannot be used with ARN buckets`)}else (!Nre(t)||t.indexOf(`.`)!==-1&&!String(e.Endpoint).startsWith(`http:`)||t.toLowerCase()!==t||t.length<3)&&(e.ForcePathStyle=!0);return e.DisableMultiRegionAccessPoints&&(e.disableMultiRegionAccessPoints=!0,e.DisableMRAP=!0),e},Are=/^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$/,jre=/(\d+\.){3}\d+/,Mre=/\.\./,Nre=e=>Are.test(e)&&!jre.test(e)&&!Mre.test(e),Pre=e=>{let[t,n,r,,,i]=e.split(`:`),a=t===`arn`&&e.split(`:`).length>=6,o=!!(a&&n&&r&&i);if(a&&!o)throw Error(`Invalid ARN: ${e} was an invalid ARN.`);return o},Fre=(e,t,n,r=!1)=>{let i=async()=>{let i;return i=r?n.clientContextParams?.[e]??n[e]??n[t]:n[e]??n[t],typeof i==`function`?i():i};return e===`credentialScope`||t===`CredentialScope`?async()=>{let e=typeof n.credentials==`function`?await n.credentials():n.credentials;return e?.credentialScope??e?.CredentialScope}:e===`accountId`||t===`AccountId`?async()=>{let e=typeof n.credentials==`function`?await n.credentials():n.credentials;return e?.accountId??e?.AccountId}:e===`endpoint`||t===`endpoint`?async()=>{if(n.isCustomEndpoint===!1)return;let e=await i();if(e&&typeof e==`object`){if(`url`in e)return e.url.href;if(`hostname`in e){let{protocol:t,hostname:n,port:r,path:i}=e;return`${t}//${n}${r?`:`+r:``}${i}`}}return e}:i},lD=async e=>void 0,uD=e=>{if(typeof e==`object`){if(`url`in e){let t=XC(e.url);if(e.headers){t.headers={};for(let[n,r]of Object.entries(e.headers))t.headers[n.toLowerCase()]=r.join(`, `)}return t}return e}return XC(e)},dD=async(e,t,n,r)=>{if(!n.isCustomEndpoint){let e;e=n.serviceConfiguredEndpoint?await n.serviceConfiguredEndpoint():await lD(n.serviceId),e&&(n.endpoint=()=>Promise.resolve(uD(e)),n.isCustomEndpoint=!0)}let i=await fD(e,t,n);if(typeof n.endpointProvider!=`function`)throw Error(`config.endpointProvider is not set.`);let a=n.endpointProvider(i,r);if(n.isCustomEndpoint&&n.endpoint){let e=await n.endpoint();if(e?.headers){a.headers??={};for(let[t,n]of Object.entries(e.headers))a.headers[t]=Array.isArray(n)?n:[n]}}return a},fD=async(e,t,n)=>{let r={},i=t?.getEndpointParameterInstructions?.()||{};for(let[t,a]of Object.entries(i))switch(a.type){case`staticContextParams`:r[t]=a.value;break;case`contextParams`:r[t]=e[a.name];break;case`clientContextParams`:case`builtInParams`:r[t]=await Fre(a.name,t,n,a.type!==`builtInParams`)();break;case`operationContextParams`:r[t]=a.get(e);break;default:throw Error(`Unrecognized endpoint parameter instruction: `+JSON.stringify(a))}return Object.keys(i).length===0&&Object.assign(r,n),String(n.serviceId).toLowerCase()===`s3`&&await kre(r),r},Ire=({config:e,instructions:t})=>(n,r)=>async i=>{e.isCustomEndpoint&&DT(r,`ENDPOINT_OVERRIDE`,`N`);let a=await dD(i.input,{getEndpointParameterInstructions(){return t}},{...e},r);r.endpointV2=a,r.authSchemes=a.properties?.authSchemes;let o=r.authSchemes?.[0];if(o){r.signing_region=o.signingRegion,r.signing_service=o.signingName;let e=FS(r)?.selectedHttpAuthScheme?.httpAuthOption;e&&(e.signingProperties=Object.assign(e.signingProperties||{},{signing_region:o.signingRegion,signingRegion:o.signingRegion,signing_service:o.signingName,signingName:o.signingName,signingRegionSet:o.signingRegionSet},o.properties))}return n({...i})},Lre={step:`serialize`,tags:[`ENDPOINT_PARAMETERS`,`ENDPOINT_V2`,`ENDPOINT`],name:`endpointV2Middleware`,override:!0,relation:`before`,toMiddleware:{name:`serializerMiddleware`,step:`serialize`,tags:[`SERIALIZER`],override:!0}.name},pD=(e,t)=>({applyToStack:n=>{n.addRelativeTo(Ire({config:e,instructions:t}),Lre)}}),mD=e=>{let t=e.tls??!0,{endpoint:n,useDualstackEndpoint:r,useFipsEndpoint:i}=e,a=Object.assign(e,{endpoint:n==null?void 0:async()=>uD(await IS(n)()),tls:t,isCustomEndpoint:!!n,useDualstackEndpoint:IS(r??!1),useFipsEndpoint:IS(i??!1)}),o;return a.serviceConfiguredEndpoint=async()=>(e.serviceId&&!o&&(o=lD(e.serviceId)),o),a},Rre=e=>e instanceof Error?e:e instanceof Object?Object.assign(Error(),e):Error(typeof e==`string`?e:`AWS SDK error wrapper for ${e}`),hD=e=>{let{retryStrategy:t,retryMode:n}=e,r=IS(e.maxAttempts??3),i=t?Promise.resolve(t):void 0,a=async()=>await IS(n)()===wE.ADAPTIVE?new qE(r):new KE(r);return Object.assign(e,{maxAttempts:r,retryStrategy:()=>i??=a()})},gD=(e,t)=>{let n=[];if(e&&n.push(e),t)for(let e of t)n.push(e);return n},_D=(e,t)=>`${e||`anonymous`}${t&&t.length>0?` (a.k.a. ${t.join(`,`)})`:``}`,vD=()=>{let e=[],t=[],n=!1,r=new Set,i=e=>e.sort((e,t)=>yD[t.step]-yD[e.step]||bD[t.priority||`normal`]-bD[e.priority||`normal`]),a=n=>{let i=!1,a=e=>{let t=gD(e.name,e.aliases);if(t.includes(n)){i=!0;for(let e of t)r.delete(e);return!1}return!0};return e=e.filter(a),t=t.filter(a),i},o=n=>{let i=!1,a=e=>{if(e.middleware===n){i=!0;for(let t of gD(e.name,e.aliases))r.delete(t);return!1}return!0};return e=e.filter(a),t=t.filter(a),i},s=n=>(e.forEach(e=>{n.add(e.middleware,{...e})}),t.forEach(e=>{n.addRelativeTo(e.middleware,{...e})}),n.identifyOnResolve?.(u.identifyOnResolve()),n),c=e=>{let t=[];return e.before.forEach(e=>{e.before.length===0&&e.after.length===0?t.push(e):t.push(...c(e))}),t.push(e),e.after.reverse().forEach(e=>{e.before.length===0&&e.after.length===0?t.push(e):t.push(...c(e))}),t},l=(n=!1)=>{let r=[],a=[],o={};return e.forEach(e=>{let t={...e,before:[],after:[]};for(let e of gD(t.name,t.aliases))o[e]=t;r.push(t)}),t.forEach(e=>{let t={...e,before:[],after:[]};for(let e of gD(t.name,t.aliases))o[e]=t;a.push(t)}),a.forEach(e=>{if(e.toMiddleware){let t=o[e.toMiddleware];if(t===void 0){if(n)return;throw Error(`${e.toMiddleware} is not found when adding ${_D(e.name,e.aliases)} middleware ${e.relation} ${e.toMiddleware}`)}e.relation===`after`&&t.after.push(e),e.relation===`before`&&t.before.push(e)}}),i(r).map(c).reduce((e,t)=>(e.push(...t),e),[])},u={add:(t,n={})=>{let{name:i,override:a,aliases:o}=n,s={step:`initialize`,priority:`normal`,middleware:t,...n},c=gD(i,o);if(c.length>0){if(c.some(e=>r.has(e))){if(!a)throw Error(`Duplicate middleware name '${_D(i,o)}'`);for(let t of c){let n=e.findIndex(e=>e.name===t||e.aliases?.some(e=>e===t));if(n===-1)continue;let r=e[n];if(r.step!==s.step||s.priority!==r.priority)throw Error(`"${_D(r.name,r.aliases)}" middleware with ${r.priority} priority in ${r.step} step cannot be overridden by "${_D(i,o)}" middleware with ${s.priority} priority in ${s.step} step.`);e.splice(n,1)}}for(let e of c)r.add(e)}e.push(s)},addRelativeTo:(e,n)=>{let{name:i,override:a,aliases:o}=n,s={middleware:e,...n},c=gD(i,o);if(c.length>0){if(c.some(e=>r.has(e))){if(!a)throw Error(`Duplicate middleware name '${_D(i,o)}'`);for(let e of c){let n=t.findIndex(t=>t.name===e||t.aliases?.some(t=>t===e));if(n===-1)continue;let r=t[n];if(r.toMiddleware!==s.toMiddleware||r.relation!==s.relation)throw Error(`"${_D(r.name,r.aliases)}" middleware ${r.relation} "${r.toMiddleware}" middleware cannot be overridden by "${_D(i,o)}" middleware ${s.relation} "${s.toMiddleware}" middleware.`);t.splice(n,1)}}for(let e of c)r.add(e)}t.push(s)},clone:()=>s(vD()),use:e=>{e.applyToStack(u)},remove:e=>typeof e==`string`?a(e):o(e),removeByTag:n=>{let i=!1,a=e=>{let{tags:t,name:a,aliases:o}=e;if(t&&t.includes(n)){let e=gD(a,o);for(let t of e)r.delete(t);return i=!0,!1}return!0};return e=e.filter(a),t=t.filter(a),i},concat:e=>{let t=s(vD());return t.use(e),t.identifyOnResolve(n||t.identifyOnResolve()||(e.identifyOnResolve?.()??!1)),t},applyToStack:s,identify:()=>l(!0).map(e=>{let t=e.step??e.relation+` `+e.toMiddleware;return _D(e.name,e.aliases)+` - `+t}),identifyOnResolve(e){return typeof e==`boolean`&&(n=e),n},resolve:(e,t)=>{for(let n of l().map(e=>e.middleware).reverse())e=n(e,t);return n&&console.log(u.identify()),e}};return u},yD={initialize:5,serialize:4,build:3,finalizeRequest:2,deserialize:1},bD={high:3,normal:2,low:1},xD=class{config;middlewareStack=vD();initConfig;handlers;constructor(e){this.config=e;let{protocol:t,protocolSettings:n}=e;n&&typeof t==`function`&&(e.protocol=new t(n))}send(e,t,n){let r=typeof t==`function`?void 0:t,i=typeof t==`function`?t:n,a=r===void 0&&this.config.cacheMiddleware===!0,o;if(a){this.handlers||=new WeakMap;let t=this.handlers;t.has(e.constructor)?o=t.get(e.constructor):(o=e.resolveMiddleware(this.middlewareStack,this.config,r),t.set(e.constructor,o))}else delete this.handlers,o=e.resolveMiddleware(this.middlewareStack,this.config,r);if(i)o(e).then(e=>i(null,e.output),e=>i(e)).catch(()=>{});else return o(e).then(e=>e.output)}destroy(){this.config?.requestHandler?.destroy?.(),delete this.handlers}},SD=`***SensitiveInformation***`;function CD(e,t){if(t==null)return t;let n=sw.of(e);if(n.getMergedTraits().sensitive)return SD;if(n.isListSchema()){if(n.getValueSchema().getMergedTraits().sensitive)return SD}else if(n.isMapSchema()){if(n.getKeySchema().getMergedTraits().sensitive||n.getValueSchema().getMergedTraits().sensitive)return SD}else if(n.isStructSchema()&&typeof t==`object`){let e=t,r={};for(let[t,i]of n.structIterator())e[t]!=null&&(r[t]=CD(i,e[t]));return r}return t}var wD=class{middlewareStack=vD();schema;static classBuilder(){return new zre}resolveMiddlewareWithContext(e,t,n,{middlewareFn:r,clientName:i,commandName:a,inputFilterSensitiveLog:o,outputFilterSensitiveLog:s,smithyContext:c,additionalContext:l,CommandCtor:u}){for(let i of r.bind(this)(u,e,t,n))this.middlewareStack.use(i);let d=e.concat(this.middlewareStack),{logger:f}=t,p={logger:f,clientName:i,commandName:a,inputFilterSensitiveLog:o,outputFilterSensitiveLog:s,[Ux]:{commandInstance:this,...c},...l},{requestHandler:m}=t,h=n??{};return c.eventStream&&(h={isEventStream:!0,...h}),d.resolve(e=>m.handle(e.request,h),p)}},zre=class{_init=()=>{};_ep={};_middlewareFn=()=>[];_commandName=``;_clientName=``;_additionalContext={};_smithyContext={};_inputFilterSensitiveLog=void 0;_outputFilterSensitiveLog=void 0;_serializer=null;_deserializer=null;_operationSchema;init(e){this._init=e}ep(e){return this._ep=e,this}m(e){return this._middlewareFn=e,this}s(e,t,n={}){return this._smithyContext={service:e,operation:t,...n},this}c(e={}){return this._additionalContext=e,this}n(e,t){return this._clientName=e,this._commandName=t,this}f(e=e=>e,t=e=>e){return this._inputFilterSensitiveLog=e,this._outputFilterSensitiveLog=t,this}ser(e){return this._serializer=e,this}de(e){return this._deserializer=e,this}sc(e){return this._operationSchema=e,this._smithyContext.operationSchema=e,this}build(){let e=this,t;return t=class extends wD{input;static getEndpointParameterInstructions(){return e._ep}constructor(...[t]){super(),this.input=t??{},e._init(this),this.schema=e._operationSchema}resolveMiddleware(n,r,i){let a=e._operationSchema,o=a?.[4]??a?.input,s=a?.[5]??a?.output;return this.resolveMiddlewareWithContext(n,r,i,{CommandCtor:t,middlewareFn:e._middlewareFn,clientName:e._clientName,commandName:e._commandName,inputFilterSensitiveLog:e._inputFilterSensitiveLog??(a?CD.bind(null,o):e=>e),outputFilterSensitiveLog:e._outputFilterSensitiveLog??(a?CD.bind(null,s):e=>e),smithyContext:e._smithyContext,additionalContext:e._additionalContext})}serialize=e._serializer;deserialize=e._deserializer}}},TD=class e extends Error{$fault;$response;$retryable;$metadata;constructor(e){super(e.message),Object.setPrototypeOf(this,Object.getPrototypeOf(this).constructor.prototype),this.name=e.name,this.$fault=e.$fault,this.$metadata=e.$metadata}static isInstance(t){if(!t)return!1;let n=t;return e.prototype.isPrototypeOf(n)||!!n.$fault&&!!n.$metadata&&(n.$fault===`client`||n.$fault===`server`)}static[Symbol.hasInstance](t){if(!t)return!1;let n=t;return this===e?e.isInstance(t):e.isInstance(t)?n.name&&this.name?this.prototype.isPrototypeOf(t)||n.name===this.name:this.prototype.isPrototypeOf(t):!1}},ED=(e,t={})=>(Object.entries(t).filter(([,e])=>e!==void 0).forEach(([t,n])=>{(e[t]==null||e[t]===``)&&(e[t]=n)}),e.message=e.message||e.Message||`UnknownError`,delete e.Message,e),DD=e=>{switch(e){case`standard`:return{retryMode:`standard`,connectionTimeout:3100};case`in-region`:return{retryMode:`standard`,connectionTimeout:1100};case`cross-region`:return{retryMode:`standard`,connectionTimeout:3100};case`mobile`:return{retryMode:`standard`,connectionTimeout:3e4};default:return{}}},OD=Object.values(Hx),Bre=e=>{let t=[];for(let n in Hx){let r=Hx[n];e[r]!==void 0&&t.push({algorithmId:()=>r,checksumConstructor:()=>e[r]})}for(let[n,r]of Object.entries(e.checksumAlgorithms??{}))t.push({algorithmId:()=>n,checksumConstructor:()=>r});return{addChecksumAlgorithm(n){e.checksumAlgorithms=e.checksumAlgorithms??{};let r=n.algorithmId(),i=n.checksumConstructor();OD.includes(r)?e.checksumAlgorithms[r.toUpperCase()]=i:e.checksumAlgorithms[r]=i,t.push(n)},checksumAlgorithms(){return t}}},Vre=e=>{let t={};return e.checksumAlgorithms().forEach(e=>{let n=e.algorithmId();OD.includes(n)&&(t[n]=e.checksumConstructor())}),t},Hre=e=>({setRetryStrategy(t){e.retryStrategy=t},retryStrategy(){return e.retryStrategy}}),Ure=e=>{let t={};return t.retryStrategy=e.retryStrategy(),t},kD=e=>Object.assign(Bre(e),Hre(e)),AD=e=>Object.assign(Vre(e),Ure(e)),jD=e=>{let t=`#text`;for(let n in e)e.hasOwnProperty(n)&&e[n][t]!==void 0?e[n]=e[n][t]:typeof e[n]==`object`&&e[n]!==null&&(e[n]=jD(e[n]));return e},MD=class{trace(){}debug(){}info(){}warn(){}error(){}},Wre=e=>e?.body instanceof ReadableStream;function Gre(e,t){if(Kx.isInstance(e))for(let n of Object.keys(e.headers)){let r=n.toLowerCase();if(r===`retry-after`){let r=e.headers[n],i=NaN;if(r.endsWith(`GMT`))try{i=(Nw(r).getTime()-Date.now())/1e3}catch(e){t?.trace?.(`Failed to parse retry-after header`),t?.trace?.(e)}else r.match(/ GMT, ((\d+)|(\d+\.\d+))$/)?i=Number(r.match(/ GMT, ([\d.]+)$/)?.[1]):r.match(/^((\d+)|(\d+\.\d+))$/)?i=Number(r):Date.parse(r)>=Date.now()&&(i=(Date.parse(r)-Date.now())/1e3);return isNaN(i)?void 0:new Date(Date.now()+i*1e3)}else if(r===`x-amz-retry-after`){let r=e.headers[n],i=Number(r);if(isNaN(i)){t?.trace?.(`Failed to parse x-amz-retry-after=${r}`);return}return new Date(Date.now()+i)}}}var Kre=e=>(t,n)=>async r=>{let i=await e.retryStrategy(),a=await e.maxAttempts();if(qre(i)){i=i;let o=await i.acquireInitialRetryToken((n.partition_id??``)+(n.__retryLongPoll?`:longpoll`:``)),s=Error(),c=0,l=0,{request:u}=r,d=Wx.isInstance(u);for(d&&(u.headers[BE]=qw());;)try{d&&(u.headers[VE]=`attempt=${c+1}; max=${a}`);let{response:e,output:n}=await t(r);return i.recordSuccess(o),n.$metadata.attempts=c+1,n.$metadata.totalRetryDelay=l,{response:e,output:n}}catch(t){let r=Jre(t,e.logger);if(s=Rre(t),d&&Wre(u))throw(n.logger instanceof MD?console:n.logger)?.warn(`An error was encountered in a non-retryable streaming request.`),s;try{o=await i.refreshRetryTokenForRetry(o,r)}catch(e){throw typeof e.$backoff==`number`&&await ND(e.$backoff),s.$metadata||={},s.$metadata.attempts=c+1,s.$metadata.totalRetryDelay=l,s}c=o.getRetryCount();let a=o.getRetryDelay();l+=a,await ND(a)}}else return i=i,i?.mode&&(n.userAgent=[...n.userAgent||[],[`cfg/retry-mode`,i.mode]]),i.retry(t,r)},ND=e=>new Promise(t=>setTimeout(t,e)),qre=e=>e.acquireInitialRetryToken!==void 0&&e.refreshRetryTokenForRetry!==void 0&&e.recordSuccess!==void 0,Jre=(e,t)=>{let n={error:e,errorType:Yre(e)},r=Gre(e.$response,t);return r&&(n.retryAfterHint=r),n},Yre=e=>PE(e)?`THROTTLING`:FE(e)?`TRANSIENT`:IE(e)?`SERVER_ERROR`:`CLIENT_ERROR`,Xre={name:`retryMiddleware`,tags:[`RETRY`],step:`finalizeRequest`,priority:`high`,override:!0},PD=e=>({applyToStack:t=>{t.add(Kre(e),Xre)}}),FD=e=>Kx.isInstance(e)?e.headers?.date??e.headers?.Date:void 0,ID=e=>new Date(Date.now()+e),Zre=(e,t)=>Math.abs(ID(t).getTime()-e)>=3e5,LD=(e,t)=>{let n=Date.parse(e);return Zre(n,t)?n-Date.now():t},RD=(e,t)=>{if(!t)throw Error(`Property \`${e}\` is not resolved for AWS SDK SigV4Auth`);return t},zD=async e=>{let t=RD(`context`,e.context),n=RD(`config`,e.config),r=t.endpointV2?.properties?.authSchemes?.[0];return{config:n,signer:await RD(`signer`,n.signer)(r),signingRegion:e?.signingRegion,signingRegionSet:e?.signingRegionSet,signingName:e?.signingName}},BD=class{async sign(e,t,n){if(!Wx.isInstance(e))throw Error("The request is not an instance of `HttpRequest` and cannot be signed");let r=await zD(n),{config:i,signer:a}=r,{signingRegion:o,signingName:s}=r,c=n.context;if(c?.authSchemes?.length??!1){let[e,t]=c.authSchemes;e?.name===`sigv4a`&&t?.name===`sigv4`&&(o=t?.signingRegion??o,s=t?.signingName??s)}return await a.sign(e,{signingDate:ID(i.systemClockOffset),signingRegion:o,signingService:s})}errorHandler(e){return t=>{let n=t.ServerTime??FD(t.$response);if(n){let r=RD(`config`,e.config),i=r.systemClockOffset;r.systemClockOffset=LD(n,r.systemClockOffset),r.systemClockOffset!==i&&t.$metadata&&(t.$metadata.clockSkewCorrected=!0)}throw t}}successHandler(e,t){let n=FD(e);if(n){let e=RD(`config`,t.config);e.systemClockOffset=LD(n,e.systemClockOffset)}}},Qre=class extends BD{async sign(e,t,n){if(!Wx.isInstance(e))throw Error("The request is not an instance of `HttpRequest` and cannot be signed");let{config:r,signer:i,signingRegion:a,signingRegionSet:o,signingName:s}=await zD(n),c=(await r.sigv4aSigningRegionSet?.()??o??[a]).join(`,`);return await i.sign(e,{signingDate:ID(r.systemClockOffset),signingRegion:c,signingService:s})}},$re=(e,t,n)=>{let r,i,a,o=!1,s=async()=>{i||=e();try{r=await i,a=!0,o=!1}finally{i=void 0}return r};return t===void 0?async e=>((!a||e?.forceRefresh)&&(r=await s()),r):async e=>((!a||e?.forceRefresh)&&(r=await s()),o?r:n&&!n(r)?(o=!0,r):(t(r)&&await s(),r))},eie=e=>(e.sigv4aSigningRegionSet=xC(e.sigv4aSigningRegionSet),e),VD=e=>{let t=e.credentials,n=!!e.credentials,r;Object.defineProperty(e,`credentials`,{set(i){i&&i!==t&&i!==r&&(n=!0),t=i;let a=nie(e,tie(e,{credentials:t,credentialDefaultProvider:e.credentialDefaultProvider}));if(n&&!a.attributed){let e=typeof t==`object`&&!!t;r=async t=>{let n=await a(t);return e&&(!n.$source||Object.keys(n.$source).length===0)?CE(n,`CREDENTIALS_CODE`,`e`):n},r.memoized=a.memoized,r.configBound=a.configBound,r.attributed=!0}else r=a},get(){return r},enumerable:!0,configurable:!0}),e.credentials=t;let{signingEscapePath:i=!0,systemClockOffset:a=e.systemClockOffset||0,sha256:o}=e,s;return s=e.signer?xC(e.signer):e.regionInfoProvider?()=>xC(e.region)().then(async t=>[await e.regionInfoProvider(t,{useFipsEndpoint:await e.useFipsEndpoint(),useDualstackEndpoint:await e.useDualstackEndpoint()})||{},t]).then(([t,n])=>{let{signingRegion:r,signingService:a}=t;e.signingRegion=e.signingRegion||r||n,e.signingName=e.signingName||a||e.serviceId;let s={...e,credentials:e.credentials,region:e.signingRegion,service:e.signingName,sha256:o,uriEscapePath:i};return new(e.signerConstructor||US)(s)}):async t=>{t=Object.assign({},{name:`sigv4`,signingName:e.signingName||e.defaultSigningName,signingRegion:await xC(e.region)(),properties:{}},t);let n=t.signingRegion,r=t.signingName;e.signingRegion=e.signingRegion||n,e.signingName=e.signingName||r||e.serviceId;let a={...e,credentials:e.credentials,region:e.signingRegion,service:e.signingName,sha256:o,uriEscapePath:i};return new(e.signerConstructor||US)(a)},Object.assign(e,{systemClockOffset:a,signingEscapePath:i,signer:s})};function tie(e,{credentials:t,credentialDefaultProvider:n}){let r;return r=t?t?.memoized?t:jT(t,kT,AT):n?xC(n(Object.assign({},e,{parentClientConfig:e}))):async()=>{throw Error("@aws-sdk/core::resolveAwsSdkSigV4Config - `credentials` not provided and no credentialDefaultProvider was configured.")},r.memoized=!0,r}function nie(e,t){if(t.configBound)return t;let n=async n=>t({...n,callerClientConfig:e});return n.memoized=t.memoized,n.configBound=!0,n}var rie=async(e,t,n)=>({operation:FS(t).operation,region:await IS(e.region)()||(()=>{throw Error("expected `region` to be configured for `aws.auth#sigv4`")})()});function iie(e){return{schemeId:`aws.auth#sigv4`,signingProperties:{name:`ec2`,region:e.region},propertiesExtractor:(e,t)=>({signingProperties:{config:e,context:t}})}}var aie=e=>{let t=[];switch(e.operation){default:t.push(iie(e))}return t},oie=e=>{let t=VD(e);return Object.assign(t,{authSchemePreference:IS(e.authSchemePreference??[])})},sie=e=>Object.assign(e,{useDualstackEndpoint:e.useDualstackEndpoint??!1,useFipsEndpoint:e.useFipsEndpoint??!1,defaultSigningName:`ec2`}),HD={UseFIPS:{type:`builtInParams`,name:`useFipsEndpoint`},Endpoint:{type:`builtInParams`,name:`endpoint`},Region:{type:`builtInParams`,name:`region`},UseDualStack:{type:`builtInParams`,name:`useDualstackEndpoint`}},cie={name:`@aws-sdk/client-ec2`,description:`AWS SDK for JavaScript Ec2 Client for Node.js, Browser and React Native`,version:`3.1045.0`,scripts:{build:`concurrently 'yarn:build:types' 'yarn:build:es' && yarn build:cjs`,"build:cjs":`node ../../scripts/compilation/inline client-ec2`,"build:es":`tsc -p tsconfig.es.json`,"build:include:deps":`yarn g:turbo run build -F="$npm_package_name"`,"build:types":`tsc -p tsconfig.types.json`,"build:types:downlevel":`downlevel-dts dist-types dist-types/ts3.4`,clean:`premove dist-cjs dist-es dist-types tsconfig.cjs.tsbuildinfo tsconfig.es.tsbuildinfo tsconfig.types.tsbuildinfo`,"extract:docs":`api-extractor run --local`,"generate:client":`node ../../scripts/generate-clients/single-service --solo ec2`,test:`yarn g:vitest run --passWithNoTests`,"test:index":`tsc --noEmit ./test/index-types.ts && node ./test/index-objects.spec.mjs`,"test:integration":`yarn g:vitest run --passWithNoTests -c vitest.config.integ.mts`,"test:integration:watch":`yarn g:vitest run --passWithNoTests -c vitest.config.integ.mts`,"test:watch":`yarn g:vitest watch --passWithNoTests`},main:`./dist-cjs/index.js`,types:`./dist-types/index.d.ts`,module:`./dist-es/index.js`,sideEffects:!1,dependencies:{"@aws-crypto/sha256-browser":`5.2.0`,"@aws-crypto/sha256-js":`5.2.0`,"@aws-sdk/core":`^3.974.8`,"@aws-sdk/credential-provider-node":`^3.972.39`,"@aws-sdk/middleware-host-header":`^3.972.10`,"@aws-sdk/middleware-logger":`^3.972.10`,"@aws-sdk/middleware-recursion-detection":`^3.972.11`,"@aws-sdk/middleware-sdk-ec2":`^3.972.22`,"@aws-sdk/middleware-user-agent":`^3.972.38`,"@aws-sdk/region-config-resolver":`^3.972.13`,"@aws-sdk/types":`^3.973.8`,"@aws-sdk/util-endpoints":`^3.996.8`,"@aws-sdk/util-user-agent-browser":`^3.972.10`,"@aws-sdk/util-user-agent-node":`^3.973.24`,"@smithy/config-resolver":`^4.4.17`,"@smithy/core":`^3.23.17`,"@smithy/fetch-http-handler":`^5.3.17`,"@smithy/hash-node":`^4.2.14`,"@smithy/invalid-dependency":`^4.2.14`,"@smithy/middleware-content-length":`^4.2.14`,"@smithy/middleware-endpoint":`^4.4.32`,"@smithy/middleware-retry":`^4.5.7`,"@smithy/middleware-serde":`^4.2.20`,"@smithy/middleware-stack":`^4.2.14`,"@smithy/node-config-provider":`^4.3.14`,"@smithy/node-http-handler":`^4.6.1`,"@smithy/protocol-http":`^5.3.14`,"@smithy/smithy-client":`^4.12.13`,"@smithy/types":`^4.14.1`,"@smithy/url-parser":`^4.2.14`,"@smithy/util-base64":`^4.3.2`,"@smithy/util-body-length-browser":`^4.2.2`,"@smithy/util-body-length-node":`^4.2.3`,"@smithy/util-defaults-mode-browser":`^4.3.49`,"@smithy/util-defaults-mode-node":`^4.2.54`,"@smithy/util-endpoints":`^3.4.2`,"@smithy/util-middleware":`^4.2.14`,"@smithy/util-retry":`^4.3.6`,"@smithy/util-utf8":`^4.2.2`,"@smithy/util-waiter":`^4.3.0`,tslib:`^2.6.2`},devDependencies:{"@smithy/snapshot-testing":`^2.0.8`,"@tsconfig/node20":`20.1.8`,"@types/node":`^20.14.8`,concurrently:`7.0.0`,"downlevel-dts":`0.10.1`,premove:`4.0.0`,typescript:`~5.8.3`,vitest:`^4.0.17`},engines:{node:`>=20.0.0`},typesVersions:{"<4.5":{"dist-types/*":[`dist-types/ts3.4/*`]}},files:[`dist-*/**`],author:{name:`AWS SDK for JavaScript Team`,url:`https://aws.amazon.com/javascript/`},license:`Apache-2.0`,browser:{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.browser`},"react-native":{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.native`},homepage:`https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-ec2`,repository:{type:`git`,url:`https://github.com/aws/aws-sdk-js-v3.git`,directory:`clients/client-ec2`}},UD=({serviceId:e,clientVersion:t})=>async n=>{let r=typeof window<`u`?window.navigator:void 0,i=r?.userAgent??``,a=r?.userAgentData?.platform??WD.os(i)??`other`,o=r?.userAgentData?.brands??[],s=o[o.length-1],c=s?.brand??WD.browser(i)??`unknown`,l=s?.version??`unknown`,u=[[`aws-sdk-js`,t],[`ua`,`2.1`],[`os/${a}`,void 0],[`lang/js`],[`md/browser`,`${c}_${l}`]];e&&u.push([`api/${e}`,t]);let d=await n?.userAgentAppId?.();return d&&u.push([`app/${d}`]),u},WD={os(e){if(/iPhone|iPad|iPod/.test(e))return`iOS`;if(/Macintosh|Mac OS X/.test(e))return`macOS`;if(/Windows NT/.test(e))return`Windows`;if(/Android/.test(e))return`Android`;if(/Linux/.test(e))return`Linux`},browser(e){if(/EdgiOS|EdgA|Edg\//.test(e))return`Microsoft Edge`;if(/Firefox\//.test(e))return`Firefox`;if(/Chrome\//.test(e))return`Chrome`;if(/Safari\//.test(e))return`Safari`}},GD=e=>()=>Promise.reject(e),KD=typeof TextEncoder==`function`?new TextEncoder:null,qD=e=>{if(typeof e==`string`){if(KD)return KD.encode(e).byteLength;let t=e.length;for(let n=t-1;n>=0;n--){let r=e.charCodeAt(n);r>127&&r<=2047?t++:r>2047&&r<=65535&&(t+=2),r>=56320&&r<=57343&&n--}return t}else if(typeof e.byteLength==`number`)return e.byteLength;else if(typeof e.size==`number`)return e.size;throw Error(`Body Length computation failed for ${e}`)},lie=[`in-region`,`cross-region`,`mobile`,`standard`,`legacy`],JD=({defaultsMode:e}={})=>$re(async()=>{let t=typeof e==`function`?await e():e;switch(t?.toLowerCase()){case`auto`:return Promise.resolve(uie()?`mobile`:`standard`);case`mobile`:case`in-region`:case`cross-region`:case`standard`:case`legacy`:return Promise.resolve(t?.toLocaleLowerCase());case void 0:return Promise.resolve(`legacy`);default:throw Error(`Invalid parameter for "defaultsMode", expect ${lie.join(`, `)}, got ${t}`)}}),uie=()=>{let e=window?.navigator;if(e?.connection){let{effectiveType:t,rtt:n,downlink:r}=e?.connection;if(typeof t==`string`&&t!==`4g`||Number(n)>100||Number(r)<10)return!0}return e?.userAgentData?.mobile||typeof e?.maxTouchPoints==`number`&&e?.maxTouchPoints>1},YD=class{queryCompat;errorRegistry;constructor(e=!1){this.queryCompat=e}resolveRestContentType(e,t){let n=t.getMemberSchemas(),r=Object.values(n).find(e=>!!e.getMergedTraits().httpPayload);if(r)return r.getMergedTraits().mediaType||(r.isStringSchema()?`text/plain`:r.isBlobSchema()?`application/octet-stream`:e);if(!t.isUnitSchema()&&Object.values(n).find(e=>{let{httpQuery:t,httpQueryParams:n,httpHeader:r,httpLabel:i,httpPrefixHeaders:a}=e.getMergedTraits();return!t&&!n&&!r&&!i&&a===void 0}))return e}async getErrorSchemaOrThrowBaseException(e,t,n,r,i,a){let o=e;e.includes(`#`)&&([,o]=e.split(`#`));let s={$metadata:i,$fault:n.statusCode<500?`client`:`server`};if(!this.errorRegistry)throw Error(`@aws-sdk/core/protocols - error handler not initialized.`);try{return{errorSchema:a?.(this.errorRegistry,o)??this.errorRegistry.getSchema(e),errorMetadata:s}}catch{r.message=r.message??r.Message??`UnknownError`;let e=this.errorRegistry,t=e.getBaseException();if(t){let n=e.getErrorCtor(t)??Error;throw this.decorateServiceException(Object.assign(new n({name:o}),s),r)}let n=r,i=n?.message??n?.Message??n?.Error?.Message??n?.Error?.message;throw this.decorateServiceException(Object.assign(Error(i),{name:o},s),r)}}compose(e,t,n){let r=n;t.includes(`#`)&&([r]=t.split(`#`));let i=dw.for(r),a=dw.for(`smithy.ts.sdk.synthetic.`+n);e.copyFrom(i),e.copyFrom(a),this.errorRegistry=e}decorateServiceException(e,t={}){if(this.queryCompat){let n=e.Message??t.Message,r=ED(e,t);n&&(r.message=n);let i=r.Error??{};i.Type=r.Error?.Type,i.Code=r.Error?.Code,i.Message=r.Error?.message??r.Error?.Message??n,r.Error=i;let a=r.$metadata.requestId;return a&&(r.RequestId=a),r}return ED(e,t)}setQueryCompatError(e,t){let n=t.headers?.[`x-amzn-query-error`];if(e!==void 0&&n!=null){let[t,r]=n.split(`;`),i=Object.keys(e),a={Code:t,Type:r};e.Code=t,e.Type=r;for(let t=0;tsw.of(e).getMergedTraits().awsQueryError?.[0]===t)}}},XD=class{serdeContext;setSerdeContext(e){this.serdeContext=e}},die=class{from;to;keys;constructor(e,t){this.from=e,this.to=t;let n=Object.keys(this.from),r=new Set(n);r.delete(`__type`),this.keys=r}mark(e){this.keys.delete(e)}hasUnknown(){return this.keys.size===1&&Object.keys(this.to).length===0}writeUnknown(){if(this.hasUnknown()){let e=this.keys.values().next().value,t=this.from[e];this.to.$unknown=[e,t]}}},fie=/[&<>"]/g,pie={"&":`&`,"<":`<`,">":`>`,'"':`"`};function mie(e){return e.replace(fie,e=>pie[e])}var hie=/[&"'<>\r\n\u0085\u2028]/g,gie={"&":`&`,'"':`"`,"'":`'`,"<":`<`,">":`>`,"\r":` `,"\n":` `,"…":`…`,"\u2028":`
`};function _ie(e){return e.replace(hie,e=>gie[e])}var ZD=class{value;constructor(e){this.value=e}toString(){return _ie(``+this.value)}},QD=class e{name;children;attributes={};static of(t,n,r){let i=new e(t);return n!==void 0&&i.addChildNode(new ZD(n)),r!==void 0&&i.withName(r),i}constructor(e,t=[]){this.name=e,this.children=t}withName(e){return this.name=e,this}addAttribute(e,t){return this.attributes[e]=t,this}addChildNode(e){return this.children.push(e),this}removeAttribute(e){return delete this.attributes[e],this}n(e){return this.name=e,this}c(e){return this.children.push(e),this}a(e,t){return t!=null&&(this.attributes[e]=t),this}cc(t,n,r=n){if(t[n]!=null){let i=e.of(n,t[n]).withName(r);this.c(i)}}l(e,t,n,r){e[t]!=null&&r().map(e=>{e.withName(n),this.c(e)})}lc(t,n,r,i){if(t[n]!=null){let t=i(),n=new e(r);t.map(e=>{n.c(e)}),this.c(n)}}toString(){let e=!!this.children.length,t=`<${this.name}`,n=this.attributes;for(let e of Object.keys(n)){let r=n[e];r!=null&&(t+=` ${e}="${mie(``+r)}"`)}return t+=e?`>${this.children.map(e=>e.toString()).join(``)}`:`/>`}},$D;function vie(e){$D||=new DOMParser;let t=$D.parseFromString(e,`application/xml`);if(t.getElementsByTagName(`parsererror`).length>0)throw Error(`DOMParser XML parsing error.`);let n=e=>{if(e.nodeType===Node.TEXT_NODE&&e.textContent?.trim())return e.textContent;if(e.nodeType===Node.ELEMENT_NODE){let t=e;if(t.attributes.length===0&&t.childNodes.length===0)return``;let r={},i=Array.from(t.attributes);for(let e of i)r[`${e.name}`]=e.value;let a=Array.from(t.childNodes);for(let e of a){let o=n(e);if(o!=null){let t=e.nodeName;if(a.length===1&&i.length===0&&t===`#text`)return o;r[t]?Array.isArray(r[t])?r[t].push(o):r[t]=[r[t],o]:r[t]=o}else if(a.length===1&&i.length===0)return t.textContent}return r}return null};return{[t.documentElement.nodeName]:n(t.documentElement)}}var eO=class extends XD{settings;stringDeserializer;constructor(e){super(),this.settings=e,this.stringDeserializer=new CT(e)}setSerdeContext(e){this.serdeContext=e,this.stringDeserializer.setSerdeContext(e)}read(e,t,n){let r=sw.of(e),i=r.getMemberSchemas();if(r.isStructSchema()&&r.isMemberSchema()&&Object.values(i).find(e=>!!e.getMemberTraits().eventPayload)){let e={},n=Object.keys(i)[0];return i[n].isBlobSchema()?e[n]=t:e[n]=this.read(i[n],t),e}let a=(this.serdeContext?.utf8Encoder??$x)(t),o=this.parseXml(a);return this.readSchema(e,n?o[n]:o)}readSchema(e,t){let n=sw.of(e);if(n.isUnitSchema())return;let r=n.getMergedTraits();if(n.isListSchema()&&!Array.isArray(t))return this.readSchema(n,[t]);if(t==null)return t;if(typeof t==`object`){let e=!!r.xmlFlattened;if(n.isListSchema()){let r=n.getValueSchema(),i=[],a=r.getMergedTraits().xmlName??`member`,o=e?t:(t[0]??t)[a];if(o==null)return i;let s=Array.isArray(o)?o:[o];for(let e of s)i.push(this.readSchema(r,e));return i}let i={};if(n.isMapSchema()){let r=n.getKeySchema(),a=n.getValueSchema(),o;o=e?Array.isArray(t)?t:[t]:Array.isArray(t.entry)?t.entry:[t.entry];let s=r.getMergedTraits().xmlName??`key`,c=a.getMergedTraits().xmlName??`value`;for(let e of o){let t=e[s],n=e[c];i[t]=this.readSchema(a,n)}return i}if(n.isStructSchema()){let e=n.isUnionSchema(),r;e&&(r=new die(t,i));for(let[a,o]of n.structIterator()){let n=o.getMergedTraits(),s=n.httpPayload?n.xmlName??o.getName():o.getMemberTraits().xmlName??a;e&&r.mark(s),t[s]!=null&&(i[a]=this.readSchema(o,t[s]))}return e&&r.writeUnknown(),i}if(n.isDocumentSchema())return t;throw Error(`@aws-sdk/core/protocols - xml deserializer unhandled schema type for ${n.getName(!0)}`)}return n.isListSchema()?[]:n.isMapSchema()||n.isStructSchema()?{}:this.stringDeserializer.read(n,t)}parseXml(e){if(e.length){let t;try{t=vie(e)}catch(t){throw t&&typeof t==`object`&&Object.defineProperty(t,`$responseBodyText`,{value:e}),t}let n=`#text`,r=Object.keys(t)[0],i=t[r];return i[n]&&(i[r]=i[n],delete i[n]),jD(i)}return{}}},yie=class extends XD{settings;buffer;constructor(e){super(),this.settings=e}write(e,t,n=``){this.buffer===void 0&&(this.buffer=``);let r=sw.of(e);if(n&&!n.endsWith(`.`)&&(n+=`.`),r.isBlobSchema())(typeof t==`string`||t instanceof Uint8Array)&&(this.writeKey(n),this.writeValue((this.serdeContext?.base64Encoder??EC)(t)));else if(r.isBooleanSchema()||r.isNumericSchema()||r.isStringSchema())t==null?r.isIdempotencyToken()&&(this.writeKey(n),this.writeValue(qw())):(this.writeKey(n),this.writeValue(String(t)));else if(r.isBigIntegerSchema())t!=null&&(this.writeKey(n),this.writeValue(String(t)));else if(r.isBigDecimalSchema())t!=null&&(this.writeKey(n),this.writeValue(t instanceof pT?t.string:String(t)));else if(r.isTimestampSchema()){if(t instanceof Date)switch(this.writeKey(n),ST(r,this.settings)){case 5:this.writeValue(t.toISOString().replace(`.000Z`,`Z`));break;case 6:this.writeValue(kw(t));break;case 7:this.writeValue(String(t.getTime()/1e3));break}}else if(r.isDocumentSchema())Array.isArray(t)?this.write(79,t,n):t instanceof Date?this.write(4,t,n):t instanceof Uint8Array?this.write(21,t,n):t&&typeof t==`object`?this.write(143,t,n):(this.writeKey(n),this.writeValue(String(t)));else if(r.isListSchema()){if(Array.isArray(t))if(t.length===0)this.settings.serializeEmptyLists&&(this.writeKey(n),this.writeValue(``));else{let e=r.getValueSchema(),i=this.settings.flattenLists||r.getMergedTraits().xmlFlattened,a=1;for(let r of t){if(r==null)continue;let t=e.getMergedTraits(),o=this.getKey(`member`,t.xmlName,t.ec2QueryName),s=i?`${n}${a}`:`${n}${o}.${a}`;this.write(e,r,s),++a}}}else if(r.isMapSchema()){if(t&&typeof t==`object`){let e=r.getKeySchema(),i=r.getValueSchema(),a=r.getMergedTraits().xmlFlattened,o=1;for(let r in t){let s=t[r];if(s==null)continue;let c=e.getMergedTraits(),l=this.getKey(`key`,c.xmlName,c.ec2QueryName),u=a?`${n}${o}.${l}`:`${n}entry.${o}.${l}`,d=i.getMergedTraits(),f=this.getKey(`value`,d.xmlName,d.ec2QueryName),p=a?`${n}${o}.${f}`:`${n}entry.${o}.${f}`;this.write(e,r,u),this.write(i,s,p),++o}}}else if(r.isStructSchema()){if(t&&typeof t==`object`){let e=!1;for(let[i,a]of r.structIterator()){if(t[i]==null&&!a.isIdempotencyToken())continue;let r=a.getMergedTraits(),o=this.getKey(i,r.xmlName,r.ec2QueryName,`struct`),s=`${n}${o}`;this.write(a,t[i],s),e=!0}if(!e&&r.isUnionSchema()){let{$unknown:e}=t;if(Array.isArray(e)){let[t,r]=e,i=`${n}${t}`;this.write(15,r,i)}}}}else if(!r.isUnitSchema())throw Error(`@aws-sdk/core/protocols - QuerySerializer unrecognized schema type ${r.getName(!0)}`)}flush(){if(this.buffer===void 0)throw Error(`@aws-sdk/core/protocols - QuerySerializer cannot flush with nothing written to buffer.`);let e=this.buffer;return delete this.buffer,e}getKey(e,t,n,r){let{ec2:i,capitalizeKeys:a}=this.settings;if(i&&n)return n;let o=t??e;return a&&r===`struct`?o[0].toUpperCase()+o.slice(1):o}writeKey(e){e.endsWith(`.`)&&(e=e.slice(0,e.length-1)),this.buffer+=`&${WC(e)}=`}writeValue(e){this.buffer+=WC(e)}},tO=class extends xT{options;serializer;deserializer;mixin=new YD;constructor(e){super({defaultNamespace:e.defaultNamespace,errorTypeRegistries:e.errorTypeRegistries}),this.options=e;let t={timestampFormat:{useTrait:!0,default:5},httpBindings:!1,xmlNamespace:e.xmlNamespace,serviceNamespace:e.defaultNamespace,serializeEmptyLists:!0};this.serializer=new yie(t),this.deserializer=new eO(t)}getShapeId(){return`aws.protocols#awsQuery`}setSerdeContext(e){this.serializer.setSerdeContext(e),this.deserializer.setSerdeContext(e)}getPayloadCodec(){throw Error(`AWSQuery protocol has no payload codec.`)}async serializeRequest(e,t,n){let r=await super.serializeRequest(e,t,n);return r.path.endsWith(`/`)||(r.path+=`/`),r.headers[`content-type`]=`application/x-www-form-urlencoded`,(GC(e.input)===`unit`||!r.body)&&(r.body=``),r.body=`Action=${e.name.split(`#`)[1]??e.name}&Version=${this.options.version}`+r.body,r.body.endsWith(`&`)&&(r.body=r.body.slice(-1)),r}async deserializeResponse(e,t,n){let r=this.deserializer,i=sw.of(e.output),a={};if(n.statusCode>=300){let i=await UC(n.body,t);i.byteLength>0&&Object.assign(a,await r.read(15,i)),await this.handleError(e,t,n,a,this.deserializeMetadata(n))}for(let e in n.headers){let t=n.headers[e];delete n.headers[e],n.headers[e.toLowerCase()]=t}let o=e.name.split(`#`)[1]??e.name,s=i.isStructSchema()&&this.useNestedResult()?o+`Result`:void 0,c=await UC(n.body,t);return c.byteLength>0&&Object.assign(a,await r.read(i,c,s)),a.$metadata=this.deserializeMetadata(n),a}useNestedResult(){return!0}async handleError(e,t,n,r,i){let a=this.loadQueryErrorCode(n,r)??`Unknown`;this.mixin.compose(this.compositeErrorRegistry,a,this.options.defaultNamespace);let o=this.loadQueryError(r)??{},s=this.loadQueryErrorMessage(r);o.message=s,o.Error={Type:o.Type,Code:o.Code,Message:s};let{errorSchema:c,errorMetadata:l}=await this.mixin.getErrorSchemaOrThrowBaseException(a,this.options.defaultNamespace,n,o,i,this.mixin.findQueryCompatibleError),u=sw.of(c),d=new((this.compositeErrorRegistry.getErrorCtor(c))??Error)(s),f={Type:o.Error.Type,Code:o.Error.Code,Error:o.Error};for(let[e,t]of u.structIterator()){let n=t.getMergedTraits().xmlName??e,i=o[n]??r[n];f[e]=this.deserializer.readSchema(t,i)}throw this.mixin.decorateServiceException(Object.assign(d,l,{$fault:u.getMergedTraits().error,message:s},f),r)}loadQueryErrorCode(e,t){let n=(t.Errors?.[0]?.Error??t.Errors?.Error??t.Error)?.Code;if(n!==void 0)return n;if(e.statusCode==404)return`NotFound`}loadQueryError(e){return e.Errors?.[0]?.Error??e.Errors?.Error??e.Error}loadQueryErrorMessage(e){let t=this.loadQueryError(e);return t?.message??t?.Message??e.message??e.Message??`Unknown`}getDefaultContentType(){return`application/x-www-form-urlencoded`}},bie=class extends tO{options;constructor(e){super(e),this.options=e,Object.assign(this.serializer.settings,{capitalizeKeys:!0,flattenLists:!0,serializeEmptyLists:!1,ec2:!0})}getShapeId(){return`aws.protocols#ec2Query`}useNestedResult(){return!1}},xie=(e,t)=>{if(t?.Error?.Code!==void 0)return t.Error.Code;if(t?.Code!==void 0)return t.Code;if(e.statusCode==404)return`NotFound`},Sie=class extends XD{settings;stringBuffer;byteBuffer;buffer;constructor(e){super(),this.settings=e}write(e,t){let n=sw.of(e);if(n.isStringSchema()&&typeof t==`string`)this.stringBuffer=t;else if(n.isBlobSchema())this.byteBuffer=`byteLength`in t?t:(this.serdeContext?.base64Decoder??TC)(t);else{this.buffer=this.writeStruct(n,t,void 0);let e=n.getMergedTraits();e.httpPayload&&!e.xmlName&&this.buffer.withName(n.getName())}}flush(){if(this.byteBuffer!==void 0){let e=this.byteBuffer;return delete this.byteBuffer,e}if(this.stringBuffer!==void 0){let e=this.stringBuffer;return delete this.stringBuffer,e}let e=this.buffer;return this.settings.xmlNamespace&&(e?.attributes?.xmlns||e.addAttribute(`xmlns`,this.settings.xmlNamespace)),delete this.buffer,e.toString()}writeStruct(e,t,n){let r=e.getMergedTraits(),i=e.isMemberSchema()&&!r.httpPayload?e.getMemberTraits().xmlName??e.getMemberName():r.xmlName??e.getName();if(!i||!e.isStructSchema())throw Error(`@aws-sdk/core/protocols - xml serializer, cannot write struct with empty name or non-struct, schema=${e.getName(!0)}.`);let a=QD.of(i),[o,s]=this.getXmlnsAttribute(e,n);for(let[n,r]of e.structIterator()){let e=t[n];if(e!=null||r.isIdempotencyToken()){if(r.getMergedTraits().xmlAttribute){a.addAttribute(r.getMergedTraits().xmlName??n,this.writeSimple(r,e));continue}if(r.isListSchema())this.writeList(r,e,a,s);else if(r.isMapSchema())this.writeMap(r,e,a,s);else if(r.isStructSchema())a.addChildNode(this.writeStruct(r,e,s));else{let t=QD.of(r.getMergedTraits().xmlName??r.getMemberName());this.writeSimpleInto(r,e,t,s),a.addChildNode(t)}}}let{$unknown:c}=t;if(c&&e.isUnionSchema()&&Array.isArray(c)&&Object.keys(t).length===1){let[e,n]=c,r=QD.of(e);if(typeof n!=`string`)if(t instanceof QD||t instanceof ZD)a.addChildNode(t);else throw Error(`@aws-sdk - $unknown union member in XML requires value of type string, @aws-sdk/xml-builder::XmlNode or XmlText.`);this.writeSimpleInto(0,n,r,s),a.addChildNode(r)}return s&&a.addAttribute(o,s),a}writeList(e,t,n,r){if(!e.isMemberSchema())throw Error(`@aws-sdk/core/protocols - xml serializer, cannot write non-member list: ${e.getName(!0)}`);let i=e.getMergedTraits(),a=e.getValueSchema(),o=a.getMergedTraits(),s=!!o.sparse,c=!!i.xmlFlattened,[l,u]=this.getXmlnsAttribute(e,r),d=(t,n)=>{if(a.isListSchema())this.writeList(a,Array.isArray(n)?n:[n],t,u);else if(a.isMapSchema())this.writeMap(a,n,t,u);else if(a.isStructSchema()){let r=this.writeStruct(a,n,u);t.addChildNode(r.withName(c?i.xmlName??e.getMemberName():o.xmlName??`member`))}else{let r=QD.of(c?i.xmlName??e.getMemberName():o.xmlName??`member`);this.writeSimpleInto(a,n,r,u),t.addChildNode(r)}};if(c)for(let e of t)(s||e!=null)&&d(n,e);else{let r=QD.of(i.xmlName??e.getMemberName());u&&r.addAttribute(l,u);for(let e of t)(s||e!=null)&&d(r,e);n.addChildNode(r)}}writeMap(e,t,n,r,i=!1){if(!e.isMemberSchema())throw Error(`@aws-sdk/core/protocols - xml serializer, cannot write non-member map: ${e.getName(!0)}`);let a=e.getMergedTraits(),o=e.getKeySchema(),s=o.getMergedTraits().xmlName??`key`,c=e.getValueSchema(),l=c.getMergedTraits(),u=l.xmlName??`value`,d=!!l.sparse,f=!!a.xmlFlattened,[p,m]=this.getXmlnsAttribute(e,r),h=(e,t,n)=>{let r=QD.of(s,t),[i,a]=this.getXmlnsAttribute(o,m);a&&r.addAttribute(i,a),e.addChildNode(r);let l=QD.of(u);c.isListSchema()?this.writeList(c,n,l,m):c.isMapSchema()?this.writeMap(c,n,l,m,!0):c.isStructSchema()?l=this.writeStruct(c,n,m):this.writeSimpleInto(c,n,l,m),e.addChildNode(l)};if(f)for(let r in t){let i=t[r];if(d||i!=null){let t=QD.of(a.xmlName??e.getMemberName());h(t,r,i),n.addChildNode(t)}}else{let r;i||(r=QD.of(a.xmlName??e.getMemberName()),m&&r.addAttribute(p,m),n.addChildNode(r));for(let e in t){let a=t[e];if(d||a!=null){let t=QD.of(`entry`);h(t,e,a),(i?n:r).addChildNode(t)}}}}writeSimple(e,t){if(t===null)throw Error(`@aws-sdk/core/protocols - (XML serializer) cannot write null value.`);let n=sw.of(e),r=null;if(t&&typeof t==`object`)if(n.isBlobSchema())r=(this.serdeContext?.base64Encoder??EC)(t);else if(n.isTimestampSchema()&&t instanceof Date)switch(ST(n,this.settings)){case 5:r=t.toISOString().replace(`.000Z`,`Z`);break;case 6:r=kw(t);break;case 7:r=String(t.getTime()/1e3);break;default:console.warn(`Missing timestamp format, using http date`,t),r=kw(t);break}else if(n.isBigDecimalSchema()&&t)return t instanceof pT?t.string:String(t);else if(n.isMapSchema()||n.isListSchema())throw Error(`@aws-sdk/core/protocols - xml serializer, cannot call _write() on List/Map schema, call writeList or writeMap() instead.`);else throw Error(`@aws-sdk/core/protocols - xml serializer, unhandled schema type for object value and schema: ${n.getName(!0)}`);if((n.isBooleanSchema()||n.isNumericSchema()||n.isBigIntegerSchema()||n.isBigDecimalSchema())&&(r=String(t)),n.isStringSchema()&&(r=t===void 0&&n.isIdempotencyToken()?qw():String(t)),r===null)throw Error(`Unhandled schema-value pair ${n.getName(!0)}=${t}`);return r}writeSimpleInto(e,t,n,r){let i=this.writeSimple(e,t),a=sw.of(e),o=new ZD(i),[s,c]=this.getXmlnsAttribute(a,r);c&&n.addAttribute(s,c),n.addChildNode(o)}getXmlnsAttribute(e,t){let[n,r]=e.getMergedTraits().xmlNamespace??[];return r&&r!==t?[n?`xmlns:${n}`:`xmlns`,r]:[void 0,void 0]}},Cie=class extends XD{settings;constructor(e){super(),this.settings=e}createSerializer(){let e=new Sie(this.settings);return e.setSerdeContext(this.serdeContext),e}createDeserializer(){let e=new eO(this.settings);return e.setSerdeContext(this.serdeContext),e}},wie=class extends bT{codec;serializer;deserializer;mixin=new YD;constructor(e){super(e);let t={timestampFormat:{useTrait:!0,default:5},httpBindings:!0,xmlNamespace:e.xmlNamespace,serviceNamespace:e.defaultNamespace};this.codec=new Cie(t),this.serializer=new ET(this.codec.createSerializer(),t),this.deserializer=new wT(this.codec.createDeserializer(),t)}getPayloadCodec(){return this.codec}getShapeId(){return`aws.protocols#restXml`}async serializeRequest(e,t,n){let r=await super.serializeRequest(e,t,n),i=sw.of(e.input);if(!r.headers[`content-type`]){let e=this.mixin.resolveRestContentType(this.getDefaultContentType(),i);e&&(r.headers[`content-type`]=e)}return typeof r.body==`string`&&r.headers[`content-type`]===this.getDefaultContentType()&&!r.body.startsWith(``+r.body),r}async deserializeResponse(e,t,n){return super.deserializeResponse(e,t,n)}async handleError(e,t,n,r,i){let a=xie(n,r)??`Unknown`;if(this.mixin.compose(this.compositeErrorRegistry,a,this.options.defaultNamespace),r.Error&&typeof r.Error==`object`)for(let e of Object.keys(r.Error))r[e]=r.Error[e],e.toLowerCase()===`message`&&(r.message=r.Error[e]);r.RequestId&&!i.requestId&&(i.requestId=r.RequestId);let{errorSchema:o,errorMetadata:s}=await this.mixin.getErrorSchemaOrThrowBaseException(a,this.options.defaultNamespace,n,r,i),c=sw.of(o),l=r.Error?.message??r.Error?.Message??r.message??r.Message??`UnknownError`,u=new((this.compositeErrorRegistry.getErrorCtor(o))??Error)(l);await this.deserializeHttpMessage(o,t,n,r);let d={},f=this.codec.createDeserializer();for(let[e,t]of c.structIterator()){let n=t.getMergedTraits().xmlName??e,i=r.Error?.[n]??r[n];d[e]=f.readSchema(t,i)}throw this.mixin.decorateServiceException(Object.assign(u,s,{$fault:c.getMergedTraits().error,message:l},d),r)}getDefaultContentType(){return`application/xml`}hasUnstructuredPayloadBinding(e){for(let[,t]of e.structIterator())if(t.getMergedTraits().httpPayload)return!(t.isStructSchema()||t.isMapSchema()||t.isListSchema());return!1}},nO=`ref`,rO=-1,iO=!0,aO=`isSet`,oO=`PartitionResult`,sO=`booleanEquals`,cO=`getAttr`,lO={[nO]:`Endpoint`},uO={[nO]:oO},dO={},fO=[{[nO]:`Region`}],pO={conditions:[[aO,[lO]],[aO,fO],[`aws.partition`,fO,oO],[sO,[{[nO]:`UseFIPS`},iO]],[sO,[{[nO]:`UseDualStack`},iO]],[sO,[{fn:cO,argv:[uO,`supportsDualStack`]},iO]],[sO,[{fn:cO,argv:[uO,`supportsFIPS`]},iO]],[`stringEquals`,[{fn:cO,argv:[uO,`name`]},`aws-us-gov`]]],results:[[rO],[rO,`Invalid Configuration: FIPS and custom endpoint are not supported`],[rO,`Invalid Configuration: Dualstack and custom endpoint are not supported`],[lO,dO],[`https://ec2-fips.{Region}.{PartitionResult#dualStackDnsSuffix}`,dO],[rO,`FIPS and DualStack are enabled, but this partition does not support one or both`],[`https://ec2.{Region}.amazonaws.com`,dO],[`https://ec2-fips.{Region}.{PartitionResult#dnsSuffix}`,dO],[rO,`FIPS is enabled but this partition does not support FIPS`],[`https://ec2.{Region}.{PartitionResult#dualStackDnsSuffix}`,dO],[rO,`DualStack is enabled but this partition does not support DualStack`],[`https://ec2.{Region}.{PartitionResult#dnsSuffix}`,dO],[rO,`Invalid Configuration: Missing Region`]]},Tie=2,mO=1e8,Eie=new Int32Array([-1,1,-1,0,13,3,1,4,mO+12,2,5,mO+12,3,8,6,4,7,mO+11,5,mO+9,mO+10,4,11,9,6,10,mO+8,7,mO+6,mO+7,5,12,mO+5,6,mO+4,mO+5,3,mO+1,14,4,mO+2,mO+3]),Die=PT.from(Eie,Tie,pO.conditions,pO.results),Oie=new FT({size:50,params:[`Endpoint`,`Region`,`UseDualStack`,`UseFIPS`]}),kie=(e,t={})=>Oie.get(e,()=>pE(Die,{endpointParams:e,logger:t.logger}));zT.aws=SE;var Aie=class e extends TD{constructor(t){super(t),Object.setPrototypeOf(this,e.prototype)}},jie=`AllAvailabilityZones`,Mie=`AttributeBooleanValue`,Nie=`AssociateCarrierIpAddress`,Pie=`AdditionalFlexibleNetworkInterfaces`,Fie=`AvailableIpAddressCount`,Iie=`AssignIpv6AddressOnCreation`,Lie=`AttachInternetGateway`,Rie=`AttachInternetGatewayRequest`,hO=`AdditionalInfo`,gO=`AssociationId`,_O=`AttachmentId`,zie=`AmiLaunchIndex`,Bie=`AttachmentLimitType`,Vie=`AssociatePublicIpAddress`,Hie=`AmazonProvidedIpv6CidrBlock`,Uie=`AutoRecoverySupported`,Wie=`AssociateRouteTableRequest`,Gie=`AssociateRouteTableResult`,Kie=`AssociateRouteTable`,qie=`AllRegions`,vO=`AssociatedResource`,yO=`AutoRecovery`,bO=`AssociationState`,Jie=`AuthorizeSecurityGroupEgress`,Yie=`AuthorizeSecurityGroupEgressRequest`,Xie=`AuthorizeSecurityGroupEgressResult`,Zie=`AuthorizeSecurityGroupIngressRequest`,Qie=`AuthorizeSecurityGroupIngressResult`,$ie=`AuthorizeSecurityGroupIngress`,xO=`AmdSevSnp`,eae=`ArchitectureTypeList`,SO=`AttachTime`,tae=`AttachVolumeRequest`,nae=`AttributeValue`,rae=`AttachVolume`,CO=`AvailabilityZone`,iae=`AvailabilityZoneGeography`,aae=`AvailabilityZoneGeographyList`,wO=`AvailabilityZoneId`,oae=`AvailabilityZoneList`,sae=`AvailabilityZoneMessage`,cae=`AvailabilityZoneMessageList`,lae=`AvailabilityZoneSubGeography`,uae=`AvailabilityZoneSubGeographyList`,dae=`AvailabilityZones`,TO=`Accelerators`,fae=`Affinity`,EO=`Arn`,DO=`Architecture`,pae=`Associations`,OO=`Association`,mae=`Attribute`,kO=`Attachment`,AO=`Attachments`,hae=`BlobAttributeValue`,gae=`BaselineBandwidthInGbps`,jO=`BaselineBandwidthInMbps`,MO=`BlockDeviceMapping`,_ae=`BlockDeviceMappingList`,vae=`BlockDeviceMappingRequestList`,NO=`BlockDeviceMappings`,yae=`BlockDurationMinutes`,PO=`BaselineIops`,FO=`BootMode`,bae=`BootModeTypeList`,xae=`BareMetal`,IO=`BlockPublicAccessStates`,Sae=`BurstablePerformanceSupported`,LO=`BaselineThroughputInMBps`,RO=`BandwidthWeighting`,Cae=`BandwidthWeightingTypeList`,wae=`BandwidthWeightings`,zO=`CidrBlock`,Tae=`CidrBlockAssociationSet`,Eae=`CapacityBlockId`,Dae=`CidrBlockState`,Oae=`CoreCountList`,BO=`CoreCount`,kae=`CpuCredits`,VO=`CompletionDurationMinutes`,Aae=`CreationDate`,HO=`CarrierGatewayId`,jae=`CurrentGeneration`,Mae=`CarrierIp`,Nae=`CurrentInstanceBootMode`,Pae=`CreateInternetGateway`,Fae=`CreateInternetGatewayRequest`,Iae=`CreateInternetGatewayResult`,Lae=`CreateImageRequest`,Rae=`CreateImageResult`,UO=`CidrIp`,WO=`CidrIpv6`,GO=`CidrIpv4`,zae=`CoreInfo`,Bae=`CreateImage`,Vae=`CreateKeyPair`,Hae=`CreateKeyPairRequest`,KO=`CoreNetworkArn`,qO=`CpuOptions`,Uae=`CustomerOwnedIp`,Wae=`CustomerOwnedIpv4Pool`,Gae=`CpuOptionsRequest`,Kae=`CreatePlacementGroup`,qae=`CreatePlacementGroupRequest`,Jae=`CreatePlacementGroupResult`,JO=`CapacityReservationId`,YO=`CapacityReservationPreference`,Yae=`CreateRouteRequest`,XO=`CapacityReservationResourceGroupArn`,Xae=`CreateRouteResult`,Zae=`CapacityReservationSpecificationResponse`,ZO=`CapacityReservationSpecification`,QO=`CapacityReservationTarget`,Qae=`CapacityReservationTargetResponse`,$ae=`CreateRouteTableRequest`,eoe=`CreateRouteTableResult`,toe=`CreateRouteTable`,noe=`CreateRoute`,roe=`CreateSecurityGroup`,ioe=`CreateSecurityGroupRequest`,aoe=`CreateSecurityGroupResult`,ooe=`CopySnapshotRequest`,soe=`CopySnapshotRequestPSU`,coe=`CopySnapshotResult`,loe=`CreateSnapshotRequest`,uoe=`CreateSubnetRequest`,doe=`CreateSubnetResult`,foe=`CreditSpecificationRequest`,poe=`CopySnapshot`,moe=`CreditSpecification`,hoe=`CreateSnapshot`,goe=`CreateSubnet`,_oe=`CurrentState`,$O=`ClientToken`,ek=`ConnectionTrackingConfiguration`,voe=`ConnectionTrackingSpecification`,yoe=`ConnectionTrackingSpecificationRequest`,boe=`ConnectionTrackingSpecificationResponse`,xoe=`CompletionTime`,tk=`CreateTime`,Soe=`CreateVolumeRequest`,Coe=`CreateVpcRequest`,woe=`CreateVpcResult`,Toe=`CreateVolume`,Eoe=`CreateVpc`,nk=`Code`,rk=`Configured`,ik=`Count`,ak=`DisableApiStop`,ok=`DisableApiTermination`,Doe=`DestinationAvailabilityZone`,Ooe=`DescribeAvailabilityZonesRequest`,koe=`DescribeAvailabilityZonesResult`,Aoe=`DescribeAvailabilityZones`,sk=`DestinationCidrBlock`,joe=`DefaultConnectionTrackingConfiguration`,Moe=`DefaultCores`,Noe=`DataEncryptionKeyId`,Poe=`DefaultEnaQueueCountPerInterface`,Foe=`DefaultForAz`,Ioe=`DedicatedHostsSupported`,ck=`DeviceIndex`,lk=`DestinationIpv6CidrBlock`,Loe=`DescribeInternetGatewaysRequest`,Roe=`DescribeInternetGatewaysResult`,zoe=`DescribeInternetGateways`,Boe=`DiskInfoList`,Voe=`DescribeImagesRequest`,Hoe=`DescribeImagesResult`,Uoe=`DescribeInstancesRequest`,Woe=`DescribeInstancesResult`,Goe=`DescribeInstanceTypesRequest`,Koe=`DescribeInstanceTypesResult`,qoe=`DescribeInstanceTypes`,Joe=`DescribeImages`,Yoe=`DescribeInstances`,Xoe=`DiskInfo`,Zoe=`DeleteKeyPair`,Qoe=`DeleteKeyPairRequest`,$oe=`DeleteKeyPairResult`,ese=`DescribeKeyPairsRequest`,tse=`DescribeKeyPairsResult`,nse=`DescribeKeyPairs`,uk=`DeviceName`,rse=`DefaultNetworkCardIndex`,ise=`DestinationOutpostArn`,ase=`DhcpOptionsId`,dk=`DeleteOnTermination`,ose=`DeletePlacementGroup`,sse=`DeletePlacementGroupRequest`,cse=`DescribePlacementGroupsRequest`,lse=`DescribePlacementGroupsResult`,use=`DescribePlacementGroups`,fk=`DestinationPrefixListId`,dse=`DeregistrationProtection`,pk=`DryRun`,fse=`DescribeRegionsRequest`,pse=`DescribeRegionsResult`,mse=`DescribeRouteTablesRequest`,hse=`DescribeRouteTablesResult`,gse=`DescribeRouteTables`,_se=`DestinationRegion`,vse=`DescribeRegions`,yse=`DeleteSecurityGroup`,bse=`DeleteSecurityGroupRequest`,xse=`DeleteSecurityGroupResult`,Sse=`DescribeSecurityGroupsRequest`,Cse=`DescribeSecurityGroupsResult`,wse=`DescribeSecurityGroups`,Tse=`DeleteSnapshotRequest`,Ese=`DeleteSubnetRequest`,Dse=`DescribeSnapshotsRequest`,Ose=`DescribeSnapshotsResult`,kse=`DescribeSubnetsRequest`,Ase=`DescribeSubnetsResult`,jse=`DeleteSnapshot`,Mse=`DeleteSubnet`,Nse=`DescribeSnapshots`,Pse=`DescribeSubnets`,Fse=`DefaultTcpEstablishedTimeout`,Ise=`DefaultThreadsPerCore`,Lse=`DeprecationTime`,Rse=`DefaultUdpStreamTimeout`,zse=`DefaultUdpTimeout`,Bse=`DefaultVCpus`,Vse=`DeleteVolumeRequest`,Hse=`DeleteVpcRequest`,Use=`DescribeVolumesRequest`,Wse=`DescribeVolumesResult`,Gse=`DescribeVpcsRequest`,Kse=`DescribeVpcsResult`,qse=`DetachVolumeRequest`,Jse=`DeleteVolume`,Yse=`DeleteVpc`,Xse=`DescribeVolumes`,Zse=`DescribeVpcs`,Qse=`DetachVolume`,mk=`Description`,hk=`Device`,$se=`Disks`,ece=`EbsBlockDevice`,tce=`ExecutableByStringList`,gk=`ExecutableBy`,_k=`EbsCardIndex`,nce=`EbsCardInfoList`,rce=`EbsCardInfo`,ice=`EbsCards`,ace=`EncryptionControl`,oce=`EnableDns64`,sce=`ElasticFileSystem`,cce=`ElasticFileSystemExclusion`,lce=`ElasticGpuAssociation`,uce=`ElasticGpuAssociationId`,dce=`ElasticGpuAssociationList`,fce=`ElasticGpuAssociationState`,pce=`ElasticGpuAssociationTime`,mce=`ElasticGpuAssociations`,hce=`ElasticGpuId`,vk=`ElasticGpuSpecification`,gce=`ElasticGpuSpecifications`,yk=`ElasticInferenceAccelerator`,_ce=`ElasticInferenceAcceleratorAssociation`,vce=`ElasticInferenceAcceleratorAssociationId`,yce=`ElasticInferenceAcceleratorAssociationList`,bce=`ElasticInferenceAcceleratorAssociationState`,xce=`ElasticInferenceAcceleratorAssociationTime`,Sce=`ElasticInferenceAcceleratorArn`,Cce=`ElasticInferenceAcceleratorAssociations`,bk=`ElasticInferenceAccelerators`,wce=`EbsInstanceBlockDevice`,Tce=`EbsInstanceBlockDeviceSpecification`,Ece=`EncryptionInTransitSupported`,xk=`EbsInfo`,Sk=`EfaInfo`,Dce=`EnableLniAtDeviceIndex`,Ck=`EbsOptimized`,wk=`EbsOptimizedInfo`,Oce=`EgressOnlyInternetGateway`,kce=`EgressOnlyInternetGatewayExclusion`,Tk=`EgressOnlyInternetGatewayId`,Ace=`EnclaveOptionsRequest`,jce=`EbsOptimizedSupport`,Ek=`EnclaveOptions`,Mce=`EnablePrimaryIpv6`,Dk=`EnaQueueCount`,Ok=`EnableResourceNameDnsAAAARecord`,kk=`EnableResourceNameDnsARecord`,Ak=`EnaSrdEnabled`,jk=`EnaSrdSpecification`,Nce=`EnaSrdSpecificationRequest`,Pce=`EnaSrdSupported`,Mk=`EnaSrdUdpEnabled`,Nk=`EnaSrdUdpSpecification`,Fce=`EnaSrdUdpSpecificationRequest`,Ice=`EfaSupported`,Pk=`EncryptionSupport`,Fk=`EnaSupport`,Lce=`EndTime`,Rce=`ExecutableUsers`,Ik=`Ebs`,Lk=`Enabled`,Rk=`Encrypted`,zce=`Endpoint`,zk=`Force`,Bce=`FpgaDeviceInfo`,Vce=`FpgaDeviceInfoList`,Hce=`FpgaDeviceMemoryInfo`,Uce=`FlexibleEnaQueuesSupport`,Bk=`FpgaInfo`,Wce=`FilterList`,Vk=`FromPort`,Gce=`FastRestored`,Kce=`FullSnapshotSizeInBytes`,Hk=`FreeTierEligible`,Uk=`Filters`,Wk=`Filter`,qce=`Fpgas`,Gk=`Groups`,Jce=`GroupArn`,Yce=`GetConsoleOutput`,Xce=`GetConsoleOutputRequest`,Zce=`GetConsoleOutputResult`,Qce=`GroupDescription`,$ce=`GpuDeviceInfo`,ele=`GpuDeviceInfoList`,tle=`GpuDeviceMemoryInfo`,Kk=`GatewayId`,nle=`GroupIdentifierList`,rle=`GroupIdStringList`,qk=`GpuInfo`,Jk=`GroupId`,Yk=`GroupIds`,ile=`GroupIdentifier`,ale=`GroupLongName`,Xk=`GroupName`,ole=`GroupNameStringList`,Zk=`GroupNames`,sle=`GroupOwnerId`,cle=`GpuPartitionSize`,Qk=`Geography`,lle=`Gpus`,ule=`HiddenByDefault`,$k=`HttpEndpoint`,dle=`HostId`,eA=`HibernationOptions`,fle=`HibernationOptionsRequest`,tA=`HttpProtocolIpv6`,nA=`HttpPutResponseHopLimit`,ple=`HostResourceGroupArn`,mle=`HibernationSupported`,rA=`HttpTokens`,iA=`HostnameType`,hle=`Hibernate`,aA=`Hypervisor`,gle=`Id`,oA=`Ipv6Addresses`,sA=`Ipv6AddressAttribute`,cA=`Ipv6AddressCount`,_le=`InstanceAttachmentEnaSrdSpecification`,vle=`InstanceAttachmentEnaSrdUdpSpecification`,lA=`InferenceAcceleratorInfo`,yle=`Ipv4AddressesPerInterface`,ble=`Ipv6AddressesPerInterface`,xle=`Ipv4AddressesPerSecondaryInterface`,Sle=`ImageAllowed`,Cle=`IpAddress`,uA=`Ipv6Address`,wle=`InstanceBlockDeviceMapping`,Tle=`InstanceBlockDeviceMappingList`,Ele=`InstanceBlockDeviceMappingSpecification`,Dle=`InstanceBlockDeviceMappingSpecificationList`,dA=`Ipv6CidrBlock`,fA=`Ipv6CidrBlockAssociationSet`,Ole=`Ipv6CidrBlockNetworkBorderGroup`,pA=`Ipv6CidrBlockState`,kle=`IncludeDeprecated`,Ale=`InferenceDeviceInfo`,jle=`InferenceDeviceInfoList`,Mle=`InferenceDeviceMemoryInfo`,Nle=`IncludeDisabled`,Ple=`IsDefault`,mA=`IsEgress`,hA=`InternetGateway`,Fle=`InternetGatewayAttachment`,Ile=`InternetGatewayAttachmentList`,Lle=`InternetGatewayBlockMode`,Rle=`InternetGatewayExclusion`,gA=`InternetGatewayId`,zle=`InternetGatewayIdList`,Ble=`InternetGatewayIds`,Vle=`InternetGatewayList`,Hle=`InternetGateways`,_A=`InstanceId`,Ule=`InstanceIpv6Address`,Wle=`InstanceIpv6AddressList`,Gle=`InstanceInterruptionBehavior`,vA=`IamInstanceProfile`,yA=`Ipv6IpamPoolId`,bA=`Ipv4IpamPoolId`,Kle=`InstanceIpv4PrefixList`,qle=`InstanceIpv6PrefixList`,Jle=`IamInstanceProfileSpecification`,Yle=`InstanceIpv4Prefix`,Xle=`InstanceIpv6Prefix`,xA=`InstanceInitiatedShutdownBehavior`,Zle=`ImageIdStringList`,Qle=`InstanceIdStringList`,SA=`ImageId`,$le=`ImageIds`,CA=`InstanceIds`,eue=`ImportKeyPair`,tue=`ImportKeyPairRequest`,nue=`ImportKeyPairResult`,rue=`ImageLocation`,iue=`ImageList`,aue=`InstanceLifecycle`,wA=`InstanceList`,TA=`InstanceMaintenanceOptions`,EA=`InstanceMaintenanceOptionsRequest`,DA=`InstanceMarketOptionsRequest`,OA=`InstanceMetadataOptionsRequest`,kA=`InstanceMetadataOptionsResponse`,AA=`InstanceMarketOptions`,jA=`IncludeManagedResources`,MA=`InstanceMetadataTags`,NA=`Ipv6Native`,PA=`InstanceNetworkInterface`,FA=`InstanceNetworkInterfaceAssociation`,IA=`InstanceNetworkInterfaceAttachment`,LA=`InstanceNetworkInterfaceList`,RA=`InstanceNetworkInterfaceSpecification`,zA=`InstanceNetworkInterfaceSpecificationList`,BA=`Ipv6NetmaskLength`,VA=`Ipv4NetmaskLength`,HA=`InstanceNetworkPerformanceOptions`,UA=`InstanceNetworkPerformanceOptionsRequest`,WA=`ImageOwnerAlias`,GA=`IpOwnerId`,KA=`InstanceOwnerId`,qA=`InstanceOwningService`,JA=`Ipv6PrefixCount`,YA=`Ipv4PrefixCount`,XA=`IpPermissionsEgress`,ZA=`InstancePrivateIpAddress`,QA=`InstancePrivateIpAddressList`,$A=`IsPrimaryIpv6`,ej=`IncludePublicKey`,tj=`IpPermissionList`,nj=`Ipv4PrefixList`,rj=`Ipv6PrefixList`,ij=`Ipv4PrefixSpecificationRequest`,aj=`Ipv6PrefixSpecificationRequest`,oj=`Ipv6Prefixes`,sj=`IpPermissions`,cj=`IpPermission`,lj=`IpProtocol`,uj=`Ipv6Prefix`,dj=`Ipv6Pool`,fj=`Ipv4Prefixes`,pj=`Ipv4Prefix`,mj=`IpRangeList`,hj=`Ipv6RangeList`,gj=`IpRanges`,_j=`IpRange`,vj=`Ipv6Ranges`,yj=`Ipv6Range`,bj=`InstanceStateChange`,xj=`InstanceStateChangeList`,Sj=`InstanceSecondaryInterfaceAttachment`,Cj=`InstanceSecondaryInterfaceList`,wj=`InstanceSecondaryInterfacePrivateIpAddress`,Tj=`InstanceSecondaryInterfacePrivateIpAddressList`,Ej=`InstanceSecondaryInterfacePrivateIpAddressListRequest`,Dj=`InstanceSecondaryInterfacePrivateIpAddressRequest`,Oj=`InstanceSecondaryInterfaceSpecificationListRequest`,kj=`InstanceSecondaryInterfaceSpecificationRequest`,Aj=`InstanceSecondaryInterface`,jj=`InstanceStorageInfo`,Mj=`InstanceStorageSupported`,Nj=`ImdsSupport`,Pj=`InstanceState`,Fj=`IpSource`,Ij=`Ipv6Supported`,Lj=`InstanceType`,Rj=`InstanceTypeInfoList`,zj=`InstanceTypeInfo`,Bj=`ImageType`,Vj=`InstanceTenancy`,Hj=`InstanceTypes`,Uj=`InterfaceType`,Wj=`IncludeUnsupportedInRegion`,Gj=`Images`,Kj=`Image`,qj=`Instance`,Jj=`Instances`,Yj=`Iops`,Xj=`Key`,Zj=`KeyFormat`,Qj=`KeyFingerprint`,$j=`KernelId`,eM=`KmsKeyId`,tM=`KeyMaterial`,nM=`KeyName`,rM=`KeyNameStringList`,iM=`KeyNames`,aM=`KeyPairs`,oM=`KeyPairId`,sM=`KeyPairIdStringList`,cM=`KeyPairIds`,lM=`KeyPairInfo`,uM=`KeyPairList`,dM=`KeyPair`,fM=`KeyType`,pM=`Kernel`,mM=`LicenseConfigurationArn`,hM=`LicenseConfigurationRequest`,gM=`LicenseConfiguration`,_M=`LambdaExclusion`,vM=`LogicalGpuCount`,yM=`LocalGatewayId`,bM=`LinkedGroupId`,xM=`LicenseList`,SM=`LastLaunchedTime`,CM=`LicenseSpecifications`,wM=`LicenseSpecificationListRequest`,TM=`LicenseSpecification`,EM=`LaunchTemplate`,DM=`LaunchTemplateId`,OM=`LaunchTemplateName`,kM=`LaunchTemplateSpecification`,AM=`LaunchTime`,jM=`Latest`,MM=`Lambda`,NM=`Licenses`,PM=`Location`,FM=`MultiAttachEnabled`,IM=`MediaAcceleratorInfo`,LM=`MacAddress`,RM=`MaximumBandwidthInMbps`,zM=`MapCustomerOwnedIpOnLaunch`,BM=`MaxCount`,VM=`MinCount`,HM=`MediaDeviceInfo`,UM=`MediaDeviceInfoList`,WM=`MediaDeviceMemoryInfo`,GM=`MaximumEbsAttachments`,KM=`MaximumEbsCards`,qM=`MaximumEfaInterfaces`,JM=`MaximumEnaQueueCount`,YM=`MaximumEnaQueueCountPerInterface`,XM=`MaximumIops`,ZM=`ModifyInstanceAttributeRequest`,QM=`ModifyInstanceAttributeValue`,$M=`ModifyInstanceAttribute`,eN=`MemoryInfo`,tN=`MaximumNetworkCards`,nN=`MaximumNetworkInterfaces`,rN=`MetadataOptions`,iN=`MaintenanceOptions`,aN=`MapPublicIpOnLaunch`,oN=`MaxPrice`,sN=`MaxResults`,cN=`MaximumSecondaryNetworkInterfaces`,lN=`ModificationState`,uN=`MarketType`,dN=`MaximumThroughputInMBps`,fN=`ModifyVolumeRequest`,pN=`ModifyVolumeResult`,mN=`ModifyVolume`,hN=`Main`,gN=`Manufacturer`,_N=`Managed`,vN=`Message`,yN=`Messages`,bN=`Mode`,xN=`Monitoring`,SN=`Name`,CN=`NetworkBorderGroup`,wN=`NetworkCards`,TN=`NetworkCardIndex`,EN=`NetworkCardInfoList`,DN=`NetworkCardInfo`,ON=`NoDevice`,kN=`NeuronDeviceCoreInfo`,AN=`NeuronDeviceInfo`,jN=`NeuronDeviceInfoList`,MN=`NeuronDeviceMemoryInfo`,NN=`NeuronDevices`,PN=`NitroEnclavesSupport`,FN=`NatGateway`,IN=`NatGatewayExclusion`,LN=`NatGatewayId`,RN=`NetworkInterfaceId`,zN=`NetworkInterfaces`,BN=`NetworkInfo`,VN=`NeuronInfo`,HN=`NetworkPerformanceOptions`,UN=`NetworkPerformance`,WN=`NoReboot`,GN=`NvmeSupport`,KN=`NitroTpmInfo`,qN=`NitroTpmSupport`,JN=`NitroTpmSupportedVersionsList`,YN=`NextToken`,XN=`NestedVirtualization`,ZN=`Origin`,QN=`OutpostArn`,$N=`OwnerAlias`,eP=`OwnerId`,tP=`OptInStatus`,nP=`OriginalIops`,rP=`OwnerIds`,iP=`OriginalMultiAttachEnabled`,aP=`OdbNetworkArn`,oP=`OperatorRequest`,sP=`OperatorResponse`,cP=`OwnerStringList`,lP=`OriginalSize`,uP=`OriginalThroughput`,dP=`OriginalVolumeType`,fP=`Operator`,pP=`Output`,mP=`Owners`,hP=`Owner`,gP=`Principal`,_P=`PeakBandwidthInGbps`,vP=`ProductCodeId`,yP=`ProductCodeList`,bP=`ProductCodeType`,xP=`PartitionCount`,SP=`ProductCode`,CP=`ProductCodes`,wP=`PrivateDnsName`,TP=`PrivateDnsNameOptions`,EP=`PrivateDnsNameOptionsOnLaunch`,DP=`PrivateDnsNameOptionsRequest`,OP=`PrivateDnsNameOptionsResponse`,kP=`PublicDnsName`,AP=`PlatformDetails`,jP=`PlacementGroup`,MP=`PlacementGroupInfo`,NP=`PlacementGroupIdStringList`,PP=`PlacementGroupList`,FP=`PlacementGroupStrategyList`,IP=`PlacementGroups`,LP=`PublicIp`,RP=`PrivateIpAddressCount`,zP=`PrivateIpAddressSpecification`,BP=`PrivateIpAddressSpecificationList`,VP=`PrivateIpAddress`,HP=`PrivateIpAddresses`,UP=`PublicIpAddress`,WP=`PublicIpv4Pool`,GP=`PrimaryIpv6`,KP=`ProcessorInfo`,qP=`PublicKey`,JP=`PublicKeyMaterial`,YP=`PrefixListId`,XP=`PrefixListIdList`,ZP=`PrefixListIds`,QP=`PartitionNumber`,$P=`PeeringStatus`,eF=`PhcSupport`,tF=`PreviousState`,nF=`PresignedUrl`,rF=`PropagatingVgw`,iF=`PropagatingVgwList`,aF=`PropagatingVgws`,oF=`ParentZoneId`,sF=`ParentZoneName`,cF=`Platform`,lF=`Placement`,uF=`Primary`,dF=`Progress`,fF=`Public`,pF=`Return`,mF=`RestorableByUserIds`,hF=`RestorableBy`,gF=`RootDeviceName`,_F=`RootDeviceType`,vF=`RootDeviceTypeList`,yF=`RestoreExpiryTime`,bF=`ResourceExclusions`,xF=`RegionGeography`,SF=`ReferencedGroupId`,CF=`ReferencedGroupInfo`,wF=`RegionGeographyList`,TF=`RunInstancesMonitoringEnabled`,EF=`RebootInstancesRequest`,DF=`RunInstancesRequest`,OF=`RunInstancesUserData`,kF=`RamdiskId`,AF=`ReservationId`,jF=`RebootInstances`,MF=`RequesterId`,NF=`RunInstances`,PF=`RegionList`,FF=`ReservationList`,IF=`RouteList`,LF=`RebootMigrationSupport`,RF=`RebootMigration`,zF=`RegionName`,BF=`RegionNameStringList`,VF=`RegionNames`,HF=`ReferencedSecurityGroup`,UF=`RevokeSecurityGroupEgress`,WF=`RevokeSecurityGroupEgressRequest`,GF=`RevokeSecurityGroupEgressResult`,KF=`RevokeSecurityGroupIngressRequest`,qF=`RevokeSecurityGroupIngressResult`,JF=`RevokeSecurityGroupIngress`,YF=`RevokedSecurityGroupRule`,XF=`RevokedSecurityGroupRuleList`,ZF=`RevokedSecurityGroupRules`,QF=`RouteTableAssociation`,$F=`RouteTableAssociationId`,eI=`RouteTableAssociationList`,tI=`RouteTableAssociationState`,nI=`RouteTableId`,rI=`RouteTableIdStringList`,iI=`RouteTableIds`,aI=`RouteTableList`,oI=`ResourceType`,sI=`RouteTable`,cI=`RouteTables`,lI=`Ramdisk`,uI=`Regions`,dI=`Region`,fI=`Reservations`,pI=`Reservation`,mI=`Route`,hI=`Routes`,gI=`SupportedAdditionalProcessorFeatureList`,_I=`SubnetArn`,vI=`SupportedArchitectures`,yI=`SupportedBootModes`,bI=`SubnetCidrBlockState`,xI=`SustainedClockSpeedInGhz`,SI=`SourceDestCheck`,CI=`SpreadDomain`,wI=`SupportedFeatures`,TI=`SubGeography`,EI=`SecurityGroupArn`,DI=`SecurityGroupId`,OI=`SecurityGroupIdStringList`,kI=`SecurityGroupIds`,AI=`SecurityGroupList`,jI=`SecurityGroupRules`,MI=`SecurityGroupRuleArn`,NI=`SecurityGroupRuleIds`,PI=`SecurityGroupRuleIdList`,FI=`SecurityGroupRuleId`,II=`SecurityGroupRuleList`,LI=`SecurityGroupRule`,RI=`SecurityGroupStringList`,zI=`SecurityGroups`,BI=`SecurityGroup`,VI=`SubnetIds`,HI=`SubnetIpv6CidrBlockAssociation`,UI=`SubnetIpv6CidrBlockAssociationSet`,WI=`SizeInGB`,GI=`SourceImageId`,KI=`SecondaryInterfaceId`,qI=`SourceInstanceId`,JI=`SizeInMiB`,YI=`SpotInstanceRequestId`,XI=`SourceImageRegion`,ZI=`StartInstancesRequest`,QI=`StartInstancesResult`,$I=`StopInstancesRequest`,eL=`StopInstancesResult`,tL=`SupportedInRegion`,nL=`SnapshotIdStringList`,rL=`SubnetIdStringList`,iL=`SpotInstanceType`,aL=`SecondaryInterfaces`,oL=`SecondaryInterface`,sL=`SnapshotId`,cL=`SnapshotIds`,lL=`StartingInstances`,uL=`StartInstances`,dL=`StoppingInstances`,fL=`StopInstances`,pL=`SubnetId`,mL=`SnapshotLocation`,hL=`SnapshotList`,gL=`SpreadLevel`,_L=`SubnetList`,vL=`SpotMarketOptions`,yL=`StatusMessage`,bL=`StateMessage`,xL=`SecondaryNetworkId`,SL=`SriovNetSupport`,CL=`SecondaryNetworkSupported`,wL=`SpotOptions`,TL=`SkipOsShutdown`,EL=`SecondaryPrivateIpAddressCount`,DL=`SupportedRootDeviceTypes`,OL=`SourceRegion`,kL=`StateReason`,AL=`SourceSecurityGroupName`,jL=`SourceSecurityGroupOwnerId`,ML=`SourceSnapshotId`,NL=`SecondarySubnetId`,PL=`SupportedStrategies`,FL=`StartTime`,IL=`StateTransitionReason`,LL=`SseType`,RL=`StorageTier`,zL=`SupportedUsageClasses`,BL=`SensitiveUserData`,VL=`SourceVolumeId`,HL=`SupportedVirtualizationTypes`,UL=`SupportedVersions`,WL=`Size`,GL=`Snapshots`,KL=`Snapshot`,qL=`State`,JL=`Status`,YL=`Strategy`,XL=`Subnet`,ZL=`Subnets`,QL=`Tags`,$L=`TcpEstablishedTimeout`,eR=`TotalFpgaMemoryInMiB`,tR=`TransitGatewayId`,nR=`TotalGpuMemoryInMiB`,rR=`TerminateInstances`,iR=`TotalInferenceMemoryInMiB`,aR=`TerminateInstancesRequest`,oR=`TerminateInstancesResult`,sR=`TargetIops`,cR=`TerminatingInstances`,lR=`TagList`,uR=`TargetMultiAttachEnabled`,dR=`TotalMediaMemoryInMiB`,fR=`TotalNeuronDeviceMemoryInMiB`,pR=`ToPort`,mR=`ThreadsPerCore`,hR=`ThreadsPerCoreList`,gR=`TagSpecifications`,_R=`TotalSizeInGB`,vR=`TagSpecificationList`,yR=`TagSpecification`,bR=`TargetSize`,xR=`TpmSupport`,SR=`TargetThroughput`,CR=`TransferType`,wR=`TargetVolumeType`,TR=`Tag`,ER=`Tenancy`,DR=`Throughput`,OR=`Timestamp`,kR=`Type`,AR=`UsageClassTypeList`,jR=`UserData`,MR=`UserId`,NR=`UserIdGroupPairs`,PR=`UserIdGroupPairList`,FR=`UserIdGroupPair`,IR=`UnknownIpPermissions`,LR=`UsageOperation`,RR=`UsageOperationUpdateTime`,zR=`UdpStreamTimeout`,BR=`UdpTimeout`,VR=`Value`,HR=`VolumeAttachmentList`,UR=`VolumeAttachment`,WR=`VpcCidrBlockAssociation`,GR=`VpcCidrBlockAssociationSet`,KR=`VpcCidrBlockState`,qR=`VCpuInfo`,JR=`ValidCores`,YR=`VpcEncryptionControl`,XR=`VpcEncryptionControlConfiguration`,ZR=`VpcEncryptionControlExclusion`,QR=`VpcEncryptionControlExclusions`,$R=`VpcEncryptionControlId`,ez=`VpcEndpointId`,tz=`VpcId`,nz=`VpcIpv6CidrBlockAssociation`,rz=`VpcIpv6CidrBlockAssociationSet`,iz=`VolumeInitializationRate`,az=`VolumeIdStringList`,oz=`VpcIdStringList`,sz=`VolumeId`,cz=`VolumeIds`,lz=`VpcIds`,uz=`VpcLattice`,dz=`VpcLatticeExclusion`,fz=`VolumeList`,pz=`VpcList`,mz=`VolumeModification`,hz=`VirtualName`,gz=`VolumeOwnerId`,_z=`VpcPeeringConnectionId`,vz=`VpcPeeringExclusion`,yz=`VirtualPrivateGateway`,bz=`VirtualPrivateGatewayExclusion`,xz=`VpcPeering`,Sz=`ValueStringList`,Cz=`VolumeSize`,wz=`VolumeType`,Tz=`VirtualizationTypeList`,Ez=`ValidThreadsPerCore`,Dz=`VirtualizationType`,Oz=`ValidUntil`,kz=`Values`,Az=`Version`,jz=`Volumes`,Mz=`Volume`,Nz=`Vpc`,Pz=`Vpcs`,Fz=`WorkloadsList`,Iz=`Workloads`,Lz=`ZoneId`,Rz=`ZoneIdStringList`,zz=`ZoneIds`,Bz=`ZoneName`,Vz=`ZoneNameStringList`,Hz=`ZoneNames`,Uz=`ZoneType`,Wz=`additionalFlexibleNetworkInterfaces`,Gz=`availableIpAddressCount`,Kz=`assignIpv6AddressOnCreation`,qz=`additionalInfo`,Jz=`associationId`,Yz=`attachmentId`,Xz=`amiLaunchIndex`,Zz=`attachmentLimitType`,Qz=`associatePublicIpAddress`,$z=`amazonProvidedIpv6CidrBlock`,eB=`autoRecoverySupported`,tB=`associatedResource`,nB=`autoRecovery`,rB=`associationState`,iB=`amdSevSnp`,aB=`associationSet`,oB=`attachmentSet`,sB=`attachTime`,cB=`availabilityZone`,lB=`availabilityZoneId`,uB=`availabilityZoneInfo`,dB=`accelerators`,fB=`affinity`,pB=`arn`,mB=`architecture`,hB=`association`,gB=`attachment`,_B=`attribute`,vB=`baselineBandwidthInGbps`,yB=`baselineBandwidthInMbps`,bB=`blockDeviceMapping`,xB=`baselineIops`,SB=`bootMode`,CB=`bareMetal`,wB=`blockPublicAccessStates`,TB=`burstablePerformanceSupported`,EB=`baselineThroughputInMBps`,DB=`bandwidthWeighting`,OB=`bandwidthWeightings`,kB=`cidrBlock`,AB=`cidrBlockAssociationSet`,jB=`capacityBlockId`,MB=`cidrBlockState`,NB=`coreCount`,PB=`completionDurationMinutes`,FB=`creationDate`,IB=`carrierGatewayId`,LB=`currentGeneration`,RB=`carrierIp`,zB=`currentInstanceBootMode`,BB=`cidrIp`,VB=`cidrIpv6`,HB=`cidrIpv4`,UB=`coreInfo`,WB=`coreNetworkArn`,GB=`cpuOptions`,KB=`customerOwnedIp`,qB=`customerOwnedIpv4Pool`,JB=`capacityReservationId`,YB=`capacityReservationPreference`,XB=`capacityReservationResourceGroupArn`,ZB=`capacityReservationSpecification`,QB=`capacityReservationTarget`,$B=`currentState`,eV=`clientToken`,tV=`connectionTrackingConfiguration`,nV=`completionTime`,rV=`createTime`,iV=`code`,aV=`configured`,oV=`count`,sV=`disableApiTermination`,cV=`destinationCidrBlock`,lV=`defaultCores`,uV=`dataEncryptionKeyId`,dV=`defaultEnaQueueCountPerInterface`,fV=`defaultForAz`,pV=`dedicatedHostsSupported`,mV=`deviceIndex`,hV=`destinationIpv6CidrBlock`,gV=`deviceName`,_V=`defaultNetworkCardIndex`,vV=`dnsName`,yV=`dhcpOptionsId`,bV=`deleteOnTermination`,xV=`destinationPrefixListId`,SV=`deregistrationProtection`,CV=`dryRun`,wV=`destinationRegion`,TV=`defaultTcpEstablishedTimeout`,EV=`defaultThreadsPerCore`,DV=`deprecationTime`,OV=`defaultUdpStreamTimeout`,kV=`defaultUdpTimeout`,AV=`defaultVCpus`,jV=`description`,MV=`device`,NV=`disks`,PV=`ebsCardIndex`,FV=`ebsCardSet`,IV=`encryptionControl`,LV=`enableDns64`,RV=`elasticFileSystem`,zV=`elasticGpuAssociationId`,BV=`elasticGpuAssociationState`,VV=`elasticGpuAssociationSet`,HV=`elasticGpuAssociationTime`,UV=`elasticGpuId`,WV=`elasticInferenceAcceleratorArn`,GV=`elasticInferenceAcceleratorAssociationId`,KV=`elasticInferenceAcceleratorAssociationState`,qV=`elasticInferenceAcceleratorAssociationSet`,JV=`elasticInferenceAcceleratorAssociationTime`,YV=`encryptionInTransitSupported`,XV=`ebsInfo`,ZV=`efaInfo`,QV=`enableLniAtDeviceIndex`,$V=`ebsOptimized`,eH=`ebsOptimizedInfo`,tH=`egressOnlyInternetGateway`,nH=`egressOnlyInternetGatewayId`,rH=`ebsOptimizedSupport`,iH=`enclaveOptions`,aH=`enaQueueCount`,H=`ec2QueryName`,oH=`enableResourceNameDnsAAAARecord`,sH=`enableResourceNameDnsARecord`,cH=`enaSrdEnabled`,lH=`enaSrdSpecification`,uH=`enaSrdSupported`,dH=`enaSrdUdpEnabled`,fH=`enaSrdUdpSpecification`,pH=`efaSupported`,mH=`encryptionSupport`,hH=`enaSupport`,gH=`endTime`,_H=`ebs`,vH=`enabled`,yH=`encrypted`,bH=`flexibleEnaQueuesSupport`,xH=`fpgaInfo`,SH=`fromPort`,CH=`fastRestored`,wH=`fullSnapshotSizeInBytes`,TH=`freeTierEligible`,EH=`force`,DH=`fpgas`,OH=`groupArn`,kH=`groupDescription`,AH=`gatewayId`,jH=`gpuInfo`,MH=`groupId`,NH=`groupLongName`,PH=`groupName`,FH=`groupOwnerId`,IH=`gpuPartitionSize`,LH=`geographySet`,RH=`groupSet`,zH=`gpus`,BH=`groups`,VH=`hypervisor`,HH=`hiddenByDefault`,UH=`httpEndpoint`,WH=`hostId`,GH=`hibernationOptions`,KH=`httpProtocolIpv6`,qH=`httpPutResponseHopLimit`,JH=`hostResourceGroupArn`,YH=`hibernationSupported`,XH=`httpTokens`,ZH=`hostnameType`,QH=`id`,$H=`ipv6AddressAttribute`,eU=`ipv6AddressCount`,tU=`inferenceAcceleratorInfo`,nU=`ipv4AddressesPerInterface`,rU=`ipv6AddressesPerInterface`,iU=`ipv4AddressesPerSecondaryInterface`,aU=`ipv6AddressesSet`,oU=`imageAllowed`,sU=`ipAddress`,cU=`ipv6Address`,lU=`ipv6CidrBlock`,uU=`ipv6CidrBlockAssociationSet`,dU=`ipv6CidrBlockState`,fU=`isDefault`,pU=`isEgress`,mU=`internetGateway`,hU=`internetGatewayBlockMode`,gU=`internetGatewayId`,_U=`internetGatewaySet`,vU=`instanceId`,yU=`iamInstanceProfile`,bU=`instanceInitiatedShutdownBehavior`,xU=`imageId`,SU=`imageLocation`,CU=`instanceLifecycle`,wU=`instanceMetadataTags`,TU=`ipv6Native`,EU=`imageOwnerAlias`,DU=`imageOwnerId`,OU=`instanceOwnerId`,kU=`ipOwnerId`,AU=`instanceOwningService`,jU=`ipPermissionsEgress`,MU=`isPrimaryIpv6`,NU=`ipv4PrefixSet`,PU=`ipv6PrefixSet`,FU=`ipProtocol`,IU=`ipPermissions`,LU=`ipv4Prefix`,RU=`ipv6Pool`,zU=`ipv6Prefix`,BU=`isPublic`,VU=`ipRanges`,HU=`ipv6Ranges`,UU=`instanceStorageInfo`,WU=`instanceStorageSupported`,GU=`imagesSet`,KU=`imageState`,qU=`imdsSupport`,JU=`instancesSet`,YU=`instanceState`,XU=`ipSource`,ZU=`ipv6Supported`,QU=`instanceType`,$U=`instanceTypeSet`,eW=`idempotencyToken`,tW=`imageType`,nW=`instanceTenancy`,rW=`interfaceType`,iW=`iops`,U=`item`,aW=`key`,oW=`keyFingerprint`,sW=`kernelId`,cW=`kmsKeyId`,lW=`keyMaterial`,uW=`keyName`,dW=`keyPairId`,fW=`keySet`,pW=`keyType`,mW=`kernel`,hW=`licenseConfigurationArn`,gW=`logicalGpuCount`,_W=`localGatewayId`,vW=`linkedGroupId`,yW=`lastLaunchedTime`,bW=`licenseSet`,xW=`launchTime`,SW=`lambda`,CW=`multiAttachEnabled`,wW=`mediaAcceleratorInfo`,TW=`macAddress`,EW=`maximumBandwidthInMbps`,DW=`mapCustomerOwnedIpOnLaunch`,OW=`maximumEbsAttachments`,kW=`maximumEbsCards`,AW=`maximumEfaInterfaces`,jW=`maximumEnaQueueCount`,MW=`maximumEnaQueueCountPerInterface`,NW=`maximumIops`,PW=`memoryInfo`,FW=`maximumNetworkCards`,IW=`maximumNetworkInterfaces`,LW=`metadataOptions`,RW=`maintenanceOptions`,zW=`mapPublicIpOnLaunch`,BW=`maxResults`,VW=`messageSet`,HW=`maximumSecondaryNetworkInterfaces`,UW=`modificationState`,WW=`maximumThroughputInMBps`,GW=`main`,KW=`manufacturer`,qW=`managed`,JW=`message`,YW=`monitoring`,XW=`mode`,ZW=`name`,QW=`networkBorderGroup`,$W=`networkCards`,eG=`networkCardIndex`,tG=`noDevice`,nG=`neuronDevices`,rG=`nitroEnclavesSupport`,iG=`natGateway`,aG=`natGatewayId`,oG=`networkInterfaceId`,sG=`networkInterfaceSet`,cG=`networkInterface`,lG=`networkInfo`,uG=`neuronInfo`,dG=`networkPerformanceOptions`,fG=`networkPerformance`,pG=`noReboot`,mG=`nvmeSupport`,hG=`nitroTpmInfo`,gG=`nitroTpmSupport`,_G=`nextToken`,vG=`nestedVirtualization`,yG=`origin`,bG=`outpostArn`,xG=`ownerAlias`,SG=`ownerId`,CG=`optInStatus`,wG=`originalIops`,TG=`originalMultiAttachEnabled`,EG=`odbNetworkArn`,DG=`originalSize`,OG=`originalThroughput`,kG=`originalVolumeType`,AG=`operator`,jG=`output`,MG=`principal`,NG=`peakBandwidthInGbps`,PG=`productCodes`,FG=`partitionCount`,IG=`productCode`,LG=`privateDnsNameOptions`,RG=`privateDnsNameOptionsOnLaunch`,zG=`privateDnsName`,BG=`publicDnsName`,VG=`platformDetails`,HG=`placementGroup`,UG=`placementGroupInfo`,WG=`placementGroupSet`,GG=`publicIp`,KG=`privateIpAddressesSet`,qG=`privateIpAddressSet`,JG=`privateIpAddress`,YG=`publicIpv4Pool`,XG=`processorInfo`,ZG=`publicKey`,QG=`publicKeyMaterial`,$G=`prefixListId`,eK=`prefixListIds`,tK=`partitionNumber`,nK=`peeringStatus`,rK=`phcSupport`,iK=`previousState`,aK=`presignedUrl`,oK=`propagatingVgwSet`,sK=`parentZoneId`,cK=`parentZoneName`,lK=`platform`,uK=`placement`,dK=`primary`,fK=`progress`,pK=`return`,mK=`rootDeviceName`,hK=`rootDeviceType`,gK=`restoreExpiryTime`,_K=`regionEndpoint`,vK=`resourceExclusions`,yK=`referencedGroupId`,bK=`referencedGroupInfo`,xK=`reservationId`,SK=`ramdiskId`,CK=`regionInfo`,wK=`requesterId`,TK=`rebootMigrationSupport`,EK=`rebootMigration`,DK=`regionName`,OK=`revokedSecurityGroupRuleSet`,kK=`reservationSet`,AK=`routeSet`,jK=`routeTableAssociationId`,MK=`routeTableId`,NK=`routeTableSet`,PK=`resourceType`,FK=`routeTable`,IK=`ramdisk`,LK=`reason`,RK=`smithy.ts.sdk.synthetic.com.amazonaws.ec2`,zK=`supportedArchitectures`,BK=`subnetArn`,VK=`supportedBootModes`,HK=`sustainedClockSpeedInGhz`,UK=`sourceDestCheck`,WK=`spreadDomain`,GK=`supportedFeatures`,KK=`securityGroupArn`,qK=`securityGroupInfo`,JK=`securityGroupRuleArn`,YK=`securityGroupRuleId`,XK=`securityGroupRuleSet`,ZK=`subGeographySet`,QK=`sizeInGB`,$K=`sourceInstanceId`,eq=`secondaryInterfaceId`,tq=`sourceImageId`,nq=`sizeInMiB`,rq=`sourceImageRegion`,iq=`spotInstanceRequestId`,aq=`supportedInRegion`,oq=`secondaryInterfaceSet`,sq=`snapshotId`,cq=`subnetId`,lq=`spreadLevel`,uq=`statusMessage`,dq=`stateMessage`,fq=`secondaryNetworkId`,pq=`secondaryNetworkSupported`,mq=`sriovNetSupport`,hq=`secondaryPrivateIpAddressCount`,gq=`supportedRootDeviceTypes`,_q=`stateReason`,vq=`sourceSecurityGroupName`,yq=`sourceSecurityGroupOwnerId`,bq=`secondarySubnetId`,xq=`snapshotSet`,Sq=`subnetSet`,Cq=`supportedStrategies`,wq=`startTime`,Tq=`sseType`,Eq=`storageTier`,Dq=`supportedUsageClasses`,Oq=`sourceVolumeId`,kq=`supportedVirtualizationTypes`,Aq=`supportedVersions`,jq=`size`,Mq=`state`,Nq=`status`,Pq=`strategy`,Fq=`subnet`,Iq=`tenancy`,Lq=`tcpEstablishedTimeout`,Rq=`totalFpgaMemoryInMiB`,zq=`transitGatewayId`,Bq=`totalGpuMemoryInMiB`,Vq=`totalInferenceMemoryInMiB`,Hq=`targetIops`,Uq=`targetMultiAttachEnabled`,Wq=`totalMediaMemoryInMiB`,Gq=`totalNeuronDeviceMemoryInMiB`,Kq=`toPort`,qq=`threadsPerCore`,Jq=`tagSet`,Yq=`totalSizeInGB`,Xq=`targetSize`,Zq=`tpmSupport`,Qq=`targetThroughput`,$q=`transferType`,eJ=`targetVolumeType`,tJ=`throughput`,nJ=`timestamp`,rJ=`type`,iJ=`userData`,aJ=`userId`,oJ=`unknownIpPermissionSet`,sJ=`usageOperation`,cJ=`usageOperationUpdateTime`,lJ=`udpStreamTimeout`,uJ=`udpTimeout`,dJ=`value`,fJ=`vCpuInfo`,pJ=`validCores`,mJ=`vpcEncryptionControlId`,hJ=`vpcId`,gJ=`volumeInitializationRate`,_J=`volumeId`,vJ=`vpcLattice`,yJ=`volumeModification`,bJ=`virtualName`,xJ=`volumeOwnerId`,SJ=`vpcPeeringConnectionId`,CJ=`virtualPrivateGateway`,wJ=`vpcPeering`,TJ=`volumeSet`,EJ=`volumeSize`,DJ=`vpcSet`,OJ=`volumeType`,kJ=`validThreadsPerCore`,AJ=`virtualizationType`,jJ=`version`,MJ=`vpc`,NJ=`workloadSet`,W=`xmlName`,PJ=`zoneId`,FJ=`zoneName`,IJ=`zoneState`,LJ=`zoneType`,G=`com.amazonaws.ec2`,RJ=dw.for(RK),zJ=[-3,RK,`EC2ServiceException`,0,[],[]];RJ.registerError(zJ,Aie);var BJ=[RJ],VJ=[0,G,soe,8,0],HJ=[0,G,QM,8,0],UJ=[0,G,OF,8,0],WJ=[0,G,BL,8,0],GJ=[3,G,Wie,0,[nI,Kk,WP,pk,pL],[[0,{[H]:`RouteTableId`,[W]:MK}],0,0,[2,{[H]:`DryRun`,[W]:CV}],[0,{[H]:`SubnetId`,[W]:cq}]],1],KJ=[3,G,Gie,0,[gO,bO],[[0,{[H]:`AssociationId`,[W]:Jz}],[()=>NQ,{[H]:`AssociationState`,[W]:rB}]]],qJ=[3,G,Rie,0,[gA,tz,pk],[[0,{[H]:`InternetGatewayId`,[W]:gU}],[0,{[H]:`VpcId`,[W]:hJ}],[2,{[H]:`DryRun`,[W]:CV}]],2],JJ=[3,G,tae,0,[hk,_A,sz,_k,pk],[0,0,0,1,[2,{[H]:`DryRun`,[W]:CV}]],3],YJ=[3,G,Mie,0,[VR],[[2,{[H]:`Value`,[W]:dJ}]]],XJ=[3,G,nae,0,[VR],[[0,{[H]:`Value`,[W]:dJ}]]],ZJ=[3,G,Yie,0,[Jk,gR,pk,AL,jL,lj,Vk,pR,UO,sj],[[0,{[H]:`GroupId`,[W]:MH}],[()=>d1,{[W]:yR}],[2,{[H]:`DryRun`,[W]:CV}],[0,{[H]:`SourceSecurityGroupName`,[W]:vq}],[0,{[H]:`SourceSecurityGroupOwnerId`,[W]:yq}],[0,{[H]:`IpProtocol`,[W]:FU}],[1,{[H]:`FromPort`,[W]:SH}],[1,{[H]:`ToPort`,[W]:Kq}],[0,{[H]:`CidrIp`,[W]:BB}],[()=>r1,{[H]:`IpPermissions`,[W]:IU}]],1],QJ=[3,G,Xie,0,[pF,jI],[[2,{[H]:`Return`,[W]:pK}],[()=>l1,{[H]:`SecurityGroupRuleSet`,[W]:XK}]]],$J=[3,G,Zie,0,[UO,Vk,Jk,Xk,sj,lj,AL,jL,pR,gR,pk],[0,1,0,0,[()=>r1,0],0,0,0,1,[()=>d1,{[W]:yR}],[2,{[H]:`DryRun`,[W]:CV}]]],eY=[3,G,Qie,0,[pF,jI],[[2,{[H]:`Return`,[W]:pK}],[()=>l1,{[H]:`SecurityGroupRuleSet`,[W]:XK}]]],tY=[3,G,CO,0,[tP,yN,zF,Bz,Lz,Xk,CN,Uz,sF,oF,ale,Qk,TI,qL],[[0,{[H]:`OptInStatus`,[W]:CG}],[()=>h$,{[H]:`MessageSet`,[W]:VW}],[0,{[H]:`RegionName`,[W]:DK}],[0,{[H]:`ZoneName`,[W]:FJ}],[0,{[H]:`ZoneId`,[W]:PJ}],[0,{[H]:`GroupName`,[W]:PH}],[0,{[H]:`NetworkBorderGroup`,[W]:QW}],[0,{[H]:`ZoneType`,[W]:LJ}],[0,{[H]:`ParentZoneName`,[W]:cK}],[0,{[H]:`ParentZoneId`,[W]:sK}],[0,{[H]:`GroupLongName`,[W]:NH}],[()=>p$,{[H]:`GeographySet`,[W]:LH}],[()=>g$,{[H]:`SubGeographySet`,[W]:ZK}],[0,{[H]:`ZoneState`,[W]:IJ}]]],nY=[3,G,iae,0,[SN],[[0,{[H]:`Name`,[W]:ZW}]]],rY=[3,G,sae,0,[vN],[[0,{[H]:`Message`,[W]:JW}]]],iY=[3,G,lae,0,[SN],[[0,{[H]:`Name`,[W]:ZW}]]],aY=[3,G,hae,0,[VR],[[21,{[H]:`Value`,[W]:dJ}]]],oY=[3,G,MO,0,[Ik,ON,uk,hz],[[()=>wX,{[H]:`Ebs`,[W]:_H}],[0,{[H]:`NoDevice`,[W]:tG}],[0,{[H]:`DeviceName`,[W]:gV}],[0,{[H]:`VirtualName`,[W]:bJ}]]],sY=[3,G,IO,0,[Lle],[[0,{[H]:`InternetGatewayBlockMode`,[W]:hU}]]],cY=[3,G,ZO,0,[YO,QO],[0,()=>uY]],lY=[3,G,Zae,0,[YO,QO],[[0,{[H]:`CapacityReservationPreference`,[W]:YB}],[()=>dY,{[H]:`CapacityReservationTarget`,[W]:QB}]]],uY=[3,G,QO,0,[JO,XO],[0,0]],dY=[3,G,Qae,0,[JO,XO],[[0,{[H]:`CapacityReservationId`,[W]:JB}],[0,{[H]:`CapacityReservationResourceGroupArn`,[W]:XB}]]],fY=[3,G,yoe,0,[$L,zR,BR],[1,1,1]],pY=[3,G,boe,0,[$L,zR,BR],[[1,{[H]:`TcpEstablishedTimeout`,[W]:Lq}],[1,{[H]:`UdpStreamTimeout`,[W]:lJ}],[1,{[H]:`UdpTimeout`,[W]:uJ}]]],mY=[3,G,ooe,0,[OL,ML,mk,ise,_se,Rk,eM,nF,gR,VO,Doe,pk],[0,0,0,0,[0,{[H]:`DestinationRegion`,[W]:wV}],[2,{[H]:`Encrypted`,[W]:yH}],[0,{[H]:`KmsKeyId`,[W]:cW}],[()=>VJ,{[H]:`PresignedUrl`,[W]:aK}],[()=>d1,{[W]:yR}],1,0,[2,{[H]:`DryRun`,[W]:CV}]],2],hY=[3,G,coe,0,[QL,sL],[[()=>u1,{[H]:`TagSet`,[W]:Jq}],[0,{[H]:`SnapshotId`,[W]:sq}]]],gY=[3,G,qO,0,[BO,mR,xO,XN],[[1,{[H]:`CoreCount`,[W]:NB}],[1,{[H]:`ThreadsPerCore`,[W]:qq}],[0,{[H]:`AmdSevSnp`,[W]:iB}],[0,{[H]:`NestedVirtualization`,[W]:vG}]]],_Y=[3,G,Gae,0,[BO,mR,xO,XN],[1,1,0,0]],vY=[3,G,Lae,0,[_A,SN,gR,mL,pk,mk,WN,NO],[[0,{[H]:`InstanceId`,[W]:vU}],[0,{[H]:`Name`,[W]:ZW}],[()=>d1,{[W]:yR}],0,[2,{[H]:`DryRun`,[W]:CV}],[0,{[H]:`Description`,[W]:jV}],[2,{[H]:`NoReboot`,[W]:pG}],[()=>y$,{[H]:`BlockDeviceMapping`,[W]:bB}]],2],yY=[3,G,Rae,0,[SA],[[0,{[H]:`ImageId`,[W]:xU}]]],bY=[3,G,Fae,0,[gR,pk],[[()=>d1,{[W]:yR}],[2,{[H]:`DryRun`,[W]:CV}]]],xY=[3,G,Iae,0,[hA],[[()=>PZ,{[H]:`InternetGateway`,[W]:mU}]]],SY=[3,G,Hae,0,[nM,fM,gR,Zj,pk],[0,0,[()=>d1,{[W]:yR}],0,[2,{[H]:`DryRun`,[W]:CV}]],1],CY=[3,G,qae,0,[xP,gR,gL,bM,fP,pk,Xk,YL],[1,[()=>d1,{[W]:yR}],0,0,()=>sQ,[2,{[H]:`DryRun`,[W]:CV}],[0,{[H]:`GroupName`,[W]:PH}],[0,{[H]:`Strategy`,[W]:Pq}]]],wY=[3,G,Jae,0,[jP],[[()=>uQ,{[H]:`PlacementGroup`,[W]:HG}]]],TY=[3,G,Yae,0,[nI,fk,ez,tR,yM,HO,KO,aP,pk,sk,Kk,lk,Tk,_A,RN,_z,LN],[[0,{[H]:`RouteTableId`,[W]:MK}],0,0,0,0,0,0,0,[2,{[H]:`DryRun`,[W]:CV}],[0,{[H]:`DestinationCidrBlock`,[W]:cV}],[0,{[H]:`GatewayId`,[W]:AH}],[0,{[H]:`DestinationIpv6CidrBlock`,[W]:hV}],[0,{[H]:`EgressOnlyInternetGatewayId`,[W]:nH}],[0,{[H]:`InstanceId`,[W]:vU}],[0,{[H]:`NetworkInterfaceId`,[W]:oG}],[0,{[H]:`VpcPeeringConnectionId`,[W]:SJ}],[0,{[H]:`NatGatewayId`,[W]:aG}]],1],EY=[3,G,Xae,0,[pF],[[2,{[H]:`Return`,[W]:pK}]]],DY=[3,G,$ae,0,[tz,gR,$O,pk],[[0,{[H]:`VpcId`,[W]:hJ}],[()=>d1,{[W]:yR}],[0,4],[2,{[H]:`DryRun`,[W]:CV}]],1],OY=[3,G,eoe,0,[sI,$O],[[()=>jQ,{[H]:`RouteTable`,[W]:FK}],[0,{[H]:`ClientToken`,[W]:eV}]]],kY=[3,G,ioe,0,[mk,Xk,tz,gR,pk],[[0,{[W]:Qce}],0,0,[()=>d1,{[W]:yR}],[2,{[H]:`DryRun`,[W]:CV}]],2],AY=[3,G,aoe,0,[Jk,QL,EI],[[0,{[H]:`GroupId`,[W]:MH}],[()=>u1,{[H]:`TagSet`,[W]:Jq}],[0,{[H]:`SecurityGroupArn`,[W]:KK}]]],jY=[3,G,loe,0,[sz,mk,QN,gR,PM,pk],[0,0,0,[()=>d1,{[W]:yR}],0,[2,{[H]:`DryRun`,[W]:CV}]],1],MY=[3,G,uoe,0,[tz,gR,CO,wO,zO,dA,QN,NA,bA,VA,yA,BA,pk],[0,[()=>d1,{[W]:yR}],0,0,0,0,0,2,0,1,0,1,[2,{[H]:`DryRun`,[W]:CV}]],1],NY=[3,G,doe,0,[XL],[[()=>GQ,{[H]:`Subnet`,[W]:Fq}]]],PY=[3,G,Soe,0,[CO,wO,Rk,Yj,eM,QN,WL,sL,wz,gR,FM,DR,$O,iz,fP,pk],[0,0,[2,{[H]:`Encrypted`,[W]:yH}],1,0,0,1,0,0,[()=>d1,{[W]:yR}],2,1,[0,4],1,()=>sQ,[2,{[H]:`DryRun`,[W]:CV}]]],FY=[3,G,Coe,0,[zO,dj,dA,bA,VA,yA,BA,Ole,YR,gR,pk,Vj,Hie],[0,0,0,0,1,0,1,0,()=>s$,[()=>d1,{[W]:yR}],[2,{[H]:`DryRun`,[W]:CV}],[0,{[H]:`InstanceTenancy`,[W]:nW}],[2,{[H]:`AmazonProvidedIpv6CidrBlock`,[W]:$z}]]],IY=[3,G,woe,0,[Nz],[[()=>r$,{[H]:`Vpc`,[W]:MJ}]]],LY=[3,G,foe,0,[kae],[0],1],RY=[3,G,joe,0,[Fse,zse,Rse],[[1,{[H]:`DefaultTcpEstablishedTimeout`,[W]:TV}],[1,{[H]:`DefaultUdpTimeout`,[W]:kV}],[1,{[H]:`DefaultUdpStreamTimeout`,[W]:OV}]]],zY=[3,G,Qoe,0,[nM,oM,pk],[0,0,[2,{[H]:`DryRun`,[W]:CV}]]],BY=[3,G,$oe,0,[pF,oM],[[2,{[H]:`Return`,[W]:pK}],[0,{[H]:`KeyPairId`,[W]:dW}]]],VY=[3,G,sse,0,[Xk,pk],[[0,{[H]:`GroupName`,[W]:PH}],[2,{[H]:`DryRun`,[W]:CV}]],1],HY=[3,G,bse,0,[Jk,Xk,pk],[0,0,[2,{[H]:`DryRun`,[W]:CV}]]],UY=[3,G,xse,0,[pF,Jk],[[2,{[H]:`Return`,[W]:pK}],[0,{[H]:`GroupId`,[W]:MH}]]],WY=[3,G,Tse,0,[sL,pk],[0,[2,{[H]:`DryRun`,[W]:CV}]],1],GY=[3,G,Ese,0,[pL,pk],[0,[2,{[H]:`DryRun`,[W]:CV}]],1],KY=[3,G,Vse,0,[sz,pk],[0,[2,{[H]:`DryRun`,[W]:CV}]],1],qY=[3,G,Hse,0,[tz,pk],[0,[2,{[H]:`DryRun`,[W]:CV}]],1],JY=[3,G,Ooe,0,[Hz,zz,jie,pk,Uk],[[()=>nde,{[W]:Bz}],[()=>tde,{[W]:Lz}],2,[2,{[H]:`DryRun`,[W]:CV}],[()=>k$,{[W]:Wk}]]],YY=[3,G,koe,0,[dae],[[()=>m$,{[H]:`AvailabilityZoneInfo`,[W]:uB}]]],XY=[3,G,Voe,0,[Rce,$le,mP,kle,Nle,sN,YN,pk,Uk],[[()=>O$,{[W]:gk}],[()=>F$,{[W]:SA}],[()=>i1,{[W]:hP}],2,2,1,0,[2,{[H]:`DryRun`,[W]:CV}],[()=>k$,{[W]:Wk}]]],ZY=[3,G,Hoe,0,[YN,Gj],[[0,{[H]:`NextToken`,[W]:_G}],[()=>I$,{[H]:`ImagesSet`,[W]:GU}]]],QY=[3,G,Uoe,0,[CA,jA,pk,Uk,YN,sN],[[()=>B$,{[W]:_A}],2,[2,{[H]:`DryRun`,[W]:CV}],[()=>k$,{[W]:Wk}],[0,{[H]:`NextToken`,[W]:_G}],[1,{[H]:`MaxResults`,[W]:BW}]]],$Y=[3,G,Woe,0,[YN,fI],[[0,{[H]:`NextToken`,[W]:_G}],[()=>Oue,{[H]:`ReservationSet`,[W]:kK}]]],eX=[3,G,Goe,0,[pk,Hj,Uk,sN,YN,Wj],[2,[64,{[W]:Lj}],[()=>k$,{[W]:Wk}],1,0,2]],tX=[3,G,Koe,0,[Hj,YN],[[()=>$$,{[H]:`InstanceTypeSet`,[W]:$U}],[0,{[H]:`NextToken`,[W]:_G}]]],nX=[3,G,Loe,0,[YN,sN,pk,Ble,Uk],[0,1,[2,{[H]:`DryRun`,[W]:CV}],[()=>t1,{[H]:`InternetGatewayId`,[W]:gU}],[()=>k$,{[W]:Wk}]]],rX=[3,G,Roe,0,[Hle,YN],[[()=>n1,{[H]:`InternetGatewaySet`,[W]:_U}],[0,{[H]:`NextToken`,[W]:_G}]]],iX=[3,G,ese,0,[iM,cM,ej,pk,Uk],[[()=>uue,{[W]:nM}],[()=>due,{[W]:oM}],2,[2,{[H]:`DryRun`,[W]:CV}],[()=>k$,{[W]:Wk}]]],aX=[3,G,tse,0,[aM],[[()=>fue,{[H]:`KeySet`,[W]:fW}]]],oX=[3,G,cse,0,[Yk,pk,Zk,Uk],[[()=>yue,{[W]:Jk}],[2,{[H]:`DryRun`,[W]:CV}],[64,{[H]:`GroupName`,[W]:PH}],[()=>k$,{[W]:Wk}]]],sX=[3,G,lse,0,[IP],[[()=>bue,{[H]:`PlacementGroupSet`,[W]:WG}]]],cX=[3,G,fse,0,[VF,qie,pk,Uk],[[()=>Due,{[W]:zF}],2,[2,{[H]:`DryRun`,[W]:CV}],[()=>k$,{[W]:Wk}]]],lX=[3,G,pse,0,[uI],[[()=>Eue,{[H]:`RegionInfo`,[W]:CK}]]],uX=[3,G,mse,0,[YN,sN,pk,iI,Uk],[0,1,[2,{[H]:`DryRun`,[W]:CV}],[()=>Mue,{[W]:nI}],[()=>k$,{[W]:Wk}]]],dX=[3,G,hse,0,[cI,YN],[[()=>Nue,{[H]:`RouteTableSet`,[W]:NK}],[0,{[H]:`NextToken`,[W]:_G}]]],fX=[3,G,Sse,0,[Yk,Zk,YN,sN,pk,Uk],[[()=>N$,{[W]:Jk}],[()=>P$,{[W]:Xk}],0,1,[2,{[H]:`DryRun`,[W]:CV}],[()=>k$,{[W]:Wk}]]],pX=[3,G,Cse,0,[YN,zI],[[0,{[H]:`NextToken`,[W]:_G}],[()=>Pue,{[H]:`SecurityGroupInfo`,[W]:qK}]]],mX=[3,G,Dse,0,[sN,YN,rP,mF,cL,pk,Uk],[1,0,[()=>i1,{[W]:hP}],[64,{[W]:hF}],[()=>Iue,{[W]:sL}],[2,{[H]:`DryRun`,[W]:CV}],[()=>k$,{[W]:Wk}]]],hX=[3,G,Ose,0,[YN,GL],[[0,{[H]:`NextToken`,[W]:_G}],[()=>Lue,{[H]:`SnapshotSet`,[W]:xq}]]],gX=[3,G,kse,0,[Uk,VI,YN,sN,pk],[[()=>k$,{[W]:Wk}],[()=>Rue,{[W]:pL}],0,1,[2,{[H]:`DryRun`,[W]:CV}]]],_X=[3,G,Ase,0,[YN,ZL],[[0,{[H]:`NextToken`,[W]:_G}],[()=>Bue,{[H]:`SubnetSet`,[W]:Sq}]]],vX=[3,G,Use,0,[cz,jA,pk,Uk,YN,sN],[[()=>Jue,{[W]:sz}],2,[2,{[H]:`DryRun`,[W]:CV}],[()=>k$,{[W]:Wk}],[0,{[H]:`NextToken`,[W]:_G}],[1,{[H]:`MaxResults`,[W]:BW}]]],yX=[3,G,Wse,0,[YN,jz],[[0,{[H]:`NextToken`,[W]:_G}],[()=>Yue,{[H]:`VolumeSet`,[W]:TJ}]]],bX=[3,G,Gse,0,[Uk,lz,YN,sN,pk],[[()=>k$,{[W]:Wk}],[()=>Zue,{[W]:tz}],0,1,[2,{[H]:`DryRun`,[W]:CV}]]],xX=[3,G,Kse,0,[YN,Pz],[[0,{[H]:`NextToken`,[W]:_G}],[()=>$ue,{[H]:`VpcSet`,[W]:DJ}]]],SX=[3,G,qse,0,[sz,hk,zk,_A,pk],[0,0,2,0,[2,{[H]:`DryRun`,[W]:CV}]],1],CX=[3,G,Xoe,0,[WI,ik,kR],[[1,{[H]:`SizeInGB`,[W]:QK}],[1,{[H]:`Count`,[W]:oV}],[0,{[H]:`Type`,[W]:rJ}]]],wX=[3,G,ece,0,[dk,Yj,sL,Cz,wz,eM,DR,QN,CO,Rk,iz,wO,_k],[[2,{[H]:`DeleteOnTermination`,[W]:bV}],[1,{[H]:`Iops`,[W]:iW}],[0,{[H]:`SnapshotId`,[W]:sq}],[1,{[H]:`VolumeSize`,[W]:EJ}],[0,{[H]:`VolumeType`,[W]:OJ}],[0,{[H]:`KmsKeyId`,[W]:cW}],[1,{[H]:`Throughput`,[W]:tJ}],[0,{[H]:`OutpostArn`,[W]:bG}],[0,{[H]:`AvailabilityZone`,[W]:cB}],[2,{[H]:`Encrypted`,[W]:yH}],1,0,1]],TX=[3,G,rce,0,[_k,jO,LO,PO,RM,dN,XM],[[1,{[H]:`EbsCardIndex`,[W]:PV}],[1,{[H]:`BaselineBandwidthInMbps`,[W]:yB}],[1,{[H]:`BaselineThroughputInMBps`,[W]:EB}],[1,{[H]:`BaselineIops`,[W]:xB}],[1,{[H]:`MaximumBandwidthInMbps`,[W]:EW}],[1,{[H]:`MaximumThroughputInMBps`,[W]:WW}],[1,{[H]:`MaximumIops`,[W]:NW}]]],EX=[3,G,xk,0,[jce,Pk,wk,GN,GM,Bie,KM,ice],[[0,{[H]:`EbsOptimizedSupport`,[W]:rH}],[0,{[H]:`EncryptionSupport`,[W]:mH}],[()=>kX,{[H]:`EbsOptimizedInfo`,[W]:eH}],[0,{[H]:`NvmeSupport`,[W]:mG}],[1,{[H]:`MaximumEbsAttachments`,[W]:OW}],[0,{[H]:`AttachmentLimitType`,[W]:Zz}],[1,{[H]:`MaximumEbsCards`,[W]:kW}],[()=>C$,{[H]:`EbsCardSet`,[W]:FV}]]],DX=[3,G,wce,0,[SO,dk,JL,sz,vO,gz,fP,_k],[[4,{[H]:`AttachTime`,[W]:sB}],[2,{[H]:`DeleteOnTermination`,[W]:bV}],[0,{[H]:`Status`,[W]:Nq}],[0,{[H]:`VolumeId`,[W]:_J}],[0,{[H]:`AssociatedResource`,[W]:tB}],[0,{[H]:`VolumeOwnerId`,[W]:xJ}],[()=>cQ,{[H]:`Operator`,[W]:AG}],[1,{[H]:`EbsCardIndex`,[W]:PV}]]],OX=[3,G,Tce,0,[sz,dk],[[0,{[H]:`VolumeId`,[W]:_J}],[2,{[H]:`DeleteOnTermination`,[W]:bV}]]],kX=[3,G,wk,0,[jO,LO,PO,RM,dN,XM],[[1,{[H]:`BaselineBandwidthInMbps`,[W]:yB}],[1,{[H]:`BaselineThroughputInMBps`,[W]:EB}],[1,{[H]:`BaselineIops`,[W]:xB}],[1,{[H]:`MaximumBandwidthInMbps`,[W]:EW}],[1,{[H]:`MaximumThroughputInMBps`,[W]:WW}],[1,{[H]:`MaximumIops`,[W]:NW}]]],AX=[3,G,Sk,0,[qM],[[1,{[H]:`MaximumEfaInterfaces`,[W]:AW}]]],jX=[3,G,lce,0,[hce,uce,fce,pce],[[0,{[H]:`ElasticGpuId`,[W]:UV}],[0,{[H]:`ElasticGpuAssociationId`,[W]:zV}],[0,{[H]:`ElasticGpuAssociationState`,[W]:BV}],[0,{[H]:`ElasticGpuAssociationTime`,[W]:HV}]]],MX=[3,G,vk,0,[kR],[0],1],NX=[3,G,yk,0,[kR,ik],[0,1],1],PX=[3,G,_ce,0,[Sce,vce,bce,xce],[[0,{[H]:`ElasticInferenceAcceleratorArn`,[W]:WV}],[0,{[H]:`ElasticInferenceAcceleratorAssociationId`,[W]:GV}],[0,{[H]:`ElasticInferenceAcceleratorAssociationState`,[W]:KV}],[4,{[H]:`ElasticInferenceAcceleratorAssociationTime`,[W]:JV}]]],FX=[3,G,Nce,0,[Ak,Nk],[2,()=>IX]],IX=[3,G,Fce,0,[Mk],[2]],LX=[3,G,Ek,0,[Lk],[[2,{[H]:`Enabled`,[W]:vH}]]],RX=[3,G,Ace,0,[Lk],[2]],zX=[3,G,Wk,0,[SN,kz],[0,[()=>Gue,{[W]:VR}]]],BX=[3,G,Bce,0,[SN,gN,ik,eN],[[0,{[H]:`Name`,[W]:ZW}],[0,{[H]:`Manufacturer`,[W]:KW}],[1,{[H]:`Count`,[W]:oV}],[()=>VX,{[H]:`MemoryInfo`,[W]:PW}]]],VX=[3,G,Hce,0,[JI],[[1,{[H]:`SizeInMiB`,[W]:nq}]]],HX=[3,G,Bk,0,[qce,eR],[[()=>A$,{[H]:`Fpgas`,[W]:DH}],[1,{[H]:`TotalFpgaMemoryInMiB`,[W]:Rq}]]],UX=[3,G,Xce,0,[_A,jM,pk],[0,2,[2,{[H]:`DryRun`,[W]:CV}]],1],WX=[3,G,Zce,0,[_A,OR,pP],[[0,{[H]:`InstanceId`,[W]:vU}],[4,{[H]:`Timestamp`,[W]:nJ}],[0,{[H]:`Output`,[W]:jG}]]],GX=[3,G,$ce,0,[SN,gN,ik,vM,cle,Iz,eN],[[0,{[H]:`Name`,[W]:ZW}],[0,{[H]:`Manufacturer`,[W]:KW}],[1,{[H]:`Count`,[W]:oV}],[1,{[H]:`LogicalGpuCount`,[W]:gW}],[1,{[H]:`GpuPartitionSize`,[W]:IH}],[()=>ede,{[H]:`WorkloadSet`,[W]:NJ}],[()=>KX,{[H]:`MemoryInfo`,[W]:PW}]]],KX=[3,G,tle,0,[JI],[[1,{[H]:`SizeInMiB`,[W]:nq}]]],qX=[3,G,qk,0,[lle,nR],[[()=>j$,{[H]:`Gpus`,[W]:zH}],[1,{[H]:`TotalGpuMemoryInMiB`,[W]:Bq}]]],JX=[3,G,ile,0,[Jk,Xk],[[0,{[H]:`GroupId`,[W]:MH}],[0,{[H]:`GroupName`,[W]:PH}]]],YX=[3,G,eA,0,[rk],[[2,{[H]:`Configured`,[W]:aV}]]],XX=[3,G,fle,0,[rk],[2]],ZX=[3,G,vA,0,[EO,gle],[[0,{[H]:`Arn`,[W]:pB}],[0,{[H]:`Id`,[W]:QH}]]],QX=[3,G,Jle,0,[EO,SN],[[0,{[H]:`Arn`,[W]:pB}],[0,{[H]:`Name`,[W]:ZW}]]],$X=[3,G,Kj,0,[AP,LR,NO,mk,Fk,aA,WA,SN,gF,_F,SL,kL,QL,Dz,FO,xR,Lse,Nj,qI,dse,SM,Sle,GI,XI,Hk,SA,rue,qL,eP,Aae,fF,CP,DO,Bj,$j,kF,cF],[[0,{[H]:`PlatformDetails`,[W]:VG}],[0,{[H]:`UsageOperation`,[W]:sJ}],[()=>v$,{[H]:`BlockDeviceMapping`,[W]:bB}],[0,{[H]:`Description`,[W]:jV}],[2,{[H]:`EnaSupport`,[W]:hH}],[0,{[H]:`Hypervisor`,[W]:VH}],[0,{[H]:`ImageOwnerAlias`,[W]:EU}],[0,{[H]:`Name`,[W]:ZW}],[0,{[H]:`RootDeviceName`,[W]:mK}],[0,{[H]:`RootDeviceType`,[W]:hK}],[0,{[H]:`SriovNetSupport`,[W]:mq}],[()=>HQ,{[H]:`StateReason`,[W]:_q}],[()=>u1,{[H]:`TagSet`,[W]:Jq}],[0,{[H]:`VirtualizationType`,[W]:AJ}],[0,{[H]:`BootMode`,[W]:SB}],[0,{[H]:`TpmSupport`,[W]:Zq}],[0,{[H]:`DeprecationTime`,[W]:DV}],[0,{[H]:`ImdsSupport`,[W]:qU}],[0,{[H]:`SourceInstanceId`,[W]:$K}],[0,{[H]:`DeregistrationProtection`,[W]:SV}],[0,{[H]:`LastLaunchedTime`,[W]:yW}],[2,{[H]:`ImageAllowed`,[W]:oU}],[0,{[H]:`SourceImageId`,[W]:tq}],[0,{[H]:`SourceImageRegion`,[W]:rq}],[2,{[H]:`FreeTierEligible`,[W]:TH}],[0,{[H]:`ImageId`,[W]:xU}],[0,{[H]:`ImageLocation`,[W]:SU}],[0,{[H]:`ImageState`,[W]:KU}],[0,{[H]:`ImageOwnerId`,[W]:DU}],[0,{[H]:`CreationDate`,[W]:FB}],[2,{[H]:`IsPublic`,[W]:BU}],[()=>a1,{[H]:`ProductCodes`,[W]:PG}],[0,{[H]:`Architecture`,[W]:mB}],[0,{[H]:`ImageType`,[W]:tW}],[0,{[H]:`KernelId`,[W]:sW}],[0,{[H]:`RamdiskId`,[W]:SK}],[0,{[H]:`Platform`,[W]:lK}]]],eZ=[3,G,tue,0,[nM,JP,gR,pk],[[0,{[H]:`KeyName`,[W]:uW}],[21,{[H]:`PublicKeyMaterial`,[W]:QG}],[()=>d1,{[W]:yR}],[2,{[H]:`DryRun`,[W]:CV}]],2],tZ=[3,G,nue,0,[Qj,nM,oM,QL],[[0,{[H]:`KeyFingerprint`,[W]:oW}],[0,{[H]:`KeyName`,[W]:uW}],[0,{[H]:`KeyPairId`,[W]:dW}],[()=>u1,{[H]:`TagSet`,[W]:Jq}]]],nZ=[3,G,lA,0,[TO,iR],[[()=>L$,{[H]:`Accelerators`,[W]:dB}],[1,{[H]:`TotalInferenceMemoryInMiB`,[W]:Vq}]]],rZ=[3,G,Ale,0,[ik,SN,gN,eN],[[1,{[H]:`Count`,[W]:oV}],[0,{[H]:`Name`,[W]:ZW}],[0,{[H]:`Manufacturer`,[W]:KW}],[()=>iZ,{[H]:`MemoryInfo`,[W]:PW}]]],iZ=[3,G,Mle,0,[JI],[[1,{[H]:`SizeInMiB`,[W]:nq}]]],aZ=[3,G,qj,0,[DO,NO,$O,Ck,Fk,aA,vA,aue,mce,Cce,zN,QN,gF,_F,zI,SI,YI,SL,kL,QL,Dz,qO,Eae,JO,ZO,eA,NM,rN,Ek,FO,AP,LR,RR,TP,uA,xR,iN,Nae,HN,fP,aL,_A,SA,qL,wP,kP,IL,nM,zie,CP,Lj,AM,lF,$j,kF,cF,xN,pL,tz,VP,UP],[[0,{[H]:`Architecture`,[W]:mB}],[()=>R$,{[H]:`BlockDeviceMapping`,[W]:bB}],[0,{[H]:`ClientToken`,[W]:eV}],[2,{[H]:`EbsOptimized`,[W]:$V}],[2,{[H]:`EnaSupport`,[W]:hH}],[0,{[H]:`Hypervisor`,[W]:VH}],[()=>ZX,{[H]:`IamInstanceProfile`,[W]:yU}],[0,{[H]:`InstanceLifecycle`,[W]:CU}],[()=>w$,{[H]:`ElasticGpuAssociationSet`,[W]:VV}],[()=>E$,{[H]:`ElasticInferenceAcceleratorAssociationSet`,[W]:qV}],[()=>G$,{[H]:`NetworkInterfaceSet`,[W]:sG}],[0,{[H]:`OutpostArn`,[W]:bG}],[0,{[H]:`RootDeviceName`,[W]:mK}],[0,{[H]:`RootDeviceType`,[W]:hK}],[()=>M$,{[H]:`GroupSet`,[W]:RH}],[2,{[H]:`SourceDestCheck`,[W]:UK}],[0,{[H]:`SpotInstanceRequestId`,[W]:iq}],[0,{[H]:`SriovNetSupport`,[W]:mq}],[()=>HQ,{[H]:`StateReason`,[W]:_q}],[()=>u1,{[H]:`TagSet`,[W]:Jq}],[0,{[H]:`VirtualizationType`,[W]:AJ}],[()=>gY,{[H]:`CpuOptions`,[W]:GB}],[0,{[H]:`CapacityBlockId`,[W]:jB}],[0,{[H]:`CapacityReservationId`,[W]:JB}],[()=>lY,{[H]:`CapacityReservationSpecification`,[W]:ZB}],[()=>YX,{[H]:`HibernationOptions`,[W]:GH}],[()=>pue,{[H]:`LicenseSet`,[W]:bW}],[()=>_Z,{[H]:`MetadataOptions`,[W]:LW}],[()=>LX,{[H]:`EnclaveOptions`,[W]:iH}],[0,{[H]:`BootMode`,[W]:SB}],[0,{[H]:`PlatformDetails`,[W]:VG}],[0,{[H]:`UsageOperation`,[W]:sJ}],[4,{[H]:`UsageOperationUpdateTime`,[W]:cJ}],[()=>hQ,{[H]:`PrivateDnsNameOptions`,[W]:LG}],[0,{[H]:`Ipv6Address`,[W]:cU}],[0,{[H]:`TpmSupport`,[W]:Zq}],[()=>pZ,{[H]:`MaintenanceOptions`,[W]:RW}],[0,{[H]:`CurrentInstanceBootMode`,[W]:zB}],[()=>SZ,{[H]:`NetworkPerformanceOptions`,[W]:dG}],[()=>cQ,{[H]:`Operator`,[W]:AG}],[()=>J$,{[H]:`SecondaryInterfaceSet`,[W]:oq}],[0,{[H]:`InstanceId`,[W]:vU}],[0,{[H]:`ImageId`,[W]:xU}],[()=>AZ,{[H]:`InstanceState`,[W]:YU}],[0,{[H]:`PrivateDnsName`,[W]:zG}],[0,{[H]:`DnsName`,[W]:vV}],[0,{[H]:`Reason`,[W]:LK}],[0,{[H]:`KeyName`,[W]:uW}],[1,{[H]:`AmiLaunchIndex`,[W]:Xz}],[()=>a1,{[H]:`ProductCodes`,[W]:PG}],[0,{[H]:`InstanceType`,[W]:QU}],[4,{[H]:`LaunchTime`,[W]:xW}],[()=>lQ,{[H]:`Placement`,[W]:uK}],[0,{[H]:`KernelId`,[W]:sW}],[0,{[H]:`RamdiskId`,[W]:SK}],[0,{[H]:`Platform`,[W]:lK}],[()=>$Z,{[H]:`Monitoring`,[W]:YW}],[0,{[H]:`SubnetId`,[W]:cq}],[0,{[H]:`VpcId`,[W]:hJ}],[0,{[H]:`PrivateIpAddress`,[W]:JG}],[0,{[H]:`IpAddress`,[W]:sU}]]],oZ=[3,G,_le,0,[Ak,Nk],[[2,{[H]:`EnaSrdEnabled`,[W]:cH}],[()=>sZ,{[H]:`EnaSrdUdpSpecification`,[W]:fH}]]],sZ=[3,G,vle,0,[Mk],[[2,{[H]:`EnaSrdUdpEnabled`,[W]:dH}]]],cZ=[3,G,wle,0,[uk,Ik],[[0,{[H]:`DeviceName`,[W]:gV}],[()=>DX,{[H]:`Ebs`,[W]:_H}]]],lZ=[3,G,Ele,0,[uk,Ik,hz,ON],[[0,{[H]:`DeviceName`,[W]:gV}],[()=>OX,{[H]:`Ebs`,[W]:_H}],[0,{[H]:`VirtualName`,[W]:bJ}],[0,{[H]:`NoDevice`,[W]:tG}]]],uZ=[3,G,Yle,0,[pj],[[0,{[H]:`Ipv4Prefix`,[W]:LU}]]],dZ=[3,G,Ule,0,[uA,$A],[[0,{[H]:`Ipv6Address`,[W]:cU}],[2,{[H]:`IsPrimaryIpv6`,[W]:MU}]]],fZ=[3,G,Xle,0,[uj],[[0,{[H]:`Ipv6Prefix`,[W]:zU}]]],pZ=[3,G,TA,0,[yO,RF],[[0,{[H]:`AutoRecovery`,[W]:nB}],[0,{[H]:`RebootMigration`,[W]:EK}]]],mZ=[3,G,EA,0,[yO],[0]],hZ=[3,G,DA,0,[uN,wL],[0,()=>zQ]],gZ=[3,G,OA,0,[rA,nA,$k,tA,MA],[0,1,0,0,0]],_Z=[3,G,kA,0,[qL,rA,nA,$k,tA,MA],[[0,{[H]:`State`,[W]:Mq}],[0,{[H]:`HttpTokens`,[W]:XH}],[1,{[H]:`HttpPutResponseHopLimit`,[W]:qH}],[0,{[H]:`HttpEndpoint`,[W]:UH}],[0,{[H]:`HttpProtocolIpv6`,[W]:KH}],[0,{[H]:`InstanceMetadataTags`,[W]:wU}]]],vZ=[3,G,PA,0,[OO,kO,mk,Gk,oA,LM,RN,eP,wP,VP,HP,SI,JL,pL,tz,Uj,fj,oj,ek,fP],[[()=>yZ,{[H]:`Association`,[W]:hB}],[()=>bZ,{[H]:`Attachment`,[W]:gB}],[0,{[H]:`Description`,[W]:jV}],[()=>M$,{[H]:`GroupSet`,[W]:RH}],[()=>H$,{[H]:`Ipv6AddressesSet`,[W]:aU}],[0,{[H]:`MacAddress`,[W]:TW}],[0,{[H]:`NetworkInterfaceId`,[W]:oG}],[0,{[H]:`OwnerId`,[W]:SG}],[0,{[H]:`PrivateDnsName`,[W]:zG}],[0,{[H]:`PrivateIpAddress`,[W]:JG}],[()=>q$,{[H]:`PrivateIpAddressesSet`,[W]:KG}],[2,{[H]:`SourceDestCheck`,[W]:UK}],[0,{[H]:`Status`,[W]:Nq}],[0,{[H]:`SubnetId`,[W]:cq}],[0,{[H]:`VpcId`,[W]:hJ}],[0,{[H]:`InterfaceType`,[W]:rW}],[()=>V$,{[H]:`Ipv4PrefixSet`,[W]:NU}],[()=>U$,{[H]:`Ipv6PrefixSet`,[W]:PU}],[()=>pY,{[H]:`ConnectionTrackingConfiguration`,[W]:tV}],[()=>cQ,{[H]:`Operator`,[W]:AG}]]],yZ=[3,G,FA,0,[Mae,Uae,GA,kP,LP],[[0,{[H]:`CarrierIp`,[W]:RB}],[0,{[H]:`CustomerOwnedIp`,[W]:KB}],[0,{[H]:`IpOwnerId`,[W]:kU}],[0,{[H]:`PublicDnsName`,[W]:BG}],[0,{[H]:`PublicIp`,[W]:GG}]]],bZ=[3,G,IA,0,[SO,_O,dk,ck,JL,TN,jk,Dk],[[4,{[H]:`AttachTime`,[W]:sB}],[0,{[H]:`AttachmentId`,[W]:Yz}],[2,{[H]:`DeleteOnTermination`,[W]:bV}],[1,{[H]:`DeviceIndex`,[W]:mV}],[0,{[H]:`Status`,[W]:Nq}],[1,{[H]:`NetworkCardIndex`,[W]:eG}],[()=>oZ,{[H]:`EnaSrdSpecification`,[W]:lH}],[1,{[H]:`EnaQueueCount`,[W]:aH}]]],xZ=[3,G,RA,0,[Vie,dk,mk,ck,Gk,cA,oA,RN,VP,HP,EL,pL,Nie,Uj,TN,fj,YA,oj,JA,GP,jk,voe,Dk],[[2,{[H]:`AssociatePublicIpAddress`,[W]:Qz}],[2,{[H]:`DeleteOnTermination`,[W]:bV}],[0,{[H]:`Description`,[W]:jV}],[1,{[H]:`DeviceIndex`,[W]:mV}],[()=>s1,{[W]:DI}],[1,{[H]:`Ipv6AddressCount`,[W]:eU}],[()=>H$,{[H]:`Ipv6Addresses`,[W]:aU}],[0,{[H]:`NetworkInterfaceId`,[W]:oG}],[0,{[H]:`PrivateIpAddress`,[W]:JG}],[()=>Cue,{[H]:`PrivateIpAddresses`,[W]:KG}],[1,{[H]:`SecondaryPrivateIpAddressCount`,[W]:hq}],[0,{[H]:`SubnetId`,[W]:cq}],2,0,1,[()=>sue,{[W]:pj}],1,[()=>cue,{[W]:uj}],1,2,()=>FX,()=>fY,1]],SZ=[3,G,HA,0,[RO],[[0,{[H]:`BandwidthWeighting`,[W]:DB}]]],CZ=[3,G,UA,0,[RO],[0]],wZ=[3,G,ZA,0,[OO,uF,wP,VP],[[()=>yZ,{[H]:`Association`,[W]:hB}],[2,{[H]:`Primary`,[W]:dK}],[0,{[H]:`PrivateDnsName`,[W]:zG}],[0,{[H]:`PrivateIpAddress`,[W]:JG}]]],TZ=[3,G,Aj,0,[kO,LM,KI,eP,HP,SI,JL,NL,xL,Uj],[[()=>EZ,{[H]:`Attachment`,[W]:gB}],[0,{[H]:`MacAddress`,[W]:TW}],[0,{[H]:`SecondaryInterfaceId`,[W]:eq}],[0,{[H]:`OwnerId`,[W]:SG}],[()=>Y$,{[H]:`PrivateIpAddressSet`,[W]:qG}],[2,{[H]:`SourceDestCheck`,[W]:UK}],[0,{[H]:`Status`,[W]:Nq}],[0,{[H]:`SecondarySubnetId`,[W]:bq}],[0,{[H]:`SecondaryNetworkId`,[W]:fq}],[0,{[H]:`InterfaceType`,[W]:rW}]]],EZ=[3,G,Sj,0,[SO,_O,dk,ck,JL,TN],[[4,{[H]:`AttachTime`,[W]:sB}],[0,{[H]:`AttachmentId`,[W]:Yz}],[2,{[H]:`DeleteOnTermination`,[W]:bV}],[1,{[H]:`DeviceIndex`,[W]:mV}],[0,{[H]:`Status`,[W]:Nq}],[1,{[H]:`NetworkCardIndex`,[W]:eG}]]],DZ=[3,G,wj,0,[VP],[[0,{[H]:`PrivateIpAddress`,[W]:JG}]]],OZ=[3,G,Dj,0,[VP],[0],1],kZ=[3,G,kj,0,[dk,ck,HP,RP,NL,Uj,TN],[2,1,[()=>X$,{[W]:VP}],1,0,0,1]],AZ=[3,G,Pj,0,[nk,SN],[[1,{[H]:`Code`,[W]:iV}],[0,{[H]:`Name`,[W]:ZW}]]],jZ=[3,G,bj,0,[_A,_oe,tF],[[0,{[H]:`InstanceId`,[W]:vU}],[()=>AZ,{[H]:`CurrentState`,[W]:$B}],[()=>AZ,{[H]:`PreviousState`,[W]:iK}]]],MZ=[3,G,jj,0,[_R,$se,GN,Pk],[[1,{[H]:`TotalSizeInGB`,[W]:Yq}],[()=>S$,{[H]:`Disks`,[W]:NV}],[0,{[H]:`NvmeSupport`,[W]:mG}],[0,{[H]:`EncryptionSupport`,[W]:mH}]]],NZ=[3,G,zj,0,[Lj,jae,Hk,zL,DL,HL,xae,aA,KP,qR,eN,Mj,jj,xk,BN,qk,Bk,MP,lA,mle,Sae,Ioe,Uie,yI,PN,qN,KN,IM,VN,eF,LF,tL],[[0,{[H]:`InstanceType`,[W]:QU}],[2,{[H]:`CurrentGeneration`,[W]:LB}],[2,{[H]:`FreeTierEligible`,[W]:TH}],[()=>Uue,{[H]:`SupportedUsageClasses`,[W]:Dq}],[()=>kue,{[H]:`SupportedRootDeviceTypes`,[W]:gq}],[()=>Kue,{[H]:`SupportedVirtualizationTypes`,[W]:kq}],[2,{[H]:`BareMetal`,[W]:CB}],[0,{[H]:`Hypervisor`,[W]:VH}],[()=>_Q,{[H]:`ProcessorInfo`,[W]:XG}],[()=>$Q,{[H]:`VCpuInfo`,[W]:fJ}],[()=>YZ,{[H]:`MemoryInfo`,[W]:PW}],[2,{[H]:`InstanceStorageSupported`,[W]:WU}],[()=>MZ,{[H]:`InstanceStorageInfo`,[W]:UU}],[()=>EX,{[H]:`EbsInfo`,[W]:XV}],[()=>tQ,{[H]:`NetworkInfo`,[W]:lG}],[()=>qX,{[H]:`GpuInfo`,[W]:jH}],[()=>HX,{[H]:`FpgaInfo`,[W]:xH}],[()=>dQ,{[H]:`PlacementGroupInfo`,[W]:UG}],[()=>nZ,{[H]:`InferenceAcceleratorInfo`,[W]:tU}],[2,{[H]:`HibernationSupported`,[W]:YH}],[2,{[H]:`BurstablePerformanceSupported`,[W]:TB}],[2,{[H]:`DedicatedHostsSupported`,[W]:pV}],[2,{[H]:`AutoRecoverySupported`,[W]:eB}],[()=>b$,{[H]:`SupportedBootModes`,[W]:VK}],[0,{[H]:`NitroEnclavesSupport`,[W]:rG}],[0,{[H]:`NitroTpmSupport`,[W]:gG}],[()=>oQ,{[H]:`NitroTpmInfo`,[W]:hG}],[()=>KZ,{[H]:`MediaAcceleratorInfo`,[W]:wW}],[()=>aQ,{[H]:`NeuronInfo`,[W]:uG}],[0,{[H]:`PhcSupport`,[W]:rK}],[0,{[H]:`RebootMigrationSupport`,[W]:TK}],[2,{[H]:`SupportedInRegion`,[W]:aq}]]],PZ=[3,G,hA,0,[AO,gA,eP,QL],[[()=>e1,{[H]:`AttachmentSet`,[W]:oB}],[0,{[H]:`InternetGatewayId`,[W]:gU}],[0,{[H]:`OwnerId`,[W]:SG}],[()=>u1,{[H]:`TagSet`,[W]:Jq}]]],FZ=[3,G,Fle,0,[qL,tz],[[0,{[H]:`State`,[W]:Mq}],[0,{[H]:`VpcId`,[W]:hJ}]]],IZ=[3,G,cj,0,[lj,Vk,pR,NR,gj,vj,ZP],[[0,{[H]:`IpProtocol`,[W]:FU}],[1,{[H]:`FromPort`,[W]:SH}],[1,{[H]:`ToPort`,[W]:Kq}],[()=>Wue,{[H]:`Groups`,[W]:BH}],[()=>oue,{[H]:`IpRanges`,[W]:VU}],[()=>lue,{[H]:`Ipv6Ranges`,[W]:HU}],[()=>Sue,{[H]:`PrefixListIds`,[W]:eK}]]],LZ=[3,G,_j,0,[mk,UO],[[0,{[H]:`Description`,[W]:jV}],[0,{[H]:`CidrIp`,[W]:BB}]]],RZ=[3,G,ij,0,[pj],[0]],zZ=[3,G,aj,0,[uj],[0]],BZ=[3,G,yj,0,[mk,WO],[[0,{[H]:`Description`,[W]:jV}],[0,{[H]:`CidrIpv6`,[W]:VB}]]],VZ=[3,G,dM,0,[oM,QL,nM,Qj,tM],[[0,{[H]:`KeyPairId`,[W]:dW}],[()=>u1,{[H]:`TagSet`,[W]:Jq}],[0,{[H]:`KeyName`,[W]:uW}],[0,{[H]:`KeyFingerprint`,[W]:oW}],[()=>WJ,{[H]:`KeyMaterial`,[W]:lW}]]],HZ=[3,G,lM,0,[oM,fM,QL,qP,tk,nM,Qj],[[0,{[H]:`KeyPairId`,[W]:dW}],[0,{[H]:`KeyType`,[W]:pW}],[()=>u1,{[H]:`TagSet`,[W]:Jq}],[0,{[H]:`PublicKey`,[W]:ZG}],[4,{[H]:`CreateTime`,[W]:rV}],[0,{[H]:`KeyName`,[W]:uW}],[0,{[H]:`KeyFingerprint`,[W]:oW}]]],UZ=[3,G,kM,0,[DM,OM,Az],[0,0,0]],WZ=[3,G,gM,0,[mM],[[0,{[H]:`LicenseConfigurationArn`,[W]:hW}]]],GZ=[3,G,hM,0,[mM],[0]],KZ=[3,G,IM,0,[TO,dR],[[()=>hue,{[H]:`Accelerators`,[W]:dB}],[1,{[H]:`TotalMediaMemoryInMiB`,[W]:Wq}]]],qZ=[3,G,HM,0,[ik,SN,gN,eN],[[1,{[H]:`Count`,[W]:oV}],[0,{[H]:`Name`,[W]:ZW}],[0,{[H]:`Manufacturer`,[W]:KW}],[()=>JZ,{[H]:`MemoryInfo`,[W]:PW}]]],JZ=[3,G,WM,0,[JI],[[1,{[H]:`SizeInMiB`,[W]:nq}]]],YZ=[3,G,eN,0,[JI],[[1,{[H]:`SizeInMiB`,[W]:nq}]]],XZ=[3,G,ZM,0,[_A,SI,ak,pk,mae,VR,NO,ok,Lj,pM,lI,jR,xA,Gk,Ck,SL,Fk],[[0,{[H]:`InstanceId`,[W]:vU}],[()=>YJ,0],[()=>YJ,0],[2,{[H]:`DryRun`,[W]:CV}],[0,{[H]:`Attribute`,[W]:_B}],[()=>HJ,{[H]:`Value`,[W]:dJ}],[()=>z$,{[H]:`BlockDeviceMapping`,[W]:bB}],[()=>YJ,{[H]:`DisableApiTermination`,[W]:sV}],[()=>XJ,{[H]:`InstanceType`,[W]:QU}],[()=>XJ,{[H]:`Kernel`,[W]:mW}],[()=>XJ,{[H]:`Ramdisk`,[W]:IK}],[()=>aY,{[H]:`UserData`,[W]:iJ}],[()=>XJ,{[H]:`InstanceInitiatedShutdownBehavior`,[W]:bU}],[()=>N$,{[W]:Jk}],[()=>YJ,{[H]:`EbsOptimized`,[W]:$V}],[()=>XJ,{[H]:`SriovNetSupport`,[W]:mq}],[()=>YJ,{[H]:`EnaSupport`,[W]:hH}]],1],ZZ=[3,G,fN,0,[sz,pk,WL,wz,Yj,DR,FM],[0,2,1,0,1,1,2],1],QZ=[3,G,pN,0,[mz],[[()=>n$,{[H]:`VolumeModification`,[W]:yJ}]]],$Z=[3,G,xN,0,[qL],[[0,{[H]:`State`,[W]:Mq}]]],eQ=[3,G,DN,0,[TN,UN,nN,Pie,gae,_P,Poe,JM,YM],[[1,{[H]:`NetworkCardIndex`,[W]:eG}],[0,{[H]:`NetworkPerformance`,[W]:fG}],[1,{[H]:`MaximumNetworkInterfaces`,[W]:IW}],[1,{[H]:`AdditionalFlexibleNetworkInterfaces`,[W]:Wz}],[1,{[H]:`BaselineBandwidthInGbps`,[W]:vB}],[1,{[H]:`PeakBandwidthInGbps`,[W]:NG}],[1,{[H]:`DefaultEnaQueueCountPerInterface`,[W]:dV}],[1,{[H]:`MaximumEnaQueueCount`,[W]:jW}],[1,{[H]:`MaximumEnaQueueCountPerInterface`,[W]:MW}]]],tQ=[3,G,BN,0,[UN,nN,tN,rse,wN,yle,ble,Ij,Fk,Ice,Sk,Ece,Pce,wae,Uce,ek,CL,cN,xle],[[0,{[H]:`NetworkPerformance`,[W]:fG}],[1,{[H]:`MaximumNetworkInterfaces`,[W]:IW}],[1,{[H]:`MaximumNetworkCards`,[W]:FW}],[1,{[H]:`DefaultNetworkCardIndex`,[W]:_V}],[()=>gue,{[H]:`NetworkCards`,[W]:$W}],[1,{[H]:`Ipv4AddressesPerInterface`,[W]:nU}],[1,{[H]:`Ipv6AddressesPerInterface`,[W]:rU}],[2,{[H]:`Ipv6Supported`,[W]:ZU}],[0,{[H]:`EnaSupport`,[W]:hH}],[2,{[H]:`EfaSupported`,[W]:pH}],[()=>AX,{[H]:`EfaInfo`,[W]:ZV}],[2,{[H]:`EncryptionInTransitSupported`,[W]:YV}],[2,{[H]:`EnaSrdSupported`,[W]:uH}],[()=>_$,{[H]:`BandwidthWeightings`,[W]:OB}],[0,{[H]:`FlexibleEnaQueuesSupport`,[W]:bH}],[()=>RY,{[H]:`ConnectionTrackingConfiguration`,[W]:tV}],[2,{[H]:`SecondaryNetworkSupported`,[W]:pq}],[1,{[H]:`MaximumSecondaryNetworkInterfaces`,[W]:HW}],[1,{[H]:`Ipv4AddressesPerSecondaryInterface`,[W]:iU}]]],nQ=[3,G,kN,0,[ik,Az],[[1,{[H]:`Count`,[W]:oV}],[1,{[H]:`Version`,[W]:jJ}]]],rQ=[3,G,AN,0,[ik,SN,zae,eN],[[1,{[H]:`Count`,[W]:oV}],[0,{[H]:`Name`,[W]:ZW}],[()=>nQ,{[H]:`CoreInfo`,[W]:UB}],[()=>iQ,{[H]:`MemoryInfo`,[W]:PW}]]],iQ=[3,G,MN,0,[JI],[[1,{[H]:`SizeInMiB`,[W]:nq}]]],aQ=[3,G,VN,0,[NN,fR],[[()=>_ue,{[H]:`NeuronDevices`,[W]:nG}],[1,{[H]:`TotalNeuronDeviceMemoryInMiB`,[W]:Gq}]]],oQ=[3,G,KN,0,[UL],[[()=>vue,{[H]:`SupportedVersions`,[W]:Aq}]]],sQ=[3,G,oP,0,[gP],[0]],cQ=[3,G,sP,0,[_N,gP,ule],[[2,{[H]:`Managed`,[W]:qW}],[0,{[H]:`Principal`,[W]:MG}],[2,{[H]:`HiddenByDefault`,[W]:HH}]]],lQ=[3,G,lF,0,[wO,fae,Xk,QP,dle,ER,CI,ple,Jk,CO],[[0,{[H]:`AvailabilityZoneId`,[W]:lB}],[0,{[H]:`Affinity`,[W]:fB}],[0,{[H]:`GroupName`,[W]:PH}],[1,{[H]:`PartitionNumber`,[W]:tK}],[0,{[H]:`HostId`,[W]:WH}],[0,{[H]:`Tenancy`,[W]:Iq}],[0,{[H]:`SpreadDomain`,[W]:WK}],[0,{[H]:`HostResourceGroupArn`,[W]:JH}],[0,{[H]:`GroupId`,[W]:MH}],[0,{[H]:`AvailabilityZone`,[W]:cB}]]],uQ=[3,G,jP,0,[Xk,qL,YL,xP,Jk,QL,Jce,gL,bM,fP],[[0,{[H]:`GroupName`,[W]:PH}],[0,{[H]:`State`,[W]:Mq}],[0,{[H]:`Strategy`,[W]:Pq}],[1,{[H]:`PartitionCount`,[W]:FG}],[0,{[H]:`GroupId`,[W]:MH}],[()=>u1,{[H]:`TagSet`,[W]:Jq}],[0,{[H]:`GroupArn`,[W]:OH}],[0,{[H]:`SpreadLevel`,[W]:lq}],[0,{[H]:`LinkedGroupId`,[W]:vW}],[()=>cQ,{[H]:`Operator`,[W]:AG}]]],dQ=[3,G,MP,0,[PL],[[()=>xue,{[H]:`SupportedStrategies`,[W]:Cq}]]],fQ=[3,G,YP,0,[mk,YP],[[0,{[H]:`Description`,[W]:jV}],[0,{[H]:`PrefixListId`,[W]:$G}]]],pQ=[3,G,EP,0,[iA,kk,Ok],[[0,{[H]:`HostnameType`,[W]:ZH}],[2,{[H]:`EnableResourceNameDnsARecord`,[W]:sH}],[2,{[H]:`EnableResourceNameDnsAAAARecord`,[W]:oH}]]],mQ=[3,G,DP,0,[iA,kk,Ok],[0,2,2]],hQ=[3,G,OP,0,[iA,kk,Ok],[[0,{[H]:`HostnameType`,[W]:ZH}],[2,{[H]:`EnableResourceNameDnsARecord`,[W]:sH}],[2,{[H]:`EnableResourceNameDnsAAAARecord`,[W]:oH}]]],gQ=[3,G,zP,0,[uF,VP],[[2,{[H]:`Primary`,[W]:dK}],[0,{[H]:`PrivateIpAddress`,[W]:JG}]]],_Q=[3,G,KP,0,[vI,xI,wI,gN],[[()=>f$,{[H]:`SupportedArchitectures`,[W]:zK}],[1,{[H]:`SustainedClockSpeedInGhz`,[W]:HK}],[()=>Vue,{[H]:`SupportedFeatures`,[W]:GK}],[0,{[H]:`Manufacturer`,[W]:KW}]]],vQ=[3,G,SP,0,[vP,bP],[[0,{[H]:`ProductCode`,[W]:IG}],[0,{[H]:`Type`,[W]:rJ}]]],yQ=[3,G,rF,0,[Kk],[[0,{[H]:`GatewayId`,[W]:AH}]]],bQ=[3,G,EF,0,[CA,pk],[[()=>B$,{[W]:_A}],[2,{[H]:`DryRun`,[W]:CV}]],1],xQ=[3,G,HF,0,[Jk,$P,MR,tz,_z],[[0,{[H]:`GroupId`,[W]:MH}],[0,{[H]:`PeeringStatus`,[W]:nK}],[0,{[H]:`UserId`,[W]:aJ}],[0,{[H]:`VpcId`,[W]:hJ}],[0,{[H]:`VpcPeeringConnectionId`,[W]:SJ}]]],SQ=[3,G,dI,0,[tP,Qk,zF,zce],[[0,{[H]:`OptInStatus`,[W]:CG}],[()=>Tue,{[H]:`GeographySet`,[W]:LH}],[0,{[H]:`RegionName`,[W]:DK}],[0,{[H]:`RegionEndpoint`,[W]:_K}]]],CQ=[3,G,xF,0,[SN],[[0,{[H]:`Name`,[W]:ZW}]]],wQ=[3,G,pI,0,[AF,eP,MF,Gk,Jj],[[0,{[H]:`ReservationId`,[W]:xK}],[0,{[H]:`OwnerId`,[W]:SG}],[0,{[H]:`RequesterId`,[W]:wK}],[()=>M$,{[H]:`GroupSet`,[W]:RH}],[()=>W$,{[H]:`InstancesSet`,[W]:JU}]]],TQ=[3,G,YF,0,[FI,Jk,mA,lj,Vk,pR,GO,WO,YP,SF,mk],[[0,{[H]:`SecurityGroupRuleId`,[W]:YK}],[0,{[H]:`GroupId`,[W]:MH}],[2,{[H]:`IsEgress`,[W]:pU}],[0,{[H]:`IpProtocol`,[W]:FU}],[1,{[H]:`FromPort`,[W]:SH}],[1,{[H]:`ToPort`,[W]:Kq}],[0,{[H]:`CidrIpv4`,[W]:HB}],[0,{[H]:`CidrIpv6`,[W]:VB}],[0,{[H]:`PrefixListId`,[W]:$G}],[0,{[H]:`ReferencedGroupId`,[W]:yK}],[0,{[H]:`Description`,[W]:jV}]]],EQ=[3,G,WF,0,[Jk,NI,pk,AL,jL,lj,Vk,pR,UO,sj],[[0,{[H]:`GroupId`,[W]:MH}],[()=>c1,{[W]:FI}],[2,{[H]:`DryRun`,[W]:CV}],[0,{[H]:`SourceSecurityGroupName`,[W]:vq}],[0,{[H]:`SourceSecurityGroupOwnerId`,[W]:yq}],[0,{[H]:`IpProtocol`,[W]:FU}],[1,{[H]:`FromPort`,[W]:SH}],[1,{[H]:`ToPort`,[W]:Kq}],[0,{[H]:`CidrIp`,[W]:BB}],[()=>r1,{[H]:`IpPermissions`,[W]:IU}]],1],DQ=[3,G,GF,0,[pF,IR,ZF],[[2,{[H]:`Return`,[W]:pK}],[()=>r1,{[H]:`UnknownIpPermissionSet`,[W]:oJ}],[()=>o1,{[H]:`RevokedSecurityGroupRuleSet`,[W]:OK}]]],OQ=[3,G,KF,0,[UO,Vk,Jk,Xk,sj,lj,AL,jL,pR,NI,pk],[0,1,0,0,[()=>r1,0],0,0,0,1,[()=>c1,{[W]:FI}],[2,{[H]:`DryRun`,[W]:CV}]]],kQ=[3,G,qF,0,[pF,IR,ZF],[[2,{[H]:`Return`,[W]:pK}],[()=>r1,{[H]:`UnknownIpPermissionSet`,[W]:oJ}],[()=>o1,{[H]:`RevokedSecurityGroupRuleSet`,[W]:OK}]]],AQ=[3,G,mI,0,[sk,lk,fk,Tk,Kk,_A,KA,LN,tR,yM,HO,RN,ZN,qL,_z,KO,aP,Cle],[[0,{[H]:`DestinationCidrBlock`,[W]:cV}],[0,{[H]:`DestinationIpv6CidrBlock`,[W]:hV}],[0,{[H]:`DestinationPrefixListId`,[W]:xV}],[0,{[H]:`EgressOnlyInternetGatewayId`,[W]:nH}],[0,{[H]:`GatewayId`,[W]:AH}],[0,{[H]:`InstanceId`,[W]:vU}],[0,{[H]:`InstanceOwnerId`,[W]:OU}],[0,{[H]:`NatGatewayId`,[W]:aG}],[0,{[H]:`TransitGatewayId`,[W]:zq}],[0,{[H]:`LocalGatewayId`,[W]:_W}],[0,{[H]:`CarrierGatewayId`,[W]:IB}],[0,{[H]:`NetworkInterfaceId`,[W]:oG}],[0,{[H]:`Origin`,[W]:yG}],[0,{[H]:`State`,[W]:Mq}],[0,{[H]:`VpcPeeringConnectionId`,[W]:SJ}],[0,{[H]:`CoreNetworkArn`,[W]:WB}],[0,{[H]:`OdbNetworkArn`,[W]:EG}],[0,{[H]:`IpAddress`,[W]:sU}]]],jQ=[3,G,sI,0,[pae,aF,nI,hI,QL,tz,eP],[[()=>jue,{[H]:`AssociationSet`,[W]:aB}],[()=>wue,{[H]:`PropagatingVgwSet`,[W]:oK}],[0,{[H]:`RouteTableId`,[W]:MK}],[()=>Aue,{[H]:`RouteSet`,[W]:AK}],[()=>u1,{[H]:`TagSet`,[W]:Jq}],[0,{[H]:`VpcId`,[W]:hJ}],[0,{[H]:`OwnerId`,[W]:SG}]]],MQ=[3,G,QF,0,[hN,$F,nI,pL,Kk,WP,bO],[[2,{[H]:`Main`,[W]:GW}],[0,{[H]:`RouteTableAssociationId`,[W]:jK}],[0,{[H]:`RouteTableId`,[W]:MK}],[0,{[H]:`SubnetId`,[W]:cq}],[0,{[H]:`GatewayId`,[W]:AH}],[0,{[H]:`PublicIpv4Pool`,[W]:YG}],[()=>NQ,{[H]:`AssociationState`,[W]:rB}]]],NQ=[3,G,tI,0,[qL,yL],[[0,{[H]:`State`,[W]:Mq}],[0,{[H]:`StatusMessage`,[W]:uq}]]],PQ=[3,G,TF,0,[Lk],[[2,{[H]:`Enabled`,[W]:vH}]],1],FQ=[3,G,DF,0,[BM,VM,NO,SA,Lj,cA,oA,$j,nM,xN,lF,kF,kI,zI,pL,jR,vk,bk,gR,EM,AA,moe,qO,ZO,eA,CM,rN,Ek,TP,iN,ak,Mce,HN,fP,aL,pk,ok,xA,VP,$O,hO,zN,vA,Ck],[1,1,[()=>y$,{[W]:MO}],0,0,1,[()=>H$,{[W]:uA}],0,0,[()=>PQ,0],[()=>lQ,0],0,[()=>s1,{[W]:DI}],[()=>Fue,{[W]:BI}],0,[()=>UJ,0],[()=>T$,0],[()=>D$,{[W]:yk}],[()=>d1,{[W]:yR}],()=>UZ,()=>hZ,()=>LY,()=>_Y,()=>cY,()=>XX,[()=>mue,{[W]:TM}],()=>gZ,()=>RX,()=>mQ,()=>mZ,2,2,()=>CZ,()=>sQ,[()=>Z$,{[W]:oL}],[2,{[H]:`DryRun`,[W]:CV}],[2,{[H]:`DisableApiTermination`,[W]:sV}],[0,{[H]:`InstanceInitiatedShutdownBehavior`,[W]:bU}],[0,{[H]:`PrivateIpAddress`,[W]:JG}],[0,{[H]:`ClientToken`,[eW]:1,[W]:eV}],[0,{[H]:`AdditionalInfo`,[W]:qz}],[()=>K$,{[H]:`NetworkInterface`,[W]:cG}],[()=>QX,{[H]:`IamInstanceProfile`,[W]:yU}],[2,{[H]:`EbsOptimized`,[W]:$V}]],2],IQ=[3,G,BI,0,[Jk,XA,QL,tz,EI,eP,Xk,mk,sj],[[0,{[H]:`GroupId`,[W]:MH}],[()=>r1,{[H]:`IpPermissionsEgress`,[W]:jU}],[()=>u1,{[H]:`TagSet`,[W]:Jq}],[0,{[H]:`VpcId`,[W]:hJ}],[0,{[H]:`SecurityGroupArn`,[W]:KK}],[0,{[H]:`OwnerId`,[W]:SG}],[0,{[H]:`GroupName`,[W]:PH}],[0,{[H]:`GroupDescription`,[W]:kH}],[()=>r1,{[H]:`IpPermissions`,[W]:IU}]]],LQ=[3,G,LI,0,[FI,Jk,sle,mA,lj,Vk,pR,GO,WO,YP,CF,mk,QL,MI],[[0,{[H]:`SecurityGroupRuleId`,[W]:YK}],[0,{[H]:`GroupId`,[W]:MH}],[0,{[H]:`GroupOwnerId`,[W]:FH}],[2,{[H]:`IsEgress`,[W]:pU}],[0,{[H]:`IpProtocol`,[W]:FU}],[1,{[H]:`FromPort`,[W]:SH}],[1,{[H]:`ToPort`,[W]:Kq}],[0,{[H]:`CidrIpv4`,[W]:HB}],[0,{[H]:`CidrIpv6`,[W]:VB}],[0,{[H]:`PrefixListId`,[W]:$G}],[()=>xQ,{[H]:`ReferencedGroupInfo`,[W]:bK}],[0,{[H]:`Description`,[W]:jV}],[()=>u1,{[H]:`TagSet`,[W]:Jq}],[0,{[H]:`SecurityGroupRuleArn`,[W]:JK}]]],RQ=[3,G,KL,0,[$N,QN,QL,RL,yF,LL,CO,CR,VO,xoe,Kce,sL,sz,qL,bL,FL,dF,eP,mk,Cz,Rk,eM,Noe],[[0,{[H]:`OwnerAlias`,[W]:xG}],[0,{[H]:`OutpostArn`,[W]:bG}],[()=>u1,{[H]:`TagSet`,[W]:Jq}],[0,{[H]:`StorageTier`,[W]:Eq}],[4,{[H]:`RestoreExpiryTime`,[W]:gK}],[0,{[H]:`SseType`,[W]:Tq}],[0,{[H]:`AvailabilityZone`,[W]:cB}],[0,{[H]:`TransferType`,[W]:$q}],[1,{[H]:`CompletionDurationMinutes`,[W]:PB}],[4,{[H]:`CompletionTime`,[W]:nV}],[1,{[H]:`FullSnapshotSizeInBytes`,[W]:wH}],[0,{[H]:`SnapshotId`,[W]:sq}],[0,{[H]:`VolumeId`,[W]:_J}],[0,{[H]:`Status`,[W]:Nq}],[0,{[H]:`StatusMessage`,[W]:uq}],[4,{[H]:`StartTime`,[W]:wq}],[0,{[H]:`Progress`,[W]:fK}],[0,{[H]:`OwnerId`,[W]:SG}],[0,{[H]:`Description`,[W]:jV}],[1,{[H]:`VolumeSize`,[W]:EJ}],[2,{[H]:`Encrypted`,[W]:yH}],[0,{[H]:`KmsKeyId`,[W]:cW}],[0,{[H]:`DataEncryptionKeyId`,[W]:uV}]]],zQ=[3,G,vL,0,[oN,iL,yae,Oz,Gle],[0,0,1,4,0]],BQ=[3,G,ZI,0,[CA,hO,pk],[[()=>B$,{[W]:_A}],[0,{[H]:`AdditionalInfo`,[W]:qz}],[2,{[H]:`DryRun`,[W]:CV}]],1],VQ=[3,G,QI,0,[lL],[[()=>Q$,{[H]:`InstancesSet`,[W]:JU}]]],HQ=[3,G,kL,0,[nk,vN],[[0,{[H]:`Code`,[W]:iV}],[0,{[H]:`Message`,[W]:JW}]]],UQ=[3,G,$I,0,[CA,hle,TL,pk,zk],[[()=>B$,{[W]:_A}],2,2,[2,{[H]:`DryRun`,[W]:CV}],[2,{[H]:`Force`,[W]:EH}]],1],WQ=[3,G,eL,0,[dL],[[()=>Q$,{[H]:`InstancesSet`,[W]:JU}]]],GQ=[3,G,XL,0,[wO,Dce,zM,Wae,eP,Iie,fA,QL,_I,QN,oce,NA,EP,IO,kR,pL,qL,tz,zO,Fie,CO,Foe,aN],[[0,{[H]:`AvailabilityZoneId`,[W]:lB}],[1,{[H]:`EnableLniAtDeviceIndex`,[W]:QV}],[2,{[H]:`MapCustomerOwnedIpOnLaunch`,[W]:DW}],[0,{[H]:`CustomerOwnedIpv4Pool`,[W]:qB}],[0,{[H]:`OwnerId`,[W]:SG}],[2,{[H]:`AssignIpv6AddressOnCreation`,[W]:Kz}],[()=>zue,{[H]:`Ipv6CidrBlockAssociationSet`,[W]:uU}],[()=>u1,{[H]:`TagSet`,[W]:Jq}],[0,{[H]:`SubnetArn`,[W]:BK}],[0,{[H]:`OutpostArn`,[W]:bG}],[2,{[H]:`EnableDns64`,[W]:LV}],[2,{[H]:`Ipv6Native`,[W]:TU}],[()=>pQ,{[H]:`PrivateDnsNameOptionsOnLaunch`,[W]:RG}],[()=>sY,{[H]:`BlockPublicAccessStates`,[W]:wB}],[0,{[H]:`Type`,[W]:rJ}],[0,{[H]:`SubnetId`,[W]:cq}],[0,{[H]:`State`,[W]:Mq}],[0,{[H]:`VpcId`,[W]:hJ}],[0,{[H]:`CidrBlock`,[W]:kB}],[1,{[H]:`AvailableIpAddressCount`,[W]:Gz}],[0,{[H]:`AvailabilityZone`,[W]:cB}],[2,{[H]:`DefaultForAz`,[W]:fV}],[2,{[H]:`MapPublicIpOnLaunch`,[W]:zW}]]],KQ=[3,G,bI,0,[qL,yL],[[0,{[H]:`State`,[W]:Mq}],[0,{[H]:`StatusMessage`,[W]:uq}]]],qQ=[3,G,HI,0,[gO,dA,pA,sA,Fj],[[0,{[H]:`AssociationId`,[W]:Jz}],[0,{[H]:`Ipv6CidrBlock`,[W]:lU}],[()=>KQ,{[H]:`Ipv6CidrBlockState`,[W]:dU}],[0,{[H]:`Ipv6AddressAttribute`,[W]:$H}],[0,{[H]:`IpSource`,[W]:XU}]]],JQ=[3,G,TR,0,[Xj,VR],[[0,{[H]:`Key`,[W]:aW}],[0,{[H]:`Value`,[W]:dJ}]]],YQ=[3,G,yR,0,[oI,QL],[[0,{[H]:`ResourceType`,[W]:PK}],[()=>u1,{[W]:TR}]]],XQ=[3,G,aR,0,[CA,zk,TL,pk],[[()=>B$,{[W]:_A}],2,2,[2,{[H]:`DryRun`,[W]:CV}]],1],ZQ=[3,G,oR,0,[cR],[[()=>Q$,{[H]:`InstancesSet`,[W]:JU}]]],QQ=[3,G,FR,0,[mk,MR,Xk,Jk,tz,_z,$P],[[0,{[H]:`Description`,[W]:jV}],[0,{[H]:`UserId`,[W]:aJ}],[0,{[H]:`GroupName`,[W]:PH}],[0,{[H]:`GroupId`,[W]:MH}],[0,{[H]:`VpcId`,[W]:hJ}],[0,{[H]:`VpcPeeringConnectionId`,[W]:SJ}],[0,{[H]:`PeeringStatus`,[W]:nK}]]],$Q=[3,G,qR,0,[Bse,Moe,Ise,JR,Ez],[[1,{[H]:`DefaultVCpus`,[W]:AV}],[1,{[H]:`DefaultCores`,[W]:lV}],[1,{[H]:`DefaultThreadsPerCore`,[W]:EV}],[()=>x$,{[H]:`ValidCores`,[W]:pJ}],[()=>Hue,{[H]:`ValidThreadsPerCore`,[W]:kJ}]]],e$=[3,G,Mz,0,[wO,QN,VL,Yj,QL,wz,Gce,FM,DR,LL,fP,iz,sz,WL,sL,CO,qL,tk,AO,Rk,eM],[[0,{[H]:`AvailabilityZoneId`,[W]:lB}],[0,{[H]:`OutpostArn`,[W]:bG}],[0,{[H]:`SourceVolumeId`,[W]:Oq}],[1,{[H]:`Iops`,[W]:iW}],[()=>u1,{[H]:`TagSet`,[W]:Jq}],[0,{[H]:`VolumeType`,[W]:OJ}],[2,{[H]:`FastRestored`,[W]:CH}],[2,{[H]:`MultiAttachEnabled`,[W]:CW}],[1,{[H]:`Throughput`,[W]:tJ}],[0,{[H]:`SseType`,[W]:Tq}],[()=>cQ,{[H]:`Operator`,[W]:AG}],[1,{[H]:`VolumeInitializationRate`,[W]:gJ}],[0,{[H]:`VolumeId`,[W]:_J}],[1,{[H]:`Size`,[W]:jq}],[0,{[H]:`SnapshotId`,[W]:sq}],[0,{[H]:`AvailabilityZone`,[W]:cB}],[0,{[H]:`Status`,[W]:Nq}],[4,{[H]:`CreateTime`,[W]:rV}],[()=>que,{[H]:`AttachmentSet`,[W]:oB}],[2,{[H]:`Encrypted`,[W]:yH}],[0,{[H]:`KmsKeyId`,[W]:cW}]]],t$=[3,G,UR,0,[dk,vO,qA,_k,sz,_A,hk,qL,SO],[[2,{[H]:`DeleteOnTermination`,[W]:bV}],[0,{[H]:`AssociatedResource`,[W]:tB}],[0,{[H]:`InstanceOwningService`,[W]:AU}],[1,{[H]:`EbsCardIndex`,[W]:PV}],[0,{[H]:`VolumeId`,[W]:_J}],[0,{[H]:`InstanceId`,[W]:vU}],[0,{[H]:`Device`,[W]:MV}],[0,{[H]:`Status`,[W]:Nq}],[4,{[H]:`AttachTime`,[W]:sB}]]],n$=[3,G,mz,0,[sz,lN,yL,bR,sR,wR,SR,uR,lP,nP,dP,uP,iP,dF,FL,Lce,fP],[[0,{[H]:`VolumeId`,[W]:_J}],[0,{[H]:`ModificationState`,[W]:UW}],[0,{[H]:`StatusMessage`,[W]:uq}],[1,{[H]:`TargetSize`,[W]:Xq}],[1,{[H]:`TargetIops`,[W]:Hq}],[0,{[H]:`TargetVolumeType`,[W]:eJ}],[1,{[H]:`TargetThroughput`,[W]:Qq}],[2,{[H]:`TargetMultiAttachEnabled`,[W]:Uq}],[1,{[H]:`OriginalSize`,[W]:DG}],[1,{[H]:`OriginalIops`,[W]:wG}],[0,{[H]:`OriginalVolumeType`,[W]:kG}],[1,{[H]:`OriginalThroughput`,[W]:OG}],[2,{[H]:`OriginalMultiAttachEnabled`,[W]:TG}],[1,{[H]:`Progress`,[W]:fK}],[4,{[H]:`StartTime`,[W]:wq}],[4,{[H]:`EndTime`,[W]:gH}],[()=>cQ,{[H]:`Operator`,[W]:AG}]]],r$=[3,G,Nz,0,[eP,Vj,fA,Tae,Ple,ace,QL,IO,tz,qL,zO,ase],[[0,{[H]:`OwnerId`,[W]:SG}],[0,{[H]:`InstanceTenancy`,[W]:nW}],[()=>Que,{[H]:`Ipv6CidrBlockAssociationSet`,[W]:uU}],[()=>Xue,{[H]:`CidrBlockAssociationSet`,[W]:AB}],[2,{[H]:`IsDefault`,[W]:fU}],[()=>o$,{[H]:`EncryptionControl`,[W]:IV}],[()=>u1,{[H]:`TagSet`,[W]:Jq}],[()=>sY,{[H]:`BlockPublicAccessStates`,[W]:wB}],[0,{[H]:`VpcId`,[W]:hJ}],[0,{[H]:`State`,[W]:Mq}],[0,{[H]:`CidrBlock`,[W]:kB}],[0,{[H]:`DhcpOptionsId`,[W]:yV}]]],i$=[3,G,WR,0,[gO,zO,Dae],[[0,{[H]:`AssociationId`,[W]:Jz}],[0,{[H]:`CidrBlock`,[W]:kB}],[()=>a$,{[H]:`CidrBlockState`,[W]:MB}]]],a$=[3,G,KR,0,[qL,yL],[[0,{[H]:`State`,[W]:Mq}],[0,{[H]:`StatusMessage`,[W]:uq}]]],o$=[3,G,YR,0,[tz,$R,bN,qL,bL,bF,QL],[[0,{[H]:`VpcId`,[W]:hJ}],[0,{[H]:`VpcEncryptionControlId`,[W]:mJ}],[0,{[H]:`Mode`,[W]:XW}],[0,{[H]:`State`,[W]:Mq}],[0,{[H]:`StateMessage`,[W]:dq}],[()=>l$,{[H]:`ResourceExclusions`,[W]:vK}],[()=>u1,{[H]:`TagSet`,[W]:Jq}]]],s$=[3,G,XR,0,[bN,Rle,kce,IN,bz,vz,_M,dz,cce],[0,0,0,0,0,0,0,0,0],1],c$=[3,G,ZR,0,[qL,bL],[[0,{[H]:`State`,[W]:Mq}],[0,{[H]:`StateMessage`,[W]:dq}]]],l$=[3,G,QR,0,[hA,Oce,FN,yz,xz,MM,uz,sce],[[()=>c$,{[H]:`InternetGateway`,[W]:mU}],[()=>c$,{[H]:`EgressOnlyInternetGateway`,[W]:tH}],[()=>c$,{[H]:`NatGateway`,[W]:iG}],[()=>c$,{[H]:`VirtualPrivateGateway`,[W]:CJ}],[()=>c$,{[H]:`VpcPeering`,[W]:wJ}],[()=>c$,{[H]:`Lambda`,[W]:SW}],[()=>c$,{[H]:`VpcLattice`,[W]:vJ}],[()=>c$,{[H]:`ElasticFileSystem`,[W]:RV}]]],u$=[3,G,nz,0,[gO,dA,pA,CN,dj,sA,Fj],[[0,{[H]:`AssociationId`,[W]:Jz}],[0,{[H]:`Ipv6CidrBlock`,[W]:lU}],[()=>a$,{[H]:`Ipv6CidrBlockState`,[W]:dU}],[0,{[H]:`NetworkBorderGroup`,[W]:QW}],[0,{[H]:`Ipv6Pool`,[W]:RU}],[0,{[H]:`Ipv6AddressAttribute`,[W]:$H}],[0,{[H]:`IpSource`,[W]:XU}]]],d$=`unit`,f$=[1,G,eae,0,[0,{[W]:U}]],p$=[1,G,aae,0,[()=>nY,{[W]:U}]],m$=[1,G,oae,0,[()=>tY,{[W]:U}]],h$=[1,G,cae,0,[()=>rY,{[W]:U}]],g$=[1,G,uae,0,[()=>iY,{[W]:U}]],_$=[1,G,Cae,0,[0,{[W]:U}]],v$=[1,G,_ae,0,[()=>oY,{[W]:U}]],y$=[1,G,vae,0,[()=>oY,{[W]:MO}]],b$=[1,G,bae,0,[0,{[W]:U}]],x$=[1,G,Oae,0,[1,{[W]:U}]],S$=[1,G,Boe,0,[()=>CX,{[W]:U}]],C$=[1,G,nce,0,[()=>TX,{[W]:U}]],w$=[1,G,dce,0,[()=>jX,{[W]:U}]],T$=[1,G,gce,0,[()=>MX,{[W]:U}]],E$=[1,G,yce,0,[()=>PX,{[W]:U}]],D$=[1,G,bk,0,[()=>NX,{[W]:U}]],O$=[1,G,tce,0,[0,{[W]:gk}]],k$=[1,G,Wce,0,[()=>zX,{[W]:Wk}]],A$=[1,G,Vce,0,[()=>BX,{[W]:U}]],j$=[1,G,ele,0,[()=>GX,{[W]:U}]],M$=[1,G,nle,0,[()=>JX,{[W]:U}]],N$=[1,G,rle,0,[0,{[W]:MH}]],P$=[1,G,ole,0,[0,{[W]:Xk}]],F$=[1,G,Zle,0,[0,{[W]:SA}]],I$=[1,G,iue,0,[()=>$X,{[W]:U}]],L$=[1,G,jle,0,[()=>rZ,0]],R$=[1,G,Tle,0,[()=>cZ,{[W]:U}]],z$=[1,G,Dle,0,[()=>lZ,{[W]:U}]],B$=[1,G,Qle,0,[0,{[W]:_A}]],V$=[1,G,Kle,0,[()=>uZ,{[W]:U}]],H$=[1,G,Wle,0,[()=>dZ,{[W]:U}]],U$=[1,G,qle,0,[()=>fZ,{[W]:U}]],W$=[1,G,wA,0,[()=>aZ,{[W]:U}]],G$=[1,G,LA,0,[()=>vZ,{[W]:U}]],K$=[1,G,zA,0,[()=>xZ,{[W]:U}]],q$=[1,G,QA,0,[()=>wZ,{[W]:U}]],J$=[1,G,Cj,0,[()=>TZ,{[W]:U}]],Y$=[1,G,Tj,0,[()=>DZ,{[W]:U}]],X$=[1,G,Ej,0,[()=>OZ,{[W]:U}]],Z$=[1,G,Oj,0,[()=>kZ,{[W]:U}]],Q$=[1,G,xj,0,[()=>jZ,{[W]:U}]],$$=[1,G,Rj,0,[()=>NZ,{[W]:U}]],e1=[1,G,Ile,0,[()=>FZ,{[W]:U}]],t1=[1,G,zle,0,[0,{[W]:U}]],n1=[1,G,Vle,0,[()=>PZ,{[W]:U}]],r1=[1,G,tj,0,[()=>IZ,{[W]:U}]],oue=[1,G,mj,0,[()=>LZ,{[W]:U}]],sue=[1,G,nj,0,[()=>RZ,{[W]:U}]],cue=[1,G,rj,0,[()=>zZ,{[W]:U}]],lue=[1,G,hj,0,[()=>BZ,{[W]:U}]],uue=[1,G,rM,0,[0,{[W]:nM}]],due=[1,G,sM,0,[0,{[W]:oM}]],fue=[1,G,uM,0,[()=>HZ,{[W]:U}]],pue=[1,G,xM,0,[()=>WZ,{[W]:U}]],mue=[1,G,wM,0,[()=>GZ,{[W]:U}]],hue=[1,G,UM,0,[()=>qZ,{[W]:U}]],gue=[1,G,EN,0,[()=>eQ,{[W]:U}]],_ue=[1,G,jN,0,[()=>rQ,{[W]:U}]],vue=[1,G,JN,0,[0,{[W]:U}]],i1=[1,G,cP,0,[0,{[W]:hP}]],yue=[1,G,NP,0,[0,{[W]:Jk}]],bue=[1,G,PP,0,[()=>uQ,{[W]:U}]],xue=[1,G,FP,0,[0,{[W]:U}]],Sue=[1,G,XP,0,[()=>fQ,{[W]:U}]],Cue=[1,G,BP,0,[()=>gQ,{[W]:U}]],a1=[1,G,yP,0,[()=>vQ,{[W]:U}]],wue=[1,G,iF,0,[()=>yQ,{[W]:U}]],Tue=[1,G,wF,0,[()=>CQ,{[W]:U}]],Eue=[1,G,PF,0,[()=>SQ,{[W]:U}]],Due=[1,G,BF,0,[0,{[W]:zF}]],Oue=[1,G,FF,0,[()=>wQ,{[W]:U}]],o1=[1,G,XF,0,[()=>TQ,{[W]:U}]],kue=[1,G,vF,0,[0,{[W]:U}]],Aue=[1,G,IF,0,[()=>AQ,{[W]:U}]],jue=[1,G,eI,0,[()=>MQ,{[W]:U}]],Mue=[1,G,rI,0,[0,{[W]:U}]],Nue=[1,G,aI,0,[()=>jQ,{[W]:U}]],s1=[1,G,OI,0,[0,{[W]:DI}]],Pue=[1,G,AI,0,[()=>IQ,{[W]:U}]],c1=[1,G,PI,0,[0,{[W]:U}]],l1=[1,G,II,0,[()=>LQ,{[W]:U}]],Fue=[1,G,RI,0,[0,{[W]:BI}]],Iue=[1,G,nL,0,[0,{[W]:sL}]],Lue=[1,G,hL,0,[()=>RQ,{[W]:U}]],Rue=[1,G,rL,0,[0,{[W]:pL}]],zue=[1,G,UI,0,[()=>qQ,{[W]:U}]],Bue=[1,G,_L,0,[()=>GQ,{[W]:U}]],Vue=[1,G,gI,0,[0,{[W]:U}]],u1=[1,G,lR,0,[()=>JQ,{[W]:U}]],d1=[1,G,vR,0,[()=>YQ,{[W]:U}]],Hue=[1,G,hR,0,[1,{[W]:U}]],Uue=[1,G,AR,0,[0,{[W]:U}]],Wue=[1,G,PR,0,[()=>QQ,{[W]:U}]],Gue=[1,G,Sz,0,[0,{[W]:U}]],Kue=[1,G,Tz,0,[0,{[W]:U}]],que=[1,G,HR,0,[()=>t$,{[W]:U}]],Jue=[1,G,az,0,[0,{[W]:sz}]],Yue=[1,G,fz,0,[()=>e$,{[W]:U}]],Xue=[1,G,GR,0,[()=>i$,{[W]:U}]],Zue=[1,G,oz,0,[0,{[W]:tz}]],Que=[1,G,rz,0,[()=>u$,{[W]:U}]],$ue=[1,G,pz,0,[()=>r$,{[W]:U}]],ede=[1,G,Fz,0,[0,{[W]:U}]],tde=[1,G,Rz,0,[0,{[W]:Lz}]],nde=[1,G,Vz,0,[0,{[W]:Bz}]],rde=[9,G,Kie,0,()=>GJ,()=>KJ],ide=[9,G,Lie,0,()=>qJ,()=>d$],ade=[9,G,rae,0,()=>JJ,()=>t$],ode=[9,G,Jie,0,()=>ZJ,()=>QJ],sde=[9,G,$ie,0,()=>$J,()=>eY],cde=[9,G,poe,0,()=>mY,()=>hY],lde=[9,G,Bae,0,()=>vY,()=>yY],ude=[9,G,Pae,0,()=>bY,()=>xY],dde=[9,G,Vae,0,()=>SY,()=>VZ],fde=[9,G,Kae,0,()=>CY,()=>wY],pde=[9,G,noe,0,()=>TY,()=>EY],mde=[9,G,toe,0,()=>DY,()=>OY],hde=[9,G,roe,0,()=>kY,()=>AY],gde=[9,G,hoe,0,()=>jY,()=>RQ],_de=[9,G,goe,0,()=>MY,()=>NY],vde=[9,G,Toe,0,()=>PY,()=>e$],yde=[9,G,Eoe,0,()=>FY,()=>IY],bde=[9,G,Zoe,0,()=>zY,()=>BY],xde=[9,G,ose,0,()=>VY,()=>d$],Sde=[9,G,yse,0,()=>HY,()=>UY],Cde=[9,G,jse,0,()=>WY,()=>d$],wde=[9,G,Mse,0,()=>GY,()=>d$],Tde=[9,G,Jse,0,()=>KY,()=>d$],Ede=[9,G,Yse,0,()=>qY,()=>d$],Dde=[9,G,Aoe,0,()=>JY,()=>YY],Ode=[9,G,Joe,0,()=>XY,()=>ZY],kde=[9,G,Yoe,0,()=>QY,()=>$Y],Ade=[9,G,qoe,0,()=>eX,()=>tX],jde=[9,G,zoe,0,()=>nX,()=>rX],Mde=[9,G,nse,0,()=>iX,()=>aX],Nde=[9,G,use,0,()=>oX,()=>sX],Pde=[9,G,vse,0,()=>cX,()=>lX],Fde=[9,G,gse,0,()=>uX,()=>dX],Ide=[9,G,wse,0,()=>fX,()=>pX],Lde=[9,G,Nse,0,()=>mX,()=>hX],Rde=[9,G,Pse,0,()=>gX,()=>_X],zde=[9,G,Xse,0,()=>vX,()=>yX],Bde=[9,G,Zse,0,()=>bX,()=>xX],Vde=[9,G,Qse,0,()=>SX,()=>t$],Hde=[9,G,Yce,0,()=>UX,()=>WX],Ude=[9,G,eue,0,()=>eZ,()=>tZ],Wde=[9,G,$M,0,()=>XZ,()=>d$],Gde=[9,G,mN,0,()=>ZZ,()=>QZ],Kde=[9,G,jF,0,()=>bQ,()=>d$],qde=[9,G,UF,0,()=>EQ,()=>DQ],Jde=[9,G,JF,0,()=>OQ,()=>kQ],Yde=[9,G,NF,0,()=>FQ,()=>wQ],Xde=[9,G,uL,0,()=>BQ,()=>VQ],Zde=[9,G,fL,0,()=>UQ,()=>WQ],Qde=[9,G,rR,0,()=>XQ,()=>ZQ],$de=e=>({apiVersion:`2016-11-15`,base64Decoder:e?.base64Decoder??TC,base64Encoder:e?.base64Encoder??EC,disableHostPrefix:e?.disableHostPrefix??!1,endpointProvider:e?.endpointProvider??kie,extensions:e?.extensions??[],httpAuthSchemeProvider:e?.httpAuthSchemeProvider??aie,httpAuthSchemes:e?.httpAuthSchemes??[{schemeId:`aws.auth#sigv4`,identityProvider:e=>e.getIdentityProvider(`aws.auth#sigv4`),signer:new BD}],logger:e?.logger??new MD,protocol:e?.protocol??bie,protocolSettings:e?.protocolSettings??{defaultNamespace:`com.amazonaws.ec2`,errorTypeRegistries:BJ,xmlNamespace:`http://ec2.amazonaws.com/doc/2016-11-15`,version:`2016-11-15`,serviceTarget:`AmazonEC2`},serviceId:e?.serviceId??`EC2`,urlParser:e?.urlParser??XC,utf8Decoder:e?.utf8Decoder??Zx,utf8Encoder:e?.utf8Encoder??$x}),efe=e=>{let t=JD(e),n=()=>t().then(DD),r=$de(e);return{...r,...e,runtime:`browser`,defaultsMode:t,bodyLengthChecker:e?.bodyLengthChecker??qD,credentialDefaultProvider:e?.credentialDefaultProvider??(e=>()=>Promise.reject(Error(`Credential is missing`))),defaultUserAgentProvider:e?.defaultUserAgentProvider??UD({serviceId:r.serviceId,clientVersion:cie.version}),maxAttempts:e?.maxAttempts??3,region:e?.region??GD(`Region is missing`),requestHandler:PC.create(e?.requestHandler??n),retryMode:e?.retryMode??(async()=>(await n()).retryMode||TE),sha256:e?.sha256??Rx,streamCollector:e?.streamCollector??IC,useDualstackEndpoint:e?.useDualstackEndpoint??(()=>Promise.resolve(!1)),useFipsEndpoint:e?.useFipsEndpoint??(()=>Promise.resolve(!1))}},f1=e=>({setRegion(t){e.region=t},region(){return e.region}}),p1=e=>({region:e.region()}),tfe=e=>{let t=e.httpAuthSchemes,n=e.httpAuthSchemeProvider,r=e.credentials;return{setHttpAuthScheme(e){let n=t.findIndex(t=>t.schemeId===e.schemeId);n===-1?t.push(e):t.splice(n,1,e)},httpAuthSchemes(){return t},setHttpAuthSchemeProvider(e){n=e},httpAuthSchemeProvider(){return n},setCredentials(e){r=e},credentials(){return r}}},nfe=e=>({httpAuthSchemes:e.httpAuthSchemes(),httpAuthSchemeProvider:e.httpAuthSchemeProvider(),credentials:e.credentials()}),rfe=(e,t)=>{let n=Object.assign(f1(e),kD(e),zx(e),tfe(e));return t.forEach(e=>e.configure(n)),Object.assign(e,p1(n),AD(n),Bx(n),nfe(n))},ife=class extends xD{config;constructor(...[e]){let t=efe(e||{});super(t),this.initConfig=t;let n=rfe(oie(mD(tC(oD(hD(NT(sie(t))))))),e?.extensions||[]);this.config=n,this.middlewareStack.use(tw(this.config)),this.middlewareStack.use(rD(this.config)),this.middlewareStack.use(PD(this.config)),this.middlewareStack.use(cD(this.config)),this.middlewareStack.use(iC(this.config)),this.middlewareStack.use(sC(this.config)),this.middlewareStack.use(uC(this.config)),this.middlewareStack.use(hC(this.config,{httpAuthSchemeParametersProvider:rie,identityProviderConfigProvider:async e=>new OT({"aws.auth#sigv4":e.credentials})})),this.middlewareStack.use(bC(this.config))}destroy(){super.destroy()}},afe=class extends wD.classBuilder().ep(HD).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeAvailabilityZones`,{}).n(`EC2Client`,`DescribeAvailabilityZonesCommand`).sc(Dde).build(){},m1=class extends wD.classBuilder().ep(HD).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeImages`,{}).n(`EC2Client`,`DescribeImagesCommand`).sc(Ode).build(){},h1=class extends wD.classBuilder().ep(HD).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeInstances`,{}).n(`EC2Client`,`DescribeInstancesCommand`).sc(kde).build(){},ofe=class extends wD.classBuilder().ep(HD).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeInstanceTypes`,{}).n(`EC2Client`,`DescribeInstanceTypesCommand`).sc(Ade).build(){};wD.classBuilder().ep(HD).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeInternetGateways`,{}).n(`EC2Client`,`DescribeInternetGatewaysCommand`).sc(jde).build();var g1=class extends wD.classBuilder().ep(HD).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeKeyPairs`,{}).n(`EC2Client`,`DescribeKeyPairsCommand`).sc(Mde).build(){},_1=class extends wD.classBuilder().ep(HD).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribePlacementGroups`,{}).n(`EC2Client`,`DescribePlacementGroupsCommand`).sc(Nde).build(){},sfe=class extends wD.classBuilder().ep(HD).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeRegions`,{}).n(`EC2Client`,`DescribeRegionsCommand`).sc(Pde).build(){};wD.classBuilder().ep(HD).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeRouteTables`,{}).n(`EC2Client`,`DescribeRouteTablesCommand`).sc(Fde).build();var v1=class extends wD.classBuilder().ep(HD).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeSecurityGroups`,{}).n(`EC2Client`,`DescribeSecurityGroupsCommand`).sc(Ide).build(){},y1=class extends wD.classBuilder().ep(HD).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeSnapshots`,{}).n(`EC2Client`,`DescribeSnapshotsCommand`).sc(Lde).build(){},b1=class extends wD.classBuilder().ep(HD).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeSubnets`,{}).n(`EC2Client`,`DescribeSubnetsCommand`).sc(Rde).build(){},x1=class extends wD.classBuilder().ep(HD).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeVolumes`,{}).n(`EC2Client`,`DescribeVolumesCommand`).sc(zde).build(){},S1=class extends wD.classBuilder().ep(HD).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeVpcs`,{}).n(`EC2Client`,`DescribeVpcsCommand`).sc(Bde).build(){},cfe=async(e,t,n)=>({operation:FS(t).operation,region:await IS(e.region)()||(()=>{throw Error("expected `region` to be configured for `aws.auth#sigv4`")})()});function lfe(e){return{schemeId:`aws.auth#sigv4`,signingProperties:{name:`elasticloadbalancing`,region:e.region},propertiesExtractor:(e,t)=>({signingProperties:{config:e,context:t}})}}var ufe=e=>{let t=[];switch(e.operation){default:t.push(lfe(e))}return t},dfe=e=>{let t=VD(e);return Object.assign(t,{authSchemePreference:IS(e.authSchemePreference??[])})},ffe=e=>Object.assign(e,{useDualstackEndpoint:e.useDualstackEndpoint??!1,useFipsEndpoint:e.useFipsEndpoint??!1,defaultSigningName:`elasticloadbalancing`}),C1={UseFIPS:{type:`builtInParams`,name:`useFipsEndpoint`},Endpoint:{type:`builtInParams`,name:`endpoint`},Region:{type:`builtInParams`,name:`region`},UseDualStack:{type:`builtInParams`,name:`useDualstackEndpoint`}},pfe={name:`@aws-sdk/client-elastic-load-balancing-v2`,description:`AWS SDK for JavaScript Elastic Load Balancing V2 Client for Node.js, Browser and React Native`,version:`3.1045.0`,scripts:{build:`concurrently 'yarn:build:types' 'yarn:build:es' && yarn build:cjs`,"build:cjs":`node ../../scripts/compilation/inline client-elastic-load-balancing-v2`,"build:es":`tsc -p tsconfig.es.json`,"build:include:deps":`yarn g:turbo run build -F="$npm_package_name"`,"build:types":`tsc -p tsconfig.types.json`,"build:types:downlevel":`downlevel-dts dist-types dist-types/ts3.4`,clean:`premove dist-cjs dist-es dist-types tsconfig.cjs.tsbuildinfo tsconfig.es.tsbuildinfo tsconfig.types.tsbuildinfo`,"extract:docs":`api-extractor run --local`,"generate:client":`node ../../scripts/generate-clients/single-service --solo elastic-load-balancing-v2`,"test:e2e":`yarn g:vitest run -c vitest.config.e2e.mts --mode development`,"test:e2e:watch":`yarn g:vitest watch -c vitest.config.e2e.mts`,"test:index":`tsc --noEmit ./test/index-types.ts && node ./test/index-objects.spec.mjs`},main:`./dist-cjs/index.js`,types:`./dist-types/index.d.ts`,module:`./dist-es/index.js`,sideEffects:!1,dependencies:{"@aws-crypto/sha256-browser":`5.2.0`,"@aws-crypto/sha256-js":`5.2.0`,"@aws-sdk/core":`^3.974.8`,"@aws-sdk/credential-provider-node":`^3.972.39`,"@aws-sdk/middleware-host-header":`^3.972.10`,"@aws-sdk/middleware-logger":`^3.972.10`,"@aws-sdk/middleware-recursion-detection":`^3.972.11`,"@aws-sdk/middleware-user-agent":`^3.972.38`,"@aws-sdk/region-config-resolver":`^3.972.13`,"@aws-sdk/types":`^3.973.8`,"@aws-sdk/util-endpoints":`^3.996.8`,"@aws-sdk/util-user-agent-browser":`^3.972.10`,"@aws-sdk/util-user-agent-node":`^3.973.24`,"@smithy/config-resolver":`^4.4.17`,"@smithy/core":`^3.23.17`,"@smithy/fetch-http-handler":`^5.3.17`,"@smithy/hash-node":`^4.2.14`,"@smithy/invalid-dependency":`^4.2.14`,"@smithy/middleware-content-length":`^4.2.14`,"@smithy/middleware-endpoint":`^4.4.32`,"@smithy/middleware-retry":`^4.5.7`,"@smithy/middleware-serde":`^4.2.20`,"@smithy/middleware-stack":`^4.2.14`,"@smithy/node-config-provider":`^4.3.14`,"@smithy/node-http-handler":`^4.6.1`,"@smithy/protocol-http":`^5.3.14`,"@smithy/smithy-client":`^4.12.13`,"@smithy/types":`^4.14.1`,"@smithy/url-parser":`^4.2.14`,"@smithy/util-base64":`^4.3.2`,"@smithy/util-body-length-browser":`^4.2.2`,"@smithy/util-body-length-node":`^4.2.3`,"@smithy/util-defaults-mode-browser":`^4.3.49`,"@smithy/util-defaults-mode-node":`^4.2.54`,"@smithy/util-endpoints":`^3.4.2`,"@smithy/util-middleware":`^4.2.14`,"@smithy/util-retry":`^4.3.6`,"@smithy/util-utf8":`^4.2.2`,"@smithy/util-waiter":`^4.3.0`,tslib:`^2.6.2`},devDependencies:{"@tsconfig/node20":`20.1.8`,"@types/node":`^20.14.8`,concurrently:`7.0.0`,"downlevel-dts":`0.10.1`,premove:`4.0.0`,typescript:`~5.8.3`},engines:{node:`>=20.0.0`},typesVersions:{"<4.5":{"dist-types/*":[`dist-types/ts3.4/*`]}},files:[`dist-*/**`],author:{name:`AWS SDK for JavaScript Team`,url:`https://aws.amazon.com/javascript/`},license:`Apache-2.0`,browser:{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.browser`},"react-native":{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.native`},homepage:`https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-elastic-load-balancing-v2`,repository:{type:`git`,url:`https://github.com/aws/aws-sdk-js-v3.git`,directory:`clients/client-elastic-load-balancing-v2`}},w1=`ref`,T1=-1,E1=!0,D1=`isSet`,O1=`PartitionResult`,k1=`booleanEquals`,A1=`getAttr`,j1={[w1]:`Endpoint`},M1={[w1]:O1},N1={},P1=[{[w1]:`Region`}],F1={conditions:[[D1,[j1]],[D1,P1],[`aws.partition`,P1,O1],[k1,[{[w1]:`UseFIPS`},E1]],[k1,[{[w1]:`UseDualStack`},E1]],[k1,[{fn:A1,argv:[M1,`supportsDualStack`]},E1]],[k1,[{fn:A1,argv:[M1,`supportsFIPS`]},E1]],[`stringEquals`,[{fn:A1,argv:[M1,`name`]},`aws-us-gov`]]],results:[[T1],[T1,`Invalid Configuration: FIPS and custom endpoint are not supported`],[T1,`Invalid Configuration: Dualstack and custom endpoint are not supported`],[j1,N1],[`https://elasticloadbalancing-fips.{Region}.{PartitionResult#dualStackDnsSuffix}`,N1],[T1,`FIPS and DualStack are enabled, but this partition does not support one or both`],[`https://elasticloadbalancing.{Region}.amazonaws.com`,N1],[`https://elasticloadbalancing-fips.{Region}.{PartitionResult#dnsSuffix}`,N1],[T1,`FIPS is enabled but this partition does not support FIPS`],[`https://elasticloadbalancing.{Region}.{PartitionResult#dualStackDnsSuffix}`,N1],[T1,`DualStack is enabled but this partition does not support DualStack`],[`https://elasticloadbalancing.{Region}.{PartitionResult#dnsSuffix}`,N1],[T1,`Invalid Configuration: Missing Region`]]},mfe=2,I1=1e8,hfe=new Int32Array([-1,1,-1,0,13,3,1,4,I1+12,2,5,I1+12,3,8,6,4,7,I1+11,5,I1+9,I1+10,4,11,9,6,10,I1+8,7,I1+6,I1+7,5,12,I1+5,6,I1+4,I1+5,3,I1+1,14,4,I1+2,I1+3]),gfe=PT.from(hfe,mfe,F1.conditions,F1.results),_fe=new FT({size:50,params:[`Endpoint`,`Region`,`UseDualStack`,`UseFIPS`]}),vfe=(e,t={})=>_fe.get(e,()=>pE(gfe,{endpointParams:e,logger:t.logger}));zT.aws=SE;var K=class e extends TD{constructor(t){super(t),Object.setPrototypeOf(this,e.prototype)}},yfe=class e extends K{name=`CertificateNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`CertificateNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},bfe=class e extends K{name=`ListenerNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`ListenerNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},xfe=class e extends K{name=`TooManyCertificatesException`;$fault=`client`;Message;constructor(t){super({name:`TooManyCertificatesException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Sfe=class e extends K{name=`DuplicateTagKeysException`;$fault=`client`;Message;constructor(t){super({name:`DuplicateTagKeysException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Cfe=class e extends K{name=`LoadBalancerNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`LoadBalancerNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},wfe=class e extends K{name=`RuleNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`RuleNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Tfe=class e extends K{name=`TargetGroupNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`TargetGroupNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Efe=class e extends K{name=`TooManyTagsException`;$fault=`client`;Message;constructor(t){super({name:`TooManyTagsException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Dfe=class e extends K{name=`TrustStoreNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`TrustStoreNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Ofe=class e extends K{name=`InvalidRevocationContentException`;$fault=`client`;Message;constructor(t){super({name:`InvalidRevocationContentException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},kfe=class e extends K{name=`RevocationContentNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`RevocationContentNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Afe=class e extends K{name=`TooManyTrustStoreRevocationEntriesException`;$fault=`client`;Message;constructor(t){super({name:`TooManyTrustStoreRevocationEntriesException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},jfe=class e extends K{name=`AllocationIdNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`AllocationIdNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Mfe=class e extends K{name=`ALPNPolicyNotSupportedException`;$fault=`client`;Message;constructor(t){super({name:`ALPNPolicyNotSupportedException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Nfe=class e extends K{name=`AvailabilityZoneNotSupportedException`;$fault=`client`;Message;constructor(t){super({name:`AvailabilityZoneNotSupportedException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Pfe=class e extends K{name=`CaCertificatesBundleNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`CaCertificatesBundleNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Ffe=class e extends K{name=`CapacityDecreaseRequestsLimitExceededException`;$fault=`client`;Message;constructor(t){super({name:`CapacityDecreaseRequestsLimitExceededException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Ife=class e extends K{name=`CapacityReservationPendingException`;$fault=`client`;Message;constructor(t){super({name:`CapacityReservationPendingException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Lfe=class e extends K{name=`CapacityUnitsLimitExceededException`;$fault=`client`;Message;constructor(t){super({name:`CapacityUnitsLimitExceededException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Rfe=class e extends K{name=`DuplicateListenerException`;$fault=`client`;Message;constructor(t){super({name:`DuplicateListenerException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},zfe=class e extends K{name=`IncompatibleProtocolsException`;$fault=`client`;Message;constructor(t){super({name:`IncompatibleProtocolsException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Bfe=class e extends K{name=`InvalidConfigurationRequestException`;$fault=`client`;Message;constructor(t){super({name:`InvalidConfigurationRequestException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Vfe=class e extends K{name=`InvalidLoadBalancerActionException`;$fault=`client`;Message;constructor(t){super({name:`InvalidLoadBalancerActionException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Hfe=class e extends K{name=`SSLPolicyNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`SSLPolicyNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Ufe=class e extends K{name=`TargetGroupAssociationLimitException`;$fault=`client`;Message;constructor(t){super({name:`TargetGroupAssociationLimitException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Wfe=class e extends K{name=`TooManyActionsException`;$fault=`client`;Message;constructor(t){super({name:`TooManyActionsException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Gfe=class e extends K{name=`TooManyListenersException`;$fault=`client`;Message;constructor(t){super({name:`TooManyListenersException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Kfe=class e extends K{name=`TooManyRegistrationsForTargetIdException`;$fault=`client`;Message;constructor(t){super({name:`TooManyRegistrationsForTargetIdException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},qfe=class e extends K{name=`TooManyTargetsException`;$fault=`client`;Message;constructor(t){super({name:`TooManyTargetsException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Jfe=class e extends K{name=`TooManyUniqueTargetGroupsPerLoadBalancerException`;$fault=`client`;Message;constructor(t){super({name:`TooManyUniqueTargetGroupsPerLoadBalancerException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Yfe=class e extends K{name=`TrustStoreNotReadyException`;$fault=`client`;Message;constructor(t){super({name:`TrustStoreNotReadyException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Xfe=class e extends K{name=`UnsupportedProtocolException`;$fault=`client`;Message;constructor(t){super({name:`UnsupportedProtocolException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Zfe=class e extends K{name=`DuplicateLoadBalancerNameException`;$fault=`client`;Message;constructor(t){super({name:`DuplicateLoadBalancerNameException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Qfe=class e extends K{name=`InvalidSchemeException`;$fault=`client`;Message;constructor(t){super({name:`InvalidSchemeException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},$fe=class e extends K{name=`InvalidSecurityGroupException`;$fault=`client`;Message;constructor(t){super({name:`InvalidSecurityGroupException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},epe=class e extends K{name=`InvalidSubnetException`;$fault=`client`;Message;constructor(t){super({name:`InvalidSubnetException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},tpe=class e extends K{name=`OperationNotPermittedException`;$fault=`client`;Message;constructor(t){super({name:`OperationNotPermittedException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},npe=class e extends K{name=`ResourceInUseException`;$fault=`client`;Message;constructor(t){super({name:`ResourceInUseException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},rpe=class e extends K{name=`SubnetNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`SubnetNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},ipe=class e extends K{name=`TooManyLoadBalancersException`;$fault=`client`;Message;constructor(t){super({name:`TooManyLoadBalancersException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},ape=class e extends K{name=`PriorityInUseException`;$fault=`client`;Message;constructor(t){super({name:`PriorityInUseException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},ope=class e extends K{name=`TooManyRulesException`;$fault=`client`;Message;constructor(t){super({name:`TooManyRulesException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},spe=class e extends K{name=`TooManyTargetGroupsException`;$fault=`client`;Message;constructor(t){super({name:`TooManyTargetGroupsException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},cpe=class e extends K{name=`DuplicateTargetGroupNameException`;$fault=`client`;Message;constructor(t){super({name:`DuplicateTargetGroupNameException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},lpe=class e extends K{name=`DuplicateTrustStoreNameException`;$fault=`client`;Message;constructor(t){super({name:`DuplicateTrustStoreNameException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},upe=class e extends K{name=`InvalidCaCertificatesBundleException`;$fault=`client`;Message;constructor(t){super({name:`InvalidCaCertificatesBundleException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},dpe=class e extends K{name=`TooManyTrustStoresException`;$fault=`client`;Message;constructor(t){super({name:`TooManyTrustStoresException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},fpe=class e extends K{name=`DeleteAssociationSameAccountException`;$fault=`client`;Message;constructor(t){super({name:`DeleteAssociationSameAccountException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},ppe=class e extends K{name=`TrustStoreAssociationNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`TrustStoreAssociationNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},mpe=class e extends K{name=`TrustStoreInUseException`;$fault=`client`;Message;constructor(t){super({name:`TrustStoreInUseException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},hpe=class e extends K{name=`InvalidTargetException`;$fault=`client`;Message;constructor(t){super({name:`InvalidTargetException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},gpe=class e extends K{name=`HealthUnavailableException`;$fault=`server`;Message;constructor(t){super({name:`HealthUnavailableException`,$fault:`server`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},_pe=class e extends K{name=`RevocationIdNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`RevocationIdNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},vpe=class e extends K{name=`ResourceNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`ResourceNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},ype=class e extends K{name=`InsufficientCapacityException`;$fault=`server`;Message;constructor(t){super({name:`InsufficientCapacityException`,$fault:`server`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},bpe=class e extends K{name=`PriorRequestNotCompleteException`;$fault=`client`;Message;constructor(t){super({name:`PriorRequestNotCompleteException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},xpe=`Action`,Spe=`AdditionalClaims`,Cpe=`AuthenticateCognitoActionConfig`,wpe=`AuthenticateCognitoConfig`,L1=`AnomalyDetection`,Tpe=`AuthorizationEndpoint`,R1=`AllocationId`,Epe=`AllocationIdNotFoundException`,Dpe=`ALPNPolicyNotSupportedException`,z1=`AdministrativeOverride`,Ope=`AuthenticateOidcActionConfig`,kpe=`AuthenticateOidcConfig`,B1=`AlpnPolicy`,V1=`AuthenticationRequestExtraParams`,Ape=`AdvertiseTrustStoreCaNames`,H1=`AvailabilityZone`,jpe=`AvailabilityZoneNotSupportedException`,U1=`AvailabilityZones`,W1=`Actions`,G1=`Attributes`,K1=`Certificates`,Mpe=`CertificateArn`,Npe=`CaCertificatesBundleNotFoundException`,Ppe=`CapacityDecreaseRequestsLimitExceededException`,Fpe=`CanonicalHostedZoneId`,Ipe=`ClientId`,Lpe=`CertificateList`,Rpe=`CreateLoadBalancer`,zpe=`CreateLoadBalancerInput`,Bpe=`CreateLoadBalancerOutput`,Vpe=`CreateListenerInput`,Hpe=`CreateListenerOutput`,Upe=`CreateListener`,Wpe=`CertificateNotFoundException`,q1=`CustomerOwnedIpv4Pool`,Gpe=`CreateRule`,Kpe=`CreateRuleInput`,qpe=`CreateRuleOutput`,Jpe=`CapacityReservationPendingException`,Ype=`ClientSecret`,Xpe=`ContentType`,Zpe=`CreateTargetGroup`,Qpe=`CreateTargetGroupInput`,$pe=`CreateTargetGroupOutput`,eme=`CreatedTime`,tme=`CapacityUnitsLimitExceededException`,nme=`Certificate`,rme=`Code`,J1=`Conditions`,Y1=`Description`,X1=`DefaultActions`,ime=`DeleteAssociationSameAccountException`,ame=`DeleteListener`,ome=`DeleteLoadBalancer`,sme=`DescribeLoadBalancerAttributes`,cme=`DescribeLoadBalancerAttributesInput`,lme=`DescribeLoadBalancerAttributesOutput`,ume=`DeleteLoadBalancerInput`,dme=`DescribeLoadBalancersInput`,fme=`DuplicateLoadBalancerNameException`,pme=`DeleteLoadBalancerOutput`,mme=`DescribeLoadBalancersOutput`,hme=`DescribeLoadBalancers`,gme=`DuplicateListenerException`,_me=`DeleteListenerInput`,vme=`DescribeListenersInput`,yme=`DeleteListenerOutput`,bme=`DescribeListenersOutput`,xme=`DescribeListeners`,Sme=`DNSName`,Cme=`DeleteRule`,wme=`DeleteRuleInput`,Tme=`DescribeRulesInput`,Eme=`DeleteRuleOutput`,Dme=`DescribeRulesOutput`,Ome=`DescribeRules`,kme=`DurationSeconds`,Ame=`DeregisterTargets`,jme=`DeleteTargetGroup`,Mme=`DescribeTargetGroupAttributes`,Nme=`DescribeTargetGroupAttributesInput`,Pme=`DescribeTargetGroupAttributesOutput`,Fme=`DeleteTargetGroupInput`,Ime=`DescribeTargetGroupsInput`,Lme=`DuplicateTargetGroupNameException`,Rme=`DeleteTargetGroupOutput`,zme=`DescribeTargetGroupsOutput`,Bme=`DescribeTargetGroups`,Vme=`DescribeTargetHealth`,Hme=`DescribeTargetHealthInput`,Ume=`DescribeTargetHealthOutput`,Wme=`DeregisterTargetsInput`,Gme=`DescribeTagsInput`,Kme=`DuplicateTagKeysException`,qme=`DeregisterTargetsOutput`,Jme=`DescribeTagsOutput`,Yme=`DuplicateTrustStoreNameException`,Xme=`DescribeTags`,Zme=`Enabled`,Z1=`EnablePrefixForIpv6SourceNat`,Qme=`EnforceSecurityGroupInboundRulesOnPrivateLinkTraffic`,$me=`Format`,ehe=`ForwardActionConfig`,the=`ForwardConfig`,nhe=`FixedResponseActionConfig`,rhe=`FixedResponseConfig`,ihe=`Field`,ahe=`GrpcCode`,ohe=`Host`,she=`HttpCode`,Q1=`HealthCheckEnabled`,$1=`HealthCheckIntervalSeconds`,e0=`HealthCheckProtocol`,t0=`HealthCheckPort`,n0=`HealthCheckPath`,r0=`HealthCheckTimeoutSeconds`,che=`HostHeaderConfig`,lhe=`HostHeaderConditionConfig`,uhe=`HttpHeaderConditionConfig`,dhe=`HttpHeaderConfig`,fhe=`HttpHeaderName`,i0=`HostHeaderRewriteConfig`,phe=`HttpRequestMethodConfig`,mhe=`HttpRequestMethodConditionConfig`,a0=`HealthyThresholdCount`,hhe=`HealthUnavailableException`,o0=`Issuer`,ghe=`IpAddress`,s0=`IpAddressType`,_he=`InvalidCaCertificatesBundleException`,vhe=`IgnoreClientCertificateExpiry`,yhe=`InsufficientCapacityException`,bhe=`InvalidConfigurationRequestException`,c0=`IsDefault`,xhe=`Ipv4IpamPoolId`,She=`InvalidLoadBalancerActionException`,l0=`IpamPools`,u0=`IPv6Address`,Che=`IncompatibleProtocolsException`,whe=`InvalidRevocationContentException`,The=`InvalidSchemeException`,Ehe=`InvalidSubnetException`,Dhe=`InvalidSecurityGroupException`,Ohe=`InvalidTargetException`,khe=`Id`,Ahe=`Include`,jhe=`JwksEndpoint`,Mhe=`JwtValidationActionAdditionalClaim`,Nhe=`JwtValidationActionAdditionalClaims`,Phe=`JwtValidationActionConfig`,Fhe=`JwtValidationConfig`,d0=`Key`,f0=`Listeners`,p0=`ListenerArn`,Ihe=`ListenerArns`,m0=`LoadBalancers`,h0=`LoadBalancerAddresses`,g0=`LoadBalancerArn`,_0=`LoadBalancerArns`,Lhe=`LoadBalancerAddress`,Rhe=`LoadBalancerAttribute`,zhe=`LoadBalancerAttributes`,Bhe=`LoadBalancerName`,Vhe=`LoadBalancerNotFoundException`,Hhe=`LoadBalancerState`,Uhe=`LoadBalancer`,Whe=`ListenerNotFoundException`,Ghe=`Listener`,q=`Message`,v0=`MutualAuthentication`,Khe=`MutualAuthenticationAttributes`,qhe=`MessageBody`,Jhe=`MitigationInEffect`,Yhe=`ModifyListener`,Xhe=`ModifyLoadBalancerAttributes`,Zhe=`ModifyLoadBalancerAttributesInput`,Qhe=`ModifyLoadBalancerAttributesOutput`,$he=`ModifyListenerInput`,ege=`ModifyListenerOutput`,tge=`ModifyRule`,nge=`ModifyRuleInput`,rge=`ModifyRuleOutput`,ige=`ModifyTargetGroupAttributes`,age=`ModifyTargetGroupAttributesInput`,oge=`ModifyTargetGroupAttributesOutput`,y0=`Matcher`,b0=`Marker`,sge=`Mode`,x0=`Name`,S0=`NextMarker`,C0=`Names`,cge=`Order`,lge=`OutpostId`,uge=`OperationNotPermittedException`,w0=`OnUnauthenticatedRequest`,T0=`Priority`,E0=`PrivateIPv4Address`,dge=`PriorityInUseException`,fge=`PathPatternConfig`,pge=`PathPatternConditionConfig`,mge=`PriorRequestNotCompleteException`,D0=`PageSize`,O0=`ProtocolVersion`,hge=`Path`,k0=`Port`,A0=`Protocol`,gge=`Query`,_ge=`QueryStringConfig`,vge=`QueryStringConditionConfig`,yge=`QuicServerId`,bge=`QueryStringKeyValuePair`,xge=`QueryStringKeyValuePairList`,j0=`Reason`,Sge=`ResourceArns`,Cge=`RedirectActionConfig`,wge=`ResourceArn`,M0=`RuleArn`,Tge=`RuleArns`,Ege=`RedirectConfig`,Dge=`RewriteConfigList`,Oge=`RuleConditionList`,kge=`RevocationContentNotFoundException`,Age=`RewriteConfig`,jge=`RuleCondition`,Mge=`RevocationIdNotFoundException`,Nge=`ResourceInUseException`,Pge=`ResourceNotFoundException`,Fge=`RuleNotFoundException`,Ige=`RegisterTargetsInput`,Lge=`RuleTransformList`,Rge=`RegisterTargetsOutput`,zge=`ResetTransforms`,Bge=`RegisterTargets`,Vge=`RuleTransform`,N0=`RegexValues`,Hge=`Result`,Uge=`Regex`,Wge=`Replace`,P0=`Rewrites`,F0=`Rules`,Gge=`Rule`,I0=`State`,L0=`StatusCode`,R0=`SessionCookieName`,z0=`SecurityGroups`,B0=`SubnetId`,Kge=`SourceIpConfig`,qge=`SourceIpConditionConfig`,V0=`SubnetMappings`,Jge=`SubnetMapping`,Yge=`SubnetNotFoundException`,Xge=`SourceNatIpv6Prefixes`,Zge=`SourceNatIpv6Prefix`,H0=`SslPolicy`,Qge=`SSLPolicyNotFoundException`,U0=`SessionTimeout`,W0=`Scope`,G0=`Scheme`,$ge=`Subnets`,K0=`Type`,q0=`TargetControlPort`,J0=`TagDescriptions`,e_e=`TagDescription`,t_e=`TargetDescription`,n_e=`TargetDescriptions`,r_e=`TokenEndpoint`,Y0=`TargetGroups`,X0=`TargetGroupArn`,i_e=`TargetGroupAssociationLimitException`,a_e=`TargetGroupArns`,o_e=`TargetGroupAttribute`,s_e=`TargetGroupAttributes`,c_e=`TargetGroupList`,l_e=`TargetGroupName`,u_e=`TargetGroupNotFoundException`,Z0=`TargetGroupStickinessConfig`,d_e=`TargetGroupTuple`,f_e=`TargetGroup`,Q0=`TargetHealth`,$0=`TargetHealthDescriptions`,p_e=`TargetHealthDescription`,m_e=`TagList`,h_e=`TooManyActionsException`,g_e=`TooManyCertificatesException`,__e=`TooManyLoadBalancersException`,v_e=`TooManyListenersException`,y_e=`TooManyRulesException`,b_e=`TooManyRegistrationsForTargetIdException`,x_e=`TooManyTagsException`,S_e=`TooManyTargetsException`,C_e=`TooManyTargetGroupsException`,w_e=`TooManyTrustStoresException`,T_e=`TooManyTrustStoreRevocationEntriesException`,E_e=`TooManyUniqueTargetGroupsPerLoadBalancerException`,D_e=`TrustStoreArn`,O_e=`TrustStoreAssociationNotFoundException`,k_e=`TrustStoreAssociationStatus`,A_e=`TrustStoreInUseException`,j_e=`TrustStoreNotFoundException`,M_e=`TrustStoreNotReadyException`,e2=`TargetType`,t2=`Tags`,N_e=`Tag`,n2=`Targets`,P_e=`Target`,r2=`Transforms`,F_e=`UseExistingClientSecret`,I_e=`UserInfoEndpoint`,L_e=`UserPoolArn`,R_e=`UserPoolClientId`,z_e=`UserPoolDomain`,B_e=`UnsupportedProtocolException`,i2=`UrlRewriteConfig`,a2=`UnhealthyThresholdCount`,o2=`Values`,s2=`VpcId`,c2=`Value`,V_e=`Weight`,H_e=`ZoneName`,l2=`awsQueryError`,u2=`client`,d2=`error`,f2=`httpError`,p2=`smithy.ts.sdk.synthetic.com.amazonaws.elasticloadbalancingv2`,m2=`server`,J=`com.amazonaws.elasticloadbalancingv2`,h2=dw.for(p2),U_e=[-3,p2,`ElasticLoadBalancingV2ServiceException`,0,[],[]];h2.registerError(U_e,K);var Y=dw.for(J),W_e=[-3,J,Epe,{[l2]:[`AllocationIdNotFound`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(W_e,jfe);var G_e=[-3,J,Dpe,{[l2]:[`ALPNPolicyNotFound`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(G_e,Mfe);var K_e=[-3,J,jpe,{[l2]:[`AvailabilityZoneNotSupported`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(K_e,Nfe);var q_e=[-3,J,Npe,{[l2]:[`CaCertificatesBundleNotFound`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(q_e,Pfe);var J_e=[-3,J,Ppe,{[l2]:[`CapacityDecreaseRequestLimitExceeded`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(J_e,Ffe);var Y_e=[-3,J,Jpe,{[l2]:[`CapacityReservationPending`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Y_e,Ife);var X_e=[-3,J,tme,{[l2]:[`CapacityUnitsLimitExceeded`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(X_e,Lfe);var Z_e=[-3,J,Wpe,{[l2]:[`CertificateNotFound`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Z_e,yfe);var Q_e=[-3,J,ime,{[l2]:[`DeleteAssociationSameAccount`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Q_e,fpe);var $_e=[-3,J,gme,{[l2]:[`DuplicateListener`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError($_e,Rfe);var eve=[-3,J,fme,{[l2]:[`DuplicateLoadBalancerName`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(eve,Zfe);var tve=[-3,J,Kme,{[l2]:[`DuplicateTagKeys`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(tve,Sfe);var nve=[-3,J,Lme,{[l2]:[`DuplicateTargetGroupName`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(nve,cpe);var rve=[-3,J,Yme,{[l2]:[`DuplicateTrustStoreName`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(rve,lpe);var ive=[-3,J,hhe,{[l2]:[`HealthUnavailable`,500],[d2]:m2,[f2]:500},[q],[0]];Y.registerError(ive,gpe);var ave=[-3,J,Che,{[l2]:[`IncompatibleProtocols`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(ave,zfe);var ove=[-3,J,yhe,{[l2]:[`InsufficientCapacity`,500],[d2]:m2,[f2]:500},[q],[0]];Y.registerError(ove,ype);var sve=[-3,J,_he,{[l2]:[`InvalidCaCertificatesBundle`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(sve,upe);var cve=[-3,J,bhe,{[l2]:[`InvalidConfigurationRequest`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(cve,Bfe);var lve=[-3,J,She,{[l2]:[`InvalidLoadBalancerAction`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(lve,Vfe);var uve=[-3,J,whe,{[l2]:[`InvalidRevocationContent`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(uve,Ofe);var dve=[-3,J,The,{[l2]:[`InvalidScheme`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(dve,Qfe);var fve=[-3,J,Dhe,{[l2]:[`InvalidSecurityGroup`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(fve,$fe);var pve=[-3,J,Ehe,{[l2]:[`InvalidSubnet`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(pve,epe);var mve=[-3,J,Ohe,{[l2]:[`InvalidTarget`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(mve,hpe);var hve=[-3,J,Whe,{[l2]:[`ListenerNotFound`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(hve,bfe);var gve=[-3,J,Vhe,{[l2]:[`LoadBalancerNotFound`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(gve,Cfe);var _ve=[-3,J,uge,{[l2]:[`OperationNotPermitted`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(_ve,tpe);var vve=[-3,J,dge,{[l2]:[`PriorityInUse`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(vve,ape);var yve=[-3,J,mge,{[l2]:[`PriorRequestNotComplete`,429],[d2]:u2,[f2]:429},[q],[0]];Y.registerError(yve,bpe);var bve=[-3,J,Nge,{[l2]:[`ResourceInUse`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(bve,npe);var xve=[-3,J,Pge,{[l2]:[`ResourceNotFound`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(xve,vpe);var Sve=[-3,J,kge,{[l2]:[`RevocationContentNotFound`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Sve,kfe);var Cve=[-3,J,Mge,{[l2]:[`RevocationIdNotFound`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Cve,_pe);var wve=[-3,J,Fge,{[l2]:[`RuleNotFound`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(wve,wfe);var Tve=[-3,J,Qge,{[l2]:[`SSLPolicyNotFound`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Tve,Hfe);var Eve=[-3,J,Yge,{[l2]:[`SubnetNotFound`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Eve,rpe);var Dve=[-3,J,i_e,{[l2]:[`TargetGroupAssociationLimit`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Dve,Ufe);var Ove=[-3,J,u_e,{[l2]:[`TargetGroupNotFound`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Ove,Tfe);var kve=[-3,J,h_e,{[l2]:[`TooManyActions`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(kve,Wfe);var Ave=[-3,J,g_e,{[l2]:[`TooManyCertificates`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Ave,xfe);var jve=[-3,J,v_e,{[l2]:[`TooManyListeners`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(jve,Gfe);var Mve=[-3,J,__e,{[l2]:[`TooManyLoadBalancers`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Mve,ipe);var Nve=[-3,J,b_e,{[l2]:[`TooManyRegistrationsForTargetId`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Nve,Kfe);var Pve=[-3,J,y_e,{[l2]:[`TooManyRules`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Pve,ope);var Fve=[-3,J,x_e,{[l2]:[`TooManyTags`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Fve,Efe);var Ive=[-3,J,C_e,{[l2]:[`TooManyTargetGroups`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Ive,spe);var Lve=[-3,J,S_e,{[l2]:[`TooManyTargets`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Lve,qfe);var Rve=[-3,J,T_e,{[l2]:[`TooManyTrustStoreRevocationEntries`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Rve,Afe);var zve=[-3,J,w_e,{[l2]:[`TooManyTrustStores`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(zve,dpe);var Bve=[-3,J,E_e,{[l2]:[`TooManyUniqueTargetGroupsPerLoadBalancer`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Bve,Jfe);var Vve=[-3,J,O_e,{[l2]:[`AssociationNotFound`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Vve,ppe);var Hve=[-3,J,A_e,{[l2]:[`TrustStoreInUse`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Hve,mpe);var Uve=[-3,J,j_e,{[l2]:[`TrustStoreNotFound`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Uve,Dfe);var Wve=[-3,J,M_e,{[l2]:[`TrustStoreNotReady`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Wve,Yfe);var Gve=[-3,J,B_e,{[l2]:[`UnsupportedProtocol`,400],[d2]:u2,[f2]:400},[q],[0]];Y.registerError(Gve,Xfe);var Kve=[h2,Y],qve=[3,J,xpe,0,[K0,X0,kpe,wpe,cge,Ege,rhe,the,Fhe],[0,0,()=>Zve,()=>Xve,1,()=>ibe,()=>Pye,()=>Fye,()=>Vye],1],Jve=[3,J,z1,0,[I0,j0,Y1],[0,0,0]],Yve=[3,J,L1,0,[Hge,Jhe],[0,0]],Xve=[3,J,Cpe,0,[L_e,R_e,z_e,R0,W0,U0,V1,w0],[0,0,0,0,0,1,128,0],3],Zve=[3,J,Ope,0,[o0,Tpe,r_e,I_e,Ipe,Ype,R0,W0,U0,V1,w0,F_e],[0,0,0,0,0,0,0,0,1,128,0,2],5],Qve=[3,J,H1,0,[H_e,B0,lge,h0,Xge],[0,0,0,()=>wbe,64]],$ve=[3,J,nme,0,[Mpe,c0],[0,2]],eye=[3,J,Vpe,0,[g0,X1,A0,k0,H0,K1,B1,t2,v0],[0,()=>b2,0,1,0,()=>x2,64,()=>k2,()=>v2],2],tye=[3,J,Hpe,0,[f0],[()=>S2]],nye=[3,J,zpe,0,[x0,$ge,V0,z0,G0,t2,K0,s0,q1,Z1,l0],[0,64,()=>Ebe,64,0,()=>k2,0,0,0,0,()=>g2],1],rye=[3,J,Bpe,0,[m0],[()=>w2]],iye=[3,J,Kpe,0,[p0,J1,T0,W1,t2,r2],[0,()=>E2,1,()=>b2,()=>k2,()=>O2],4],aye=[3,J,qpe,0,[F0],[()=>D2]],oye=[3,J,Qpe,0,[x0,A0,O0,k0,s2,e0,t0,Q1,n0,$1,r0,a0,a2,y0,e2,t2,s0,q0],[0,0,0,1,0,0,0,2,0,1,1,1,1,()=>_2,0,()=>k2,0,1],1],sye=[3,J,$pe,0,[Y0],[()=>M2]],cye=[3,J,_me,0,[p0],[0],1],lye=[3,J,yme,0,[],[]],uye=[3,J,ume,0,[g0],[0],1],dye=[3,J,pme,0,[],[]],fye=[3,J,wme,0,[M0],[0],1],pye=[3,J,Eme,0,[],[]],mye=[3,J,Fme,0,[X0],[0],1],hye=[3,J,Rme,0,[],[]],gye=[3,J,Wme,0,[X0,n2],[0,()=>A2],2],_ye=[3,J,qme,0,[],[]],vye=[3,J,vme,0,[g0,Ihe,b0,D0],[0,64,0,1]],yye=[3,J,bme,0,[f0,S0],[()=>S2,0]],bye=[3,J,cme,0,[g0],[0],1],xye=[3,J,lme,0,[G1],[()=>C2]],Sye=[3,J,dme,0,[_0,C0,b0,D0],[64,64,0,1]],Cye=[3,J,mme,0,[m0,S0],[()=>w2,0]],wye=[3,J,Tme,0,[p0,Tge,b0,D0],[0,64,0,1]],Tye=[3,J,Dme,0,[F0,S0],[()=>D2,0]],Eye=[3,J,Gme,0,[Sge],[64],1],Dye=[3,J,Jme,0,[J0],[()=>Dbe]],Oye=[3,J,Nme,0,[X0],[0],1],kye=[3,J,Pme,0,[G1],[()=>j2]],Aye=[3,J,Ime,0,[g0,a_e,C0,b0,D0],[0,64,64,0,1]],jye=[3,J,zme,0,[Y0,S0],[()=>M2,0]],Mye=[3,J,Hme,0,[X0,n2,Ahe],[0,()=>A2,64],1],Nye=[3,J,Ume,0,[$0],[()=>kbe]],Pye=[3,J,nhe,0,[L0,qhe,Xpe],[0,0,0],1],Fye=[3,J,ehe,0,[Y0,Z0],[()=>Obe,()=>_be]],Iye=[3,J,lhe,0,[o2,N0],[64,64]],Lye=[3,J,i0,0,[P0],[()=>T2]],Rye=[3,J,uhe,0,[fhe,o2,N0],[0,64,64]],zye=[3,J,mhe,0,[o2],[64]],g2=[3,J,l0,0,[xhe],[0]],Bye=[3,J,Mhe,0,[$me,x0,o2],[0,0,64],3],Vye=[3,J,Phe,0,[jhe,o0,Spe],[0,0,()=>Cbe],2],Hye=[3,J,Ghe,0,[p0,g0,k0,A0,K1,H0,X1,B1,v0],[0,0,1,0,()=>x2,0,()=>b2,64,()=>v2]],Uye=[3,J,Uhe,0,[g0,Sme,Fpe,eme,Bhe,G0,s2,I0,K0,U1,z0,s0,q1,Qme,Z1,l0],[0,0,0,4,0,0,0,()=>Kye,0,()=>Sbe,64,0,0,0,0,()=>g2]],Wye=[3,J,Lhe,0,[ghe,R1,E0,u0],[0,0,0,0]],Gye=[3,J,Rhe,0,[d0,c2],[0,0]],Kye=[3,J,Hhe,0,[rme,j0],[0,0]],_2=[3,J,y0,0,[she,ahe],[0,0]],qye=[3,J,$he,0,[p0,k0,A0,H0,K1,X1,B1,v0],[0,1,0,0,()=>x2,()=>b2,64,()=>v2],1],Jye=[3,J,ege,0,[f0],[()=>S2]],Yye=[3,J,Zhe,0,[g0,G1],[0,()=>C2],2],Xye=[3,J,Qhe,0,[G1],[()=>C2]],Zye=[3,J,nge,0,[M0,J1,W1,r2,zge],[0,()=>E2,()=>b2,()=>O2,2],1],Qye=[3,J,rge,0,[F0],[()=>D2]],$ye=[3,J,age,0,[X0,G1],[0,()=>j2],2],ebe=[3,J,oge,0,[G1],[()=>j2]],v2=[3,J,Khe,0,[sge,D_e,vhe,k_e,Ape],[0,0,2,0,0]],tbe=[3,J,pge,0,[o2,N0],[64,64]],nbe=[3,J,vge,0,[o2],[()=>Tbe]],rbe=[3,J,bge,0,[d0,c2],[0,0]],ibe=[3,J,Cge,0,[L0,A0,k0,ohe,hge,gge],[0,0,0,0,0,0],1],abe=[3,J,Ige,0,[X0,n2],[0,()=>A2],2],obe=[3,J,Rge,0,[],[]],sbe=[3,J,Age,0,[Uge,Wge],[0,0],2],cbe=[3,J,Gge,0,[M0,T0,J1,W1,c0,r2],[0,0,()=>E2,()=>b2,2,()=>O2]],lbe=[3,J,jge,0,[ihe,o2,che,fge,dhe,_ge,phe,Kge,N0],[0,64,()=>Iye,()=>tbe,()=>Rye,()=>nbe,()=>zye,()=>dbe,64]],ube=[3,J,Vge,0,[K0,i0,i2],[0,()=>Lye,()=>xbe],1],dbe=[3,J,qge,0,[o2],[64]],fbe=[3,J,Jge,0,[B0,R1,E0,u0,Zge],[0,0,0,0,0]],pbe=[3,J,N_e,0,[d0,c2],[0,0],1],mbe=[3,J,e_e,0,[wge,t2],[0,()=>k2]],y2=[3,J,t_e,0,[khe,k0,H1,yge],[0,1,0,0],1],hbe=[3,J,f_e,0,[X0,l_e,A0,k0,s2,e0,t0,Q1,$1,r0,a0,a2,n0,y0,_0,e2,O0,s0,q0],[0,0,0,1,0,0,0,2,1,1,1,1,0,()=>_2,64,0,0,0,1]],gbe=[3,J,o_e,0,[d0,c2],[0,0]],_be=[3,J,Z0,0,[Zme,kme],[2,1]],vbe=[3,J,d_e,0,[X0,V_e],[0,1]],ybe=[3,J,Q0,0,[I0,j0,Y1],[0,0,0]],bbe=[3,J,p_e,0,[P_e,t0,Q0,L1,z1],[()=>y2,0,()=>ybe,()=>Yve,()=>Jve]],xbe=[3,J,i2,0,[P0],[()=>T2]],b2=[1,J,W1,0,()=>qve],Sbe=[1,J,U1,0,()=>Qve],x2=[1,J,Lpe,0,()=>$ve],Cbe=[1,J,Nhe,0,()=>Bye],S2=[1,J,f0,0,()=>Hye],wbe=[1,J,h0,0,()=>Wye],C2=[1,J,zhe,0,()=>Gye],w2=[1,J,m0,0,()=>Uye],Tbe=[1,J,xge,0,()=>rbe],T2=[1,J,Dge,0,()=>sbe],E2=[1,J,Oge,0,()=>lbe],D2=[1,J,F0,0,()=>cbe],O2=[1,J,Lge,0,()=>ube],Ebe=[1,J,V0,0,()=>fbe],Dbe=[1,J,J0,0,()=>mbe],k2=[1,J,m_e,0,()=>pbe],A2=[1,J,n_e,0,()=>y2],j2=[1,J,s_e,0,()=>gbe],Obe=[1,J,c_e,0,()=>vbe],M2=[1,J,Y0,0,()=>hbe],kbe=[1,J,$0,0,()=>bbe],Abe=[9,J,Upe,0,()=>eye,()=>tye],jbe=[9,J,Rpe,0,()=>nye,()=>rye],Mbe=[9,J,Gpe,0,()=>iye,()=>aye],Nbe=[9,J,Zpe,0,()=>oye,()=>sye],Pbe=[9,J,ame,0,()=>cye,()=>lye],Fbe=[9,J,ome,0,()=>uye,()=>dye],Ibe=[9,J,Cme,0,()=>fye,()=>pye],Lbe=[9,J,jme,0,()=>mye,()=>hye],Rbe=[9,J,Ame,0,()=>gye,()=>_ye],zbe=[9,J,xme,0,()=>vye,()=>yye],Bbe=[9,J,sme,0,()=>bye,()=>xye],Vbe=[9,J,hme,0,()=>Sye,()=>Cye],Hbe=[9,J,Ome,0,()=>wye,()=>Tye],Ube=[9,J,Xme,0,()=>Eye,()=>Dye],Wbe=[9,J,Mme,0,()=>Oye,()=>kye],Gbe=[9,J,Bme,0,()=>Aye,()=>jye],Kbe=[9,J,Vme,0,()=>Mye,()=>Nye],qbe=[9,J,Yhe,0,()=>qye,()=>Jye],Jbe=[9,J,Xhe,0,()=>Yye,()=>Xye],Ybe=[9,J,tge,0,()=>Zye,()=>Qye],Xbe=[9,J,ige,0,()=>$ye,()=>ebe],Zbe=[9,J,Bge,0,()=>abe,()=>obe],Qbe=e=>({apiVersion:`2015-12-01`,base64Decoder:e?.base64Decoder??TC,base64Encoder:e?.base64Encoder??EC,disableHostPrefix:e?.disableHostPrefix??!1,endpointProvider:e?.endpointProvider??vfe,extensions:e?.extensions??[],httpAuthSchemeProvider:e?.httpAuthSchemeProvider??ufe,httpAuthSchemes:e?.httpAuthSchemes??[{schemeId:`aws.auth#sigv4`,identityProvider:e=>e.getIdentityProvider(`aws.auth#sigv4`),signer:new BD}],logger:e?.logger??new MD,protocol:e?.protocol??tO,protocolSettings:e?.protocolSettings??{defaultNamespace:`com.amazonaws.elasticloadbalancingv2`,errorTypeRegistries:Kve,xmlNamespace:`http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/`,version:`2015-12-01`,serviceTarget:`ElasticLoadBalancing_v10`},serviceId:e?.serviceId??`Elastic Load Balancing v2`,urlParser:e?.urlParser??XC,utf8Decoder:e?.utf8Decoder??Zx,utf8Encoder:e?.utf8Encoder??$x}),$be=e=>{let t=JD(e),n=()=>t().then(DD),r=Qbe(e);return{...r,...e,runtime:`browser`,defaultsMode:t,bodyLengthChecker:e?.bodyLengthChecker??qD,credentialDefaultProvider:e?.credentialDefaultProvider??(e=>()=>Promise.reject(Error(`Credential is missing`))),defaultUserAgentProvider:e?.defaultUserAgentProvider??UD({serviceId:r.serviceId,clientVersion:pfe.version}),maxAttempts:e?.maxAttempts??3,region:e?.region??GD(`Region is missing`),requestHandler:PC.create(e?.requestHandler??n),retryMode:e?.retryMode??(async()=>(await n()).retryMode||TE),sha256:e?.sha256??Rx,streamCollector:e?.streamCollector??IC,useDualstackEndpoint:e?.useDualstackEndpoint??(()=>Promise.resolve(!1)),useFipsEndpoint:e?.useFipsEndpoint??(()=>Promise.resolve(!1))}},exe=e=>{let t=e.httpAuthSchemes,n=e.httpAuthSchemeProvider,r=e.credentials;return{setHttpAuthScheme(e){let n=t.findIndex(t=>t.schemeId===e.schemeId);n===-1?t.push(e):t.splice(n,1,e)},httpAuthSchemes(){return t},setHttpAuthSchemeProvider(e){n=e},httpAuthSchemeProvider(){return n},setCredentials(e){r=e},credentials(){return r}}},txe=e=>({httpAuthSchemes:e.httpAuthSchemes(),httpAuthSchemeProvider:e.httpAuthSchemeProvider(),credentials:e.credentials()}),nxe=(e,t)=>{let n=Object.assign(f1(e),kD(e),zx(e),exe(e));return t.forEach(e=>e.configure(n)),Object.assign(e,p1(n),AD(n),Bx(n),txe(n))},rxe=class extends xD{config;constructor(...[e]){let t=$be(e||{});super(t),this.initConfig=t;let n=nxe(dfe(mD(tC(oD(hD(NT(ffe(t))))))),e?.extensions||[]);this.config=n,this.middlewareStack.use(tw(this.config)),this.middlewareStack.use(rD(this.config)),this.middlewareStack.use(PD(this.config)),this.middlewareStack.use(cD(this.config)),this.middlewareStack.use(iC(this.config)),this.middlewareStack.use(sC(this.config)),this.middlewareStack.use(uC(this.config)),this.middlewareStack.use(hC(this.config,{httpAuthSchemeParametersProvider:cfe,identityProviderConfigProvider:async e=>new OT({"aws.auth#sigv4":e.credentials})})),this.middlewareStack.use(bC(this.config))}destroy(){super.destroy()}},ixe=class extends wD.classBuilder().ep(C1).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeListeners`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeListenersCommand`).sc(zbe).build(){},axe=class extends wD.classBuilder().ep(C1).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeLoadBalancerAttributes`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeLoadBalancerAttributesCommand`).sc(Bbe).build(){},N2=class extends wD.classBuilder().ep(C1).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeLoadBalancers`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeLoadBalancersCommand`).sc(Vbe).build(){},oxe=class extends wD.classBuilder().ep(C1).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeRules`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeRulesCommand`).sc(Hbe).build(){},sxe=class extends wD.classBuilder().ep(C1).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeTags`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeTagsCommand`).sc(Ube).build(){},cxe=class extends wD.classBuilder().ep(C1).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeTargetGroupAttributes`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeTargetGroupAttributesCommand`).sc(Wbe).build(){},P2=class extends wD.classBuilder().ep(C1).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeTargetGroups`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeTargetGroupsCommand`).sc(Gbe).build(){},lxe=class extends wD.classBuilder().ep(C1).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeTargetHealth`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeTargetHealthCommand`).sc(Kbe).build(){},uxe=async(e,t,n)=>({operation:FS(t).operation,region:await IS(e.region)()||(()=>{throw Error("expected `region` to be configured for `aws.auth#sigv4`")})()});function dxe(e){return{schemeId:`aws.auth#sigv4`,signingProperties:{name:`iam`,region:e.region},propertiesExtractor:(e,t)=>({signingProperties:{config:e,context:t}})}}var fxe=e=>{let t=[];switch(e.operation){default:t.push(dxe(e))}return t},pxe=e=>{let t=VD(e);return Object.assign(t,{authSchemePreference:IS(e.authSchemePreference??[])})},mxe=e=>Object.assign(e,{useDualstackEndpoint:e.useDualstackEndpoint??!1,useFipsEndpoint:e.useFipsEndpoint??!1,defaultSigningName:`iam`}),F2={UseFIPS:{type:`builtInParams`,name:`useFipsEndpoint`},Endpoint:{type:`builtInParams`,name:`endpoint`},Region:{type:`builtInParams`,name:`region`},UseDualStack:{type:`builtInParams`,name:`useDualstackEndpoint`}},hxe={name:`@aws-sdk/client-iam`,description:`AWS SDK for JavaScript Iam Client for Node.js, Browser and React Native`,version:`3.1045.0`,scripts:{build:`concurrently 'yarn:build:types' 'yarn:build:es' && yarn build:cjs`,"build:cjs":`node ../../scripts/compilation/inline client-iam`,"build:es":`tsc -p tsconfig.es.json`,"build:include:deps":`yarn g:turbo run build -F="$npm_package_name"`,"build:types":`tsc -p tsconfig.types.json`,"build:types:downlevel":`downlevel-dts dist-types dist-types/ts3.4`,clean:`premove dist-cjs dist-es dist-types tsconfig.cjs.tsbuildinfo tsconfig.es.tsbuildinfo tsconfig.types.tsbuildinfo`,"extract:docs":`api-extractor run --local`,"generate:client":`node ../../scripts/generate-clients/single-service --solo iam`,test:`yarn g:vitest run --passWithNoTests`,"test:e2e":`yarn g:vitest run -c vitest.config.e2e.mts --mode development`,"test:e2e:watch":`yarn g:vitest watch -c vitest.config.e2e.mts`,"test:index":`tsc --noEmit ./test/index-types.ts && node ./test/index-objects.spec.mjs`,"test:integration":`yarn g:vitest run --passWithNoTests -c vitest.config.integ.mts`,"test:integration:watch":`yarn g:vitest run --passWithNoTests -c vitest.config.integ.mts`,"test:watch":`yarn g:vitest watch --passWithNoTests`},main:`./dist-cjs/index.js`,types:`./dist-types/index.d.ts`,module:`./dist-es/index.js`,sideEffects:!1,dependencies:{"@aws-crypto/sha256-browser":`5.2.0`,"@aws-crypto/sha256-js":`5.2.0`,"@aws-sdk/core":`^3.974.8`,"@aws-sdk/credential-provider-node":`^3.972.39`,"@aws-sdk/middleware-host-header":`^3.972.10`,"@aws-sdk/middleware-logger":`^3.972.10`,"@aws-sdk/middleware-recursion-detection":`^3.972.11`,"@aws-sdk/middleware-user-agent":`^3.972.38`,"@aws-sdk/region-config-resolver":`^3.972.13`,"@aws-sdk/types":`^3.973.8`,"@aws-sdk/util-endpoints":`^3.996.8`,"@aws-sdk/util-user-agent-browser":`^3.972.10`,"@aws-sdk/util-user-agent-node":`^3.973.24`,"@smithy/config-resolver":`^4.4.17`,"@smithy/core":`^3.23.17`,"@smithy/fetch-http-handler":`^5.3.17`,"@smithy/hash-node":`^4.2.14`,"@smithy/invalid-dependency":`^4.2.14`,"@smithy/middleware-content-length":`^4.2.14`,"@smithy/middleware-endpoint":`^4.4.32`,"@smithy/middleware-retry":`^4.5.7`,"@smithy/middleware-serde":`^4.2.20`,"@smithy/middleware-stack":`^4.2.14`,"@smithy/node-config-provider":`^4.3.14`,"@smithy/node-http-handler":`^4.6.1`,"@smithy/protocol-http":`^5.3.14`,"@smithy/smithy-client":`^4.12.13`,"@smithy/types":`^4.14.1`,"@smithy/url-parser":`^4.2.14`,"@smithy/util-base64":`^4.3.2`,"@smithy/util-body-length-browser":`^4.2.2`,"@smithy/util-body-length-node":`^4.2.3`,"@smithy/util-defaults-mode-browser":`^4.3.49`,"@smithy/util-defaults-mode-node":`^4.2.54`,"@smithy/util-endpoints":`^3.4.2`,"@smithy/util-middleware":`^4.2.14`,"@smithy/util-retry":`^4.3.6`,"@smithy/util-utf8":`^4.2.2`,"@smithy/util-waiter":`^4.3.0`,tslib:`^2.6.2`},devDependencies:{"@smithy/snapshot-testing":`^2.0.8`,"@tsconfig/node20":`20.1.8`,"@types/node":`^20.14.8`,concurrently:`7.0.0`,"downlevel-dts":`0.10.1`,premove:`4.0.0`,typescript:`~5.8.3`,vitest:`^4.0.17`},engines:{node:`>=20.0.0`},typesVersions:{"<4.5":{"dist-types/*":[`dist-types/ts3.4/*`]}},files:[`dist-*/**`],author:{name:`AWS SDK for JavaScript Team`,url:`https://aws.amazon.com/javascript/`},license:`Apache-2.0`,browser:{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.browser`},"react-native":{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.native`},homepage:`https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-iam`,repository:{type:`git`,url:`https://github.com/aws/aws-sdk-js-v3.git`,directory:`clients/client-iam`}},I2=`ref`,L2=`authSchemes`,R2=`name`,z2=`signingRegion`,B2=-1,V2=!0,H2=`isSet`,U2=`PartitionResult`,W2=`booleanEquals`,G2=`stringEquals`,K2=`getAttr`,q2=`sigv4`,J2={[I2]:`Endpoint`},Y2={fn:K2,argv:[{[I2]:U2},`name`]},X2={[I2]:U2},Z2={[L2]:[{[R2]:q2,[z2]:`us-east-1`}]},Q2={[L2]:[{[R2]:q2,[z2]:`cn-north-1`}]},$2={[L2]:[{[R2]:q2,[z2]:`us-gov-west-1`}]},e4={[L2]:[{[R2]:q2,[z2]:`us-iso-east-1`}]},t4={[L2]:[{[R2]:q2,[z2]:`us-isob-east-1`}]},n4={[L2]:[{[R2]:q2,[z2]:`{PartitionResult#implicitGlobalRegion}`}]},r4=[{[I2]:`Region`}],i4={conditions:[[H2,[J2]],[H2,r4],[`aws.partition`,r4,U2],[W2,[{[I2]:`UseFIPS`},V2]],[W2,[{[I2]:`UseDualStack`},V2]],[G2,[Y2,`aws`]],[G2,[Y2,`aws-cn`]],[G2,[Y2,`aws-us-gov`]],[W2,[{fn:K2,argv:[X2,`supportsDualStack`]},V2]],[G2,[Y2,`aws-iso`]],[G2,[Y2,`aws-iso-b`]],[W2,[{fn:K2,argv:[X2,`supportsFIPS`]},V2]],[G2,[Y2,`aws-iso-e`]],[G2,[Y2,`aws-iso-f`]],[G2,[Y2,`aws-eusc`]]],results:[[B2],[B2,`Invalid Configuration: FIPS and custom endpoint are not supported`],[B2,`Invalid Configuration: Dualstack and custom endpoint are not supported`],[J2,{}],[`https://iam.global.api.aws`,Z2],[`https://iam-fips.global.api.aws`,Z2],[`https://iam.global.api.amazonwebservices.com.cn`,Q2],[`https://iam.cn-north-1.amazonaws.com.cn`,Q2],[`https://iam.us-gov.api.aws`,$2],[`https://iam.us-gov.amazonaws.com`,$2],[`https://iam.us-iso-east-1.c2s.ic.gov`,e4],[`https://iam-fips.us-iso-east-1.c2s.ic.gov`,e4],[`https://iam.us-isob-east-1.sc2s.sgov.gov`,t4],[`https://iam-fips.us-isob-east-1.sc2s.sgov.gov`,t4],[`https://iam.eu-isoe-west-1.cloud.adc-e.uk`,{[L2]:[{[R2]:q2,[z2]:`eu-isoe-west-1`}]}],[`https://iam.us-isof-south-1.csp.hci.ic.gov`,{[L2]:[{[R2]:q2,[z2]:`us-isof-south-1`}]}],[`https://iam.eusc-de-east-1.amazonaws.eu`,{[L2]:[{[R2]:q2,[z2]:`eusc-de-east-1`}]}],[`https://iam-fips.{PartitionResult#dualStackDnsSuffix}`,n4],[B2,`FIPS and DualStack are enabled, but this partition does not support one or both`],[`https://iam-fips.{PartitionResult#dnsSuffix}`,n4],[B2,`FIPS is enabled but this partition does not support FIPS`],[`https://iam.{PartitionResult#dualStackDnsSuffix}`,n4],[B2,`DualStack is enabled but this partition does not support DualStack`],[`https://iam.{PartitionResult#dnsSuffix}`,n4],[B2,`Invalid Configuration: Missing Region`]]},gxe=2,a4=1e8,_xe=new Int32Array([-1,1,-1,0,27,3,1,4,a4+24,2,5,a4+24,3,18,6,4,14,7,6,a4+7,8,7,a4+9,9,9,a4+10,10,10,a4+12,11,12,a4+14,12,13,a4+15,13,14,a4+16,a4+23,5,a4+4,15,6,a4+6,16,7,a4+8,17,8,a4+21,a4+22,4,23,19,7,a4+9,20,9,a4+11,21,10,a4+13,22,11,a4+19,a4+20,5,a4+5,24,7,a4+8,25,8,26,a4+18,11,a4+17,a4+18,3,a4+1,28,4,a4+2,a4+3]),vxe=PT.from(_xe,gxe,i4.conditions,i4.results),yxe=new FT({size:50,params:[`Endpoint`,`Region`,`UseDualStack`,`UseFIPS`]}),bxe=(e,t={})=>yxe.get(e,()=>pE(vxe,{endpointParams:e,logger:t.logger}));zT.aws=SE;var o4=class e extends TD{constructor(t){super(t),Object.setPrototypeOf(this,e.prototype)}},xxe=class e extends o4{name=`ConcurrentModificationException`;$fault=`client`;constructor(t){super({name:`ConcurrentModificationException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Sxe=class e extends o4{name=`NoSuchEntityException`;$fault=`client`;constructor(t){super({name:`NoSuchEntityException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Cxe=class e extends o4{name=`ServiceFailureException`;$fault=`server`;constructor(t){super({name:`ServiceFailureException`,$fault:`server`,...t}),Object.setPrototypeOf(this,e.prototype)}},wxe=class e extends o4{name=`AccountNotManagementOrDelegatedAdministratorException`;$fault=`client`;Message;constructor(t){super({name:`AccountNotManagementOrDelegatedAdministratorException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Txe=class e extends o4{name=`InvalidInputException`;$fault=`client`;constructor(t){super({name:`InvalidInputException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Exe=class e extends o4{name=`LimitExceededException`;$fault=`client`;constructor(t){super({name:`LimitExceededException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Dxe=class e extends o4{name=`EntityAlreadyExistsException`;$fault=`client`;constructor(t){super({name:`EntityAlreadyExistsException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Oxe=class e extends o4{name=`UnmodifiableEntityException`;$fault=`client`;constructor(t){super({name:`UnmodifiableEntityException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},kxe=class e extends o4{name=`PolicyNotAttachableException`;$fault=`client`;constructor(t){super({name:`PolicyNotAttachableException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Axe=class e extends o4{name=`EntityTemporarilyUnmodifiableException`;$fault=`client`;constructor(t){super({name:`EntityTemporarilyUnmodifiableException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},jxe=class e extends o4{name=`InvalidUserTypeException`;$fault=`client`;constructor(t){super({name:`InvalidUserTypeException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Mxe=class e extends o4{name=`PasswordPolicyViolationException`;$fault=`client`;constructor(t){super({name:`PasswordPolicyViolationException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Nxe=class e extends o4{name=`OpenIdIdpCommunicationErrorException`;$fault=`client`;constructor(t){super({name:`OpenIdIdpCommunicationErrorException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Pxe=class e extends o4{name=`MalformedPolicyDocumentException`;$fault=`client`;constructor(t){super({name:`MalformedPolicyDocumentException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Fxe=class e extends o4{name=`ServiceNotSupportedException`;$fault=`client`;constructor(t){super({name:`ServiceNotSupportedException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Ixe=class e extends o4{name=`DeleteConflictException`;$fault=`client`;constructor(t){super({name:`DeleteConflictException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Lxe=class e extends o4{name=`OrganizationNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`OrganizationNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Rxe=class e extends o4{name=`OrganizationNotInAllFeaturesModeException`;$fault=`client`;Message;constructor(t){super({name:`OrganizationNotInAllFeaturesModeException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},zxe=class e extends o4{name=`ServiceAccessNotEnabledException`;$fault=`client`;Message;constructor(t){super({name:`ServiceAccessNotEnabledException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Bxe=class e extends o4{name=`FeatureDisabledException`;$fault=`client`;constructor(t){super({name:`FeatureDisabledException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Vxe=class e extends o4{name=`InvalidAuthenticationCodeException`;$fault=`client`;constructor(t){super({name:`InvalidAuthenticationCodeException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Hxe=class e extends o4{name=`CallerIsNotManagementAccountException`;$fault=`client`;Message;constructor(t){super({name:`CallerIsNotManagementAccountException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Uxe=class e extends o4{name=`FeatureEnabledException`;$fault=`client`;constructor(t){super({name:`FeatureEnabledException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Wxe=class e extends o4{name=`ReportGenerationLimitExceededException`;$fault=`client`;constructor(t){super({name:`ReportGenerationLimitExceededException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Gxe=class e extends o4{name=`CredentialReportExpiredException`;$fault=`client`;constructor(t){super({name:`CredentialReportExpiredException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Kxe=class e extends o4{name=`CredentialReportNotPresentException`;$fault=`client`;constructor(t){super({name:`CredentialReportNotPresentException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},qxe=class e extends o4{name=`CredentialReportNotReadyException`;$fault=`client`;constructor(t){super({name:`CredentialReportNotReadyException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Jxe=class e extends o4{name=`UnrecognizedPublicKeyEncodingException`;$fault=`client`;constructor(t){super({name:`UnrecognizedPublicKeyEncodingException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Yxe=class e extends o4{name=`PolicyEvaluationException`;$fault=`server`;constructor(t){super({name:`PolicyEvaluationException`,$fault:`server`,...t}),Object.setPrototypeOf(this,e.prototype)}},Xxe=class e extends o4{name=`KeyPairMismatchException`;$fault=`client`;constructor(t){super({name:`KeyPairMismatchException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Zxe=class e extends o4{name=`MalformedCertificateException`;$fault=`client`;constructor(t){super({name:`MalformedCertificateException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Qxe=class e extends o4{name=`DuplicateCertificateException`;$fault=`client`;constructor(t){super({name:`DuplicateCertificateException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},$xe=class e extends o4{name=`InvalidCertificateException`;$fault=`client`;constructor(t){super({name:`InvalidCertificateException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},eSe=class e extends o4{name=`DuplicateSSHPublicKeyException`;$fault=`client`;constructor(t){super({name:`DuplicateSSHPublicKeyException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},tSe=class e extends o4{name=`InvalidPublicKeyException`;$fault=`client`;constructor(t){super({name:`InvalidPublicKeyException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},s4=`Arn`,nSe=`AttachmentCount`,c4=`AccessKey`,l4=`AccessKeyId`,u4=`AccessKeyMetadata`,rSe=`AccountNotManagementOrDelegatedAdministratorException`,iSe=`AttachedPolicy`,aSe=`AttachedPermissionsBoundary`,oSe=`AttachedPolicies`,sSe=`AttachUserPolicy`,cSe=`AttachUserPolicyRequest`,lSe=`CreateAccessKey`,uSe=`CreateAccessKeyRequest`,dSe=`CreateAccessKeyResponse`,d4=`CreateDate`,fSe=`CallerIsNotManagementAccountException`,pSe=`ConcurrentModificationException`,mSe=`CreatePolicyRequest`,hSe=`CreatePolicyResponse`,gSe=`CreatePolicy`,_Se=`CredentialReportExpiredException`,vSe=`CredentialReportNotPresentException`,ySe=`CredentialReportNotReadyException`,bSe=`CreateUser`,xSe=`CreateUserRequest`,SSe=`CreateUserResponse`,f4=`Description`,CSe=`DeleteAccessKey`,wSe=`DeleteAccessKeyRequest`,TSe=`DeleteConflictException`,ESe=`DuplicateCertificateException`,DSe=`DeletePolicyRequest`,OSe=`DeletePolicy`,kSe=`DuplicateSSHPublicKeyException`,ASe=`DeleteUser`,jSe=`DetachUserPolicyRequest`,MSe=`DetachUserPolicy`,NSe=`DeleteUserRequest`,PSe=`DefaultVersionId`,FSe=`Document`,ISe=`EntityAlreadyExistsException`,LSe=`EntityTemporarilyUnmodifiableException`,RSe=`FeatureDisabledException`,zSe=`FeatureEnabledException`,BSe=`GetPolicy`,VSe=`GetPolicyRequest`,HSe=`GetPolicyResponse`,USe=`GetPolicyVersion`,WSe=`GetPolicyVersionRequest`,GSe=`GetPolicyVersionResponse`,KSe=`GetUser`,qSe=`GetUserRequest`,JSe=`GetUserResponse`,YSe=`IsAttachable`,XSe=`InvalidAuthenticationCodeException`,ZSe=`InvalidCertificateException`,QSe=`IsDefaultVersion`,$Se=`InvalidInputException`,eCe=`InvalidPublicKeyException`,p4=`IsTruncated`,tCe=`InvalidUserTypeException`,nCe=`Key`,rCe=`KeyPairMismatchException`,iCe=`ListAccessKeys`,aCe=`ListAccessKeysRequest`,oCe=`ListAccessKeysResponse`,sCe=`ListAttachedUserPolicies`,cCe=`ListAttachedUserPoliciesRequest`,lCe=`ListAttachedUserPoliciesResponse`,uCe=`LimitExceededException`,dCe=`ListPoliciesRequest`,fCe=`ListPoliciesResponse`,pCe=`ListPolicies`,mCe=`ListUsers`,hCe=`ListUsersRequest`,gCe=`ListUsersResponse`,m4=`Message`,_Ce=`MalformedCertificateException`,h4=`MaxItems`,vCe=`MalformedPolicyDocumentException`,g4=`Marker`,yCe=`NoSuchEntityException`,bCe=`OnlyAttached`,xCe=`OpenIdIdpCommunicationErrorException`,SCe=`OrganizationNotFoundException`,CCe=`OrganizationNotInAllFeaturesModeException`,_4=`PolicyArn`,v4=`PermissionsBoundary`,wCe=`PermissionsBoundaryArn`,TCe=`PermissionsBoundaryType`,ECe=`PermissionsBoundaryUsageCount`,DCe=`PolicyDocument`,OCe=`PolicyEvaluationException`,kCe=`PolicyId`,ACe=`PasswordLastUsed`,y4=`PolicyName`,jCe=`PolicyNotAttachableException`,MCe=`PasswordPolicyViolationException`,b4=`PathPrefix`,NCe=`PolicyUsageFilter`,x4=`PolicyVersion`,S4=`Path`,C4=`Policy`,PCe=`Policies`,FCe=`ReportGenerationLimitExceededException`,w4=`Status`,ICe=`SecretAccessKey`,LCe=`ServiceAccessNotEnabledException`,RCe=`ServiceFailureException`,zCe=`ServiceNotSupportedException`,BCe=`Scope`,T4=`Tags`,VCe=`Tag`,HCe=`UpdateAccessKey`,UCe=`UpdateAccessKeyRequest`,WCe=`UpdateDate`,GCe=`UnmodifiableEntityException`,KCe=`UserId`,E4=`UserName`,qCe=`UnrecognizedPublicKeyEncodingException`,D4=`User`,JCe=`Users`,O4=`VersionId`,YCe=`Value`,XCe=`accessKeyMetadataListType`,ZCe=`accessKeySecretType`,QCe=`attachedPoliciesListType`,k4=`awsQueryError`,A4=`client`,j4=`error`,M4=`httpError`,N4=`message`,$Ce=`policyListType`,P4=`smithy.ts.sdk.synthetic.com.amazonaws.iam`,F4=`server`,ewe=`tagListType`,twe=`userListType`,X=`com.amazonaws.iam`,I4=dw.for(P4),nwe=[-3,P4,`IAMServiceException`,0,[],[]];I4.registerError(nwe,o4);var L4=dw.for(X),rwe=[-3,X,rSe,{[j4]:A4,[M4]:400},[m4],[0]];L4.registerError(rwe,wxe);var iwe=[-3,X,fSe,{[j4]:A4,[M4]:400},[m4],[0]];L4.registerError(iwe,Hxe);var awe=[-3,X,pSe,{[k4]:[`ConcurrentModification`,409],[j4]:A4,[M4]:409},[N4],[0]];L4.registerError(awe,xxe);var owe=[-3,X,_Se,{[k4]:[`ReportExpired`,410],[j4]:A4,[M4]:410},[N4],[0]];L4.registerError(owe,Gxe);var swe=[-3,X,vSe,{[k4]:[`ReportNotPresent`,410],[j4]:A4,[M4]:410},[N4],[0]];L4.registerError(swe,Kxe);var cwe=[-3,X,ySe,{[k4]:[`ReportInProgress`,404],[j4]:A4,[M4]:404},[N4],[0]];L4.registerError(cwe,qxe);var lwe=[-3,X,TSe,{[k4]:[`DeleteConflict`,409],[j4]:A4,[M4]:409},[N4],[0]];L4.registerError(lwe,Ixe);var uwe=[-3,X,ESe,{[k4]:[`DuplicateCertificate`,409],[j4]:A4,[M4]:409},[N4],[0]];L4.registerError(uwe,Qxe);var dwe=[-3,X,kSe,{[k4]:[`DuplicateSSHPublicKey`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(dwe,eSe);var fwe=[-3,X,ISe,{[k4]:[`EntityAlreadyExists`,409],[j4]:A4,[M4]:409},[N4],[0]];L4.registerError(fwe,Dxe);var pwe=[-3,X,LSe,{[k4]:[`EntityTemporarilyUnmodifiable`,409],[j4]:A4,[M4]:409},[N4],[0]];L4.registerError(pwe,Axe);var mwe=[-3,X,RSe,{[k4]:[`FeatureDisabled`,404],[j4]:A4,[M4]:404},[N4],[0]];L4.registerError(mwe,Bxe);var hwe=[-3,X,zSe,{[k4]:[`FeatureEnabled`,409],[j4]:A4,[M4]:409},[N4],[0]];L4.registerError(hwe,Uxe);var gwe=[-3,X,XSe,{[k4]:[`InvalidAuthenticationCode`,403],[j4]:A4,[M4]:403},[N4],[0]];L4.registerError(gwe,Vxe);var _we=[-3,X,ZSe,{[k4]:[`InvalidCertificate`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(_we,$xe);var vwe=[-3,X,$Se,{[k4]:[`InvalidInput`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(vwe,Txe);var ywe=[-3,X,eCe,{[k4]:[`InvalidPublicKey`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(ywe,tSe);var bwe=[-3,X,tCe,{[k4]:[`InvalidUserType`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(bwe,jxe);var xwe=[-3,X,rCe,{[k4]:[`KeyPairMismatch`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(xwe,Xxe);var Swe=[-3,X,uCe,{[k4]:[`LimitExceeded`,409],[j4]:A4,[M4]:409},[N4],[0]];L4.registerError(Swe,Exe);var Cwe=[-3,X,_Ce,{[k4]:[`MalformedCertificate`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(Cwe,Zxe);var wwe=[-3,X,vCe,{[k4]:[`MalformedPolicyDocument`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(wwe,Pxe);var Twe=[-3,X,yCe,{[k4]:[`NoSuchEntity`,404],[j4]:A4,[M4]:404},[N4],[0]];L4.registerError(Twe,Sxe);var Ewe=[-3,X,xCe,{[k4]:[`OpenIdIdpCommunicationError`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(Ewe,Nxe);var Dwe=[-3,X,SCe,{[j4]:A4,[M4]:400},[m4],[0]];L4.registerError(Dwe,Lxe);var Owe=[-3,X,CCe,{[j4]:A4,[M4]:400},[m4],[0]];L4.registerError(Owe,Rxe);var kwe=[-3,X,MCe,{[k4]:[`PasswordPolicyViolation`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(kwe,Mxe);var Awe=[-3,X,OCe,{[k4]:[`PolicyEvaluation`,500],[j4]:F4,[M4]:500},[N4],[0]];L4.registerError(Awe,Yxe);var jwe=[-3,X,jCe,{[k4]:[`PolicyNotAttachable`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(jwe,kxe);var Mwe=[-3,X,FCe,{[k4]:[`ReportGenerationLimitExceeded`,409],[j4]:A4,[M4]:409},[N4],[0]];L4.registerError(Mwe,Wxe);var Nwe=[-3,X,LCe,{[j4]:A4,[M4]:400},[m4],[0]];L4.registerError(Nwe,zxe);var Pwe=[-3,X,RCe,{[k4]:[`ServiceFailure`,500],[j4]:F4,[M4]:500},[N4],[0]];L4.registerError(Pwe,Cxe);var Fwe=[-3,X,zCe,{[k4]:[`NotSupportedService`,404],[j4]:A4,[M4]:404},[N4],[0]];L4.registerError(Fwe,Fxe);var Iwe=[-3,X,GCe,{[k4]:[`UnmodifiableEntity`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(Iwe,Oxe);var Lwe=[-3,X,qCe,{[k4]:[`UnrecognizedPublicKeyEncoding`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(Lwe,Jxe);var Rwe=[I4,L4],zwe=[0,X,ZCe,8,0],Bwe=[3,X,c4,0,[E4,l4,w4,ICe,d4],[0,0,0,[()=>zwe,0],4],4],Vwe=[3,X,u4,0,[E4,l4,w4,d4],[0,0,0,4]],Hwe=[3,X,aSe,0,[TCe,wCe],[0,0]],Uwe=[3,X,iSe,0,[y4,_4],[0,0]],Wwe=[3,X,cSe,0,[E4,_4],[0,0],2],Gwe=[3,X,uSe,0,[E4],[0]],Kwe=[3,X,dSe,0,[c4],[[()=>Bwe,0]],1],qwe=[3,X,mSe,0,[y4,DCe,S4,f4,T4],[0,0,0,0,()=>V4],2],Jwe=[3,X,hSe,0,[C4],[()=>R4]],Ywe=[3,X,xSe,0,[E4,S4,v4,T4],[0,0,0,()=>V4],1],Xwe=[3,X,SSe,0,[D4],[()=>z4]],Zwe=[3,X,wSe,0,[l4,E4],[0,0],1],Qwe=[3,X,DSe,0,[_4],[0],1],$we=[3,X,NSe,0,[E4],[0],1],eTe=[3,X,jSe,0,[E4,_4],[0,0],2],tTe=[3,X,VSe,0,[_4],[0],1],nTe=[3,X,HSe,0,[C4],[()=>R4]],rTe=[3,X,WSe,0,[_4,O4],[0,0],2],iTe=[3,X,GSe,0,[x4],[()=>hTe]],aTe=[3,X,qSe,0,[E4],[0]],oTe=[3,X,JSe,0,[D4],[()=>z4],1],sTe=[3,X,aCe,0,[E4,g4,h4],[0,0,1]],cTe=[3,X,oCe,0,[u4,p4,g4],[()=>vTe,2,0],1],lTe=[3,X,cCe,0,[E4,b4,g4,h4],[0,0,0,1],1],uTe=[3,X,lCe,0,[oSe,p4,g4],[()=>yTe,2,0]],dTe=[3,X,dCe,0,[BCe,bCe,b4,NCe,g4,h4],[0,2,0,0,0,1]],fTe=[3,X,fCe,0,[PCe,p4,g4],[()=>bTe,2,0]],pTe=[3,X,hCe,0,[b4,g4,h4],[0,0,1]],mTe=[3,X,gCe,0,[JCe,p4,g4],[()=>xTe,2,0],1],R4=[3,X,C4,0,[y4,kCe,s4,S4,PSe,nSe,ECe,YSe,f4,d4,WCe,T4],[0,0,0,0,0,1,1,2,0,4,4,()=>V4]],hTe=[3,X,x4,0,[FSe,O4,QSe,d4],[0,0,2,4]],gTe=[3,X,VCe,0,[nCe,YCe],[0,0],2],_Te=[3,X,UCe,0,[l4,w4,E4],[0,0,0],2],z4=[3,X,D4,0,[S4,E4,KCe,s4,d4,ACe,v4,T4],[0,0,0,0,4,4,()=>Hwe,()=>V4],5],B4=`unit`,vTe=[1,X,XCe,0,()=>Vwe],yTe=[1,X,QCe,0,()=>Uwe],bTe=[1,X,$Ce,0,()=>R4],V4=[1,X,ewe,0,()=>gTe],xTe=[1,X,twe,0,()=>z4],STe=[9,X,sSe,0,()=>Wwe,()=>B4],CTe=[9,X,lSe,0,()=>Gwe,()=>Kwe],wTe=[9,X,gSe,0,()=>qwe,()=>Jwe],TTe=[9,X,bSe,0,()=>Ywe,()=>Xwe],ETe=[9,X,CSe,0,()=>Zwe,()=>B4],DTe=[9,X,OSe,0,()=>Qwe,()=>B4],OTe=[9,X,ASe,0,()=>$we,()=>B4],kTe=[9,X,MSe,0,()=>eTe,()=>B4],ATe=[9,X,BSe,0,()=>tTe,()=>nTe],jTe=[9,X,USe,0,()=>rTe,()=>iTe],MTe=[9,X,KSe,0,()=>aTe,()=>oTe],NTe=[9,X,iCe,0,()=>sTe,()=>cTe],PTe=[9,X,sCe,0,()=>lTe,()=>uTe],FTe=[9,X,pCe,0,()=>dTe,()=>fTe],ITe=[9,X,mCe,0,()=>pTe,()=>mTe],LTe=[9,X,HCe,0,()=>_Te,()=>B4],RTe=e=>({apiVersion:`2010-05-08`,base64Decoder:e?.base64Decoder??TC,base64Encoder:e?.base64Encoder??EC,disableHostPrefix:e?.disableHostPrefix??!1,endpointProvider:e?.endpointProvider??bxe,extensions:e?.extensions??[],httpAuthSchemeProvider:e?.httpAuthSchemeProvider??fxe,httpAuthSchemes:e?.httpAuthSchemes??[{schemeId:`aws.auth#sigv4`,identityProvider:e=>e.getIdentityProvider(`aws.auth#sigv4`),signer:new BD}],logger:e?.logger??new MD,protocol:e?.protocol??tO,protocolSettings:e?.protocolSettings??{defaultNamespace:`com.amazonaws.iam`,errorTypeRegistries:Rwe,xmlNamespace:`https://iam.amazonaws.com/doc/2010-05-08/`,version:`2010-05-08`,serviceTarget:`AWSIdentityManagementV20100508`},serviceId:e?.serviceId??`IAM`,urlParser:e?.urlParser??XC,utf8Decoder:e?.utf8Decoder??Zx,utf8Encoder:e?.utf8Encoder??$x}),zTe=e=>{let t=JD(e),n=()=>t().then(DD),r=RTe(e);return{...r,...e,runtime:`browser`,defaultsMode:t,bodyLengthChecker:e?.bodyLengthChecker??qD,credentialDefaultProvider:e?.credentialDefaultProvider??(e=>()=>Promise.reject(Error(`Credential is missing`))),defaultUserAgentProvider:e?.defaultUserAgentProvider??UD({serviceId:r.serviceId,clientVersion:hxe.version}),maxAttempts:e?.maxAttempts??3,region:e?.region??GD(`Region is missing`),requestHandler:PC.create(e?.requestHandler??n),retryMode:e?.retryMode??(async()=>(await n()).retryMode||TE),sha256:e?.sha256??Rx,streamCollector:e?.streamCollector??IC,useDualstackEndpoint:e?.useDualstackEndpoint??(()=>Promise.resolve(!1)),useFipsEndpoint:e?.useFipsEndpoint??(()=>Promise.resolve(!1))}},BTe=e=>{let t=e.httpAuthSchemes,n=e.httpAuthSchemeProvider,r=e.credentials;return{setHttpAuthScheme(e){let n=t.findIndex(t=>t.schemeId===e.schemeId);n===-1?t.push(e):t.splice(n,1,e)},httpAuthSchemes(){return t},setHttpAuthSchemeProvider(e){n=e},httpAuthSchemeProvider(){return n},setCredentials(e){r=e},credentials(){return r}}},VTe=e=>({httpAuthSchemes:e.httpAuthSchemes(),httpAuthSchemeProvider:e.httpAuthSchemeProvider(),credentials:e.credentials()}),HTe=(e,t)=>{let n=Object.assign(f1(e),kD(e),zx(e),BTe(e));return t.forEach(e=>e.configure(n)),Object.assign(e,p1(n),AD(n),Bx(n),VTe(n))},UTe=class extends xD{config;constructor(...[e]){let t=zTe(e||{});super(t),this.initConfig=t;let n=HTe(pxe(mD(tC(oD(hD(NT(mxe(t))))))),e?.extensions||[]);this.config=n,this.middlewareStack.use(tw(this.config)),this.middlewareStack.use(rD(this.config)),this.middlewareStack.use(PD(this.config)),this.middlewareStack.use(cD(this.config)),this.middlewareStack.use(iC(this.config)),this.middlewareStack.use(sC(this.config)),this.middlewareStack.use(uC(this.config)),this.middlewareStack.use(hC(this.config,{httpAuthSchemeParametersProvider:uxe,identityProviderConfigProvider:async e=>new OT({"aws.auth#sigv4":e.credentials})})),this.middlewareStack.use(bC(this.config))}destroy(){super.destroy()}},WTe=class extends wD.classBuilder().ep(F2).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`GetPolicy`,{}).n(`IAMClient`,`GetPolicyCommand`).sc(ATe).build(){},GTe=class extends wD.classBuilder().ep(F2).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`GetPolicyVersion`,{}).n(`IAMClient`,`GetPolicyVersionCommand`).sc(jTe).build(){},KTe=class extends wD.classBuilder().ep(F2).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`GetUser`,{}).n(`IAMClient`,`GetUserCommand`).sc(MTe).build(){},qTe=class extends wD.classBuilder().ep(F2).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`ListAccessKeys`,{}).n(`IAMClient`,`ListAccessKeysCommand`).sc(NTe).build(){},JTe=class extends wD.classBuilder().ep(F2).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`ListAttachedUserPolicies`,{}).n(`IAMClient`,`ListAttachedUserPoliciesCommand`).sc(PTe).build(){},YTe=class extends wD.classBuilder().ep(F2).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`ListPolicies`,{}).n(`IAMClient`,`ListPoliciesCommand`).sc(FTe).build(){},XTe=class extends wD.classBuilder().ep(F2).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`ListUsers`,{}).n(`IAMClient`,`ListUsersCommand`).sc(ITe).build(){};function ZTe(e){return t=>async n=>{let{request:r}=n;if(e.expectContinueHeader!==!1&&Wx.isInstance(r)&&r.body&&e.runtime===`node`&&e.requestHandler?.constructor?.name!==`FetchHttpHandler`){let t=!0;if(typeof e.expectContinueHeader==`number`)try{t=(Number(r.headers?.[`content-length`])??e.bodyLengthChecker?.(r.body)??1/0)>=e.expectContinueHeader}catch{}else t=!!e.expectContinueHeader;t&&(r.headers.Expect=`100-continue`)}return t({...n,request:r})}}var QTe={step:`build`,tags:[`SET_EXPECT_HEADER`,`EXPECT_HEADER`],name:`addExpectContinueMiddleware`,override:!0},$Te=e=>({applyToStack:t=>{t.add(ZTe(e),QTe)}}),H4={WHEN_SUPPORTED:`WHEN_SUPPORTED`,WHEN_REQUIRED:`WHEN_REQUIRED`},eEe=H4.WHEN_SUPPORTED,tEe={WHEN_SUPPORTED:`WHEN_SUPPORTED`,WHEN_REQUIRED:`WHEN_REQUIRED`},nEe=H4.WHEN_SUPPORTED,U4;(function(e){e.MD5=`MD5`,e.CRC32=`CRC32`,e.CRC32C=`CRC32C`,e.CRC64NVME=`CRC64NVME`,e.SHA1=`SHA1`,e.SHA256=`SHA256`})(U4||={});var rEe;(function(e){e.HEADER=`header`,e.TRAILER=`trailer`})(rEe||={});var iEe=U4.CRC32,aEe=function(){function e(){this.crc32=new W4}return e.prototype.update=function(e){gx(e)||this.crc32.update(hx(e))},e.prototype.digest=function(){return Tx(this,void 0,void 0,function(){return Ex(this,function(e){return[2,_x(this.crc32.digest())]})})},e.prototype.reset=function(){this.crc32=new W4},e}(),W4=function(){function e(){this.checksum=4294967295}return e.prototype.update=function(e){var t,n;try{for(var r=Dx(e),i=r.next();!i.done;i=r.next()){var a=i.value;this.checksum=this.checksum>>>8^oEe[(this.checksum^a)&255]}}catch(e){t={error:e}}finally{try{i&&!i.done&&(n=r.return)&&n.call(r)}finally{if(t)throw t.error}}return this},e.prototype.digest=function(){return(this.checksum^4294967295)>>>0},e}(),oEe=vx([0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,2898065728,853044451,1172266101,3705015759,2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,4111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977,2362670323,4224994405,1303535960,984961486,2747007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,855842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,1591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,1957810842,3939845945,2647816111,81470997,1943803523,3814918930,2489596804,225274430,2053790376,3826175755,2466906013,167816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,2312317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,3518719985,2797360999,1068828381,1219638859,3624741850,2936675148,906185462,1090812512,3747672003,2825379669,829329135,1181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400815,3317316542,2998733608,733239954,1555261956,3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,3943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,2262029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,285281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,1231636301,1047427035,2932959818,3654703836,1088359270,936918e3,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117]),sEe=e=>{let{requestChecksumCalculation:t,responseChecksumValidation:n,requestStreamBufferSize:r}=e;return Object.assign(e,{requestChecksumCalculation:IS(t??eEe),responseChecksumValidation:IS(n??nEe),requestStreamBufferSize:Number(r??0),checksumAlgorithms:e.checksumAlgorithms??{}})},cEe=e=>(t,n)=>async r=>{let i=await e.region(),a=e.region,o=()=>{};n.__s3RegionRedirect&&(Object.defineProperty(e,`region`,{writable:!1,value:async()=>n.__s3RegionRedirect}),o=()=>Object.defineProperty(e,`region`,{writable:!0,value:a}));try{let a=await t(r);if(n.__s3RegionRedirect&&(o(),i!==await e.region()))throw Error(`Region was not restored following S3 region redirect.`);return a}catch(e){throw o(),e}},lEe={tags:[`REGION_REDIRECT`,`S3`],name:`regionRedirectEndpointMiddleware`,override:!0,relation:`before`,toMiddleware:`endpointV2Middleware`};function uEe(e){return(t,n)=>async r=>{try{return await t(r)}catch(i){if(e.followRegionRedirects){let a=i?.$metadata?.httpStatusCode,o=n.commandName===`HeadBucketCommand`,s=i?.$response?.headers?.[`x-amz-bucket-region`];if(s&&(a===301||a===400&&(i?.name===`IllegalLocationConstraintException`||o))){try{let t=s;n.logger?.debug(`Redirecting from ${await e.region()} to ${t}`),n.__s3RegionRedirect=t}catch(e){throw Error(`Region redirect failed: `+e)}return t(r)}}throw i}}}var dEe={step:`initialize`,tags:[`REGION_REDIRECT`,`S3`],name:`regionRedirectMiddleware`,override:!0},fEe=e=>({applyToStack:t=>{t.add(uEe(e),dEe),t.addRelativeTo(cEe(e),lEe)}}),pEe=class e{data;lastPurgeTime=Date.now();static EXPIRED_CREDENTIAL_PURGE_INTERVAL_MS=3e4;constructor(e={}){this.data=e}get(e){let t=this.data[e];if(t)return t}set(e,t){return this.data[e]=t,t}delete(e){delete this.data[e]}async purgeExpired(){let t=Date.now();if(!(this.lastPurgeTime+e.EXPIRED_CREDENTIAL_PURGE_INTERVAL_MS>t))for(let e in this.data){let n=this.data[e];if(!n.isRefreshing){let r=await n.identity;r.expiration&&r.expiration.getTime()(t.expiration?.getTime()??0){i.set(r,new G4(Promise.resolve(e)))})),t)):i.set(r,new G4(this.getIdentity(r))).identity}async getIdentity(e){await this.cache.purgeExpired().catch(e=>{console.warn(`Error while clearing expired entries in S3ExpressIdentityCache: -`+e)});let t=await this.createSessionFn(e);if(!t.Credentials?.AccessKeyId||!t.Credentials?.SecretAccessKey)throw Error(`s3#createSession response credential missing AccessKeyId or SecretAccessKey.`);return{accessKeyId:t.Credentials.AccessKeyId,secretAccessKey:t.Credentials.SecretAccessKey,sessionToken:t.Credentials.SessionToken,expiration:t.Credentials.Expiration?new Date(t.Credentials.Expiration):void 0}}},hEe=`sigv4-s3express`,K4=`X-Amz-S3session-Token`,q4=K4.toLowerCase(),gEe=class extends US{async signWithCredentials(e,t,n){let r=J4(t);e.headers[q4]=t.sessionToken;let i=this;return Y4(i,r),i.signRequest(e,n??{})}async presignWithCredentials(e,t,n){let r=J4(t);return delete e.headers[q4],e.headers[K4]=t.sessionToken,e.query=e.query??{},e.query[K4]=t.sessionToken,Y4(this,r),this.presign(e,n)}};function J4(e){return{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey,expiration:e.expiration}}function Y4(e,t){let n=setTimeout(()=>{throw Error(`SignatureV4S3Express credential override was created but not called.`)},10),r=e.credentialProvider;e.credentialProvider=()=>(clearTimeout(n),e.credentialProvider=r,Promise.resolve(t))}var _Ee=e=>(t,n)=>async r=>{if(n.endpointV2){let t=n.endpointV2,i=t.properties?.authSchemes?.[0]?.name===hEe;if((t.properties?.backend===`S3Express`||t.properties?.bucketType===`Directory`)&&(JE(n,`S3_EXPRESS_BUCKET`,`J`),n.isS3ExpressBucket=!0),i){let t=r.input.Bucket;if(t){let i=await e.s3ExpressIdentityProvider.getS3ExpressIdentity(await e.credentials(),{Bucket:t});n.s3ExpressIdentity=i,Wx.isInstance(r.request)&&i.sessionToken&&(r.request.headers[q4]=i.sessionToken)}}}return t(r)},vEe={name:`s3ExpressMiddleware`,step:`build`,tags:[`S3`,`S3_EXPRESS`],override:!0},yEe=e=>({applyToStack:t=>{t.add(_Ee(e),vEe)}}),bEe=async(e,t,n,r)=>{let i=await r.signWithCredentials(n,e,{});if(i.headers[`X-Amz-Security-Token`]||i.headers[`x-amz-security-token`])throw Error(`X-Amz-Security-Token must not be set for s3-express requests.`);return i},xEe=e=>e=>{throw e},SEe=(e,t)=>{},CEe=e=>(t,n)=>async r=>{if(!Wx.isInstance(r.request))return t(r);let i=FS(n).selectedHttpAuthScheme;if(!i)throw Error(`No HttpAuthScheme was selected: unable to sign request`);let{httpAuthOption:{signingProperties:a={}},identity:o,signer:s}=i,c;c=n.s3ExpressIdentity?await bEe(n.s3ExpressIdentity,a,r.request,await e.signer()):await s.sign(r.request,o,a);let l=await t({...r,request:c}).catch((s.errorHandler||xEe)(a));return(s.successHandler||SEe)(l.response,a),l},wEe=e=>({applyToStack:t=>{t.addRelativeTo(CEe(e),yC)}}),TEe=(e,{session:t})=>{let[n,r]=t,{forcePathStyle:i,useAccelerateEndpoint:a,disableMultiregionAccessPoints:o,followRegionRedirects:s,s3ExpressIdentityProvider:c,bucketEndpoint:l,expectContinueHeader:u}=e;return Object.assign(e,{forcePathStyle:i??!1,useAccelerateEndpoint:a??!1,disableMultiregionAccessPoints:o??!1,followRegionRedirects:s??!1,s3ExpressIdentityProvider:c??new mEe(async e=>n().send(new r({Bucket:e}))),bucketEndpoint:l??!1,expectContinueHeader:u??2097152})};function EEe(e){return new ReadableStream({start(t){t.enqueue(e),t.close()}})}var DEe={CopyObjectCommand:!0,UploadPartCopyCommand:!0,CompleteMultipartUploadCommand:!0},OEe=e=>(t,n)=>async r=>{let i=await t(r),{response:a}=i;if(!Kx.isInstance(a))return i;let{statusCode:o,body:s}=a;if(o<200||o>=300)return i;let c=await kEe(s,e);if(a.body=EEe(c),c.length===0&&DEe[n.commandName]){let e=Error(`S3 aborted request`);throw e.$metadata={httpStatusCode:503},e.name=`InternalError`,e}let l=e.utf8Encoder(c.subarray(c.length-16));return l&&l.endsWith(``)&&(a.statusCode=503),i},kEe=(e=new Uint8Array,t)=>e instanceof Uint8Array?Promise.resolve(e):t.streamCollector(e)||Promise.resolve(new Uint8Array),AEe={relation:`after`,toMiddleware:`deserializerMiddleware`,tags:[`THROW_200_EXCEPTIONS`,`S3`],name:`throw200ExceptionsMiddleware`,override:!0},X4=e=>({applyToStack:t=>{t.addRelativeTo(OEe(e),AEe)}}),jEe=e=>typeof e==`string`&&e.indexOf(`arn:`)===0&&e.split(`:`).length>=6;function MEe(e){return(t,n)=>async r=>{if(e.bucketEndpoint){let e=n.endpointV2;if(e){let t=r.input.Bucket;if(typeof t==`string`)try{let r=new URL(t);n.endpointV2={...e,url:r}}catch(e){let r=`@aws-sdk/middleware-sdk-s3: bucketEndpoint=true was set but Bucket=${t} could not be parsed as URL.`;throw n.logger?.constructor?.name===`NoOpLogger`?console.warn(r):n.logger?.warn?.(r),e}}}return t(r)}}var NEe={name:`bucketEndpointMiddleware`,override:!0,relation:`after`,toMiddleware:`endpointV2Middleware`};function PEe({bucketEndpoint:e}){return t=>async n=>{let{input:{Bucket:r}}=n;if(!e&&typeof r==`string`&&!jEe(r)&&r.indexOf(`/`)>=0){let e=Error(`Bucket name shouldn't contain '/', received '${r}'`);throw e.name=`InvalidBucketName`,e}return t({...n})}}var FEe={step:`initialize`,tags:[`VALIDATE_BUCKET_NAME`],name:`validateBucketNameMiddleware`,override:!0},IEe=e=>({applyToStack:t=>{t.add(PEe(e),FEe),t.addRelativeTo(MEe(e),NEe)}}),LEe=class extends wie{async serializeRequest(e,t,n){let r=await super.serializeRequest(e,t,n),i=sw.of(e.input),a=i.getSchema(),o=0,s=a[6]??0;if(t&&typeof t==`object`)for(let[e,n]of i.structIterator()){if(++o>s)break;if(e===`Bucket`){if(!t.Bucket&&n.getMergedTraits().httpLabel)throw Error(`No value provided for input HTTP label: Bucket.`);break}}return r}},REe=e=>Object.assign(e,{eventStreamMarshaller:e.eventStreamSerdeProvider(e)}),Z4={CrtSignerV4:null},Q4=class{sigv4aSigner;sigv4Signer;signerOptions;static sigv4aDependency(){return typeof Z4.CrtSignerV4==`function`?`crt`:typeof WS.SignatureV4a==`function`?`js`:`none`}constructor(e){this.sigv4Signer=new gEe(e),this.signerOptions=e}async sign(e,t={}){return t.signingRegion===`*`?this.getSigv4aSigner().sign(e,t):this.sigv4Signer.sign(e,t)}async signWithCredentials(e,t,n={}){if(n.signingRegion===`*`){let r=this.getSigv4aSigner(),i=Z4.CrtSignerV4;if(i&&r instanceof i)return r.signWithCredentials(e,t,n);throw Error(`signWithCredentials with signingRegion '*' is only supported when using the CRT dependency @aws-sdk/signature-v4-crt. Please check whether you have installed the "@aws-sdk/signature-v4-crt" package explicitly. You must also register the package by calling [require("@aws-sdk/signature-v4-crt");] or an ESM equivalent such as [import "@aws-sdk/signature-v4-crt";]. For more information please go to https://github.com/aws/aws-sdk-js-v3#functionality-requiring-aws-common-runtime-crt`)}return this.sigv4Signer.signWithCredentials(e,t,n)}async presign(e,t={}){if(t.signingRegion===`*`){let n=this.getSigv4aSigner(),r=Z4.CrtSignerV4;if(r&&n instanceof r)return n.presign(e,t);throw Error(`presign with signingRegion '*' is only supported when using the CRT dependency @aws-sdk/signature-v4-crt. Please check whether you have installed the "@aws-sdk/signature-v4-crt" package explicitly. You must also register the package by calling [require("@aws-sdk/signature-v4-crt");] or an ESM equivalent such as [import "@aws-sdk/signature-v4-crt";]. For more information please go to https://github.com/aws/aws-sdk-js-v3#functionality-requiring-aws-common-runtime-crt`)}return this.sigv4Signer.presign(e,t)}async presignWithCredentials(e,t,n={}){if(n.signingRegion===`*`)throw Error(`Method presignWithCredentials is not supported for [signingRegion=*].`);return this.sigv4Signer.presignWithCredentials(e,t,n)}getSigv4aSigner(){if(!this.sigv4aSigner){let e=Z4.CrtSignerV4,t=WS.SignatureV4a;if(this.signerOptions.runtime===`node`){if(!e&&!t)throw Error(`Neither CRT nor JS SigV4a implementation is available. Please load either @aws-sdk/signature-v4-crt or @aws-sdk/signature-v4a. For more information please go to https://github.com/aws/aws-sdk-js-v3#functionality-requiring-aws-common-runtime-crt`);if(e&&typeof e==`function`)this.sigv4aSigner=new e({...this.signerOptions,signingAlgorithm:1});else if(t&&typeof t==`function`)this.sigv4aSigner=new t({...this.signerOptions});else throw Error(`Available SigV4a implementation is not a valid constructor. Please ensure you've properly imported @aws-sdk/signature-v4-crt or @aws-sdk/signature-v4a.For more information please go to https://github.com/aws/aws-sdk-js-v3#functionality-requiring-aws-common-runtime-crt`)}else{if(!t||typeof t!=`function`)throw Error(`JS SigV4a implementation is not available or not a valid constructor. Please check whether you have installed the @aws-sdk/signature-v4a package explicitly. The CRT implementation is not available for browsers. You must also register the package by calling [require('@aws-sdk/signature-v4a');] or an ESM equivalent such as [import '@aws-sdk/signature-v4a';]. For more information please go to https://github.com/aws/aws-sdk-js-v3#using-javascript-non-crt-implementation-of-sigv4a`);this.sigv4aSigner=new t({...this.signerOptions})}}return this.sigv4aSigner}},$4=`ref`,e3=`argv`,t3=`backend`,n3=`authSchemes`,r3=`disableDoubleEncoding`,i3=`signingName`,a3=`signingRegion`,o3=`signingRegionSet`,s3=-1,c3=!0,l3=!1,u3=`isSet`,d3=`booleanEquals`,f3=`stringEquals`,p3=`coalesce`,m3=`substring`,h3=``,g3=`aws.partition`,_3=`partitionResult`,v3=`accessPointSuffix`,y3=`regionPrefix`,b3=e=>`outpostId_ssa_`+e+h3,x3=`hardwareType`,S3=`ite`,C3=`isValidHostLabel`,w3=`sigv4`,T3=`aws.isVirtualHostableS3Bucket`,E3=`url`,D3=`getAttr`,O3=`bucketArn`,k3=`--`,A3=`arnType`,j3=`accesspoint`,M3=e=>`accessPointName_ssa_`+e+h3,N3=`s3-object-lambda`,P3=`s3-outposts`,F3=`bucketPartition`,I3=`us-east-1`,L3=`outpostType`,R3=`name`,z3=`s3`,B3=`{url#scheme}://{Bucket}.{url#authority}{url#path}`,V3=`{url#scheme}://{url#authority}{url#path}`,H3=`{url#scheme}://{url#authority}{url#normalizedPath}{Bucket}`,U3=`https://{Bucket}.s3-accelerate.{partitionResult#dnsSuffix}`,W3=`https://{Bucket}.s3.{partitionResult#dnsSuffix}`,G3=e=>`{url#scheme}://{accessPointName_ssa_`+e+`}-{bucketArn#accountId}.{url#authority}{url#path}`,K3=e=>"Invalid ARN: The access point name may only contain a-z, A-Z, 0-9 and `-`. Found: `{accessPointName_ssa_"+e+"}`",q3=`sigv4a`,J3=`{url#scheme}://{url#authority}{url#normalizedPath}{uri_encoded_bucket}`,Y3=`https://s3.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,X3=`https://s3.{partitionResult#dnsSuffix}`,Z3={[$4]:`UseFIPS`},Q3={[$4]:`UseDualStack`},$3={[$4]:`Bucket`},e6={fn:D3,[e3]:[{[$4]:_3},R3]},t6={[$4]:E3},n6={[$4]:`Region`},r6={[$4]:O3},i6={[$4]:A3},a6={[$4]:`accessPointName_ssa_1`},o6={fn:D3,[e3]:[r6,`region`]},s6={[$4]:x3},c6={fn:D3,[e3]:[r6,`service`]},l6={fn:D3,[e3]:[r6,`accountId`]},u6={[t3]:`S3Express`,[n3]:[{[r3]:!0,[R3]:`{_s3e_auth}`,[i3]:`s3express`,[a3]:`{Region}`}]},d6={[t3]:`S3Express`,[n3]:[{[r3]:!0,[R3]:w3,[i3]:`s3express`,[a3]:`{Region}`}]},f6={[n3]:[{[r3]:!0,[R3]:q3,[i3]:P3,[o3]:[`*`]},{[r3]:!0,[R3]:w3,[i3]:P3,[a3]:`{Region}`}]},p6={[n3]:[{[r3]:!0,[R3]:w3,[i3]:z3,[a3]:I3}]},m6={[n3]:[{[r3]:!0,[R3]:w3,[i3]:z3,[a3]:`{Region}`}]},h6={[n3]:[{[r3]:!0,[R3]:w3,[i3]:N3,[a3]:`{bucketArn#region}`}]},g6={[n3]:[{[r3]:!0,[R3]:w3,[i3]:z3,[a3]:`{bucketArn#region}`}]},_6={[n3]:[{[r3]:!0,[R3]:q3,[i3]:P3,[o3]:[`*`]},{[r3]:!0,[R3]:w3,[i3]:P3,[a3]:`{bucketArn#region}`}]},v6={[n3]:[{[r3]:!0,[R3]:w3,[i3]:N3,[a3]:`{Region}`}]},y6=[n6],b6=[{[$4]:`Endpoint`}],x6=[$3],S6=[$3,0,7,!0],C6=[r6,`resourceId[1]`],zEe=[`*`],w6={conditions:[[u3,y6],[d3,[{[$4]:`Accelerate`},c3]],[d3,[Z3,c3]],[d3,[Q3,c3]],[u3,b6],[u3,x6],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,0,6,c3]},h3]},`--x-s3`]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:S6},h3]},`--xa-s3`]],[g3,y6,_3],[m3,S6,v3],[f3,[{[$4]:v3},`--op-s3`]],[m3,[$3,8,12,c3],y3],[m3,[$3,32,49,c3],b3(2)],[m3,[$3,49,50,c3],x3],[d3,[{[$4]:`ForcePathStyle`},c3]],[f3,[e6,`aws-cn`]],[S3,[Q3,`.dualstack`,h3],`_s3e_ds`],[C3,[{[$4]:b3(2)},l3]],[S3,[Z3,`-fips`,h3],`_s3e_fips`],[S3,[{fn:p3,[e3]:[{[$4]:`DisableS3ExpressSessionAuth`},l3]},w3,`sigv4-s3express`],`_s3e_auth`],[T3,[$3,l3]],[`parseURL`,b6,E3],[d3,[{fn:p3,[e3]:[{[$4]:`UseS3ExpressControlEndpoint`},l3]},c3]],[T3,[$3,c3]],[f3,[{fn:D3,[e3]:[t6,`scheme`]},`http`]],[C3,[n6,l3]],[`aws.parseArn`,x6,O3],[D3,[{fn:`split`,[e3]:[$3,k3,0]},`[-2]`],`s3expressAvailabilityZoneId`],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,0,4,l3]},h3]},`arn:`]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,16,18,c3]},h3]},k3]],[d3,[{fn:D3,[e3]:[t6,`isIp`]},c3]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,21,23,c3]},h3]},k3]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,27,29,c3]},h3]},k3]],[f3,[{[$4]:y3},`beta`]],[`uriEncode`,x6,`uri_encoded_bucket`],[C3,[n6,c3]],[d3,[{fn:p3,[e3]:[{[$4]:`UseObjectLambdaEndpoint`},l3]},c3]],[D3,[r6,`resourceId[0]`],A3],[f3,[i6,h3]],[f3,[i6,j3]],[D3,C6,M3(1)],[f3,[a6,h3]],[f3,[o6,h3]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,14,16,c3]},h3]},k3]],[f3,[s6,`e`]],[f3,[s6,`o`]],[f3,[n6,`aws-global`]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,19,21,c3]},h3]},k3]],[f3,[c6,N3]],[d3,[{fn:p3,[e3]:[{[$4]:`DisableAccessPoints`},l3]},c3]],[f3,[c6,P3]],[g3,[o6],F3],[C3,[a6,c3]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,26,28,c3]},h3]},k3]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,15,17,c3]},h3]},k3]],[D3,[r6,`resourceId[4]`]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,20,22,c3]},h3]},k3]],[d3,[{[$4]:`UseGlobalEndpoint`},c3]],[f3,[n6,I3]],[D3,C6,b3(1)],[d3,[{fn:p3,[e3]:[{[$4]:`UseArnRegion`},c3]},c3]],[C3,[{[$4]:b3(1)},l3]],[D3,[r6,`resourceId[2]`],L3],[f3,[n6,o6]],[f3,[{fn:D3,[e3]:[{[$4]:F3},R3]},e6]],[d3,[{[$4]:`DisableMultiRegionAccessPoints`},c3]],[C3,[o6,c3]],[f3,[{fn:D3,[e3]:[r6,`partition`]},e6]],[f3,[l6,h3]],[f3,[c6,z3]],[C3,[l6,l3]],[D3,[r6,`resourceId[3]`],M3(2)],[C3,[a6,l3]],[f3,[{[$4]:L3},j3]],[C3,[{[$4]:M3(2)},l3]]],results:[[s3],[s3,`Accelerate cannot be used with FIPS`],[s3,`Cannot set dual-stack in combination with a custom endpoint.`],[s3,`A custom endpoint cannot be combined with FIPS`],[s3,`A custom endpoint cannot be combined with S3 Accelerate`],[s3,`Partition does not support FIPS`],[s3,`S3Express does not support S3 Accelerate.`],[`{url#scheme}://{url#authority}/{uri_encoded_bucket}{url#path}`,u6],[B3,u6],[s3,`S3Express bucket name is not a valid virtual hostable name.`],[`https://s3express-control{_s3e_fips}{_s3e_ds}.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,d6],[`https://{Bucket}.s3express{_s3e_fips}-{s3expressAvailabilityZoneId}{_s3e_ds}.{Region}.{partitionResult#dnsSuffix}`,u6],[s3,`Unrecognized S3Express bucket name format.`],[V3,u6],[`https://s3express-control{_s3e_fips}{_s3e_ds}.{Region}.{partitionResult#dnsSuffix}`,d6],[s3,`Expected a endpoint to be specified but no endpoint was found`],[`https://{Bucket}.ec2.{url#authority}`,f6],[`https://{Bucket}.ec2.s3-outposts.{Region}.{partitionResult#dnsSuffix}`,f6],[`https://{Bucket}.op-{outpostId_ssa_2}.{url#authority}`,f6],[`https://{Bucket}.op-{outpostId_ssa_2}.s3-outposts.{Region}.{partitionResult#dnsSuffix}`,f6],[s3,`Unrecognized hardware type: "Expected hardware type o or e but got {hardwareType}"`],[s3,`Invalid Outposts Bucket alias - it must be a valid bucket name.`],[s3,"Invalid ARN: The outpost Id must only contain a-z, A-Z, 0-9 and `-`."],[s3,"Custom endpoint `{Endpoint}` was not a valid URI"],[s3,`S3 Accelerate cannot be used in this region`],[`https://{Bucket}.s3-fips.dualstack.us-east-1.{partitionResult#dnsSuffix}`,p6],[`https://{Bucket}.s3-fips.dualstack.{Region}.{partitionResult#dnsSuffix}`,m6],[`https://{Bucket}.s3-fips.us-east-1.{partitionResult#dnsSuffix}`,p6],[`https://{Bucket}.s3-fips.{Region}.{partitionResult#dnsSuffix}`,m6],[`https://{Bucket}.s3-accelerate.dualstack.us-east-1.{partitionResult#dnsSuffix}`,p6],[`https://{Bucket}.s3-accelerate.dualstack.{partitionResult#dnsSuffix}`,m6],[`https://{Bucket}.s3.dualstack.us-east-1.{partitionResult#dnsSuffix}`,p6],[`https://{Bucket}.s3.dualstack.{Region}.{partitionResult#dnsSuffix}`,m6],[H3,p6],[B3,p6],[H3,m6],[B3,m6],[U3,p6],[U3,m6],[W3,p6],[W3,m6],[`https://{Bucket}.s3.{Region}.{partitionResult#dnsSuffix}`,m6],[s3,`Invalid region: region was not a valid DNS name.`],[s3,`S3 Object Lambda does not support Dual-stack`],[s3,`S3 Object Lambda does not support S3 Accelerate`],[s3,`Access points are not supported for this operation`],[s3,"Invalid configuration: region from ARN `{bucketArn#region}` does not match client region `{Region}` and UseArnRegion is `false`"],[s3,`Invalid ARN: Missing account id`],[G3(1),h6],[`https://{accessPointName_ssa_1}-{bucketArn#accountId}.s3-object-lambda-fips.{bucketArn#region}.{bucketPartition#dnsSuffix}`,h6],[`https://{accessPointName_ssa_1}-{bucketArn#accountId}.s3-object-lambda.{bucketArn#region}.{bucketPartition#dnsSuffix}`,h6],[s3,K3(1)],[s3,"Invalid ARN: The account id may only contain a-z, A-Z, 0-9 and `-`. Found: `{bucketArn#accountId}`"],[s3,"Invalid region in ARN: `{bucketArn#region}` (invalid DNS name)"],[s3,"Client was configured for partition `{partitionResult#name}` but ARN (`{Bucket}`) has `{bucketPartition#name}`"],[s3,"Invalid ARN: The ARN may only contain a single resource component after `accesspoint`."],[s3,`Invalid ARN: bucket ARN is missing a region`],[s3,"Invalid ARN: Expected a resource of the format `accesspoint:` but no name was provided"],[s3,"Invalid ARN: Object Lambda ARNs only support `accesspoint` arn types, but found: `{arnType}`"],[s3,`Access Points do not support S3 Accelerate`],[`https://{accessPointName_ssa_1}-{bucketArn#accountId}.s3-accesspoint-fips.dualstack.{bucketArn#region}.{bucketPartition#dnsSuffix}`,g6],[`https://{accessPointName_ssa_1}-{bucketArn#accountId}.s3-accesspoint-fips.{bucketArn#region}.{bucketPartition#dnsSuffix}`,g6],[`https://{accessPointName_ssa_1}-{bucketArn#accountId}.s3-accesspoint.dualstack.{bucketArn#region}.{bucketPartition#dnsSuffix}`,g6],[G3(1),g6],[`https://{accessPointName_ssa_1}-{bucketArn#accountId}.s3-accesspoint.{bucketArn#region}.{bucketPartition#dnsSuffix}`,g6],[s3,`Invalid ARN: The ARN was not for the S3 service, found: {bucketArn#service}`],[s3,`S3 MRAP does not support dual-stack`],[s3,`S3 MRAP does not support FIPS`],[s3,`S3 MRAP does not support S3 Accelerate`],[s3,`Invalid configuration: Multi-Region Access Point ARNs are disabled.`],[`https://{accessPointName_ssa_1}.accesspoint.s3-global.{partitionResult#dnsSuffix}`,{[n3]:[{[r3]:c3,name:q3,[i3]:z3,[o3]:zEe}]}],[s3,"Client was configured for partition `{partitionResult#name}` but bucket referred to partition `{bucketArn#partition}`"],[s3,`Invalid Access Point Name`],[s3,`S3 Outposts does not support Dual-stack`],[s3,`S3 Outposts does not support FIPS`],[s3,`S3 Outposts does not support S3 Accelerate`],[s3,`Invalid Arn: Outpost Access Point ARN contains sub resources`],[`https://{accessPointName_ssa_2}-{bucketArn#accountId}.{outpostId_ssa_1}.{url#authority}`,_6],[`https://{accessPointName_ssa_2}-{bucketArn#accountId}.{outpostId_ssa_1}.s3-outposts.{bucketArn#region}.{bucketPartition#dnsSuffix}`,_6],[s3,K3(2)],[s3,"Expected an outpost type `accesspoint`, found {outpostType}"],[s3,`Invalid ARN: expected an access point name`],[s3,`Invalid ARN: Expected a 4-component resource`],[s3,"Invalid ARN: The outpost Id may only contain a-z, A-Z, 0-9 and `-`. Found: `{outpostId_ssa_1}`"],[s3,`Invalid ARN: The Outpost Id was not set`],[s3,`Invalid ARN: Unrecognized format: {Bucket} (type: {arnType})`],[s3,`Invalid ARN: No ARN type specified`],[s3,"Invalid ARN: `{Bucket}` was not a valid ARN"],[s3,`Path-style addressing cannot be used with ARN buckets`],[`https://s3-fips.dualstack.us-east-1.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,p6],[`https://s3-fips.dualstack.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,m6],[`https://s3-fips.us-east-1.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,p6],[`https://s3-fips.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,m6],[`https://s3.dualstack.us-east-1.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,p6],[`https://s3.dualstack.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,m6],[J3,p6],[J3,m6],[Y3,p6],[Y3,m6],[`https://s3.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,m6],[s3,`Path-style addressing cannot be used with S3 Accelerate`],[V3,v6],[`https://s3-object-lambda-fips.{Region}.{partitionResult#dnsSuffix}`,v6],[`https://s3-object-lambda.{Region}.{partitionResult#dnsSuffix}`,v6],[`https://s3-fips.dualstack.us-east-1.{partitionResult#dnsSuffix}`,p6],[`https://s3-fips.dualstack.{Region}.{partitionResult#dnsSuffix}`,m6],[`https://s3-fips.us-east-1.{partitionResult#dnsSuffix}`,p6],[`https://s3-fips.{Region}.{partitionResult#dnsSuffix}`,m6],[`https://s3.dualstack.us-east-1.{partitionResult#dnsSuffix}`,p6],[`https://s3.dualstack.{Region}.{partitionResult#dnsSuffix}`,m6],[V3,p6],[V3,m6],[X3,p6],[X3,m6],[`https://s3.{Region}.{partitionResult#dnsSuffix}`,m6],[s3,`A region must be set when sending requests to S3.`]]},BEe=2,Z=1e8,VEe=new Int32Array([-1,1,-1,0,3,Z+115,1,424,4,2,272,5,3,233,6,4,85,7,5,15,8,8,9,Z+115,16,10,13,18,11,13,19,12,13,22,Z+14,13,35,14,Z+42,36,Z+103,435,6,271,16,7,270,17,8,19,18,14,501,106,9,20,24,10,21,24,11,22,24,12,23,24,13,547,24,14,77,25,20,73,26,26,27,78,37,28,Z+86,38,Z+86,29,39,47,30,48,Z+58,31,50,32,Z+85,51,33,136,55,Z+76,34,59,35,Z+84,60,39,36,61,37,Z+83,62,38,146,63,41,Z+46,61,40,Z+83,62,41,150,64,42,Z+54,66,43,Z+53,70,44,Z+52,71,45,Z+81,73,46,Z+80,74,Z+78,Z+79,40,48,Z+57,41,Z+57,49,42,185,50,48,62,51,49,Z+45,52,51,53,526,60,56,54,62,Z+55,55,63,57,Z+46,62,Z+55,57,64,58,Z+54,66,59,Z+53,69,60,Z+65,70,61,Z+52,72,Z+64,Z+51,49,Z+45,63,51,64,526,60,67,65,62,Z+55,66,63,68,Z+46,62,Z+55,68,64,69,Z+54,66,70,Z+53,68,Z+47,71,70,72,Z+52,72,Z+50,Z+51,25,74,Z+42,46,Z+39,75,57,76,Z+41,58,Z+40,Z+41,26,Z+88,78,28,Z+87,79,34,82,80,35,81,545,36,Z+103,Z+115,46,Z+97,83,57,84,Z+99,58,Z+98,Z+99,5,101,86,8,87,Z+115,16,88,89,18,91,89,19,90,92,21,97,95,19,93,92,21,98,95,21,97,94,22,Z+14,95,35,96,Z+42,36,Z+103,Z+42,22,Z+13,98,35,99,Z+42,36,Z+101,100,46,Z+110,Z+111,6,214,102,7,208,103,8,119,104,14,118,105,21,106,Z+23,26,107,502,37,108,Z+86,38,Z+86,109,39,112,110,48,Z+58,111,50,136,Z+85,40,113,Z+57,41,Z+57,114,42,115,500,48,Z+56,116,52,117,Z+72,65,Z+69,Z+72,21,501,Z+23,9,120,124,10,121,124,11,122,124,12,123,124,13,202,124,14,195,125,20,190,126,21,127,Z+23,23,128,129,24,189,129,26,130,197,37,131,Z+86,38,Z+86,132,39,159,133,48,Z+58,134,50,135,Z+85,51,141,136,55,Z+76,137,59,138,Z+84,60,Z+83,139,61,140,Z+83,63,Z+83,Z+46,55,Z+76,142,59,143,Z+84,60,148,144,61,145,Z+83,62,147,146,63,150,Z+46,63,153,Z+46,61,149,Z+83,62,153,150,64,151,Z+54,66,152,Z+53,70,Z+82,Z+52,64,154,Z+54,66,155,Z+53,70,156,Z+52,71,157,Z+81,73,158,Z+80,74,Z+77,Z+79,40,160,Z+57,41,Z+57,161,42,185,162,48,174,163,49,Z+45,164,51,165,526,60,168,166,62,Z+55,167,63,169,Z+46,62,Z+55,169,64,170,Z+54,66,171,Z+53,69,172,Z+65,70,173,Z+52,72,Z+63,Z+51,49,Z+45,175,51,176,526,60,179,177,62,Z+55,178,63,180,Z+46,62,Z+55,180,64,181,Z+54,66,182,Z+53,68,Z+47,183,70,184,Z+52,72,Z+48,Z+51,48,Z+56,186,52,187,Z+72,65,Z+69,188,67,Z+70,Z+71,25,Z+36,Z+42,21,191,Z+23,25,192,Z+42,30,194,193,46,Z+34,Z+36,46,Z+33,Z+35,21,196,Z+23,26,Z+88,197,28,Z+87,198,34,201,199,35,200,545,36,Z+101,Z+115,46,Z+95,Z+96,17,203,Z+22,20,204,Z+21,21,205,550,33,206,550,44,Z+16,207,45,Z+18,Z+20,8,209,215,16,210,220,18,211,220,19,212,224,20,213,227,21,231,401,8,218,215,19,216,Z+9,20,217,227,21,231,Z+9,16,219,220,18,223,220,19,221,224,20,222,227,21,231,Z+12,19,226,224,20,225,Z+9,21,Z+9,Z+12,20,230,227,21,228,Z+9,30,229,Z+9,34,Z+7,Z+9,21,231,415,30,232,Z+8,34,Z+7,Z+8,4,Z+2,234,5,235,480,6,271,236,7,270,237,8,238,491,9,239,243,10,240,243,11,241,243,12,242,243,13,547,243,14,266,244,20,264,245,26,246,267,37,247,Z+86,38,Z+86,248,39,249,518,40,250,Z+57,41,Z+57,251,42,538,252,48,Z+43,253,49,Z+45,254,51,255,526,60,258,256,62,Z+55,257,63,259,Z+46,62,Z+55,259,64,260,Z+54,66,261,Z+53,69,262,Z+65,70,263,Z+52,72,Z+62,Z+51,25,265,Z+42,46,Z+31,Z+32,26,Z+88,267,28,Z+87,268,34,269,544,46,Z+93,Z+94,8,397,Z+9,8,407,Z+9,3,346,273,4,Z+3,274,5,284,275,8,276,Z+115,15,Z+5,277,16,278,281,18,279,281,19,280,281,22,Z+14,281,35,282,Z+42,36,Z+102,283,46,Z+106,Z+107,6,405,285,7,395,286,8,295,287,14,501,288,26,289,502,37,290,Z+86,38,Z+86,291,39,292,307,40,293,Z+57,41,Z+57,294,42,335,500,9,296,300,10,297,300,11,298,300,12,299,300,13,394,300,14,339,301,15,Z+5,302,20,337,303,26,304,341,37,305,Z+86,38,Z+86,306,39,309,307,48,Z+58,308,50,Z+74,Z+85,40,310,Z+57,41,Z+57,311,42,335,312,48,324,313,49,Z+45,314,51,315,526,60,318,316,62,Z+55,317,63,319,Z+46,62,Z+55,319,64,320,Z+54,66,321,Z+53,69,322,Z+65,70,323,Z+52,72,Z+61,Z+51,49,Z+45,325,51,326,526,60,329,327,62,Z+55,328,63,330,Z+46,62,Z+55,330,64,331,Z+54,66,332,Z+53,68,Z+47,333,70,334,Z+52,72,Z+49,Z+51,48,Z+56,336,52,Z+67,Z+72,25,338,Z+42,46,Z+27,Z+28,15,Z+5,340,26,Z+88,341,28,Z+87,342,34,345,343,35,344,545,36,Z+102,Z+115,46,Z+91,Z+92,4,Z+2,347,5,357,348,8,349,Z+115,15,Z+5,350,16,351,354,18,352,354,19,353,354,22,Z+14,354,35,355,Z+42,36,Z+43,356,46,Z+104,Z+105,6,405,358,7,395,359,8,360,491,9,361,365,10,362,365,11,363,365,12,364,365,13,394,365,14,389,366,15,Z+5,367,20,387,368,26,369,391,37,370,Z+86,38,Z+86,371,39,372,518,40,373,Z+57,41,Z+57,374,42,538,375,48,Z+43,376,49,Z+45,377,51,378,526,60,381,379,62,Z+55,380,63,382,Z+46,62,Z+55,382,64,383,Z+54,66,384,Z+53,69,385,Z+65,70,386,Z+52,72,Z+60,Z+51,25,388,Z+42,46,Z+25,Z+26,15,Z+5,390,26,Z+88,391,28,Z+87,392,34,393,544,46,Z+89,Z+90,15,Z+5,547,8,396,Z+9,15,Z+5,397,16,398,410,18,399,410,19,400,410,20,401,Z+9,27,402,Z+12,29,Z+11,403,31,Z+11,404,32,Z+11,422,8,406,Z+9,15,Z+5,407,16,408,410,18,409,410,19,411,410,20,Z+12,Z+9,20,414,412,22,413,Z+9,34,Z+10,Z+9,22,416,415,27,419,Z+12,27,418,417,34,Z+10,Z+12,34,Z+10,419,43,Z+11,420,47,Z+11,421,53,Z+11,422,54,Z+11,423,56,Z+11,Z+12,2,Z+1,425,3,478,426,4,Z+4,427,5,438,428,8,429,Z+115,16,430,433,18,431,433,19,432,433,22,Z+14,433,35,434,Z+42,36,Z+44,435,46,Z+112,436,57,437,Z+114,58,Z+113,Z+114,6,Z+6,439,7,Z+6,440,8,450,441,14,501,442,26,443,502,37,444,Z+86,38,Z+86,445,39,446,465,40,447,Z+57,41,Z+57,448,42,471,449,48,Z+44,500,9,451,455,10,452,455,11,453,455,12,454,455,13,547,455,14,473,456,15,460,457,20,458,461,25,459,Z+42,46,Z+37,Z+38,20,540,461,26,462,474,37,463,Z+86,38,Z+86,464,39,467,465,48,Z+58,466,50,Z+75,Z+85,40,468,Z+57,41,Z+57,469,42,471,470,48,Z+44,524,48,Z+44,472,52,Z+68,Z+72,26,Z+88,474,28,Z+87,475,34,Z+100,476,35,477,545,36,Z+44,Z+115,4,Z+2,479,5,488,480,8,481,Z+115,16,482,485,18,483,485,19,484,485,22,Z+14,485,35,486,Z+42,36,Z+43,487,46,Z+108,Z+109,6,Z+6,489,7,Z+6,490,8,503,491,14,501,492,26,493,502,37,494,Z+86,38,Z+86,495,39,496,518,40,497,Z+57,41,Z+57,498,42,538,499,48,Z+43,500,49,Z+45,526,26,Z+88,502,28,Z+87,Z+115,9,504,508,10,505,508,11,506,508,12,507,508,13,547,508,14,541,509,15,513,510,20,511,514,25,512,Z+42,46,Z+29,Z+30,20,540,514,26,515,542,37,516,Z+86,38,Z+86,517,39,520,518,48,Z+58,519,50,Z+73,Z+85,40,521,Z+57,41,Z+57,522,42,538,523,48,Z+43,524,49,Z+45,525,51,529,526,60,Z+55,527,62,Z+55,528,63,Z+55,Z+46,60,532,530,62,Z+55,531,63,533,Z+46,62,Z+55,533,64,534,Z+54,66,535,Z+53,69,536,Z+65,70,537,Z+52,72,Z+59,Z+51,48,Z+43,539,52,Z+66,Z+72,25,Z+24,Z+42,26,Z+88,542,28,Z+87,543,34,Z+100,544,35,546,545,36,Z+42,Z+115,36,Z+43,Z+115,17,548,Z+22,20,549,Z+21,33,552,550,44,Z+17,551,45,Z+19,Z+20,44,Z+15,553,45,Z+15,Z+20]),HEe=PT.from(VEe,BEe,w6.conditions,w6.results),UEe=new FT({size:50,params:[`Accelerate`,`Bucket`,`DisableAccessPoints`,`DisableMultiRegionAccessPoints`,`DisableS3ExpressSessionAuth`,`Endpoint`,`ForcePathStyle`,`Region`,`UseArnRegion`,`UseDualStack`,`UseFIPS`,`UseGlobalEndpoint`,`UseObjectLambdaEndpoint`,`UseS3ExpressControlEndpoint`]}),T6=(e,t={})=>UEe.get(e,()=>pE(HEe,{endpointParams:e,logger:t.logger}));zT.aws=SE;var WEe=(e=>async(t,n,r)=>{if(!r)throw Error("Could not find `input` for `defaultEndpointRuleSetHttpAuthSchemeParametersProvider`");let i=await e(t,n,r),a=FS(n)?.commandInstance?.constructor?.getEndpointParameterInstructions;if(!a)throw Error(`getEndpointParameterInstructions() is not defined on '${n.commandName}'`);let o=await fD(r,{getEndpointParameterInstructions:a},t);return Object.assign(i,o)})(async(e,t,n)=>({operation:FS(t).operation,region:await IS(e.region)()||(()=>{throw Error("expected `region` to be configured for `aws.auth#sigv4`")})()}));function E6(e){return{schemeId:`aws.auth#sigv4`,signingProperties:{name:`s3`,region:e.region},propertiesExtractor:(e,t)=>({signingProperties:{config:e,context:t}})}}function D6(e){return{schemeId:`aws.auth#sigv4a`,signingProperties:{name:`s3`,region:e.region},propertiesExtractor:(e,t)=>({signingProperties:{config:e,context:t}})}}var GEe=((e,t,n)=>r=>{let i=e(r).properties?.authSchemes;if(!i)return t(r);let a=[];for(let e of i){let{name:t,properties:o={},...s}=e,c=t.toLowerCase();t!==c&&console.warn(`HttpAuthScheme has been normalized with lowercasing: '${t}' to '${c}'`);let l;if(c===`sigv4a`){l=`aws.auth#sigv4a`;let e=i.find(e=>{let t=e.name.toLowerCase();return t!==`sigv4a`&&t.startsWith(`sigv4`)});if(Q4.sigv4aDependency()===`none`&&e)continue}else if(c.startsWith(`sigv4`))l=`aws.auth#sigv4`;else throw Error(`Unknown HttpAuthScheme found in '@smithy.rules#endpointRuleSet': '${c}'`);let u=n[l];if(!u)throw Error(`Could not find HttpAuthOption create function for '${l}'`);let d=u(r);d.schemeId=l,d.signingProperties={...d.signingProperties||{},...s,...o},a.push(d)}return a})(T6,e=>{let t=[];switch(e.operation){default:t.push(E6(e)),t.push(D6(e))}return t},{"aws.auth#sigv4":E6,"aws.auth#sigv4a":D6}),KEe=e=>{let t=eie(VD(e));return Object.assign(t,{authSchemePreference:IS(e.authSchemePreference??[])})},qEe=e=>Object.assign(e,{useFipsEndpoint:e.useFipsEndpoint??!1,useDualstackEndpoint:e.useDualstackEndpoint??!1,forcePathStyle:e.forcePathStyle??!1,useAccelerateEndpoint:e.useAccelerateEndpoint??!1,useGlobalEndpoint:e.useGlobalEndpoint??!1,disableMultiregionAccessPoints:e.disableMultiregionAccessPoints??!1,defaultSigningName:`s3`,clientContextParams:e.clientContextParams??{}}),O6={ForcePathStyle:{type:`clientContextParams`,name:`forcePathStyle`},UseArnRegion:{type:`clientContextParams`,name:`useArnRegion`},DisableMultiRegionAccessPoints:{type:`clientContextParams`,name:`disableMultiregionAccessPoints`},Accelerate:{type:`clientContextParams`,name:`useAccelerateEndpoint`},DisableS3ExpressSessionAuth:{type:`clientContextParams`,name:`disableS3ExpressSessionAuth`},UseGlobalEndpoint:{type:`builtInParams`,name:`useGlobalEndpoint`},UseFIPS:{type:`builtInParams`,name:`useFipsEndpoint`},Endpoint:{type:`builtInParams`,name:`endpoint`},Region:{type:`builtInParams`,name:`region`},UseDualStack:{type:`builtInParams`,name:`useDualstackEndpoint`}},k6=class e extends TD{constructor(t){super(t),Object.setPrototypeOf(this,e.prototype)}},JEe=class e extends k6{name=`NoSuchUpload`;$fault=`client`;constructor(t){super({name:`NoSuchUpload`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},YEe=class e extends k6{name=`AccessDenied`;$fault=`client`;constructor(t){super({name:`AccessDenied`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},XEe=class e extends k6{name=`ObjectNotInActiveTierError`;$fault=`client`;constructor(t){super({name:`ObjectNotInActiveTierError`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},ZEe=class e extends k6{name=`BucketAlreadyExists`;$fault=`client`;constructor(t){super({name:`BucketAlreadyExists`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},QEe=class e extends k6{name=`BucketAlreadyOwnedByYou`;$fault=`client`;constructor(t){super({name:`BucketAlreadyOwnedByYou`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},$Ee=class e extends k6{name=`NoSuchBucket`;$fault=`client`;constructor(t){super({name:`NoSuchBucket`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},eDe=class e extends k6{name=`InvalidObjectState`;$fault=`client`;StorageClass;AccessTier;constructor(t){super({name:`InvalidObjectState`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.StorageClass=t.StorageClass,this.AccessTier=t.AccessTier}},tDe=class e extends k6{name=`NoSuchKey`;$fault=`client`;constructor(t){super({name:`NoSuchKey`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},nDe=class e extends k6{name=`NotFound`;$fault=`client`;constructor(t){super({name:`NotFound`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},rDe=class e extends k6{name=`EncryptionTypeMismatch`;$fault=`client`;constructor(t){super({name:`EncryptionTypeMismatch`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},iDe=class e extends k6{name=`InvalidRequest`;$fault=`client`;constructor(t){super({name:`InvalidRequest`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},aDe=class e extends k6{name=`InvalidWriteOffset`;$fault=`client`;constructor(t){super({name:`InvalidWriteOffset`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},oDe=class e extends k6{name=`TooManyParts`;$fault=`client`;constructor(t){super({name:`TooManyParts`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},sDe=class e extends k6{name=`IdempotencyParameterMismatch`;$fault=`client`;constructor(t){super({name:`IdempotencyParameterMismatch`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},cDe=class e extends k6{name=`ObjectAlreadyInActiveTierError`;$fault=`client`;constructor(t){super({name:`ObjectAlreadyInActiveTierError`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},A6=`ACL`,lDe=`AccessDenied`,uDe=`AbortDate`,j6=`AccessKeyId`,dDe=`AbortMultipartUpload`,fDe=`AbortMultipartUploadOutput`,pDe=`AbortMultipartUploadRequest`,mDe=`AcceptRanges`,hDe=`AbortRuleId`,gDe=`AccessTier`,M6=`Bucket`,N6=`BucketArn`,_De=`BucketAlreadyExists`,vDe=`BucketAlreadyOwnedByYou`,yDe=`BypassGovernanceRetention`,bDe=`BucketInfo`,P6=`BucketKeyEnabled`,xDe=`BucketNamespace`,F6=`BucketRegion`,I6=`Body`,L6=`Buckets`,R6=`ChecksumAlgorithm`,SDe=`CreateBucket`,z6=`CreateBucketConfiguration`,CDe=`CreateBucketOutput`,wDe=`CreateBucketRequest`,B6=`CacheControl`,V6=`ChecksumCRC32`,H6=`ChecksumCRC32C`,U6=`ChecksumCRC64NVME`,W6=`Cache-Control`,TDe=`CreationDate`,G6=`Content-Disposition`,K6=`ContentDisposition`,q6=`Content-Encoding`,J6=`ContentEncoding`,Y6=`ContentLanguage`,X6=`Content-Language`,Z6=`Content-Length`,Q6=`ContentLength`,$6=`Content-MD5`,e8=`ChecksumMD5`,t8=`ContentMD5`,EDe=`CompletedMultipartUpload`,DDe=`CompleteMultipartUploadOutput`,ODe=`CreateMultipartUploadOutput`,kDe=`CompleteMultipartUploadResult`,ADe=`CompleteMultipartUploadRequest`,jDe=`CreateMultipartUploadRequest`,n8=`CompleteMultipartUpload`,MDe=`CreateMultipartUpload`,NDe=`ChecksumMode`,PDe=`CommonPrefix`,FDe=`CommonPrefixList`,IDe=`CompletedPartList`,LDe=`CompletedPart`,RDe=`CommonPrefixes`,zDe=`ContentRange`,BDe=`Content-Range`,r8=`ChecksumSHA1`,i8=`ChecksumSHA256`,a8=`ChecksumSHA512`,VDe=`CreateSessionOutput`,HDe=`CreateSessionResult`,UDe=`CreateSessionRequest`,WDe=`CreateSession`,o8=`ChecksumType`,s8=`Content-Type`,c8=`ContentType`,l8=`ContinuationToken`,u8=`ChecksumXXHASH64`,d8=`ChecksumXXHASH3`,f8=`ChecksumXXHASH128`,GDe=`Contents`,p8=`Credentials`,m8=`DeleteMarker`,KDe=`DisplayName`,qDe=`DeleteObjectOutput`,JDe=`DeleteObjectRequest`,YDe=`DeleteObject`,XDe=`DataRedundancy`,h8=`Delimiter`,g8=`Expiration`,_8=`ExpectedBucketOwner`,v8=`ExpiresString`,ZDe=`EncryptionTypeMismatch`,y8=`ETag`,b8=`EncodingType`,x8=`Expires`,QDe=`FetchOwner`,S8=`GrantFullControl`,$De=`GetObject`,eOe=`GetObjectOutput`,tOe=`GetObjectRequest`,C8=`GrantRead`,w8=`GrantReadACP`,nOe=`GrantWrite`,T8=`GrantWriteACP`,rOe=`ID`,E8=`IfMatch`,iOe=`IfMatchInitiatedTime`,aOe=`IfMatchLastModifiedTime`,oOe=`IfMatchSize`,sOe=`If-Modified-Since`,cOe=`IfModifiedSince`,lOe=`InitiateMultipartUploadResult`,D8=`If-Match`,O8=`IfNoneMatch`,k8=`If-None-Match`,uOe=`InvalidObjectState`,dOe=`IdempotencyParameterMismatch`,fOe=`InvalidRequest`,pOe=`IsRestoreInProgress`,mOe=`IsTruncated`,hOe=`IfUnmodifiedSince`,gOe=`If-Unmodified-Since`,_Oe=`InvalidWriteOffset`,A8=`Key`,vOe=`KeyCount`,j8=`Location`,yOe=`ListAllMyBucketsResult`,bOe=`ListBuckets`,xOe=`ListBucketsOutput`,SOe=`ListBucketsRequest`,COe=`ListBucketResult`,wOe=`LocationConstraint`,TOe=`LocationInfo`,M8=`LastModified`,EOe=`Last-Modified`,DOe=`ListObjectsV2`,OOe=`ListObjectsV2Output`,kOe=`ListObjectsV2Request`,N8=`Metadata`,AOe=`MaxBuckets`,jOe=`MFA`,P8=`MaxKeys`,MOe=`MissingMeta`,NOe=`MpuObjectSize`,POe=`MultipartUpload`,F8=`Name`,FOe=`NextContinuationToken`,IOe=`NotFound`,LOe=`NoSuchBucket`,ROe=`NoSuchKey`,zOe=`NoSuchUpload`,I8=`Owner`,BOe=`ObjectAlreadyInActiveTierError`,VOe=`ObjectLockEnabledForBucket`,L8=`ObjectLockLegalHoldStatus`,R8=`ObjectLockMode`,z8=`ObjectLockRetainUntilDate`,HOe=`ObjectList`,UOe=`ObjectNotInActiveTierError`,WOe=`ObjectOwnership`,GOe=`OptionalObjectAttributes`,KOe=`Object`,B8=`Prefix`,qOe=`PartsCount`,V8=`PartNumber`,JOe=`PutObject`,YOe=`PutObjectOutput`,XOe=`PutObjectRequest`,ZOe=`PutObjectTagging`,QOe=`PutObjectTaggingOutput`,$Oe=`PutObjectTaggingRequest`,eke=`Parts`,tke=`Part`,H8=`RequestCharged`,nke=`ResponseCacheControl`,rke=`ResponseContentDisposition`,ike=`ResponseContentEncoding`,ake=`ResponseContentLanguage`,oke=`ResponseContentType`,ske=`ResponseExpires`,cke=`RestoreExpiryDate`,U8=`RequestPayer`,lke=`ReplicationStatus`,W8=`RestoreStatus`,G8=`Range`,uke=`Restore`,K8=`StartAfter`,q8=`SecretAccessKey`,dke=`StreamingBlob`,J8=`StorageClass`,fke=`SessionCredentialValue`,pke=`SessionCredentials`,mke=`SessionMode`,Y8=`ServerSideEncryption`,X8=`SSECustomerAlgorithm`,Z8=`SSECustomerKey`,Q8=`SSECustomerKeyMD5`,$8=`SSEKMSEncryptionContext`,e5=`SSEKMSKeyId`,t5=`SessionToken`,n5=`Size`,hke=`Tags`,gke=`TagCount`,_ke=`TooManyParts`,r5=`TagSet`,i5=`Tag`,a5=`Tagging`,o5=`Type`,s5=`UploadId`,vke=`UploadPart`,yke=`UploadPartOutput`,bke=`UploadPartRequest`,xke=`Value`,c5=`VersionId`,Ske=`WriteOffsetBytes`,l5=`WebsiteRedirectLocation`,Cke=`accept-ranges`,wke=`bucket-region`,u5=`client`,d5=`continuation-token`,Tke=`delimiter`,f5=`error`,Eke=`encoding-type`,Dke=`fetch-owner`,p5=`http`,m5=`httpChecksum`,h5=`httpError`,Q=`httpHeader`,g5=`httpPayload`,_5=`httpPrefixHeaders`,v5=`httpQuery`,Oke=`max-buckets`,kke=`max-keys`,y5=`prefix`,b5=`partNumber`,Ake=`response-cache-control`,jke=`response-content-disposition`,Mke=`response-content-encoding`,Nke=`response-content-language`,Pke=`response-content-type`,Fke=`response-expires`,x5=`smithy.ts.sdk.synthetic.com.amazonaws.s3`,Ike=`start-after`,Lke=`streaming`,S5=`uploadId`,C5=`versionId`,w5=`xmlFlattened`,T5=`xmlName`,E5=`x-amz-acl`,Rke=`x-amz-abort-date`,zke=`x-amz-abort-rule-id`,Bke=`x-amz-bucket-arn`,Vke=`x-amz-bypass-governance-retention`,Hke=`x-amz-bucket-namespace`,Uke=`x-amz-bucket-object-lock-enabled`,D5=`x-amz-checksum-algorithm`,O5=`x-amz-checksum-crc32`,k5=`x-amz-checksum-crc32c`,A5=`x-amz-checksum-crc64nvme`,j5=`x-amz-checksum-md5`,Wke=`x-amz-checksum-mode`,M5=`x-amz-checksum-sha1`,N5=`x-amz-checksum-sha256`,P5=`x-amz-checksum-sha512`,Gke=`x-amz-create-session-mode`,F5=`x-amz-checksum-type`,I5=`x-amz-checksum-xxhash64`,L5=`x-amz-checksum-xxhash3`,R5=`x-amz-checksum-xxhash128`,z5=`x-amz-delete-marker`,B5=`x-amz-expiration`,V5=`x-amz-expected-bucket-owner`,H5=`x-amz-grant-full-control`,U5=`x-amz-grant-read`,W5=`x-amz-grant-read-acp`,Kke=`x-amz-grant-write`,G5=`x-amz-grant-write-acp`,qke=`x-amz-if-match-initiated-time`,Jke=`x-amz-if-match-last-modified-time`,Yke=`x-amz-if-match-size`,K5=`x-amz-meta-`,Xke=`x-amz-mfa`,Zke=`x-amz-missing-meta`,Qke=`x-amz-mp-object-size`,$ke=`x-amz-mp-parts-count`,q5=`x-amz-object-lock-legal-hold`,J5=`x-amz-object-lock-mode`,Y5=`x-amz-object-lock-retain-until-date`,eAe=`x-amz-object-ownership`,tAe=`x-amz-optional-object-attributes`,nAe=`x-amz-object-size`,rAe=`x-amz-restore`,X5=`x-amz-request-charged`,Z5=`x-amz-request-payer`,iAe=`x-amz-replication-status`,Q5=`x-amz-storage-class`,$5=`x-amz-sdk-checksum-algorithm`,e7=`x-amz-server-side-encryption`,t7=`x-amz-server-side-encryption-aws-kms-key-id`,n7=`x-amz-server-side-encryption-bucket-key-enabled`,r7=`x-amz-server-side-encryption-context`,i7=`x-amz-server-side-encryption-customer-algorithm`,a7=`x-amz-server-side-encryption-customer-key`,o7=`x-amz-server-side-encryption-customer-key-MD5`,s7=`x-amz-tagging`,aAe=`x-amz-tagging-count`,c7=`x-amz-version-id`,oAe=`x-amz-write-offset-bytes`,l7=`x-amz-website-redirect-location`,$=`com.amazonaws.s3`,u7=dw.for(x5),sAe=[-3,x5,`S3ServiceException`,0,[],[]];u7.registerError(sAe,k6);var d7=dw.for($),cAe=[-3,$,lDe,{[f5]:u5,[h5]:403},[],[]];d7.registerError(cAe,YEe);var lAe=[-3,$,_De,{[f5]:u5,[h5]:409},[],[]];d7.registerError(lAe,ZEe);var uAe=[-3,$,vDe,{[f5]:u5,[h5]:409},[],[]];d7.registerError(uAe,QEe);var dAe=[-3,$,ZDe,{[f5]:u5,[h5]:400},[],[]];d7.registerError(dAe,rDe);var fAe=[-3,$,dOe,{[f5]:u5,[h5]:400},[],[]];d7.registerError(fAe,sDe);var pAe=[-3,$,uOe,{[f5]:u5,[h5]:403},[J8,gDe],[0,0]];d7.registerError(pAe,eDe);var f7=[-3,$,fOe,{[f5]:u5,[h5]:400},[],[]];d7.registerError(f7,iDe);var mAe=[-3,$,_Oe,{[f5]:u5,[h5]:400},[],[]];d7.registerError(mAe,aDe);var hAe=[-3,$,LOe,{[f5]:u5,[h5]:404},[],[]];d7.registerError(hAe,$Ee);var gAe=[-3,$,ROe,{[f5]:u5,[h5]:404},[],[]];d7.registerError(gAe,tDe);var _Ae=[-3,$,zOe,{[f5]:u5,[h5]:404},[],[]];d7.registerError(_Ae,JEe);var vAe=[-3,$,IOe,{[f5]:u5},[],[]];d7.registerError(vAe,nDe);var yAe=[-3,$,BOe,{[f5]:u5,[h5]:403},[],[]];d7.registerError(yAe,cDe);var bAe=[-3,$,UOe,{[f5]:u5,[h5]:403},[],[]];d7.registerError(bAe,XEe);var xAe=[-3,$,_ke,{[f5]:u5,[h5]:400},[],[]];d7.registerError(xAe,oDe);var SAe=[u7,d7],p7=[0,$,fke,8,0],m7=[0,$,Z8,8,0],h7=[0,$,$8,8,0],g7=[0,$,e5,8,0],_7=[0,$,dke,{[Lke]:1},42],CAe=[3,$,fDe,0,[H8],[[0,{[Q]:X5}]]],wAe=[3,$,pDe,0,[M6,A8,s5,U8,_8,iOe],[[0,1],[0,1],[0,{[v5]:S5}],[0,{[Q]:Z5}],[0,{[Q]:V5}],[6,{[Q]:qke}]],3],TAe=[3,$,M6,0,[F8,TDe,F6,N6],[0,4,0,0]],EAe=[3,$,bDe,0,[XDe,o5],[0,0]],DAe=[3,$,PDe,0,[B8],[0]],OAe=[3,$,EDe,0,[eke],[[()=>sje,{[w5]:1,[T5]:tke}]]],kAe=[3,$,LDe,0,[y8,V6,H6,U6,r8,i8,a8,e8,u8,d8,f8,V8],[0,0,0,0,0,0,0,0,0,0,0,1]],AAe=[3,$,DDe,{[T5]:kDe},[j8,M6,A8,g8,y8,V6,H6,U6,r8,i8,a8,e8,u8,d8,f8,o8,Y8,c5,e5,P6,H8],[0,0,0,[0,{[Q]:B5}],0,0,0,0,0,0,0,0,0,0,0,0,[0,{[Q]:e7}],[0,{[Q]:c7}],[()=>g7,{[Q]:t7}],[2,{[Q]:n7}],[0,{[Q]:X5}]]],jAe=[3,$,ADe,0,[M6,A8,s5,POe,V6,H6,U6,r8,i8,a8,e8,u8,d8,f8,o8,NOe,U8,_8,E8,O8,X8,Z8,Q8],[[0,1],[0,1],[0,{[v5]:S5}],[()=>OAe,{[g5]:1,[T5]:n8}],[0,{[Q]:O5}],[0,{[Q]:k5}],[0,{[Q]:A5}],[0,{[Q]:M5}],[0,{[Q]:N5}],[0,{[Q]:P5}],[0,{[Q]:j5}],[0,{[Q]:I5}],[0,{[Q]:L5}],[0,{[Q]:R5}],[0,{[Q]:F5}],[1,{[Q]:Qke}],[0,{[Q]:Z5}],[0,{[Q]:V5}],[0,{[Q]:D8}],[0,{[Q]:k8}],[0,{[Q]:i7}],[()=>m7,{[Q]:a7}],[0,{[Q]:o7}]],3],MAe=[3,$,z6,0,[wOe,j8,M6,hke],[0,()=>qAe,()=>EAe,[()=>y7,0]]],NAe=[3,$,CDe,0,[j8,N6],[[0,{[Q]:j8}],[0,{[Q]:Bke}]]],PAe=[3,$,wDe,0,[M6,A6,z6,S8,C8,w8,nOe,T8,VOe,WOe,xDe],[[0,1],[0,{[Q]:E5}],[()=>MAe,{[g5]:1,[T5]:z6}],[0,{[Q]:H5}],[0,{[Q]:U5}],[0,{[Q]:W5}],[0,{[Q]:Kke}],[0,{[Q]:G5}],[2,{[Q]:Uke}],[0,{[Q]:eAe}],[0,{[Q]:Hke}]],1],FAe=[3,$,ODe,{[T5]:lOe},[uDe,hDe,M6,A8,s5,Y8,X8,Q8,e5,$8,P6,H8,R6,o8],[[4,{[Q]:Rke}],[0,{[Q]:zke}],[0,{[T5]:M6}],0,0,[0,{[Q]:e7}],[0,{[Q]:i7}],[0,{[Q]:o7}],[()=>g7,{[Q]:t7}],[()=>h7,{[Q]:r7}],[2,{[Q]:n7}],[0,{[Q]:X5}],[0,{[Q]:D5}],[0,{[Q]:F5}]]],IAe=[3,$,jDe,0,[M6,A8,A6,B6,K6,J6,Y6,c8,x8,S8,C8,w8,T8,N8,Y8,J8,l5,X8,Z8,Q8,e5,$8,P6,U8,a5,R8,z8,L8,_8,R6,o8],[[0,1],[0,1],[0,{[Q]:E5}],[0,{[Q]:W6}],[0,{[Q]:G6}],[0,{[Q]:q6}],[0,{[Q]:X6}],[0,{[Q]:s8}],[4,{[Q]:x8}],[0,{[Q]:H5}],[0,{[Q]:U5}],[0,{[Q]:W5}],[0,{[Q]:G5}],[128,{[_5]:K5}],[0,{[Q]:e7}],[0,{[Q]:Q5}],[0,{[Q]:l7}],[0,{[Q]:i7}],[()=>m7,{[Q]:a7}],[0,{[Q]:o7}],[()=>g7,{[Q]:t7}],[()=>h7,{[Q]:r7}],[2,{[Q]:n7}],[0,{[Q]:Z5}],[0,{[Q]:s7}],[0,{[Q]:J5}],[5,{[Q]:Y5}],[0,{[Q]:q5}],[0,{[Q]:V5}],[0,{[Q]:D5}],[0,{[Q]:F5}]],2],LAe=[3,$,VDe,{[T5]:HDe},[p8,Y8,e5,$8,P6],[[()=>eje,{[T5]:p8}],[0,{[Q]:e7}],[()=>g7,{[Q]:t7}],[()=>h7,{[Q]:r7}],[2,{[Q]:n7}]],1],RAe=[3,$,UDe,0,[M6,mke,Y8,e5,$8,P6],[[0,1],[0,{[Q]:Gke}],[0,{[Q]:e7}],[()=>g7,{[Q]:t7}],[()=>h7,{[Q]:r7}],[2,{[Q]:n7}]],1],zAe=[3,$,qDe,0,[m8,c5,H8],[[2,{[Q]:z5}],[0,{[Q]:c7}],[0,{[Q]:X5}]]],BAe=[3,$,JDe,0,[M6,A8,jOe,c5,U8,yDe,_8,E8,aOe,oOe],[[0,1],[0,1],[0,{[Q]:Xke}],[0,{[v5]:C5}],[0,{[Q]:Z5}],[2,{[Q]:Vke}],[0,{[Q]:V5}],[0,{[Q]:D8}],[6,{[Q]:Jke}],[1,{[Q]:Yke}]],2],VAe=[3,$,eOe,0,[I6,m8,mDe,g8,uke,M8,Q6,y8,V6,H6,U6,r8,i8,a8,e8,u8,d8,f8,o8,MOe,c5,B6,K6,J6,Y6,zDe,c8,x8,v8,l5,Y8,N8,X8,Q8,e5,P6,J8,H8,lke,qOe,gke,R8,z8,L8],[[()=>_7,16],[2,{[Q]:z5}],[0,{[Q]:Cke}],[0,{[Q]:B5}],[0,{[Q]:rAe}],[4,{[Q]:EOe}],[1,{[Q]:Z6}],[0,{[Q]:y8}],[0,{[Q]:O5}],[0,{[Q]:k5}],[0,{[Q]:A5}],[0,{[Q]:M5}],[0,{[Q]:N5}],[0,{[Q]:P5}],[0,{[Q]:j5}],[0,{[Q]:I5}],[0,{[Q]:L5}],[0,{[Q]:R5}],[0,{[Q]:F5}],[1,{[Q]:Zke}],[0,{[Q]:c7}],[0,{[Q]:W6}],[0,{[Q]:G6}],[0,{[Q]:q6}],[0,{[Q]:X6}],[0,{[Q]:BDe}],[0,{[Q]:s8}],[4,{[Q]:x8}],[0,{[Q]:v8}],[0,{[Q]:l7}],[0,{[Q]:e7}],[128,{[_5]:K5}],[0,{[Q]:i7}],[0,{[Q]:o7}],[()=>g7,{[Q]:t7}],[2,{[Q]:n7}],[0,{[Q]:Q5}],[0,{[Q]:X5}],[0,{[Q]:iAe}],[1,{[Q]:$ke}],[1,{[Q]:aAe}],[0,{[Q]:J5}],[5,{[Q]:Y5}],[0,{[Q]:q5}]]],HAe=[3,$,tOe,0,[M6,A8,E8,cOe,O8,hOe,G8,nke,rke,ike,ake,oke,ske,c5,X8,Z8,Q8,U8,V8,_8,NDe],[[0,1],[0,1],[0,{[Q]:D8}],[4,{[Q]:sOe}],[0,{[Q]:k8}],[4,{[Q]:gOe}],[0,{[Q]:G8}],[0,{[v5]:Ake}],[0,{[v5]:jke}],[0,{[v5]:Mke}],[0,{[v5]:Nke}],[0,{[v5]:Pke}],[6,{[v5]:Fke}],[0,{[v5]:C5}],[0,{[Q]:i7}],[()=>m7,{[Q]:a7}],[0,{[Q]:o7}],[0,{[Q]:Z5}],[1,{[v5]:b5}],[0,{[Q]:V5}],[0,{[Q]:Wke}]],2],UAe=[3,$,xOe,{[T5]:yOe},[L6,I8,l8,B8],[[()=>aje,0],()=>v7,0,0]],WAe=[3,$,SOe,0,[AOe,l8,B8,F6],[[1,{[v5]:Oke}],[0,{[v5]:d5}],[0,{[v5]:y5}],[0,{[v5]:wke}]]],GAe=[3,$,OOe,{[T5]:COe},[mOe,GDe,F8,B8,h8,P8,RDe,b8,vOe,l8,FOe,K8,H8],[2,[()=>cje,{[w5]:1}],0,0,0,1,[()=>oje,{[w5]:1}],0,1,0,0,0,[0,{[Q]:X5}]]],KAe=[3,$,kOe,0,[M6,h8,b8,P8,B8,l8,QDe,K8,U8,_8,GOe],[[0,1],[0,{[v5]:Tke}],[0,{[v5]:Eke}],[1,{[v5]:kke}],[0,{[v5]:y5}],[0,{[v5]:d5}],[2,{[v5]:Dke}],[0,{[v5]:Ike}],[0,{[Q]:Z5}],[0,{[Q]:V5}],[64,{[Q]:tAe}]],1],qAe=[3,$,TOe,0,[o5,F8],[0,0]],JAe=[3,$,KOe,0,[A8,M8,y8,R6,o8,n5,J8,I8,W8],[0,4,0,[64,{[w5]:1}],0,1,0,()=>v7,()=>$Ae]],v7=[3,$,I8,0,[KDe,rOe],[0,0]],YAe=[3,$,YOe,0,[g8,y8,V6,H6,U6,r8,i8,a8,e8,u8,d8,f8,o8,Y8,c5,X8,Q8,e5,$8,P6,n5,H8],[[0,{[Q]:B5}],[0,{[Q]:y8}],[0,{[Q]:O5}],[0,{[Q]:k5}],[0,{[Q]:A5}],[0,{[Q]:M5}],[0,{[Q]:N5}],[0,{[Q]:P5}],[0,{[Q]:j5}],[0,{[Q]:I5}],[0,{[Q]:L5}],[0,{[Q]:R5}],[0,{[Q]:F5}],[0,{[Q]:e7}],[0,{[Q]:c7}],[0,{[Q]:i7}],[0,{[Q]:o7}],[()=>g7,{[Q]:t7}],[()=>h7,{[Q]:r7}],[2,{[Q]:n7}],[1,{[Q]:nAe}],[0,{[Q]:X5}]]],XAe=[3,$,XOe,0,[M6,A8,A6,I6,B6,K6,J6,Y6,Q6,t8,c8,R6,V6,H6,U6,r8,i8,a8,e8,u8,d8,f8,x8,E8,O8,S8,C8,w8,T8,Ske,N8,Y8,J8,l5,X8,Z8,Q8,e5,$8,P6,U8,a5,R8,z8,L8,_8],[[0,1],[0,1],[0,{[Q]:E5}],[()=>_7,16],[0,{[Q]:W6}],[0,{[Q]:G6}],[0,{[Q]:q6}],[0,{[Q]:X6}],[1,{[Q]:Z6}],[0,{[Q]:$6}],[0,{[Q]:s8}],[0,{[Q]:$5}],[0,{[Q]:O5}],[0,{[Q]:k5}],[0,{[Q]:A5}],[0,{[Q]:M5}],[0,{[Q]:N5}],[0,{[Q]:P5}],[0,{[Q]:j5}],[0,{[Q]:I5}],[0,{[Q]:L5}],[0,{[Q]:R5}],[4,{[Q]:x8}],[0,{[Q]:D8}],[0,{[Q]:k8}],[0,{[Q]:H5}],[0,{[Q]:U5}],[0,{[Q]:W5}],[0,{[Q]:G5}],[1,{[Q]:oAe}],[128,{[_5]:K5}],[0,{[Q]:e7}],[0,{[Q]:Q5}],[0,{[Q]:l7}],[0,{[Q]:i7}],[()=>m7,{[Q]:a7}],[0,{[Q]:o7}],[()=>g7,{[Q]:t7}],[()=>h7,{[Q]:r7}],[2,{[Q]:n7}],[0,{[Q]:Z5}],[0,{[Q]:s7}],[0,{[Q]:J5}],[5,{[Q]:Y5}],[0,{[Q]:q5}],[0,{[Q]:V5}]],2],ZAe=[3,$,QOe,0,[c5],[[0,{[Q]:c7}]]],QAe=[3,$,$Oe,0,[M6,A8,a5,c5,t8,R6,_8,U8],[[0,1],[0,1],[()=>nje,{[g5]:1,[T5]:a5}],[0,{[v5]:C5}],[0,{[Q]:$6}],[0,{[Q]:$5}],[0,{[Q]:V5}],[0,{[Q]:Z5}]],3],$Ae=[3,$,W8,0,[pOe,cke],[2,4]],eje=[3,$,pke,0,[j6,q8,t5,g8],[[0,{[T5]:j6}],[()=>p7,{[T5]:q8}],[()=>p7,{[T5]:t5}],[4,{[T5]:g8}]],4],tje=[3,$,i5,0,[A8,xke],[0,0],2],nje=[3,$,a5,0,[r5],[[()=>y7,0]],1],rje=[3,$,yke,0,[Y8,y8,V6,H6,U6,r8,i8,a8,e8,u8,d8,f8,X8,Q8,e5,P6,H8],[[0,{[Q]:e7}],[0,{[Q]:y8}],[0,{[Q]:O5}],[0,{[Q]:k5}],[0,{[Q]:A5}],[0,{[Q]:M5}],[0,{[Q]:N5}],[0,{[Q]:P5}],[0,{[Q]:j5}],[0,{[Q]:I5}],[0,{[Q]:L5}],[0,{[Q]:R5}],[0,{[Q]:i7}],[0,{[Q]:o7}],[()=>g7,{[Q]:t7}],[2,{[Q]:n7}],[0,{[Q]:X5}]]],ije=[3,$,bke,0,[M6,A8,V8,s5,I6,Q6,t8,R6,V6,H6,U6,r8,i8,a8,e8,u8,d8,f8,X8,Z8,Q8,U8,_8],[[0,1],[0,1],[1,{[v5]:b5}],[0,{[v5]:S5}],[()=>_7,16],[1,{[Q]:Z6}],[0,{[Q]:$6}],[0,{[Q]:$5}],[0,{[Q]:O5}],[0,{[Q]:k5}],[0,{[Q]:A5}],[0,{[Q]:M5}],[0,{[Q]:N5}],[0,{[Q]:P5}],[0,{[Q]:j5}],[0,{[Q]:I5}],[0,{[Q]:L5}],[0,{[Q]:R5}],[0,{[Q]:i7}],[()=>m7,{[Q]:a7}],[0,{[Q]:o7}],[0,{[Q]:Z5}],[0,{[Q]:V5}]],4],aje=[1,$,L6,0,[()=>TAe,{[T5]:M6}]],oje=[1,$,FDe,0,()=>DAe],sje=[1,$,IDe,0,()=>kAe],cje=[1,$,HOe,0,[()=>JAe,0]],y7=[1,$,r5,0,[()=>tje,{[T5]:i5}]],lje=[9,$,dDe,{[p5]:[`DELETE`,`/{Key+}?x-id=AbortMultipartUpload`,204]},()=>wAe,()=>CAe],uje=[9,$,n8,{[p5]:[`POST`,`/{Key+}`,200]},()=>jAe,()=>AAe],dje=[9,$,SDe,{[p5]:[`PUT`,`/`,200]},()=>PAe,()=>NAe],fje=[9,$,MDe,{[p5]:[`POST`,`/{Key+}?uploads`,200]},()=>IAe,()=>FAe],pje=[9,$,WDe,{[p5]:[`GET`,`/?session`,200]},()=>RAe,()=>LAe],mje=[9,$,YDe,{[p5]:[`DELETE`,`/{Key+}?x-id=DeleteObject`,204]},()=>BAe,()=>zAe],hje=[9,$,$De,{[m5]:`-`,[p5]:[`GET`,`/{Key+}?x-id=GetObject`,200]},()=>HAe,()=>VAe],gje=[9,$,bOe,{[p5]:[`GET`,`/?x-id=ListBuckets`,200]},()=>WAe,()=>UAe],_je=[9,$,DOe,{[p5]:[`GET`,`/?list-type=2`,200]},()=>KAe,()=>GAe],vje=[9,$,JOe,{[m5]:`-`,[p5]:[`PUT`,`/{Key+}?x-id=PutObject`,200]},()=>XAe,()=>YAe],yje=[9,$,ZOe,{[m5]:`-`,[p5]:[`PUT`,`/{Key+}?tagging`,200]},()=>QAe,()=>ZAe],bje=[9,$,vke,{[m5]:`-`,[p5]:[`PUT`,`/{Key+}?x-id=UploadPart`,200]},()=>ije,()=>rje],xje=class extends wD.classBuilder().ep({...O6,DisableS3ExpressSessionAuth:{type:`staticContextParams`,value:!0},Bucket:{type:`contextParams`,name:`Bucket`}}).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions()),X4(n)]}).s(`AmazonS3`,`CreateSession`,{}).n(`S3Client`,`CreateSessionCommand`).sc(pje).build(){},Sje={name:`@aws-sdk/client-s3`,description:`AWS SDK for JavaScript S3 Client for Node.js, Browser and React Native`,version:`3.1045.0`,scripts:{build:`concurrently 'yarn:build:types' 'yarn:build:es' && yarn build:cjs`,"build:cjs":`node ../../scripts/compilation/inline client-s3`,"build:es":`tsc -p tsconfig.es.json`,"build:include:deps":`yarn g:turbo run build -F="$npm_package_name"`,"build:types":`tsc -p tsconfig.types.json`,"build:types:downlevel":`downlevel-dts dist-types dist-types/ts3.4`,clean:`premove dist-cjs dist-es dist-types tsconfig.cjs.tsbuildinfo tsconfig.es.tsbuildinfo tsconfig.types.tsbuildinfo`,"extract:docs":`api-extractor run --local`,"generate:client":`node ../../scripts/generate-clients/single-service --solo s3`,test:`yarn g:vitest run`,"test:browser":`node ./test/browser-build/esbuild && yarn g:vitest run -c vitest.config.browser.mts`,"test:browser:watch":`node ./test/browser-build/esbuild && yarn g:vitest watch -c vitest.config.browser.mts`,"test:e2e":`yarn g:vitest run -c vitest.config.e2e.mts && yarn test:browser`,"test:e2e:watch":`yarn g:vitest watch -c vitest.config.e2e.mts`,"test:index":`tsc --noEmit ./test/index-types.ts && node ./test/index-objects.spec.mjs`,"test:integration":`yarn g:vitest run -c vitest.config.integ.mts`,"test:integration:watch":`yarn g:vitest watch -c vitest.config.integ.mts`,"test:watch":`yarn g:vitest watch`},main:`./dist-cjs/index.js`,types:`./dist-types/index.d.ts`,module:`./dist-es/index.js`,sideEffects:!1,dependencies:{"@aws-crypto/sha1-browser":`5.2.0`,"@aws-crypto/sha256-browser":`5.2.0`,"@aws-crypto/sha256-js":`5.2.0`,"@aws-sdk/core":`^3.974.8`,"@aws-sdk/credential-provider-node":`^3.972.39`,"@aws-sdk/middleware-bucket-endpoint":`^3.972.10`,"@aws-sdk/middleware-expect-continue":`^3.972.10`,"@aws-sdk/middleware-flexible-checksums":`^3.974.16`,"@aws-sdk/middleware-host-header":`^3.972.10`,"@aws-sdk/middleware-location-constraint":`^3.972.10`,"@aws-sdk/middleware-logger":`^3.972.10`,"@aws-sdk/middleware-recursion-detection":`^3.972.11`,"@aws-sdk/middleware-sdk-s3":`^3.972.37`,"@aws-sdk/middleware-ssec":`^3.972.10`,"@aws-sdk/middleware-user-agent":`^3.972.38`,"@aws-sdk/region-config-resolver":`^3.972.13`,"@aws-sdk/signature-v4-multi-region":`^3.996.25`,"@aws-sdk/types":`^3.973.8`,"@aws-sdk/util-endpoints":`^3.996.8`,"@aws-sdk/util-user-agent-browser":`^3.972.10`,"@aws-sdk/util-user-agent-node":`^3.973.24`,"@smithy/config-resolver":`^4.4.17`,"@smithy/core":`^3.23.17`,"@smithy/eventstream-serde-browser":`^4.2.14`,"@smithy/eventstream-serde-config-resolver":`^4.3.14`,"@smithy/eventstream-serde-node":`^4.2.14`,"@smithy/fetch-http-handler":`^5.3.17`,"@smithy/hash-blob-browser":`^4.2.15`,"@smithy/hash-node":`^4.2.14`,"@smithy/hash-stream-node":`^4.2.14`,"@smithy/invalid-dependency":`^4.2.14`,"@smithy/md5-js":`^4.2.14`,"@smithy/middleware-content-length":`^4.2.14`,"@smithy/middleware-endpoint":`^4.4.32`,"@smithy/middleware-retry":`^4.5.7`,"@smithy/middleware-serde":`^4.2.20`,"@smithy/middleware-stack":`^4.2.14`,"@smithy/node-config-provider":`^4.3.14`,"@smithy/node-http-handler":`^4.6.1`,"@smithy/protocol-http":`^5.3.14`,"@smithy/smithy-client":`^4.12.13`,"@smithy/types":`^4.14.1`,"@smithy/url-parser":`^4.2.14`,"@smithy/util-base64":`^4.3.2`,"@smithy/util-body-length-browser":`^4.2.2`,"@smithy/util-body-length-node":`^4.2.3`,"@smithy/util-defaults-mode-browser":`^4.3.49`,"@smithy/util-defaults-mode-node":`^4.2.54`,"@smithy/util-endpoints":`^3.4.2`,"@smithy/util-middleware":`^4.2.14`,"@smithy/util-retry":`^4.3.6`,"@smithy/util-stream":`^4.5.25`,"@smithy/util-utf8":`^4.2.2`,"@smithy/util-waiter":`^4.3.0`,tslib:`^2.6.2`},devDependencies:{"@aws-sdk/signature-v4-crt":`3.1045.0`,"@smithy/snapshot-testing":`^2.0.8`,"@tsconfig/node20":`20.1.8`,"@types/node":`^20.14.8`,concurrently:`7.0.0`,"downlevel-dts":`0.10.1`,premove:`4.0.0`,typescript:`~5.8.3`,vitest:`^4.0.17`},engines:{node:`>=20.0.0`},typesVersions:{"<4.5":{"dist-types/*":[`dist-types/ts3.4/*`]}},files:[`dist-*/**`],author:{name:`AWS SDK for JavaScript Team`,url:`https://aws.amazon.com/javascript/`},license:`Apache-2.0`,browser:{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.browser`},"react-native":{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.native`},homepage:`https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-s3`,repository:{type:`git`,url:`https://github.com/aws/aws-sdk-js-v3.git`,directory:`clients/client-s3`}};function b7(e){return typeof e==`string`?e.length===0:e.byteLength===0}var x7={name:`SHA-1`},S7={name:`HMAC`,hash:x7},Cje=new Uint8Array([218,57,163,238,94,107,75,13,50,85,191,239,149,96,24,144,175,216,7,9]),wje=function(){function e(e){this.toHash=new Uint8Array,e!==void 0&&(this.key=new Promise(function(t,n){Cx().crypto.subtle.importKey(`raw`,C7(e),S7,!1,[`sign`]).then(t,n)}),this.key.catch(function(){}))}return e.prototype.update=function(e){if(!b7(e)){var t=C7(e),n=new Uint8Array(this.toHash.byteLength+t.byteLength);n.set(this.toHash,0),n.set(t,this.toHash.byteLength),this.toHash=n}},e.prototype.digest=function(){var e=this;return this.key?this.key.then(function(t){return Cx().crypto.subtle.sign(S7,t,e.toHash).then(function(e){return new Uint8Array(e)})}):b7(this.toHash)?Promise.resolve(Cje):Promise.resolve().then(function(){return Cx().crypto.subtle.digest(x7,e.toHash)}).then(function(e){return Promise.resolve(new Uint8Array(e))})},e.prototype.reset=function(){this.toHash=new Uint8Array},e}();function C7(e){return typeof e==`string`?px(e):ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength/Uint8Array.BYTES_PER_ELEMENT):new Uint8Array(e)}var Tje=function(){function e(e){if(Fx(Cx()))this.hash=new wje(e);else throw Error(`SHA1 not supported`)}return e.prototype.update=function(e,t){this.hash.update(hx(e))},e.prototype.digest=function(){return this.hash.digest()},e.prototype.reset=function(){this.hash.reset()},e}(),w7=class e{bytes;constructor(e){if(this.bytes=e,e.byteLength!==8)throw Error(`Int64 buffers must be exactly 8 bytes`)}static fromNumber(t){if(t>0x8000000000000000||t<-0x8000000000000000)throw Error(`${t} is too large (or, if negative, too small) to represent as an Int64`);let n=new Uint8Array(8);for(let e=7,r=Math.abs(Math.round(t));e>-1&&r>0;e--,r/=256)n[e]=r;return t<0&&T7(n),new e(n)}valueOf(){let e=this.bytes.slice(0),t=e[0]&128;return t&&T7(e),parseInt(Xx(e),16)*(t?-1:1)}toString(){return String(this.valueOf())}};function T7(e){for(let t=0;t<8;t++)e[t]^=255;for(let t=7;t>-1&&(e[t]++,e[t]===0);t--);}var Eje=class{toUtf8;fromUtf8;constructor(e,t){this.toUtf8=e,this.fromUtf8=t}format(e){let t=[];for(let n of Object.keys(e)){let r=this.fromUtf8(n);t.push(Uint8Array.from([r.byteLength]),r,this.formatHeaderValue(e[n]))}let n=new Uint8Array(t.reduce((e,t)=>e+t.byteLength,0)),r=0;for(let e of t)n.set(e,r),r+=e.byteLength;return n}formatHeaderValue(e){switch(e.type){case`boolean`:return Uint8Array.from([+!e.value]);case`byte`:return Uint8Array.from([2,e.value]);case`short`:let t=new DataView(new ArrayBuffer(3));return t.setUint8(0,3),t.setInt16(1,e.value,!1),new Uint8Array(t.buffer);case`integer`:let n=new DataView(new ArrayBuffer(5));return n.setUint8(0,4),n.setInt32(1,e.value,!1),new Uint8Array(n.buffer);case`long`:let r=new Uint8Array(9);return r[0]=5,r.set(e.value.bytes,1),r;case`binary`:let i=new DataView(new ArrayBuffer(3+e.value.byteLength));i.setUint8(0,6),i.setUint16(1,e.value.byteLength,!1);let a=new Uint8Array(i.buffer);return a.set(e.value,3),a;case`string`:let o=this.fromUtf8(e.value),s=new DataView(new ArrayBuffer(3+o.byteLength));s.setUint8(0,7),s.setUint16(1,o.byteLength,!1);let c=new Uint8Array(s.buffer);return c.set(o,3),c;case`timestamp`:let l=new Uint8Array(9);return l[0]=8,l.set(w7.fromNumber(e.value.valueOf()).bytes,1),l;case`uuid`:if(!Ije.test(e.value))throw Error(`Invalid UUID received: ${e.value}`);let u=new Uint8Array(17);return u[0]=9,u.set(Yx(e.value.replace(/\-/g,``)),1),u}}parse(e){let t={},n=0;for(;n{if(typeof e!=`number`)throw Error(`Attempted to allocate an event message where size was not a number: `+e);t=e,n=4,r=new Uint8Array(e),new DataView(r.buffer).setUint32(0,e,!1)},o=async function*(){let o=e[Symbol.asyncIterator]();for(;;){let{value:e,done:s}=await o.next();if(s){if(!t)return;if(t===n)yield r;else throw Error(`Truncated event message received.`);return}let c=e.length,l=0;for(;l({[Symbol.asyncIterator]:async function*(){let t=e.getReader();try{for(;;){let{done:e,value:n}=await t.read();if(e)return;yield n}}finally{t.releaseLock()}}}),Jje=e=>{let t=e[Symbol.asyncIterator]();return new ReadableStream({async pull(e){let{done:n,value:r}=await t.next();if(n)return e.close();e.enqueue(r)}})},Yje=class{universalMarshaller;constructor({utf8Encoder:e,utf8Decoder:t}){this.universalMarshaller=new Kje({utf8Decoder:t,utf8Encoder:e})}deserialize(e,t){let n=Xje(e)?qje(e):e;return this.universalMarshaller.deserialize(n,t)}serialize(e,t){let n=this.universalMarshaller.serialize(e,t);return typeof ReadableStream==`function`?Jje(n):n}},Xje=e=>typeof ReadableStream==`function`&&e instanceof ReadableStream,Zje=e=>new Yje(e);async function Qje(e,t,n=1024*1024){let r=e.size,i=0;for(;i{n.update(e)}),n.digest()},eMe=[1732584193,4023233417,2562383102,271733878],tMe=class{state;buffer;bufferLength;bytesHashed;finished;constructor(){this.reset()}update(e){if(nMe(e))return;if(this.finished)throw Error(`Attempted to update an already finished hash.`);let t=rMe(e),n=0,{byteLength:r}=t;for(this.bytesHashed+=r;r>0;)this.buffer.setUint8(this.bufferLength++,t[n++]),r--,this.bufferLength===64&&(this.hashBuffer(),this.bufferLength=0)}async digest(){if(!this.finished){let{buffer:e,bufferLength:t,bytesHashed:n}=this,r=n*8;if(e.setUint8(this.bufferLength++,128),t%64>=56){for(let t=this.bufferLength;t<64;t++)e.setUint8(t,0);this.hashBuffer(),this.bufferLength=0}for(let t=this.bufferLength;t<56;t++)e.setUint8(t,0);e.setUint32(56,r>>>0,!0),e.setUint32(60,Math.floor(r/4294967296),!0),this.hashBuffer(),this.finished=!0}let e=new DataView(new ArrayBuffer(16));for(let t=0;t<4;t++)e.setUint32(t*4,this.state[t],!0);return new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}hashBuffer(){let{buffer:e,state:t}=this,n=t[0],r=t[1],i=t[2],a=t[3];n=j7(n,r,i,a,e.getUint32(0,!0),7,3614090360),a=j7(a,n,r,i,e.getUint32(4,!0),12,3905402710),i=j7(i,a,n,r,e.getUint32(8,!0),17,606105819),r=j7(r,i,a,n,e.getUint32(12,!0),22,3250441966),n=j7(n,r,i,a,e.getUint32(16,!0),7,4118548399),a=j7(a,n,r,i,e.getUint32(20,!0),12,1200080426),i=j7(i,a,n,r,e.getUint32(24,!0),17,2821735955),r=j7(r,i,a,n,e.getUint32(28,!0),22,4249261313),n=j7(n,r,i,a,e.getUint32(32,!0),7,1770035416),a=j7(a,n,r,i,e.getUint32(36,!0),12,2336552879),i=j7(i,a,n,r,e.getUint32(40,!0),17,4294925233),r=j7(r,i,a,n,e.getUint32(44,!0),22,2304563134),n=j7(n,r,i,a,e.getUint32(48,!0),7,1804603682),a=j7(a,n,r,i,e.getUint32(52,!0),12,4254626195),i=j7(i,a,n,r,e.getUint32(56,!0),17,2792965006),r=j7(r,i,a,n,e.getUint32(60,!0),22,1236535329),n=M7(n,r,i,a,e.getUint32(4,!0),5,4129170786),a=M7(a,n,r,i,e.getUint32(24,!0),9,3225465664),i=M7(i,a,n,r,e.getUint32(44,!0),14,643717713),r=M7(r,i,a,n,e.getUint32(0,!0),20,3921069994),n=M7(n,r,i,a,e.getUint32(20,!0),5,3593408605),a=M7(a,n,r,i,e.getUint32(40,!0),9,38016083),i=M7(i,a,n,r,e.getUint32(60,!0),14,3634488961),r=M7(r,i,a,n,e.getUint32(16,!0),20,3889429448),n=M7(n,r,i,a,e.getUint32(36,!0),5,568446438),a=M7(a,n,r,i,e.getUint32(56,!0),9,3275163606),i=M7(i,a,n,r,e.getUint32(12,!0),14,4107603335),r=M7(r,i,a,n,e.getUint32(32,!0),20,1163531501),n=M7(n,r,i,a,e.getUint32(52,!0),5,2850285829),a=M7(a,n,r,i,e.getUint32(8,!0),9,4243563512),i=M7(i,a,n,r,e.getUint32(28,!0),14,1735328473),r=M7(r,i,a,n,e.getUint32(48,!0),20,2368359562),n=N7(n,r,i,a,e.getUint32(20,!0),4,4294588738),a=N7(a,n,r,i,e.getUint32(32,!0),11,2272392833),i=N7(i,a,n,r,e.getUint32(44,!0),16,1839030562),r=N7(r,i,a,n,e.getUint32(56,!0),23,4259657740),n=N7(n,r,i,a,e.getUint32(4,!0),4,2763975236),a=N7(a,n,r,i,e.getUint32(16,!0),11,1272893353),i=N7(i,a,n,r,e.getUint32(28,!0),16,4139469664),r=N7(r,i,a,n,e.getUint32(40,!0),23,3200236656),n=N7(n,r,i,a,e.getUint32(52,!0),4,681279174),a=N7(a,n,r,i,e.getUint32(0,!0),11,3936430074),i=N7(i,a,n,r,e.getUint32(12,!0),16,3572445317),r=N7(r,i,a,n,e.getUint32(24,!0),23,76029189),n=N7(n,r,i,a,e.getUint32(36,!0),4,3654602809),a=N7(a,n,r,i,e.getUint32(48,!0),11,3873151461),i=N7(i,a,n,r,e.getUint32(60,!0),16,530742520),r=N7(r,i,a,n,e.getUint32(8,!0),23,3299628645),n=P7(n,r,i,a,e.getUint32(0,!0),6,4096336452),a=P7(a,n,r,i,e.getUint32(28,!0),10,1126891415),i=P7(i,a,n,r,e.getUint32(56,!0),15,2878612391),r=P7(r,i,a,n,e.getUint32(20,!0),21,4237533241),n=P7(n,r,i,a,e.getUint32(48,!0),6,1700485571),a=P7(a,n,r,i,e.getUint32(12,!0),10,2399980690),i=P7(i,a,n,r,e.getUint32(40,!0),15,4293915773),r=P7(r,i,a,n,e.getUint32(4,!0),21,2240044497),n=P7(n,r,i,a,e.getUint32(32,!0),6,1873313359),a=P7(a,n,r,i,e.getUint32(60,!0),10,4264355552),i=P7(i,a,n,r,e.getUint32(24,!0),15,2734768916),r=P7(r,i,a,n,e.getUint32(52,!0),21,1309151649),n=P7(n,r,i,a,e.getUint32(16,!0),6,4149444226),a=P7(a,n,r,i,e.getUint32(44,!0),10,3174756917),i=P7(i,a,n,r,e.getUint32(8,!0),15,718787259),r=P7(r,i,a,n,e.getUint32(36,!0),21,3951481745),t[0]=n+t[0]&4294967295,t[1]=r+t[1]&4294967295,t[2]=i+t[2]&4294967295,t[3]=a+t[3]&4294967295}reset(){this.state=Uint32Array.from(eMe),this.buffer=new DataView(new ArrayBuffer(64)),this.bufferLength=0,this.bytesHashed=0,this.finished=!1}};function A7(e,t,n,r,i,a){return t=(t+e&4294967295)+(r+a&4294967295)&4294967295,(t<>>32-i)+n&4294967295}function j7(e,t,n,r,i,a,o){return A7(t&n|~t&r,e,t,i,a,o)}function M7(e,t,n,r,i,a,o){return A7(t&r|n&~r,e,t,i,a,o)}function N7(e,t,n,r,i,a,o){return A7(t^n^r,e,t,i,a,o)}function P7(e,t,n,r,i,a,o){return A7(n^(t|~r),e,t,i,a,o)}function nMe(e){return typeof e==`string`?e.length===0:e.byteLength===0}function rMe(e){return typeof e==`string`?Zx(e):ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength/Uint8Array.BYTES_PER_ELEMENT):new Uint8Array(e)}var iMe=e=>({apiVersion:`2006-03-01`,base64Decoder:e?.base64Decoder??TC,base64Encoder:e?.base64Encoder??EC,disableHostPrefix:e?.disableHostPrefix??!1,endpointProvider:e?.endpointProvider??T6,extensions:e?.extensions??[],getAwsChunkedEncodingStream:e?.getAwsChunkedEncodingStream??kC,httpAuthSchemeProvider:e?.httpAuthSchemeProvider??GEe,httpAuthSchemes:e?.httpAuthSchemes??[{schemeId:`aws.auth#sigv4`,identityProvider:e=>e.getIdentityProvider(`aws.auth#sigv4`),signer:new BD},{schemeId:`aws.auth#sigv4a`,identityProvider:e=>e.getIdentityProvider(`aws.auth#sigv4a`),signer:new Qre}],logger:e?.logger??new MD,protocol:e?.protocol??LEe,protocolSettings:e?.protocolSettings??{defaultNamespace:`com.amazonaws.s3`,errorTypeRegistries:SAe,xmlNamespace:`http://s3.amazonaws.com/doc/2006-03-01/`,version:`2006-03-01`,serviceTarget:`AmazonS3`},sdkStreamMixin:e?.sdkStreamMixin??VC,serviceId:e?.serviceId??`S3`,signerConstructor:e?.signerConstructor??Q4,signingEscapePath:e?.signingEscapePath??!1,urlParser:e?.urlParser??XC,useArnRegion:e?.useArnRegion??void 0,utf8Decoder:e?.utf8Decoder??Zx,utf8Encoder:e?.utf8Encoder??$x}),aMe=e=>{let t=JD(e),n=()=>t().then(DD),r=iMe(e);return{...r,...e,runtime:`browser`,defaultsMode:t,bodyLengthChecker:e?.bodyLengthChecker??qD,credentialDefaultProvider:e?.credentialDefaultProvider??(e=>()=>Promise.reject(Error(`Credential is missing`))),defaultUserAgentProvider:e?.defaultUserAgentProvider??UD({serviceId:r.serviceId,clientVersion:Sje.version}),eventStreamSerdeProvider:e?.eventStreamSerdeProvider??Zje,maxAttempts:e?.maxAttempts??3,md5:e?.md5??tMe,region:e?.region??GD(`Region is missing`),requestHandler:PC.create(e?.requestHandler??n),retryMode:e?.retryMode??(async()=>(await n()).retryMode||TE),sha1:e?.sha1??Tje,sha256:e?.sha256??Rx,streamCollector:e?.streamCollector??IC,streamHasher:e?.streamHasher??$je,useDualstackEndpoint:e?.useDualstackEndpoint??(()=>Promise.resolve(!1)),useFipsEndpoint:e?.useFipsEndpoint??(()=>Promise.resolve(!1))}},oMe=e=>{let t=e.httpAuthSchemes,n=e.httpAuthSchemeProvider,r=e.credentials;return{setHttpAuthScheme(e){let n=t.findIndex(t=>t.schemeId===e.schemeId);n===-1?t.push(e):t.splice(n,1,e)},httpAuthSchemes(){return t},setHttpAuthSchemeProvider(e){n=e},httpAuthSchemeProvider(){return n},setCredentials(e){r=e},credentials(){return r}}},sMe=e=>({httpAuthSchemes:e.httpAuthSchemes(),httpAuthSchemeProvider:e.httpAuthSchemeProvider(),credentials:e.credentials()}),cMe=(e,t)=>{let n=Object.assign(f1(e),kD(e),zx(e),oMe(e));return t.forEach(e=>e.configure(n)),Object.assign(e,p1(n),AD(n),Bx(n),sMe(n))},lMe=class extends xD{config;constructor(...[e]){let t=aMe(e||{});super(t),this.initConfig=t;let n=cMe(TEe(KEe(REe(mD(tC(oD(hD(sEe(NT(qEe(t))))))))),{session:[()=>this,xje]}),e?.extensions||[]);this.config=n,this.middlewareStack.use(tw(this.config)),this.middlewareStack.use(rD(this.config)),this.middlewareStack.use(PD(this.config)),this.middlewareStack.use(cD(this.config)),this.middlewareStack.use(iC(this.config)),this.middlewareStack.use(sC(this.config)),this.middlewareStack.use(uC(this.config)),this.middlewareStack.use(hC(this.config,{httpAuthSchemeParametersProvider:WEe,identityProviderConfigProvider:async e=>new OT({"aws.auth#sigv4":e.credentials,"aws.auth#sigv4a":e.credentials})})),this.middlewareStack.use(bC(this.config)),this.middlewareStack.use(IEe(this.config)),this.middlewareStack.use($Te(this.config)),this.middlewareStack.use(fEe(this.config)),this.middlewareStack.use(yEe(this.config)),this.middlewareStack.use(wEe(this.config))}destroy(){super.destroy()}},uMe=class extends wD.classBuilder().ep(O6).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions()),X4(n)]}).s(`AmazonS3`,`ListBuckets`,{}).n(`S3Client`,`ListBucketsCommand`).sc(gje).build(){},dMe=class extends wD.classBuilder().ep({...O6,Bucket:{type:`contextParams`,name:`Bucket`},Prefix:{type:`contextParams`,name:`Prefix`}}).m(function(e,t,n,r){return[pD(n,e.getEndpointParameterInstructions()),X4(n)]}).s(`AmazonS3`,`ListObjectsV2`,{}).n(`S3Client`,`ListObjectsV2Command`).sc(_je).build(){},F7=`ap-southeast-2`,I7=`${window.location.protocol}//localhost:9999`,fMe=`${window.location.protocol}//localhost:8443`,L7=null,R7=null,z7=null,B7=null;function V7(){if(!L7){let e=ux();if(!e)throw Error(`AWS credentials not configured`);L7=new ife({endpoint:I7,region:F7,credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}}),L7.middlewareStack.add(e=>async t=>(Wx.isInstance(t.request)&&(t.request.hostname=window.location.hostname,t.request.port=Number(window.location.port)||443,t.request.path=`/proxy/awsgw${t.request.path}`),await e(t)),{step:`finalizeRequest`,name:`proxyRewrite`,override:!0})}return L7}function H7(){if(!R7){let e=ux();if(!e)throw Error(`AWS credentials not configured`);R7=new rxe({endpoint:I7,region:F7,credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}}),R7.middlewareStack.add(e=>async t=>(Wx.isInstance(t.request)&&(t.request.hostname=window.location.hostname,t.request.port=Number(window.location.port)||443,t.request.path=`/proxy/awsgw${t.request.path}`),await e(t)),{step:`finalizeRequest`,name:`proxyRewrite`,override:!0})}return R7}function U7(){if(!z7){let e=ux();if(!e)throw Error(`AWS credentials not configured`);z7=new UTe({endpoint:I7,region:F7,credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}}),z7.middlewareStack.add(e=>async t=>(Wx.isInstance(t.request)&&(t.request.hostname=window.location.hostname,t.request.port=Number(window.location.port)||443,t.request.path=`/proxy/awsgw${t.request.path}`),await e(t)),{step:`finalizeRequest`,name:`proxyRewrite`,override:!0})}return z7}function W7(){if(!B7){let e=ux();if(!e)throw Error(`AWS credentials not configured`);B7=new lMe({endpoint:fMe,region:F7,credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey},forcePathStyle:!0}),B7.middlewareStack.add(e=>async t=>(Wx.isInstance(t.request)&&t.request.path.endsWith(`/`)&&t.request.path!==`/`&&(t.request.path=t.request.path.slice(0,-1)),await e(t)),{step:`build`,name:`removeTrailingSlash`}),B7.middlewareStack.add(e=>async t=>(Wx.isInstance(t.request)&&(t.request.hostname=window.location.hostname,t.request.port=Number(window.location.port)||443,t.request.path=`/proxy/s3${t.request.path}`),await e(t)),{step:`finalizeRequest`,name:`proxyRewrite`,override:!0})}return B7}function G7(){L7=null,R7=null,z7=null,B7=null}function K7(){let e=(0,fa.c)(144),t;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(t={select:pMe},e[0]=t):t=e[0];let n=$i(t),r=fi(),i=Fe(),{isAdmin:a}=ZS(),o;e[1]!==r||e[2]!==i?(o=function(){fx(),G7(),i.clear(),r({to:`/login`})},e[1]=r,e[2]=i,e[3]=o):o=e[3];let s=o,c;e[4]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,F.jsxs)(qg,{className:`flex flex-row items-center gap-2 px-4 py-3`,children:[(0,F.jsx)(`img`,{src:`/mulga-logo.svg`,alt:`Mulga`,className:`size-6 shrink-0 dark:invert`}),(0,F.jsx)(`span`,{className:`truncate text-sm font-semibold group-data-[collapsible=icon]:hidden`,children:`Spinifex`})]}),e[4]=c):c=e[4];let l;e[5]===Symbol.for(`react.memo_cache_sentinel`)?(l=(0,F.jsx)(Qg,{children:`General`}),e[5]=l):l=e[5];let u=n===`/`,d,f;e[6]===Symbol.for(`react.memo_cache_sentinel`)?(d=(0,F.jsx)(Do,{className:`size-4`}),f=(0,F.jsx)(`span`,{children:`Dashboard`}),e[6]=d,e[7]=f):(d=e[6],f=e[7]);let p;e[8]===u?p=e[9]:(p=(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/`,children:(0,F.jsxs)(n_,{isActive:u,tooltip:`Dashboard`,children:[d,f]})})}),e[8]=u,e[9]=p);let m;e[10]!==a||e[11]!==n?(m=a&&(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/nodes`,children:(0,F.jsxs)(n_,{isActive:n.startsWith(`/nodes`),tooltip:`Nodes`,children:[(0,F.jsx)(Io,{className:`size-4`}),(0,F.jsx)(`span`,{children:`Nodes`})]})})}),e[10]=a,e[11]=n,e[12]=m):m=e[12];let h;e[13]!==p||e[14]!==m?(h=(0,F.jsxs)(Zg,{children:[l,(0,F.jsxs)($g,{children:[p,m]})]}),e[13]=p,e[14]=m,e[15]=h):h=e[15];let g;e[16]===Symbol.for(`react.memo_cache_sentinel`)?(g=(0,F.jsx)(Qg,{children:`EC2`}),e[16]=g):g=e[16];let _;e[17]===n?_=e[18]:(_=n.startsWith(`/ec2/describe-instances`)||n.startsWith(`/ec2/run-instances`),e[17]=n,e[18]=_);let v,y;e[19]===Symbol.for(`react.memo_cache_sentinel`)?(v=(0,F.jsx)(Io,{className:`size-4`}),y=(0,F.jsx)(`span`,{children:`Instances`}),e[19]=v,e[20]=y):(v=e[19],y=e[20]);let b;e[21]===_?b=e[22]:(b=(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-instances`,children:(0,F.jsxs)(n_,{isActive:_,tooltip:`Instances`,children:[v,y]})})}),e[21]=_,e[22]=b);let x;e[23]===n?x=e[24]:(x=n.startsWith(`/ec2/describe-images`),e[23]=n,e[24]=x);let S,C;e[25]===Symbol.for(`react.memo_cache_sentinel`)?(S=(0,F.jsx)(Oo,{className:`size-4`}),C=(0,F.jsx)(`span`,{children:`Images`}),e[25]=S,e[26]=C):(S=e[25],C=e[26]);let w;e[27]===x?w=e[28]:(w=(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-images`,children:(0,F.jsxs)(n_,{isActive:x,tooltip:`Images`,children:[S,C]})})}),e[27]=x,e[28]=w);let T;e[29]===n?T=e[30]:(T=n.startsWith(`/ec2/describe-key-pairs`),e[29]=n,e[30]=T);let E,ee;e[31]===Symbol.for(`react.memo_cache_sentinel`)?(E=(0,F.jsx)(ko,{className:`size-4`}),ee=(0,F.jsx)(`span`,{children:`Key Pairs`}),e[31]=E,e[32]=ee):(E=e[31],ee=e[32]);let D;e[33]===T?D=e[34]:(D=(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-key-pairs`,children:(0,F.jsxs)(n_,{isActive:T,tooltip:`Key Pairs`,children:[E,ee]})})}),e[33]=T,e[34]=D);let O;e[35]===n?O=e[36]:(O=n.startsWith(`/ec2/describe-volumes`)||n.startsWith(`/ec2/create-volume`)||n.startsWith(`/ec2/modify-volume`),e[35]=n,e[36]=O);let te,ne;e[37]===Symbol.for(`react.memo_cache_sentinel`)?(te=(0,F.jsx)(Eo,{className:`size-4`}),ne=(0,F.jsx)(`span`,{children:`Volumes`}),e[37]=te,e[38]=ne):(te=e[37],ne=e[38]);let re;e[39]===O?re=e[40]:(re=(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-volumes`,children:(0,F.jsxs)(n_,{isActive:O,tooltip:`Volumes`,children:[te,ne]})})}),e[39]=O,e[40]=re);let k;e[41]===n?k=e[42]:(k=n.startsWith(`/ec2/describe-snapshots`)||n.startsWith(`/ec2/create-snapshot`),e[41]=n,e[42]=k);let A,ie;e[43]===Symbol.for(`react.memo_cache_sentinel`)?(A=(0,F.jsx)(Co,{className:`size-4`}),ie=(0,F.jsx)(`span`,{children:`Snapshots`}),e[43]=A,e[44]=ie):(A=e[43],ie=e[44]);let j;e[45]===k?j=e[46]:(j=(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-snapshots`,children:(0,F.jsxs)(n_,{isActive:k,tooltip:`Snapshots`,children:[A,ie]})})}),e[45]=k,e[46]=j);let ae;e[47]===n?ae=e[48]:(ae=n.startsWith(`/ec2/describe-placement-groups`)||n.startsWith(`/ec2/create-placement-group`),e[47]=n,e[48]=ae);let oe,se;e[49]===Symbol.for(`react.memo_cache_sentinel`)?(oe=(0,F.jsx)(Ao,{className:`size-4`}),se=(0,F.jsx)(`span`,{children:`Placement Groups`}),e[49]=oe,e[50]=se):(oe=e[49],se=e[50]);let ce;e[51]===ae?ce=e[52]:(ce=(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-placement-groups`,children:(0,F.jsxs)(n_,{isActive:ae,tooltip:`Placement Groups`,children:[oe,se]})})}),e[51]=ae,e[52]=ce);let M;e[53]===n?M=e[54]:(M=n.startsWith(`/ec2/describe-load-balancers`)||n.startsWith(`/ec2/create-load-balancer`),e[53]=n,e[54]=M);let le,ue;e[55]===Symbol.for(`react.memo_cache_sentinel`)?(le=(0,F.jsx)(Vo,{className:`size-4`}),ue=(0,F.jsx)(`span`,{children:`Load Balancers`}),e[55]=le,e[56]=ue):(le=e[55],ue=e[56]);let N;e[57]===M?N=e[58]:(N=(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-load-balancers`,children:(0,F.jsxs)(n_,{isActive:M,tooltip:`Load Balancers`,children:[le,ue]})})}),e[57]=M,e[58]=N);let de;e[59]===n?de=e[60]:(de=n.startsWith(`/ec2/describe-target-groups`)||n.startsWith(`/ec2/create-target-group`),e[59]=n,e[60]=de);let fe,pe;e[61]===Symbol.for(`react.memo_cache_sentinel`)?(fe=(0,F.jsx)(To,{className:`size-4`}),pe=(0,F.jsx)(`span`,{children:`Target Groups`}),e[61]=fe,e[62]=pe):(fe=e[61],pe=e[62]);let me;e[63]===de?me=e[64]:(me=(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-target-groups`,children:(0,F.jsxs)(n_,{isActive:de,tooltip:`Target Groups`,children:[fe,pe]})})}),e[63]=de,e[64]=me);let he;e[65]!==b||e[66]!==w||e[67]!==D||e[68]!==re||e[69]!==j||e[70]!==ce||e[71]!==N||e[72]!==me?(he=(0,F.jsxs)(Zg,{children:[g,(0,F.jsxs)($g,{children:[b,w,D,re,j,ce,N,me]})]}),e[65]=b,e[66]=w,e[67]=D,e[68]=re,e[69]=j,e[70]=ce,e[71]=N,e[72]=me,e[73]=he):he=e[73];let ge;e[74]===Symbol.for(`react.memo_cache_sentinel`)?(ge=(0,F.jsx)(Qg,{children:`Networking`}),e[74]=ge):ge=e[74];let _e;e[75]===n?_e=e[76]:(_e=n.startsWith(`/ec2/describe-vpcs`)||n.startsWith(`/ec2/create-vpc`),e[75]=n,e[76]=_e);let ve,ye;e[77]===Symbol.for(`react.memo_cache_sentinel`)?(ve=(0,F.jsx)(Po,{className:`size-4`}),ye=(0,F.jsx)(`span`,{children:`VPCs`}),e[77]=ve,e[78]=ye):(ve=e[77],ye=e[78]);let be;e[79]===_e?be=e[80]:(be=(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-vpcs`,children:(0,F.jsxs)(n_,{isActive:_e,tooltip:`VPCs`,children:[ve,ye]})})}),e[79]=_e,e[80]=be);let xe;e[81]===n?xe=e[82]:(xe=n.startsWith(`/ec2/describe-subnets`)||n.startsWith(`/ec2/create-subnet`),e[81]=n,e[82]=xe);let Se,Ce;e[83]===Symbol.for(`react.memo_cache_sentinel`)?(Se=(0,F.jsx)(jo,{className:`size-4`}),Ce=(0,F.jsx)(`span`,{children:`Subnets`}),e[83]=Se,e[84]=Ce):(Se=e[83],Ce=e[84]);let we;e[85]===xe?we=e[86]:(we=(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-subnets`,children:(0,F.jsxs)(n_,{isActive:xe,tooltip:`Subnets`,children:[Se,Ce]})})}),e[85]=xe,e[86]=we);let Te;e[87]===n?Te=e[88]:(Te=n.startsWith(`/ec2/describe-security-groups`)||n.startsWith(`/ec2/create-security-group`),e[87]=n,e[88]=Te);let Ee,De;e[89]===Symbol.for(`react.memo_cache_sentinel`)?(Ee=(0,F.jsx)(Lo,{className:`size-4`}),De=(0,F.jsx)(`span`,{children:`Security Groups`}),e[89]=Ee,e[90]=De):(Ee=e[89],De=e[90]);let Oe;e[91]===Te?Oe=e[92]:(Oe=(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-security-groups`,children:(0,F.jsxs)(n_,{isActive:Te,tooltip:`Security Groups`,children:[Ee,De]})})}),e[91]=Te,e[92]=Oe);let ke;e[93]!==be||e[94]!==we||e[95]!==Oe?(ke=(0,F.jsxs)(Zg,{children:[ge,(0,F.jsxs)($g,{children:[be,we,Oe]})]}),e[93]=be,e[94]=we,e[95]=Oe,e[96]=ke):ke=e[96];let Ae;e[97]===Symbol.for(`react.memo_cache_sentinel`)?(Ae=(0,F.jsx)(Qg,{children:`IAM`}),e[97]=Ae):Ae=e[97];let je;e[98]===n?je=e[99]:(je=n.startsWith(`/iam/list-users`)||n.startsWith(`/iam/create-user`),e[98]=n,e[99]=je);let Me,Ne;e[100]===Symbol.for(`react.memo_cache_sentinel`)?(Me=(0,F.jsx)(Bo,{className:`size-4`}),Ne=(0,F.jsx)(`span`,{children:`Users`}),e[100]=Me,e[101]=Ne):(Me=e[100],Ne=e[101]);let P;e[102]===je?P=e[103]:(P=(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/iam/list-users`,children:(0,F.jsxs)(n_,{isActive:je,tooltip:`Users`,children:[Me,Ne]})})}),e[102]=je,e[103]=P);let Pe;e[104]===n?Pe=e[105]:(Pe=n.startsWith(`/iam/list-policies`)||n.startsWith(`/iam/create-policy`),e[104]=n,e[105]=Pe);let Ie,Le;e[106]===Symbol.for(`react.memo_cache_sentinel`)?(Ie=(0,F.jsx)(Ro,{className:`size-4`}),Le=(0,F.jsx)(`span`,{children:`Policies`}),e[106]=Ie,e[107]=Le):(Ie=e[106],Le=e[107]);let Re;e[108]===Pe?Re=e[109]:(Re=(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/iam/list-policies`,children:(0,F.jsxs)(n_,{isActive:Pe,tooltip:`Policies`,children:[Ie,Le]})})}),e[108]=Pe,e[109]=Re);let ze;e[110]!==P||e[111]!==Re?(ze=(0,F.jsxs)(Zg,{children:[Ae,(0,F.jsxs)($g,{children:[P,Re]})]}),e[110]=P,e[111]=Re,e[112]=ze):ze=e[112];let Be;e[113]===Symbol.for(`react.memo_cache_sentinel`)?(Be=(0,F.jsx)(Qg,{children:`S3`}),e[113]=Be):Be=e[113];let Ve;e[114]===n?Ve=e[115]:(Ve=n.startsWith(`/s3/ls`),e[114]=n,e[115]=Ve);let He,Ue;e[116]===Symbol.for(`react.memo_cache_sentinel`)?(He=(0,F.jsx)(Io,{className:`size-4`}),Ue=(0,F.jsx)(`span`,{children:`Buckets`}),e[116]=He,e[117]=Ue):(He=e[116],Ue=e[117]);let We;e[118]===Ve?We=e[119]:(We=(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/s3/ls`,children:(0,F.jsxs)(n_,{isActive:Ve,tooltip:`Buckets`,children:[He,Ue]})})}),e[118]=Ve,e[119]=We);let Ge;e[120]!==a||e[121]!==n?(Ge=a&&(0,F.jsx)(e_,{children:(0,F.jsx)(Oi,{to:`/s3/service-metrics`,children:(0,F.jsxs)(n_,{isActive:n.startsWith(`/s3/service-metrics`),tooltip:`Service Metrics`,children:[(0,F.jsx)(xo,{className:`size-4`}),(0,F.jsx)(`span`,{children:`Service Metrics`})]})})}),e[120]=a,e[121]=n,e[122]=Ge):Ge=e[122];let Ke;e[123]!==We||e[124]!==Ge?(Ke=(0,F.jsxs)(Zg,{children:[Be,(0,F.jsxs)($g,{children:[We,Ge]})]}),e[123]=We,e[124]=Ge,e[125]=Ke):Ke=e[125];let qe;e[126]===a?qe=e[127]:(qe=a&&(0,F.jsxs)(Zg,{children:[(0,F.jsx)(Qg,{children:`Documentation`}),(0,F.jsx)($g,{children:(0,F.jsx)(e_,{children:(0,F.jsx)(`a`,{href:`https://docs.mulgadc.com`,target:`_blank`,rel:`noopener noreferrer`,children:(0,F.jsxs)(n_,{tooltip:`Documentation`,children:[(0,F.jsx)(So,{className:`size-4`}),(0,F.jsx)(`span`,{children:`Docs`})]})})})})]}),e[126]=a,e[127]=qe);let Je;e[128]!==he||e[129]!==ke||e[130]!==ze||e[131]!==Ke||e[132]!==qe||e[133]!==h?(Je=(0,F.jsxs)(Xg,{children:[h,he,ke,ze,Ke,qe]}),e[128]=he,e[129]=ke,e[130]=ze,e[131]=Ke,e[132]=qe,e[133]=h,e[134]=Je):Je=e[134];let Ye;e[135]===Symbol.for(`react.memo_cache_sentinel`)?(Ye=(0,F.jsx)(Yg,{className:`mx-0 w-full`}),e[135]=Ye):Ye=e[135];let Xe,Ze;e[136]===Symbol.for(`react.memo_cache_sentinel`)?(Xe=(0,F.jsx)(Mo,{className:`size-4`}),Ze=(0,F.jsx)(`span`,{children:`Sign out`}),e[136]=Xe,e[137]=Ze):(Xe=e[136],Ze=e[137]);let Qe;e[138]===s?Qe=e[139]:(Qe=(0,F.jsxs)(Jg,{children:[Ye,(0,F.jsx)($g,{children:(0,F.jsx)(e_,{children:(0,F.jsxs)(n_,{onClick:s,tooltip:`Sign out`,children:[Xe,Ze]})})})]}),e[138]=s,e[139]=Qe);let $e;e[140]===Symbol.for(`react.memo_cache_sentinel`)?($e=(0,F.jsx)(Kg,{}),e[140]=$e):$e=e[140];let et;return e[141]!==Je||e[142]!==Qe?(et=(0,F.jsxs)(Wg,{collapsible:`icon`,children:[c,Je,Qe,$e]}),e[141]=Je,e[142]=Qe,e[143]=et):et=e[143],et}function pMe(e){return e.pathname}function mMe(e){let t=(0,fa.c)(18),{error:n,reset:r}=e,i=Mr(),a=Fe(),o;t[0]!==a||t[1]!==r||t[2]!==i?(o=function(){a.invalidateQueries(),r(),i.invalidate()},t[0]=a,t[1]=r,t[2]=i,t[3]=o):o=t[3];let s=o,c;t[4]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,F.jsx)(K7,{}),t[4]=c):c=t[4];let l;t[5]===Symbol.for(`react.memo_cache_sentinel`)?(l=(0,F.jsx)($S,{}),t[5]=l):l=t[5];let u,d;t[6]===Symbol.for(`react.memo_cache_sentinel`)?(u=(0,F.jsx)(`div`,{className:`flex justify-center`,children:(0,F.jsx)(wo,{className:`size-12 text-destructive`})}),d=(0,F.jsx)(`h1`,{className:`text-2xl font-semibold`,children:`Something went wrong`}),t[6]=u,t[7]=d):(u=t[6],d=t[7]);let f=n.message||`An unexpected error occurred`,p;t[8]===f?p=t[9]:(p=(0,F.jsx)(`p`,{className:`text-muted-foreground`,children:f}),t[8]=f,t[9]=p);let m;t[10]===s?m=t[11]:(m=(0,F.jsx)(pl,{onClick:s,variant:`default`,children:`Try Again`}),t[10]=s,t[11]=m);let h;t[12]===Symbol.for(`react.memo_cache_sentinel`)?(h=(0,F.jsx)(Oi,{to:`/`,children:(0,F.jsx)(pl,{variant:`outline`,children:`Go Home`})}),t[12]=h):h=t[12];let g;t[13]===m?g=t[14]:(g=(0,F.jsxs)(`div`,{className:`flex justify-center gap-2`,children:[m,h]}),t[13]=m,t[14]=g);let _;return t[15]!==g||t[16]!==p?(_=(0,F.jsxs)(F.Fragment,{children:[c,(0,F.jsxs)(`main`,{className:`flex flex-1 flex-col`,children:[l,(0,F.jsx)(`div`,{className:`flex flex-1 items-center justify-center p-6 pt-0`,children:(0,F.jsxs)(`div`,{className:`max-w-md space-y-4 text-center`,children:[u,d,p,g]})})]})]}),t[15]=g,t[16]=p,t[17]=_):_=t[17],_}var q7=Mi()({head:()=>({meta:[{title:`Mulga`}]}),component:()=>(0,F.jsxs)(F.Fragment,{children:[(0,F.jsx)(ia,{}),(0,F.jsx)(K7,{}),(0,F.jsxs)(`main`,{className:`flex flex-1 flex-col`,children:[(0,F.jsx)($S,{}),(0,F.jsx)(`div`,{className:`flex flex-1 flex-col p-8`,children:(0,F.jsx)(Wi,{})})]})]}),errorComponent:mMe,notFoundComponent:eC}),hMe=I(`/login`)({beforeLoad:()=>{if(ux())throw bn({to:`/`})},component:L(()=>vT(()=>import(`./login.js`),__vite__mapDeps([0,1,2,3,4])),`component`)}),gMe=I(`/_auth`)({beforeLoad:()=>{if(!ux())throw bn({to:`/login`})},component:L(()=>vT(()=>import(`./route.js`),[]),`component`)}),J7=Le({queryKey:[`ec2`,`availabilityZones`],queryFn:async()=>{let e=new afe({});return await V7().send(e)},staleTime:3e5}),Y7=Le({queryKey:[`ec2`,`instances`],queryFn:async()=>{let e=new h1({});return await V7().send(e)},refetchInterval:5e3}),X7=e=>Le({queryKey:[`ec2`,`instances`,e],queryFn:async()=>{let t=new h1({InstanceIds:[e]});return await V7().send(t)},refetchInterval:5e3}),Z7=Le({queryKey:[`ec2`,`instances`,`types`],queryFn:async()=>{let e=new ofe({Filters:[{Name:`capacity`,Values:[`true`]}]});return await V7().send(e)},refetchInterval:5e3}),Q7=Le({queryKey:[`ec2`,`images`],queryFn:async()=>{let e=new m1({});return await V7().send(e)}}),$7=e=>Le({queryKey:[`ec2`,`images`,e??`none`],queryFn:async()=>{if(!e)return{Images:[],$metadata:{}};let t=new m1({ImageIds:[e]});return await V7().send(t)}}),e9=Le({queryKey:[`ec2`,`keypairs`],queryFn:async()=>{let e=new g1({});return await V7().send(e)}}),t9=e=>Le({queryKey:[`ec2`,`keypairs`,e],queryFn:async()=>{let t=new g1({KeyPairIds:[e]});return await V7().send(t)}}),n9=Le({queryKey:[`ec2`,`regions`],queryFn:async()=>{let e=new sfe({});return await V7().send(e)},staleTime:3e5}),r9=Le({queryKey:[`ec2`,`subnets`],queryFn:async()=>{let e=new b1({});return await V7().send(e)}}),i9=e=>Le({queryKey:[`ec2`,`subnets`,e],queryFn:async()=>{let t=new b1({SubnetIds:[e]});return await V7().send(t)}}),a9=Le({queryKey:[`ec2`,`snapshots`],queryFn:async()=>{let e=new y1({});return await V7().send(e)},refetchInterval:5e3}),o9=e=>Le({queryKey:[`ec2`,`snapshots`,e],queryFn:async()=>{let t=new y1({SnapshotIds:[e]});return await V7().send(t)},refetchInterval:5e3}),s9=Le({queryKey:[`ec2`,`vpcs`],queryFn:async()=>{let e=new S1({});return await V7().send(e)}}),c9=e=>Le({queryKey:[`ec2`,`vpcs`,e],queryFn:async()=>{let t=new S1({VpcIds:[e]});return await V7().send(t)}}),l9=Le({queryKey:[`ec2`,`placementGroups`],queryFn:async()=>{let e=new _1({});return await V7().send(e)}}),u9=e=>Le({queryKey:[`ec2`,`placementGroups`,e],queryFn:async()=>{let t=new _1({GroupIds:[e]});return await V7().send(t)}}),d9=Le({queryKey:[`ec2`,`securityGroups`],queryFn:async()=>{let e=new v1({});return await V7().send(e)}}),f9=e=>Le({queryKey:[`ec2`,`securityGroups`,e],queryFn:async()=>{let t=new v1({GroupIds:[e]});return await V7().send(t)}}),p9=Le({queryKey:[`ec2`,`volumes`],queryFn:async()=>{let e=new x1({});return await V7().send(e)},refetchInterval:5e3}),m9=e=>Le({queryKey:[`ec2`,`volumes`,e],queryFn:async()=>{let t=new x1({VolumeIds:[e]});return await V7().send(t)},refetchInterval:5e3}),h9=Le({queryKey:[`s3`,`buckets`],queryFn:async()=>{let e=new uMe({});return await W7().send(e)}}),g9=(e,t)=>Le({queryKey:[`s3`,`buckets`,e,`objects`,t??``],queryFn:async()=>{let n=new dMe({Bucket:e,Prefix:t,Delimiter:`/`});return await W7().send(n)}}),_Me=I(`/_auth/`)({loader:async({context:e})=>{await Promise.all([e.queryClient.ensureQueryData(Y7),e.queryClient.ensureQueryData(p9),e.queryClient.ensureQueryData(s9),e.queryClient.ensureQueryData(e9),e.queryClient.ensureQueryData(h9),e.queryClient.ensureQueryData(d9)])},head:()=>({meta:[{title:`Dashboard | Mulga`}]}),component:L(()=>vT(()=>import(`./_auth.js`),__vite__mapDeps([5,6,7,8,9,10,11,12,3,13])),`component`)}),vMe=I(`/_auth/nodes`)({head:()=>({meta:[{title:`Nodes | Mulga`}]}),component:L(()=>vT(()=>import(`./nodes.js`),__vite__mapDeps([14,6,7,10,12,3,13])),`component`)}),yMe=I(`/_auth/s3/service-metrics`)({head:()=>({meta:[{title:`Service Metrics | S3 | Mulga`}]}),component:L(()=>vT(()=>import(`./service-metrics.js`),__vite__mapDeps([15,6,7,10,12,3,13])),`component`)}),bMe=I(`/_auth/s3/ls/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(h9)},head:()=>({meta:[{title:`Buckets | S3 | Mulga`}]}),component:L(()=>vT(()=>import(`./ls.js`),__vite__mapDeps([16,17,7,18,10])),`component`)}),xMe=I(`/_auth/s3/(buckets)/create-bucket`)({head:()=>({meta:[{title:`Create Bucket | S3 | Mulga`}]}),component:L(()=>vT(()=>import(`./create-bucket.js`),__vite__mapDeps([19,20,21,2,22,23,24,8,25,26,27,10,4])),`component`)}),SMe=I(`/_auth/iam/(users)/create-user`)({head:()=>({meta:[{title:`Create User | IAM | Mulga`}]}),component:L(()=>vT(()=>import(`./create-user.js`),__vite__mapDeps([28,29,21,2,22,23,24,8,25,26,27,10,4,30])),`component`)}),CMe=I(`/_auth/iam/(policies)/create-policy`)({head:()=>({meta:[{title:`Create Policy | IAM | Mulga`}]}),component:L(()=>vT(()=>import(`./create-policy.js`),__vite__mapDeps([31,29,21,2,22,23,24,8,25,26,27,10,4,32,30])),`component`)}),wMe=I(`/_auth/ec2/(vpc)/create-vpc`)({head:()=>({meta:[{title:`Create VPC | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./create-vpc.js`),__vite__mapDeps([33,34,21,35,24,8,2,22,9,23,25,26,27,10,4,36])),`component`)}),TMe=I(`/_auth/ec2/(volumes)/create-volume`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(J7)},head:()=>({meta:[{title:`Create Volume | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./create-volume.js`),__vite__mapDeps([37,34,21,35,24,8,2,17,7,22,23,25,26,27,10,4,36])),`component`)}),EMe=I(`/_auth/ec2/(target-groups)/create-target-group`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(s9)},head:()=>({meta:[{title:`Create Target Group | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./create-target-group.js`),__vite__mapDeps([38,39,21,2,17,7,22,23,24,8,25,26,40,1,35,41,42,4,27,10,43])),`component`)}),DMe=I(`/_auth/ec2/(subnet)/create-subnet`)({loader:async({context:e})=>{await Promise.all([e.queryClient.ensureQueryData(s9),e.queryClient.ensureQueryData(J7)])},head:()=>({meta:[{title:`Create Subnet | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./create-subnet.js`),__vite__mapDeps([44,34,21,35,24,8,2,17,7,22,23,25,26,27,10,4,36])),`component`)}),_9=I(`/_auth/ec2/(snapshots)/create-snapshot`)({validateSearch:e=>({volumeId:typeof e.volumeId==`string`?e.volumeId:void 0}),loader:async({context:e})=>{await e.queryClient.ensureQueryData(p9)},head:()=>({meta:[{title:`Create Snapshot | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./create-snapshot.js`),__vite__mapDeps([45,34,21,35,24,8,2,17,7,22,23,25,26,27,10,4,32,36])),`component`)}),OMe=I(`/_auth/ec2/(security-groups)/create-security-group`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(s9)},head:()=>({meta:[{title:`Create Security Group | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./create-security-group.js`),__vite__mapDeps([46,34,21,35,24,8,2,17,7,22,23,25,26,27,10,4,36])),`component`)}),kMe=I(`/_auth/ec2/(placement-groups)/create-placement-group`)({head:()=>({meta:[{title:`Create Placement Group | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./create-placement-group.js`),__vite__mapDeps([47,34,21,35,24,8,2,22,23,25,26,27,10,4,36])),`component`)}),v9=5e3,y9=Le({queryKey:[`elbv2`,`loadBalancers`],queryFn:async()=>{let e=new N2({});return await H7().send(e)},refetchInterval:e=>(e.state.data?.LoadBalancers??[]).some(e=>e.State?.Code===`provisioning`)?v9:!1}),b9=e=>Le({queryKey:[`elbv2`,`loadBalancers`,e],queryFn:async()=>{let t=new N2({LoadBalancerArns:[e]});return await H7().send(t)},refetchInterval:e=>(e.state.data?.LoadBalancers?.[0])?.State?.Code===`provisioning`?v9:!1}),x9=e=>Le({queryKey:[`elbv2`,`loadBalancers`,e,`attributes`],queryFn:async()=>{let t=new axe({LoadBalancerArn:e});return await H7().send(t)}}),S9=Le({queryKey:[`elbv2`,`targetGroups`],queryFn:async()=>{let e=new P2({});return await H7().send(e)}}),C9=e=>Le({queryKey:[`elbv2`,`targetGroups`,e],queryFn:async()=>{let t=new P2({TargetGroupArns:[e]});return await H7().send(t)}}),w9=e=>Le({queryKey:[`elbv2`,`targetGroups`,e,`attributes`],queryFn:async()=>{let t=new cxe({TargetGroupArn:e});return await H7().send(t)}}),T9=e=>Le({queryKey:[`elbv2`,`listeners`,e],queryFn:async()=>{let t=new ixe({LoadBalancerArn:e});return await H7().send(t)}}),AMe=e=>Le({queryKey:[`elbv2`,`listeners`,e,`rules`],queryFn:async()=>{let t=new oxe({ListenerArn:e});return await H7().send(t)}}),jMe=e=>Le({queryKey:[`elbv2`,`targetGroups`,e,`health`],queryFn:async()=>{let t=new lxe({TargetGroupArn:e});return await H7().send(t)}}),E9=e=>Le({queryKey:[`elbv2`,`tags`,...e],queryFn:async()=>{let t=new sxe({ResourceArns:e});return await H7().send(t)},enabled:e.length>0}),MMe=I(`/_auth/ec2/(load-balancers)/create-load-balancer`)({loader:async({context:e})=>{await Promise.all([e.queryClient.ensureQueryData(s9),e.queryClient.ensureQueryData(r9),e.queryClient.ensureQueryData(d9),e.queryClient.ensureQueryData(S9)])},head:()=>({meta:[{title:`Create Load Balancer | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./create-load-balancer.js`),__vite__mapDeps([48,39,21,35,24,8,2,17,7,22,41,23,25,26,42,40,1,4,27,10,43])),`component`)}),NMe=I(`/_auth/ec2/(key)/import-key-pair`)({head:()=>({meta:[{title:`Import Key Pair | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./import-key-pair.js`),__vite__mapDeps([49,34,21,2,22,23,24,8,25,26,27,10,4,32,36])),`component`)}),PMe=I(`/_auth/ec2/(key)/create-key-pair`)({head:()=>({meta:[{title:`Create Key Pair | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./create-key-pair.js`),__vite__mapDeps([50,34,21,51,2,22,24,52,23,8,25,26,53,27,10,4,36])),`component`)}),FMe=I(`/_auth/ec2/(instances)/run-instances`)({loader:async({context:e})=>{await Promise.all([e.queryClient.ensureQueryData(Q7),e.queryClient.ensureQueryData(e9),e.queryClient.ensureQueryData(Z7),e.queryClient.ensureQueryData(r9),e.queryClient.ensureQueryData(l9)])},head:()=>({meta:[{title:`Run Instances | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./run-instances.js`),__vite__mapDeps([54,34,21,1,35,24,8,2,17,7,22,23,25,26,10,4,36])),`component`)}),IMe=I(`/_auth/s3/ls/$bucket`)({component:L(()=>vT(()=>import(`./route2.js`),[]),`component`)}),D9=I(`/_auth/s3/ls/$bucket/`)({loader:async({context:e,params:t})=>{await e.queryClient.ensureQueryData(g9(t.bucket))},head:({params:e})=>({meta:[{title:`${e.bucket} | S3 | Mulga`}]}),component:L(()=>vT(()=>import(`./_bucket.js`),__vite__mapDeps([55,20,21,56,52,42,57,51,17,7,22,10])),`component`)}),O9=Le({queryKey:[`iam`,`users`],queryFn:async()=>{let e=new XTe({});return await U7().send(e)},staleTime:3e5}),k9=e=>Le({queryKey:[`iam`,`users`,e],queryFn:async()=>{let t=new KTe({UserName:e});return await U7().send(t)},staleTime:3e5}),A9=e=>Le({queryKey:[`iam`,`access-keys`,e],queryFn:async()=>{let t=new qTe({UserName:e});return await U7().send(t)},staleTime:3e5}),j9=Le({queryKey:[`iam`,`policies`],queryFn:async()=>{let e=new YTe({Scope:`Local`});return await U7().send(e)},staleTime:3e5}),M9=e=>Le({queryKey:[`iam`,`policies`,e],queryFn:async()=>{let t=new WTe({PolicyArn:e});return await U7().send(t)},staleTime:3e5}),N9=(e,t)=>Le({queryKey:[`iam`,`policy-versions`,e,t],queryFn:async()=>{let n=new GTe({PolicyArn:e,VersionId:t});return await U7().send(n)},staleTime:3e5}),P9=e=>Le({queryKey:[`iam`,`attached-user-policies`,e],queryFn:async()=>{let t=new JTe({UserName:e});return await U7().send(t)},staleTime:3e5}),LMe=I(`/_auth/iam/(users)/list-users/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(O9)},head:()=>({meta:[{title:`Users | IAM | Mulga`}]}),component:L(()=>vT(()=>import(`./list-users.js`),__vite__mapDeps([58,17,7,18,10])),`component`)}),RMe=I(`/_auth/iam/(policies)/list-policies/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(j9)},head:()=>({meta:[{title:`Policies | IAM | Mulga`}]}),component:L(()=>vT(()=>import(`./list-policies.js`),__vite__mapDeps([59,17,7,18,10])),`component`)}),zMe=I(`/_auth/ec2/(vpc)/describe-vpcs/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(s9)},head:()=>({meta:[{title:`VPCs | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./describe-vpcs.js`),__vite__mapDeps([60,17,7,18,10,11])),`component`)}),BMe=I(`/_auth/ec2/(volumes)/describe-volumes/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(p9)},head:()=>({meta:[{title:`Volumes | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./describe-volumes.js`),__vite__mapDeps([61,17,7,18,10,11])),`component`)}),VMe=I(`/_auth/ec2/(target-groups)/describe-target-groups/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(S9)},head:()=>({meta:[{title:`Target Groups | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./describe-target-groups.js`),__vite__mapDeps([62,6,7,17,10])),`component`)}),HMe=I(`/_auth/ec2/(subnet)/describe-subnets/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(r9)},head:()=>({meta:[{title:`Subnets | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./describe-subnets.js`),__vite__mapDeps([63,17,7,18,10,11])),`component`)}),UMe=I(`/_auth/ec2/(snapshots)/describe-snapshots/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(a9)},head:()=>({meta:[{title:`Snapshots | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./describe-snapshots.js`),__vite__mapDeps([64,17,7,18,10,11])),`component`)}),WMe=I(`/_auth/ec2/(security-groups)/describe-security-groups/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(d9)},head:()=>({meta:[{title:`Security Groups | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./describe-security-groups.js`),__vite__mapDeps([65,17,7,18,10])),`component`)}),GMe=I(`/_auth/ec2/(placement-groups)/describe-placement-groups/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(l9)},head:()=>({meta:[{title:`Placement Groups | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./describe-placement-groups.js`),__vite__mapDeps([66,17,7,18,10,11])),`component`)}),KMe=I(`/_auth/ec2/(load-balancers)/describe-load-balancers/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(y9)},head:()=>({meta:[{title:`Load Balancers | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./describe-load-balancers.js`),__vite__mapDeps([67,17,7,10,11])),`component`)}),qMe=I(`/_auth/ec2/(key)/describe-key-pairs/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(e9)},head:()=>({meta:[{title:`Key Pairs | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./describe-key-pairs.js`),__vite__mapDeps([68,17,7,18,10])),`component`)}),JMe=I(`/_auth/ec2/(instances)/describe-instances/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(Y7)},head:()=>({meta:[{title:`Instances | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./describe-instances.js`),__vite__mapDeps([69,17,7,18,10,11])),`component`)}),YMe=I(`/_auth/ec2/(images)/describe-images/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(Q7)},head:()=>({meta:[{title:`Images | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./describe-images.js`),__vite__mapDeps([70,17,7,18,10,11,71])),`component`)}),F9=I(`/_auth/s3/ls/$bucket/$`)({loader:async({context:e,params:t})=>{let n=ll(t._splat??``);await e.queryClient.ensureQueryData(g9(t.bucket,n))},head:({params:e})=>({meta:[{title:`${ul(e._splat??``,`${e.bucket}/`)} | S3 | Mulga`}]}),component:L(()=>vT(()=>import(`./_.js`),__vite__mapDeps([72,20,21,56,52,42,57,51,17,7,22])),`component`)}),I9=I(`/_auth/iam/(users)/list-users/$userName`)({loader:async({context:e,params:t})=>{await Promise.all([e.queryClient.ensureQueryData(k9(t.userName)),e.queryClient.ensureQueryData(A9(t.userName)),e.queryClient.ensureQueryData(P9(t.userName)),e.queryClient.ensureQueryData(j9)])},head:({params:e})=>({meta:[{title:`${e.userName} | IAM | Mulga`}]}),component:L(()=>vT(()=>import(`./_userName.js`),__vite__mapDeps([73,29,21,51,17,7,22,24,42,53,57,74,10,11,26])),`component`)}),L9=I(`/_auth/iam/(policies)/list-policies/$policyArn`)({loader:async({context:e,params:t})=>{let n=decodeURIComponent(t.policyArn),r=await e.queryClient.ensureQueryData(M9(n)),i=r.Policy?.DefaultVersionId;return i&&await e.queryClient.ensureQueryData(N9(n,i)),r},head:({loaderData:e})=>({meta:[{title:`${e?.Policy?.PolicyName??`Policy`} | IAM | Mulga`}]}),component:L(()=>vT(()=>import(`./_policyArn.js`),__vite__mapDeps([75,29,21,17,7,22,42,57,51,74,10])),`component`)}),R9=I(`/_auth/ec2/(vpc)/describe-vpcs/$id`)({loader:async({context:e,params:t})=>{await Promise.all([e.queryClient.ensureQueryData(c9(t.id)),e.queryClient.ensureQueryData(r9)])},head:({params:e})=>({meta:[{title:`${e.id} | VPC | Mulga`}]}),component:L(()=>vT(()=>import(`./_id12.js`),__vite__mapDeps([76,34,21,17,7,22,42,57,51,74,10,11])),`component`)}),z9=I(`/_auth/ec2/(volumes)/modify-volume/$id`)({loader:async({context:e,params:t})=>{await e.queryClient.ensureQueryData(m9(t.id))},head:({params:e})=>({meta:[{title:`Resize ${e.id} | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./_id11.js`),__vite__mapDeps([77,34,21,2,17,7,22,27,10,4,36])),`component`)}),B9=I(`/_auth/ec2/(volumes)/describe-volumes/$id`)({loader:async({context:e,params:t})=>{await Promise.all([e.queryClient.ensureQueryData(m9(t.id)),e.queryClient.ensureQueryData(Y7)])},head:({params:e})=>({meta:[{title:`${e.id} | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./_id10.js`),__vite__mapDeps([78,34,21,51,35,24,8,17,7,22,42,57,74,10,11,4])),`component`)}),V9=I(`/_auth/ec2/(target-groups)/describe-target-groups/$id`)({loader:async({context:e,params:t})=>{let n=decodeURIComponent(t.id);await Promise.all([e.queryClient.ensureQueryData(C9(n)),e.queryClient.ensureQueryData(w9(n)),e.queryClient.ensureQueryData(E9([n])),e.queryClient.ensureQueryData(Y7)])},head:({params:e})=>({meta:[{title:`${decodeURIComponent(e.id)} | Target Group | Mulga`}]}),component:L(()=>vT(()=>import(`./_id9.js`),__vite__mapDeps([79,39,21,51,80,35,24,8,4,6,7,17,22,42,57,74,10])),`component`)}),H9=I(`/_auth/ec2/(subnet)/describe-subnets/$id`)({loader:async({context:e,params:t})=>{await e.queryClient.ensureQueryData(i9(t.id))},head:({params:e})=>({meta:[{title:`${e.id} | Subnet | Mulga`}]}),component:L(()=>vT(()=>import(`./_id8.js`),__vite__mapDeps([81,34,21,17,7,22,42,57,51,74,10,11])),`component`)}),U9=I(`/_auth/ec2/(snapshots)/describe-snapshots/$id`)({loader:async({context:e,params:t})=>{await Promise.all([e.queryClient.ensureQueryData(o9(t.id)),e.queryClient.ensureQueryData(n9)])},head:({params:e})=>({meta:[{title:`${e.id} | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./_id7.js`),__vite__mapDeps([82,34,21,51,17,7,22,25,42,57,74,10,11,4])),`component`)}),W9=I(`/_auth/ec2/(security-groups)/describe-security-groups/$id`)({loader:async({context:e,params:t})=>{await e.queryClient.ensureQueryData(f9(t.id))},head:({params:e})=>({meta:[{title:`${e.id} | Security Group | Mulga`}]}),component:L(()=>vT(()=>import(`./_id6.js`),__vite__mapDeps([83,34,21,51,35,24,8,2,17,7,22,41,42,57,74,10,4,36])),`component`)}),G9=I(`/_auth/ec2/(placement-groups)/describe-placement-groups/$id`)({loader:async({context:e,params:t})=>{await Promise.all([e.queryClient.ensureQueryData(u9(t.id)),e.queryClient.ensureQueryData(Y7)])},head:({params:e})=>({meta:[{title:`${e.id} | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./_id5.js`),__vite__mapDeps([84,34,21,17,7,22,42,57,51,74,10,11])),`component`)}),K9=I(`/_auth/ec2/(load-balancers)/describe-load-balancers/$id`)({loader:async({context:e,params:t})=>{let n=decodeURIComponent(t.id);await Promise.all([e.queryClient.ensureQueryData(b9(n)),e.queryClient.ensureQueryData(T9(n)),e.queryClient.ensureQueryData(x9(n)),e.queryClient.ensureQueryData(E9([n])),e.queryClient.ensureQueryData(S9),e.queryClient.ensureQueryData(r9)])},head:({params:e})=>({meta:[{title:`${decodeURIComponent(e.id)} | Load Balancer | Mulga`}]}),component:L(()=>vT(()=>import(`./_id4.js`),__vite__mapDeps([85,39,21,51,35,24,8,80,4,2,17,7,22,42,57,74,10,11,43])),`component`)}),q9=I(`/_auth/ec2/(key)/describe-key-pairs/$id`)({loader:async({context:e,params:t})=>await e.queryClient.ensureQueryData(t9(t.id)),head:({loaderData:e})=>({meta:[{title:`${e?.KeyPairs?.[0]?.KeyName??`Key Pair`} | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./_id3.js`),__vite__mapDeps([86,34,21,17,7,22,42,57,51,74,10])),`component`)}),J9=I(`/_auth/ec2/(instances)/describe-instances/$id`)({loader:async({context:e,params:t})=>{let[n]=await Promise.all([e.queryClient.ensureQueryData(X7(t.id)),e.queryClient.ensureQueryData(Z7)]),r=n.Reservations?.[0]?.Instances?.[0]?.ImageId;return await e.queryClient.ensureQueryData($7(r)),n},head:({loaderData:e})=>({meta:[{title:`${e?.Reservations?.[0]?.Instances?.[0]?.InstanceId??`Instance`} | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./_id2.js`),__vite__mapDeps([87,34,21,51,35,24,8,6,7,17,22,42,57,74,10,11,4,32,13,88])),`component`)}),Y9=I(`/_auth/ec2/(images)/describe-images/$id`)({loader:async({context:e,params:t})=>await e.queryClient.ensureQueryData($7(t.id)),head:({loaderData:e})=>({meta:[{title:`${e?.Images?.[0]?.Name??`Image`} | EC2 | Mulga`}]}),component:L(()=>vT(()=>import(`./_id.js`),__vite__mapDeps([89,17,7,22,10,11,71,88,74])),`component`)}),XMe=hMe.update({id:`/login`,path:`/login`,getParentRoute:()=>q7}),X9=gMe.update({id:`/_auth`,getParentRoute:()=>q7}),ZMe=_Me.update({id:`/`,path:`/`,getParentRoute:()=>X9}),QMe=vMe.update({id:`/nodes`,path:`/nodes`,getParentRoute:()=>X9}),$Me=yMe.update({id:`/s3/service-metrics`,path:`/s3/service-metrics`,getParentRoute:()=>X9}),eNe=bMe.update({id:`/s3/ls/`,path:`/s3/ls/`,getParentRoute:()=>X9}),tNe=xMe.update({id:`/s3/(buckets)/create-bucket`,path:`/s3/create-bucket`,getParentRoute:()=>X9}),nNe=SMe.update({id:`/iam/(users)/create-user`,path:`/iam/create-user`,getParentRoute:()=>X9}),rNe=CMe.update({id:`/iam/(policies)/create-policy`,path:`/iam/create-policy`,getParentRoute:()=>X9}),iNe=wMe.update({id:`/ec2/(vpc)/create-vpc`,path:`/ec2/create-vpc`,getParentRoute:()=>X9}),aNe=TMe.update({id:`/ec2/(volumes)/create-volume`,path:`/ec2/create-volume`,getParentRoute:()=>X9}),oNe=EMe.update({id:`/ec2/(target-groups)/create-target-group`,path:`/ec2/create-target-group`,getParentRoute:()=>X9}),sNe=DMe.update({id:`/ec2/(subnet)/create-subnet`,path:`/ec2/create-subnet`,getParentRoute:()=>X9}),cNe=_9.update({id:`/ec2/(snapshots)/create-snapshot`,path:`/ec2/create-snapshot`,getParentRoute:()=>X9}),lNe=OMe.update({id:`/ec2/(security-groups)/create-security-group`,path:`/ec2/create-security-group`,getParentRoute:()=>X9}),uNe=kMe.update({id:`/ec2/(placement-groups)/create-placement-group`,path:`/ec2/create-placement-group`,getParentRoute:()=>X9}),dNe=MMe.update({id:`/ec2/(load-balancers)/create-load-balancer`,path:`/ec2/create-load-balancer`,getParentRoute:()=>X9}),fNe=NMe.update({id:`/ec2/(key)/import-key-pair`,path:`/ec2/import-key-pair`,getParentRoute:()=>X9}),pNe=PMe.update({id:`/ec2/(key)/create-key-pair`,path:`/ec2/create-key-pair`,getParentRoute:()=>X9}),mNe=FMe.update({id:`/ec2/(instances)/run-instances`,path:`/ec2/run-instances`,getParentRoute:()=>X9}),Z9=IMe.update({id:`/s3/ls/$bucket`,path:`/s3/ls/$bucket`,getParentRoute:()=>X9}),hNe=D9.update({id:`/`,path:`/`,getParentRoute:()=>Z9}),gNe=LMe.update({id:`/iam/(users)/list-users/`,path:`/iam/list-users/`,getParentRoute:()=>X9}),_Ne=RMe.update({id:`/iam/(policies)/list-policies/`,path:`/iam/list-policies/`,getParentRoute:()=>X9}),vNe=zMe.update({id:`/ec2/(vpc)/describe-vpcs/`,path:`/ec2/describe-vpcs/`,getParentRoute:()=>X9}),yNe=BMe.update({id:`/ec2/(volumes)/describe-volumes/`,path:`/ec2/describe-volumes/`,getParentRoute:()=>X9}),bNe=VMe.update({id:`/ec2/(target-groups)/describe-target-groups/`,path:`/ec2/describe-target-groups/`,getParentRoute:()=>X9}),xNe=HMe.update({id:`/ec2/(subnet)/describe-subnets/`,path:`/ec2/describe-subnets/`,getParentRoute:()=>X9}),SNe=UMe.update({id:`/ec2/(snapshots)/describe-snapshots/`,path:`/ec2/describe-snapshots/`,getParentRoute:()=>X9}),CNe=WMe.update({id:`/ec2/(security-groups)/describe-security-groups/`,path:`/ec2/describe-security-groups/`,getParentRoute:()=>X9}),wNe=GMe.update({id:`/ec2/(placement-groups)/describe-placement-groups/`,path:`/ec2/describe-placement-groups/`,getParentRoute:()=>X9}),TNe=KMe.update({id:`/ec2/(load-balancers)/describe-load-balancers/`,path:`/ec2/describe-load-balancers/`,getParentRoute:()=>X9}),ENe=qMe.update({id:`/ec2/(key)/describe-key-pairs/`,path:`/ec2/describe-key-pairs/`,getParentRoute:()=>X9}),DNe=JMe.update({id:`/ec2/(instances)/describe-instances/`,path:`/ec2/describe-instances/`,getParentRoute:()=>X9}),ONe=YMe.update({id:`/ec2/(images)/describe-images/`,path:`/ec2/describe-images/`,getParentRoute:()=>X9}),kNe=F9.update({id:`/$`,path:`/$`,getParentRoute:()=>Z9}),ANe=I9.update({id:`/iam/(users)/list-users/$userName`,path:`/iam/list-users/$userName`,getParentRoute:()=>X9}),jNe=L9.update({id:`/iam/(policies)/list-policies/$policyArn`,path:`/iam/list-policies/$policyArn`,getParentRoute:()=>X9}),MNe=R9.update({id:`/ec2/(vpc)/describe-vpcs/$id`,path:`/ec2/describe-vpcs/$id`,getParentRoute:()=>X9}),NNe=z9.update({id:`/ec2/(volumes)/modify-volume/$id`,path:`/ec2/modify-volume/$id`,getParentRoute:()=>X9}),PNe=B9.update({id:`/ec2/(volumes)/describe-volumes/$id`,path:`/ec2/describe-volumes/$id`,getParentRoute:()=>X9}),FNe=V9.update({id:`/ec2/(target-groups)/describe-target-groups/$id`,path:`/ec2/describe-target-groups/$id`,getParentRoute:()=>X9}),INe=H9.update({id:`/ec2/(subnet)/describe-subnets/$id`,path:`/ec2/describe-subnets/$id`,getParentRoute:()=>X9}),LNe=U9.update({id:`/ec2/(snapshots)/describe-snapshots/$id`,path:`/ec2/describe-snapshots/$id`,getParentRoute:()=>X9}),RNe=W9.update({id:`/ec2/(security-groups)/describe-security-groups/$id`,path:`/ec2/describe-security-groups/$id`,getParentRoute:()=>X9}),zNe=G9.update({id:`/ec2/(placement-groups)/describe-placement-groups/$id`,path:`/ec2/describe-placement-groups/$id`,getParentRoute:()=>X9}),BNe=K9.update({id:`/ec2/(load-balancers)/describe-load-balancers/$id`,path:`/ec2/describe-load-balancers/$id`,getParentRoute:()=>X9}),VNe=q9.update({id:`/ec2/(key)/describe-key-pairs/$id`,path:`/ec2/describe-key-pairs/$id`,getParentRoute:()=>X9}),HNe=J9.update({id:`/ec2/(instances)/describe-instances/$id`,path:`/ec2/describe-instances/$id`,getParentRoute:()=>X9}),UNe=Y9.update({id:`/ec2/(images)/describe-images/$id`,path:`/ec2/describe-images/$id`,getParentRoute:()=>X9}),WNe={AuthS3LsBucketSplatRoute:kNe,AuthS3LsBucketIndexRoute:hNe},GNe={AuthNodesRoute:QMe,AuthIndexRoute:ZMe,AuthS3ServiceMetricsRoute:$Me,AuthS3LsBucketRouteRoute:Z9._addFileChildren(WNe),AuthEc2instancesRunInstancesRoute:mNe,AuthEc2keyCreateKeyPairRoute:pNe,AuthEc2keyImportKeyPairRoute:fNe,AuthEc2loadBalancersCreateLoadBalancerRoute:dNe,AuthEc2placementGroupsCreatePlacementGroupRoute:uNe,AuthEc2securityGroupsCreateSecurityGroupRoute:lNe,AuthEc2snapshotsCreateSnapshotRoute:cNe,AuthEc2subnetCreateSubnetRoute:sNe,AuthEc2targetGroupsCreateTargetGroupRoute:oNe,AuthEc2volumesCreateVolumeRoute:aNe,AuthEc2vpcCreateVpcRoute:iNe,AuthIampoliciesCreatePolicyRoute:rNe,AuthIamusersCreateUserRoute:nNe,AuthS3bucketsCreateBucketRoute:tNe,AuthS3LsIndexRoute:eNe,AuthEc2imagesDescribeImagesIdRoute:UNe,AuthEc2instancesDescribeInstancesIdRoute:HNe,AuthEc2keyDescribeKeyPairsIdRoute:VNe,AuthEc2loadBalancersDescribeLoadBalancersIdRoute:BNe,AuthEc2placementGroupsDescribePlacementGroupsIdRoute:zNe,AuthEc2securityGroupsDescribeSecurityGroupsIdRoute:RNe,AuthEc2snapshotsDescribeSnapshotsIdRoute:LNe,AuthEc2subnetDescribeSubnetsIdRoute:INe,AuthEc2targetGroupsDescribeTargetGroupsIdRoute:FNe,AuthEc2volumesDescribeVolumesIdRoute:PNe,AuthEc2volumesModifyVolumeIdRoute:NNe,AuthEc2vpcDescribeVpcsIdRoute:MNe,AuthIampoliciesListPoliciesPolicyArnRoute:jNe,AuthIamusersListUsersUserNameRoute:ANe,AuthEc2imagesDescribeImagesIndexRoute:ONe,AuthEc2instancesDescribeInstancesIndexRoute:DNe,AuthEc2keyDescribeKeyPairsIndexRoute:ENe,AuthEc2loadBalancersDescribeLoadBalancersIndexRoute:TNe,AuthEc2placementGroupsDescribePlacementGroupsIndexRoute:wNe,AuthEc2securityGroupsDescribeSecurityGroupsIndexRoute:CNe,AuthEc2snapshotsDescribeSnapshotsIndexRoute:SNe,AuthEc2subnetDescribeSubnetsIndexRoute:xNe,AuthEc2targetGroupsDescribeTargetGroupsIndexRoute:bNe,AuthEc2volumesDescribeVolumesIndexRoute:yNe,AuthEc2vpcDescribeVpcsIndexRoute:vNe,AuthIampoliciesListPoliciesIndexRoute:_Ne,AuthIamusersListUsersIndexRoute:gNe},KNe={AuthRouteRoute:X9._addFileChildren(GNe),LoginRoute:XMe},qNe=q7._addFileChildren(KNe)._addFileTypes(),Q9=new ke({defaultOptions:{queries:{staleTime:5e3,refetchIntervalInBackground:!1}}}),JNe=Yi({routeTree:qNe,context:{queryClient:Q9},defaultPreload:`intent`,scrollRestoration:!0,defaultStructuralSharing:!0,defaultPreloadStaleTime:0}),$9=document.querySelector(`#app`);$9&&!$9.innerHTML&&da.createRoot($9).render((0,F.jsx)(P.StrictMode,{children:(0,F.jsx)(ha,{defaultTheme:`dark`,storageKey:`spinifex-ui-theme`,children:(0,F.jsx)(Ie,{client:Q9,children:(0,F.jsx)(XS,{children:(0,F.jsx)(Vg,{children:(0,F.jsx)(Qi,{router:JNe})})})})})}));export{r9 as $,Qa as $a,$u as $i,Wx as $n,fh as $r,ade as $t,w9 as A,dl as Aa,Xd as Ai,Xde as An,f as Ao,cg as Ar,DTe as At,X7 as B,gs as Ba,Md as Bi,Nw as Bn,Ih as Br,Fbe as Bt,D9 as C,bl as Ca,lf as Ci,Ude as Cn,h as Co,Mg as Cr,H4 as Ct,b9 as D,ul as Da,Zd as Di,qde as Dn,D as Do,pg as Dr,wTe as Dt,x9 as E,fl as Ea,tf as Ei,Kde as En,y as Eo,hg as Er,CTe as Et,g9 as F,cl as Fa,Bd as Fi,wD as Fn,Jh as Fr,Abe as Ft,u9 as G,Io as Ga,Cd as Gi,ZS as Gn,jh as Gr,Jbe as Gt,Y7 as H,Yo as Ha,kd as Hi,AC as Hn,Ah as Hr,Lbe as Ht,h9 as I,ws as Ia,zd as Ii,pD as In,qh as Ir,jbe as It,f9 as J,Eo as Ja,Yu as Ji,TS as Jn,zh as Jr,Zbe as Jt,l9 as K,Po as Ka,Ju as Ki,qS as Kn,Mh as Kr,Ybe as Kt,J7 as L,xs as La,Rd as Li,dD as Ln,Kh as Lr,Mbe as Lt,S9 as M,al as Ma,Gd as Mi,Qde as Mn,l as Mo,ag as Mr,kTe as Mt,jMe as N,rl as Na,Hd as Ni,HD as Nn,o as No,Xh as Nr,LTe as Nt,y9 as O,el as Oa,Jd as Oi,Jde as On,oe as Oo,dg as Or,TTe as Ot,_9 as P,ol as Pa,ef as Pi,MD as Pn,c as Po,Yh as Pr,F2 as Pt,i9 as Q,io as Qa,Wu as Qi,Kx as Qn,Hh as Qr,ide as Qt,$7 as R,Ss as Ra,Ld as Ri,uD as Rn,Lh as Rr,Nbe as Rt,O9 as S,Tl as Sa,cf as Si,Hde as Sn,_ as So,Ng as Sr,iEe as St,T9 as T,pl as Ta,af as Ti,Gde as Tn,b as To,Eg as Tr,STe as Tt,t9 as U,Ho as Ua,Ad as Ui,OC as Un,Dh as Ur,Rbe as Ut,Z7 as V,Go as Va,Fd as Vi,WC as Vn,kh as Vr,Ibe as Vt,e9 as W,Ro as Wa,Ed as Wi,EC as Wn,Rh as Wr,qbe as Wt,o9 as X,bo as Xa,qu as Xi,Qx as Xn,Fh as Xr,h1 as Xt,d9 as Y,Co as Ya,Xu as Yi,$x as Yn,Ph as Yr,C1 as Yt,a9 as Z,lo as Za,Gu as Zi,Zx as Zn,Vh as Zr,rde as Zt,P9 as _,ql as _a,Sf as _i,Cde as _n,xe as _o,Fb as _r,bje as _t,G9 as a,uu as aa,kp as ai,dde as an,Pa as ao,gx as ar,V7 as at,N9 as b,Ol as ba,vf as bi,Ede as bn,ce as bo,Q_ as br,aEe as bt,H9 as c,au as ca,pp as ci,mde as cn,Wi as co,fx as cr,W7 as ct,z9 as d,Yl as da,Vf as di,_de as dn,bn as do,Lb as dr,dje as dt,Uu as ea,ih as ei,ode as en,qa as eo,Tx as er,m9 as et,R9 as f,Xl as fa,If as fi,vde as fn,Le as fo,Mb as fr,fje as ft,A9 as g,Kl as ga,Cf as gi,Sde as gn,Te as go,Nb as gr,yje as gt,F9 as h,Gl as ha,jf as hi,xde as hn,je as ho,lre as hr,vje as ht,K9 as i,fu as ia,hm as ii,ude as in,Ia as io,_x as ir,G7 as it,C9 as j,nl as ja,Vd as ji,Zde as jn,u as jo,sg as jr,OTe as jt,E9 as k,ll as ka,Kd as ki,Yde as kn,v as ko,lg as kr,ETe as kt,V9 as l,ru as la,cp as li,hde as ln,Oi as lo,ux as lr,lje as lt,I9 as m,Jl as ma,Nf as mi,bde as mn,Ne as mo,Ab as mr,hje as mt,J9 as n,Vu as na,Vm as ni,cde as nn,Ka as no,Dx as nr,c9 as nt,W9 as o,du as oa,Sp as oi,fde as on,ya as oo,hx as or,H7 as ot,L9 as p,Zl as pa,Lf as pi,yde as pn,Fe as po,fre as pr,mje as pt,n9 as q,ko as qa,Ku as qi,US as qn,Nh as qr,Xbe as qt,q9 as r,pu as ra,jm as ri,lde as rn,La as ro,vx as rr,s9 as rt,U9 as s,cu as sa,fp as si,pde as sn,ua as so,cx as sr,U7 as st,Y9 as t,Zu as ta,Gm as ti,sde as tn,Ja as to,Ex as tr,p9 as tt,B9 as u,tu as ua,tp as ui,gde as un,fi as uo,dx as ur,uje as ut,j9 as v,Pl as va,xf as vi,wde as vn,N as vo,Tb as vr,O6 as vt,AMe as w,vl as wa,of as wi,Wde as wn,k as wo,Ag as wr,tEe as wt,k9 as x,Dl as xa,_f as xi,Vde as xn,w as xo,G_ as xr,U4 as xt,M9 as y,kl as ya,yf as yi,Tde as yn,M as yo,X_ as yr,X4 as yt,Q7 as z,bs as za,Id as zi,JE as zn,Oh as zr,Pbe as zt}; \ No newline at end of file +`),Bae={warn:console.warn},Vae=[`Sun`,`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`],aS=[`Jan`,`Feb`,`Mar`,`Apr`,`May`,`Jun`,`Jul`,`Aug`,`Sep`,`Oct`,`Nov`,`Dec`];function Hae(e){let t=e.getUTCFullYear(),n=e.getUTCMonth(),r=e.getUTCDay(),i=e.getUTCDate(),a=e.getUTCHours(),o=e.getUTCMinutes(),s=e.getUTCSeconds(),c=i<10?`0${i}`:`${i}`,l=a<10?`0${a}`:`${a}`,u=o<10?`0${o}`:`${o}`,d=s<10?`0${s}`:`${s}`;return`${Vae[r]}, ${c} ${aS[n]} ${t} ${l}:${u}:${d} GMT`}var Uae=new RegExp(/^(\d{4})-(\d{2})-(\d{2})[tT](\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?(([-+]\d{2}\:\d{2})|[zZ])$/),Wae=e=>{if(e==null)return;if(typeof e!=`string`)throw TypeError(`RFC-3339 date-times must be expressed as strings`);let t=Uae.exec(e);if(!t)throw TypeError(`Invalid RFC-3339 date-time value`);let[n,r,i,a,o,s,c,l,u]=t,d=sS(iS(uS(r)),lS(i,`month`,1,12),lS(a,`day`,1,31),{hours:o,minutes:s,seconds:c,fractionalMilliseconds:l});return u.toUpperCase()!=`Z`&&d.setTime(d.getTime()-noe(u)),d},Gae=new RegExp(/^(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d{2}) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d{1,2}):(\d{2}):(\d{2})(?:\.(\d+))? GMT$/),Kae=new RegExp(/^(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (\d{2})-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d{2}) (\d{1,2}):(\d{2}):(\d{2})(?:\.(\d+))? GMT$/),qae=new RegExp(/^(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ( [1-9]|\d{2}) (\d{1,2}):(\d{2}):(\d{2})(?:\.(\d+))? (\d{4})$/),oS=e=>{if(e==null)return;if(typeof e!=`string`)throw TypeError(`RFC-7231 date-times must be expressed as strings`);let t=Gae.exec(e);if(t){let[e,n,r,i,a,o,s,c]=t;return sS(iS(uS(i)),cS(r),lS(n,`day`,1,31),{hours:a,minutes:o,seconds:s,fractionalMilliseconds:c})}if(t=Kae.exec(e),t){let[e,n,r,i,a,o,s,c]=t;return Zae(sS(Yae(i),cS(r),lS(n,`day`,1,31),{hours:a,minutes:o,seconds:s,fractionalMilliseconds:c}))}if(t=qae.exec(e),t){let[e,n,r,i,a,o,s,c]=t;return sS(iS(uS(c)),cS(n),lS(r.trimLeft(),`day`,1,31),{hours:i,minutes:a,seconds:o,fractionalMilliseconds:s})}throw TypeError(`Invalid RFC-7231 date-time value`)},Jae=e=>{if(e==null)return;let t;if(typeof e==`number`)t=e;else if(typeof e==`string`)t=Fae(e);else if(typeof e==`object`&&e.tag===1)t=e.value;else throw TypeError(`Epoch timestamps must be expressed as floating point numbers or their string representation`);if(Number.isNaN(t)||t===1/0||t===-1/0)throw TypeError(`Epoch timestamps must be valid, non-Infinite, non-NaN numerics`);return new Date(Math.round(t*1e3))},sS=(e,t,n,r)=>{let i=t-1;return $ae(e,i,n),new Date(Date.UTC(e,i,n,lS(r.hours,`hour`,0,23),lS(r.minutes,`minute`,0,59),lS(r.seconds,`seconds`,0,60),toe(r.fractionalMilliseconds)))},Yae=e=>{let t=new Date().getUTCFullYear(),n=Math.floor(t/100)*100+iS(uS(e));return ne.getTime()-new Date().getTime()>Xae?new Date(Date.UTC(e.getUTCFullYear()-100,e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds(),e.getUTCMilliseconds())):e,cS=e=>{let t=aS.indexOf(e);if(t<0)throw TypeError(`Invalid month: ${e}`);return t+1},Qae=[31,28,31,30,31,30,31,31,30,31,30,31],$ae=(e,t,n)=>{let r=Qae[t];if(t===1&&eoe(e)&&(r=29),n>r)throw TypeError(`Invalid day for ${aS[t]} in ${e}: ${n}`)},eoe=e=>e%4==0&&(e%100!=0||e%400==0),lS=(e,t,n,r)=>{let i=Rae(uS(e));if(ir)throw TypeError(`${t} must be between ${n} and ${r}, inclusive`);return i},toe=e=>e==null?0:Iae(`0.`+e)*1e3,noe=e=>{let t=e[0],n=1;if(t==`+`)n=1;else if(t==`-`)n=-1;else throw TypeError(`Offset direction, ${t}, must be "+" or "-"`);let r=Number(e.substring(1,3)),i=Number(e.substring(4,6));return n*(r*60+i)*60*1e3},uS=e=>{let t=0;for(;te&&typeof e==`object`&&(e instanceof dS||`deserializeJSON`in e)?e:typeof e==`string`||Object.getPrototypeOf(e)===String.prototype?dS(String(e)):dS(JSON.stringify(e)),dS.fromObject=dS.from;var fS=/^-?\d*(\.\d+)?$/,pS=class e{string;type;constructor(e,t){if(this.string=e,this.type=t,!fS.test(e))throw Error(`@smithy/core/serde - NumericValue must only contain [0-9], at most one decimal point ".", and an optional negation prefix "-".`)}toString(){return this.string}static[Symbol.hasInstance](t){if(!t||typeof t!=`object`)return!1;let n=t;return e.prototype.isPrototypeOf(t)||n.type===`bigDecimal`&&fS.test(n.string)}},mS={},hS={};for(let e=0;e<256;e++){let t=e.toString(16).toLowerCase();t.length===1&&(t=`0${t}`),mS[e]=t,hS[t]=e}function roe(e){if(e.length%2!=0)throw Error(`Hex encoded strings must have an even number length`);let t=new Uint8Array(e.length/2);for(let n=0;n{if(typeof e==`string`){if(_S)return _S.encode(e).byteLength;let t=e.length;for(let n=t-1;n>=0;n--){let r=e.charCodeAt(n);r>127&&r<=2047?t++:r>2047&&r<=65535&&(t+=2),r>=56320&&r<=57343&&n--}return t}else if(typeof e.byteLength==`number`)return e.byteLength;else if(typeof e.size==`number`)return e.size;throw Error(`Body Length computation failed for ${e}`)},vS=e=>typeof e==`string`?Zx(e):ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength/Uint8Array.BYTES_PER_ELEMENT):new Uint8Array(e),aoe=e=>typeof ArrayBuffer==`function`&&e instanceof ArrayBuffer||Object.prototype.toString.call(e)===`[object ArrayBuffer]`,yS=async e=>void 0,ooe=async e=>{let t=e?.Bucket||``;if(typeof e.Bucket==`string`&&(e.Bucket=t.replace(/#/g,`%23`).replace(/\?/g,`%3F`)),doe(t)){if(e.ForcePathStyle===!0)throw Error(`Path-style addressing cannot be used with ARN buckets`)}else (!uoe(t)||t.indexOf(`.`)!==-1&&!String(e.Endpoint).startsWith(`http:`)||t.toLowerCase()!==t||t.length<3)&&(e.ForcePathStyle=!0);return e.DisableMultiRegionAccessPoints&&(e.disableMultiRegionAccessPoints=!0,e.DisableMRAP=!0),e},soe=/^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$/,coe=/(\d+\.){3}\d+/,loe=/\.\./,uoe=e=>soe.test(e)&&!coe.test(e)&&!loe.test(e),doe=e=>{let[t,n,r,,,i]=e.split(`:`),a=t===`arn`&&e.split(`:`).length>=6,o=!!(a&&n&&r&&i);if(a&&!o)throw Error(`Invalid ARN: ${e} was an invalid ARN.`);return o},foe=(e,t,n,r=!1)=>{let i=async()=>{let i;return i=r?n.clientContextParams?.[e]??n[e]??n[t]:n[e]??n[t],typeof i==`function`?i():i};return e===`credentialScope`||t===`CredentialScope`?async()=>{let e=typeof n.credentials==`function`?await n.credentials():n.credentials;return e?.credentialScope??e?.CredentialScope}:e===`accountId`||t===`AccountId`?async()=>{let e=typeof n.credentials==`function`?await n.credentials():n.credentials;return e?.accountId??e?.AccountId}:e===`endpoint`||t===`endpoint`?async()=>{if(n.isCustomEndpoint===!1)return;let e=await i();if(e&&typeof e==`object`){if(`url`in e)return e.url.href;if(`hostname`in e){let{protocol:t,hostname:n,port:r,path:i}=e;return`${t}//${n}${r?`:`+r:``}${i}`}}return e}:i};function poe(e){return async(t,n,r,i)=>{if(!r.isCustomEndpoint){let t;t=r.serviceConfiguredEndpoint?await r.serviceConfiguredEndpoint():await e(r.serviceId),t&&(r.endpoint=()=>Promise.resolve(Mx(t)),r.isCustomEndpoint=!0)}let a=await moe(t,n,r);if(typeof r.endpointProvider!=`function`)throw Error(`config.endpointProvider is not set.`);let o=r.endpointProvider(a,i);if(r.isCustomEndpoint&&r.endpoint){let e=await r.endpoint();if(e?.headers){o.headers??={};for(let[t,n]of Object.entries(e.headers))o.headers[t]=Array.isArray(n)?n:[n]}}return o}}var moe=async(e,t,n)=>{let r={},i=t?.getEndpointParameterInstructions?.()||{};for(let[t,a]of Object.entries(i))switch(a.type){case`staticContextParams`:r[t]=a.value;break;case`contextParams`:r[t]=e[a.name];break;case`clientContextParams`:case`builtInParams`:r[t]=await foe(a.name,t,n,a.type!==`builtInParams`)();break;case`operationContextParams`:r[t]=a.get(e);break;default:throw Error(`Unrecognized endpoint parameter instruction: `+JSON.stringify(a))}return Object.keys(i).length===0&&Object.assign(r,n),String(n.serviceId).toLowerCase()===`s3`&&await ooe(r),r};function hoe(e,t,n){e.__smithy_context?e.__smithy_context.features||(e.__smithy_context.features={}):e.__smithy_context={features:{}},e.__smithy_context.features[t]=n}function bS(e){let t=poe(e);return({config:e,instructions:n})=>(r,i)=>async a=>{e.isCustomEndpoint&&hoe(i,`ENDPOINT_OVERRIDE`,`N`);let o=await t(a.input,{getEndpointParameterInstructions(){return n}},{...e},i);i.endpointV2=o,i.authSchemes=o.properties?.authSchemes;let s=i.authSchemes?.[0];if(s){i.signing_region=s.signingRegion,i.signing_service=s.signingName;let e=Ex(i)?.selectedHttpAuthScheme?.httpAuthOption;e&&(e.signingProperties=Object.assign(e.signingProperties||{},{signing_region:s.signingRegion,signingRegion:s.signingRegion,signing_service:s.signingName,signingName:s.signingName,signingRegionSet:s.signingRegionSet},s.properties))}return r({...a})}}var goe={step:`serialize`,tags:[`ENDPOINT_PARAMETERS`,`ENDPOINT_V2`,`ENDPOINT`],name:`endpointV2Middleware`,override:!0,relation:`before`,toMiddleware:{name:`serializerMiddleware`,step:`serialize`,tags:[`SERIALIZER`],override:!0}.name};function _oe(e){let t=bS(e);return(e,n)=>({applyToStack:r=>{r.addRelativeTo(t({config:e,instructions:n}),goe)}})}function voe(e){return t=>{let n=t.tls??!0,{endpoint:r,useDualstackEndpoint:i,useFipsEndpoint:a}=t,o=Object.assign(t,{endpoint:r==null?void 0:async()=>Mx(await Ax(r)()),tls:n,isCustomEndpoint:!!r,useDualstackEndpoint:Ax(i??!1),useFipsEndpoint:Ax(a??!1)}),s;return o.serviceConfiguredEndpoint=async()=>(t.serviceId&&!s&&(s=e(t.serviceId)),s),o}}var yoe=class e{nodes;root;conditions;results;constructor(e,t,n,r){this.nodes=e,this.root=t,this.conditions=n,this.results=r}static from(t,n,r,i){return new e(t,n,r,i)}},boe=class{capacity;data=new Map;parameters=[];constructor({size:e,params:t}){this.capacity=e??50,t&&(this.parameters=t)}get(e,t){let n=this.hash(e);if(n===!1)return t();if(!this.data.has(n)){if(this.data.size>this.capacity+10){let e=this.data.keys(),t=0;for(;;){let{value:n,done:r}=e.next();if(this.data.delete(n),r||++t>10)break}}this.data.set(n,t())}return this.data.get(n)}size(){return this.data.size}hash(e){let t=``,{parameters:n}=this;if(n.length===0)return!1;for(let r of n){let n=String(e[r]??``);if(n.includes(`|;`))return!1;t+=n+`|;`}return t}},xS=class extends Error{constructor(e){super(e),this.name=`EndpointError`}},xoe=`endpoints`;function SS(e){return typeof e!=`object`||!e?e:`ref`in e?`$${SS(e.ref)}`:`fn`in e?`${e.fn}(${(e.argv||[]).map(SS).join(`, `)})`:JSON.stringify(e,null,2)}var CS={},Soe=(e,t)=>e===t;function Coe(...e){for(let t of e)if(t!=null)return t}var woe=e=>{let t=e.split(`.`),n=[];for(let r of t){let t=r.indexOf(`[`);if(t!==-1){if(r.indexOf(`]`)!==r.length-1)throw new xS(`Path: '${e}' does not end with ']'`);let i=r.slice(t+1,-1);if(Number.isNaN(parseInt(i)))throw new xS(`Invalid array index: '${i}' in path: '${e}'`);t!==0&&n.push(r.slice(0,t)),n.push(i)}else n.push(r)}return n},wS=(e,t)=>woe(t).reduce((n,r)=>{if(typeof n!=`object`)throw new xS(`Index '${r}' in '${t}' not found in '${JSON.stringify(e)}'`);if(Array.isArray(n)){let e=parseInt(r);return n[e<0?n.length+e:e]}return n[r]},e),Toe=e=>e!=null;function TS(e,t,n){return e?t:n}var Eoe=e=>!e,Doe=RegExp(`^(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}$`),ES=e=>Doe.test(e)||e.startsWith(`[`)&&e.endsWith(`]`),DS={[wx.HTTP]:80,[wx.HTTPS]:443},OS=e=>{let t=(()=>{try{if(e instanceof URL)return e;if(typeof e==`object`&&`hostname`in e){let{hostname:t,port:n,protocol:r=``,path:i=``,query:a={}}=e,o=new URL(`${r}//${t}${n?`:${n}`:``}${i}`);return o.search=Object.entries(a).map(([e,t])=>`${e}=${t}`).join(`&`),o}return new URL(e)}catch{return null}})();if(!t)return console.error(`Unable to parse ${JSON.stringify(e)} as a whatwg URL.`),null;let n=t.href,{host:r,hostname:i,pathname:a,protocol:o,search:s}=t;if(s)return null;let c=o.slice(0,-1);if(!Object.values(wx).includes(c))return null;let l=ES(i);return{scheme:c,authority:`${r}${n.includes(`${r}:${DS[c]}`)||typeof e==`string`&&e.includes(`${r}:${DS[c]}`)?`:${DS[c]}`:``}`,path:a,normalizedPath:a.endsWith(`/`)?a:`${a}/`,isIp:l}};function Ooe(e,t,n){if(n===1)return[e];if(e===``)return[``];let r=e.split(t);return n===0?r:r.slice(0,n-1).concat(r.slice(1).join(t))}var koe={booleanEquals:Soe,coalesce:Coe,getAttr:wS,isSet:Toe,isValidHostLabel:kx,ite:TS,not:Eoe,parseURL:OS,split:Ooe,stringEquals:(e,t)=>e===t,substring:(e,t,n,r)=>e==null||t>=n||e.lengthencodeURIComponent(e).replace(/[!*'()]/g,e=>`%${e.charCodeAt(0).toString(16).toUpperCase()}`)},kS=(e,t)=>{let n=[],{referenceRecord:r,endpointParams:i}=t,a=0;for(;at.referenceRecord[e]??t.endpointParams[e],AS=(e,t,n)=>{if(typeof e==`string`)return kS(e,n);if(e.fn)return MS.callFunction(e,n);if(e.ref)return Aoe(e,n);throw new xS(`'${t}': ${String(e)} is not a string, function or reference.`)},jS=({fn:e,argv:t},n)=>{let r=Array(t.length);for(let e=0;e{let{assign:n}=e;if(n&&n in t.referenceRecord)throw new xS(`'${n}' is already defined in Reference Record.`);let r=jS(e,t);t.logger?.debug?.(`${xoe} evaluateCondition: ${SS(e)} = ${SS(r)}`);let i=r===``?!0:!!r;return n==null?{result:i}:{result:i,toAssign:{name:n,value:r}}},PS=(e,t)=>Object.entries(e??{}).reduce((e,[n,r])=>(e[n]=r.map(e=>{let r=AS(e,`Header value entry`,t);if(typeof r!=`string`)throw new xS(`Header '${n}' value '${r}' is not a string`);return r}),e),{}),FS=(e,t)=>Object.entries(e).reduce((e,[n,r])=>(e[n]=LS.getEndpointProperty(r,t),e),{}),IS=(e,t)=>{if(Array.isArray(e))return e.map(e=>IS(e,t));switch(typeof e){case`string`:return kS(e,t);case`object`:if(e===null)throw new xS(`Unexpected endpoint property: ${e}`);return LS.getEndpointProperties(e,t);case`boolean`:return e;default:throw new xS(`Unexpected endpoint property type: ${typeof e}`)}},LS={getEndpointProperty:IS,getEndpointProperties:FS},joe=(e,t)=>{let n=AS(e,`Endpoint URL`,t);if(typeof n==`string`)try{return new URL(n)}catch(e){throw console.error(`Failed to construct URL with ${n}`,e),e}throw new xS(`Endpoint URL must be a string, got ${typeof n}`)},RS=1e8,Moe=(e,t)=>{let{nodes:n,root:r,results:i,conditions:a}=e,o=r,s={},c={referenceRecord:s,endpointParams:t.endpointParams,logger:t.logger};for(;o!==1&&o!==-1&&o=0===f.result?r:i}if(o>=RS){let e=i[o-RS];if(e[0]===-1){let[,t]=e;throw new xS(AS(t,`Error`,c))}let[t,n,r]=e;return{url:joe(t,c),properties:FS(n,c),headers:PS(r??{},c)}}throw new xS(`No matching endpoint.`)},Noe=voe(yS);bS(yS);var Poe=_oe(yS),zS=class extends Dae($x,Zx,Qx,Xx){},BS=Oae(e=>crypto.getRandomValues(e)),Foe=BS,VS=async(e=new Uint8Array,t)=>{if(e instanceof Uint8Array)return zS.mutate(e);if(!e)return zS.mutate(new Uint8Array);let n=t.streamCollector(e);return zS.mutate(await n)},Ioe=class{serdeContext;setSerdeContext(e){this.serdeContext=e}},Loe=`modulepreload`,Roe=function(e){return`/`+e},HS={},US=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}r=o(t.map(t=>{if(t=Roe(t,n),t in HS)return;HS[t]=!0;let r=t.endsWith(`.css`),i=r?`[rel="stylesheet"]`:``;if(n)for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}else if(document.querySelector(`link[href="${t}"]${i}`))return;let o=document.createElement(`link`);if(o.rel=r?`stylesheet`:Loe,r||(o.as=`script`),o.crossOrigin=``,o.href=t,a&&o.setAttribute(`nonce`,a),document.head.appendChild(o),r)return new Promise((e,n)=>{o.addEventListener(`load`,e),o.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},zoe=class extends Ioe{options;compositeErrorRegistry;constructor(e){super(),this.options=e,this.compositeErrorRegistry=Wx.for(e.defaultNamespace);for(let t of e.errorTypeRegistries??[])this.compositeErrorRegistry.copyFrom(t)}getRequestType(){return Dx}getResponseType(){return Ox}setSerdeContext(e){this.serdeContext=e,this.serializer.setSerdeContext(e),this.deserializer.setSerdeContext(e),this.getPayloadCodec()&&this.getPayloadCodec().setSerdeContext(e)}updateServiceEndpoint(e,t){if(`url`in t){e.protocol=t.url.protocol,e.hostname=t.url.hostname,e.port=t.url.port?Number(t.url.port):void 0,e.path=t.url.pathname,e.fragment=t.url.hash||void 0,e.username=t.url.username||void 0,e.password=t.url.password||void 0,e.query||={};for(let[n,r]of t.url.searchParams.entries())e.query[n]=r;if(t.headers)for(let n in t.headers)e.headers[n]=t.headers[n].join(`, `);return e}else{if(e.protocol=t.protocol,e.hostname=t.hostname,e.port=t.port?Number(t.port):void 0,e.path=t.path,e.query={...t.query},t.headers)for(let n in t.headers)e.headers[n]=t.headers[n];return e}}setHostPrefix(e,t,n){if(this.serdeContext?.disableHostPrefix)return;let r=Vx.of(t.input),i=Lx(t.traits??{});if(i.endpoint){let t=i.endpoint?.[0];if(typeof t==`string`){for(let[e,i]of r.structIterator()){if(!i.getMergedTraits().hostLabel)continue;let r=n[e];if(typeof r!=`string`)throw Error(`@smithy/core/schema - ${e} in input must be a string as hostLabel.`);t=t.replace(`{${e}}`,r)}e.hostname=t+e.hostname}}}deserializeMetadata(e){return{httpStatusCode:e.statusCode,requestId:e.headers[`x-amzn-requestid`]??e.headers[`x-amzn-request-id`]??e.headers[`x-amz-request-id`],extendedRequestId:e.headers[`x-amz-id-2`],cfId:e.headers[`x-amz-cf-id`]}}async serializeEventStream({eventStream:e,requestSchema:t,initialRequest:n}){return(await this.loadEventStreamCapability()).serializeEventStream({eventStream:e,requestSchema:t,initialRequest:n})}async deserializeEventStream({response:e,responseSchema:t,initialResponseContainer:n}){return(await this.loadEventStreamCapability()).deserializeEventStream({response:e,responseSchema:t,initialResponseContainer:n})}async loadEventStreamCapability(){let{EventStreamSerde:e}=await US(async()=>{let{EventStreamSerde:e}=await import(`./index.browser.js`);return{EventStreamSerde:e}},[]);return new e({marshaller:this.getEventStreamMarshaller(),serializer:this.serializer,deserializer:this.deserializer,serdeContext:this.serdeContext,defaultContentType:this.getDefaultContentType()})}getDefaultContentType(){throw Error(`@smithy/core/protocols - ${this.constructor.name} getDefaultContentType() implementation missing.`)}async deserializeHttpMessage(e,t,n,r,i){return[]}getEventStreamMarshaller(){let e=this.serdeContext;if(!e.eventStreamMarshaller)throw Error(`@smithy/core - HttpProtocol: eventStreamMarshaller missing in serdeContext.`);return e.eventStreamMarshaller}},Boe=class extends zoe{async serializeRequest(e,t,n){let r=this.serializer,i={},a={},o=await n.endpoint(),s=Vx.of(e?.input),c=s.getSchema(),l,u=t&&typeof t==`object`?t:{},d=new Dx({protocol:``,hostname:``,port:void 0,path:`/`,fragment:void 0,query:i,headers:a,body:void 0});if(o&&(this.updateServiceEndpoint(d,o),this.setHostPrefix(d,e,u)),u){let e=s.getEventStreamMember();if(e){if(u[e]){let t={};for(let[n,i]of s.structIterator())n!==e&&u[n]&&(r.write(i,u[n]),t[n]=r.flush());l=await this.serializeEventStream({eventStream:u[e],requestSchema:s,initialRequest:t})}}else r.write(c,u),l=r.flush()}return d.headers=Object.assign(d.headers,a),d.query=i,d.body=l,d.method=`POST`,d}async deserializeResponse(e,t,n){let r=this.deserializer,i=Vx.of(e.output),a={};if(n.statusCode>=300){let i=await VS(n.body,t);throw i.byteLength>0&&Object.assign(a,await r.read(15,i)),await this.handleError(e,t,n,a,this.deserializeMetadata(n)),Error(`@smithy/core/protocols - RPC Protocol error handler failed to throw.`)}for(let e in n.headers){let t=n.headers[e];delete n.headers[e],n.headers[e.toLowerCase()]=t}let o=i.getEventStreamMember();if(o)a[o]=await this.deserializeEventStream({response:n,responseSchema:i,initialResponseContainer:a});else{let e=await VS(n.body,t);e.byteLength>0&&Object.assign(a,await r.read(i,e))}return a.$metadata=this.deserializeMetadata(n),a}};function WS(e,t){if(t.timestampFormat.useTrait&&e.isTimestampSchema()&&(e.getSchema()===5||e.getSchema()===6||e.getSchema()===7))return e.getSchema();let{httpLabel:n,httpPrefixHeaders:r,httpHeader:i,httpQuery:a}=e.getMergedTraits();return(t.httpBindings?typeof r==`string`||i?6:a||n?5:void 0:void 0)??t.timestampFormat.default}var Voe=e=>({setHttpHandler(t){e.httpHandler=t},httpHandler(){return e.httpHandler},updateHttpClientConfig(t,n){e.httpHandler?.updateHttpClientConfig(t,n)},httpHandlerConfigs(){return e.httpHandler.httpHandlerConfigs()}}),Hoe=e=>({httpHandler:e.httpHandler()}),GS=`content-length`;function Uoe(e){return t=>async n=>{let r=n.request;if(Dx.isInstance(r)){let{body:t,headers:n}=r;if(t&&Object.keys(n).map(e=>e.toLowerCase()).indexOf(GS)===-1)try{let n=e(t);r.headers={...r.headers,[GS]:String(n)}}catch{}}return t({...n,request:r})}}var Woe={step:`build`,tags:[`SET_CONTENT_LENGTH`,`CONTENT_LENGTH`],name:`contentLengthMiddleware`,override:!0},Goe=e=>({applyToStack:t=>{t.add(Uoe(e.bodyLengthChecker),Woe)}}),KS=e=>encodeURIComponent(e).replace(/[!'()*]/g,Koe),Koe=e=>`%${e.charCodeAt(0).toString(16).toUpperCase()}`;function qoe(e){let t=[];for(let n of Object.keys(e).sort()){let r=e[n];if(n=KS(n),Array.isArray(r))for(let e=0,i=r.length;ee?.$retryable!==void 0,$S=e=>e.$metadata?.clockSkewCorrected,eC=e=>{let t=new Set([`Failed to fetch`,`NetworkError when attempting to fetch resource`,`The Internet connection appears to be offline`,`Load failed`,`Network request failed`]);return e&&e instanceof TypeError?t.has(e.message):!1},tC=e=>e.$metadata?.httpStatusCode===429||qS.includes(e.name)||e.$retryable?.throttling==1,nC=(e,t=0)=>QS(e)||$S(e)||e.name===`InvalidSignatureException`&&e.message?.includes(`Signature expired`)||JS.includes(e.name)||XS.includes(e?.code||``)||ZS.includes(e?.code||``)||YS.includes(e.$metadata?.httpStatusCode||0)||eC(e)||iC(e)||e.cause!==void 0&&t<=10&&nC(e.cause,t+1),rC=e=>{if(e.$metadata?.httpStatusCode!==void 0){let t=e.$metadata.httpStatusCode;return 500<=t&&t<=599&&!nC(e)}return!1};function iC(e){return e.code===`ERR_HTTP2_STREAM_ERROR`&&e.message.includes(`NGHTTP2_REFUSED_STREAM`)}var aC=20*1e3,oC=`amz-sdk-invocation-id`,sC=`amz-sdk-request`;function cC(e,t){if(Ox.isInstance(e))for(let n of Object.keys(e.headers)){let r=n.toLowerCase();if(r===`retry-after`){let r=e.headers[n],i=NaN;if(r.endsWith(`GMT`))try{i=(oS(r).getTime()-Date.now())/1e3}catch(e){t?.trace?.(`Failed to parse retry-after header`),t?.trace?.(e)}else r.match(/ GMT, ((\d+)|(\d+\.\d+))$/)?i=Number(r.match(/ GMT, ([\d.]+)$/)?.[1]):r.match(/^((\d+)|(\d+\.\d+))$/)?i=Number(r):Date.parse(r)>=Date.now()&&(i=(Date.parse(r)-Date.now())/1e3);return isNaN(i)?void 0:new Date(Date.now()+i*1e3)}else if(r===`x-amz-retry-after`){let r=e.headers[n],i=Number(r);if(isNaN(i)){t?.trace?.(`Failed to parse x-amz-retry-after=${r}`);return}return new Date(Date.now()+i)}}}var lC=e=>e instanceof Error?e:e instanceof Object?Object.assign(Error(),e):Error(typeof e==`string`?e:`AWS SDK error wrapper for ${e}`);function uC(e){return t=>(n,r)=>async i=>{let a=await t.retryStrategy(),o=await t.maxAttempts();if(fC(a)){a=a;let s=await a.acquireInitialRetryToken((r.partition_id??``)+(r.__retryLongPoll?`:longpoll`:``)),c=Error(),l=0,u=0,{request:d}=i,f=Dx.isInstance(d);for(f&&(d.headers[oC]=BS());;)try{f&&(d.headers[sC]=`attempt=${l+1}; max=${o}`);let{response:e,output:t}=await n(i);return a.recordSuccess(s),t.$metadata.attempts=l+1,t.$metadata.totalRetryDelay=u,{response:e,output:t}}catch(n){let i=pC(n,t.logger);if(c=lC(n),f&&e(d))throw(r.logger instanceof qx?console:r.logger)?.warn(`An error was encountered in a non-retryable streaming request.`),c;try{s=await a.refreshRetryTokenForRetry(s,i)}catch(e){throw typeof e.$backoff==`number`&&await dC(e.$backoff),c.$metadata||={},c.$metadata.attempts=l+1,c.$metadata.totalRetryDelay=u,c}l=s.getRetryCount();let o=s.getRetryDelay();u+=o,await dC(o)}}else return a=a,a?.mode&&(r.userAgent=[...r.userAgent||[],[`cfg/retry-mode`,a.mode]]),a.retry(n,i)}}var dC=e=>new Promise(t=>setTimeout(t,e)),fC=e=>e.acquireInitialRetryToken!==void 0&&e.refreshRetryTokenForRetry!==void 0&&e.recordSuccess!==void 0,pC=(e,t)=>{let n={error:e,errorType:mC(e)},r=cC(e.$response,t);return r&&(n.retryAfterHint=r),n},mC=e=>tC(e)?`THROTTLING`:nC(e)?`TRANSIENT`:rC(e)?`SERVER_ERROR`:`CLIENT_ERROR`,hC={name:`retryMiddleware`,tags:[`RETRY`],step:`finalizeRequest`,priority:`high`,override:!0};function gC(e){let t=uC(e);return e=>({applyToStack:n=>{n.add(t(e),hC)}})}var _C=class e{static setTimeoutFn=setTimeout;beta;minCapacity;minFillRate;scaleConstant;smooth;enabled=!1;availableTokens=0;lastMaxRate=0;measuredTxRate=0;requestCount=0;fillRate;lastThrottleTime;lastTimestamp=0;lastTxRateBucket;maxCapacity;timeWindow=0;constructor(e){this.beta=e?.beta??.7,this.minCapacity=e?.minCapacity??1,this.minFillRate=e?.minFillRate??.5,this.scaleConstant=e?.scaleConstant??.4,this.smooth=e?.smooth??.8,this.lastThrottleTime=this.getCurrentTimeInSeconds(),this.lastTxRateBucket=Math.floor(this.getCurrentTimeInSeconds()),this.fillRate=this.minFillRate,this.maxCapacity=this.minCapacity}async getSendToken(){return this.acquireTokenBucket(1)}updateClientSendingRate(e){let t;this.updateMeasuredRate();let n=e;if(n?.errorType===`THROTTLING`||tC(n?.error??e)){let e=this.enabled?Math.min(this.measuredTxRate,this.fillRate):this.measuredTxRate;this.lastMaxRate=e,this.calculateTimeWindow(),this.lastThrottleTime=this.getCurrentTimeInSeconds(),t=this.cubicThrottle(e),this.enableTokenBucket()}else this.calculateTimeWindow(),t=this.cubicSuccess(this.getCurrentTimeInSeconds());let r=Math.min(t,2*this.measuredTxRate);this.updateTokenBucketRate(r)}getCurrentTimeInSeconds(){return Date.now()/1e3}async acquireTokenBucket(t){if(this.enabled){for(this.refillTokenBucket();t>this.availableTokens;){let n=(t-this.availableTokens)/this.fillRate*1e3;await new Promise(t=>e.setTimeoutFn(t,n)),this.refillTokenBucket()}this.availableTokens-=t}}refillTokenBucket(){let e=this.getCurrentTimeInSeconds();if(!this.lastTimestamp){this.lastTimestamp=e;return}let t=(e-this.lastTimestamp)*this.fillRate;this.availableTokens=Math.min(this.maxCapacity,this.availableTokens+t),this.lastTimestamp=e}calculateTimeWindow(){this.timeWindow=this.getPrecise((this.lastMaxRate*(1-this.beta)/this.scaleConstant)**(1/3))}cubicThrottle(e){return this.getPrecise(e*this.beta)}cubicSuccess(e){return this.getPrecise(this.scaleConstant*(e-this.lastThrottleTime-this.timeWindow)**3+this.lastMaxRate)}enableTokenBucket(){this.enabled=!0}updateTokenBucketRate(e){this.refillTokenBucket(),this.fillRate=Math.max(e,this.minFillRate),this.maxCapacity=Math.max(e,this.minCapacity),this.availableTokens=Math.min(this.availableTokens,this.maxCapacity)}updateMeasuredRate(){let e=this.getCurrentTimeInSeconds(),t=Math.floor(e*2)/2;if(this.requestCount++,t>this.lastTxRateBucket){let e=this.requestCount/(t-this.lastTxRateBucket);this.measuredTxRate=this.getPrecise(e*this.smooth+this.measuredTxRate*(1-this.smooth)),this.requestCount=0,this.lastTxRateBucket=t}}getPrecise(e){return parseFloat(e.toFixed(8))}},vC=class e{static v2026=typeof process<`u`&&{}?.SMITHY_NEW_RETRIES_2026===`true`;static delay(){return e.v2026?50:100}static throttlingDelay(){return e.v2026?1e3:500}static cost(){return e.v2026?14:5}static throttlingCost(){return e.v2026?5:10}static modifiedCostType(){return e.v2026?`THROTTLING`:`TRANSIENT`}},Joe=class{x=vC.delay();computeNextBackoffDelay(e){let t=Math.random()*Math.min(this.x*2**e,aC);return Math.floor(t)}setDelayBase(e){this.x=e}},yC=class{delay;count;cost;longPoll;constructor(e,t,n,r){this.delay=e,this.count=t,this.cost=n,this.longPoll=r}getRetryCount(){return this.count}getRetryDelay(){return Math.min(aC,this.delay)}getRetryCost(){return this.cost}isLongPoll(){return this.longPoll}},bC;(function(e){e.STANDARD=`standard`,e.ADAPTIVE=`adaptive`})(bC||={});var Yoe=bC.STANDARD,xC={incompatible:1,attempts:2,capacity:3},SC=class{mode=bC.STANDARD;capacity=500;retryBackoffStrategy;maxAttemptsProvider;baseDelay;constructor(e){typeof e==`number`?this.maxAttemptsProvider=async()=>e:typeof e==`function`?this.maxAttemptsProvider=e:e&&typeof e==`object`&&(this.maxAttemptsProvider=async()=>e.maxAttempts,this.baseDelay=e.baseDelay,this.retryBackoffStrategy=e.backoff),this.maxAttemptsProvider??=async()=>3,this.baseDelay??=vC.delay(),this.retryBackoffStrategy??=new Joe}async acquireInitialRetryToken(e){return new yC(vC.delay(),0,void 0,vC.v2026&&e.includes(`:longpoll`))}async refreshRetryTokenForRetry(e,t){let n=await this.getMaxAttempts(),r=this.retryCode(e,t,n),i=r===0,a=e.isLongPoll?.();if(i||a){let n=t.errorType;this.retryBackoffStrategy.setDelayBase(n===`THROTTLING`?vC.throttlingDelay():this.baseDelay);let o=this.retryBackoffStrategy.computeNextBackoffDelay(e.getRetryCount()),s=o;if(t.retryAfterHint instanceof Date&&(s=Math.max(o,Math.min(t.retryAfterHint.getTime()-Date.now(),o+5e3))),i){let t=this.getCapacityCost(n);return this.capacity-=t,new yC(s,e.getRetryCount()+1,t,e.isLongPoll?.()??!1)}else throw Object.assign(Error(`No retry token available`),{$backoff:vC.v2026&&r===xC.capacity&&a?s:0})}throw Error(`No retry token available`)}recordSuccess(e){this.capacity=Math.min(500,this.capacity+(e.getRetryCost()??1))}getCapacity(){return this.capacity}async maxAttempts(){return this.maxAttemptsProvider()}async getMaxAttempts(){try{return await this.maxAttemptsProvider()}catch{return console.warn(`Max attempts provider could not resolve. Using default of 3`),3}}retryCode(e,t,n){let r=e.getRetryCount()+1,i=this.isRetryableError(t.errorType)?0:xC.incompatible,a=r=this.getCapacityCost(t.errorType)?0:xC.capacity;return i||a||o}getCapacityCost(e){return e===vC.modifiedCostType()?vC.throttlingCost():vC.cost()}isRetryableError(e){return e===`THROTTLING`||e===`TRANSIENT`}},Xoe=class{mode=bC.ADAPTIVE;rateLimiter;standardRetryStrategy;constructor(e,t){let{rateLimiter:n}=t??{};this.rateLimiter=n??new _C,this.standardRetryStrategy=t?new SC({maxAttempts:typeof e==`number`?e:3,...t}):new SC(e)}async acquireInitialRetryToken(e){let t=await this.standardRetryStrategy.acquireInitialRetryToken(e);return await this.rateLimiter.getSendToken(),t}async refreshRetryTokenForRetry(e,t){this.rateLimiter.updateClientSendingRate(t);let n=await this.standardRetryStrategy.refreshRetryTokenForRetry(e,t);return await this.rateLimiter.getSendToken(),n}recordSuccess(e){this.rateLimiter.updateClientSendingRate({}),this.standardRetryStrategy.recordSuccess(e)}async maxAttemptsProvider(){return this.standardRetryStrategy.maxAttempts()}},Zoe=e=>{let{retryStrategy:t,retryMode:n}=e,r=Ax(e.maxAttempts??3),i=t?Promise.resolve(t):void 0,a=async()=>await Ax(n)()===bC.ADAPTIVE?new Xoe(r):new SC(r);return Object.assign(e,{maxAttempts:r,retryStrategy:()=>i??=a()})},Qoe=gC(aae);vC.v2026||=typeof process==`object`&&{}?.AWS_NEW_RETRIES_2026===`true`;function CC(e,t,n){e.__aws_sdk_context?e.__aws_sdk_context.features||(e.__aws_sdk_context.features={}):e.__aws_sdk_context={features:{}},e.__aws_sdk_context.features[t]=n}function $oe(e){return e}var ese=e=>t=>async n=>{if(!Dx.isInstance(n.request))return t(n);let{request:r}=n,{handlerProtocol:i=``}=e.requestHandler.metadata||{};if(i.indexOf(`h2`)>=0&&!r.headers[`:authority`])delete r.headers.host,r.headers[`:authority`]=r.hostname+(r.port?`:`+r.port:``);else if(!r.headers.host){let e=r.hostname;r.port!=null&&(e+=`:${r.port}`),r.headers.host=e}return t(n)},tse={name:`hostHeaderMiddleware`,step:`build`,priority:`low`,tags:[`HOST`],override:!0},nse=e=>({applyToStack:t=>{t.add(ese(e),tse)}}),rse=()=>(e,t)=>async n=>{try{let r=await e(n),{clientName:i,commandName:a,logger:o,dynamoDbDocumentClientOptions:s={}}=t,{overrideInputFilterSensitiveLog:c,overrideOutputFilterSensitiveLog:l}=s,u=c??t.inputFilterSensitiveLog,d=l??t.outputFilterSensitiveLog,{$metadata:f,...p}=r.output;return o?.info?.({clientName:i,commandName:a,input:u(n.input),output:d(p),metadata:f}),r}catch(e){let{clientName:r,commandName:i,logger:a,dynamoDbDocumentClientOptions:o={}}=t,{overrideInputFilterSensitiveLog:s}=o,c=s??t.inputFilterSensitiveLog;throw a?.error?.({clientName:r,commandName:i,input:c(n.input),error:e,metadata:e.$metadata}),e}},ise={name:`loggerMiddleware`,tags:[`LOGGER`],step:`initialize`,override:!0},ase=e=>({applyToStack:e=>{e.add(rse(),ise)}}),ose=e=>({applyToStack:e=>{}}),sse=(e,t)=>{if(!t||t.length===0)return e;let n=[];for(let r of t)for(let t of e)t.schemeId.split(`#`)[1]===r&&n.push(t);for(let t of e)n.find(({schemeId:e})=>e===t.schemeId)||n.push(t);return n};function cse(e){let t=new Map;for(let n of e)t.set(n.schemeId,n);return t}var lse=(e,t)=>(n,r)=>async i=>{let a=sse(e.httpAuthSchemeProvider(await t.httpAuthSchemeParametersProvider(e,r,i.input)),e.authSchemePreference?await e.authSchemePreference():[]),o=cse(e.httpAuthSchemes),s=Ex(r),c=[];for(let n of a){let i=o.get(n.schemeId);if(!i){c.push(`HttpAuthScheme \`${n.schemeId}\` was not enabled for this service.`);continue}let a=i.identityProvider(await t.identityProviderConfigProvider(e));if(!a){c.push(`HttpAuthScheme \`${n.schemeId}\` did not have an IdentityProvider configured.`);continue}let{identityProperties:l={},signingProperties:u={}}=n.propertiesExtractor?.(e,r)||{};n.identityProperties=Object.assign(n.identityProperties||{},l),n.signingProperties=Object.assign(n.signingProperties||{},u),s.selectedHttpAuthScheme={httpAuthOption:n,identity:await a(n.identityProperties),signer:i.signer};break}if(!s.selectedHttpAuthScheme)throw Error(c.join(` +`));return n(i)},use={step:`serialize`,tags:[`HTTP_AUTH_SCHEME`],name:`httpAuthSchemeMiddleware`,override:!0,relation:`before`,toMiddleware:`endpointV2Middleware`},dse=(e,{httpAuthSchemeParametersProvider:t,identityProviderConfigProvider:n})=>({applyToStack:r=>{r.addRelativeTo(lse(e,{httpAuthSchemeParametersProvider:t,identityProviderConfigProvider:n}),use)}}),fse=e=>e=>{throw e},pse=(e,t)=>{},mse=e=>(e,t)=>async n=>{if(!Dx.isInstance(n.request))return e(n);let r=Ex(t).selectedHttpAuthScheme;if(!r)throw Error(`No HttpAuthScheme was selected: unable to sign request`);let{httpAuthOption:{signingProperties:i={}},identity:a,signer:o}=r,s=await e({...n,request:await o.sign(n.request,a,i)}).catch((o.errorHandler||fse)(i));return(o.successHandler||pse)(s.response,i),s},hse={step:`finalizeRequest`,tags:[`HTTP_SIGNING`],name:`httpSigningMiddleware`,aliases:[`apiKeyMiddleware`,`tokenMiddleware`,`awsAuthMiddleware`],override:!0,relation:`after`,toMiddleware:`retryMiddleware`},gse=e=>({applyToStack:t=>{t.addRelativeTo(mse(e),hse)}}),wC=e=>{if(typeof e==`function`)return e;let t=Promise.resolve(e);return()=>t},_se=class{authSchemes=new Map;constructor(e){for(let t in e){let n=e[t];n!==void 0&&this.authSchemes.set(t,n)}}getIdentityProvider(e){return this.authSchemes.get(e)}},vse=(e=>function(t){return TC(t)&&t.expiration.getTime()-Date.now()e.expiration!==void 0,yse=(e,t,n)=>{if(e===void 0)return;let r=typeof e==`function`?e:async()=>Promise.resolve(e),i,a,o,s=!1,c=async e=>{a||=r(e);try{i=await a,o=!0,s=!1}finally{a=void 0}return i};return t===void 0?async e=>((!o||e?.forceRefresh)&&(i=await c(e)),i):async e=>((!o||e?.forceRefresh)&&(i=await c(e)),s?i:n(i)?(t(i)&&await c(e),i):(s=!0,i))};function bse(e){return e===void 0?!0:typeof e==`string`&&e.length<=50}function xse(e){let t=wC(e.userAgentAppId??void 0),{customUserAgent:n}=e;return Object.assign(e,{customUserAgent:typeof n==`string`?[[n]]:n,userAgentAppId:async()=>{let n=await t();if(!bse(n)){let t=e.logger?.constructor?.name===`NoOpLogger`||!e.logger?console:e.logger;typeof n==`string`?n.length>50&&t?.warn(`The provided userAgentAppId exceeds the maximum length of 50 characters.`):t?.warn(`userAgentAppId must be a string or undefined.`)}return n}})}var Sse={partitions:[{id:`aws`,outputs:{dnsSuffix:`amazonaws.com`,dualStackDnsSuffix:`api.aws`,implicitGlobalRegion:`us-east-1`,name:`aws`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^(us|eu|ap|sa|ca|me|af|il|mx)\\-\\w+\\-\\d+$`,regions:{"af-south-1":{description:`Africa (Cape Town)`},"ap-east-1":{description:`Asia Pacific (Hong Kong)`},"ap-east-2":{description:`Asia Pacific (Taipei)`},"ap-northeast-1":{description:`Asia Pacific (Tokyo)`},"ap-northeast-2":{description:`Asia Pacific (Seoul)`},"ap-northeast-3":{description:`Asia Pacific (Osaka)`},"ap-south-1":{description:`Asia Pacific (Mumbai)`},"ap-south-2":{description:`Asia Pacific (Hyderabad)`},"ap-southeast-1":{description:`Asia Pacific (Singapore)`},"ap-southeast-2":{description:`Asia Pacific (Sydney)`},"ap-southeast-3":{description:`Asia Pacific (Jakarta)`},"ap-southeast-4":{description:`Asia Pacific (Melbourne)`},"ap-southeast-5":{description:`Asia Pacific (Malaysia)`},"ap-southeast-6":{description:`Asia Pacific (New Zealand)`},"ap-southeast-7":{description:`Asia Pacific (Thailand)`},"aws-global":{description:`aws global region`},"ca-central-1":{description:`Canada (Central)`},"ca-west-1":{description:`Canada West (Calgary)`},"eu-central-1":{description:`Europe (Frankfurt)`},"eu-central-2":{description:`Europe (Zurich)`},"eu-north-1":{description:`Europe (Stockholm)`},"eu-south-1":{description:`Europe (Milan)`},"eu-south-2":{description:`Europe (Spain)`},"eu-west-1":{description:`Europe (Ireland)`},"eu-west-2":{description:`Europe (London)`},"eu-west-3":{description:`Europe (Paris)`},"il-central-1":{description:`Israel (Tel Aviv)`},"me-central-1":{description:`Middle East (UAE)`},"me-south-1":{description:`Middle East (Bahrain)`},"mx-central-1":{description:`Mexico (Central)`},"sa-east-1":{description:`South America (Sao Paulo)`},"us-east-1":{description:`US East (N. Virginia)`},"us-east-2":{description:`US East (Ohio)`},"us-west-1":{description:`US West (N. California)`},"us-west-2":{description:`US West (Oregon)`}}},{id:`aws-cn`,outputs:{dnsSuffix:`amazonaws.com.cn`,dualStackDnsSuffix:`api.amazonwebservices.com.cn`,implicitGlobalRegion:`cn-northwest-1`,name:`aws-cn`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^cn\\-\\w+\\-\\d+$`,regions:{"aws-cn-global":{description:`aws-cn global region`},"cn-north-1":{description:`China (Beijing)`},"cn-northwest-1":{description:`China (Ningxia)`}}},{id:`aws-eusc`,outputs:{dnsSuffix:`amazonaws.eu`,dualStackDnsSuffix:`api.amazonwebservices.eu`,implicitGlobalRegion:`eusc-de-east-1`,name:`aws-eusc`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^eusc\\-(de)\\-\\w+\\-\\d+$`,regions:{"eusc-de-east-1":{description:`AWS European Sovereign Cloud (Germany)`}}},{id:`aws-iso`,outputs:{dnsSuffix:`c2s.ic.gov`,dualStackDnsSuffix:`api.aws.ic.gov`,implicitGlobalRegion:`us-iso-east-1`,name:`aws-iso`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^us\\-iso\\-\\w+\\-\\d+$`,regions:{"aws-iso-global":{description:`aws-iso global region`},"us-iso-east-1":{description:`US ISO East`},"us-iso-west-1":{description:`US ISO WEST`}}},{id:`aws-iso-b`,outputs:{dnsSuffix:`sc2s.sgov.gov`,dualStackDnsSuffix:`api.aws.scloud`,implicitGlobalRegion:`us-isob-east-1`,name:`aws-iso-b`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^us\\-isob\\-\\w+\\-\\d+$`,regions:{"aws-iso-b-global":{description:`aws-iso-b global region`},"us-isob-east-1":{description:`US ISOB East (Ohio)`},"us-isob-west-1":{description:`US ISOB West`}}},{id:`aws-iso-e`,outputs:{dnsSuffix:`cloud.adc-e.uk`,dualStackDnsSuffix:`api.cloud-aws.adc-e.uk`,implicitGlobalRegion:`eu-isoe-west-1`,name:`aws-iso-e`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^eu\\-isoe\\-\\w+\\-\\d+$`,regions:{"aws-iso-e-global":{description:`aws-iso-e global region`},"eu-isoe-west-1":{description:`EU ISOE West`}}},{id:`aws-iso-f`,outputs:{dnsSuffix:`csp.hci.ic.gov`,dualStackDnsSuffix:`api.aws.hci.ic.gov`,implicitGlobalRegion:`us-isof-south-1`,name:`aws-iso-f`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^us\\-isof\\-\\w+\\-\\d+$`,regions:{"aws-iso-f-global":{description:`aws-iso-f global region`},"us-isof-east-1":{description:`US ISOF EAST`},"us-isof-south-1":{description:`US ISOF SOUTH`}}},{id:`aws-us-gov`,outputs:{dnsSuffix:`amazonaws.com`,dualStackDnsSuffix:`api.aws`,implicitGlobalRegion:`us-gov-west-1`,name:`aws-us-gov`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^us\\-gov\\-\\w+\\-\\d+$`,regions:{"aws-us-gov-global":{description:`aws-us-gov global region`},"us-gov-east-1":{description:`AWS GovCloud (US-East)`},"us-gov-west-1":{description:`AWS GovCloud (US-West)`}}}],version:`1.1`},Cse=``,wse=e=>{let{partitions:t}=Sse;for(let n of t){let{regions:t,outputs:r}=n;for(let[n,i]of Object.entries(t))if(n===e)return{...r,...i}}for(let n of t){let{regionRegex:t,outputs:r}=n;if(new RegExp(t).test(e))return{...r}}let n=t.find(e=>e.id===`aws`);if(!n)throw Error(`Provided region was not found in the partition array or regex, and default partition with id 'aws' doesn't exist.`);return{...n.outputs}},Tse=()=>Cse,Ese=/\d{12}\.ddb/;async function Dse(e,t,n){if(n.request?.headers?.[`smithy-protocol`]===`rpc-v2-cbor`&&CC(e,`PROTOCOL_RPC_V2_CBOR`,`M`),typeof t.retryStrategy==`function`){let n=await t.retryStrategy();if(typeof n.mode==`string`)switch(n.mode){case bC.ADAPTIVE:CC(e,`RETRY_MODE_ADAPTIVE`,`F`);break;case bC.STANDARD:CC(e,`RETRY_MODE_STANDARD`,`E`);break}}if(typeof t.accountIdEndpointMode==`function`){let n=e.endpointV2;switch(String(n?.url?.hostname).match(Ese)&&CC(e,`ACCOUNT_ID_ENDPOINT`,`O`),await t.accountIdEndpointMode?.()){case`disabled`:CC(e,`ACCOUNT_ID_MODE_DISABLED`,`Q`);break;case`preferred`:CC(e,`ACCOUNT_ID_MODE_PREFERRED`,`P`);break;case`required`:CC(e,`ACCOUNT_ID_MODE_REQUIRED`,`R`);break}}let r=e.__smithy_context?.selectedHttpAuthScheme?.identity;if(r?.$source){let t=r;t.accountId&&CC(e,`RESOLVED_ACCOUNT_ID`,`T`);for(let[n,r]of Object.entries(t.$source??{}))CC(e,n,r)}}var EC=`user-agent`,DC=`x-amz-user-agent`,Ose=/[^!$%&'*+\-.^_`|~\w]/g,kse=/[^!$%&'*+\-.^_`|~\w#]/g,Ase=1024;function jse(e){let t=``;for(let n in e){let r=e[n];if(t.length+r.length+1<=Ase){t.length?t+=`,`+r:t+=r;continue}break}return t}var Mse=e=>(t,n)=>async r=>{let{request:i}=r;if(!Dx.isInstance(i))return t(r);let{headers:a}=i,o=n?.userAgent?.map(OC)||[],s=(await e.defaultUserAgentProvider()).map(OC);await Dse(n,e,r);let c=n;s.push(`m/${jse(Object.assign({},n.__smithy_context?.features,c.__aws_sdk_context?.features))}`);let l=e?.customUserAgent?.map(OC)||[],u=await e.userAgentAppId();u&&s.push(OC([`app`,`${u}`]));let d=Tse(),f=(d?[d]:[]).concat([...s,...o,...l]).join(` `),p=[...s.filter(e=>e.startsWith(`aws-sdk-`)),...l].join(` `);return e.runtime===`browser`?a[DC]=f:(p&&(a[DC]=a[`x-amz-user-agent`]?`${a[EC]} ${p}`:p),a[EC]=f),t({...r,request:i})},OC=e=>{let t=e[0].split(`/`).map(e=>e.replace(Ose,`-`)).join(`/`),n=e[1]?.replace(kse,`-`),r=t.indexOf(`/`),i=t.substring(0,r),a=t.substring(r+1);return i===`api`&&(a=a.toLowerCase()),[i,a,n].filter(e=>e&&e.length>0).reduce((e,t,n)=>{switch(n){case 0:return t;case 1:return`${e}/${t}`;default:return`${e}#${t}`}},``)},Nse={name:`getUserAgentMiddleware`,step:`build`,priority:`low`,tags:[`SET_USER_AGENT`,`USER_AGENT`],override:!0},Pse=e=>({applyToStack:t=>{t.add(Mse(e),Nse)}}),Fse=({serviceId:e,clientVersion:t})=>async n=>{let r=typeof window<`u`?window.navigator:void 0,i=r?.userAgent??``,a=r?.userAgentData?.platform??kC.os(i)??`other`,o=r?.userAgentData?.brands??[],s=o[o.length-1],c=s?.brand??kC.browser(i)??`unknown`,l=s?.version??`unknown`,u=[[`aws-sdk-js`,t],[`ua`,`2.1`],[`os/${a}`,void 0],[`lang/js`],[`md/browser`,`${c}_${l}`]];e&&u.push([`api/${e}`,t]);let d=await n?.userAgentAppId?.();return d&&u.push([`app/${d}`]),u},kC={os(e){if(/iPhone|iPad|iPod/.test(e))return`iOS`;if(/Macintosh|Mac OS X/.test(e))return`macOS`;if(/Windows NT/.test(e))return`Windows`;if(/Android/.test(e))return`Android`;if(/Linux/.test(e))return`Linux`},browser(e){if(/EdgiOS|EdgA|Edg\//.test(e))return`Microsoft Edge`;if(/Firefox\//.test(e))return`Firefox`;if(/Chrome\//.test(e))return`Chrome`;if(/Safari\//.test(e))return`Safari`}},AC=(e,t=!1)=>{if(t){for(let t of e.split(`.`))if(!AC(t))return!1;return!0}return!(!kx(e)||e.length<3||e.length>63||e!==e.toLowerCase()||ES(e))},jC=`:`,Ise=`/`,MC={isVirtualHostableS3Bucket:AC,parseArn:e=>{let t=e.split(jC);if(t.length<6)return null;let[n,r,i,a,o,...s]=t;return n!==`arn`||r===``||i===``||s.join(jC)===``?null:{partition:r,service:i,region:a,accountId:o,resourceId:s.map(e=>e.split(Ise)).flat()}},partition:wse};CS.aws=MC;var Lse=(e,t,n)=>{let r,i,a,o=!1,s=async()=>{i||=e();try{r=await i,a=!0,o=!1}finally{i=void 0}return r};return t===void 0?async e=>((!a||e?.forceRefresh)&&(r=await s()),r):async e=>((!a||e?.forceRefresh)&&(r=await s()),o?r:n&&!n(r)?(o=!0,r):(t(r)&&await s(),r))},NC=new Set,Rse=(e,t=kx)=>{if(!NC.has(e)&&!t(e))if(e===`*`)console.warn(`@smithy/config-resolver WARN - Please use the caller region instead of "*". See "sigv4a" in https://github.com/aws/aws-sdk-js-v3/blob/main/supplemental-docs/CLIENTS.md.`);else throw Error(`Region not accepted: region="${e}" is not a valid hostname component.`);else NC.add(e)},PC=e=>typeof e==`string`&&(e.startsWith(`fips-`)||e.endsWith(`-fips`)),zse=e=>PC(e)?[`fips-aws-global`,`aws-fips`].includes(e)?`us-east-1`:e.replace(/fips-(dkr-|prod-)?|-fips/,``):e,Bse=e=>{let{region:t,useFipsEndpoint:n}=e;if(!t)throw Error(`Region is missing`);return Object.assign(e,{region:async()=>{let e=zse(typeof t==`function`?await t():t);return Rse(e),e},useFipsEndpoint:async()=>PC(typeof t==`string`?t:await t())?!0:typeof n==`function`?n():Promise.resolve(!!n)})},Vse=[`in-region`,`cross-region`,`mobile`,`standard`,`legacy`],Hse=({defaultsMode:e}={})=>Lse(async()=>{let t=typeof e==`function`?await e():e;switch(t?.toLowerCase()){case`auto`:return Promise.resolve(Use()?`mobile`:`standard`);case`mobile`:case`in-region`:case`cross-region`:case`standard`:case`legacy`:return Promise.resolve(t?.toLocaleLowerCase());case void 0:return Promise.resolve(`legacy`);default:throw Error(`Invalid parameter for "defaultsMode", expect ${Vse.join(`, `)}, got ${t}`)}}),Use=()=>{let e=window?.navigator;if(e?.connection){let{effectiveType:t,rtt:n,downlink:r}=e?.connection;if(typeof t==`string`&&t!==`4g`||Number(n)>100||Number(r)<10)return!0}return e?.userAgentData?.mobile||typeof e?.maxTouchPoints==`number`&&e?.maxTouchPoints>1},Wse=e=>({setRegion(t){e.region=t},region(){return e.region}}),Gse=e=>({region:e.region()}),FC=e=>Ox.isInstance(e)?e.headers?.date??e.headers?.Date:void 0,IC=e=>new Date(Date.now()+e),Kse=(e,t)=>Math.abs(IC(t).getTime()-e)>=3e5,LC=(e,t)=>{let n=Date.parse(e);return Kse(n,t)?n-Date.now():t},RC=(e,t)=>{if(!t)throw Error(`Property \`${e}\` is not resolved for AWS SDK SigV4Auth`);return t},qse=async e=>{let t=RC(`context`,e.context),n=RC(`config`,e.config),r=t.endpointV2?.properties?.authSchemes?.[0];return{config:n,signer:await RC(`signer`,n.signer)(r),signingRegion:e?.signingRegion,signingRegionSet:e?.signingRegionSet,signingName:e?.signingName}},Jse=class{async sign(e,t,n){if(!Dx.isInstance(e))throw Error("The request is not an instance of `HttpRequest` and cannot be signed");let r=await qse(n),{config:i,signer:a}=r,{signingRegion:o,signingName:s}=r,c=n.context;if(c?.authSchemes?.length??!1){let[e,t]=c.authSchemes;e?.name===`sigv4a`&&t?.name===`sigv4`&&(o=t?.signingRegion??o,s=t?.signingName??s)}return await a.sign(e,{signingDate:IC(i.systemClockOffset),signingRegion:o,signingService:s})}errorHandler(e){return t=>{let n=t.ServerTime??FC(t.$response);if(n){let r=RC(`config`,e.config),i=r.systemClockOffset;r.systemClockOffset=LC(n,r.systemClockOffset),r.systemClockOffset!==i&&t.$metadata&&(t.$metadata.clockSkewCorrected=!0)}throw t}}successHandler(e,t){let n=FC(e);if(n){let e=RC(`config`,t.config);e.systemClockOffset=LC(n,e.systemClockOffset)}}},Yse=class{format(e){let t=[];for(let n of Object.keys(e)){let r=Zx(n);t.push(Uint8Array.from([r.byteLength]),r,this.formatHeaderValue(e[n]))}let n=new Uint8Array(t.reduce((e,t)=>e+t.byteLength,0)),r=0;for(let e of t)n.set(e,r),r+=e.byteLength;return n}formatHeaderValue(e){switch(e.type){case`boolean`:return Uint8Array.from([+!e.value]);case`byte`:return Uint8Array.from([2,e.value]);case`short`:let t=new DataView(new ArrayBuffer(3));return t.setUint8(0,3),t.setInt16(1,e.value,!1),new Uint8Array(t.buffer);case`integer`:let n=new DataView(new ArrayBuffer(5));return n.setUint8(0,4),n.setInt32(1,e.value,!1),new Uint8Array(n.buffer);case`long`:let r=new Uint8Array(9);return r[0]=5,r.set(e.value.bytes,1),r;case`binary`:let i=new DataView(new ArrayBuffer(3+e.value.byteLength));i.setUint8(0,6),i.setUint16(1,e.value.byteLength,!1);let a=new Uint8Array(i.buffer);return a.set(e.value,3),a;case`string`:let o=Zx(e.value),s=new DataView(new ArrayBuffer(3+o.byteLength));s.setUint8(0,7),s.setUint16(1,o.byteLength,!1);let c=new Uint8Array(s.buffer);return c.set(o,3),c;case`timestamp`:let l=new Uint8Array(9);return l[0]=8,l.set(Qse.fromNumber(e.value.valueOf()).bytes,1),l;case`uuid`:if(!Zse.test(e.value))throw Error(`Invalid UUID received: ${e.value}`);let u=new Uint8Array(17);return u[0]=9,u.set(roe(e.value.replace(/\-/g,``)),1),u}}},Xse;(function(e){e[e.boolTrue=0]=`boolTrue`,e[e.boolFalse=1]=`boolFalse`,e[e.byte=2]=`byte`,e[e.short=3]=`short`,e[e.integer=4]=`integer`,e[e.long=5]=`long`,e[e.byteArray=6]=`byteArray`,e[e.string=7]=`string`,e[e.timestamp=8]=`timestamp`,e[e.uuid=9]=`uuid`})(Xse||={});var Zse=/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/,Qse=class e{bytes;constructor(e){if(this.bytes=e,e.byteLength!==8)throw Error(`Int64 buffers must be exactly 8 bytes`)}static fromNumber(t){if(t>0x8000000000000000||t<-0x8000000000000000)throw Error(`${t} is too large (or, if negative, too small) to represent as an Int64`);let n=new Uint8Array(8);for(let e=7,r=Math.abs(Math.round(t));e>-1&&r>0;e--,r/=256)n[e]=r;return t<0&&zC(n),new e(n)}valueOf(){let e=this.bytes.slice(0),t=e[0]&128;return t&&zC(e),parseInt(gS(e),16)*(t?-1:1)}toString(){return String(this.valueOf())}};function zC(e){for(let t=0;t<8;t++)e[t]^=255;for(let t=7;t>-1&&(e[t]++,e[t]===0);t--);}var $se=`X-Amz-Algorithm`,ece=`X-Amz-Credential`,BC=`X-Amz-Date`,tce=`X-Amz-SignedHeaders`,nce=`X-Amz-Expires`,VC=`X-Amz-Signature`,HC=`X-Amz-Security-Token`,UC=`authorization`,WC=BC.toLowerCase(),rce=[UC,WC,`date`];VC.toLowerCase();var ice=`x-amz-content-sha256`,ace=HC.toLowerCase(),oce={authorization:!0,"cache-control":!0,connection:!0,expect:!0,from:!0,"keep-alive":!0,"max-forwards":!0,pragma:!0,referer:!0,te:!0,trailer:!0,"transfer-encoding":!0,upgrade:!0,"user-agent":!0,"x-amzn-trace-id":!0},sce=/^proxy-/,cce=/^sec-/,GC=`AWS4-HMAC-SHA256`,lce=`AWS4-HMAC-SHA256-PAYLOAD`,uce=`UNSIGNED-PAYLOAD`,KC=`aws4_request`,dce=({query:e={}})=>{let t=[],n={};for(let r of Object.keys(e)){if(r.toLowerCase()===`x-amz-signature`)continue;let i=KS(r);t.push(i);let a=e[r];typeof a==`string`?n[i]=`${i}=${KS(a)}`:Array.isArray(a)&&(n[i]=a.slice(0).reduce((e,t)=>e.concat([`${i}=${KS(t)}`]),[]).sort().join(`&`))}return t.sort().map(e=>n[e]).filter(e=>e).join(`&`)},fce=e=>pce(e).toISOString().replace(/\.\d{3}Z$/,`Z`),pce=e=>typeof e==`number`?new Date(e*1e3):typeof e==`string`?Number(e)?new Date(Number(e)*1e3):new Date(e):e,mce=class{service;regionProvider;credentialProvider;sha256;uriEscapePath;applyChecksum;constructor({applyChecksum:e,credentials:t,region:n,service:r,sha256:i,uriEscapePath:a=!0}){this.service=r,this.sha256=i,this.uriEscapePath=a,this.applyChecksum=typeof e==`boolean`?e:!0,this.regionProvider=Ax(n),this.credentialProvider=Ax(t)}createCanonicalRequest(e,t,n){let r=Object.keys(t).sort();return`${e.method} +${this.getCanonicalPath(e)} +${dce(e)} +${r.map(e=>`${e}:${t[e]}`).join(` +`)} + +${r.join(`;`)} +${n}`}async createStringToSign(e,t,n,r){let i=new this.sha256;return i.update(vS(n)),`${r} +${e} +${t} +${gS(await i.digest())}`}getCanonicalPath({path:e}){if(this.uriEscapePath){let t=[];for(let n of e.split(`/`))n?.length!==0&&n!==`.`&&(n===`..`?t.pop():t.push(n));return KS(`${e?.startsWith(`/`)?`/`:``}${t.join(`/`)}${t.length>0&&e?.endsWith(`/`)?`/`:``}`).replace(/%2F/g,`/`)}return e}validateResolvedCredentials(e){if(typeof e!=`object`||typeof e.accessKeyId!=`string`||typeof e.secretAccessKey!=`string`)throw Error(`Resolved credential object is not valid`)}formatDate(e){let t=fce(e).replace(/[\-:]/g,``);return{longDate:t,shortDate:t.slice(0,8)}}getCanonicalHeaderList(e){return Object.keys(e).sort().join(`;`)}},qC={},JC=[],YC=(e,t,n)=>`${e}/${t}/${n}/${KC}`,hce=async(e,t,n,r,i)=>{let a=`${n}:${r}:${i}:${gS(await XC(e,t.secretAccessKey,t.accessKeyId))}:${t.sessionToken}`;if(a in qC)return qC[a];for(JC.push(a);JC.length>50;)delete qC[JC.shift()];let o=`AWS4${t.secretAccessKey}`;for(let t of[n,r,i,KC])o=await XC(e,o,t);return qC[a]=o},XC=(e,t,n)=>{let r=new e(t);return r.update(vS(n)),r.digest()},ZC=({headers:e},t,n)=>{let r={};for(let i of Object.keys(e).sort()){if(e[i]==null)continue;let a=i.toLowerCase();(a in oce||t?.has(a)||sce.test(a)||cce.test(a))&&(!n||n&&!n.has(a))||(r[a]=e[i].trim().replace(/\s+/g,` `))}return r},QC=async({headers:e,body:t},n)=>{for(let t of Object.keys(e))if(t.toLowerCase()===`x-amz-content-sha256`)return e[t];if(t==null)return`e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`;if(typeof t==`string`||ArrayBuffer.isView(t)||aoe(t)){let e=new n;return e.update(vS(t)),gS(await e.digest())}return uce},$C=(e,t)=>{e=e.toLowerCase();for(let n of Object.keys(t))if(e===n.toLowerCase())return!0;return!1},ew=(e,t={})=>{let{headers:n,query:r={}}=Dx.clone(e);for(let e of Object.keys(n)){let i=e.toLowerCase();(i.slice(0,6)===`x-amz-`&&!t.unhoistableHeaders?.has(i)||t.hoistableHeaders?.has(i))&&(r[e]=n[e],delete n[e])}return{...e,headers:n,query:r}},tw=e=>{e=Dx.clone(e);for(let t of Object.keys(e.headers))rce.indexOf(t.toLowerCase())>-1&&delete e.headers[t];return e},nw=class extends mce{headerFormatter=new Yse;constructor({applyChecksum:e,credentials:t,region:n,service:r,sha256:i,uriEscapePath:a=!0}){super({applyChecksum:e,credentials:t,region:n,service:r,sha256:i,uriEscapePath:a})}async presign(e,t={}){let{signingDate:n=new Date,expiresIn:r=3600,unsignableHeaders:i,unhoistableHeaders:a,signableHeaders:o,hoistableHeaders:s,signingRegion:c,signingService:l}=t,u=await this.credentialProvider();this.validateResolvedCredentials(u);let d=c??await this.regionProvider(),{longDate:f,shortDate:p}=this.formatDate(n);if(r>604800)return Promise.reject(`Signature version 4 presigned URLs must have an expiration date less than one week in the future`);let m=YC(p,d,l??this.service),h=ew(tw(e),{unhoistableHeaders:a,hoistableHeaders:s});u.sessionToken&&(h.query[HC]=u.sessionToken),h.query[$se]=GC,h.query[ece]=`${u.accessKeyId}/${m}`,h.query[BC]=f,h.query[nce]=r.toString(10);let g=ZC(h,i,o);return h.query[tce]=this.getCanonicalHeaderList(g),h.query[VC]=await this.getSignature(f,m,this.getSigningKey(u,d,p,l),this.createCanonicalRequest(h,g,await QC(e,this.sha256))),h}async sign(e,t){return typeof e==`string`?this.signString(e,t):e.headers&&e.payload?this.signEvent(e,t):e.message?this.signMessage(e,t):this.signRequest(e,t)}async signEvent({headers:e,payload:t},{signingDate:n=new Date,priorSignature:r,signingRegion:i,signingService:a,eventStreamCredentials:o}){let s=i??await this.regionProvider(),{shortDate:c,longDate:l}=this.formatDate(n),u=YC(c,s,a??this.service),d=await QC({headers:{},body:t},this.sha256),f=new this.sha256;f.update(e);let p=[lce,l,u,r,gS(await f.digest()),d].join(` +`);return this.signString(p,{signingDate:n,signingRegion:s,signingService:a,eventStreamCredentials:o})}async signMessage(e,{signingDate:t=new Date,signingRegion:n,signingService:r,eventStreamCredentials:i}){return this.signEvent({headers:this.headerFormatter.format(e.message.headers),payload:e.message.body},{signingDate:t,signingRegion:n,signingService:r,priorSignature:e.priorSignature,eventStreamCredentials:i}).then(t=>({message:e.message,signature:t}))}async signString(e,{signingDate:t=new Date,signingRegion:n,signingService:r,eventStreamCredentials:i}={}){let a=i??await this.credentialProvider();this.validateResolvedCredentials(a);let o=n??await this.regionProvider(),{shortDate:s}=this.formatDate(t),c=new this.sha256(await this.getSigningKey(a,o,s,r));return c.update(vS(e)),gS(await c.digest())}async signRequest(e,{signingDate:t=new Date,signableHeaders:n,unsignableHeaders:r,signingRegion:i,signingService:a}={}){let o=await this.credentialProvider();this.validateResolvedCredentials(o);let s=i??await this.regionProvider(),c=tw(e),{longDate:l,shortDate:u}=this.formatDate(t),d=YC(u,s,a??this.service);c.headers[WC]=l,o.sessionToken&&(c.headers[ace]=o.sessionToken);let f=await QC(c,this.sha256);!$C(`x-amz-content-sha256`,c.headers)&&this.applyChecksum&&(c.headers[ice]=f);let p=ZC(c,r,n),m=await this.getSignature(l,d,this.getSigningKey(o,s,u,a),this.createCanonicalRequest(c,p,f));return c.headers[UC]=`${GC} Credential=${o.accessKeyId}/${d}, SignedHeaders=${this.getCanonicalHeaderList(p)}, Signature=${m}`,c}async getSignature(e,t,n,r){let i=await this.createStringToSign(e,t,r,GC),a=new this.sha256(await n);return a.update(vS(i)),gS(await a.digest())}getSigningKey(e,t,n,r){return hce(this.sha256,e,n,t,r||this.service)}},rw=e=>{let t=e.credentials,n=!!e.credentials,r;Object.defineProperty(e,`credentials`,{set(i){i&&i!==t&&i!==r&&(n=!0),t=i;let a=aw(e,iw(e,{credentials:t,credentialDefaultProvider:e.credentialDefaultProvider}));if(n&&!a.attributed){let e=typeof t==`object`&&!!t;r=async t=>{let n=await a(t);return e&&(!n.$source||Object.keys(n.$source).length===0)?iae(n,`CREDENTIALS_CODE`,`e`):n},r.memoized=a.memoized,r.configBound=a.configBound,r.attributed=!0}else r=a},get(){return r},enumerable:!0,configurable:!0}),e.credentials=t;let{signingEscapePath:i=!0,systemClockOffset:a=e.systemClockOffset||0,sha256:o}=e,s;return s=e.signer?wC(e.signer):e.regionInfoProvider?()=>wC(e.region)().then(async t=>[await e.regionInfoProvider(t,{useFipsEndpoint:await e.useFipsEndpoint(),useDualstackEndpoint:await e.useDualstackEndpoint()})||{},t]).then(([t,n])=>{let{signingRegion:r,signingService:a}=t;e.signingRegion=e.signingRegion||r||n,e.signingName=e.signingName||a||e.serviceId;let s={...e,credentials:e.credentials,region:e.signingRegion,service:e.signingName,sha256:o,uriEscapePath:i};return new(e.signerConstructor||nw)(s)}):async t=>{t=Object.assign({},{name:`sigv4`,signingName:e.signingName||e.defaultSigningName,signingRegion:await wC(e.region)(),properties:{}},t);let n=t.signingRegion,r=t.signingName;e.signingRegion=e.signingRegion||n,e.signingName=e.signingName||r||e.serviceId;let a={...e,credentials:e.credentials,region:e.signingRegion,service:e.signingName,sha256:o,uriEscapePath:i};return new(e.signerConstructor||nw)(a)},Object.assign(e,{systemClockOffset:a,signingEscapePath:i,signer:s})};function iw(e,{credentials:t,credentialDefaultProvider:n}){let r;return r=t?t?.memoized?t:yse(t,vse,TC):n?wC(n(Object.assign({},e,{parentClientConfig:e}))):async()=>{throw Error("@aws-sdk/core::resolveAwsSdkSigV4Config - `credentials` not provided and no credentialDefaultProvider was configured.")},r.memoized=!0,r}function aw(e,t){if(t.configBound)return t;let n=async n=>t({...n,callerClientConfig:e});return n.memoized=t.memoized,n.configBound=!0,n}var ow=async(e,t,n)=>({operation:Ex(t).operation,region:await Ax(e.region)()||(()=>{throw Error("expected `region` to be configured for `aws.auth#sigv4`")})()});function sw(e){return{schemeId:`aws.auth#sigv4`,signingProperties:{name:`acm`,region:e.region},propertiesExtractor:(e,t)=>({signingProperties:{config:e,context:t}})}}var cw=e=>{let t=[];switch(e.operation){default:t.push(sw(e))}return t},lw=e=>{let t=rw(e);return Object.assign(t,{authSchemePreference:Ax(e.authSchemePreference??[])})},uw=e=>Object.assign(e,{useDualstackEndpoint:e.useDualstackEndpoint??!1,useFipsEndpoint:e.useFipsEndpoint??!1,defaultSigningName:`acm`}),dw={UseFIPS:{type:`builtInParams`,name:`useFipsEndpoint`},Endpoint:{type:`builtInParams`,name:`endpoint`},Region:{type:`builtInParams`,name:`region`},UseDualStack:{type:`builtInParams`,name:`useDualstackEndpoint`}},fw={name:`@aws-sdk/client-acm`,description:`AWS SDK for JavaScript Acm Client for Node.js, Browser and React Native`,version:`3.1057.0`,scripts:{build:`concurrently 'yarn:build:types' 'yarn:build:es' && yarn build:cjs`,"build:cjs":`node ../../scripts/compilation/inline client-acm`,"build:es":`tsc -p tsconfig.es.json`,"build:include:deps":`yarn g:turbo run build -F="$npm_package_name"`,"build:types":`tsc -p tsconfig.types.json`,"build:types:downlevel":`downlevel-dts dist-types dist-types/ts3.4`,clean:`premove dist-cjs dist-es dist-types tsconfig.cjs.tsbuildinfo tsconfig.es.tsbuildinfo tsconfig.types.tsbuildinfo`,"extract:docs":`api-extractor run --local`,"generate:client":`node ../../scripts/generate-clients/single-service --solo acm`,"test:e2e":`yarn g:vitest run -c vitest.config.e2e.mts`,"test:e2e:watch":`yarn g:vitest watch -c vitest.config.e2e.mts`,"test:index":`tsc --noEmit ./test/index-types.ts && node ./test/index-objects.spec.mjs`},main:`./dist-cjs/index.js`,types:`./dist-types/index.d.ts`,module:`./dist-es/index.js`,sideEffects:!1,dependencies:{"@aws-crypto/sha256-browser":`5.2.0`,"@aws-crypto/sha256-js":`5.2.0`,"@aws-sdk/core":`^3.974.15`,"@aws-sdk/credential-provider-node":`^3.972.47`,"@aws-sdk/types":`^3.973.9`,"@smithy/core":`^3.24.5`,"@smithy/fetch-http-handler":`^5.4.5`,"@smithy/node-http-handler":`^4.7.5`,"@smithy/types":`^4.14.2`,tslib:`^2.6.2`},devDependencies:{"@tsconfig/node20":`20.1.8`,"@types/node":`^20.14.8`,concurrently:`7.0.0`,"downlevel-dts":`0.10.1`,premove:`4.0.0`,typescript:`~5.8.3`},engines:{node:`>=20.0.0`},typesVersions:{"<4.5":{"dist-types/*":[`dist-types/ts3.4/*`]}},files:[`dist-*/**`],author:{name:`AWS SDK for JavaScript Team`,url:`https://aws.amazon.com/javascript/`},license:`Apache-2.0`,browser:{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.browser`},"react-native":{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.native`},homepage:`https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-acm`,repository:{type:`git`,url:`https://github.com/aws/aws-sdk-js-v3.git`,directory:`clients/client-acm`}};function pw(e,t){return new Request(e,t)}function mw(e=0){return new Promise((t,n)=>{e&&setTimeout(()=>{let t=Error(`Request did not complete within ${e} ms`);t.name=`TimeoutError`,n(t)},e)})}var hw={supported:void 0},gw=class e{config;configProvider;static create(t){return typeof t?.handle==`function`?t:new e(t)}constructor(e){typeof e==`function`?this.configProvider=e().then(e=>e||{}):(this.config=e??{},this.configProvider=Promise.resolve(this.config)),hw.supported===void 0&&(hw.supported=typeof Request<`u`&&`keepalive`in pw(`https://[::1]`))}destroy(){}async handle(e,{abortSignal:t,requestTimeout:n}={}){this.config||=await this.configProvider;let r=n??this.config.requestTimeout,i=this.config.keepAlive===!0,a=this.config.credentials;if(t?.aborted){let e=_w(t);return Promise.reject(e)}let o=e.path,s=qoe(e.query||{});s&&(o+=`?${s}`),e.fragment&&(o+=`#${e.fragment}`);let c=``;(e.username!=null||e.password!=null)&&(c=`${e.username??``}:${e.password??``}@`);let{port:l,method:u}=e,d=`${e.protocol}//${c}${e.hostname}${l?`:${l}`:``}${o}`,f=u===`GET`||u===`HEAD`?void 0:e.body,p={body:f,headers:new Headers(e.headers),method:u,credentials:a};this.config?.cache&&(p.cache=this.config.cache),f&&(p.duplex=`half`),typeof AbortController<`u`&&(p.signal=t),hw.supported&&(p.keepalive=i),typeof this.config.requestInit==`function`&&Object.assign(p,this.config.requestInit(e));let m=()=>{},h=pw(d,p),g=[fetch(h).then(e=>{let t=e.headers,n={};for(let e of t.entries())n[e[0]]=e[1];return e.body==null?e.blob().then(t=>({response:new Ox({headers:n,reason:e.statusText,statusCode:e.status,body:t})})):{response:new Ox({headers:n,reason:e.statusText,statusCode:e.status,body:e.body})}}),mw(r)];return t&&g.push(new Promise((e,n)=>{let r=()=>{n(_w(t))};if(typeof t.addEventListener==`function`){let e=t;e.addEventListener(`abort`,r,{once:!0}),m=()=>e.removeEventListener(`abort`,r)}else t.onabort=r})),Promise.race(g).finally(m)}updateHttpClientConfig(e,t){this.config=void 0,this.configProvider=this.configProvider.then(n=>(n[e]=t,n))}httpHandlerConfigs(){return this.config??{}}};function _w(e){let t=e&&typeof e==`object`&&`reason`in e?e.reason:void 0;if(t){if(t instanceof Error){let e=Error(`Request aborted`);return e.name=`AbortError`,e.cause=t,e}let e=Error(String(t));return e.name=`AbortError`,e}let n=Error(`Request aborted`);return n.name=`AbortError`,n}var vw=async e=>typeof Blob==`function`&&e instanceof Blob||e.constructor?.name===`Blob`?Blob.prototype.arrayBuffer===void 0?yw(e):new Uint8Array(await e.arrayBuffer()):bw(e);async function yw(e){let t=Xx(await xw(e));return new Uint8Array(t)}async function bw(e){let t=[],n=e.getReader(),r=!1,i=0;for(;!r;){let{done:e,value:a}=await n.read();a&&(t.push(a),i+=a.length),r=e}let a=new Uint8Array(i),o=0;for(let e of t)a.set(e,o),o+=e.length;return a}function xw(e){return new Promise((t,n)=>{let r=new FileReader;r.onloadend=()=>{if(r.readyState!==2)return n(Error(`Reader aborted too early`));let e=r.result??``,i=e.indexOf(`,`),a=i>-1?i+1:e.length;t(e.substring(a))},r.onabort=()=>n(Error(`Read aborted`)),r.onerror=()=>n(r.error),r.readAsDataURL(e)})}var Sw=class{queryCompat;errorRegistry;constructor(e=!1){this.queryCompat=e}resolveRestContentType(e,t){let n=t.getMemberSchemas(),r=Object.values(n).find(e=>!!e.getMergedTraits().httpPayload);if(r)return r.getMergedTraits().mediaType||(r.isStringSchema()?`text/plain`:r.isBlobSchema()?`application/octet-stream`:e);if(!t.isUnitSchema()&&Object.values(n).find(e=>{let{httpQuery:t,httpQueryParams:n,httpHeader:r,httpLabel:i,httpPrefixHeaders:a}=e.getMergedTraits();return!t&&!n&&!r&&!i&&a===void 0}))return e}async getErrorSchemaOrThrowBaseException(e,t,n,r,i,a){let o=e;e.includes(`#`)&&([,o]=e.split(`#`));let s={$metadata:i,$fault:n.statusCode<500?`client`:`server`};if(!this.errorRegistry)throw Error(`@aws-sdk/core/protocols - error handler not initialized.`);try{return{errorSchema:a?.(this.errorRegistry,o)??this.errorRegistry.getSchema(e),errorMetadata:s}}catch{r.message=r.message??r.Message??`UnknownError`;let e=this.errorRegistry,t=e.getBaseException();if(t){let n=e.getErrorCtor(t)??Error;throw this.decorateServiceException(Object.assign(new n({name:o}),s),r)}let n=r,i=n?.message??n?.Message??n?.Error?.Message??n?.Error?.message;throw this.decorateServiceException(Object.assign(Error(i),{name:o},s),r)}}compose(e,t,n){let r=n;t.includes(`#`)&&([r]=t.split(`#`));let i=Wx.for(r),a=Wx.for(`smithy.ts.sdk.synthetic.`+n);e.copyFrom(i),e.copyFrom(a),this.errorRegistry=e}decorateServiceException(e,t={}){if(this.queryCompat){let n=e.Message??t.Message,r=Gx(e,t);n&&(r.message=n);let i=r.Error??{};i.Type=r.Error?.Type,i.Code=r.Error?.Code,i.Message=r.Error?.message??r.Error?.Message??n,r.Error=i;let a=r.$metadata.requestId;return a&&(r.RequestId=a),r}return Gx(e,t)}setQueryCompatError(e,t){let n=t.headers?.[`x-amzn-query-error`];if(e!==void 0&&n!=null){let[t,r]=n.split(`;`),i=Object.keys(e),a={Code:t,Type:r};e.Code=t,e.Type=r;for(let t=0;tVx.of(e).getMergedTraits().awsQueryError?.[0]===t)}}},Cw=class{serdeContext;setSerdeContext(e){this.serdeContext=e}},ww=class{from;to;keys;constructor(e,t){this.from=e,this.to=t;let n=Object.keys(this.from),r=new Set(n);r.delete(`__type`),this.keys=r}mark(e){this.keys.delete(e)}hasUnknown(){return this.keys.size===1&&Object.keys(this.to).length===0}writeUnknown(){if(this.hasUnknown()){let e=this.keys.values().next().value,t=this.from[e];this.to.$unknown=[e,t]}}};function Tw(e,t,n){if(n?.source){let e=n.source;if(typeof t==`number`&&(t>2**53-1||t<-(2**53-1)||e!==String(t)))return e.includes(`.`)?new pS(e,`bigDecimal`):BigInt(e)}return t}var Ew=(e,t)=>VS(e,t).then(e=>(t?.utf8Encoder??$x)(e)),Dw=(e,t)=>Ew(e,t).then(e=>{if(e.length)try{return JSON.parse(e)}catch(t){throw t?.name===`SyntaxError`&&Object.defineProperty(t,`$responseBodyText`,{value:e}),t}return{}}),Ow=(e,t)=>Object.keys(e).find(e=>e.toLowerCase()===t.toLowerCase()),kw=e=>{let t=e;return typeof t==`number`&&(t=t.toString()),t.indexOf(`,`)>=0&&(t=t.split(`,`)[0]),t.indexOf(`:`)>=0&&(t=t.split(`:`)[0]),t.indexOf(`#`)>=0&&(t=t.split(`#`)[1]),t},Aw=(e,t,n=!1)=>jw(e,t,n?[`code`,`header`,`type`]:[`type`,`code`,`header`]),jw=({headers:e},t,n)=>{for(;n.length>0;)switch(n.shift()){case`header`:let n=Ow(e??{},`x-amzn-errortype`);if(n!==void 0)return kw(e[n]);break;case`code`:let r=Ow(t??{},`code`);if(r&&t[r]!==void 0)return kw(t[r]);break;case`type`:if(t?.__type!==void 0)return kw(t.__type);break}},Mw=class extends Cw{settings;constructor(e){super(),this.settings=e}async read(e,t){return this._read(e,typeof t==`string`?JSON.parse(t,Tw):await Dw(t,this.serdeContext))}readObject(e,t){return this._read(e,t)}_read(e,t){let n=typeof t==`object`&&!!t,r=Vx.of(e);if(n){if(r.isStructSchema()){let e=t,n=r.isUnionSchema(),i={},a,{jsonName:o}=this.settings;o&&(a={});let s;n&&(s=new ww(e,i));for(let[t,c]of r.structIterator()){let r=t;o&&(r=c.getMergedTraits().jsonName??r,a[r]=t),n&&s.mark(r),e[r]!=null&&(i[t]=this._read(c,e[r]))}if(n)s.writeUnknown();else if(typeof e.__type==`string`)for(let t in e){let n=e[t],r=o?a[t]??t:t;r in i||(i[r]=n)}return i}if(Array.isArray(t)&&r.isListSchema()){let e=r.getValueSchema(),n=[];for(let r of t)n.push(this._read(e,r));return n}if(r.isMapSchema()){let e=r.getValueSchema(),n={};for(let r in t)n[r]=this._read(e,t[r]);return n}}if(r.isBlobSchema()&&typeof t==`string`)return Xx(t);let i=r.getMergedTraits().mediaType;if(r.isStringSchema()&&typeof t==`string`&&i)return i===`application/json`||i.endsWith(`+json`)?dS.from(t):t;if(r.isTimestampSchema()&&t!=null)switch(WS(r,this.settings)){case 5:return Wae(t);case 6:return oS(t);case 7:return Jae(t);default:return console.warn(`Missing timestamp format, parsing value with Date constructor:`,t),new Date(t)}if(r.isBigIntegerSchema()&&(typeof t==`number`||typeof t==`string`))return BigInt(t);if(r.isBigDecimalSchema()&&t!=null){if(t instanceof pS)return t;let e=t;return e.type===`bigDecimal`&&`string`in e?new pS(e.string,e.type):new pS(String(t),`bigDecimal`)}if(r.isNumericSchema()&&typeof t==`string`){switch(t){case`Infinity`:return 1/0;case`-Infinity`:return-1/0;case`NaN`:return NaN}return t}if(r.isDocumentSchema())if(n){let e=Array.isArray(t)?[]:{};for(let n in t){let i=t[n];i instanceof pS?e[n]=i:e[n]=this._read(r,i)}return e}else return structuredClone(t);return t}},Nw=`Ν`,Pw=class{values=new Map;counter=0;stage=0;createReplacer(){if(this.stage===1)throw Error(`@aws-sdk/core/protocols - JsonReplacer already created.`);if(this.stage===2)throw Error(`@aws-sdk/core/protocols - JsonReplacer exhausted.`);return this.stage=1,(e,t)=>{if(t instanceof pS){let e=`${Nw+`nv`+ this.counter++}_`+t.string;return this.values.set(`"${e}"`,t.string),e}if(typeof t==`bigint`){let e=t.toString(),n=`${Nw+`b`+ this.counter++}_`+e;return this.values.set(`"${n}"`,e),n}return t}}replaceInJson(e){if(this.stage===0)throw Error(`@aws-sdk/core/protocols - JsonReplacer not created yet.`);if(this.stage===2)throw Error(`@aws-sdk/core/protocols - JsonReplacer exhausted.`);if(this.stage=2,this.counter===0)return e;for(let[t,n]of this.values)e=e.replace(t,n);return e}},Fw=class extends Cw{settings;buffer;useReplacer=!1;rootSchema;constructor(e){super(),this.settings=e}write(e,t){this.rootSchema=Vx.of(e),this.buffer=this._write(this.rootSchema,t)}flush(){let{rootSchema:e,useReplacer:t}=this;if(this.rootSchema=void 0,this.useReplacer=!1,e?.isStructSchema()||e?.isDocumentSchema()){if(!t)return JSON.stringify(this.buffer);let e=new Pw;return e.replaceInJson(JSON.stringify(this.buffer,e.createReplacer(),0))}return this.buffer}writeDiscriminatedDocument(e,t){this.write(e,t),typeof this.buffer==`object`&&(this.buffer.__type=Vx.of(e).getName(!0))}_write(e,t,n){let r=typeof t==`object`&&!!t,i=Vx.of(e);if(r){if(i.isStructSchema()){let e=t,n={},{jsonName:r}=this.settings,a;r&&(a={});let o=0;for(let[t,s]of i.structIterator()){let c=this._write(s,e[t],i);if(c!==void 0){let e=t;r&&(e=s.getMergedTraits().jsonName??t,a[t]=e),n[e]=c,o++}}if(i.isUnionSchema()&&o===0){let{$unknown:t}=e;if(Array.isArray(t)){let[e,r]=t;n[e]=this._write(15,r)}}else if(typeof e.__type==`string`)for(let t in e){let i=e[t],o=r?a[t]??t:t;o in n||(n[o]=this._write(15,i))}return n}if(Array.isArray(t)&&i.isListSchema()){let e=i.getValueSchema(),n=[],r=!!i.getMergedTraits().sparse;for(let i of t)(r||i!=null)&&n.push(this._write(e,i));return n}if(i.isMapSchema()){let e=i.getValueSchema(),n={},r=!!i.getMergedTraits().sparse;for(let i in t){let a=t[i];(r||a!=null)&&(n[i]=this._write(e,a))}return n}if(t instanceof Uint8Array&&(i.isBlobSchema()||i.isDocumentSchema()))return i===this.rootSchema?t:(this.serdeContext?.base64Encoder??Qx)(t);if(t instanceof Date&&(i.isTimestampSchema()||i.isDocumentSchema()))switch(WS(i,this.settings)){case 5:return t.toISOString().replace(`.000Z`,`Z`);case 6:return Hae(t);case 7:return t.getTime()/1e3;default:return console.warn(`Missing timestamp format, using epoch seconds`,t),t.getTime()/1e3}t instanceof pS&&(this.useReplacer=!0)}if(!(t===null&&n?.isStructSchema())){if(i.isStringSchema()){if(t===void 0&&i.isIdempotencyToken())return Foe();let e=i.getMergedTraits().mediaType;return t!=null&&e&&(e===`application/json`||e.endsWith(`+json`))?dS.from(t):t}if(typeof t==`number`&&i.isNumericSchema())return Math.abs(t)===1/0||isNaN(t)?String(t):t;if(typeof t==`string`&&i.isBlobSchema())return i===this.rootSchema?t:(this.serdeContext?.base64Encoder??Qx)(t);if(typeof t==`bigint`&&(this.useReplacer=!0),i.isDocumentSchema())if(r){let e=Array.isArray(t)?[]:{};for(let n in t){let r=t[n];r instanceof pS?(this.useReplacer=!0,e[n]=r):e[n]=this._write(i,r)}return e}else return structuredClone(t);return t}}},Iw=class extends Cw{settings;constructor(e){super(),this.settings=e}createSerializer(){let e=new Fw(this.settings);return e.setSerdeContext(this.serdeContext),e}createDeserializer(){let e=new Mw(this.settings);return e.setSerdeContext(this.serdeContext),e}},Lw=class extends Boe{serializer;deserializer;serviceTarget;codec;mixin;awsQueryCompatible;constructor({defaultNamespace:e,errorTypeRegistries:t,serviceTarget:n,awsQueryCompatible:r,jsonCodec:i}){super({defaultNamespace:e,errorTypeRegistries:t}),this.serviceTarget=n,this.codec=i??new Iw({timestampFormat:{useTrait:!0,default:7},jsonName:!1}),this.serializer=this.codec.createSerializer(),this.deserializer=this.codec.createDeserializer(),this.awsQueryCompatible=!!r,this.mixin=new Sw(this.awsQueryCompatible)}async serializeRequest(e,t,n){let r=await super.serializeRequest(e,t,n);return r.path.endsWith(`/`)||(r.path+=`/`),r.headers[`content-type`]=`application/x-amz-json-${this.getJsonRpcVersion()}`,r.headers[`x-amz-target`]=`${this.serviceTarget}.${e.name}`,this.awsQueryCompatible&&(r.headers[`x-amzn-query-mode`]=`true`),(Nx(e.input)===`unit`||!r.body)&&(r.body=`{}`),r}getPayloadCodec(){return this.codec}async handleError(e,t,n,r,i){let{awsQueryCompatible:a}=this;a&&this.mixin.setQueryCompatError(r,n);let o=Aw(n,r,a)??`Unknown`;this.mixin.compose(this.compositeErrorRegistry,o,this.options.defaultNamespace);let{errorSchema:s,errorMetadata:c}=await this.mixin.getErrorSchemaOrThrowBaseException(o,this.options.defaultNamespace,n,r,i,a?this.mixin.findQueryCompatibleError:void 0),l=Vx.of(s),u=r.message??r.Message??`UnknownError`,d=new((this.compositeErrorRegistry.getErrorCtor(s))??Error)({}),f={},p=this.codec.createDeserializer();for(let[e,t]of l.structIterator())r[e]!=null&&(f[e]=p.readObject(t,r[e]));throw a&&this.mixin.queryCompatOutput(r,f),this.mixin.decorateServiceException(Object.assign(d,c,{$fault:l.getMergedTraits().error,message:u},f),r)}},Rw=class extends Lw{constructor({defaultNamespace:e,errorTypeRegistries:t,serviceTarget:n,awsQueryCompatible:r,jsonCodec:i}){super({defaultNamespace:e,errorTypeRegistries:t,serviceTarget:n,awsQueryCompatible:r,jsonCodec:i})}getShapeId(){return`aws.protocols#awsJson1_1`}getJsonRpcVersion(){return`1.1`}getDefaultContentType(){return`application/x-amz-json-1.1`}},zw=`ref`,Bw=-1,Vw=!0,Hw=`isSet`,Uw=`PartitionResult`,Ww=`booleanEquals`,Gw=`getAttr`,Kw={[zw]:`Endpoint`},qw={[zw]:Uw},Jw={},Yw=[{[zw]:`Region`}],Xw={conditions:[[Hw,[Kw]],[Hw,Yw],[`aws.partition`,Yw,Uw],[Ww,[{[zw]:`UseFIPS`},Vw]],[Ww,[{[zw]:`UseDualStack`},Vw]],[Ww,[{fn:Gw,argv:[qw,`supportsDualStack`]},Vw]],[Ww,[{fn:Gw,argv:[qw,`supportsFIPS`]},Vw]],[`stringEquals`,[{fn:Gw,argv:[qw,`name`]},`aws-us-gov`]]],results:[[Bw],[Bw,`Invalid Configuration: FIPS and custom endpoint are not supported`],[Bw,`Invalid Configuration: Dualstack and custom endpoint are not supported`],[Kw,Jw],[`https://acm-fips.{Region}.{PartitionResult#dualStackDnsSuffix}`,Jw],[Bw,`FIPS and DualStack are enabled, but this partition does not support one or both`],[`https://acm.{Region}.amazonaws.com`,Jw],[`https://acm-fips.{Region}.{PartitionResult#dnsSuffix}`,Jw],[Bw,`FIPS is enabled but this partition does not support FIPS`],[`https://acm.{Region}.{PartitionResult#dualStackDnsSuffix}`,Jw],[Bw,`DualStack is enabled but this partition does not support DualStack`],[`https://acm.{Region}.{PartitionResult#dnsSuffix}`,Jw],[Bw,`Invalid Configuration: Missing Region`]]},Zw=2,Qw=1e8,$w=new Int32Array([-1,1,-1,0,13,3,1,4,Qw+12,2,5,Qw+12,3,8,6,4,7,Qw+11,5,Qw+9,Qw+10,4,11,9,6,10,Qw+8,7,Qw+6,Qw+7,5,12,Qw+5,6,Qw+4,Qw+5,3,Qw+1,14,4,Qw+2,Qw+3]),eT=yoe.from($w,Zw,Xw.conditions,Xw.results),tT=new boe({size:50,params:[`Endpoint`,`Region`,`UseDualStack`,`UseFIPS`]}),nT=(e,t={})=>tT.get(e,()=>Moe(eT,{endpointParams:e,logger:t.logger}));CS.aws=MC;var rT=class e extends vae{constructor(t){super(t),Object.setPrototypeOf(this,e.prototype)}},iT=class e extends rT{name=`AccessDeniedException`;$fault=`client`;Message;constructor(t){super({name:`AccessDeniedException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},aT=class e extends rT{name=`InvalidArnException`;$fault=`client`;constructor(t){super({name:`InvalidArnException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},oT=class e extends rT{name=`InvalidParameterException`;$fault=`client`;constructor(t){super({name:`InvalidParameterException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},sT=class e extends rT{name=`InvalidTagException`;$fault=`client`;constructor(t){super({name:`InvalidTagException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},cT=class e extends rT{name=`ResourceNotFoundException`;$fault=`client`;constructor(t){super({name:`ResourceNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},lT=class e extends rT{name=`TagPolicyException`;$fault=`client`;constructor(t){super({name:`TagPolicyException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},uT=class e extends rT{name=`ThrottlingException`;$fault=`client`;throttlingReasons;constructor(t){super({name:`ThrottlingException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.throttlingReasons=t.throttlingReasons}},dT=class e extends rT{name=`TooManyTagsException`;$fault=`client`;constructor(t){super({name:`TooManyTagsException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},fT=class e extends rT{name=`ConflictException`;$fault=`client`;constructor(t){super({name:`ConflictException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},pT=class e extends rT{name=`ResourceInUseException`;$fault=`client`;constructor(t){super({name:`ResourceInUseException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},mT=class e extends rT{name=`RequestInProgressException`;$fault=`client`;constructor(t){super({name:`RequestInProgressException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},hT=class e extends rT{name=`LimitExceededException`;$fault=`client`;constructor(t){super({name:`LimitExceededException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},gT=class e extends rT{name=`InvalidArgsException`;$fault=`client`;constructor(t){super({name:`InvalidArgsException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},_T=class e extends rT{name=`ValidationException`;$fault=`client`;constructor(t){super({name:`ValidationException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},vT=class e extends rT{name=`InvalidDomainValidationOptionsException`;$fault=`client`;constructor(t){super({name:`InvalidDomainValidationOptionsException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},yT=class e extends rT{name=`InvalidStateException`;$fault=`client`;constructor(t){super({name:`InvalidStateException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},bT=`AccessDeniedException`,xT=`Certificate`,ST=`CreatedAt`,CT=`CertificateArn`,wT=`CertificateChain`,TT=`ConflictException`,ET=`CertificateSummary`,DT=`CertificateSummaryList`,OT=`CertificateStatuses`,kT=`DomainName`,AT=`Exported`,jT=`ExtendedKeyUsages`,MT=`ExportOption`,NT=`Filters`,PT=`HasAdditionalSubjectAlternativeNames`,FT=`ImportedAt`,IT=`InvalidArgsException`,LT=`InvalidArnException`,RT=`IssuedAt`,zT=`ImportCertificate`,BT=`ImportCertificateRequest`,VT=`ImportCertificateResponse`,HT=`InvalidDomainValidationOptionsException`,UT=`InvalidParameterException`,WT=`InvalidStateException`,GT=`InvalidTagException`,KT=`InUse`,qT=`Includes`,JT=`Key`,YT=`KeyAlgorithm`,XT=`KeyUsages`,ZT=`ListCertificates`,QT=`ListCertificatesRequest`,$T=`ListCertificatesResponse`,eE=`LimitExceededException`,tE=`Message`,nE=`ManagedBy`,rE=`MaxItems`,iE=`NotAfter`,aE=`NotBefore`,oE=`NextToken`,sE=`PrivateKey`,cE=`PrivateKeyBlob`,lE=`RevokedAt`,uE=`RenewalEligibility`,dE=`RequestInProgressException`,fE=`ResourceInUseException`,pE=`ResourceNotFoundException`,mE=`Status`,hE=`SubjectAlternativeNameSummaries`,gE=`SortBy`,_E=`SortOrder`,vE=`Type`,yE=`ThrottlingException`,bE=`TagList`,xE=`TooManyTagsException`,SE=`TagPolicyException`,CE=`ThrottlingReason`,wE=`ThrottlingReasonList`,TE=`Tags`,EE=`Tag`,DE=`Value`,OE=`ValidationException`,kE=`awsQueryError`,AE=`client`,jE=`error`,ME=`extendedKeyUsage`,NE=`exportOption`,PE=`httpError`,FE=`keyTypes`,IE=`keyUsage`,LE=`message`,RE=`managedBy`,zE=`reason`,BE=`resource`,VE=`smithy.ts.sdk.synthetic.com.amazonaws.acm`,HE=`throttlingReasons`,UE=`com.amazonaws.acm`,WE=Wx.for(VE),GE=[-3,VE,`ACMServiceException`,0,[],[]];WE.registerError(GE,rT);var KE=Wx.for(UE),qE=[-3,UE,bT,{[kE]:[`AccessDenied`,403],[jE]:AE,[PE]:403},[tE],[0]];KE.registerError(qE,iT);var JE=[-3,UE,TT,{[jE]:AE},[LE],[0]];KE.registerError(JE,fT);var YE=[-3,UE,IT,{[jE]:AE},[LE],[0]];KE.registerError(YE,gT);var XE=[-3,UE,LT,{[jE]:AE},[LE],[0]];KE.registerError(XE,aT);var ZE=[-3,UE,HT,{[jE]:AE},[LE],[0]];KE.registerError(ZE,vT);var QE=[-3,UE,UT,{[jE]:AE},[LE],[0]];KE.registerError(QE,oT);var $E=[-3,UE,WT,{[jE]:AE},[LE],[0]];KE.registerError($E,yT);var eD=[-3,UE,GT,{[jE]:AE},[LE],[0]];KE.registerError(eD,sT);var tD=[-3,UE,eE,{[jE]:AE},[LE],[0]];KE.registerError(tD,hT);var nD=[-3,UE,dE,{[jE]:AE},[LE],[0]];KE.registerError(nD,mT);var rD=[-3,UE,fE,{[jE]:AE},[LE],[0]];KE.registerError(rD,pT);var iD=[-3,UE,pE,{[jE]:AE},[LE],[0]];KE.registerError(iD,cT);var aD=[-3,UE,SE,{[jE]:AE},[LE],[0]];KE.registerError(aD,lT);var oD=[-3,UE,yE,{[kE]:[`Throttling`,400],[jE]:AE,[PE]:400},[LE,HE],[0,()=>xD]];KE.registerError(oD,uT);var sD=[-3,UE,xE,{[jE]:AE},[LE],[0]];KE.registerError(sD,dT);var cD=[-3,UE,OE,{[kE]:[`ValidationError`,400],[jE]:AE,[PE]:400},[LE],[0]];KE.registerError(cD,_T);var lD=[WE,KE],uD=[0,UE,cE,8,21],dD=[3,UE,ET,0,[CT,kT,hE,PT,mE,vE,YT,XT,jT,MT,KT,AT,uE,aE,iE,ST,RT,FT,lE,nE],[0,0,64,2,0,0,0,64,64,0,2,2,0,4,4,4,4,4,4,0]],fD=[3,UE,NT,0,[ME,IE,FE,NE,RE],[64,64,64,0,0]],pD=[3,UE,BT,0,[xT,sE,CT,wT,TE],[21,[()=>uD,0],0,21,()=>bD],2],mD=[3,UE,VT,0,[CT],[0]],hD=[3,UE,QT,0,[OT,qT,oE,rE,gE,_E],[64,()=>fD,0,1,0,0]],gD=[3,UE,$T,0,[oE,DT],[0,()=>yD]],_D=[3,UE,EE,0,[JT,DE],[0,0],1],vD=[3,UE,CE,0,[zE,BE],[0,0]],yD=[1,UE,DT,0,()=>dD],bD=[1,UE,bE,0,()=>_D],xD=[1,UE,wE,0,()=>vD],SD=[9,UE,zT,0,()=>pD,()=>mD],CD=[9,UE,ZT,0,()=>hD,()=>gD],wD=e=>({apiVersion:`2015-12-08`,base64Decoder:e?.base64Decoder??Xx,base64Encoder:e?.base64Encoder??Qx,disableHostPrefix:e?.disableHostPrefix??!1,endpointProvider:e?.endpointProvider??nT,extensions:e?.extensions??[],httpAuthSchemeProvider:e?.httpAuthSchemeProvider??cw,httpAuthSchemes:e?.httpAuthSchemes??[{schemeId:`aws.auth#sigv4`,identityProvider:e=>e.getIdentityProvider(`aws.auth#sigv4`),signer:new Jse}],logger:e?.logger??new qx,protocol:e?.protocol??Rw,protocolSettings:e?.protocolSettings??{defaultNamespace:`com.amazonaws.acm`,errorTypeRegistries:lD,version:`2015-12-08`,serviceTarget:`CertificateManager`},serviceId:e?.serviceId??`ACM`,urlParser:e?.urlParser??jx,utf8Decoder:e?.utf8Decoder??Zx,utf8Encoder:e?.utf8Encoder??$x}),TD=e=>{let t=Hse(e),n=()=>t().then(yae),r=wD(e);return{...r,...e,runtime:`browser`,defaultsMode:t,bodyLengthChecker:e?.bodyLengthChecker??ioe,credentialDefaultProvider:e?.credentialDefaultProvider??(e=>()=>Promise.reject(Error(`Credential is missing`))),defaultUserAgentProvider:e?.defaultUserAgentProvider??Fse({serviceId:r.serviceId,clientVersion:fw.version}),maxAttempts:e?.maxAttempts??3,region:e?.region??uae(`Region is missing`),requestHandler:gw.create(e?.requestHandler??n),retryMode:e?.retryMode??(async()=>(await n()).retryMode||Yoe),sha256:e?.sha256??Nb,streamCollector:e?.streamCollector??vw,useDualstackEndpoint:e?.useDualstackEndpoint??(()=>Promise.resolve(!1)),useFipsEndpoint:e?.useFipsEndpoint??(()=>Promise.resolve(!1))}},ED=e=>{let t=e.httpAuthSchemes,n=e.httpAuthSchemeProvider,r=e.credentials;return{setHttpAuthScheme(e){let n=t.findIndex(t=>t.schemeId===e.schemeId);n===-1?t.push(e):t.splice(n,1,e)},httpAuthSchemes(){return t},setHttpAuthSchemeProvider(e){n=e},httpAuthSchemeProvider(){return n},setCredentials(e){r=e},credentials(){return r}}},DD=e=>({httpAuthSchemes:e.httpAuthSchemes(),httpAuthSchemeProvider:e.httpAuthSchemeProvider(),credentials:e.credentials()}),OD=(e,t)=>{let n=Object.assign(Wse(e),wae(e),Voe(e),ED(e));return t.forEach(e=>e.configure(n)),Object.assign(e,Gse(n),Tae(n),Hoe(n),DD(n))},kD=class extends dae{config;constructor(...[e]){let t=TD(e||{});super(t),this.initConfig=t;let n=OD(lw(Noe($oe(Bse(Zoe(xse(uw(t))))))),e?.extensions||[]);this.config=n,this.middlewareStack.use(gae(this.config)),this.middlewareStack.use(Pse(this.config)),this.middlewareStack.use(Qoe(this.config)),this.middlewareStack.use(Goe(this.config)),this.middlewareStack.use(nse(this.config)),this.middlewareStack.use(ase(this.config)),this.middlewareStack.use(ose(this.config)),this.middlewareStack.use(dse(this.config,{httpAuthSchemeParametersProvider:ow,identityProviderConfigProvider:async e=>new _se({"aws.auth#sigv4":e.credentials})})),this.middlewareStack.use(gse(this.config))}destroy(){super.destroy()}};function AD(e){return e}var jD=e=>t=>async n=>{if(!Rb.isInstance(n.request))return t(n);let{request:r}=n,{handlerProtocol:i=``}=e.requestHandler.metadata||{};if(i.indexOf(`h2`)>=0&&!r.headers[`:authority`])delete r.headers.host,r.headers[`:authority`]=r.hostname+(r.port?`:`+r.port:``);else if(!r.headers.host){let e=r.hostname;r.port!=null&&(e+=`:${r.port}`),r.headers.host=e}return t(n)},MD={name:`hostHeaderMiddleware`,step:`build`,priority:`low`,tags:[`HOST`],override:!0},ND=e=>({applyToStack:t=>{t.add(jD(e),MD)}}),PD=()=>(e,t)=>async n=>{try{let r=await e(n),{clientName:i,commandName:a,logger:o,dynamoDbDocumentClientOptions:s={}}=t,{overrideInputFilterSensitiveLog:c,overrideOutputFilterSensitiveLog:l}=s,u=c??t.inputFilterSensitiveLog,d=l??t.outputFilterSensitiveLog,{$metadata:f,...p}=r.output;return o?.info?.({clientName:i,commandName:a,input:u(n.input),output:d(p),metadata:f}),r}catch(e){let{clientName:r,commandName:i,logger:a,dynamoDbDocumentClientOptions:o={}}=t,{overrideInputFilterSensitiveLog:s}=o,c=s??t.inputFilterSensitiveLog;throw a?.error?.({clientName:r,commandName:i,input:c(n.input),error:e,metadata:e.$metadata}),e}},FD={name:`loggerMiddleware`,tags:[`LOGGER`],step:`initialize`,override:!0},ID=e=>({applyToStack:e=>{e.add(PD(),FD)}}),LD={step:`build`,tags:[`RECURSION_DETECTION`],name:`recursionDetectionMiddleware`,override:!0,priority:`low`},RD=()=>e=>async t=>e(t),zD=e=>({applyToStack:e=>{e.add(RD(),LD)}}),BD=(e,t)=>{if(!t||t.length===0)return e;let n=[];for(let r of t)for(let t of e)t.schemeId.split(`#`)[1]===r&&n.push(t);for(let t of e)n.find(({schemeId:e})=>e===t.schemeId)||n.push(t);return n};function VD(e){let t=new Map;for(let n of e)t.set(n.schemeId,n);return t}var HD=(e,t)=>(n,r)=>async i=>{let a=BD(e.httpAuthSchemeProvider(await t.httpAuthSchemeParametersProvider(e,r,i.input)),e.authSchemePreference?await e.authSchemePreference():[]),o=VD(e.httpAuthSchemes),s=lx(r),c=[];for(let n of a){let i=o.get(n.schemeId);if(!i){c.push(`HttpAuthScheme \`${n.schemeId}\` was not enabled for this service.`);continue}let a=i.identityProvider(await t.identityProviderConfigProvider(e));if(!a){c.push(`HttpAuthScheme \`${n.schemeId}\` did not have an IdentityProvider configured.`);continue}let{identityProperties:l={},signingProperties:u={}}=n.propertiesExtractor?.(e,r)||{};n.identityProperties=Object.assign(n.identityProperties||{},l),n.signingProperties=Object.assign(n.signingProperties||{},u),s.selectedHttpAuthScheme={httpAuthOption:n,identity:await a(n.identityProperties),signer:i.signer};break}if(!s.selectedHttpAuthScheme)throw Error(c.join(` +`));return n(i)},UD={step:`serialize`,tags:[`HTTP_AUTH_SCHEME`],name:`httpAuthSchemeMiddleware`,override:!0,relation:`before`,toMiddleware:`endpointV2Middleware`},WD=(e,{httpAuthSchemeParametersProvider:t,identityProviderConfigProvider:n})=>({applyToStack:r=>{r.addRelativeTo(HD(e,{httpAuthSchemeParametersProvider:t,identityProviderConfigProvider:n}),UD)}}),GD=e=>e=>{throw e},KD=(e,t)=>{},qD=e=>(e,t)=>async n=>{if(!Rb.isInstance(n.request))return e(n);let r=lx(t).selectedHttpAuthScheme;if(!r)throw Error(`No HttpAuthScheme was selected: unable to sign request`);let{httpAuthOption:{signingProperties:i={}},identity:a,signer:o}=r,s=await e({...n,request:await o.sign(n.request,a,i)}).catch((o.errorHandler||GD)(i));return(o.successHandler||KD)(s.response,i),s},JD={step:`finalizeRequest`,tags:[`HTTP_SIGNING`],name:`httpSigningMiddleware`,aliases:[`apiKeyMiddleware`,`tokenMiddleware`,`awsAuthMiddleware`],override:!0,relation:`after`,toMiddleware:`retryMiddleware`},YD=e=>({applyToStack:t=>{t.addRelativeTo(qD(e),JD)}}),XD=e=>{if(typeof e==`function`)return e;let t=Promise.resolve(e);return()=>t},ZD=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`,QD=Object.entries(ZD).reduce((e,[t,n])=>(e[n]=Number(t),e),{}),$D=ZD.split(``),eO=e=>{let t=e.length/4*3;e.slice(-2)===`==`?t-=2:e.slice(-1)===`=`&&t--;let n=new ArrayBuffer(t),r=new DataView(n);for(let t=0;t>=6;let a=t/4*3;n>>=i%8;let o=Math.floor(i/8);for(let e=0;e>t)}}return new Uint8Array(n)};function tO(e){let t;t=typeof e==`string`?Wb(e):e;let n=typeof t==`object`&&typeof t.length==`number`,r=typeof t==`object`&&typeof t.byteOffset==`number`&&typeof t.byteLength==`number`;if(!n&&!r)throw Error(`@smithy/util-base64: toBase64 encoder function only accepts string | Uint8Array.`);let i=``;for(let e=0;e>t]}i+=`==`.slice(0,4-a)}return i}var nO=class e extends Uint8Array{static fromString(t,n=`utf-8`){if(typeof t==`string`)return n===`base64`?e.mutate(eO(t)):e.mutate(Wb(t));throw Error(`Unsupported conversion from ${typeof t} to Uint8ArrayBlobAdapter.`)}static mutate(t){return Object.setPrototypeOf(t,e.prototype),t}transformToString(e=`utf-8`){return e===`base64`?tO(this):Kb(this)}},rO=e=>typeof ReadableStream==`function`&&(e?.constructor?.name===ReadableStream.name||e instanceof ReadableStream),gce=(e,t)=>{let{base64Encoder:n,bodyLengthChecker:r,checksumAlgorithmFn:i,checksumLocationName:a,streamHasher:o}=t,s=n!==void 0&&r!==void 0&&i!==void 0&&a!==void 0&&o!==void 0,c=s?o(i,e):void 0,l=e.getReader();return new ReadableStream({async pull(e){let{value:t,done:i}=await l.read();if(i){if(e.enqueue(`0\r +`),s){let t=n(await c);e.enqueue(`${a}:${t}\r\n`),e.enqueue(`\r +`)}e.close()}else e.enqueue(`${(r(t)||0).toString(16)}\r\n${t}\r\n`)}})};function iO(e){let t=[];for(let n of Object.keys(e).sort()){let r=e[n];if(n=dx(n),Array.isArray(r))for(let e=0,i=r.length;e{e&&setTimeout(()=>{let t=Error(`Request did not complete within ${e} ms`);t.name=`TimeoutError`,n(t)},e)})}var oO={supported:void 0},sO=class e{config;configProvider;static create(t){return typeof t?.handle==`function`?t:new e(t)}constructor(e){typeof e==`function`?this.configProvider=e().then(e=>e||{}):(this.config=e??{},this.configProvider=Promise.resolve(this.config)),oO.supported===void 0&&(oO.supported=typeof Request<`u`&&`keepalive`in aO(`https://[::1]`))}destroy(){}async handle(e,{abortSignal:t,requestTimeout:n}={}){this.config||=await this.configProvider;let r=n??this.config.requestTimeout,i=this.config.keepAlive===!0,a=this.config.credentials;if(t?.aborted){let e=cO(t);return Promise.reject(e)}let o=e.path,s=iO(e.query||{});s&&(o+=`?${s}`),e.fragment&&(o+=`#${e.fragment}`);let c=``;(e.username!=null||e.password!=null)&&(c=`${e.username??``}:${e.password??``}@`);let{port:l,method:u}=e,d=`${e.protocol}//${c}${e.hostname}${l?`:${l}`:``}${o}`,f=u===`GET`||u===`HEAD`?void 0:e.body,p={body:f,headers:new Headers(e.headers),method:u,credentials:a};this.config?.cache&&(p.cache=this.config.cache),f&&(p.duplex=`half`),typeof AbortController<`u`&&(p.signal=t),oO.supported&&(p.keepalive=i),typeof this.config.requestInit==`function`&&Object.assign(p,this.config.requestInit(e));let m=()=>{},h=aO(d,p),g=[fetch(h).then(e=>{let t=e.headers,n={};for(let e of t.entries())n[e[0]]=e[1];return e.body==null?e.blob().then(t=>({response:new zb({headers:n,reason:e.statusText,statusCode:e.status,body:t})})):{response:new zb({headers:n,reason:e.statusText,statusCode:e.status,body:e.body})}}),_ce(r)];return t&&g.push(new Promise((e,n)=>{let r=()=>{n(cO(t))};if(typeof t.addEventListener==`function`){let e=t;e.addEventListener(`abort`,r,{once:!0}),m=()=>e.removeEventListener(`abort`,r)}else t.onabort=r})),Promise.race(g).finally(m)}updateHttpClientConfig(e,t){this.config=void 0,this.configProvider=this.configProvider.then(n=>(n[e]=t,n))}httpHandlerConfigs(){return this.config??{}}};function cO(e){let t=e&&typeof e==`object`&&`reason`in e?e.reason:void 0;if(t){if(t instanceof Error){let e=Error(`Request aborted`);return e.name=`AbortError`,e.cause=t,e}let e=Error(String(t));return e.name=`AbortError`,e}let n=Error(`Request aborted`);return n.name=`AbortError`,n}var lO=async e=>typeof Blob==`function`&&e instanceof Blob||e.constructor?.name===`Blob`?Blob.prototype.arrayBuffer===void 0?vce(e):new Uint8Array(await e.arrayBuffer()):yce(e);async function vce(e){let t=eO(await bce(e));return new Uint8Array(t)}async function yce(e){let t=[],n=e.getReader(),r=!1,i=0;for(;!r;){let{done:e,value:a}=await n.read();a&&(t.push(a),i+=a.length),r=e}let a=new Uint8Array(i),o=0;for(let e of t)a.set(e,o),o+=e.length;return a}function bce(e){return new Promise((t,n)=>{let r=new FileReader;r.onloadend=()=>{if(r.readyState!==2)return n(Error(`Reader aborted too early`));let e=r.result??``,i=e.indexOf(`,`),a=i>-1?i+1:e.length;t(e.substring(a))},r.onabort=()=>n(Error(`Read aborted`)),r.onerror=()=>n(r.error),r.readAsDataURL(e)})}var uO=`The stream has already been transformed.`,dO=e=>{if(!fO(e)&&!rO(e)){let t=e?.__proto__?.constructor?.name||e;throw Error(`Unexpected stream implementation, expect Blob or ReadableStream, got ${t}`)}let t=!1,n=async()=>{if(t)throw Error(uO);return t=!0,await lO(e)},r=e=>{if(typeof e.stream!=`function`)throw Error(`Cannot transform payload Blob to web stream. Please make sure the Blob.stream() is polyfilled. +If you are using React Native, this API is not yet supported, see: https://react-native.canny.io/feature-requests/p/fetch-streaming-body`);return e.stream()};return Object.assign(e,{transformToByteArray:n,transformToString:async e=>{let t=await n();if(e===`base64`)return tO(t);if(e===`hex`)return Ub(t);if(e===void 0||e===`utf8`||e===`utf-8`)return Kb(t);if(typeof TextDecoder==`function`)return new TextDecoder(e).decode(t);throw Error(`TextDecoder is not available, please make sure polyfill is provided.`)},transformToWebStream:()=>{if(t)throw Error(uO);if(t=!0,fO(e))return r(e);if(rO(e))return e;throw Error(`Cannot transform payload to web stream, got ${e}`)}})},fO=e=>typeof Blob==`function`&&e instanceof Blob,pO=async(e=new Uint8Array,t)=>{if(e instanceof Uint8Array)return nO.mutate(e);if(!e)return nO.mutate(new Uint8Array);let n=t.streamCollector(e);return nO.mutate(await n)};function mO(e){return encodeURIComponent(e).replace(/[!'()*]/g,function(e){return`%`+e.charCodeAt(0).toString(16).toUpperCase()})}var hO=e=>typeof e==`function`?e():e,gO=(e,t,n,r,i)=>({name:t,namespace:e,traits:n,input:r,output:i}),xce=e=>(t,n)=>async r=>{let{response:i}=await t(r),{operationSchema:a}=lx(n),[,o,s,c,l,u]=a??[];try{return{response:i,output:await e.protocol.deserializeResponse(gO(o,s,c,l,u),{...e,...n},i)}}catch(e){if(Object.defineProperty(e,`$response`,{value:i,enumerable:!1,writable:!1,configurable:!1}),!(`$metadata`in e)){let t=`Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.`;try{e.message+=` + `+t}catch{!n.logger||n.logger?.constructor?.name===`NoOpLogger`?console.warn(t):n.logger?.warn?.(t)}e.$responseBodyText!==void 0&&e.$response&&(e.$response.body=e.$responseBodyText);try{if(zb.isInstance(i)){let{headers:t={}}=i,n=Object.entries(t);e.$metadata={httpStatusCode:i.statusCode,requestId:_O(/^x-[\w-]+-request-?id$/,n),extendedRequestId:_O(/^x-[\w-]+-id-2$/,n),cfId:_O(/^x-[\w-]+-cf-id$/,n)}}}catch{}}throw e}},_O=(e,t)=>(t.find(([t])=>t.match(e))||[void 0,void 0])[1];function Sce(e){let t={};if(e=e.replace(/^\?/,``),e)for(let n of e.split(`&`)){let[e,r=null]=n.split(`=`);e=decodeURIComponent(e),r&&=decodeURIComponent(r),e in t?Array.isArray(t[e])?t[e].push(r):t[e]=[t[e],r]:t[e]=r}return t}var vO=e=>{if(typeof e==`string`)return vO(new URL(e));let{hostname:t,pathname:n,port:r,protocol:i,search:a}=e,o;return a&&(o=Sce(a)),{hostname:t,port:r?parseInt(r):void 0,protocol:i,path:n,query:o}},Cce=e=>{if(typeof e==`object`){if(`url`in e){let t=vO(e.url);if(e.headers){t.headers={};for(let n in e.headers)t.headers[n.toLowerCase()]=e.headers[n].join(`, `)}return t}return e}return vO(e)},wce=e=>(t,n)=>async r=>{let{operationSchema:i}=lx(n),[,a,o,s,c,l]=i??[],u=n.endpointV2?async()=>Cce(n.endpointV2):e.endpoint,d=await e.protocol.serializeRequest(gO(a,o,s,c,l),r.input,{...e,...n,endpoint:u});return t({...r,request:d})},Tce={name:`deserializerMiddleware`,step:`deserialize`,tags:[`DESERIALIZER`],override:!0},Ece={name:`serializerMiddleware`,step:`serialize`,tags:[`SERIALIZER`],override:!0};function yO(e){return{applyToStack:t=>{t.add(wce(e),Ece),t.add(xce(e),Tce),e.protocol.setSerdeContext(e)}}}var bO=[];function xO(e){if(typeof e==`object`)return e;if(e|=0,bO[e])return bO[e];let t={},n=0;for(let r of[`httpLabel`,`idempotent`,`idempotencyToken`,`sensitive`,`httpPayload`,`httpResponseCode`,`httpQueryParams`])(e>>n++&1)==1&&(t[r]=1);return bO[e]=t}var SO={it:Symbol.for(`@smithy/nor-struct-it`),ns:Symbol.for(`@smithy/ns`)},CO=[],wO={},TO=class e{ref;memberName;static symbol=Symbol.for(`@smithy/nor`);symbol=e.symbol;name;schema;_isMemberSchema;traits;memberTraits;normalizedTraits;constructor(t,n){this.ref=t,this.memberName=n;let r=[],i=t,a=t;for(this._isMemberSchema=!1;DO(i);)r.push(i[1]),i=i[0],a=hO(i),this._isMemberSchema=!0;if(r.length>0){this.memberTraits={};for(let e=r.length-1;e>=0;--e){let t=r[e];Object.assign(this.memberTraits,xO(t))}}else this.memberTraits=0;if(a instanceof e){let e=this.memberTraits;Object.assign(this,a),this.memberTraits=Object.assign({},e,a.getMemberTraits(),this.getMemberTraits()),this.normalizedTraits=void 0,this.memberName=n??a.memberName;return}if(this.schema=hO(a),Dce(this.schema)?(this.name=`${this.schema[1]}#${this.schema[2]}`,this.traits=this.schema[3]):(this.name=this.memberName??String(a),this.traits=0),this._isMemberSchema&&!n)throw Error(`@smithy/core/schema - NormalizedSchema member init ${this.getName(!0)} missing member name.`)}static[Symbol.hasInstance](e){let t=this.prototype.isPrototypeOf(e);return!t&&typeof e==`object`&&e?e.symbol===this.symbol:t}static of(t){let n=typeof t==`function`||typeof t==`object`&&!!t;if(typeof t==`number`){if(CO[t])return CO[t]}else if(typeof t==`string`){if(wO[t])return wO[t]}else if(n&&t[SO.ns])return t[SO.ns];let r=hO(t);if(r instanceof e)return r;if(DO(r)){let[n,i]=r;if(n instanceof e)return Object.assign(n.getMergedTraits(),xO(i)),n;throw Error(`@smithy/core/schema - may not init unwrapped member schema=${JSON.stringify(t,null,2)}.`)}let i=new e(r);return n?t[SO.ns]=i:typeof r==`string`?wO[r]=i:typeof r==`number`?CO[r]=i:i}getSchema(){let e=this.schema;return Array.isArray(e)&&e[0]===0?e[4]:e}getName(e=!1){let{name:t}=this;return!e&&t&&t.includes(`#`)?t.split(`#`)[1]:t||void 0}getMemberName(){return this.memberName}isMemberSchema(){return this._isMemberSchema}isListSchema(){let e=this.getSchema();return typeof e==`number`?e>=64&&e<128:e[0]===1}isMapSchema(){let e=this.getSchema();return typeof e==`number`?e>=128&&e<=255:e[0]===2}isStructSchema(){let e=this.getSchema();if(typeof e!=`object`)return!1;let t=e[0];return t===3||t===-3||t===4}isUnionSchema(){let e=this.getSchema();return typeof e==`object`?e[0]===4:!1}isBlobSchema(){let e=this.getSchema();return e===21||e===42}isTimestampSchema(){let e=this.getSchema();return typeof e==`number`&&e>=4&&e<=7}isUnitSchema(){return this.getSchema()===`unit`}isDocumentSchema(){return this.getSchema()===15}isStringSchema(){return this.getSchema()===0}isBooleanSchema(){return this.getSchema()===2}isNumericSchema(){return this.getSchema()===1}isBigIntegerSchema(){return this.getSchema()===17}isBigDecimalSchema(){return this.getSchema()===19}isStreaming(){let{streaming:e}=this.getMergedTraits();return!!e||this.getSchema()===42}isIdempotencyToken(){return!!this.getMergedTraits().idempotencyToken}getMergedTraits(){return this.normalizedTraits??={...this.getOwnTraits(),...this.getMemberTraits()}}getMemberTraits(){return xO(this.memberTraits)}getOwnTraits(){return xO(this.traits)}getKeySchema(){let[e,t]=[this.isDocumentSchema(),this.isMapSchema()];if(!e&&!t)throw Error(`@smithy/core/schema - cannot get key for non-map: ${this.getName(!0)}`);let n=this.getSchema();return EO([e?15:n[4]??0,0],`key`)}getValueSchema(){let e=this.getSchema(),[t,n,r]=[this.isDocumentSchema(),this.isMapSchema(),this.isListSchema()],i=typeof e==`number`?63&e:e&&typeof e==`object`&&(n||r)?e[3+e[0]]:t?15:void 0;if(i!=null)return EO([i,0],n?`value`:`member`);throw Error(`@smithy/core/schema - ${this.getName(!0)} has no value member.`)}getMemberSchema(e){let t=this.getSchema();if(this.isStructSchema()&&t[4].includes(e)){let n=t[4].indexOf(e),r=t[5][n];return EO(DO(r)?r:[r,0],e)}if(this.isDocumentSchema())return EO([15,0],e);throw Error(`@smithy/core/schema - ${this.getName(!0)} has no member=${e}.`)}getMemberSchemas(){let e={};try{for(let[t,n]of this.structIterator())e[t]=n}catch{}return e}getEventStreamMember(){if(this.isStructSchema()){for(let[e,t]of this.structIterator())if(t.isStreaming()&&t.isStructSchema())return e}return``}*structIterator(){if(this.isUnitSchema())return;if(!this.isStructSchema())throw Error(`@smithy/core/schema - cannot iterate non-struct schema.`);let e=this.getSchema(),t=e[4].length,n=e[SO.it];if(n&&t===n.length){yield*n;return}n=Array(t);for(let r=0;rArray.isArray(e)&&e.length===2,Dce=e=>Array.isArray(e)&&e.length>=5,OO=class e{namespace;schemas;exceptions;static registries=new Map;constructor(e,t=new Map,n=new Map){this.namespace=e,this.schemas=t,this.exceptions=n}static for(t){return e.registries.has(t)||e.registries.set(t,new e(t)),e.registries.get(t)}copyFrom(e){let{schemas:t,exceptions:n}=this;for(let[n,r]of e.schemas)t.has(n)||t.set(n,r);for(let[t,r]of e.exceptions)n.has(t)||n.set(t,r)}register(t,n){let r=this.normalizeShapeId(t);for(let t of[this,e.for(r.split(`#`)[0])])t.schemas.set(r,n)}getSchema(e){let t=this.normalizeShapeId(e);if(!this.schemas.has(t))throw Error(`@smithy/core/schema - schema not found for ${t}`);return this.schemas.get(t)}registerError(t,n){let r=t,i=r[1];for(let t of[this,e.for(i)])t.schemas.set(i+`#`+r[2],r),t.exceptions.set(r,n)}getErrorCtor(t){let n=t;return this.exceptions.has(n)?this.exceptions.get(n):e.for(n[1]).exceptions.get(n)}getBaseException(){for(let e of this.exceptions.keys())if(Array.isArray(e)){let[,t,n]=e,r=t+`#`+n;if(r.startsWith(`smithy.ts.sdk.synthetic.`)&&r.endsWith(`ServiceException`))return e}}find(e){for(let t of this.schemas.values())if(e(t))return t}clear(){this.schemas.clear(),this.exceptions.clear()}normalizeShapeId(e){return e.includes(`#`)?e:this.namespace+`#`+e}},Oce=e=>{if(e!=null){if(typeof e==`string`){let t=parseFloat(e);if(!Number.isNaN(t))return String(t)!==String(e)&&zce.warn(Rce(`Expected number but observed string: ${e}`)),t}if(typeof e==`number`)return e;throw TypeError(`Expected number, got ${typeof e}: ${e}`)}},kce=Math.ceil(2**127*(2-2**-23)),Ace=e=>{let t=Oce(e);if(t!==void 0&&!Number.isNaN(t)&&t!==1/0&&t!==-1/0&&Math.abs(t)>kce)throw TypeError(`Expected 32-bit float, got ${e}`);return t},jce=e=>{if(e!=null){if(Number.isInteger(e)&&!Number.isNaN(e))return e;throw TypeError(`Expected integer, got ${typeof e}: ${e}`)}},Mce=e=>kO(e,16),Nce=e=>kO(e,8),kO=(e,t)=>{let n=jce(e);if(n!==void 0&&Pce(n,t)!==n)throw TypeError(`Expected ${t}-bit integer, got ${e}`);return n},Pce=(e,t)=>{switch(t){case 32:return Int32Array.of(e)[0];case 16:return Int16Array.of(e)[0];case 8:return Int8Array.of(e)[0]}},Fce=e=>Ace(typeof e==`string`?AO(e):e),Ice=/(-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?)|(-?Infinity)|(NaN)/g,AO=e=>{let t=e.match(Ice);if(t===null||t[0].length!==e.length)throw TypeError(`Expected real number, got implicit NaN`);return parseFloat(e)},jO=e=>Mce(typeof e==`string`?AO(e):e),Lce=e=>Nce(typeof e==`string`?AO(e):e),Rce=e=>String(TypeError(e).stack||e).split(` +`).slice(0,5).filter(e=>!e.includes(`stackTraceWarning`)).join(` +`),zce={warn:console.warn},Bce=[`Sun`,`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`],MO=[`Jan`,`Feb`,`Mar`,`Apr`,`May`,`Jun`,`Jul`,`Aug`,`Sep`,`Oct`,`Nov`,`Dec`];function NO(e){let t=e.getUTCFullYear(),n=e.getUTCMonth(),r=e.getUTCDay(),i=e.getUTCDate(),a=e.getUTCHours(),o=e.getUTCMinutes(),s=e.getUTCSeconds(),c=i<10?`0${i}`:`${i}`,l=a<10?`0${a}`:`${a}`,u=o<10?`0${o}`:`${o}`,d=s<10?`0${s}`:`${s}`;return`${Bce[r]}, ${c} ${MO[n]} ${t} ${l}:${u}:${d} GMT`}var Vce=new RegExp(/^(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d{2}) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d{1,2}):(\d{2}):(\d{2})(?:\.(\d+))? GMT$/),Hce=new RegExp(/^(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (\d{2})-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d{2}) (\d{1,2}):(\d{2}):(\d{2})(?:\.(\d+))? GMT$/),Uce=new RegExp(/^(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ( [1-9]|\d{2}) (\d{1,2}):(\d{2}):(\d{2})(?:\.(\d+))? (\d{4})$/),PO=e=>{if(e==null)return;if(typeof e!=`string`)throw TypeError(`RFC-7231 date-times must be expressed as strings`);let t=Vce.exec(e);if(t){let[e,n,r,i,a,o,s,c]=t;return FO(jO(RO(i)),IO(r),LO(n,`day`,1,31),{hours:a,minutes:o,seconds:s,fractionalMilliseconds:c})}if(t=Hce.exec(e),t){let[e,n,r,i,a,o,s,c]=t;return Kce(FO(Wce(i),IO(r),LO(n,`day`,1,31),{hours:a,minutes:o,seconds:s,fractionalMilliseconds:c}))}if(t=Uce.exec(e),t){let[e,n,r,i,a,o,s,c]=t;return FO(jO(RO(c)),IO(n),LO(r.trimLeft(),`day`,1,31),{hours:i,minutes:a,seconds:o,fractionalMilliseconds:s})}throw TypeError(`Invalid RFC-7231 date-time value`)},FO=(e,t,n,r)=>{let i=t-1;return Jce(e,i,n),new Date(Date.UTC(e,i,n,LO(r.hours,`hour`,0,23),LO(r.minutes,`minute`,0,59),LO(r.seconds,`seconds`,0,60),Xce(r.fractionalMilliseconds)))},Wce=e=>{let t=new Date().getUTCFullYear(),n=Math.floor(t/100)*100+jO(RO(e));return ne.getTime()-new Date().getTime()>Gce?new Date(Date.UTC(e.getUTCFullYear()-100,e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds(),e.getUTCMilliseconds())):e,IO=e=>{let t=MO.indexOf(e);if(t<0)throw TypeError(`Invalid month: ${e}`);return t+1},qce=[31,28,31,30,31,30,31,31,30,31,30,31],Jce=(e,t,n)=>{let r=qce[t];if(t===1&&Yce(e)&&(r=29),n>r)throw TypeError(`Invalid day for ${MO[t]} in ${e}: ${n}`)},Yce=e=>e%4==0&&(e%100!=0||e%400==0),LO=(e,t,n,r)=>{let i=Lce(RO(e));if(ir)throw TypeError(`${t} must be between ${n} and ${r}, inclusive`);return i},Xce=e=>e==null?0:Fce(`0.`+e)*1e3,RO=e=>{let t=0;for(;tt.toString(16).padStart(2,`0`)),VO=()=>{if(zO)return zO();let e=new Uint8Array(16);return crypto.getRandomValues(e),e[6]=e[6]&15|64,e[8]=e[8]&63|128,BO[e[0]]+BO[e[1]]+BO[e[2]]+BO[e[3]]+`-`+BO[e[4]]+BO[e[5]]+`-`+BO[e[6]]+BO[e[7]]+`-`+BO[e[8]]+BO[e[9]]+`-`+BO[e[10]]+BO[e[11]]+BO[e[12]]+BO[e[13]]+BO[e[14]]+BO[e[15]]},HO=function(e){return Object.assign(new String(e),{deserializeJSON(){return JSON.parse(String(e))},toString(){return String(e)},toJSON(){return String(e)}})};HO.from=e=>e&&typeof e==`object`&&(e instanceof HO||`deserializeJSON`in e)?e:typeof e==`string`||Object.getPrototypeOf(e)===String.prototype?HO(String(e)):HO(JSON.stringify(e)),HO.fromObject=HO.from;function Zce(e){return(e.includes(`,`)||e.includes(`"`))&&(e=`"${e.replace(/"/g,`\\"`)}"`),e}var UO=`(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)(?:[ne|u?r]?s?day)?`,WO=`(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)`,GO=`(\\d?\\d):(\\d{2}):(\\d{2})(?:\\.(\\d+))?`,KO=`(\\d?\\d)`,qO=`(\\d{4})`,Qce=new RegExp(/^(\d{4})-(\d\d)-(\d\d)[tT](\d\d):(\d\d):(\d\d)(\.(\d+))?(([-+]\d\d:\d\d)|[zZ])$/),$ce=RegExp(`^${UO}, ${KO} ${WO} ${qO} ${GO} GMT$`),ele=RegExp(`^${UO}, ${KO}-${WO}-(\\d\\d) ${GO} GMT$`),tle=RegExp(`^${UO} ${WO} ( [1-9]|\\d\\d) ${GO} ${qO}$`),nle=[`Jan`,`Feb`,`Mar`,`Apr`,`May`,`Jun`,`Jul`,`Aug`,`Sep`,`Oct`,`Nov`,`Dec`],rle=e=>{if(e==null)return;let t=NaN;if(typeof e==`number`)t=e;else if(typeof e==`string`){if(!/^-?\d*\.?\d+$/.test(e))throw TypeError(`parseEpochTimestamp - numeric string invalid.`);t=Number.parseFloat(e)}else typeof e==`object`&&e.tag===1&&(t=e.value);if(isNaN(t)||Math.abs(t)===1/0)throw TypeError(`Epoch timestamps must be valid finite numbers.`);return new Date(Math.round(t*1e3))},ile=e=>{if(e==null)return;if(typeof e!=`string`)throw TypeError(`RFC3339 timestamps must be strings`);let t=Qce.exec(e);if(!t)throw TypeError(`Invalid RFC3339 timestamp format ${e}`);let[,n,r,i,a,o,s,,c,l]=t;JO(r,1,12),JO(i,1,31),JO(a,0,23),JO(o,0,59),JO(s,0,60);let u=new Date(Date.UTC(Number(n),Number(r)-1,Number(i),Number(a),Number(o),Number(s),Number(c)?Math.round(parseFloat(`0.${c}`)*1e3):0));if(u.setUTCFullYear(Number(n)),l.toUpperCase()!=`Z`){let[,e,t,n]=/([+-])(\d\d):(\d\d)/.exec(l)||[void 0,`+`,0,0],r=e===`-`?1:-1;u.setTime(u.getTime()+r*(Number(t)*60*60*1e3+Number(n)*60*1e3))}return u},ale=e=>{if(e==null)return;if(typeof e!=`string`)throw TypeError(`RFC7231 timestamps must be strings.`);let t,n,r,i,a,o,s,c;if((c=$ce.exec(e))?[,t,n,r,i,a,o,s]=c:(c=ele.exec(e))?([,t,n,r,i,a,o,s]=c,r=(Number(r)+1900).toString()):(c=tle.exec(e))&&([,n,t,i,a,o,s,r]=c),r&&o){let e=Date.UTC(Number(r),nle.indexOf(n),Number(t),Number(i),Number(a),Number(o),s?Math.round(parseFloat(`0.${s}`)*1e3):0);JO(t,1,31),JO(i,0,23),JO(a,0,59),JO(o,0,60);let c=new Date(e);return c.setUTCFullYear(Number(r)),c}throw TypeError(`Invalid RFC7231 date-time value ${e}.`)};function JO(e,t,n){let r=Number(e);if(rn)throw Error(`Value ${r} out of range [${t}, ${n}]`)}function ole(e,t,n){if(n<=0||!Number.isInteger(n))throw Error(`Invalid number of delimiters (`+n+`) for splitEvery.`);let r=e.split(t);if(n===1)return r;let i=[],a=``;for(let e=0;e{let t=e.length,n=[],r=!1,i,a=0;for(let o=0;o{e=e.trim();let t=e.length;return t<2?e:(e[0]===`"`&&e[t-1]===`"`&&(e=e.slice(1,t-1)),e.replace(/\\"/g,`"`))})},XO=/^-?\d*(\.\d+)?$/,ZO=class e{string;type;constructor(e,t){if(this.string=e,this.type=t,!XO.test(e))throw Error(`@smithy/core/serde - NumericValue must only contain [0-9], at most one decimal point ".", and an optional negation prefix "-".`)}toString(){return this.string}static[Symbol.hasInstance](t){if(!t||typeof t!=`object`)return!1;let n=t;return e.prototype.isPrototypeOf(t)||n.type===`bigDecimal`&&XO.test(n.string)}},QO=class{serdeContext;setSerdeContext(e){this.serdeContext=e}},$O=class extends QO{options;compositeErrorRegistry;constructor(e){super(),this.options=e,this.compositeErrorRegistry=OO.for(e.defaultNamespace);for(let t of e.errorTypeRegistries??[])this.compositeErrorRegistry.copyFrom(t)}getRequestType(){return Rb}getResponseType(){return zb}setSerdeContext(e){this.serdeContext=e,this.serializer.setSerdeContext(e),this.deserializer.setSerdeContext(e),this.getPayloadCodec()&&this.getPayloadCodec().setSerdeContext(e)}updateServiceEndpoint(e,t){if(`url`in t){e.protocol=t.url.protocol,e.hostname=t.url.hostname,e.port=t.url.port?Number(t.url.port):void 0,e.path=t.url.pathname,e.fragment=t.url.hash||void 0,e.username=t.url.username||void 0,e.password=t.url.password||void 0,e.query||={};for(let[n,r]of t.url.searchParams.entries())e.query[n]=r;if(t.headers)for(let n in t.headers)e.headers[n]=t.headers[n].join(`, `);return e}else{if(e.protocol=t.protocol,e.hostname=t.hostname,e.port=t.port?Number(t.port):void 0,e.path=t.path,e.query={...t.query},t.headers)for(let n in t.headers)e.headers[n]=t.headers[n];return e}}setHostPrefix(e,t,n){if(this.serdeContext?.disableHostPrefix)return;let r=TO.of(t.input),i=xO(t.traits??{});if(i.endpoint){let t=i.endpoint?.[0];if(typeof t==`string`){for(let[e,i]of r.structIterator()){if(!i.getMergedTraits().hostLabel)continue;let r=n[e];if(typeof r!=`string`)throw Error(`@smithy/core/schema - ${e} in input must be a string as hostLabel.`);t=t.replace(`{${e}}`,r)}e.hostname=t+e.hostname}}}deserializeMetadata(e){return{httpStatusCode:e.statusCode,requestId:e.headers[`x-amzn-requestid`]??e.headers[`x-amzn-request-id`]??e.headers[`x-amz-request-id`],extendedRequestId:e.headers[`x-amz-id-2`],cfId:e.headers[`x-amz-cf-id`]}}async serializeEventStream({eventStream:e,requestSchema:t,initialRequest:n}){return(await this.loadEventStreamCapability()).serializeEventStream({eventStream:e,requestSchema:t,initialRequest:n})}async deserializeEventStream({response:e,responseSchema:t,initialResponseContainer:n}){return(await this.loadEventStreamCapability()).deserializeEventStream({response:e,responseSchema:t,initialResponseContainer:n})}async loadEventStreamCapability(){let{EventStreamSerde:e}=await US(async()=>{let{EventStreamSerde:e}=await import(`./event-streams.js`);return{EventStreamSerde:e}},[]);return new e({marshaller:this.getEventStreamMarshaller(),serializer:this.serializer,deserializer:this.deserializer,serdeContext:this.serdeContext,defaultContentType:this.getDefaultContentType()})}getDefaultContentType(){throw Error(`@smithy/core/protocols - ${this.constructor.name} getDefaultContentType() implementation missing.`)}async deserializeHttpMessage(e,t,n,r,i){return[]}getEventStreamMarshaller(){let e=this.serdeContext;if(!e.eventStreamMarshaller)throw Error(`@smithy/core - HttpProtocol: eventStreamMarshaller missing in serdeContext.`);return e.eventStreamMarshaller}},sle=class extends $O{async serializeRequest(e,t,n){let r=t&&typeof t==`object`?t:{},i=this.serializer,a={},o={},s=await n.endpoint(),c=TO.of(e?.input),l=[],u=[],d=!1,f,p=new Rb({protocol:``,hostname:``,port:void 0,path:``,fragment:void 0,query:a,headers:o,body:void 0});if(s){this.updateServiceEndpoint(p,s),this.setHostPrefix(p,e,r);let t=xO(e.traits);if(t.http){p.method=t.http[0];let[e,n]=t.http[1].split(`?`);p.path==`/`?p.path=e:p.path+=e;let r=new URLSearchParams(n??``);for(let[e,t]of r)a[e]=t}}for(let[e,t]of c.structIterator()){let n=t.getMergedTraits()??{},s=r[e];if(s==null&&!t.isIdempotencyToken()){if(n.httpLabel&&(p.path.includes(`{${e}+}`)||p.path.includes(`{${e}}`)))throw Error(`No value provided for input HTTP label: ${e}.`);continue}if(n.httpPayload)t.isStreaming()?t.isStructSchema()?r[e]&&(f=await this.serializeEventStream({eventStream:r[e],requestSchema:c})):f=s:(i.write(t,s),f=i.flush());else if(n.httpLabel){i.write(t,s);let n=i.flush();p.path.includes(`{${e}+}`)?p.path=p.path.replace(`{${e}+}`,n.split(`/`).map(mO).join(`/`)):p.path.includes(`{${e}}`)&&(p.path=p.path.replace(`{${e}}`,mO(n)))}else if(n.httpHeader)i.write(t,s),o[n.httpHeader.toLowerCase()]=String(i.flush());else if(typeof n.httpPrefixHeaders==`string`)for(let e in s){let r=s[e],a=n.httpPrefixHeaders+e;i.write([t.getValueSchema(),{httpHeader:a}],r),o[a.toLowerCase()]=i.flush()}else n.httpQuery||n.httpQueryParams?this.serializeQuery(t,s,a):(d=!0,l.push(e),u.push(t))}if(d&&r){let[e,t]=(c.getName(!0)??`#Unknown`).split(`#`),n=c.getSchema()[6],a=[3,e,t,c.getMergedTraits(),l,u,void 0];n?a[6]=n:a.pop(),i.write(a,r),f=i.flush()}return p.headers=o,p.query=a,p.body=f,p}serializeQuery(e,t,n){let r=this.serializer,i=e.getMergedTraits();if(i.httpQueryParams){for(let r in t)if(!(r in n)){let a=t[r],o=e.getValueSchema();Object.assign(o.getMergedTraits(),{...i,httpQuery:r,httpQueryParams:void 0}),this.serializeQuery(o,a,n)}return}if(e.isListSchema()){let a=!!e.getMergedTraits().sparse,o=[];for(let n of t){r.write([e.getValueSchema(),i],n);let t=r.flush();(a||t!==void 0)&&o.push(t)}n[i.httpQuery]=o}else r.write([e,i],t),n[i.httpQuery]=r.flush()}async deserializeResponse(e,t,n){let r=this.deserializer,i=TO.of(e.output),a={};if(n.statusCode>=300){let i=await pO(n.body,t);throw i.byteLength>0&&Object.assign(a,await r.read(15,i)),await this.handleError(e,t,n,a,this.deserializeMetadata(n)),Error(`@smithy/core/protocols - HTTP Protocol error handler failed to throw.`)}for(let e in n.headers){let t=n.headers[e];delete n.headers[e],n.headers[e.toLowerCase()]=t}let o=await this.deserializeHttpMessage(i,t,n,a);if(o.length){let e=await pO(n.body,t);if(e.byteLength>0){let t=await r.read(i,e);for(let e of o)t[e]!=null&&(a[e]=t[e])}}else o.discardResponseBody&&await pO(n.body,t);return a.$metadata=this.deserializeMetadata(n),a}async deserializeHttpMessage(e,t,n,r,i){let a;a=r instanceof Set?i:r;let o=!0,s=this.deserializer,c=TO.of(e),l=[];for(let[e,r]of c.structIterator()){let i=r.getMemberTraits();if(i.httpPayload){if(o=!1,r.isStreaming())r.isStructSchema()?a[e]=await this.deserializeEventStream({response:n,responseSchema:c}):a[e]=dO(n.body);else if(n.body){let i=await pO(n.body,t);i.byteLength>0&&(a[e]=await s.read(r,i))}}else if(i.httpHeader){let t=String(i.httpHeader).toLowerCase(),o=n.headers[t];if(o!=null)if(r.isListSchema()){let n=r.getValueSchema();n.getMergedTraits().httpHeader=t;let i;i=n.isTimestampSchema()&&n.getSchema()===4?ole(o,`,`,2):YO(o);let c=[];for(let e of i)c.push(await s.read(n,e.trim()));a[e]=c}else a[e]=await s.read(r,o)}else if(i.httpPrefixHeaders!==void 0){a[e]={};for(let t in n.headers)if(t.startsWith(i.httpPrefixHeaders)){let o=n.headers[t],c=r.getValueSchema();c.getMergedTraits().httpHeader=t,a[e][t.slice(i.httpPrefixHeaders.length)]=await s.read(c,o)}}else i.httpResponseCode?a[e]=n.statusCode:l.push(e)}return l.discardResponseBody=o,l}},cle=class extends $O{async serializeRequest(e,t,n){let r=this.serializer,i={},a={},o=await n.endpoint(),s=TO.of(e?.input),c=s.getSchema(),l,u=t&&typeof t==`object`?t:{},d=new Rb({protocol:``,hostname:``,port:void 0,path:`/`,fragment:void 0,query:i,headers:a,body:void 0});if(o&&(this.updateServiceEndpoint(d,o),this.setHostPrefix(d,e,u)),u){let e=s.getEventStreamMember();if(e){if(u[e]){let t={};for(let[n,i]of s.structIterator())n!==e&&u[n]&&(r.write(i,u[n]),t[n]=r.flush());l=await this.serializeEventStream({eventStream:u[e],requestSchema:s,initialRequest:t})}}else r.write(c,u),l=r.flush()}return d.headers=Object.assign(d.headers,a),d.query=i,d.body=l,d.method=`POST`,d}async deserializeResponse(e,t,n){let r=this.deserializer,i=TO.of(e.output),a={};if(n.statusCode>=300){let i=await pO(n.body,t);throw i.byteLength>0&&Object.assign(a,await r.read(15,i)),await this.handleError(e,t,n,a,this.deserializeMetadata(n)),Error(`@smithy/core/protocols - RPC Protocol error handler failed to throw.`)}for(let e in n.headers){let t=n.headers[e];delete n.headers[e],n.headers[e.toLowerCase()]=t}let o=i.getEventStreamMember();if(o)a[o]=await this.deserializeEventStream({response:n,responseSchema:i,initialResponseContainer:a});else{let e=await pO(n.body,t);e.byteLength>0&&Object.assign(a,await r.read(i,e))}return a.$metadata=this.deserializeMetadata(n),a}};function ek(e,t){if(t.timestampFormat.useTrait&&e.isTimestampSchema()&&(e.getSchema()===5||e.getSchema()===6||e.getSchema()===7))return e.getSchema();let{httpLabel:n,httpPrefixHeaders:r,httpHeader:i,httpQuery:a}=e.getMergedTraits();return(t.httpBindings?typeof r==`string`||i?6:a||n?5:void 0:void 0)??t.timestampFormat.default}var tk=class extends QO{settings;constructor(e){super(),this.settings=e}read(e,t){let n=TO.of(e);if(n.isListSchema())return YO(t).map(e=>this.read(n.getValueSchema(),e));if(n.isBlobSchema())return(this.serdeContext?.base64Decoder??eO)(t);if(n.isTimestampSchema())switch(ek(n,this.settings)){case 5:return ile(t);case 6:return ale(t);case 7:return rle(t);default:return console.warn(`Missing timestamp format, parsing value with Date constructor:`,t),new Date(t)}if(n.isStringSchema()){let e=n.getMergedTraits().mediaType,r=t;if(e)return n.getMergedTraits().httpHeader&&(r=this.base64ToUtf8(r)),(e===`application/json`||e.endsWith(`+json`))&&(r=HO.from(r)),r}return n.isNumericSchema()?Number(t):n.isBigIntegerSchema()?BigInt(t):n.isBigDecimalSchema()?new ZO(t,`bigDecimal`):n.isBooleanSchema()?String(t).toLowerCase()===`true`:t}base64ToUtf8(e){return(this.serdeContext?.utf8Encoder??Kb)((this.serdeContext?.base64Decoder??eO)(e))}},lle=class extends QO{codecDeserializer;stringDeserializer;constructor(e,t){super(),this.codecDeserializer=e,this.stringDeserializer=new tk(t)}setSerdeContext(e){this.stringDeserializer.setSerdeContext(e),this.codecDeserializer.setSerdeContext(e),this.serdeContext=e}read(e,t){let n=TO.of(e),r=n.getMergedTraits(),i=this.serdeContext?.utf8Encoder??Kb;if(r.httpHeader||r.httpResponseCode)return this.stringDeserializer.read(n,i(t));if(r.httpPayload){if(n.isBlobSchema()){let e=this.serdeContext?.utf8Decoder??Wb;return typeof t==`string`?e(t):t}else if(n.isStringSchema())return`byteLength`in t?i(t):t}return this.codecDeserializer.read(n,t)}},ule=class extends QO{settings;stringBuffer=``;constructor(e){super(),this.settings=e}write(e,t){let n=TO.of(e);switch(typeof t){case`object`:if(t===null){this.stringBuffer=`null`;return}if(n.isTimestampSchema()){if(!(t instanceof Date))throw Error(`@smithy/core/protocols - received non-Date value ${t} when schema expected Date in ${n.getName(!0)}`);switch(ek(n,this.settings)){case 5:this.stringBuffer=t.toISOString().replace(`.000Z`,`Z`);break;case 6:this.stringBuffer=NO(t);break;case 7:this.stringBuffer=String(t.getTime()/1e3);break;default:console.warn(`Missing timestamp format, using epoch seconds`,t),this.stringBuffer=String(t.getTime()/1e3)}return}if(n.isBlobSchema()&&`byteLength`in t){this.stringBuffer=(this.serdeContext?.base64Encoder??tO)(t);return}if(n.isListSchema()&&Array.isArray(t)){let e=``;for(let r of t){this.write([n.getValueSchema(),n.getMergedTraits()],r);let t=this.flush(),i=n.getValueSchema().isTimestampSchema()?t:Zce(t);e!==``&&(e+=`, `),e+=i}this.stringBuffer=e;return}this.stringBuffer=JSON.stringify(t,null,2);break;case`string`:let e=n.getMergedTraits().mediaType,r=t;if(e&&((e===`application/json`||e.endsWith(`+json`))&&(r=HO.from(r)),n.getMergedTraits().httpHeader)){this.stringBuffer=(this.serdeContext?.base64Encoder??tO)(r.toString());return}this.stringBuffer=t;break;default:n.isIdempotencyToken()?this.stringBuffer=VO():this.stringBuffer=String(t)}}flush(){let e=this.stringBuffer;return this.stringBuffer=``,e}},dle=class{codecSerializer;stringSerializer;buffer;constructor(e,t,n=new ule(t)){this.codecSerializer=e,this.stringSerializer=n}setSerdeContext(e){this.codecSerializer.setSerdeContext(e),this.stringSerializer.setSerdeContext(e)}write(e,t){let n=TO.of(e),r=n.getMergedTraits();if(r.httpHeader||r.httpLabel||r.httpQuery){this.stringSerializer.write(n,t),this.buffer=this.stringSerializer.flush();return}return this.codecSerializer.write(n,t)}flush(){if(this.buffer!==void 0){let e=this.buffer;return this.buffer=void 0,e}return this.codecSerializer.flush()}};function fle(e,t,n){e.__smithy_context?e.__smithy_context.features||(e.__smithy_context.features={}):e.__smithy_context={features:{}},e.__smithy_context.features[t]=n}var nk=class{authSchemes=new Map;constructor(e){for(let t in e){let n=e[t];n!==void 0&&this.authSchemes.set(t,n)}}getIdentityProvider(e){return this.authSchemes.get(e)}},ple=(e=>function(t){return rk(t)&&t.expiration.getTime()-Date.now()e.expiration!==void 0,mle=(e,t,n)=>{if(e===void 0)return;let r=typeof e==`function`?e:async()=>Promise.resolve(e),i,a,o,s=!1,c=async e=>{a||=r(e);try{i=await a,o=!0,s=!1}finally{a=void 0}return i};return t===void 0?async e=>((!o||e?.forceRefresh)&&(i=await c(e)),i):async e=>((!o||e?.forceRefresh)&&(i=await c(e)),s?i:n(i)?(t(i)&&await c(e),i):(s=!0,i))};function hle(e){return e===void 0?!0:typeof e==`string`&&e.length<=50}function ik(e){let t=XD(e.userAgentAppId??void 0),{customUserAgent:n}=e;return Object.assign(e,{customUserAgent:typeof n==`string`?[[n]]:n,userAgentAppId:async()=>{let n=await t();if(!hle(n)){let t=e.logger?.constructor?.name===`NoOpLogger`||!e.logger?console:e.logger;typeof n==`string`?n.length>50&&t?.warn(`The provided userAgentAppId exceeds the maximum length of 50 characters.`):t?.warn(`userAgentAppId must be a string or undefined.`)}return n}})}var ak=class e{nodes;root;conditions;results;constructor(e,t,n,r){this.nodes=e,this.root=t,this.conditions=n,this.results=r}static from(t,n,r,i){return new e(t,n,r,i)}},ok=class{capacity;data=new Map;parameters=[];constructor({size:e,params:t}){this.capacity=e??50,t&&(this.parameters=t)}get(e,t){let n=this.hash(e);if(n===!1)return t();if(!this.data.has(n)){if(this.data.size>this.capacity+10){let e=this.data.keys(),t=0;for(;;){let{value:n,done:r}=e.next();if(this.data.delete(n),r||++t>10)break}}this.data.set(n,t())}return this.data.get(n)}size(){return this.data.size}hash(e){let t=``,{parameters:n}=this;if(n.length===0)return!1;for(let r of n){let n=String(e[r]??``);if(n.includes(`|;`))return!1;t+=n+`|;`}return t}},sk=class extends Error{constructor(e){super(e),this.name=`EndpointError`}},gle=`endpoints`;function ck(e){return typeof e!=`object`||!e?e:`ref`in e?`$${ck(e.ref)}`:`fn`in e?`${e.fn}(${(e.argv||[]).map(ck).join(`, `)})`:JSON.stringify(e,null,2)}var lk={},_le=(e,t)=>e===t;function vle(...e){for(let t of e)if(t!=null)return t}var yle=e=>{let t=e.split(`.`),n=[];for(let r of t){let t=r.indexOf(`[`);if(t!==-1){if(r.indexOf(`]`)!==r.length-1)throw new sk(`Path: '${e}' does not end with ']'`);let i=r.slice(t+1,-1);if(Number.isNaN(parseInt(i)))throw new sk(`Invalid array index: '${i}' in path: '${e}'`);t!==0&&n.push(r.slice(0,t)),n.push(i)}else n.push(r)}return n},uk=(e,t)=>yle(t).reduce((n,r)=>{if(typeof n!=`object`)throw new sk(`Index '${r}' in '${t}' not found in '${JSON.stringify(e)}'`);if(Array.isArray(n)){let e=parseInt(r);return n[e<0?n.length+e:e]}return n[r]},e),ble=e=>e!=null,xle=RegExp(`^(?!.*-$)(?!-)[a-zA-Z0-9-]{1,63}$`),dk=(e,t=!1)=>{if(!t)return xle.test(e);let n=e.split(`.`);for(let e of n)if(!dk(e))return!1;return!0};function Sle(e,t,n){return e?t:n}var Cle=e=>!e,wle=RegExp(`^(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}$`),fk=e=>wle.test(e)||e.startsWith(`[`)&&e.endsWith(`]`),pk={[Ib.HTTP]:80,[Ib.HTTPS]:443},Tle=e=>{let t=(()=>{try{if(e instanceof URL)return e;if(typeof e==`object`&&`hostname`in e){let{hostname:t,port:n,protocol:r=``,path:i=``,query:a={}}=e,o=new URL(`${r}//${t}${n?`:${n}`:``}${i}`);return o.search=Object.entries(a).map(([e,t])=>`${e}=${t}`).join(`&`),o}return new URL(e)}catch{return null}})();if(!t)return console.error(`Unable to parse ${JSON.stringify(e)} as a whatwg URL.`),null;let n=t.href,{host:r,hostname:i,pathname:a,protocol:o,search:s}=t;if(s)return null;let c=o.slice(0,-1);if(!Object.values(Ib).includes(c))return null;let l=fk(i);return{scheme:c,authority:`${r}${n.includes(`${r}:${pk[c]}`)||typeof e==`string`&&e.includes(`${r}:${pk[c]}`)?`:${pk[c]}`:``}`,path:a,normalizedPath:a.endsWith(`/`)?a:`${a}/`,isIp:l}};function Ele(e,t,n){if(n===1)return[e];if(e===``)return[``];let r=e.split(t);return n===0?r:r.slice(0,n-1).concat(r.slice(1).join(t))}var Dle={booleanEquals:_le,coalesce:vle,getAttr:uk,isSet:ble,isValidHostLabel:dk,ite:Sle,not:Cle,parseURL:Tle,split:Ele,stringEquals:(e,t)=>e===t,substring:(e,t,n,r)=>e==null||t>=n||e.lengthencodeURIComponent(e).replace(/[!*'()]/g,e=>`%${e.charCodeAt(0).toString(16).toUpperCase()}`)},mk=(e,t)=>{let n=[],{referenceRecord:r,endpointParams:i}=t,a=0;for(;at.referenceRecord[e]??t.endpointParams[e],hk=(e,t,n)=>{if(typeof e==`string`)return mk(e,n);if(e.fn)return _k.callFunction(e,n);if(e.ref)return Ole(e,n);throw new sk(`'${t}': ${String(e)} is not a string, function or reference.`)},gk=({fn:e,argv:t},n)=>{let r=Array(t.length);for(let e=0;e{let{assign:n}=e;if(n&&n in t.referenceRecord)throw new sk(`'${n}' is already defined in Reference Record.`);let r=gk(e,t);t.logger?.debug?.(`${gle} evaluateCondition: ${ck(e)} = ${ck(r)}`);let i=r===``?!0:!!r;return n==null?{result:i}:{result:i,toAssign:{name:n,value:r}}},Ale=(e,t)=>Object.entries(e??{}).reduce((e,[n,r])=>(e[n]=r.map(e=>{let r=hk(e,`Header value entry`,t);if(typeof r!=`string`)throw new sk(`Header '${n}' value '${r}' is not a string`);return r}),e),{}),vk=(e,t)=>Object.entries(e).reduce((e,[n,r])=>(e[n]=bk.getEndpointProperty(r,t),e),{}),yk=(e,t)=>{if(Array.isArray(e))return e.map(e=>yk(e,t));switch(typeof e){case`string`:return mk(e,t);case`object`:if(e===null)throw new sk(`Unexpected endpoint property: ${e}`);return bk.getEndpointProperties(e,t);case`boolean`:return e;default:throw new sk(`Unexpected endpoint property type: ${typeof e}`)}},bk={getEndpointProperty:yk,getEndpointProperties:vk},jle=(e,t)=>{let n=hk(e,`Endpoint URL`,t);if(typeof n==`string`)try{return new URL(n)}catch(e){throw console.error(`Failed to construct URL with ${n}`,e),e}throw new sk(`Endpoint URL must be a string, got ${typeof n}`)},xk=1e8,Sk=(e,t)=>{let{nodes:n,root:r,results:i,conditions:a}=e,o=r,s={},c={referenceRecord:s,endpointParams:t.endpointParams,logger:t.logger};for(;o!==1&&o!==-1&&o=0===f.result?r:i}if(o>=xk){let e=i[o-xk];if(e[0]===-1){let[,t]=e;throw new sk(hk(t,`Error`,c))}let[t,n,r]=e;return{url:jle(t,c),properties:vk(n,c),headers:Ale(r??{},c)}}throw new sk(`No matching endpoint.`)},Ck=(e,t=!1)=>{if(t){for(let t of e.split(`.`))if(!Ck(t))return!1;return!0}return!(!dk(e)||e.length<3||e.length>63||e!==e.toLowerCase()||fk(e))},wk=`:`,Mle=`/`,Nle=e=>{let t=e.split(wk);if(t.length<6)return null;let[n,r,i,a,o,...s]=t;return n!==`arn`||r===``||i===``||s.join(wk)===``?null:{partition:r,service:i,region:a,accountId:o,resourceId:s.map(e=>e.split(Mle)).flat()}},Ple={partitions:[{id:`aws`,outputs:{dnsSuffix:`amazonaws.com`,dualStackDnsSuffix:`api.aws`,implicitGlobalRegion:`us-east-1`,name:`aws`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^(us|eu|ap|sa|ca|me|af|il|mx)\\-\\w+\\-\\d+$`,regions:{"af-south-1":{description:`Africa (Cape Town)`},"ap-east-1":{description:`Asia Pacific (Hong Kong)`},"ap-east-2":{description:`Asia Pacific (Taipei)`},"ap-northeast-1":{description:`Asia Pacific (Tokyo)`},"ap-northeast-2":{description:`Asia Pacific (Seoul)`},"ap-northeast-3":{description:`Asia Pacific (Osaka)`},"ap-south-1":{description:`Asia Pacific (Mumbai)`},"ap-south-2":{description:`Asia Pacific (Hyderabad)`},"ap-southeast-1":{description:`Asia Pacific (Singapore)`},"ap-southeast-2":{description:`Asia Pacific (Sydney)`},"ap-southeast-3":{description:`Asia Pacific (Jakarta)`},"ap-southeast-4":{description:`Asia Pacific (Melbourne)`},"ap-southeast-5":{description:`Asia Pacific (Malaysia)`},"ap-southeast-6":{description:`Asia Pacific (New Zealand)`},"ap-southeast-7":{description:`Asia Pacific (Thailand)`},"aws-global":{description:`aws global region`},"ca-central-1":{description:`Canada (Central)`},"ca-west-1":{description:`Canada West (Calgary)`},"eu-central-1":{description:`Europe (Frankfurt)`},"eu-central-2":{description:`Europe (Zurich)`},"eu-north-1":{description:`Europe (Stockholm)`},"eu-south-1":{description:`Europe (Milan)`},"eu-south-2":{description:`Europe (Spain)`},"eu-west-1":{description:`Europe (Ireland)`},"eu-west-2":{description:`Europe (London)`},"eu-west-3":{description:`Europe (Paris)`},"il-central-1":{description:`Israel (Tel Aviv)`},"me-central-1":{description:`Middle East (UAE)`},"me-south-1":{description:`Middle East (Bahrain)`},"mx-central-1":{description:`Mexico (Central)`},"sa-east-1":{description:`South America (Sao Paulo)`},"us-east-1":{description:`US East (N. Virginia)`},"us-east-2":{description:`US East (Ohio)`},"us-west-1":{description:`US West (N. California)`},"us-west-2":{description:`US West (Oregon)`}}},{id:`aws-cn`,outputs:{dnsSuffix:`amazonaws.com.cn`,dualStackDnsSuffix:`api.amazonwebservices.com.cn`,implicitGlobalRegion:`cn-northwest-1`,name:`aws-cn`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^cn\\-\\w+\\-\\d+$`,regions:{"aws-cn-global":{description:`aws-cn global region`},"cn-north-1":{description:`China (Beijing)`},"cn-northwest-1":{description:`China (Ningxia)`}}},{id:`aws-eusc`,outputs:{dnsSuffix:`amazonaws.eu`,dualStackDnsSuffix:`api.amazonwebservices.eu`,implicitGlobalRegion:`eusc-de-east-1`,name:`aws-eusc`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^eusc\\-(de)\\-\\w+\\-\\d+$`,regions:{"eusc-de-east-1":{description:`AWS European Sovereign Cloud (Germany)`}}},{id:`aws-iso`,outputs:{dnsSuffix:`c2s.ic.gov`,dualStackDnsSuffix:`api.aws.ic.gov`,implicitGlobalRegion:`us-iso-east-1`,name:`aws-iso`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^us\\-iso\\-\\w+\\-\\d+$`,regions:{"aws-iso-global":{description:`aws-iso global region`},"us-iso-east-1":{description:`US ISO East`},"us-iso-west-1":{description:`US ISO WEST`}}},{id:`aws-iso-b`,outputs:{dnsSuffix:`sc2s.sgov.gov`,dualStackDnsSuffix:`api.aws.scloud`,implicitGlobalRegion:`us-isob-east-1`,name:`aws-iso-b`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^us\\-isob\\-\\w+\\-\\d+$`,regions:{"aws-iso-b-global":{description:`aws-iso-b global region`},"us-isob-east-1":{description:`US ISOB East (Ohio)`},"us-isob-west-1":{description:`US ISOB West`}}},{id:`aws-iso-e`,outputs:{dnsSuffix:`cloud.adc-e.uk`,dualStackDnsSuffix:`api.cloud-aws.adc-e.uk`,implicitGlobalRegion:`eu-isoe-west-1`,name:`aws-iso-e`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^eu\\-isoe\\-\\w+\\-\\d+$`,regions:{"aws-iso-e-global":{description:`aws-iso-e global region`},"eu-isoe-west-1":{description:`EU ISOE West`}}},{id:`aws-iso-f`,outputs:{dnsSuffix:`csp.hci.ic.gov`,dualStackDnsSuffix:`api.aws.hci.ic.gov`,implicitGlobalRegion:`us-isof-south-1`,name:`aws-iso-f`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^us\\-isof\\-\\w+\\-\\d+$`,regions:{"aws-iso-f-global":{description:`aws-iso-f global region`},"us-isof-east-1":{description:`US ISOF EAST`},"us-isof-south-1":{description:`US ISOF SOUTH`}}},{id:`aws-us-gov`,outputs:{dnsSuffix:`amazonaws.com`,dualStackDnsSuffix:`api.aws`,implicitGlobalRegion:`us-gov-west-1`,name:`aws-us-gov`,supportsDualStack:!0,supportsFIPS:!0},regionRegex:`^us\\-gov\\-\\w+\\-\\d+$`,regions:{"aws-us-gov-global":{description:`aws-us-gov global region`},"us-gov-east-1":{description:`AWS GovCloud (US-East)`},"us-gov-west-1":{description:`AWS GovCloud (US-West)`}}}],version:`1.1`},Fle=``,Ile=e=>{let{partitions:t}=Ple;for(let n of t){let{regions:t,outputs:r}=n;for(let[n,i]of Object.entries(t))if(n===e)return{...r,...i}}for(let n of t){let{regionRegex:t,outputs:r}=n;if(new RegExp(t).test(e))return{...r}}let n=t.find(e=>e.id===`aws`);if(!n)throw Error(`Provided region was not found in the partition array or regex, and default partition with id 'aws' doesn't exist.`);return{...n.outputs}},Lle=()=>Fle,Tk={isVirtualHostableS3Bucket:Ck,parseArn:Nle,partition:Ile};lk.aws=Tk;function Rle(e,t,n){return e.$source||={},e.$source[t]=n,e}var Ek;(function(e){e.STANDARD=`standard`,e.ADAPTIVE=`adaptive`})(Ek||={});var Dk=Ek.STANDARD,zle=[`BandwidthLimitExceeded`,`EC2ThrottledException`,`LimitExceededException`,`PriorRequestNotComplete`,`ProvisionedThroughputExceededException`,`RequestLimitExceeded`,`RequestThrottled`,`RequestThrottledException`,`SlowDown`,`ThrottledException`,`Throttling`,`ThrottlingException`,`TooManyRequestsException`,`TransactionInProgressException`],Ble=[`TimeoutError`,`RequestTimeout`,`RequestTimeoutException`],Vle=[500,502,503,504],Hle=[`ECONNRESET`,`ECONNREFUSED`,`EPIPE`,`ETIMEDOUT`],Ule=[`EHOSTUNREACH`,`ENETUNREACH`,`ENOTFOUND`],Wle=e=>e?.$retryable!==void 0,Gle=e=>e.$metadata?.clockSkewCorrected,Kle=e=>{let t=new Set([`Failed to fetch`,`NetworkError when attempting to fetch resource`,`The Internet connection appears to be offline`,`Load failed`,`Network request failed`]);return e&&e instanceof TypeError?t.has(e.message):!1},Ok=e=>e.$metadata?.httpStatusCode===429||zle.includes(e.name)||e.$retryable?.throttling==1,kk=(e,t=0)=>Wle(e)||Gle(e)||e.name===`InvalidSignatureException`&&e.message?.includes(`Signature expired`)||Ble.includes(e.name)||Hle.includes(e?.code||``)||Ule.includes(e?.code||``)||Vle.includes(e.$metadata?.httpStatusCode||0)||Kle(e)||Jle(e)||e.cause!==void 0&&t<=10&&kk(e.cause,t+1),qle=e=>{if(e.$metadata?.httpStatusCode!==void 0){let t=e.$metadata.httpStatusCode;return 500<=t&&t<=599&&!kk(e)}return!1};function Jle(e){return e.code===`ERR_HTTP2_STREAM_ERROR`&&e.message.includes(`NGHTTP2_REFUSED_STREAM`)}var Yle=class e{static setTimeoutFn=setTimeout;beta;minCapacity;minFillRate;scaleConstant;smooth;enabled=!1;availableTokens=0;lastMaxRate=0;measuredTxRate=0;requestCount=0;fillRate;lastThrottleTime;lastTimestamp=0;lastTxRateBucket;maxCapacity;timeWindow=0;constructor(e){this.beta=e?.beta??.7,this.minCapacity=e?.minCapacity??1,this.minFillRate=e?.minFillRate??.5,this.scaleConstant=e?.scaleConstant??.4,this.smooth=e?.smooth??.8,this.lastThrottleTime=this.getCurrentTimeInSeconds(),this.lastTxRateBucket=Math.floor(this.getCurrentTimeInSeconds()),this.fillRate=this.minFillRate,this.maxCapacity=this.minCapacity}async getSendToken(){return this.acquireTokenBucket(1)}updateClientSendingRate(e){let t;this.updateMeasuredRate();let n=e;if(n?.errorType===`THROTTLING`||Ok(n?.error??e)){let e=this.enabled?Math.min(this.measuredTxRate,this.fillRate):this.measuredTxRate;this.lastMaxRate=e,this.calculateTimeWindow(),this.lastThrottleTime=this.getCurrentTimeInSeconds(),t=this.cubicThrottle(e),this.enableTokenBucket()}else this.calculateTimeWindow(),t=this.cubicSuccess(this.getCurrentTimeInSeconds());let r=Math.min(t,2*this.measuredTxRate);this.updateTokenBucketRate(r)}getCurrentTimeInSeconds(){return Date.now()/1e3}async acquireTokenBucket(t){if(this.enabled){for(this.refillTokenBucket();t>this.availableTokens;){let n=(t-this.availableTokens)/this.fillRate*1e3;await new Promise(t=>e.setTimeoutFn(t,n)),this.refillTokenBucket()}this.availableTokens-=t}}refillTokenBucket(){let e=this.getCurrentTimeInSeconds();if(!this.lastTimestamp){this.lastTimestamp=e;return}let t=(e-this.lastTimestamp)*this.fillRate;this.availableTokens=Math.min(this.maxCapacity,this.availableTokens+t),this.lastTimestamp=e}calculateTimeWindow(){this.timeWindow=this.getPrecise((this.lastMaxRate*(1-this.beta)/this.scaleConstant)**(1/3))}cubicThrottle(e){return this.getPrecise(e*this.beta)}cubicSuccess(e){return this.getPrecise(this.scaleConstant*(e-this.lastThrottleTime-this.timeWindow)**3+this.lastMaxRate)}enableTokenBucket(){this.enabled=!0}updateTokenBucketRate(e){this.refillTokenBucket(),this.fillRate=Math.max(e,this.minFillRate),this.maxCapacity=Math.max(e,this.minCapacity),this.availableTokens=Math.min(this.availableTokens,this.maxCapacity)}updateMeasuredRate(){let e=this.getCurrentTimeInSeconds(),t=Math.floor(e*2)/2;if(this.requestCount++,t>this.lastTxRateBucket){let e=this.requestCount/(t-this.lastTxRateBucket);this.measuredTxRate=this.getPrecise(e*this.smooth+this.measuredTxRate*(1-this.smooth)),this.requestCount=0,this.lastTxRateBucket=t}}getPrecise(e){return parseFloat(e.toFixed(8))}},Ak=20*1e3,Xle=`amz-sdk-invocation-id`,Zle=`amz-sdk-request`,jk=class e{static v2026=typeof process<`u`&&{}?.SMITHY_NEW_RETRIES_2026===`true`;static delay(){return e.v2026?50:100}static throttlingDelay(){return e.v2026?1e3:500}static cost(){return e.v2026?14:5}static throttlingCost(){return e.v2026?5:10}static modifiedCostType(){return e.v2026?`THROTTLING`:`TRANSIENT`}},Qle=class{x=jk.delay();computeNextBackoffDelay(e){let t=Math.random()*Math.min(this.x*2**e,Ak);return Math.floor(t)}setDelayBase(e){this.x=e}},Mk=class{delay;count;cost;longPoll;constructor(e,t,n,r){this.delay=e,this.count=t,this.cost=n,this.longPoll=r}getRetryCount(){return this.count}getRetryDelay(){return Math.min(Ak,this.delay)}getRetryCost(){return this.cost}isLongPoll(){return this.longPoll}},Nk={incompatible:1,attempts:2,capacity:3},Pk=class{mode=Ek.STANDARD;capacity=500;retryBackoffStrategy;maxAttemptsProvider;baseDelay;constructor(e){typeof e==`number`?this.maxAttemptsProvider=async()=>e:typeof e==`function`?this.maxAttemptsProvider=e:e&&typeof e==`object`&&(this.maxAttemptsProvider=async()=>e.maxAttempts,this.baseDelay=e.baseDelay,this.retryBackoffStrategy=e.backoff),this.maxAttemptsProvider??=async()=>3,this.baseDelay??=jk.delay(),this.retryBackoffStrategy??=new Qle}async acquireInitialRetryToken(e){return new Mk(jk.delay(),0,void 0,jk.v2026&&e.includes(`:longpoll`))}async refreshRetryTokenForRetry(e,t){let n=await this.getMaxAttempts(),r=this.retryCode(e,t,n),i=r===0,a=e.isLongPoll?.();if(i||a){let n=t.errorType;this.retryBackoffStrategy.setDelayBase(n===`THROTTLING`?jk.throttlingDelay():this.baseDelay);let o=this.retryBackoffStrategy.computeNextBackoffDelay(e.getRetryCount()),s=o;if(t.retryAfterHint instanceof Date&&(s=Math.max(o,Math.min(t.retryAfterHint.getTime()-Date.now(),o+5e3))),i){let t=this.getCapacityCost(n);return this.capacity-=t,new Mk(s,e.getRetryCount()+1,t,e.isLongPoll?.()??!1)}else throw Object.assign(Error(`No retry token available`),{$backoff:jk.v2026&&r===Nk.capacity&&a?s:0})}throw Error(`No retry token available`)}recordSuccess(e){this.capacity=Math.min(500,this.capacity+(e.getRetryCost()??1))}getCapacity(){return this.capacity}async maxAttempts(){return this.maxAttemptsProvider()}async getMaxAttempts(){try{return await this.maxAttemptsProvider()}catch{return console.warn(`Max attempts provider could not resolve. Using default of 3`),3}}retryCode(e,t,n){let r=e.getRetryCount()+1,i=this.isRetryableError(t.errorType)?0:Nk.incompatible,a=r=this.getCapacityCost(t.errorType)?0:Nk.capacity;return i||a||o}getCapacityCost(e){return e===jk.modifiedCostType()?jk.throttlingCost():jk.cost()}isRetryableError(e){return e===`THROTTLING`||e===`TRANSIENT`}},$le=class{mode=Ek.ADAPTIVE;rateLimiter;standardRetryStrategy;constructor(e,t){let{rateLimiter:n}=t??{};this.rateLimiter=n??new Yle,this.standardRetryStrategy=t?new Pk({maxAttempts:typeof e==`number`?e:3,...t}):new Pk(e)}async acquireInitialRetryToken(e){let t=await this.standardRetryStrategy.acquireInitialRetryToken(e);return await this.rateLimiter.getSendToken(),t}async refreshRetryTokenForRetry(e,t){this.rateLimiter.updateClientSendingRate(t);let n=await this.standardRetryStrategy.refreshRetryTokenForRetry(e,t);return await this.rateLimiter.getSendToken(),n}recordSuccess(e){this.rateLimiter.updateClientSendingRate({}),this.standardRetryStrategy.recordSuccess(e)}async maxAttemptsProvider(){return this.standardRetryStrategy.maxAttempts()}};jk.v2026||=typeof process==`object`&&{}?.AWS_NEW_RETRIES_2026===`true`;function Fk(e,t,n){e.__aws_sdk_context?e.__aws_sdk_context.features||(e.__aws_sdk_context.features={}):e.__aws_sdk_context={features:{}},e.__aws_sdk_context.features[t]=n}var eue=/\d{12}\.ddb/;async function tue(e,t,n){if(n.request?.headers?.[`smithy-protocol`]===`rpc-v2-cbor`&&Fk(e,`PROTOCOL_RPC_V2_CBOR`,`M`),typeof t.retryStrategy==`function`){let n=await t.retryStrategy();if(typeof n.mode==`string`)switch(n.mode){case Ek.ADAPTIVE:Fk(e,`RETRY_MODE_ADAPTIVE`,`F`);break;case Ek.STANDARD:Fk(e,`RETRY_MODE_STANDARD`,`E`);break}}if(typeof t.accountIdEndpointMode==`function`){let n=e.endpointV2;switch(String(n?.url?.hostname).match(eue)&&Fk(e,`ACCOUNT_ID_ENDPOINT`,`O`),await t.accountIdEndpointMode?.()){case`disabled`:Fk(e,`ACCOUNT_ID_MODE_DISABLED`,`Q`);break;case`preferred`:Fk(e,`ACCOUNT_ID_MODE_PREFERRED`,`P`);break;case`required`:Fk(e,`ACCOUNT_ID_MODE_REQUIRED`,`R`);break}}let r=e.__smithy_context?.selectedHttpAuthScheme?.identity;if(r?.$source){let t=r;t.accountId&&Fk(e,`RESOLVED_ACCOUNT_ID`,`T`);for(let[n,r]of Object.entries(t.$source??{}))Fk(e,n,r)}}var Ik=`user-agent`,Lk=`x-amz-user-agent`,nue=/[^!$%&'*+\-.^_`|~\w]/g,rue=/[^!$%&'*+\-.^_`|~\w#]/g,iue=1024;function aue(e){let t=``;for(let n in e){let r=e[n];if(t.length+r.length+1<=iue){t.length?t+=`,`+r:t+=r;continue}break}return t}var oue=e=>(t,n)=>async r=>{let{request:i}=r;if(!Rb.isInstance(i))return t(r);let{headers:a}=i,o=n?.userAgent?.map(Rk)||[],s=(await e.defaultUserAgentProvider()).map(Rk);await tue(n,e,r);let c=n;s.push(`m/${aue(Object.assign({},n.__smithy_context?.features,c.__aws_sdk_context?.features))}`);let l=e?.customUserAgent?.map(Rk)||[],u=await e.userAgentAppId();u&&s.push(Rk([`app`,`${u}`]));let d=Lle(),f=(d?[d]:[]).concat([...s,...o,...l]).join(` `),p=[...s.filter(e=>e.startsWith(`aws-sdk-`)),...l].join(` `);return e.runtime===`browser`?a[Lk]=f:(p&&(a[Lk]=a[`x-amz-user-agent`]?`${a[Ik]} ${p}`:p),a[Ik]=f),t({...r,request:i})},Rk=e=>{let t=e[0].split(`/`).map(e=>e.replace(nue,`-`)).join(`/`),n=e[1]?.replace(rue,`-`),r=t.indexOf(`/`),i=t.substring(0,r),a=t.substring(r+1);return i===`api`&&(a=a.toLowerCase()),[i,a,n].filter(e=>e&&e.length>0).reduce((e,t,n)=>{switch(n){case 0:return t;case 1:return`${e}/${t}`;default:return`${e}#${t}`}},``)},sue={name:`getUserAgentMiddleware`,step:`build`,priority:`low`,tags:[`SET_USER_AGENT`,`USER_AGENT`],override:!0},zk=e=>({applyToStack:t=>{t.add(oue(e),sue)}}),Bk=new Set,cue=(e,t=dk)=>{if(!Bk.has(e)&&!t(e))if(e===`*`)console.warn(`@smithy/config-resolver WARN - Please use the caller region instead of "*". See "sigv4a" in https://github.com/aws/aws-sdk-js-v3/blob/main/supplemental-docs/CLIENTS.md.`);else throw Error(`Region not accepted: region="${e}" is not a valid hostname component.`);else Bk.add(e)},Vk=e=>typeof e==`string`&&(e.startsWith(`fips-`)||e.endsWith(`-fips`)),lue=e=>Vk(e)?[`fips-aws-global`,`aws-fips`].includes(e)?`us-east-1`:e.replace(/fips-(dkr-|prod-)?|-fips/,``):e,Hk=e=>{let{region:t,useFipsEndpoint:n}=e;if(!t)throw Error(`Region is missing`);return Object.assign(e,{region:async()=>{let e=lue(typeof t==`function`?await t():t);return cue(e),e},useFipsEndpoint:async()=>Vk(typeof t==`string`?t:await t())?!0:typeof n==`function`?n():Promise.resolve(!!n)})},Uk=`content-length`;function uue(e){return t=>async n=>{let r=n.request;if(Rb.isInstance(r)){let{body:t,headers:n}=r;if(t&&Object.keys(n).map(e=>e.toLowerCase()).indexOf(Uk)===-1)try{let n=e(t);r.headers={...r.headers,[Uk]:String(n)}}catch{}}return t({...n,request:r})}}var due={step:`build`,tags:[`SET_CONTENT_LENGTH`,`CONTENT_LENGTH`],name:`contentLengthMiddleware`,override:!0},Wk=e=>({applyToStack:t=>{t.add(uue(e.bodyLengthChecker),due)}}),fue=async e=>{let t=e?.Bucket||``;if(typeof e.Bucket==`string`&&(e.Bucket=t.replace(/#/g,`%23`).replace(/\?/g,`%3F`)),_ue(t)){if(e.ForcePathStyle===!0)throw Error(`Path-style addressing cannot be used with ARN buckets`)}else (!gue(t)||t.indexOf(`.`)!==-1&&!String(e.Endpoint).startsWith(`http:`)||t.toLowerCase()!==t||t.length<3)&&(e.ForcePathStyle=!0);return e.DisableMultiRegionAccessPoints&&(e.disableMultiRegionAccessPoints=!0,e.DisableMRAP=!0),e},pue=/^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$/,mue=/(\d+\.){3}\d+/,hue=/\.\./,gue=e=>pue.test(e)&&!mue.test(e)&&!hue.test(e),_ue=e=>{let[t,n,r,,,i]=e.split(`:`),a=t===`arn`&&e.split(`:`).length>=6,o=!!(a&&n&&r&&i);if(a&&!o)throw Error(`Invalid ARN: ${e} was an invalid ARN.`);return o},vue=(e,t,n,r=!1)=>{let i=async()=>{let i;return i=r?n.clientContextParams?.[e]??n[e]??n[t]:n[e]??n[t],typeof i==`function`?i():i};return e===`credentialScope`||t===`CredentialScope`?async()=>{let e=typeof n.credentials==`function`?await n.credentials():n.credentials;return e?.credentialScope??e?.CredentialScope}:e===`accountId`||t===`AccountId`?async()=>{let e=typeof n.credentials==`function`?await n.credentials():n.credentials;return e?.accountId??e?.AccountId}:e===`endpoint`||t===`endpoint`?async()=>{if(n.isCustomEndpoint===!1)return;let e=await i();if(e&&typeof e==`object`){if(`url`in e)return e.url.href;if(`hostname`in e){let{protocol:t,hostname:n,port:r,path:i}=e;return`${t}//${n}${r?`:`+r:``}${i}`}}return e}:i},Gk=async e=>void 0,Kk=e=>{if(typeof e==`object`){if(`url`in e){let t=vO(e.url);if(e.headers){t.headers={};for(let[n,r]of Object.entries(e.headers))t.headers[n.toLowerCase()]=r.join(`, `)}return t}return e}return vO(e)},qk=async(e,t,n,r)=>{if(!n.isCustomEndpoint){let e;e=n.serviceConfiguredEndpoint?await n.serviceConfiguredEndpoint():await Gk(n.serviceId),e&&(n.endpoint=()=>Promise.resolve(Kk(e)),n.isCustomEndpoint=!0)}let i=await Jk(e,t,n);if(typeof n.endpointProvider!=`function`)throw Error(`config.endpointProvider is not set.`);let a=n.endpointProvider(i,r);if(n.isCustomEndpoint&&n.endpoint){let e=await n.endpoint();if(e?.headers){a.headers??={};for(let[t,n]of Object.entries(e.headers))a.headers[t]=Array.isArray(n)?n:[n]}}return a},Jk=async(e,t,n)=>{let r={},i=t?.getEndpointParameterInstructions?.()||{};for(let[t,a]of Object.entries(i))switch(a.type){case`staticContextParams`:r[t]=a.value;break;case`contextParams`:r[t]=e[a.name];break;case`clientContextParams`:case`builtInParams`:r[t]=await vue(a.name,t,n,a.type!==`builtInParams`)();break;case`operationContextParams`:r[t]=a.get(e);break;default:throw Error(`Unrecognized endpoint parameter instruction: `+JSON.stringify(a))}return Object.keys(i).length===0&&Object.assign(r,n),String(n.serviceId).toLowerCase()===`s3`&&await fue(r),r},yue=({config:e,instructions:t})=>(n,r)=>async i=>{e.isCustomEndpoint&&fle(r,`ENDPOINT_OVERRIDE`,`N`);let a=await qk(i.input,{getEndpointParameterInstructions(){return t}},{...e},r);r.endpointV2=a,r.authSchemes=a.properties?.authSchemes;let o=r.authSchemes?.[0];if(o){r.signing_region=o.signingRegion,r.signing_service=o.signingName;let e=lx(r)?.selectedHttpAuthScheme?.httpAuthOption;e&&(e.signingProperties=Object.assign(e.signingProperties||{},{signing_region:o.signingRegion,signingRegion:o.signingRegion,signing_service:o.signingName,signingName:o.signingName,signingRegionSet:o.signingRegionSet},o.properties))}return n({...i})},bue={step:`serialize`,tags:[`ENDPOINT_PARAMETERS`,`ENDPOINT_V2`,`ENDPOINT`],name:`endpointV2Middleware`,override:!0,relation:`before`,toMiddleware:{name:`serializerMiddleware`,step:`serialize`,tags:[`SERIALIZER`],override:!0}.name},Yk=(e,t)=>({applyToStack:n=>{n.addRelativeTo(yue({config:e,instructions:t}),bue)}}),Xk=e=>{let t=e.tls??!0,{endpoint:n,useDualstackEndpoint:r,useFipsEndpoint:i}=e,a=Object.assign(e,{endpoint:n==null?void 0:async()=>Kk(await ux(n)()),tls:t,isCustomEndpoint:!!n,useDualstackEndpoint:ux(r??!1),useFipsEndpoint:ux(i??!1)}),o;return a.serviceConfiguredEndpoint=async()=>(e.serviceId&&!o&&(o=Gk(e.serviceId)),o),a},xue=e=>e instanceof Error?e:e instanceof Object?Object.assign(Error(),e):Error(typeof e==`string`?e:`AWS SDK error wrapper for ${e}`),Zk=e=>{let{retryStrategy:t,retryMode:n}=e,r=ux(e.maxAttempts??3),i=t?Promise.resolve(t):void 0,a=async()=>await ux(n)()===Ek.ADAPTIVE?new $le(r):new Pk(r);return Object.assign(e,{maxAttempts:r,retryStrategy:()=>i??=a()})},Qk=(e,t)=>{let n=[];if(e&&n.push(e),t)for(let e of t)n.push(e);return n},$k=(e,t)=>`${e||`anonymous`}${t&&t.length>0?` (a.k.a. ${t.join(`,`)})`:``}`,eA=()=>{let e=[],t=[],n=!1,r=new Set,i=e=>e.sort((e,t)=>tA[t.step]-tA[e.step]||nA[t.priority||`normal`]-nA[e.priority||`normal`]),a=n=>{let i=!1,a=e=>{let t=Qk(e.name,e.aliases);if(t.includes(n)){i=!0;for(let e of t)r.delete(e);return!1}return!0};return e=e.filter(a),t=t.filter(a),i},o=n=>{let i=!1,a=e=>{if(e.middleware===n){i=!0;for(let t of Qk(e.name,e.aliases))r.delete(t);return!1}return!0};return e=e.filter(a),t=t.filter(a),i},s=n=>(e.forEach(e=>{n.add(e.middleware,{...e})}),t.forEach(e=>{n.addRelativeTo(e.middleware,{...e})}),n.identifyOnResolve?.(u.identifyOnResolve()),n),c=e=>{let t=[];return e.before.forEach(e=>{e.before.length===0&&e.after.length===0?t.push(e):t.push(...c(e))}),t.push(e),e.after.reverse().forEach(e=>{e.before.length===0&&e.after.length===0?t.push(e):t.push(...c(e))}),t},l=(n=!1)=>{let r=[],a=[],o={};return e.forEach(e=>{let t={...e,before:[],after:[]};for(let e of Qk(t.name,t.aliases))o[e]=t;r.push(t)}),t.forEach(e=>{let t={...e,before:[],after:[]};for(let e of Qk(t.name,t.aliases))o[e]=t;a.push(t)}),a.forEach(e=>{if(e.toMiddleware){let t=o[e.toMiddleware];if(t===void 0){if(n)return;throw Error(`${e.toMiddleware} is not found when adding ${$k(e.name,e.aliases)} middleware ${e.relation} ${e.toMiddleware}`)}e.relation===`after`&&t.after.push(e),e.relation===`before`&&t.before.push(e)}}),i(r).map(c).reduce((e,t)=>(e.push(...t),e),[])},u={add:(t,n={})=>{let{name:i,override:a,aliases:o}=n,s={step:`initialize`,priority:`normal`,middleware:t,...n},c=Qk(i,o);if(c.length>0){if(c.some(e=>r.has(e))){if(!a)throw Error(`Duplicate middleware name '${$k(i,o)}'`);for(let t of c){let n=e.findIndex(e=>e.name===t||e.aliases?.some(e=>e===t));if(n===-1)continue;let r=e[n];if(r.step!==s.step||s.priority!==r.priority)throw Error(`"${$k(r.name,r.aliases)}" middleware with ${r.priority} priority in ${r.step} step cannot be overridden by "${$k(i,o)}" middleware with ${s.priority} priority in ${s.step} step.`);e.splice(n,1)}}for(let e of c)r.add(e)}e.push(s)},addRelativeTo:(e,n)=>{let{name:i,override:a,aliases:o}=n,s={middleware:e,...n},c=Qk(i,o);if(c.length>0){if(c.some(e=>r.has(e))){if(!a)throw Error(`Duplicate middleware name '${$k(i,o)}'`);for(let e of c){let n=t.findIndex(t=>t.name===e||t.aliases?.some(t=>t===e));if(n===-1)continue;let r=t[n];if(r.toMiddleware!==s.toMiddleware||r.relation!==s.relation)throw Error(`"${$k(r.name,r.aliases)}" middleware ${r.relation} "${r.toMiddleware}" middleware cannot be overridden by "${$k(i,o)}" middleware ${s.relation} "${s.toMiddleware}" middleware.`);t.splice(n,1)}}for(let e of c)r.add(e)}t.push(s)},clone:()=>s(eA()),use:e=>{e.applyToStack(u)},remove:e=>typeof e==`string`?a(e):o(e),removeByTag:n=>{let i=!1,a=e=>{let{tags:t,name:a,aliases:o}=e;if(t&&t.includes(n)){let e=Qk(a,o);for(let t of e)r.delete(t);return i=!0,!1}return!0};return e=e.filter(a),t=t.filter(a),i},concat:e=>{let t=s(eA());return t.use(e),t.identifyOnResolve(n||t.identifyOnResolve()||(e.identifyOnResolve?.()??!1)),t},applyToStack:s,identify:()=>l(!0).map(e=>{let t=e.step??e.relation+` `+e.toMiddleware;return $k(e.name,e.aliases)+` - `+t}),identifyOnResolve(e){return typeof e==`boolean`&&(n=e),n},resolve:(e,t)=>{for(let n of l().map(e=>e.middleware).reverse())e=n(e,t);return n&&console.log(u.identify()),e}};return u},tA={initialize:5,serialize:4,build:3,finalizeRequest:2,deserialize:1},nA={high:3,normal:2,low:1},rA=class{config;middlewareStack=eA();initConfig;handlers;constructor(e){this.config=e;let{protocol:t,protocolSettings:n}=e;n&&typeof t==`function`&&(e.protocol=new t(n))}send(e,t,n){let r=typeof t==`function`?void 0:t,i=typeof t==`function`?t:n,a=r===void 0&&this.config.cacheMiddleware===!0,o;if(a){this.handlers||=new WeakMap;let t=this.handlers;t.has(e.constructor)?o=t.get(e.constructor):(o=e.resolveMiddleware(this.middlewareStack,this.config,r),t.set(e.constructor,o))}else delete this.handlers,o=e.resolveMiddleware(this.middlewareStack,this.config,r);if(i)o(e).then(e=>i(null,e.output),e=>i(e)).catch(()=>{});else return o(e).then(e=>e.output)}destroy(){this.config?.requestHandler?.destroy?.(),delete this.handlers}},iA=`***SensitiveInformation***`;function aA(e,t){if(t==null)return t;let n=TO.of(e);if(n.getMergedTraits().sensitive)return iA;if(n.isListSchema()){if(n.getValueSchema().getMergedTraits().sensitive)return iA}else if(n.isMapSchema()){if(n.getKeySchema().getMergedTraits().sensitive||n.getValueSchema().getMergedTraits().sensitive)return iA}else if(n.isStructSchema()&&typeof t==`object`){let e=t,r={};for(let[t,i]of n.structIterator())e[t]!=null&&(r[t]=aA(i,e[t]));return r}return t}var oA=class{middlewareStack=eA();schema;static classBuilder(){return new Sue}resolveMiddlewareWithContext(e,t,n,{middlewareFn:r,clientName:i,commandName:a,inputFilterSensitiveLog:o,outputFilterSensitiveLog:s,smithyContext:c,additionalContext:l,CommandCtor:u}){for(let i of r.bind(this)(u,e,t,n))this.middlewareStack.use(i);let d=e.concat(this.middlewareStack),{logger:f}=t,p={logger:f,clientName:i,commandName:a,inputFilterSensitiveLog:o,outputFilterSensitiveLog:s,[Die]:{commandInstance:this,...c},...l},{requestHandler:m}=t,h=n??{};return c.eventStream&&(h={isEventStream:!0,...h}),d.resolve(e=>m.handle(e.request,h),p)}},Sue=class{_init=()=>{};_ep={};_middlewareFn=()=>[];_commandName=``;_clientName=``;_additionalContext={};_smithyContext={};_inputFilterSensitiveLog=void 0;_outputFilterSensitiveLog=void 0;_serializer=null;_deserializer=null;_operationSchema;init(e){this._init=e}ep(e){return this._ep=e,this}m(e){return this._middlewareFn=e,this}s(e,t,n={}){return this._smithyContext={service:e,operation:t,...n},this}c(e={}){return this._additionalContext=e,this}n(e,t){return this._clientName=e,this._commandName=t,this}f(e=e=>e,t=e=>e){return this._inputFilterSensitiveLog=e,this._outputFilterSensitiveLog=t,this}ser(e){return this._serializer=e,this}de(e){return this._deserializer=e,this}sc(e){return this._operationSchema=e,this._smithyContext.operationSchema=e,this}build(){let e=this,t;return t=class extends oA{input;static getEndpointParameterInstructions(){return e._ep}constructor(...[t]){super(),this.input=t??{},e._init(this),this.schema=e._operationSchema}resolveMiddleware(n,r,i){let a=e._operationSchema,o=a?.[4]??a?.input,s=a?.[5]??a?.output;return this.resolveMiddlewareWithContext(n,r,i,{CommandCtor:t,middlewareFn:e._middlewareFn,clientName:e._clientName,commandName:e._commandName,inputFilterSensitiveLog:e._inputFilterSensitiveLog??(a?aA.bind(null,o):e=>e),outputFilterSensitiveLog:e._outputFilterSensitiveLog??(a?aA.bind(null,s):e=>e),smithyContext:e._smithyContext,additionalContext:e._additionalContext})}serialize=e._serializer;deserialize=e._deserializer}}},sA=class e extends Error{$fault;$response;$retryable;$metadata;constructor(e){super(e.message),Object.setPrototypeOf(this,Object.getPrototypeOf(this).constructor.prototype),this.name=e.name,this.$fault=e.$fault,this.$metadata=e.$metadata}static isInstance(t){if(!t)return!1;let n=t;return e.prototype.isPrototypeOf(n)||!!n.$fault&&!!n.$metadata&&(n.$fault===`client`||n.$fault===`server`)}static[Symbol.hasInstance](t){if(!t)return!1;let n=t;return this===e?e.isInstance(t):e.isInstance(t)?n.name&&this.name?this.prototype.isPrototypeOf(t)||n.name===this.name:this.prototype.isPrototypeOf(t):!1}},cA=(e,t={})=>(Object.entries(t).filter(([,e])=>e!==void 0).forEach(([t,n])=>{(e[t]==null||e[t]===``)&&(e[t]=n)}),e.message=e.message||e.Message||`UnknownError`,delete e.Message,e),lA=e=>{switch(e){case`standard`:return{retryMode:`standard`,connectionTimeout:3100};case`in-region`:return{retryMode:`standard`,connectionTimeout:1100};case`cross-region`:return{retryMode:`standard`,connectionTimeout:3100};case`mobile`:return{retryMode:`standard`,connectionTimeout:3e4};default:return{}}},uA=Object.values(Lb),Cue=e=>{let t=[];for(let n in Lb){let r=Lb[n];e[r]!==void 0&&t.push({algorithmId:()=>r,checksumConstructor:()=>e[r]})}for(let[n,r]of Object.entries(e.checksumAlgorithms??{}))t.push({algorithmId:()=>n,checksumConstructor:()=>r});return{addChecksumAlgorithm(n){e.checksumAlgorithms=e.checksumAlgorithms??{};let r=n.algorithmId(),i=n.checksumConstructor();uA.includes(r)?e.checksumAlgorithms[r.toUpperCase()]=i:e.checksumAlgorithms[r]=i,t.push(n)},checksumAlgorithms(){return t}}},wue=e=>{let t={};return e.checksumAlgorithms().forEach(e=>{let n=e.algorithmId();uA.includes(n)&&(t[n]=e.checksumConstructor())}),t},Tue=e=>({setRetryStrategy(t){e.retryStrategy=t},retryStrategy(){return e.retryStrategy}}),Eue=e=>{let t={};return t.retryStrategy=e.retryStrategy(),t},dA=e=>Object.assign(Cue(e),Tue(e)),fA=e=>Object.assign(wue(e),Eue(e)),pA=e=>{let t=`#text`;for(let n in e)e.hasOwnProperty(n)&&e[n][t]!==void 0?e[n]=e[n][t]:typeof e[n]==`object`&&e[n]!==null&&(e[n]=pA(e[n]));return e},mA=class{trace(){}debug(){}info(){}warn(){}error(){}},Due=e=>e?.body instanceof ReadableStream;function Oue(e,t){if(zb.isInstance(e))for(let n of Object.keys(e.headers)){let r=n.toLowerCase();if(r===`retry-after`){let r=e.headers[n],i=NaN;if(r.endsWith(`GMT`))try{i=(PO(r).getTime()-Date.now())/1e3}catch(e){t?.trace?.(`Failed to parse retry-after header`),t?.trace?.(e)}else r.match(/ GMT, ((\d+)|(\d+\.\d+))$/)?i=Number(r.match(/ GMT, ([\d.]+)$/)?.[1]):r.match(/^((\d+)|(\d+\.\d+))$/)?i=Number(r):Date.parse(r)>=Date.now()&&(i=(Date.parse(r)-Date.now())/1e3);return isNaN(i)?void 0:new Date(Date.now()+i*1e3)}else if(r===`x-amz-retry-after`){let r=e.headers[n],i=Number(r);if(isNaN(i)){t?.trace?.(`Failed to parse x-amz-retry-after=${r}`);return}return new Date(Date.now()+i)}}}var kue=e=>(t,n)=>async r=>{let i=await e.retryStrategy(),a=await e.maxAttempts();if(Aue(i)){i=i;let o=await i.acquireInitialRetryToken((n.partition_id??``)+(n.__retryLongPoll?`:longpoll`:``)),s=Error(),c=0,l=0,{request:u}=r,d=Rb.isInstance(u);for(d&&(u.headers[Xle]=VO());;)try{d&&(u.headers[Zle]=`attempt=${c+1}; max=${a}`);let{response:e,output:n}=await t(r);return i.recordSuccess(o),n.$metadata.attempts=c+1,n.$metadata.totalRetryDelay=l,{response:e,output:n}}catch(t){let r=jue(t,e.logger);if(s=xue(t),d&&Due(u))throw(n.logger instanceof mA?console:n.logger)?.warn(`An error was encountered in a non-retryable streaming request.`),s;try{o=await i.refreshRetryTokenForRetry(o,r)}catch(e){throw typeof e.$backoff==`number`&&await hA(e.$backoff),s.$metadata||={},s.$metadata.attempts=c+1,s.$metadata.totalRetryDelay=l,s}c=o.getRetryCount();let a=o.getRetryDelay();l+=a,await hA(a)}}else return i=i,i?.mode&&(n.userAgent=[...n.userAgent||[],[`cfg/retry-mode`,i.mode]]),i.retry(t,r)},hA=e=>new Promise(t=>setTimeout(t,e)),Aue=e=>e.acquireInitialRetryToken!==void 0&&e.refreshRetryTokenForRetry!==void 0&&e.recordSuccess!==void 0,jue=(e,t)=>{let n={error:e,errorType:Mue(e)},r=Oue(e.$response,t);return r&&(n.retryAfterHint=r),n},Mue=e=>Ok(e)?`THROTTLING`:kk(e)?`TRANSIENT`:qle(e)?`SERVER_ERROR`:`CLIENT_ERROR`,Nue={name:`retryMiddleware`,tags:[`RETRY`],step:`finalizeRequest`,priority:`high`,override:!0},gA=e=>({applyToStack:t=>{t.add(kue(e),Nue)}}),_A=e=>zb.isInstance(e)?e.headers?.date??e.headers?.Date:void 0,vA=e=>new Date(Date.now()+e),Pue=(e,t)=>Math.abs(vA(t).getTime()-e)>=3e5,yA=(e,t)=>{let n=Date.parse(e);return Pue(n,t)?n-Date.now():t},bA=(e,t)=>{if(!t)throw Error(`Property \`${e}\` is not resolved for AWS SDK SigV4Auth`);return t},xA=async e=>{let t=bA(`context`,e.context),n=bA(`config`,e.config),r=t.endpointV2?.properties?.authSchemes?.[0];return{config:n,signer:await bA(`signer`,n.signer)(r),signingRegion:e?.signingRegion,signingRegionSet:e?.signingRegionSet,signingName:e?.signingName}},SA=class{async sign(e,t,n){if(!Rb.isInstance(e))throw Error("The request is not an instance of `HttpRequest` and cannot be signed");let r=await xA(n),{config:i,signer:a}=r,{signingRegion:o,signingName:s}=r,c=n.context;if(c?.authSchemes?.length??!1){let[e,t]=c.authSchemes;e?.name===`sigv4a`&&t?.name===`sigv4`&&(o=t?.signingRegion??o,s=t?.signingName??s)}return await a.sign(e,{signingDate:vA(i.systemClockOffset),signingRegion:o,signingService:s})}errorHandler(e){return t=>{let n=t.ServerTime??_A(t.$response);if(n){let r=bA(`config`,e.config),i=r.systemClockOffset;r.systemClockOffset=yA(n,r.systemClockOffset),r.systemClockOffset!==i&&t.$metadata&&(t.$metadata.clockSkewCorrected=!0)}throw t}}successHandler(e,t){let n=_A(e);if(n){let e=bA(`config`,t.config);e.systemClockOffset=yA(n,e.systemClockOffset)}}},Fue=class extends SA{async sign(e,t,n){if(!Rb.isInstance(e))throw Error("The request is not an instance of `HttpRequest` and cannot be signed");let{config:r,signer:i,signingRegion:a,signingRegionSet:o,signingName:s}=await xA(n),c=(await r.sigv4aSigningRegionSet?.()??o??[a]).join(`,`);return await i.sign(e,{signingDate:vA(r.systemClockOffset),signingRegion:c,signingService:s})}},Iue=(e,t,n)=>{let r,i,a,o=!1,s=async()=>{i||=e();try{r=await i,a=!0,o=!1}finally{i=void 0}return r};return t===void 0?async e=>((!a||e?.forceRefresh)&&(r=await s()),r):async e=>((!a||e?.forceRefresh)&&(r=await s()),o?r:n&&!n(r)?(o=!0,r):(t(r)&&await s(),r))},Lue=e=>(e.sigv4aSigningRegionSet=XD(e.sigv4aSigningRegionSet),e),CA=e=>{let t=e.credentials,n=!!e.credentials,r;Object.defineProperty(e,`credentials`,{set(i){i&&i!==t&&i!==r&&(n=!0),t=i;let a=zue(e,Rue(e,{credentials:t,credentialDefaultProvider:e.credentialDefaultProvider}));if(n&&!a.attributed){let e=typeof t==`object`&&!!t;r=async t=>{let n=await a(t);return e&&(!n.$source||Object.keys(n.$source).length===0)?Rle(n,`CREDENTIALS_CODE`,`e`):n},r.memoized=a.memoized,r.configBound=a.configBound,r.attributed=!0}else r=a},get(){return r},enumerable:!0,configurable:!0}),e.credentials=t;let{signingEscapePath:i=!0,systemClockOffset:a=e.systemClockOffset||0,sha256:o}=e,s;return s=e.signer?XD(e.signer):e.regionInfoProvider?()=>XD(e.region)().then(async t=>[await e.regionInfoProvider(t,{useFipsEndpoint:await e.useFipsEndpoint(),useDualstackEndpoint:await e.useDualstackEndpoint()})||{},t]).then(([t,n])=>{let{signingRegion:r,signingService:a}=t;e.signingRegion=e.signingRegion||r||n,e.signingName=e.signingName||a||e.serviceId;let s={...e,credentials:e.credentials,region:e.signingRegion,service:e.signingName,sha256:o,uriEscapePath:i};return new(e.signerConstructor||fx)(s)}):async t=>{t=Object.assign({},{name:`sigv4`,signingName:e.signingName||e.defaultSigningName,signingRegion:await XD(e.region)(),properties:{}},t);let n=t.signingRegion,r=t.signingName;e.signingRegion=e.signingRegion||n,e.signingName=e.signingName||r||e.serviceId;let a={...e,credentials:e.credentials,region:e.signingRegion,service:e.signingName,sha256:o,uriEscapePath:i};return new(e.signerConstructor||fx)(a)},Object.assign(e,{systemClockOffset:a,signingEscapePath:i,signer:s})};function Rue(e,{credentials:t,credentialDefaultProvider:n}){let r;return r=t?t?.memoized?t:mle(t,ple,rk):n?XD(n(Object.assign({},e,{parentClientConfig:e}))):async()=>{throw Error("@aws-sdk/core::resolveAwsSdkSigV4Config - `credentials` not provided and no credentialDefaultProvider was configured.")},r.memoized=!0,r}function zue(e,t){if(t.configBound)return t;let n=async n=>t({...n,callerClientConfig:e});return n.memoized=t.memoized,n.configBound=!0,n}var Bue=async(e,t,n)=>({operation:lx(t).operation,region:await ux(e.region)()||(()=>{throw Error("expected `region` to be configured for `aws.auth#sigv4`")})()});function Vue(e){return{schemeId:`aws.auth#sigv4`,signingProperties:{name:`ec2`,region:e.region},propertiesExtractor:(e,t)=>({signingProperties:{config:e,context:t}})}}var Hue=e=>{let t=[];switch(e.operation){default:t.push(Vue(e))}return t},Uue=e=>{let t=CA(e);return Object.assign(t,{authSchemePreference:ux(e.authSchemePreference??[])})},Wue=e=>Object.assign(e,{useDualstackEndpoint:e.useDualstackEndpoint??!1,useFipsEndpoint:e.useFipsEndpoint??!1,defaultSigningName:`ec2`}),wA={UseFIPS:{type:`builtInParams`,name:`useFipsEndpoint`},Endpoint:{type:`builtInParams`,name:`endpoint`},Region:{type:`builtInParams`,name:`region`},UseDualStack:{type:`builtInParams`,name:`useDualstackEndpoint`}},Gue={name:`@aws-sdk/client-ec2`,description:`AWS SDK for JavaScript Ec2 Client for Node.js, Browser and React Native`,version:`3.1045.0`,scripts:{build:`concurrently 'yarn:build:types' 'yarn:build:es' && yarn build:cjs`,"build:cjs":`node ../../scripts/compilation/inline client-ec2`,"build:es":`tsc -p tsconfig.es.json`,"build:include:deps":`yarn g:turbo run build -F="$npm_package_name"`,"build:types":`tsc -p tsconfig.types.json`,"build:types:downlevel":`downlevel-dts dist-types dist-types/ts3.4`,clean:`premove dist-cjs dist-es dist-types tsconfig.cjs.tsbuildinfo tsconfig.es.tsbuildinfo tsconfig.types.tsbuildinfo`,"extract:docs":`api-extractor run --local`,"generate:client":`node ../../scripts/generate-clients/single-service --solo ec2`,test:`yarn g:vitest run --passWithNoTests`,"test:index":`tsc --noEmit ./test/index-types.ts && node ./test/index-objects.spec.mjs`,"test:integration":`yarn g:vitest run --passWithNoTests -c vitest.config.integ.mts`,"test:integration:watch":`yarn g:vitest run --passWithNoTests -c vitest.config.integ.mts`,"test:watch":`yarn g:vitest watch --passWithNoTests`},main:`./dist-cjs/index.js`,types:`./dist-types/index.d.ts`,module:`./dist-es/index.js`,sideEffects:!1,dependencies:{"@aws-crypto/sha256-browser":`5.2.0`,"@aws-crypto/sha256-js":`5.2.0`,"@aws-sdk/core":`^3.974.8`,"@aws-sdk/credential-provider-node":`^3.972.39`,"@aws-sdk/middleware-host-header":`^3.972.10`,"@aws-sdk/middleware-logger":`^3.972.10`,"@aws-sdk/middleware-recursion-detection":`^3.972.11`,"@aws-sdk/middleware-sdk-ec2":`^3.972.22`,"@aws-sdk/middleware-user-agent":`^3.972.38`,"@aws-sdk/region-config-resolver":`^3.972.13`,"@aws-sdk/types":`^3.973.8`,"@aws-sdk/util-endpoints":`^3.996.8`,"@aws-sdk/util-user-agent-browser":`^3.972.10`,"@aws-sdk/util-user-agent-node":`^3.973.24`,"@smithy/config-resolver":`^4.4.17`,"@smithy/core":`^3.23.17`,"@smithy/fetch-http-handler":`^5.3.17`,"@smithy/hash-node":`^4.2.14`,"@smithy/invalid-dependency":`^4.2.14`,"@smithy/middleware-content-length":`^4.2.14`,"@smithy/middleware-endpoint":`^4.4.32`,"@smithy/middleware-retry":`^4.5.7`,"@smithy/middleware-serde":`^4.2.20`,"@smithy/middleware-stack":`^4.2.14`,"@smithy/node-config-provider":`^4.3.14`,"@smithy/node-http-handler":`^4.6.1`,"@smithy/protocol-http":`^5.3.14`,"@smithy/smithy-client":`^4.12.13`,"@smithy/types":`^4.14.1`,"@smithy/url-parser":`^4.2.14`,"@smithy/util-base64":`^4.3.2`,"@smithy/util-body-length-browser":`^4.2.2`,"@smithy/util-body-length-node":`^4.2.3`,"@smithy/util-defaults-mode-browser":`^4.3.49`,"@smithy/util-defaults-mode-node":`^4.2.54`,"@smithy/util-endpoints":`^3.4.2`,"@smithy/util-middleware":`^4.2.14`,"@smithy/util-retry":`^4.3.6`,"@smithy/util-utf8":`^4.2.2`,"@smithy/util-waiter":`^4.3.0`,tslib:`^2.6.2`},devDependencies:{"@smithy/snapshot-testing":`^2.0.8`,"@tsconfig/node20":`20.1.8`,"@types/node":`^20.14.8`,concurrently:`7.0.0`,"downlevel-dts":`0.10.1`,premove:`4.0.0`,typescript:`~5.8.3`,vitest:`^4.0.17`},engines:{node:`>=20.0.0`},typesVersions:{"<4.5":{"dist-types/*":[`dist-types/ts3.4/*`]}},files:[`dist-*/**`],author:{name:`AWS SDK for JavaScript Team`,url:`https://aws.amazon.com/javascript/`},license:`Apache-2.0`,browser:{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.browser`},"react-native":{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.native`},homepage:`https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-ec2`,repository:{type:`git`,url:`https://github.com/aws/aws-sdk-js-v3.git`,directory:`clients/client-ec2`}},TA=({serviceId:e,clientVersion:t})=>async n=>{let r=typeof window<`u`?window.navigator:void 0,i=r?.userAgent??``,a=r?.userAgentData?.platform??EA.os(i)??`other`,o=r?.userAgentData?.brands??[],s=o[o.length-1],c=s?.brand??EA.browser(i)??`unknown`,l=s?.version??`unknown`,u=[[`aws-sdk-js`,t],[`ua`,`2.1`],[`os/${a}`,void 0],[`lang/js`],[`md/browser`,`${c}_${l}`]];e&&u.push([`api/${e}`,t]);let d=await n?.userAgentAppId?.();return d&&u.push([`app/${d}`]),u},EA={os(e){if(/iPhone|iPad|iPod/.test(e))return`iOS`;if(/Macintosh|Mac OS X/.test(e))return`macOS`;if(/Windows NT/.test(e))return`Windows`;if(/Android/.test(e))return`Android`;if(/Linux/.test(e))return`Linux`},browser(e){if(/EdgiOS|EdgA|Edg\//.test(e))return`Microsoft Edge`;if(/Firefox\//.test(e))return`Firefox`;if(/Chrome\//.test(e))return`Chrome`;if(/Safari\//.test(e))return`Safari`}},DA=e=>()=>Promise.reject(e),OA=typeof TextEncoder==`function`?new TextEncoder:null,kA=e=>{if(typeof e==`string`){if(OA)return OA.encode(e).byteLength;let t=e.length;for(let n=t-1;n>=0;n--){let r=e.charCodeAt(n);r>127&&r<=2047?t++:r>2047&&r<=65535&&(t+=2),r>=56320&&r<=57343&&n--}return t}else if(typeof e.byteLength==`number`)return e.byteLength;else if(typeof e.size==`number`)return e.size;throw Error(`Body Length computation failed for ${e}`)},Kue=[`in-region`,`cross-region`,`mobile`,`standard`,`legacy`],AA=({defaultsMode:e}={})=>Iue(async()=>{let t=typeof e==`function`?await e():e;switch(t?.toLowerCase()){case`auto`:return Promise.resolve(que()?`mobile`:`standard`);case`mobile`:case`in-region`:case`cross-region`:case`standard`:case`legacy`:return Promise.resolve(t?.toLocaleLowerCase());case void 0:return Promise.resolve(`legacy`);default:throw Error(`Invalid parameter for "defaultsMode", expect ${Kue.join(`, `)}, got ${t}`)}}),que=()=>{let e=window?.navigator;if(e?.connection){let{effectiveType:t,rtt:n,downlink:r}=e?.connection;if(typeof t==`string`&&t!==`4g`||Number(n)>100||Number(r)<10)return!0}return e?.userAgentData?.mobile||typeof e?.maxTouchPoints==`number`&&e?.maxTouchPoints>1},jA=class{queryCompat;errorRegistry;constructor(e=!1){this.queryCompat=e}resolveRestContentType(e,t){let n=t.getMemberSchemas(),r=Object.values(n).find(e=>!!e.getMergedTraits().httpPayload);if(r)return r.getMergedTraits().mediaType||(r.isStringSchema()?`text/plain`:r.isBlobSchema()?`application/octet-stream`:e);if(!t.isUnitSchema()&&Object.values(n).find(e=>{let{httpQuery:t,httpQueryParams:n,httpHeader:r,httpLabel:i,httpPrefixHeaders:a}=e.getMergedTraits();return!t&&!n&&!r&&!i&&a===void 0}))return e}async getErrorSchemaOrThrowBaseException(e,t,n,r,i,a){let o=e;e.includes(`#`)&&([,o]=e.split(`#`));let s={$metadata:i,$fault:n.statusCode<500?`client`:`server`};if(!this.errorRegistry)throw Error(`@aws-sdk/core/protocols - error handler not initialized.`);try{return{errorSchema:a?.(this.errorRegistry,o)??this.errorRegistry.getSchema(e),errorMetadata:s}}catch{r.message=r.message??r.Message??`UnknownError`;let e=this.errorRegistry,t=e.getBaseException();if(t){let n=e.getErrorCtor(t)??Error;throw this.decorateServiceException(Object.assign(new n({name:o}),s),r)}let n=r,i=n?.message??n?.Message??n?.Error?.Message??n?.Error?.message;throw this.decorateServiceException(Object.assign(Error(i),{name:o},s),r)}}compose(e,t,n){let r=n;t.includes(`#`)&&([r]=t.split(`#`));let i=OO.for(r),a=OO.for(`smithy.ts.sdk.synthetic.`+n);e.copyFrom(i),e.copyFrom(a),this.errorRegistry=e}decorateServiceException(e,t={}){if(this.queryCompat){let n=e.Message??t.Message,r=cA(e,t);n&&(r.message=n);let i=r.Error??{};i.Type=r.Error?.Type,i.Code=r.Error?.Code,i.Message=r.Error?.message??r.Error?.Message??n,r.Error=i;let a=r.$metadata.requestId;return a&&(r.RequestId=a),r}return cA(e,t)}setQueryCompatError(e,t){let n=t.headers?.[`x-amzn-query-error`];if(e!==void 0&&n!=null){let[t,r]=n.split(`;`),i=Object.keys(e),a={Code:t,Type:r};e.Code=t,e.Type=r;for(let t=0;tTO.of(e).getMergedTraits().awsQueryError?.[0]===t)}}},MA=class{serdeContext;setSerdeContext(e){this.serdeContext=e}},Jue=class{from;to;keys;constructor(e,t){this.from=e,this.to=t;let n=Object.keys(this.from),r=new Set(n);r.delete(`__type`),this.keys=r}mark(e){this.keys.delete(e)}hasUnknown(){return this.keys.size===1&&Object.keys(this.to).length===0}writeUnknown(){if(this.hasUnknown()){let e=this.keys.values().next().value,t=this.from[e];this.to.$unknown=[e,t]}}},Yue=/[&<>"]/g,Xue={"&":`&`,"<":`<`,">":`>`,'"':`"`};function Zue(e){return e.replace(Yue,e=>Xue[e])}var Que=/[&"'<>\r\n\u0085\u2028]/g,$ue={"&":`&`,'"':`"`,"'":`'`,"<":`<`,">":`>`,"\r":` `,"\n":` `,"…":`…`,"\u2028":`
`};function ede(e){return e.replace(Que,e=>$ue[e])}var NA=class{value;constructor(e){this.value=e}toString(){return ede(``+this.value)}},PA=class e{name;children;attributes={};static of(t,n,r){let i=new e(t);return n!==void 0&&i.addChildNode(new NA(n)),r!==void 0&&i.withName(r),i}constructor(e,t=[]){this.name=e,this.children=t}withName(e){return this.name=e,this}addAttribute(e,t){return this.attributes[e]=t,this}addChildNode(e){return this.children.push(e),this}removeAttribute(e){return delete this.attributes[e],this}n(e){return this.name=e,this}c(e){return this.children.push(e),this}a(e,t){return t!=null&&(this.attributes[e]=t),this}cc(t,n,r=n){if(t[n]!=null){let i=e.of(n,t[n]).withName(r);this.c(i)}}l(e,t,n,r){e[t]!=null&&r().map(e=>{e.withName(n),this.c(e)})}lc(t,n,r,i){if(t[n]!=null){let t=i(),n=new e(r);t.map(e=>{n.c(e)}),this.c(n)}}toString(){let e=!!this.children.length,t=`<${this.name}`,n=this.attributes;for(let e of Object.keys(n)){let r=n[e];r!=null&&(t+=` ${e}="${Zue(``+r)}"`)}return t+=e?`>${this.children.map(e=>e.toString()).join(``)}`:`/>`}},FA;function tde(e){FA||=new DOMParser;let t=FA.parseFromString(e,`application/xml`);if(t.getElementsByTagName(`parsererror`).length>0)throw Error(`DOMParser XML parsing error.`);let n=e=>{if(e.nodeType===Node.TEXT_NODE&&e.textContent?.trim())return e.textContent;if(e.nodeType===Node.ELEMENT_NODE){let t=e;if(t.attributes.length===0&&t.childNodes.length===0)return``;let r={},i=Array.from(t.attributes);for(let e of i)r[`${e.name}`]=e.value;let a=Array.from(t.childNodes);for(let e of a){let o=n(e);if(o!=null){let t=e.nodeName;if(a.length===1&&i.length===0&&t===`#text`)return o;r[t]?Array.isArray(r[t])?r[t].push(o):r[t]=[r[t],o]:r[t]=o}else if(a.length===1&&i.length===0)return t.textContent}return r}return null};return{[t.documentElement.nodeName]:n(t.documentElement)}}var IA=class extends MA{settings;stringDeserializer;constructor(e){super(),this.settings=e,this.stringDeserializer=new tk(e)}setSerdeContext(e){this.serdeContext=e,this.stringDeserializer.setSerdeContext(e)}read(e,t,n){let r=TO.of(e),i=r.getMemberSchemas();if(r.isStructSchema()&&r.isMemberSchema()&&Object.values(i).find(e=>!!e.getMemberTraits().eventPayload)){let e={},n=Object.keys(i)[0];return i[n].isBlobSchema()?e[n]=t:e[n]=this.read(i[n],t),e}let a=(this.serdeContext?.utf8Encoder??Kb)(t),o=this.parseXml(a);return this.readSchema(e,n?o[n]:o)}readSchema(e,t){let n=TO.of(e);if(n.isUnitSchema())return;let r=n.getMergedTraits();if(n.isListSchema()&&!Array.isArray(t))return this.readSchema(n,[t]);if(t==null)return t;if(typeof t==`object`){let e=!!r.xmlFlattened;if(n.isListSchema()){let r=n.getValueSchema(),i=[],a=r.getMergedTraits().xmlName??`member`,o=e?t:(t[0]??t)[a];if(o==null)return i;let s=Array.isArray(o)?o:[o];for(let e of s)i.push(this.readSchema(r,e));return i}let i={};if(n.isMapSchema()){let r=n.getKeySchema(),a=n.getValueSchema(),o;o=e?Array.isArray(t)?t:[t]:Array.isArray(t.entry)?t.entry:[t.entry];let s=r.getMergedTraits().xmlName??`key`,c=a.getMergedTraits().xmlName??`value`;for(let e of o){let t=e[s],n=e[c];i[t]=this.readSchema(a,n)}return i}if(n.isStructSchema()){let e=n.isUnionSchema(),r;e&&(r=new Jue(t,i));for(let[a,o]of n.structIterator()){let n=o.getMergedTraits(),s=n.httpPayload?n.xmlName??o.getName():o.getMemberTraits().xmlName??a;e&&r.mark(s),t[s]!=null&&(i[a]=this.readSchema(o,t[s]))}return e&&r.writeUnknown(),i}if(n.isDocumentSchema())return t;throw Error(`@aws-sdk/core/protocols - xml deserializer unhandled schema type for ${n.getName(!0)}`)}return n.isListSchema()?[]:n.isMapSchema()||n.isStructSchema()?{}:this.stringDeserializer.read(n,t)}parseXml(e){if(e.length){let t;try{t=tde(e)}catch(t){throw t&&typeof t==`object`&&Object.defineProperty(t,`$responseBodyText`,{value:e}),t}let n=`#text`,r=Object.keys(t)[0],i=t[r];return i[n]&&(i[r]=i[n],delete i[n]),pA(i)}return{}}},nde=class extends MA{settings;buffer;constructor(e){super(),this.settings=e}write(e,t,n=``){this.buffer===void 0&&(this.buffer=``);let r=TO.of(e);if(n&&!n.endsWith(`.`)&&(n+=`.`),r.isBlobSchema())(typeof t==`string`||t instanceof Uint8Array)&&(this.writeKey(n),this.writeValue((this.serdeContext?.base64Encoder??tO)(t)));else if(r.isBooleanSchema()||r.isNumericSchema()||r.isStringSchema())t==null?r.isIdempotencyToken()&&(this.writeKey(n),this.writeValue(VO())):(this.writeKey(n),this.writeValue(String(t)));else if(r.isBigIntegerSchema())t!=null&&(this.writeKey(n),this.writeValue(String(t)));else if(r.isBigDecimalSchema())t!=null&&(this.writeKey(n),this.writeValue(t instanceof ZO?t.string:String(t)));else if(r.isTimestampSchema()){if(t instanceof Date)switch(this.writeKey(n),ek(r,this.settings)){case 5:this.writeValue(t.toISOString().replace(`.000Z`,`Z`));break;case 6:this.writeValue(NO(t));break;case 7:this.writeValue(String(t.getTime()/1e3));break}}else if(r.isDocumentSchema())Array.isArray(t)?this.write(79,t,n):t instanceof Date?this.write(4,t,n):t instanceof Uint8Array?this.write(21,t,n):t&&typeof t==`object`?this.write(143,t,n):(this.writeKey(n),this.writeValue(String(t)));else if(r.isListSchema()){if(Array.isArray(t))if(t.length===0)this.settings.serializeEmptyLists&&(this.writeKey(n),this.writeValue(``));else{let e=r.getValueSchema(),i=this.settings.flattenLists||r.getMergedTraits().xmlFlattened,a=1;for(let r of t){if(r==null)continue;let t=e.getMergedTraits(),o=this.getKey(`member`,t.xmlName,t.ec2QueryName),s=i?`${n}${a}`:`${n}${o}.${a}`;this.write(e,r,s),++a}}}else if(r.isMapSchema()){if(t&&typeof t==`object`){let e=r.getKeySchema(),i=r.getValueSchema(),a=r.getMergedTraits().xmlFlattened,o=1;for(let r in t){let s=t[r];if(s==null)continue;let c=e.getMergedTraits(),l=this.getKey(`key`,c.xmlName,c.ec2QueryName),u=a?`${n}${o}.${l}`:`${n}entry.${o}.${l}`,d=i.getMergedTraits(),f=this.getKey(`value`,d.xmlName,d.ec2QueryName),p=a?`${n}${o}.${f}`:`${n}entry.${o}.${f}`;this.write(e,r,u),this.write(i,s,p),++o}}}else if(r.isStructSchema()){if(t&&typeof t==`object`){let e=!1;for(let[i,a]of r.structIterator()){if(t[i]==null&&!a.isIdempotencyToken())continue;let r=a.getMergedTraits(),o=this.getKey(i,r.xmlName,r.ec2QueryName,`struct`),s=`${n}${o}`;this.write(a,t[i],s),e=!0}if(!e&&r.isUnionSchema()){let{$unknown:e}=t;if(Array.isArray(e)){let[t,r]=e,i=`${n}${t}`;this.write(15,r,i)}}}}else if(!r.isUnitSchema())throw Error(`@aws-sdk/core/protocols - QuerySerializer unrecognized schema type ${r.getName(!0)}`)}flush(){if(this.buffer===void 0)throw Error(`@aws-sdk/core/protocols - QuerySerializer cannot flush with nothing written to buffer.`);let e=this.buffer;return delete this.buffer,e}getKey(e,t,n,r){let{ec2:i,capitalizeKeys:a}=this.settings;if(i&&n)return n;let o=t??e;return a&&r===`struct`?o[0].toUpperCase()+o.slice(1):o}writeKey(e){e.endsWith(`.`)&&(e=e.slice(0,e.length-1)),this.buffer+=`&${mO(e)}=`}writeValue(e){this.buffer+=mO(e)}},LA=class extends cle{options;serializer;deserializer;mixin=new jA;constructor(e){super({defaultNamespace:e.defaultNamespace,errorTypeRegistries:e.errorTypeRegistries}),this.options=e;let t={timestampFormat:{useTrait:!0,default:5},httpBindings:!1,xmlNamespace:e.xmlNamespace,serviceNamespace:e.defaultNamespace,serializeEmptyLists:!0};this.serializer=new nde(t),this.deserializer=new IA(t)}getShapeId(){return`aws.protocols#awsQuery`}setSerdeContext(e){this.serializer.setSerdeContext(e),this.deserializer.setSerdeContext(e)}getPayloadCodec(){throw Error(`AWSQuery protocol has no payload codec.`)}async serializeRequest(e,t,n){let r=await super.serializeRequest(e,t,n);return r.path.endsWith(`/`)||(r.path+=`/`),r.headers[`content-type`]=`application/x-www-form-urlencoded`,(hO(e.input)===`unit`||!r.body)&&(r.body=``),r.body=`Action=${e.name.split(`#`)[1]??e.name}&Version=${this.options.version}`+r.body,r.body.endsWith(`&`)&&(r.body=r.body.slice(-1)),r}async deserializeResponse(e,t,n){let r=this.deserializer,i=TO.of(e.output),a={};if(n.statusCode>=300){let i=await pO(n.body,t);i.byteLength>0&&Object.assign(a,await r.read(15,i)),await this.handleError(e,t,n,a,this.deserializeMetadata(n))}for(let e in n.headers){let t=n.headers[e];delete n.headers[e],n.headers[e.toLowerCase()]=t}let o=e.name.split(`#`)[1]??e.name,s=i.isStructSchema()&&this.useNestedResult()?o+`Result`:void 0,c=await pO(n.body,t);return c.byteLength>0&&Object.assign(a,await r.read(i,c,s)),a.$metadata=this.deserializeMetadata(n),a}useNestedResult(){return!0}async handleError(e,t,n,r,i){let a=this.loadQueryErrorCode(n,r)??`Unknown`;this.mixin.compose(this.compositeErrorRegistry,a,this.options.defaultNamespace);let o=this.loadQueryError(r)??{},s=this.loadQueryErrorMessage(r);o.message=s,o.Error={Type:o.Type,Code:o.Code,Message:s};let{errorSchema:c,errorMetadata:l}=await this.mixin.getErrorSchemaOrThrowBaseException(a,this.options.defaultNamespace,n,o,i,this.mixin.findQueryCompatibleError),u=TO.of(c),d=new((this.compositeErrorRegistry.getErrorCtor(c))??Error)(s),f={Type:o.Error.Type,Code:o.Error.Code,Error:o.Error};for(let[e,t]of u.structIterator()){let n=t.getMergedTraits().xmlName??e,i=o[n]??r[n];f[e]=this.deserializer.readSchema(t,i)}throw this.mixin.decorateServiceException(Object.assign(d,l,{$fault:u.getMergedTraits().error,message:s},f),r)}loadQueryErrorCode(e,t){let n=(t.Errors?.[0]?.Error??t.Errors?.Error??t.Error)?.Code;if(n!==void 0)return n;if(e.statusCode==404)return`NotFound`}loadQueryError(e){return e.Errors?.[0]?.Error??e.Errors?.Error??e.Error}loadQueryErrorMessage(e){let t=this.loadQueryError(e);return t?.message??t?.Message??e.message??e.Message??`Unknown`}getDefaultContentType(){return`application/x-www-form-urlencoded`}},rde=class extends LA{options;constructor(e){super(e),this.options=e,Object.assign(this.serializer.settings,{capitalizeKeys:!0,flattenLists:!0,serializeEmptyLists:!1,ec2:!0})}getShapeId(){return`aws.protocols#ec2Query`}useNestedResult(){return!1}},ide=(e,t)=>{if(t?.Error?.Code!==void 0)return t.Error.Code;if(t?.Code!==void 0)return t.Code;if(e.statusCode==404)return`NotFound`},ade=class extends MA{settings;stringBuffer;byteBuffer;buffer;constructor(e){super(),this.settings=e}write(e,t){let n=TO.of(e);if(n.isStringSchema()&&typeof t==`string`)this.stringBuffer=t;else if(n.isBlobSchema())this.byteBuffer=`byteLength`in t?t:(this.serdeContext?.base64Decoder??eO)(t);else{this.buffer=this.writeStruct(n,t,void 0);let e=n.getMergedTraits();e.httpPayload&&!e.xmlName&&this.buffer.withName(n.getName())}}flush(){if(this.byteBuffer!==void 0){let e=this.byteBuffer;return delete this.byteBuffer,e}if(this.stringBuffer!==void 0){let e=this.stringBuffer;return delete this.stringBuffer,e}let e=this.buffer;return this.settings.xmlNamespace&&(e?.attributes?.xmlns||e.addAttribute(`xmlns`,this.settings.xmlNamespace)),delete this.buffer,e.toString()}writeStruct(e,t,n){let r=e.getMergedTraits(),i=e.isMemberSchema()&&!r.httpPayload?e.getMemberTraits().xmlName??e.getMemberName():r.xmlName??e.getName();if(!i||!e.isStructSchema())throw Error(`@aws-sdk/core/protocols - xml serializer, cannot write struct with empty name or non-struct, schema=${e.getName(!0)}.`);let a=PA.of(i),[o,s]=this.getXmlnsAttribute(e,n);for(let[n,r]of e.structIterator()){let e=t[n];if(e!=null||r.isIdempotencyToken()){if(r.getMergedTraits().xmlAttribute){a.addAttribute(r.getMergedTraits().xmlName??n,this.writeSimple(r,e));continue}if(r.isListSchema())this.writeList(r,e,a,s);else if(r.isMapSchema())this.writeMap(r,e,a,s);else if(r.isStructSchema())a.addChildNode(this.writeStruct(r,e,s));else{let t=PA.of(r.getMergedTraits().xmlName??r.getMemberName());this.writeSimpleInto(r,e,t,s),a.addChildNode(t)}}}let{$unknown:c}=t;if(c&&e.isUnionSchema()&&Array.isArray(c)&&Object.keys(t).length===1){let[e,n]=c,r=PA.of(e);if(typeof n!=`string`)if(t instanceof PA||t instanceof NA)a.addChildNode(t);else throw Error(`@aws-sdk - $unknown union member in XML requires value of type string, @aws-sdk/xml-builder::XmlNode or XmlText.`);this.writeSimpleInto(0,n,r,s),a.addChildNode(r)}return s&&a.addAttribute(o,s),a}writeList(e,t,n,r){if(!e.isMemberSchema())throw Error(`@aws-sdk/core/protocols - xml serializer, cannot write non-member list: ${e.getName(!0)}`);let i=e.getMergedTraits(),a=e.getValueSchema(),o=a.getMergedTraits(),s=!!o.sparse,c=!!i.xmlFlattened,[l,u]=this.getXmlnsAttribute(e,r),d=(t,n)=>{if(a.isListSchema())this.writeList(a,Array.isArray(n)?n:[n],t,u);else if(a.isMapSchema())this.writeMap(a,n,t,u);else if(a.isStructSchema()){let r=this.writeStruct(a,n,u);t.addChildNode(r.withName(c?i.xmlName??e.getMemberName():o.xmlName??`member`))}else{let r=PA.of(c?i.xmlName??e.getMemberName():o.xmlName??`member`);this.writeSimpleInto(a,n,r,u),t.addChildNode(r)}};if(c)for(let e of t)(s||e!=null)&&d(n,e);else{let r=PA.of(i.xmlName??e.getMemberName());u&&r.addAttribute(l,u);for(let e of t)(s||e!=null)&&d(r,e);n.addChildNode(r)}}writeMap(e,t,n,r,i=!1){if(!e.isMemberSchema())throw Error(`@aws-sdk/core/protocols - xml serializer, cannot write non-member map: ${e.getName(!0)}`);let a=e.getMergedTraits(),o=e.getKeySchema(),s=o.getMergedTraits().xmlName??`key`,c=e.getValueSchema(),l=c.getMergedTraits(),u=l.xmlName??`value`,d=!!l.sparse,f=!!a.xmlFlattened,[p,m]=this.getXmlnsAttribute(e,r),h=(e,t,n)=>{let r=PA.of(s,t),[i,a]=this.getXmlnsAttribute(o,m);a&&r.addAttribute(i,a),e.addChildNode(r);let l=PA.of(u);c.isListSchema()?this.writeList(c,n,l,m):c.isMapSchema()?this.writeMap(c,n,l,m,!0):c.isStructSchema()?l=this.writeStruct(c,n,m):this.writeSimpleInto(c,n,l,m),e.addChildNode(l)};if(f)for(let r in t){let i=t[r];if(d||i!=null){let t=PA.of(a.xmlName??e.getMemberName());h(t,r,i),n.addChildNode(t)}}else{let r;i||(r=PA.of(a.xmlName??e.getMemberName()),m&&r.addAttribute(p,m),n.addChildNode(r));for(let e in t){let a=t[e];if(d||a!=null){let t=PA.of(`entry`);h(t,e,a),(i?n:r).addChildNode(t)}}}}writeSimple(e,t){if(t===null)throw Error(`@aws-sdk/core/protocols - (XML serializer) cannot write null value.`);let n=TO.of(e),r=null;if(t&&typeof t==`object`)if(n.isBlobSchema())r=(this.serdeContext?.base64Encoder??tO)(t);else if(n.isTimestampSchema()&&t instanceof Date)switch(ek(n,this.settings)){case 5:r=t.toISOString().replace(`.000Z`,`Z`);break;case 6:r=NO(t);break;case 7:r=String(t.getTime()/1e3);break;default:console.warn(`Missing timestamp format, using http date`,t),r=NO(t);break}else if(n.isBigDecimalSchema()&&t)return t instanceof ZO?t.string:String(t);else if(n.isMapSchema()||n.isListSchema())throw Error(`@aws-sdk/core/protocols - xml serializer, cannot call _write() on List/Map schema, call writeList or writeMap() instead.`);else throw Error(`@aws-sdk/core/protocols - xml serializer, unhandled schema type for object value and schema: ${n.getName(!0)}`);if((n.isBooleanSchema()||n.isNumericSchema()||n.isBigIntegerSchema()||n.isBigDecimalSchema())&&(r=String(t)),n.isStringSchema()&&(r=t===void 0&&n.isIdempotencyToken()?VO():String(t)),r===null)throw Error(`Unhandled schema-value pair ${n.getName(!0)}=${t}`);return r}writeSimpleInto(e,t,n,r){let i=this.writeSimple(e,t),a=TO.of(e),o=new NA(i),[s,c]=this.getXmlnsAttribute(a,r);c&&n.addAttribute(s,c),n.addChildNode(o)}getXmlnsAttribute(e,t){let[n,r]=e.getMergedTraits().xmlNamespace??[];return r&&r!==t?[n?`xmlns:${n}`:`xmlns`,r]:[void 0,void 0]}},ode=class extends MA{settings;constructor(e){super(),this.settings=e}createSerializer(){let e=new ade(this.settings);return e.setSerdeContext(this.serdeContext),e}createDeserializer(){let e=new IA(this.settings);return e.setSerdeContext(this.serdeContext),e}},sde=class extends sle{codec;serializer;deserializer;mixin=new jA;constructor(e){super(e);let t={timestampFormat:{useTrait:!0,default:5},httpBindings:!0,xmlNamespace:e.xmlNamespace,serviceNamespace:e.defaultNamespace};this.codec=new ode(t),this.serializer=new dle(this.codec.createSerializer(),t),this.deserializer=new lle(this.codec.createDeserializer(),t)}getPayloadCodec(){return this.codec}getShapeId(){return`aws.protocols#restXml`}async serializeRequest(e,t,n){let r=await super.serializeRequest(e,t,n),i=TO.of(e.input);if(!r.headers[`content-type`]){let e=this.mixin.resolveRestContentType(this.getDefaultContentType(),i);e&&(r.headers[`content-type`]=e)}return typeof r.body==`string`&&r.headers[`content-type`]===this.getDefaultContentType()&&!r.body.startsWith(``+r.body),r}async deserializeResponse(e,t,n){return super.deserializeResponse(e,t,n)}async handleError(e,t,n,r,i){let a=ide(n,r)??`Unknown`;if(this.mixin.compose(this.compositeErrorRegistry,a,this.options.defaultNamespace),r.Error&&typeof r.Error==`object`)for(let e of Object.keys(r.Error))r[e]=r.Error[e],e.toLowerCase()===`message`&&(r.message=r.Error[e]);r.RequestId&&!i.requestId&&(i.requestId=r.RequestId);let{errorSchema:o,errorMetadata:s}=await this.mixin.getErrorSchemaOrThrowBaseException(a,this.options.defaultNamespace,n,r,i),c=TO.of(o),l=r.Error?.message??r.Error?.Message??r.message??r.Message??`UnknownError`,u=new((this.compositeErrorRegistry.getErrorCtor(o))??Error)(l);await this.deserializeHttpMessage(o,t,n,r);let d={},f=this.codec.createDeserializer();for(let[e,t]of c.structIterator()){let n=t.getMergedTraits().xmlName??e,i=r.Error?.[n]??r[n];d[e]=f.readSchema(t,i)}throw this.mixin.decorateServiceException(Object.assign(u,s,{$fault:c.getMergedTraits().error,message:l},d),r)}getDefaultContentType(){return`application/xml`}hasUnstructuredPayloadBinding(e){for(let[,t]of e.structIterator())if(t.getMergedTraits().httpPayload)return!(t.isStructSchema()||t.isMapSchema()||t.isListSchema());return!1}},RA=`ref`,zA=-1,BA=!0,VA=`isSet`,HA=`PartitionResult`,UA=`booleanEquals`,WA=`getAttr`,GA={[RA]:`Endpoint`},KA={[RA]:HA},qA={},JA=[{[RA]:`Region`}],YA={conditions:[[VA,[GA]],[VA,JA],[`aws.partition`,JA,HA],[UA,[{[RA]:`UseFIPS`},BA]],[UA,[{[RA]:`UseDualStack`},BA]],[UA,[{fn:WA,argv:[KA,`supportsDualStack`]},BA]],[UA,[{fn:WA,argv:[KA,`supportsFIPS`]},BA]],[`stringEquals`,[{fn:WA,argv:[KA,`name`]},`aws-us-gov`]]],results:[[zA],[zA,`Invalid Configuration: FIPS and custom endpoint are not supported`],[zA,`Invalid Configuration: Dualstack and custom endpoint are not supported`],[GA,qA],[`https://ec2-fips.{Region}.{PartitionResult#dualStackDnsSuffix}`,qA],[zA,`FIPS and DualStack are enabled, but this partition does not support one or both`],[`https://ec2.{Region}.amazonaws.com`,qA],[`https://ec2-fips.{Region}.{PartitionResult#dnsSuffix}`,qA],[zA,`FIPS is enabled but this partition does not support FIPS`],[`https://ec2.{Region}.{PartitionResult#dualStackDnsSuffix}`,qA],[zA,`DualStack is enabled but this partition does not support DualStack`],[`https://ec2.{Region}.{PartitionResult#dnsSuffix}`,qA],[zA,`Invalid Configuration: Missing Region`]]},cde=2,XA=1e8,lde=new Int32Array([-1,1,-1,0,13,3,1,4,XA+12,2,5,XA+12,3,8,6,4,7,XA+11,5,XA+9,XA+10,4,11,9,6,10,XA+8,7,XA+6,XA+7,5,12,XA+5,6,XA+4,XA+5,3,XA+1,14,4,XA+2,XA+3]),ude=ak.from(lde,cde,YA.conditions,YA.results),dde=new ok({size:50,params:[`Endpoint`,`Region`,`UseDualStack`,`UseFIPS`]}),fde=(e,t={})=>dde.get(e,()=>Sk(ude,{endpointParams:e,logger:t.logger}));lk.aws=Tk;var pde=class e extends sA{constructor(t){super(t),Object.setPrototypeOf(this,e.prototype)}},mde=`AllAvailabilityZones`,hde=`AttributeBooleanValue`,gde=`AssociateCarrierIpAddress`,_de=`AdditionalFlexibleNetworkInterfaces`,vde=`AvailableIpAddressCount`,yde=`AssignIpv6AddressOnCreation`,bde=`AttachInternetGateway`,xde=`AttachInternetGatewayRequest`,ZA=`AdditionalInfo`,QA=`AssociationId`,$A=`AttachmentId`,Sde=`AmiLaunchIndex`,Cde=`AttachmentLimitType`,wde=`AssociatePublicIpAddress`,Tde=`AmazonProvidedIpv6CidrBlock`,Ede=`AutoRecoverySupported`,Dde=`AssociateRouteTableRequest`,Ode=`AssociateRouteTableResult`,kde=`AssociateRouteTable`,Ade=`AllRegions`,ej=`AssociatedResource`,tj=`AutoRecovery`,nj=`AssociationState`,jde=`AuthorizeSecurityGroupEgress`,Mde=`AuthorizeSecurityGroupEgressRequest`,Nde=`AuthorizeSecurityGroupEgressResult`,Pde=`AuthorizeSecurityGroupIngressRequest`,Fde=`AuthorizeSecurityGroupIngressResult`,Ide=`AuthorizeSecurityGroupIngress`,rj=`AmdSevSnp`,Lde=`ArchitectureTypeList`,ij=`AttachTime`,Rde=`AttachVolumeRequest`,zde=`AttributeValue`,Bde=`AttachVolume`,aj=`AvailabilityZone`,Vde=`AvailabilityZoneGeography`,Hde=`AvailabilityZoneGeographyList`,oj=`AvailabilityZoneId`,Ude=`AvailabilityZoneList`,Wde=`AvailabilityZoneMessage`,Gde=`AvailabilityZoneMessageList`,Kde=`AvailabilityZoneSubGeography`,qde=`AvailabilityZoneSubGeographyList`,Jde=`AvailabilityZones`,sj=`Accelerators`,Yde=`Affinity`,cj=`Arn`,lj=`Architecture`,Xde=`Associations`,uj=`Association`,Zde=`Attribute`,dj=`Attachment`,fj=`Attachments`,Qde=`BlobAttributeValue`,$de=`BaselineBandwidthInGbps`,pj=`BaselineBandwidthInMbps`,mj=`BlockDeviceMapping`,efe=`BlockDeviceMappingList`,tfe=`BlockDeviceMappingRequestList`,hj=`BlockDeviceMappings`,nfe=`BlockDurationMinutes`,gj=`BaselineIops`,_j=`BootMode`,rfe=`BootModeTypeList`,ife=`BareMetal`,vj=`BlockPublicAccessStates`,yj=`BurstablePerformanceSupported`,bj=`BaselineThroughputInMBps`,xj=`BandwidthWeighting`,Sj=`BandwidthWeightingTypeList`,Cj=`BandwidthWeightings`,wj=`CidrBlock`,Tj=`CidrBlockAssociationSet`,Ej=`CapacityBlockId`,Dj=`CidrBlockState`,Oj=`CoreCountList`,kj=`CoreCount`,Aj=`CpuCredits`,jj=`CompletionDurationMinutes`,Mj=`CreationDate`,Nj=`CarrierGatewayId`,Pj=`CurrentGeneration`,Fj=`CarrierIp`,Ij=`CurrentInstanceBootMode`,Lj=`CreateInternetGateway`,Rj=`CreateInternetGatewayRequest`,zj=`CreateInternetGatewayResult`,Bj=`CreateImageRequest`,Vj=`CreateImageResult`,Hj=`CidrIp`,Uj=`CidrIpv6`,Wj=`CidrIpv4`,Gj=`CoreInfo`,Kj=`CreateImage`,qj=`CreateKeyPair`,Jj=`CreateKeyPairRequest`,Yj=`CoreNetworkArn`,Xj=`CpuOptions`,Zj=`CustomerOwnedIp`,Qj=`CustomerOwnedIpv4Pool`,$j=`CpuOptionsRequest`,eM=`CreatePlacementGroup`,tM=`CreatePlacementGroupRequest`,nM=`CreatePlacementGroupResult`,rM=`CapacityReservationId`,iM=`CapacityReservationPreference`,aM=`CreateRouteRequest`,oM=`CapacityReservationResourceGroupArn`,sM=`CreateRouteResult`,cM=`CapacityReservationSpecificationResponse`,lM=`CapacityReservationSpecification`,uM=`CapacityReservationTarget`,dM=`CapacityReservationTargetResponse`,fM=`CreateRouteTableRequest`,pM=`CreateRouteTableResult`,mM=`CreateRouteTable`,hM=`CreateRoute`,gM=`CreateSecurityGroup`,_M=`CreateSecurityGroupRequest`,vM=`CreateSecurityGroupResult`,yM=`CopySnapshotRequest`,bM=`CopySnapshotRequestPSU`,xM=`CopySnapshotResult`,SM=`CreateSnapshotRequest`,CM=`CreateSubnetRequest`,wM=`CreateSubnetResult`,TM=`CreditSpecificationRequest`,EM=`CopySnapshot`,DM=`CreditSpecification`,OM=`CreateSnapshot`,kM=`CreateSubnet`,AM=`CurrentState`,jM=`ClientToken`,MM=`ConnectionTrackingConfiguration`,NM=`ConnectionTrackingSpecification`,PM=`ConnectionTrackingSpecificationRequest`,FM=`ConnectionTrackingSpecificationResponse`,IM=`CompletionTime`,LM=`CreateTime`,RM=`CreateVolumeRequest`,zM=`CreateVpcRequest`,BM=`CreateVpcResult`,VM=`CreateVolume`,HM=`CreateVpc`,UM=`Code`,WM=`Configured`,GM=`Count`,KM=`DisableApiStop`,qM=`DisableApiTermination`,JM=`DestinationAvailabilityZone`,YM=`DescribeAvailabilityZonesRequest`,XM=`DescribeAvailabilityZonesResult`,ZM=`DescribeAvailabilityZones`,QM=`DestinationCidrBlock`,$M=`DefaultConnectionTrackingConfiguration`,eN=`DefaultCores`,tN=`DataEncryptionKeyId`,nN=`DefaultEnaQueueCountPerInterface`,rN=`DefaultForAz`,iN=`DedicatedHostsSupported`,aN=`DeviceIndex`,oN=`DestinationIpv6CidrBlock`,sN=`DescribeInternetGatewaysRequest`,cN=`DescribeInternetGatewaysResult`,lN=`DescribeInternetGateways`,uN=`DiskInfoList`,dN=`DescribeImagesRequest`,fN=`DescribeImagesResult`,pN=`DescribeInstancesRequest`,mN=`DescribeInstancesResult`,hN=`DescribeInstanceTypesRequest`,gN=`DescribeInstanceTypesResult`,_N=`DescribeInstanceTypes`,vN=`DescribeImages`,yN=`DescribeInstances`,bN=`DiskInfo`,xN=`DeleteKeyPair`,SN=`DeleteKeyPairRequest`,CN=`DeleteKeyPairResult`,wN=`DescribeKeyPairsRequest`,TN=`DescribeKeyPairsResult`,EN=`DescribeKeyPairs`,DN=`DeviceName`,ON=`DefaultNetworkCardIndex`,kN=`DestinationOutpostArn`,AN=`DhcpOptionsId`,jN=`DeleteOnTermination`,MN=`DeletePlacementGroup`,NN=`DeletePlacementGroupRequest`,PN=`DescribePlacementGroupsRequest`,FN=`DescribePlacementGroupsResult`,IN=`DescribePlacementGroups`,LN=`DestinationPrefixListId`,RN=`DeregistrationProtection`,zN=`DryRun`,BN=`DescribeRegionsRequest`,VN=`DescribeRegionsResult`,HN=`DescribeRouteTablesRequest`,UN=`DescribeRouteTablesResult`,WN=`DescribeRouteTables`,GN=`DestinationRegion`,KN=`DescribeRegions`,qN=`DeleteSecurityGroup`,JN=`DeleteSecurityGroupRequest`,YN=`DeleteSecurityGroupResult`,XN=`DescribeSecurityGroupsRequest`,ZN=`DescribeSecurityGroupsResult`,QN=`DescribeSecurityGroups`,$N=`DeleteSnapshotRequest`,eP=`DeleteSubnetRequest`,tP=`DescribeSnapshotsRequest`,nP=`DescribeSnapshotsResult`,rP=`DescribeSubnetsRequest`,iP=`DescribeSubnetsResult`,aP=`DeleteSnapshot`,oP=`DeleteSubnet`,sP=`DescribeSnapshots`,cP=`DescribeSubnets`,lP=`DefaultTcpEstablishedTimeout`,uP=`DefaultThreadsPerCore`,dP=`DeprecationTime`,fP=`DefaultUdpStreamTimeout`,pP=`DefaultUdpTimeout`,mP=`DefaultVCpus`,hP=`DeleteVolumeRequest`,gP=`DeleteVpcRequest`,_P=`DescribeVolumesRequest`,vP=`DescribeVolumesResult`,yP=`DescribeVpcsRequest`,bP=`DescribeVpcsResult`,xP=`DetachVolumeRequest`,SP=`DeleteVolume`,CP=`DeleteVpc`,wP=`DescribeVolumes`,TP=`DescribeVpcs`,EP=`DetachVolume`,DP=`Description`,OP=`Device`,kP=`Disks`,AP=`EbsBlockDevice`,jP=`ExecutableByStringList`,MP=`ExecutableBy`,NP=`EbsCardIndex`,PP=`EbsCardInfoList`,FP=`EbsCardInfo`,IP=`EbsCards`,LP=`EncryptionControl`,RP=`EnableDns64`,zP=`ElasticFileSystem`,BP=`ElasticFileSystemExclusion`,VP=`ElasticGpuAssociation`,HP=`ElasticGpuAssociationId`,UP=`ElasticGpuAssociationList`,WP=`ElasticGpuAssociationState`,GP=`ElasticGpuAssociationTime`,KP=`ElasticGpuAssociations`,qP=`ElasticGpuId`,JP=`ElasticGpuSpecification`,YP=`ElasticGpuSpecifications`,XP=`ElasticInferenceAccelerator`,ZP=`ElasticInferenceAcceleratorAssociation`,QP=`ElasticInferenceAcceleratorAssociationId`,$P=`ElasticInferenceAcceleratorAssociationList`,eF=`ElasticInferenceAcceleratorAssociationState`,tF=`ElasticInferenceAcceleratorAssociationTime`,nF=`ElasticInferenceAcceleratorArn`,rF=`ElasticInferenceAcceleratorAssociations`,iF=`ElasticInferenceAccelerators`,aF=`EbsInstanceBlockDevice`,oF=`EbsInstanceBlockDeviceSpecification`,sF=`EncryptionInTransitSupported`,cF=`EbsInfo`,lF=`EfaInfo`,uF=`EnableLniAtDeviceIndex`,dF=`EbsOptimized`,fF=`EbsOptimizedInfo`,pF=`EgressOnlyInternetGateway`,mF=`EgressOnlyInternetGatewayExclusion`,hF=`EgressOnlyInternetGatewayId`,gF=`EnclaveOptionsRequest`,_F=`EbsOptimizedSupport`,vF=`EnclaveOptions`,yF=`EnablePrimaryIpv6`,bF=`EnaQueueCount`,xF=`EnableResourceNameDnsAAAARecord`,SF=`EnableResourceNameDnsARecord`,CF=`EnaSrdEnabled`,wF=`EnaSrdSpecification`,TF=`EnaSrdSpecificationRequest`,EF=`EnaSrdSupported`,DF=`EnaSrdUdpEnabled`,OF=`EnaSrdUdpSpecification`,kF=`EnaSrdUdpSpecificationRequest`,AF=`EfaSupported`,jF=`EncryptionSupport`,MF=`EnaSupport`,NF=`EndTime`,PF=`ExecutableUsers`,FF=`Ebs`,IF=`Enabled`,LF=`Encrypted`,RF=`Endpoint`,zF=`Force`,BF=`FpgaDeviceInfo`,VF=`FpgaDeviceInfoList`,HF=`FpgaDeviceMemoryInfo`,UF=`FlexibleEnaQueuesSupport`,WF=`FpgaInfo`,GF=`FilterList`,KF=`FromPort`,qF=`FastRestored`,JF=`FullSnapshotSizeInBytes`,YF=`FreeTierEligible`,XF=`Filters`,ZF=`Filter`,QF=`Fpgas`,$F=`Groups`,eI=`GroupArn`,tI=`GetConsoleOutput`,nI=`GetConsoleOutputRequest`,rI=`GetConsoleOutputResult`,iI=`GroupDescription`,aI=`GpuDeviceInfo`,oI=`GpuDeviceInfoList`,sI=`GpuDeviceMemoryInfo`,cI=`GatewayId`,lI=`GroupIdentifierList`,uI=`GroupIdStringList`,dI=`GpuInfo`,fI=`GroupId`,pI=`GroupIds`,mI=`GroupIdentifier`,hI=`GroupLongName`,gI=`GroupName`,_I=`GroupNameStringList`,vI=`GroupNames`,yI=`GroupOwnerId`,bI=`GpuPartitionSize`,xI=`Geography`,SI=`Gpus`,CI=`HiddenByDefault`,wI=`HttpEndpoint`,TI=`HostId`,EI=`HibernationOptions`,DI=`HibernationOptionsRequest`,OI=`HttpProtocolIpv6`,kI=`HttpPutResponseHopLimit`,AI=`HostResourceGroupArn`,jI=`HibernationSupported`,MI=`HttpTokens`,NI=`HostnameType`,PI=`Hibernate`,FI=`Hypervisor`,II=`Id`,LI=`Ipv6Addresses`,RI=`Ipv6AddressAttribute`,zI=`Ipv6AddressCount`,BI=`InstanceAttachmentEnaSrdSpecification`,VI=`InstanceAttachmentEnaSrdUdpSpecification`,HI=`InferenceAcceleratorInfo`,UI=`Ipv4AddressesPerInterface`,WI=`Ipv6AddressesPerInterface`,GI=`Ipv4AddressesPerSecondaryInterface`,KI=`ImageAllowed`,qI=`IpAddress`,JI=`Ipv6Address`,YI=`InstanceBlockDeviceMapping`,XI=`InstanceBlockDeviceMappingList`,ZI=`InstanceBlockDeviceMappingSpecification`,QI=`InstanceBlockDeviceMappingSpecificationList`,$I=`Ipv6CidrBlock`,eL=`Ipv6CidrBlockAssociationSet`,tL=`Ipv6CidrBlockNetworkBorderGroup`,nL=`Ipv6CidrBlockState`,rL=`IncludeDeprecated`,iL=`InferenceDeviceInfo`,aL=`InferenceDeviceInfoList`,oL=`InferenceDeviceMemoryInfo`,sL=`IncludeDisabled`,cL=`IsDefault`,lL=`IsEgress`,uL=`InternetGateway`,dL=`InternetGatewayAttachment`,fL=`InternetGatewayAttachmentList`,pL=`InternetGatewayBlockMode`,mL=`InternetGatewayExclusion`,hL=`InternetGatewayId`,gL=`InternetGatewayIdList`,_L=`InternetGatewayIds`,vL=`InternetGatewayList`,yL=`InternetGateways`,bL=`InstanceId`,xL=`InstanceIpv6Address`,SL=`InstanceIpv6AddressList`,CL=`InstanceInterruptionBehavior`,wL=`IamInstanceProfile`,TL=`Ipv6IpamPoolId`,EL=`Ipv4IpamPoolId`,DL=`InstanceIpv4PrefixList`,OL=`InstanceIpv6PrefixList`,kL=`IamInstanceProfileSpecification`,AL=`InstanceIpv4Prefix`,jL=`InstanceIpv6Prefix`,ML=`InstanceInitiatedShutdownBehavior`,NL=`ImageIdStringList`,PL=`InstanceIdStringList`,FL=`ImageId`,IL=`ImageIds`,LL=`InstanceIds`,RL=`ImportKeyPair`,zL=`ImportKeyPairRequest`,BL=`ImportKeyPairResult`,VL=`ImageLocation`,HL=`ImageList`,UL=`InstanceLifecycle`,WL=`InstanceList`,GL=`InstanceMaintenanceOptions`,KL=`InstanceMaintenanceOptionsRequest`,qL=`InstanceMarketOptionsRequest`,JL=`InstanceMetadataOptionsRequest`,YL=`InstanceMetadataOptionsResponse`,XL=`InstanceMarketOptions`,ZL=`IncludeManagedResources`,QL=`InstanceMetadataTags`,$L=`Ipv6Native`,eR=`InstanceNetworkInterface`,tR=`InstanceNetworkInterfaceAssociation`,nR=`InstanceNetworkInterfaceAttachment`,rR=`InstanceNetworkInterfaceList`,iR=`InstanceNetworkInterfaceSpecification`,aR=`InstanceNetworkInterfaceSpecificationList`,oR=`Ipv6NetmaskLength`,sR=`Ipv4NetmaskLength`,cR=`InstanceNetworkPerformanceOptions`,lR=`InstanceNetworkPerformanceOptionsRequest`,uR=`ImageOwnerAlias`,dR=`IpOwnerId`,fR=`InstanceOwnerId`,pR=`InstanceOwningService`,mR=`Ipv6PrefixCount`,hR=`Ipv4PrefixCount`,gR=`IpPermissionsEgress`,_R=`InstancePrivateIpAddress`,vR=`InstancePrivateIpAddressList`,yR=`IsPrimaryIpv6`,bR=`IncludePublicKey`,xR=`IpPermissionList`,SR=`Ipv4PrefixList`,CR=`Ipv6PrefixList`,wR=`Ipv4PrefixSpecificationRequest`,TR=`Ipv6PrefixSpecificationRequest`,ER=`Ipv6Prefixes`,DR=`IpPermissions`,OR=`IpPermission`,kR=`IpProtocol`,AR=`Ipv6Prefix`,jR=`Ipv6Pool`,MR=`Ipv4Prefixes`,NR=`Ipv4Prefix`,PR=`IpRangeList`,FR=`Ipv6RangeList`,IR=`IpRanges`,LR=`IpRange`,RR=`Ipv6Ranges`,zR=`Ipv6Range`,BR=`InstanceStateChange`,VR=`InstanceStateChangeList`,HR=`InstanceSecondaryInterfaceAttachment`,UR=`InstanceSecondaryInterfaceList`,WR=`InstanceSecondaryInterfacePrivateIpAddress`,GR=`InstanceSecondaryInterfacePrivateIpAddressList`,KR=`InstanceSecondaryInterfacePrivateIpAddressListRequest`,qR=`InstanceSecondaryInterfacePrivateIpAddressRequest`,JR=`InstanceSecondaryInterfaceSpecificationListRequest`,YR=`InstanceSecondaryInterfaceSpecificationRequest`,XR=`InstanceSecondaryInterface`,ZR=`InstanceStorageInfo`,QR=`InstanceStorageSupported`,$R=`ImdsSupport`,ez=`InstanceState`,tz=`IpSource`,nz=`Ipv6Supported`,rz=`InstanceType`,iz=`InstanceTypeInfoList`,az=`InstanceTypeInfo`,oz=`ImageType`,sz=`InstanceTenancy`,cz=`InstanceTypes`,lz=`InterfaceType`,uz=`IncludeUnsupportedInRegion`,dz=`Images`,fz=`Image`,pz=`Instance`,mz=`Instances`,hz=`Iops`,gz=`Key`,_z=`KeyFormat`,vz=`KeyFingerprint`,yz=`KernelId`,bz=`KmsKeyId`,xz=`KeyMaterial`,Sz=`KeyName`,Cz=`KeyNameStringList`,wz=`KeyNames`,Tz=`KeyPairs`,Ez=`KeyPairId`,Dz=`KeyPairIdStringList`,Oz=`KeyPairIds`,kz=`KeyPairInfo`,Az=`KeyPairList`,jz=`KeyPair`,Mz=`KeyType`,Nz=`Kernel`,Pz=`LicenseConfigurationArn`,Fz=`LicenseConfigurationRequest`,Iz=`LicenseConfiguration`,Lz=`LambdaExclusion`,Rz=`LogicalGpuCount`,zz=`LocalGatewayId`,Bz=`LinkedGroupId`,Vz=`LicenseList`,Hz=`LastLaunchedTime`,Uz=`LicenseSpecifications`,Wz=`LicenseSpecificationListRequest`,Gz=`LicenseSpecification`,Kz=`LaunchTemplate`,qz=`LaunchTemplateId`,Jz=`LaunchTemplateName`,Yz=`LaunchTemplateSpecification`,Xz=`LaunchTime`,Zz=`Latest`,Qz=`Lambda`,$z=`Licenses`,eB=`Location`,tB=`MultiAttachEnabled`,nB=`MediaAcceleratorInfo`,rB=`MacAddress`,iB=`MaximumBandwidthInMbps`,aB=`MapCustomerOwnedIpOnLaunch`,oB=`MaxCount`,sB=`MinCount`,cB=`MediaDeviceInfo`,lB=`MediaDeviceInfoList`,uB=`MediaDeviceMemoryInfo`,dB=`MaximumEbsAttachments`,fB=`MaximumEbsCards`,pB=`MaximumEfaInterfaces`,mB=`MaximumEnaQueueCount`,hB=`MaximumEnaQueueCountPerInterface`,gB=`MaximumIops`,_B=`ModifyInstanceAttributeRequest`,vB=`ModifyInstanceAttributeValue`,yB=`ModifyInstanceAttribute`,bB=`MemoryInfo`,xB=`MaximumNetworkCards`,SB=`MaximumNetworkInterfaces`,CB=`MetadataOptions`,wB=`MaintenanceOptions`,TB=`MapPublicIpOnLaunch`,EB=`MaxPrice`,DB=`MaxResults`,OB=`MaximumSecondaryNetworkInterfaces`,kB=`ModificationState`,AB=`MarketType`,jB=`MaximumThroughputInMBps`,MB=`ModifyVolumeRequest`,NB=`ModifyVolumeResult`,PB=`ModifyVolume`,FB=`Main`,IB=`Manufacturer`,LB=`Managed`,RB=`Message`,zB=`Messages`,BB=`Mode`,VB=`Monitoring`,HB=`Name`,UB=`NetworkBorderGroup`,WB=`NetworkCards`,GB=`NetworkCardIndex`,KB=`NetworkCardInfoList`,qB=`NetworkCardInfo`,JB=`NoDevice`,YB=`NeuronDeviceCoreInfo`,XB=`NeuronDeviceInfo`,ZB=`NeuronDeviceInfoList`,QB=`NeuronDeviceMemoryInfo`,$B=`NeuronDevices`,eV=`NitroEnclavesSupport`,tV=`NatGateway`,nV=`NatGatewayExclusion`,rV=`NatGatewayId`,iV=`NetworkInterfaceId`,aV=`NetworkInterfaces`,oV=`NetworkInfo`,sV=`NeuronInfo`,cV=`NetworkPerformanceOptions`,lV=`NetworkPerformance`,uV=`NoReboot`,dV=`NvmeSupport`,fV=`NitroTpmInfo`,pV=`NitroTpmSupport`,mV=`NitroTpmSupportedVersionsList`,hV=`NextToken`,gV=`NestedVirtualization`,_V=`Origin`,vV=`OutpostArn`,yV=`OwnerAlias`,bV=`OwnerId`,xV=`OptInStatus`,SV=`OriginalIops`,CV=`OwnerIds`,wV=`OriginalMultiAttachEnabled`,TV=`OdbNetworkArn`,EV=`OperatorRequest`,DV=`OperatorResponse`,OV=`OwnerStringList`,kV=`OriginalSize`,AV=`OriginalThroughput`,jV=`OriginalVolumeType`,MV=`Operator`,NV=`Output`,PV=`Owners`,FV=`Owner`,IV=`Principal`,LV=`PeakBandwidthInGbps`,RV=`ProductCodeId`,zV=`ProductCodeList`,BV=`ProductCodeType`,VV=`PartitionCount`,HV=`ProductCode`,UV=`ProductCodes`,WV=`PrivateDnsName`,GV=`PrivateDnsNameOptions`,KV=`PrivateDnsNameOptionsOnLaunch`,qV=`PrivateDnsNameOptionsRequest`,JV=`PrivateDnsNameOptionsResponse`,YV=`PublicDnsName`,XV=`PlatformDetails`,ZV=`PlacementGroup`,QV=`PlacementGroupInfo`,$V=`PlacementGroupIdStringList`,eH=`PlacementGroupList`,tH=`PlacementGroupStrategyList`,nH=`PlacementGroups`,rH=`PublicIp`,iH=`PrivateIpAddressCount`,aH=`PrivateIpAddressSpecification`,oH=`PrivateIpAddressSpecificationList`,sH=`PrivateIpAddress`,cH=`PrivateIpAddresses`,lH=`PublicIpAddress`,uH=`PublicIpv4Pool`,dH=`PrimaryIpv6`,fH=`ProcessorInfo`,pH=`PublicKey`,mH=`PublicKeyMaterial`,hH=`PrefixListId`,gH=`PrefixListIdList`,_H=`PrefixListIds`,vH=`PartitionNumber`,yH=`PeeringStatus`,bH=`PhcSupport`,xH=`PreviousState`,SH=`PresignedUrl`,CH=`PropagatingVgw`,wH=`PropagatingVgwList`,TH=`PropagatingVgws`,EH=`ParentZoneId`,DH=`ParentZoneName`,OH=`Platform`,kH=`Placement`,AH=`Primary`,jH=`Progress`,MH=`Public`,NH=`Return`,PH=`RestorableByUserIds`,FH=`RestorableBy`,IH=`RootDeviceName`,LH=`RootDeviceType`,RH=`RootDeviceTypeList`,zH=`RestoreExpiryTime`,BH=`ResourceExclusions`,VH=`RegionGeography`,HH=`ReferencedGroupId`,UH=`ReferencedGroupInfo`,WH=`RegionGeographyList`,GH=`RunInstancesMonitoringEnabled`,KH=`RebootInstancesRequest`,qH=`RunInstancesRequest`,JH=`RunInstancesUserData`,YH=`RamdiskId`,XH=`ReservationId`,ZH=`RebootInstances`,QH=`RequesterId`,$H=`RunInstances`,eU=`RegionList`,tU=`ReservationList`,nU=`RouteList`,rU=`RebootMigrationSupport`,iU=`RebootMigration`,aU=`RegionName`,oU=`RegionNameStringList`,sU=`RegionNames`,cU=`ReferencedSecurityGroup`,lU=`RevokeSecurityGroupEgress`,uU=`RevokeSecurityGroupEgressRequest`,dU=`RevokeSecurityGroupEgressResult`,fU=`RevokeSecurityGroupIngressRequest`,pU=`RevokeSecurityGroupIngressResult`,mU=`RevokeSecurityGroupIngress`,hU=`RevokedSecurityGroupRule`,gU=`RevokedSecurityGroupRuleList`,_U=`RevokedSecurityGroupRules`,vU=`RouteTableAssociation`,yU=`RouteTableAssociationId`,bU=`RouteTableAssociationList`,xU=`RouteTableAssociationState`,SU=`RouteTableId`,CU=`RouteTableIdStringList`,wU=`RouteTableIds`,TU=`RouteTableList`,EU=`ResourceType`,DU=`RouteTable`,OU=`RouteTables`,kU=`Ramdisk`,AU=`Regions`,jU=`Region`,MU=`Reservations`,NU=`Reservation`,PU=`Route`,FU=`Routes`,IU=`SupportedAdditionalProcessorFeatureList`,LU=`SubnetArn`,RU=`SupportedArchitectures`,zU=`SupportedBootModes`,BU=`SubnetCidrBlockState`,VU=`SustainedClockSpeedInGhz`,HU=`SourceDestCheck`,UU=`SpreadDomain`,WU=`SupportedFeatures`,GU=`SubGeography`,KU=`SecurityGroupArn`,qU=`SecurityGroupId`,JU=`SecurityGroupIdStringList`,YU=`SecurityGroupIds`,XU=`SecurityGroupList`,ZU=`SecurityGroupRules`,QU=`SecurityGroupRuleArn`,$U=`SecurityGroupRuleIds`,eW=`SecurityGroupRuleIdList`,tW=`SecurityGroupRuleId`,nW=`SecurityGroupRuleList`,rW=`SecurityGroupRule`,iW=`SecurityGroupStringList`,aW=`SecurityGroups`,oW=`SecurityGroup`,sW=`SubnetIds`,cW=`SubnetIpv6CidrBlockAssociation`,lW=`SubnetIpv6CidrBlockAssociationSet`,uW=`SizeInGB`,dW=`SourceImageId`,fW=`SecondaryInterfaceId`,pW=`SourceInstanceId`,mW=`SizeInMiB`,hW=`SpotInstanceRequestId`,gW=`SourceImageRegion`,_W=`StartInstancesRequest`,vW=`StartInstancesResult`,yW=`StopInstancesRequest`,bW=`StopInstancesResult`,xW=`SupportedInRegion`,SW=`SnapshotIdStringList`,CW=`SubnetIdStringList`,wW=`SpotInstanceType`,TW=`SecondaryInterfaces`,EW=`SecondaryInterface`,DW=`SnapshotId`,OW=`SnapshotIds`,kW=`StartingInstances`,AW=`StartInstances`,jW=`StoppingInstances`,MW=`StopInstances`,NW=`SubnetId`,PW=`SnapshotLocation`,FW=`SnapshotList`,IW=`SpreadLevel`,LW=`SubnetList`,RW=`SpotMarketOptions`,zW=`StatusMessage`,BW=`StateMessage`,VW=`SecondaryNetworkId`,HW=`SriovNetSupport`,UW=`SecondaryNetworkSupported`,WW=`SpotOptions`,GW=`SkipOsShutdown`,KW=`SecondaryPrivateIpAddressCount`,qW=`SupportedRootDeviceTypes`,JW=`SourceRegion`,YW=`StateReason`,XW=`SourceSecurityGroupName`,ZW=`SourceSecurityGroupOwnerId`,QW=`SourceSnapshotId`,$W=`SecondarySubnetId`,eG=`SupportedStrategies`,tG=`StartTime`,nG=`StateTransitionReason`,rG=`SseType`,iG=`StorageTier`,aG=`SupportedUsageClasses`,oG=`SensitiveUserData`,sG=`SourceVolumeId`,cG=`SupportedVirtualizationTypes`,lG=`SupportedVersions`,uG=`Size`,dG=`Snapshots`,fG=`Snapshot`,pG=`State`,mG=`Status`,hG=`Strategy`,gG=`Subnet`,_G=`Subnets`,vG=`Tags`,yG=`TcpEstablishedTimeout`,bG=`TotalFpgaMemoryInMiB`,xG=`TransitGatewayId`,SG=`TotalGpuMemoryInMiB`,CG=`TerminateInstances`,wG=`TotalInferenceMemoryInMiB`,TG=`TerminateInstancesRequest`,EG=`TerminateInstancesResult`,DG=`TargetIops`,OG=`TerminatingInstances`,kG=`TagList`,AG=`TargetMultiAttachEnabled`,jG=`TotalMediaMemoryInMiB`,MG=`TotalNeuronDeviceMemoryInMiB`,NG=`ToPort`,PG=`ThreadsPerCore`,FG=`ThreadsPerCoreList`,IG=`TagSpecifications`,LG=`TotalSizeInGB`,RG=`TagSpecificationList`,zG=`TagSpecification`,BG=`TargetSize`,VG=`TpmSupport`,HG=`TargetThroughput`,UG=`TransferType`,WG=`TargetVolumeType`,GG=`Tag`,KG=`Tenancy`,qG=`Throughput`,JG=`Timestamp`,YG=`Type`,XG=`UsageClassTypeList`,ZG=`UserData`,QG=`UserId`,$G=`UserIdGroupPairs`,eK=`UserIdGroupPairList`,tK=`UserIdGroupPair`,nK=`UnknownIpPermissions`,rK=`UsageOperation`,iK=`UsageOperationUpdateTime`,aK=`UdpStreamTimeout`,oK=`UdpTimeout`,sK=`Value`,cK=`VolumeAttachmentList`,lK=`VolumeAttachment`,uK=`VpcCidrBlockAssociation`,dK=`VpcCidrBlockAssociationSet`,fK=`VpcCidrBlockState`,pK=`VCpuInfo`,mK=`ValidCores`,hK=`VpcEncryptionControl`,gK=`VpcEncryptionControlConfiguration`,_K=`VpcEncryptionControlExclusion`,vK=`VpcEncryptionControlExclusions`,yK=`VpcEncryptionControlId`,bK=`VpcEndpointId`,xK=`VpcId`,SK=`VpcIpv6CidrBlockAssociation`,CK=`VpcIpv6CidrBlockAssociationSet`,wK=`VolumeInitializationRate`,TK=`VolumeIdStringList`,EK=`VpcIdStringList`,DK=`VolumeId`,OK=`VolumeIds`,kK=`VpcIds`,AK=`VpcLattice`,jK=`VpcLatticeExclusion`,MK=`VolumeList`,NK=`VpcList`,PK=`VolumeModification`,FK=`VirtualName`,IK=`VolumeOwnerId`,LK=`VpcPeeringConnectionId`,RK=`VpcPeeringExclusion`,zK=`VirtualPrivateGateway`,BK=`VirtualPrivateGatewayExclusion`,VK=`VpcPeering`,HK=`ValueStringList`,UK=`VolumeSize`,WK=`VolumeType`,GK=`VirtualizationTypeList`,KK=`ValidThreadsPerCore`,qK=`VirtualizationType`,JK=`ValidUntil`,YK=`Values`,XK=`Version`,ZK=`Volumes`,QK=`Volume`,$K=`Vpc`,eq=`Vpcs`,tq=`WorkloadsList`,nq=`Workloads`,rq=`ZoneId`,iq=`ZoneIdStringList`,aq=`ZoneIds`,oq=`ZoneName`,sq=`ZoneNameStringList`,cq=`ZoneNames`,lq=`ZoneType`,uq=`additionalFlexibleNetworkInterfaces`,dq=`availableIpAddressCount`,fq=`assignIpv6AddressOnCreation`,pq=`additionalInfo`,mq=`associationId`,hq=`attachmentId`,gq=`amiLaunchIndex`,_q=`attachmentLimitType`,vq=`associatePublicIpAddress`,yq=`amazonProvidedIpv6CidrBlock`,bq=`autoRecoverySupported`,xq=`associatedResource`,Sq=`autoRecovery`,Cq=`associationState`,wq=`amdSevSnp`,Tq=`associationSet`,Eq=`attachmentSet`,Dq=`attachTime`,Oq=`availabilityZone`,kq=`availabilityZoneId`,Aq=`availabilityZoneInfo`,jq=`accelerators`,Mq=`affinity`,Nq=`arn`,Pq=`architecture`,Fq=`association`,Iq=`attachment`,Lq=`attribute`,Rq=`baselineBandwidthInGbps`,zq=`baselineBandwidthInMbps`,Bq=`blockDeviceMapping`,Vq=`baselineIops`,Hq=`bootMode`,Uq=`bareMetal`,Wq=`blockPublicAccessStates`,Gq=`burstablePerformanceSupported`,Kq=`baselineThroughputInMBps`,qq=`bandwidthWeighting`,Jq=`bandwidthWeightings`,Yq=`cidrBlock`,Xq=`cidrBlockAssociationSet`,Zq=`capacityBlockId`,Qq=`cidrBlockState`,$q=`coreCount`,eJ=`completionDurationMinutes`,tJ=`creationDate`,nJ=`carrierGatewayId`,rJ=`currentGeneration`,iJ=`carrierIp`,aJ=`currentInstanceBootMode`,oJ=`cidrIp`,sJ=`cidrIpv6`,cJ=`cidrIpv4`,lJ=`coreInfo`,uJ=`coreNetworkArn`,dJ=`cpuOptions`,fJ=`customerOwnedIp`,pJ=`customerOwnedIpv4Pool`,mJ=`capacityReservationId`,hJ=`capacityReservationPreference`,gJ=`capacityReservationResourceGroupArn`,_J=`capacityReservationSpecification`,vJ=`capacityReservationTarget`,yJ=`currentState`,bJ=`clientToken`,xJ=`connectionTrackingConfiguration`,SJ=`completionTime`,CJ=`createTime`,wJ=`code`,TJ=`configured`,EJ=`count`,DJ=`disableApiTermination`,OJ=`destinationCidrBlock`,kJ=`defaultCores`,AJ=`dataEncryptionKeyId`,jJ=`defaultEnaQueueCountPerInterface`,MJ=`defaultForAz`,NJ=`dedicatedHostsSupported`,PJ=`deviceIndex`,FJ=`destinationIpv6CidrBlock`,IJ=`deviceName`,LJ=`defaultNetworkCardIndex`,RJ=`dnsName`,zJ=`dhcpOptionsId`,BJ=`deleteOnTermination`,VJ=`destinationPrefixListId`,HJ=`deregistrationProtection`,UJ=`dryRun`,WJ=`destinationRegion`,GJ=`defaultTcpEstablishedTimeout`,KJ=`defaultThreadsPerCore`,qJ=`deprecationTime`,JJ=`defaultUdpStreamTimeout`,YJ=`defaultUdpTimeout`,XJ=`defaultVCpus`,ZJ=`description`,QJ=`device`,$J=`disks`,eY=`ebsCardIndex`,tY=`ebsCardSet`,nY=`encryptionControl`,rY=`enableDns64`,iY=`elasticFileSystem`,aY=`elasticGpuAssociationId`,oY=`elasticGpuAssociationState`,sY=`elasticGpuAssociationSet`,cY=`elasticGpuAssociationTime`,lY=`elasticGpuId`,uY=`elasticInferenceAcceleratorArn`,dY=`elasticInferenceAcceleratorAssociationId`,fY=`elasticInferenceAcceleratorAssociationState`,pY=`elasticInferenceAcceleratorAssociationSet`,mY=`elasticInferenceAcceleratorAssociationTime`,hY=`encryptionInTransitSupported`,gY=`ebsInfo`,_Y=`efaInfo`,vY=`enableLniAtDeviceIndex`,yY=`ebsOptimized`,bY=`ebsOptimizedInfo`,xY=`egressOnlyInternetGateway`,SY=`egressOnlyInternetGatewayId`,CY=`ebsOptimizedSupport`,wY=`enclaveOptions`,TY=`enaQueueCount`,H=`ec2QueryName`,EY=`enableResourceNameDnsAAAARecord`,DY=`enableResourceNameDnsARecord`,OY=`enaSrdEnabled`,kY=`enaSrdSpecification`,AY=`enaSrdSupported`,jY=`enaSrdUdpEnabled`,MY=`enaSrdUdpSpecification`,NY=`efaSupported`,PY=`encryptionSupport`,FY=`enaSupport`,IY=`endTime`,LY=`ebs`,RY=`enabled`,zY=`encrypted`,BY=`flexibleEnaQueuesSupport`,VY=`fpgaInfo`,HY=`fromPort`,UY=`fastRestored`,WY=`fullSnapshotSizeInBytes`,GY=`freeTierEligible`,KY=`force`,qY=`fpgas`,JY=`groupArn`,YY=`groupDescription`,XY=`gatewayId`,ZY=`gpuInfo`,QY=`groupId`,$Y=`groupLongName`,eX=`groupName`,tX=`groupOwnerId`,nX=`gpuPartitionSize`,rX=`geographySet`,iX=`groupSet`,aX=`gpus`,oX=`groups`,sX=`hypervisor`,cX=`hiddenByDefault`,lX=`httpEndpoint`,uX=`hostId`,dX=`hibernationOptions`,fX=`httpProtocolIpv6`,pX=`httpPutResponseHopLimit`,mX=`hostResourceGroupArn`,hX=`hibernationSupported`,gX=`httpTokens`,_X=`hostnameType`,vX=`id`,yX=`ipv6AddressAttribute`,bX=`ipv6AddressCount`,xX=`inferenceAcceleratorInfo`,SX=`ipv4AddressesPerInterface`,CX=`ipv6AddressesPerInterface`,wX=`ipv4AddressesPerSecondaryInterface`,TX=`ipv6AddressesSet`,EX=`imageAllowed`,DX=`ipAddress`,OX=`ipv6Address`,kX=`ipv6CidrBlock`,AX=`ipv6CidrBlockAssociationSet`,jX=`ipv6CidrBlockState`,MX=`isDefault`,NX=`isEgress`,PX=`internetGateway`,FX=`internetGatewayBlockMode`,IX=`internetGatewayId`,LX=`internetGatewaySet`,RX=`instanceId`,zX=`iamInstanceProfile`,BX=`instanceInitiatedShutdownBehavior`,VX=`imageId`,HX=`imageLocation`,UX=`instanceLifecycle`,WX=`instanceMetadataTags`,GX=`ipv6Native`,KX=`imageOwnerAlias`,qX=`imageOwnerId`,JX=`instanceOwnerId`,YX=`ipOwnerId`,XX=`instanceOwningService`,ZX=`ipPermissionsEgress`,QX=`isPrimaryIpv6`,$X=`ipv4PrefixSet`,eZ=`ipv6PrefixSet`,tZ=`ipProtocol`,nZ=`ipPermissions`,rZ=`ipv4Prefix`,iZ=`ipv6Pool`,aZ=`ipv6Prefix`,oZ=`isPublic`,sZ=`ipRanges`,cZ=`ipv6Ranges`,lZ=`instanceStorageInfo`,uZ=`instanceStorageSupported`,dZ=`imagesSet`,fZ=`imageState`,pZ=`imdsSupport`,mZ=`instancesSet`,hZ=`instanceState`,gZ=`ipSource`,_Z=`ipv6Supported`,vZ=`instanceType`,yZ=`instanceTypeSet`,bZ=`idempotencyToken`,xZ=`imageType`,SZ=`instanceTenancy`,CZ=`interfaceType`,wZ=`iops`,U=`item`,TZ=`key`,EZ=`keyFingerprint`,DZ=`kernelId`,OZ=`kmsKeyId`,kZ=`keyMaterial`,AZ=`keyName`,jZ=`keyPairId`,MZ=`keySet`,NZ=`keyType`,PZ=`kernel`,FZ=`licenseConfigurationArn`,IZ=`logicalGpuCount`,LZ=`localGatewayId`,RZ=`linkedGroupId`,zZ=`lastLaunchedTime`,BZ=`licenseSet`,VZ=`launchTime`,HZ=`lambda`,UZ=`multiAttachEnabled`,WZ=`mediaAcceleratorInfo`,GZ=`macAddress`,KZ=`maximumBandwidthInMbps`,qZ=`mapCustomerOwnedIpOnLaunch`,JZ=`maximumEbsAttachments`,YZ=`maximumEbsCards`,XZ=`maximumEfaInterfaces`,ZZ=`maximumEnaQueueCount`,QZ=`maximumEnaQueueCountPerInterface`,$Z=`maximumIops`,eQ=`memoryInfo`,tQ=`maximumNetworkCards`,nQ=`maximumNetworkInterfaces`,rQ=`metadataOptions`,iQ=`maintenanceOptions`,aQ=`mapPublicIpOnLaunch`,oQ=`maxResults`,afe=`messageSet`,ofe=`maximumSecondaryNetworkInterfaces`,sfe=`modificationState`,sQ=`maximumThroughputInMBps`,cfe=`main`,cQ=`manufacturer`,lfe=`managed`,lQ=`message`,ufe=`monitoring`,dfe=`mode`,uQ=`name`,dQ=`networkBorderGroup`,ffe=`networkCards`,fQ=`networkCardIndex`,pQ=`noDevice`,pfe=`neuronDevices`,mfe=`nitroEnclavesSupport`,hfe=`natGateway`,mQ=`natGatewayId`,hQ=`networkInterfaceId`,gfe=`networkInterfaceSet`,_fe=`networkInterface`,vfe=`networkInfo`,yfe=`neuronInfo`,bfe=`networkPerformanceOptions`,gQ=`networkPerformance`,xfe=`noReboot`,_Q=`nvmeSupport`,Sfe=`nitroTpmInfo`,Cfe=`nitroTpmSupport`,vQ=`nextToken`,wfe=`nestedVirtualization`,Tfe=`origin`,yQ=`outpostArn`,Efe=`ownerAlias`,bQ=`ownerId`,xQ=`optInStatus`,Dfe=`originalIops`,Ofe=`originalMultiAttachEnabled`,kfe=`odbNetworkArn`,Afe=`originalSize`,jfe=`originalThroughput`,Mfe=`originalVolumeType`,SQ=`operator`,Nfe=`output`,Pfe=`principal`,Ffe=`peakBandwidthInGbps`,CQ=`productCodes`,Ife=`partitionCount`,Lfe=`productCode`,Rfe=`privateDnsNameOptions`,zfe=`privateDnsNameOptionsOnLaunch`,wQ=`privateDnsName`,Bfe=`publicDnsName`,TQ=`platformDetails`,Vfe=`placementGroup`,Hfe=`placementGroupInfo`,Ufe=`placementGroupSet`,Wfe=`publicIp`,EQ=`privateIpAddressesSet`,Gfe=`privateIpAddressSet`,DQ=`privateIpAddress`,Kfe=`publicIpv4Pool`,qfe=`processorInfo`,Jfe=`publicKey`,Yfe=`publicKeyMaterial`,OQ=`prefixListId`,Xfe=`prefixListIds`,Zfe=`partitionNumber`,kQ=`peeringStatus`,Qfe=`phcSupport`,$fe=`previousState`,epe=`presignedUrl`,tpe=`propagatingVgwSet`,npe=`parentZoneId`,rpe=`parentZoneName`,AQ=`platform`,ipe=`placement`,jQ=`primary`,MQ=`progress`,NQ=`return`,PQ=`rootDeviceName`,FQ=`rootDeviceType`,ape=`restoreExpiryTime`,ope=`regionEndpoint`,spe=`resourceExclusions`,cpe=`referencedGroupId`,lpe=`referencedGroupInfo`,upe=`reservationId`,IQ=`ramdiskId`,dpe=`regionInfo`,fpe=`requesterId`,ppe=`rebootMigrationSupport`,mpe=`rebootMigration`,LQ=`regionName`,RQ=`revokedSecurityGroupRuleSet`,hpe=`reservationSet`,gpe=`routeSet`,_pe=`routeTableAssociationId`,zQ=`routeTableId`,vpe=`routeTableSet`,ype=`resourceType`,bpe=`routeTable`,xpe=`ramdisk`,Spe=`reason`,BQ=`smithy.ts.sdk.synthetic.com.amazonaws.ec2`,Cpe=`supportedArchitectures`,wpe=`subnetArn`,Tpe=`supportedBootModes`,Epe=`sustainedClockSpeedInGhz`,VQ=`sourceDestCheck`,Dpe=`spreadDomain`,Ope=`supportedFeatures`,HQ=`securityGroupArn`,kpe=`securityGroupInfo`,Ape=`securityGroupRuleArn`,UQ=`securityGroupRuleId`,WQ=`securityGroupRuleSet`,jpe=`subGeographySet`,Mpe=`sizeInGB`,Npe=`sourceInstanceId`,Ppe=`secondaryInterfaceId`,Fpe=`sourceImageId`,GQ=`sizeInMiB`,Ipe=`sourceImageRegion`,Lpe=`spotInstanceRequestId`,Rpe=`supportedInRegion`,zpe=`secondaryInterfaceSet`,KQ=`snapshotId`,qQ=`subnetId`,Bpe=`spreadLevel`,JQ=`statusMessage`,YQ=`stateMessage`,Vpe=`secondaryNetworkId`,Hpe=`secondaryNetworkSupported`,XQ=`sriovNetSupport`,Upe=`secondaryPrivateIpAddressCount`,Wpe=`supportedRootDeviceTypes`,ZQ=`stateReason`,QQ=`sourceSecurityGroupName`,$Q=`sourceSecurityGroupOwnerId`,Gpe=`secondarySubnetId`,Kpe=`snapshotSet`,qpe=`subnetSet`,Jpe=`supportedStrategies`,e$=`startTime`,t$=`sseType`,Ype=`storageTier`,Xpe=`supportedUsageClasses`,Zpe=`sourceVolumeId`,Qpe=`supportedVirtualizationTypes`,$pe=`supportedVersions`,eme=`size`,n$=`state`,r$=`status`,i$=`strategy`,tme=`subnet`,nme=`tenancy`,rme=`tcpEstablishedTimeout`,ime=`totalFpgaMemoryInMiB`,ame=`transitGatewayId`,ome=`totalGpuMemoryInMiB`,sme=`totalInferenceMemoryInMiB`,cme=`targetIops`,lme=`targetMultiAttachEnabled`,ume=`totalMediaMemoryInMiB`,dme=`totalNeuronDeviceMemoryInMiB`,a$=`toPort`,fme=`threadsPerCore`,o$=`tagSet`,pme=`totalSizeInGB`,mme=`targetSize`,s$=`tpmSupport`,hme=`targetThroughput`,gme=`transferType`,_me=`targetVolumeType`,c$=`throughput`,vme=`timestamp`,l$=`type`,yme=`userData`,u$=`userId`,d$=`unknownIpPermissionSet`,f$=`usageOperation`,bme=`usageOperationUpdateTime`,xme=`udpStreamTimeout`,Sme=`udpTimeout`,p$=`value`,Cme=`vCpuInfo`,wme=`validCores`,Tme=`vpcEncryptionControlId`,m$=`vpcId`,Eme=`volumeInitializationRate`,h$=`volumeId`,Dme=`vpcLattice`,Ome=`volumeModification`,g$=`virtualName`,kme=`volumeOwnerId`,_$=`vpcPeeringConnectionId`,Ame=`virtualPrivateGateway`,jme=`vpcPeering`,Mme=`volumeSet`,v$=`volumeSize`,Nme=`vpcSet`,y$=`volumeType`,Pme=`validThreadsPerCore`,b$=`virtualizationType`,Fme=`version`,Ime=`vpc`,Lme=`workloadSet`,W=`xmlName`,Rme=`zoneId`,zme=`zoneName`,Bme=`zoneState`,Vme=`zoneType`,G=`com.amazonaws.ec2`,x$=OO.for(BQ),Hme=[-3,BQ,`EC2ServiceException`,0,[],[]];x$.registerError(Hme,pde);var Ume=[x$],Wme=[0,G,bM,8,0],Gme=[0,G,vB,8,0],Kme=[0,G,JH,8,0],qme=[0,G,oG,8,0],Jme=[3,G,Dde,0,[SU,cI,uH,zN,NW],[[0,{[H]:`RouteTableId`,[W]:zQ}],0,0,[2,{[H]:`DryRun`,[W]:UJ}],[0,{[H]:`SubnetId`,[W]:qQ}]],1],Yme=[3,G,Ode,0,[QA,nj],[[0,{[H]:`AssociationId`,[W]:mq}],[()=>F$,{[H]:`AssociationState`,[W]:Cq}]]],Xme=[3,G,xde,0,[hL,xK,zN],[[0,{[H]:`InternetGatewayId`,[W]:IX}],[0,{[H]:`VpcId`,[W]:m$}],[2,{[H]:`DryRun`,[W]:UJ}]],2],Zme=[3,G,Rde,0,[OP,bL,DK,NP,zN],[0,0,0,1,[2,{[H]:`DryRun`,[W]:UJ}]],3],S$=[3,G,hde,0,[sK],[[2,{[H]:`Value`,[W]:p$}]]],C$=[3,G,zde,0,[sK],[[0,{[H]:`Value`,[W]:p$}]]],Qme=[3,G,Mde,0,[fI,IG,zN,XW,ZW,kR,KF,NG,Hj,DR],[[0,{[H]:`GroupId`,[W]:QY}],[()=>s1,{[W]:zG}],[2,{[H]:`DryRun`,[W]:UJ}],[0,{[H]:`SourceSecurityGroupName`,[W]:QQ}],[0,{[H]:`SourceSecurityGroupOwnerId`,[W]:$Q}],[0,{[H]:`IpProtocol`,[W]:tZ}],[1,{[H]:`FromPort`,[W]:HY}],[1,{[H]:`ToPort`,[W]:a$}],[0,{[H]:`CidrIp`,[W]:oJ}],[()=>Q$,{[H]:`IpPermissions`,[W]:nZ}]],1],$me=[3,G,Nde,0,[NH,ZU],[[2,{[H]:`Return`,[W]:NQ}],[()=>a1,{[H]:`SecurityGroupRuleSet`,[W]:WQ}]]],ehe=[3,G,Pde,0,[Hj,KF,fI,gI,DR,kR,XW,ZW,NG,IG,zN],[0,1,0,0,[()=>Q$,0],0,0,0,1,[()=>s1,{[W]:zG}],[2,{[H]:`DryRun`,[W]:UJ}]]],the=[3,G,Fde,0,[NH,ZU],[[2,{[H]:`Return`,[W]:NQ}],[()=>a1,{[H]:`SecurityGroupRuleSet`,[W]:WQ}]]],nhe=[3,G,aj,0,[xV,zB,aU,oq,rq,gI,UB,lq,DH,EH,hI,xI,GU,pG],[[0,{[H]:`OptInStatus`,[W]:xQ}],[()=>Yve,{[H]:`MessageSet`,[W]:afe}],[0,{[H]:`RegionName`,[W]:LQ}],[0,{[H]:`ZoneName`,[W]:zme}],[0,{[H]:`ZoneId`,[W]:Rme}],[0,{[H]:`GroupName`,[W]:eX}],[0,{[H]:`NetworkBorderGroup`,[W]:dQ}],[0,{[H]:`ZoneType`,[W]:Vme}],[0,{[H]:`ParentZoneName`,[W]:rpe}],[0,{[H]:`ParentZoneId`,[W]:npe}],[0,{[H]:`GroupLongName`,[W]:$Y}],[()=>qve,{[H]:`GeographySet`,[W]:rX}],[()=>Xve,{[H]:`SubGeographySet`,[W]:jpe}],[0,{[H]:`ZoneState`,[W]:Bme}]]],rhe=[3,G,Vde,0,[HB],[[0,{[H]:`Name`,[W]:uQ}]]],ihe=[3,G,Wde,0,[RB],[[0,{[H]:`Message`,[W]:lQ}]]],ahe=[3,G,Kde,0,[HB],[[0,{[H]:`Name`,[W]:uQ}]]],ohe=[3,G,Qde,0,[sK],[[21,{[H]:`Value`,[W]:p$}]]],w$=[3,G,mj,0,[FF,JB,DN,FK],[[()=>Cge,{[H]:`Ebs`,[W]:LY}],[0,{[H]:`NoDevice`,[W]:pQ}],[0,{[H]:`DeviceName`,[W]:IJ}],[0,{[H]:`VirtualName`,[W]:g$}]]],T$=[3,G,vj,0,[pL],[[0,{[H]:`InternetGatewayBlockMode`,[W]:FX}]]],she=[3,G,lM,0,[iM,uM],[0,()=>lhe]],che=[3,G,cM,0,[iM,uM],[[0,{[H]:`CapacityReservationPreference`,[W]:hJ}],[()=>uhe,{[H]:`CapacityReservationTarget`,[W]:vJ}]]],lhe=[3,G,uM,0,[rM,oM],[0,0]],uhe=[3,G,dM,0,[rM,oM],[[0,{[H]:`CapacityReservationId`,[W]:mJ}],[0,{[H]:`CapacityReservationResourceGroupArn`,[W]:gJ}]]],dhe=[3,G,PM,0,[yG,aK,oK],[1,1,1]],fhe=[3,G,FM,0,[yG,aK,oK],[[1,{[H]:`TcpEstablishedTimeout`,[W]:rme}],[1,{[H]:`UdpStreamTimeout`,[W]:xme}],[1,{[H]:`UdpTimeout`,[W]:Sme}]]],phe=[3,G,yM,0,[JW,QW,DP,kN,GN,LF,bz,SH,IG,jj,JM,zN],[0,0,0,0,[0,{[H]:`DestinationRegion`,[W]:WJ}],[2,{[H]:`Encrypted`,[W]:zY}],[0,{[H]:`KmsKeyId`,[W]:OZ}],[()=>Wme,{[H]:`PresignedUrl`,[W]:epe}],[()=>s1,{[W]:zG}],1,0,[2,{[H]:`DryRun`,[W]:UJ}]],2],mhe=[3,G,xM,0,[vG,DW],[[()=>o1,{[H]:`TagSet`,[W]:o$}],[0,{[H]:`SnapshotId`,[W]:KQ}]]],hhe=[3,G,Xj,0,[kj,PG,rj,gV],[[1,{[H]:`CoreCount`,[W]:$q}],[1,{[H]:`ThreadsPerCore`,[W]:fme}],[0,{[H]:`AmdSevSnp`,[W]:wq}],[0,{[H]:`NestedVirtualization`,[W]:wfe}]]],ghe=[3,G,$j,0,[kj,PG,rj,gV],[1,1,0,0]],_he=[3,G,Bj,0,[bL,HB,IG,PW,zN,DP,uV,hj],[[0,{[H]:`InstanceId`,[W]:RX}],[0,{[H]:`Name`,[W]:uQ}],[()=>s1,{[W]:zG}],0,[2,{[H]:`DryRun`,[W]:UJ}],[0,{[H]:`Description`,[W]:ZJ}],[2,{[H]:`NoReboot`,[W]:xfe}],[()=>G$,{[H]:`BlockDeviceMapping`,[W]:Bq}]],2],vhe=[3,G,Vj,0,[FL],[[0,{[H]:`ImageId`,[W]:VX}]]],yhe=[3,G,Rj,0,[IG,zN],[[()=>s1,{[W]:zG}],[2,{[H]:`DryRun`,[W]:UJ}]]],bhe=[3,G,zj,0,[uL],[[()=>O$,{[H]:`InternetGateway`,[W]:PX}]]],xhe=[3,G,Jj,0,[Sz,Mz,IG,_z,zN],[0,0,[()=>s1,{[W]:zG}],0,[2,{[H]:`DryRun`,[W]:UJ}]],1],She=[3,G,tM,0,[VV,IG,IW,Bz,MV,zN,gI,hG],[1,[()=>s1,{[W]:zG}],0,0,()=>k$,[2,{[H]:`DryRun`,[W]:UJ}],[0,{[H]:`GroupName`,[W]:eX}],[0,{[H]:`Strategy`,[W]:i$}]]],Che=[3,G,nM,0,[ZV],[[()=>M$,{[H]:`PlacementGroup`,[W]:Vfe}]]],whe=[3,G,aM,0,[SU,LN,bK,xG,zz,Nj,Yj,TV,zN,QM,cI,oN,hF,bL,iV,LK,rV],[[0,{[H]:`RouteTableId`,[W]:zQ}],0,0,0,0,0,0,0,[2,{[H]:`DryRun`,[W]:UJ}],[0,{[H]:`DestinationCidrBlock`,[W]:OJ}],[0,{[H]:`GatewayId`,[W]:XY}],[0,{[H]:`DestinationIpv6CidrBlock`,[W]:FJ}],[0,{[H]:`EgressOnlyInternetGatewayId`,[W]:SY}],[0,{[H]:`InstanceId`,[W]:RX}],[0,{[H]:`NetworkInterfaceId`,[W]:hQ}],[0,{[H]:`VpcPeeringConnectionId`,[W]:_$}],[0,{[H]:`NatGatewayId`,[W]:mQ}]],1],The=[3,G,sM,0,[NH],[[2,{[H]:`Return`,[W]:NQ}]]],Ehe=[3,G,fM,0,[xK,IG,jM,zN],[[0,{[H]:`VpcId`,[W]:m$}],[()=>s1,{[W]:zG}],[0,4],[2,{[H]:`DryRun`,[W]:UJ}]],1],Dhe=[3,G,pM,0,[DU,jM],[[()=>P$,{[H]:`RouteTable`,[W]:bpe}],[0,{[H]:`ClientToken`,[W]:bJ}]]],Ohe=[3,G,_M,0,[DP,gI,xK,IG,zN],[[0,{[W]:iI}],0,0,[()=>s1,{[W]:zG}],[2,{[H]:`DryRun`,[W]:UJ}]],2],khe=[3,G,vM,0,[fI,vG,KU],[[0,{[H]:`GroupId`,[W]:QY}],[()=>o1,{[H]:`TagSet`,[W]:o$}],[0,{[H]:`SecurityGroupArn`,[W]:HQ}]]],Ahe=[3,G,SM,0,[DK,DP,vV,IG,eB,zN],[0,0,0,[()=>s1,{[W]:zG}],0,[2,{[H]:`DryRun`,[W]:UJ}]],1],jhe=[3,G,CM,0,[xK,IG,aj,oj,wj,$I,vV,$L,EL,sR,TL,oR,zN],[0,[()=>s1,{[W]:zG}],0,0,0,0,0,2,0,1,0,1,[2,{[H]:`DryRun`,[W]:UJ}]],1],Mhe=[3,G,wM,0,[gG],[[()=>R$,{[H]:`Subnet`,[W]:tme}]]],Nhe=[3,G,RM,0,[aj,oj,LF,hz,bz,vV,uG,DW,WK,IG,tB,qG,jM,wK,MV,zN],[0,0,[2,{[H]:`Encrypted`,[W]:zY}],1,0,0,1,0,0,[()=>s1,{[W]:zG}],2,1,[0,4],1,()=>k$,[2,{[H]:`DryRun`,[W]:UJ}]]],Phe=[3,G,zM,0,[wj,jR,$I,EL,sR,TL,oR,tL,hK,IG,zN,sz,Tde],[0,0,0,0,1,0,1,0,()=>Uve,[()=>s1,{[W]:zG}],[2,{[H]:`DryRun`,[W]:UJ}],[0,{[H]:`InstanceTenancy`,[W]:SZ}],[2,{[H]:`AmazonProvidedIpv6CidrBlock`,[W]:yq}]]],Fhe=[3,G,BM,0,[$K],[[()=>V$,{[H]:`Vpc`,[W]:Ime}]]],Ihe=[3,G,TM,0,[Aj],[0],1],Lhe=[3,G,$M,0,[lP,pP,fP],[[1,{[H]:`DefaultTcpEstablishedTimeout`,[W]:GJ}],[1,{[H]:`DefaultUdpTimeout`,[W]:YJ}],[1,{[H]:`DefaultUdpStreamTimeout`,[W]:JJ}]]],Rhe=[3,G,SN,0,[Sz,Ez,zN],[0,0,[2,{[H]:`DryRun`,[W]:UJ}]]],zhe=[3,G,CN,0,[NH,Ez],[[2,{[H]:`Return`,[W]:NQ}],[0,{[H]:`KeyPairId`,[W]:jZ}]]],Bhe=[3,G,NN,0,[gI,zN],[[0,{[H]:`GroupName`,[W]:eX}],[2,{[H]:`DryRun`,[W]:UJ}]],1],Vhe=[3,G,JN,0,[fI,gI,zN],[0,0,[2,{[H]:`DryRun`,[W]:UJ}]]],Hhe=[3,G,YN,0,[NH,fI],[[2,{[H]:`Return`,[W]:NQ}],[0,{[H]:`GroupId`,[W]:QY}]]],Uhe=[3,G,$N,0,[DW,zN],[0,[2,{[H]:`DryRun`,[W]:UJ}]],1],Whe=[3,G,eP,0,[NW,zN],[0,[2,{[H]:`DryRun`,[W]:UJ}]],1],Ghe=[3,G,hP,0,[DK,zN],[0,[2,{[H]:`DryRun`,[W]:UJ}]],1],Khe=[3,G,gP,0,[xK,zN],[0,[2,{[H]:`DryRun`,[W]:UJ}]],1],qhe=[3,G,YM,0,[cq,aq,mde,zN,XF],[[()=>Tbe,{[W]:oq}],[()=>wbe,{[W]:rq}],2,[2,{[H]:`DryRun`,[W]:UJ}],[()=>K$,{[W]:ZF}]]],Jhe=[3,G,XM,0,[Jde],[[()=>Jve,{[H]:`AvailabilityZoneInfo`,[W]:Aq}]]],Yhe=[3,G,dN,0,[PF,IL,PV,rL,sL,DB,hV,zN,XF],[[()=>sye,{[W]:MP}],[()=>dye,{[W]:FL}],[()=>$$,{[W]:FV}],2,2,1,0,[2,{[H]:`DryRun`,[W]:UJ}],[()=>K$,{[W]:ZF}]]],Xhe=[3,G,fN,0,[hV,dz],[[0,{[H]:`NextToken`,[W]:vQ}],[()=>fye,{[H]:`ImagesSet`,[W]:dZ}]]],Zhe=[3,G,pN,0,[LL,ZL,zN,XF,hV,DB],[[()=>Y$,{[W]:bL}],2,[2,{[H]:`DryRun`,[W]:UJ}],[()=>K$,{[W]:ZF}],[0,{[H]:`NextToken`,[W]:vQ}],[1,{[H]:`MaxResults`,[W]:oQ}]]],Qhe=[3,G,mN,0,[hV,MU],[[0,{[H]:`NextToken`,[W]:vQ}],[()=>t1,{[H]:`ReservationSet`,[W]:hpe}]]],$he=[3,G,hN,0,[zN,cz,XF,DB,hV,uz],[2,[64,{[W]:rz}],[()=>K$,{[W]:ZF}],1,0,2]],ege=[3,G,gN,0,[cz,hV],[[()=>Eye,{[H]:`InstanceTypeSet`,[W]:yZ}],[0,{[H]:`NextToken`,[W]:vQ}]]],tge=[3,G,sN,0,[hV,DB,zN,_L,XF],[0,1,[2,{[H]:`DryRun`,[W]:UJ}],[()=>Oye,{[H]:`InternetGatewayId`,[W]:IX}],[()=>K$,{[W]:ZF}]]],nge=[3,G,cN,0,[yL,hV],[[()=>kye,{[H]:`InternetGatewaySet`,[W]:LX}],[0,{[H]:`NextToken`,[W]:vQ}]]],rge=[3,G,wN,0,[wz,Oz,bR,zN,XF],[[()=>Pye,{[W]:Sz}],[()=>Fye,{[W]:Ez}],2,[2,{[H]:`DryRun`,[W]:UJ}],[()=>K$,{[W]:ZF}]]],ige=[3,G,TN,0,[Tz],[[()=>Iye,{[H]:`KeySet`,[W]:MZ}]]],age=[3,G,PN,0,[pI,zN,vI,XF],[[()=>Uye,{[W]:fI}],[2,{[H]:`DryRun`,[W]:UJ}],[64,{[H]:`GroupName`,[W]:eX}],[()=>K$,{[W]:ZF}]]],oge=[3,G,FN,0,[nH],[[()=>Wye,{[H]:`PlacementGroupSet`,[W]:Ufe}]]],sge=[3,G,BN,0,[sU,Ade,zN,XF],[[()=>Zye,{[W]:aU}],2,[2,{[H]:`DryRun`,[W]:UJ}],[()=>K$,{[W]:ZF}]]],cge=[3,G,VN,0,[AU],[[()=>Xye,{[H]:`RegionInfo`,[W]:dpe}]]],lge=[3,G,HN,0,[hV,DB,zN,wU,XF],[0,1,[2,{[H]:`DryRun`,[W]:UJ}],[()=>tbe,{[W]:SU}],[()=>K$,{[W]:ZF}]]],uge=[3,G,UN,0,[OU,hV],[[()=>nbe,{[H]:`RouteTableSet`,[W]:vpe}],[0,{[H]:`NextToken`,[W]:vQ}]]],dge=[3,G,XN,0,[pI,vI,hV,DB,zN,XF],[[()=>J$,{[W]:fI}],[()=>uye,{[W]:gI}],0,1,[2,{[H]:`DryRun`,[W]:UJ}],[()=>K$,{[W]:ZF}]]],fge=[3,G,ZN,0,[hV,aW],[[0,{[H]:`NextToken`,[W]:vQ}],[()=>rbe,{[H]:`SecurityGroupInfo`,[W]:kpe}]]],pge=[3,G,tP,0,[DB,hV,CV,PH,OW,zN,XF],[1,0,[()=>$$,{[W]:FV}],[64,{[W]:FH}],[()=>abe,{[W]:DW}],[2,{[H]:`DryRun`,[W]:UJ}],[()=>K$,{[W]:ZF}]]],mge=[3,G,nP,0,[hV,dG],[[0,{[H]:`NextToken`,[W]:vQ}],[()=>obe,{[H]:`SnapshotSet`,[W]:Kpe}]]],hge=[3,G,rP,0,[XF,sW,hV,DB,zN],[[()=>K$,{[W]:ZF}],[()=>sbe,{[W]:NW}],0,1,[2,{[H]:`DryRun`,[W]:UJ}]]],gge=[3,G,iP,0,[hV,_G],[[0,{[H]:`NextToken`,[W]:vQ}],[()=>lbe,{[H]:`SubnetSet`,[W]:qpe}]]],_ge=[3,G,_P,0,[OK,ZL,zN,XF,hV,DB],[[()=>_be,{[W]:DK}],2,[2,{[H]:`DryRun`,[W]:UJ}],[()=>K$,{[W]:ZF}],[0,{[H]:`NextToken`,[W]:vQ}],[1,{[H]:`MaxResults`,[W]:oQ}]]],vge=[3,G,vP,0,[hV,ZK],[[0,{[H]:`NextToken`,[W]:vQ}],[()=>vbe,{[H]:`VolumeSet`,[W]:Mme}]]],yge=[3,G,yP,0,[XF,kK,hV,DB,zN],[[()=>K$,{[W]:ZF}],[()=>bbe,{[W]:xK}],0,1,[2,{[H]:`DryRun`,[W]:UJ}]]],bge=[3,G,bP,0,[hV,eq],[[0,{[H]:`NextToken`,[W]:vQ}],[()=>Sbe,{[H]:`VpcSet`,[W]:Nme}]]],xge=[3,G,xP,0,[DK,OP,zF,bL,zN],[0,0,2,0,[2,{[H]:`DryRun`,[W]:UJ}]],1],Sge=[3,G,bN,0,[uW,GM,YG],[[1,{[H]:`SizeInGB`,[W]:Mpe}],[1,{[H]:`Count`,[W]:EJ}],[0,{[H]:`Type`,[W]:l$}]]],Cge=[3,G,AP,0,[jN,hz,DW,UK,WK,bz,qG,vV,aj,LF,wK,oj,NP],[[2,{[H]:`DeleteOnTermination`,[W]:BJ}],[1,{[H]:`Iops`,[W]:wZ}],[0,{[H]:`SnapshotId`,[W]:KQ}],[1,{[H]:`VolumeSize`,[W]:v$}],[0,{[H]:`VolumeType`,[W]:y$}],[0,{[H]:`KmsKeyId`,[W]:OZ}],[1,{[H]:`Throughput`,[W]:c$}],[0,{[H]:`OutpostArn`,[W]:yQ}],[0,{[H]:`AvailabilityZone`,[W]:Oq}],[2,{[H]:`Encrypted`,[W]:zY}],1,0,1]],wge=[3,G,FP,0,[NP,pj,bj,gj,iB,jB,gB],[[1,{[H]:`EbsCardIndex`,[W]:eY}],[1,{[H]:`BaselineBandwidthInMbps`,[W]:zq}],[1,{[H]:`BaselineThroughputInMBps`,[W]:Kq}],[1,{[H]:`BaselineIops`,[W]:Vq}],[1,{[H]:`MaximumBandwidthInMbps`,[W]:KZ}],[1,{[H]:`MaximumThroughputInMBps`,[W]:sQ}],[1,{[H]:`MaximumIops`,[W]:$Z}]]],Tge=[3,G,cF,0,[_F,jF,fF,dV,dB,Cde,fB,IP],[[0,{[H]:`EbsOptimizedSupport`,[W]:CY}],[0,{[H]:`EncryptionSupport`,[W]:PY}],[()=>Oge,{[H]:`EbsOptimizedInfo`,[W]:bY}],[0,{[H]:`NvmeSupport`,[W]:_Q}],[1,{[H]:`MaximumEbsAttachments`,[W]:JZ}],[0,{[H]:`AttachmentLimitType`,[W]:_q}],[1,{[H]:`MaximumEbsCards`,[W]:YZ}],[()=>nye,{[H]:`EbsCardSet`,[W]:tY}]]],Ege=[3,G,aF,0,[ij,jN,mG,DK,ej,IK,MV,NP],[[4,{[H]:`AttachTime`,[W]:Dq}],[2,{[H]:`DeleteOnTermination`,[W]:BJ}],[0,{[H]:`Status`,[W]:r$}],[0,{[H]:`VolumeId`,[W]:h$}],[0,{[H]:`AssociatedResource`,[W]:xq}],[0,{[H]:`VolumeOwnerId`,[W]:kme}],[()=>A$,{[H]:`Operator`,[W]:SQ}],[1,{[H]:`EbsCardIndex`,[W]:eY}]]],Dge=[3,G,oF,0,[DK,jN],[[0,{[H]:`VolumeId`,[W]:h$}],[2,{[H]:`DeleteOnTermination`,[W]:BJ}]]],Oge=[3,G,fF,0,[pj,bj,gj,iB,jB,gB],[[1,{[H]:`BaselineBandwidthInMbps`,[W]:zq}],[1,{[H]:`BaselineThroughputInMBps`,[W]:Kq}],[1,{[H]:`BaselineIops`,[W]:Vq}],[1,{[H]:`MaximumBandwidthInMbps`,[W]:KZ}],[1,{[H]:`MaximumThroughputInMBps`,[W]:sQ}],[1,{[H]:`MaximumIops`,[W]:$Z}]]],kge=[3,G,lF,0,[pB],[[1,{[H]:`MaximumEfaInterfaces`,[W]:XZ}]]],Age=[3,G,VP,0,[qP,HP,WP,GP],[[0,{[H]:`ElasticGpuId`,[W]:lY}],[0,{[H]:`ElasticGpuAssociationId`,[W]:aY}],[0,{[H]:`ElasticGpuAssociationState`,[W]:oY}],[0,{[H]:`ElasticGpuAssociationTime`,[W]:cY}]]],jge=[3,G,JP,0,[YG],[0],1],Mge=[3,G,XP,0,[YG,GM],[0,1],1],Nge=[3,G,ZP,0,[nF,QP,eF,tF],[[0,{[H]:`ElasticInferenceAcceleratorArn`,[W]:uY}],[0,{[H]:`ElasticInferenceAcceleratorAssociationId`,[W]:dY}],[0,{[H]:`ElasticInferenceAcceleratorAssociationState`,[W]:fY}],[4,{[H]:`ElasticInferenceAcceleratorAssociationTime`,[W]:mY}]]],Pge=[3,G,TF,0,[CF,OF],[2,()=>Fge]],Fge=[3,G,kF,0,[DF],[2]],Ige=[3,G,vF,0,[IF],[[2,{[H]:`Enabled`,[W]:RY}]]],Lge=[3,G,gF,0,[IF],[2]],Rge=[3,G,ZF,0,[HB,YK],[0,[()=>mbe,{[W]:sK}]]],zge=[3,G,BF,0,[HB,IB,GM,bB],[[0,{[H]:`Name`,[W]:uQ}],[0,{[H]:`Manufacturer`,[W]:cQ}],[1,{[H]:`Count`,[W]:EJ}],[()=>Bge,{[H]:`MemoryInfo`,[W]:eQ}]]],Bge=[3,G,HF,0,[mW],[[1,{[H]:`SizeInMiB`,[W]:GQ}]]],Vge=[3,G,WF,0,[QF,bG],[[()=>cye,{[H]:`Fpgas`,[W]:qY}],[1,{[H]:`TotalFpgaMemoryInMiB`,[W]:ime}]]],Hge=[3,G,nI,0,[bL,Zz,zN],[0,2,[2,{[H]:`DryRun`,[W]:UJ}]],1],Uge=[3,G,rI,0,[bL,JG,NV],[[0,{[H]:`InstanceId`,[W]:RX}],[4,{[H]:`Timestamp`,[W]:vme}],[0,{[H]:`Output`,[W]:Nfe}]]],Wge=[3,G,aI,0,[HB,IB,GM,Rz,bI,nq,bB],[[0,{[H]:`Name`,[W]:uQ}],[0,{[H]:`Manufacturer`,[W]:cQ}],[1,{[H]:`Count`,[W]:EJ}],[1,{[H]:`LogicalGpuCount`,[W]:IZ}],[1,{[H]:`GpuPartitionSize`,[W]:nX}],[()=>Cbe,{[H]:`WorkloadSet`,[W]:Lme}],[()=>Gge,{[H]:`MemoryInfo`,[W]:eQ}]]],Gge=[3,G,sI,0,[mW],[[1,{[H]:`SizeInMiB`,[W]:GQ}]]],Kge=[3,G,dI,0,[SI,SG],[[()=>lye,{[H]:`Gpus`,[W]:aX}],[1,{[H]:`TotalGpuMemoryInMiB`,[W]:ome}]]],qge=[3,G,mI,0,[fI,gI],[[0,{[H]:`GroupId`,[W]:QY}],[0,{[H]:`GroupName`,[W]:eX}]]],Jge=[3,G,EI,0,[WM],[[2,{[H]:`Configured`,[W]:TJ}]]],Yge=[3,G,DI,0,[WM],[2]],Xge=[3,G,wL,0,[cj,II],[[0,{[H]:`Arn`,[W]:Nq}],[0,{[H]:`Id`,[W]:vX}]]],Zge=[3,G,kL,0,[cj,HB],[[0,{[H]:`Arn`,[W]:Nq}],[0,{[H]:`Name`,[W]:uQ}]]],Qge=[3,G,fz,0,[XV,rK,hj,DP,MF,FI,uR,HB,IH,LH,HW,YW,vG,qK,_j,VG,dP,$R,pW,RN,Hz,KI,dW,gW,YF,FL,VL,pG,bV,Mj,MH,UV,lj,oz,yz,YH,OH],[[0,{[H]:`PlatformDetails`,[W]:TQ}],[0,{[H]:`UsageOperation`,[W]:f$}],[()=>Qve,{[H]:`BlockDeviceMapping`,[W]:Bq}],[0,{[H]:`Description`,[W]:ZJ}],[2,{[H]:`EnaSupport`,[W]:FY}],[0,{[H]:`Hypervisor`,[W]:sX}],[0,{[H]:`ImageOwnerAlias`,[W]:KX}],[0,{[H]:`Name`,[W]:uQ}],[0,{[H]:`RootDeviceName`,[W]:PQ}],[0,{[H]:`RootDeviceType`,[W]:FQ}],[0,{[H]:`SriovNetSupport`,[W]:XQ}],[()=>L$,{[H]:`StateReason`,[W]:ZQ}],[()=>o1,{[H]:`TagSet`,[W]:o$}],[0,{[H]:`VirtualizationType`,[W]:b$}],[0,{[H]:`BootMode`,[W]:Hq}],[0,{[H]:`TpmSupport`,[W]:s$}],[0,{[H]:`DeprecationTime`,[W]:qJ}],[0,{[H]:`ImdsSupport`,[W]:pZ}],[0,{[H]:`SourceInstanceId`,[W]:Npe}],[0,{[H]:`DeregistrationProtection`,[W]:HJ}],[0,{[H]:`LastLaunchedTime`,[W]:zZ}],[2,{[H]:`ImageAllowed`,[W]:EX}],[0,{[H]:`SourceImageId`,[W]:Fpe}],[0,{[H]:`SourceImageRegion`,[W]:Ipe}],[2,{[H]:`FreeTierEligible`,[W]:GY}],[0,{[H]:`ImageId`,[W]:VX}],[0,{[H]:`ImageLocation`,[W]:HX}],[0,{[H]:`ImageState`,[W]:fZ}],[0,{[H]:`ImageOwnerId`,[W]:qX}],[0,{[H]:`CreationDate`,[W]:tJ}],[2,{[H]:`IsPublic`,[W]:oZ}],[()=>e1,{[H]:`ProductCodes`,[W]:CQ}],[0,{[H]:`Architecture`,[W]:Pq}],[0,{[H]:`ImageType`,[W]:xZ}],[0,{[H]:`KernelId`,[W]:DZ}],[0,{[H]:`RamdiskId`,[W]:IQ}],[0,{[H]:`Platform`,[W]:AQ}]]],$ge=[3,G,zL,0,[Sz,mH,IG,zN],[[0,{[H]:`KeyName`,[W]:AZ}],[21,{[H]:`PublicKeyMaterial`,[W]:Yfe}],[()=>s1,{[W]:zG}],[2,{[H]:`DryRun`,[W]:UJ}]],2],e_e=[3,G,BL,0,[vz,Sz,Ez,vG],[[0,{[H]:`KeyFingerprint`,[W]:EZ}],[0,{[H]:`KeyName`,[W]:AZ}],[0,{[H]:`KeyPairId`,[W]:jZ}],[()=>o1,{[H]:`TagSet`,[W]:o$}]]],t_e=[3,G,HI,0,[sj,wG],[[()=>pye,{[H]:`Accelerators`,[W]:jq}],[1,{[H]:`TotalInferenceMemoryInMiB`,[W]:sme}]]],n_e=[3,G,iL,0,[GM,HB,IB,bB],[[1,{[H]:`Count`,[W]:EJ}],[0,{[H]:`Name`,[W]:uQ}],[0,{[H]:`Manufacturer`,[W]:cQ}],[()=>r_e,{[H]:`MemoryInfo`,[W]:eQ}]]],r_e=[3,G,oL,0,[mW],[[1,{[H]:`SizeInMiB`,[W]:GQ}]]],i_e=[3,G,pz,0,[lj,hj,jM,dF,MF,FI,wL,UL,KP,rF,aV,vV,IH,LH,aW,HU,hW,HW,YW,vG,qK,Xj,Ej,rM,lM,EI,$z,CB,vF,_j,XV,rK,iK,GV,JI,VG,wB,Ij,cV,MV,TW,bL,FL,pG,WV,YV,nG,Sz,Sde,UV,rz,Xz,kH,yz,YH,OH,VB,NW,xK,sH,lH],[[0,{[H]:`Architecture`,[W]:Pq}],[()=>mye,{[H]:`BlockDeviceMapping`,[W]:Bq}],[0,{[H]:`ClientToken`,[W]:bJ}],[2,{[H]:`EbsOptimized`,[W]:yY}],[2,{[H]:`EnaSupport`,[W]:FY}],[0,{[H]:`Hypervisor`,[W]:sX}],[()=>Xge,{[H]:`IamInstanceProfile`,[W]:zX}],[0,{[H]:`InstanceLifecycle`,[W]:UX}],[()=>rye,{[H]:`ElasticGpuAssociationSet`,[W]:sY}],[()=>aye,{[H]:`ElasticInferenceAcceleratorAssociationSet`,[W]:pY}],[()=>yye,{[H]:`NetworkInterfaceSet`,[W]:gfe}],[0,{[H]:`OutpostArn`,[W]:yQ}],[0,{[H]:`RootDeviceName`,[W]:PQ}],[0,{[H]:`RootDeviceType`,[W]:FQ}],[()=>q$,{[H]:`GroupSet`,[W]:iX}],[2,{[H]:`SourceDestCheck`,[W]:VQ}],[0,{[H]:`SpotInstanceRequestId`,[W]:Lpe}],[0,{[H]:`SriovNetSupport`,[W]:XQ}],[()=>L$,{[H]:`StateReason`,[W]:ZQ}],[()=>o1,{[H]:`TagSet`,[W]:o$}],[0,{[H]:`VirtualizationType`,[W]:b$}],[()=>hhe,{[H]:`CpuOptions`,[W]:dJ}],[0,{[H]:`CapacityBlockId`,[W]:Zq}],[0,{[H]:`CapacityReservationId`,[W]:mJ}],[()=>che,{[H]:`CapacityReservationSpecification`,[W]:_J}],[()=>Jge,{[H]:`HibernationOptions`,[W]:dX}],[()=>Lye,{[H]:`LicenseSet`,[W]:BZ}],[()=>g_e,{[H]:`MetadataOptions`,[W]:rQ}],[()=>Ige,{[H]:`EnclaveOptions`,[W]:wY}],[0,{[H]:`BootMode`,[W]:Hq}],[0,{[H]:`PlatformDetails`,[W]:TQ}],[0,{[H]:`UsageOperation`,[W]:f$}],[4,{[H]:`UsageOperationUpdateTime`,[W]:bme}],[()=>sve,{[H]:`PrivateDnsNameOptions`,[W]:Rfe}],[0,{[H]:`Ipv6Address`,[W]:OX}],[0,{[H]:`TpmSupport`,[W]:s$}],[()=>f_e,{[H]:`MaintenanceOptions`,[W]:iQ}],[0,{[H]:`CurrentInstanceBootMode`,[W]:aJ}],[()=>b_e,{[H]:`NetworkPerformanceOptions`,[W]:bfe}],[()=>A$,{[H]:`Operator`,[W]:SQ}],[()=>Sye,{[H]:`SecondaryInterfaceSet`,[W]:zpe}],[0,{[H]:`InstanceId`,[W]:RX}],[0,{[H]:`ImageId`,[W]:VX}],[()=>D$,{[H]:`InstanceState`,[W]:hZ}],[0,{[H]:`PrivateDnsName`,[W]:wQ}],[0,{[H]:`DnsName`,[W]:RJ}],[0,{[H]:`Reason`,[W]:Spe}],[0,{[H]:`KeyName`,[W]:AZ}],[1,{[H]:`AmiLaunchIndex`,[W]:gq}],[()=>e1,{[H]:`ProductCodes`,[W]:CQ}],[0,{[H]:`InstanceType`,[W]:vZ}],[4,{[H]:`LaunchTime`,[W]:VZ}],[()=>j$,{[H]:`Placement`,[W]:ipe}],[0,{[H]:`KernelId`,[W]:DZ}],[0,{[H]:`RamdiskId`,[W]:IQ}],[0,{[H]:`Platform`,[W]:AQ}],[()=>Y_e,{[H]:`Monitoring`,[W]:ufe}],[0,{[H]:`SubnetId`,[W]:qQ}],[0,{[H]:`VpcId`,[W]:m$}],[0,{[H]:`PrivateIpAddress`,[W]:DQ}],[0,{[H]:`IpAddress`,[W]:DX}]]],a_e=[3,G,BI,0,[CF,OF],[[2,{[H]:`EnaSrdEnabled`,[W]:OY}],[()=>o_e,{[H]:`EnaSrdUdpSpecification`,[W]:MY}]]],o_e=[3,G,VI,0,[DF],[[2,{[H]:`EnaSrdUdpEnabled`,[W]:jY}]]],s_e=[3,G,YI,0,[DN,FF],[[0,{[H]:`DeviceName`,[W]:IJ}],[()=>Ege,{[H]:`Ebs`,[W]:LY}]]],c_e=[3,G,ZI,0,[DN,FF,FK,JB],[[0,{[H]:`DeviceName`,[W]:IJ}],[()=>Dge,{[H]:`Ebs`,[W]:LY}],[0,{[H]:`VirtualName`,[W]:g$}],[0,{[H]:`NoDevice`,[W]:pQ}]]],l_e=[3,G,AL,0,[NR],[[0,{[H]:`Ipv4Prefix`,[W]:rZ}]]],u_e=[3,G,xL,0,[JI,yR],[[0,{[H]:`Ipv6Address`,[W]:OX}],[2,{[H]:`IsPrimaryIpv6`,[W]:QX}]]],d_e=[3,G,jL,0,[AR],[[0,{[H]:`Ipv6Prefix`,[W]:aZ}]]],f_e=[3,G,GL,0,[tj,iU],[[0,{[H]:`AutoRecovery`,[W]:Sq}],[0,{[H]:`RebootMigration`,[W]:mpe}]]],p_e=[3,G,KL,0,[tj],[0]],m_e=[3,G,qL,0,[AB,WW],[0,()=>Dve]],h_e=[3,G,JL,0,[MI,kI,wI,OI,QL],[0,1,0,0,0]],g_e=[3,G,YL,0,[pG,MI,kI,wI,OI,QL],[[0,{[H]:`State`,[W]:n$}],[0,{[H]:`HttpTokens`,[W]:gX}],[1,{[H]:`HttpPutResponseHopLimit`,[W]:pX}],[0,{[H]:`HttpEndpoint`,[W]:lX}],[0,{[H]:`HttpProtocolIpv6`,[W]:fX}],[0,{[H]:`InstanceMetadataTags`,[W]:WX}]]],__e=[3,G,eR,0,[uj,dj,DP,$F,LI,rB,iV,bV,WV,sH,cH,HU,mG,NW,xK,lz,MR,ER,MM,MV],[[()=>E$,{[H]:`Association`,[W]:Fq}],[()=>v_e,{[H]:`Attachment`,[W]:Iq}],[0,{[H]:`Description`,[W]:ZJ}],[()=>q$,{[H]:`GroupSet`,[W]:iX}],[()=>X$,{[H]:`Ipv6AddressesSet`,[W]:TX}],[0,{[H]:`MacAddress`,[W]:GZ}],[0,{[H]:`NetworkInterfaceId`,[W]:hQ}],[0,{[H]:`OwnerId`,[W]:bQ}],[0,{[H]:`PrivateDnsName`,[W]:wQ}],[0,{[H]:`PrivateIpAddress`,[W]:DQ}],[()=>xye,{[H]:`PrivateIpAddressesSet`,[W]:EQ}],[2,{[H]:`SourceDestCheck`,[W]:VQ}],[0,{[H]:`Status`,[W]:r$}],[0,{[H]:`SubnetId`,[W]:qQ}],[0,{[H]:`VpcId`,[W]:m$}],[0,{[H]:`InterfaceType`,[W]:CZ}],[()=>gye,{[H]:`Ipv4PrefixSet`,[W]:$X}],[()=>_ye,{[H]:`Ipv6PrefixSet`,[W]:eZ}],[()=>fhe,{[H]:`ConnectionTrackingConfiguration`,[W]:xJ}],[()=>A$,{[H]:`Operator`,[W]:SQ}]]],E$=[3,G,tR,0,[Fj,Zj,dR,YV,rH],[[0,{[H]:`CarrierIp`,[W]:iJ}],[0,{[H]:`CustomerOwnedIp`,[W]:fJ}],[0,{[H]:`IpOwnerId`,[W]:YX}],[0,{[H]:`PublicDnsName`,[W]:Bfe}],[0,{[H]:`PublicIp`,[W]:Wfe}]]],v_e=[3,G,nR,0,[ij,$A,jN,aN,mG,GB,wF,bF],[[4,{[H]:`AttachTime`,[W]:Dq}],[0,{[H]:`AttachmentId`,[W]:hq}],[2,{[H]:`DeleteOnTermination`,[W]:BJ}],[1,{[H]:`DeviceIndex`,[W]:PJ}],[0,{[H]:`Status`,[W]:r$}],[1,{[H]:`NetworkCardIndex`,[W]:fQ}],[()=>a_e,{[H]:`EnaSrdSpecification`,[W]:kY}],[1,{[H]:`EnaQueueCount`,[W]:TY}]]],y_e=[3,G,iR,0,[wde,jN,DP,aN,$F,zI,LI,iV,sH,cH,KW,NW,gde,lz,GB,MR,hR,ER,mR,dH,wF,NM,bF],[[2,{[H]:`AssociatePublicIpAddress`,[W]:vq}],[2,{[H]:`DeleteOnTermination`,[W]:BJ}],[0,{[H]:`Description`,[W]:ZJ}],[1,{[H]:`DeviceIndex`,[W]:PJ}],[()=>r1,{[W]:qU}],[1,{[H]:`Ipv6AddressCount`,[W]:bX}],[()=>X$,{[H]:`Ipv6Addresses`,[W]:TX}],[0,{[H]:`NetworkInterfaceId`,[W]:hQ}],[0,{[H]:`PrivateIpAddress`,[W]:DQ}],[()=>qye,{[H]:`PrivateIpAddresses`,[W]:EQ}],[1,{[H]:`SecondaryPrivateIpAddressCount`,[W]:Upe}],[0,{[H]:`SubnetId`,[W]:qQ}],2,0,1,[()=>jye,{[W]:NR}],1,[()=>Mye,{[W]:AR}],1,2,()=>Pge,()=>dhe,1]],b_e=[3,G,cR,0,[xj],[[0,{[H]:`BandwidthWeighting`,[W]:qq}]]],x_e=[3,G,lR,0,[xj],[0]],S_e=[3,G,_R,0,[uj,AH,WV,sH],[[()=>E$,{[H]:`Association`,[W]:Fq}],[2,{[H]:`Primary`,[W]:jQ}],[0,{[H]:`PrivateDnsName`,[W]:wQ}],[0,{[H]:`PrivateIpAddress`,[W]:DQ}]]],C_e=[3,G,XR,0,[dj,rB,fW,bV,cH,HU,mG,$W,VW,lz],[[()=>w_e,{[H]:`Attachment`,[W]:Iq}],[0,{[H]:`MacAddress`,[W]:GZ}],[0,{[H]:`SecondaryInterfaceId`,[W]:Ppe}],[0,{[H]:`OwnerId`,[W]:bQ}],[()=>Cye,{[H]:`PrivateIpAddressSet`,[W]:Gfe}],[2,{[H]:`SourceDestCheck`,[W]:VQ}],[0,{[H]:`Status`,[W]:r$}],[0,{[H]:`SecondarySubnetId`,[W]:Gpe}],[0,{[H]:`SecondaryNetworkId`,[W]:Vpe}],[0,{[H]:`InterfaceType`,[W]:CZ}]]],w_e=[3,G,HR,0,[ij,$A,jN,aN,mG,GB],[[4,{[H]:`AttachTime`,[W]:Dq}],[0,{[H]:`AttachmentId`,[W]:hq}],[2,{[H]:`DeleteOnTermination`,[W]:BJ}],[1,{[H]:`DeviceIndex`,[W]:PJ}],[0,{[H]:`Status`,[W]:r$}],[1,{[H]:`NetworkCardIndex`,[W]:fQ}]]],T_e=[3,G,WR,0,[sH],[[0,{[H]:`PrivateIpAddress`,[W]:DQ}]]],E_e=[3,G,qR,0,[sH],[0],1],D_e=[3,G,YR,0,[jN,aN,cH,iH,$W,lz,GB],[2,1,[()=>wye,{[W]:sH}],1,0,0,1]],D$=[3,G,ez,0,[UM,HB],[[1,{[H]:`Code`,[W]:wJ}],[0,{[H]:`Name`,[W]:uQ}]]],O_e=[3,G,BR,0,[bL,AM,xH],[[0,{[H]:`InstanceId`,[W]:RX}],[()=>D$,{[H]:`CurrentState`,[W]:yJ}],[()=>D$,{[H]:`PreviousState`,[W]:$fe}]]],k_e=[3,G,ZR,0,[LG,kP,dV,jF],[[1,{[H]:`TotalSizeInGB`,[W]:pme}],[()=>tye,{[H]:`Disks`,[W]:$J}],[0,{[H]:`NvmeSupport`,[W]:_Q}],[0,{[H]:`EncryptionSupport`,[W]:PY}]]],A_e=[3,G,az,0,[rz,Pj,YF,aG,qW,cG,ife,FI,fH,pK,bB,QR,ZR,cF,oV,dI,WF,QV,HI,jI,yj,iN,Ede,zU,eV,pV,fV,nB,sV,bH,rU,xW],[[0,{[H]:`InstanceType`,[W]:vZ}],[2,{[H]:`CurrentGeneration`,[W]:rJ}],[2,{[H]:`FreeTierEligible`,[W]:GY}],[()=>fbe,{[H]:`SupportedUsageClasses`,[W]:Xpe}],[()=>Qye,{[H]:`SupportedRootDeviceTypes`,[W]:Wpe}],[()=>hbe,{[H]:`SupportedVirtualizationTypes`,[W]:Qpe}],[2,{[H]:`BareMetal`,[W]:Uq}],[0,{[H]:`Hypervisor`,[W]:sX}],[()=>lve,{[H]:`ProcessorInfo`,[W]:qfe}],[()=>zve,{[H]:`VCpuInfo`,[W]:Cme}],[()=>G_e,{[H]:`MemoryInfo`,[W]:eQ}],[2,{[H]:`InstanceStorageSupported`,[W]:uZ}],[()=>k_e,{[H]:`InstanceStorageInfo`,[W]:lZ}],[()=>Tge,{[H]:`EbsInfo`,[W]:gY}],[()=>Z_e,{[H]:`NetworkInfo`,[W]:vfe}],[()=>Kge,{[H]:`GpuInfo`,[W]:ZY}],[()=>Vge,{[H]:`FpgaInfo`,[W]:VY}],[()=>rve,{[H]:`PlacementGroupInfo`,[W]:Hfe}],[()=>t_e,{[H]:`InferenceAcceleratorInfo`,[W]:xX}],[2,{[H]:`HibernationSupported`,[W]:hX}],[2,{[H]:`BurstablePerformanceSupported`,[W]:Gq}],[2,{[H]:`DedicatedHostsSupported`,[W]:NJ}],[2,{[H]:`AutoRecoverySupported`,[W]:bq}],[()=>$ve,{[H]:`SupportedBootModes`,[W]:Tpe}],[0,{[H]:`NitroEnclavesSupport`,[W]:mfe}],[0,{[H]:`NitroTpmSupport`,[W]:Cfe}],[()=>nve,{[H]:`NitroTpmInfo`,[W]:Sfe}],[()=>H_e,{[H]:`MediaAcceleratorInfo`,[W]:WZ}],[()=>tve,{[H]:`NeuronInfo`,[W]:yfe}],[0,{[H]:`PhcSupport`,[W]:Qfe}],[0,{[H]:`RebootMigrationSupport`,[W]:ppe}],[2,{[H]:`SupportedInRegion`,[W]:Rpe}]]],O$=[3,G,uL,0,[fj,hL,bV,vG],[[()=>Dye,{[H]:`AttachmentSet`,[W]:Eq}],[0,{[H]:`InternetGatewayId`,[W]:IX}],[0,{[H]:`OwnerId`,[W]:bQ}],[()=>o1,{[H]:`TagSet`,[W]:o$}]]],j_e=[3,G,dL,0,[pG,xK],[[0,{[H]:`State`,[W]:n$}],[0,{[H]:`VpcId`,[W]:m$}]]],M_e=[3,G,OR,0,[kR,KF,NG,$G,IR,RR,_H],[[0,{[H]:`IpProtocol`,[W]:tZ}],[1,{[H]:`FromPort`,[W]:HY}],[1,{[H]:`ToPort`,[W]:a$}],[()=>pbe,{[H]:`Groups`,[W]:oX}],[()=>Aye,{[H]:`IpRanges`,[W]:sZ}],[()=>Nye,{[H]:`Ipv6Ranges`,[W]:cZ}],[()=>Kye,{[H]:`PrefixListIds`,[W]:Xfe}]]],N_e=[3,G,LR,0,[DP,Hj],[[0,{[H]:`Description`,[W]:ZJ}],[0,{[H]:`CidrIp`,[W]:oJ}]]],P_e=[3,G,wR,0,[NR],[0]],F_e=[3,G,TR,0,[AR],[0]],I_e=[3,G,zR,0,[DP,Uj],[[0,{[H]:`Description`,[W]:ZJ}],[0,{[H]:`CidrIpv6`,[W]:sJ}]]],L_e=[3,G,jz,0,[Ez,vG,Sz,vz,xz],[[0,{[H]:`KeyPairId`,[W]:jZ}],[()=>o1,{[H]:`TagSet`,[W]:o$}],[0,{[H]:`KeyName`,[W]:AZ}],[0,{[H]:`KeyFingerprint`,[W]:EZ}],[()=>qme,{[H]:`KeyMaterial`,[W]:kZ}]]],R_e=[3,G,kz,0,[Ez,Mz,vG,pH,LM,Sz,vz],[[0,{[H]:`KeyPairId`,[W]:jZ}],[0,{[H]:`KeyType`,[W]:NZ}],[()=>o1,{[H]:`TagSet`,[W]:o$}],[0,{[H]:`PublicKey`,[W]:Jfe}],[4,{[H]:`CreateTime`,[W]:CJ}],[0,{[H]:`KeyName`,[W]:AZ}],[0,{[H]:`KeyFingerprint`,[W]:EZ}]]],z_e=[3,G,Yz,0,[qz,Jz,XK],[0,0,0]],B_e=[3,G,Iz,0,[Pz],[[0,{[H]:`LicenseConfigurationArn`,[W]:FZ}]]],V_e=[3,G,Fz,0,[Pz],[0]],H_e=[3,G,nB,0,[sj,jG],[[()=>zye,{[H]:`Accelerators`,[W]:jq}],[1,{[H]:`TotalMediaMemoryInMiB`,[W]:ume}]]],U_e=[3,G,cB,0,[GM,HB,IB,bB],[[1,{[H]:`Count`,[W]:EJ}],[0,{[H]:`Name`,[W]:uQ}],[0,{[H]:`Manufacturer`,[W]:cQ}],[()=>W_e,{[H]:`MemoryInfo`,[W]:eQ}]]],W_e=[3,G,uB,0,[mW],[[1,{[H]:`SizeInMiB`,[W]:GQ}]]],G_e=[3,G,bB,0,[mW],[[1,{[H]:`SizeInMiB`,[W]:GQ}]]],K_e=[3,G,_B,0,[bL,HU,KM,zN,Zde,sK,hj,qM,rz,Nz,kU,ZG,ML,$F,dF,HW,MF],[[0,{[H]:`InstanceId`,[W]:RX}],[()=>S$,0],[()=>S$,0],[2,{[H]:`DryRun`,[W]:UJ}],[0,{[H]:`Attribute`,[W]:Lq}],[()=>Gme,{[H]:`Value`,[W]:p$}],[()=>hye,{[H]:`BlockDeviceMapping`,[W]:Bq}],[()=>S$,{[H]:`DisableApiTermination`,[W]:DJ}],[()=>C$,{[H]:`InstanceType`,[W]:vZ}],[()=>C$,{[H]:`Kernel`,[W]:PZ}],[()=>C$,{[H]:`Ramdisk`,[W]:xpe}],[()=>ohe,{[H]:`UserData`,[W]:yme}],[()=>C$,{[H]:`InstanceInitiatedShutdownBehavior`,[W]:BX}],[()=>J$,{[W]:fI}],[()=>S$,{[H]:`EbsOptimized`,[W]:yY}],[()=>C$,{[H]:`SriovNetSupport`,[W]:XQ}],[()=>S$,{[H]:`EnaSupport`,[W]:FY}]],1],q_e=[3,G,MB,0,[DK,zN,uG,WK,hz,qG,tB],[0,2,1,0,1,1,2],1],J_e=[3,G,NB,0,[PK],[[()=>Bve,{[H]:`VolumeModification`,[W]:Ome}]]],Y_e=[3,G,VB,0,[pG],[[0,{[H]:`State`,[W]:n$}]]],X_e=[3,G,qB,0,[GB,lV,SB,_de,$de,LV,nN,mB,hB],[[1,{[H]:`NetworkCardIndex`,[W]:fQ}],[0,{[H]:`NetworkPerformance`,[W]:gQ}],[1,{[H]:`MaximumNetworkInterfaces`,[W]:nQ}],[1,{[H]:`AdditionalFlexibleNetworkInterfaces`,[W]:uq}],[1,{[H]:`BaselineBandwidthInGbps`,[W]:Rq}],[1,{[H]:`PeakBandwidthInGbps`,[W]:Ffe}],[1,{[H]:`DefaultEnaQueueCountPerInterface`,[W]:jJ}],[1,{[H]:`MaximumEnaQueueCount`,[W]:ZZ}],[1,{[H]:`MaximumEnaQueueCountPerInterface`,[W]:QZ}]]],Z_e=[3,G,oV,0,[lV,SB,xB,ON,WB,UI,WI,nz,MF,AF,lF,sF,EF,Cj,UF,MM,UW,OB,GI],[[0,{[H]:`NetworkPerformance`,[W]:gQ}],[1,{[H]:`MaximumNetworkInterfaces`,[W]:nQ}],[1,{[H]:`MaximumNetworkCards`,[W]:tQ}],[1,{[H]:`DefaultNetworkCardIndex`,[W]:LJ}],[()=>Bye,{[H]:`NetworkCards`,[W]:ffe}],[1,{[H]:`Ipv4AddressesPerInterface`,[W]:SX}],[1,{[H]:`Ipv6AddressesPerInterface`,[W]:CX}],[2,{[H]:`Ipv6Supported`,[W]:_Z}],[0,{[H]:`EnaSupport`,[W]:FY}],[2,{[H]:`EfaSupported`,[W]:NY}],[()=>kge,{[H]:`EfaInfo`,[W]:_Y}],[2,{[H]:`EncryptionInTransitSupported`,[W]:hY}],[2,{[H]:`EnaSrdSupported`,[W]:AY}],[()=>Zve,{[H]:`BandwidthWeightings`,[W]:Jq}],[0,{[H]:`FlexibleEnaQueuesSupport`,[W]:BY}],[()=>Lhe,{[H]:`ConnectionTrackingConfiguration`,[W]:xJ}],[2,{[H]:`SecondaryNetworkSupported`,[W]:Hpe}],[1,{[H]:`MaximumSecondaryNetworkInterfaces`,[W]:ofe}],[1,{[H]:`Ipv4AddressesPerSecondaryInterface`,[W]:wX}]]],Q_e=[3,G,YB,0,[GM,XK],[[1,{[H]:`Count`,[W]:EJ}],[1,{[H]:`Version`,[W]:Fme}]]],$_e=[3,G,XB,0,[GM,HB,Gj,bB],[[1,{[H]:`Count`,[W]:EJ}],[0,{[H]:`Name`,[W]:uQ}],[()=>Q_e,{[H]:`CoreInfo`,[W]:lJ}],[()=>eve,{[H]:`MemoryInfo`,[W]:eQ}]]],eve=[3,G,QB,0,[mW],[[1,{[H]:`SizeInMiB`,[W]:GQ}]]],tve=[3,G,sV,0,[$B,MG],[[()=>Vye,{[H]:`NeuronDevices`,[W]:pfe}],[1,{[H]:`TotalNeuronDeviceMemoryInMiB`,[W]:dme}]]],nve=[3,G,fV,0,[lG],[[()=>Hye,{[H]:`SupportedVersions`,[W]:$pe}]]],k$=[3,G,EV,0,[IV],[0]],A$=[3,G,DV,0,[LB,IV,CI],[[2,{[H]:`Managed`,[W]:lfe}],[0,{[H]:`Principal`,[W]:Pfe}],[2,{[H]:`HiddenByDefault`,[W]:cX}]]],j$=[3,G,kH,0,[oj,Yde,gI,vH,TI,KG,UU,AI,fI,aj],[[0,{[H]:`AvailabilityZoneId`,[W]:kq}],[0,{[H]:`Affinity`,[W]:Mq}],[0,{[H]:`GroupName`,[W]:eX}],[1,{[H]:`PartitionNumber`,[W]:Zfe}],[0,{[H]:`HostId`,[W]:uX}],[0,{[H]:`Tenancy`,[W]:nme}],[0,{[H]:`SpreadDomain`,[W]:Dpe}],[0,{[H]:`HostResourceGroupArn`,[W]:mX}],[0,{[H]:`GroupId`,[W]:QY}],[0,{[H]:`AvailabilityZone`,[W]:Oq}]]],M$=[3,G,ZV,0,[gI,pG,hG,VV,fI,vG,eI,IW,Bz,MV],[[0,{[H]:`GroupName`,[W]:eX}],[0,{[H]:`State`,[W]:n$}],[0,{[H]:`Strategy`,[W]:i$}],[1,{[H]:`PartitionCount`,[W]:Ife}],[0,{[H]:`GroupId`,[W]:QY}],[()=>o1,{[H]:`TagSet`,[W]:o$}],[0,{[H]:`GroupArn`,[W]:JY}],[0,{[H]:`SpreadLevel`,[W]:Bpe}],[0,{[H]:`LinkedGroupId`,[W]:RZ}],[()=>A$,{[H]:`Operator`,[W]:SQ}]]],rve=[3,G,QV,0,[eG],[[()=>Gye,{[H]:`SupportedStrategies`,[W]:Jpe}]]],ive=[3,G,hH,0,[DP,hH],[[0,{[H]:`Description`,[W]:ZJ}],[0,{[H]:`PrefixListId`,[W]:OQ}]]],ave=[3,G,KV,0,[NI,SF,xF],[[0,{[H]:`HostnameType`,[W]:_X}],[2,{[H]:`EnableResourceNameDnsARecord`,[W]:DY}],[2,{[H]:`EnableResourceNameDnsAAAARecord`,[W]:EY}]]],ove=[3,G,qV,0,[NI,SF,xF],[0,2,2]],sve=[3,G,JV,0,[NI,SF,xF],[[0,{[H]:`HostnameType`,[W]:_X}],[2,{[H]:`EnableResourceNameDnsARecord`,[W]:DY}],[2,{[H]:`EnableResourceNameDnsAAAARecord`,[W]:EY}]]],cve=[3,G,aH,0,[AH,sH],[[2,{[H]:`Primary`,[W]:jQ}],[0,{[H]:`PrivateIpAddress`,[W]:DQ}]]],lve=[3,G,fH,0,[RU,VU,WU,IB],[[()=>Kve,{[H]:`SupportedArchitectures`,[W]:Cpe}],[1,{[H]:`SustainedClockSpeedInGhz`,[W]:Epe}],[()=>ube,{[H]:`SupportedFeatures`,[W]:Ope}],[0,{[H]:`Manufacturer`,[W]:cQ}]]],uve=[3,G,HV,0,[RV,BV],[[0,{[H]:`ProductCode`,[W]:Lfe}],[0,{[H]:`Type`,[W]:l$}]]],dve=[3,G,CH,0,[cI],[[0,{[H]:`GatewayId`,[W]:XY}]]],fve=[3,G,KH,0,[LL,zN],[[()=>Y$,{[W]:bL}],[2,{[H]:`DryRun`,[W]:UJ}]],1],pve=[3,G,cU,0,[fI,yH,QG,xK,LK],[[0,{[H]:`GroupId`,[W]:QY}],[0,{[H]:`PeeringStatus`,[W]:kQ}],[0,{[H]:`UserId`,[W]:u$}],[0,{[H]:`VpcId`,[W]:m$}],[0,{[H]:`VpcPeeringConnectionId`,[W]:_$}]]],mve=[3,G,jU,0,[xV,xI,aU,RF],[[0,{[H]:`OptInStatus`,[W]:xQ}],[()=>Yye,{[H]:`GeographySet`,[W]:rX}],[0,{[H]:`RegionName`,[W]:LQ}],[0,{[H]:`RegionEndpoint`,[W]:ope}]]],hve=[3,G,VH,0,[HB],[[0,{[H]:`Name`,[W]:uQ}]]],N$=[3,G,NU,0,[XH,bV,QH,$F,mz],[[0,{[H]:`ReservationId`,[W]:upe}],[0,{[H]:`OwnerId`,[W]:bQ}],[0,{[H]:`RequesterId`,[W]:fpe}],[()=>q$,{[H]:`GroupSet`,[W]:iX}],[()=>vye,{[H]:`InstancesSet`,[W]:mZ}]]],gve=[3,G,hU,0,[tW,fI,lL,kR,KF,NG,Wj,Uj,hH,HH,DP],[[0,{[H]:`SecurityGroupRuleId`,[W]:UQ}],[0,{[H]:`GroupId`,[W]:QY}],[2,{[H]:`IsEgress`,[W]:NX}],[0,{[H]:`IpProtocol`,[W]:tZ}],[1,{[H]:`FromPort`,[W]:HY}],[1,{[H]:`ToPort`,[W]:a$}],[0,{[H]:`CidrIpv4`,[W]:cJ}],[0,{[H]:`CidrIpv6`,[W]:sJ}],[0,{[H]:`PrefixListId`,[W]:OQ}],[0,{[H]:`ReferencedGroupId`,[W]:cpe}],[0,{[H]:`Description`,[W]:ZJ}]]],_ve=[3,G,uU,0,[fI,$U,zN,XW,ZW,kR,KF,NG,Hj,DR],[[0,{[H]:`GroupId`,[W]:QY}],[()=>i1,{[W]:tW}],[2,{[H]:`DryRun`,[W]:UJ}],[0,{[H]:`SourceSecurityGroupName`,[W]:QQ}],[0,{[H]:`SourceSecurityGroupOwnerId`,[W]:$Q}],[0,{[H]:`IpProtocol`,[W]:tZ}],[1,{[H]:`FromPort`,[W]:HY}],[1,{[H]:`ToPort`,[W]:a$}],[0,{[H]:`CidrIp`,[W]:oJ}],[()=>Q$,{[H]:`IpPermissions`,[W]:nZ}]],1],vve=[3,G,dU,0,[NH,nK,_U],[[2,{[H]:`Return`,[W]:NQ}],[()=>Q$,{[H]:`UnknownIpPermissionSet`,[W]:d$}],[()=>n1,{[H]:`RevokedSecurityGroupRuleSet`,[W]:RQ}]]],yve=[3,G,fU,0,[Hj,KF,fI,gI,DR,kR,XW,ZW,NG,$U,zN],[0,1,0,0,[()=>Q$,0],0,0,0,1,[()=>i1,{[W]:tW}],[2,{[H]:`DryRun`,[W]:UJ}]]],bve=[3,G,pU,0,[NH,nK,_U],[[2,{[H]:`Return`,[W]:NQ}],[()=>Q$,{[H]:`UnknownIpPermissionSet`,[W]:d$}],[()=>n1,{[H]:`RevokedSecurityGroupRuleSet`,[W]:RQ}]]],xve=[3,G,PU,0,[QM,oN,LN,hF,cI,bL,fR,rV,xG,zz,Nj,iV,_V,pG,LK,Yj,TV,qI],[[0,{[H]:`DestinationCidrBlock`,[W]:OJ}],[0,{[H]:`DestinationIpv6CidrBlock`,[W]:FJ}],[0,{[H]:`DestinationPrefixListId`,[W]:VJ}],[0,{[H]:`EgressOnlyInternetGatewayId`,[W]:SY}],[0,{[H]:`GatewayId`,[W]:XY}],[0,{[H]:`InstanceId`,[W]:RX}],[0,{[H]:`InstanceOwnerId`,[W]:JX}],[0,{[H]:`NatGatewayId`,[W]:mQ}],[0,{[H]:`TransitGatewayId`,[W]:ame}],[0,{[H]:`LocalGatewayId`,[W]:LZ}],[0,{[H]:`CarrierGatewayId`,[W]:nJ}],[0,{[H]:`NetworkInterfaceId`,[W]:hQ}],[0,{[H]:`Origin`,[W]:Tfe}],[0,{[H]:`State`,[W]:n$}],[0,{[H]:`VpcPeeringConnectionId`,[W]:_$}],[0,{[H]:`CoreNetworkArn`,[W]:uJ}],[0,{[H]:`OdbNetworkArn`,[W]:kfe}],[0,{[H]:`IpAddress`,[W]:DX}]]],P$=[3,G,DU,0,[Xde,TH,SU,FU,vG,xK,bV],[[()=>ebe,{[H]:`AssociationSet`,[W]:Tq}],[()=>Jye,{[H]:`PropagatingVgwSet`,[W]:tpe}],[0,{[H]:`RouteTableId`,[W]:zQ}],[()=>$ye,{[H]:`RouteSet`,[W]:gpe}],[()=>o1,{[H]:`TagSet`,[W]:o$}],[0,{[H]:`VpcId`,[W]:m$}],[0,{[H]:`OwnerId`,[W]:bQ}]]],Sve=[3,G,vU,0,[FB,yU,SU,NW,cI,uH,nj],[[2,{[H]:`Main`,[W]:cfe}],[0,{[H]:`RouteTableAssociationId`,[W]:_pe}],[0,{[H]:`RouteTableId`,[W]:zQ}],[0,{[H]:`SubnetId`,[W]:qQ}],[0,{[H]:`GatewayId`,[W]:XY}],[0,{[H]:`PublicIpv4Pool`,[W]:Kfe}],[()=>F$,{[H]:`AssociationState`,[W]:Cq}]]],F$=[3,G,xU,0,[pG,zW],[[0,{[H]:`State`,[W]:n$}],[0,{[H]:`StatusMessage`,[W]:JQ}]]],Cve=[3,G,GH,0,[IF],[[2,{[H]:`Enabled`,[W]:RY}]],1],wve=[3,G,qH,0,[oB,sB,hj,FL,rz,zI,LI,yz,Sz,VB,kH,YH,YU,aW,NW,ZG,JP,iF,IG,Kz,XL,DM,Xj,lM,EI,Uz,CB,vF,GV,wB,KM,yF,cV,MV,TW,zN,qM,ML,sH,jM,ZA,aV,wL,dF],[1,1,[()=>G$,{[W]:mj}],0,0,1,[()=>X$,{[W]:JI}],0,0,[()=>Cve,0],[()=>j$,0],0,[()=>r1,{[W]:qU}],[()=>ibe,{[W]:oW}],0,[()=>Kme,0],[()=>iye,0],[()=>oye,{[W]:XP}],[()=>s1,{[W]:zG}],()=>z_e,()=>m_e,()=>Ihe,()=>ghe,()=>she,()=>Yge,[()=>Rye,{[W]:Gz}],()=>h_e,()=>Lge,()=>ove,()=>p_e,2,2,()=>x_e,()=>k$,[()=>Tye,{[W]:EW}],[2,{[H]:`DryRun`,[W]:UJ}],[2,{[H]:`DisableApiTermination`,[W]:DJ}],[0,{[H]:`InstanceInitiatedShutdownBehavior`,[W]:BX}],[0,{[H]:`PrivateIpAddress`,[W]:DQ}],[0,{[H]:`ClientToken`,[bZ]:1,[W]:bJ}],[0,{[H]:`AdditionalInfo`,[W]:pq}],[()=>bye,{[H]:`NetworkInterface`,[W]:_fe}],[()=>Zge,{[H]:`IamInstanceProfile`,[W]:zX}],[2,{[H]:`EbsOptimized`,[W]:yY}]],2],Tve=[3,G,oW,0,[fI,gR,vG,xK,KU,bV,gI,DP,DR],[[0,{[H]:`GroupId`,[W]:QY}],[()=>Q$,{[H]:`IpPermissionsEgress`,[W]:ZX}],[()=>o1,{[H]:`TagSet`,[W]:o$}],[0,{[H]:`VpcId`,[W]:m$}],[0,{[H]:`SecurityGroupArn`,[W]:HQ}],[0,{[H]:`OwnerId`,[W]:bQ}],[0,{[H]:`GroupName`,[W]:eX}],[0,{[H]:`GroupDescription`,[W]:YY}],[()=>Q$,{[H]:`IpPermissions`,[W]:nZ}]]],Eve=[3,G,rW,0,[tW,fI,yI,lL,kR,KF,NG,Wj,Uj,hH,UH,DP,vG,QU],[[0,{[H]:`SecurityGroupRuleId`,[W]:UQ}],[0,{[H]:`GroupId`,[W]:QY}],[0,{[H]:`GroupOwnerId`,[W]:tX}],[2,{[H]:`IsEgress`,[W]:NX}],[0,{[H]:`IpProtocol`,[W]:tZ}],[1,{[H]:`FromPort`,[W]:HY}],[1,{[H]:`ToPort`,[W]:a$}],[0,{[H]:`CidrIpv4`,[W]:cJ}],[0,{[H]:`CidrIpv6`,[W]:sJ}],[0,{[H]:`PrefixListId`,[W]:OQ}],[()=>pve,{[H]:`ReferencedGroupInfo`,[W]:lpe}],[0,{[H]:`Description`,[W]:ZJ}],[()=>o1,{[H]:`TagSet`,[W]:o$}],[0,{[H]:`SecurityGroupRuleArn`,[W]:Ape}]]],I$=[3,G,fG,0,[yV,vV,vG,iG,zH,rG,aj,UG,jj,IM,JF,DW,DK,pG,BW,tG,jH,bV,DP,UK,LF,bz,tN],[[0,{[H]:`OwnerAlias`,[W]:Efe}],[0,{[H]:`OutpostArn`,[W]:yQ}],[()=>o1,{[H]:`TagSet`,[W]:o$}],[0,{[H]:`StorageTier`,[W]:Ype}],[4,{[H]:`RestoreExpiryTime`,[W]:ape}],[0,{[H]:`SseType`,[W]:t$}],[0,{[H]:`AvailabilityZone`,[W]:Oq}],[0,{[H]:`TransferType`,[W]:gme}],[1,{[H]:`CompletionDurationMinutes`,[W]:eJ}],[4,{[H]:`CompletionTime`,[W]:SJ}],[1,{[H]:`FullSnapshotSizeInBytes`,[W]:WY}],[0,{[H]:`SnapshotId`,[W]:KQ}],[0,{[H]:`VolumeId`,[W]:h$}],[0,{[H]:`Status`,[W]:r$}],[0,{[H]:`StatusMessage`,[W]:JQ}],[4,{[H]:`StartTime`,[W]:e$}],[0,{[H]:`Progress`,[W]:MQ}],[0,{[H]:`OwnerId`,[W]:bQ}],[0,{[H]:`Description`,[W]:ZJ}],[1,{[H]:`VolumeSize`,[W]:v$}],[2,{[H]:`Encrypted`,[W]:zY}],[0,{[H]:`KmsKeyId`,[W]:OZ}],[0,{[H]:`DataEncryptionKeyId`,[W]:AJ}]]],Dve=[3,G,RW,0,[EB,wW,nfe,JK,CL],[0,0,1,4,0]],Ove=[3,G,_W,0,[LL,ZA,zN],[[()=>Y$,{[W]:bL}],[0,{[H]:`AdditionalInfo`,[W]:pq}],[2,{[H]:`DryRun`,[W]:UJ}]],1],kve=[3,G,vW,0,[kW],[[()=>Z$,{[H]:`InstancesSet`,[W]:mZ}]]],L$=[3,G,YW,0,[UM,RB],[[0,{[H]:`Code`,[W]:wJ}],[0,{[H]:`Message`,[W]:lQ}]]],Ave=[3,G,yW,0,[LL,PI,GW,zN,zF],[[()=>Y$,{[W]:bL}],2,2,[2,{[H]:`DryRun`,[W]:UJ}],[2,{[H]:`Force`,[W]:KY}]],1],jve=[3,G,bW,0,[jW],[[()=>Z$,{[H]:`InstancesSet`,[W]:mZ}]]],R$=[3,G,gG,0,[oj,uF,aB,Qj,bV,yde,eL,vG,LU,vV,RP,$L,KV,vj,YG,NW,pG,xK,wj,vde,aj,rN,TB],[[0,{[H]:`AvailabilityZoneId`,[W]:kq}],[1,{[H]:`EnableLniAtDeviceIndex`,[W]:vY}],[2,{[H]:`MapCustomerOwnedIpOnLaunch`,[W]:qZ}],[0,{[H]:`CustomerOwnedIpv4Pool`,[W]:pJ}],[0,{[H]:`OwnerId`,[W]:bQ}],[2,{[H]:`AssignIpv6AddressOnCreation`,[W]:fq}],[()=>cbe,{[H]:`Ipv6CidrBlockAssociationSet`,[W]:AX}],[()=>o1,{[H]:`TagSet`,[W]:o$}],[0,{[H]:`SubnetArn`,[W]:wpe}],[0,{[H]:`OutpostArn`,[W]:yQ}],[2,{[H]:`EnableDns64`,[W]:rY}],[2,{[H]:`Ipv6Native`,[W]:GX}],[()=>ave,{[H]:`PrivateDnsNameOptionsOnLaunch`,[W]:zfe}],[()=>T$,{[H]:`BlockPublicAccessStates`,[W]:Wq}],[0,{[H]:`Type`,[W]:l$}],[0,{[H]:`SubnetId`,[W]:qQ}],[0,{[H]:`State`,[W]:n$}],[0,{[H]:`VpcId`,[W]:m$}],[0,{[H]:`CidrBlock`,[W]:Yq}],[1,{[H]:`AvailableIpAddressCount`,[W]:dq}],[0,{[H]:`AvailabilityZone`,[W]:Oq}],[2,{[H]:`DefaultForAz`,[W]:MJ}],[2,{[H]:`MapPublicIpOnLaunch`,[W]:aQ}]]],Mve=[3,G,BU,0,[pG,zW],[[0,{[H]:`State`,[W]:n$}],[0,{[H]:`StatusMessage`,[W]:JQ}]]],Nve=[3,G,cW,0,[QA,$I,nL,RI,tz],[[0,{[H]:`AssociationId`,[W]:mq}],[0,{[H]:`Ipv6CidrBlock`,[W]:kX}],[()=>Mve,{[H]:`Ipv6CidrBlockState`,[W]:jX}],[0,{[H]:`Ipv6AddressAttribute`,[W]:yX}],[0,{[H]:`IpSource`,[W]:gZ}]]],Pve=[3,G,GG,0,[gz,sK],[[0,{[H]:`Key`,[W]:TZ}],[0,{[H]:`Value`,[W]:p$}]]],Fve=[3,G,zG,0,[EU,vG],[[0,{[H]:`ResourceType`,[W]:ype}],[()=>o1,{[W]:GG}]]],Ive=[3,G,TG,0,[LL,zF,GW,zN],[[()=>Y$,{[W]:bL}],2,2,[2,{[H]:`DryRun`,[W]:UJ}]],1],Lve=[3,G,EG,0,[OG],[[()=>Z$,{[H]:`InstancesSet`,[W]:mZ}]]],Rve=[3,G,tK,0,[DP,QG,gI,fI,xK,LK,yH],[[0,{[H]:`Description`,[W]:ZJ}],[0,{[H]:`UserId`,[W]:u$}],[0,{[H]:`GroupName`,[W]:eX}],[0,{[H]:`GroupId`,[W]:QY}],[0,{[H]:`VpcId`,[W]:m$}],[0,{[H]:`VpcPeeringConnectionId`,[W]:_$}],[0,{[H]:`PeeringStatus`,[W]:kQ}]]],zve=[3,G,pK,0,[mP,eN,uP,mK,KK],[[1,{[H]:`DefaultVCpus`,[W]:XJ}],[1,{[H]:`DefaultCores`,[W]:kJ}],[1,{[H]:`DefaultThreadsPerCore`,[W]:KJ}],[()=>eye,{[H]:`ValidCores`,[W]:wme}],[()=>dbe,{[H]:`ValidThreadsPerCore`,[W]:Pme}]]],z$=[3,G,QK,0,[oj,vV,sG,hz,vG,WK,qF,tB,qG,rG,MV,wK,DK,uG,DW,aj,pG,LM,fj,LF,bz],[[0,{[H]:`AvailabilityZoneId`,[W]:kq}],[0,{[H]:`OutpostArn`,[W]:yQ}],[0,{[H]:`SourceVolumeId`,[W]:Zpe}],[1,{[H]:`Iops`,[W]:wZ}],[()=>o1,{[H]:`TagSet`,[W]:o$}],[0,{[H]:`VolumeType`,[W]:y$}],[2,{[H]:`FastRestored`,[W]:UY}],[2,{[H]:`MultiAttachEnabled`,[W]:UZ}],[1,{[H]:`Throughput`,[W]:c$}],[0,{[H]:`SseType`,[W]:t$}],[()=>A$,{[H]:`Operator`,[W]:SQ}],[1,{[H]:`VolumeInitializationRate`,[W]:Eme}],[0,{[H]:`VolumeId`,[W]:h$}],[1,{[H]:`Size`,[W]:eme}],[0,{[H]:`SnapshotId`,[W]:KQ}],[0,{[H]:`AvailabilityZone`,[W]:Oq}],[0,{[H]:`Status`,[W]:r$}],[4,{[H]:`CreateTime`,[W]:CJ}],[()=>gbe,{[H]:`AttachmentSet`,[W]:Eq}],[2,{[H]:`Encrypted`,[W]:zY}],[0,{[H]:`KmsKeyId`,[W]:OZ}]]],B$=[3,G,lK,0,[jN,ej,pR,NP,DK,bL,OP,pG,ij],[[2,{[H]:`DeleteOnTermination`,[W]:BJ}],[0,{[H]:`AssociatedResource`,[W]:xq}],[0,{[H]:`InstanceOwningService`,[W]:XX}],[1,{[H]:`EbsCardIndex`,[W]:eY}],[0,{[H]:`VolumeId`,[W]:h$}],[0,{[H]:`InstanceId`,[W]:RX}],[0,{[H]:`Device`,[W]:QJ}],[0,{[H]:`Status`,[W]:r$}],[4,{[H]:`AttachTime`,[W]:Dq}]]],Bve=[3,G,PK,0,[DK,kB,zW,BG,DG,WG,HG,AG,kV,SV,jV,AV,wV,jH,tG,NF,MV],[[0,{[H]:`VolumeId`,[W]:h$}],[0,{[H]:`ModificationState`,[W]:sfe}],[0,{[H]:`StatusMessage`,[W]:JQ}],[1,{[H]:`TargetSize`,[W]:mme}],[1,{[H]:`TargetIops`,[W]:cme}],[0,{[H]:`TargetVolumeType`,[W]:_me}],[1,{[H]:`TargetThroughput`,[W]:hme}],[2,{[H]:`TargetMultiAttachEnabled`,[W]:lme}],[1,{[H]:`OriginalSize`,[W]:Afe}],[1,{[H]:`OriginalIops`,[W]:Dfe}],[0,{[H]:`OriginalVolumeType`,[W]:Mfe}],[1,{[H]:`OriginalThroughput`,[W]:jfe}],[2,{[H]:`OriginalMultiAttachEnabled`,[W]:Ofe}],[1,{[H]:`Progress`,[W]:MQ}],[4,{[H]:`StartTime`,[W]:e$}],[4,{[H]:`EndTime`,[W]:IY}],[()=>A$,{[H]:`Operator`,[W]:SQ}]]],V$=[3,G,$K,0,[bV,sz,eL,Tj,cL,LP,vG,vj,xK,pG,wj,AN],[[0,{[H]:`OwnerId`,[W]:bQ}],[0,{[H]:`InstanceTenancy`,[W]:SZ}],[()=>xbe,{[H]:`Ipv6CidrBlockAssociationSet`,[W]:AX}],[()=>ybe,{[H]:`CidrBlockAssociationSet`,[W]:Xq}],[2,{[H]:`IsDefault`,[W]:MX}],[()=>Hve,{[H]:`EncryptionControl`,[W]:nY}],[()=>o1,{[H]:`TagSet`,[W]:o$}],[()=>T$,{[H]:`BlockPublicAccessStates`,[W]:Wq}],[0,{[H]:`VpcId`,[W]:m$}],[0,{[H]:`State`,[W]:n$}],[0,{[H]:`CidrBlock`,[W]:Yq}],[0,{[H]:`DhcpOptionsId`,[W]:zJ}]]],Vve=[3,G,uK,0,[QA,wj,Dj],[[0,{[H]:`AssociationId`,[W]:mq}],[0,{[H]:`CidrBlock`,[W]:Yq}],[()=>H$,{[H]:`CidrBlockState`,[W]:Qq}]]],H$=[3,G,fK,0,[pG,zW],[[0,{[H]:`State`,[W]:n$}],[0,{[H]:`StatusMessage`,[W]:JQ}]]],Hve=[3,G,hK,0,[xK,yK,BB,pG,BW,BH,vG],[[0,{[H]:`VpcId`,[W]:m$}],[0,{[H]:`VpcEncryptionControlId`,[W]:Tme}],[0,{[H]:`Mode`,[W]:dfe}],[0,{[H]:`State`,[W]:n$}],[0,{[H]:`StateMessage`,[W]:YQ}],[()=>Wve,{[H]:`ResourceExclusions`,[W]:spe}],[()=>o1,{[H]:`TagSet`,[W]:o$}]]],Uve=[3,G,gK,0,[BB,mL,mF,nV,BK,RK,Lz,jK,BP],[0,0,0,0,0,0,0,0,0],1],U$=[3,G,_K,0,[pG,BW],[[0,{[H]:`State`,[W]:n$}],[0,{[H]:`StateMessage`,[W]:YQ}]]],Wve=[3,G,vK,0,[uL,pF,tV,zK,VK,Qz,AK,zP],[[()=>U$,{[H]:`InternetGateway`,[W]:PX}],[()=>U$,{[H]:`EgressOnlyInternetGateway`,[W]:xY}],[()=>U$,{[H]:`NatGateway`,[W]:hfe}],[()=>U$,{[H]:`VirtualPrivateGateway`,[W]:Ame}],[()=>U$,{[H]:`VpcPeering`,[W]:jme}],[()=>U$,{[H]:`Lambda`,[W]:HZ}],[()=>U$,{[H]:`VpcLattice`,[W]:Dme}],[()=>U$,{[H]:`ElasticFileSystem`,[W]:iY}]]],Gve=[3,G,SK,0,[QA,$I,nL,UB,jR,RI,tz],[[0,{[H]:`AssociationId`,[W]:mq}],[0,{[H]:`Ipv6CidrBlock`,[W]:kX}],[()=>H$,{[H]:`Ipv6CidrBlockState`,[W]:jX}],[0,{[H]:`NetworkBorderGroup`,[W]:dQ}],[0,{[H]:`Ipv6Pool`,[W]:iZ}],[0,{[H]:`Ipv6AddressAttribute`,[W]:yX}],[0,{[H]:`IpSource`,[W]:gZ}]]],W$=`unit`,Kve=[1,G,Lde,0,[0,{[W]:U}]],qve=[1,G,Hde,0,[()=>rhe,{[W]:U}]],Jve=[1,G,Ude,0,[()=>nhe,{[W]:U}]],Yve=[1,G,Gde,0,[()=>ihe,{[W]:U}]],Xve=[1,G,qde,0,[()=>ahe,{[W]:U}]],Zve=[1,G,Sj,0,[0,{[W]:U}]],Qve=[1,G,efe,0,[()=>w$,{[W]:U}]],G$=[1,G,tfe,0,[()=>w$,{[W]:mj}]],$ve=[1,G,rfe,0,[0,{[W]:U}]],eye=[1,G,Oj,0,[1,{[W]:U}]],tye=[1,G,uN,0,[()=>Sge,{[W]:U}]],nye=[1,G,PP,0,[()=>wge,{[W]:U}]],rye=[1,G,UP,0,[()=>Age,{[W]:U}]],iye=[1,G,YP,0,[()=>jge,{[W]:U}]],aye=[1,G,$P,0,[()=>Nge,{[W]:U}]],oye=[1,G,iF,0,[()=>Mge,{[W]:U}]],sye=[1,G,jP,0,[0,{[W]:MP}]],K$=[1,G,GF,0,[()=>Rge,{[W]:ZF}]],cye=[1,G,VF,0,[()=>zge,{[W]:U}]],lye=[1,G,oI,0,[()=>Wge,{[W]:U}]],q$=[1,G,lI,0,[()=>qge,{[W]:U}]],J$=[1,G,uI,0,[0,{[W]:QY}]],uye=[1,G,_I,0,[0,{[W]:gI}]],dye=[1,G,NL,0,[0,{[W]:FL}]],fye=[1,G,HL,0,[()=>Qge,{[W]:U}]],pye=[1,G,aL,0,[()=>n_e,0]],mye=[1,G,XI,0,[()=>s_e,{[W]:U}]],hye=[1,G,QI,0,[()=>c_e,{[W]:U}]],Y$=[1,G,PL,0,[0,{[W]:bL}]],gye=[1,G,DL,0,[()=>l_e,{[W]:U}]],X$=[1,G,SL,0,[()=>u_e,{[W]:U}]],_ye=[1,G,OL,0,[()=>d_e,{[W]:U}]],vye=[1,G,WL,0,[()=>i_e,{[W]:U}]],yye=[1,G,rR,0,[()=>__e,{[W]:U}]],bye=[1,G,aR,0,[()=>y_e,{[W]:U}]],xye=[1,G,vR,0,[()=>S_e,{[W]:U}]],Sye=[1,G,UR,0,[()=>C_e,{[W]:U}]],Cye=[1,G,GR,0,[()=>T_e,{[W]:U}]],wye=[1,G,KR,0,[()=>E_e,{[W]:U}]],Tye=[1,G,JR,0,[()=>D_e,{[W]:U}]],Z$=[1,G,VR,0,[()=>O_e,{[W]:U}]],Eye=[1,G,iz,0,[()=>A_e,{[W]:U}]],Dye=[1,G,fL,0,[()=>j_e,{[W]:U}]],Oye=[1,G,gL,0,[0,{[W]:U}]],kye=[1,G,vL,0,[()=>O$,{[W]:U}]],Q$=[1,G,xR,0,[()=>M_e,{[W]:U}]],Aye=[1,G,PR,0,[()=>N_e,{[W]:U}]],jye=[1,G,SR,0,[()=>P_e,{[W]:U}]],Mye=[1,G,CR,0,[()=>F_e,{[W]:U}]],Nye=[1,G,FR,0,[()=>I_e,{[W]:U}]],Pye=[1,G,Cz,0,[0,{[W]:Sz}]],Fye=[1,G,Dz,0,[0,{[W]:Ez}]],Iye=[1,G,Az,0,[()=>R_e,{[W]:U}]],Lye=[1,G,Vz,0,[()=>B_e,{[W]:U}]],Rye=[1,G,Wz,0,[()=>V_e,{[W]:U}]],zye=[1,G,lB,0,[()=>U_e,{[W]:U}]],Bye=[1,G,KB,0,[()=>X_e,{[W]:U}]],Vye=[1,G,ZB,0,[()=>$_e,{[W]:U}]],Hye=[1,G,mV,0,[0,{[W]:U}]],$$=[1,G,OV,0,[0,{[W]:FV}]],Uye=[1,G,$V,0,[0,{[W]:fI}]],Wye=[1,G,eH,0,[()=>M$,{[W]:U}]],Gye=[1,G,tH,0,[0,{[W]:U}]],Kye=[1,G,gH,0,[()=>ive,{[W]:U}]],qye=[1,G,oH,0,[()=>cve,{[W]:U}]],e1=[1,G,zV,0,[()=>uve,{[W]:U}]],Jye=[1,G,wH,0,[()=>dve,{[W]:U}]],Yye=[1,G,WH,0,[()=>hve,{[W]:U}]],Xye=[1,G,eU,0,[()=>mve,{[W]:U}]],Zye=[1,G,oU,0,[0,{[W]:aU}]],t1=[1,G,tU,0,[()=>N$,{[W]:U}]],n1=[1,G,gU,0,[()=>gve,{[W]:U}]],Qye=[1,G,RH,0,[0,{[W]:U}]],$ye=[1,G,nU,0,[()=>xve,{[W]:U}]],ebe=[1,G,bU,0,[()=>Sve,{[W]:U}]],tbe=[1,G,CU,0,[0,{[W]:U}]],nbe=[1,G,TU,0,[()=>P$,{[W]:U}]],r1=[1,G,JU,0,[0,{[W]:qU}]],rbe=[1,G,XU,0,[()=>Tve,{[W]:U}]],i1=[1,G,eW,0,[0,{[W]:U}]],a1=[1,G,nW,0,[()=>Eve,{[W]:U}]],ibe=[1,G,iW,0,[0,{[W]:oW}]],abe=[1,G,SW,0,[0,{[W]:DW}]],obe=[1,G,FW,0,[()=>I$,{[W]:U}]],sbe=[1,G,CW,0,[0,{[W]:NW}]],cbe=[1,G,lW,0,[()=>Nve,{[W]:U}]],lbe=[1,G,LW,0,[()=>R$,{[W]:U}]],ube=[1,G,IU,0,[0,{[W]:U}]],o1=[1,G,kG,0,[()=>Pve,{[W]:U}]],s1=[1,G,RG,0,[()=>Fve,{[W]:U}]],dbe=[1,G,FG,0,[1,{[W]:U}]],fbe=[1,G,XG,0,[0,{[W]:U}]],pbe=[1,G,eK,0,[()=>Rve,{[W]:U}]],mbe=[1,G,HK,0,[0,{[W]:U}]],hbe=[1,G,GK,0,[0,{[W]:U}]],gbe=[1,G,cK,0,[()=>B$,{[W]:U}]],_be=[1,G,TK,0,[0,{[W]:DK}]],vbe=[1,G,MK,0,[()=>z$,{[W]:U}]],ybe=[1,G,dK,0,[()=>Vve,{[W]:U}]],bbe=[1,G,EK,0,[0,{[W]:xK}]],xbe=[1,G,CK,0,[()=>Gve,{[W]:U}]],Sbe=[1,G,NK,0,[()=>V$,{[W]:U}]],Cbe=[1,G,tq,0,[0,{[W]:U}]],wbe=[1,G,iq,0,[0,{[W]:rq}]],Tbe=[1,G,sq,0,[0,{[W]:oq}]],Ebe=[9,G,kde,0,()=>Jme,()=>Yme],Dbe=[9,G,bde,0,()=>Xme,()=>W$],Obe=[9,G,Bde,0,()=>Zme,()=>B$],kbe=[9,G,jde,0,()=>Qme,()=>$me],Abe=[9,G,Ide,0,()=>ehe,()=>the],jbe=[9,G,EM,0,()=>phe,()=>mhe],Mbe=[9,G,Kj,0,()=>_he,()=>vhe],Nbe=[9,G,Lj,0,()=>yhe,()=>bhe],Pbe=[9,G,qj,0,()=>xhe,()=>L_e],Fbe=[9,G,eM,0,()=>She,()=>Che],Ibe=[9,G,hM,0,()=>whe,()=>The],Lbe=[9,G,mM,0,()=>Ehe,()=>Dhe],Rbe=[9,G,gM,0,()=>Ohe,()=>khe],zbe=[9,G,OM,0,()=>Ahe,()=>I$],Bbe=[9,G,kM,0,()=>jhe,()=>Mhe],Vbe=[9,G,VM,0,()=>Nhe,()=>z$],Hbe=[9,G,HM,0,()=>Phe,()=>Fhe],Ube=[9,G,xN,0,()=>Rhe,()=>zhe],Wbe=[9,G,MN,0,()=>Bhe,()=>W$],Gbe=[9,G,qN,0,()=>Vhe,()=>Hhe],Kbe=[9,G,aP,0,()=>Uhe,()=>W$],qbe=[9,G,oP,0,()=>Whe,()=>W$],Jbe=[9,G,SP,0,()=>Ghe,()=>W$],Ybe=[9,G,CP,0,()=>Khe,()=>W$],Xbe=[9,G,ZM,0,()=>qhe,()=>Jhe],Zbe=[9,G,vN,0,()=>Yhe,()=>Xhe],Qbe=[9,G,yN,0,()=>Zhe,()=>Qhe],$be=[9,G,_N,0,()=>$he,()=>ege],exe=[9,G,lN,0,()=>tge,()=>nge],txe=[9,G,EN,0,()=>rge,()=>ige],nxe=[9,G,IN,0,()=>age,()=>oge],rxe=[9,G,KN,0,()=>sge,()=>cge],ixe=[9,G,WN,0,()=>lge,()=>uge],axe=[9,G,QN,0,()=>dge,()=>fge],oxe=[9,G,sP,0,()=>pge,()=>mge],sxe=[9,G,cP,0,()=>hge,()=>gge],cxe=[9,G,wP,0,()=>_ge,()=>vge],lxe=[9,G,TP,0,()=>yge,()=>bge],uxe=[9,G,EP,0,()=>xge,()=>B$],dxe=[9,G,tI,0,()=>Hge,()=>Uge],fxe=[9,G,RL,0,()=>$ge,()=>e_e],pxe=[9,G,yB,0,()=>K_e,()=>W$],mxe=[9,G,PB,0,()=>q_e,()=>J_e],hxe=[9,G,ZH,0,()=>fve,()=>W$],gxe=[9,G,lU,0,()=>_ve,()=>vve],_xe=[9,G,mU,0,()=>yve,()=>bve],vxe=[9,G,$H,0,()=>wve,()=>N$],yxe=[9,G,AW,0,()=>Ove,()=>kve],bxe=[9,G,MW,0,()=>Ave,()=>jve],xxe=[9,G,CG,0,()=>Ive,()=>Lve],Sxe=e=>({apiVersion:`2016-11-15`,base64Decoder:e?.base64Decoder??eO,base64Encoder:e?.base64Encoder??tO,disableHostPrefix:e?.disableHostPrefix??!1,endpointProvider:e?.endpointProvider??fde,extensions:e?.extensions??[],httpAuthSchemeProvider:e?.httpAuthSchemeProvider??Hue,httpAuthSchemes:e?.httpAuthSchemes??[{schemeId:`aws.auth#sigv4`,identityProvider:e=>e.getIdentityProvider(`aws.auth#sigv4`),signer:new SA}],logger:e?.logger??new mA,protocol:e?.protocol??rde,protocolSettings:e?.protocolSettings??{defaultNamespace:`com.amazonaws.ec2`,errorTypeRegistries:Ume,xmlNamespace:`http://ec2.amazonaws.com/doc/2016-11-15`,version:`2016-11-15`,serviceTarget:`AmazonEC2`},serviceId:e?.serviceId??`EC2`,urlParser:e?.urlParser??vO,utf8Decoder:e?.utf8Decoder??Wb,utf8Encoder:e?.utf8Encoder??Kb}),Cxe=e=>{let t=AA(e),n=()=>t().then(lA),r=Sxe(e);return{...r,...e,runtime:`browser`,defaultsMode:t,bodyLengthChecker:e?.bodyLengthChecker??kA,credentialDefaultProvider:e?.credentialDefaultProvider??(e=>()=>Promise.reject(Error(`Credential is missing`))),defaultUserAgentProvider:e?.defaultUserAgentProvider??TA({serviceId:r.serviceId,clientVersion:Gue.version}),maxAttempts:e?.maxAttempts??3,region:e?.region??DA(`Region is missing`),requestHandler:sO.create(e?.requestHandler??n),retryMode:e?.retryMode??(async()=>(await n()).retryMode||Dk),sha256:e?.sha256??Nb,streamCollector:e?.streamCollector??lO,useDualstackEndpoint:e?.useDualstackEndpoint??(()=>Promise.resolve(!1)),useFipsEndpoint:e?.useFipsEndpoint??(()=>Promise.resolve(!1))}},c1=e=>({setRegion(t){e.region=t},region(){return e.region}}),l1=e=>({region:e.region()}),wxe=e=>{let t=e.httpAuthSchemes,n=e.httpAuthSchemeProvider,r=e.credentials;return{setHttpAuthScheme(e){let n=t.findIndex(t=>t.schemeId===e.schemeId);n===-1?t.push(e):t.splice(n,1,e)},httpAuthSchemes(){return t},setHttpAuthSchemeProvider(e){n=e},httpAuthSchemeProvider(){return n},setCredentials(e){r=e},credentials(){return r}}},Txe=e=>({httpAuthSchemes:e.httpAuthSchemes(),httpAuthSchemeProvider:e.httpAuthSchemeProvider(),credentials:e.credentials()}),Exe=(e,t)=>{let n=Object.assign(c1(e),dA(e),Pb(e),wxe(e));return t.forEach(e=>e.configure(n)),Object.assign(e,l1(n),fA(n),Fb(n),Txe(n))},Dxe=class extends rA{config;constructor(...[e]){let t=Cxe(e||{});super(t),this.initConfig=t;let n=Exe(Uue(Xk(AD(Hk(Zk(ik(Wue(t))))))),e?.extensions||[]);this.config=n,this.middlewareStack.use(yO(this.config)),this.middlewareStack.use(zk(this.config)),this.middlewareStack.use(gA(this.config)),this.middlewareStack.use(Wk(this.config)),this.middlewareStack.use(ND(this.config)),this.middlewareStack.use(ID(this.config)),this.middlewareStack.use(zD(this.config)),this.middlewareStack.use(WD(this.config,{httpAuthSchemeParametersProvider:Bue,identityProviderConfigProvider:async e=>new nk({"aws.auth#sigv4":e.credentials})})),this.middlewareStack.use(YD(this.config))}destroy(){super.destroy()}},Oxe=class extends oA.classBuilder().ep(wA).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeAvailabilityZones`,{}).n(`EC2Client`,`DescribeAvailabilityZonesCommand`).sc(Xbe).build(){},u1=class extends oA.classBuilder().ep(wA).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeImages`,{}).n(`EC2Client`,`DescribeImagesCommand`).sc(Zbe).build(){},d1=class extends oA.classBuilder().ep(wA).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeInstances`,{}).n(`EC2Client`,`DescribeInstancesCommand`).sc(Qbe).build(){},kxe=class extends oA.classBuilder().ep(wA).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeInstanceTypes`,{}).n(`EC2Client`,`DescribeInstanceTypesCommand`).sc($be).build(){};oA.classBuilder().ep(wA).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeInternetGateways`,{}).n(`EC2Client`,`DescribeInternetGatewaysCommand`).sc(exe).build();var f1=class extends oA.classBuilder().ep(wA).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeKeyPairs`,{}).n(`EC2Client`,`DescribeKeyPairsCommand`).sc(txe).build(){},p1=class extends oA.classBuilder().ep(wA).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribePlacementGroups`,{}).n(`EC2Client`,`DescribePlacementGroupsCommand`).sc(nxe).build(){},Axe=class extends oA.classBuilder().ep(wA).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeRegions`,{}).n(`EC2Client`,`DescribeRegionsCommand`).sc(rxe).build(){};oA.classBuilder().ep(wA).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeRouteTables`,{}).n(`EC2Client`,`DescribeRouteTablesCommand`).sc(ixe).build();var m1=class extends oA.classBuilder().ep(wA).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeSecurityGroups`,{}).n(`EC2Client`,`DescribeSecurityGroupsCommand`).sc(axe).build(){},h1=class extends oA.classBuilder().ep(wA).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeSnapshots`,{}).n(`EC2Client`,`DescribeSnapshotsCommand`).sc(oxe).build(){},g1=class extends oA.classBuilder().ep(wA).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeSubnets`,{}).n(`EC2Client`,`DescribeSubnetsCommand`).sc(sxe).build(){},_1=class extends oA.classBuilder().ep(wA).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeVolumes`,{}).n(`EC2Client`,`DescribeVolumesCommand`).sc(cxe).build(){},v1=class extends oA.classBuilder().ep(wA).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AmazonEC2`,`DescribeVpcs`,{}).n(`EC2Client`,`DescribeVpcsCommand`).sc(lxe).build(){},jxe=async(e,t,n)=>({operation:lx(t).operation,region:await ux(e.region)()||(()=>{throw Error("expected `region` to be configured for `aws.auth#sigv4`")})()});function Mxe(e){return{schemeId:`aws.auth#sigv4`,signingProperties:{name:`elasticloadbalancing`,region:e.region},propertiesExtractor:(e,t)=>({signingProperties:{config:e,context:t}})}}var Nxe=e=>{let t=[];switch(e.operation){default:t.push(Mxe(e))}return t},Pxe=e=>{let t=CA(e);return Object.assign(t,{authSchemePreference:ux(e.authSchemePreference??[])})},Fxe=e=>Object.assign(e,{useDualstackEndpoint:e.useDualstackEndpoint??!1,useFipsEndpoint:e.useFipsEndpoint??!1,defaultSigningName:`elasticloadbalancing`}),y1={UseFIPS:{type:`builtInParams`,name:`useFipsEndpoint`},Endpoint:{type:`builtInParams`,name:`endpoint`},Region:{type:`builtInParams`,name:`region`},UseDualStack:{type:`builtInParams`,name:`useDualstackEndpoint`}},Ixe={name:`@aws-sdk/client-elastic-load-balancing-v2`,description:`AWS SDK for JavaScript Elastic Load Balancing V2 Client for Node.js, Browser and React Native`,version:`3.1045.0`,scripts:{build:`concurrently 'yarn:build:types' 'yarn:build:es' && yarn build:cjs`,"build:cjs":`node ../../scripts/compilation/inline client-elastic-load-balancing-v2`,"build:es":`tsc -p tsconfig.es.json`,"build:include:deps":`yarn g:turbo run build -F="$npm_package_name"`,"build:types":`tsc -p tsconfig.types.json`,"build:types:downlevel":`downlevel-dts dist-types dist-types/ts3.4`,clean:`premove dist-cjs dist-es dist-types tsconfig.cjs.tsbuildinfo tsconfig.es.tsbuildinfo tsconfig.types.tsbuildinfo`,"extract:docs":`api-extractor run --local`,"generate:client":`node ../../scripts/generate-clients/single-service --solo elastic-load-balancing-v2`,"test:e2e":`yarn g:vitest run -c vitest.config.e2e.mts --mode development`,"test:e2e:watch":`yarn g:vitest watch -c vitest.config.e2e.mts`,"test:index":`tsc --noEmit ./test/index-types.ts && node ./test/index-objects.spec.mjs`},main:`./dist-cjs/index.js`,types:`./dist-types/index.d.ts`,module:`./dist-es/index.js`,sideEffects:!1,dependencies:{"@aws-crypto/sha256-browser":`5.2.0`,"@aws-crypto/sha256-js":`5.2.0`,"@aws-sdk/core":`^3.974.8`,"@aws-sdk/credential-provider-node":`^3.972.39`,"@aws-sdk/middleware-host-header":`^3.972.10`,"@aws-sdk/middleware-logger":`^3.972.10`,"@aws-sdk/middleware-recursion-detection":`^3.972.11`,"@aws-sdk/middleware-user-agent":`^3.972.38`,"@aws-sdk/region-config-resolver":`^3.972.13`,"@aws-sdk/types":`^3.973.8`,"@aws-sdk/util-endpoints":`^3.996.8`,"@aws-sdk/util-user-agent-browser":`^3.972.10`,"@aws-sdk/util-user-agent-node":`^3.973.24`,"@smithy/config-resolver":`^4.4.17`,"@smithy/core":`^3.23.17`,"@smithy/fetch-http-handler":`^5.3.17`,"@smithy/hash-node":`^4.2.14`,"@smithy/invalid-dependency":`^4.2.14`,"@smithy/middleware-content-length":`^4.2.14`,"@smithy/middleware-endpoint":`^4.4.32`,"@smithy/middleware-retry":`^4.5.7`,"@smithy/middleware-serde":`^4.2.20`,"@smithy/middleware-stack":`^4.2.14`,"@smithy/node-config-provider":`^4.3.14`,"@smithy/node-http-handler":`^4.6.1`,"@smithy/protocol-http":`^5.3.14`,"@smithy/smithy-client":`^4.12.13`,"@smithy/types":`^4.14.1`,"@smithy/url-parser":`^4.2.14`,"@smithy/util-base64":`^4.3.2`,"@smithy/util-body-length-browser":`^4.2.2`,"@smithy/util-body-length-node":`^4.2.3`,"@smithy/util-defaults-mode-browser":`^4.3.49`,"@smithy/util-defaults-mode-node":`^4.2.54`,"@smithy/util-endpoints":`^3.4.2`,"@smithy/util-middleware":`^4.2.14`,"@smithy/util-retry":`^4.3.6`,"@smithy/util-utf8":`^4.2.2`,"@smithy/util-waiter":`^4.3.0`,tslib:`^2.6.2`},devDependencies:{"@tsconfig/node20":`20.1.8`,"@types/node":`^20.14.8`,concurrently:`7.0.0`,"downlevel-dts":`0.10.1`,premove:`4.0.0`,typescript:`~5.8.3`},engines:{node:`>=20.0.0`},typesVersions:{"<4.5":{"dist-types/*":[`dist-types/ts3.4/*`]}},files:[`dist-*/**`],author:{name:`AWS SDK for JavaScript Team`,url:`https://aws.amazon.com/javascript/`},license:`Apache-2.0`,browser:{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.browser`},"react-native":{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.native`},homepage:`https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-elastic-load-balancing-v2`,repository:{type:`git`,url:`https://github.com/aws/aws-sdk-js-v3.git`,directory:`clients/client-elastic-load-balancing-v2`}},b1=`ref`,x1=-1,S1=!0,C1=`isSet`,w1=`PartitionResult`,T1=`booleanEquals`,E1=`getAttr`,D1={[b1]:`Endpoint`},O1={[b1]:w1},k1={},A1=[{[b1]:`Region`}],j1={conditions:[[C1,[D1]],[C1,A1],[`aws.partition`,A1,w1],[T1,[{[b1]:`UseFIPS`},S1]],[T1,[{[b1]:`UseDualStack`},S1]],[T1,[{fn:E1,argv:[O1,`supportsDualStack`]},S1]],[T1,[{fn:E1,argv:[O1,`supportsFIPS`]},S1]],[`stringEquals`,[{fn:E1,argv:[O1,`name`]},`aws-us-gov`]]],results:[[x1],[x1,`Invalid Configuration: FIPS and custom endpoint are not supported`],[x1,`Invalid Configuration: Dualstack and custom endpoint are not supported`],[D1,k1],[`https://elasticloadbalancing-fips.{Region}.{PartitionResult#dualStackDnsSuffix}`,k1],[x1,`FIPS and DualStack are enabled, but this partition does not support one or both`],[`https://elasticloadbalancing.{Region}.amazonaws.com`,k1],[`https://elasticloadbalancing-fips.{Region}.{PartitionResult#dnsSuffix}`,k1],[x1,`FIPS is enabled but this partition does not support FIPS`],[`https://elasticloadbalancing.{Region}.{PartitionResult#dualStackDnsSuffix}`,k1],[x1,`DualStack is enabled but this partition does not support DualStack`],[`https://elasticloadbalancing.{Region}.{PartitionResult#dnsSuffix}`,k1],[x1,`Invalid Configuration: Missing Region`]]},Lxe=2,M1=1e8,Rxe=new Int32Array([-1,1,-1,0,13,3,1,4,M1+12,2,5,M1+12,3,8,6,4,7,M1+11,5,M1+9,M1+10,4,11,9,6,10,M1+8,7,M1+6,M1+7,5,12,M1+5,6,M1+4,M1+5,3,M1+1,14,4,M1+2,M1+3]),zxe=ak.from(Rxe,Lxe,j1.conditions,j1.results),Bxe=new ok({size:50,params:[`Endpoint`,`Region`,`UseDualStack`,`UseFIPS`]}),Vxe=(e,t={})=>Bxe.get(e,()=>Sk(zxe,{endpointParams:e,logger:t.logger}));lk.aws=Tk;var K=class e extends sA{constructor(t){super(t),Object.setPrototypeOf(this,e.prototype)}},Hxe=class e extends K{name=`CertificateNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`CertificateNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Uxe=class e extends K{name=`ListenerNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`ListenerNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Wxe=class e extends K{name=`TooManyCertificatesException`;$fault=`client`;Message;constructor(t){super({name:`TooManyCertificatesException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Gxe=class e extends K{name=`DuplicateTagKeysException`;$fault=`client`;Message;constructor(t){super({name:`DuplicateTagKeysException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Kxe=class e extends K{name=`LoadBalancerNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`LoadBalancerNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},qxe=class e extends K{name=`RuleNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`RuleNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Jxe=class e extends K{name=`TargetGroupNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`TargetGroupNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Yxe=class e extends K{name=`TooManyTagsException`;$fault=`client`;Message;constructor(t){super({name:`TooManyTagsException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Xxe=class e extends K{name=`TrustStoreNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`TrustStoreNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Zxe=class e extends K{name=`InvalidRevocationContentException`;$fault=`client`;Message;constructor(t){super({name:`InvalidRevocationContentException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Qxe=class e extends K{name=`RevocationContentNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`RevocationContentNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},$xe=class e extends K{name=`TooManyTrustStoreRevocationEntriesException`;$fault=`client`;Message;constructor(t){super({name:`TooManyTrustStoreRevocationEntriesException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},eSe=class e extends K{name=`AllocationIdNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`AllocationIdNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},tSe=class e extends K{name=`ALPNPolicyNotSupportedException`;$fault=`client`;Message;constructor(t){super({name:`ALPNPolicyNotSupportedException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},nSe=class e extends K{name=`AvailabilityZoneNotSupportedException`;$fault=`client`;Message;constructor(t){super({name:`AvailabilityZoneNotSupportedException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},rSe=class e extends K{name=`CaCertificatesBundleNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`CaCertificatesBundleNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},iSe=class e extends K{name=`CapacityDecreaseRequestsLimitExceededException`;$fault=`client`;Message;constructor(t){super({name:`CapacityDecreaseRequestsLimitExceededException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},aSe=class e extends K{name=`CapacityReservationPendingException`;$fault=`client`;Message;constructor(t){super({name:`CapacityReservationPendingException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},oSe=class e extends K{name=`CapacityUnitsLimitExceededException`;$fault=`client`;Message;constructor(t){super({name:`CapacityUnitsLimitExceededException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},sSe=class e extends K{name=`DuplicateListenerException`;$fault=`client`;Message;constructor(t){super({name:`DuplicateListenerException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},cSe=class e extends K{name=`IncompatibleProtocolsException`;$fault=`client`;Message;constructor(t){super({name:`IncompatibleProtocolsException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},lSe=class e extends K{name=`InvalidConfigurationRequestException`;$fault=`client`;Message;constructor(t){super({name:`InvalidConfigurationRequestException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},uSe=class e extends K{name=`InvalidLoadBalancerActionException`;$fault=`client`;Message;constructor(t){super({name:`InvalidLoadBalancerActionException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},dSe=class e extends K{name=`SSLPolicyNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`SSLPolicyNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},fSe=class e extends K{name=`TargetGroupAssociationLimitException`;$fault=`client`;Message;constructor(t){super({name:`TargetGroupAssociationLimitException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},pSe=class e extends K{name=`TooManyActionsException`;$fault=`client`;Message;constructor(t){super({name:`TooManyActionsException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},mSe=class e extends K{name=`TooManyListenersException`;$fault=`client`;Message;constructor(t){super({name:`TooManyListenersException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},hSe=class e extends K{name=`TooManyRegistrationsForTargetIdException`;$fault=`client`;Message;constructor(t){super({name:`TooManyRegistrationsForTargetIdException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},gSe=class e extends K{name=`TooManyTargetsException`;$fault=`client`;Message;constructor(t){super({name:`TooManyTargetsException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},_Se=class e extends K{name=`TooManyUniqueTargetGroupsPerLoadBalancerException`;$fault=`client`;Message;constructor(t){super({name:`TooManyUniqueTargetGroupsPerLoadBalancerException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},vSe=class e extends K{name=`TrustStoreNotReadyException`;$fault=`client`;Message;constructor(t){super({name:`TrustStoreNotReadyException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},ySe=class e extends K{name=`UnsupportedProtocolException`;$fault=`client`;Message;constructor(t){super({name:`UnsupportedProtocolException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},bSe=class e extends K{name=`DuplicateLoadBalancerNameException`;$fault=`client`;Message;constructor(t){super({name:`DuplicateLoadBalancerNameException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},xSe=class e extends K{name=`InvalidSchemeException`;$fault=`client`;Message;constructor(t){super({name:`InvalidSchemeException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},SSe=class e extends K{name=`InvalidSecurityGroupException`;$fault=`client`;Message;constructor(t){super({name:`InvalidSecurityGroupException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},CSe=class e extends K{name=`InvalidSubnetException`;$fault=`client`;Message;constructor(t){super({name:`InvalidSubnetException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},wSe=class e extends K{name=`OperationNotPermittedException`;$fault=`client`;Message;constructor(t){super({name:`OperationNotPermittedException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},TSe=class e extends K{name=`ResourceInUseException`;$fault=`client`;Message;constructor(t){super({name:`ResourceInUseException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},ESe=class e extends K{name=`SubnetNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`SubnetNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},DSe=class e extends K{name=`TooManyLoadBalancersException`;$fault=`client`;Message;constructor(t){super({name:`TooManyLoadBalancersException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},OSe=class e extends K{name=`PriorityInUseException`;$fault=`client`;Message;constructor(t){super({name:`PriorityInUseException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},kSe=class e extends K{name=`TooManyRulesException`;$fault=`client`;Message;constructor(t){super({name:`TooManyRulesException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},ASe=class e extends K{name=`TooManyTargetGroupsException`;$fault=`client`;Message;constructor(t){super({name:`TooManyTargetGroupsException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},jSe=class e extends K{name=`DuplicateTargetGroupNameException`;$fault=`client`;Message;constructor(t){super({name:`DuplicateTargetGroupNameException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},MSe=class e extends K{name=`DuplicateTrustStoreNameException`;$fault=`client`;Message;constructor(t){super({name:`DuplicateTrustStoreNameException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},NSe=class e extends K{name=`InvalidCaCertificatesBundleException`;$fault=`client`;Message;constructor(t){super({name:`InvalidCaCertificatesBundleException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},PSe=class e extends K{name=`TooManyTrustStoresException`;$fault=`client`;Message;constructor(t){super({name:`TooManyTrustStoresException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},FSe=class e extends K{name=`DeleteAssociationSameAccountException`;$fault=`client`;Message;constructor(t){super({name:`DeleteAssociationSameAccountException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},ISe=class e extends K{name=`TrustStoreAssociationNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`TrustStoreAssociationNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},LSe=class e extends K{name=`TrustStoreInUseException`;$fault=`client`;Message;constructor(t){super({name:`TrustStoreInUseException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},RSe=class e extends K{name=`InvalidTargetException`;$fault=`client`;Message;constructor(t){super({name:`InvalidTargetException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},zSe=class e extends K{name=`HealthUnavailableException`;$fault=`server`;Message;constructor(t){super({name:`HealthUnavailableException`,$fault:`server`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},BSe=class e extends K{name=`RevocationIdNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`RevocationIdNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},VSe=class e extends K{name=`ResourceNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`ResourceNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},HSe=class e extends K{name=`InsufficientCapacityException`;$fault=`server`;Message;constructor(t){super({name:`InsufficientCapacityException`,$fault:`server`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},USe=class e extends K{name=`PriorRequestNotCompleteException`;$fault=`client`;Message;constructor(t){super({name:`PriorRequestNotCompleteException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},WSe=`Action`,GSe=`AdditionalClaims`,KSe=`AuthenticateCognitoActionConfig`,qSe=`AuthenticateCognitoConfig`,N1=`AnomalyDetection`,JSe=`AuthorizationEndpoint`,P1=`AllocationId`,YSe=`AllocationIdNotFoundException`,XSe=`ALPNPolicyNotSupportedException`,F1=`AdministrativeOverride`,ZSe=`AuthenticateOidcActionConfig`,QSe=`AuthenticateOidcConfig`,I1=`AlpnPolicy`,L1=`AuthenticationRequestExtraParams`,$Se=`AddTags`,eCe=`AddTagsInput`,tCe=`AddTagsOutput`,nCe=`AdvertiseTrustStoreCaNames`,R1=`AvailabilityZone`,rCe=`AvailabilityZoneNotSupportedException`,z1=`AvailabilityZones`,B1=`Actions`,V1=`Attributes`,H1=`Certificates`,iCe=`CertificateArn`,aCe=`CaCertificatesBundleNotFoundException`,oCe=`CapacityDecreaseRequestsLimitExceededException`,sCe=`CanonicalHostedZoneId`,cCe=`ClientId`,lCe=`CertificateList`,uCe=`CreateLoadBalancer`,dCe=`CreateLoadBalancerInput`,fCe=`CreateLoadBalancerOutput`,pCe=`CreateListenerInput`,mCe=`CreateListenerOutput`,hCe=`CreateListener`,gCe=`CertificateNotFoundException`,U1=`CustomerOwnedIpv4Pool`,_Ce=`CreateRule`,vCe=`CreateRuleInput`,yCe=`CreateRuleOutput`,bCe=`CapacityReservationPendingException`,xCe=`ClientSecret`,SCe=`ContentType`,CCe=`CreateTargetGroup`,wCe=`CreateTargetGroupInput`,TCe=`CreateTargetGroupOutput`,ECe=`CreatedTime`,DCe=`CapacityUnitsLimitExceededException`,OCe=`Certificate`,kCe=`Cipher`,W1=`Ciphers`,ACe=`Code`,G1=`Conditions`,K1=`Description`,q1=`DefaultActions`,jCe=`DeleteAssociationSameAccountException`,MCe=`DeleteListener`,NCe=`DeleteLoadBalancer`,PCe=`DescribeLoadBalancerAttributes`,FCe=`DescribeLoadBalancerAttributesInput`,ICe=`DescribeLoadBalancerAttributesOutput`,LCe=`DeleteLoadBalancerInput`,RCe=`DescribeLoadBalancersInput`,zCe=`DuplicateLoadBalancerNameException`,BCe=`DeleteLoadBalancerOutput`,VCe=`DescribeLoadBalancersOutput`,HCe=`DescribeLoadBalancers`,UCe=`DuplicateListenerException`,WCe=`DeleteListenerInput`,GCe=`DescribeListenersInput`,KCe=`DeleteListenerOutput`,qCe=`DescribeListenersOutput`,JCe=`DescribeListeners`,YCe=`DNSName`,XCe=`DeleteRule`,ZCe=`DeleteRuleInput`,QCe=`DescribeRulesInput`,$Ce=`DeleteRuleOutput`,ewe=`DescribeRulesOutput`,twe=`DescribeRules`,nwe=`DurationSeconds`,rwe=`DescribeSSLPolicies`,iwe=`DescribeSSLPoliciesInput`,awe=`DescribeSSLPoliciesOutput`,owe=`DeregisterTargets`,swe=`DeleteTargetGroup`,cwe=`DescribeTargetGroupAttributes`,lwe=`DescribeTargetGroupAttributesInput`,uwe=`DescribeTargetGroupAttributesOutput`,dwe=`DeleteTargetGroupInput`,fwe=`DescribeTargetGroupsInput`,pwe=`DuplicateTargetGroupNameException`,mwe=`DeleteTargetGroupOutput`,hwe=`DescribeTargetGroupsOutput`,gwe=`DescribeTargetGroups`,_we=`DescribeTargetHealth`,vwe=`DescribeTargetHealthInput`,ywe=`DescribeTargetHealthOutput`,bwe=`DeregisterTargetsInput`,xwe=`DescribeTagsInput`,Swe=`DuplicateTagKeysException`,Cwe=`DeregisterTargetsOutput`,wwe=`DescribeTagsOutput`,Twe=`DuplicateTrustStoreNameException`,Ewe=`DescribeTags`,Dwe=`Enabled`,J1=`EnablePrefixForIpv6SourceNat`,Y1=`EnforceSecurityGroupInboundRulesOnPrivateLinkTraffic`,Owe=`Format`,kwe=`ForwardActionConfig`,Awe=`ForwardConfig`,jwe=`FixedResponseActionConfig`,Mwe=`FixedResponseConfig`,Nwe=`Field`,Pwe=`GrpcCode`,Fwe=`Host`,Iwe=`HttpCode`,X1=`HealthCheckEnabled`,Z1=`HealthCheckIntervalSeconds`,Q1=`HealthCheckProtocol`,$1=`HealthCheckPort`,e0=`HealthCheckPath`,t0=`HealthCheckTimeoutSeconds`,Lwe=`HostHeaderConfig`,Rwe=`HostHeaderConditionConfig`,zwe=`HttpHeaderConditionConfig`,Bwe=`HttpHeaderConfig`,Vwe=`HttpHeaderName`,n0=`HostHeaderRewriteConfig`,Hwe=`HttpRequestMethodConfig`,Uwe=`HttpRequestMethodConditionConfig`,r0=`HealthyThresholdCount`,Wwe=`HealthUnavailableException`,i0=`Issuer`,Gwe=`IpAddress`,a0=`IpAddressType`,Kwe=`InvalidCaCertificatesBundleException`,qwe=`IgnoreClientCertificateExpiry`,Jwe=`InsufficientCapacityException`,Ywe=`InvalidConfigurationRequestException`,o0=`IsDefault`,Xwe=`Ipv4IpamPoolId`,Zwe=`InvalidLoadBalancerActionException`,s0=`IpamPools`,c0=`IPv6Address`,Qwe=`IncompatibleProtocolsException`,$we=`InvalidRevocationContentException`,eTe=`InvalidSchemeException`,tTe=`InvalidSubnetException`,nTe=`InvalidSecurityGroupException`,rTe=`InvalidTargetException`,iTe=`Id`,aTe=`Include`,oTe=`JwksEndpoint`,sTe=`JwtValidationActionAdditionalClaim`,cTe=`JwtValidationActionAdditionalClaims`,lTe=`JwtValidationActionConfig`,uTe=`JwtValidationConfig`,l0=`Key`,u0=`Listeners`,d0=`ListenerArn`,dTe=`ListenerArns`,f0=`LoadBalancers`,p0=`LoadBalancerAddresses`,m0=`LoadBalancerArn`,h0=`LoadBalancerArns`,fTe=`LoadBalancerAddress`,pTe=`LoadBalancerAttribute`,mTe=`LoadBalancerAttributes`,hTe=`LoadBalancerName`,gTe=`LoadBalancerNotFoundException`,_Te=`LoadBalancerState`,vTe=`LoadBalancerType`,yTe=`LoadBalancer`,bTe=`ListenerNotFoundException`,xTe=`Listener`,g0=`Message`,_0=`MutualAuthentication`,STe=`MutualAuthenticationAttributes`,CTe=`MessageBody`,wTe=`MitigationInEffect`,TTe=`ModifyListener`,ETe=`ModifyLoadBalancerAttributes`,DTe=`ModifyLoadBalancerAttributesInput`,OTe=`ModifyLoadBalancerAttributesOutput`,kTe=`ModifyListenerInput`,ATe=`ModifyListenerOutput`,jTe=`ModifyRule`,MTe=`ModifyRuleInput`,NTe=`ModifyRuleOutput`,PTe=`ModifyTargetGroupAttributes`,FTe=`ModifyTargetGroupAttributesInput`,ITe=`ModifyTargetGroupAttributesOutput`,v0=`Matcher`,y0=`Marker`,LTe=`Mode`,b0=`Name`,x0=`NextMarker`,S0=`Names`,RTe=`Order`,zTe=`OutpostId`,BTe=`OperationNotPermittedException`,C0=`OnUnauthenticatedRequest`,w0=`Priority`,T0=`PrivateIPv4Address`,VTe=`PriorityInUseException`,HTe=`PathPatternConfig`,UTe=`PathPatternConditionConfig`,WTe=`PriorRequestNotCompleteException`,E0=`PageSize`,D0=`ProtocolVersion`,GTe=`Path`,O0=`Port`,k0=`Protocol`,KTe=`Query`,qTe=`QueryStringConfig`,JTe=`QueryStringConditionConfig`,YTe=`QuicServerId`,XTe=`QueryStringKeyValuePair`,ZTe=`QueryStringKeyValuePairList`,A0=`Reason`,j0=`ResourceArns`,QTe=`RedirectActionConfig`,$Te=`ResourceArn`,M0=`RuleArn`,eEe=`RuleArns`,tEe=`RedirectConfig`,nEe=`RewriteConfigList`,rEe=`RuleConditionList`,iEe=`RevocationContentNotFoundException`,aEe=`RewriteConfig`,oEe=`RuleCondition`,sEe=`RevocationIdNotFoundException`,cEe=`ResourceInUseException`,lEe=`ResourceNotFoundException`,uEe=`RuleNotFoundException`,dEe=`RegisterTargetsInput`,fEe=`RemoveTagsInput`,pEe=`RuleTransformList`,mEe=`RegisterTargetsOutput`,hEe=`RemoveTagsOutput`,gEe=`ResetTransforms`,_Ee=`RegisterTargets`,vEe=`RemoveTags`,yEe=`RuleTransform`,N0=`RegexValues`,bEe=`Result`,xEe=`Regex`,SEe=`Replace`,P0=`Rewrites`,F0=`Rules`,CEe=`Rule`,I0=`State`,L0=`StatusCode`,R0=`SessionCookieName`,z0=`SecurityGroups`,wEe=`SecurityGroupIds`,B0=`SubnetId`,TEe=`SourceIpConfig`,EEe=`SourceIpConditionConfig`,DEe=`SupportedLoadBalancerTypes`,V0=`SubnetMappings`,OEe=`SubnetMapping`,kEe=`SubnetNotFoundException`,AEe=`SourceNatIpv6Prefixes`,jEe=`SourceNatIpv6Prefix`,H0=`SslPolicy`,U0=`SslPolicies`,MEe=`SslProtocols`,NEe=`SetSecurityGroups`,PEe=`SetSecurityGroupsInput`,FEe=`SetSecurityGroupsOutput`,IEe=`SSLPolicyNotFoundException`,W0=`SessionTimeout`,G0=`Scope`,K0=`Scheme`,LEe=`Subnets`,q0=`Type`,J0=`TargetControlPort`,Y0=`TagDescriptions`,REe=`TagDescription`,zEe=`TargetDescription`,BEe=`TargetDescriptions`,VEe=`TokenEndpoint`,X0=`TargetGroups`,Z0=`TargetGroupArn`,HEe=`TargetGroupAssociationLimitException`,UEe=`TargetGroupArns`,WEe=`TargetGroupAttribute`,GEe=`TargetGroupAttributes`,KEe=`TargetGroupList`,qEe=`TargetGroupName`,JEe=`TargetGroupNotFoundException`,Q0=`TargetGroupStickinessConfig`,YEe=`TargetGroupTuple`,XEe=`TargetGroup`,$0=`TargetHealth`,e2=`TargetHealthDescriptions`,ZEe=`TargetHealthDescription`,QEe=`TagKeys`,$Ee=`TagList`,eDe=`TooManyActionsException`,tDe=`TooManyCertificatesException`,nDe=`TooManyLoadBalancersException`,rDe=`TooManyListenersException`,iDe=`TooManyRulesException`,aDe=`TooManyRegistrationsForTargetIdException`,oDe=`TooManyTagsException`,sDe=`TooManyTargetsException`,cDe=`TooManyTargetGroupsException`,lDe=`TooManyTrustStoresException`,uDe=`TooManyTrustStoreRevocationEntriesException`,dDe=`TooManyUniqueTargetGroupsPerLoadBalancerException`,fDe=`TrustStoreArn`,pDe=`TrustStoreAssociationNotFoundException`,mDe=`TrustStoreAssociationStatus`,hDe=`TrustStoreInUseException`,gDe=`TrustStoreNotFoundException`,_De=`TrustStoreNotReadyException`,t2=`TargetType`,n2=`Tags`,vDe=`Tag`,r2=`Targets`,yDe=`Target`,i2=`Transforms`,bDe=`UseExistingClientSecret`,xDe=`UserInfoEndpoint`,SDe=`UserPoolArn`,CDe=`UserPoolClientId`,wDe=`UserPoolDomain`,TDe=`UnsupportedProtocolException`,a2=`UrlRewriteConfig`,o2=`UnhealthyThresholdCount`,s2=`Values`,c2=`VpcId`,l2=`Value`,EDe=`Weight`,DDe=`ZoneName`,u2=`awsQueryError`,d2=`client`,f2=`error`,q=`httpError`,p2=`smithy.ts.sdk.synthetic.com.amazonaws.elasticloadbalancingv2`,m2=`server`,J=`com.amazonaws.elasticloadbalancingv2`,h2=OO.for(p2),ODe=[-3,p2,`ElasticLoadBalancingV2ServiceException`,0,[],[]];h2.registerError(ODe,K);var Y=OO.for(J),kDe=[-3,J,YSe,{[u2]:[`AllocationIdNotFound`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(kDe,eSe);var ADe=[-3,J,XSe,{[u2]:[`ALPNPolicyNotFound`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(ADe,tSe);var jDe=[-3,J,rCe,{[u2]:[`AvailabilityZoneNotSupported`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(jDe,nSe);var MDe=[-3,J,aCe,{[u2]:[`CaCertificatesBundleNotFound`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(MDe,rSe);var NDe=[-3,J,oCe,{[u2]:[`CapacityDecreaseRequestLimitExceeded`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(NDe,iSe);var PDe=[-3,J,bCe,{[u2]:[`CapacityReservationPending`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(PDe,aSe);var FDe=[-3,J,DCe,{[u2]:[`CapacityUnitsLimitExceeded`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(FDe,oSe);var IDe=[-3,J,gCe,{[u2]:[`CertificateNotFound`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(IDe,Hxe);var LDe=[-3,J,jCe,{[u2]:[`DeleteAssociationSameAccount`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(LDe,FSe);var RDe=[-3,J,UCe,{[u2]:[`DuplicateListener`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(RDe,sSe);var zDe=[-3,J,zCe,{[u2]:[`DuplicateLoadBalancerName`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(zDe,bSe);var BDe=[-3,J,Swe,{[u2]:[`DuplicateTagKeys`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(BDe,Gxe);var VDe=[-3,J,pwe,{[u2]:[`DuplicateTargetGroupName`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(VDe,jSe);var HDe=[-3,J,Twe,{[u2]:[`DuplicateTrustStoreName`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(HDe,MSe);var UDe=[-3,J,Wwe,{[u2]:[`HealthUnavailable`,500],[f2]:m2,[q]:500},[g0],[0]];Y.registerError(UDe,zSe);var WDe=[-3,J,Qwe,{[u2]:[`IncompatibleProtocols`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(WDe,cSe);var GDe=[-3,J,Jwe,{[u2]:[`InsufficientCapacity`,500],[f2]:m2,[q]:500},[g0],[0]];Y.registerError(GDe,HSe);var KDe=[-3,J,Kwe,{[u2]:[`InvalidCaCertificatesBundle`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(KDe,NSe);var qDe=[-3,J,Ywe,{[u2]:[`InvalidConfigurationRequest`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(qDe,lSe);var JDe=[-3,J,Zwe,{[u2]:[`InvalidLoadBalancerAction`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(JDe,uSe);var YDe=[-3,J,$we,{[u2]:[`InvalidRevocationContent`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(YDe,Zxe);var XDe=[-3,J,eTe,{[u2]:[`InvalidScheme`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(XDe,xSe);var ZDe=[-3,J,nTe,{[u2]:[`InvalidSecurityGroup`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(ZDe,SSe);var QDe=[-3,J,tTe,{[u2]:[`InvalidSubnet`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(QDe,CSe);var $De=[-3,J,rTe,{[u2]:[`InvalidTarget`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError($De,RSe);var eOe=[-3,J,bTe,{[u2]:[`ListenerNotFound`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(eOe,Uxe);var tOe=[-3,J,gTe,{[u2]:[`LoadBalancerNotFound`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(tOe,Kxe);var nOe=[-3,J,BTe,{[u2]:[`OperationNotPermitted`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(nOe,wSe);var rOe=[-3,J,VTe,{[u2]:[`PriorityInUse`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(rOe,OSe);var iOe=[-3,J,WTe,{[u2]:[`PriorRequestNotComplete`,429],[f2]:d2,[q]:429},[g0],[0]];Y.registerError(iOe,USe);var aOe=[-3,J,cEe,{[u2]:[`ResourceInUse`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(aOe,TSe);var oOe=[-3,J,lEe,{[u2]:[`ResourceNotFound`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(oOe,VSe);var sOe=[-3,J,iEe,{[u2]:[`RevocationContentNotFound`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(sOe,Qxe);var cOe=[-3,J,sEe,{[u2]:[`RevocationIdNotFound`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(cOe,BSe);var lOe=[-3,J,uEe,{[u2]:[`RuleNotFound`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(lOe,qxe);var uOe=[-3,J,IEe,{[u2]:[`SSLPolicyNotFound`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(uOe,dSe);var dOe=[-3,J,kEe,{[u2]:[`SubnetNotFound`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(dOe,ESe);var fOe=[-3,J,HEe,{[u2]:[`TargetGroupAssociationLimit`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(fOe,fSe);var pOe=[-3,J,JEe,{[u2]:[`TargetGroupNotFound`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(pOe,Jxe);var mOe=[-3,J,eDe,{[u2]:[`TooManyActions`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(mOe,pSe);var hOe=[-3,J,tDe,{[u2]:[`TooManyCertificates`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(hOe,Wxe);var gOe=[-3,J,rDe,{[u2]:[`TooManyListeners`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(gOe,mSe);var _Oe=[-3,J,nDe,{[u2]:[`TooManyLoadBalancers`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(_Oe,DSe);var vOe=[-3,J,aDe,{[u2]:[`TooManyRegistrationsForTargetId`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(vOe,hSe);var yOe=[-3,J,iDe,{[u2]:[`TooManyRules`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(yOe,kSe);var bOe=[-3,J,oDe,{[u2]:[`TooManyTags`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(bOe,Yxe);var xOe=[-3,J,cDe,{[u2]:[`TooManyTargetGroups`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(xOe,ASe);var SOe=[-3,J,sDe,{[u2]:[`TooManyTargets`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(SOe,gSe);var COe=[-3,J,uDe,{[u2]:[`TooManyTrustStoreRevocationEntries`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(COe,$xe);var wOe=[-3,J,lDe,{[u2]:[`TooManyTrustStores`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(wOe,PSe);var TOe=[-3,J,dDe,{[u2]:[`TooManyUniqueTargetGroupsPerLoadBalancer`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(TOe,_Se);var EOe=[-3,J,pDe,{[u2]:[`AssociationNotFound`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(EOe,ISe);var DOe=[-3,J,hDe,{[u2]:[`TrustStoreInUse`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(DOe,LSe);var OOe=[-3,J,gDe,{[u2]:[`TrustStoreNotFound`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(OOe,Xxe);var kOe=[-3,J,_De,{[u2]:[`TrustStoreNotReady`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(kOe,vSe);var AOe=[-3,J,TDe,{[u2]:[`UnsupportedProtocol`,400],[f2]:d2,[q]:400},[g0],[0]];Y.registerError(AOe,ySe);var jOe=[h2,Y],MOe=[3,J,WSe,0,[q0,Z0,QSe,qSe,RTe,tEe,Mwe,Awe,uTe],[0,0,()=>ROe,()=>LOe,1,()=>Jke,()=>wke,()=>Tke,()=>jke],1],NOe=[3,J,eCe,0,[j0,n2],[64,()=>k2],2],POe=[3,J,tCe,0,[],[]],FOe=[3,J,F1,0,[I0,A0,K1],[0,0,0]],IOe=[3,J,N1,0,[bEe,wTe],[0,0]],LOe=[3,J,KSe,0,[SDe,CDe,wDe,R0,G0,W0,L1,C0],[0,0,0,0,0,1,128,0],3],ROe=[3,J,ZSe,0,[i0,JSe,VEe,xDe,cCe,xCe,R0,G0,W0,L1,C0,bDe],[0,0,0,0,0,0,0,0,1,128,0,2],5],zOe=[3,J,R1,0,[DDe,B0,zTe,p0,AEe],[0,0,0,()=>bAe,64]],BOe=[3,J,OCe,0,[iCe,o0],[0,2]],VOe=[3,J,kCe,0,[b0,w0],[0,1]],HOe=[3,J,pCe,0,[m0,q1,k0,O0,H0,H1,I1,n2,_0],[0,()=>b2,0,1,0,()=>x2,64,()=>k2,()=>v2],2],UOe=[3,J,mCe,0,[u0],[()=>S2]],WOe=[3,J,dCe,0,[b0,LEe,V0,z0,K0,n2,q0,a0,U1,J1,s0],[0,64,()=>CAe,64,0,()=>k2,0,0,0,0,()=>g2],1],GOe=[3,J,fCe,0,[f0],[()=>w2]],KOe=[3,J,vCe,0,[d0,G1,w0,B1,n2,i2],[0,()=>E2,1,()=>b2,()=>k2,()=>O2],4],qOe=[3,J,yCe,0,[F0],[()=>D2]],JOe=[3,J,wCe,0,[b0,k0,D0,O0,c2,Q1,$1,X1,e0,Z1,t0,r0,o2,v0,t2,n2,a0,J0],[0,0,0,1,0,0,0,2,0,1,1,1,1,()=>_2,0,()=>k2,0,1],1],YOe=[3,J,TCe,0,[X0],[()=>M2]],XOe=[3,J,WCe,0,[d0],[0],1],ZOe=[3,J,KCe,0,[],[]],QOe=[3,J,LCe,0,[m0],[0],1],$Oe=[3,J,BCe,0,[],[]],eke=[3,J,ZCe,0,[M0],[0],1],tke=[3,J,$Ce,0,[],[]],nke=[3,J,dwe,0,[Z0],[0],1],rke=[3,J,mwe,0,[],[]],ike=[3,J,bwe,0,[Z0,r2],[0,()=>A2],2],ake=[3,J,Cwe,0,[],[]],oke=[3,J,GCe,0,[m0,dTe,y0,E0],[0,64,0,1]],ske=[3,J,qCe,0,[u0,x0],[()=>S2,0]],cke=[3,J,FCe,0,[m0],[0],1],lke=[3,J,ICe,0,[V1],[()=>C2]],uke=[3,J,RCe,0,[h0,S0,y0,E0],[64,64,0,1]],dke=[3,J,VCe,0,[f0,x0],[()=>w2,0]],fke=[3,J,QCe,0,[d0,eEe,y0,E0],[0,64,0,1]],pke=[3,J,ewe,0,[F0,x0],[()=>D2,0]],mke=[3,J,iwe,0,[S0,y0,E0,vTe],[64,0,1,0]],hke=[3,J,awe,0,[U0,x0],[()=>SAe,0]],gke=[3,J,xwe,0,[j0],[64],1],_ke=[3,J,wwe,0,[Y0],[()=>wAe]],vke=[3,J,lwe,0,[Z0],[0],1],yke=[3,J,uwe,0,[V1],[()=>j2]],bke=[3,J,fwe,0,[m0,UEe,S0,y0,E0],[0,64,64,0,1]],xke=[3,J,hwe,0,[X0,x0],[()=>M2,0]],Ske=[3,J,vwe,0,[Z0,r2,aTe],[0,()=>A2,64],1],Cke=[3,J,ywe,0,[e2],[()=>EAe]],wke=[3,J,jwe,0,[L0,CTe,SCe],[0,0,0],1],Tke=[3,J,kwe,0,[X0,Q0],[()=>TAe,()=>fAe]],Eke=[3,J,Rwe,0,[s2,N0],[64,64]],Dke=[3,J,n0,0,[P0],[()=>T2]],Oke=[3,J,zwe,0,[Vwe,s2,N0],[0,64,64]],kke=[3,J,Uwe,0,[s2],[64]],g2=[3,J,s0,0,[Xwe],[0]],Ake=[3,J,sTe,0,[Owe,b0,s2],[0,0,64],3],jke=[3,J,lTe,0,[oTe,i0,GSe],[0,0,()=>yAe],2],Mke=[3,J,xTe,0,[d0,m0,O0,k0,H1,H0,q1,I1,_0],[0,0,1,0,()=>x2,0,()=>b2,64,()=>v2]],Nke=[3,J,yTe,0,[m0,YCe,sCe,ECe,hTe,K0,c2,I0,q0,z1,z0,a0,U1,Y1,J1,s0],[0,0,0,4,0,0,0,()=>Ike,0,()=>_Ae,64,0,0,0,0,()=>g2]],Pke=[3,J,fTe,0,[Gwe,P1,T0,c0],[0,0,0,0]],Fke=[3,J,pTe,0,[l0,l2],[0,0]],Ike=[3,J,_Te,0,[ACe,A0],[0,0]],_2=[3,J,v0,0,[Iwe,Pwe],[0,0]],Lke=[3,J,kTe,0,[d0,O0,k0,H0,H1,q1,I1,_0],[0,1,0,0,()=>x2,()=>b2,64,()=>v2],1],Rke=[3,J,ATe,0,[u0],[()=>S2]],zke=[3,J,DTe,0,[m0,V1],[0,()=>C2],2],Bke=[3,J,OTe,0,[V1],[()=>C2]],Vke=[3,J,MTe,0,[M0,G1,B1,i2,gEe],[0,()=>E2,()=>b2,()=>O2,2],1],Hke=[3,J,NTe,0,[F0],[()=>D2]],Uke=[3,J,FTe,0,[Z0,V1],[0,()=>j2],2],Wke=[3,J,ITe,0,[V1],[()=>j2]],v2=[3,J,STe,0,[LTe,fDe,qwe,mDe,nCe],[0,0,2,0,0]],Gke=[3,J,UTe,0,[s2,N0],[64,64]],Kke=[3,J,JTe,0,[s2],[()=>xAe]],qke=[3,J,XTe,0,[l0,l2],[0,0]],Jke=[3,J,QTe,0,[L0,k0,O0,Fwe,GTe,KTe],[0,0,0,0,0,0],1],Yke=[3,J,dEe,0,[Z0,r2],[0,()=>A2],2],Xke=[3,J,mEe,0,[],[]],Zke=[3,J,fEe,0,[j0,QEe],[64,64],2],Qke=[3,J,hEe,0,[],[]],$ke=[3,J,aEe,0,[xEe,SEe],[0,0],2],eAe=[3,J,CEe,0,[M0,w0,G1,B1,o0,i2],[0,0,()=>E2,()=>b2,2,()=>O2]],tAe=[3,J,oEe,0,[Nwe,s2,Lwe,HTe,Bwe,qTe,Hwe,TEe,N0],[0,64,()=>Eke,()=>Gke,()=>Oke,()=>Kke,()=>kke,()=>aAe,64]],nAe=[3,J,yEe,0,[q0,n0,a2],[0,()=>Dke,()=>gAe],1],rAe=[3,J,PEe,0,[m0,z0,Y1],[0,64,0],2],iAe=[3,J,FEe,0,[wEe,Y1],[64,0]],aAe=[3,J,EEe,0,[s2],[64]],oAe=[3,J,H0,0,[MEe,W1,b0,DEe],[64,()=>vAe,0,64]],sAe=[3,J,OEe,0,[B0,P1,T0,c0,jEe],[0,0,0,0,0]],cAe=[3,J,vDe,0,[l0,l2],[0,0],1],lAe=[3,J,REe,0,[$Te,n2],[0,()=>k2]],y2=[3,J,zEe,0,[iTe,O0,R1,YTe],[0,1,0,0],1],uAe=[3,J,XEe,0,[Z0,qEe,k0,O0,c2,Q1,$1,X1,Z1,t0,r0,o2,e0,v0,h0,t2,D0,a0,J0],[0,0,0,1,0,0,0,2,1,1,1,1,0,()=>_2,64,0,0,0,1]],dAe=[3,J,WEe,0,[l0,l2],[0,0]],fAe=[3,J,Q0,0,[Dwe,nwe],[2,1]],pAe=[3,J,YEe,0,[Z0,EDe],[0,1]],mAe=[3,J,$0,0,[I0,A0,K1],[0,0,0]],hAe=[3,J,ZEe,0,[yDe,$1,$0,N1,F1],[()=>y2,0,()=>mAe,()=>IOe,()=>FOe]],gAe=[3,J,a2,0,[P0],[()=>T2]],b2=[1,J,B1,0,()=>MOe],_Ae=[1,J,z1,0,()=>zOe],x2=[1,J,lCe,0,()=>BOe],vAe=[1,J,W1,0,()=>VOe],yAe=[1,J,cTe,0,()=>Ake],S2=[1,J,u0,0,()=>Mke],bAe=[1,J,p0,0,()=>Pke],C2=[1,J,mTe,0,()=>Fke],w2=[1,J,f0,0,()=>Nke],xAe=[1,J,ZTe,0,()=>qke],T2=[1,J,nEe,0,()=>$ke],E2=[1,J,rEe,0,()=>tAe],D2=[1,J,F0,0,()=>eAe],O2=[1,J,pEe,0,()=>nAe],SAe=[1,J,U0,0,()=>oAe],CAe=[1,J,V0,0,()=>sAe],wAe=[1,J,Y0,0,()=>lAe],k2=[1,J,$Ee,0,()=>cAe],A2=[1,J,BEe,0,()=>y2],j2=[1,J,GEe,0,()=>dAe],TAe=[1,J,KEe,0,()=>pAe],M2=[1,J,X0,0,()=>uAe],EAe=[1,J,e2,0,()=>hAe],DAe=[9,J,$Se,0,()=>NOe,()=>POe],OAe=[9,J,hCe,0,()=>HOe,()=>UOe],kAe=[9,J,uCe,0,()=>WOe,()=>GOe],AAe=[9,J,_Ce,0,()=>KOe,()=>qOe],jAe=[9,J,CCe,0,()=>JOe,()=>YOe],MAe=[9,J,MCe,0,()=>XOe,()=>ZOe],NAe=[9,J,NCe,0,()=>QOe,()=>$Oe],PAe=[9,J,XCe,0,()=>eke,()=>tke],FAe=[9,J,swe,0,()=>nke,()=>rke],IAe=[9,J,owe,0,()=>ike,()=>ake],LAe=[9,J,JCe,0,()=>oke,()=>ske],RAe=[9,J,PCe,0,()=>cke,()=>lke],zAe=[9,J,HCe,0,()=>uke,()=>dke],BAe=[9,J,twe,0,()=>fke,()=>pke],VAe=[9,J,rwe,0,()=>mke,()=>hke],HAe=[9,J,Ewe,0,()=>gke,()=>_ke],UAe=[9,J,cwe,0,()=>vke,()=>yke],WAe=[9,J,gwe,0,()=>bke,()=>xke],GAe=[9,J,_we,0,()=>Ske,()=>Cke],KAe=[9,J,TTe,0,()=>Lke,()=>Rke],qAe=[9,J,ETe,0,()=>zke,()=>Bke],JAe=[9,J,jTe,0,()=>Vke,()=>Hke],YAe=[9,J,PTe,0,()=>Uke,()=>Wke],XAe=[9,J,_Ee,0,()=>Yke,()=>Xke],ZAe=[9,J,vEe,0,()=>Zke,()=>Qke],QAe=[9,J,NEe,0,()=>rAe,()=>iAe],$Ae=e=>({apiVersion:`2015-12-01`,base64Decoder:e?.base64Decoder??eO,base64Encoder:e?.base64Encoder??tO,disableHostPrefix:e?.disableHostPrefix??!1,endpointProvider:e?.endpointProvider??Vxe,extensions:e?.extensions??[],httpAuthSchemeProvider:e?.httpAuthSchemeProvider??Nxe,httpAuthSchemes:e?.httpAuthSchemes??[{schemeId:`aws.auth#sigv4`,identityProvider:e=>e.getIdentityProvider(`aws.auth#sigv4`),signer:new SA}],logger:e?.logger??new mA,protocol:e?.protocol??LA,protocolSettings:e?.protocolSettings??{defaultNamespace:`com.amazonaws.elasticloadbalancingv2`,errorTypeRegistries:jOe,xmlNamespace:`http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/`,version:`2015-12-01`,serviceTarget:`ElasticLoadBalancing_v10`},serviceId:e?.serviceId??`Elastic Load Balancing v2`,urlParser:e?.urlParser??vO,utf8Decoder:e?.utf8Decoder??Wb,utf8Encoder:e?.utf8Encoder??Kb}),eje=e=>{let t=AA(e),n=()=>t().then(lA),r=$Ae(e);return{...r,...e,runtime:`browser`,defaultsMode:t,bodyLengthChecker:e?.bodyLengthChecker??kA,credentialDefaultProvider:e?.credentialDefaultProvider??(e=>()=>Promise.reject(Error(`Credential is missing`))),defaultUserAgentProvider:e?.defaultUserAgentProvider??TA({serviceId:r.serviceId,clientVersion:Ixe.version}),maxAttempts:e?.maxAttempts??3,region:e?.region??DA(`Region is missing`),requestHandler:sO.create(e?.requestHandler??n),retryMode:e?.retryMode??(async()=>(await n()).retryMode||Dk),sha256:e?.sha256??Nb,streamCollector:e?.streamCollector??lO,useDualstackEndpoint:e?.useDualstackEndpoint??(()=>Promise.resolve(!1)),useFipsEndpoint:e?.useFipsEndpoint??(()=>Promise.resolve(!1))}},tje=e=>{let t=e.httpAuthSchemes,n=e.httpAuthSchemeProvider,r=e.credentials;return{setHttpAuthScheme(e){let n=t.findIndex(t=>t.schemeId===e.schemeId);n===-1?t.push(e):t.splice(n,1,e)},httpAuthSchemes(){return t},setHttpAuthSchemeProvider(e){n=e},httpAuthSchemeProvider(){return n},setCredentials(e){r=e},credentials(){return r}}},nje=e=>({httpAuthSchemes:e.httpAuthSchemes(),httpAuthSchemeProvider:e.httpAuthSchemeProvider(),credentials:e.credentials()}),rje=(e,t)=>{let n=Object.assign(c1(e),dA(e),Pb(e),tje(e));return t.forEach(e=>e.configure(n)),Object.assign(e,l1(n),fA(n),Fb(n),nje(n))},ije=class extends rA{config;constructor(...[e]){let t=eje(e||{});super(t),this.initConfig=t;let n=rje(Pxe(Xk(AD(Hk(Zk(ik(Fxe(t))))))),e?.extensions||[]);this.config=n,this.middlewareStack.use(yO(this.config)),this.middlewareStack.use(zk(this.config)),this.middlewareStack.use(gA(this.config)),this.middlewareStack.use(Wk(this.config)),this.middlewareStack.use(ND(this.config)),this.middlewareStack.use(ID(this.config)),this.middlewareStack.use(zD(this.config)),this.middlewareStack.use(WD(this.config,{httpAuthSchemeParametersProvider:jxe,identityProviderConfigProvider:async e=>new nk({"aws.auth#sigv4":e.credentials})})),this.middlewareStack.use(YD(this.config))}destroy(){super.destroy()}},aje=class extends oA.classBuilder().ep(y1).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeListeners`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeListenersCommand`).sc(LAe).build(){},oje=class extends oA.classBuilder().ep(y1).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeLoadBalancerAttributes`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeLoadBalancerAttributesCommand`).sc(RAe).build(){},N2=class extends oA.classBuilder().ep(y1).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeLoadBalancers`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeLoadBalancersCommand`).sc(zAe).build(){},sje=class extends oA.classBuilder().ep(y1).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeRules`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeRulesCommand`).sc(BAe).build(){},cje=class extends oA.classBuilder().ep(y1).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeSSLPolicies`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeSSLPoliciesCommand`).sc(VAe).build(){},lje=class extends oA.classBuilder().ep(y1).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeTags`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeTagsCommand`).sc(HAe).build(){},uje=class extends oA.classBuilder().ep(y1).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeTargetGroupAttributes`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeTargetGroupAttributesCommand`).sc(UAe).build(){},P2=class extends oA.classBuilder().ep(y1).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeTargetGroups`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeTargetGroupsCommand`).sc(WAe).build(){},dje=class extends oA.classBuilder().ep(y1).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`ElasticLoadBalancing_v10`,`DescribeTargetHealth`,{}).n(`ElasticLoadBalancingV2Client`,`DescribeTargetHealthCommand`).sc(GAe).build(){},fje=async(e,t,n)=>({operation:lx(t).operation,region:await ux(e.region)()||(()=>{throw Error("expected `region` to be configured for `aws.auth#sigv4`")})()});function pje(e){return{schemeId:`aws.auth#sigv4`,signingProperties:{name:`iam`,region:e.region},propertiesExtractor:(e,t)=>({signingProperties:{config:e,context:t}})}}var mje=e=>{let t=[];switch(e.operation){default:t.push(pje(e))}return t},hje=e=>{let t=CA(e);return Object.assign(t,{authSchemePreference:ux(e.authSchemePreference??[])})},gje=e=>Object.assign(e,{useDualstackEndpoint:e.useDualstackEndpoint??!1,useFipsEndpoint:e.useFipsEndpoint??!1,defaultSigningName:`iam`}),F2={UseFIPS:{type:`builtInParams`,name:`useFipsEndpoint`},Endpoint:{type:`builtInParams`,name:`endpoint`},Region:{type:`builtInParams`,name:`region`},UseDualStack:{type:`builtInParams`,name:`useDualstackEndpoint`}},_je={name:`@aws-sdk/client-iam`,description:`AWS SDK for JavaScript Iam Client for Node.js, Browser and React Native`,version:`3.1045.0`,scripts:{build:`concurrently 'yarn:build:types' 'yarn:build:es' && yarn build:cjs`,"build:cjs":`node ../../scripts/compilation/inline client-iam`,"build:es":`tsc -p tsconfig.es.json`,"build:include:deps":`yarn g:turbo run build -F="$npm_package_name"`,"build:types":`tsc -p tsconfig.types.json`,"build:types:downlevel":`downlevel-dts dist-types dist-types/ts3.4`,clean:`premove dist-cjs dist-es dist-types tsconfig.cjs.tsbuildinfo tsconfig.es.tsbuildinfo tsconfig.types.tsbuildinfo`,"extract:docs":`api-extractor run --local`,"generate:client":`node ../../scripts/generate-clients/single-service --solo iam`,test:`yarn g:vitest run --passWithNoTests`,"test:e2e":`yarn g:vitest run -c vitest.config.e2e.mts --mode development`,"test:e2e:watch":`yarn g:vitest watch -c vitest.config.e2e.mts`,"test:index":`tsc --noEmit ./test/index-types.ts && node ./test/index-objects.spec.mjs`,"test:integration":`yarn g:vitest run --passWithNoTests -c vitest.config.integ.mts`,"test:integration:watch":`yarn g:vitest run --passWithNoTests -c vitest.config.integ.mts`,"test:watch":`yarn g:vitest watch --passWithNoTests`},main:`./dist-cjs/index.js`,types:`./dist-types/index.d.ts`,module:`./dist-es/index.js`,sideEffects:!1,dependencies:{"@aws-crypto/sha256-browser":`5.2.0`,"@aws-crypto/sha256-js":`5.2.0`,"@aws-sdk/core":`^3.974.8`,"@aws-sdk/credential-provider-node":`^3.972.39`,"@aws-sdk/middleware-host-header":`^3.972.10`,"@aws-sdk/middleware-logger":`^3.972.10`,"@aws-sdk/middleware-recursion-detection":`^3.972.11`,"@aws-sdk/middleware-user-agent":`^3.972.38`,"@aws-sdk/region-config-resolver":`^3.972.13`,"@aws-sdk/types":`^3.973.8`,"@aws-sdk/util-endpoints":`^3.996.8`,"@aws-sdk/util-user-agent-browser":`^3.972.10`,"@aws-sdk/util-user-agent-node":`^3.973.24`,"@smithy/config-resolver":`^4.4.17`,"@smithy/core":`^3.23.17`,"@smithy/fetch-http-handler":`^5.3.17`,"@smithy/hash-node":`^4.2.14`,"@smithy/invalid-dependency":`^4.2.14`,"@smithy/middleware-content-length":`^4.2.14`,"@smithy/middleware-endpoint":`^4.4.32`,"@smithy/middleware-retry":`^4.5.7`,"@smithy/middleware-serde":`^4.2.20`,"@smithy/middleware-stack":`^4.2.14`,"@smithy/node-config-provider":`^4.3.14`,"@smithy/node-http-handler":`^4.6.1`,"@smithy/protocol-http":`^5.3.14`,"@smithy/smithy-client":`^4.12.13`,"@smithy/types":`^4.14.1`,"@smithy/url-parser":`^4.2.14`,"@smithy/util-base64":`^4.3.2`,"@smithy/util-body-length-browser":`^4.2.2`,"@smithy/util-body-length-node":`^4.2.3`,"@smithy/util-defaults-mode-browser":`^4.3.49`,"@smithy/util-defaults-mode-node":`^4.2.54`,"@smithy/util-endpoints":`^3.4.2`,"@smithy/util-middleware":`^4.2.14`,"@smithy/util-retry":`^4.3.6`,"@smithy/util-utf8":`^4.2.2`,"@smithy/util-waiter":`^4.3.0`,tslib:`^2.6.2`},devDependencies:{"@smithy/snapshot-testing":`^2.0.8`,"@tsconfig/node20":`20.1.8`,"@types/node":`^20.14.8`,concurrently:`7.0.0`,"downlevel-dts":`0.10.1`,premove:`4.0.0`,typescript:`~5.8.3`,vitest:`^4.0.17`},engines:{node:`>=20.0.0`},typesVersions:{"<4.5":{"dist-types/*":[`dist-types/ts3.4/*`]}},files:[`dist-*/**`],author:{name:`AWS SDK for JavaScript Team`,url:`https://aws.amazon.com/javascript/`},license:`Apache-2.0`,browser:{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.browser`},"react-native":{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.native`},homepage:`https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-iam`,repository:{type:`git`,url:`https://github.com/aws/aws-sdk-js-v3.git`,directory:`clients/client-iam`}},I2=`ref`,L2=`authSchemes`,R2=`name`,z2=`signingRegion`,B2=-1,V2=!0,H2=`isSet`,U2=`PartitionResult`,W2=`booleanEquals`,G2=`stringEquals`,K2=`getAttr`,q2=`sigv4`,J2={[I2]:`Endpoint`},Y2={fn:K2,argv:[{[I2]:U2},`name`]},X2={[I2]:U2},Z2={[L2]:[{[R2]:q2,[z2]:`us-east-1`}]},Q2={[L2]:[{[R2]:q2,[z2]:`cn-north-1`}]},$2={[L2]:[{[R2]:q2,[z2]:`us-gov-west-1`}]},e4={[L2]:[{[R2]:q2,[z2]:`us-iso-east-1`}]},t4={[L2]:[{[R2]:q2,[z2]:`us-isob-east-1`}]},n4={[L2]:[{[R2]:q2,[z2]:`{PartitionResult#implicitGlobalRegion}`}]},r4=[{[I2]:`Region`}],i4={conditions:[[H2,[J2]],[H2,r4],[`aws.partition`,r4,U2],[W2,[{[I2]:`UseFIPS`},V2]],[W2,[{[I2]:`UseDualStack`},V2]],[G2,[Y2,`aws`]],[G2,[Y2,`aws-cn`]],[G2,[Y2,`aws-us-gov`]],[W2,[{fn:K2,argv:[X2,`supportsDualStack`]},V2]],[G2,[Y2,`aws-iso`]],[G2,[Y2,`aws-iso-b`]],[W2,[{fn:K2,argv:[X2,`supportsFIPS`]},V2]],[G2,[Y2,`aws-iso-e`]],[G2,[Y2,`aws-iso-f`]],[G2,[Y2,`aws-eusc`]]],results:[[B2],[B2,`Invalid Configuration: FIPS and custom endpoint are not supported`],[B2,`Invalid Configuration: Dualstack and custom endpoint are not supported`],[J2,{}],[`https://iam.global.api.aws`,Z2],[`https://iam-fips.global.api.aws`,Z2],[`https://iam.global.api.amazonwebservices.com.cn`,Q2],[`https://iam.cn-north-1.amazonaws.com.cn`,Q2],[`https://iam.us-gov.api.aws`,$2],[`https://iam.us-gov.amazonaws.com`,$2],[`https://iam.us-iso-east-1.c2s.ic.gov`,e4],[`https://iam-fips.us-iso-east-1.c2s.ic.gov`,e4],[`https://iam.us-isob-east-1.sc2s.sgov.gov`,t4],[`https://iam-fips.us-isob-east-1.sc2s.sgov.gov`,t4],[`https://iam.eu-isoe-west-1.cloud.adc-e.uk`,{[L2]:[{[R2]:q2,[z2]:`eu-isoe-west-1`}]}],[`https://iam.us-isof-south-1.csp.hci.ic.gov`,{[L2]:[{[R2]:q2,[z2]:`us-isof-south-1`}]}],[`https://iam.eusc-de-east-1.amazonaws.eu`,{[L2]:[{[R2]:q2,[z2]:`eusc-de-east-1`}]}],[`https://iam-fips.{PartitionResult#dualStackDnsSuffix}`,n4],[B2,`FIPS and DualStack are enabled, but this partition does not support one or both`],[`https://iam-fips.{PartitionResult#dnsSuffix}`,n4],[B2,`FIPS is enabled but this partition does not support FIPS`],[`https://iam.{PartitionResult#dualStackDnsSuffix}`,n4],[B2,`DualStack is enabled but this partition does not support DualStack`],[`https://iam.{PartitionResult#dnsSuffix}`,n4],[B2,`Invalid Configuration: Missing Region`]]},vje=2,a4=1e8,yje=new Int32Array([-1,1,-1,0,27,3,1,4,a4+24,2,5,a4+24,3,18,6,4,14,7,6,a4+7,8,7,a4+9,9,9,a4+10,10,10,a4+12,11,12,a4+14,12,13,a4+15,13,14,a4+16,a4+23,5,a4+4,15,6,a4+6,16,7,a4+8,17,8,a4+21,a4+22,4,23,19,7,a4+9,20,9,a4+11,21,10,a4+13,22,11,a4+19,a4+20,5,a4+5,24,7,a4+8,25,8,26,a4+18,11,a4+17,a4+18,3,a4+1,28,4,a4+2,a4+3]),bje=ak.from(yje,vje,i4.conditions,i4.results),xje=new ok({size:50,params:[`Endpoint`,`Region`,`UseDualStack`,`UseFIPS`]}),Sje=(e,t={})=>xje.get(e,()=>Sk(bje,{endpointParams:e,logger:t.logger}));lk.aws=Tk;var o4=class e extends sA{constructor(t){super(t),Object.setPrototypeOf(this,e.prototype)}},Cje=class e extends o4{name=`ConcurrentModificationException`;$fault=`client`;constructor(t){super({name:`ConcurrentModificationException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},wje=class e extends o4{name=`NoSuchEntityException`;$fault=`client`;constructor(t){super({name:`NoSuchEntityException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Tje=class e extends o4{name=`ServiceFailureException`;$fault=`server`;constructor(t){super({name:`ServiceFailureException`,$fault:`server`,...t}),Object.setPrototypeOf(this,e.prototype)}},Eje=class e extends o4{name=`AccountNotManagementOrDelegatedAdministratorException`;$fault=`client`;Message;constructor(t){super({name:`AccountNotManagementOrDelegatedAdministratorException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Dje=class e extends o4{name=`InvalidInputException`;$fault=`client`;constructor(t){super({name:`InvalidInputException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Oje=class e extends o4{name=`LimitExceededException`;$fault=`client`;constructor(t){super({name:`LimitExceededException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},kje=class e extends o4{name=`EntityAlreadyExistsException`;$fault=`client`;constructor(t){super({name:`EntityAlreadyExistsException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Aje=class e extends o4{name=`UnmodifiableEntityException`;$fault=`client`;constructor(t){super({name:`UnmodifiableEntityException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},jje=class e extends o4{name=`PolicyNotAttachableException`;$fault=`client`;constructor(t){super({name:`PolicyNotAttachableException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Mje=class e extends o4{name=`EntityTemporarilyUnmodifiableException`;$fault=`client`;constructor(t){super({name:`EntityTemporarilyUnmodifiableException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Nje=class e extends o4{name=`InvalidUserTypeException`;$fault=`client`;constructor(t){super({name:`InvalidUserTypeException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Pje=class e extends o4{name=`PasswordPolicyViolationException`;$fault=`client`;constructor(t){super({name:`PasswordPolicyViolationException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Fje=class e extends o4{name=`OpenIdIdpCommunicationErrorException`;$fault=`client`;constructor(t){super({name:`OpenIdIdpCommunicationErrorException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Ije=class e extends o4{name=`MalformedPolicyDocumentException`;$fault=`client`;constructor(t){super({name:`MalformedPolicyDocumentException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Lje=class e extends o4{name=`ServiceNotSupportedException`;$fault=`client`;constructor(t){super({name:`ServiceNotSupportedException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Rje=class e extends o4{name=`DeleteConflictException`;$fault=`client`;constructor(t){super({name:`DeleteConflictException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},zje=class e extends o4{name=`OrganizationNotFoundException`;$fault=`client`;Message;constructor(t){super({name:`OrganizationNotFoundException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Bje=class e extends o4{name=`OrganizationNotInAllFeaturesModeException`;$fault=`client`;Message;constructor(t){super({name:`OrganizationNotInAllFeaturesModeException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Vje=class e extends o4{name=`ServiceAccessNotEnabledException`;$fault=`client`;Message;constructor(t){super({name:`ServiceAccessNotEnabledException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Hje=class e extends o4{name=`FeatureDisabledException`;$fault=`client`;constructor(t){super({name:`FeatureDisabledException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Uje=class e extends o4{name=`InvalidAuthenticationCodeException`;$fault=`client`;constructor(t){super({name:`InvalidAuthenticationCodeException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Wje=class e extends o4{name=`CallerIsNotManagementAccountException`;$fault=`client`;Message;constructor(t){super({name:`CallerIsNotManagementAccountException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.Message=t.Message}},Gje=class e extends o4{name=`FeatureEnabledException`;$fault=`client`;constructor(t){super({name:`FeatureEnabledException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Kje=class e extends o4{name=`ReportGenerationLimitExceededException`;$fault=`client`;constructor(t){super({name:`ReportGenerationLimitExceededException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},qje=class e extends o4{name=`CredentialReportExpiredException`;$fault=`client`;constructor(t){super({name:`CredentialReportExpiredException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Jje=class e extends o4{name=`CredentialReportNotPresentException`;$fault=`client`;constructor(t){super({name:`CredentialReportNotPresentException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Yje=class e extends o4{name=`CredentialReportNotReadyException`;$fault=`client`;constructor(t){super({name:`CredentialReportNotReadyException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Xje=class e extends o4{name=`UnrecognizedPublicKeyEncodingException`;$fault=`client`;constructor(t){super({name:`UnrecognizedPublicKeyEncodingException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},Zje=class e extends o4{name=`PolicyEvaluationException`;$fault=`server`;constructor(t){super({name:`PolicyEvaluationException`,$fault:`server`,...t}),Object.setPrototypeOf(this,e.prototype)}},Qje=class e extends o4{name=`KeyPairMismatchException`;$fault=`client`;constructor(t){super({name:`KeyPairMismatchException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},$je=class e extends o4{name=`MalformedCertificateException`;$fault=`client`;constructor(t){super({name:`MalformedCertificateException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},eMe=class e extends o4{name=`DuplicateCertificateException`;$fault=`client`;constructor(t){super({name:`DuplicateCertificateException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},tMe=class e extends o4{name=`InvalidCertificateException`;$fault=`client`;constructor(t){super({name:`InvalidCertificateException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},nMe=class e extends o4{name=`DuplicateSSHPublicKeyException`;$fault=`client`;constructor(t){super({name:`DuplicateSSHPublicKeyException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},rMe=class e extends o4{name=`InvalidPublicKeyException`;$fault=`client`;constructor(t){super({name:`InvalidPublicKeyException`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},s4=`Arn`,iMe=`AttachmentCount`,c4=`AccessKey`,l4=`AccessKeyId`,u4=`AccessKeyMetadata`,aMe=`AccountNotManagementOrDelegatedAdministratorException`,oMe=`AttachedPolicy`,sMe=`AttachedPermissionsBoundary`,cMe=`AttachedPolicies`,lMe=`AttachUserPolicy`,uMe=`AttachUserPolicyRequest`,dMe=`CreateAccessKey`,fMe=`CreateAccessKeyRequest`,pMe=`CreateAccessKeyResponse`,d4=`CreateDate`,mMe=`CallerIsNotManagementAccountException`,hMe=`ConcurrentModificationException`,gMe=`CreatePolicyRequest`,_Me=`CreatePolicyResponse`,vMe=`CreatePolicy`,yMe=`CredentialReportExpiredException`,bMe=`CredentialReportNotPresentException`,xMe=`CredentialReportNotReadyException`,SMe=`CreateUser`,CMe=`CreateUserRequest`,wMe=`CreateUserResponse`,f4=`Description`,TMe=`DeleteAccessKey`,EMe=`DeleteAccessKeyRequest`,DMe=`DeleteConflictException`,OMe=`DuplicateCertificateException`,kMe=`DeletePolicyRequest`,AMe=`DeletePolicy`,jMe=`DuplicateSSHPublicKeyException`,MMe=`DeleteUser`,NMe=`DetachUserPolicyRequest`,PMe=`DetachUserPolicy`,FMe=`DeleteUserRequest`,IMe=`DefaultVersionId`,LMe=`Document`,RMe=`EntityAlreadyExistsException`,zMe=`EntityTemporarilyUnmodifiableException`,BMe=`FeatureDisabledException`,VMe=`FeatureEnabledException`,HMe=`GetPolicy`,UMe=`GetPolicyRequest`,WMe=`GetPolicyResponse`,GMe=`GetPolicyVersion`,KMe=`GetPolicyVersionRequest`,qMe=`GetPolicyVersionResponse`,JMe=`GetUser`,YMe=`GetUserRequest`,XMe=`GetUserResponse`,ZMe=`IsAttachable`,QMe=`InvalidAuthenticationCodeException`,$Me=`InvalidCertificateException`,eNe=`IsDefaultVersion`,tNe=`InvalidInputException`,nNe=`InvalidPublicKeyException`,p4=`IsTruncated`,rNe=`InvalidUserTypeException`,iNe=`Key`,aNe=`KeyPairMismatchException`,oNe=`ListAccessKeys`,sNe=`ListAccessKeysRequest`,cNe=`ListAccessKeysResponse`,lNe=`ListAttachedUserPolicies`,uNe=`ListAttachedUserPoliciesRequest`,dNe=`ListAttachedUserPoliciesResponse`,fNe=`LimitExceededException`,pNe=`ListPoliciesRequest`,mNe=`ListPoliciesResponse`,hNe=`ListPolicies`,gNe=`ListUsers`,_Ne=`ListUsersRequest`,vNe=`ListUsersResponse`,m4=`Message`,yNe=`MalformedCertificateException`,h4=`MaxItems`,bNe=`MalformedPolicyDocumentException`,g4=`Marker`,xNe=`NoSuchEntityException`,SNe=`OnlyAttached`,CNe=`OpenIdIdpCommunicationErrorException`,wNe=`OrganizationNotFoundException`,TNe=`OrganizationNotInAllFeaturesModeException`,_4=`PolicyArn`,v4=`PermissionsBoundary`,ENe=`PermissionsBoundaryArn`,DNe=`PermissionsBoundaryType`,ONe=`PermissionsBoundaryUsageCount`,kNe=`PolicyDocument`,ANe=`PolicyEvaluationException`,jNe=`PolicyId`,MNe=`PasswordLastUsed`,y4=`PolicyName`,NNe=`PolicyNotAttachableException`,PNe=`PasswordPolicyViolationException`,b4=`PathPrefix`,FNe=`PolicyUsageFilter`,x4=`PolicyVersion`,S4=`Path`,C4=`Policy`,INe=`Policies`,LNe=`ReportGenerationLimitExceededException`,w4=`Status`,RNe=`SecretAccessKey`,zNe=`ServiceAccessNotEnabledException`,BNe=`ServiceFailureException`,VNe=`ServiceNotSupportedException`,HNe=`Scope`,T4=`Tags`,UNe=`Tag`,WNe=`UpdateAccessKey`,GNe=`UpdateAccessKeyRequest`,KNe=`UpdateDate`,qNe=`UnmodifiableEntityException`,JNe=`UserId`,E4=`UserName`,YNe=`UnrecognizedPublicKeyEncodingException`,D4=`User`,XNe=`Users`,O4=`VersionId`,ZNe=`Value`,QNe=`accessKeyMetadataListType`,$Ne=`accessKeySecretType`,ePe=`attachedPoliciesListType`,k4=`awsQueryError`,A4=`client`,j4=`error`,M4=`httpError`,N4=`message`,tPe=`policyListType`,P4=`smithy.ts.sdk.synthetic.com.amazonaws.iam`,F4=`server`,nPe=`tagListType`,rPe=`userListType`,X=`com.amazonaws.iam`,I4=OO.for(P4),iPe=[-3,P4,`IAMServiceException`,0,[],[]];I4.registerError(iPe,o4);var L4=OO.for(X),aPe=[-3,X,aMe,{[j4]:A4,[M4]:400},[m4],[0]];L4.registerError(aPe,Eje);var oPe=[-3,X,mMe,{[j4]:A4,[M4]:400},[m4],[0]];L4.registerError(oPe,Wje);var sPe=[-3,X,hMe,{[k4]:[`ConcurrentModification`,409],[j4]:A4,[M4]:409},[N4],[0]];L4.registerError(sPe,Cje);var cPe=[-3,X,yMe,{[k4]:[`ReportExpired`,410],[j4]:A4,[M4]:410},[N4],[0]];L4.registerError(cPe,qje);var lPe=[-3,X,bMe,{[k4]:[`ReportNotPresent`,410],[j4]:A4,[M4]:410},[N4],[0]];L4.registerError(lPe,Jje);var uPe=[-3,X,xMe,{[k4]:[`ReportInProgress`,404],[j4]:A4,[M4]:404},[N4],[0]];L4.registerError(uPe,Yje);var dPe=[-3,X,DMe,{[k4]:[`DeleteConflict`,409],[j4]:A4,[M4]:409},[N4],[0]];L4.registerError(dPe,Rje);var fPe=[-3,X,OMe,{[k4]:[`DuplicateCertificate`,409],[j4]:A4,[M4]:409},[N4],[0]];L4.registerError(fPe,eMe);var pPe=[-3,X,jMe,{[k4]:[`DuplicateSSHPublicKey`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(pPe,nMe);var mPe=[-3,X,RMe,{[k4]:[`EntityAlreadyExists`,409],[j4]:A4,[M4]:409},[N4],[0]];L4.registerError(mPe,kje);var hPe=[-3,X,zMe,{[k4]:[`EntityTemporarilyUnmodifiable`,409],[j4]:A4,[M4]:409},[N4],[0]];L4.registerError(hPe,Mje);var gPe=[-3,X,BMe,{[k4]:[`FeatureDisabled`,404],[j4]:A4,[M4]:404},[N4],[0]];L4.registerError(gPe,Hje);var _Pe=[-3,X,VMe,{[k4]:[`FeatureEnabled`,409],[j4]:A4,[M4]:409},[N4],[0]];L4.registerError(_Pe,Gje);var vPe=[-3,X,QMe,{[k4]:[`InvalidAuthenticationCode`,403],[j4]:A4,[M4]:403},[N4],[0]];L4.registerError(vPe,Uje);var yPe=[-3,X,$Me,{[k4]:[`InvalidCertificate`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(yPe,tMe);var bPe=[-3,X,tNe,{[k4]:[`InvalidInput`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(bPe,Dje);var xPe=[-3,X,nNe,{[k4]:[`InvalidPublicKey`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(xPe,rMe);var SPe=[-3,X,rNe,{[k4]:[`InvalidUserType`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(SPe,Nje);var CPe=[-3,X,aNe,{[k4]:[`KeyPairMismatch`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(CPe,Qje);var wPe=[-3,X,fNe,{[k4]:[`LimitExceeded`,409],[j4]:A4,[M4]:409},[N4],[0]];L4.registerError(wPe,Oje);var TPe=[-3,X,yNe,{[k4]:[`MalformedCertificate`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(TPe,$je);var EPe=[-3,X,bNe,{[k4]:[`MalformedPolicyDocument`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(EPe,Ije);var DPe=[-3,X,xNe,{[k4]:[`NoSuchEntity`,404],[j4]:A4,[M4]:404},[N4],[0]];L4.registerError(DPe,wje);var OPe=[-3,X,CNe,{[k4]:[`OpenIdIdpCommunicationError`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(OPe,Fje);var kPe=[-3,X,wNe,{[j4]:A4,[M4]:400},[m4],[0]];L4.registerError(kPe,zje);var APe=[-3,X,TNe,{[j4]:A4,[M4]:400},[m4],[0]];L4.registerError(APe,Bje);var jPe=[-3,X,PNe,{[k4]:[`PasswordPolicyViolation`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(jPe,Pje);var MPe=[-3,X,ANe,{[k4]:[`PolicyEvaluation`,500],[j4]:F4,[M4]:500},[N4],[0]];L4.registerError(MPe,Zje);var NPe=[-3,X,NNe,{[k4]:[`PolicyNotAttachable`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(NPe,jje);var PPe=[-3,X,LNe,{[k4]:[`ReportGenerationLimitExceeded`,409],[j4]:A4,[M4]:409},[N4],[0]];L4.registerError(PPe,Kje);var FPe=[-3,X,zNe,{[j4]:A4,[M4]:400},[m4],[0]];L4.registerError(FPe,Vje);var IPe=[-3,X,BNe,{[k4]:[`ServiceFailure`,500],[j4]:F4,[M4]:500},[N4],[0]];L4.registerError(IPe,Tje);var LPe=[-3,X,VNe,{[k4]:[`NotSupportedService`,404],[j4]:A4,[M4]:404},[N4],[0]];L4.registerError(LPe,Lje);var RPe=[-3,X,qNe,{[k4]:[`UnmodifiableEntity`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(RPe,Aje);var zPe=[-3,X,YNe,{[k4]:[`UnrecognizedPublicKeyEncoding`,400],[j4]:A4,[M4]:400},[N4],[0]];L4.registerError(zPe,Xje);var BPe=[I4,L4],VPe=[0,X,$Ne,8,0],HPe=[3,X,c4,0,[E4,l4,w4,RNe,d4],[0,0,0,[()=>VPe,0],4],4],UPe=[3,X,u4,0,[E4,l4,w4,d4],[0,0,0,4]],WPe=[3,X,sMe,0,[DNe,ENe],[0,0]],GPe=[3,X,oMe,0,[y4,_4],[0,0]],KPe=[3,X,uMe,0,[E4,_4],[0,0],2],qPe=[3,X,fMe,0,[E4],[0]],JPe=[3,X,pMe,0,[c4],[[()=>HPe,0]],1],YPe=[3,X,gMe,0,[y4,kNe,S4,f4,T4],[0,0,0,0,()=>V4],2],XPe=[3,X,_Me,0,[C4],[()=>R4]],ZPe=[3,X,CMe,0,[E4,S4,v4,T4],[0,0,0,()=>V4],1],QPe=[3,X,wMe,0,[D4],[()=>z4]],$Pe=[3,X,EMe,0,[l4,E4],[0,0],1],eFe=[3,X,kMe,0,[_4],[0],1],tFe=[3,X,FMe,0,[E4],[0],1],nFe=[3,X,NMe,0,[E4,_4],[0,0],2],rFe=[3,X,UMe,0,[_4],[0],1],iFe=[3,X,WMe,0,[C4],[()=>R4]],aFe=[3,X,KMe,0,[_4,O4],[0,0],2],oFe=[3,X,qMe,0,[x4],[()=>_Fe]],sFe=[3,X,YMe,0,[E4],[0]],cFe=[3,X,XMe,0,[D4],[()=>z4],1],lFe=[3,X,sNe,0,[E4,g4,h4],[0,0,1]],uFe=[3,X,cNe,0,[u4,p4,g4],[()=>bFe,2,0],1],dFe=[3,X,uNe,0,[E4,b4,g4,h4],[0,0,0,1],1],fFe=[3,X,dNe,0,[cMe,p4,g4],[()=>xFe,2,0]],pFe=[3,X,pNe,0,[HNe,SNe,b4,FNe,g4,h4],[0,2,0,0,0,1]],mFe=[3,X,mNe,0,[INe,p4,g4],[()=>SFe,2,0]],hFe=[3,X,_Ne,0,[b4,g4,h4],[0,0,1]],gFe=[3,X,vNe,0,[XNe,p4,g4],[()=>CFe,2,0],1],R4=[3,X,C4,0,[y4,jNe,s4,S4,IMe,iMe,ONe,ZMe,f4,d4,KNe,T4],[0,0,0,0,0,1,1,2,0,4,4,()=>V4]],_Fe=[3,X,x4,0,[LMe,O4,eNe,d4],[0,0,2,4]],vFe=[3,X,UNe,0,[iNe,ZNe],[0,0],2],yFe=[3,X,GNe,0,[l4,w4,E4],[0,0,0],2],z4=[3,X,D4,0,[S4,E4,JNe,s4,d4,MNe,v4,T4],[0,0,0,0,4,4,()=>WPe,()=>V4],5],B4=`unit`,bFe=[1,X,QNe,0,()=>UPe],xFe=[1,X,ePe,0,()=>GPe],SFe=[1,X,tPe,0,()=>R4],V4=[1,X,nPe,0,()=>vFe],CFe=[1,X,rPe,0,()=>z4],wFe=[9,X,lMe,0,()=>KPe,()=>B4],TFe=[9,X,dMe,0,()=>qPe,()=>JPe],EFe=[9,X,vMe,0,()=>YPe,()=>XPe],DFe=[9,X,SMe,0,()=>ZPe,()=>QPe],OFe=[9,X,TMe,0,()=>$Pe,()=>B4],kFe=[9,X,AMe,0,()=>eFe,()=>B4],AFe=[9,X,MMe,0,()=>tFe,()=>B4],jFe=[9,X,PMe,0,()=>nFe,()=>B4],MFe=[9,X,HMe,0,()=>rFe,()=>iFe],NFe=[9,X,GMe,0,()=>aFe,()=>oFe],PFe=[9,X,JMe,0,()=>sFe,()=>cFe],FFe=[9,X,oNe,0,()=>lFe,()=>uFe],IFe=[9,X,lNe,0,()=>dFe,()=>fFe],LFe=[9,X,hNe,0,()=>pFe,()=>mFe],RFe=[9,X,gNe,0,()=>hFe,()=>gFe],zFe=[9,X,WNe,0,()=>yFe,()=>B4],BFe=e=>({apiVersion:`2010-05-08`,base64Decoder:e?.base64Decoder??eO,base64Encoder:e?.base64Encoder??tO,disableHostPrefix:e?.disableHostPrefix??!1,endpointProvider:e?.endpointProvider??Sje,extensions:e?.extensions??[],httpAuthSchemeProvider:e?.httpAuthSchemeProvider??mje,httpAuthSchemes:e?.httpAuthSchemes??[{schemeId:`aws.auth#sigv4`,identityProvider:e=>e.getIdentityProvider(`aws.auth#sigv4`),signer:new SA}],logger:e?.logger??new mA,protocol:e?.protocol??LA,protocolSettings:e?.protocolSettings??{defaultNamespace:`com.amazonaws.iam`,errorTypeRegistries:BPe,xmlNamespace:`https://iam.amazonaws.com/doc/2010-05-08/`,version:`2010-05-08`,serviceTarget:`AWSIdentityManagementV20100508`},serviceId:e?.serviceId??`IAM`,urlParser:e?.urlParser??vO,utf8Decoder:e?.utf8Decoder??Wb,utf8Encoder:e?.utf8Encoder??Kb}),VFe=e=>{let t=AA(e),n=()=>t().then(lA),r=BFe(e);return{...r,...e,runtime:`browser`,defaultsMode:t,bodyLengthChecker:e?.bodyLengthChecker??kA,credentialDefaultProvider:e?.credentialDefaultProvider??(e=>()=>Promise.reject(Error(`Credential is missing`))),defaultUserAgentProvider:e?.defaultUserAgentProvider??TA({serviceId:r.serviceId,clientVersion:_je.version}),maxAttempts:e?.maxAttempts??3,region:e?.region??DA(`Region is missing`),requestHandler:sO.create(e?.requestHandler??n),retryMode:e?.retryMode??(async()=>(await n()).retryMode||Dk),sha256:e?.sha256??Nb,streamCollector:e?.streamCollector??lO,useDualstackEndpoint:e?.useDualstackEndpoint??(()=>Promise.resolve(!1)),useFipsEndpoint:e?.useFipsEndpoint??(()=>Promise.resolve(!1))}},HFe=e=>{let t=e.httpAuthSchemes,n=e.httpAuthSchemeProvider,r=e.credentials;return{setHttpAuthScheme(e){let n=t.findIndex(t=>t.schemeId===e.schemeId);n===-1?t.push(e):t.splice(n,1,e)},httpAuthSchemes(){return t},setHttpAuthSchemeProvider(e){n=e},httpAuthSchemeProvider(){return n},setCredentials(e){r=e},credentials(){return r}}},UFe=e=>({httpAuthSchemes:e.httpAuthSchemes(),httpAuthSchemeProvider:e.httpAuthSchemeProvider(),credentials:e.credentials()}),WFe=(e,t)=>{let n=Object.assign(c1(e),dA(e),Pb(e),HFe(e));return t.forEach(e=>e.configure(n)),Object.assign(e,l1(n),fA(n),Fb(n),UFe(n))},GFe=class extends rA{config;constructor(...[e]){let t=VFe(e||{});super(t),this.initConfig=t;let n=WFe(hje(Xk(AD(Hk(Zk(ik(gje(t))))))),e?.extensions||[]);this.config=n,this.middlewareStack.use(yO(this.config)),this.middlewareStack.use(zk(this.config)),this.middlewareStack.use(gA(this.config)),this.middlewareStack.use(Wk(this.config)),this.middlewareStack.use(ND(this.config)),this.middlewareStack.use(ID(this.config)),this.middlewareStack.use(zD(this.config)),this.middlewareStack.use(WD(this.config,{httpAuthSchemeParametersProvider:fje,identityProviderConfigProvider:async e=>new nk({"aws.auth#sigv4":e.credentials})})),this.middlewareStack.use(YD(this.config))}destroy(){super.destroy()}},KFe=class extends oA.classBuilder().ep(F2).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`GetPolicy`,{}).n(`IAMClient`,`GetPolicyCommand`).sc(MFe).build(){},qFe=class extends oA.classBuilder().ep(F2).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`GetPolicyVersion`,{}).n(`IAMClient`,`GetPolicyVersionCommand`).sc(NFe).build(){},JFe=class extends oA.classBuilder().ep(F2).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`GetUser`,{}).n(`IAMClient`,`GetUserCommand`).sc(PFe).build(){},YFe=class extends oA.classBuilder().ep(F2).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`ListAccessKeys`,{}).n(`IAMClient`,`ListAccessKeysCommand`).sc(FFe).build(){},XFe=class extends oA.classBuilder().ep(F2).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`ListAttachedUserPolicies`,{}).n(`IAMClient`,`ListAttachedUserPoliciesCommand`).sc(IFe).build(){},ZFe=class extends oA.classBuilder().ep(F2).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`ListPolicies`,{}).n(`IAMClient`,`ListPoliciesCommand`).sc(LFe).build(){},QFe=class extends oA.classBuilder().ep(F2).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions())]}).s(`AWSIdentityManagementV20100508`,`ListUsers`,{}).n(`IAMClient`,`ListUsersCommand`).sc(RFe).build(){};function $Fe(e){return t=>async n=>{let{request:r}=n;if(e.expectContinueHeader!==!1&&Rb.isInstance(r)&&r.body&&e.runtime===`node`&&e.requestHandler?.constructor?.name!==`FetchHttpHandler`){let t=!0;if(typeof e.expectContinueHeader==`number`)try{t=(Number(r.headers?.[`content-length`])??e.bodyLengthChecker?.(r.body)??1/0)>=e.expectContinueHeader}catch{}else t=!!e.expectContinueHeader;t&&(r.headers.Expect=`100-continue`)}return t({...n,request:r})}}var eIe={step:`build`,tags:[`SET_EXPECT_HEADER`,`EXPECT_HEADER`],name:`addExpectContinueMiddleware`,override:!0},tIe=e=>({applyToStack:t=>{t.add($Fe(e),eIe)}}),H4={WHEN_SUPPORTED:`WHEN_SUPPORTED`,WHEN_REQUIRED:`WHEN_REQUIRED`},nIe=H4.WHEN_SUPPORTED,rIe={WHEN_SUPPORTED:`WHEN_SUPPORTED`,WHEN_REQUIRED:`WHEN_REQUIRED`},iIe=H4.WHEN_SUPPORTED,U4;(function(e){e.MD5=`MD5`,e.CRC32=`CRC32`,e.CRC32C=`CRC32C`,e.CRC64NVME=`CRC64NVME`,e.SHA1=`SHA1`,e.SHA256=`SHA256`})(U4||={});var aIe;(function(e){e.HEADER=`header`,e.TRAILER=`trailer`})(aIe||={});var oIe=U4.CRC32,sIe=function(){function e(){this.crc32=new W4}return e.prototype.update=function(e){Sb(e)||this.crc32.update(xb(e))},e.prototype.digest=function(){return Ob(this,void 0,void 0,function(){return kb(this,function(e){return[2,Cb(this.crc32.digest())]})})},e.prototype.reset=function(){this.crc32=new W4},e}(),W4=function(){function e(){this.checksum=4294967295}return e.prototype.update=function(e){var t,n;try{for(var r=Ab(e),i=r.next();!i.done;i=r.next()){var a=i.value;this.checksum=this.checksum>>>8^cIe[(this.checksum^a)&255]}}catch(e){t={error:e}}finally{try{i&&!i.done&&(n=r.return)&&n.call(r)}finally{if(t)throw t.error}}return this},e.prototype.digest=function(){return(this.checksum^4294967295)>>>0},e}(),cIe=wb([0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,2898065728,853044451,1172266101,3705015759,2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,4111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977,2362670323,4224994405,1303535960,984961486,2747007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,855842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,1591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,1957810842,3939845945,2647816111,81470997,1943803523,3814918930,2489596804,225274430,2053790376,3826175755,2466906013,167816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,2312317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,3518719985,2797360999,1068828381,1219638859,3624741850,2936675148,906185462,1090812512,3747672003,2825379669,829329135,1181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400815,3317316542,2998733608,733239954,1555261956,3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,3943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,2262029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,285281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,1231636301,1047427035,2932959818,3654703836,1088359270,936918e3,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117]),lIe=e=>{let{requestChecksumCalculation:t,responseChecksumValidation:n,requestStreamBufferSize:r}=e;return Object.assign(e,{requestChecksumCalculation:ux(t??nIe),responseChecksumValidation:ux(n??iIe),requestStreamBufferSize:Number(r??0),checksumAlgorithms:e.checksumAlgorithms??{}})},uIe=e=>(t,n)=>async r=>{let i=await e.region(),a=e.region,o=()=>{};n.__s3RegionRedirect&&(Object.defineProperty(e,`region`,{writable:!1,value:async()=>n.__s3RegionRedirect}),o=()=>Object.defineProperty(e,`region`,{writable:!0,value:a}));try{let a=await t(r);if(n.__s3RegionRedirect&&(o(),i!==await e.region()))throw Error(`Region was not restored following S3 region redirect.`);return a}catch(e){throw o(),e}},dIe={tags:[`REGION_REDIRECT`,`S3`],name:`regionRedirectEndpointMiddleware`,override:!0,relation:`before`,toMiddleware:`endpointV2Middleware`};function fIe(e){return(t,n)=>async r=>{try{return await t(r)}catch(i){if(e.followRegionRedirects){let a=i?.$metadata?.httpStatusCode,o=n.commandName===`HeadBucketCommand`,s=i?.$response?.headers?.[`x-amz-bucket-region`];if(s&&(a===301||a===400&&(i?.name===`IllegalLocationConstraintException`||o))){try{let t=s;n.logger?.debug(`Redirecting from ${await e.region()} to ${t}`),n.__s3RegionRedirect=t}catch(e){throw Error(`Region redirect failed: `+e)}return t(r)}}throw i}}}var pIe={step:`initialize`,tags:[`REGION_REDIRECT`,`S3`],name:`regionRedirectMiddleware`,override:!0},mIe=e=>({applyToStack:t=>{t.add(fIe(e),pIe),t.addRelativeTo(uIe(e),dIe)}}),hIe=class e{data;lastPurgeTime=Date.now();static EXPIRED_CREDENTIAL_PURGE_INTERVAL_MS=3e4;constructor(e={}){this.data=e}get(e){let t=this.data[e];if(t)return t}set(e,t){return this.data[e]=t,t}delete(e){delete this.data[e]}async purgeExpired(){let t=Date.now();if(!(this.lastPurgeTime+e.EXPIRED_CREDENTIAL_PURGE_INTERVAL_MS>t))for(let e in this.data){let n=this.data[e];if(!n.isRefreshing){let r=await n.identity;r.expiration&&r.expiration.getTime()(t.expiration?.getTime()??0){i.set(r,new G4(Promise.resolve(e)))})),t)):i.set(r,new G4(this.getIdentity(r))).identity}async getIdentity(e){await this.cache.purgeExpired().catch(e=>{console.warn(`Error while clearing expired entries in S3ExpressIdentityCache: +`+e)});let t=await this.createSessionFn(e);if(!t.Credentials?.AccessKeyId||!t.Credentials?.SecretAccessKey)throw Error(`s3#createSession response credential missing AccessKeyId or SecretAccessKey.`);return{accessKeyId:t.Credentials.AccessKeyId,secretAccessKey:t.Credentials.SecretAccessKey,sessionToken:t.Credentials.SessionToken,expiration:t.Credentials.Expiration?new Date(t.Credentials.Expiration):void 0}}},_Ie=`sigv4-s3express`,K4=`X-Amz-S3session-Token`,q4=K4.toLowerCase(),vIe=class extends fx{async signWithCredentials(e,t,n){let r=J4(t);e.headers[q4]=t.sessionToken;let i=this;return Y4(i,r),i.signRequest(e,n??{})}async presignWithCredentials(e,t,n){let r=J4(t);return delete e.headers[q4],e.headers[K4]=t.sessionToken,e.query=e.query??{},e.query[K4]=t.sessionToken,Y4(this,r),this.presign(e,n)}};function J4(e){return{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey,expiration:e.expiration}}function Y4(e,t){let n=setTimeout(()=>{throw Error(`SignatureV4S3Express credential override was created but not called.`)},10),r=e.credentialProvider;e.credentialProvider=()=>(clearTimeout(n),e.credentialProvider=r,Promise.resolve(t))}var yIe=e=>(t,n)=>async r=>{if(n.endpointV2){let t=n.endpointV2,i=t.properties?.authSchemes?.[0]?.name===_Ie;if((t.properties?.backend===`S3Express`||t.properties?.bucketType===`Directory`)&&(Fk(n,`S3_EXPRESS_BUCKET`,`J`),n.isS3ExpressBucket=!0),i){let t=r.input.Bucket;if(t){let i=await e.s3ExpressIdentityProvider.getS3ExpressIdentity(await e.credentials(),{Bucket:t});n.s3ExpressIdentity=i,Rb.isInstance(r.request)&&i.sessionToken&&(r.request.headers[q4]=i.sessionToken)}}}return t(r)},bIe={name:`s3ExpressMiddleware`,step:`build`,tags:[`S3`,`S3_EXPRESS`],override:!0},xIe=e=>({applyToStack:t=>{t.add(yIe(e),bIe)}}),SIe=async(e,t,n,r)=>{let i=await r.signWithCredentials(n,e,{});if(i.headers[`X-Amz-Security-Token`]||i.headers[`x-amz-security-token`])throw Error(`X-Amz-Security-Token must not be set for s3-express requests.`);return i},CIe=e=>e=>{throw e},wIe=(e,t)=>{},TIe=e=>(t,n)=>async r=>{if(!Rb.isInstance(r.request))return t(r);let i=lx(n).selectedHttpAuthScheme;if(!i)throw Error(`No HttpAuthScheme was selected: unable to sign request`);let{httpAuthOption:{signingProperties:a={}},identity:o,signer:s}=i,c;c=n.s3ExpressIdentity?await SIe(n.s3ExpressIdentity,a,r.request,await e.signer()):await s.sign(r.request,o,a);let l=await t({...r,request:c}).catch((s.errorHandler||CIe)(a));return(s.successHandler||wIe)(l.response,a),l},EIe=e=>({applyToStack:t=>{t.addRelativeTo(TIe(e),JD)}}),DIe=(e,{session:t})=>{let[n,r]=t,{forcePathStyle:i,useAccelerateEndpoint:a,disableMultiregionAccessPoints:o,followRegionRedirects:s,s3ExpressIdentityProvider:c,bucketEndpoint:l,expectContinueHeader:u}=e;return Object.assign(e,{forcePathStyle:i??!1,useAccelerateEndpoint:a??!1,disableMultiregionAccessPoints:o??!1,followRegionRedirects:s??!1,s3ExpressIdentityProvider:c??new gIe(async e=>n().send(new r({Bucket:e}))),bucketEndpoint:l??!1,expectContinueHeader:u??2097152})};function OIe(e){return new ReadableStream({start(t){t.enqueue(e),t.close()}})}var kIe={CopyObjectCommand:!0,UploadPartCopyCommand:!0,CompleteMultipartUploadCommand:!0},AIe=e=>(t,n)=>async r=>{let i=await t(r),{response:a}=i;if(!zb.isInstance(a))return i;let{statusCode:o,body:s}=a;if(o<200||o>=300)return i;let c=await jIe(s,e);if(a.body=OIe(c),c.length===0&&kIe[n.commandName]){let e=Error(`S3 aborted request`);throw e.$metadata={httpStatusCode:503},e.name=`InternalError`,e}let l=e.utf8Encoder(c.subarray(c.length-16));return l&&l.endsWith(``)&&(a.statusCode=503),i},jIe=(e=new Uint8Array,t)=>e instanceof Uint8Array?Promise.resolve(e):t.streamCollector(e)||Promise.resolve(new Uint8Array),MIe={relation:`after`,toMiddleware:`deserializerMiddleware`,tags:[`THROW_200_EXCEPTIONS`,`S3`],name:`throw200ExceptionsMiddleware`,override:!0},X4=e=>({applyToStack:t=>{t.addRelativeTo(AIe(e),MIe)}}),NIe=e=>typeof e==`string`&&e.indexOf(`arn:`)===0&&e.split(`:`).length>=6;function PIe(e){return(t,n)=>async r=>{if(e.bucketEndpoint){let e=n.endpointV2;if(e){let t=r.input.Bucket;if(typeof t==`string`)try{let r=new URL(t);n.endpointV2={...e,url:r}}catch(e){let r=`@aws-sdk/middleware-sdk-s3: bucketEndpoint=true was set but Bucket=${t} could not be parsed as URL.`;throw n.logger?.constructor?.name===`NoOpLogger`?console.warn(r):n.logger?.warn?.(r),e}}}return t(r)}}var FIe={name:`bucketEndpointMiddleware`,override:!0,relation:`after`,toMiddleware:`endpointV2Middleware`};function IIe({bucketEndpoint:e}){return t=>async n=>{let{input:{Bucket:r}}=n;if(!e&&typeof r==`string`&&!NIe(r)&&r.indexOf(`/`)>=0){let e=Error(`Bucket name shouldn't contain '/', received '${r}'`);throw e.name=`InvalidBucketName`,e}return t({...n})}}var LIe={step:`initialize`,tags:[`VALIDATE_BUCKET_NAME`],name:`validateBucketNameMiddleware`,override:!0},RIe=e=>({applyToStack:t=>{t.add(IIe(e),LIe),t.addRelativeTo(PIe(e),FIe)}}),zIe=class extends sde{async serializeRequest(e,t,n){let r=await super.serializeRequest(e,t,n),i=TO.of(e.input),a=i.getSchema(),o=0,s=a[6]??0;if(t&&typeof t==`object`)for(let[e,n]of i.structIterator()){if(++o>s)break;if(e===`Bucket`){if(!t.Bucket&&n.getMergedTraits().httpLabel)throw Error(`No value provided for input HTTP label: Bucket.`);break}}return r}},BIe=e=>Object.assign(e,{eventStreamMarshaller:e.eventStreamSerdeProvider(e)}),Z4={CrtSignerV4:null},Q4=class{sigv4aSigner;sigv4Signer;signerOptions;static sigv4aDependency(){return typeof Z4.CrtSignerV4==`function`?`crt`:typeof px.SignatureV4a==`function`?`js`:`none`}constructor(e){this.sigv4Signer=new vIe(e),this.signerOptions=e}async sign(e,t={}){return t.signingRegion===`*`?this.getSigv4aSigner().sign(e,t):this.sigv4Signer.sign(e,t)}async signWithCredentials(e,t,n={}){if(n.signingRegion===`*`){let r=this.getSigv4aSigner(),i=Z4.CrtSignerV4;if(i&&r instanceof i)return r.signWithCredentials(e,t,n);throw Error(`signWithCredentials with signingRegion '*' is only supported when using the CRT dependency @aws-sdk/signature-v4-crt. Please check whether you have installed the "@aws-sdk/signature-v4-crt" package explicitly. You must also register the package by calling [require("@aws-sdk/signature-v4-crt");] or an ESM equivalent such as [import "@aws-sdk/signature-v4-crt";]. For more information please go to https://github.com/aws/aws-sdk-js-v3#functionality-requiring-aws-common-runtime-crt`)}return this.sigv4Signer.signWithCredentials(e,t,n)}async presign(e,t={}){if(t.signingRegion===`*`){let n=this.getSigv4aSigner(),r=Z4.CrtSignerV4;if(r&&n instanceof r)return n.presign(e,t);throw Error(`presign with signingRegion '*' is only supported when using the CRT dependency @aws-sdk/signature-v4-crt. Please check whether you have installed the "@aws-sdk/signature-v4-crt" package explicitly. You must also register the package by calling [require("@aws-sdk/signature-v4-crt");] or an ESM equivalent such as [import "@aws-sdk/signature-v4-crt";]. For more information please go to https://github.com/aws/aws-sdk-js-v3#functionality-requiring-aws-common-runtime-crt`)}return this.sigv4Signer.presign(e,t)}async presignWithCredentials(e,t,n={}){if(n.signingRegion===`*`)throw Error(`Method presignWithCredentials is not supported for [signingRegion=*].`);return this.sigv4Signer.presignWithCredentials(e,t,n)}getSigv4aSigner(){if(!this.sigv4aSigner){let e=Z4.CrtSignerV4,t=px.SignatureV4a;if(this.signerOptions.runtime===`node`){if(!e&&!t)throw Error(`Neither CRT nor JS SigV4a implementation is available. Please load either @aws-sdk/signature-v4-crt or @aws-sdk/signature-v4a. For more information please go to https://github.com/aws/aws-sdk-js-v3#functionality-requiring-aws-common-runtime-crt`);if(e&&typeof e==`function`)this.sigv4aSigner=new e({...this.signerOptions,signingAlgorithm:1});else if(t&&typeof t==`function`)this.sigv4aSigner=new t({...this.signerOptions});else throw Error(`Available SigV4a implementation is not a valid constructor. Please ensure you've properly imported @aws-sdk/signature-v4-crt or @aws-sdk/signature-v4a.For more information please go to https://github.com/aws/aws-sdk-js-v3#functionality-requiring-aws-common-runtime-crt`)}else{if(!t||typeof t!=`function`)throw Error(`JS SigV4a implementation is not available or not a valid constructor. Please check whether you have installed the @aws-sdk/signature-v4a package explicitly. The CRT implementation is not available for browsers. You must also register the package by calling [require('@aws-sdk/signature-v4a');] or an ESM equivalent such as [import '@aws-sdk/signature-v4a';]. For more information please go to https://github.com/aws/aws-sdk-js-v3#using-javascript-non-crt-implementation-of-sigv4a`);this.sigv4aSigner=new t({...this.signerOptions})}}return this.sigv4aSigner}},$4=`ref`,e3=`argv`,t3=`backend`,n3=`authSchemes`,r3=`disableDoubleEncoding`,i3=`signingName`,a3=`signingRegion`,o3=`signingRegionSet`,s3=-1,c3=!0,l3=!1,u3=`isSet`,d3=`booleanEquals`,f3=`stringEquals`,p3=`coalesce`,m3=`substring`,h3=``,g3=`aws.partition`,_3=`partitionResult`,v3=`accessPointSuffix`,y3=`regionPrefix`,b3=e=>`outpostId_ssa_`+e+h3,x3=`hardwareType`,S3=`ite`,C3=`isValidHostLabel`,w3=`sigv4`,T3=`aws.isVirtualHostableS3Bucket`,E3=`url`,D3=`getAttr`,O3=`bucketArn`,k3=`--`,A3=`arnType`,j3=`accesspoint`,M3=e=>`accessPointName_ssa_`+e+h3,N3=`s3-object-lambda`,P3=`s3-outposts`,F3=`bucketPartition`,I3=`us-east-1`,L3=`outpostType`,R3=`name`,z3=`s3`,B3=`{url#scheme}://{Bucket}.{url#authority}{url#path}`,V3=`{url#scheme}://{url#authority}{url#path}`,H3=`{url#scheme}://{url#authority}{url#normalizedPath}{Bucket}`,U3=`https://{Bucket}.s3-accelerate.{partitionResult#dnsSuffix}`,W3=`https://{Bucket}.s3.{partitionResult#dnsSuffix}`,G3=e=>`{url#scheme}://{accessPointName_ssa_`+e+`}-{bucketArn#accountId}.{url#authority}{url#path}`,K3=e=>"Invalid ARN: The access point name may only contain a-z, A-Z, 0-9 and `-`. Found: `{accessPointName_ssa_"+e+"}`",q3=`sigv4a`,J3=`{url#scheme}://{url#authority}{url#normalizedPath}{uri_encoded_bucket}`,Y3=`https://s3.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,X3=`https://s3.{partitionResult#dnsSuffix}`,Z3={[$4]:`UseFIPS`},Q3={[$4]:`UseDualStack`},$3={[$4]:`Bucket`},e6={fn:D3,[e3]:[{[$4]:_3},R3]},t6={[$4]:E3},n6={[$4]:`Region`},r6={[$4]:O3},i6={[$4]:A3},a6={[$4]:`accessPointName_ssa_1`},o6={fn:D3,[e3]:[r6,`region`]},s6={[$4]:x3},c6={fn:D3,[e3]:[r6,`service`]},l6={fn:D3,[e3]:[r6,`accountId`]},u6={[t3]:`S3Express`,[n3]:[{[r3]:!0,[R3]:`{_s3e_auth}`,[i3]:`s3express`,[a3]:`{Region}`}]},d6={[t3]:`S3Express`,[n3]:[{[r3]:!0,[R3]:w3,[i3]:`s3express`,[a3]:`{Region}`}]},f6={[n3]:[{[r3]:!0,[R3]:q3,[i3]:P3,[o3]:[`*`]},{[r3]:!0,[R3]:w3,[i3]:P3,[a3]:`{Region}`}]},p6={[n3]:[{[r3]:!0,[R3]:w3,[i3]:z3,[a3]:I3}]},m6={[n3]:[{[r3]:!0,[R3]:w3,[i3]:z3,[a3]:`{Region}`}]},h6={[n3]:[{[r3]:!0,[R3]:w3,[i3]:N3,[a3]:`{bucketArn#region}`}]},g6={[n3]:[{[r3]:!0,[R3]:w3,[i3]:z3,[a3]:`{bucketArn#region}`}]},_6={[n3]:[{[r3]:!0,[R3]:q3,[i3]:P3,[o3]:[`*`]},{[r3]:!0,[R3]:w3,[i3]:P3,[a3]:`{bucketArn#region}`}]},v6={[n3]:[{[r3]:!0,[R3]:w3,[i3]:N3,[a3]:`{Region}`}]},y6=[n6],b6=[{[$4]:`Endpoint`}],x6=[$3],S6=[$3,0,7,!0],C6=[r6,`resourceId[1]`],VIe=[`*`],w6={conditions:[[u3,y6],[d3,[{[$4]:`Accelerate`},c3]],[d3,[Z3,c3]],[d3,[Q3,c3]],[u3,b6],[u3,x6],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,0,6,c3]},h3]},`--x-s3`]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:S6},h3]},`--xa-s3`]],[g3,y6,_3],[m3,S6,v3],[f3,[{[$4]:v3},`--op-s3`]],[m3,[$3,8,12,c3],y3],[m3,[$3,32,49,c3],b3(2)],[m3,[$3,49,50,c3],x3],[d3,[{[$4]:`ForcePathStyle`},c3]],[f3,[e6,`aws-cn`]],[S3,[Q3,`.dualstack`,h3],`_s3e_ds`],[C3,[{[$4]:b3(2)},l3]],[S3,[Z3,`-fips`,h3],`_s3e_fips`],[S3,[{fn:p3,[e3]:[{[$4]:`DisableS3ExpressSessionAuth`},l3]},w3,`sigv4-s3express`],`_s3e_auth`],[T3,[$3,l3]],[`parseURL`,b6,E3],[d3,[{fn:p3,[e3]:[{[$4]:`UseS3ExpressControlEndpoint`},l3]},c3]],[T3,[$3,c3]],[f3,[{fn:D3,[e3]:[t6,`scheme`]},`http`]],[C3,[n6,l3]],[`aws.parseArn`,x6,O3],[D3,[{fn:`split`,[e3]:[$3,k3,0]},`[-2]`],`s3expressAvailabilityZoneId`],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,0,4,l3]},h3]},`arn:`]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,16,18,c3]},h3]},k3]],[d3,[{fn:D3,[e3]:[t6,`isIp`]},c3]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,21,23,c3]},h3]},k3]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,27,29,c3]},h3]},k3]],[f3,[{[$4]:y3},`beta`]],[`uriEncode`,x6,`uri_encoded_bucket`],[C3,[n6,c3]],[d3,[{fn:p3,[e3]:[{[$4]:`UseObjectLambdaEndpoint`},l3]},c3]],[D3,[r6,`resourceId[0]`],A3],[f3,[i6,h3]],[f3,[i6,j3]],[D3,C6,M3(1)],[f3,[a6,h3]],[f3,[o6,h3]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,14,16,c3]},h3]},k3]],[f3,[s6,`e`]],[f3,[s6,`o`]],[f3,[n6,`aws-global`]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,19,21,c3]},h3]},k3]],[f3,[c6,N3]],[d3,[{fn:p3,[e3]:[{[$4]:`DisableAccessPoints`},l3]},c3]],[f3,[c6,P3]],[g3,[o6],F3],[C3,[a6,c3]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,26,28,c3]},h3]},k3]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,15,17,c3]},h3]},k3]],[D3,[r6,`resourceId[4]`]],[f3,[{fn:p3,[e3]:[{fn:m3,[e3]:[$3,20,22,c3]},h3]},k3]],[d3,[{[$4]:`UseGlobalEndpoint`},c3]],[f3,[n6,I3]],[D3,C6,b3(1)],[d3,[{fn:p3,[e3]:[{[$4]:`UseArnRegion`},c3]},c3]],[C3,[{[$4]:b3(1)},l3]],[D3,[r6,`resourceId[2]`],L3],[f3,[n6,o6]],[f3,[{fn:D3,[e3]:[{[$4]:F3},R3]},e6]],[d3,[{[$4]:`DisableMultiRegionAccessPoints`},c3]],[C3,[o6,c3]],[f3,[{fn:D3,[e3]:[r6,`partition`]},e6]],[f3,[l6,h3]],[f3,[c6,z3]],[C3,[l6,l3]],[D3,[r6,`resourceId[3]`],M3(2)],[C3,[a6,l3]],[f3,[{[$4]:L3},j3]],[C3,[{[$4]:M3(2)},l3]]],results:[[s3],[s3,`Accelerate cannot be used with FIPS`],[s3,`Cannot set dual-stack in combination with a custom endpoint.`],[s3,`A custom endpoint cannot be combined with FIPS`],[s3,`A custom endpoint cannot be combined with S3 Accelerate`],[s3,`Partition does not support FIPS`],[s3,`S3Express does not support S3 Accelerate.`],[`{url#scheme}://{url#authority}/{uri_encoded_bucket}{url#path}`,u6],[B3,u6],[s3,`S3Express bucket name is not a valid virtual hostable name.`],[`https://s3express-control{_s3e_fips}{_s3e_ds}.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,d6],[`https://{Bucket}.s3express{_s3e_fips}-{s3expressAvailabilityZoneId}{_s3e_ds}.{Region}.{partitionResult#dnsSuffix}`,u6],[s3,`Unrecognized S3Express bucket name format.`],[V3,u6],[`https://s3express-control{_s3e_fips}{_s3e_ds}.{Region}.{partitionResult#dnsSuffix}`,d6],[s3,`Expected a endpoint to be specified but no endpoint was found`],[`https://{Bucket}.ec2.{url#authority}`,f6],[`https://{Bucket}.ec2.s3-outposts.{Region}.{partitionResult#dnsSuffix}`,f6],[`https://{Bucket}.op-{outpostId_ssa_2}.{url#authority}`,f6],[`https://{Bucket}.op-{outpostId_ssa_2}.s3-outposts.{Region}.{partitionResult#dnsSuffix}`,f6],[s3,`Unrecognized hardware type: "Expected hardware type o or e but got {hardwareType}"`],[s3,`Invalid Outposts Bucket alias - it must be a valid bucket name.`],[s3,"Invalid ARN: The outpost Id must only contain a-z, A-Z, 0-9 and `-`."],[s3,"Custom endpoint `{Endpoint}` was not a valid URI"],[s3,`S3 Accelerate cannot be used in this region`],[`https://{Bucket}.s3-fips.dualstack.us-east-1.{partitionResult#dnsSuffix}`,p6],[`https://{Bucket}.s3-fips.dualstack.{Region}.{partitionResult#dnsSuffix}`,m6],[`https://{Bucket}.s3-fips.us-east-1.{partitionResult#dnsSuffix}`,p6],[`https://{Bucket}.s3-fips.{Region}.{partitionResult#dnsSuffix}`,m6],[`https://{Bucket}.s3-accelerate.dualstack.us-east-1.{partitionResult#dnsSuffix}`,p6],[`https://{Bucket}.s3-accelerate.dualstack.{partitionResult#dnsSuffix}`,m6],[`https://{Bucket}.s3.dualstack.us-east-1.{partitionResult#dnsSuffix}`,p6],[`https://{Bucket}.s3.dualstack.{Region}.{partitionResult#dnsSuffix}`,m6],[H3,p6],[B3,p6],[H3,m6],[B3,m6],[U3,p6],[U3,m6],[W3,p6],[W3,m6],[`https://{Bucket}.s3.{Region}.{partitionResult#dnsSuffix}`,m6],[s3,`Invalid region: region was not a valid DNS name.`],[s3,`S3 Object Lambda does not support Dual-stack`],[s3,`S3 Object Lambda does not support S3 Accelerate`],[s3,`Access points are not supported for this operation`],[s3,"Invalid configuration: region from ARN `{bucketArn#region}` does not match client region `{Region}` and UseArnRegion is `false`"],[s3,`Invalid ARN: Missing account id`],[G3(1),h6],[`https://{accessPointName_ssa_1}-{bucketArn#accountId}.s3-object-lambda-fips.{bucketArn#region}.{bucketPartition#dnsSuffix}`,h6],[`https://{accessPointName_ssa_1}-{bucketArn#accountId}.s3-object-lambda.{bucketArn#region}.{bucketPartition#dnsSuffix}`,h6],[s3,K3(1)],[s3,"Invalid ARN: The account id may only contain a-z, A-Z, 0-9 and `-`. Found: `{bucketArn#accountId}`"],[s3,"Invalid region in ARN: `{bucketArn#region}` (invalid DNS name)"],[s3,"Client was configured for partition `{partitionResult#name}` but ARN (`{Bucket}`) has `{bucketPartition#name}`"],[s3,"Invalid ARN: The ARN may only contain a single resource component after `accesspoint`."],[s3,`Invalid ARN: bucket ARN is missing a region`],[s3,"Invalid ARN: Expected a resource of the format `accesspoint:` but no name was provided"],[s3,"Invalid ARN: Object Lambda ARNs only support `accesspoint` arn types, but found: `{arnType}`"],[s3,`Access Points do not support S3 Accelerate`],[`https://{accessPointName_ssa_1}-{bucketArn#accountId}.s3-accesspoint-fips.dualstack.{bucketArn#region}.{bucketPartition#dnsSuffix}`,g6],[`https://{accessPointName_ssa_1}-{bucketArn#accountId}.s3-accesspoint-fips.{bucketArn#region}.{bucketPartition#dnsSuffix}`,g6],[`https://{accessPointName_ssa_1}-{bucketArn#accountId}.s3-accesspoint.dualstack.{bucketArn#region}.{bucketPartition#dnsSuffix}`,g6],[G3(1),g6],[`https://{accessPointName_ssa_1}-{bucketArn#accountId}.s3-accesspoint.{bucketArn#region}.{bucketPartition#dnsSuffix}`,g6],[s3,`Invalid ARN: The ARN was not for the S3 service, found: {bucketArn#service}`],[s3,`S3 MRAP does not support dual-stack`],[s3,`S3 MRAP does not support FIPS`],[s3,`S3 MRAP does not support S3 Accelerate`],[s3,`Invalid configuration: Multi-Region Access Point ARNs are disabled.`],[`https://{accessPointName_ssa_1}.accesspoint.s3-global.{partitionResult#dnsSuffix}`,{[n3]:[{[r3]:c3,name:q3,[i3]:z3,[o3]:VIe}]}],[s3,"Client was configured for partition `{partitionResult#name}` but bucket referred to partition `{bucketArn#partition}`"],[s3,`Invalid Access Point Name`],[s3,`S3 Outposts does not support Dual-stack`],[s3,`S3 Outposts does not support FIPS`],[s3,`S3 Outposts does not support S3 Accelerate`],[s3,`Invalid Arn: Outpost Access Point ARN contains sub resources`],[`https://{accessPointName_ssa_2}-{bucketArn#accountId}.{outpostId_ssa_1}.{url#authority}`,_6],[`https://{accessPointName_ssa_2}-{bucketArn#accountId}.{outpostId_ssa_1}.s3-outposts.{bucketArn#region}.{bucketPartition#dnsSuffix}`,_6],[s3,K3(2)],[s3,"Expected an outpost type `accesspoint`, found {outpostType}"],[s3,`Invalid ARN: expected an access point name`],[s3,`Invalid ARN: Expected a 4-component resource`],[s3,"Invalid ARN: The outpost Id may only contain a-z, A-Z, 0-9 and `-`. Found: `{outpostId_ssa_1}`"],[s3,`Invalid ARN: The Outpost Id was not set`],[s3,`Invalid ARN: Unrecognized format: {Bucket} (type: {arnType})`],[s3,`Invalid ARN: No ARN type specified`],[s3,"Invalid ARN: `{Bucket}` was not a valid ARN"],[s3,`Path-style addressing cannot be used with ARN buckets`],[`https://s3-fips.dualstack.us-east-1.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,p6],[`https://s3-fips.dualstack.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,m6],[`https://s3-fips.us-east-1.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,p6],[`https://s3-fips.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,m6],[`https://s3.dualstack.us-east-1.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,p6],[`https://s3.dualstack.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,m6],[J3,p6],[J3,m6],[Y3,p6],[Y3,m6],[`https://s3.{Region}.{partitionResult#dnsSuffix}/{uri_encoded_bucket}`,m6],[s3,`Path-style addressing cannot be used with S3 Accelerate`],[V3,v6],[`https://s3-object-lambda-fips.{Region}.{partitionResult#dnsSuffix}`,v6],[`https://s3-object-lambda.{Region}.{partitionResult#dnsSuffix}`,v6],[`https://s3-fips.dualstack.us-east-1.{partitionResult#dnsSuffix}`,p6],[`https://s3-fips.dualstack.{Region}.{partitionResult#dnsSuffix}`,m6],[`https://s3-fips.us-east-1.{partitionResult#dnsSuffix}`,p6],[`https://s3-fips.{Region}.{partitionResult#dnsSuffix}`,m6],[`https://s3.dualstack.us-east-1.{partitionResult#dnsSuffix}`,p6],[`https://s3.dualstack.{Region}.{partitionResult#dnsSuffix}`,m6],[V3,p6],[V3,m6],[X3,p6],[X3,m6],[`https://s3.{Region}.{partitionResult#dnsSuffix}`,m6],[s3,`A region must be set when sending requests to S3.`]]},HIe=2,Z=1e8,UIe=new Int32Array([-1,1,-1,0,3,Z+115,1,424,4,2,272,5,3,233,6,4,85,7,5,15,8,8,9,Z+115,16,10,13,18,11,13,19,12,13,22,Z+14,13,35,14,Z+42,36,Z+103,435,6,271,16,7,270,17,8,19,18,14,501,106,9,20,24,10,21,24,11,22,24,12,23,24,13,547,24,14,77,25,20,73,26,26,27,78,37,28,Z+86,38,Z+86,29,39,47,30,48,Z+58,31,50,32,Z+85,51,33,136,55,Z+76,34,59,35,Z+84,60,39,36,61,37,Z+83,62,38,146,63,41,Z+46,61,40,Z+83,62,41,150,64,42,Z+54,66,43,Z+53,70,44,Z+52,71,45,Z+81,73,46,Z+80,74,Z+78,Z+79,40,48,Z+57,41,Z+57,49,42,185,50,48,62,51,49,Z+45,52,51,53,526,60,56,54,62,Z+55,55,63,57,Z+46,62,Z+55,57,64,58,Z+54,66,59,Z+53,69,60,Z+65,70,61,Z+52,72,Z+64,Z+51,49,Z+45,63,51,64,526,60,67,65,62,Z+55,66,63,68,Z+46,62,Z+55,68,64,69,Z+54,66,70,Z+53,68,Z+47,71,70,72,Z+52,72,Z+50,Z+51,25,74,Z+42,46,Z+39,75,57,76,Z+41,58,Z+40,Z+41,26,Z+88,78,28,Z+87,79,34,82,80,35,81,545,36,Z+103,Z+115,46,Z+97,83,57,84,Z+99,58,Z+98,Z+99,5,101,86,8,87,Z+115,16,88,89,18,91,89,19,90,92,21,97,95,19,93,92,21,98,95,21,97,94,22,Z+14,95,35,96,Z+42,36,Z+103,Z+42,22,Z+13,98,35,99,Z+42,36,Z+101,100,46,Z+110,Z+111,6,214,102,7,208,103,8,119,104,14,118,105,21,106,Z+23,26,107,502,37,108,Z+86,38,Z+86,109,39,112,110,48,Z+58,111,50,136,Z+85,40,113,Z+57,41,Z+57,114,42,115,500,48,Z+56,116,52,117,Z+72,65,Z+69,Z+72,21,501,Z+23,9,120,124,10,121,124,11,122,124,12,123,124,13,202,124,14,195,125,20,190,126,21,127,Z+23,23,128,129,24,189,129,26,130,197,37,131,Z+86,38,Z+86,132,39,159,133,48,Z+58,134,50,135,Z+85,51,141,136,55,Z+76,137,59,138,Z+84,60,Z+83,139,61,140,Z+83,63,Z+83,Z+46,55,Z+76,142,59,143,Z+84,60,148,144,61,145,Z+83,62,147,146,63,150,Z+46,63,153,Z+46,61,149,Z+83,62,153,150,64,151,Z+54,66,152,Z+53,70,Z+82,Z+52,64,154,Z+54,66,155,Z+53,70,156,Z+52,71,157,Z+81,73,158,Z+80,74,Z+77,Z+79,40,160,Z+57,41,Z+57,161,42,185,162,48,174,163,49,Z+45,164,51,165,526,60,168,166,62,Z+55,167,63,169,Z+46,62,Z+55,169,64,170,Z+54,66,171,Z+53,69,172,Z+65,70,173,Z+52,72,Z+63,Z+51,49,Z+45,175,51,176,526,60,179,177,62,Z+55,178,63,180,Z+46,62,Z+55,180,64,181,Z+54,66,182,Z+53,68,Z+47,183,70,184,Z+52,72,Z+48,Z+51,48,Z+56,186,52,187,Z+72,65,Z+69,188,67,Z+70,Z+71,25,Z+36,Z+42,21,191,Z+23,25,192,Z+42,30,194,193,46,Z+34,Z+36,46,Z+33,Z+35,21,196,Z+23,26,Z+88,197,28,Z+87,198,34,201,199,35,200,545,36,Z+101,Z+115,46,Z+95,Z+96,17,203,Z+22,20,204,Z+21,21,205,550,33,206,550,44,Z+16,207,45,Z+18,Z+20,8,209,215,16,210,220,18,211,220,19,212,224,20,213,227,21,231,401,8,218,215,19,216,Z+9,20,217,227,21,231,Z+9,16,219,220,18,223,220,19,221,224,20,222,227,21,231,Z+12,19,226,224,20,225,Z+9,21,Z+9,Z+12,20,230,227,21,228,Z+9,30,229,Z+9,34,Z+7,Z+9,21,231,415,30,232,Z+8,34,Z+7,Z+8,4,Z+2,234,5,235,480,6,271,236,7,270,237,8,238,491,9,239,243,10,240,243,11,241,243,12,242,243,13,547,243,14,266,244,20,264,245,26,246,267,37,247,Z+86,38,Z+86,248,39,249,518,40,250,Z+57,41,Z+57,251,42,538,252,48,Z+43,253,49,Z+45,254,51,255,526,60,258,256,62,Z+55,257,63,259,Z+46,62,Z+55,259,64,260,Z+54,66,261,Z+53,69,262,Z+65,70,263,Z+52,72,Z+62,Z+51,25,265,Z+42,46,Z+31,Z+32,26,Z+88,267,28,Z+87,268,34,269,544,46,Z+93,Z+94,8,397,Z+9,8,407,Z+9,3,346,273,4,Z+3,274,5,284,275,8,276,Z+115,15,Z+5,277,16,278,281,18,279,281,19,280,281,22,Z+14,281,35,282,Z+42,36,Z+102,283,46,Z+106,Z+107,6,405,285,7,395,286,8,295,287,14,501,288,26,289,502,37,290,Z+86,38,Z+86,291,39,292,307,40,293,Z+57,41,Z+57,294,42,335,500,9,296,300,10,297,300,11,298,300,12,299,300,13,394,300,14,339,301,15,Z+5,302,20,337,303,26,304,341,37,305,Z+86,38,Z+86,306,39,309,307,48,Z+58,308,50,Z+74,Z+85,40,310,Z+57,41,Z+57,311,42,335,312,48,324,313,49,Z+45,314,51,315,526,60,318,316,62,Z+55,317,63,319,Z+46,62,Z+55,319,64,320,Z+54,66,321,Z+53,69,322,Z+65,70,323,Z+52,72,Z+61,Z+51,49,Z+45,325,51,326,526,60,329,327,62,Z+55,328,63,330,Z+46,62,Z+55,330,64,331,Z+54,66,332,Z+53,68,Z+47,333,70,334,Z+52,72,Z+49,Z+51,48,Z+56,336,52,Z+67,Z+72,25,338,Z+42,46,Z+27,Z+28,15,Z+5,340,26,Z+88,341,28,Z+87,342,34,345,343,35,344,545,36,Z+102,Z+115,46,Z+91,Z+92,4,Z+2,347,5,357,348,8,349,Z+115,15,Z+5,350,16,351,354,18,352,354,19,353,354,22,Z+14,354,35,355,Z+42,36,Z+43,356,46,Z+104,Z+105,6,405,358,7,395,359,8,360,491,9,361,365,10,362,365,11,363,365,12,364,365,13,394,365,14,389,366,15,Z+5,367,20,387,368,26,369,391,37,370,Z+86,38,Z+86,371,39,372,518,40,373,Z+57,41,Z+57,374,42,538,375,48,Z+43,376,49,Z+45,377,51,378,526,60,381,379,62,Z+55,380,63,382,Z+46,62,Z+55,382,64,383,Z+54,66,384,Z+53,69,385,Z+65,70,386,Z+52,72,Z+60,Z+51,25,388,Z+42,46,Z+25,Z+26,15,Z+5,390,26,Z+88,391,28,Z+87,392,34,393,544,46,Z+89,Z+90,15,Z+5,547,8,396,Z+9,15,Z+5,397,16,398,410,18,399,410,19,400,410,20,401,Z+9,27,402,Z+12,29,Z+11,403,31,Z+11,404,32,Z+11,422,8,406,Z+9,15,Z+5,407,16,408,410,18,409,410,19,411,410,20,Z+12,Z+9,20,414,412,22,413,Z+9,34,Z+10,Z+9,22,416,415,27,419,Z+12,27,418,417,34,Z+10,Z+12,34,Z+10,419,43,Z+11,420,47,Z+11,421,53,Z+11,422,54,Z+11,423,56,Z+11,Z+12,2,Z+1,425,3,478,426,4,Z+4,427,5,438,428,8,429,Z+115,16,430,433,18,431,433,19,432,433,22,Z+14,433,35,434,Z+42,36,Z+44,435,46,Z+112,436,57,437,Z+114,58,Z+113,Z+114,6,Z+6,439,7,Z+6,440,8,450,441,14,501,442,26,443,502,37,444,Z+86,38,Z+86,445,39,446,465,40,447,Z+57,41,Z+57,448,42,471,449,48,Z+44,500,9,451,455,10,452,455,11,453,455,12,454,455,13,547,455,14,473,456,15,460,457,20,458,461,25,459,Z+42,46,Z+37,Z+38,20,540,461,26,462,474,37,463,Z+86,38,Z+86,464,39,467,465,48,Z+58,466,50,Z+75,Z+85,40,468,Z+57,41,Z+57,469,42,471,470,48,Z+44,524,48,Z+44,472,52,Z+68,Z+72,26,Z+88,474,28,Z+87,475,34,Z+100,476,35,477,545,36,Z+44,Z+115,4,Z+2,479,5,488,480,8,481,Z+115,16,482,485,18,483,485,19,484,485,22,Z+14,485,35,486,Z+42,36,Z+43,487,46,Z+108,Z+109,6,Z+6,489,7,Z+6,490,8,503,491,14,501,492,26,493,502,37,494,Z+86,38,Z+86,495,39,496,518,40,497,Z+57,41,Z+57,498,42,538,499,48,Z+43,500,49,Z+45,526,26,Z+88,502,28,Z+87,Z+115,9,504,508,10,505,508,11,506,508,12,507,508,13,547,508,14,541,509,15,513,510,20,511,514,25,512,Z+42,46,Z+29,Z+30,20,540,514,26,515,542,37,516,Z+86,38,Z+86,517,39,520,518,48,Z+58,519,50,Z+73,Z+85,40,521,Z+57,41,Z+57,522,42,538,523,48,Z+43,524,49,Z+45,525,51,529,526,60,Z+55,527,62,Z+55,528,63,Z+55,Z+46,60,532,530,62,Z+55,531,63,533,Z+46,62,Z+55,533,64,534,Z+54,66,535,Z+53,69,536,Z+65,70,537,Z+52,72,Z+59,Z+51,48,Z+43,539,52,Z+66,Z+72,25,Z+24,Z+42,26,Z+88,542,28,Z+87,543,34,Z+100,544,35,546,545,36,Z+42,Z+115,36,Z+43,Z+115,17,548,Z+22,20,549,Z+21,33,552,550,44,Z+17,551,45,Z+19,Z+20,44,Z+15,553,45,Z+15,Z+20]),WIe=ak.from(UIe,HIe,w6.conditions,w6.results),GIe=new ok({size:50,params:[`Accelerate`,`Bucket`,`DisableAccessPoints`,`DisableMultiRegionAccessPoints`,`DisableS3ExpressSessionAuth`,`Endpoint`,`ForcePathStyle`,`Region`,`UseArnRegion`,`UseDualStack`,`UseFIPS`,`UseGlobalEndpoint`,`UseObjectLambdaEndpoint`,`UseS3ExpressControlEndpoint`]}),T6=(e,t={})=>GIe.get(e,()=>Sk(WIe,{endpointParams:e,logger:t.logger}));lk.aws=Tk;var KIe=(e=>async(t,n,r)=>{if(!r)throw Error("Could not find `input` for `defaultEndpointRuleSetHttpAuthSchemeParametersProvider`");let i=await e(t,n,r),a=lx(n)?.commandInstance?.constructor?.getEndpointParameterInstructions;if(!a)throw Error(`getEndpointParameterInstructions() is not defined on '${n.commandName}'`);let o=await Jk(r,{getEndpointParameterInstructions:a},t);return Object.assign(i,o)})(async(e,t,n)=>({operation:lx(t).operation,region:await ux(e.region)()||(()=>{throw Error("expected `region` to be configured for `aws.auth#sigv4`")})()}));function E6(e){return{schemeId:`aws.auth#sigv4`,signingProperties:{name:`s3`,region:e.region},propertiesExtractor:(e,t)=>({signingProperties:{config:e,context:t}})}}function D6(e){return{schemeId:`aws.auth#sigv4a`,signingProperties:{name:`s3`,region:e.region},propertiesExtractor:(e,t)=>({signingProperties:{config:e,context:t}})}}var qIe=((e,t,n)=>r=>{let i=e(r).properties?.authSchemes;if(!i)return t(r);let a=[];for(let e of i){let{name:t,properties:o={},...s}=e,c=t.toLowerCase();t!==c&&console.warn(`HttpAuthScheme has been normalized with lowercasing: '${t}' to '${c}'`);let l;if(c===`sigv4a`){l=`aws.auth#sigv4a`;let e=i.find(e=>{let t=e.name.toLowerCase();return t!==`sigv4a`&&t.startsWith(`sigv4`)});if(Q4.sigv4aDependency()===`none`&&e)continue}else if(c.startsWith(`sigv4`))l=`aws.auth#sigv4`;else throw Error(`Unknown HttpAuthScheme found in '@smithy.rules#endpointRuleSet': '${c}'`);let u=n[l];if(!u)throw Error(`Could not find HttpAuthOption create function for '${l}'`);let d=u(r);d.schemeId=l,d.signingProperties={...d.signingProperties||{},...s,...o},a.push(d)}return a})(T6,e=>{let t=[];switch(e.operation){default:t.push(E6(e)),t.push(D6(e))}return t},{"aws.auth#sigv4":E6,"aws.auth#sigv4a":D6}),JIe=e=>{let t=Lue(CA(e));return Object.assign(t,{authSchemePreference:ux(e.authSchemePreference??[])})},YIe=e=>Object.assign(e,{useFipsEndpoint:e.useFipsEndpoint??!1,useDualstackEndpoint:e.useDualstackEndpoint??!1,forcePathStyle:e.forcePathStyle??!1,useAccelerateEndpoint:e.useAccelerateEndpoint??!1,useGlobalEndpoint:e.useGlobalEndpoint??!1,disableMultiregionAccessPoints:e.disableMultiregionAccessPoints??!1,defaultSigningName:`s3`,clientContextParams:e.clientContextParams??{}}),O6={ForcePathStyle:{type:`clientContextParams`,name:`forcePathStyle`},UseArnRegion:{type:`clientContextParams`,name:`useArnRegion`},DisableMultiRegionAccessPoints:{type:`clientContextParams`,name:`disableMultiregionAccessPoints`},Accelerate:{type:`clientContextParams`,name:`useAccelerateEndpoint`},DisableS3ExpressSessionAuth:{type:`clientContextParams`,name:`disableS3ExpressSessionAuth`},UseGlobalEndpoint:{type:`builtInParams`,name:`useGlobalEndpoint`},UseFIPS:{type:`builtInParams`,name:`useFipsEndpoint`},Endpoint:{type:`builtInParams`,name:`endpoint`},Region:{type:`builtInParams`,name:`region`},UseDualStack:{type:`builtInParams`,name:`useDualstackEndpoint`}},k6=class e extends sA{constructor(t){super(t),Object.setPrototypeOf(this,e.prototype)}},XIe=class e extends k6{name=`NoSuchUpload`;$fault=`client`;constructor(t){super({name:`NoSuchUpload`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},ZIe=class e extends k6{name=`AccessDenied`;$fault=`client`;constructor(t){super({name:`AccessDenied`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},QIe=class e extends k6{name=`ObjectNotInActiveTierError`;$fault=`client`;constructor(t){super({name:`ObjectNotInActiveTierError`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},$Ie=class e extends k6{name=`BucketAlreadyExists`;$fault=`client`;constructor(t){super({name:`BucketAlreadyExists`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},eLe=class e extends k6{name=`BucketAlreadyOwnedByYou`;$fault=`client`;constructor(t){super({name:`BucketAlreadyOwnedByYou`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},tLe=class e extends k6{name=`NoSuchBucket`;$fault=`client`;constructor(t){super({name:`NoSuchBucket`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},nLe=class e extends k6{name=`InvalidObjectState`;$fault=`client`;StorageClass;AccessTier;constructor(t){super({name:`InvalidObjectState`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype),this.StorageClass=t.StorageClass,this.AccessTier=t.AccessTier}},rLe=class e extends k6{name=`NoSuchKey`;$fault=`client`;constructor(t){super({name:`NoSuchKey`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},iLe=class e extends k6{name=`NotFound`;$fault=`client`;constructor(t){super({name:`NotFound`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},aLe=class e extends k6{name=`EncryptionTypeMismatch`;$fault=`client`;constructor(t){super({name:`EncryptionTypeMismatch`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},oLe=class e extends k6{name=`InvalidRequest`;$fault=`client`;constructor(t){super({name:`InvalidRequest`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},sLe=class e extends k6{name=`InvalidWriteOffset`;$fault=`client`;constructor(t){super({name:`InvalidWriteOffset`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},cLe=class e extends k6{name=`TooManyParts`;$fault=`client`;constructor(t){super({name:`TooManyParts`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},lLe=class e extends k6{name=`IdempotencyParameterMismatch`;$fault=`client`;constructor(t){super({name:`IdempotencyParameterMismatch`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},uLe=class e extends k6{name=`ObjectAlreadyInActiveTierError`;$fault=`client`;constructor(t){super({name:`ObjectAlreadyInActiveTierError`,$fault:`client`,...t}),Object.setPrototypeOf(this,e.prototype)}},A6=`ACL`,dLe=`AccessDenied`,fLe=`AbortDate`,j6=`AccessKeyId`,pLe=`AbortMultipartUpload`,mLe=`AbortMultipartUploadOutput`,hLe=`AbortMultipartUploadRequest`,gLe=`AcceptRanges`,_Le=`AbortRuleId`,vLe=`AccessTier`,M6=`Bucket`,N6=`BucketArn`,yLe=`BucketAlreadyExists`,bLe=`BucketAlreadyOwnedByYou`,xLe=`BypassGovernanceRetention`,SLe=`BucketInfo`,P6=`BucketKeyEnabled`,CLe=`BucketNamespace`,F6=`BucketRegion`,I6=`Body`,L6=`Buckets`,R6=`ChecksumAlgorithm`,wLe=`CreateBucket`,z6=`CreateBucketConfiguration`,TLe=`CreateBucketOutput`,ELe=`CreateBucketRequest`,B6=`CacheControl`,V6=`ChecksumCRC32`,H6=`ChecksumCRC32C`,U6=`ChecksumCRC64NVME`,W6=`Cache-Control`,DLe=`CreationDate`,G6=`Content-Disposition`,K6=`ContentDisposition`,q6=`Content-Encoding`,J6=`ContentEncoding`,Y6=`ContentLanguage`,X6=`Content-Language`,Z6=`Content-Length`,Q6=`ContentLength`,$6=`Content-MD5`,e8=`ChecksumMD5`,t8=`ContentMD5`,OLe=`CompletedMultipartUpload`,kLe=`CompleteMultipartUploadOutput`,ALe=`CreateMultipartUploadOutput`,jLe=`CompleteMultipartUploadResult`,MLe=`CompleteMultipartUploadRequest`,NLe=`CreateMultipartUploadRequest`,n8=`CompleteMultipartUpload`,PLe=`CreateMultipartUpload`,FLe=`ChecksumMode`,ILe=`CommonPrefix`,LLe=`CommonPrefixList`,RLe=`CompletedPartList`,zLe=`CompletedPart`,BLe=`CommonPrefixes`,VLe=`ContentRange`,HLe=`Content-Range`,r8=`ChecksumSHA1`,i8=`ChecksumSHA256`,a8=`ChecksumSHA512`,ULe=`CreateSessionOutput`,WLe=`CreateSessionResult`,GLe=`CreateSessionRequest`,KLe=`CreateSession`,o8=`ChecksumType`,s8=`Content-Type`,c8=`ContentType`,l8=`ContinuationToken`,u8=`ChecksumXXHASH64`,d8=`ChecksumXXHASH3`,f8=`ChecksumXXHASH128`,qLe=`Contents`,p8=`Credentials`,m8=`DeleteMarker`,JLe=`DisplayName`,YLe=`DeleteObjectOutput`,XLe=`DeleteObjectRequest`,ZLe=`DeleteObject`,QLe=`DataRedundancy`,h8=`Delimiter`,g8=`Expiration`,_8=`ExpectedBucketOwner`,v8=`ExpiresString`,$Le=`EncryptionTypeMismatch`,y8=`ETag`,b8=`EncodingType`,x8=`Expires`,eRe=`FetchOwner`,S8=`GrantFullControl`,tRe=`GetObject`,nRe=`GetObjectOutput`,rRe=`GetObjectRequest`,C8=`GrantRead`,w8=`GrantReadACP`,iRe=`GrantWrite`,T8=`GrantWriteACP`,aRe=`ID`,E8=`IfMatch`,oRe=`IfMatchInitiatedTime`,sRe=`IfMatchLastModifiedTime`,cRe=`IfMatchSize`,lRe=`If-Modified-Since`,uRe=`IfModifiedSince`,dRe=`InitiateMultipartUploadResult`,D8=`If-Match`,O8=`IfNoneMatch`,k8=`If-None-Match`,fRe=`InvalidObjectState`,pRe=`IdempotencyParameterMismatch`,mRe=`InvalidRequest`,hRe=`IsRestoreInProgress`,gRe=`IsTruncated`,_Re=`IfUnmodifiedSince`,vRe=`If-Unmodified-Since`,yRe=`InvalidWriteOffset`,A8=`Key`,bRe=`KeyCount`,j8=`Location`,xRe=`ListAllMyBucketsResult`,SRe=`ListBuckets`,CRe=`ListBucketsOutput`,wRe=`ListBucketsRequest`,TRe=`ListBucketResult`,ERe=`LocationConstraint`,DRe=`LocationInfo`,M8=`LastModified`,ORe=`Last-Modified`,kRe=`ListObjectsV2`,ARe=`ListObjectsV2Output`,jRe=`ListObjectsV2Request`,N8=`Metadata`,MRe=`MaxBuckets`,NRe=`MFA`,P8=`MaxKeys`,PRe=`MissingMeta`,FRe=`MpuObjectSize`,IRe=`MultipartUpload`,F8=`Name`,LRe=`NextContinuationToken`,RRe=`NotFound`,zRe=`NoSuchBucket`,BRe=`NoSuchKey`,VRe=`NoSuchUpload`,I8=`Owner`,HRe=`ObjectAlreadyInActiveTierError`,URe=`ObjectLockEnabledForBucket`,L8=`ObjectLockLegalHoldStatus`,R8=`ObjectLockMode`,z8=`ObjectLockRetainUntilDate`,WRe=`ObjectList`,GRe=`ObjectNotInActiveTierError`,KRe=`ObjectOwnership`,qRe=`OptionalObjectAttributes`,JRe=`Object`,B8=`Prefix`,YRe=`PartsCount`,V8=`PartNumber`,XRe=`PutObject`,ZRe=`PutObjectOutput`,QRe=`PutObjectRequest`,$Re=`PutObjectTagging`,eze=`PutObjectTaggingOutput`,tze=`PutObjectTaggingRequest`,nze=`Parts`,rze=`Part`,H8=`RequestCharged`,ize=`ResponseCacheControl`,aze=`ResponseContentDisposition`,oze=`ResponseContentEncoding`,sze=`ResponseContentLanguage`,cze=`ResponseContentType`,lze=`ResponseExpires`,uze=`RestoreExpiryDate`,U8=`RequestPayer`,dze=`ReplicationStatus`,W8=`RestoreStatus`,G8=`Range`,fze=`Restore`,K8=`StartAfter`,q8=`SecretAccessKey`,pze=`StreamingBlob`,J8=`StorageClass`,mze=`SessionCredentialValue`,hze=`SessionCredentials`,gze=`SessionMode`,Y8=`ServerSideEncryption`,X8=`SSECustomerAlgorithm`,Z8=`SSECustomerKey`,Q8=`SSECustomerKeyMD5`,$8=`SSEKMSEncryptionContext`,e5=`SSEKMSKeyId`,t5=`SessionToken`,n5=`Size`,_ze=`Tags`,vze=`TagCount`,yze=`TooManyParts`,r5=`TagSet`,i5=`Tag`,a5=`Tagging`,o5=`Type`,s5=`UploadId`,bze=`UploadPart`,xze=`UploadPartOutput`,Sze=`UploadPartRequest`,Cze=`Value`,c5=`VersionId`,wze=`WriteOffsetBytes`,l5=`WebsiteRedirectLocation`,Tze=`accept-ranges`,Eze=`bucket-region`,u5=`client`,d5=`continuation-token`,Dze=`delimiter`,f5=`error`,Oze=`encoding-type`,kze=`fetch-owner`,p5=`http`,m5=`httpChecksum`,h5=`httpError`,Q=`httpHeader`,g5=`httpPayload`,_5=`httpPrefixHeaders`,v5=`httpQuery`,Aze=`max-buckets`,jze=`max-keys`,y5=`prefix`,b5=`partNumber`,Mze=`response-cache-control`,Nze=`response-content-disposition`,Pze=`response-content-encoding`,Fze=`response-content-language`,Ize=`response-content-type`,Lze=`response-expires`,x5=`smithy.ts.sdk.synthetic.com.amazonaws.s3`,Rze=`start-after`,zze=`streaming`,S5=`uploadId`,C5=`versionId`,w5=`xmlFlattened`,T5=`xmlName`,E5=`x-amz-acl`,Bze=`x-amz-abort-date`,Vze=`x-amz-abort-rule-id`,Hze=`x-amz-bucket-arn`,Uze=`x-amz-bypass-governance-retention`,Wze=`x-amz-bucket-namespace`,Gze=`x-amz-bucket-object-lock-enabled`,D5=`x-amz-checksum-algorithm`,O5=`x-amz-checksum-crc32`,k5=`x-amz-checksum-crc32c`,A5=`x-amz-checksum-crc64nvme`,j5=`x-amz-checksum-md5`,Kze=`x-amz-checksum-mode`,M5=`x-amz-checksum-sha1`,N5=`x-amz-checksum-sha256`,P5=`x-amz-checksum-sha512`,qze=`x-amz-create-session-mode`,F5=`x-amz-checksum-type`,I5=`x-amz-checksum-xxhash64`,L5=`x-amz-checksum-xxhash3`,R5=`x-amz-checksum-xxhash128`,z5=`x-amz-delete-marker`,B5=`x-amz-expiration`,V5=`x-amz-expected-bucket-owner`,H5=`x-amz-grant-full-control`,U5=`x-amz-grant-read`,W5=`x-amz-grant-read-acp`,Jze=`x-amz-grant-write`,G5=`x-amz-grant-write-acp`,Yze=`x-amz-if-match-initiated-time`,Xze=`x-amz-if-match-last-modified-time`,Zze=`x-amz-if-match-size`,K5=`x-amz-meta-`,Qze=`x-amz-mfa`,$ze=`x-amz-missing-meta`,eBe=`x-amz-mp-object-size`,tBe=`x-amz-mp-parts-count`,q5=`x-amz-object-lock-legal-hold`,J5=`x-amz-object-lock-mode`,Y5=`x-amz-object-lock-retain-until-date`,nBe=`x-amz-object-ownership`,rBe=`x-amz-optional-object-attributes`,iBe=`x-amz-object-size`,aBe=`x-amz-restore`,X5=`x-amz-request-charged`,Z5=`x-amz-request-payer`,oBe=`x-amz-replication-status`,Q5=`x-amz-storage-class`,$5=`x-amz-sdk-checksum-algorithm`,e7=`x-amz-server-side-encryption`,t7=`x-amz-server-side-encryption-aws-kms-key-id`,n7=`x-amz-server-side-encryption-bucket-key-enabled`,r7=`x-amz-server-side-encryption-context`,i7=`x-amz-server-side-encryption-customer-algorithm`,a7=`x-amz-server-side-encryption-customer-key`,o7=`x-amz-server-side-encryption-customer-key-MD5`,s7=`x-amz-tagging`,sBe=`x-amz-tagging-count`,c7=`x-amz-version-id`,cBe=`x-amz-write-offset-bytes`,l7=`x-amz-website-redirect-location`,$=`com.amazonaws.s3`,u7=OO.for(x5),lBe=[-3,x5,`S3ServiceException`,0,[],[]];u7.registerError(lBe,k6);var d7=OO.for($),uBe=[-3,$,dLe,{[f5]:u5,[h5]:403},[],[]];d7.registerError(uBe,ZIe);var dBe=[-3,$,yLe,{[f5]:u5,[h5]:409},[],[]];d7.registerError(dBe,$Ie);var fBe=[-3,$,bLe,{[f5]:u5,[h5]:409},[],[]];d7.registerError(fBe,eLe);var pBe=[-3,$,$Le,{[f5]:u5,[h5]:400},[],[]];d7.registerError(pBe,aLe);var mBe=[-3,$,pRe,{[f5]:u5,[h5]:400},[],[]];d7.registerError(mBe,lLe);var hBe=[-3,$,fRe,{[f5]:u5,[h5]:403},[J8,vLe],[0,0]];d7.registerError(hBe,nLe);var gBe=[-3,$,mRe,{[f5]:u5,[h5]:400},[],[]];d7.registerError(gBe,oLe);var _Be=[-3,$,yRe,{[f5]:u5,[h5]:400},[],[]];d7.registerError(_Be,sLe);var vBe=[-3,$,zRe,{[f5]:u5,[h5]:404},[],[]];d7.registerError(vBe,tLe);var yBe=[-3,$,BRe,{[f5]:u5,[h5]:404},[],[]];d7.registerError(yBe,rLe);var bBe=[-3,$,VRe,{[f5]:u5,[h5]:404},[],[]];d7.registerError(bBe,XIe);var xBe=[-3,$,RRe,{[f5]:u5},[],[]];d7.registerError(xBe,iLe);var SBe=[-3,$,HRe,{[f5]:u5,[h5]:403},[],[]];d7.registerError(SBe,uLe);var CBe=[-3,$,GRe,{[f5]:u5,[h5]:403},[],[]];d7.registerError(CBe,QIe);var wBe=[-3,$,yze,{[f5]:u5,[h5]:400},[],[]];d7.registerError(wBe,cLe);var TBe=[u7,d7],f7=[0,$,mze,8,0],p7=[0,$,Z8,8,0],m7=[0,$,$8,8,0],h7=[0,$,e5,8,0],g7=[0,$,pze,{[zze]:1},42],EBe=[3,$,mLe,0,[H8],[[0,{[Q]:X5}]]],DBe=[3,$,hLe,0,[M6,A8,s5,U8,_8,oRe],[[0,1],[0,1],[0,{[v5]:S5}],[0,{[Q]:Z5}],[0,{[Q]:V5}],[6,{[Q]:Yze}]],3],OBe=[3,$,M6,0,[F8,DLe,F6,N6],[0,4,0,0]],kBe=[3,$,SLe,0,[QLe,o5],[0,0]],ABe=[3,$,ILe,0,[B8],[0]],jBe=[3,$,OLe,0,[nze],[[()=>uVe,{[w5]:1,[T5]:rze}]]],MBe=[3,$,zLe,0,[y8,V6,H6,U6,r8,i8,a8,e8,u8,d8,f8,V8],[0,0,0,0,0,0,0,0,0,0,0,1]],NBe=[3,$,kLe,{[T5]:jLe},[j8,M6,A8,g8,y8,V6,H6,U6,r8,i8,a8,e8,u8,d8,f8,o8,Y8,c5,e5,P6,H8],[0,0,0,[0,{[Q]:B5}],0,0,0,0,0,0,0,0,0,0,0,0,[0,{[Q]:e7}],[0,{[Q]:c7}],[()=>h7,{[Q]:t7}],[2,{[Q]:n7}],[0,{[Q]:X5}]]],PBe=[3,$,MLe,0,[M6,A8,s5,IRe,V6,H6,U6,r8,i8,a8,e8,u8,d8,f8,o8,FRe,U8,_8,E8,O8,X8,Z8,Q8],[[0,1],[0,1],[0,{[v5]:S5}],[()=>jBe,{[g5]:1,[T5]:n8}],[0,{[Q]:O5}],[0,{[Q]:k5}],[0,{[Q]:A5}],[0,{[Q]:M5}],[0,{[Q]:N5}],[0,{[Q]:P5}],[0,{[Q]:j5}],[0,{[Q]:I5}],[0,{[Q]:L5}],[0,{[Q]:R5}],[0,{[Q]:F5}],[1,{[Q]:eBe}],[0,{[Q]:Z5}],[0,{[Q]:V5}],[0,{[Q]:D8}],[0,{[Q]:k8}],[0,{[Q]:i7}],[()=>p7,{[Q]:a7}],[0,{[Q]:o7}]],3],FBe=[3,$,z6,0,[ERe,j8,M6,_ze],[0,()=>XBe,()=>kBe,[()=>v7,0]]],IBe=[3,$,TLe,0,[j8,N6],[[0,{[Q]:j8}],[0,{[Q]:Hze}]]],LBe=[3,$,ELe,0,[M6,A6,z6,S8,C8,w8,iRe,T8,URe,KRe,CLe],[[0,1],[0,{[Q]:E5}],[()=>FBe,{[g5]:1,[T5]:z6}],[0,{[Q]:H5}],[0,{[Q]:U5}],[0,{[Q]:W5}],[0,{[Q]:Jze}],[0,{[Q]:G5}],[2,{[Q]:Gze}],[0,{[Q]:nBe}],[0,{[Q]:Wze}]],1],RBe=[3,$,ALe,{[T5]:dRe},[fLe,_Le,M6,A8,s5,Y8,X8,Q8,e5,$8,P6,H8,R6,o8],[[4,{[Q]:Bze}],[0,{[Q]:Vze}],[0,{[T5]:M6}],0,0,[0,{[Q]:e7}],[0,{[Q]:i7}],[0,{[Q]:o7}],[()=>h7,{[Q]:t7}],[()=>m7,{[Q]:r7}],[2,{[Q]:n7}],[0,{[Q]:X5}],[0,{[Q]:D5}],[0,{[Q]:F5}]]],zBe=[3,$,NLe,0,[M6,A8,A6,B6,K6,J6,Y6,c8,x8,S8,C8,w8,T8,N8,Y8,J8,l5,X8,Z8,Q8,e5,$8,P6,U8,a5,R8,z8,L8,_8,R6,o8],[[0,1],[0,1],[0,{[Q]:E5}],[0,{[Q]:W6}],[0,{[Q]:G6}],[0,{[Q]:q6}],[0,{[Q]:X6}],[0,{[Q]:s8}],[4,{[Q]:x8}],[0,{[Q]:H5}],[0,{[Q]:U5}],[0,{[Q]:W5}],[0,{[Q]:G5}],[128,{[_5]:K5}],[0,{[Q]:e7}],[0,{[Q]:Q5}],[0,{[Q]:l7}],[0,{[Q]:i7}],[()=>p7,{[Q]:a7}],[0,{[Q]:o7}],[()=>h7,{[Q]:t7}],[()=>m7,{[Q]:r7}],[2,{[Q]:n7}],[0,{[Q]:Z5}],[0,{[Q]:s7}],[0,{[Q]:J5}],[5,{[Q]:Y5}],[0,{[Q]:q5}],[0,{[Q]:V5}],[0,{[Q]:D5}],[0,{[Q]:F5}]],2],BBe=[3,$,ULe,{[T5]:WLe},[p8,Y8,e5,$8,P6],[[()=>rVe,{[T5]:p8}],[0,{[Q]:e7}],[()=>h7,{[Q]:t7}],[()=>m7,{[Q]:r7}],[2,{[Q]:n7}]],1],VBe=[3,$,GLe,0,[M6,gze,Y8,e5,$8,P6],[[0,1],[0,{[Q]:qze}],[0,{[Q]:e7}],[()=>h7,{[Q]:t7}],[()=>m7,{[Q]:r7}],[2,{[Q]:n7}]],1],HBe=[3,$,YLe,0,[m8,c5,H8],[[2,{[Q]:z5}],[0,{[Q]:c7}],[0,{[Q]:X5}]]],UBe=[3,$,XLe,0,[M6,A8,NRe,c5,U8,xLe,_8,E8,sRe,cRe],[[0,1],[0,1],[0,{[Q]:Qze}],[0,{[v5]:C5}],[0,{[Q]:Z5}],[2,{[Q]:Uze}],[0,{[Q]:V5}],[0,{[Q]:D8}],[6,{[Q]:Xze}],[1,{[Q]:Zze}]],2],WBe=[3,$,nRe,0,[I6,m8,gLe,g8,fze,M8,Q6,y8,V6,H6,U6,r8,i8,a8,e8,u8,d8,f8,o8,PRe,c5,B6,K6,J6,Y6,VLe,c8,x8,v8,l5,Y8,N8,X8,Q8,e5,P6,J8,H8,dze,YRe,vze,R8,z8,L8],[[()=>g7,16],[2,{[Q]:z5}],[0,{[Q]:Tze}],[0,{[Q]:B5}],[0,{[Q]:aBe}],[4,{[Q]:ORe}],[1,{[Q]:Z6}],[0,{[Q]:y8}],[0,{[Q]:O5}],[0,{[Q]:k5}],[0,{[Q]:A5}],[0,{[Q]:M5}],[0,{[Q]:N5}],[0,{[Q]:P5}],[0,{[Q]:j5}],[0,{[Q]:I5}],[0,{[Q]:L5}],[0,{[Q]:R5}],[0,{[Q]:F5}],[1,{[Q]:$ze}],[0,{[Q]:c7}],[0,{[Q]:W6}],[0,{[Q]:G6}],[0,{[Q]:q6}],[0,{[Q]:X6}],[0,{[Q]:HLe}],[0,{[Q]:s8}],[4,{[Q]:x8}],[0,{[Q]:v8}],[0,{[Q]:l7}],[0,{[Q]:e7}],[128,{[_5]:K5}],[0,{[Q]:i7}],[0,{[Q]:o7}],[()=>h7,{[Q]:t7}],[2,{[Q]:n7}],[0,{[Q]:Q5}],[0,{[Q]:X5}],[0,{[Q]:oBe}],[1,{[Q]:tBe}],[1,{[Q]:sBe}],[0,{[Q]:J5}],[5,{[Q]:Y5}],[0,{[Q]:q5}]]],GBe=[3,$,rRe,0,[M6,A8,E8,uRe,O8,_Re,G8,ize,aze,oze,sze,cze,lze,c5,X8,Z8,Q8,U8,V8,_8,FLe],[[0,1],[0,1],[0,{[Q]:D8}],[4,{[Q]:lRe}],[0,{[Q]:k8}],[4,{[Q]:vRe}],[0,{[Q]:G8}],[0,{[v5]:Mze}],[0,{[v5]:Nze}],[0,{[v5]:Pze}],[0,{[v5]:Fze}],[0,{[v5]:Ize}],[6,{[v5]:Lze}],[0,{[v5]:C5}],[0,{[Q]:i7}],[()=>p7,{[Q]:a7}],[0,{[Q]:o7}],[0,{[Q]:Z5}],[1,{[v5]:b5}],[0,{[Q]:V5}],[0,{[Q]:Kze}]],2],KBe=[3,$,CRe,{[T5]:xRe},[L6,I8,l8,B8],[[()=>cVe,0],()=>_7,0,0]],qBe=[3,$,wRe,0,[MRe,l8,B8,F6],[[1,{[v5]:Aze}],[0,{[v5]:d5}],[0,{[v5]:y5}],[0,{[v5]:Eze}]]],JBe=[3,$,ARe,{[T5]:TRe},[gRe,qLe,F8,B8,h8,P8,BLe,b8,bRe,l8,LRe,K8,H8],[2,[()=>dVe,{[w5]:1}],0,0,0,1,[()=>lVe,{[w5]:1}],0,1,0,0,0,[0,{[Q]:X5}]]],YBe=[3,$,jRe,0,[M6,h8,b8,P8,B8,l8,eRe,K8,U8,_8,qRe],[[0,1],[0,{[v5]:Dze}],[0,{[v5]:Oze}],[1,{[v5]:jze}],[0,{[v5]:y5}],[0,{[v5]:d5}],[2,{[v5]:kze}],[0,{[v5]:Rze}],[0,{[Q]:Z5}],[0,{[Q]:V5}],[64,{[Q]:rBe}]],1],XBe=[3,$,DRe,0,[o5,F8],[0,0]],ZBe=[3,$,JRe,0,[A8,M8,y8,R6,o8,n5,J8,I8,W8],[0,4,0,[64,{[w5]:1}],0,1,0,()=>_7,()=>nVe]],_7=[3,$,I8,0,[JLe,aRe],[0,0]],QBe=[3,$,ZRe,0,[g8,y8,V6,H6,U6,r8,i8,a8,e8,u8,d8,f8,o8,Y8,c5,X8,Q8,e5,$8,P6,n5,H8],[[0,{[Q]:B5}],[0,{[Q]:y8}],[0,{[Q]:O5}],[0,{[Q]:k5}],[0,{[Q]:A5}],[0,{[Q]:M5}],[0,{[Q]:N5}],[0,{[Q]:P5}],[0,{[Q]:j5}],[0,{[Q]:I5}],[0,{[Q]:L5}],[0,{[Q]:R5}],[0,{[Q]:F5}],[0,{[Q]:e7}],[0,{[Q]:c7}],[0,{[Q]:i7}],[0,{[Q]:o7}],[()=>h7,{[Q]:t7}],[()=>m7,{[Q]:r7}],[2,{[Q]:n7}],[1,{[Q]:iBe}],[0,{[Q]:X5}]]],$Be=[3,$,QRe,0,[M6,A8,A6,I6,B6,K6,J6,Y6,Q6,t8,c8,R6,V6,H6,U6,r8,i8,a8,e8,u8,d8,f8,x8,E8,O8,S8,C8,w8,T8,wze,N8,Y8,J8,l5,X8,Z8,Q8,e5,$8,P6,U8,a5,R8,z8,L8,_8],[[0,1],[0,1],[0,{[Q]:E5}],[()=>g7,16],[0,{[Q]:W6}],[0,{[Q]:G6}],[0,{[Q]:q6}],[0,{[Q]:X6}],[1,{[Q]:Z6}],[0,{[Q]:$6}],[0,{[Q]:s8}],[0,{[Q]:$5}],[0,{[Q]:O5}],[0,{[Q]:k5}],[0,{[Q]:A5}],[0,{[Q]:M5}],[0,{[Q]:N5}],[0,{[Q]:P5}],[0,{[Q]:j5}],[0,{[Q]:I5}],[0,{[Q]:L5}],[0,{[Q]:R5}],[4,{[Q]:x8}],[0,{[Q]:D8}],[0,{[Q]:k8}],[0,{[Q]:H5}],[0,{[Q]:U5}],[0,{[Q]:W5}],[0,{[Q]:G5}],[1,{[Q]:cBe}],[128,{[_5]:K5}],[0,{[Q]:e7}],[0,{[Q]:Q5}],[0,{[Q]:l7}],[0,{[Q]:i7}],[()=>p7,{[Q]:a7}],[0,{[Q]:o7}],[()=>h7,{[Q]:t7}],[()=>m7,{[Q]:r7}],[2,{[Q]:n7}],[0,{[Q]:Z5}],[0,{[Q]:s7}],[0,{[Q]:J5}],[5,{[Q]:Y5}],[0,{[Q]:q5}],[0,{[Q]:V5}]],2],eVe=[3,$,eze,0,[c5],[[0,{[Q]:c7}]]],tVe=[3,$,tze,0,[M6,A8,a5,c5,t8,R6,_8,U8],[[0,1],[0,1],[()=>aVe,{[g5]:1,[T5]:a5}],[0,{[v5]:C5}],[0,{[Q]:$6}],[0,{[Q]:$5}],[0,{[Q]:V5}],[0,{[Q]:Z5}]],3],nVe=[3,$,W8,0,[hRe,uze],[2,4]],rVe=[3,$,hze,0,[j6,q8,t5,g8],[[0,{[T5]:j6}],[()=>f7,{[T5]:q8}],[()=>f7,{[T5]:t5}],[4,{[T5]:g8}]],4],iVe=[3,$,i5,0,[A8,Cze],[0,0],2],aVe=[3,$,a5,0,[r5],[[()=>v7,0]],1],oVe=[3,$,xze,0,[Y8,y8,V6,H6,U6,r8,i8,a8,e8,u8,d8,f8,X8,Q8,e5,P6,H8],[[0,{[Q]:e7}],[0,{[Q]:y8}],[0,{[Q]:O5}],[0,{[Q]:k5}],[0,{[Q]:A5}],[0,{[Q]:M5}],[0,{[Q]:N5}],[0,{[Q]:P5}],[0,{[Q]:j5}],[0,{[Q]:I5}],[0,{[Q]:L5}],[0,{[Q]:R5}],[0,{[Q]:i7}],[0,{[Q]:o7}],[()=>h7,{[Q]:t7}],[2,{[Q]:n7}],[0,{[Q]:X5}]]],sVe=[3,$,Sze,0,[M6,A8,V8,s5,I6,Q6,t8,R6,V6,H6,U6,r8,i8,a8,e8,u8,d8,f8,X8,Z8,Q8,U8,_8],[[0,1],[0,1],[1,{[v5]:b5}],[0,{[v5]:S5}],[()=>g7,16],[1,{[Q]:Z6}],[0,{[Q]:$6}],[0,{[Q]:$5}],[0,{[Q]:O5}],[0,{[Q]:k5}],[0,{[Q]:A5}],[0,{[Q]:M5}],[0,{[Q]:N5}],[0,{[Q]:P5}],[0,{[Q]:j5}],[0,{[Q]:I5}],[0,{[Q]:L5}],[0,{[Q]:R5}],[0,{[Q]:i7}],[()=>p7,{[Q]:a7}],[0,{[Q]:o7}],[0,{[Q]:Z5}],[0,{[Q]:V5}]],4],cVe=[1,$,L6,0,[()=>OBe,{[T5]:M6}]],lVe=[1,$,LLe,0,()=>ABe],uVe=[1,$,RLe,0,()=>MBe],dVe=[1,$,WRe,0,[()=>ZBe,0]],v7=[1,$,r5,0,[()=>iVe,{[T5]:i5}]],fVe=[9,$,pLe,{[p5]:[`DELETE`,`/{Key+}?x-id=AbortMultipartUpload`,204]},()=>DBe,()=>EBe],pVe=[9,$,n8,{[p5]:[`POST`,`/{Key+}`,200]},()=>PBe,()=>NBe],mVe=[9,$,wLe,{[p5]:[`PUT`,`/`,200]},()=>LBe,()=>IBe],hVe=[9,$,PLe,{[p5]:[`POST`,`/{Key+}?uploads`,200]},()=>zBe,()=>RBe],gVe=[9,$,KLe,{[p5]:[`GET`,`/?session`,200]},()=>VBe,()=>BBe],_Ve=[9,$,ZLe,{[p5]:[`DELETE`,`/{Key+}?x-id=DeleteObject`,204]},()=>UBe,()=>HBe],vVe=[9,$,tRe,{[m5]:`-`,[p5]:[`GET`,`/{Key+}?x-id=GetObject`,200]},()=>GBe,()=>WBe],yVe=[9,$,SRe,{[p5]:[`GET`,`/?x-id=ListBuckets`,200]},()=>qBe,()=>KBe],bVe=[9,$,kRe,{[p5]:[`GET`,`/?list-type=2`,200]},()=>YBe,()=>JBe],xVe=[9,$,XRe,{[m5]:`-`,[p5]:[`PUT`,`/{Key+}?x-id=PutObject`,200]},()=>$Be,()=>QBe],SVe=[9,$,$Re,{[m5]:`-`,[p5]:[`PUT`,`/{Key+}?tagging`,200]},()=>tVe,()=>eVe],CVe=[9,$,bze,{[m5]:`-`,[p5]:[`PUT`,`/{Key+}?x-id=UploadPart`,200]},()=>sVe,()=>oVe],wVe=class extends oA.classBuilder().ep({...O6,DisableS3ExpressSessionAuth:{type:`staticContextParams`,value:!0},Bucket:{type:`contextParams`,name:`Bucket`}}).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions()),X4(n)]}).s(`AmazonS3`,`CreateSession`,{}).n(`S3Client`,`CreateSessionCommand`).sc(gVe).build(){},TVe={name:`@aws-sdk/client-s3`,description:`AWS SDK for JavaScript S3 Client for Node.js, Browser and React Native`,version:`3.1045.0`,scripts:{build:`concurrently 'yarn:build:types' 'yarn:build:es' && yarn build:cjs`,"build:cjs":`node ../../scripts/compilation/inline client-s3`,"build:es":`tsc -p tsconfig.es.json`,"build:include:deps":`yarn g:turbo run build -F="$npm_package_name"`,"build:types":`tsc -p tsconfig.types.json`,"build:types:downlevel":`downlevel-dts dist-types dist-types/ts3.4`,clean:`premove dist-cjs dist-es dist-types tsconfig.cjs.tsbuildinfo tsconfig.es.tsbuildinfo tsconfig.types.tsbuildinfo`,"extract:docs":`api-extractor run --local`,"generate:client":`node ../../scripts/generate-clients/single-service --solo s3`,test:`yarn g:vitest run`,"test:browser":`node ./test/browser-build/esbuild && yarn g:vitest run -c vitest.config.browser.mts`,"test:browser:watch":`node ./test/browser-build/esbuild && yarn g:vitest watch -c vitest.config.browser.mts`,"test:e2e":`yarn g:vitest run -c vitest.config.e2e.mts && yarn test:browser`,"test:e2e:watch":`yarn g:vitest watch -c vitest.config.e2e.mts`,"test:index":`tsc --noEmit ./test/index-types.ts && node ./test/index-objects.spec.mjs`,"test:integration":`yarn g:vitest run -c vitest.config.integ.mts`,"test:integration:watch":`yarn g:vitest watch -c vitest.config.integ.mts`,"test:watch":`yarn g:vitest watch`},main:`./dist-cjs/index.js`,types:`./dist-types/index.d.ts`,module:`./dist-es/index.js`,sideEffects:!1,dependencies:{"@aws-crypto/sha1-browser":`5.2.0`,"@aws-crypto/sha256-browser":`5.2.0`,"@aws-crypto/sha256-js":`5.2.0`,"@aws-sdk/core":`^3.974.8`,"@aws-sdk/credential-provider-node":`^3.972.39`,"@aws-sdk/middleware-bucket-endpoint":`^3.972.10`,"@aws-sdk/middleware-expect-continue":`^3.972.10`,"@aws-sdk/middleware-flexible-checksums":`^3.974.16`,"@aws-sdk/middleware-host-header":`^3.972.10`,"@aws-sdk/middleware-location-constraint":`^3.972.10`,"@aws-sdk/middleware-logger":`^3.972.10`,"@aws-sdk/middleware-recursion-detection":`^3.972.11`,"@aws-sdk/middleware-sdk-s3":`^3.972.37`,"@aws-sdk/middleware-ssec":`^3.972.10`,"@aws-sdk/middleware-user-agent":`^3.972.38`,"@aws-sdk/region-config-resolver":`^3.972.13`,"@aws-sdk/signature-v4-multi-region":`^3.996.25`,"@aws-sdk/types":`^3.973.8`,"@aws-sdk/util-endpoints":`^3.996.8`,"@aws-sdk/util-user-agent-browser":`^3.972.10`,"@aws-sdk/util-user-agent-node":`^3.973.24`,"@smithy/config-resolver":`^4.4.17`,"@smithy/core":`^3.23.17`,"@smithy/eventstream-serde-browser":`^4.2.14`,"@smithy/eventstream-serde-config-resolver":`^4.3.14`,"@smithy/eventstream-serde-node":`^4.2.14`,"@smithy/fetch-http-handler":`^5.3.17`,"@smithy/hash-blob-browser":`^4.2.15`,"@smithy/hash-node":`^4.2.14`,"@smithy/hash-stream-node":`^4.2.14`,"@smithy/invalid-dependency":`^4.2.14`,"@smithy/md5-js":`^4.2.14`,"@smithy/middleware-content-length":`^4.2.14`,"@smithy/middleware-endpoint":`^4.4.32`,"@smithy/middleware-retry":`^4.5.7`,"@smithy/middleware-serde":`^4.2.20`,"@smithy/middleware-stack":`^4.2.14`,"@smithy/node-config-provider":`^4.3.14`,"@smithy/node-http-handler":`^4.6.1`,"@smithy/protocol-http":`^5.3.14`,"@smithy/smithy-client":`^4.12.13`,"@smithy/types":`^4.14.1`,"@smithy/url-parser":`^4.2.14`,"@smithy/util-base64":`^4.3.2`,"@smithy/util-body-length-browser":`^4.2.2`,"@smithy/util-body-length-node":`^4.2.3`,"@smithy/util-defaults-mode-browser":`^4.3.49`,"@smithy/util-defaults-mode-node":`^4.2.54`,"@smithy/util-endpoints":`^3.4.2`,"@smithy/util-middleware":`^4.2.14`,"@smithy/util-retry":`^4.3.6`,"@smithy/util-stream":`^4.5.25`,"@smithy/util-utf8":`^4.2.2`,"@smithy/util-waiter":`^4.3.0`,tslib:`^2.6.2`},devDependencies:{"@aws-sdk/signature-v4-crt":`3.1045.0`,"@smithy/snapshot-testing":`^2.0.8`,"@tsconfig/node20":`20.1.8`,"@types/node":`^20.14.8`,concurrently:`7.0.0`,"downlevel-dts":`0.10.1`,premove:`4.0.0`,typescript:`~5.8.3`,vitest:`^4.0.17`},engines:{node:`>=20.0.0`},typesVersions:{"<4.5":{"dist-types/*":[`dist-types/ts3.4/*`]}},files:[`dist-*/**`],author:{name:`AWS SDK for JavaScript Team`,url:`https://aws.amazon.com/javascript/`},license:`Apache-2.0`,browser:{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.browser`},"react-native":{"./dist-es/runtimeConfig":`./dist-es/runtimeConfig.native`},homepage:`https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-s3`,repository:{type:`git`,url:`https://github.com/aws/aws-sdk-js-v3.git`,directory:`clients/client-s3`}};function y7(e){return typeof e==`string`?e.length===0:e.byteLength===0}var b7={name:`SHA-1`},x7={name:`HMAC`,hash:b7},EVe=new Uint8Array([218,57,163,238,94,107,75,13,50,85,191,239,149,96,24,144,175,216,7,9]),DVe=function(){function e(e){this.toHash=new Uint8Array,e!==void 0&&(this.key=new Promise(function(t,n){Db().crypto.subtle.importKey(`raw`,S7(e),x7,!1,[`sign`]).then(t,n)}),this.key.catch(function(){}))}return e.prototype.update=function(e){if(!y7(e)){var t=S7(e),n=new Uint8Array(this.toHash.byteLength+t.byteLength);n.set(this.toHash,0),n.set(t,this.toHash.byteLength),this.toHash=n}},e.prototype.digest=function(){var e=this;return this.key?this.key.then(function(t){return Db().crypto.subtle.sign(x7,t,e.toHash).then(function(e){return new Uint8Array(e)})}):y7(this.toHash)?Promise.resolve(EVe):Promise.resolve().then(function(){return Db().crypto.subtle.digest(b7,e.toHash)}).then(function(e){return Promise.resolve(new Uint8Array(e))})},e.prototype.reset=function(){this.toHash=new Uint8Array},e}();function S7(e){return typeof e==`string`?bb(e):ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength/Uint8Array.BYTES_PER_ELEMENT):new Uint8Array(e)}var OVe=function(){function e(e){if(Mb(Db()))this.hash=new DVe(e);else throw Error(`SHA1 not supported`)}return e.prototype.update=function(e,t){this.hash.update(xb(e))},e.prototype.digest=function(){return this.hash.digest()},e.prototype.reset=function(){this.hash.reset()},e}(),C7=class e{bytes;constructor(e){if(this.bytes=e,e.byteLength!==8)throw Error(`Int64 buffers must be exactly 8 bytes`)}static fromNumber(t){if(t>0x8000000000000000||t<-0x8000000000000000)throw Error(`${t} is too large (or, if negative, too small) to represent as an Int64`);let n=new Uint8Array(8);for(let e=7,r=Math.abs(Math.round(t));e>-1&&r>0;e--,r/=256)n[e]=r;return t<0&&w7(n),new e(n)}valueOf(){let e=this.bytes.slice(0),t=e[0]&128;return t&&w7(e),parseInt(Ub(e),16)*(t?-1:1)}toString(){return String(this.valueOf())}};function w7(e){for(let t=0;t<8;t++)e[t]^=255;for(let t=7;t>-1&&(e[t]++,e[t]===0);t--);}var kVe=class{toUtf8;fromUtf8;constructor(e,t){this.toUtf8=e,this.fromUtf8=t}format(e){let t=[];for(let n of Object.keys(e)){let r=this.fromUtf8(n);t.push(Uint8Array.from([r.byteLength]),r,this.formatHeaderValue(e[n]))}let n=new Uint8Array(t.reduce((e,t)=>e+t.byteLength,0)),r=0;for(let e of t)n.set(e,r),r+=e.byteLength;return n}formatHeaderValue(e){switch(e.type){case`boolean`:return Uint8Array.from([+!e.value]);case`byte`:return Uint8Array.from([2,e.value]);case`short`:let t=new DataView(new ArrayBuffer(3));return t.setUint8(0,3),t.setInt16(1,e.value,!1),new Uint8Array(t.buffer);case`integer`:let n=new DataView(new ArrayBuffer(5));return n.setUint8(0,4),n.setInt32(1,e.value,!1),new Uint8Array(n.buffer);case`long`:let r=new Uint8Array(9);return r[0]=5,r.set(e.value.bytes,1),r;case`binary`:let i=new DataView(new ArrayBuffer(3+e.value.byteLength));i.setUint8(0,6),i.setUint16(1,e.value.byteLength,!1);let a=new Uint8Array(i.buffer);return a.set(e.value,3),a;case`string`:let o=this.fromUtf8(e.value),s=new DataView(new ArrayBuffer(3+o.byteLength));s.setUint8(0,7),s.setUint16(1,o.byteLength,!1);let c=new Uint8Array(s.buffer);return c.set(o,3),c;case`timestamp`:let l=new Uint8Array(9);return l[0]=8,l.set(C7.fromNumber(e.value.valueOf()).bytes,1),l;case`uuid`:if(!zVe.test(e.value))throw Error(`Invalid UUID received: ${e.value}`);let u=new Uint8Array(17);return u[0]=9,u.set(Hb(e.value.replace(/\-/g,``)),1),u}}parse(e){let t={},n=0;for(;n{if(typeof e!=`number`)throw Error(`Attempted to allocate an event message where size was not a number: `+e);t=e,n=4,r=new Uint8Array(e),new DataView(r.buffer).setUint32(0,e,!1)},o=async function*(){let o=e[Symbol.asyncIterator]();for(;;){let{value:e,done:s}=await o.next();if(s){if(!t)return;if(t===n)yield r;else throw Error(`Truncated event message received.`);return}let c=e.length,l=0;for(;l({[Symbol.asyncIterator]:async function*(){let t=e.getReader();try{for(;;){let{done:e,value:n}=await t.read();if(e)return;yield n}}finally{t.releaseLock()}}}),ZVe=e=>{let t=e[Symbol.asyncIterator]();return new ReadableStream({async pull(e){let{done:n,value:r}=await t.next();if(n)return e.close();e.enqueue(r)}})},QVe=class{universalMarshaller;constructor({utf8Encoder:e,utf8Decoder:t}){this.universalMarshaller=new YVe({utf8Decoder:t,utf8Encoder:e})}deserialize(e,t){let n=$Ve(e)?XVe(e):e;return this.universalMarshaller.deserialize(n,t)}serialize(e,t){let n=this.universalMarshaller.serialize(e,t);return typeof ReadableStream==`function`?ZVe(n):n}},$Ve=e=>typeof ReadableStream==`function`&&e instanceof ReadableStream,eHe=e=>new QVe(e);async function tHe(e,t,n=1024*1024){let r=e.size,i=0;for(;i{n.update(e)}),n.digest()},rHe=[1732584193,4023233417,2562383102,271733878],iHe=class{state;buffer;bufferLength;bytesHashed;finished;constructor(){this.reset()}update(e){if(aHe(e))return;if(this.finished)throw Error(`Attempted to update an already finished hash.`);let t=oHe(e),n=0,{byteLength:r}=t;for(this.bytesHashed+=r;r>0;)this.buffer.setUint8(this.bufferLength++,t[n++]),r--,this.bufferLength===64&&(this.hashBuffer(),this.bufferLength=0)}async digest(){if(!this.finished){let{buffer:e,bufferLength:t,bytesHashed:n}=this,r=n*8;if(e.setUint8(this.bufferLength++,128),t%64>=56){for(let t=this.bufferLength;t<64;t++)e.setUint8(t,0);this.hashBuffer(),this.bufferLength=0}for(let t=this.bufferLength;t<56;t++)e.setUint8(t,0);e.setUint32(56,r>>>0,!0),e.setUint32(60,Math.floor(r/4294967296),!0),this.hashBuffer(),this.finished=!0}let e=new DataView(new ArrayBuffer(16));for(let t=0;t<4;t++)e.setUint32(t*4,this.state[t],!0);return new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}hashBuffer(){let{buffer:e,state:t}=this,n=t[0],r=t[1],i=t[2],a=t[3];n=A7(n,r,i,a,e.getUint32(0,!0),7,3614090360),a=A7(a,n,r,i,e.getUint32(4,!0),12,3905402710),i=A7(i,a,n,r,e.getUint32(8,!0),17,606105819),r=A7(r,i,a,n,e.getUint32(12,!0),22,3250441966),n=A7(n,r,i,a,e.getUint32(16,!0),7,4118548399),a=A7(a,n,r,i,e.getUint32(20,!0),12,1200080426),i=A7(i,a,n,r,e.getUint32(24,!0),17,2821735955),r=A7(r,i,a,n,e.getUint32(28,!0),22,4249261313),n=A7(n,r,i,a,e.getUint32(32,!0),7,1770035416),a=A7(a,n,r,i,e.getUint32(36,!0),12,2336552879),i=A7(i,a,n,r,e.getUint32(40,!0),17,4294925233),r=A7(r,i,a,n,e.getUint32(44,!0),22,2304563134),n=A7(n,r,i,a,e.getUint32(48,!0),7,1804603682),a=A7(a,n,r,i,e.getUint32(52,!0),12,4254626195),i=A7(i,a,n,r,e.getUint32(56,!0),17,2792965006),r=A7(r,i,a,n,e.getUint32(60,!0),22,1236535329),n=j7(n,r,i,a,e.getUint32(4,!0),5,4129170786),a=j7(a,n,r,i,e.getUint32(24,!0),9,3225465664),i=j7(i,a,n,r,e.getUint32(44,!0),14,643717713),r=j7(r,i,a,n,e.getUint32(0,!0),20,3921069994),n=j7(n,r,i,a,e.getUint32(20,!0),5,3593408605),a=j7(a,n,r,i,e.getUint32(40,!0),9,38016083),i=j7(i,a,n,r,e.getUint32(60,!0),14,3634488961),r=j7(r,i,a,n,e.getUint32(16,!0),20,3889429448),n=j7(n,r,i,a,e.getUint32(36,!0),5,568446438),a=j7(a,n,r,i,e.getUint32(56,!0),9,3275163606),i=j7(i,a,n,r,e.getUint32(12,!0),14,4107603335),r=j7(r,i,a,n,e.getUint32(32,!0),20,1163531501),n=j7(n,r,i,a,e.getUint32(52,!0),5,2850285829),a=j7(a,n,r,i,e.getUint32(8,!0),9,4243563512),i=j7(i,a,n,r,e.getUint32(28,!0),14,1735328473),r=j7(r,i,a,n,e.getUint32(48,!0),20,2368359562),n=M7(n,r,i,a,e.getUint32(20,!0),4,4294588738),a=M7(a,n,r,i,e.getUint32(32,!0),11,2272392833),i=M7(i,a,n,r,e.getUint32(44,!0),16,1839030562),r=M7(r,i,a,n,e.getUint32(56,!0),23,4259657740),n=M7(n,r,i,a,e.getUint32(4,!0),4,2763975236),a=M7(a,n,r,i,e.getUint32(16,!0),11,1272893353),i=M7(i,a,n,r,e.getUint32(28,!0),16,4139469664),r=M7(r,i,a,n,e.getUint32(40,!0),23,3200236656),n=M7(n,r,i,a,e.getUint32(52,!0),4,681279174),a=M7(a,n,r,i,e.getUint32(0,!0),11,3936430074),i=M7(i,a,n,r,e.getUint32(12,!0),16,3572445317),r=M7(r,i,a,n,e.getUint32(24,!0),23,76029189),n=M7(n,r,i,a,e.getUint32(36,!0),4,3654602809),a=M7(a,n,r,i,e.getUint32(48,!0),11,3873151461),i=M7(i,a,n,r,e.getUint32(60,!0),16,530742520),r=M7(r,i,a,n,e.getUint32(8,!0),23,3299628645),n=N7(n,r,i,a,e.getUint32(0,!0),6,4096336452),a=N7(a,n,r,i,e.getUint32(28,!0),10,1126891415),i=N7(i,a,n,r,e.getUint32(56,!0),15,2878612391),r=N7(r,i,a,n,e.getUint32(20,!0),21,4237533241),n=N7(n,r,i,a,e.getUint32(48,!0),6,1700485571),a=N7(a,n,r,i,e.getUint32(12,!0),10,2399980690),i=N7(i,a,n,r,e.getUint32(40,!0),15,4293915773),r=N7(r,i,a,n,e.getUint32(4,!0),21,2240044497),n=N7(n,r,i,a,e.getUint32(32,!0),6,1873313359),a=N7(a,n,r,i,e.getUint32(60,!0),10,4264355552),i=N7(i,a,n,r,e.getUint32(24,!0),15,2734768916),r=N7(r,i,a,n,e.getUint32(52,!0),21,1309151649),n=N7(n,r,i,a,e.getUint32(16,!0),6,4149444226),a=N7(a,n,r,i,e.getUint32(44,!0),10,3174756917),i=N7(i,a,n,r,e.getUint32(8,!0),15,718787259),r=N7(r,i,a,n,e.getUint32(36,!0),21,3951481745),t[0]=n+t[0]&4294967295,t[1]=r+t[1]&4294967295,t[2]=i+t[2]&4294967295,t[3]=a+t[3]&4294967295}reset(){this.state=Uint32Array.from(rHe),this.buffer=new DataView(new ArrayBuffer(64)),this.bufferLength=0,this.bytesHashed=0,this.finished=!1}};function k7(e,t,n,r,i,a){return t=(t+e&4294967295)+(r+a&4294967295)&4294967295,(t<>>32-i)+n&4294967295}function A7(e,t,n,r,i,a,o){return k7(t&n|~t&r,e,t,i,a,o)}function j7(e,t,n,r,i,a,o){return k7(t&r|n&~r,e,t,i,a,o)}function M7(e,t,n,r,i,a,o){return k7(t^n^r,e,t,i,a,o)}function N7(e,t,n,r,i,a,o){return k7(n^(t|~r),e,t,i,a,o)}function aHe(e){return typeof e==`string`?e.length===0:e.byteLength===0}function oHe(e){return typeof e==`string`?Wb(e):ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength/Uint8Array.BYTES_PER_ELEMENT):new Uint8Array(e)}var sHe=e=>({apiVersion:`2006-03-01`,base64Decoder:e?.base64Decoder??eO,base64Encoder:e?.base64Encoder??tO,disableHostPrefix:e?.disableHostPrefix??!1,endpointProvider:e?.endpointProvider??T6,extensions:e?.extensions??[],getAwsChunkedEncodingStream:e?.getAwsChunkedEncodingStream??gce,httpAuthSchemeProvider:e?.httpAuthSchemeProvider??qIe,httpAuthSchemes:e?.httpAuthSchemes??[{schemeId:`aws.auth#sigv4`,identityProvider:e=>e.getIdentityProvider(`aws.auth#sigv4`),signer:new SA},{schemeId:`aws.auth#sigv4a`,identityProvider:e=>e.getIdentityProvider(`aws.auth#sigv4a`),signer:new Fue}],logger:e?.logger??new mA,protocol:e?.protocol??zIe,protocolSettings:e?.protocolSettings??{defaultNamespace:`com.amazonaws.s3`,errorTypeRegistries:TBe,xmlNamespace:`http://s3.amazonaws.com/doc/2006-03-01/`,version:`2006-03-01`,serviceTarget:`AmazonS3`},sdkStreamMixin:e?.sdkStreamMixin??dO,serviceId:e?.serviceId??`S3`,signerConstructor:e?.signerConstructor??Q4,signingEscapePath:e?.signingEscapePath??!1,urlParser:e?.urlParser??vO,useArnRegion:e?.useArnRegion??void 0,utf8Decoder:e?.utf8Decoder??Wb,utf8Encoder:e?.utf8Encoder??Kb}),cHe=e=>{let t=AA(e),n=()=>t().then(lA),r=sHe(e);return{...r,...e,runtime:`browser`,defaultsMode:t,bodyLengthChecker:e?.bodyLengthChecker??kA,credentialDefaultProvider:e?.credentialDefaultProvider??(e=>()=>Promise.reject(Error(`Credential is missing`))),defaultUserAgentProvider:e?.defaultUserAgentProvider??TA({serviceId:r.serviceId,clientVersion:TVe.version}),eventStreamSerdeProvider:e?.eventStreamSerdeProvider??eHe,maxAttempts:e?.maxAttempts??3,md5:e?.md5??iHe,region:e?.region??DA(`Region is missing`),requestHandler:sO.create(e?.requestHandler??n),retryMode:e?.retryMode??(async()=>(await n()).retryMode||Dk),sha1:e?.sha1??OVe,sha256:e?.sha256??Nb,streamCollector:e?.streamCollector??lO,streamHasher:e?.streamHasher??nHe,useDualstackEndpoint:e?.useDualstackEndpoint??(()=>Promise.resolve(!1)),useFipsEndpoint:e?.useFipsEndpoint??(()=>Promise.resolve(!1))}},lHe=e=>{let t=e.httpAuthSchemes,n=e.httpAuthSchemeProvider,r=e.credentials;return{setHttpAuthScheme(e){let n=t.findIndex(t=>t.schemeId===e.schemeId);n===-1?t.push(e):t.splice(n,1,e)},httpAuthSchemes(){return t},setHttpAuthSchemeProvider(e){n=e},httpAuthSchemeProvider(){return n},setCredentials(e){r=e},credentials(){return r}}},uHe=e=>({httpAuthSchemes:e.httpAuthSchemes(),httpAuthSchemeProvider:e.httpAuthSchemeProvider(),credentials:e.credentials()}),dHe=(e,t)=>{let n=Object.assign(c1(e),dA(e),Pb(e),lHe(e));return t.forEach(e=>e.configure(n)),Object.assign(e,l1(n),fA(n),Fb(n),uHe(n))},fHe=class extends rA{config;constructor(...[e]){let t=cHe(e||{});super(t),this.initConfig=t;let n=dHe(DIe(JIe(BIe(Xk(AD(Hk(Zk(lIe(ik(YIe(t))))))))),{session:[()=>this,wVe]}),e?.extensions||[]);this.config=n,this.middlewareStack.use(yO(this.config)),this.middlewareStack.use(zk(this.config)),this.middlewareStack.use(gA(this.config)),this.middlewareStack.use(Wk(this.config)),this.middlewareStack.use(ND(this.config)),this.middlewareStack.use(ID(this.config)),this.middlewareStack.use(zD(this.config)),this.middlewareStack.use(WD(this.config,{httpAuthSchemeParametersProvider:KIe,identityProviderConfigProvider:async e=>new nk({"aws.auth#sigv4":e.credentials,"aws.auth#sigv4a":e.credentials})})),this.middlewareStack.use(YD(this.config)),this.middlewareStack.use(RIe(this.config)),this.middlewareStack.use(tIe(this.config)),this.middlewareStack.use(mIe(this.config)),this.middlewareStack.use(xIe(this.config)),this.middlewareStack.use(EIe(this.config))}destroy(){super.destroy()}},pHe=class extends oA.classBuilder().ep(O6).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions()),X4(n)]}).s(`AmazonS3`,`ListBuckets`,{}).n(`S3Client`,`ListBucketsCommand`).sc(yVe).build(){},mHe=class extends oA.classBuilder().ep({...O6,Bucket:{type:`contextParams`,name:`Bucket`},Prefix:{type:`contextParams`,name:`Prefix`}}).m(function(e,t,n,r){return[Yk(n,e.getEndpointParameterInstructions()),X4(n)]}).s(`AmazonS3`,`ListObjectsV2`,{}).n(`S3Client`,`ListObjectsV2Command`).sc(bVe).build(){},P7=`ap-southeast-2`,F7=`${window.location.protocol}//localhost:9999`,hHe=`${window.location.protocol}//localhost:8443`,I7=null,L7=null,R7=null,z7=null,B7=null;function V7(){if(!I7){let e=vb();if(!e)throw Error(`AWS credentials not configured`);I7=new Dxe({endpoint:F7,region:P7,credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}}),I7.middlewareStack.add(e=>async t=>(Rb.isInstance(t.request)&&(t.request.hostname=window.location.hostname,t.request.port=Number(window.location.port)||443,t.request.path=`/proxy/awsgw${t.request.path}`),await e(t)),{step:`finalizeRequest`,name:`proxyRewrite`,override:!0})}return I7}function H7(){if(!L7){let e=vb();if(!e)throw Error(`AWS credentials not configured`);L7=new ije({endpoint:F7,region:P7,credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}}),L7.middlewareStack.add(e=>async t=>(Rb.isInstance(t.request)&&(t.request.hostname=window.location.hostname,t.request.port=Number(window.location.port)||443,t.request.path=`/proxy/awsgw${t.request.path}`),await e(t)),{step:`finalizeRequest`,name:`proxyRewrite`,override:!0})}return L7}function gHe(){if(!R7){let e=vb();if(!e)throw Error(`AWS credentials not configured`);R7=new kD({endpoint:F7,region:P7,credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}}),R7.middlewareStack.add(e=>async t=>(Rb.isInstance(t.request)&&(t.request.hostname=window.location.hostname,t.request.port=Number(window.location.port)||443,t.request.path=`/proxy/awsgw${t.request.path}`),await e(t)),{step:`finalizeRequest`,name:`proxyRewrite`,override:!0})}return R7}function U7(){if(!z7){let e=vb();if(!e)throw Error(`AWS credentials not configured`);z7=new GFe({endpoint:F7,region:P7,credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}}),z7.middlewareStack.add(e=>async t=>(Rb.isInstance(t.request)&&(t.request.hostname=window.location.hostname,t.request.port=Number(window.location.port)||443,t.request.path=`/proxy/awsgw${t.request.path}`),await e(t)),{step:`finalizeRequest`,name:`proxyRewrite`,override:!0})}return z7}function W7(){if(!B7){let e=vb();if(!e)throw Error(`AWS credentials not configured`);B7=new fHe({endpoint:hHe,region:P7,credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey},forcePathStyle:!0}),B7.middlewareStack.add(e=>async t=>(Rb.isInstance(t.request)&&t.request.path.endsWith(`/`)&&t.request.path!==`/`&&(t.request.path=t.request.path.slice(0,-1)),await e(t)),{step:`build`,name:`removeTrailingSlash`}),B7.middlewareStack.add(e=>async t=>(Rb.isInstance(t.request)&&(t.request.hostname=window.location.hostname,t.request.port=Number(window.location.port)||443,t.request.path=`/proxy/s3${t.request.path}`),await e(t)),{step:`finalizeRequest`,name:`proxyRewrite`,override:!0})}return B7}function G7(){I7=null,L7=null,R7=null,z7=null,B7=null}function K7(){let e=(0,da.c)(144),t;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(t={select:_He},e[0]=t):t=e[0];let n=$i(t),r=fi(),i=Fe(),{isAdmin:a}=_x(),o;e[1]!==r||e[2]!==i?(o=function(){yb(),G7(),i.clear(),r({to:`/login`})},e[1]=r,e[2]=i,e[3]=o):o=e[3];let s=o,c;e[4]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,F.jsxs)(Fte,{className:`flex flex-row items-center gap-2 px-4 py-3`,children:[(0,F.jsx)(`img`,{src:`/mulga-logo.svg`,alt:`Mulga`,className:`size-6 shrink-0 dark:invert`}),(0,F.jsx)(`span`,{className:`truncate text-sm font-semibold group-data-[collapsible=icon]:hidden`,children:`Spinifex`})]}),e[4]=c):c=e[4];let l;e[5]===Symbol.for(`react.memo_cache_sentinel`)?(l=(0,F.jsx)(og,{children:`General`}),e[5]=l):l=e[5];let u=n===`/`,d,f;e[6]===Symbol.for(`react.memo_cache_sentinel`)?(d=(0,F.jsx)(Eo,{className:`size-4`}),f=(0,F.jsx)(`span`,{children:`Dashboard`}),e[6]=d,e[7]=f):(d=e[6],f=e[7]);let p;e[8]===u?p=e[9]:(p=(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/`,children:(0,F.jsxs)(lg,{isActive:u,tooltip:`Dashboard`,children:[d,f]})})}),e[8]=u,e[9]=p);let m;e[10]!==a||e[11]!==n?(m=a&&(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/nodes`,children:(0,F.jsxs)(lg,{isActive:n.startsWith(`/nodes`),tooltip:`Nodes`,children:[(0,F.jsx)(Fo,{className:`size-4`}),(0,F.jsx)(`span`,{children:`Nodes`})]})})}),e[10]=a,e[11]=n,e[12]=m):m=e[12];let h;e[13]!==p||e[14]!==m?(h=(0,F.jsxs)(ag,{children:[l,(0,F.jsxs)(sg,{children:[p,m]})]}),e[13]=p,e[14]=m,e[15]=h):h=e[15];let g;e[16]===Symbol.for(`react.memo_cache_sentinel`)?(g=(0,F.jsx)(og,{children:`EC2`}),e[16]=g):g=e[16];let _;e[17]===n?_=e[18]:(_=n.startsWith(`/ec2/describe-instances`)||n.startsWith(`/ec2/run-instances`),e[17]=n,e[18]=_);let v,y;e[19]===Symbol.for(`react.memo_cache_sentinel`)?(v=(0,F.jsx)(Fo,{className:`size-4`}),y=(0,F.jsx)(`span`,{children:`Instances`}),e[19]=v,e[20]=y):(v=e[19],y=e[20]);let b;e[21]===_?b=e[22]:(b=(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-instances`,children:(0,F.jsxs)(lg,{isActive:_,tooltip:`Instances`,children:[v,y]})})}),e[21]=_,e[22]=b);let x;e[23]===n?x=e[24]:(x=n.startsWith(`/ec2/describe-images`),e[23]=n,e[24]=x);let S,C;e[25]===Symbol.for(`react.memo_cache_sentinel`)?(S=(0,F.jsx)(Do,{className:`size-4`}),C=(0,F.jsx)(`span`,{children:`Images`}),e[25]=S,e[26]=C):(S=e[25],C=e[26]);let w;e[27]===x?w=e[28]:(w=(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-images`,children:(0,F.jsxs)(lg,{isActive:x,tooltip:`Images`,children:[S,C]})})}),e[27]=x,e[28]=w);let T;e[29]===n?T=e[30]:(T=n.startsWith(`/ec2/describe-key-pairs`),e[29]=n,e[30]=T);let E,ee;e[31]===Symbol.for(`react.memo_cache_sentinel`)?(E=(0,F.jsx)(Oo,{className:`size-4`}),ee=(0,F.jsx)(`span`,{children:`Key Pairs`}),e[31]=E,e[32]=ee):(E=e[31],ee=e[32]);let D;e[33]===T?D=e[34]:(D=(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-key-pairs`,children:(0,F.jsxs)(lg,{isActive:T,tooltip:`Key Pairs`,children:[E,ee]})})}),e[33]=T,e[34]=D);let O;e[35]===n?O=e[36]:(O=n.startsWith(`/ec2/describe-volumes`)||n.startsWith(`/ec2/create-volume`)||n.startsWith(`/ec2/modify-volume`),e[35]=n,e[36]=O);let te,ne;e[37]===Symbol.for(`react.memo_cache_sentinel`)?(te=(0,F.jsx)(To,{className:`size-4`}),ne=(0,F.jsx)(`span`,{children:`Volumes`}),e[37]=te,e[38]=ne):(te=e[37],ne=e[38]);let re;e[39]===O?re=e[40]:(re=(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-volumes`,children:(0,F.jsxs)(lg,{isActive:O,tooltip:`Volumes`,children:[te,ne]})})}),e[39]=O,e[40]=re);let k;e[41]===n?k=e[42]:(k=n.startsWith(`/ec2/describe-snapshots`)||n.startsWith(`/ec2/create-snapshot`),e[41]=n,e[42]=k);let A,ie;e[43]===Symbol.for(`react.memo_cache_sentinel`)?(A=(0,F.jsx)(So,{className:`size-4`}),ie=(0,F.jsx)(`span`,{children:`Snapshots`}),e[43]=A,e[44]=ie):(A=e[43],ie=e[44]);let j;e[45]===k?j=e[46]:(j=(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-snapshots`,children:(0,F.jsxs)(lg,{isActive:k,tooltip:`Snapshots`,children:[A,ie]})})}),e[45]=k,e[46]=j);let ae;e[47]===n?ae=e[48]:(ae=n.startsWith(`/ec2/describe-placement-groups`)||n.startsWith(`/ec2/create-placement-group`),e[47]=n,e[48]=ae);let oe,se;e[49]===Symbol.for(`react.memo_cache_sentinel`)?(oe=(0,F.jsx)(ko,{className:`size-4`}),se=(0,F.jsx)(`span`,{children:`Placement Groups`}),e[49]=oe,e[50]=se):(oe=e[49],se=e[50]);let ce;e[51]===ae?ce=e[52]:(ce=(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-placement-groups`,children:(0,F.jsxs)(lg,{isActive:ae,tooltip:`Placement Groups`,children:[oe,se]})})}),e[51]=ae,e[52]=ce);let M;e[53]===n?M=e[54]:(M=n.startsWith(`/ec2/describe-load-balancers`)||n.startsWith(`/ec2/create-load-balancer`),e[53]=n,e[54]=M);let le,ue;e[55]===Symbol.for(`react.memo_cache_sentinel`)?(le=(0,F.jsx)(Bo,{className:`size-4`}),ue=(0,F.jsx)(`span`,{children:`Load Balancers`}),e[55]=le,e[56]=ue):(le=e[55],ue=e[56]);let N;e[57]===M?N=e[58]:(N=(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-load-balancers`,children:(0,F.jsxs)(lg,{isActive:M,tooltip:`Load Balancers`,children:[le,ue]})})}),e[57]=M,e[58]=N);let de;e[59]===n?de=e[60]:(de=n.startsWith(`/ec2/describe-target-groups`)||n.startsWith(`/ec2/create-target-group`),e[59]=n,e[60]=de);let fe,pe;e[61]===Symbol.for(`react.memo_cache_sentinel`)?(fe=(0,F.jsx)(wo,{className:`size-4`}),pe=(0,F.jsx)(`span`,{children:`Target Groups`}),e[61]=fe,e[62]=pe):(fe=e[61],pe=e[62]);let me;e[63]===de?me=e[64]:(me=(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-target-groups`,children:(0,F.jsxs)(lg,{isActive:de,tooltip:`Target Groups`,children:[fe,pe]})})}),e[63]=de,e[64]=me);let he;e[65]!==b||e[66]!==w||e[67]!==D||e[68]!==re||e[69]!==j||e[70]!==ce||e[71]!==N||e[72]!==me?(he=(0,F.jsxs)(ag,{children:[g,(0,F.jsxs)(sg,{children:[b,w,D,re,j,ce,N,me]})]}),e[65]=b,e[66]=w,e[67]=D,e[68]=re,e[69]=j,e[70]=ce,e[71]=N,e[72]=me,e[73]=he):he=e[73];let ge;e[74]===Symbol.for(`react.memo_cache_sentinel`)?(ge=(0,F.jsx)(og,{children:`Networking`}),e[74]=ge):ge=e[74];let _e;e[75]===n?_e=e[76]:(_e=n.startsWith(`/ec2/describe-vpcs`)||n.startsWith(`/ec2/create-vpc`),e[75]=n,e[76]=_e);let ve,ye;e[77]===Symbol.for(`react.memo_cache_sentinel`)?(ve=(0,F.jsx)(No,{className:`size-4`}),ye=(0,F.jsx)(`span`,{children:`VPCs`}),e[77]=ve,e[78]=ye):(ve=e[77],ye=e[78]);let be;e[79]===_e?be=e[80]:(be=(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-vpcs`,children:(0,F.jsxs)(lg,{isActive:_e,tooltip:`VPCs`,children:[ve,ye]})})}),e[79]=_e,e[80]=be);let xe;e[81]===n?xe=e[82]:(xe=n.startsWith(`/ec2/describe-subnets`)||n.startsWith(`/ec2/create-subnet`),e[81]=n,e[82]=xe);let Se,Ce;e[83]===Symbol.for(`react.memo_cache_sentinel`)?(Se=(0,F.jsx)(Ao,{className:`size-4`}),Ce=(0,F.jsx)(`span`,{children:`Subnets`}),e[83]=Se,e[84]=Ce):(Se=e[83],Ce=e[84]);let we;e[85]===xe?we=e[86]:(we=(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-subnets`,children:(0,F.jsxs)(lg,{isActive:xe,tooltip:`Subnets`,children:[Se,Ce]})})}),e[85]=xe,e[86]=we);let Te;e[87]===n?Te=e[88]:(Te=n.startsWith(`/ec2/describe-security-groups`)||n.startsWith(`/ec2/create-security-group`),e[87]=n,e[88]=Te);let Ee,De;e[89]===Symbol.for(`react.memo_cache_sentinel`)?(Ee=(0,F.jsx)(Io,{className:`size-4`}),De=(0,F.jsx)(`span`,{children:`Security Groups`}),e[89]=Ee,e[90]=De):(Ee=e[89],De=e[90]);let Oe;e[91]===Te?Oe=e[92]:(Oe=(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/ec2/describe-security-groups`,children:(0,F.jsxs)(lg,{isActive:Te,tooltip:`Security Groups`,children:[Ee,De]})})}),e[91]=Te,e[92]=Oe);let ke;e[93]!==be||e[94]!==we||e[95]!==Oe?(ke=(0,F.jsxs)(ag,{children:[ge,(0,F.jsxs)(sg,{children:[be,we,Oe]})]}),e[93]=be,e[94]=we,e[95]=Oe,e[96]=ke):ke=e[96];let Ae;e[97]===Symbol.for(`react.memo_cache_sentinel`)?(Ae=(0,F.jsx)(og,{children:`IAM`}),e[97]=Ae):Ae=e[97];let je;e[98]===n?je=e[99]:(je=n.startsWith(`/iam/list-users`)||n.startsWith(`/iam/create-user`),e[98]=n,e[99]=je);let Me,Ne;e[100]===Symbol.for(`react.memo_cache_sentinel`)?(Me=(0,F.jsx)(zo,{className:`size-4`}),Ne=(0,F.jsx)(`span`,{children:`Users`}),e[100]=Me,e[101]=Ne):(Me=e[100],Ne=e[101]);let P;e[102]===je?P=e[103]:(P=(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/iam/list-users`,children:(0,F.jsxs)(lg,{isActive:je,tooltip:`Users`,children:[Me,Ne]})})}),e[102]=je,e[103]=P);let Pe;e[104]===n?Pe=e[105]:(Pe=n.startsWith(`/iam/list-policies`)||n.startsWith(`/iam/create-policy`),e[104]=n,e[105]=Pe);let Ie,Le;e[106]===Symbol.for(`react.memo_cache_sentinel`)?(Ie=(0,F.jsx)(Lo,{className:`size-4`}),Le=(0,F.jsx)(`span`,{children:`Policies`}),e[106]=Ie,e[107]=Le):(Ie=e[106],Le=e[107]);let Re;e[108]===Pe?Re=e[109]:(Re=(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/iam/list-policies`,children:(0,F.jsxs)(lg,{isActive:Pe,tooltip:`Policies`,children:[Ie,Le]})})}),e[108]=Pe,e[109]=Re);let ze;e[110]!==P||e[111]!==Re?(ze=(0,F.jsxs)(ag,{children:[Ae,(0,F.jsxs)(sg,{children:[P,Re]})]}),e[110]=P,e[111]=Re,e[112]=ze):ze=e[112];let Be;e[113]===Symbol.for(`react.memo_cache_sentinel`)?(Be=(0,F.jsx)(og,{children:`S3`}),e[113]=Be):Be=e[113];let Ve;e[114]===n?Ve=e[115]:(Ve=n.startsWith(`/s3/ls`),e[114]=n,e[115]=Ve);let He,Ue;e[116]===Symbol.for(`react.memo_cache_sentinel`)?(He=(0,F.jsx)(Fo,{className:`size-4`}),Ue=(0,F.jsx)(`span`,{children:`Buckets`}),e[116]=He,e[117]=Ue):(He=e[116],Ue=e[117]);let We;e[118]===Ve?We=e[119]:(We=(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/s3/ls`,children:(0,F.jsxs)(lg,{isActive:Ve,tooltip:`Buckets`,children:[He,Ue]})})}),e[118]=Ve,e[119]=We);let Ge;e[120]!==a||e[121]!==n?(Ge=a&&(0,F.jsx)(cg,{children:(0,F.jsx)(Oi,{to:`/s3/service-metrics`,children:(0,F.jsxs)(lg,{isActive:n.startsWith(`/s3/service-metrics`),tooltip:`Service Metrics`,children:[(0,F.jsx)(bo,{className:`size-4`}),(0,F.jsx)(`span`,{children:`Service Metrics`})]})})}),e[120]=a,e[121]=n,e[122]=Ge):Ge=e[122];let Ke;e[123]!==We||e[124]!==Ge?(Ke=(0,F.jsxs)(ag,{children:[Be,(0,F.jsxs)(sg,{children:[We,Ge]})]}),e[123]=We,e[124]=Ge,e[125]=Ke):Ke=e[125];let qe;e[126]===a?qe=e[127]:(qe=a&&(0,F.jsxs)(ag,{children:[(0,F.jsx)(og,{children:`Documentation`}),(0,F.jsx)(sg,{children:(0,F.jsx)(cg,{children:(0,F.jsx)(`a`,{href:`https://docs.mulgadc.com`,target:`_blank`,rel:`noopener noreferrer`,children:(0,F.jsxs)(lg,{tooltip:`Documentation`,children:[(0,F.jsx)(xo,{className:`size-4`}),(0,F.jsx)(`span`,{children:`Docs`})]})})})})]}),e[126]=a,e[127]=qe);let Je;e[128]!==he||e[129]!==ke||e[130]!==ze||e[131]!==Ke||e[132]!==qe||e[133]!==h?(Je=(0,F.jsxs)(Rte,{children:[h,he,ke,ze,Ke,qe]}),e[128]=he,e[129]=ke,e[130]=ze,e[131]=Ke,e[132]=qe,e[133]=h,e[134]=Je):Je=e[134];let Ye;e[135]===Symbol.for(`react.memo_cache_sentinel`)?(Ye=(0,F.jsx)(Lte,{className:`mx-0 w-full`}),e[135]=Ye):Ye=e[135];let Xe,Ze;e[136]===Symbol.for(`react.memo_cache_sentinel`)?(Xe=(0,F.jsx)(jo,{className:`size-4`}),Ze=(0,F.jsx)(`span`,{children:`Sign out`}),e[136]=Xe,e[137]=Ze):(Xe=e[136],Ze=e[137]);let Qe;e[138]===s?Qe=e[139]:(Qe=(0,F.jsxs)(Ite,{children:[Ye,(0,F.jsx)(sg,{children:(0,F.jsx)(cg,{children:(0,F.jsxs)(lg,{onClick:s,tooltip:`Sign out`,children:[Xe,Ze]})})})]}),e[138]=s,e[139]=Qe);let $e;e[140]===Symbol.for(`react.memo_cache_sentinel`)?($e=(0,F.jsx)(Pte,{}),e[140]=$e):$e=e[140];let et;return e[141]!==Je||e[142]!==Qe?(et=(0,F.jsxs)(Mte,{collapsible:`icon`,children:[c,Je,Qe,$e]}),e[141]=Je,e[142]=Qe,e[143]=et):et=e[143],et}function _He(e){return e.pathname}function vHe(e){let t=(0,da.c)(18),{error:n,reset:r}=e,i=Mr(),a=Fe(),o;t[0]!==a||t[1]!==r||t[2]!==i?(o=function(){a.invalidateQueries(),r(),i.invalidate()},t[0]=a,t[1]=r,t[2]=i,t[3]=o):o=t[3];let s=o,c;t[4]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,F.jsx)(K7,{}),t[4]=c):c=t[4];let l;t[5]===Symbol.for(`react.memo_cache_sentinel`)?(l=(0,F.jsx)(vx,{}),t[5]=l):l=t[5];let u,d;t[6]===Symbol.for(`react.memo_cache_sentinel`)?(u=(0,F.jsx)(`div`,{className:`flex justify-center`,children:(0,F.jsx)(Co,{className:`size-12 text-destructive`})}),d=(0,F.jsx)(`h1`,{className:`text-2xl font-semibold`,children:`Something went wrong`}),t[6]=u,t[7]=d):(u=t[6],d=t[7]);let f=n.message||`An unexpected error occurred`,p;t[8]===f?p=t[9]:(p=(0,F.jsx)(`p`,{className:`text-muted-foreground`,children:f}),t[8]=f,t[9]=p);let m;t[10]===s?m=t[11]:(m=(0,F.jsx)(fl,{onClick:s,variant:`default`,children:`Try Again`}),t[10]=s,t[11]=m);let h;t[12]===Symbol.for(`react.memo_cache_sentinel`)?(h=(0,F.jsx)(Oi,{to:`/`,children:(0,F.jsx)(fl,{variant:`outline`,children:`Go Home`})}),t[12]=h):h=t[12];let g;t[13]===m?g=t[14]:(g=(0,F.jsxs)(`div`,{className:`flex justify-center gap-2`,children:[m,h]}),t[13]=m,t[14]=g);let _;return t[15]!==g||t[16]!==p?(_=(0,F.jsxs)(F.Fragment,{children:[c,(0,F.jsxs)(`main`,{className:`flex flex-1 flex-col`,children:[l,(0,F.jsx)(`div`,{className:`flex flex-1 items-center justify-center p-6 pt-0`,children:(0,F.jsxs)(`div`,{className:`max-w-md space-y-4 text-center`,children:[u,d,p,g]})})]})]}),t[15]=g,t[16]=p,t[17]=_):_=t[17],_}var q7=Mi()({head:()=>({meta:[{title:`Mulga`}]}),component:()=>(0,F.jsxs)(F.Fragment,{children:[(0,F.jsx)(ia,{}),(0,F.jsx)(K7,{}),(0,F.jsxs)(`main`,{className:`flex flex-1 flex-col`,children:[(0,F.jsx)(vx,{}),(0,F.jsx)(`div`,{className:`flex flex-1 flex-col p-8`,children:(0,F.jsx)(Wi,{})})]})]}),errorComponent:vHe,notFoundComponent:rae}),yHe=I(`/login`)({beforeLoad:()=>{if(vb())throw bn({to:`/`})},component:L(()=>US(()=>import(`./login.js`),__vite__mapDeps([0,1,2,3,4])),`component`)}),bHe=I(`/_auth`)({beforeLoad:()=>{if(!vb())throw bn({to:`/login`})},component:L(()=>US(()=>import(`./route.js`),[]),`component`)}),J7=Le({queryKey:[`ec2`,`availabilityZones`],queryFn:async()=>{let e=new Oxe({});return await V7().send(e)},staleTime:3e5}),Y7=Le({queryKey:[`ec2`,`instances`],queryFn:async()=>{let e=new d1({});return await V7().send(e)},refetchInterval:5e3}),X7=e=>Le({queryKey:[`ec2`,`instances`,e],queryFn:async()=>{let t=new d1({InstanceIds:[e]});return await V7().send(t)},refetchInterval:5e3}),Z7=Le({queryKey:[`ec2`,`instances`,`types`],queryFn:async()=>{let e=new kxe({Filters:[{Name:`capacity`,Values:[`true`]}]});return await V7().send(e)},refetchInterval:5e3}),Q7=Le({queryKey:[`ec2`,`images`],queryFn:async()=>{let e=new u1({});return await V7().send(e)}}),$7=e=>Le({queryKey:[`ec2`,`images`,e??`none`],queryFn:async()=>{if(!e)return{Images:[],$metadata:{}};let t=new u1({ImageIds:[e]});return await V7().send(t)}}),e9=Le({queryKey:[`ec2`,`keypairs`],queryFn:async()=>{let e=new f1({});return await V7().send(e)}}),t9=e=>Le({queryKey:[`ec2`,`keypairs`,e],queryFn:async()=>{let t=new f1({KeyPairIds:[e]});return await V7().send(t)}}),n9=Le({queryKey:[`ec2`,`regions`],queryFn:async()=>{let e=new Axe({});return await V7().send(e)},staleTime:3e5}),r9=Le({queryKey:[`ec2`,`subnets`],queryFn:async()=>{let e=new g1({});return await V7().send(e)}}),i9=e=>Le({queryKey:[`ec2`,`subnets`,e],queryFn:async()=>{let t=new g1({SubnetIds:[e]});return await V7().send(t)}}),a9=Le({queryKey:[`ec2`,`snapshots`],queryFn:async()=>{let e=new h1({});return await V7().send(e)},refetchInterval:5e3}),o9=e=>Le({queryKey:[`ec2`,`snapshots`,e],queryFn:async()=>{let t=new h1({SnapshotIds:[e]});return await V7().send(t)},refetchInterval:5e3}),s9=Le({queryKey:[`ec2`,`vpcs`],queryFn:async()=>{let e=new v1({});return await V7().send(e)}}),c9=e=>Le({queryKey:[`ec2`,`vpcs`,e],queryFn:async()=>{let t=new v1({VpcIds:[e]});return await V7().send(t)}}),l9=Le({queryKey:[`ec2`,`placementGroups`],queryFn:async()=>{let e=new p1({});return await V7().send(e)}}),u9=e=>Le({queryKey:[`ec2`,`placementGroups`,e],queryFn:async()=>{let t=new p1({GroupIds:[e]});return await V7().send(t)}}),d9=Le({queryKey:[`ec2`,`securityGroups`],queryFn:async()=>{let e=new m1({});return await V7().send(e)}}),f9=e=>Le({queryKey:[`ec2`,`securityGroups`,e],queryFn:async()=>{let t=new m1({GroupIds:[e]});return await V7().send(t)}}),p9=Le({queryKey:[`ec2`,`volumes`],queryFn:async()=>{let e=new _1({});return await V7().send(e)},refetchInterval:5e3}),m9=e=>Le({queryKey:[`ec2`,`volumes`,e],queryFn:async()=>{let t=new _1({VolumeIds:[e]});return await V7().send(t)},refetchInterval:5e3}),h9=Le({queryKey:[`s3`,`buckets`],queryFn:async()=>{let e=new pHe({});return await W7().send(e)}}),g9=(e,t)=>Le({queryKey:[`s3`,`buckets`,e,`objects`,t??``],queryFn:async()=>{let n=new mHe({Bucket:e,Prefix:t,Delimiter:`/`});return await W7().send(n)}}),xHe=I(`/_auth/`)({loader:async({context:e})=>{await Promise.all([e.queryClient.ensureQueryData(Y7),e.queryClient.ensureQueryData(p9),e.queryClient.ensureQueryData(s9),e.queryClient.ensureQueryData(e9),e.queryClient.ensureQueryData(h9),e.queryClient.ensureQueryData(d9)])},head:()=>({meta:[{title:`Dashboard | Mulga`}]}),component:L(()=>US(()=>import(`./_auth.js`),__vite__mapDeps([5,6,7,8,9,10,11,12,3,13])),`component`)}),SHe=I(`/_auth/nodes`)({head:()=>({meta:[{title:`Nodes | Mulga`}]}),component:L(()=>US(()=>import(`./nodes.js`),__vite__mapDeps([14,6,7,10,12,3,13])),`component`)}),CHe=I(`/_auth/s3/service-metrics`)({head:()=>({meta:[{title:`Service Metrics | S3 | Mulga`}]}),component:L(()=>US(()=>import(`./service-metrics.js`),__vite__mapDeps([15,6,7,10,12,3,13])),`component`)}),wHe=I(`/_auth/s3/ls/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(h9)},head:()=>({meta:[{title:`Buckets | S3 | Mulga`}]}),component:L(()=>US(()=>import(`./ls.js`),__vite__mapDeps([16,17,7,18,10])),`component`)}),THe=I(`/_auth/s3/(buckets)/create-bucket`)({head:()=>({meta:[{title:`Create Bucket | S3 | Mulga`}]}),component:L(()=>US(()=>import(`./create-bucket.js`),__vite__mapDeps([19,20,21,2,22,23,24,8,25,26,27,10,4])),`component`)}),EHe=I(`/_auth/iam/(users)/create-user`)({head:()=>({meta:[{title:`Create User | IAM | Mulga`}]}),component:L(()=>US(()=>import(`./create-user.js`),__vite__mapDeps([28,29,21,2,22,23,24,8,25,26,27,10,4,30])),`component`)}),DHe=I(`/_auth/iam/(policies)/create-policy`)({head:()=>({meta:[{title:`Create Policy | IAM | Mulga`}]}),component:L(()=>US(()=>import(`./create-policy.js`),__vite__mapDeps([31,29,21,2,22,23,24,8,25,26,27,10,4,32,30])),`component`)}),OHe=I(`/_auth/ec2/(vpc)/create-vpc`)({head:()=>({meta:[{title:`Create VPC | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./create-vpc.js`),__vite__mapDeps([33,34,21,35,24,8,2,22,9,23,25,26,27,10,4,36])),`component`)}),kHe=I(`/_auth/ec2/(volumes)/create-volume`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(J7)},head:()=>({meta:[{title:`Create Volume | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./create-volume.js`),__vite__mapDeps([37,34,21,35,24,8,2,17,7,22,23,25,26,27,10,4,36])),`component`)}),AHe=I(`/_auth/ec2/(target-groups)/create-target-group`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(s9)},head:()=>({meta:[{title:`Create Target Group | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./create-target-group.js`),__vite__mapDeps([38,39,21,2,17,7,22,23,24,8,25,26,40,1,35,41,42,4,27,10,43])),`component`)}),jHe=I(`/_auth/ec2/(subnet)/create-subnet`)({loader:async({context:e})=>{await Promise.all([e.queryClient.ensureQueryData(s9),e.queryClient.ensureQueryData(J7)])},head:()=>({meta:[{title:`Create Subnet | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./create-subnet.js`),__vite__mapDeps([44,34,21,35,24,8,2,17,7,22,23,25,26,27,10,4,36])),`component`)}),_9=I(`/_auth/ec2/(snapshots)/create-snapshot`)({validateSearch:e=>({volumeId:typeof e.volumeId==`string`?e.volumeId:void 0}),loader:async({context:e})=>{await e.queryClient.ensureQueryData(p9)},head:()=>({meta:[{title:`Create Snapshot | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./create-snapshot.js`),__vite__mapDeps([45,34,21,35,24,8,2,17,7,22,23,25,26,27,10,4,32,36])),`component`)}),MHe=I(`/_auth/ec2/(security-groups)/create-security-group`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(s9)},head:()=>({meta:[{title:`Create Security Group | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./create-security-group.js`),__vite__mapDeps([46,34,21,35,24,8,2,17,7,22,23,25,26,27,10,4,36])),`component`)}),NHe=I(`/_auth/ec2/(placement-groups)/create-placement-group`)({head:()=>({meta:[{title:`Create Placement Group | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./create-placement-group.js`),__vite__mapDeps([47,34,21,35,24,8,2,22,23,25,26,27,10,4,36])),`component`)}),v9=5e3,y9=Le({queryKey:[`elbv2`,`loadBalancers`],queryFn:async()=>{let e=new N2({});return await H7().send(e)},refetchInterval:e=>(e.state.data?.LoadBalancers??[]).some(e=>e.State?.Code===`provisioning`)?v9:!1}),b9=e=>Le({queryKey:[`elbv2`,`loadBalancers`,e],queryFn:async()=>{let t=new N2({LoadBalancerArns:[e]});return await H7().send(t)},refetchInterval:e=>(e.state.data?.LoadBalancers?.[0])?.State?.Code===`provisioning`?v9:!1}),x9=e=>Le({queryKey:[`elbv2`,`loadBalancers`,e,`attributes`],queryFn:async()=>{let t=new oje({LoadBalancerArn:e});return await H7().send(t)}}),S9=Le({queryKey:[`elbv2`,`targetGroups`],queryFn:async()=>{let e=new P2({});return await H7().send(e)}}),C9=e=>Le({queryKey:[`elbv2`,`targetGroups`,e],queryFn:async()=>{let t=new P2({TargetGroupArns:[e]});return await H7().send(t)}}),w9=e=>Le({queryKey:[`elbv2`,`targetGroups`,e,`attributes`],queryFn:async()=>{let t=new uje({TargetGroupArn:e});return await H7().send(t)}}),T9=e=>Le({queryKey:[`elbv2`,`listeners`,e],queryFn:async()=>{let t=new aje({LoadBalancerArn:e});return await H7().send(t)}}),PHe=e=>Le({queryKey:[`elbv2`,`listeners`,e,`rules`],queryFn:async()=>{let t=new sje({ListenerArn:e});return await H7().send(t)}}),FHe=e=>Le({queryKey:[`elbv2`,`targetGroups`,e,`health`],queryFn:async()=>{let t=new dje({TargetGroupArn:e});return await H7().send(t)}}),IHe=Le({queryKey:[`elbv2`,`sslPolicies`],queryFn:async()=>{let e=new cje({});return await H7().send(e)},staleTime:1/0}),E9=e=>Le({queryKey:[`elbv2`,`tags`,...e],queryFn:async()=>{let t=new lje({ResourceArns:e});return await H7().send(t)},enabled:e.length>0}),LHe=I(`/_auth/ec2/(load-balancers)/create-load-balancer`)({loader:async({context:e})=>{await Promise.all([e.queryClient.ensureQueryData(s9),e.queryClient.ensureQueryData(r9),e.queryClient.ensureQueryData(d9),e.queryClient.ensureQueryData(S9)])},head:()=>({meta:[{title:`Create Load Balancer | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./create-load-balancer.js`),__vite__mapDeps([48,39,21,35,24,8,2,17,7,22,41,23,25,26,42,40,1,4,27,10,43])),`component`)}),RHe=I(`/_auth/ec2/(key)/import-key-pair`)({head:()=>({meta:[{title:`Import Key Pair | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./import-key-pair.js`),__vite__mapDeps([49,34,21,2,22,23,24,8,25,26,27,10,4,32,36])),`component`)}),zHe=I(`/_auth/ec2/(key)/create-key-pair`)({head:()=>({meta:[{title:`Create Key Pair | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./create-key-pair.js`),__vite__mapDeps([50,34,21,51,2,22,24,52,23,8,25,26,53,27,10,4,36])),`component`)}),BHe=I(`/_auth/ec2/(instances)/run-instances`)({loader:async({context:e})=>{await Promise.all([e.queryClient.ensureQueryData(Q7),e.queryClient.ensureQueryData(e9),e.queryClient.ensureQueryData(Z7),e.queryClient.ensureQueryData(r9),e.queryClient.ensureQueryData(l9)])},head:()=>({meta:[{title:`Run Instances | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./run-instances.js`),__vite__mapDeps([54,34,21,1,35,24,8,2,17,7,22,23,25,26,10,4,36])),`component`)}),VHe=I(`/_auth/s3/ls/$bucket`)({component:L(()=>US(()=>import(`./route2.js`),[]),`component`)}),D9=I(`/_auth/s3/ls/$bucket/`)({loader:async({context:e,params:t})=>{await e.queryClient.ensureQueryData(g9(t.bucket))},head:({params:e})=>({meta:[{title:`${e.bucket} | S3 | Mulga`}]}),component:L(()=>US(()=>import(`./_bucket.js`),__vite__mapDeps([55,20,21,56,52,42,57,51,17,7,22,10])),`component`)}),O9=Le({queryKey:[`iam`,`users`],queryFn:async()=>{let e=new QFe({});return await U7().send(e)},staleTime:3e5}),k9=e=>Le({queryKey:[`iam`,`users`,e],queryFn:async()=>{let t=new JFe({UserName:e});return await U7().send(t)},staleTime:3e5}),A9=e=>Le({queryKey:[`iam`,`access-keys`,e],queryFn:async()=>{let t=new YFe({UserName:e});return await U7().send(t)},staleTime:3e5}),j9=Le({queryKey:[`iam`,`policies`],queryFn:async()=>{let e=new ZFe({Scope:`Local`});return await U7().send(e)},staleTime:3e5}),M9=e=>Le({queryKey:[`iam`,`policies`,e],queryFn:async()=>{let t=new KFe({PolicyArn:e});return await U7().send(t)},staleTime:3e5}),N9=(e,t)=>Le({queryKey:[`iam`,`policy-versions`,e,t],queryFn:async()=>{let n=new qFe({PolicyArn:e,VersionId:t});return await U7().send(n)},staleTime:3e5}),P9=e=>Le({queryKey:[`iam`,`attached-user-policies`,e],queryFn:async()=>{let t=new XFe({UserName:e});return await U7().send(t)},staleTime:3e5}),HHe=I(`/_auth/iam/(users)/list-users/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(O9)},head:()=>({meta:[{title:`Users | IAM | Mulga`}]}),component:L(()=>US(()=>import(`./list-users.js`),__vite__mapDeps([58,17,7,18,10])),`component`)}),UHe=I(`/_auth/iam/(policies)/list-policies/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(j9)},head:()=>({meta:[{title:`Policies | IAM | Mulga`}]}),component:L(()=>US(()=>import(`./list-policies.js`),__vite__mapDeps([59,17,7,18,10])),`component`)}),WHe=I(`/_auth/ec2/(vpc)/describe-vpcs/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(s9)},head:()=>({meta:[{title:`VPCs | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./describe-vpcs.js`),__vite__mapDeps([60,17,7,18,10,11])),`component`)}),GHe=I(`/_auth/ec2/(volumes)/describe-volumes/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(p9)},head:()=>({meta:[{title:`Volumes | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./describe-volumes.js`),__vite__mapDeps([61,17,7,18,10,11])),`component`)}),KHe=I(`/_auth/ec2/(target-groups)/describe-target-groups/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(S9)},head:()=>({meta:[{title:`Target Groups | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./describe-target-groups.js`),__vite__mapDeps([62,6,7,17,10])),`component`)}),qHe=I(`/_auth/ec2/(subnet)/describe-subnets/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(r9)},head:()=>({meta:[{title:`Subnets | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./describe-subnets.js`),__vite__mapDeps([63,17,7,18,10,11])),`component`)}),JHe=I(`/_auth/ec2/(snapshots)/describe-snapshots/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(a9)},head:()=>({meta:[{title:`Snapshots | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./describe-snapshots.js`),__vite__mapDeps([64,17,7,18,10,11])),`component`)}),YHe=I(`/_auth/ec2/(security-groups)/describe-security-groups/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(d9)},head:()=>({meta:[{title:`Security Groups | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./describe-security-groups.js`),__vite__mapDeps([65,17,7,18,10])),`component`)}),XHe=I(`/_auth/ec2/(placement-groups)/describe-placement-groups/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(l9)},head:()=>({meta:[{title:`Placement Groups | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./describe-placement-groups.js`),__vite__mapDeps([66,17,7,18,10,11])),`component`)}),ZHe=I(`/_auth/ec2/(load-balancers)/describe-load-balancers/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(y9)},head:()=>({meta:[{title:`Load Balancers | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./describe-load-balancers.js`),__vite__mapDeps([67,17,7,10,11])),`component`)}),QHe=I(`/_auth/ec2/(key)/describe-key-pairs/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(e9)},head:()=>({meta:[{title:`Key Pairs | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./describe-key-pairs.js`),__vite__mapDeps([68,17,7,18,10])),`component`)}),$He=I(`/_auth/ec2/(instances)/describe-instances/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(Y7)},head:()=>({meta:[{title:`Instances | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./describe-instances.js`),__vite__mapDeps([69,17,7,18,10,11])),`component`)}),eUe=I(`/_auth/ec2/(images)/describe-images/`)({loader:async({context:e})=>{await e.queryClient.ensureQueryData(Q7)},head:()=>({meta:[{title:`Images | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./describe-images.js`),__vite__mapDeps([70,17,7,18,10,11,71])),`component`)}),F9=I(`/_auth/s3/ls/$bucket/$`)({loader:async({context:e,params:t})=>{let n=cl(t._splat??``);await e.queryClient.ensureQueryData(g9(t.bucket,n))},head:({params:e})=>({meta:[{title:`${ll(e._splat??``,`${e.bucket}/`)} | S3 | Mulga`}]}),component:L(()=>US(()=>import(`./_.js`),__vite__mapDeps([72,20,21,56,52,42,57,51,17,7,22])),`component`)}),I9=I(`/_auth/iam/(users)/list-users/$userName`)({loader:async({context:e,params:t})=>{await Promise.all([e.queryClient.ensureQueryData(k9(t.userName)),e.queryClient.ensureQueryData(A9(t.userName)),e.queryClient.ensureQueryData(P9(t.userName)),e.queryClient.ensureQueryData(j9)])},head:({params:e})=>({meta:[{title:`${e.userName} | IAM | Mulga`}]}),component:L(()=>US(()=>import(`./_userName.js`),__vite__mapDeps([73,29,21,51,17,7,22,24,42,53,57,74,10,11,26])),`component`)}),L9=I(`/_auth/iam/(policies)/list-policies/$policyArn`)({loader:async({context:e,params:t})=>{let n=decodeURIComponent(t.policyArn),r=await e.queryClient.ensureQueryData(M9(n)),i=r.Policy?.DefaultVersionId;return i&&await e.queryClient.ensureQueryData(N9(n,i)),r},head:({loaderData:e})=>({meta:[{title:`${e?.Policy?.PolicyName??`Policy`} | IAM | Mulga`}]}),component:L(()=>US(()=>import(`./_policyArn.js`),__vite__mapDeps([75,29,21,17,7,22,42,57,51,74,10])),`component`)}),R9=I(`/_auth/ec2/(vpc)/describe-vpcs/$id`)({loader:async({context:e,params:t})=>{await Promise.all([e.queryClient.ensureQueryData(c9(t.id)),e.queryClient.ensureQueryData(r9)])},head:({params:e})=>({meta:[{title:`${e.id} | VPC | Mulga`}]}),component:L(()=>US(()=>import(`./_id12.js`),__vite__mapDeps([76,34,21,17,7,22,42,57,51,74,10,11])),`component`)}),z9=I(`/_auth/ec2/(volumes)/modify-volume/$id`)({loader:async({context:e,params:t})=>{await e.queryClient.ensureQueryData(m9(t.id))},head:({params:e})=>({meta:[{title:`Resize ${e.id} | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./_id11.js`),__vite__mapDeps([77,34,21,2,17,7,22,27,10,4,36])),`component`)}),B9=I(`/_auth/ec2/(volumes)/describe-volumes/$id`)({loader:async({context:e,params:t})=>{await Promise.all([e.queryClient.ensureQueryData(m9(t.id)),e.queryClient.ensureQueryData(Y7)])},head:({params:e})=>({meta:[{title:`${e.id} | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./_id10.js`),__vite__mapDeps([78,34,21,51,35,24,8,17,7,22,42,57,74,10,11,4])),`component`)}),V9=I(`/_auth/ec2/(target-groups)/describe-target-groups/$id`)({loader:async({context:e,params:t})=>{let n=decodeURIComponent(t.id);await Promise.all([e.queryClient.ensureQueryData(C9(n)),e.queryClient.ensureQueryData(w9(n)),e.queryClient.ensureQueryData(E9([n])),e.queryClient.ensureQueryData(Y7)])},head:({params:e})=>({meta:[{title:`${decodeURIComponent(e.id)} | Target Group | Mulga`}]}),component:L(()=>US(()=>import(`./_id9.js`),__vite__mapDeps([79,39,21,51,80,35,24,8,41,42,4,6,7,17,22,57,74,10])),`component`)}),H9=I(`/_auth/ec2/(subnet)/describe-subnets/$id`)({loader:async({context:e,params:t})=>{await e.queryClient.ensureQueryData(i9(t.id))},head:({params:e})=>({meta:[{title:`${e.id} | Subnet | Mulga`}]}),component:L(()=>US(()=>import(`./_id8.js`),__vite__mapDeps([81,34,21,17,7,22,42,57,51,74,10,11])),`component`)}),U9=I(`/_auth/ec2/(snapshots)/describe-snapshots/$id`)({loader:async({context:e,params:t})=>{await Promise.all([e.queryClient.ensureQueryData(o9(t.id)),e.queryClient.ensureQueryData(n9)])},head:({params:e})=>({meta:[{title:`${e.id} | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./_id7.js`),__vite__mapDeps([82,34,21,51,17,7,22,25,42,57,74,10,11,4])),`component`)}),W9=I(`/_auth/ec2/(security-groups)/describe-security-groups/$id`)({loader:async({context:e,params:t})=>{await e.queryClient.ensureQueryData(f9(t.id))},head:({params:e})=>({meta:[{title:`${e.id} | Security Group | Mulga`}]}),component:L(()=>US(()=>import(`./_id6.js`),__vite__mapDeps([83,34,21,51,35,24,8,2,17,7,22,41,42,57,74,10,4,36])),`component`)}),G9=I(`/_auth/ec2/(placement-groups)/describe-placement-groups/$id`)({loader:async({context:e,params:t})=>{await Promise.all([e.queryClient.ensureQueryData(u9(t.id)),e.queryClient.ensureQueryData(Y7)])},head:({params:e})=>({meta:[{title:`${e.id} | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./_id5.js`),__vite__mapDeps([84,34,21,17,7,22,42,57,51,74,10,11])),`component`)}),K9=I(`/_auth/ec2/(load-balancers)/describe-load-balancers/$id`)({loader:async({context:e,params:t})=>{let n=decodeURIComponent(t.id);await Promise.all([e.queryClient.ensureQueryData(b9(n)),e.queryClient.ensureQueryData(T9(n)),e.queryClient.ensureQueryData(x9(n)),e.queryClient.ensureQueryData(E9([n])),e.queryClient.ensureQueryData(S9),e.queryClient.ensureQueryData(r9)])},head:({params:e})=>({meta:[{title:`${decodeURIComponent(e.id)} | Load Balancer | Mulga`}]}),component:L(()=>US(()=>import(`./_id4.js`),__vite__mapDeps([85,39,21,51,35,24,8,80,41,42,4,2,17,7,22,57,74,10,11,32,43])),`component`)}),q9=I(`/_auth/ec2/(key)/describe-key-pairs/$id`)({loader:async({context:e,params:t})=>await e.queryClient.ensureQueryData(t9(t.id)),head:({loaderData:e})=>({meta:[{title:`${e?.KeyPairs?.[0]?.KeyName??`Key Pair`} | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./_id3.js`),__vite__mapDeps([86,34,21,17,7,22,42,57,51,74,10])),`component`)}),J9=I(`/_auth/ec2/(instances)/describe-instances/$id`)({loader:async({context:e,params:t})=>{let[n]=await Promise.all([e.queryClient.ensureQueryData(X7(t.id)),e.queryClient.ensureQueryData(Z7)]),r=n.Reservations?.[0]?.Instances?.[0]?.ImageId;return await e.queryClient.ensureQueryData($7(r)),n},head:({loaderData:e})=>({meta:[{title:`${e?.Reservations?.[0]?.Instances?.[0]?.InstanceId??`Instance`} | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./_id2.js`),__vite__mapDeps([87,34,21,51,35,24,8,6,7,17,22,42,57,74,10,11,4,32,13,88])),`component`)}),Y9=I(`/_auth/ec2/(images)/describe-images/$id`)({loader:async({context:e,params:t})=>await e.queryClient.ensureQueryData($7(t.id)),head:({loaderData:e})=>({meta:[{title:`${e?.Images?.[0]?.Name??`Image`} | EC2 | Mulga`}]}),component:L(()=>US(()=>import(`./_id.js`),__vite__mapDeps([89,17,7,22,10,11,71,88,74])),`component`)}),tUe=yHe.update({id:`/login`,path:`/login`,getParentRoute:()=>q7}),X9=bHe.update({id:`/_auth`,getParentRoute:()=>q7}),nUe=xHe.update({id:`/`,path:`/`,getParentRoute:()=>X9}),rUe=SHe.update({id:`/nodes`,path:`/nodes`,getParentRoute:()=>X9}),iUe=CHe.update({id:`/s3/service-metrics`,path:`/s3/service-metrics`,getParentRoute:()=>X9}),aUe=wHe.update({id:`/s3/ls/`,path:`/s3/ls/`,getParentRoute:()=>X9}),oUe=THe.update({id:`/s3/(buckets)/create-bucket`,path:`/s3/create-bucket`,getParentRoute:()=>X9}),sUe=EHe.update({id:`/iam/(users)/create-user`,path:`/iam/create-user`,getParentRoute:()=>X9}),cUe=DHe.update({id:`/iam/(policies)/create-policy`,path:`/iam/create-policy`,getParentRoute:()=>X9}),lUe=OHe.update({id:`/ec2/(vpc)/create-vpc`,path:`/ec2/create-vpc`,getParentRoute:()=>X9}),uUe=kHe.update({id:`/ec2/(volumes)/create-volume`,path:`/ec2/create-volume`,getParentRoute:()=>X9}),dUe=AHe.update({id:`/ec2/(target-groups)/create-target-group`,path:`/ec2/create-target-group`,getParentRoute:()=>X9}),fUe=jHe.update({id:`/ec2/(subnet)/create-subnet`,path:`/ec2/create-subnet`,getParentRoute:()=>X9}),pUe=_9.update({id:`/ec2/(snapshots)/create-snapshot`,path:`/ec2/create-snapshot`,getParentRoute:()=>X9}),mUe=MHe.update({id:`/ec2/(security-groups)/create-security-group`,path:`/ec2/create-security-group`,getParentRoute:()=>X9}),hUe=NHe.update({id:`/ec2/(placement-groups)/create-placement-group`,path:`/ec2/create-placement-group`,getParentRoute:()=>X9}),gUe=LHe.update({id:`/ec2/(load-balancers)/create-load-balancer`,path:`/ec2/create-load-balancer`,getParentRoute:()=>X9}),_Ue=RHe.update({id:`/ec2/(key)/import-key-pair`,path:`/ec2/import-key-pair`,getParentRoute:()=>X9}),vUe=zHe.update({id:`/ec2/(key)/create-key-pair`,path:`/ec2/create-key-pair`,getParentRoute:()=>X9}),yUe=BHe.update({id:`/ec2/(instances)/run-instances`,path:`/ec2/run-instances`,getParentRoute:()=>X9}),Z9=VHe.update({id:`/s3/ls/$bucket`,path:`/s3/ls/$bucket`,getParentRoute:()=>X9}),bUe=D9.update({id:`/`,path:`/`,getParentRoute:()=>Z9}),xUe=HHe.update({id:`/iam/(users)/list-users/`,path:`/iam/list-users/`,getParentRoute:()=>X9}),SUe=UHe.update({id:`/iam/(policies)/list-policies/`,path:`/iam/list-policies/`,getParentRoute:()=>X9}),CUe=WHe.update({id:`/ec2/(vpc)/describe-vpcs/`,path:`/ec2/describe-vpcs/`,getParentRoute:()=>X9}),wUe=GHe.update({id:`/ec2/(volumes)/describe-volumes/`,path:`/ec2/describe-volumes/`,getParentRoute:()=>X9}),TUe=KHe.update({id:`/ec2/(target-groups)/describe-target-groups/`,path:`/ec2/describe-target-groups/`,getParentRoute:()=>X9}),EUe=qHe.update({id:`/ec2/(subnet)/describe-subnets/`,path:`/ec2/describe-subnets/`,getParentRoute:()=>X9}),DUe=JHe.update({id:`/ec2/(snapshots)/describe-snapshots/`,path:`/ec2/describe-snapshots/`,getParentRoute:()=>X9}),OUe=YHe.update({id:`/ec2/(security-groups)/describe-security-groups/`,path:`/ec2/describe-security-groups/`,getParentRoute:()=>X9}),kUe=XHe.update({id:`/ec2/(placement-groups)/describe-placement-groups/`,path:`/ec2/describe-placement-groups/`,getParentRoute:()=>X9}),AUe=ZHe.update({id:`/ec2/(load-balancers)/describe-load-balancers/`,path:`/ec2/describe-load-balancers/`,getParentRoute:()=>X9}),jUe=QHe.update({id:`/ec2/(key)/describe-key-pairs/`,path:`/ec2/describe-key-pairs/`,getParentRoute:()=>X9}),MUe=$He.update({id:`/ec2/(instances)/describe-instances/`,path:`/ec2/describe-instances/`,getParentRoute:()=>X9}),NUe=eUe.update({id:`/ec2/(images)/describe-images/`,path:`/ec2/describe-images/`,getParentRoute:()=>X9}),PUe=F9.update({id:`/$`,path:`/$`,getParentRoute:()=>Z9}),FUe=I9.update({id:`/iam/(users)/list-users/$userName`,path:`/iam/list-users/$userName`,getParentRoute:()=>X9}),IUe=L9.update({id:`/iam/(policies)/list-policies/$policyArn`,path:`/iam/list-policies/$policyArn`,getParentRoute:()=>X9}),LUe=R9.update({id:`/ec2/(vpc)/describe-vpcs/$id`,path:`/ec2/describe-vpcs/$id`,getParentRoute:()=>X9}),RUe=z9.update({id:`/ec2/(volumes)/modify-volume/$id`,path:`/ec2/modify-volume/$id`,getParentRoute:()=>X9}),zUe=B9.update({id:`/ec2/(volumes)/describe-volumes/$id`,path:`/ec2/describe-volumes/$id`,getParentRoute:()=>X9}),BUe=V9.update({id:`/ec2/(target-groups)/describe-target-groups/$id`,path:`/ec2/describe-target-groups/$id`,getParentRoute:()=>X9}),VUe=H9.update({id:`/ec2/(subnet)/describe-subnets/$id`,path:`/ec2/describe-subnets/$id`,getParentRoute:()=>X9}),HUe=U9.update({id:`/ec2/(snapshots)/describe-snapshots/$id`,path:`/ec2/describe-snapshots/$id`,getParentRoute:()=>X9}),UUe=W9.update({id:`/ec2/(security-groups)/describe-security-groups/$id`,path:`/ec2/describe-security-groups/$id`,getParentRoute:()=>X9}),WUe=G9.update({id:`/ec2/(placement-groups)/describe-placement-groups/$id`,path:`/ec2/describe-placement-groups/$id`,getParentRoute:()=>X9}),GUe=K9.update({id:`/ec2/(load-balancers)/describe-load-balancers/$id`,path:`/ec2/describe-load-balancers/$id`,getParentRoute:()=>X9}),KUe=q9.update({id:`/ec2/(key)/describe-key-pairs/$id`,path:`/ec2/describe-key-pairs/$id`,getParentRoute:()=>X9}),qUe=J9.update({id:`/ec2/(instances)/describe-instances/$id`,path:`/ec2/describe-instances/$id`,getParentRoute:()=>X9}),JUe=Y9.update({id:`/ec2/(images)/describe-images/$id`,path:`/ec2/describe-images/$id`,getParentRoute:()=>X9}),YUe={AuthS3LsBucketSplatRoute:PUe,AuthS3LsBucketIndexRoute:bUe},XUe={AuthNodesRoute:rUe,AuthIndexRoute:nUe,AuthS3ServiceMetricsRoute:iUe,AuthS3LsBucketRouteRoute:Z9._addFileChildren(YUe),AuthEc2instancesRunInstancesRoute:yUe,AuthEc2keyCreateKeyPairRoute:vUe,AuthEc2keyImportKeyPairRoute:_Ue,AuthEc2loadBalancersCreateLoadBalancerRoute:gUe,AuthEc2placementGroupsCreatePlacementGroupRoute:hUe,AuthEc2securityGroupsCreateSecurityGroupRoute:mUe,AuthEc2snapshotsCreateSnapshotRoute:pUe,AuthEc2subnetCreateSubnetRoute:fUe,AuthEc2targetGroupsCreateTargetGroupRoute:dUe,AuthEc2volumesCreateVolumeRoute:uUe,AuthEc2vpcCreateVpcRoute:lUe,AuthIampoliciesCreatePolicyRoute:cUe,AuthIamusersCreateUserRoute:sUe,AuthS3bucketsCreateBucketRoute:oUe,AuthS3LsIndexRoute:aUe,AuthEc2imagesDescribeImagesIdRoute:JUe,AuthEc2instancesDescribeInstancesIdRoute:qUe,AuthEc2keyDescribeKeyPairsIdRoute:KUe,AuthEc2loadBalancersDescribeLoadBalancersIdRoute:GUe,AuthEc2placementGroupsDescribePlacementGroupsIdRoute:WUe,AuthEc2securityGroupsDescribeSecurityGroupsIdRoute:UUe,AuthEc2snapshotsDescribeSnapshotsIdRoute:HUe,AuthEc2subnetDescribeSubnetsIdRoute:VUe,AuthEc2targetGroupsDescribeTargetGroupsIdRoute:BUe,AuthEc2volumesDescribeVolumesIdRoute:zUe,AuthEc2volumesModifyVolumeIdRoute:RUe,AuthEc2vpcDescribeVpcsIdRoute:LUe,AuthIampoliciesListPoliciesPolicyArnRoute:IUe,AuthIamusersListUsersUserNameRoute:FUe,AuthEc2imagesDescribeImagesIndexRoute:NUe,AuthEc2instancesDescribeInstancesIndexRoute:MUe,AuthEc2keyDescribeKeyPairsIndexRoute:jUe,AuthEc2loadBalancersDescribeLoadBalancersIndexRoute:AUe,AuthEc2placementGroupsDescribePlacementGroupsIndexRoute:kUe,AuthEc2securityGroupsDescribeSecurityGroupsIndexRoute:OUe,AuthEc2snapshotsDescribeSnapshotsIndexRoute:DUe,AuthEc2subnetDescribeSubnetsIndexRoute:EUe,AuthEc2targetGroupsDescribeTargetGroupsIndexRoute:TUe,AuthEc2volumesDescribeVolumesIndexRoute:wUe,AuthEc2vpcDescribeVpcsIndexRoute:CUe,AuthIampoliciesListPoliciesIndexRoute:SUe,AuthIamusersListUsersIndexRoute:xUe},ZUe={AuthRouteRoute:X9._addFileChildren(XUe),LoginRoute:tUe},QUe=q7._addFileChildren(ZUe)._addFileTypes(),Q9=new ke({defaultOptions:{queries:{staleTime:5e3,refetchIntervalInBackground:!1}}}),$Ue=Yi({routeTree:QUe,context:{queryClient:Q9},defaultPreload:`intent`,scrollRestoration:!0,defaultStructuralSharing:!0,defaultPreloadStaleTime:0}),$9=document.querySelector(`#app`);$9&&!$9.innerHTML&&ua.createRoot($9).render((0,F.jsx)(P.StrictMode,{children:(0,F.jsx)(ma,{defaultTheme:`dark`,storageKey:`spinifex-ui-theme`,children:(0,F.jsx)(Ie,{client:Q9,children:(0,F.jsx)(tae,{children:(0,F.jsx)(kte,{children:(0,F.jsx)(Qi,{router:$Ue})})})})})}));export{i9 as $,ys as $a,Fd as $i,Poe as $n,Zm as $r,QAe as $t,E9 as A,Gl as Aa,Sf as Ai,mxe as An,Te as Ao,ob as Ar,DFe as At,Q7 as B,dl as Ba,ef as Bi,oA as Bn,y as Bo,Sh as Br,AAe as Bt,D9 as C,nu as Ca,sp as Ci,qbe as Cn,Oi as Co,vb as Cr,U4 as Ct,b9 as D,Xl as Da,If as Di,dxe as Dn,Fe as Do,zre as Dr,wFe as Dt,x9 as E,Yl as Ea,Ff as Ei,uxe as En,Le as Eo,ab as Er,rIe as Et,_9 as F,El as Fa,gf as Fi,yxe as Fn,w as Fo,Rg as Fr,zFe as Ft,e9 as G,tl as Ga,Bd as Gi,PO as Gn,u as Go,_h as Gr,FAe as Gt,Z7 as H,$c as Ha,qd as Hi,qk as Hn,oe as Ho,bh as Hr,MAe as Ht,g9 as I,wl as Ia,sf as Ii,bxe as In,_ as Io,tg as Ir,F2 as It,n9 as J,al as Ja,$d as Ji,rO as Jn,c as Jo,uh as Jr,qAe as Jt,u9 as K,il as Ka,Wd as Ki,mO as Kn,l as Ko,hh as Kr,IAe as Kt,h9 as L,yl as La,cf as Li,xxe as Ln,h as Lo,eg as Lr,DAe as Lt,C9 as M,Nl as Ma,bf as Mi,gxe as Mn,N as Mo,Qy as Mr,kFe as Mt,S9 as N,Ol as Na,vf as Ni,_xe as Nn,M as No,nne as Nr,AFe as Nt,y9 as O,ql as Oa,Mf as Oi,fxe as On,Ne as Oo,rb as Or,TFe as Ot,FHe as P,Dl as Pa,_f as Pi,vxe as Pn,ce as Po,rne as Pr,jFe as Pt,a9 as Q,xs as Qa,Id as Qi,dw as Qn,Jee as Qr,ZAe as Qt,J7 as R,_l as Ra,af as Ri,wA as Rn,k as Ro,Qh as Rr,OAe as Rt,O9 as S,iu as Sa,fp as Si,Kbe as Sn,Wi as So,yb as Sr,sIe as St,T9 as T,Jl as Ta,Bf as Ti,Ybe as Tn,bn as To,lb as Tr,H4 as Tt,Y7 as U,cl as Ua,Gd as Ui,Kk as Un,v as Uo,yh as Ur,NAe as Ut,X7 as V,ll as Va,Xd as Vi,Yk as Vn,D as Vo,xh as Vr,jAe as Vt,t9 as W,ul as Wa,Yd as Wi,Fk as Wn,f as Wo,vh as Wr,PAe as Wt,d9 as X,Cs as Xa,Rd as Xi,SD as Xn,ch as Xr,YAe as Xt,f9 as Y,sl as Ya,zd as Yi,tO as Yn,lh as Yr,JAe as Yt,o9 as Z,bs as Za,Ld as Zi,CD as Zn,sh as Zr,XAe as Zt,P9 as _,fu as _a,ym as _i,Vbe as _n,Ia as _o,wb as _r,xVe as _t,G9 as a,Sd as aa,eh as ai,kbe as an,Fo as ao,_x as ar,G7 as at,N9 as b,uu as ba,xp as bi,Wbe as bn,va as bo,xb as br,O6 as bt,H9 as c,Ju as ca,Yee as ci,Mbe as cn,To as co,ax as cr,H7 as ct,z9 as d,Wu as da,Zee as di,Fbe as dn,co as do,Wb as dr,fVe as dt,jd as ea,rh as ei,y1 as en,hs as eo,$x as er,r9 as et,R9 as f,Uu as fa,Qee as fi,Ibe as fn,ro as fo,zb as fr,pVe as ft,A9 as g,Bu as ga,wm as gi,Bbe as gn,Ga as go,Ab as gr,vVe as gt,F9 as h,Xu as ha,Tm as hi,zbe as hn,qa as ho,kb as hr,_Ve as ht,K9 as i,Td as ia,ih as ii,Obe as in,Lo as io,xx as ir,s9 as it,w9 as j,Kl as ja,xf as ji,hxe as jn,xe as jo,Yre as jr,OFe as jt,IHe as k,Wl as ka,Af as ki,pxe as kn,je as ko,Ire as kr,EFe as kt,V9 as l,Yu as la,nh as li,Nbe as ln,So as lo,Kb as lr,U7 as lt,I9 as m,Hu as ma,Pm as mi,Rbe as mn,Ka as mo,Ob as mr,hVe as mt,J9 as n,Od as na,$m as ni,Ebe as nn,Jo as no,Vx as nr,p9 as nt,W9 as o,qu as oa,th as oi,Abe as on,No as oo,hx as or,gHe as ot,L9 as p,Qu as pa,Vm as pi,Lbe as pn,Za as po,Rb as pr,mVe as pt,l9 as q,nl as qa,Vd as qi,iO as qn,o as qo,dh as qr,KAe as qt,q9 as r,kd as ra,Xm as ri,Dbe as rn,Vo as ro,oae as rr,c9 as rt,U9 as s,Gu as sa,Kee as si,jbe as sn,Oo as so,fx as sr,V7 as st,Y9 as t,Pd as ta,Qm as ti,d1 as tn,Wo as to,Zx as tr,m9 as tt,B9 as u,Ku as ua,qee as ui,Pbe as un,yo as uo,Gb as ur,W7 as ut,j9 as v,du as va,am as vi,Hbe as vn,Fa as vo,Cb as vr,SVe as vt,PHe as w,eu as wa,ep as wi,Jbe as wn,fi as wo,mie as wr,oIe as wt,k9 as x,su as xa,dp as xi,Gbe as xn,la as xo,gb as xr,X4 as xt,M9 as y,lu as ya,Op as yi,Ube as yn,Na as yo,Sb as yr,CVe as yt,$7 as z,fl as za,rf as zi,mA as zn,b as zo,Wh as zr,kAe as zt}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/list-card.js b/spinifex/services/spinifexui/frontend/dist/assets/list-card.js index 6a59119e4..eaff82e82 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/list-card.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/list-card.js @@ -1 +1 @@ -import{lo as e,mo as t,so as n}from"./index.js";var r=n(),i=t();function a(t){let n=(0,r.c)(22),a,o,s,c,l;n[0]===t?(a=n[1],o=n[2],s=n[3],c=n[4],l=n[5]):({title:l,subtitle:c,badge:a,children:o,...s}=t,n[0]=t,n[1]=a,n[2]=o,n[3]=s,n[4]=c,n[5]=l);let u;n[6]===l?u=n[7]:(u=(0,i.jsx)(`h3`,{className:`font-semibold`,children:l}),n[6]=l,n[7]=u);let d;n[8]===c?d=n[9]:(d=c&&(0,i.jsx)(`p`,{className:`mt-1 text-sm font-medium text-muted-foreground`,children:c}),n[8]=c,n[9]=d);let f;n[10]!==o||n[11]!==u||n[12]!==d?(f=(0,i.jsxs)(`div`,{className:`flex-1`,children:[u,d,o]}),n[10]=o,n[11]=u,n[12]=d,n[13]=f):f=n[13];let p;n[14]===a?p=n[15]:(p=a&&(0,i.jsx)(`div`,{className:`ml-4`,children:a}),n[14]=a,n[15]=p);let m;n[16]!==f||n[17]!==p?(m=(0,i.jsxs)(`div`,{className:`flex items-start justify-between`,children:[f,p]}),n[16]=f,n[17]=p,n[18]=m):m=n[18];let h;return n[19]!==s||n[20]!==m?(h=(0,i.jsx)(e,{className:`block rounded-lg border bg-card p-4 transition-colors hover:bg-accent`,...s,children:m}),n[19]=s,n[20]=m,n[21]=h):h=n[21],h}export{a as t}; \ No newline at end of file +import{Co as e,Oo as t,xo as n}from"./index.js";var r=n(),i=t();function a(t){let n=(0,r.c)(22),a,o,s,c,l;n[0]===t?(a=n[1],o=n[2],s=n[3],c=n[4],l=n[5]):({title:l,subtitle:c,badge:a,children:o,...s}=t,n[0]=t,n[1]=a,n[2]=o,n[3]=s,n[4]=c,n[5]=l);let u;n[6]===l?u=n[7]:(u=(0,i.jsx)(`h3`,{className:`font-semibold`,children:l}),n[6]=l,n[7]=u);let d;n[8]===c?d=n[9]:(d=c&&(0,i.jsx)(`p`,{className:`mt-1 text-sm font-medium text-muted-foreground`,children:c}),n[8]=c,n[9]=d);let f;n[10]!==o||n[11]!==u||n[12]!==d?(f=(0,i.jsxs)(`div`,{className:`flex-1`,children:[u,d,o]}),n[10]=o,n[11]=u,n[12]=d,n[13]=f):f=n[13];let p;n[14]===a?p=n[15]:(p=a&&(0,i.jsx)(`div`,{className:`ml-4`,children:a}),n[14]=a,n[15]=p);let m;n[16]!==f||n[17]!==p?(m=(0,i.jsxs)(`div`,{className:`flex items-start justify-between`,children:[f,p]}),n[16]=f,n[17]=p,n[18]=m):m=n[18];let h;return n[19]!==s||n[20]!==m?(h=(0,i.jsx)(e,{className:`block rounded-lg border bg-card p-4 transition-colors hover:bg-accent`,...s,children:m}),n[19]=s,n[20]=m,n[21]=h):h=n[21],h}export{a as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/list-policies.js b/spinifex/services/spinifexui/frontend/dist/assets/list-policies.js index 5951e4d89..6e00e5801 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/list-policies.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/list-policies.js @@ -1 +1 @@ -import{t as e}from"./useSuspenseQuery.js";import{Ta as t,lo as n,mo as r,so as i,v as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./list-card.js";var c=i(),l=r();function u(){let r=(0,c.c)(3),{data:i}=e(a),s;if(r[0]!==i.Policies){let e=(i.Policies??[]).toSorted(f),a;r[2]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,l.jsx)(o,{actions:(0,l.jsx)(n,{to:`/iam/create-policy`,children:(0,l.jsx)(t,{children:`Create Policy`})}),title:`Policies`}),r[2]=a):a=r[2],s=(0,l.jsxs)(l.Fragment,{children:[a,e.length>0?(0,l.jsx)(`div`,{className:`space-y-4`,children:e.map(d)}):(0,l.jsx)(`p`,{className:`text-muted-foreground`,children:`No IAM policies found.`})]}),r[0]=i.Policies,r[1]=s}else s=r[1];return s}function d(e){return e.Arn?(0,l.jsx)(s,{params:{policyArn:encodeURIComponent(e.Arn)},subtitle:e.Arn??``,title:e.PolicyName??``,to:`/iam/list-policies/$policyArn`},e.Arn):null}function f(e,t){let n=e.PolicyName?.toLowerCase()??``,r=t.PolicyName?.toLowerCase()??``;return n.localeCompare(r)}export{u as component}; \ No newline at end of file +import{t as e}from"./useSuspenseQuery.js";import{Co as t,Oo as n,v as r,xo as i,za as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./list-card.js";var c=i(),l=n();function u(){let n=(0,c.c)(3),{data:i}=e(r),s;if(n[0]!==i.Policies){let e=(i.Policies??[]).toSorted(f),r;n[2]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,l.jsx)(o,{actions:(0,l.jsx)(t,{to:`/iam/create-policy`,children:(0,l.jsx)(a,{children:`Create Policy`})}),title:`Policies`}),n[2]=r):r=n[2],s=(0,l.jsxs)(l.Fragment,{children:[r,e.length>0?(0,l.jsx)(`div`,{className:`space-y-4`,children:e.map(d)}):(0,l.jsx)(`p`,{className:`text-muted-foreground`,children:`No IAM policies found.`})]}),n[0]=i.Policies,n[1]=s}else s=n[1];return s}function d(e){return e.Arn?(0,l.jsx)(s,{params:{policyArn:encodeURIComponent(e.Arn)},subtitle:e.Arn??``,title:e.PolicyName??``,to:`/iam/list-policies/$policyArn`},e.Arn):null}function f(e,t){let n=e.PolicyName?.toLowerCase()??``,r=t.PolicyName?.toLowerCase()??``;return n.localeCompare(r)}export{u as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/list-users.js b/spinifex/services/spinifexui/frontend/dist/assets/list-users.js index 8334f3d3e..9589e00c4 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/list-users.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/list-users.js @@ -1 +1 @@ -import{t as e}from"./useSuspenseQuery.js";import{S as t,Ta as n,lo as r,mo as i,so as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./list-card.js";var c=a(),l=i();function u(){let i=(0,c.c)(3),{data:a}=e(t),s;if(i[0]!==a.Users){let e=(a.Users??[]).toSorted(f),t;i[2]===Symbol.for(`react.memo_cache_sentinel`)?(t=(0,l.jsx)(o,{actions:(0,l.jsx)(r,{to:`/iam/create-user`,children:(0,l.jsx)(n,{children:`Create User`})}),title:`Users`}),i[2]=t):t=i[2],s=(0,l.jsxs)(l.Fragment,{children:[t,e.length>0?(0,l.jsx)(`div`,{className:`space-y-4`,children:e.map(d)}):(0,l.jsx)(`p`,{className:`text-muted-foreground`,children:`No IAM users found.`})]}),i[0]=a.Users,i[1]=s}else s=i[1];return s}function d(e){return e.UserName?(0,l.jsx)(s,{params:{userName:e.UserName},subtitle:e.UserId??``,title:e.UserName,to:`/iam/list-users/$userName`},e.UserName):null}function f(e,t){let n=e.UserName?.toLowerCase()??``,r=t.UserName?.toLowerCase()??``;return n.localeCompare(r)}export{u as component}; \ No newline at end of file +import{t as e}from"./useSuspenseQuery.js";import{Co as t,Oo as n,S as r,xo as i,za as a}from"./index.js";import{t as o}from"./page-heading.js";import{t as s}from"./list-card.js";var c=i(),l=n();function u(){let n=(0,c.c)(3),{data:i}=e(r),s;if(n[0]!==i.Users){let e=(i.Users??[]).toSorted(f),r;n[2]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,l.jsx)(o,{actions:(0,l.jsx)(t,{to:`/iam/create-user`,children:(0,l.jsx)(a,{children:`Create User`})}),title:`Users`}),n[2]=r):r=n[2],s=(0,l.jsxs)(l.Fragment,{children:[r,e.length>0?(0,l.jsx)(`div`,{className:`space-y-4`,children:e.map(d)}):(0,l.jsx)(`p`,{className:`text-muted-foreground`,children:`No IAM users found.`})]}),n[0]=i.Users,n[1]=s}else s=n[1];return s}function d(e){return e.UserName?(0,l.jsx)(s,{params:{userName:e.UserName},subtitle:e.UserId??``,title:e.UserName,to:`/iam/list-users/$userName`},e.UserName):null}function f(e,t){let n=e.UserName?.toLowerCase()??``,r=t.UserName?.toLowerCase()??``;return n.localeCompare(r)}export{u as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/login.js b/spinifex/services/spinifexui/frontend/dist/assets/login.js index 6e6a124a7..a59d9cec8 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/login.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/login.js @@ -1 +1 @@ -import{Po as e,Ta as t,Ti as n,Xt as r,at as i,cr as a,ho as o,it as s,mo as c,so as l,sr as u,ur as d}from"./index.js";import{a as f,i as p,r as m,t as h}from"./field.js";import{i as g,t as _}from"./zod.js";import{n as v,r as y,t as b}from"./collapsible.js";import{a as x,o as S,r as C,t as w}from"./card.js";var T=l(),E=e(o()),D=c();function O(){let[e,o]=(0,E.useState)(null),{register:c,handleSubmit:l,formState:{errors:v,isSubmitting:y}}=g({resolver:_(u)});async function b(e){o(null),s(),d(e);try{await i().send(new r({})),window.location.href=`/`}catch{a(),s(),o(`Invalid credentials. Please check your Access Key ID and Secret Access Key.`)}}return(0,D.jsx)(`div`,{className:`flex flex-1 items-center justify-center`,children:(0,D.jsxs)(`div`,{className:`flex w-full max-w-sm flex-col gap-4`,children:[(0,D.jsxs)(w,{children:[(0,D.jsx)(x,{children:(0,D.jsx)(S,{children:`AWS Credentials`})}),(0,D.jsxs)(C,{children:[e&&(0,D.jsx)(`p`,{className:`mb-4 rounded-md bg-destructive/10 p-3 text-sm text-destructive`,children:e}),(0,D.jsx)(`form`,{onSubmit:l(b),children:(0,D.jsxs)(p,{children:[(0,D.jsxs)(h,{children:[(0,D.jsx)(f,{children:(0,D.jsx)(`label`,{htmlFor:`accessKeyId`,children:`Access Key ID`})}),(0,D.jsx)(n,{"aria-invalid":!!v.accessKeyId,autoComplete:`username`,id:`accessKeyId`,placeholder:`AKIAIOSFODNN7EXAMPLE`,...c(`accessKeyId`)}),(0,D.jsx)(m,{errors:[v.accessKeyId]})]}),(0,D.jsxs)(h,{children:[(0,D.jsx)(f,{children:(0,D.jsx)(`label`,{htmlFor:`secretAccessKey`,children:`Secret Access Key`})}),(0,D.jsx)(n,{"aria-invalid":!!v.secretAccessKey,autoComplete:`current-password`,id:`secretAccessKey`,placeholder:`wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`,type:`password`,...c(`secretAccessKey`)}),(0,D.jsx)(m,{errors:[v.secretAccessKey]})]}),(0,D.jsx)(t,{className:`w-full`,disabled:y,type:`submit`,children:y?`Signing in...`:`Sign In`})]})})]})]}),(0,D.jsx)(k,{})]})})}function k(){let e=(0,T.c)(4),t,n;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(t=(0,D.jsxs)(`div`,{children:[(0,D.jsx)(`p`,{className:`text-sm font-medium`,children:`Install Local Certificate Authority`}),(0,D.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`To avoid browser certificate warnings, download and install the Spinifex CA as a trusted root on your OS.`})]}),n=(0,D.jsx)(`a`,{className:`inline-flex h-8 w-full items-center justify-center rounded-md border border-input bg-background px-3 text-sm font-medium hover:bg-accent hover:text-accent-foreground`,download:`spinifex-ca.pem`,href:`/api/ca.pem`,children:`Download CA Certificate`}),e[0]=t,e[1]=n):(t=e[0],n=e[1]);let r;e[2]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,D.jsx)(y,{className:`cursor-pointer text-xs text-muted-foreground underline-offset-4 hover:underline`,children:`Installation instructions`}),e[2]=r):r=e[2];let i;return e[3]===Symbol.for(`react.memo_cache_sentinel`)?(i=(0,D.jsx)(w,{className:`border-muted bg-muted/30`,children:(0,D.jsx)(C,{className:`pt-4 pb-4`,children:(0,D.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[t,n,(0,D.jsxs)(b,{children:[r,(0,D.jsx)(v,{children:(0,D.jsxs)(`div`,{className:`mt-2 flex flex-col gap-2 text-xs text-muted-foreground`,children:[(0,D.jsxs)(`div`,{children:[(0,D.jsx)(`p`,{className:`font-medium text-foreground`,children:`macOS`}),(0,D.jsx)(`code`,{className:`mt-1 block rounded bg-muted p-2 text-[11px] break-all`,children:`sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain spinifex-ca.pem`})]}),(0,D.jsxs)(`div`,{children:[(0,D.jsx)(`p`,{className:`font-medium text-foreground`,children:`Windows`}),(0,D.jsx)(`p`,{children:`Double-click the file → Install Certificate → Local Machine → Trusted Root Certification Authorities`})]}),(0,D.jsxs)(`div`,{children:[(0,D.jsx)(`p`,{className:`font-medium text-foreground`,children:`Linux`}),(0,D.jsx)(`code`,{className:`mt-1 block rounded bg-muted p-2 text-[11px] break-all`,children:`sudo cp spinifex-ca.pem /usr/local/share/ca-certificates/spinifex-ca.crt && sudo update-ca-certificates`})]})]})})]})]})})}),e[3]=i):i=e[3],i}export{O as component}; \ No newline at end of file +import{Jo as e,Oo as t,Sr as n,at as r,ko as i,st as a,tn as o,wr as s,xo as c,xr as l,za as u,zi as d}from"./index.js";import{a as f,i as p,r as m,t as h}from"./field.js";import{i as g,t as _}from"./zod.js";import{n as v,r as y,t as b}from"./collapsible.js";import{a as x,o as S,r as C,t as w}from"./card.js";var T=c(),E=e(i()),D=t();function O(){let[e,t]=(0,E.useState)(null),{register:i,handleSubmit:c,formState:{errors:v,isSubmitting:y}}=g({resolver:_(l)});async function b(e){t(null),r(),s(e);try{await a().send(new o({})),window.location.href=`/`}catch{n(),r(),t(`Invalid credentials. Please check your Access Key ID and Secret Access Key.`)}}return(0,D.jsx)(`div`,{className:`flex flex-1 items-center justify-center`,children:(0,D.jsxs)(`div`,{className:`flex w-full max-w-sm flex-col gap-4`,children:[(0,D.jsxs)(w,{children:[(0,D.jsx)(x,{children:(0,D.jsx)(S,{children:`AWS Credentials`})}),(0,D.jsxs)(C,{children:[e&&(0,D.jsx)(`p`,{className:`mb-4 rounded-md bg-destructive/10 p-3 text-sm text-destructive`,children:e}),(0,D.jsx)(`form`,{onSubmit:c(b),children:(0,D.jsxs)(p,{children:[(0,D.jsxs)(h,{children:[(0,D.jsx)(f,{children:(0,D.jsx)(`label`,{htmlFor:`accessKeyId`,children:`Access Key ID`})}),(0,D.jsx)(d,{"aria-invalid":!!v.accessKeyId,autoComplete:`username`,id:`accessKeyId`,placeholder:`AKIAIOSFODNN7EXAMPLE`,...i(`accessKeyId`)}),(0,D.jsx)(m,{errors:[v.accessKeyId]})]}),(0,D.jsxs)(h,{children:[(0,D.jsx)(f,{children:(0,D.jsx)(`label`,{htmlFor:`secretAccessKey`,children:`Secret Access Key`})}),(0,D.jsx)(d,{"aria-invalid":!!v.secretAccessKey,autoComplete:`current-password`,id:`secretAccessKey`,placeholder:`wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`,type:`password`,...i(`secretAccessKey`)}),(0,D.jsx)(m,{errors:[v.secretAccessKey]})]}),(0,D.jsx)(u,{className:`w-full`,disabled:y,type:`submit`,children:y?`Signing in...`:`Sign In`})]})})]})]}),(0,D.jsx)(k,{})]})})}function k(){let e=(0,T.c)(4),t,n;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(t=(0,D.jsxs)(`div`,{children:[(0,D.jsx)(`p`,{className:`text-sm font-medium`,children:`Install Local Certificate Authority`}),(0,D.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`To avoid browser certificate warnings, download and install the Spinifex CA as a trusted root on your OS.`})]}),n=(0,D.jsx)(`a`,{className:`inline-flex h-8 w-full items-center justify-center rounded-md border border-input bg-background px-3 text-sm font-medium hover:bg-accent hover:text-accent-foreground`,download:`spinifex-ca.pem`,href:`/api/ca.pem`,children:`Download CA Certificate`}),e[0]=t,e[1]=n):(t=e[0],n=e[1]);let r;e[2]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,D.jsx)(y,{className:`cursor-pointer text-xs text-muted-foreground underline-offset-4 hover:underline`,children:`Installation instructions`}),e[2]=r):r=e[2];let i;return e[3]===Symbol.for(`react.memo_cache_sentinel`)?(i=(0,D.jsx)(w,{className:`border-muted bg-muted/30`,children:(0,D.jsx)(C,{className:`pt-4 pb-4`,children:(0,D.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[t,n,(0,D.jsxs)(b,{children:[r,(0,D.jsx)(v,{children:(0,D.jsxs)(`div`,{className:`mt-2 flex flex-col gap-2 text-xs text-muted-foreground`,children:[(0,D.jsxs)(`div`,{children:[(0,D.jsx)(`p`,{className:`font-medium text-foreground`,children:`macOS`}),(0,D.jsx)(`code`,{className:`mt-1 block rounded bg-muted p-2 text-[11px] break-all`,children:`sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain spinifex-ca.pem`})]}),(0,D.jsxs)(`div`,{children:[(0,D.jsx)(`p`,{className:`font-medium text-foreground`,children:`Windows`}),(0,D.jsx)(`p`,{children:`Double-click the file → Install Certificate → Local Machine → Trusted Root Certification Authorities`})]}),(0,D.jsxs)(`div`,{children:[(0,D.jsx)(`p`,{className:`font-medium text-foreground`,children:`Linux`}),(0,D.jsx)(`code`,{className:`mt-1 block rounded bg-muted p-2 text-[11px] break-all`,children:`sudo cp spinifex-ca.pem /usr/local/share/ca-certificates/spinifex-ca.crt && sudo update-ca-certificates`})]})]})})]})]})})}),e[3]=i):i=e[3],i}export{O as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/ls.js b/spinifex/services/spinifexui/frontend/dist/assets/ls.js index 3b2be61b3..a957f9657 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/ls.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/ls.js @@ -1 +1 @@ -import{t as e}from"./useSuspenseQuery.js";import{I as t,Ta as n,ja as r,lo as i,mo as a,so as o}from"./index.js";import{t as s}from"./page-heading.js";import{t as c}from"./list-card.js";var l=o(),u=a();function d(){let r=(0,l.c)(5),{data:a}=e(t),o;r[0]===a.Buckets?o=r[1]:(o=a.Buckets??[],r[0]=a.Buckets,r[1]=o);let c=o,d;r[2]===Symbol.for(`react.memo_cache_sentinel`)?(d=(0,u.jsx)(s,{actions:(0,u.jsx)(i,{to:`/s3/create-bucket`,children:(0,u.jsx)(n,{children:`Create Bucket`})}),title:`Buckets`}),r[2]=d):d=r[2];let p;return r[3]===c?p=r[4]:(p=(0,u.jsxs)(u.Fragment,{children:[d,c.length>0?(0,u.jsx)(`div`,{className:`space-y-4`,children:c.map(f)}):(0,u.jsx)(`p`,{className:`text-muted-foreground`,children:`No buckets found.`})]}),r[3]=c,r[4]=p),p}function f(e){return e.Name?(0,u.jsx)(c,{params:{bucket:e.Name},subtitle:e.CreationDate?`Created: ${r(e.CreationDate)}`:void 0,title:e.Name,to:`/s3/ls/$bucket`},e.Name):null}export{d as component}; \ No newline at end of file +import{t as e}from"./useSuspenseQuery.js";import{Co as t,Ga as n,L as r,Oo as i,xo as a,za as o}from"./index.js";import{t as s}from"./page-heading.js";import{t as c}from"./list-card.js";var l=a(),u=i();function d(){let n=(0,l.c)(5),{data:i}=e(r),a;n[0]===i.Buckets?a=n[1]:(a=i.Buckets??[],n[0]=i.Buckets,n[1]=a);let c=a,d;n[2]===Symbol.for(`react.memo_cache_sentinel`)?(d=(0,u.jsx)(s,{actions:(0,u.jsx)(t,{to:`/s3/create-bucket`,children:(0,u.jsx)(o,{children:`Create Bucket`})}),title:`Buckets`}),n[2]=d):d=n[2];let p;return n[3]===c?p=n[4]:(p=(0,u.jsxs)(u.Fragment,{children:[d,c.length>0?(0,u.jsx)(`div`,{className:`space-y-4`,children:c.map(f)}):(0,u.jsx)(`p`,{className:`text-muted-foreground`,children:`No buckets found.`})]}),n[3]=c,n[4]=p),p}function f(e){return e.Name?(0,u.jsx)(c,{params:{bucket:e.Name},subtitle:e.CreationDate?`Created: ${n(e.CreationDate)}`:void 0,title:e.Name,to:`/s3/ls/$bucket`},e.Name):null}export{d as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/nodes.js b/spinifex/services/spinifexui/frontend/dist/assets/nodes.js index f79c7d336..da600f9e1 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/nodes.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/nodes.js @@ -1 +1 @@ -import{t as e}from"./useQuery.js";import{Gn as t,Na as n,do as r,mo as i,so as a}from"./index.js";import{t as o}from"./page-heading.js";import{r as s,t as c}from"./admin.js";import{t as l}from"./badge.js";import{a as u,o as d,r as f,t as p}from"./card.js";var m=a(),h=i();function g(e){let t=Math.floor(e/86400),n=Math.floor(e%86400/3600);if(t>0)return`${t}d ${n}h`;let r=Math.floor(e%3600/60);return n>0?`${n}h ${r}m`:`${r}m`}function _(e){return e>=1?`${e.toFixed(1)}Gi`:`${Math.round(e*1024)}Mi`}function v(e){let t=Math.floor(Date.now()/1e3-e);if(t<60)return`${t}s`;let n=Math.floor(t/60);if(n<60)return`${n}m`;let r=Math.floor(n/60);return r<24?`${r}h ${n%60}m`:`${Math.floor(r/24)}d ${r%24}h`}function y(){let n=(0,m.c)(31),{isAdmin:i}=t(),a;n[0]===i?a=n[1]:(a={...c,enabled:i,refetchInterval:5e3},n[0]=i,n[1]=a);let{data:l}=e(a),g;n[2]===i?g=n[3]:(g={...s,enabled:i,refetchInterval:5e3},n[2]=i,n[3]=g);let{data:_}=e(g);if(!i)throw r({to:`/`});let v,y,T;if(n[4]!==l?.nodes||n[5]!==_?.vms){v=l?.nodes??[];let e;n[9]===_?.vms?e=n[10]:(e=_?.vms??[],n[9]=_?.vms,n[10]=e);let t;n[11]===e?t=n[12]:(t=e.filter(C),n[11]=e,n[12]=t),T=t;let r=new Map;for(let e of v)for(let t of e.instance_types??[]){let e=r.get(t.name);e?e.available+=t.available:r.set(t.name,{vcpu:t.vcpu,memory_gb:t.memory_gb,available:t.available})}y=[...r.entries()].map(S).toSorted(x),n[4]=l?.nodes,n[5]=_?.vms,n[6]=v,n[7]=y,n[8]=T}else v=n[6],y=n[7],T=n[8];let E=y,O;n[13]===Symbol.for(`react.memo_cache_sentinel`)?(O=(0,h.jsx)(o,{title:`Nodes`}),n[13]=O):O=n[13];let A;n[14]===Symbol.for(`react.memo_cache_sentinel`)?(A=(0,h.jsx)(u,{children:(0,h.jsx)(d,{className:`text-sm`,children:`Cluster Nodes`})}),n[14]=A):A=n[14];let M;n[15]===v?M=n[16]:(M=(0,h.jsxs)(p,{children:[A,(0,h.jsx)(f,{children:v.length===0?(0,h.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No nodes responding`}):(0,h.jsx)(w,{nodes:v})})]}),n[15]=v,n[16]=M);let N;n[17]===Symbol.for(`react.memo_cache_sentinel`)?(N=(0,h.jsx)(u,{children:(0,h.jsx)(d,{className:`text-sm`,children:`Elastic Compute Cloud (EC2)`})}),n[17]=N):N=n[17];let P;n[18]===T?P=n[19]:(P=(0,h.jsxs)(p,{children:[N,(0,h.jsx)(f,{children:T.length===0?(0,h.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No instances running`}):(0,h.jsx)(D,{vms:T})})]}),n[18]=T,n[19]=P);let I;n[20]===Symbol.for(`react.memo_cache_sentinel`)?(I=(0,h.jsx)(u,{children:(0,h.jsx)(d,{className:`text-sm`,children:`Resource Usage`})}),n[20]=I):I=n[20];let L;n[21]!==E||n[22]!==v?(L=(0,h.jsxs)(p,{children:[I,(0,h.jsx)(f,{className:`space-y-4`,children:v.length===0?(0,h.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No data`}):(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(k,{nodes:v}),E.length>0&&(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`h4`,{className:`mt-4 text-xs font-medium text-muted-foreground`,children:`Instance Type Capacity`}),(0,h.jsx)(j,{instanceTypes:E})]})]})})]}),n[21]=E,n[22]=v,n[23]=L):L=n[23];let R;n[24]===v?R=n[25]:(R=v.some(b)&&(0,h.jsxs)(p,{children:[(0,h.jsx)(u,{children:(0,h.jsx)(d,{className:`text-sm`,children:`GPU Inventory`})}),(0,h.jsx)(f,{children:(0,h.jsx)(F,{nodes:v})})]}),n[24]=v,n[25]=R);let z;return n[26]!==R||n[27]!==M||n[28]!==P||n[29]!==L?(z=(0,h.jsxs)(h.Fragment,{children:[O,(0,h.jsxs)(`div`,{className:`space-y-6`,children:[M,P,L,R]})]}),n[26]=R,n[27]=M,n[28]=P,n[29]=L,n[30]=z):z=n[30],z}function b(e){return(e.gpus?.length??0)>0}function x(e,t){return e.name.localeCompare(t.name)}function S(e){let[t,n]=e;return{name:t,...n}}function C(e){return!e.managed_by}function w(e){let t=(0,m.c)(5),{nodes:n}=e,r;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,h.jsx)(`thead`,{children:(0,h.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Name`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Status`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Roles`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`IP`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Region`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`AZ`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Uptime`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`EC2`}),(0,h.jsx)(`th`,{className:`pb-1 font-medium`,children:`Services`})]})}),t[0]=r):r=t[0];let i;t[1]===n?i=t[2]:(i=n.map(T),t[1]=n,t[2]=i);let a;return t[3]===i?a=t[4]:(a=(0,h.jsx)(`div`,{className:`overflow-x-auto`,children:(0,h.jsxs)(`table`,{className:`w-full text-xs`,children:[r,(0,h.jsx)(`tbody`,{children:i})]})}),t[3]=i,t[4]=a),a}function T(e){let t=[e.nats_role?`nats:${e.nats_role}`:null,e.predastore_role?`predastore:${e.predastore_role}`:null].filter(Boolean).join(`,`);return(0,h.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono font-medium`,children:e.node}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:(0,h.jsx)(l,{variant:e.status===`Ready`?`default`:`secondary`,className:`text-[0.625rem]`,children:e.status})}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono text-muted-foreground`,children:t||`-`}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.host}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.region}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.az}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:g(e.uptime)}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.vm_count}),(0,h.jsx)(`td`,{className:`py-1.5`,children:(0,h.jsx)(`span`,{className:`text-muted-foreground`,children:e.services?.join(`,`)??`-`})})]},e.node)}function E(e){return e?e.profile?`${n(e.vram_mib)} (${e.profile})`:`${e.model} ${n(e.vram_mib)}`:`-`}function D(e){let t=(0,m.c)(5),{vms:n}=e,r;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,h.jsx)(`thead`,{children:(0,h.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Instance`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Status`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Type`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`vCPU`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Memory`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`GPU`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Node`}),(0,h.jsx)(`th`,{className:`pb-1 font-medium`,children:`Age`})]})}),t[0]=r):r=t[0];let i;t[1]===n?i=t[2]:(i=n.map(O),t[1]=n,t[2]=i);let a;return t[3]===i?a=t[4]:(a=(0,h.jsx)(`div`,{className:`overflow-x-auto`,children:(0,h.jsxs)(`table`,{className:`w-full text-xs`,children:[r,(0,h.jsx)(`tbody`,{children:i})]})}),t[3]=i,t[4]=a),a}function O(e){return(0,h.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.instance_id}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:(0,h.jsx)(l,{variant:e.status===`running`?`default`:`secondary`,className:`text-[0.625rem]`,children:e.status})}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.instance_type}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.vcpu}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:_(e.memory_gb)}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:E(e.gpu)}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.node}),(0,h.jsx)(`td`,{className:`py-1.5`,children:e.launch_time>0?v(e.launch_time):`-`})]},e.instance_id)}function k(e){let t=(0,m.c)(5),{nodes:n}=e,r;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,h.jsx)(`thead`,{children:(0,h.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Name`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`CPU (used/total)`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`MEM (used/total)`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`GPU (used/total)`}),(0,h.jsx)(`th`,{className:`pb-1 font-medium`,children:`EC2`})]})}),t[0]=r):r=t[0];let i;t[1]===n?i=t[2]:(i=n.map(A),t[1]=n,t[2]=i);let a;return t[3]===i?a=t[4]:(a=(0,h.jsx)(`div`,{className:`overflow-x-auto`,children:(0,h.jsxs)(`table`,{className:`w-full text-xs`,children:[r,(0,h.jsx)(`tbody`,{children:i})]})}),t[3]=i,t[4]=a),a}function A(e){return(0,h.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono font-medium`,children:e.node}),(0,h.jsxs)(`td`,{className:`py-1.5 pr-4 font-mono`,children:[e.alloc_vcpu,`/`,e.total_vcpu]}),(0,h.jsxs)(`td`,{className:`py-1.5 pr-4 font-mono`,children:[_(e.alloc_mem_gb),`/`,_(e.total_mem_gb)]}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.total_gpus>0?`${e.alloc_gpus}/${e.total_gpus}`:`-`}),(0,h.jsx)(`td`,{className:`py-1.5`,children:e.vm_count})]},e.node)}function j(e){let t=(0,m.c)(5),{instanceTypes:n}=e,r;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,h.jsx)(`thead`,{children:(0,h.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Instance Type`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Available`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`vCPU`}),(0,h.jsx)(`th`,{className:`pb-1 font-medium`,children:`Memory`})]})}),t[0]=r):r=t[0];let i;t[1]===n?i=t[2]:(i=n.map(M),t[1]=n,t[2]=i);let a;return t[3]===i?a=t[4]:(a=(0,h.jsx)(`div`,{className:`overflow-x-auto`,children:(0,h.jsxs)(`table`,{className:`w-full text-xs`,children:[r,(0,h.jsx)(`tbody`,{children:i})]})}),t[3]=i,t[4]=a),a}function M(e){return(0,h.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.name}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.available}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.vcpu}),(0,h.jsx)(`td`,{className:`py-1.5`,children:_(e.memory_gb)})]},e.name)}function N(e){let t=(0,m.c)(22),{gpu:r}=e,i;t[0]===r.model?i=t[1]:(i=(0,h.jsx)(`span`,{className:`font-medium`,children:r.model}),t[0]=r.model,t[1]=i);let a;t[2]===r.vram_mib?a=t[3]:(a=n(r.vram_mib),t[2]=r.vram_mib,t[3]=a);let o;t[4]===a?o=t[5]:(o=(0,h.jsx)(`span`,{className:`text-muted-foreground`,children:a}),t[4]=a,t[5]=o);let s;t[6]===r.pci_address?s=t[7]:(s=(0,h.jsx)(`span`,{className:`text-muted-foreground`,children:r.pci_address}),t[6]=r.pci_address,t[7]=s);let c;t[8]!==r.instance_id||t[9]!==r.mig_enabled?(c=r.mig_enabled?(0,h.jsx)(l,{className:`text-[0.625rem]`,variant:`secondary`,children:`MIG`}):(0,h.jsx)(`span`,{className:r.instance_id?`text-amber-500`:`text-green-600`,children:r.instance_id?`in-use: ${r.instance_id}`:`free`}),t[8]=r.instance_id,t[9]=r.mig_enabled,t[10]=c):c=t[10];let u;t[11]!==i||t[12]!==o||t[13]!==s||t[14]!==c?(u=(0,h.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3 font-mono`,children:[i,o,s,c]}),t[11]=i,t[12]=o,t[13]=s,t[14]=c,t[15]=u):u=t[15];let d;t[16]!==r.mig_enabled||t[17]!==r.slices?(d=r.mig_enabled&&r.slices&&r.slices.length>0&&(0,h.jsxs)(`table`,{className:`mt-2 w-full`,children:[(0,h.jsx)(`thead`,{children:(0,h.jsxs)(`tr`,{className:`text-left text-muted-foreground`,children:[(0,h.jsx)(`th`,{className:`pr-4 pb-0.5 font-normal`,children:`GI`}),(0,h.jsx)(`th`,{className:`pr-4 pb-0.5 font-normal`,children:`Profile`}),(0,h.jsx)(`th`,{className:`pr-4 pb-0.5 font-normal`,children:`VRAM`}),(0,h.jsx)(`th`,{className:`pb-0.5 font-normal`,children:`Instance`})]})}),(0,h.jsx)(`tbody`,{children:r.slices.map(P)})]}),t[16]=r.mig_enabled,t[17]=r.slices,t[18]=d):d=t[18];let f;return t[19]!==u||t[20]!==d?(f=(0,h.jsxs)(`div`,{className:`rounded border p-2 text-xs`,children:[u,d]}),t[19]=u,t[20]=d,t[21]=f):f=t[21],f}function P(e){return(0,h.jsxs)(`tr`,{children:[(0,h.jsx)(`td`,{className:`py-0.5 pr-4 font-mono`,children:e.gi_id}),(0,h.jsx)(`td`,{className:`py-0.5 pr-4 font-mono`,children:e.profile}),(0,h.jsx)(`td`,{className:`py-0.5 pr-4`,children:n(e.vram_mib)}),(0,h.jsx)(`td`,{className:e.instance_id?`py-0.5 font-mono text-amber-500`:`py-0.5 text-green-600`,children:e.instance_id??`free`})]},e.gi_id)}function F(e){let t=(0,m.c)(6),{nodes:n}=e,r,i;if(t[0]!==n){let e=n.filter(R);r=`space-y-4`,i=e.map(I),t[0]=n,t[1]=r,t[2]=i}else r=t[1],i=t[2];let a;return t[3]!==r||t[4]!==i?(a=(0,h.jsx)(`div`,{className:r,children:i}),t[3]=r,t[4]=i,t[5]=a):a=t[5],a}function I(e){return(0,h.jsxs)(`div`,{children:[(0,h.jsx)(`h4`,{className:`mb-1.5 text-xs font-medium text-muted-foreground`,children:e.node}),(0,h.jsx)(`div`,{className:`space-y-2`,children:e.gpus?.map(L)})]},e.node)}function L(e){return(0,h.jsx)(N,{gpu:e},e.pci_address)}function R(e){return(e.gpus?.length??0)>0}export{y as component}; \ No newline at end of file +import{t as e}from"./useQuery.js";import{Oo as t,To as n,ar as r,qa as i,xo as a}from"./index.js";import{t as o}from"./page-heading.js";import{r as s,t as c}from"./admin.js";import{t as l}from"./badge.js";import{a as u,o as d,r as f,t as p}from"./card.js";var m=a(),h=t();function g(e){let t=Math.floor(e/86400),n=Math.floor(e%86400/3600);if(t>0)return`${t}d ${n}h`;let r=Math.floor(e%3600/60);return n>0?`${n}h ${r}m`:`${r}m`}function _(e){return e>=1?`${e.toFixed(1)}Gi`:`${Math.round(e*1024)}Mi`}function v(e){let t=Math.floor(Date.now()/1e3-e);if(t<60)return`${t}s`;let n=Math.floor(t/60);if(n<60)return`${n}m`;let r=Math.floor(n/60);return r<24?`${r}h ${n%60}m`:`${Math.floor(r/24)}d ${r%24}h`}function y(){let t=(0,m.c)(31),{isAdmin:i}=r(),a;t[0]===i?a=t[1]:(a={...c,enabled:i,refetchInterval:5e3},t[0]=i,t[1]=a);let{data:l}=e(a),g;t[2]===i?g=t[3]:(g={...s,enabled:i,refetchInterval:5e3},t[2]=i,t[3]=g);let{data:_}=e(g);if(!i)throw n({to:`/`});let v,y,T;if(t[4]!==l?.nodes||t[5]!==_?.vms){v=l?.nodes??[];let e;t[9]===_?.vms?e=t[10]:(e=_?.vms??[],t[9]=_?.vms,t[10]=e);let n;t[11]===e?n=t[12]:(n=e.filter(C),t[11]=e,t[12]=n),T=n;let r=new Map;for(let e of v)for(let t of e.instance_types??[]){let e=r.get(t.name);e?e.available+=t.available:r.set(t.name,{vcpu:t.vcpu,memory_gb:t.memory_gb,available:t.available})}y=[...r.entries()].map(S).toSorted(x),t[4]=l?.nodes,t[5]=_?.vms,t[6]=v,t[7]=y,t[8]=T}else v=t[6],y=t[7],T=t[8];let E=y,O;t[13]===Symbol.for(`react.memo_cache_sentinel`)?(O=(0,h.jsx)(o,{title:`Nodes`}),t[13]=O):O=t[13];let A;t[14]===Symbol.for(`react.memo_cache_sentinel`)?(A=(0,h.jsx)(u,{children:(0,h.jsx)(d,{className:`text-sm`,children:`Cluster Nodes`})}),t[14]=A):A=t[14];let M;t[15]===v?M=t[16]:(M=(0,h.jsxs)(p,{children:[A,(0,h.jsx)(f,{children:v.length===0?(0,h.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No nodes responding`}):(0,h.jsx)(w,{nodes:v})})]}),t[15]=v,t[16]=M);let N;t[17]===Symbol.for(`react.memo_cache_sentinel`)?(N=(0,h.jsx)(u,{children:(0,h.jsx)(d,{className:`text-sm`,children:`Elastic Compute Cloud (EC2)`})}),t[17]=N):N=t[17];let P;t[18]===T?P=t[19]:(P=(0,h.jsxs)(p,{children:[N,(0,h.jsx)(f,{children:T.length===0?(0,h.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No instances running`}):(0,h.jsx)(D,{vms:T})})]}),t[18]=T,t[19]=P);let I;t[20]===Symbol.for(`react.memo_cache_sentinel`)?(I=(0,h.jsx)(u,{children:(0,h.jsx)(d,{className:`text-sm`,children:`Resource Usage`})}),t[20]=I):I=t[20];let L;t[21]!==E||t[22]!==v?(L=(0,h.jsxs)(p,{children:[I,(0,h.jsx)(f,{className:`space-y-4`,children:v.length===0?(0,h.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No data`}):(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(k,{nodes:v}),E.length>0&&(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`h4`,{className:`mt-4 text-xs font-medium text-muted-foreground`,children:`Instance Type Capacity`}),(0,h.jsx)(j,{instanceTypes:E})]})]})})]}),t[21]=E,t[22]=v,t[23]=L):L=t[23];let R;t[24]===v?R=t[25]:(R=v.some(b)&&(0,h.jsxs)(p,{children:[(0,h.jsx)(u,{children:(0,h.jsx)(d,{className:`text-sm`,children:`GPU Inventory`})}),(0,h.jsx)(f,{children:(0,h.jsx)(F,{nodes:v})})]}),t[24]=v,t[25]=R);let z;return t[26]!==R||t[27]!==M||t[28]!==P||t[29]!==L?(z=(0,h.jsxs)(h.Fragment,{children:[O,(0,h.jsxs)(`div`,{className:`space-y-6`,children:[M,P,L,R]})]}),t[26]=R,t[27]=M,t[28]=P,t[29]=L,t[30]=z):z=t[30],z}function b(e){return(e.gpus?.length??0)>0}function x(e,t){return e.name.localeCompare(t.name)}function S(e){let[t,n]=e;return{name:t,...n}}function C(e){return!e.managed_by}function w(e){let t=(0,m.c)(5),{nodes:n}=e,r;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,h.jsx)(`thead`,{children:(0,h.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Name`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Status`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Roles`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`IP`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Region`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`AZ`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Uptime`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`EC2`}),(0,h.jsx)(`th`,{className:`pb-1 font-medium`,children:`Services`})]})}),t[0]=r):r=t[0];let i;t[1]===n?i=t[2]:(i=n.map(T),t[1]=n,t[2]=i);let a;return t[3]===i?a=t[4]:(a=(0,h.jsx)(`div`,{className:`overflow-x-auto`,children:(0,h.jsxs)(`table`,{className:`w-full text-xs`,children:[r,(0,h.jsx)(`tbody`,{children:i})]})}),t[3]=i,t[4]=a),a}function T(e){let t=[e.nats_role?`nats:${e.nats_role}`:null,e.predastore_role?`predastore:${e.predastore_role}`:null].filter(Boolean).join(`,`);return(0,h.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono font-medium`,children:e.node}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:(0,h.jsx)(l,{variant:e.status===`Ready`?`default`:`secondary`,className:`text-[0.625rem]`,children:e.status})}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono text-muted-foreground`,children:t||`-`}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.host}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.region}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.az}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:g(e.uptime)}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.vm_count}),(0,h.jsx)(`td`,{className:`py-1.5`,children:(0,h.jsx)(`span`,{className:`text-muted-foreground`,children:e.services?.join(`,`)??`-`})})]},e.node)}function E(e){return e?e.profile?`${i(e.vram_mib)} (${e.profile})`:`${e.model} ${i(e.vram_mib)}`:`-`}function D(e){let t=(0,m.c)(5),{vms:n}=e,r;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,h.jsx)(`thead`,{children:(0,h.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Instance`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Status`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Type`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`vCPU`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Memory`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`GPU`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Node`}),(0,h.jsx)(`th`,{className:`pb-1 font-medium`,children:`Age`})]})}),t[0]=r):r=t[0];let i;t[1]===n?i=t[2]:(i=n.map(O),t[1]=n,t[2]=i);let a;return t[3]===i?a=t[4]:(a=(0,h.jsx)(`div`,{className:`overflow-x-auto`,children:(0,h.jsxs)(`table`,{className:`w-full text-xs`,children:[r,(0,h.jsx)(`tbody`,{children:i})]})}),t[3]=i,t[4]=a),a}function O(e){return(0,h.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.instance_id}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:(0,h.jsx)(l,{variant:e.status===`running`?`default`:`secondary`,className:`text-[0.625rem]`,children:e.status})}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.instance_type}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.vcpu}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:_(e.memory_gb)}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:E(e.gpu)}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.node}),(0,h.jsx)(`td`,{className:`py-1.5`,children:e.launch_time>0?v(e.launch_time):`-`})]},e.instance_id)}function k(e){let t=(0,m.c)(5),{nodes:n}=e,r;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,h.jsx)(`thead`,{children:(0,h.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Name`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`CPU (used/total)`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`MEM (used/total)`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`GPU (used/total)`}),(0,h.jsx)(`th`,{className:`pb-1 font-medium`,children:`EC2`})]})}),t[0]=r):r=t[0];let i;t[1]===n?i=t[2]:(i=n.map(A),t[1]=n,t[2]=i);let a;return t[3]===i?a=t[4]:(a=(0,h.jsx)(`div`,{className:`overflow-x-auto`,children:(0,h.jsxs)(`table`,{className:`w-full text-xs`,children:[r,(0,h.jsx)(`tbody`,{children:i})]})}),t[3]=i,t[4]=a),a}function A(e){return(0,h.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono font-medium`,children:e.node}),(0,h.jsxs)(`td`,{className:`py-1.5 pr-4 font-mono`,children:[e.alloc_vcpu,`/`,e.total_vcpu]}),(0,h.jsxs)(`td`,{className:`py-1.5 pr-4 font-mono`,children:[_(e.alloc_mem_gb),`/`,_(e.total_mem_gb)]}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.total_gpus>0?`${e.alloc_gpus}/${e.total_gpus}`:`-`}),(0,h.jsx)(`td`,{className:`py-1.5`,children:e.vm_count})]},e.node)}function j(e){let t=(0,m.c)(5),{instanceTypes:n}=e,r;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,h.jsx)(`thead`,{children:(0,h.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Instance Type`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Available`}),(0,h.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`vCPU`}),(0,h.jsx)(`th`,{className:`pb-1 font-medium`,children:`Memory`})]})}),t[0]=r):r=t[0];let i;t[1]===n?i=t[2]:(i=n.map(M),t[1]=n,t[2]=i);let a;return t[3]===i?a=t[4]:(a=(0,h.jsx)(`div`,{className:`overflow-x-auto`,children:(0,h.jsxs)(`table`,{className:`w-full text-xs`,children:[r,(0,h.jsx)(`tbody`,{children:i})]})}),t[3]=i,t[4]=a),a}function M(e){return(0,h.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,h.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.name}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.available}),(0,h.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.vcpu}),(0,h.jsx)(`td`,{className:`py-1.5`,children:_(e.memory_gb)})]},e.name)}function N(e){let t=(0,m.c)(22),{gpu:n}=e,r;t[0]===n.model?r=t[1]:(r=(0,h.jsx)(`span`,{className:`font-medium`,children:n.model}),t[0]=n.model,t[1]=r);let a;t[2]===n.vram_mib?a=t[3]:(a=i(n.vram_mib),t[2]=n.vram_mib,t[3]=a);let o;t[4]===a?o=t[5]:(o=(0,h.jsx)(`span`,{className:`text-muted-foreground`,children:a}),t[4]=a,t[5]=o);let s;t[6]===n.pci_address?s=t[7]:(s=(0,h.jsx)(`span`,{className:`text-muted-foreground`,children:n.pci_address}),t[6]=n.pci_address,t[7]=s);let c;t[8]!==n.instance_id||t[9]!==n.mig_enabled?(c=n.mig_enabled?(0,h.jsx)(l,{className:`text-[0.625rem]`,variant:`secondary`,children:`MIG`}):(0,h.jsx)(`span`,{className:n.instance_id?`text-amber-500`:`text-green-600`,children:n.instance_id?`in-use: ${n.instance_id}`:`free`}),t[8]=n.instance_id,t[9]=n.mig_enabled,t[10]=c):c=t[10];let u;t[11]!==r||t[12]!==o||t[13]!==s||t[14]!==c?(u=(0,h.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3 font-mono`,children:[r,o,s,c]}),t[11]=r,t[12]=o,t[13]=s,t[14]=c,t[15]=u):u=t[15];let d;t[16]!==n.mig_enabled||t[17]!==n.slices?(d=n.mig_enabled&&n.slices&&n.slices.length>0&&(0,h.jsxs)(`table`,{className:`mt-2 w-full`,children:[(0,h.jsx)(`thead`,{children:(0,h.jsxs)(`tr`,{className:`text-left text-muted-foreground`,children:[(0,h.jsx)(`th`,{className:`pr-4 pb-0.5 font-normal`,children:`GI`}),(0,h.jsx)(`th`,{className:`pr-4 pb-0.5 font-normal`,children:`Profile`}),(0,h.jsx)(`th`,{className:`pr-4 pb-0.5 font-normal`,children:`VRAM`}),(0,h.jsx)(`th`,{className:`pb-0.5 font-normal`,children:`Instance`})]})}),(0,h.jsx)(`tbody`,{children:n.slices.map(P)})]}),t[16]=n.mig_enabled,t[17]=n.slices,t[18]=d):d=t[18];let f;return t[19]!==u||t[20]!==d?(f=(0,h.jsxs)(`div`,{className:`rounded border p-2 text-xs`,children:[u,d]}),t[19]=u,t[20]=d,t[21]=f):f=t[21],f}function P(e){return(0,h.jsxs)(`tr`,{children:[(0,h.jsx)(`td`,{className:`py-0.5 pr-4 font-mono`,children:e.gi_id}),(0,h.jsx)(`td`,{className:`py-0.5 pr-4 font-mono`,children:e.profile}),(0,h.jsx)(`td`,{className:`py-0.5 pr-4`,children:i(e.vram_mib)}),(0,h.jsx)(`td`,{className:e.instance_id?`py-0.5 font-mono text-amber-500`:`py-0.5 text-green-600`,children:e.instance_id??`free`})]},e.gi_id)}function F(e){let t=(0,m.c)(6),{nodes:n}=e,r,i;if(t[0]!==n){let e=n.filter(R);r=`space-y-4`,i=e.map(I),t[0]=n,t[1]=r,t[2]=i}else r=t[1],i=t[2];let a;return t[3]!==r||t[4]!==i?(a=(0,h.jsx)(`div`,{className:r,children:i}),t[3]=r,t[4]=i,t[5]=a):a=t[5],a}function I(e){return(0,h.jsxs)(`div`,{children:[(0,h.jsx)(`h4`,{className:`mb-1.5 text-xs font-medium text-muted-foreground`,children:e.node}),(0,h.jsx)(`div`,{className:`space-y-2`,children:e.gpus?.map(L)})]},e.node)}function L(e){return(0,h.jsx)(N,{gpu:e},e.pci_address)}function R(e){return(e.gpus?.length??0)>0}export{y as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/page-heading.js b/spinifex/services/spinifexui/frontend/dist/assets/page-heading.js index 0fef9ea92..e4a9bb141 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/page-heading.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/page-heading.js @@ -1 +1 @@ -import{mo as e,so as t}from"./index.js";var n=t(),r=e();function i(e){let t=(0,n.c)(12),{title:i,subtitle:a,actions:o}=e,s;t[0]===i?s=t[1]:(s=(0,r.jsx)(`h1`,{className:`text-3xl`,children:i}),t[0]=i,t[1]=s);let c;t[2]===a?c=t[3]:(c=a&&(0,r.jsx)(`p`,{className:`mt-1 text-muted-foreground`,children:a}),t[2]=a,t[3]=c);let l;t[4]!==s||t[5]!==c?(l=(0,r.jsxs)(`div`,{children:[s,c]}),t[4]=s,t[5]=c,t[6]=l):l=t[6];let u;t[7]===o?u=t[8]:(u=o&&(0,r.jsx)(`div`,{children:o}),t[7]=o,t[8]=u);let d;return t[9]!==l||t[10]!==u?(d=(0,r.jsxs)(`div`,{className:`mb-6 flex items-start justify-between`,children:[l,u]}),t[9]=l,t[10]=u,t[11]=d):d=t[11],d}export{i as t}; \ No newline at end of file +import{Oo as e,xo as t}from"./index.js";var n=t(),r=e();function i(e){let t=(0,n.c)(12),{title:i,subtitle:a,actions:o}=e,s;t[0]===i?s=t[1]:(s=(0,r.jsx)(`h1`,{className:`text-3xl`,children:i}),t[0]=i,t[1]=s);let c;t[2]===a?c=t[3]:(c=a&&(0,r.jsx)(`p`,{className:`mt-1 text-muted-foreground`,children:a}),t[2]=a,t[3]=c);let l;t[4]!==s||t[5]!==c?(l=(0,r.jsxs)(`div`,{children:[s,c]}),t[4]=s,t[5]=c,t[6]=l):l=t[6];let u;t[7]===o?u=t[8]:(u=o&&(0,r.jsx)(`div`,{children:o}),t[7]=o,t[8]=u);let d;return t[9]!==l||t[10]!==u?(d=(0,r.jsxs)(`div`,{className:`mb-6 flex items-start justify-between`,children:[l,u]}),t[9]=l,t[10]=u,t[11]=d):d=t[11],d}export{i as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/plus.js b/spinifex/services/spinifexui/frontend/dist/assets/plus.js index fde93a47c..f7d23bb06 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/plus.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/plus.js @@ -1 +1 @@ -import{Xa as e}from"./index.js";var t=e(`plus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]);export{t}; \ No newline at end of file +import{uo as e}from"./index.js";var t=e(`plus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]);export{t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/route.js b/spinifex/services/spinifexui/frontend/dist/assets/route.js index 7202b1f31..3b31c1b72 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/route.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/route.js @@ -1 +1 @@ -import{co as e,mo as t,so as n}from"./index.js";var r=n(),i=t(),a=()=>{let t=(0,r.c)(1),n;return t[0]===Symbol.for(`react.memo_cache_sentinel`)?(n=(0,i.jsx)(e,{}),t[0]=n):n=t[0],n};export{a as component}; \ No newline at end of file +import{Oo as e,So as t,xo as n}from"./index.js";var r=n(),i=e(),a=()=>{let e=(0,r.c)(1),n;return e[0]===Symbol.for(`react.memo_cache_sentinel`)?(n=(0,i.jsx)(t,{}),e[0]=n):n=e[0],n};export{a as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/route2.js b/spinifex/services/spinifexui/frontend/dist/assets/route2.js index 7202b1f31..3b31c1b72 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/route2.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/route2.js @@ -1 +1 @@ -import{co as e,mo as t,so as n}from"./index.js";var r=n(),i=t(),a=()=>{let t=(0,r.c)(1),n;return t[0]===Symbol.for(`react.memo_cache_sentinel`)?(n=(0,i.jsx)(e,{}),t[0]=n):n=t[0],n};export{a as component}; \ No newline at end of file +import{Oo as e,So as t,xo as n}from"./index.js";var r=n(),i=e(),a=()=>{let e=(0,r.c)(1),n;return e[0]===Symbol.for(`react.memo_cache_sentinel`)?(n=(0,i.jsx)(t,{}),e[0]=n):n=e[0],n};export{a as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/run-instances.js b/spinifex/services/spinifexui/frontend/dist/assets/run-instances.js index 2bbbf3bf2..626962585 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/run-instances.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/run-instances.js @@ -1,8 +1,8 @@ -import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./chevron-down.js";import{a as i,c as a,i as o,n as s,o as c,r as l,s as u,t as d}from"./select.js";import{t as f}from"./cli-command-panel.js";import{o as p}from"./ec2.js";import{$ as m,K as h,Na as g,Po as _,Ta as v,Ti as y,V as b,W as x,ho as S,mo as C,uo as ee,z as te}from"./index.js";import{t as ne}from"./page-heading.js";import{a as w,n as T,r as E,t as D}from"./field.js";import{i as re,n as O,t as ie}from"./zod.js";import{n as ae,r as k,t as oe}from"./collapsible.js";import{n as se,t as ce}from"./ec22.js";var le=_(S()),A=C(),j=`/dev/sda1`,ue=`gp3`,M=1,de=16384;function N(){let _=ee(),{data:S}=t(te),{data:C}=t(x),{data:j}=t(b),{data:N}=t(m),{data:pe}=t(h),F=p(),I=S.Images??[],L=C.KeyPairs??[],me=N.Subnets??[],he=pe.PlacementGroups??[],R={},z=new Map;for(let e of j.InstanceTypes??[]){let t=e.InstanceType;if(t&&(R[t]=(R[t]??0)+1,!z.has(t))){let n=e.GpuInfo?.Gpus;n&&n.length>0&&z.set(t,{totalMiB:e.GpuInfo?.TotalGpuMemoryInMiB??0,gpuName:n[0]?.Name??``})}}let B=Object.keys(R).toSorted(),V=B.filter(e=>z.has(e)),H=B.filter(e=>!z.has(e)),U=I[0]?.ImageId,ge=L[0]?.KeyName,_e=B.find(e=>e.endsWith(`.nano`))??B[0],ve=P(I.find(e=>e.ImageId===U)),{control:W,handleSubmit:ye,register:G,setValue:K,watch:q,formState:{errors:J,isSubmitting:Y}}=re({resolver:ie(se.refine(e=>e.count<=(R[e.instanceType]??1),{message:`Cannot exceed available capacity`,path:[`count`]}).superRefine((e,t)=>{let n=P(I.find(t=>t.ImageId===e.imageId)).snapshotSize;e.rootVolumeSize!==void 0&&n!==void 0&&e.rootVolumeSizee.ImageId===Q));return(0,le.useEffect)(()=>{K(`rootDeviceName`,$.deviceName)},[Q,$.deviceName,K]),(0,A.jsxs)(A.Fragment,{children:[(0,A.jsx)(n,{to:`/ec2/describe-instances`,children:`Back to instances`}),(0,A.jsx)(ne,{title:`Run Instances`}),B.length===0&&(0,A.jsx)(e,{msg:`No compute available. No new instances can be created until compute is available.`}),F.error&&(0,A.jsx)(e,{error:F.error,msg:`Failed to create instance`}),(0,A.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:ye(async e=>{await F.mutateAsync(e),_({to:`/ec2/describe-instances`})}),children:[(0,A.jsxs)(D,{children:[(0,A.jsx)(w,{children:(0,A.jsx)(`label`,{htmlFor:`imageId`,children:`Image`})}),(0,A.jsx)(O,{control:W,name:`imageId`,render:({field:e})=>{let t=I.find(t=>t.ImageId===e.value);return(0,A.jsxs)(d,{onValueChange:t=>e.onChange(t),value:e.value??``,children:[(0,A.jsx)(u,{"aria-invalid":!!J.imageId,className:`w-full`,id:`imageId`,children:(0,A.jsx)(a,{children:t?`${t.Name??`Unnamed`} (${t.Architecture})`:``})}),(0,A.jsx)(s,{children:I.map(e=>(0,A.jsxs)(o,{value:e.ImageId??``,children:[e.Name??`Unnamed`,` (`,e.Architecture,`)`]},e.ImageId))})]})}}),(0,A.jsx)(E,{errors:[J.imageId]})]}),(0,A.jsxs)(D,{children:[(0,A.jsx)(w,{children:(0,A.jsx)(`label`,{htmlFor:`instanceType`,children:`Instance Type`})}),(0,A.jsx)(O,{control:W,name:`instanceType`,render:({field:e})=>(0,A.jsxs)(d,{onValueChange:t=>e.onChange(t),value:e.value||``,children:[(0,A.jsx)(u,{"aria-invalid":!!J.instanceType,className:`w-full`,id:`instanceType`,children:(0,A.jsx)(a,{})}),(0,A.jsxs)(s,{children:[H.length>0&&(0,A.jsxs)(l,{children:[V.length>0&&(0,A.jsx)(i,{children:`Standard`}),H.map(e=>(0,A.jsxs)(o,{value:e,children:[e,` (`,R[e],` available)`]},e))]}),V.length>0&&H.length>0&&(0,A.jsx)(c,{}),V.length>0&&(0,A.jsxs)(l,{children:[(0,A.jsx)(i,{children:`GPU-Accelerated`}),V.map(e=>{let t=z.get(e);return(0,A.jsxs)(o,{value:e,children:[e,t?` — ${g(t.totalMiB)}`:``,` (`,R[e],` available)`]},e)})]})]})]})}),Z&&(0,A.jsxs)(T,{children:[`GPU: `,Z.gpuName,` ·`,` `,g(Z.totalMiB),` VRAM`]}),(0,A.jsx)(E,{errors:[J.instanceType]})]}),(0,A.jsxs)(D,{children:[(0,A.jsx)(w,{children:(0,A.jsx)(`label`,{htmlFor:`keyName`,children:`Key Pair`})}),(0,A.jsx)(O,{control:W,name:`keyName`,render:({field:e})=>(0,A.jsxs)(d,{onValueChange:t=>e.onChange(t),value:e.value||``,children:[(0,A.jsx)(u,{"aria-invalid":!!J.keyName,className:`w-full`,id:`keyName`,children:(0,A.jsx)(a,{})}),(0,A.jsx)(s,{children:L.map(e=>(0,A.jsx)(o,{value:e.KeyName??``,children:e.KeyName},e.KeyPairId))})]})}),(0,A.jsx)(E,{errors:[J.keyName]})]}),(0,A.jsxs)(D,{children:[(0,A.jsx)(w,{children:(0,A.jsx)(`label`,{htmlFor:`subnetId`,children:`Subnet`})}),(0,A.jsx)(O,{control:W,name:`subnetId`,render:({field:e})=>(0,A.jsxs)(d,{onValueChange:t=>e.onChange(t===`none`?void 0:t),value:e.value??`none`,children:[(0,A.jsx)(u,{className:`w-full`,id:`subnetId`,children:(0,A.jsx)(a,{})}),(0,A.jsxs)(s,{children:[(0,A.jsx)(o,{value:`none`,children:`none`}),me.map(e=>(0,A.jsx)(o,{value:e.SubnetId??``,children:e.SubnetId},e.SubnetId))]})]})})]}),(0,A.jsxs)(D,{children:[(0,A.jsx)(w,{children:(0,A.jsx)(`label`,{htmlFor:`placementGroupName`,children:`Placement Group`})}),(0,A.jsx)(O,{control:W,name:`placementGroupName`,render:({field:e})=>(0,A.jsxs)(d,{onValueChange:t=>e.onChange(t===`none`?void 0:t),value:e.value??`none`,children:[(0,A.jsx)(u,{className:`w-full`,id:`placementGroupName`,children:(0,A.jsx)(a,{})}),(0,A.jsxs)(s,{children:[(0,A.jsx)(o,{value:`none`,children:`none`}),he.map(e=>(0,A.jsxs)(o,{value:e.GroupName??``,children:[e.GroupName,` (`,e.Strategy,`)`]},e.GroupId))]})]})})]}),(0,A.jsxs)(D,{children:[(0,A.jsx)(w,{children:(0,A.jsx)(`label`,{htmlFor:`count`,children:`Number of Instances`})}),(0,A.jsx)(y,{"aria-describedby":`count-description`,"aria-invalid":!!J.count,id:`count`,type:`number`,...G(`count`,{valueAsNumber:!0})}),(0,A.jsx)(`p`,{className:`text-xs text-muted-foreground`,id:`count-description`,children:X&&`Available capacity for ${X}: ${be}`}),(0,A.jsx)(E,{errors:[J.count]})]}),(0,A.jsxs)(oe,{children:[(0,A.jsxs)(k,{className:`group flex h-7 w-full items-center justify-between rounded-md border border-input bg-input/20 px-2 py-0.5 text-sm transition-colors outline-none hover:bg-input/40 focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 md:text-xs/relaxed dark:bg-input/30 dark:hover:bg-input/50`,render:(0,A.jsx)(`button`,{"aria-label":`Block Device Mappings (root volume)`,type:`button`}),children:[(0,A.jsx)(`span`,{children:`Block Device Mappings (root volume)`}),(0,A.jsx)(r,{className:`size-3.5 text-muted-foreground transition-transform group-data-[panel-open]:rotate-180`})]}),(0,A.jsxs)(ae,{className:`mt-3 space-y-4 rounded-md border border-border p-4`,children:[(0,A.jsxs)(D,{children:[(0,A.jsx)(w,{children:(0,A.jsx)(`label`,{htmlFor:`rootDeviceName`,children:`Device Name`})}),(0,A.jsx)(y,{"aria-invalid":!!J.rootDeviceName,id:`rootDeviceName`,type:`text`,...G(`rootDeviceName`)}),(0,A.jsx)(E,{errors:[J.rootDeviceName]})]}),(0,A.jsxs)(D,{children:[(0,A.jsx)(w,{children:(0,A.jsx)(`label`,{htmlFor:`rootVolumeSize`,children:`Volume Size (GiB)`})}),(0,A.jsx)(y,{"aria-invalid":!!J.rootVolumeSize,id:`rootVolumeSize`,max:de,min:$.snapshotSize??M,placeholder:$.snapshotSize?`${$.snapshotSize} (AMI default)`:`use AMI / backend default`,type:`number`,...G(`rootVolumeSize`,{setValueAs:e=>e===``||e==null?void 0:Number(e)})}),$.snapshotSize!==void 0&&(0,A.jsxs)(T,{children:[`AMI snapshot size: `,$.snapshotSize,` GiB`]}),(0,A.jsx)(E,{errors:[J.rootVolumeSize]})]}),(0,A.jsxs)(D,{children:[(0,A.jsx)(w,{children:(0,A.jsx)(`label`,{htmlFor:`rootVolumeType`,children:`Volume Type`})}),(0,A.jsx)(O,{control:W,name:`rootVolumeType`,render:({field:e})=>(0,A.jsxs)(d,{onValueChange:t=>e.onChange(t),value:e.value??ue,children:[(0,A.jsx)(u,{"aria-invalid":!!J.rootVolumeType,className:`w-full`,id:`rootVolumeType`,children:(0,A.jsx)(a,{})}),(0,A.jsx)(s,{children:ce.map(e=>(0,A.jsx)(o,{value:e,children:e},e))})]})}),(0,A.jsx)(E,{errors:[J.rootVolumeType]})]}),(0,A.jsx)(D,{children:(0,A.jsx)(O,{control:W,name:`rootDeleteOnTermination`,render:({field:e})=>(0,A.jsxs)(`label`,{className:`flex items-center gap-2 text-sm`,children:[(0,A.jsx)(`input`,{"aria-label":`Delete on termination`,checked:e.value??!0,onChange:t=>e.onChange(t.target.checked),type:`checkbox`}),`Delete on termination`]})})})]})]}),(0,A.jsx)(f,{commands:fe(q)}),(0,A.jsxs)(`div`,{className:`flex gap-2`,children:[(0,A.jsx)(v,{disabled:Y||F.isPending,onClick:async()=>await _({to:`/ec2/describe-instances`}),type:`button`,variant:`outline`,children:`Cancel`}),(0,A.jsx)(v,{disabled:Y||F.isPending||B.length===0,type:`submit`,children:Y||F.isPending?`Creating…`:`Create Instance`})]})]})]})}function P(e){let t=e?.RootDeviceName??j,n=e?.BlockDeviceMappings??[];return{deviceName:t,snapshotSize:(n.find(e=>e.DeviceName===t)??n[0])?.Ebs?.VolumeSize}}function fe(e){let t=e(`imageId`),n=typeof t==`string`?t:``,r=e(`instanceType`),i=typeof r==`string`?r:``,a=e(`keyName`),o=typeof a==`string`?a:``,s=e(`subnetId`),c=typeof s==`string`?s:``,l=e(`placementGroupName`),u=typeof l==`string`?l:``,d=e(`count`),f=typeof d==`number`?d:0,p=e(`rootDeviceName`),m=typeof p==`string`?p:``,h=e(`rootVolumeSize`),g=typeof h==`number`?h:void 0,_=e(`rootVolumeType`),v=typeof _==`string`?_:``,y=e(`rootDeleteOnTermination`),b=typeof y==`boolean`?y:!0,x=[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 run-instances`},{type:`flag`,value:` \\ +import{t as e}from"./error-banner.js";import{t}from"./useSuspenseQuery.js";import{t as n}from"./back-link.js";import{t as r}from"./chevron-down.js";import{a as i,c as a,i as o,n as s,o as c,r as l,s as u,t as d}from"./select.js";import{t as f}from"./cli-command-panel.js";import{o as p}from"./ec2.js";import{B as m,G as h,H as g,Jo as _,Oo as v,et as y,ko as b,q as x,qa as S,wo as ee,za as C,zi as w}from"./index.js";import{t as te}from"./page-heading.js";import{a as T,n as E,r as D,t as O}from"./field.js";import{i as k,n as A,t as ne}from"./zod.js";import{n as re,r as ie,t as ae}from"./collapsible.js";import{n as oe,t as se}from"./ec22.js";var ce=_(b()),j=v(),M=`/dev/sda1`,le=`gp3`,ue=1,de=16384;function N(){let _=ee(),{data:v}=t(m),{data:b}=t(h),{data:M}=t(g),{data:N}=t(y),{data:pe}=t(x),F=p(),I=v.Images??[],L=b.KeyPairs??[],me=N.Subnets??[],he=pe.PlacementGroups??[],R={},z=new Map;for(let e of M.InstanceTypes??[]){let t=e.InstanceType;if(t&&(R[t]=(R[t]??0)+1,!z.has(t))){let n=e.GpuInfo?.Gpus;n&&n.length>0&&z.set(t,{totalMiB:e.GpuInfo?.TotalGpuMemoryInMiB??0,gpuName:n[0]?.Name??``})}}let B=Object.keys(R).toSorted(),V=B.filter(e=>z.has(e)),H=B.filter(e=>!z.has(e)),U=I[0]?.ImageId,ge=L[0]?.KeyName,_e=B.find(e=>e.endsWith(`.nano`))??B[0],ve=P(I.find(e=>e.ImageId===U)),{control:W,handleSubmit:ye,register:G,setValue:K,watch:q,formState:{errors:J,isSubmitting:Y}}=k({resolver:ne(oe.refine(e=>e.count<=(R[e.instanceType]??1),{message:`Cannot exceed available capacity`,path:[`count`]}).superRefine((e,t)=>{let n=P(I.find(t=>t.ImageId===e.imageId)).snapshotSize;e.rootVolumeSize!==void 0&&n!==void 0&&e.rootVolumeSizee.ImageId===Q));return(0,ce.useEffect)(()=>{K(`rootDeviceName`,$.deviceName)},[Q,$.deviceName,K]),(0,j.jsxs)(j.Fragment,{children:[(0,j.jsx)(n,{to:`/ec2/describe-instances`,children:`Back to instances`}),(0,j.jsx)(te,{title:`Run Instances`}),B.length===0&&(0,j.jsx)(e,{msg:`No compute available. No new instances can be created until compute is available.`}),F.error&&(0,j.jsx)(e,{error:F.error,msg:`Failed to create instance`}),(0,j.jsxs)(`form`,{className:`max-w-4xl space-y-6`,onSubmit:ye(async e=>{await F.mutateAsync(e),_({to:`/ec2/describe-instances`})}),children:[(0,j.jsxs)(O,{children:[(0,j.jsx)(T,{children:(0,j.jsx)(`label`,{htmlFor:`imageId`,children:`Image`})}),(0,j.jsx)(A,{control:W,name:`imageId`,render:({field:e})=>{let t=I.find(t=>t.ImageId===e.value);return(0,j.jsxs)(d,{onValueChange:t=>e.onChange(t),value:e.value??``,children:[(0,j.jsx)(u,{"aria-invalid":!!J.imageId,className:`w-full`,id:`imageId`,children:(0,j.jsx)(a,{children:t?`${t.Name??`Unnamed`} (${t.Architecture})`:``})}),(0,j.jsx)(s,{children:I.map(e=>(0,j.jsxs)(o,{value:e.ImageId??``,children:[e.Name??`Unnamed`,` (`,e.Architecture,`)`]},e.ImageId))})]})}}),(0,j.jsx)(D,{errors:[J.imageId]})]}),(0,j.jsxs)(O,{children:[(0,j.jsx)(T,{children:(0,j.jsx)(`label`,{htmlFor:`instanceType`,children:`Instance Type`})}),(0,j.jsx)(A,{control:W,name:`instanceType`,render:({field:e})=>(0,j.jsxs)(d,{onValueChange:t=>e.onChange(t),value:e.value||``,children:[(0,j.jsx)(u,{"aria-invalid":!!J.instanceType,className:`w-full`,id:`instanceType`,children:(0,j.jsx)(a,{})}),(0,j.jsxs)(s,{children:[H.length>0&&(0,j.jsxs)(l,{children:[V.length>0&&(0,j.jsx)(i,{children:`Standard`}),H.map(e=>(0,j.jsxs)(o,{value:e,children:[e,` (`,R[e],` available)`]},e))]}),V.length>0&&H.length>0&&(0,j.jsx)(c,{}),V.length>0&&(0,j.jsxs)(l,{children:[(0,j.jsx)(i,{children:`GPU-Accelerated`}),V.map(e=>{let t=z.get(e);return(0,j.jsxs)(o,{value:e,children:[e,t?` — ${S(t.totalMiB)}`:``,` (`,R[e],` available)`]},e)})]})]})]})}),Z&&(0,j.jsxs)(E,{children:[`GPU: `,Z.gpuName,` ·`,` `,S(Z.totalMiB),` VRAM`]}),(0,j.jsx)(D,{errors:[J.instanceType]})]}),(0,j.jsxs)(O,{children:[(0,j.jsx)(T,{children:(0,j.jsx)(`label`,{htmlFor:`keyName`,children:`Key Pair`})}),(0,j.jsx)(A,{control:W,name:`keyName`,render:({field:e})=>(0,j.jsxs)(d,{onValueChange:t=>e.onChange(t),value:e.value||``,children:[(0,j.jsx)(u,{"aria-invalid":!!J.keyName,className:`w-full`,id:`keyName`,children:(0,j.jsx)(a,{})}),(0,j.jsx)(s,{children:L.map(e=>(0,j.jsx)(o,{value:e.KeyName??``,children:e.KeyName},e.KeyPairId))})]})}),(0,j.jsx)(D,{errors:[J.keyName]})]}),(0,j.jsxs)(O,{children:[(0,j.jsx)(T,{children:(0,j.jsx)(`label`,{htmlFor:`subnetId`,children:`Subnet`})}),(0,j.jsx)(A,{control:W,name:`subnetId`,render:({field:e})=>(0,j.jsxs)(d,{onValueChange:t=>e.onChange(t===`none`?void 0:t),value:e.value??`none`,children:[(0,j.jsx)(u,{className:`w-full`,id:`subnetId`,children:(0,j.jsx)(a,{})}),(0,j.jsxs)(s,{children:[(0,j.jsx)(o,{value:`none`,children:`none`}),me.map(e=>(0,j.jsx)(o,{value:e.SubnetId??``,children:e.SubnetId},e.SubnetId))]})]})})]}),(0,j.jsxs)(O,{children:[(0,j.jsx)(T,{children:(0,j.jsx)(`label`,{htmlFor:`placementGroupName`,children:`Placement Group`})}),(0,j.jsx)(A,{control:W,name:`placementGroupName`,render:({field:e})=>(0,j.jsxs)(d,{onValueChange:t=>e.onChange(t===`none`?void 0:t),value:e.value??`none`,children:[(0,j.jsx)(u,{className:`w-full`,id:`placementGroupName`,children:(0,j.jsx)(a,{})}),(0,j.jsxs)(s,{children:[(0,j.jsx)(o,{value:`none`,children:`none`}),he.map(e=>(0,j.jsxs)(o,{value:e.GroupName??``,children:[e.GroupName,` (`,e.Strategy,`)`]},e.GroupId))]})]})})]}),(0,j.jsxs)(O,{children:[(0,j.jsx)(T,{children:(0,j.jsx)(`label`,{htmlFor:`count`,children:`Number of Instances`})}),(0,j.jsx)(w,{"aria-describedby":`count-description`,"aria-invalid":!!J.count,id:`count`,type:`number`,...G(`count`,{valueAsNumber:!0})}),(0,j.jsx)(`p`,{className:`text-xs text-muted-foreground`,id:`count-description`,children:X&&`Available capacity for ${X}: ${be}`}),(0,j.jsx)(D,{errors:[J.count]})]}),(0,j.jsxs)(ae,{children:[(0,j.jsxs)(ie,{className:`group flex h-7 w-full items-center justify-between rounded-md border border-input bg-input/20 px-2 py-0.5 text-sm transition-colors outline-none hover:bg-input/40 focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 md:text-xs/relaxed dark:bg-input/30 dark:hover:bg-input/50`,render:(0,j.jsx)(`button`,{"aria-label":`Block Device Mappings (root volume)`,type:`button`}),children:[(0,j.jsx)(`span`,{children:`Block Device Mappings (root volume)`}),(0,j.jsx)(r,{className:`size-3.5 text-muted-foreground transition-transform group-data-[panel-open]:rotate-180`})]}),(0,j.jsxs)(re,{className:`mt-3 space-y-4 rounded-md border border-border p-4`,children:[(0,j.jsxs)(O,{children:[(0,j.jsx)(T,{children:(0,j.jsx)(`label`,{htmlFor:`rootDeviceName`,children:`Device Name`})}),(0,j.jsx)(w,{"aria-invalid":!!J.rootDeviceName,id:`rootDeviceName`,type:`text`,...G(`rootDeviceName`)}),(0,j.jsx)(D,{errors:[J.rootDeviceName]})]}),(0,j.jsxs)(O,{children:[(0,j.jsx)(T,{children:(0,j.jsx)(`label`,{htmlFor:`rootVolumeSize`,children:`Volume Size (GiB)`})}),(0,j.jsx)(w,{"aria-invalid":!!J.rootVolumeSize,id:`rootVolumeSize`,max:de,min:$.snapshotSize??ue,placeholder:$.snapshotSize?`${$.snapshotSize} (AMI default)`:`use AMI / backend default`,type:`number`,...G(`rootVolumeSize`,{setValueAs:e=>e===``||e==null?void 0:Number(e)})}),$.snapshotSize!==void 0&&(0,j.jsxs)(E,{children:[`AMI snapshot size: `,$.snapshotSize,` GiB`]}),(0,j.jsx)(D,{errors:[J.rootVolumeSize]})]}),(0,j.jsxs)(O,{children:[(0,j.jsx)(T,{children:(0,j.jsx)(`label`,{htmlFor:`rootVolumeType`,children:`Volume Type`})}),(0,j.jsx)(A,{control:W,name:`rootVolumeType`,render:({field:e})=>(0,j.jsxs)(d,{onValueChange:t=>e.onChange(t),value:e.value??le,children:[(0,j.jsx)(u,{"aria-invalid":!!J.rootVolumeType,className:`w-full`,id:`rootVolumeType`,children:(0,j.jsx)(a,{})}),(0,j.jsx)(s,{children:se.map(e=>(0,j.jsx)(o,{value:e,children:e},e))})]})}),(0,j.jsx)(D,{errors:[J.rootVolumeType]})]}),(0,j.jsx)(O,{children:(0,j.jsx)(A,{control:W,name:`rootDeleteOnTermination`,render:({field:e})=>(0,j.jsxs)(`label`,{className:`flex items-center gap-2 text-sm`,children:[(0,j.jsx)(`input`,{"aria-label":`Delete on termination`,checked:e.value??!0,onChange:t=>e.onChange(t.target.checked),type:`checkbox`}),`Delete on termination`]})})})]})]}),(0,j.jsx)(f,{commands:fe(q)}),(0,j.jsxs)(`div`,{className:`flex gap-2`,children:[(0,j.jsx)(C,{disabled:Y||F.isPending,onClick:async()=>await _({to:`/ec2/describe-instances`}),type:`button`,variant:`outline`,children:`Cancel`}),(0,j.jsx)(C,{disabled:Y||F.isPending||B.length===0,type:`submit`,children:Y||F.isPending?`Creating…`:`Create Instance`})]})]})]})}function P(e){let t=e?.RootDeviceName??M,n=e?.BlockDeviceMappings??[];return{deviceName:t,snapshotSize:(n.find(e=>e.DeviceName===t)??n[0])?.Ebs?.VolumeSize}}function fe(e){let t=e(`imageId`),n=typeof t==`string`?t:``,r=e(`instanceType`),i=typeof r==`string`?r:``,a=e(`keyName`),o=typeof a==`string`?a:``,s=e(`subnetId`),c=typeof s==`string`?s:``,l=e(`placementGroupName`),u=typeof l==`string`?l:``,d=e(`count`),f=typeof d==`number`?d:0,p=e(`rootDeviceName`),m=typeof p==`string`?p:``,h=e(`rootVolumeSize`),g=typeof h==`number`?h:void 0,_=e(`rootVolumeType`),v=typeof _==`string`?_:``,y=e(`rootDeleteOnTermination`),b=typeof y==`boolean`?y:!0,x=[{type:`bin`,value:`AWS_PROFILE=spinifex aws ec2 run-instances`},{type:`flag`,value:` \\ --image-id`},{type:`value`,value:` ${n||``}`},{type:`flag`,value:` \\ --instance-type`},{type:`value`,value:` ${i||``}`},{type:`flag`,value:` \\ --key-name`},{type:`value`,value:` ${o||``}`}];if(c&&x.push({type:`flag`,value:` \\ --subnet-id`},{type:`value`,value:` ${c}`}),u&&x.push({type:`flag`,value:` \\ --placement`},{type:`value`,value:` GroupName=${u}`}),x.push({type:`flag`,value:` \\ - --count`},{type:`value`,value:` ${f||1}`}),g!==void 0||_!==void 0||y!==void 0){let e={};g!==void 0&&(e.VolumeSize=g),v&&(e.VolumeType=v),y!==void 0&&(e.DeleteOnTermination=b);let t=JSON.stringify([{DeviceName:m||j,Ebs:e}]);x.push({type:`flag`,value:` \\ + --count`},{type:`value`,value:` ${f||1}`}),g!==void 0||_!==void 0||y!==void 0){let e={};g!==void 0&&(e.VolumeSize=g),v&&(e.VolumeType=v),y!==void 0&&(e.DeleteOnTermination=b);let t=JSON.stringify([{DeviceName:m||M,Ebs:e}]);x.push({type:`flag`,value:` \\ --block-device-mappings`},{type:`value`,value:` '${t}'`})}return[{label:`Run Instances`,parts:x}]}export{N as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/s3.js b/spinifex/services/spinifexui/frontend/dist/assets/s3.js index b3cb3b88d..d4f341557 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/s3.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/s3.js @@ -1,6 +1,6 @@ -import{n as e}from"./error-banner.js";import{$n as t,Ct as n,Fn as r,In as i,Jn as a,Ln as o,No as s,Pn as c,Rn as l,St as u,Un as d,Vn as f,Wn as p,Xn as m,_t as h,ar as g,bt as _,ct as v,dt as y,er as b,ft as x,gt as S,ht as C,ir as w,lt as T,nr as E,or as D,po as O,pt as ee,rr as k,so as A,tr as j,ut as te,vt as M,wt as N,xt as P,yt as F,zn as I}from"./index.js";var L=typeof ReadableStream==`function`?ReadableStream:function(){},R=class extends L{},ne=({expectedChecksum:e,checksum:t,source:n,checksumSourceLocation:r,base64Encoder:i})=>{if(!d(n))throw Error(`@smithy/util-stream: unsupported source type ${n?.constructor?.name??n} in ChecksumStream.`);let a=i??p;if(typeof TransformStream!=`function`)throw Error(`@smithy/util-stream: unable to instantiate ChecksumStream because API unavailable: ReadableStream/TransformStream.`);let o=new TransformStream({start(){},async transform(e,n){t.update(e),n.enqueue(e)},async flush(n){let i=a(await t.digest());if(e!==i){let t=Error(`Checksum mismatch: expected "${e}" but received "${i}" in response header "${r}".`);n.error(t)}else n.terminate()}});n.pipeThrough(o);let s=o.readable;return Object.setPrototypeOf(s,R.prototype),s},re=class{allocByteArray;byteLength=0;byteArrays=[];constructor(e){this.allocByteArray=e}push(e){this.byteArrays.push(e),this.byteLength+=e.byteLength}flush(){if(this.byteArrays.length===1){let e=this.byteArrays[0];return this.reset(),e}let e=this.allocByteArray(this.byteLength),t=0;for(let n=0;nnew Uint8Array(e))],s=-1,c=async e=>{let{value:l,done:u}=await r.read(),d=l;if(u){if(s!==-1){let t=H(o,s);U(t)>0&&e.enqueue(t)}e.close()}else{let r=W(d,!1);if(s!==r&&(s>=0&&e.enqueue(H(o,s)),s=r),s===-1){e.enqueue(d);return}let l=U(d);a+=l;let u=U(o[s]);if(l>=t&&u===0)e.enqueue(d);else{let r=V(o,s,d);!i&&a>t*2&&(i=!0,n?.warn(`@smithy/util-stream - stream chunk size ${l} is below threshold of ${t}, automatically buffering.`)),r>=t?e.enqueue(H(o,s)):await c(e)}}};return new ReadableStream({pull:c})}var B=z;function V(e,t,n){switch(t){case 0:return e[0]+=n,U(e[0]);case 1:case 2:return e[t].push(n),U(e[t])}}function H(e,t){switch(t){case 0:let n=e[0];return e[0]=``,n;case 1:case 2:return e[t].flush()}throw Error(`@smithy/util-stream - invalid index ${t} given to flush()`)}function U(e){return e?.byteLength??e?.length??0}function W(e,t=!0){return t&&typeof Buffer<`u`&&e instanceof Buffer?2:e instanceof Uint8Array?1:typeof e==`string`?0:-1}var G=(e,{requestChecksumRequired:t,requestAlgorithmMember:r,requestChecksumCalculation:i})=>{if(!r)return i===n.WHEN_SUPPORTED||t?u:void 0;if(e[r])return e[r]},K=e=>e===P.MD5?`content-md5`:`x-amz-checksum-${e.toLowerCase()}`,ie=(e,t)=>{let n=e.toLowerCase();for(let e of Object.keys(t))if(n===e.toLowerCase())return!0;return!1},ae=(e,t)=>{let n=e.toLowerCase();for(let e of Object.keys(t))if(e.toLowerCase().startsWith(n))return!0;return!1},oe=e=>e!==void 0&&typeof e!=`string`&&!ArrayBuffer.isView(e)&&!a(e),se=function(){function e(){this.crc32c=new ce}return e.prototype.update=function(e){g(e)||this.crc32c.update(D(e))},e.prototype.digest=function(){return b(this,void 0,void 0,function(){return j(this,function(e){return[2,w(this.crc32c.digest())]})})},e.prototype.reset=function(){this.crc32c=new ce},e}(),ce=function(){function e(){this.checksum=4294967295}return e.prototype.update=function(e){var t,n;try{for(var r=E(e),i=r.next();!i.done;i=r.next()){var a=i.value;this.checksum=this.checksum>>>8^le[(this.checksum^a)&255]}}catch(e){t={error:e}}finally{try{i&&!i.done&&(n=r.return)&&n.call(r)}finally{if(t)throw t.error}}return this},e.prototype.digest=function(){return(this.checksum^4294967295)>>>0},e}(),le=k([0,4067132163,3778769143,324072436,3348797215,904991772,648144872,3570033899,2329499855,2024987596,1809983544,2575936315,1296289744,3207089363,2893594407,1578318884,274646895,3795141740,4049975192,51262619,3619967088,632279923,922689671,3298075524,2592579488,1760304291,2075979607,2312596564,1562183871,2943781820,3156637768,1313733451,549293790,3537243613,3246849577,871202090,3878099393,357341890,102525238,4101499445,2858735121,1477399826,1264559846,3107202533,1845379342,2677391885,2361733625,2125378298,820201905,3263744690,3520608582,598981189,4151959214,85089709,373468761,3827903834,3124367742,1213305469,1526817161,2842354314,2107672161,2412447074,2627466902,1861252501,1098587580,3004210879,2688576843,1378610760,2262928035,1955203488,1742404180,2511436119,3416409459,969524848,714683780,3639785095,205050476,4266873199,3976438427,526918040,1361435347,2739821008,2954799652,1114974503,2529119692,1691668175,2005155131,2247081528,3690758684,697762079,986182379,3366744552,476452099,3993867776,4250756596,255256311,1640403810,2477592673,2164122517,1922457750,2791048317,1412925310,1197962378,3037525897,3944729517,427051182,170179418,4165941337,746937522,3740196785,3451792453,1070968646,1905808397,2213795598,2426610938,1657317369,3053634322,1147748369,1463399397,2773627110,4215344322,153784257,444234805,3893493558,1021025245,3467647198,3722505002,797665321,2197175160,1889384571,1674398607,2443626636,1164749927,3070701412,2757221520,1446797203,137323447,4198817972,3910406976,461344835,3484808360,1037989803,781091935,3705997148,2460548119,1623424788,1939049696,2180517859,1429367560,2807687179,3020495871,1180866812,410100952,3927582683,4182430767,186734380,3756733383,763408580,1053836080,3434856499,2722870694,1344288421,1131464017,2971354706,1708204729,2545590714,2229949006,1988219213,680717673,3673779818,3383336350,1002577565,4010310262,493091189,238226049,4233660802,2987750089,1082061258,1395524158,2705686845,1972364758,2279892693,2494862625,1725896226,952904198,3399985413,3656866545,731699698,4283874585,222117402,510512622,3959836397,3280807620,837199303,582374963,3504198960,68661723,4135334616,3844915500,390545967,1230274059,3141532936,2825850620,1510247935,2395924756,2091215383,1878366691,2644384480,3553878443,565732008,854102364,3229815391,340358836,3861050807,4117890627,119113024,1493875044,2875275879,3090270611,1247431312,2660249211,1828433272,2141937292,2378227087,3811616794,291187481,34330861,4032846830,615137029,3603020806,3314634738,939183345,1776939221,2609017814,2295496738,2058945313,2926798794,1545135305,1330124605,3173225534,4084100981,17165430,307568514,3762199681,888469610,3332340585,3587147933,665062302,2042050490,2346497209,2559330125,1793573966,3190661285,1279665062,1595330642,2910671697]),ue=()=>{let e=Array(8);for(let t=0;t<8;t++){let n=Array(512);for(let e=0;e<256;e++){let r=BigInt(e);for(let e=0;e<8*(t+1);e++)r&1n?r=r>>1n^11127430586519243189n:r>>=1n;n[e*2]=Number(r>>32n&4294967295n),n[e*2+1]=Number(r&4294967295n)}e[t]=new Uint32Array(n)}return e},de,q,fe,pe,me,he,ge,_e,ve,ye=()=>{de||(de=ue(),[q,fe,pe,me,he,ge,_e,ve]=de)},be=class{c1=0;c2=0;constructor(){ye(),this.reset()}update(e){let t=e.length,n=0,r=this.c1,i=this.c2;for(;n+8<=t;){let t=((i^e[n++])&255)<<1,a=((i>>>8^e[n++])&255)<<1,o=((i>>>16^e[n++])&255)<<1,s=((i>>>24^e[n++])&255)<<1,c=((r^e[n++])&255)<<1,l=((r>>>8^e[n++])&255)<<1,u=((r>>>16^e[n++])&255)<<1,d=((r>>>24^e[n++])&255)<<1;r=ve[t]^_e[a]^ge[o]^he[s]^me[c]^pe[l]^fe[u]^q[d],i=ve[t+1]^_e[a+1]^ge[o+1]^he[s+1]^me[c+1]^pe[l+1]^fe[u+1]^q[d+1]}for(;n>>8|(r&255)<<24)>>>0,r=r>>>8^q[t],i^=q[t+1],n++}this.c1=r,this.c2=i}async digest(){let e=this.c1^4294967295,t=this.c2^4294967295;return new Uint8Array([e>>>24,e>>>16&255,e>>>8&255,e&255,t>>>24,t>>>16&255,t>>>8&255,t&255])}reset(){this.c1=4294967295,this.c2=4294967295}},xe={CrtCrc64Nvme:null},Se=()=>_,Ce=[P.CRC32,P.CRC32C,P.CRC64NVME,P.SHA1,P.SHA256],we=[P.SHA256,P.SHA1,P.CRC32,P.CRC32C,P.CRC64NVME],Te=(e,t)=>{let{checksumAlgorithms:n={}}=t;switch(e){case P.MD5:return n?.MD5??t.md5;case P.CRC32:return n?.CRC32??Se();case P.CRC32C:return n?.CRC32C??se;case P.CRC64NVME:return typeof xe.CrtCrc64Nvme==`function`?n?.CRC64NVME??xe.CrtCrc64Nvme:n?.CRC64NVME??be;case P.SHA1:return n?.SHA1??t.sha1;case P.SHA256:return n?.SHA256??t.sha256;default:if(n?.[e])return n[e];throw Error(`The checksum algorithm "${e}" is not supported by the client. Select one of ${Ce}, or provide an implementation to the client constructor checksums field.`)}},Ee=(e,t)=>{let n=new e;return n.update(m(t||``)),n.digest()},De={name:`flexibleChecksumsMiddleware`,step:`build`,tags:[`BODY_CHECKSUM`],override:!0},Oe=(e,r)=>(i,a)=>async o=>{if(!t.isInstance(o.request)||ae(`x-amz-checksum-`,o.request.headers))return i(o);let{request:s,input:c}=o,{body:l,headers:d}=s,{base64Encoder:f,streamHasher:p}=e,{requestChecksumRequired:m,requestAlgorithmMember:h}=r,g=await e.requestChecksumCalculation(),_=h?.name,v=h?.httpHeader;_&&!c[_]&&(g===n.WHEN_SUPPORTED||m)&&(c[_]=u,v&&(d[v]=u));let y=G(c,{requestChecksumRequired:m,requestAlgorithmMember:h?.name,requestChecksumCalculation:g}),b=l,x=d;if(y){switch(y){case P.CRC32:I(a,`FLEXIBLE_CHECKSUMS_REQ_CRC32`,`U`);break;case P.CRC32C:I(a,`FLEXIBLE_CHECKSUMS_REQ_CRC32C`,`V`);break;case P.CRC64NVME:I(a,`FLEXIBLE_CHECKSUMS_REQ_CRC64`,`W`);break;case P.SHA1:I(a,`FLEXIBLE_CHECKSUMS_REQ_SHA1`,`X`);break;case P.SHA256:I(a,`FLEXIBLE_CHECKSUMS_REQ_SHA256`,`Y`);break}let t=K(y),n=Te(y,e);if(oe(l)){let{getAwsChunkedEncodingStream:r,bodyLengthChecker:i}=e;b=r(typeof e.requestStreamBufferSize==`number`&&e.requestStreamBufferSize>=8*1024?B(l,e.requestStreamBufferSize,a.logger):l,{base64Encoder:f,bodyLengthChecker:i,checksumLocationName:t,checksumAlgorithmFn:n,streamHasher:p}),x={...d,"content-encoding":d[`content-encoding`]?`${d[`content-encoding`]},aws-chunked`:`aws-chunked`,"transfer-encoding":`chunked`,"x-amz-decoded-content-length":d[`content-length`],"x-amz-content-sha256":`STREAMING-UNSIGNED-PAYLOAD-TRAILER`,"x-amz-trailer":t},delete x[`content-length`]}else if(!ie(t,d)){let e=await Ee(n,l);x={...d,[t]:f(e)}}}try{return await i({...o,request:{...s,headers:x,body:b}})}catch(e){if(e instanceof Error&&e.name===`InvalidChunkSizeError`)try{e.message.endsWith(`.`)||(e.message+=`.`),e.message+=` Set [requestStreamBufferSize=number e.g. 65_536] in client constructor to instruct AWS SDK to buffer your input stream.`}catch{}throw e}},ke={name:`flexibleChecksumsInputMiddleware`,toMiddleware:`serializerMiddleware`,relation:`before`,tags:[`BODY_CHECKSUM`],override:!0},Ae=(e,t)=>(r,i)=>async a=>{let o=a.input,{requestValidationModeMember:s}=t,c=await e.requestChecksumCalculation(),l=await e.responseChecksumValidation();switch(c){case n.WHEN_REQUIRED:I(i,`FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED`,`a`);break;case n.WHEN_SUPPORTED:I(i,`FLEXIBLE_CHECKSUMS_REQ_WHEN_SUPPORTED`,`Z`);break}switch(l){case N.WHEN_REQUIRED:I(i,`FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED`,`c`);break;case N.WHEN_SUPPORTED:I(i,`FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED`,`b`);break}return s&&!o[s]&&l===N.WHEN_SUPPORTED&&(o[s]=`ENABLED`),r(a)},je=(e=[])=>{let t=[],n=we.length;for(let r of e){let e=we.indexOf(r);e===-1?t[n++]=r:t[e]=r}return t.filter(Boolean)},Me=e=>{let t=e.lastIndexOf(`-`);if(t!==-1){let n=e.slice(t+1);if(!n.startsWith(`0`)){let e=parseInt(n,10);if(!isNaN(e)&&e>=1&&e<=1e4)return!0}}return!1},Ne=async(e,{checksumAlgorithmFn:t,base64Encoder:n})=>n(await Ee(t,e)),Pe=async(e,{config:t,responseAlgorithms:n,logger:r})=>{let i=je(n),{body:a,headers:o}=e;for(let n of i){let i=K(n),s=o[i];if(s){let o;try{o=Te(n,t)}catch(e){if(n===P.CRC64NVME){r?.warn(`Skipping ${P.CRC64NVME} checksum validation: ${e.message}`);continue}throw e}let{base64Encoder:c}=t;if(oe(a)){e.body=ne({expectedChecksum:s,checksumSourceLocation:i,checksum:new o,source:a,base64Encoder:c});return}let l=await Ne(a,{checksumAlgorithmFn:o,base64Encoder:c});if(l===s)break;throw Error(`Checksum mismatch: expected "${l}" but received "${s}" in response header "${i}".`)}}},Fe={name:`flexibleChecksumsResponseMiddleware`,toMiddleware:`deserializerMiddleware`,relation:`after`,tags:[`BODY_CHECKSUM`],override:!0},Ie=(e,n)=>(r,i)=>async a=>{if(!t.isInstance(a.request))return r(a);let o=a.input,s=await r(a),c=s.response,{requestValidationModeMember:l,responseAlgorithms:u}=n;if(l&&o[l]===`ENABLED`){let{clientName:t,commandName:n}=i,r=Object.keys(e.checksumAlgorithms??{}).filter(e=>{let t=K(e);return c.headers[t]!==void 0}),a=je([...u??[],...r]);if(t===`S3Client`&&n===`GetObjectCommand`&&a.every(e=>{let t=K(e),n=c.headers[t];return!n||Me(n)}))return s;await Pe(c,{config:e,responseAlgorithms:a,logger:i.logger})}return s},Le=(e,t)=>({applyToStack:n=>{n.add(Oe(e,t),De),n.addRelativeTo(Ae(e,t),ke),n.addRelativeTo(Ie(e,t),Fe)}}),Re=`content-length`,ze=`x-amz-decoded-content-length`;function Be(){return(e,n)=>async r=>{let{request:i}=r;if(t.isInstance(i)&&!(Re in i.headers)&&!(ze in i.headers)){let e=`Are you using a Stream of unknown length as the Body of a PutObject request? Consider using Upload instead from @aws-sdk/lib-storage.`;typeof n?.logger?.warn==`function`&&!(n.logger instanceof c)?n.logger.warn(e):console.warn(e)}return e({...r})}}var Ve={step:`finalizeRequest`,tags:[`CHECK_CONTENT_LENGTH_HEADER`],name:`getCheckContentLengthHeaderPlugin`,override:!0},He=e=>({applyToStack:e=>{e.add(Be(),Ve)}}),Ue=class extends r.classBuilder().ep({...M,Bucket:{type:`contextParams`,name:`Bucket`},Key:{type:`contextParams`,name:`Key`}}).m(function(e,t,n,r){return[i(n,e.getEndpointParameterInstructions()),F(n)]}).s(`AmazonS3`,`AbortMultipartUpload`,{}).n(`S3Client`,`AbortMultipartUploadCommand`).sc(T).build(){};function We(e){return t=>async n=>{let r={...n.input};for(let t of[{target:`SSECustomerKey`,hash:`SSECustomerKeyMD5`},{target:`CopySourceSSECustomerKey`,hash:`CopySourceSSECustomerKeyMD5`}]){let n=r[t.target];if(n){let i;typeof n==`string`?Ke(n,e)?i=e.base64Decoder(n):(i=e.utf8Decoder(n),r[t.target]=e.base64Encoder(i)):(i=ArrayBuffer.isView(n)?new Uint8Array(n.buffer,n.byteOffset,n.byteLength):new Uint8Array(n),r[t.target]=e.base64Encoder(i));let a=new e.md5;a.update(i),r[t.hash]=e.base64Encoder(await a.digest())}}return t({...n,input:r})}}var Ge={name:`ssecMiddleware`,step:`initialize`,tags:[`SSE`],override:!0},J=e=>({applyToStack:t=>{t.add(We(e),Ge)}});function Ke(e,t){if(!/^(?:[A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(e))return!1;try{return t.base64Decoder(e).length===32}catch{return!1}}var qe=class extends r.classBuilder().ep({...M,Bucket:{type:`contextParams`,name:`Bucket`},Key:{type:`contextParams`,name:`Key`}}).m(function(e,t,n,r){return[i(n,e.getEndpointParameterInstructions()),F(n),J(n)]}).s(`AmazonS3`,`CompleteMultipartUpload`,{}).n(`S3Client`,`CompleteMultipartUploadCommand`).sc(te).build(){};function Je(e){return t=>async n=>{let{CreateBucketConfiguration:r}=n.input,i=await e.region();return!r?.LocationConstraint&&!r?.Location&&i!==`us-east-1`&&(n.input.CreateBucketConfiguration=n.input.CreateBucketConfiguration??{},n.input.CreateBucketConfiguration.LocationConstraint=i),t(n)}}var Ye={step:`initialize`,tags:[`LOCATION_CONSTRAINT`,`CREATE_BUCKET_CONFIGURATION`],name:`locationConstraintMiddleware`,override:!0},Xe=e=>({applyToStack:t=>{t.add(Je(e),Ye)}}),Ze=class extends r.classBuilder().ep({...M,UseS3ExpressControlEndpoint:{type:`staticContextParams`,value:!0},DisableAccessPoints:{type:`staticContextParams`,value:!0},Bucket:{type:`contextParams`,name:`Bucket`}}).m(function(e,t,n,r){return[i(n,e.getEndpointParameterInstructions()),F(n),Xe(n)]}).s(`AmazonS3`,`CreateBucket`,{}).n(`S3Client`,`CreateBucketCommand`).sc(y).build(){},Qe=class extends r.classBuilder().ep({...M,Bucket:{type:`contextParams`,name:`Bucket`},Key:{type:`contextParams`,name:`Key`}}).m(function(e,t,n,r){return[i(n,e.getEndpointParameterInstructions()),F(n),J(n)]}).s(`AmazonS3`,`CreateMultipartUpload`,{}).n(`S3Client`,`CreateMultipartUploadCommand`).sc(x).build(){},$e=class extends r.classBuilder().ep({...M,Bucket:{type:`contextParams`,name:`Bucket`},Key:{type:`contextParams`,name:`Key`}}).m(function(e,t,n,r){return[i(n,e.getEndpointParameterInstructions()),F(n)]}).s(`AmazonS3`,`DeleteObject`,{}).n(`S3Client`,`DeleteObjectCommand`).sc(ee).build(){},et=class extends r.classBuilder().ep({...M,Bucket:{type:`contextParams`,name:`Bucket`},Key:{type:`contextParams`,name:`Key`}}).m(function(e,t,n,r){return[i(n,e.getEndpointParameterInstructions()),Le(n,{requestAlgorithmMember:{httpHeader:`x-amz-sdk-checksum-algorithm`,name:`ChecksumAlgorithm`},requestChecksumRequired:!1}),He(n),F(n),J(n)]}).s(`AmazonS3`,`PutObject`,{}).n(`S3Client`,`PutObjectCommand`).sc(C).build(){},tt=class extends r.classBuilder().ep({...M,Bucket:{type:`contextParams`,name:`Bucket`}}).m(function(e,t,n,r){return[i(n,e.getEndpointParameterInstructions()),Le(n,{requestAlgorithmMember:{httpHeader:`x-amz-sdk-checksum-algorithm`,name:`ChecksumAlgorithm`},requestChecksumRequired:!0}),F(n)]}).s(`AmazonS3`,`PutObjectTagging`,{}).n(`S3Client`,`PutObjectTaggingCommand`).sc(S).build(){},nt=class extends r.classBuilder().ep({...M,Bucket:{type:`contextParams`,name:`Bucket`},Key:{type:`contextParams`,name:`Key`}}).m(function(e,t,n,r){return[i(n,e.getEndpointParameterInstructions()),Le(n,{requestAlgorithmMember:{httpHeader:`x-amz-sdk-checksum-algorithm`,name:`ChecksumAlgorithm`},requestChecksumRequired:!1}),F(n),J(n)]}).s(`AmazonS3`,`UploadPart`,{}).n(`S3Client`,`UploadPartCommand`).sc(h).build(){},rt={CRC32:`CRC32`,CRC32C:`CRC32C`,CRC64NVME:`CRC64NVME`,MD5:`MD5`,SHA1:`SHA1`,SHA256:`SHA256`,SHA512:`SHA512`,XXHASH128:`XXHASH128`,XXHASH3:`XXHASH3`,XXHASH64:`XXHASH64`},it=s(((e,t)=>{var n=typeof Reflect==`object`?Reflect:null,r=n&&typeof n.apply==`function`?n.apply:function(e,t,n){return Function.prototype.apply.call(e,t,n)},i=n&&typeof n.ownKeys==`function`?n.ownKeys:Object.getOwnPropertySymbols?function(e){return Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e))}:function(e){return Object.getOwnPropertyNames(e)};function a(e){console&&console.warn&&console.warn(e)}var o=Number.isNaN||function(e){return e!==e};function s(){s.init.call(this)}t.exports=s,t.exports.once=y,s.EventEmitter=s,s.prototype._events=void 0,s.prototype._eventsCount=0,s.prototype._maxListeners=void 0;var c=10;function l(e){if(typeof e!=`function`)throw TypeError(`The "listener" argument must be of type Function. Received type `+typeof e)}Object.defineProperty(s,`defaultMaxListeners`,{enumerable:!0,get:function(){return c},set:function(e){if(typeof e!=`number`||e<0||o(e))throw RangeError(`The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received `+e+`.`);c=e}}),s.init=function(){(this._events===void 0||this._events===Object.getPrototypeOf(this)._events)&&(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0},s.prototype.setMaxListeners=function(e){if(typeof e!=`number`||e<0||o(e))throw RangeError(`The value of "n" is out of range. It must be a non-negative number. Received `+e+`.`);return this._maxListeners=e,this};function u(e){return e._maxListeners===void 0?s.defaultMaxListeners:e._maxListeners}s.prototype.getMaxListeners=function(){return u(this)},s.prototype.emit=function(e){for(var t=[],n=1;n0&&(o=t[0]),o instanceof Error)throw o;var s=Error(`Unhandled error.`+(o?` (`+o.message+`)`:``));throw s.context=o,s}var c=a[e];if(c===void 0)return!1;if(typeof c==`function`)r(c,this,t);else for(var l=c.length,u=g(c,l),n=0;n0&&s.length>i&&!s.warned){s.warned=!0;var c=Error(`Possible EventEmitter memory leak detected. `+s.length+` `+String(t)+` listeners added. Use emitter.setMaxListeners() to increase limit`);c.name=`MaxListenersExceededWarning`,c.emitter=e,c.type=t,c.count=s.length,a(c)}return e}s.prototype.addListener=function(e,t){return d(this,e,t,!1)},s.prototype.on=s.prototype.addListener,s.prototype.prependListener=function(e,t){return d(this,e,t,!0)};function f(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,arguments.length===0?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function p(e,t,n){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},i=f.bind(r);return i.listener=n,r.wrapFn=i,i}s.prototype.once=function(e,t){return l(t),this.on(e,p(this,e,t)),this},s.prototype.prependOnceListener=function(e,t){return l(t),this.prependListener(e,p(this,e,t)),this},s.prototype.removeListener=function(e,t){var n,r,i,a,o;if(l(t),r=this._events,r===void 0||(n=r[e],n===void 0))return this;if(n===t||n.listener===t)--this._eventsCount===0?this._events=Object.create(null):(delete r[e],r.removeListener&&this.emit(`removeListener`,e,n.listener||t));else if(typeof n!=`function`){for(i=-1,a=n.length-1;a>=0;a--)if(n[a]===t||n[a].listener===t){o=n[a].listener,i=a;break}if(i<0)return this;i===0?n.shift():_(n,i),n.length===1&&(r[e]=n[0]),r.removeListener!==void 0&&this.emit(`removeListener`,e,o||t)}return this},s.prototype.off=s.prototype.removeListener,s.prototype.removeAllListeners=function(e){var t,n=this._events,r;if(n===void 0)return this;if(n.removeListener===void 0)return arguments.length===0?(this._events=Object.create(null),this._eventsCount=0):n[e]!==void 0&&(--this._eventsCount===0?this._events=Object.create(null):delete n[e]),this;if(arguments.length===0){var i=Object.keys(n),a;for(r=0;r=0;r--)this.removeListener(e,t[r]);return this};function m(e,t,n){var r=e._events;if(r===void 0)return[];var i=r[t];return i===void 0?[]:typeof i==`function`?n?[i.listener||i]:[i]:n?v(i):g(i,i.length)}s.prototype.listeners=function(e){return m(this,e,!0)},s.prototype.rawListeners=function(e){return m(this,e,!1)},s.listenerCount=function(e,t){return typeof e.listenerCount==`function`?e.listenerCount(t):h.call(e,t)},s.prototype.listenerCount=h;function h(e){var t=this._events;if(t!==void 0){var n=t[e];if(typeof n==`function`)return 1;if(n!==void 0)return n.length}return 0}s.prototype.eventNames=function(){return this._eventsCount>0?i(this._events):[]};function g(e,t){for(var n=Array(t),r=0;r{e.byteLength=c,e.toByteArray=u,e.fromByteArray=p;for(var t=[],n=[],r=typeof Uint8Array<`u`?Uint8Array:Array,i=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`,a=0,o=i.length;a0)throw Error(`Invalid string. Length must be a multiple of 4`);var n=e.indexOf(`=`);n===-1&&(n=t);var r=n===t?0:4-n%4;return[n,r]}function c(e){var t=s(e),n=t[0],r=t[1];return(n+r)*3/4-r}function l(e,t,n){return(t+n)*3/4-n}function u(e){var t,i=s(e),a=i[0],o=i[1],c=new r(l(e,a,o)),u=0,d=o>0?a-4:a,f;for(f=0;f>16&255,c[u++]=t>>8&255,c[u++]=t&255;return o===2&&(t=n[e.charCodeAt(f)]<<2|n[e.charCodeAt(f+1)]>>4,c[u++]=t&255),o===1&&(t=n[e.charCodeAt(f)]<<10|n[e.charCodeAt(f+1)]<<4|n[e.charCodeAt(f+2)]>>2,c[u++]=t>>8&255,c[u++]=t&255),c}function d(e){return t[e>>18&63]+t[e>>12&63]+t[e>>6&63]+t[e&63]}function f(e,t,n){for(var r,i=[],a=t;ac?c:s+o));return i===1?(n=e[r-1],a.push(t[n>>2]+t[n<<4&63]+`==`)):i===2&&(n=(e[r-2]<<8)+e[r-1],a.push(t[n>>10]+t[n>>4&63]+t[n<<2&63]+`=`)),a.join(``)}})),ot=s((e=>{e.read=function(e,t,n,r,i){var a,o,s=i*8-r-1,c=(1<>1,u=-7,d=n?i-1:0,f=n?-1:1,p=e[t+d];for(d+=f,a=p&(1<<-u)-1,p>>=-u,u+=s;u>0;a=a*256+e[t+d],d+=f,u-=8);for(o=a&(1<<-u)-1,a>>=-u,u+=r;u>0;o=o*256+e[t+d],d+=f,u-=8);if(a===0)a=1-l;else if(a===c)return o?NaN:(p?-1:1)*(1/0);else o+=2**r,a-=l;return(p?-1:1)*o*2**(a-r)},e.write=function(e,t,n,r,i,a){var o,s,c,l=a*8-i-1,u=(1<>1,f=i===23?2**-24-2**-77:0,p=r?0:a-1,m=r?1:-1,h=+(t<0||t===0&&1/t<0);for(t=Math.abs(t),isNaN(t)||t===1/0?(s=+!!isNaN(t),o=u):(o=Math.floor(Math.log(t)/Math.LN2),t*(c=2**-o)<1&&(o--,c*=2),o+d>=1?t+=f/c:t+=f*2**(1-d),t*c>=2&&(o++,c/=2),o+d>=u?(s=0,o=u):o+d>=1?(s=(t*c-1)*2**i,o+=d):(s=t*2**(d-1)*2**i,o=0));i>=8;e[n+p]=s&255,p+=m,s/=256,i-=8);for(o=o<0;e[n+p]=o&255,p+=m,o/=256,l-=8);e[n+p-m]|=h*128}})),st=s((e=>{var t=at(),n=ot(),r=typeof Symbol==`function`&&typeof Symbol.for==`function`?Symbol.for(`nodejs.util.inspect.custom`):null;e.Buffer=s,e.SlowBuffer=_,e.INSPECT_MAX_BYTES=50;var i=2147483647;e.kMaxLength=i,s.TYPED_ARRAY_SUPPORT=a(),!s.TYPED_ARRAY_SUPPORT&&typeof console<`u`&&typeof console.error==`function`&&console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support.");function a(){try{var e=new Uint8Array(1),t={foo:function(){return 42}};return Object.setPrototypeOf(t,Uint8Array.prototype),Object.setPrototypeOf(e,t),e.foo()===42}catch{return!1}}Object.defineProperty(s.prototype,`parent`,{enumerable:!0,get:function(){if(s.isBuffer(this))return this.buffer}}),Object.defineProperty(s.prototype,`offset`,{enumerable:!0,get:function(){if(s.isBuffer(this))return this.byteOffset}});function o(e){if(e>i)throw RangeError(`The value "`+e+`" is invalid for option "size"`);var t=new Uint8Array(e);return Object.setPrototypeOf(t,s.prototype),t}function s(e,t,n){if(typeof e==`number`){if(typeof t==`string`)throw TypeError(`The "string" argument must be of type string. Received type number`);return d(e)}return c(e,t,n)}s.poolSize=8192;function c(e,t,n){if(typeof e==`string`)return f(e,t);if(ArrayBuffer.isView(e))return p(e);if(e==null)throw TypeError(`The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type `+typeof e);if(G(e,ArrayBuffer)||e&&G(e.buffer,ArrayBuffer)||typeof SharedArrayBuffer<`u`&&(G(e,SharedArrayBuffer)||e&&G(e.buffer,SharedArrayBuffer)))return m(e,t,n);if(typeof e==`number`)throw TypeError(`The "value" argument must not be of type number. Received type number`);var r=e.valueOf&&e.valueOf();if(r!=null&&r!==e)return s.from(r,t,n);var i=h(e);if(i)return i;if(typeof Symbol<`u`&&Symbol.toPrimitive!=null&&typeof e[Symbol.toPrimitive]==`function`)return s.from(e[Symbol.toPrimitive](`string`),t,n);throw TypeError(`The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type `+typeof e)}s.from=function(e,t,n){return c(e,t,n)},Object.setPrototypeOf(s.prototype,Uint8Array.prototype),Object.setPrototypeOf(s,Uint8Array);function l(e){if(typeof e!=`number`)throw TypeError(`"size" argument must be of type number`);if(e<0)throw RangeError(`The value "`+e+`" is invalid for option "size"`)}function u(e,t,n){return l(e),e<=0||t===void 0?o(e):typeof n==`string`?o(e).fill(t,n):o(e).fill(t)}s.alloc=function(e,t,n){return u(e,t,n)};function d(e){return l(e),o(e<0?0:g(e)|0)}s.allocUnsafe=function(e){return d(e)},s.allocUnsafeSlow=function(e){return d(e)};function f(e,t){if((typeof t!=`string`||t===``)&&(t=`utf8`),!s.isEncoding(t))throw TypeError(`Unknown encoding: `+t);var n=v(e,t)|0,r=o(n),i=r.write(e,t);return i!==n&&(r=r.slice(0,i)),r}function p(e){for(var t=e.length<0?0:g(e.length)|0,n=o(t),r=0;r=i)throw RangeError(`Attempt to allocate Buffer larger than maximum size: 0x`+i.toString(16)+` bytes`);return e|0}function _(e){return+e!=e&&(e=0),s.alloc(+e)}s.isBuffer=function(e){return e!=null&&e._isBuffer===!0&&e!==s.prototype},s.compare=function(e,t){if(G(e,Uint8Array)&&(e=s.from(e,e.offset,e.byteLength)),G(t,Uint8Array)&&(t=s.from(t,t.offset,t.byteLength)),!s.isBuffer(e)||!s.isBuffer(t))throw TypeError(`The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array`);if(e===t)return 0;for(var n=e.length,r=t.length,i=0,a=Math.min(n,r);i2&&arguments[2]===!0;if(!r&&n===0)return 0;for(var i=!1;;)switch(t){case`ascii`:case`latin1`:case`binary`:return n;case`utf8`:case`utf-8`:return B(e).length;case`ucs2`:case`ucs-2`:case`utf16le`:case`utf-16le`:return n*2;case`hex`:return n>>>1;case`base64`:return U(e).length;default:if(i)return r?-1:B(e).length;t=(``+t).toLowerCase(),i=!0}}s.byteLength=v;function y(e,t,n){var r=!1;if((t===void 0||t<0)&&(t=0),t>this.length||((n===void 0||n>this.length)&&(n=this.length),n<=0)||(n>>>=0,t>>>=0,n<=t))return``;for(e||=`utf8`;;)switch(e){case`hex`:return N(this,t,n);case`utf8`:case`utf-8`:return k(this,t,n);case`ascii`:return te(this,t,n);case`latin1`:case`binary`:return M(this,t,n);case`base64`:return ee(this,t,n);case`ucs2`:case`ucs-2`:case`utf16le`:case`utf-16le`:return P(this,t,n);default:if(r)throw TypeError(`Unknown encoding: `+e);e=(e+``).toLowerCase(),r=!0}}s.prototype._isBuffer=!0;function b(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}s.prototype.swap16=function(){var e=this.length;if(e%2!=0)throw RangeError(`Buffer size must be a multiple of 16-bits`);for(var t=0;tn&&(t+=` ... `),``},r&&(s.prototype[r]=s.prototype.inspect),s.prototype.compare=function(e,t,n,r,i){if(G(e,Uint8Array)&&(e=s.from(e,e.offset,e.byteLength)),!s.isBuffer(e))throw TypeError(`The "target" argument must be one of type Buffer or Uint8Array. Received type `+typeof e);if(t===void 0&&(t=0),n===void 0&&(n=e?e.length:0),r===void 0&&(r=0),i===void 0&&(i=this.length),t<0||n>e.length||r<0||i>this.length)throw RangeError(`out of range index`);if(r>=i&&t>=n)return 0;if(r>=i)return-1;if(t>=n)return 1;if(t>>>=0,n>>>=0,r>>>=0,i>>>=0,this===e)return 0;for(var a=i-r,o=n-t,c=Math.min(a,o),l=this.slice(r,i),u=e.slice(t,n),d=0;d2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,K(n)&&(n=i?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(i)return-1;n=e.length-1}else if(n<0)if(i)n=0;else return-1;if(typeof t==`string`&&(t=s.from(t,r)),s.isBuffer(t))return t.length===0?-1:S(e,t,n,r,i);if(typeof t==`number`)return t&=255,typeof Uint8Array.prototype.indexOf==`function`?i?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):S(e,[t],n,r,i);throw TypeError(`val must be string, number or Buffer`)}function S(e,t,n,r,i){var a=1,o=e.length,s=t.length;if(r!==void 0&&(r=String(r).toLowerCase(),r===`ucs2`||r===`ucs-2`||r===`utf16le`||r===`utf-16le`)){if(e.length<2||t.length<2)return-1;a=2,o/=2,s/=2,n/=2}function c(e,t){return a===1?e[t]:e.readUInt16BE(t*a)}var l;if(i){var u=-1;for(l=n;lo&&(n=o-s),l=n;l>=0;l--){for(var d=!0,f=0;fi&&(r=i)):r=i;var a=t.length;r>a/2&&(r=a/2);for(var o=0;o>>=0,isFinite(n)?(n>>>=0,r===void 0&&(r=`utf8`)):(r=n,n=void 0);else throw Error(`Buffer.write(string, encoding, offset[, length]) is no longer supported`);var i=this.length-t;if((n===void 0||n>i)&&(n=i),e.length>0&&(n<0||t<0)||t>this.length)throw RangeError(`Attempt to write outside buffer bounds`);r||=`utf8`;for(var a=!1;;)switch(r){case`hex`:return C(this,e,t,n);case`utf8`:case`utf-8`:return w(this,e,t,n);case`ascii`:return T(this,e,t,n);case`latin1`:case`binary`:return E(this,e,t,n);case`base64`:return D(this,e,t,n);case`ucs2`:case`ucs-2`:case`utf16le`:case`utf-16le`:return O(this,e,t,n);default:if(a)throw TypeError(`Unknown encoding: `+r);r=(``+r).toLowerCase(),a=!0}},s.prototype.toJSON=function(){return{type:`Buffer`,data:Array.prototype.slice.call(this._arr||this,0)}};function ee(e,n,r){return n===0&&r===e.length?t.fromByteArray(e):t.fromByteArray(e.slice(n,r))}function k(e,t,n){n=Math.min(e.length,n);for(var r=[],i=t;i239?4:a>223?3:a>191?2:1;if(i+s<=n){var c,l,u,d;switch(s){case 1:a<128&&(o=a);break;case 2:c=e[i+1],(c&192)==128&&(d=(a&31)<<6|c&63,d>127&&(o=d));break;case 3:c=e[i+1],l=e[i+2],(c&192)==128&&(l&192)==128&&(d=(a&15)<<12|(c&63)<<6|l&63,d>2047&&(d<55296||d>57343)&&(o=d));break;case 4:c=e[i+1],l=e[i+2],u=e[i+3],(c&192)==128&&(l&192)==128&&(u&192)==128&&(d=(a&15)<<18|(c&63)<<12|(l&63)<<6|u&63,d>65535&&d<1114112&&(o=d))}}o===null?(o=65533,s=1):o>65535&&(o-=65536,r.push(o>>>10&1023|55296),o=56320|o&1023),r.push(o),i+=s}return j(r)}var A=4096;function j(e){var t=e.length;if(t<=A)return String.fromCharCode.apply(String,e);for(var n=``,r=0;rr)&&(n=r);for(var i=``,a=t;an&&(e=n),t<0?(t+=n,t<0&&(t=0)):t>n&&(t=n),tn)throw RangeError(`Trying to access beyond buffer length`)}s.prototype.readUIntLE=function(e,t,n){e>>>=0,t>>>=0,n||F(e,t,this.length);for(var r=this[e],i=1,a=0;++a>>=0,t>>>=0,n||F(e,t,this.length);for(var r=this[e+--t],i=1;t>0&&(i*=256);)r+=this[e+--t]*i;return r},s.prototype.readUInt8=function(e,t){return e>>>=0,t||F(e,1,this.length),this[e]},s.prototype.readUInt16LE=function(e,t){return e>>>=0,t||F(e,2,this.length),this[e]|this[e+1]<<8},s.prototype.readUInt16BE=function(e,t){return e>>>=0,t||F(e,2,this.length),this[e]<<8|this[e+1]},s.prototype.readUInt32LE=function(e,t){return e>>>=0,t||F(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+this[e+3]*16777216},s.prototype.readUInt32BE=function(e,t){return e>>>=0,t||F(e,4,this.length),this[e]*16777216+(this[e+1]<<16|this[e+2]<<8|this[e+3])},s.prototype.readIntLE=function(e,t,n){e>>>=0,t>>>=0,n||F(e,t,this.length);for(var r=this[e],i=1,a=0;++a=i&&(r-=2**(8*t)),r},s.prototype.readIntBE=function(e,t,n){e>>>=0,t>>>=0,n||F(e,t,this.length);for(var r=t,i=1,a=this[e+--r];r>0&&(i*=256);)a+=this[e+--r]*i;return i*=128,a>=i&&(a-=2**(8*t)),a},s.prototype.readInt8=function(e,t){return e>>>=0,t||F(e,1,this.length),this[e]&128?(255-this[e]+1)*-1:this[e]},s.prototype.readInt16LE=function(e,t){e>>>=0,t||F(e,2,this.length);var n=this[e]|this[e+1]<<8;return n&32768?n|4294901760:n},s.prototype.readInt16BE=function(e,t){e>>>=0,t||F(e,2,this.length);var n=this[e+1]|this[e]<<8;return n&32768?n|4294901760:n},s.prototype.readInt32LE=function(e,t){return e>>>=0,t||F(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},s.prototype.readInt32BE=function(e,t){return e>>>=0,t||F(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},s.prototype.readFloatLE=function(e,t){return e>>>=0,t||F(e,4,this.length),n.read(this,e,!0,23,4)},s.prototype.readFloatBE=function(e,t){return e>>>=0,t||F(e,4,this.length),n.read(this,e,!1,23,4)},s.prototype.readDoubleLE=function(e,t){return e>>>=0,t||F(e,8,this.length),n.read(this,e,!0,52,8)},s.prototype.readDoubleBE=function(e,t){return e>>>=0,t||F(e,8,this.length),n.read(this,e,!1,52,8)};function I(e,t,n,r,i,a){if(!s.isBuffer(e))throw TypeError(`"buffer" argument must be a Buffer instance`);if(t>i||te.length)throw RangeError(`Index out of range`)}s.prototype.writeUIntLE=function(e,t,n,r){if(e=+e,t>>>=0,n>>>=0,!r){var i=2**(8*n)-1;I(this,e,t,n,i,0)}var a=1,o=0;for(this[t]=e&255;++o>>=0,n>>>=0,!r){var i=2**(8*n)-1;I(this,e,t,n,i,0)}var a=n-1,o=1;for(this[t+a]=e&255;--a>=0&&(o*=256);)this[t+a]=e/o&255;return t+n},s.prototype.writeUInt8=function(e,t,n){return e=+e,t>>>=0,n||I(this,e,t,1,255,0),this[t]=e&255,t+1},s.prototype.writeUInt16LE=function(e,t,n){return e=+e,t>>>=0,n||I(this,e,t,2,65535,0),this[t]=e&255,this[t+1]=e>>>8,t+2},s.prototype.writeUInt16BE=function(e,t,n){return e=+e,t>>>=0,n||I(this,e,t,2,65535,0),this[t]=e>>>8,this[t+1]=e&255,t+2},s.prototype.writeUInt32LE=function(e,t,n){return e=+e,t>>>=0,n||I(this,e,t,4,4294967295,0),this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=e&255,t+4},s.prototype.writeUInt32BE=function(e,t,n){return e=+e,t>>>=0,n||I(this,e,t,4,4294967295,0),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=e&255,t+4},s.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t>>>=0,!r){var i=2**(8*n-1);I(this,e,t,n,i-1,-i)}var a=0,o=1,s=0;for(this[t]=e&255;++a>0)-s&255;return t+n},s.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t>>>=0,!r){var i=2**(8*n-1);I(this,e,t,n,i-1,-i)}var a=n-1,o=1,s=0;for(this[t+a]=e&255;--a>=0&&(o*=256);)e<0&&s===0&&this[t+a+1]!==0&&(s=1),this[t+a]=(e/o>>0)-s&255;return t+n},s.prototype.writeInt8=function(e,t,n){return e=+e,t>>>=0,n||I(this,e,t,1,127,-128),e<0&&(e=255+e+1),this[t]=e&255,t+1},s.prototype.writeInt16LE=function(e,t,n){return e=+e,t>>>=0,n||I(this,e,t,2,32767,-32768),this[t]=e&255,this[t+1]=e>>>8,t+2},s.prototype.writeInt16BE=function(e,t,n){return e=+e,t>>>=0,n||I(this,e,t,2,32767,-32768),this[t]=e>>>8,this[t+1]=e&255,t+2},s.prototype.writeInt32LE=function(e,t,n){return e=+e,t>>>=0,n||I(this,e,t,4,2147483647,-2147483648),this[t]=e&255,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24,t+4},s.prototype.writeInt32BE=function(e,t,n){return e=+e,t>>>=0,n||I(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=e&255,t+4};function L(e,t,n,r,i,a){if(n+r>e.length||n<0)throw RangeError(`Index out of range`)}function R(e,t,r,i,a){return t=+t,r>>>=0,a||L(e,t,r,4,34028234663852886e22,-34028234663852886e22),n.write(e,t,r,i,23,4),r+4}s.prototype.writeFloatLE=function(e,t,n){return R(this,e,t,!0,n)},s.prototype.writeFloatBE=function(e,t,n){return R(this,e,t,!1,n)};function ne(e,t,r,i,a){return t=+t,r>>>=0,a||L(e,t,r,8,17976931348623157e292,-17976931348623157e292),n.write(e,t,r,i,52,8),r+8}s.prototype.writeDoubleLE=function(e,t,n){return ne(this,e,t,!0,n)},s.prototype.writeDoubleBE=function(e,t,n){return ne(this,e,t,!1,n)},s.prototype.copy=function(e,t,n,r){if(!s.isBuffer(e))throw TypeError(`argument should be a Buffer`);if(n||=0,!r&&r!==0&&(r=this.length),t>=e.length&&(t=e.length),t||=0,r>0&&r=this.length)throw RangeError(`Index out of range`);if(r<0)throw RangeError(`sourceEnd out of bounds`);r>this.length&&(r=this.length),e.length-t=0;--a)e[a+t]=this[a+n];else Uint8Array.prototype.set.call(e,this.subarray(n,r),t);return i},s.prototype.fill=function(e,t,n,r){if(typeof e==`string`){if(typeof t==`string`?(r=t,t=0,n=this.length):typeof n==`string`&&(r=n,n=this.length),r!==void 0&&typeof r!=`string`)throw TypeError(`encoding must be a string`);if(typeof r==`string`&&!s.isEncoding(r))throw TypeError(`Unknown encoding: `+r);if(e.length===1){var i=e.charCodeAt(0);(r===`utf8`&&i<128||r===`latin1`)&&(e=i)}}else typeof e==`number`?e&=255:typeof e==`boolean`&&(e=Number(e));if(t<0||this.length>>=0,n=n===void 0?this.length:n>>>0,e||=0;var a;if(typeof e==`number`)for(a=t;a55295&&n<57344){if(!i){if(n>56319){(t-=3)>-1&&a.push(239,191,189);continue}else if(o+1===r){(t-=3)>-1&&a.push(239,191,189);continue}i=n;continue}if(n<56320){(t-=3)>-1&&a.push(239,191,189),i=n;continue}n=(i-55296<<10|n-56320)+65536}else i&&(t-=3)>-1&&a.push(239,191,189);if(i=null,n<128){if(--t<0)break;a.push(n)}else if(n<2048){if((t-=2)<0)break;a.push(n>>6|192,n&63|128)}else if(n<65536){if((t-=3)<0)break;a.push(n>>12|224,n>>6&63|128,n&63|128)}else if(n<1114112){if((t-=4)<0)break;a.push(n>>18|240,n>>12&63|128,n>>6&63|128,n&63|128)}else throw Error(`Invalid code point`)}return a}function V(e){for(var t=[],n=0;n>8,i=n%256,a.push(i),a.push(r);return a}function U(e){return t.toByteArray(z(e))}function W(e,t,n,r){for(var i=0;i=t.length||i>=e.length);++i)t[i+n]=e[i];return i}function G(e,t){return e instanceof t||e!=null&&e.constructor!=null&&e.constructor.name!=null&&e.constructor.name===t.name}function K(e){return e!==e}var ie=(function(){for(var e=`0123456789abcdef`,t=Array(256),n=0;n<16;++n)for(var r=n*16,i=0;i<16;++i)t[r+i]=e[n]+e[i];return t})()})),ct=A(),lt=it(),Y=st(),ut={lstatSync:()=>{},isFileReadStream(e){return!1},runtime:`browser`},dt=e=>{if(e==null)return 0;if(typeof e==`string`)return Y.Buffer.byteLength(e);if(typeof e.byteLength==`number`)return e.byteLength;if(typeof e.length==`number`)return e.length;if(typeof e.size==`number`)return e.size;if(typeof e.start==`number`&&typeof e.end==`number`)return e.end+1-e.start;if(ut.isFileReadStream(e))try{return ut.lstatSync(e.path).size}catch{return}},X;(function(e){e.EMPTY_INPUT=`a null or undefined Body`,e.CONTENT_LENGTH=`the ContentLength property of the params set by the caller`,e.STRING_LENGTH=`the encoded byte length of the Body string`,e.TYPED_ARRAY=`the byteLength of a typed byte array such as Uint8Array`,e.LENGTH=`the value of Body.length`,e.SIZE=`the value of Body.size`,e.START_END_DIFF=`the numeric difference between Body.start and Body.end`,e.LSTAT=`the size of the file given by Body.path on disk as reported by lstatSync`})(X||={});var ft=(e,t)=>{if(t!=null)return X.CONTENT_LENGTH;if(e==null)return X.EMPTY_INPUT;if(typeof e==`string`)return X.STRING_LENGTH;if(typeof e.byteLength==`number`)return X.TYPED_ARRAY;if(typeof e.length==`number`)return X.LENGTH;if(typeof e.size==`number`)return X.SIZE;if(typeof e.start==`number`&&typeof e.end==`number`)return X.START_END_DIFF;if(ut.isFileReadStream(e))try{return ut.lstatSync(e.path).size,X.LSTAT}catch{return}},Z=s(((e,t)=>{typeof Object.create==`function`?t.exports=function(e,t){t&&(e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:t.exports=function(e,t){if(t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}}})),pt=s(((e,t)=>{t.exports=it().EventEmitter})),mt=s(((e,t)=>{t.exports={}})),ht=s(((e,t)=>{function n(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function r(e){for(var t=1;t0?this.tail.next=t:this.head=t,this.tail=t,++this.length}},{key:`unshift`,value:function(e){var t={data:e,next:this.head};this.length===0&&(this.tail=t),this.head=t,++this.length}},{key:`shift`,value:function(){if(this.length!==0){var e=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,e}}},{key:`clear`,value:function(){this.head=this.tail=null,this.length=0}},{key:`join`,value:function(e){if(this.length===0)return``;for(var t=this.head,n=``+t.data;t=t.next;)n+=e+t.data;return n}},{key:`concat`,value:function(e){if(this.length===0)return u.alloc(0);for(var t=u.allocUnsafe(e>>>0),n=this.head,r=0;n;)p(n.data,t,r),r+=n.data.length,n=n.next;return t}},{key:`consume`,value:function(e,t){var n;return ei.length?i.length:e;if(a===i.length?r+=i:r+=i.slice(0,e),e-=a,e===0){a===i.length?(++n,t.next?this.head=t.next:this.head=this.tail=null):(this.head=t,t.data=i.slice(a));break}++n}return this.length-=n,r}},{key:`_getBuffer`,value:function(e){var t=u.allocUnsafe(e),n=this.head,r=1;for(n.data.copy(t),e-=n.data.length;n=n.next;){var i=n.data,a=e>i.length?i.length:e;if(i.copy(t,t.length-e,0,a),e-=a,e===0){a===i.length?(++r,n.next?this.head=n.next:this.head=this.tail=null):(this.head=n,n.data=i.slice(a));break}++r}return this.length-=r,t}},{key:f,value:function(e,t){return d(this,r(r({},t),{},{depth:0,customInspect:!1}))}}]),e}()})),gt=s(((e,t)=>{function n(e,t){var n=this,a=this._readableState&&this._readableState.destroyed,s=this._writableState&&this._writableState.destroyed;return a||s?(t?t(e):e&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,process.nextTick(o,this,e)):process.nextTick(o,this,e)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(e||null,function(e){!t&&e?n._writableState?n._writableState.errorEmitted?process.nextTick(i,n):(n._writableState.errorEmitted=!0,process.nextTick(r,n,e)):process.nextTick(r,n,e):t?(process.nextTick(i,n),t(e)):process.nextTick(i,n)}),this)}function r(e,t){o(e,t),i(e)}function i(e){e._writableState&&!e._writableState.emitClose||e._readableState&&!e._readableState.emitClose||e.emit(`close`)}function a(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function o(e,t){e.emit(`error`,t)}function s(e,t){var n=e._readableState,r=e._writableState;n&&n.autoDestroy||r&&r.autoDestroy?e.destroy(t):e.emit(`error`,t)}t.exports={destroy:n,undestroy:a,errorOrDestroy:s}})),Q=s(((e,t)=>{function n(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}var r={};function i(e,t,i){i||=Error;function a(e,n,r){return typeof t==`string`?t:t(e,n,r)}var o=function(e){n(t,e);function t(t,n,r){return e.call(this,a(t,n,r))||this}return t}(i);o.prototype.name=i.name,o.prototype.code=e,r[e]=o}function a(e,t){if(Array.isArray(e)){var n=e.length;return e=e.map(function(e){return String(e)}),n>2?`one of ${t} ${e.slice(0,n-1).join(`, `)}, or `+e[n-1]:n===2?`one of ${t} ${e[0]} or ${e[1]}`:`of ${t} ${e[0]}`}else return`of ${t} ${String(e)}`}function o(e,t,n){return e.substr(!n||n<0?0:+n,t.length)===t}function s(e,t,n){return(n===void 0||n>e.length)&&(n=e.length),e.substring(n-t.length,n)===t}function c(e,t,n){return typeof n!=`number`&&(n=0),n+t.length>e.length?!1:e.indexOf(t,n)!==-1}i(`ERR_INVALID_OPT_VALUE`,function(e,t){return`The value "`+t+`" is invalid for option "`+e+`"`},TypeError),i(`ERR_INVALID_ARG_TYPE`,function(e,t,n){var r;typeof t==`string`&&o(t,`not `)?(r=`must not be`,t=t.replace(/^not /,``)):r=`must be`;var i=s(e,` argument`)?`The ${e} ${r} ${a(t,`type`)}`:`The "${e}" ${c(e,`.`)?`property`:`argument`} ${r} ${a(t,`type`)}`;return i+=`. Received type ${typeof n}`,i},TypeError),i(`ERR_STREAM_PUSH_AFTER_EOF`,`stream.push() after EOF`),i(`ERR_METHOD_NOT_IMPLEMENTED`,function(e){return`The `+e+` method is not implemented`}),i(`ERR_STREAM_PREMATURE_CLOSE`,`Premature close`),i(`ERR_STREAM_DESTROYED`,function(e){return`Cannot call `+e+` after a stream was destroyed`}),i(`ERR_MULTIPLE_CALLBACK`,`Callback called multiple times`),i(`ERR_STREAM_CANNOT_PIPE`,`Cannot pipe, not readable`),i(`ERR_STREAM_WRITE_AFTER_END`,`write after end`),i(`ERR_STREAM_NULL_VALUES`,`May not write null values to stream`,TypeError),i(`ERR_UNKNOWN_ENCODING`,function(e){return`Unknown encoding: `+e},TypeError),i(`ERR_STREAM_UNSHIFT_AFTER_END_EVENT`,`stream.unshift() after end event`),t.exports.codes=r})),_t=s(((e,t)=>{var n=Q().codes.ERR_INVALID_OPT_VALUE;function r(e,t,n){return e.highWaterMark==null?t?e[n]:null:e.highWaterMark}function i(e,t,i,a){var o=r(t,a,i);if(o!=null){if(!(isFinite(o)&&Math.floor(o)===o)||o<0)throw new n(a?i:`highWaterMark`,o);return Math.floor(o)}return e.objectMode?16:16*1024}t.exports={getHighWaterMark:i}})),vt=s(((e,t)=>{t.exports=n;function n(e,t){if(r(`noDeprecation`))return e;var n=!1;function i(){if(!n){if(r(`throwDeprecation`))throw Error(t);r(`traceDeprecation`)?console.trace(t):console.warn(t),n=!0}return e.apply(this,arguments)}return i}function r(e){try{if(!global.localStorage)return!1}catch{return!1}var t=global.localStorage[e];return t==null?!1:String(t).toLowerCase()===`true`}})),yt=s(((e,t)=>{t.exports=T;function n(e){var t=this;this.next=null,this.entry=null,this.finish=function(){re(t,e)}}var r;T.WritableState=C;var i={deprecate:vt()},a=pt(),o=st().Buffer,s=(typeof global<`u`?global:typeof window<`u`?window:typeof self<`u`?self:{}).Uint8Array||function(){};function c(e){return o.from(e)}function l(e){return o.isBuffer(e)||e instanceof s}var u=gt(),d=_t().getHighWaterMark,f=Q().codes,p=f.ERR_INVALID_ARG_TYPE,m=f.ERR_METHOD_NOT_IMPLEMENTED,h=f.ERR_MULTIPLE_CALLBACK,g=f.ERR_STREAM_CANNOT_PIPE,_=f.ERR_STREAM_DESTROYED,v=f.ERR_STREAM_NULL_VALUES,y=f.ERR_STREAM_WRITE_AFTER_END,b=f.ERR_UNKNOWN_ENCODING,x=u.errorOrDestroy;Z()(T,a);function S(){}function C(e,t,i){r||=$(),e||={},typeof i!=`boolean`&&(i=t instanceof r),this.objectMode=!!e.objectMode,i&&(this.objectMode=this.objectMode||!!e.writableObjectMode),this.highWaterMark=d(this,e,`writableHighWaterMark`,i),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var a=e.decodeStrings===!1;this.decodeStrings=!a,this.defaultEncoding=e.defaultEncoding||`utf8`,this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(e){te(t,e)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.emitClose=e.emitClose!==!1,this.autoDestroy=!!e.autoDestroy,this.bufferedRequestCount=0,this.corkedRequestsFree=new n(this)}C.prototype.getBuffer=function(){for(var e=this.bufferedRequest,t=[];e;)t.push(e),e=e.next;return t},(function(){try{Object.defineProperty(C.prototype,`buffer`,{get:i.deprecate(function(){return this.getBuffer()},`_writableState.buffer is deprecated. Use _writableState.getBuffer instead.`,`DEP0003`)})}catch{}})();var w;typeof Symbol==`function`&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]==`function`?(w=Function.prototype[Symbol.hasInstance],Object.defineProperty(T,Symbol.hasInstance,{value:function(e){return w.call(this,e)?!0:this===T?e&&e._writableState instanceof C:!1}})):w=function(e){return e instanceof this};function T(e){r||=$();var t=this instanceof r;if(!t&&!w.call(T,this))return new T(e);this._writableState=new C(e,this,t),this.writable=!0,e&&(typeof e.write==`function`&&(this._write=e.write),typeof e.writev==`function`&&(this._writev=e.writev),typeof e.destroy==`function`&&(this._destroy=e.destroy),typeof e.final==`function`&&(this._final=e.final)),a.call(this)}T.prototype.pipe=function(){x(this,new g)};function E(e,t){var n=new y;x(e,n),process.nextTick(t,n)}function D(e,t,n,r){var i;return n===null?i=new v:typeof n!=`string`&&!t.objectMode&&(i=new p(`chunk`,[`string`,`Buffer`],n)),i?(x(e,i),process.nextTick(r,i),!1):!0}T.prototype.write=function(e,t,n){var r=this._writableState,i=!1,a=!r.objectMode&&l(e);return a&&!o.isBuffer(e)&&(e=c(e)),typeof t==`function`&&(n=t,t=null),a?t=`buffer`:t||=r.defaultEncoding,typeof n!=`function`&&(n=S),r.ending?E(this,n):(a||D(this,r,e,n))&&(r.pendingcb++,i=ee(this,r,a,e,t,n)),i},T.prototype.cork=function(){this._writableState.corked++},T.prototype.uncork=function(){var e=this._writableState;e.corked&&(e.corked--,!e.writing&&!e.corked&&!e.bufferProcessing&&e.bufferedRequest&&P(this,e))},T.prototype.setDefaultEncoding=function(e){if(typeof e==`string`&&(e=e.toLowerCase()),!([`hex`,`utf8`,`utf-8`,`ascii`,`binary`,`base64`,`ucs2`,`ucs-2`,`utf16le`,`utf-16le`,`raw`].indexOf((e+``).toLowerCase())>-1))throw new b(e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(T.prototype,`writableBuffer`,{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});function O(e,t,n){return!e.objectMode&&e.decodeStrings!==!1&&typeof t==`string`&&(t=o.from(t,n)),t}Object.defineProperty(T.prototype,`writableHighWaterMark`,{enumerable:!1,get:function(){return this._writableState.highWaterMark}});function ee(e,t,n,r,i,a){if(!n){var o=O(t,r,i);r!==o&&(n=!0,i=`buffer`,r=o)}var s=t.objectMode?1:r.length;t.length+=s;var c=t.length{var n=Object.keys||function(e){var t=[];for(var n in e)t.push(n);return t};t.exports=c;var r=Tt(),i=yt();Z()(c,r);for(var a=n(i.prototype),o=0;o{var n=st(),r=n.Buffer;function i(e,t){for(var n in e)t[n]=e[n]}r.from&&r.alloc&&r.allocUnsafe&&r.allocUnsafeSlow?t.exports=n:(i(n,e),e.Buffer=a);function a(e,t,n){return r(e,t,n)}a.prototype=Object.create(r.prototype),i(r,a),a.from=function(e,t,n){if(typeof e==`number`)throw TypeError(`Argument must not be a number`);return r(e,t,n)},a.alloc=function(e,t,n){if(typeof e!=`number`)throw TypeError(`Argument must be a number`);var i=r(e);return t===void 0?i.fill(0):typeof n==`string`?i.fill(t,n):i.fill(t),i},a.allocUnsafe=function(e){if(typeof e!=`number`)throw TypeError(`Argument must be a number`);return r(e)},a.allocUnsafeSlow=function(e){if(typeof e!=`number`)throw TypeError(`Argument must be a number`);return n.SlowBuffer(e)}})),xt=s((e=>{var t=bt().Buffer,n=t.isEncoding||function(e){switch(e=``+e,e&&e.toLowerCase()){case`hex`:case`utf8`:case`utf-8`:case`ascii`:case`binary`:case`base64`:case`ucs2`:case`ucs-2`:case`utf16le`:case`utf-16le`:case`raw`:return!0;default:return!1}};function r(e){if(!e)return`utf8`;for(var t;;)switch(e){case`utf8`:case`utf-8`:return`utf8`;case`ucs2`:case`ucs-2`:case`utf16le`:case`utf-16le`:return`utf16le`;case`latin1`:case`binary`:return`latin1`;case`base64`:case`ascii`:case`hex`:return e;default:if(t)return;e=(``+e).toLowerCase(),t=!0}}function i(e){var i=r(e);if(typeof i!=`string`&&(t.isEncoding===n||!n(e)))throw Error(`Unknown encoding: `+e);return i||e}e.StringDecoder=a;function a(e){this.encoding=i(e);var n;switch(this.encoding){case`utf16le`:this.text=f,this.end=p,n=4;break;case`utf8`:this.fillLast=l,n=4;break;case`base64`:this.text=m,this.end=h,n=3;break;default:this.write=g,this.end=_;return}this.lastNeed=0,this.lastTotal=0,this.lastChar=t.allocUnsafe(n)}a.prototype.write=function(e){if(e.length===0)return``;var t,n;if(this.lastNeed){if(t=this.fillLast(e),t===void 0)return``;n=this.lastNeed,this.lastNeed=0}else n=0;return n>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function s(e,t,n){var r=t.length-1;if(r=0?(i>0&&(e.lastNeed=i-1),i):--r=0?(i>0&&(e.lastNeed=i-2),i):--r=0?(i>0&&(i===2?i=0:e.lastNeed=i-3),i):0))}function c(e,t,n){if((t[0]&192)!=128)return e.lastNeed=0,`�`;if(e.lastNeed>1&&t.length>1){if((t[1]&192)!=128)return e.lastNeed=1,`�`;if(e.lastNeed>2&&t.length>2&&(t[2]&192)!=128)return e.lastNeed=2,`�`}}function l(e){var t=this.lastTotal-this.lastNeed,n=c(this,e,t);if(n!==void 0)return n;if(this.lastNeed<=e.length)return e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);e.copy(this.lastChar,t,0,e.length),this.lastNeed-=e.length}function u(e,t){var n=s(this,e,t);if(!this.lastNeed)return e.toString(`utf8`,t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString(`utf8`,t,r)}function d(e){var t=e&&e.length?this.write(e):``;return this.lastNeed?t+`�`:t}function f(e,t){if((e.length-t)%2==0){var n=e.toString(`utf16le`,t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString(`utf16le`,t,e.length-1)}function p(e){var t=e&&e.length?this.write(e):``;if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString(`utf16le`,0,n)}return t}function m(e,t){var n=(e.length-t)%3;return n===0?e.toString(`base64`,t):(this.lastNeed=3-n,this.lastTotal=3,n===1?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString(`base64`,t,e.length-n))}function h(e){var t=e&&e.length?this.write(e):``;return this.lastNeed?t+this.lastChar.toString(`base64`,0,3-this.lastNeed):t}function g(e){return e.toString(this.encoding)}function _(e){return e&&e.length?this.write(e):``}})),St=s(((e,t)=>{var n=Q().codes.ERR_STREAM_PREMATURE_CLOSE;function r(e){var t=!1;return function(){if(!t){t=!0;var n=[...arguments];e.apply(this,n)}}}function i(){}function a(e){return e.setHeader&&typeof e.abort==`function`}function o(e,t,s){if(typeof t==`function`)return o(e,null,t);t||={},s=r(s||i);var c=t.readable||t.readable!==!1&&e.readable,l=t.writable||t.writable!==!1&&e.writable,u=function(){e.writable||f()},d=e._writableState&&e._writableState.finished,f=function(){l=!1,d=!0,c||s.call(e)},p=e._readableState&&e._readableState.endEmitted,m=function(){c=!1,p=!0,l||s.call(e)},h=function(t){s.call(e,t)},g=function(){var t;if(c&&!p)return(!e._readableState||!e._readableState.ended)&&(t=new n),s.call(e,t);if(l&&!d)return(!e._writableState||!e._writableState.ended)&&(t=new n),s.call(e,t)},_=function(){e.req.on(`finish`,f)};return a(e)?(e.on(`complete`,f),e.on(`abort`,g),e.req?_():e.on(`request`,_)):l&&!e._writableState&&(e.on(`end`,u),e.on(`close`,u)),e.on(`end`,m),e.on(`finish`,f),t.error!==!1&&e.on(`error`,h),e.on(`close`,g),function(){e.removeListener(`complete`,f),e.removeListener(`abort`,g),e.removeListener(`request`,_),e.req&&e.req.removeListener(`finish`,f),e.removeListener(`end`,u),e.removeListener(`close`,u),e.removeListener(`finish`,f),e.removeListener(`end`,m),e.removeListener(`error`,h),e.removeListener(`close`,g)}}t.exports=o})),Ct=s(((e,t)=>{var n;function r(e,t,n){return t=i(t),t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e){var t=a(e,`string`);return typeof t==`symbol`?t:String(t)}function a(e,t){if(typeof e!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(typeof r!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}var o=St(),s=Symbol(`lastResolve`),c=Symbol(`lastReject`),l=Symbol(`error`),u=Symbol(`ended`),d=Symbol(`lastPromise`),f=Symbol(`handlePromise`),p=Symbol(`stream`);function m(e,t){return{value:e,done:t}}function h(e){var t=e[s];if(t!==null){var n=e[p].read();n!==null&&(e[d]=null,e[s]=null,e[c]=null,t(m(n,!1)))}}function g(e){process.nextTick(h,e)}function _(e,t){return function(n,r){e.then(function(){if(t[u]){n(m(void 0,!0));return}t[f](n,r)},r)}}var v=Object.getPrototypeOf(function(){}),y=Object.setPrototypeOf((n={get stream(){return this[p]},next:function(){var e=this,t=this[l];if(t!==null)return Promise.reject(t);if(this[u])return Promise.resolve(m(void 0,!0));if(this[p].destroyed)return new Promise(function(t,n){process.nextTick(function(){e[l]?n(e[l]):t(m(void 0,!0))})});var n=this[d],r;if(n)r=new Promise(_(n,this));else{var i=this[p].read();if(i!==null)return Promise.resolve(m(i,!1));r=new Promise(this[f])}return this[d]=r,r}},r(n,Symbol.asyncIterator,function(){return this}),r(n,`return`,function(){var e=this;return new Promise(function(t,n){e[p].destroy(null,function(e){if(e){n(e);return}t(m(void 0,!0))})})}),n),v);t.exports=function(e){var t,n=Object.create(y,(t={},r(t,p,{value:e,writable:!0}),r(t,s,{value:null,writable:!0}),r(t,c,{value:null,writable:!0}),r(t,l,{value:null,writable:!0}),r(t,u,{value:e._readableState.endEmitted,writable:!0}),r(t,f,{value:function(e,t){var r=n[p].read();r?(n[d]=null,n[s]=null,n[c]=null,e(m(r,!1))):(n[s]=e,n[c]=t)},writable:!0}),t));return n[d]=null,o(e,function(e){if(e&&e.code!==`ERR_STREAM_PREMATURE_CLOSE`){var t=n[c];t!==null&&(n[d]=null,n[s]=null,n[c]=null,t(e)),n[l]=e;return}var r=n[s];r!==null&&(n[d]=null,n[s]=null,n[c]=null,r(m(void 0,!0))),n[u]=!0}),e.on(`readable`,g.bind(null,n)),n}})),wt=s(((e,t)=>{t.exports=function(){throw Error(`Readable.from is not available in the browser`)}})),Tt=s(((e,t)=>{t.exports=E;var n;E.ReadableState=T,it().EventEmitter;var r=function(e,t){return e.listeners(t).length},i=pt(),a=st().Buffer,o=(typeof global<`u`?global:typeof window<`u`?window:typeof self<`u`?self:{}).Uint8Array||function(){};function s(e){return a.from(e)}function c(e){return a.isBuffer(e)||e instanceof o}var l=mt(),u=l&&l.debuglog?l.debuglog(`stream`):function(){},d=ht(),f=gt(),p=_t().getHighWaterMark,m=Q().codes,h=m.ERR_INVALID_ARG_TYPE,g=m.ERR_STREAM_PUSH_AFTER_EOF,_=m.ERR_METHOD_NOT_IMPLEMENTED,v=m.ERR_STREAM_UNSHIFT_AFTER_END_EVENT,y,b,x;Z()(E,i);var S=f.errorOrDestroy,C=[`error`,`close`,`destroy`,`pause`,`resume`];function w(e,t,n){if(typeof e.prependListener==`function`)return e.prependListener(t,n);!e._events||!e._events[t]?e.on(t,n):Array.isArray(e._events[t])?e._events[t].unshift(n):e._events[t]=[n,e._events[t]]}function T(e,t,r){n||=$(),e||={},typeof r!=`boolean`&&(r=t instanceof n),this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.readableObjectMode),this.highWaterMark=p(this,e,`readableHighWaterMark`,r),this.buffer=new d,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.paused=!0,this.emitClose=e.emitClose!==!1,this.autoDestroy=!!e.autoDestroy,this.destroyed=!1,this.defaultEncoding=e.defaultEncoding||`utf8`,this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(y||=xt().StringDecoder,this.decoder=new y(e.encoding),this.encoding=e.encoding)}function E(e){if(n||=$(),!(this instanceof E))return new E(e);var t=this instanceof n;this._readableState=new T(e,this,t),this.readable=!0,e&&(typeof e.read==`function`&&(this._read=e.read),typeof e.destroy==`function`&&(this._destroy=e.destroy)),i.call(this)}Object.defineProperty(E.prototype,`destroyed`,{enumerable:!1,get:function(){return this._readableState===void 0?!1:this._readableState.destroyed},set:function(e){this._readableState&&(this._readableState.destroyed=e)}}),E.prototype.destroy=f.destroy,E.prototype._undestroy=f.undestroy,E.prototype._destroy=function(e,t){t(e)},E.prototype.push=function(e,t){var n=this._readableState,r;return n.objectMode?r=!0:typeof e==`string`&&(t||=n.defaultEncoding,t!==n.encoding&&(e=a.from(e,t),t=``),r=!0),D(this,e,t,!1,r)},E.prototype.unshift=function(e){return D(this,e,null,!0,!1)};function D(e,t,n,r,i){u(`readableAddChunk`,t);var o=e._readableState;if(t===null)o.reading=!1,te(e,o);else{var c;if(i||(c=ee(o,t)),c)S(e,c);else if(o.objectMode||t&&t.length>0)if(typeof t!=`string`&&!o.objectMode&&Object.getPrototypeOf(t)!==a.prototype&&(t=s(t)),r)o.endEmitted?S(e,new v):O(e,o,t,!0);else if(o.ended)S(e,new g);else if(o.destroyed)return!1;else o.reading=!1,o.decoder&&!n?(t=o.decoder.write(t),o.objectMode||t.length!==0?O(e,o,t,!1):P(e,o)):O(e,o,t,!1);else r||(o.reading=!1,P(e,o))}return!o.ended&&(o.length=k?e=k:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}function j(e,t){return e<=0||t.length===0&&t.ended?0:t.objectMode?1:e===e?(e>t.highWaterMark&&(t.highWaterMark=A(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0)):t.flowing&&t.length?t.buffer.head.data.length:t.length}E.prototype.read=function(e){u(`read`,e),e=parseInt(e,10);var t=this._readableState,n=e;if(e!==0&&(t.emittedReadable=!1),e===0&&t.needReadable&&((t.highWaterMark===0?t.length>0:t.length>=t.highWaterMark)||t.ended))return u(`read: emitReadable`,t.length,t.ended),t.length===0&&t.ended?V(this):M(this),null;if(e=j(e,t),e===0&&t.ended)return t.length===0&&V(this),null;var r=t.needReadable;u(`need readable`,r),(t.length===0||t.length-e0?B(e,t):null;return i===null?(t.needReadable=t.length<=t.highWaterMark,e=0):(t.length-=e,t.awaitDrain=0),t.length===0&&(t.ended||(t.needReadable=!0),n!==e&&t.ended&&V(this)),i!==null&&this.emit(`data`,i),i};function te(e,t){if(u(`onEofChunk`),!t.ended){if(t.decoder){var n=t.decoder.end();n&&n.length&&(t.buffer.push(n),t.length+=t.objectMode?1:n.length)}t.ended=!0,t.sync?M(e):(t.needReadable=!1,t.emittedReadable||(t.emittedReadable=!0,N(e)))}}function M(e){var t=e._readableState;u(`emitReadable`,t.needReadable,t.emittedReadable),t.needReadable=!1,t.emittedReadable||(u(`emitReadable`,t.flowing),t.emittedReadable=!0,process.nextTick(N,e))}function N(e){var t=e._readableState;u(`emitReadable_`,t.destroyed,t.length,t.ended),!t.destroyed&&(t.length||t.ended)&&(e.emit(`readable`),t.emittedReadable=!1),t.needReadable=!t.flowing&&!t.ended&&t.length<=t.highWaterMark,z(e)}function P(e,t){t.readingMore||(t.readingMore=!0,process.nextTick(F,e,t))}function F(e,t){for(;!t.reading&&!t.ended&&(t.length1&&U(i.pipes,e)!==-1)&&!l&&(u(`false write response, pause`,i.awaitDrain),i.awaitDrain++),n.pause())}function p(t){u(`onerror`,t),g(),e.removeListener(`error`,p),r(e,`error`)===0&&S(e,t)}w(e,`error`,p);function m(){e.removeListener(`finish`,h),g()}e.once(`close`,m);function h(){u(`onfinish`),e.removeListener(`close`,m),g()}e.once(`finish`,h);function g(){u(`unpipe`),n.unpipe(e)}return e.emit(`pipe`,n),i.flowing||(u(`pipe resume`),n.resume()),e};function I(e){return function(){var t=e._readableState;u(`pipeOnDrain`,t.awaitDrain),t.awaitDrain&&t.awaitDrain--,t.awaitDrain===0&&r(e,`data`)&&(t.flowing=!0,z(e))}}E.prototype.unpipe=function(e){var t=this._readableState,n={hasUnpiped:!1};if(t.pipesCount===0)return this;if(t.pipesCount===1)return e&&e!==t.pipes?this:(e||=t.pipes,t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit(`unpipe`,this,n),this);if(!e){var r=t.pipes,i=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var a=0;a0,r.flowing!==!1&&this.resume()):e===`readable`&&!r.endEmitted&&!r.readableListening&&(r.readableListening=r.needReadable=!0,r.flowing=!1,r.emittedReadable=!1,u(`on readable`,r.length,r.reading),r.length?M(this):r.reading||process.nextTick(R,this)),n},E.prototype.addListener=E.prototype.on,E.prototype.removeListener=function(e,t){var n=i.prototype.removeListener.call(this,e,t);return e===`readable`&&process.nextTick(L,this),n},E.prototype.removeAllListeners=function(e){var t=i.prototype.removeAllListeners.apply(this,arguments);return(e===`readable`||e===void 0)&&process.nextTick(L,this),t};function L(e){var t=e._readableState;t.readableListening=e.listenerCount(`readable`)>0,t.resumeScheduled&&!t.paused?t.flowing=!0:e.listenerCount(`data`)>0&&e.resume()}function R(e){u(`readable nexttick read 0`),e.read(0)}E.prototype.resume=function(){var e=this._readableState;return e.flowing||(u(`resume`),e.flowing=!e.readableListening,ne(this,e)),e.paused=!1,this};function ne(e,t){t.resumeScheduled||(t.resumeScheduled=!0,process.nextTick(re,e,t))}function re(e,t){u(`resume`,t.reading),t.reading||e.read(0),t.resumeScheduled=!1,e.emit(`resume`),z(e),t.flowing&&!t.reading&&e.read(0)}E.prototype.pause=function(){return u(`call pause flowing=%j`,this._readableState.flowing),this._readableState.flowing!==!1&&(u(`pause`),this._readableState.flowing=!1,this.emit(`pause`)),this._readableState.paused=!0,this};function z(e){var t=e._readableState;for(u(`flow`,t.flowing);t.flowing&&e.read()!==null;);}E.prototype.wrap=function(e){var t=this,n=this._readableState,r=!1;for(var i in e.on(`end`,function(){if(u(`wrapped end`),n.decoder&&!n.ended){var e=n.decoder.end();e&&e.length&&t.push(e)}t.push(null)}),e.on(`data`,function(i){u(`wrapped data`),n.decoder&&(i=n.decoder.write(i)),!(n.objectMode&&i==null)&&(!n.objectMode&&(!i||!i.length)||t.push(i)||(r=!0,e.pause()))}),e)this[i]===void 0&&typeof e[i]==`function`&&(this[i]=function(t){return function(){return e[t].apply(e,arguments)}}(i));for(var a=0;a=t.length?(n=t.decoder?t.buffer.join(``):t.buffer.length===1?t.buffer.first():t.buffer.concat(t.length),t.buffer.clear()):n=t.buffer.consume(e,t.decoder),n}function V(e){var t=e._readableState;u(`endReadable`,t.endEmitted),t.endEmitted||(t.ended=!0,process.nextTick(H,t,e))}function H(e,t){if(u(`endReadableNT`,e.endEmitted,e.length),!e.endEmitted&&e.length===0&&(e.endEmitted=!0,t.readable=!1,t.emit(`end`),e.autoDestroy)){var n=t._writableState;(!n||n.autoDestroy&&n.finished)&&t.destroy()}}typeof Symbol==`function`&&(E.from=function(e,t){return x===void 0&&(x=wt()),x(E,e,t)});function U(e,t){for(var n=0,r=e.length;n{t.exports=l;var n=Q().codes,r=n.ERR_METHOD_NOT_IMPLEMENTED,i=n.ERR_MULTIPLE_CALLBACK,a=n.ERR_TRANSFORM_ALREADY_TRANSFORMING,o=n.ERR_TRANSFORM_WITH_LENGTH_0,s=$();Z()(l,s);function c(e,t){var n=this._transformState;n.transforming=!1;var r=n.writecb;if(r===null)return this.emit(`error`,new i);n.writechunk=null,n.writecb=null,t!=null&&this.push(t),r(e);var a=this._readableState;a.reading=!1,(a.needReadable||a.length{t.exports=r;var n=Et();Z()(r,n);function r(e){if(!(this instanceof r))return new r(e);n.call(this,e)}r.prototype._transform=function(e,t,n){n(null,e)}})),Ot=s(((e,t)=>{var n;function r(e){var t=!1;return function(){t||(t=!0,e.apply(void 0,arguments))}}var i=Q().codes,a=i.ERR_MISSING_ARGS,o=i.ERR_STREAM_DESTROYED;function s(e){if(e)throw e}function c(e){return e.setHeader&&typeof e.abort==`function`}function l(e,t,i,a){a=r(a);var s=!1;e.on(`close`,function(){s=!0}),n===void 0&&(n=St()),n(e,{readable:t,writable:i},function(e){if(e)return a(e);s=!0,a()});var l=!1;return function(t){if(!s&&!l){if(l=!0,c(e))return e.abort();if(typeof e.destroy==`function`)return e.destroy();a(t||new o(`pipe`))}}}function u(e){e()}function d(e,t){return e.pipe(t)}function f(e){return!e.length||typeof e[e.length-1]!=`function`?s:e.pop()}function p(){var e=[...arguments],t=f(e);if(Array.isArray(e[0])&&(e=e[0]),e.length<2)throw new a(`streams`);var n,r=e.map(function(i,a){var o=a0,function(e){n||=e,e&&r.forEach(u),!o&&(r.forEach(u),t(n))})});return e.reduce(d)}t.exports=p})),kt=s(((e,t)=>{t.exports=r;var n=it().EventEmitter;Z()(r,n),r.Readable=Tt(),r.Writable=yt(),r.Duplex=$(),r.Transform=Et(),r.PassThrough=Dt(),r.finished=St(),r.pipeline=Ot(),r.Stream=r;function r(){n.call(this)}r.prototype.pipe=function(e,t){var r=this;function i(t){e.writable&&!1===e.write(t)&&r.pause&&r.pause()}r.on(`data`,i);function a(){r.readable&&r.resume&&r.resume()}e.on(`drain`,a),!e._isStdio&&(!t||t.end!==!1)&&(r.on(`end`,s),r.on(`close`,c));var o=!1;function s(){o||(o=!0,e.end())}function c(){o||(o=!0,typeof e.destroy==`function`&&e.destroy())}function l(e){if(u(),n.listenerCount(this,`error`)===0)throw e}r.on(`error`,l),e.on(`error`,l);function u(){r.removeListener(`data`,i),e.removeListener(`drain`,a),r.removeListener(`end`,s),r.removeListener(`close`,c),r.removeListener(`error`,l),e.removeListener(`error`,l),r.removeListener(`end`,u),r.removeListener(`close`,u),e.removeListener(`close`,u)}return r.on(`end`,u),r.on(`close`,u),e.on(`close`,u),e.emit(`pipe`,r),e}}))();async function*At(e,t,n){let r=1,i={chunks:[],length:0};for await(let a of n(e))for(i.chunks.push(a),i.length+=a.byteLength;i.length>t;){let e=i.chunks.length>1?Y.Buffer.concat(i.chunks):i.chunks[0];yield{partNumber:r,data:e.subarray(0,t)},i.chunks=[e.subarray(t)],i.length=i.chunks[0].byteLength,r+=1}yield{partNumber:r,data:i.chunks.length===1?i.chunks[0]:Y.Buffer.concat(i.chunks),lastPart:!0}}async function*jt(e,t){let n=1,r=0,i=t;for(;i{if(e instanceof Uint8Array)return jt(e,t);if(e instanceof kt.Readable)return At(e,t,Mt);if(e instanceof String||typeof e==`string`)return jt(Y.Buffer.from(e),t);if(typeof e.stream==`function`)return At(e.stream(),t,Nt);if(e instanceof ReadableStream)return At(e,t,Nt);throw Error(`Body Data is unsupported format, expected data to be one of: string | Uint8Array | Buffer | Readable | ReadableStream | Blob;.`)},Ft=class e extends lt.EventEmitter{static MIN_PART_SIZE=1024*1024*5;MAX_PARTS=1e4;queueSize=4;partSize;leavePartsOnError=!1;tags=[];client;params;totalBytes;totalBytesSource;bytesUploadedSoFar;abortController;concurrentUploaders=[];createMultiPartPromise;abortMultipartUploadCommand=null;uploadedParts=[];uploadEnqueuedPartsCount=0;expectedPartsCount;uploadId;uploadEvent;isMultiPart=!0;singleUploadResult;sent=!1;constructor(t){if(super(),this.queueSize=t.queueSize||this.queueSize,this.leavePartsOnError=t.leavePartsOnError||this.leavePartsOnError,this.tags=t.tags||this.tags,this.client=t.client,this.params=t.params,!this.params)throw Error(`InputError: Upload requires params to be passed to upload.`);this.totalBytes=this.params.ContentLength??dt(this.params.Body),this.totalBytesSource=ft(this.params.Body,this.params.ContentLength),this.bytesUploadedSoFar=0,this.abortController=t.abortController??new AbortController,this.partSize=t.partSize||Math.max(e.MIN_PART_SIZE,Math.ceil((this.totalBytes||0)/this.MAX_PARTS)),this.totalBytes!==void 0&&(this.expectedPartsCount=Math.ceil(this.totalBytes/this.partSize)),this.__validateInput()}async abort(){this.abortController.abort()}async done(){if(this.sent)throw Error(`@aws-sdk/lib-storage: this instance of Upload has already executed .done(). Create a new instance.`);return this.sent=!0,await Promise.race([this.__doMultipartUpload(),this.__abortTimeout(this.abortController.signal)])}on(e,t){return this.uploadEvent=e,super.on(e,t)}async __uploadUsingPut(e){this.isMultiPart=!1;let t={...this.params,Body:e.data},n=this.client.config,r=n.requestHandler,i=r instanceof lt.EventEmitter?r:null,a=t=>{this.bytesUploadedSoFar=t.loaded,this.totalBytes=t.total,this.__notifyProgress({loaded:this.bytesUploadedSoFar,total:this.totalBytes,part:e.partNumber,Key:this.params.Key,Bucket:this.params.Bucket})};i!==null&&i.on(`xhr.upload.progress`,a);let s=await Promise.all([this.client.send(new et(t)),n?.endpoint?.()]),c=s[0],u=s[1];if(u||=l(await o(t,et,{...n})),!u)throw Error(`Could not resolve endpoint from S3 "client.config.endpoint()" nor EndpointsV2.`);i!==null&&i.off(`xhr.upload.progress`,a);let d=this.params.Key.split(`/`).map(e=>f(e)).join(`/`),p=f(this.params.Bucket),m=(()=>{let e=u.hostname.startsWith(`${p}.`),t=this.client.config.forcePathStyle,n=u.port?`:${u.port}`:``;return t?`${u.protocol}//${u.hostname}${n}/${p}/${d}`:e?`${u.protocol}//${u.hostname}${n}/${d}`:`${u.protocol}//${p}.${u.hostname}${n}/${d}`})();this.singleUploadResult={...c,Bucket:this.params.Bucket,Key:this.params.Key,Location:m};let h=dt(e.data);this.__notifyProgress({loaded:h,total:h,part:1,Key:this.params.Key,Bucket:this.params.Bucket})}async __createMultipartUpload(){let e=await this.client.config.requestChecksumCalculation();if(!this.createMultiPartPromise){let t={...this.params,Body:void 0};e===`WHEN_SUPPORTED`&&(t.ChecksumAlgorithm=this.params.ChecksumAlgorithm||rt.CRC32),this.createMultiPartPromise=this.client.send(new Qe(t)).then(e=>(this.abortMultipartUploadCommand=new Ue({Bucket:this.params.Bucket,Key:this.params.Key,UploadId:e.UploadId}),e))}return this.createMultiPartPromise}async __doConcurrentUpload(e){for await(let t of e){if(this.uploadEnqueuedPartsCount>this.MAX_PARTS)throw Error(`Exceeded ${this.MAX_PARTS} parts in multipart upload to Bucket: ${this.params.Bucket} Key: ${this.params.Key}.`);if(this.abortController.signal.aborted)return;if(t.partNumber===1&&t.lastPart)return await this.__uploadUsingPut(t);if(!this.uploadId){let{UploadId:e}=await this.__createMultipartUpload();if(this.uploadId=e,this.abortController.signal.aborted)return}let e=dt(t.data)||0,n=this.client.config.requestHandler,r=n instanceof lt.EventEmitter?n:null,i=0,a=(n,r)=>{(Number(r.query.partNumber)||-1)===t.partNumber&&(n.total&&e&&(this.bytesUploadedSoFar+=n.loaded-i,i=n.loaded),this.__notifyProgress({loaded:this.bytesUploadedSoFar,total:this.totalBytes,part:t.partNumber,Key:this.params.Key,Bucket:this.params.Bucket}))};r!==null&&r.on(`xhr.upload.progress`,a),this.uploadEnqueuedPartsCount+=1,this.__validateUploadPart(t);let o=await this.client.send(new nt({...this.params,ContentLength:void 0,UploadId:this.uploadId,Body:t.data,PartNumber:t.partNumber}));if(r!==null&&r.off(`xhr.upload.progress`,a),this.abortController.signal.aborted)return;if(!o.ETag)throw Error(`Part ${t.partNumber} is missing ETag in UploadPart response. Missing Bucket CORS configuration for ETag header?`);this.uploadedParts.push({PartNumber:t.partNumber,ETag:o.ETag,...o.ChecksumCRC32&&{ChecksumCRC32:o.ChecksumCRC32},...o.ChecksumCRC32C&&{ChecksumCRC32C:o.ChecksumCRC32C},...o.ChecksumSHA1&&{ChecksumSHA1:o.ChecksumSHA1},...o.ChecksumSHA256&&{ChecksumSHA256:o.ChecksumSHA256}}),r===null&&(this.bytesUploadedSoFar+=e),this.__notifyProgress({loaded:this.bytesUploadedSoFar,total:this.totalBytes,part:t.partNumber,Key:this.params.Key,Bucket:this.params.Bucket})}}async __doMultipartUpload(){let e=Pt(this.params.Body,this.partSize),t=[];for(let n=0;n{t.push(e)});this.concurrentUploaders.push(n)}if(await Promise.all(this.concurrentUploaders),t.length>=1)throw await this.markUploadAsAborted(),t[0];if(this.abortController.signal.aborted)throw await this.markUploadAsAborted(),Object.assign(Error(`Upload aborted.`),{name:`AbortError`});let n;if(this.isMultiPart){let{expectedPartsCount:e,uploadedParts:t,totalBytes:r,totalBytesSource:i}=this;if(r!==void 0&&e!==void 0&&t.length!==e)throw Error(`Expected ${e} part(s) but uploaded ${t.length} part(s). +import{n as e}from"./error-banner.js";import{Bn as t,Ct as n,Do as r,Et as i,Hn as a,Jn as o,Kn as s,St as c,Tt as l,Un as u,Vn as d,Wn as f,Yn as p,_r as m,_t as h,br as g,bt as _,cr as v,dt as y,ft as b,gr as x,hr as S,ht as C,mr as w,mt as T,pr as E,pt as D,qo as O,ur as ee,ut as k,vr as A,vt as j,wt as M,xo as N,xt as P,yr as F,yt as I,zn as L}from"./index.js";var R=typeof ReadableStream==`function`?ReadableStream:function(){},z=class extends R{},te=({expectedChecksum:e,checksum:t,source:n,checksumSourceLocation:r,base64Encoder:i})=>{if(!o(n))throw Error(`@smithy/util-stream: unsupported source type ${n?.constructor?.name??n} in ChecksumStream.`);let a=i??p;if(typeof TransformStream!=`function`)throw Error(`@smithy/util-stream: unable to instantiate ChecksumStream because API unavailable: ReadableStream/TransformStream.`);let s=new TransformStream({start(){},async transform(e,n){t.update(e),n.enqueue(e)},async flush(n){let i=a(await t.digest());if(e!==i){let t=Error(`Checksum mismatch: expected "${e}" but received "${i}" in response header "${r}".`);n.error(t)}else n.terminate()}});n.pipeThrough(s);let c=s.readable;return Object.setPrototypeOf(c,z.prototype),c},ne=class{allocByteArray;byteLength=0;byteArrays=[];constructor(e){this.allocByteArray=e}push(e){this.byteArrays.push(e),this.byteLength+=e.byteLength}flush(){if(this.byteArrays.length===1){let e=this.byteArrays[0];return this.reset(),e}let e=this.allocByteArray(this.byteLength),t=0;for(let n=0;nnew Uint8Array(e))],s=-1,c=async e=>{let{value:l,done:u}=await r.read(),d=l;if(u){if(s!==-1){let t=U(o,s);W(t)>0&&e.enqueue(t)}e.close()}else{let r=G(d,!1);if(s!==r&&(s>=0&&e.enqueue(U(o,s)),s=r),s===-1){e.enqueue(d);return}let l=W(d);a+=l;let u=W(o[s]);if(l>=t&&u===0)e.enqueue(d);else{let r=H(o,s,d);!i&&a>t*2&&(i=!0,n?.warn(`@smithy/util-stream - stream chunk size ${l} is below threshold of ${t}, automatically buffering.`)),r>=t?e.enqueue(U(o,s)):await c(e)}}};return new ReadableStream({pull:c})}var V=B;function H(e,t,n){switch(t){case 0:return e[0]+=n,W(e[0]);case 1:case 2:return e[t].push(n),W(e[t])}}function U(e,t){switch(t){case 0:let n=e[0];return e[0]=``,n;case 1:case 2:return e[t].flush()}throw Error(`@smithy/util-stream - invalid index ${t} given to flush()`)}function W(e){return e?.byteLength??e?.length??0}function G(e,t=!0){return t&&typeof Buffer<`u`&&e instanceof Buffer?2:e instanceof Uint8Array?1:typeof e==`string`?0:-1}var K=(e,{requestChecksumRequired:t,requestAlgorithmMember:n,requestChecksumCalculation:r})=>{if(!n)return r===l.WHEN_SUPPORTED||t?M:void 0;if(e[n])return e[n]},q=e=>e===n.MD5?`content-md5`:`x-amz-checksum-${e.toLowerCase()}`,re=(e,t)=>{let n=e.toLowerCase();for(let e of Object.keys(t))if(n===e.toLowerCase())return!0;return!1},ie=(e,t)=>{let n=e.toLowerCase();for(let e of Object.keys(t))if(e.toLowerCase().startsWith(n))return!0;return!1},ae=e=>e!==void 0&&typeof e!=`string`&&!ArrayBuffer.isView(e)&&!v(e),oe=function(){function e(){this.crc32c=new se}return e.prototype.update=function(e){F(e)||this.crc32c.update(g(e))},e.prototype.digest=function(){return w(this,void 0,void 0,function(){return S(this,function(e){return[2,A(this.crc32c.digest())]})})},e.prototype.reset=function(){this.crc32c=new se},e}(),se=function(){function e(){this.checksum=4294967295}return e.prototype.update=function(e){var t,n;try{for(var r=x(e),i=r.next();!i.done;i=r.next()){var a=i.value;this.checksum=this.checksum>>>8^ce[(this.checksum^a)&255]}}catch(e){t={error:e}}finally{try{i&&!i.done&&(n=r.return)&&n.call(r)}finally{if(t)throw t.error}}return this},e.prototype.digest=function(){return(this.checksum^4294967295)>>>0},e}(),ce=m([0,4067132163,3778769143,324072436,3348797215,904991772,648144872,3570033899,2329499855,2024987596,1809983544,2575936315,1296289744,3207089363,2893594407,1578318884,274646895,3795141740,4049975192,51262619,3619967088,632279923,922689671,3298075524,2592579488,1760304291,2075979607,2312596564,1562183871,2943781820,3156637768,1313733451,549293790,3537243613,3246849577,871202090,3878099393,357341890,102525238,4101499445,2858735121,1477399826,1264559846,3107202533,1845379342,2677391885,2361733625,2125378298,820201905,3263744690,3520608582,598981189,4151959214,85089709,373468761,3827903834,3124367742,1213305469,1526817161,2842354314,2107672161,2412447074,2627466902,1861252501,1098587580,3004210879,2688576843,1378610760,2262928035,1955203488,1742404180,2511436119,3416409459,969524848,714683780,3639785095,205050476,4266873199,3976438427,526918040,1361435347,2739821008,2954799652,1114974503,2529119692,1691668175,2005155131,2247081528,3690758684,697762079,986182379,3366744552,476452099,3993867776,4250756596,255256311,1640403810,2477592673,2164122517,1922457750,2791048317,1412925310,1197962378,3037525897,3944729517,427051182,170179418,4165941337,746937522,3740196785,3451792453,1070968646,1905808397,2213795598,2426610938,1657317369,3053634322,1147748369,1463399397,2773627110,4215344322,153784257,444234805,3893493558,1021025245,3467647198,3722505002,797665321,2197175160,1889384571,1674398607,2443626636,1164749927,3070701412,2757221520,1446797203,137323447,4198817972,3910406976,461344835,3484808360,1037989803,781091935,3705997148,2460548119,1623424788,1939049696,2180517859,1429367560,2807687179,3020495871,1180866812,410100952,3927582683,4182430767,186734380,3756733383,763408580,1053836080,3434856499,2722870694,1344288421,1131464017,2971354706,1708204729,2545590714,2229949006,1988219213,680717673,3673779818,3383336350,1002577565,4010310262,493091189,238226049,4233660802,2987750089,1082061258,1395524158,2705686845,1972364758,2279892693,2494862625,1725896226,952904198,3399985413,3656866545,731699698,4283874585,222117402,510512622,3959836397,3280807620,837199303,582374963,3504198960,68661723,4135334616,3844915500,390545967,1230274059,3141532936,2825850620,1510247935,2395924756,2091215383,1878366691,2644384480,3553878443,565732008,854102364,3229815391,340358836,3861050807,4117890627,119113024,1493875044,2875275879,3090270611,1247431312,2660249211,1828433272,2141937292,2378227087,3811616794,291187481,34330861,4032846830,615137029,3603020806,3314634738,939183345,1776939221,2609017814,2295496738,2058945313,2926798794,1545135305,1330124605,3173225534,4084100981,17165430,307568514,3762199681,888469610,3332340585,3587147933,665062302,2042050490,2346497209,2559330125,1793573966,3190661285,1279665062,1595330642,2910671697]),le=()=>{let e=Array(8);for(let t=0;t<8;t++){let n=Array(512);for(let e=0;e<256;e++){let r=BigInt(e);for(let e=0;e<8*(t+1);e++)r&1n?r=r>>1n^11127430586519243189n:r>>=1n;n[e*2]=Number(r>>32n&4294967295n),n[e*2+1]=Number(r&4294967295n)}e[t]=new Uint32Array(n)}return e},ue,J,de,fe,pe,me,he,ge,_e,ve=()=>{ue||(ue=le(),[J,de,fe,pe,me,he,ge,_e]=ue)},ye=class{c1=0;c2=0;constructor(){ve(),this.reset()}update(e){let t=e.length,n=0,r=this.c1,i=this.c2;for(;n+8<=t;){let t=((i^e[n++])&255)<<1,a=((i>>>8^e[n++])&255)<<1,o=((i>>>16^e[n++])&255)<<1,s=((i>>>24^e[n++])&255)<<1,c=((r^e[n++])&255)<<1,l=((r>>>8^e[n++])&255)<<1,u=((r>>>16^e[n++])&255)<<1,d=((r>>>24^e[n++])&255)<<1;r=_e[t]^ge[a]^he[o]^me[s]^pe[c]^fe[l]^de[u]^J[d],i=_e[t+1]^ge[a+1]^he[o+1]^me[s+1]^pe[c+1]^fe[l+1]^de[u+1]^J[d+1]}for(;n>>8|(r&255)<<24)>>>0,r=r>>>8^J[t],i^=J[t+1],n++}this.c1=r,this.c2=i}async digest(){let e=this.c1^4294967295,t=this.c2^4294967295;return new Uint8Array([e>>>24,e>>>16&255,e>>>8&255,e&255,t>>>24,t>>>16&255,t>>>8&255,t&255])}reset(){this.c1=4294967295,this.c2=4294967295}},be={CrtCrc64Nvme:null},xe=()=>c,Se=[n.CRC32,n.CRC32C,n.CRC64NVME,n.SHA1,n.SHA256],Ce=[n.SHA256,n.SHA1,n.CRC32,n.CRC32C,n.CRC64NVME],we=(e,t)=>{let{checksumAlgorithms:r={}}=t;switch(e){case n.MD5:return r?.MD5??t.md5;case n.CRC32:return r?.CRC32??xe();case n.CRC32C:return r?.CRC32C??oe;case n.CRC64NVME:return typeof be.CrtCrc64Nvme==`function`?r?.CRC64NVME??be.CrtCrc64Nvme:r?.CRC64NVME??ye;case n.SHA1:return r?.SHA1??t.sha1;case n.SHA256:return r?.SHA256??t.sha256;default:if(r?.[e])return r[e];throw Error(`The checksum algorithm "${e}" is not supported by the client. Select one of ${Se}, or provide an implementation to the client constructor checksums field.`)}},Te=(e,t)=>{let n=new e;return n.update(ee(t||``)),n.digest()},Ee={name:`flexibleChecksumsMiddleware`,step:`build`,tags:[`BODY_CHECKSUM`],override:!0},De=(e,t)=>(r,i)=>async a=>{if(!E.isInstance(a.request)||ie(`x-amz-checksum-`,a.request.headers))return r(a);let{request:o,input:s}=a,{body:c,headers:u}=o,{base64Encoder:d,streamHasher:p}=e,{requestChecksumRequired:m,requestAlgorithmMember:h}=t,g=await e.requestChecksumCalculation(),_=h?.name,v=h?.httpHeader;_&&!s[_]&&(g===l.WHEN_SUPPORTED||m)&&(s[_]=M,v&&(u[v]=M));let y=K(s,{requestChecksumRequired:m,requestAlgorithmMember:h?.name,requestChecksumCalculation:g}),b=c,x=u;if(y){switch(y){case n.CRC32:f(i,`FLEXIBLE_CHECKSUMS_REQ_CRC32`,`U`);break;case n.CRC32C:f(i,`FLEXIBLE_CHECKSUMS_REQ_CRC32C`,`V`);break;case n.CRC64NVME:f(i,`FLEXIBLE_CHECKSUMS_REQ_CRC64`,`W`);break;case n.SHA1:f(i,`FLEXIBLE_CHECKSUMS_REQ_SHA1`,`X`);break;case n.SHA256:f(i,`FLEXIBLE_CHECKSUMS_REQ_SHA256`,`Y`);break}let t=q(y),r=we(y,e);if(ae(c)){let{getAwsChunkedEncodingStream:n,bodyLengthChecker:a}=e;b=n(typeof e.requestStreamBufferSize==`number`&&e.requestStreamBufferSize>=8*1024?V(c,e.requestStreamBufferSize,i.logger):c,{base64Encoder:d,bodyLengthChecker:a,checksumLocationName:t,checksumAlgorithmFn:r,streamHasher:p}),x={...u,"content-encoding":u[`content-encoding`]?`${u[`content-encoding`]},aws-chunked`:`aws-chunked`,"transfer-encoding":`chunked`,"x-amz-decoded-content-length":u[`content-length`],"x-amz-content-sha256":`STREAMING-UNSIGNED-PAYLOAD-TRAILER`,"x-amz-trailer":t},delete x[`content-length`]}else if(!re(t,u)){let e=await Te(r,c);x={...u,[t]:d(e)}}}try{return await r({...a,request:{...o,headers:x,body:b}})}catch(e){if(e instanceof Error&&e.name===`InvalidChunkSizeError`)try{e.message.endsWith(`.`)||(e.message+=`.`),e.message+=` Set [requestStreamBufferSize=number e.g. 65_536] in client constructor to instruct AWS SDK to buffer your input stream.`}catch{}throw e}},Oe={name:`flexibleChecksumsInputMiddleware`,toMiddleware:`serializerMiddleware`,relation:`before`,tags:[`BODY_CHECKSUM`],override:!0},ke=(e,t)=>(n,r)=>async a=>{let o=a.input,{requestValidationModeMember:s}=t,c=await e.requestChecksumCalculation(),u=await e.responseChecksumValidation();switch(c){case l.WHEN_REQUIRED:f(r,`FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED`,`a`);break;case l.WHEN_SUPPORTED:f(r,`FLEXIBLE_CHECKSUMS_REQ_WHEN_SUPPORTED`,`Z`);break}switch(u){case i.WHEN_REQUIRED:f(r,`FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED`,`c`);break;case i.WHEN_SUPPORTED:f(r,`FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED`,`b`);break}return s&&!o[s]&&u===i.WHEN_SUPPORTED&&(o[s]=`ENABLED`),n(a)},Ae=(e=[])=>{let t=[],n=Ce.length;for(let r of e){let e=Ce.indexOf(r);e===-1?t[n++]=r:t[e]=r}return t.filter(Boolean)},je=e=>{let t=e.lastIndexOf(`-`);if(t!==-1){let n=e.slice(t+1);if(!n.startsWith(`0`)){let e=parseInt(n,10);if(!isNaN(e)&&e>=1&&e<=1e4)return!0}}return!1},Me=async(e,{checksumAlgorithmFn:t,base64Encoder:n})=>n(await Te(t,e)),Ne=async(e,{config:t,responseAlgorithms:r,logger:i})=>{let a=Ae(r),{body:o,headers:s}=e;for(let r of a){let a=q(r),c=s[a];if(c){let s;try{s=we(r,t)}catch(e){if(r===n.CRC64NVME){i?.warn(`Skipping ${n.CRC64NVME} checksum validation: ${e.message}`);continue}throw e}let{base64Encoder:l}=t;if(ae(o)){e.body=te({expectedChecksum:c,checksumSourceLocation:a,checksum:new s,source:o,base64Encoder:l});return}let u=await Me(o,{checksumAlgorithmFn:s,base64Encoder:l});if(u===c)break;throw Error(`Checksum mismatch: expected "${u}" but received "${c}" in response header "${a}".`)}}},Pe={name:`flexibleChecksumsResponseMiddleware`,toMiddleware:`deserializerMiddleware`,relation:`after`,tags:[`BODY_CHECKSUM`],override:!0},Fe=(e,t)=>(n,r)=>async i=>{if(!E.isInstance(i.request))return n(i);let a=i.input,o=await n(i),s=o.response,{requestValidationModeMember:c,responseAlgorithms:l}=t;if(c&&a[c]===`ENABLED`){let{clientName:t,commandName:n}=r,i=Object.keys(e.checksumAlgorithms??{}).filter(e=>{let t=q(e);return s.headers[t]!==void 0}),a=Ae([...l??[],...i]);if(t===`S3Client`&&n===`GetObjectCommand`&&a.every(e=>{let t=q(e),n=s.headers[t];return!n||je(n)}))return o;await Ne(s,{config:e,responseAlgorithms:a,logger:r.logger})}return o},Ie=(e,t)=>({applyToStack:n=>{n.add(De(e,t),Ee),n.addRelativeTo(ke(e,t),Oe),n.addRelativeTo(Fe(e,t),Pe)}}),Le=`content-length`,Re=`x-amz-decoded-content-length`;function ze(){return(e,t)=>async n=>{let{request:r}=n;if(E.isInstance(r)&&!(Le in r.headers)&&!(Re in r.headers)){let e=`Are you using a Stream of unknown length as the Body of a PutObject request? Consider using Upload instead from @aws-sdk/lib-storage.`;typeof t?.logger?.warn==`function`&&!(t.logger instanceof L)?t.logger.warn(e):console.warn(e)}return e({...n})}}var Be={step:`finalizeRequest`,tags:[`CHECK_CONTENT_LENGTH_HEADER`],name:`getCheckContentLengthHeaderPlugin`,override:!0},Ve=e=>({applyToStack:e=>{e.add(ze(),Be)}}),He=class extends t.classBuilder().ep({..._,Bucket:{type:`contextParams`,name:`Bucket`},Key:{type:`contextParams`,name:`Key`}}).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions()),P(n)]}).s(`AmazonS3`,`AbortMultipartUpload`,{}).n(`S3Client`,`AbortMultipartUploadCommand`).sc(y).build(){};function Ue(e){return t=>async n=>{let r={...n.input};for(let t of[{target:`SSECustomerKey`,hash:`SSECustomerKeyMD5`},{target:`CopySourceSSECustomerKey`,hash:`CopySourceSSECustomerKeyMD5`}]){let n=r[t.target];if(n){let i;typeof n==`string`?Ke(n,e)?i=e.base64Decoder(n):(i=e.utf8Decoder(n),r[t.target]=e.base64Encoder(i)):(i=ArrayBuffer.isView(n)?new Uint8Array(n.buffer,n.byteOffset,n.byteLength):new Uint8Array(n),r[t.target]=e.base64Encoder(i));let a=new e.md5;a.update(i),r[t.hash]=e.base64Encoder(await a.digest())}}return t({...n,input:r})}}var We={name:`ssecMiddleware`,step:`initialize`,tags:[`SSE`],override:!0},Ge=e=>({applyToStack:t=>{t.add(Ue(e),We)}});function Ke(e,t){if(!/^(?:[A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(e))return!1;try{return t.base64Decoder(e).length===32}catch{return!1}}var qe=class extends t.classBuilder().ep({..._,Bucket:{type:`contextParams`,name:`Bucket`},Key:{type:`contextParams`,name:`Key`}}).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions()),P(n),Ge(n)]}).s(`AmazonS3`,`CompleteMultipartUpload`,{}).n(`S3Client`,`CompleteMultipartUploadCommand`).sc(b).build(){};function Je(e){return t=>async n=>{let{CreateBucketConfiguration:r}=n.input,i=await e.region();return!r?.LocationConstraint&&!r?.Location&&i!==`us-east-1`&&(n.input.CreateBucketConfiguration=n.input.CreateBucketConfiguration??{},n.input.CreateBucketConfiguration.LocationConstraint=i),t(n)}}var Ye={step:`initialize`,tags:[`LOCATION_CONSTRAINT`,`CREATE_BUCKET_CONFIGURATION`],name:`locationConstraintMiddleware`,override:!0},Xe=e=>({applyToStack:t=>{t.add(Je(e),Ye)}}),Ze=class extends t.classBuilder().ep({..._,UseS3ExpressControlEndpoint:{type:`staticContextParams`,value:!0},DisableAccessPoints:{type:`staticContextParams`,value:!0},Bucket:{type:`contextParams`,name:`Bucket`}}).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions()),P(n),Xe(n)]}).s(`AmazonS3`,`CreateBucket`,{}).n(`S3Client`,`CreateBucketCommand`).sc(D).build(){},Qe=class extends t.classBuilder().ep({..._,Bucket:{type:`contextParams`,name:`Bucket`},Key:{type:`contextParams`,name:`Key`}}).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions()),P(n),Ge(n)]}).s(`AmazonS3`,`CreateMultipartUpload`,{}).n(`S3Client`,`CreateMultipartUploadCommand`).sc(T).build(){},$e=class extends t.classBuilder().ep({..._,Bucket:{type:`contextParams`,name:`Bucket`},Key:{type:`contextParams`,name:`Key`}}).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions()),P(n)]}).s(`AmazonS3`,`DeleteObject`,{}).n(`S3Client`,`DeleteObjectCommand`).sc(C).build(){},et=class extends t.classBuilder().ep({..._,Bucket:{type:`contextParams`,name:`Bucket`},Key:{type:`contextParams`,name:`Key`}}).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions()),Ie(n,{requestAlgorithmMember:{httpHeader:`x-amz-sdk-checksum-algorithm`,name:`ChecksumAlgorithm`},requestChecksumRequired:!1}),Ve(n),P(n),Ge(n)]}).s(`AmazonS3`,`PutObject`,{}).n(`S3Client`,`PutObjectCommand`).sc(h).build(){},tt=class extends t.classBuilder().ep({..._,Bucket:{type:`contextParams`,name:`Bucket`}}).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions()),Ie(n,{requestAlgorithmMember:{httpHeader:`x-amz-sdk-checksum-algorithm`,name:`ChecksumAlgorithm`},requestChecksumRequired:!0}),P(n)]}).s(`AmazonS3`,`PutObjectTagging`,{}).n(`S3Client`,`PutObjectTaggingCommand`).sc(j).build(){},nt=class extends t.classBuilder().ep({..._,Bucket:{type:`contextParams`,name:`Bucket`},Key:{type:`contextParams`,name:`Key`}}).m(function(e,t,n,r){return[d(n,e.getEndpointParameterInstructions()),Ie(n,{requestAlgorithmMember:{httpHeader:`x-amz-sdk-checksum-algorithm`,name:`ChecksumAlgorithm`},requestChecksumRequired:!1}),P(n),Ge(n)]}).s(`AmazonS3`,`UploadPart`,{}).n(`S3Client`,`UploadPartCommand`).sc(I).build(){},rt={CRC32:`CRC32`,CRC32C:`CRC32C`,CRC64NVME:`CRC64NVME`,MD5:`MD5`,SHA1:`SHA1`,SHA256:`SHA256`,SHA512:`SHA512`,XXHASH128:`XXHASH128`,XXHASH3:`XXHASH3`,XXHASH64:`XXHASH64`},it=O(((e,t)=>{var n=typeof Reflect==`object`?Reflect:null,r=n&&typeof n.apply==`function`?n.apply:function(e,t,n){return Function.prototype.apply.call(e,t,n)},i=n&&typeof n.ownKeys==`function`?n.ownKeys:Object.getOwnPropertySymbols?function(e){return Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e))}:function(e){return Object.getOwnPropertyNames(e)};function a(e){console&&console.warn&&console.warn(e)}var o=Number.isNaN||function(e){return e!==e};function s(){s.init.call(this)}t.exports=s,t.exports.once=y,s.EventEmitter=s,s.prototype._events=void 0,s.prototype._eventsCount=0,s.prototype._maxListeners=void 0;var c=10;function l(e){if(typeof e!=`function`)throw TypeError(`The "listener" argument must be of type Function. Received type `+typeof e)}Object.defineProperty(s,`defaultMaxListeners`,{enumerable:!0,get:function(){return c},set:function(e){if(typeof e!=`number`||e<0||o(e))throw RangeError(`The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received `+e+`.`);c=e}}),s.init=function(){(this._events===void 0||this._events===Object.getPrototypeOf(this)._events)&&(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0},s.prototype.setMaxListeners=function(e){if(typeof e!=`number`||e<0||o(e))throw RangeError(`The value of "n" is out of range. It must be a non-negative number. Received `+e+`.`);return this._maxListeners=e,this};function u(e){return e._maxListeners===void 0?s.defaultMaxListeners:e._maxListeners}s.prototype.getMaxListeners=function(){return u(this)},s.prototype.emit=function(e){for(var t=[],n=1;n0&&(o=t[0]),o instanceof Error)throw o;var s=Error(`Unhandled error.`+(o?` (`+o.message+`)`:``));throw s.context=o,s}var c=a[e];if(c===void 0)return!1;if(typeof c==`function`)r(c,this,t);else for(var l=c.length,u=g(c,l),n=0;n0&&s.length>i&&!s.warned){s.warned=!0;var c=Error(`Possible EventEmitter memory leak detected. `+s.length+` `+String(t)+` listeners added. Use emitter.setMaxListeners() to increase limit`);c.name=`MaxListenersExceededWarning`,c.emitter=e,c.type=t,c.count=s.length,a(c)}return e}s.prototype.addListener=function(e,t){return d(this,e,t,!1)},s.prototype.on=s.prototype.addListener,s.prototype.prependListener=function(e,t){return d(this,e,t,!0)};function f(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,arguments.length===0?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function p(e,t,n){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},i=f.bind(r);return i.listener=n,r.wrapFn=i,i}s.prototype.once=function(e,t){return l(t),this.on(e,p(this,e,t)),this},s.prototype.prependOnceListener=function(e,t){return l(t),this.prependListener(e,p(this,e,t)),this},s.prototype.removeListener=function(e,t){var n,r,i,a,o;if(l(t),r=this._events,r===void 0||(n=r[e],n===void 0))return this;if(n===t||n.listener===t)--this._eventsCount===0?this._events=Object.create(null):(delete r[e],r.removeListener&&this.emit(`removeListener`,e,n.listener||t));else if(typeof n!=`function`){for(i=-1,a=n.length-1;a>=0;a--)if(n[a]===t||n[a].listener===t){o=n[a].listener,i=a;break}if(i<0)return this;i===0?n.shift():_(n,i),n.length===1&&(r[e]=n[0]),r.removeListener!==void 0&&this.emit(`removeListener`,e,o||t)}return this},s.prototype.off=s.prototype.removeListener,s.prototype.removeAllListeners=function(e){var t,n=this._events,r;if(n===void 0)return this;if(n.removeListener===void 0)return arguments.length===0?(this._events=Object.create(null),this._eventsCount=0):n[e]!==void 0&&(--this._eventsCount===0?this._events=Object.create(null):delete n[e]),this;if(arguments.length===0){var i=Object.keys(n),a;for(r=0;r=0;r--)this.removeListener(e,t[r]);return this};function m(e,t,n){var r=e._events;if(r===void 0)return[];var i=r[t];return i===void 0?[]:typeof i==`function`?n?[i.listener||i]:[i]:n?v(i):g(i,i.length)}s.prototype.listeners=function(e){return m(this,e,!0)},s.prototype.rawListeners=function(e){return m(this,e,!1)},s.listenerCount=function(e,t){return typeof e.listenerCount==`function`?e.listenerCount(t):h.call(e,t)},s.prototype.listenerCount=h;function h(e){var t=this._events;if(t!==void 0){var n=t[e];if(typeof n==`function`)return 1;if(n!==void 0)return n.length}return 0}s.prototype.eventNames=function(){return this._eventsCount>0?i(this._events):[]};function g(e,t){for(var n=Array(t),r=0;r{e.byteLength=c,e.toByteArray=u,e.fromByteArray=p;for(var t=[],n=[],r=typeof Uint8Array<`u`?Uint8Array:Array,i=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`,a=0,o=i.length;a0)throw Error(`Invalid string. Length must be a multiple of 4`);var n=e.indexOf(`=`);n===-1&&(n=t);var r=n===t?0:4-n%4;return[n,r]}function c(e){var t=s(e),n=t[0],r=t[1];return(n+r)*3/4-r}function l(e,t,n){return(t+n)*3/4-n}function u(e){var t,i=s(e),a=i[0],o=i[1],c=new r(l(e,a,o)),u=0,d=o>0?a-4:a,f;for(f=0;f>16&255,c[u++]=t>>8&255,c[u++]=t&255;return o===2&&(t=n[e.charCodeAt(f)]<<2|n[e.charCodeAt(f+1)]>>4,c[u++]=t&255),o===1&&(t=n[e.charCodeAt(f)]<<10|n[e.charCodeAt(f+1)]<<4|n[e.charCodeAt(f+2)]>>2,c[u++]=t>>8&255,c[u++]=t&255),c}function d(e){return t[e>>18&63]+t[e>>12&63]+t[e>>6&63]+t[e&63]}function f(e,t,n){for(var r,i=[],a=t;ac?c:s+o));return i===1?(n=e[r-1],a.push(t[n>>2]+t[n<<4&63]+`==`)):i===2&&(n=(e[r-2]<<8)+e[r-1],a.push(t[n>>10]+t[n>>4&63]+t[n<<2&63]+`=`)),a.join(``)}})),ot=O((e=>{e.read=function(e,t,n,r,i){var a,o,s=i*8-r-1,c=(1<>1,u=-7,d=n?i-1:0,f=n?-1:1,p=e[t+d];for(d+=f,a=p&(1<<-u)-1,p>>=-u,u+=s;u>0;a=a*256+e[t+d],d+=f,u-=8);for(o=a&(1<<-u)-1,a>>=-u,u+=r;u>0;o=o*256+e[t+d],d+=f,u-=8);if(a===0)a=1-l;else if(a===c)return o?NaN:(p?-1:1)*(1/0);else o+=2**r,a-=l;return(p?-1:1)*o*2**(a-r)},e.write=function(e,t,n,r,i,a){var o,s,c,l=a*8-i-1,u=(1<>1,f=i===23?2**-24-2**-77:0,p=r?0:a-1,m=r?1:-1,h=+(t<0||t===0&&1/t<0);for(t=Math.abs(t),isNaN(t)||t===1/0?(s=+!!isNaN(t),o=u):(o=Math.floor(Math.log(t)/Math.LN2),t*(c=2**-o)<1&&(o--,c*=2),o+d>=1?t+=f/c:t+=f*2**(1-d),t*c>=2&&(o++,c/=2),o+d>=u?(s=0,o=u):o+d>=1?(s=(t*c-1)*2**i,o+=d):(s=t*2**(d-1)*2**i,o=0));i>=8;e[n+p]=s&255,p+=m,s/=256,i-=8);for(o=o<0;e[n+p]=o&255,p+=m,o/=256,l-=8);e[n+p-m]|=h*128}})),st=O((e=>{var t=at(),n=ot(),r=typeof Symbol==`function`&&typeof Symbol.for==`function`?Symbol.for(`nodejs.util.inspect.custom`):null;e.Buffer=s,e.SlowBuffer=_,e.INSPECT_MAX_BYTES=50;var i=2147483647;e.kMaxLength=i,s.TYPED_ARRAY_SUPPORT=a(),!s.TYPED_ARRAY_SUPPORT&&typeof console<`u`&&typeof console.error==`function`&&console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support.");function a(){try{var e=new Uint8Array(1),t={foo:function(){return 42}};return Object.setPrototypeOf(t,Uint8Array.prototype),Object.setPrototypeOf(e,t),e.foo()===42}catch{return!1}}Object.defineProperty(s.prototype,`parent`,{enumerable:!0,get:function(){if(s.isBuffer(this))return this.buffer}}),Object.defineProperty(s.prototype,`offset`,{enumerable:!0,get:function(){if(s.isBuffer(this))return this.byteOffset}});function o(e){if(e>i)throw RangeError(`The value "`+e+`" is invalid for option "size"`);var t=new Uint8Array(e);return Object.setPrototypeOf(t,s.prototype),t}function s(e,t,n){if(typeof e==`number`){if(typeof t==`string`)throw TypeError(`The "string" argument must be of type string. Received type number`);return d(e)}return c(e,t,n)}s.poolSize=8192;function c(e,t,n){if(typeof e==`string`)return f(e,t);if(ArrayBuffer.isView(e))return p(e);if(e==null)throw TypeError(`The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type `+typeof e);if(K(e,ArrayBuffer)||e&&K(e.buffer,ArrayBuffer)||typeof SharedArrayBuffer<`u`&&(K(e,SharedArrayBuffer)||e&&K(e.buffer,SharedArrayBuffer)))return m(e,t,n);if(typeof e==`number`)throw TypeError(`The "value" argument must not be of type number. Received type number`);var r=e.valueOf&&e.valueOf();if(r!=null&&r!==e)return s.from(r,t,n);var i=h(e);if(i)return i;if(typeof Symbol<`u`&&Symbol.toPrimitive!=null&&typeof e[Symbol.toPrimitive]==`function`)return s.from(e[Symbol.toPrimitive](`string`),t,n);throw TypeError(`The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type `+typeof e)}s.from=function(e,t,n){return c(e,t,n)},Object.setPrototypeOf(s.prototype,Uint8Array.prototype),Object.setPrototypeOf(s,Uint8Array);function l(e){if(typeof e!=`number`)throw TypeError(`"size" argument must be of type number`);if(e<0)throw RangeError(`The value "`+e+`" is invalid for option "size"`)}function u(e,t,n){return l(e),e<=0||t===void 0?o(e):typeof n==`string`?o(e).fill(t,n):o(e).fill(t)}s.alloc=function(e,t,n){return u(e,t,n)};function d(e){return l(e),o(e<0?0:g(e)|0)}s.allocUnsafe=function(e){return d(e)},s.allocUnsafeSlow=function(e){return d(e)};function f(e,t){if((typeof t!=`string`||t===``)&&(t=`utf8`),!s.isEncoding(t))throw TypeError(`Unknown encoding: `+t);var n=v(e,t)|0,r=o(n),i=r.write(e,t);return i!==n&&(r=r.slice(0,i)),r}function p(e){for(var t=e.length<0?0:g(e.length)|0,n=o(t),r=0;r=i)throw RangeError(`Attempt to allocate Buffer larger than maximum size: 0x`+i.toString(16)+` bytes`);return e|0}function _(e){return+e!=e&&(e=0),s.alloc(+e)}s.isBuffer=function(e){return e!=null&&e._isBuffer===!0&&e!==s.prototype},s.compare=function(e,t){if(K(e,Uint8Array)&&(e=s.from(e,e.offset,e.byteLength)),K(t,Uint8Array)&&(t=s.from(t,t.offset,t.byteLength)),!s.isBuffer(e)||!s.isBuffer(t))throw TypeError(`The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array`);if(e===t)return 0;for(var n=e.length,r=t.length,i=0,a=Math.min(n,r);i2&&arguments[2]===!0;if(!r&&n===0)return 0;for(var i=!1;;)switch(t){case`ascii`:case`latin1`:case`binary`:return n;case`utf8`:case`utf-8`:return V(e).length;case`ucs2`:case`ucs-2`:case`utf16le`:case`utf-16le`:return n*2;case`hex`:return n>>>1;case`base64`:return W(e).length;default:if(i)return r?-1:V(e).length;t=(``+t).toLowerCase(),i=!0}}s.byteLength=v;function y(e,t,n){var r=!1;if((t===void 0||t<0)&&(t=0),t>this.length||((n===void 0||n>this.length)&&(n=this.length),n<=0)||(n>>>=0,t>>>=0,n<=t))return``;for(e||=`utf8`;;)switch(e){case`hex`:return P(this,t,n);case`utf8`:case`utf-8`:return k(this,t,n);case`ascii`:return M(this,t,n);case`latin1`:case`binary`:return N(this,t,n);case`base64`:return ee(this,t,n);case`ucs2`:case`ucs-2`:case`utf16le`:case`utf-16le`:return F(this,t,n);default:if(r)throw TypeError(`Unknown encoding: `+e);e=(e+``).toLowerCase(),r=!0}}s.prototype._isBuffer=!0;function b(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}s.prototype.swap16=function(){var e=this.length;if(e%2!=0)throw RangeError(`Buffer size must be a multiple of 16-bits`);for(var t=0;tn&&(t+=` ... `),``},r&&(s.prototype[r]=s.prototype.inspect),s.prototype.compare=function(e,t,n,r,i){if(K(e,Uint8Array)&&(e=s.from(e,e.offset,e.byteLength)),!s.isBuffer(e))throw TypeError(`The "target" argument must be one of type Buffer or Uint8Array. Received type `+typeof e);if(t===void 0&&(t=0),n===void 0&&(n=e?e.length:0),r===void 0&&(r=0),i===void 0&&(i=this.length),t<0||n>e.length||r<0||i>this.length)throw RangeError(`out of range index`);if(r>=i&&t>=n)return 0;if(r>=i)return-1;if(t>=n)return 1;if(t>>>=0,n>>>=0,r>>>=0,i>>>=0,this===e)return 0;for(var a=i-r,o=n-t,c=Math.min(a,o),l=this.slice(r,i),u=e.slice(t,n),d=0;d2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,q(n)&&(n=i?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(i)return-1;n=e.length-1}else if(n<0)if(i)n=0;else return-1;if(typeof t==`string`&&(t=s.from(t,r)),s.isBuffer(t))return t.length===0?-1:S(e,t,n,r,i);if(typeof t==`number`)return t&=255,typeof Uint8Array.prototype.indexOf==`function`?i?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):S(e,[t],n,r,i);throw TypeError(`val must be string, number or Buffer`)}function S(e,t,n,r,i){var a=1,o=e.length,s=t.length;if(r!==void 0&&(r=String(r).toLowerCase(),r===`ucs2`||r===`ucs-2`||r===`utf16le`||r===`utf-16le`)){if(e.length<2||t.length<2)return-1;a=2,o/=2,s/=2,n/=2}function c(e,t){return a===1?e[t]:e.readUInt16BE(t*a)}var l;if(i){var u=-1;for(l=n;lo&&(n=o-s),l=n;l>=0;l--){for(var d=!0,f=0;fi&&(r=i)):r=i;var a=t.length;r>a/2&&(r=a/2);for(var o=0;o>>=0,isFinite(n)?(n>>>=0,r===void 0&&(r=`utf8`)):(r=n,n=void 0);else throw Error(`Buffer.write(string, encoding, offset[, length]) is no longer supported`);var i=this.length-t;if((n===void 0||n>i)&&(n=i),e.length>0&&(n<0||t<0)||t>this.length)throw RangeError(`Attempt to write outside buffer bounds`);r||=`utf8`;for(var a=!1;;)switch(r){case`hex`:return C(this,e,t,n);case`utf8`:case`utf-8`:return w(this,e,t,n);case`ascii`:return T(this,e,t,n);case`latin1`:case`binary`:return E(this,e,t,n);case`base64`:return D(this,e,t,n);case`ucs2`:case`ucs-2`:case`utf16le`:case`utf-16le`:return O(this,e,t,n);default:if(a)throw TypeError(`Unknown encoding: `+r);r=(``+r).toLowerCase(),a=!0}},s.prototype.toJSON=function(){return{type:`Buffer`,data:Array.prototype.slice.call(this._arr||this,0)}};function ee(e,n,r){return n===0&&r===e.length?t.fromByteArray(e):t.fromByteArray(e.slice(n,r))}function k(e,t,n){n=Math.min(e.length,n);for(var r=[],i=t;i239?4:a>223?3:a>191?2:1;if(i+s<=n){var c,l,u,d;switch(s){case 1:a<128&&(o=a);break;case 2:c=e[i+1],(c&192)==128&&(d=(a&31)<<6|c&63,d>127&&(o=d));break;case 3:c=e[i+1],l=e[i+2],(c&192)==128&&(l&192)==128&&(d=(a&15)<<12|(c&63)<<6|l&63,d>2047&&(d<55296||d>57343)&&(o=d));break;case 4:c=e[i+1],l=e[i+2],u=e[i+3],(c&192)==128&&(l&192)==128&&(u&192)==128&&(d=(a&15)<<18|(c&63)<<12|(l&63)<<6|u&63,d>65535&&d<1114112&&(o=d))}}o===null?(o=65533,s=1):o>65535&&(o-=65536,r.push(o>>>10&1023|55296),o=56320|o&1023),r.push(o),i+=s}return j(r)}var A=4096;function j(e){var t=e.length;if(t<=A)return String.fromCharCode.apply(String,e);for(var n=``,r=0;rr)&&(n=r);for(var i=``,a=t;an&&(e=n),t<0?(t+=n,t<0&&(t=0)):t>n&&(t=n),tn)throw RangeError(`Trying to access beyond buffer length`)}s.prototype.readUIntLE=function(e,t,n){e>>>=0,t>>>=0,n||I(e,t,this.length);for(var r=this[e],i=1,a=0;++a>>=0,t>>>=0,n||I(e,t,this.length);for(var r=this[e+--t],i=1;t>0&&(i*=256);)r+=this[e+--t]*i;return r},s.prototype.readUInt8=function(e,t){return e>>>=0,t||I(e,1,this.length),this[e]},s.prototype.readUInt16LE=function(e,t){return e>>>=0,t||I(e,2,this.length),this[e]|this[e+1]<<8},s.prototype.readUInt16BE=function(e,t){return e>>>=0,t||I(e,2,this.length),this[e]<<8|this[e+1]},s.prototype.readUInt32LE=function(e,t){return e>>>=0,t||I(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+this[e+3]*16777216},s.prototype.readUInt32BE=function(e,t){return e>>>=0,t||I(e,4,this.length),this[e]*16777216+(this[e+1]<<16|this[e+2]<<8|this[e+3])},s.prototype.readIntLE=function(e,t,n){e>>>=0,t>>>=0,n||I(e,t,this.length);for(var r=this[e],i=1,a=0;++a=i&&(r-=2**(8*t)),r},s.prototype.readIntBE=function(e,t,n){e>>>=0,t>>>=0,n||I(e,t,this.length);for(var r=t,i=1,a=this[e+--r];r>0&&(i*=256);)a+=this[e+--r]*i;return i*=128,a>=i&&(a-=2**(8*t)),a},s.prototype.readInt8=function(e,t){return e>>>=0,t||I(e,1,this.length),this[e]&128?(255-this[e]+1)*-1:this[e]},s.prototype.readInt16LE=function(e,t){e>>>=0,t||I(e,2,this.length);var n=this[e]|this[e+1]<<8;return n&32768?n|4294901760:n},s.prototype.readInt16BE=function(e,t){e>>>=0,t||I(e,2,this.length);var n=this[e+1]|this[e]<<8;return n&32768?n|4294901760:n},s.prototype.readInt32LE=function(e,t){return e>>>=0,t||I(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},s.prototype.readInt32BE=function(e,t){return e>>>=0,t||I(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},s.prototype.readFloatLE=function(e,t){return e>>>=0,t||I(e,4,this.length),n.read(this,e,!0,23,4)},s.prototype.readFloatBE=function(e,t){return e>>>=0,t||I(e,4,this.length),n.read(this,e,!1,23,4)},s.prototype.readDoubleLE=function(e,t){return e>>>=0,t||I(e,8,this.length),n.read(this,e,!0,52,8)},s.prototype.readDoubleBE=function(e,t){return e>>>=0,t||I(e,8,this.length),n.read(this,e,!1,52,8)};function L(e,t,n,r,i,a){if(!s.isBuffer(e))throw TypeError(`"buffer" argument must be a Buffer instance`);if(t>i||te.length)throw RangeError(`Index out of range`)}s.prototype.writeUIntLE=function(e,t,n,r){if(e=+e,t>>>=0,n>>>=0,!r){var i=2**(8*n)-1;L(this,e,t,n,i,0)}var a=1,o=0;for(this[t]=e&255;++o>>=0,n>>>=0,!r){var i=2**(8*n)-1;L(this,e,t,n,i,0)}var a=n-1,o=1;for(this[t+a]=e&255;--a>=0&&(o*=256);)this[t+a]=e/o&255;return t+n},s.prototype.writeUInt8=function(e,t,n){return e=+e,t>>>=0,n||L(this,e,t,1,255,0),this[t]=e&255,t+1},s.prototype.writeUInt16LE=function(e,t,n){return e=+e,t>>>=0,n||L(this,e,t,2,65535,0),this[t]=e&255,this[t+1]=e>>>8,t+2},s.prototype.writeUInt16BE=function(e,t,n){return e=+e,t>>>=0,n||L(this,e,t,2,65535,0),this[t]=e>>>8,this[t+1]=e&255,t+2},s.prototype.writeUInt32LE=function(e,t,n){return e=+e,t>>>=0,n||L(this,e,t,4,4294967295,0),this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=e&255,t+4},s.prototype.writeUInt32BE=function(e,t,n){return e=+e,t>>>=0,n||L(this,e,t,4,4294967295,0),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=e&255,t+4},s.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t>>>=0,!r){var i=2**(8*n-1);L(this,e,t,n,i-1,-i)}var a=0,o=1,s=0;for(this[t]=e&255;++a>0)-s&255;return t+n},s.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t>>>=0,!r){var i=2**(8*n-1);L(this,e,t,n,i-1,-i)}var a=n-1,o=1,s=0;for(this[t+a]=e&255;--a>=0&&(o*=256);)e<0&&s===0&&this[t+a+1]!==0&&(s=1),this[t+a]=(e/o>>0)-s&255;return t+n},s.prototype.writeInt8=function(e,t,n){return e=+e,t>>>=0,n||L(this,e,t,1,127,-128),e<0&&(e=255+e+1),this[t]=e&255,t+1},s.prototype.writeInt16LE=function(e,t,n){return e=+e,t>>>=0,n||L(this,e,t,2,32767,-32768),this[t]=e&255,this[t+1]=e>>>8,t+2},s.prototype.writeInt16BE=function(e,t,n){return e=+e,t>>>=0,n||L(this,e,t,2,32767,-32768),this[t]=e>>>8,this[t+1]=e&255,t+2},s.prototype.writeInt32LE=function(e,t,n){return e=+e,t>>>=0,n||L(this,e,t,4,2147483647,-2147483648),this[t]=e&255,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24,t+4},s.prototype.writeInt32BE=function(e,t,n){return e=+e,t>>>=0,n||L(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=e&255,t+4};function R(e,t,n,r,i,a){if(n+r>e.length||n<0)throw RangeError(`Index out of range`)}function z(e,t,r,i,a){return t=+t,r>>>=0,a||R(e,t,r,4,34028234663852886e22,-34028234663852886e22),n.write(e,t,r,i,23,4),r+4}s.prototype.writeFloatLE=function(e,t,n){return z(this,e,t,!0,n)},s.prototype.writeFloatBE=function(e,t,n){return z(this,e,t,!1,n)};function te(e,t,r,i,a){return t=+t,r>>>=0,a||R(e,t,r,8,17976931348623157e292,-17976931348623157e292),n.write(e,t,r,i,52,8),r+8}s.prototype.writeDoubleLE=function(e,t,n){return te(this,e,t,!0,n)},s.prototype.writeDoubleBE=function(e,t,n){return te(this,e,t,!1,n)},s.prototype.copy=function(e,t,n,r){if(!s.isBuffer(e))throw TypeError(`argument should be a Buffer`);if(n||=0,!r&&r!==0&&(r=this.length),t>=e.length&&(t=e.length),t||=0,r>0&&r=this.length)throw RangeError(`Index out of range`);if(r<0)throw RangeError(`sourceEnd out of bounds`);r>this.length&&(r=this.length),e.length-t=0;--a)e[a+t]=this[a+n];else Uint8Array.prototype.set.call(e,this.subarray(n,r),t);return i},s.prototype.fill=function(e,t,n,r){if(typeof e==`string`){if(typeof t==`string`?(r=t,t=0,n=this.length):typeof n==`string`&&(r=n,n=this.length),r!==void 0&&typeof r!=`string`)throw TypeError(`encoding must be a string`);if(typeof r==`string`&&!s.isEncoding(r))throw TypeError(`Unknown encoding: `+r);if(e.length===1){var i=e.charCodeAt(0);(r===`utf8`&&i<128||r===`latin1`)&&(e=i)}}else typeof e==`number`?e&=255:typeof e==`boolean`&&(e=Number(e));if(t<0||this.length>>=0,n=n===void 0?this.length:n>>>0,e||=0;var a;if(typeof e==`number`)for(a=t;a55295&&n<57344){if(!i){if(n>56319){(t-=3)>-1&&a.push(239,191,189);continue}else if(o+1===r){(t-=3)>-1&&a.push(239,191,189);continue}i=n;continue}if(n<56320){(t-=3)>-1&&a.push(239,191,189),i=n;continue}n=(i-55296<<10|n-56320)+65536}else i&&(t-=3)>-1&&a.push(239,191,189);if(i=null,n<128){if(--t<0)break;a.push(n)}else if(n<2048){if((t-=2)<0)break;a.push(n>>6|192,n&63|128)}else if(n<65536){if((t-=3)<0)break;a.push(n>>12|224,n>>6&63|128,n&63|128)}else if(n<1114112){if((t-=4)<0)break;a.push(n>>18|240,n>>12&63|128,n>>6&63|128,n&63|128)}else throw Error(`Invalid code point`)}return a}function H(e){for(var t=[],n=0;n>8,i=n%256,a.push(i),a.push(r);return a}function W(e){return t.toByteArray(B(e))}function G(e,t,n,r){for(var i=0;i=t.length||i>=e.length);++i)t[i+n]=e[i];return i}function K(e,t){return e instanceof t||e!=null&&e.constructor!=null&&e.constructor.name!=null&&e.constructor.name===t.name}function q(e){return e!==e}var re=(function(){for(var e=`0123456789abcdef`,t=Array(256),n=0;n<16;++n)for(var r=n*16,i=0;i<16;++i)t[r+i]=e[n]+e[i];return t})()})),ct=N(),lt=it(),Y=st(),ut={lstatSync:()=>{},isFileReadStream(e){return!1},runtime:`browser`},dt=e=>{if(e==null)return 0;if(typeof e==`string`)return Y.Buffer.byteLength(e);if(typeof e.byteLength==`number`)return e.byteLength;if(typeof e.length==`number`)return e.length;if(typeof e.size==`number`)return e.size;if(typeof e.start==`number`&&typeof e.end==`number`)return e.end+1-e.start;if(ut.isFileReadStream(e))try{return ut.lstatSync(e.path).size}catch{return}},X;(function(e){e.EMPTY_INPUT=`a null or undefined Body`,e.CONTENT_LENGTH=`the ContentLength property of the params set by the caller`,e.STRING_LENGTH=`the encoded byte length of the Body string`,e.TYPED_ARRAY=`the byteLength of a typed byte array such as Uint8Array`,e.LENGTH=`the value of Body.length`,e.SIZE=`the value of Body.size`,e.START_END_DIFF=`the numeric difference between Body.start and Body.end`,e.LSTAT=`the size of the file given by Body.path on disk as reported by lstatSync`})(X||={});var ft=(e,t)=>{if(t!=null)return X.CONTENT_LENGTH;if(e==null)return X.EMPTY_INPUT;if(typeof e==`string`)return X.STRING_LENGTH;if(typeof e.byteLength==`number`)return X.TYPED_ARRAY;if(typeof e.length==`number`)return X.LENGTH;if(typeof e.size==`number`)return X.SIZE;if(typeof e.start==`number`&&typeof e.end==`number`)return X.START_END_DIFF;if(ut.isFileReadStream(e))try{return ut.lstatSync(e.path).size,X.LSTAT}catch{return}},Z=O(((e,t)=>{typeof Object.create==`function`?t.exports=function(e,t){t&&(e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:t.exports=function(e,t){if(t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}}})),pt=O(((e,t)=>{t.exports=it().EventEmitter})),mt=O(((e,t)=>{t.exports={}})),ht=O(((e,t)=>{function n(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function r(e){for(var t=1;t0?this.tail.next=t:this.head=t,this.tail=t,++this.length}},{key:`unshift`,value:function(e){var t={data:e,next:this.head};this.length===0&&(this.tail=t),this.head=t,++this.length}},{key:`shift`,value:function(){if(this.length!==0){var e=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,e}}},{key:`clear`,value:function(){this.head=this.tail=null,this.length=0}},{key:`join`,value:function(e){if(this.length===0)return``;for(var t=this.head,n=``+t.data;t=t.next;)n+=e+t.data;return n}},{key:`concat`,value:function(e){if(this.length===0)return u.alloc(0);for(var t=u.allocUnsafe(e>>>0),n=this.head,r=0;n;)p(n.data,t,r),r+=n.data.length,n=n.next;return t}},{key:`consume`,value:function(e,t){var n;return ei.length?i.length:e;if(a===i.length?r+=i:r+=i.slice(0,e),e-=a,e===0){a===i.length?(++n,t.next?this.head=t.next:this.head=this.tail=null):(this.head=t,t.data=i.slice(a));break}++n}return this.length-=n,r}},{key:`_getBuffer`,value:function(e){var t=u.allocUnsafe(e),n=this.head,r=1;for(n.data.copy(t),e-=n.data.length;n=n.next;){var i=n.data,a=e>i.length?i.length:e;if(i.copy(t,t.length-e,0,a),e-=a,e===0){a===i.length?(++r,n.next?this.head=n.next:this.head=this.tail=null):(this.head=n,n.data=i.slice(a));break}++r}return this.length-=r,t}},{key:f,value:function(e,t){return d(this,r(r({},t),{},{depth:0,customInspect:!1}))}}]),e}()})),gt=O(((e,t)=>{function n(e,t){var n=this,a=this._readableState&&this._readableState.destroyed,s=this._writableState&&this._writableState.destroyed;return a||s?(t?t(e):e&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,process.nextTick(o,this,e)):process.nextTick(o,this,e)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(e||null,function(e){!t&&e?n._writableState?n._writableState.errorEmitted?process.nextTick(i,n):(n._writableState.errorEmitted=!0,process.nextTick(r,n,e)):process.nextTick(r,n,e):t?(process.nextTick(i,n),t(e)):process.nextTick(i,n)}),this)}function r(e,t){o(e,t),i(e)}function i(e){e._writableState&&!e._writableState.emitClose||e._readableState&&!e._readableState.emitClose||e.emit(`close`)}function a(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function o(e,t){e.emit(`error`,t)}function s(e,t){var n=e._readableState,r=e._writableState;n&&n.autoDestroy||r&&r.autoDestroy?e.destroy(t):e.emit(`error`,t)}t.exports={destroy:n,undestroy:a,errorOrDestroy:s}})),Q=O(((e,t)=>{function n(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}var r={};function i(e,t,i){i||=Error;function a(e,n,r){return typeof t==`string`?t:t(e,n,r)}var o=function(e){n(t,e);function t(t,n,r){return e.call(this,a(t,n,r))||this}return t}(i);o.prototype.name=i.name,o.prototype.code=e,r[e]=o}function a(e,t){if(Array.isArray(e)){var n=e.length;return e=e.map(function(e){return String(e)}),n>2?`one of ${t} ${e.slice(0,n-1).join(`, `)}, or `+e[n-1]:n===2?`one of ${t} ${e[0]} or ${e[1]}`:`of ${t} ${e[0]}`}else return`of ${t} ${String(e)}`}function o(e,t,n){return e.substr(!n||n<0?0:+n,t.length)===t}function s(e,t,n){return(n===void 0||n>e.length)&&(n=e.length),e.substring(n-t.length,n)===t}function c(e,t,n){return typeof n!=`number`&&(n=0),n+t.length>e.length?!1:e.indexOf(t,n)!==-1}i(`ERR_INVALID_OPT_VALUE`,function(e,t){return`The value "`+t+`" is invalid for option "`+e+`"`},TypeError),i(`ERR_INVALID_ARG_TYPE`,function(e,t,n){var r;typeof t==`string`&&o(t,`not `)?(r=`must not be`,t=t.replace(/^not /,``)):r=`must be`;var i=s(e,` argument`)?`The ${e} ${r} ${a(t,`type`)}`:`The "${e}" ${c(e,`.`)?`property`:`argument`} ${r} ${a(t,`type`)}`;return i+=`. Received type ${typeof n}`,i},TypeError),i(`ERR_STREAM_PUSH_AFTER_EOF`,`stream.push() after EOF`),i(`ERR_METHOD_NOT_IMPLEMENTED`,function(e){return`The `+e+` method is not implemented`}),i(`ERR_STREAM_PREMATURE_CLOSE`,`Premature close`),i(`ERR_STREAM_DESTROYED`,function(e){return`Cannot call `+e+` after a stream was destroyed`}),i(`ERR_MULTIPLE_CALLBACK`,`Callback called multiple times`),i(`ERR_STREAM_CANNOT_PIPE`,`Cannot pipe, not readable`),i(`ERR_STREAM_WRITE_AFTER_END`,`write after end`),i(`ERR_STREAM_NULL_VALUES`,`May not write null values to stream`,TypeError),i(`ERR_UNKNOWN_ENCODING`,function(e){return`Unknown encoding: `+e},TypeError),i(`ERR_STREAM_UNSHIFT_AFTER_END_EVENT`,`stream.unshift() after end event`),t.exports.codes=r})),_t=O(((e,t)=>{var n=Q().codes.ERR_INVALID_OPT_VALUE;function r(e,t,n){return e.highWaterMark==null?t?e[n]:null:e.highWaterMark}function i(e,t,i,a){var o=r(t,a,i);if(o!=null){if(!(isFinite(o)&&Math.floor(o)===o)||o<0)throw new n(a?i:`highWaterMark`,o);return Math.floor(o)}return e.objectMode?16:16*1024}t.exports={getHighWaterMark:i}})),vt=O(((e,t)=>{t.exports=n;function n(e,t){if(r(`noDeprecation`))return e;var n=!1;function i(){if(!n){if(r(`throwDeprecation`))throw Error(t);r(`traceDeprecation`)?console.trace(t):console.warn(t),n=!0}return e.apply(this,arguments)}return i}function r(e){try{if(!global.localStorage)return!1}catch{return!1}var t=global.localStorage[e];return t==null?!1:String(t).toLowerCase()===`true`}})),yt=O(((e,t)=>{t.exports=T;function n(e){var t=this;this.next=null,this.entry=null,this.finish=function(){ne(t,e)}}var r;T.WritableState=C;var i={deprecate:vt()},a=pt(),o=st().Buffer,s=(typeof global<`u`?global:typeof window<`u`?window:typeof self<`u`?self:{}).Uint8Array||function(){};function c(e){return o.from(e)}function l(e){return o.isBuffer(e)||e instanceof s}var u=gt(),d=_t().getHighWaterMark,f=Q().codes,p=f.ERR_INVALID_ARG_TYPE,m=f.ERR_METHOD_NOT_IMPLEMENTED,h=f.ERR_MULTIPLE_CALLBACK,g=f.ERR_STREAM_CANNOT_PIPE,_=f.ERR_STREAM_DESTROYED,v=f.ERR_STREAM_NULL_VALUES,y=f.ERR_STREAM_WRITE_AFTER_END,b=f.ERR_UNKNOWN_ENCODING,x=u.errorOrDestroy;Z()(T,a);function S(){}function C(e,t,i){r||=$(),e||={},typeof i!=`boolean`&&(i=t instanceof r),this.objectMode=!!e.objectMode,i&&(this.objectMode=this.objectMode||!!e.writableObjectMode),this.highWaterMark=d(this,e,`writableHighWaterMark`,i),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var a=e.decodeStrings===!1;this.decodeStrings=!a,this.defaultEncoding=e.defaultEncoding||`utf8`,this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(e){M(t,e)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.emitClose=e.emitClose!==!1,this.autoDestroy=!!e.autoDestroy,this.bufferedRequestCount=0,this.corkedRequestsFree=new n(this)}C.prototype.getBuffer=function(){for(var e=this.bufferedRequest,t=[];e;)t.push(e),e=e.next;return t},(function(){try{Object.defineProperty(C.prototype,`buffer`,{get:i.deprecate(function(){return this.getBuffer()},`_writableState.buffer is deprecated. Use _writableState.getBuffer instead.`,`DEP0003`)})}catch{}})();var w;typeof Symbol==`function`&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]==`function`?(w=Function.prototype[Symbol.hasInstance],Object.defineProperty(T,Symbol.hasInstance,{value:function(e){return w.call(this,e)?!0:this===T?e&&e._writableState instanceof C:!1}})):w=function(e){return e instanceof this};function T(e){r||=$();var t=this instanceof r;if(!t&&!w.call(T,this))return new T(e);this._writableState=new C(e,this,t),this.writable=!0,e&&(typeof e.write==`function`&&(this._write=e.write),typeof e.writev==`function`&&(this._writev=e.writev),typeof e.destroy==`function`&&(this._destroy=e.destroy),typeof e.final==`function`&&(this._final=e.final)),a.call(this)}T.prototype.pipe=function(){x(this,new g)};function E(e,t){var n=new y;x(e,n),process.nextTick(t,n)}function D(e,t,n,r){var i;return n===null?i=new v:typeof n!=`string`&&!t.objectMode&&(i=new p(`chunk`,[`string`,`Buffer`],n)),i?(x(e,i),process.nextTick(r,i),!1):!0}T.prototype.write=function(e,t,n){var r=this._writableState,i=!1,a=!r.objectMode&&l(e);return a&&!o.isBuffer(e)&&(e=c(e)),typeof t==`function`&&(n=t,t=null),a?t=`buffer`:t||=r.defaultEncoding,typeof n!=`function`&&(n=S),r.ending?E(this,n):(a||D(this,r,e,n))&&(r.pendingcb++,i=ee(this,r,a,e,t,n)),i},T.prototype.cork=function(){this._writableState.corked++},T.prototype.uncork=function(){var e=this._writableState;e.corked&&(e.corked--,!e.writing&&!e.corked&&!e.bufferProcessing&&e.bufferedRequest&&F(this,e))},T.prototype.setDefaultEncoding=function(e){if(typeof e==`string`&&(e=e.toLowerCase()),!([`hex`,`utf8`,`utf-8`,`ascii`,`binary`,`base64`,`ucs2`,`ucs-2`,`utf16le`,`utf-16le`,`raw`].indexOf((e+``).toLowerCase())>-1))throw new b(e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(T.prototype,`writableBuffer`,{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});function O(e,t,n){return!e.objectMode&&e.decodeStrings!==!1&&typeof t==`string`&&(t=o.from(t,n)),t}Object.defineProperty(T.prototype,`writableHighWaterMark`,{enumerable:!1,get:function(){return this._writableState.highWaterMark}});function ee(e,t,n,r,i,a){if(!n){var o=O(t,r,i);r!==o&&(n=!0,i=`buffer`,r=o)}var s=t.objectMode?1:r.length;t.length+=s;var c=t.length{var n=Object.keys||function(e){var t=[];for(var n in e)t.push(n);return t};t.exports=c;var r=Tt(),i=yt();Z()(c,r);for(var a=n(i.prototype),o=0;o{var n=st(),r=n.Buffer;function i(e,t){for(var n in e)t[n]=e[n]}r.from&&r.alloc&&r.allocUnsafe&&r.allocUnsafeSlow?t.exports=n:(i(n,e),e.Buffer=a);function a(e,t,n){return r(e,t,n)}a.prototype=Object.create(r.prototype),i(r,a),a.from=function(e,t,n){if(typeof e==`number`)throw TypeError(`Argument must not be a number`);return r(e,t,n)},a.alloc=function(e,t,n){if(typeof e!=`number`)throw TypeError(`Argument must be a number`);var i=r(e);return t===void 0?i.fill(0):typeof n==`string`?i.fill(t,n):i.fill(t),i},a.allocUnsafe=function(e){if(typeof e!=`number`)throw TypeError(`Argument must be a number`);return r(e)},a.allocUnsafeSlow=function(e){if(typeof e!=`number`)throw TypeError(`Argument must be a number`);return n.SlowBuffer(e)}})),xt=O((e=>{var t=bt().Buffer,n=t.isEncoding||function(e){switch(e=``+e,e&&e.toLowerCase()){case`hex`:case`utf8`:case`utf-8`:case`ascii`:case`binary`:case`base64`:case`ucs2`:case`ucs-2`:case`utf16le`:case`utf-16le`:case`raw`:return!0;default:return!1}};function r(e){if(!e)return`utf8`;for(var t;;)switch(e){case`utf8`:case`utf-8`:return`utf8`;case`ucs2`:case`ucs-2`:case`utf16le`:case`utf-16le`:return`utf16le`;case`latin1`:case`binary`:return`latin1`;case`base64`:case`ascii`:case`hex`:return e;default:if(t)return;e=(``+e).toLowerCase(),t=!0}}function i(e){var i=r(e);if(typeof i!=`string`&&(t.isEncoding===n||!n(e)))throw Error(`Unknown encoding: `+e);return i||e}e.StringDecoder=a;function a(e){this.encoding=i(e);var n;switch(this.encoding){case`utf16le`:this.text=f,this.end=p,n=4;break;case`utf8`:this.fillLast=l,n=4;break;case`base64`:this.text=m,this.end=h,n=3;break;default:this.write=g,this.end=_;return}this.lastNeed=0,this.lastTotal=0,this.lastChar=t.allocUnsafe(n)}a.prototype.write=function(e){if(e.length===0)return``;var t,n;if(this.lastNeed){if(t=this.fillLast(e),t===void 0)return``;n=this.lastNeed,this.lastNeed=0}else n=0;return n>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function s(e,t,n){var r=t.length-1;if(r=0?(i>0&&(e.lastNeed=i-1),i):--r=0?(i>0&&(e.lastNeed=i-2),i):--r=0?(i>0&&(i===2?i=0:e.lastNeed=i-3),i):0))}function c(e,t,n){if((t[0]&192)!=128)return e.lastNeed=0,`�`;if(e.lastNeed>1&&t.length>1){if((t[1]&192)!=128)return e.lastNeed=1,`�`;if(e.lastNeed>2&&t.length>2&&(t[2]&192)!=128)return e.lastNeed=2,`�`}}function l(e){var t=this.lastTotal-this.lastNeed,n=c(this,e,t);if(n!==void 0)return n;if(this.lastNeed<=e.length)return e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);e.copy(this.lastChar,t,0,e.length),this.lastNeed-=e.length}function u(e,t){var n=s(this,e,t);if(!this.lastNeed)return e.toString(`utf8`,t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString(`utf8`,t,r)}function d(e){var t=e&&e.length?this.write(e):``;return this.lastNeed?t+`�`:t}function f(e,t){if((e.length-t)%2==0){var n=e.toString(`utf16le`,t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString(`utf16le`,t,e.length-1)}function p(e){var t=e&&e.length?this.write(e):``;if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString(`utf16le`,0,n)}return t}function m(e,t){var n=(e.length-t)%3;return n===0?e.toString(`base64`,t):(this.lastNeed=3-n,this.lastTotal=3,n===1?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString(`base64`,t,e.length-n))}function h(e){var t=e&&e.length?this.write(e):``;return this.lastNeed?t+this.lastChar.toString(`base64`,0,3-this.lastNeed):t}function g(e){return e.toString(this.encoding)}function _(e){return e&&e.length?this.write(e):``}})),St=O(((e,t)=>{var n=Q().codes.ERR_STREAM_PREMATURE_CLOSE;function r(e){var t=!1;return function(){if(!t){t=!0;var n=[...arguments];e.apply(this,n)}}}function i(){}function a(e){return e.setHeader&&typeof e.abort==`function`}function o(e,t,s){if(typeof t==`function`)return o(e,null,t);t||={},s=r(s||i);var c=t.readable||t.readable!==!1&&e.readable,l=t.writable||t.writable!==!1&&e.writable,u=function(){e.writable||f()},d=e._writableState&&e._writableState.finished,f=function(){l=!1,d=!0,c||s.call(e)},p=e._readableState&&e._readableState.endEmitted,m=function(){c=!1,p=!0,l||s.call(e)},h=function(t){s.call(e,t)},g=function(){var t;if(c&&!p)return(!e._readableState||!e._readableState.ended)&&(t=new n),s.call(e,t);if(l&&!d)return(!e._writableState||!e._writableState.ended)&&(t=new n),s.call(e,t)},_=function(){e.req.on(`finish`,f)};return a(e)?(e.on(`complete`,f),e.on(`abort`,g),e.req?_():e.on(`request`,_)):l&&!e._writableState&&(e.on(`end`,u),e.on(`close`,u)),e.on(`end`,m),e.on(`finish`,f),t.error!==!1&&e.on(`error`,h),e.on(`close`,g),function(){e.removeListener(`complete`,f),e.removeListener(`abort`,g),e.removeListener(`request`,_),e.req&&e.req.removeListener(`finish`,f),e.removeListener(`end`,u),e.removeListener(`close`,u),e.removeListener(`finish`,f),e.removeListener(`end`,m),e.removeListener(`error`,h),e.removeListener(`close`,g)}}t.exports=o})),Ct=O(((e,t)=>{var n;function r(e,t,n){return t=i(t),t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e){var t=a(e,`string`);return typeof t==`symbol`?t:String(t)}function a(e,t){if(typeof e!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(typeof r!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}var o=St(),s=Symbol(`lastResolve`),c=Symbol(`lastReject`),l=Symbol(`error`),u=Symbol(`ended`),d=Symbol(`lastPromise`),f=Symbol(`handlePromise`),p=Symbol(`stream`);function m(e,t){return{value:e,done:t}}function h(e){var t=e[s];if(t!==null){var n=e[p].read();n!==null&&(e[d]=null,e[s]=null,e[c]=null,t(m(n,!1)))}}function g(e){process.nextTick(h,e)}function _(e,t){return function(n,r){e.then(function(){if(t[u]){n(m(void 0,!0));return}t[f](n,r)},r)}}var v=Object.getPrototypeOf(function(){}),y=Object.setPrototypeOf((n={get stream(){return this[p]},next:function(){var e=this,t=this[l];if(t!==null)return Promise.reject(t);if(this[u])return Promise.resolve(m(void 0,!0));if(this[p].destroyed)return new Promise(function(t,n){process.nextTick(function(){e[l]?n(e[l]):t(m(void 0,!0))})});var n=this[d],r;if(n)r=new Promise(_(n,this));else{var i=this[p].read();if(i!==null)return Promise.resolve(m(i,!1));r=new Promise(this[f])}return this[d]=r,r}},r(n,Symbol.asyncIterator,function(){return this}),r(n,`return`,function(){var e=this;return new Promise(function(t,n){e[p].destroy(null,function(e){if(e){n(e);return}t(m(void 0,!0))})})}),n),v);t.exports=function(e){var t,n=Object.create(y,(t={},r(t,p,{value:e,writable:!0}),r(t,s,{value:null,writable:!0}),r(t,c,{value:null,writable:!0}),r(t,l,{value:null,writable:!0}),r(t,u,{value:e._readableState.endEmitted,writable:!0}),r(t,f,{value:function(e,t){var r=n[p].read();r?(n[d]=null,n[s]=null,n[c]=null,e(m(r,!1))):(n[s]=e,n[c]=t)},writable:!0}),t));return n[d]=null,o(e,function(e){if(e&&e.code!==`ERR_STREAM_PREMATURE_CLOSE`){var t=n[c];t!==null&&(n[d]=null,n[s]=null,n[c]=null,t(e)),n[l]=e;return}var r=n[s];r!==null&&(n[d]=null,n[s]=null,n[c]=null,r(m(void 0,!0))),n[u]=!0}),e.on(`readable`,g.bind(null,n)),n}})),wt=O(((e,t)=>{t.exports=function(){throw Error(`Readable.from is not available in the browser`)}})),Tt=O(((e,t)=>{t.exports=E;var n;E.ReadableState=T,it().EventEmitter;var r=function(e,t){return e.listeners(t).length},i=pt(),a=st().Buffer,o=(typeof global<`u`?global:typeof window<`u`?window:typeof self<`u`?self:{}).Uint8Array||function(){};function s(e){return a.from(e)}function c(e){return a.isBuffer(e)||e instanceof o}var l=mt(),u=l&&l.debuglog?l.debuglog(`stream`):function(){},d=ht(),f=gt(),p=_t().getHighWaterMark,m=Q().codes,h=m.ERR_INVALID_ARG_TYPE,g=m.ERR_STREAM_PUSH_AFTER_EOF,_=m.ERR_METHOD_NOT_IMPLEMENTED,v=m.ERR_STREAM_UNSHIFT_AFTER_END_EVENT,y,b,x;Z()(E,i);var S=f.errorOrDestroy,C=[`error`,`close`,`destroy`,`pause`,`resume`];function w(e,t,n){if(typeof e.prependListener==`function`)return e.prependListener(t,n);!e._events||!e._events[t]?e.on(t,n):Array.isArray(e._events[t])?e._events[t].unshift(n):e._events[t]=[n,e._events[t]]}function T(e,t,r){n||=$(),e||={},typeof r!=`boolean`&&(r=t instanceof n),this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.readableObjectMode),this.highWaterMark=p(this,e,`readableHighWaterMark`,r),this.buffer=new d,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.paused=!0,this.emitClose=e.emitClose!==!1,this.autoDestroy=!!e.autoDestroy,this.destroyed=!1,this.defaultEncoding=e.defaultEncoding||`utf8`,this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(y||=xt().StringDecoder,this.decoder=new y(e.encoding),this.encoding=e.encoding)}function E(e){if(n||=$(),!(this instanceof E))return new E(e);var t=this instanceof n;this._readableState=new T(e,this,t),this.readable=!0,e&&(typeof e.read==`function`&&(this._read=e.read),typeof e.destroy==`function`&&(this._destroy=e.destroy)),i.call(this)}Object.defineProperty(E.prototype,`destroyed`,{enumerable:!1,get:function(){return this._readableState===void 0?!1:this._readableState.destroyed},set:function(e){this._readableState&&(this._readableState.destroyed=e)}}),E.prototype.destroy=f.destroy,E.prototype._undestroy=f.undestroy,E.prototype._destroy=function(e,t){t(e)},E.prototype.push=function(e,t){var n=this._readableState,r;return n.objectMode?r=!0:typeof e==`string`&&(t||=n.defaultEncoding,t!==n.encoding&&(e=a.from(e,t),t=``),r=!0),D(this,e,t,!1,r)},E.prototype.unshift=function(e){return D(this,e,null,!0,!1)};function D(e,t,n,r,i){u(`readableAddChunk`,t);var o=e._readableState;if(t===null)o.reading=!1,M(e,o);else{var c;if(i||(c=ee(o,t)),c)S(e,c);else if(o.objectMode||t&&t.length>0)if(typeof t!=`string`&&!o.objectMode&&Object.getPrototypeOf(t)!==a.prototype&&(t=s(t)),r)o.endEmitted?S(e,new v):O(e,o,t,!0);else if(o.ended)S(e,new g);else if(o.destroyed)return!1;else o.reading=!1,o.decoder&&!n?(t=o.decoder.write(t),o.objectMode||t.length!==0?O(e,o,t,!1):F(e,o)):O(e,o,t,!1);else r||(o.reading=!1,F(e,o))}return!o.ended&&(o.length=k?e=k:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}function j(e,t){return e<=0||t.length===0&&t.ended?0:t.objectMode?1:e===e?(e>t.highWaterMark&&(t.highWaterMark=A(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0)):t.flowing&&t.length?t.buffer.head.data.length:t.length}E.prototype.read=function(e){u(`read`,e),e=parseInt(e,10);var t=this._readableState,n=e;if(e!==0&&(t.emittedReadable=!1),e===0&&t.needReadable&&((t.highWaterMark===0?t.length>0:t.length>=t.highWaterMark)||t.ended))return u(`read: emitReadable`,t.length,t.ended),t.length===0&&t.ended?H(this):N(this),null;if(e=j(e,t),e===0&&t.ended)return t.length===0&&H(this),null;var r=t.needReadable;u(`need readable`,r),(t.length===0||t.length-e0?V(e,t):null;return i===null?(t.needReadable=t.length<=t.highWaterMark,e=0):(t.length-=e,t.awaitDrain=0),t.length===0&&(t.ended||(t.needReadable=!0),n!==e&&t.ended&&H(this)),i!==null&&this.emit(`data`,i),i};function M(e,t){if(u(`onEofChunk`),!t.ended){if(t.decoder){var n=t.decoder.end();n&&n.length&&(t.buffer.push(n),t.length+=t.objectMode?1:n.length)}t.ended=!0,t.sync?N(e):(t.needReadable=!1,t.emittedReadable||(t.emittedReadable=!0,P(e)))}}function N(e){var t=e._readableState;u(`emitReadable`,t.needReadable,t.emittedReadable),t.needReadable=!1,t.emittedReadable||(u(`emitReadable`,t.flowing),t.emittedReadable=!0,process.nextTick(P,e))}function P(e){var t=e._readableState;u(`emitReadable_`,t.destroyed,t.length,t.ended),!t.destroyed&&(t.length||t.ended)&&(e.emit(`readable`),t.emittedReadable=!1),t.needReadable=!t.flowing&&!t.ended&&t.length<=t.highWaterMark,B(e)}function F(e,t){t.readingMore||(t.readingMore=!0,process.nextTick(I,e,t))}function I(e,t){for(;!t.reading&&!t.ended&&(t.length1&&W(i.pipes,e)!==-1)&&!l&&(u(`false write response, pause`,i.awaitDrain),i.awaitDrain++),n.pause())}function p(t){u(`onerror`,t),g(),e.removeListener(`error`,p),r(e,`error`)===0&&S(e,t)}w(e,`error`,p);function m(){e.removeListener(`finish`,h),g()}e.once(`close`,m);function h(){u(`onfinish`),e.removeListener(`close`,m),g()}e.once(`finish`,h);function g(){u(`unpipe`),n.unpipe(e)}return e.emit(`pipe`,n),i.flowing||(u(`pipe resume`),n.resume()),e};function L(e){return function(){var t=e._readableState;u(`pipeOnDrain`,t.awaitDrain),t.awaitDrain&&t.awaitDrain--,t.awaitDrain===0&&r(e,`data`)&&(t.flowing=!0,B(e))}}E.prototype.unpipe=function(e){var t=this._readableState,n={hasUnpiped:!1};if(t.pipesCount===0)return this;if(t.pipesCount===1)return e&&e!==t.pipes?this:(e||=t.pipes,t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit(`unpipe`,this,n),this);if(!e){var r=t.pipes,i=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var a=0;a0,r.flowing!==!1&&this.resume()):e===`readable`&&!r.endEmitted&&!r.readableListening&&(r.readableListening=r.needReadable=!0,r.flowing=!1,r.emittedReadable=!1,u(`on readable`,r.length,r.reading),r.length?N(this):r.reading||process.nextTick(z,this)),n},E.prototype.addListener=E.prototype.on,E.prototype.removeListener=function(e,t){var n=i.prototype.removeListener.call(this,e,t);return e===`readable`&&process.nextTick(R,this),n},E.prototype.removeAllListeners=function(e){var t=i.prototype.removeAllListeners.apply(this,arguments);return(e===`readable`||e===void 0)&&process.nextTick(R,this),t};function R(e){var t=e._readableState;t.readableListening=e.listenerCount(`readable`)>0,t.resumeScheduled&&!t.paused?t.flowing=!0:e.listenerCount(`data`)>0&&e.resume()}function z(e){u(`readable nexttick read 0`),e.read(0)}E.prototype.resume=function(){var e=this._readableState;return e.flowing||(u(`resume`),e.flowing=!e.readableListening,te(this,e)),e.paused=!1,this};function te(e,t){t.resumeScheduled||(t.resumeScheduled=!0,process.nextTick(ne,e,t))}function ne(e,t){u(`resume`,t.reading),t.reading||e.read(0),t.resumeScheduled=!1,e.emit(`resume`),B(e),t.flowing&&!t.reading&&e.read(0)}E.prototype.pause=function(){return u(`call pause flowing=%j`,this._readableState.flowing),this._readableState.flowing!==!1&&(u(`pause`),this._readableState.flowing=!1,this.emit(`pause`)),this._readableState.paused=!0,this};function B(e){var t=e._readableState;for(u(`flow`,t.flowing);t.flowing&&e.read()!==null;);}E.prototype.wrap=function(e){var t=this,n=this._readableState,r=!1;for(var i in e.on(`end`,function(){if(u(`wrapped end`),n.decoder&&!n.ended){var e=n.decoder.end();e&&e.length&&t.push(e)}t.push(null)}),e.on(`data`,function(i){u(`wrapped data`),n.decoder&&(i=n.decoder.write(i)),!(n.objectMode&&i==null)&&(!n.objectMode&&(!i||!i.length)||t.push(i)||(r=!0,e.pause()))}),e)this[i]===void 0&&typeof e[i]==`function`&&(this[i]=function(t){return function(){return e[t].apply(e,arguments)}}(i));for(var a=0;a=t.length?(n=t.decoder?t.buffer.join(``):t.buffer.length===1?t.buffer.first():t.buffer.concat(t.length),t.buffer.clear()):n=t.buffer.consume(e,t.decoder),n}function H(e){var t=e._readableState;u(`endReadable`,t.endEmitted),t.endEmitted||(t.ended=!0,process.nextTick(U,t,e))}function U(e,t){if(u(`endReadableNT`,e.endEmitted,e.length),!e.endEmitted&&e.length===0&&(e.endEmitted=!0,t.readable=!1,t.emit(`end`),e.autoDestroy)){var n=t._writableState;(!n||n.autoDestroy&&n.finished)&&t.destroy()}}typeof Symbol==`function`&&(E.from=function(e,t){return x===void 0&&(x=wt()),x(E,e,t)});function W(e,t){for(var n=0,r=e.length;n{t.exports=l;var n=Q().codes,r=n.ERR_METHOD_NOT_IMPLEMENTED,i=n.ERR_MULTIPLE_CALLBACK,a=n.ERR_TRANSFORM_ALREADY_TRANSFORMING,o=n.ERR_TRANSFORM_WITH_LENGTH_0,s=$();Z()(l,s);function c(e,t){var n=this._transformState;n.transforming=!1;var r=n.writecb;if(r===null)return this.emit(`error`,new i);n.writechunk=null,n.writecb=null,t!=null&&this.push(t),r(e);var a=this._readableState;a.reading=!1,(a.needReadable||a.length{t.exports=r;var n=Et();Z()(r,n);function r(e){if(!(this instanceof r))return new r(e);n.call(this,e)}r.prototype._transform=function(e,t,n){n(null,e)}})),Ot=O(((e,t)=>{var n;function r(e){var t=!1;return function(){t||(t=!0,e.apply(void 0,arguments))}}var i=Q().codes,a=i.ERR_MISSING_ARGS,o=i.ERR_STREAM_DESTROYED;function s(e){if(e)throw e}function c(e){return e.setHeader&&typeof e.abort==`function`}function l(e,t,i,a){a=r(a);var s=!1;e.on(`close`,function(){s=!0}),n===void 0&&(n=St()),n(e,{readable:t,writable:i},function(e){if(e)return a(e);s=!0,a()});var l=!1;return function(t){if(!s&&!l){if(l=!0,c(e))return e.abort();if(typeof e.destroy==`function`)return e.destroy();a(t||new o(`pipe`))}}}function u(e){e()}function d(e,t){return e.pipe(t)}function f(e){return!e.length||typeof e[e.length-1]!=`function`?s:e.pop()}function p(){var e=[...arguments],t=f(e);if(Array.isArray(e[0])&&(e=e[0]),e.length<2)throw new a(`streams`);var n,r=e.map(function(i,a){var o=a0,function(e){n||=e,e&&r.forEach(u),!o&&(r.forEach(u),t(n))})});return e.reduce(d)}t.exports=p})),kt=O(((e,t)=>{t.exports=r;var n=it().EventEmitter;Z()(r,n),r.Readable=Tt(),r.Writable=yt(),r.Duplex=$(),r.Transform=Et(),r.PassThrough=Dt(),r.finished=St(),r.pipeline=Ot(),r.Stream=r;function r(){n.call(this)}r.prototype.pipe=function(e,t){var r=this;function i(t){e.writable&&!1===e.write(t)&&r.pause&&r.pause()}r.on(`data`,i);function a(){r.readable&&r.resume&&r.resume()}e.on(`drain`,a),!e._isStdio&&(!t||t.end!==!1)&&(r.on(`end`,s),r.on(`close`,c));var o=!1;function s(){o||(o=!0,e.end())}function c(){o||(o=!0,typeof e.destroy==`function`&&e.destroy())}function l(e){if(u(),n.listenerCount(this,`error`)===0)throw e}r.on(`error`,l),e.on(`error`,l);function u(){r.removeListener(`data`,i),e.removeListener(`drain`,a),r.removeListener(`end`,s),r.removeListener(`close`,c),r.removeListener(`error`,l),e.removeListener(`error`,l),r.removeListener(`end`,u),r.removeListener(`close`,u),e.removeListener(`close`,u)}return r.on(`end`,u),r.on(`close`,u),e.on(`close`,u),e.emit(`pipe`,r),e}}))();async function*At(e,t,n){let r=1,i={chunks:[],length:0};for await(let a of n(e))for(i.chunks.push(a),i.length+=a.byteLength;i.length>t;){let e=i.chunks.length>1?Y.Buffer.concat(i.chunks):i.chunks[0];yield{partNumber:r,data:e.subarray(0,t)},i.chunks=[e.subarray(t)],i.length=i.chunks[0].byteLength,r+=1}yield{partNumber:r,data:i.chunks.length===1?i.chunks[0]:Y.Buffer.concat(i.chunks),lastPart:!0}}async function*jt(e,t){let n=1,r=0,i=t;for(;i{if(e instanceof Uint8Array)return jt(e,t);if(e instanceof kt.Readable)return At(e,t,Mt);if(e instanceof String||typeof e==`string`)return jt(Y.Buffer.from(e),t);if(typeof e.stream==`function`)return At(e.stream(),t,Nt);if(e instanceof ReadableStream)return At(e,t,Nt);throw Error(`Body Data is unsupported format, expected data to be one of: string | Uint8Array | Buffer | Readable | ReadableStream | Blob;.`)},Ft=class e extends lt.EventEmitter{static MIN_PART_SIZE=1024*1024*5;MAX_PARTS=1e4;queueSize=4;partSize;leavePartsOnError=!1;tags=[];client;params;totalBytes;totalBytesSource;bytesUploadedSoFar;abortController;concurrentUploaders=[];createMultiPartPromise;abortMultipartUploadCommand=null;uploadedParts=[];uploadEnqueuedPartsCount=0;expectedPartsCount;uploadId;uploadEvent;isMultiPart=!0;singleUploadResult;sent=!1;constructor(t){if(super(),this.queueSize=t.queueSize||this.queueSize,this.leavePartsOnError=t.leavePartsOnError||this.leavePartsOnError,this.tags=t.tags||this.tags,this.client=t.client,this.params=t.params,!this.params)throw Error(`InputError: Upload requires params to be passed to upload.`);this.totalBytes=this.params.ContentLength??dt(this.params.Body),this.totalBytesSource=ft(this.params.Body,this.params.ContentLength),this.bytesUploadedSoFar=0,this.abortController=t.abortController??new AbortController,this.partSize=t.partSize||Math.max(e.MIN_PART_SIZE,Math.ceil((this.totalBytes||0)/this.MAX_PARTS)),this.totalBytes!==void 0&&(this.expectedPartsCount=Math.ceil(this.totalBytes/this.partSize)),this.__validateInput()}async abort(){this.abortController.abort()}async done(){if(this.sent)throw Error(`@aws-sdk/lib-storage: this instance of Upload has already executed .done(). Create a new instance.`);return this.sent=!0,await Promise.race([this.__doMultipartUpload(),this.__abortTimeout(this.abortController.signal)])}on(e,t){return this.uploadEvent=e,super.on(e,t)}async __uploadUsingPut(e){this.isMultiPart=!1;let t={...this.params,Body:e.data},n=this.client.config,r=n.requestHandler,i=r instanceof lt.EventEmitter?r:null,o=t=>{this.bytesUploadedSoFar=t.loaded,this.totalBytes=t.total,this.__notifyProgress({loaded:this.bytesUploadedSoFar,total:this.totalBytes,part:e.partNumber,Key:this.params.Key,Bucket:this.params.Bucket})};i!==null&&i.on(`xhr.upload.progress`,o);let c=await Promise.all([this.client.send(new et(t)),n?.endpoint?.()]),l=c[0],d=c[1];if(d||=u(await a(t,et,{...n})),!d)throw Error(`Could not resolve endpoint from S3 "client.config.endpoint()" nor EndpointsV2.`);i!==null&&i.off(`xhr.upload.progress`,o);let f=this.params.Key.split(`/`).map(e=>s(e)).join(`/`),p=s(this.params.Bucket),m=(()=>{let e=d.hostname.startsWith(`${p}.`),t=this.client.config.forcePathStyle,n=d.port?`:${d.port}`:``;return t?`${d.protocol}//${d.hostname}${n}/${p}/${f}`:e?`${d.protocol}//${d.hostname}${n}/${f}`:`${d.protocol}//${p}.${d.hostname}${n}/${f}`})();this.singleUploadResult={...l,Bucket:this.params.Bucket,Key:this.params.Key,Location:m};let h=dt(e.data);this.__notifyProgress({loaded:h,total:h,part:1,Key:this.params.Key,Bucket:this.params.Bucket})}async __createMultipartUpload(){let e=await this.client.config.requestChecksumCalculation();if(!this.createMultiPartPromise){let t={...this.params,Body:void 0};e===`WHEN_SUPPORTED`&&(t.ChecksumAlgorithm=this.params.ChecksumAlgorithm||rt.CRC32),this.createMultiPartPromise=this.client.send(new Qe(t)).then(e=>(this.abortMultipartUploadCommand=new He({Bucket:this.params.Bucket,Key:this.params.Key,UploadId:e.UploadId}),e))}return this.createMultiPartPromise}async __doConcurrentUpload(e){for await(let t of e){if(this.uploadEnqueuedPartsCount>this.MAX_PARTS)throw Error(`Exceeded ${this.MAX_PARTS} parts in multipart upload to Bucket: ${this.params.Bucket} Key: ${this.params.Key}.`);if(this.abortController.signal.aborted)return;if(t.partNumber===1&&t.lastPart)return await this.__uploadUsingPut(t);if(!this.uploadId){let{UploadId:e}=await this.__createMultipartUpload();if(this.uploadId=e,this.abortController.signal.aborted)return}let e=dt(t.data)||0,n=this.client.config.requestHandler,r=n instanceof lt.EventEmitter?n:null,i=0,a=(n,r)=>{(Number(r.query.partNumber)||-1)===t.partNumber&&(n.total&&e&&(this.bytesUploadedSoFar+=n.loaded-i,i=n.loaded),this.__notifyProgress({loaded:this.bytesUploadedSoFar,total:this.totalBytes,part:t.partNumber,Key:this.params.Key,Bucket:this.params.Bucket}))};r!==null&&r.on(`xhr.upload.progress`,a),this.uploadEnqueuedPartsCount+=1,this.__validateUploadPart(t);let o=await this.client.send(new nt({...this.params,ContentLength:void 0,UploadId:this.uploadId,Body:t.data,PartNumber:t.partNumber}));if(r!==null&&r.off(`xhr.upload.progress`,a),this.abortController.signal.aborted)return;if(!o.ETag)throw Error(`Part ${t.partNumber} is missing ETag in UploadPart response. Missing Bucket CORS configuration for ETag header?`);this.uploadedParts.push({PartNumber:t.partNumber,ETag:o.ETag,...o.ChecksumCRC32&&{ChecksumCRC32:o.ChecksumCRC32},...o.ChecksumCRC32C&&{ChecksumCRC32C:o.ChecksumCRC32C},...o.ChecksumSHA1&&{ChecksumSHA1:o.ChecksumSHA1},...o.ChecksumSHA256&&{ChecksumSHA256:o.ChecksumSHA256}}),r===null&&(this.bytesUploadedSoFar+=e),this.__notifyProgress({loaded:this.bytesUploadedSoFar,total:this.totalBytes,part:t.partNumber,Key:this.params.Key,Bucket:this.params.Bucket})}}async __doMultipartUpload(){let e=Pt(this.params.Body,this.partSize),t=[];for(let n=0;n{t.push(e)});this.concurrentUploaders.push(n)}if(await Promise.all(this.concurrentUploaders),t.length>=1)throw await this.markUploadAsAborted(),t[0];if(this.abortController.signal.aborted)throw await this.markUploadAsAborted(),Object.assign(Error(`Upload aborted.`),{name:`AbortError`});let n;if(this.isMultiPart){let{expectedPartsCount:e,uploadedParts:t,totalBytes:r,totalBytesSource:i}=this;if(r!==void 0&&e!==void 0&&t.length!==e)throw Error(`Expected ${e} part(s) but uploaded ${t.length} part(s). The expected part count is based on the byte-count of the input.params.Body, which was read from ${i} and is ${r}. If this is not correct, provide an override value by setting a number to input.params.ContentLength in bytes. -`);this.uploadedParts.sort((e,t)=>e.PartNumber-t.PartNumber);let a={...this.params,Body:void 0,UploadId:this.uploadId,MultipartUpload:{Parts:this.uploadedParts}};n=await this.client.send(new qe(a)),typeof n?.Location==`string`&&n.Location.includes(`%2F`)&&(n.Location=n.Location.replace(/%2F/g,`/`))}else n=this.singleUploadResult;return this.abortMultipartUploadCommand=null,this.tags.length&&await this.client.send(new tt({...this.params,Tagging:{TagSet:this.tags}})),n}async markUploadAsAborted(){this.uploadId&&!this.leavePartsOnError&&this.abortMultipartUploadCommand!==null&&(await this.client.send(this.abortMultipartUploadCommand),this.abortMultipartUploadCommand=null)}__notifyProgress(e){this.uploadEvent&&this.emit(this.uploadEvent,e)}async __abortTimeout(e){return new Promise((t,n)=>{e.onabort=()=>{let e=Error(`Upload aborted.`);e.name=`AbortError`,n(e)}})}__validateUploadPart(e){let t=dt(e.data);if(t===void 0)throw Error(`A dataPart was generated without a measurable data chunk size for part number ${e.partNumber}`);if(!(e.partNumber===1&&e.lastPart)&&!e.lastPart&&t!==this.partSize)throw Error(`The byte size for part number ${e.partNumber}, size ${t} does not match expected size ${this.partSize}`)}__validateInput(){if(!this.client)throw Error(`InputError: Upload requires a AWS client to do uploads with.`);if(this.partSize{n.invalidateQueries({queryKey:[`s3`,`buckets`,t.bucket,`objects`]})}},t[0]=n,t[1]=r),e(r)}async function Lt(e){let{bucket:t,key:n,file:r}=e;return await new Ft({client:v(),params:{Bucket:t,Key:n,Body:r,ContentType:r.type}}).done()}function Rt(){let t=(0,ct.c)(2),n=O(),r;return t[0]===n?r=t[1]:(r={mutationFn:zt,onSuccess:()=>{n.invalidateQueries({queryKey:[`s3`,`buckets`]})}},t[0]=n,t[1]=r),e(r)}async function zt(e){let{bucketName:t}=e,n=new Ze({Bucket:t});return await v().send(n)}function Bt(){let t=(0,ct.c)(2),n=O(),r;return t[0]===n?r=t[1]:(r={mutationFn:Vt,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`s3`,`buckets`,t.bucket,`objects`]})}},t[0]=n,t[1]=r),e(r)}async function Vt(e){let{bucket:t,key:n}=e,r=new $e({Bucket:t,Key:n});return await v().send(r)}export{Le as a,J as i,Bt as n,It as r,Rt as t}; \ No newline at end of file +`);this.uploadedParts.sort((e,t)=>e.PartNumber-t.PartNumber);let a={...this.params,Body:void 0,UploadId:this.uploadId,MultipartUpload:{Parts:this.uploadedParts}};n=await this.client.send(new qe(a)),typeof n?.Location==`string`&&n.Location.includes(`%2F`)&&(n.Location=n.Location.replace(/%2F/g,`/`))}else n=this.singleUploadResult;return this.abortMultipartUploadCommand=null,this.tags.length&&await this.client.send(new tt({...this.params,Tagging:{TagSet:this.tags}})),n}async markUploadAsAborted(){this.uploadId&&!this.leavePartsOnError&&this.abortMultipartUploadCommand!==null&&(await this.client.send(this.abortMultipartUploadCommand),this.abortMultipartUploadCommand=null)}__notifyProgress(e){this.uploadEvent&&this.emit(this.uploadEvent,e)}async __abortTimeout(e){return new Promise((t,n)=>{e.onabort=()=>{let e=Error(`Upload aborted.`);e.name=`AbortError`,n(e)}})}__validateUploadPart(e){let t=dt(e.data);if(t===void 0)throw Error(`A dataPart was generated without a measurable data chunk size for part number ${e.partNumber}`);if(!(e.partNumber===1&&e.lastPart)&&!e.lastPart&&t!==this.partSize)throw Error(`The byte size for part number ${e.partNumber}, size ${t} does not match expected size ${this.partSize}`)}__validateInput(){if(!this.client)throw Error(`InputError: Upload requires a AWS client to do uploads with.`);if(this.partSize{n.invalidateQueries({queryKey:[`s3`,`buckets`,t.bucket,`objects`]})}},t[0]=n,t[1]=i),e(i)}async function Lt(e){let{bucket:t,key:n,file:r}=e;return await new Ft({client:k(),params:{Bucket:t,Key:n,Body:r,ContentType:r.type}}).done()}function Rt(){let t=(0,ct.c)(2),n=r(),i;return t[0]===n?i=t[1]:(i={mutationFn:zt,onSuccess:()=>{n.invalidateQueries({queryKey:[`s3`,`buckets`]})}},t[0]=n,t[1]=i),e(i)}async function zt(e){let{bucketName:t}=e,n=new Ze({Bucket:t});return await k().send(n)}function Bt(){let t=(0,ct.c)(2),n=r(),i;return t[0]===n?i=t[1]:(i={mutationFn:Vt,onSuccess:(e,t)=>{n.invalidateQueries({queryKey:[`s3`,`buckets`,t.bucket,`objects`]})}},t[0]=n,t[1]=i),e(i)}async function Vt(e){let{bucket:t,key:n}=e,r=new $e({Bucket:t,Key:n});return await k().send(r)}export{Ie as a,Ge as i,Bt as n,It as r,Rt as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/select.js b/spinifex/services/spinifexui/frontend/dist/assets/select.js index 8a12c3673..c1635c9d4 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/select.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/select.js @@ -1 +1 @@ -import{t as e}from"./check.js";import{t}from"./chevron-down.js";import{$a as n,$i as r,$r as i,Ai as a,Ar as o,Ba as s,Ca as c,Cr as l,Di as u,Ei as d,Fi as f,Fr as p,Ha as m,Ia as h,Ii as g,Ir as _,Ji as v,Ki as y,Li as b,Mr as x,Ni as S,Nr as C,Oa as w,Oi as T,Pi as ee,Po as E,Qi as D,Ri as O,Sa as k,Sr as A,Tr as j,Ui as te,Va as M,Vi as N,Wi as P,Wr as F,Xa as ne,Xi as I,Yi as re,Zi as ie,_a as L,aa as ae,ai as R,ao as z,ba as B,bi as V,ca as H,ci as U,da as W,di as G,ea as oe,ei as se,eo as ce,fa as K,fi as le,ga as q,ha as ue,hi as de,ho as fe,ia as pe,ii as me,io as he,ji as ge,jr as _e,ki as ve,la as ye,li as be,ma as xe,mi as Se,mo as Ce,na as we,ni as J,no as Te,oa as Ee,oi as De,oo as Oe,pa as ke,pi as Ae,qi as je,ra as Me,ri as Y,ro as Ne,sa as Pe,si as Fe,so as Ie,ta as Le,ti as Re,to as ze,ua as Be,ui as Ve,va as He,wa as Ue,wi as We,wr as Ge,xa as Ke,xi as qe,ya as Je,yi as Ye,za as X}from"./index.js";var Xe=ne(`chevron-up`,[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]]),Z=Ce(),Q=E(fe()),Ze=Q.createContext({formRef:{current:{fields:new Map}},errors:{},clearErrors:Te,validationMode:`onSubmit`,submitAttemptedRef:{current:!1}});function Qe(){return Q.useContext(Ze)}function $e(e,t={}){let n=`rootStore`in e?e.rootStore:e,r=n.context.dataRef,{enabled:i=!0,event:a=`click`,toggle:o=!0,ignoreMouse:s=!1,stickIfOpen:c=!0,touchOpenDelay:l=0,reason:u=S}=t,f=Q.useRef(void 0),p=te(),m=P(),h=Q.useMemo(()=>({onPointerDown(e){f.current=e.pointerType},onMouseDown(e){let t=f.current,i=e.nativeEvent,h=n.select(`open`);if(e.button!==0||a===`click`||pe(t,!0)&&s)return;let g=r.current.openEvent,_=g?.type,v=n.select(`domReferenceElement`)!==e.currentTarget,y=h&&v||!(h&&o&&(!(g&&c)||_===`click`||_===`mousedown`)),b=ke(i);if(Be(b)){let e=d(u,i,b);y&&t===`touch`&&l>0?m.start(l,()=>{n.setOpen(!0,e)}):n.setOpen(y,e);return}let x=e.currentTarget;p.request(()=>{let e=d(u,i,x);y&&t===`touch`&&l>0?m.start(l,()=>{n.setOpen(!0,e)}):n.setOpen(y,e)})},onClick(e){if(a===`mousedown-only`)return;let t=f.current;if(a===`mousedown`&&t){f.current=void 0;return}if(pe(t,!0)&&s)return;let i=n.select(`open`),p=r.current.openEvent,h=n.select(`domReferenceElement`)!==e.currentTarget,g=i&&h||!(i&&o&&(!(p&&c)||Me(p))),_=d(u,e.nativeEvent,e.currentTarget);g&&t===`touch`&&l>0?m.start(l,()=>{n.setOpen(!0,_)}):n.setOpen(g,_)},onKeyDown(){f.current=void 0}}),[r,a,s,n,c,o,p,m,l,u]);return Q.useMemo(()=>i?{reference:h}:ze,[i,h])}var et=`Escape`;function tt(e,t,n){switch(e){case`vertical`:return t;case`horizontal`:return n;default:return t||n}}function nt(e,t){return tt(t,e===`ArrowUp`||e===`ArrowDown`,e===`ArrowLeft`||e===`ArrowRight`)}function rt(e,t,n){return tt(t,e===`ArrowDown`,n?e===`ArrowLeft`:e===`ArrowRight`)||e===`Enter`||e===` `||e===``}function it(e,t,n){return tt(t,n?e===ue:e===q,e===xe)}function at(e,t,n,r){return t===`both`||t===`horizontal`&&r&&r>1?e===et:tt(t,n?e===q:e===ue,e===L)}function ot(e,t){let n=`rootStore`in e?e.rootStore:e,r=n.useState(`open`),i=n.useState(`floatingElement`),o=n.useState(`domReferenceElement`),c=n.context.dataRef,{listRef:l,activeIndex:u,onNavigate:f=()=>{},enabled:p=!0,selectedIndex:h=null,allowEscape:g=!1,loopFocus:_=!1,nested:b=!1,rtl:x=!1,virtual:S=!1,focusItemOnOpen:C=`auto`,focusItemOnHover:w=!0,openOnArrowKeyDown:ee=!0,disabledIndices:E=void 0,orientation:O=`vertical`,parentOrientation:k,cols:A=1,id:j,resetOnPointerLeave:te=!0,externalTree:M}=t,N=Se(H(i)),P=Fe(),F=U(M);X(()=>{c.current.orientation=O},[c,O]);let ne=ye(o),L=Q.useRef(C),R=Q.useRef(h??-1),z=Q.useRef(null),B=Q.useRef(!0),V=s(e=>{f(R.current===-1?null:R.current,e)}),se=Q.useRef(V),ce=Q.useRef(!!i),le=Q.useRef(r),q=Q.useRef(!1),ue=Q.useRef(!1),de=Q.useRef(null),fe=Se(E),pe=Se(r),me=Se(h),he=Se(te),ge=s(()=>{function e(e){S?F?.events.emit(`virtualfocus`,e):de.current=G(e,{sync:q.current,preventScroll:!0})}let t=l.current[R.current],n=ue.current;t&&e(t),(q.current?e=>e():requestAnimationFrame)(()=>{let r=l.current[R.current]||t;r&&(t||e(r),be&&(n||!B.current)&&r.scrollIntoView?.({block:`nearest`,inline:`nearest`}))})});X(()=>{p&&(r&&i?(R.current=h??-1,L.current&&h!=null&&(ue.current=!0,V())):ce.current&&(R.current=-1,se.current()))},[p,r,i,h,V]),X(()=>{if(p){if(!r){q.current=!1;return}if(i)if(u==null){if(q.current=!1,me.current!=null)return;if(ce.current&&(R.current=-1,ge()),(!le.current||!ce.current)&&L.current&&(z.current!=null||L.current===!0&&z.current==null)){let e=0,t=()=>{l.current[0]==null?(e<2&&(e?requestAnimationFrame:queueMicrotask)(t),e+=1):(R.current=z.current==null||rt(z.current,O,x)||b?D(l):ie(l),z.current=null,V())};t()}}else oe(l.current,u)||(R.current=u,ge(),ue.current=!1)}},[p,r,i,u,me,b,l,O,x,V,ge,fe]),X(()=>{if(!p||i||!F||S||!ce.current)return;let e=F.nodesRef.current,t=e.find(e=>e.id===P)?.context?.elements.floating,n=W(Je(i)),r=e.some(e=>e.context&&K(e.context.elements.floating,n));t&&!r&&B.current&&t.focus({preventScroll:!0})},[p,i,F,P,S]),X(()=>{se.current=V,le.current=r,ce.current=!!i}),X(()=>{r||(z.current=null,L.current=C)},[r,C]);let _e=u!=null,ve=s(e=>{if(!pe.current)return;let t=l.current.indexOf(e.currentTarget);t!==-1&&(R.current!==t||u!==t)&&(R.current=t,V(e))}),be=Q.useMemo(()=>({onFocus(e){q.current=!0,ve(e)},onClick:({currentTarget:e})=>e.focus({preventScroll:!0}),onMouseMove(e){q.current=!0,ue.current=!1,w&&ve(e)},onPointerLeave(e){if(!pe.current||!B.current||e.pointerType===`touch`)return;q.current=!0;let t=e.relatedTarget;if(!(!w||l.current.includes(t))&&he.current&&(de.current?.(),de.current=null,R.current=-1,V(e),!S)){let e=N.current,t=W(Je(e));e&&K(e,t)&&e.focus({preventScroll:!0})}}}),[ve,pe,N,w,l,V,he,S]),xe=Q.useCallback(()=>k??F?.nodesRef.current.find(e=>e.id===P)?.context?.dataRef?.current.orientation,[P,F,k]),Ce=s(e=>{if(B.current=!1,q.current=!0,e.which===229||!pe.current&&e.currentTarget===N.current)return;if(b&&at(e.key,O,x,A)){nt(e.key,xe())||Pe(e),n.setOpen(!1,d(a,e.nativeEvent)),m(o)&&(S?F?.events.emit(`virtualfocus`,o):o.focus());return}let t=R.current,i=D(l,E),s=ie(l,E);if(ne||(e.key===`Home`&&(Pe(e),R.current=i,V(e)),e.key===`End`&&(Pe(e),R.current=s,V(e))),A>1){let t=Array.from({length:l.current.length},()=>({width:1,height:1})),n=y(t,A,!1),r=n.findIndex(e=>e!=null&&!Le(l.current,e,E)),a=n.reduce((e,t,n)=>t!=null&&!Le(l.current,t,E)?n:e,-1),o=n[I(n.map(e=>e==null?null:l.current[e]),{event:e,orientation:O,loopFocus:_,rtl:x,cols:A,disabledIndices:re([...(typeof E==`function`?null:E)||l.current.map((e,t)=>Le(l.current,t,E)?t:void 0),void 0],n),minIndex:r,maxIndex:a,prevIndex:v(R.current>s?i:R.current,t,n,A,e.key===`ArrowDown`?`bl`:e.key===(x?`ArrowLeft`:`ArrowRight`)?`tr`:`tl`),stopEvent:!0})];if(o!=null&&(R.current=o,V(e)),O===`both`)return}if(nt(e.key,O)){if(Pe(e),r&&!S&&W(e.currentTarget.ownerDocument)===e.currentTarget){R.current=rt(e.key,O,x)?i:s,V(e);return}rt(e.key,O,x)?_?t>=s?g&&t!==l.current.length?R.current=-1:(q.current=!1,R.current=i):R.current=je(l.current,{startingIndex:t,disabledIndices:E}):R.current=Math.min(s,je(l.current,{startingIndex:t,disabledIndices:E})):_?t<=i?g&&t!==-1?R.current=l.current.length:(q.current=!1,R.current=s):R.current=je(l.current,{startingIndex:t,decrement:!0,disabledIndices:E}):R.current=Math.max(i,je(l.current,{startingIndex:t,decrement:!0,disabledIndices:E})),oe(l.current,R.current)&&(R.current=-1),V(e)}}),we=Q.useMemo(()=>S&&r&&_e&&{"aria-activedescendant":`${j}-${u}`},[S,r,_e,j,u]),J=Q.useMemo(()=>({"aria-orientation":O===`both`?void 0:O,...ne?{}:we,onKeyDown(e){if(e.key===`Tab`&&e.shiftKey&&r&&!S){let t=ke(e.nativeEvent);if(t&&!K(N.current,t))return;Pe(e),n.setOpen(!1,d(T,e.nativeEvent)),m(o)&&o.focus();return}Ce(e)},onPointerMove(){B.current=!0}}),[we,Ce,N,O,ne,n,r,S,o]),Te=Q.useMemo(()=>{function e(e){C===`auto`&&ae(e.nativeEvent)&&(L.current=!S)}function t(e){L.current=C,C===`auto`&&Ee(e.nativeEvent)&&(L.current=!0)}return{onKeyDown(e){let t=n.select(`open`);B.current=!1;let r=e.key.startsWith(`Arrow`),i=it(e.key,xe(),x),o=nt(e.key,O),s=(b?i:o)||e.key===`Enter`||e.key.trim()===``;if(S&&t)return Ce(e);if(!(!t&&!ee&&r)){if(s){let t=nt(e.key,xe());z.current=b&&t?null:e.key}if(b){i&&(Pe(e),t?(R.current=D(l,fe.current),V(e)):n.setOpen(!0,d(a,e.nativeEvent,e.currentTarget)));return}o&&(me.current!=null&&(R.current=me.current),Pe(e),!t&&ee?n.setOpen(!0,d(a,e.nativeEvent,e.currentTarget)):Ce(e),t&&V(e))}},onFocus(e){n.select(`open`)&&!S&&(R.current=-1,V(e))},onPointerDown:t,onPointerEnter:t,onMouseDown:e,onClick:e}},[Ce,fe,C,l,b,V,n,ee,O,xe,x,me,S]),De=Q.useMemo(()=>({...we,...Te}),[we,Te]);return Q.useMemo(()=>p?{reference:De,floating:J,item:be,trigger:Te}:{},[p,De,J,Te,be])}function st(e,t){let n=`rootStore`in e?e.rootStore:e,i=n.context.dataRef,a=n.useState(`open`),{listRef:o,elementsRef:c,activeIndex:l,onMatch:u,onTypingChange:d,enabled:f=!0,resetMs:p=750,selectedIndex:m=null}=t,h=P(),g=Q.useRef(``),_=Q.useRef(m??l??-1),v=Q.useRef(null);X(()=>{!a&&m!==null||(h.clear(),v.current=null,g.current!==``&&(g.current=``))},[a,m,h]),X(()=>{a&&g.current===``&&(_.current=m??l??-1)},[a,m,l]);let y=s(e=>{e?i.current.typing||(i.current.typing=e,d?.(e)):i.current.typing&&(i.current.typing=e,d?.(e))}),b=s(e=>{function t(e){let t=c?.current[e];return!t||r(t)}function n(e,n,r=0){if(e.length===0)return-1;let i=(r%e.length+e.length)%e.length,a=n.toLocaleLowerCase();for(let n=0;n0&&e.key===` `&&(Pe(e),y(!0)),g.current.length>0&&g.current[0]!==` `&&n(i,g.current)===-1&&e.key!==` `&&y(!1),i==null||e.key.length!==1||e.ctrlKey||e.metaKey||e.altKey)return;a&&e.key!==` `&&(Pe(e),y(!0));let s=g.current===``;s&&(_.current=m??l??-1),i.every(e=>e?e[0]?.toLocaleLowerCase()!==e[1]?.toLocaleLowerCase():!0)&&g.current===e.key&&(g.current=``,_.current=v.current),g.current+=e.key,h.start(p,()=>{g.current=``,_.current=v.current,y(!1)});let d=((s?m??l??-1:_.current)??0)+1,f=n(i,g.current,d);f===-1?e.key!==` `&&(g.current=``,y(!1)):(u?.(f),v.current=f)}),x=s(e=>{let t=e.relatedTarget,r=n.select(`domReferenceElement`),i=n.select(`floatingElement`),a=K(r,t),o=K(i,t);a||o||(h.clear(),g.current=``,_.current=v.current,y(!1))}),S=Q.useMemo(()=>({onKeyDown:b,onBlur:x}),[b,x]),C=Q.useMemo(()=>({onKeyDown:b,onBlur:x}),[b,x]);return Q.useMemo(()=>f?{reference:S,floating:C}:{},[f,S,C])}function ct(e){let[t,n]=Q.useState({current:e,previous:null});return e!==t.current&&n({current:e,previous:t.current}),t.previous}var lt=Q.createContext(null),ut=Q.createContext(null);function dt(){let e=Q.useContext(lt);if(e===null)throw Error(z(60));return e}function ft(){let e=Q.useContext(ut);if(e===null)throw Error(z(61));return e}var pt=(e,t)=>Object.is(e,t);function mt(e,t,n){return e==null||t==null?Object.is(e,t):n(e,t)}function ht(e,t,n){return!e||e.length===0?!1:e.some(e=>e===void 0?!1:mt(t,e,n))}function gt(e,t,n){return!e||e.length===0?-1:e.findIndex(e=>e===void 0?!1:mt(e,t,n))}function _t(e,t,n){return e.filter(e=>!mt(t,e,n))}function vt(e){if(e==null)return``;if(typeof e==`string`)return e;try{return JSON.stringify(e)}catch{return String(e)}}function yt(e){return e!=null&&e.length>0&&typeof e[0]==`object`&&e[0]!=null&&`items`in e[0]}function bt(e){if(!Array.isArray(e))return e!=null&&`null`in e;let t=e;if(yt(t)){for(let e of t)for(let t of e.items)if(t&&t.value==null&&t.label!=null)return!0;return!1}for(let e of t)if(e&&e.value==null&&e.label!=null)return!0;return!1}function xt(e,t){if(t&&e!=null)return t(e)??``;if(e&&typeof e==`object`){if(`label`in e&&e.label!=null)return String(e.label);if(`value`in e)return String(e.value)}return vt(e)}function St(e,t){return t&&e!=null?t(e)??``:e&&typeof e==`object`&&`value`in e&&`label`in e?vt(e.value):vt(e)}function Ct(e,t,n){function r(){return xt(e,n)}if(n&&e!=null)return n(e);if(e&&typeof e==`object`&&`label`in e&&e.label!=null)return e.label;if(t&&!Array.isArray(t))return t[e]??r();if(Array.isArray(t)){let n=t,i=yt(n)?n.flatMap(e=>e.items):n;if(typeof e!=`object`||!e){let t=i.find(t=>t.value===e);return t&&t.label!=null?t.label:r()}if(`value`in e){let t=i.find(t=>t&&t.value===e.value);if(t&&t.label!=null)return t.label}}return r()}function wt(e,t,n){return e.reduce((e,r,i)=>(i>0&&e.push(`, `),e.push((0,Z.jsx)(Q.Fragment,{children:Ct(r,t,n)},i)),e),[])}var $={id:Y(e=>e.id),labelId:Y(e=>e.labelId),modal:Y(e=>e.modal),multiple:Y(e=>e.multiple),items:Y(e=>e.items),itemToStringLabel:Y(e=>e.itemToStringLabel),itemToStringValue:Y(e=>e.itemToStringValue),isItemEqualToValue:Y(e=>e.isItemEqualToValue),value:Y(e=>e.value),hasSelectedValue:Y(e=>{let{value:t,multiple:n,itemToStringValue:r}=e;return t==null?!1:n&&Array.isArray(t)?t.length>0:St(t,r)!==``}),hasNullItemLabel:Y((e,t)=>t?bt(e.items):!1),open:Y(e=>e.open),mounted:Y(e=>e.mounted),forceMount:Y(e=>e.forceMount),transitionStatus:Y(e=>e.transitionStatus),openMethod:Y(e=>e.openMethod),activeIndex:Y(e=>e.activeIndex),selectedIndex:Y(e=>e.selectedIndex),isActive:Y((e,t)=>e.activeIndex===t),isSelected:Y((e,t,n)=>{let r=e.isItemEqualToValue,i=e.value;return e.multiple?Array.isArray(i)&&i.some(e=>mt(n,e,r)):e.selectedIndex===t&&e.selectedIndex!==null?!0:mt(n,i,r)}),isSelectedByFocus:Y((e,t)=>e.selectedIndex===t),popupProps:Y(e=>e.popupProps),triggerProps:Y(e=>e.triggerProps),triggerElement:Y(e=>e.triggerElement),positionerElement:Y(e=>e.positionerElement),listElement:Y(e=>e.listElement),scrollUpArrowVisible:Y(e=>e.scrollUpArrowVisible),scrollDownArrowVisible:Y(e=>e.scrollDownArrowVisible),hasScrollArrows:Y(e=>e.hasScrollArrows)};function Tt(e,t=-(2**53-1),n=2**53-1){return Math.max(t,Math.min(e,n))}function Et(e,t){return Math.max(0,e-t)}function Dt(e,t){if(t<=0)return 0;let n=Tt(e,0,t),r=n,i=t-n,a=r<=1,o=i<=1;return a&&o?r<=i?0:t:a?0:o?t:n}function Ot(e){let{id:t,value:n,defaultValue:r=null,onValueChange:a,open:l,defaultOpen:u=!1,onOpenChange:p,name:m,form:h,autoComplete:_,disabled:v=!1,readOnly:y=!1,required:x=!1,modal:S=!0,actionsRef:w,inputRef:T,onOpenChangeComplete:ee,items:E,multiple:D=!1,itemToStringLabel:k,itemToStringValue:A,isItemEqualToValue:j=pt,highlightItemOnHover:te=!0,children:M}=e,{clearErrors:N}=Qe(),{setDirty:P,setTouched:F,setFocused:ne,shouldValidateOnChange:I,validityData:re,setFilled:ie,name:L,disabled:ae,validation:z,validationMode:V}=c(),H=B({id:t}),U=ae||v,W=L??m,[G,oe]=g({controlled:n,default:D?r??ce:r,name:`Select`,state:`value`}),[K,q]=g({controlled:l,default:u,name:`Select`,state:`open`}),ue=Q.useRef([]),de=Q.useRef([]),fe=Q.useRef(null),pe=Q.useRef(null),me=Q.useRef(0),ve=Q.useRef(null),ye=Q.useRef([]),be=Q.useRef(!1),xe=Q.useRef(!1),Ce=Q.useRef(null),we=Q.useRef({allowSelectedMouseUp:!1,allowUnselectedMouseUp:!1}),Te=Q.useRef(!1),{mounted:Ee,setMounted:De,transitionStatus:ke}=b(K),{openMethod:je,triggerProps:Me}=o(K),Y=he(()=>new Re({id:H,labelId:void 0,modal:S,multiple:D,itemToStringLabel:k,itemToStringValue:A,isItemEqualToValue:j,value:G,open:K,mounted:Ee,transitionStatus:ke,items:E,forceMount:!1,openMethod:null,activeIndex:null,selectedIndex:null,popupProps:{},triggerProps:{},triggerElement:null,positionerElement:null,listElement:null,scrollUpArrowVisible:!1,scrollDownArrowVisible:!1,hasScrollArrows:!1})).current,Pe=J(Y,$.activeIndex),Fe=J(Y,$.selectedIndex),Ie=J(Y,$.triggerElement),Le=J(Y,$.positionerElement),Be=ct(je),Ve=je??Be,He=Q.useMemo(()=>D&&Array.isArray(G)&&G.length===0?``:St(G,A),[D,G,A]),Ue=Q.useMemo(()=>D&&Array.isArray(G)?G.map(e=>St(e,A)):St(G,A),[D,G,A]);f(Se(Y.state.triggerElement),{id:H,value:G,getValue:s(()=>Ue)});let We=Q.useRef(G);X(()=>{G!==We.current&&Y.set(`forceMount`,!0)},[Y,G]),X(()=>{ie(D?Array.isArray(G)&&G.length>0:G!=null)},[D,G,ie]),X(function(){if(K)return;let e=ye.current;if(D){let t=Array.isArray(G)?G:[];if(t.length===0){Y.set(`selectedIndex`,null);return}let n=t[t.length-1],r=gt(e,n,j);Y.set(`selectedIndex`,r===-1?null:r);return}let t=gt(e,G,j);Y.set(`selectedIndex`,t===-1?null:t)},[D,K,G,ye,j,Y]),_e(G,()=>{N(W),P(G!==re.initialValue),I()?z.commit(G):z.commit(G,!0)});let Ge=s((e,t)=>{if(p?.(e,t),!t.isCanceled&&(q(e),!e&&(t.reason===`focus-out`||t.reason===`outside-press`)&&(F(!0),ne(!1),V===`onBlur`&&z.commit(G)),!e&&Y.state.activeIndex!==null)){let e=ue.current[Y.state.activeIndex];queueMicrotask(()=>{e?.setAttribute(`tabindex`,`-1`)})}}),Ke=s(()=>{De(!1),Y.update({activeIndex:null,openMethod:null}),ee?.(!1)});O({enabled:!w,open:K,ref:fe,onComplete(){K||Ke()}}),Q.useImperativeHandle(w,()=>({unmount:Ke}),[Ke]);let qe=s((e,t)=>{a?.(e,t),!t.isCanceled&&oe(e)}),Je=s(()=>{let e=Y.state.listElement||fe.current;if(!e)return;let t=Et(e.scrollHeight,e.clientHeight),n=Dt(e.scrollTop,t),r=n>0,i=nOe(Xe(),Me,H?{id:H}:ze),[Xe,Me,H]);C(()=>{Y.update({popupProps:Ze(),triggerProps:tt})}),X(()=>{Y.update({id:H,modal:S,multiple:D,value:G,open:K,mounted:Ee,transitionStatus:ke,popupProps:Ze(),triggerProps:tt,items:E,itemToStringLabel:k,itemToStringValue:A,isItemEqualToValue:j,openMethod:Ve})},[Y,H,S,D,G,K,Ee,ke,Ze,tt,E,k,A,j,Ve]);let nt=Q.useMemo(()=>({store:Y,name:W,required:x,disabled:U,readOnly:y,multiple:D,highlightItemOnHover:te,setValue:qe,setOpen:Ge,listRef:ue,popupRef:fe,scrollHandlerRef:pe,handleScrollArrowVisibility:Je,scrollArrowsMountedCountRef:me,getItemProps:et,events:Ye.context.events,valueRef:ve,valuesRef:ye,labelsRef:de,typingRef:be,selectionRef:we,selectedItemTextRef:Ce,validation:z,onOpenChangeComplete:ee,keyboardActiveRef:xe,alignItemWithTriggerActiveRef:Te,initialValueRef:We}),[Y,W,x,U,y,D,te,qe,Ge,et,Ye.context.events,z,ee,Je]),rt=Ne(T,z.inputRef),it=D&&Array.isArray(G)&&G.length>0,at=D?void 0:W,dt=Q.useMemo(()=>!D||!Array.isArray(G)||!W?null:G.map(e=>{let t=St(e,A);return(0,Z.jsx)(`input`,{type:`hidden`,form:h,name:W,value:t},t)}),[D,G,h,W,A]);return(0,Z.jsx)(lt.Provider,{value:nt,children:(0,Z.jsxs)(ut.Provider,{value:Ye,children:[M,(0,Z.jsx)(`input`,{...z.getInputValidationProps({onFocus(){Y.state.triggerElement?.focus({focusVisible:!0})},onChange(e){if(e.nativeEvent.defaultPrevented)return;let t=e.currentTarget.value,n=d(ge,e.nativeEvent);function r(){if(D)return;let e=ye.current.find(e=>St(e,A).toLowerCase()===t.toLowerCase()||xt(e,k).toLowerCase()===t.toLowerCase());e!=null&&(P(e!==re.initialValue),qe(e,n),I()&&z.commit(e))}Y.set(`forceMount`,!0),queueMicrotask(r)}}),id:H&&at==null?`${H}-hidden-input`:void 0,form:h,name:at,autoComplete:_,value:He,disabled:U,required:x&&!it,readOnly:y,ref:rt,style:W?Ae:le,tabIndex:-1,"aria-hidden":!0,suppressHydrationWarning:!0}),dt]})})}function kt(e,t){return e??t}function At(e){let t=e.getBoundingClientRect(),n=M(e),r=n.getComputedStyle(e,`::before`),i=n.getComputedStyle(e,`::after`);if(!(r.content!==`none`||i.content!==`none`))return t;let a=parseFloat(r.width)||0,o=parseFloat(r.height)||0,s=parseFloat(i.width)||0,c=parseFloat(i.height)||0,l=Math.max(t.width,a,s),u=Math.max(t.height,o,c),d=l-t.width,f=u-t.height;return{left:t.left-d/2,right:t.right+d/2,top:t.top-f/2,bottom:t.bottom+f/2}}var jt=2,Mt=400,Nt=200,Pt={...V,...Ue,value:()=>null},Ft=Q.forwardRef(function(e,t){let{render:r,className:i,id:a,disabled:o=!1,nativeButton:l=!0,style:f,...p}=e,{setTouched:m,setFocused:g,validationMode:_,state:v,disabled:y}=c(),{labelId:b}=Ke(),{store:x,setOpen:S,selectionRef:C,validation:w,readOnly:T,required:ee,alignItemWithTriggerActiveRef:E,disabled:D,keyboardActiveRef:O}=dt(),k=y||D||o,A=J(x,$.open),j=J(x,$.value),te=J(x,$.triggerProps),M=J(x,$.positionerElement),N=J(x,$.listElement),F=J(x,$.id),ne=J(x,$.labelId),I=J(x,$.hasSelectedValue),re=!I&&A,ie=J(x,$.hasNullItemLabel,re),L=a??F,ae=kt(b,ne);B({id:L});let R=Se(M),z=Q.useRef(null),{getButtonProps:V,buttonRef:U}=h({disabled:k,native:l}),W=Ne(t,z,U,s(e=>{x.set(`triggerElement`,e)})),G=P(),oe=P(),se=P(),ce=P();Q.useEffect(()=>{if(A)return I||ie?ce.start(Nt,()=>{C.current.allowUnselectedMouseUp=!0,se.start(Nt,()=>{C.current.allowSelectedMouseUp=!0})}):se.start(Mt,()=>{C.current.allowUnselectedMouseUp=!0,C.current.allowSelectedMouseUp=!0}),()=>{se.clear(),ce.clear()};C.current={allowSelectedMouseUp:!1,allowUnselectedMouseUp:!1},oe.clear()},[A,I,ie,C,oe,se,ce]);let le=Q.useMemo(()=>N?.id??H(M)?.id,[N,M]),q=Oe(te,{id:L,role:`combobox`,"aria-expanded":A?`true`:`false`,"aria-haspopup":`listbox`,"aria-controls":A?le:void 0,"aria-labelledby":ae,"aria-readonly":T||void 0,"aria-required":ee||void 0,tabIndex:k?-1:0,ref:W,onFocus(e){g(!0),A&&E.current&&S(!1,d(ge,e.nativeEvent)),G.start(0,()=>{x.set(`forceMount`,!0)})},onBlur(e){K(M,e.relatedTarget)||(m(!0),g(!1),_===`onBlur`&&w.commit(j))},onPointerMove(){O.current=!1},onKeyDown(){O.current=!0},onMouseDown(e){if(A)return;let t=Je(e.currentTarget);function n(e){if(!z.current)return;let t=e.target;if(K(z.current,t)||K(R.current,t)||t===z.current)return;let n=At(z.current);e.clientX>=n.left-jt&&e.clientX<=n.right+jt&&e.clientY>=n.top-jt&&e.clientY<=n.bottom+jt||S(!1,d(u,e))}oe.start(0,()=>{t.addEventListener(`mouseup`,n,{once:!0})})}},w.getValidationProps,p,V);q.role=`combobox`;let ue={...v,open:A,disabled:k,value:j,readOnly:T,placeholder:!I};return n(`button`,e,{ref:[t,z],state:ue,stateAttributesMapping:Pt,props:q})}),It={value:()=>null},Lt=Q.forwardRef(function(e,t){let{className:r,render:i,children:a,placeholder:o,style:s,...c}=e,{store:l,valueRef:u}=dt(),d=J(l,$.value),f=J(l,$.items),p=J(l,$.itemToStringLabel),m=J(l,$.hasSelectedValue),h=!m&&o!=null&&a==null,g=J(l,$.hasNullItemLabel,h),_={value:d,placeholder:!m},v=null;return v=typeof a==`function`?a(d):a??(!m&&o!=null&&!g?o:Array.isArray(d)?wt(d,f,p):Ct(d,f,p)),n(`span`,e,{state:_,ref:[t,u],props:[{children:v},c],stateAttributesMapping:It})}),Rt=Q.forwardRef(function(e,t){let{className:r,render:i,style:a,...o}=e,{store:s}=dt();return n(`span`,e,{state:{open:J(s,$.open)},ref:t,props:[{"aria-hidden":!0,children:`▼`},o],stateAttributesMapping:qe})}),zt=Q.createContext(void 0),Bt=Q.forwardRef(function(e,t){let{store:n}=dt(),r=J(n,$.mounted),i=J(n,$.forceMount);return r||i?(0,Z.jsx)(zt.Provider,{value:!0,children:(0,Z.jsx)(be,{ref:t,...e})}):null}),Vt=Q.createContext({register:()=>{},unregister:()=>{},subscribeMapChange:()=>()=>{},elementsRef:{current:[]},nextIndexRef:{current:0}});function Ht(){return Q.useContext(Vt)}function Ut(e){let{children:t,elementsRef:n,labelsRef:r,onMapChange:i}=e,a=s(i),o=Q.useRef(0),c=he(Gt).current,l=he(Wt).current,[u,d]=Q.useState(0),f=Q.useRef(u),p=s((e,t)=>{l.set(e,t??null),f.current+=1,d(f.current)}),m=s(e=>{l.delete(e),f.current+=1,d(f.current)}),h=Q.useMemo(()=>{let e=new Map;return Array.from(l.keys()).filter(e=>e.isConnected).sort(Kt).forEach((t,n)=>{let r=l.get(t)??{};e.set(t,{...r,index:n})}),e},[l,u]);X(()=>{if(typeof MutationObserver!=`function`||h.size===0)return;let e=new MutationObserver(e=>{let t=new Set,n=e=>t.has(e)?t.delete(e):t.add(e);e.forEach(e=>{e.removedNodes.forEach(n),e.addedNodes.forEach(n)}),t.size===0&&(f.current+=1,d(f.current))});return h.forEach((t,n)=>{n.parentElement&&e.observe(n.parentElement,{childList:!0})}),()=>{e.disconnect()}},[h]),X(()=>{f.current===u&&(n.current.length!==h.size&&(n.current.length=h.size),r&&r.current.length!==h.size&&(r.current.length=h.size),o.current=h.size),a(h)},[a,h,n,r,u]),X(()=>()=>{n.current=[]},[n]),X(()=>()=>{r&&(r.current=[])},[r]);let g=s(e=>(c.add(e),()=>{c.delete(e)}));X(()=>{c.forEach(e=>e(h))},[c,h]);let _=Q.useMemo(()=>({register:p,unregister:m,subscribeMapChange:g,elementsRef:n,labelsRef:r,nextIndexRef:o}),[p,m,g,n,r,o]);return(0,Z.jsx)(Vt.Provider,{value:_,children:t})}function Wt(){return new Map}function Gt(){return new Set}function Kt(e,t){let n=e.compareDocumentPosition(t);return n&Node.DOCUMENT_POSITION_FOLLOWING||n&Node.DOCUMENT_POSITION_CONTAINED_BY?-1:n&Node.DOCUMENT_POSITION_PRECEDING||n&Node.DOCUMENT_POSITION_CONTAINS?1:0}var qt=Q.createContext(void 0);function Jt(){let e=Q.useContext(qt);if(!e)throw Error(z(59));return e}function Yt(e,t){e&&Object.assign(e.style,t)}var Xt={position:`relative`,maxHeight:`100%`,overflowX:`hidden`,overflowY:`auto`},Zt=20;function Qt(e,t,n,r){let[i,a]=Q.useState(!1);X(()=>{if(!e||!t||n==null){a(!1);return}let r=Je(n).documentElement.clientWidth,i=n.offsetWidth;a(r>0&&i>0&&i>=r-Zt)},[e,t,n]),x(e&&(!t||i),r)}var $t={position:`fixed`},en=Q.forwardRef(function(e,t){let{anchor:n,positionMethod:r=`absolute`,className:i,render:a,side:o=`bottom`,align:c=`center`,sideOffset:l=0,alignOffset:u=0,collisionBoundary:f=`clipping-ancestors`,collisionPadding:m,arrowPadding:h=5,sticky:g=!1,disableAnchorTracking:v,alignItemWithTrigger:y=!0,collisionAvoidance:b=Ve,style:x,...S}=e,{store:C,listRef:w,labelsRef:T,alignItemWithTriggerActiveRef:ee,selectedItemTextRef:E,valuesRef:D,initialValueRef:O,popupRef:k,setValue:j}=dt(),te=ft(),M=J(C,$.open),N=J(C,$.mounted),P=J(C,$.modal),F=J(C,$.value),ne=J(C,$.openMethod),I=J(C,$.positionerElement),re=J(C,$.triggerElement),ie=J(C,$.isItemEqualToValue),L=J(C,$.transitionStatus),ae=Q.useRef(null),R=Q.useRef(null),[z,B]=Q.useState(y),V=N&&z&&ne!==`touch`;!N&&z!==y&&B(y),X(()=>{N||($.scrollUpArrowVisible(C.state)&&C.set(`scrollUpArrowVisible`,!1),$.scrollDownArrowVisible(C.state)&&C.set(`scrollDownArrowVisible`,!1))},[C,N]),Q.useImperativeHandle(ee,()=>V),Qt((V||P)&&M,ne===`touch`,I,re);let H=Ge({anchor:n,floatingRootContext:te,positionMethod:r,mounted:N,side:o,sideOffset:l,align:c,alignOffset:u,arrowPadding:h,collisionBoundary:f,collisionPadding:m,sticky:g,disableAnchorTracking:v??V,collisionAvoidance:b,keepMounted:!0}),U=V?`none`:H.side,W=V?$t:H.positionerStyles,G=A(e,{open:M,side:U,align:H.align,anchorHidden:H.anchorHidden},{styles:W,transitionStatus:L,props:S,refs:[t,s(e=>{C.set(`positionerElement`,e)})],hidden:!N,inert:!M}),oe=Q.useRef(0),se=s(e=>{if(e.size===0&&oe.current===0||D.current.length===0)return;let t=oe.current;if(oe.current=e.size,e.size===t)return;let n=d(ge);if(t!==0&&!C.state.multiple&&F!==null&>(D.current,F,ie)===-1){let e=O.current,t=e!=null&>(D.current,e,ie)!==-1?e:null;j(t,n),t===null&&(C.set(`selectedIndex`,null),E.current=null)}if(t!==0&&C.state.multiple&&Array.isArray(F)){let e=e=>gt(D.current,e,ie)!==-1,t=F.filter(t=>e(t));(t.length!==F.length||t.some(e=>!ht(F,e,ie)))&&(j(t,n),t.length===0&&(C.set(`selectedIndex`,null),E.current=null))}if(M&&V){C.update({scrollUpArrowVisible:!1,scrollDownArrowVisible:!1});let e={height:``};Yt(I,e),Yt(k.current,e)}}),ce=Q.useMemo(()=>({...H,side:U,alignItemWithTriggerActive:V,setControlledAlignItemWithTrigger:B,scrollUpArrowRef:ae,scrollDownArrowRef:R}),[H,U,V,B]);return(0,Z.jsx)(Ut,{elementsRef:w,labelsRef:T,onMapChange:se,children:(0,Z.jsxs)(qt.Provider,{value:ce,children:[N&&P&&(0,Z.jsx)(p,{inert:_(!M),cutout:re}),G]})})}),tn=`base-ui-disable-scrollbar`,nn={className:tn,getElement(e){return(0,Z.jsx)(`style`,{nonce:e,href:tn,precedence:`base-ui:low`,children:`.${tn}{scrollbar-width:none}.${tn}::-webkit-scrollbar{display:none}`})}},rn=Q.createContext(void 0);function an(e){let t=Q.useContext(rn);if(t===void 0&&!e)throw Error(z(69));return t}var on=Q.createContext(void 0),sn={disableStyleElements:!1};function cn(){return Q.useContext(on)??sn}var ln={...Ye,...N},un=Q.forwardRef(function(e,t){let{render:r,className:i,style:a,finalFocus:o,...c}=e,{store:u,popupRef:f,onOpenChangeComplete:p,setOpen:m,valueRef:h,selectedItemTextRef:g,keyboardActiveRef:_,multiple:v,handleScrollArrowVisibility:y,scrollHandlerRef:b,listRef:x,highlightItemOnHover:S}=dt(),{side:C,align:w,alignItemWithTriggerActive:T,isPositioned:E,setControlledAlignItemWithTrigger:D,scrollDownArrowRef:k,scrollUpArrowRef:A}=Jt(),N=an(!0)!=null,P=ft(),ne=j(),{nonce:I,disableStyleElements:re}=cn(),ie=J(u,$.id),L=J(u,$.open),ae=J(u,$.mounted),R=J(u,$.popupProps),z=J(u,$.transitionStatus),B=J(u,$.triggerElement),V=J(u,$.positionerElement),H=J(u,$.listElement),U=Q.useRef(!1),W=Q.useRef(!1),G=Q.useRef({}),oe=te(),se=s(e=>{if(!V||!f.current||!W.current)return;if(U.current||!T){y();return}let t=V.style.top===`0px`,n=V.style.bottom===`0px`;if(!t&&!n){y();return}let r=pn(V),i=mn(V.getBoundingClientRect().height,`y`,r),a=Je(V),o=getComputedStyle(V),s=parseFloat(o.marginTop),c=parseFloat(o.marginBottom),l=dn(getComputedStyle(f.current)),u=Math.min(a.documentElement.clientHeight-s-c,l),d=e.scrollTop,p=fn(e),m=0,h=null,g=!1,_=!1,v=e=>{V.style.height=`${e}px`},b=(t,n)=>{let r=Tt(t,0,u-i);r>0&&v(i+r),e.scrollTop=n,u-(i+r)<=1&&(U.current=!0),y()},x=t?p-d:d,S=Math.min(i+x,u);if(m=S,x<=1){b(x,t?p:0);return}if(u-S>1?t?_=!0:h=0:(g=!0,n&&d1&&(e.scrollTop=n)}(g||m>=u-1)&&(U.current=!0),y()});Q.useImperativeHandle(b,()=>se,[se]),O({open:L,ref:f,onComplete(){L&&p?.(!0)}});let ce={open:L,transitionStatus:z,side:C,align:w};X(()=>{!V||!f.current||Object.keys(G.current).length||(G.current={top:V.style.top||`0`,left:V.style.left||`0`,right:V.style.right,height:V.style.height,bottom:V.style.bottom,minHeight:V.style.minHeight,maxHeight:V.style.maxHeight,marginTop:V.style.marginTop,marginBottom:V.style.marginBottom})},[f,V]),X(()=>{L||T||(W.current=!1,U.current=!1,Yt(V,G.current))},[L,T,V,f]),X(()=>{let e=f.current;if(!L||!B||!V||!e||T&&!E||u.state.transitionStatus===`ending`)return;if(!T){W.current=!0,oe.request(y),e.style.removeProperty(`--transform-origin`);return}let t=_n(e);e.style.removeProperty(`--transform-origin`);try{let t=g.current,n=h.current,r=getComputedStyle(V),i=getComputedStyle(e),a=Je(B),o=M(V),s=pn(B),c=hn(B.getBoundingClientRect(),s),l=hn(V.getBoundingClientRect(),s),d=c.height,f=H||e,p=f.scrollHeight,m=parseFloat(i.borderBottomWidth),_=parseFloat(r.marginTop)||10,v=parseFloat(r.marginBottom)||10,b=parseFloat(r.minHeight)||100,C=dn(i),w=a.documentElement.clientHeight-_-v,T=a.documentElement.clientWidth,ee=w-c.bottom+d,E,O=ne===`rtl`?c.right-l.width:c.left,k=0;if(t&&n){let e=hn(n.getBoundingClientRect(),s);E=hn(t.getBoundingClientRect(),s),O=l.left+(ne===`rtl`?e.right-E.right:e.left-E.left);let r=e.top-c.top+e.height/2;k=E.top-l.top+E.height/2-r}let A=ee+k+v+m,j=Math.min(w,A),te=w-_-v,N=A-j,P=T-5;V.style.left=`${Tt(O,5,P-l.width)}px`,V.style.height=`${j}px`,V.style.maxHeight=`auto`,V.style.marginTop=`${_}px`,V.style.marginBottom=`${v}px`,e.style.height=`100%`;let F=fn(f),I=N>=F-1;I&&(j=Math.min(w,l.height)-(N-F));let re=c.top<20||c.bottom>w-20||Math.ceil(j)+1=te?`0`:`${e}px`,V.style.height=`${j}px`,f.scrollTop=fn(f)}else V.style.bottom=`0`,f.scrollTop=N;if(E){let t=l.top,n=l.height,r=E.top+E.height/2,i=Tt(n>0?(r-t)/n*100:50,0,100);e.style.setProperty(`--transform-origin`,`50% ${i}%`)}(L===w||j>=C)&&(U.current=!0),y(),S&&u.state.selectedIndex===null&&u.state.activeIndex===null&&x.current[0]!=null&&u.set(`activeIndex`,0),W.current=!0}finally{t()}},[u,L,V,B,h,g,f,y,T,D,oe,k,A,H,x,S,ne,E]),Q.useEffect(()=>{if(!T||!V||!L)return;let e=M(V);function t(e){m(!1,d(ee,e))}return de(e,`resize`,t)},[m,T,V,L]);let K={...H?{role:`presentation`,"aria-orientation":void 0}:{role:`listbox`,"aria-multiselectable":v||void 0,id:`${ie}-list`},onKeyDown(e){_.current=!0,N&&F.has(e.key)&&e.stopPropagation()},onMouseMove(){_.current=!1},onScroll(e){H||se(e.currentTarget)},...T&&{style:H?{height:`100%`}:Xt}},le=n(`div`,e,{ref:[t,f],state:ce,stateAttributesMapping:ln,props:[R,K,l(z),{className:!H&&T?nn.className:void 0},c]});return(0,Z.jsxs)(Q.Fragment,{children:[!re&&nn.getElement(I),(0,Z.jsx)(De,{context:P,modal:!1,disabled:!ae,returnFocus:o,restoreFocus:!0,children:le})]})});function dn(e){let t=e.maxHeight||``;return t.endsWith(`px`)&&parseFloat(t)||1/0}function fn(e){return Et(e.scrollHeight,e.clientHeight)}function pn(e){return me.getScale(e)}function mn(e,t,n){return e/n[t]}function hn(e,t){return we({x:mn(e.x,`x`,t),y:mn(e.y,`y`,t),width:mn(e.width,`x`,t),height:mn(e.height,`y`,t)})}var gn=[[`transform`,`none`],[`scale`,`1`],[`translate`,`0 0`]];function _n(e){let{style:t}=e,n={};for(let[e,r]of gn)n[e]=t.getPropertyValue(e),t.setProperty(e,r,`important`);return()=>{for(let[e]of gn){let r=n[e];r?t.setProperty(e,r):t.removeProperty(e)}}}var vn=Q.forwardRef(function(e,t){let{className:r,render:i,style:a,...o}=e,{store:c,scrollHandlerRef:l}=dt(),{alignItemWithTriggerActive:u}=Jt(),d=J(c,$.hasScrollArrows),f=J(c,$.openMethod),p=J(c,$.multiple),m={id:`${J(c,$.id)}-list`,role:`listbox`,"aria-multiselectable":p||void 0,onScroll(e){l.current?.(e.currentTarget)},...u&&{style:Xt},className:d&&f!==`touch`?nn.className:void 0};return n(`div`,e,{ref:[t,s(e=>{c.set(`listElement`,e)})],props:[m,o]})}),yn=function(e){return e[e.None=0]=`None`,e[e.GuessFromOrder=1]=`GuessFromOrder`,e}({});function bn(e={}){let{label:t,metadata:n,textRef:r,indexGuessBehavior:i,index:a}=e,{register:o,unregister:s,subscribeMapChange:c,elementsRef:l,labelsRef:u,nextIndexRef:d}=Ht(),f=Q.useRef(-1),[p,m]=Q.useState(a??(i===yn.GuessFromOrder?()=>{if(f.current===-1){let e=d.current;d.current+=1,f.current=e}return f.current}:-1)),h=Q.useRef(null),g=Q.useCallback(e=>{if(h.current=e,p!==-1&&e!==null&&(l.current[p]=e,u)){let n=t!==void 0;u.current[p]=n?t:r?.current?.textContent??e.textContent}},[p,l,u,t,r]);return X(()=>{if(a!=null)return;let e=h.current;if(e)return o(e,n),()=>{s(e)}},[a,o,s,n]),X(()=>{if(a==null)return c(e=>{let t=h.current?e.get(h.current)?.index:null;t!=null&&m(t)})},[a,c,m]),Q.useMemo(()=>({ref:g,index:p}),[p,g])}var xn=Q.createContext(void 0);function Sn(){let e=Q.useContext(xn);if(!e)throw Error(z(57));return e}var Cn=Q.memo(Q.forwardRef(function(e,t){let{render:r,className:i,value:a=null,label:o,disabled:s=!1,nativeButton:c=!1,style:l,...u}=e,f=Q.useRef(null),p=bn({label:o,textRef:f,indexGuessBehavior:yn.GuessFromOrder}),{store:m,getItemProps:g,setOpen:_,setValue:v,selectionRef:y,typingRef:b,valuesRef:x,multiple:S,selectedItemTextRef:C}=dt(),w=J(m,$.isActive,p.index),T=J(m,$.isSelected,p.index,a),ee=J(m,$.isSelectedByFocus,p.index),E=J(m,$.isItemEqualToValue),D=p.index,O=D!==-1,k=Q.useRef(null),A=Se(D);X(()=>{if(!O)return;let e=x.current;return e[D]=a,()=>{delete e[D]}},[O,D,a,x]),X(()=>{if(!O)return;let e=m.state.value,t=e;S&&Array.isArray(e)&&e.length>0&&(t=e[e.length-1]),t!==void 0&&mt(a,t,E)&&(m.set(`selectedIndex`,D),f.current&&(C.current=f.current))},[O,D,S,E,m,a,C]);let j={disabled:s,selected:T,highlighted:w},te=g({active:w,selected:T});te.id=void 0;let M=Q.useRef(null),N=Q.useRef(`mouse`),P=Q.useRef(!1),{getButtonProps:F,buttonRef:ne}=h({disabled:s,focusableWhenDisabled:!0,native:c,composite:!0});function I(e){let t=m.state.value;if(S){let n=Array.isArray(t)?t:[];v(T?_t(n,a,E):[...n,a],d(ve,e))}else v(a,d(ve,e)),_(!1,d(ve,e))}let re={role:`option`,"aria-selected":T,tabIndex:w?0:-1,onTouchStart(){y.current={allowSelectedMouseUp:!1,allowUnselectedMouseUp:!1}},onKeyDown(e){M.current=e.key,m.set(`activeIndex`,D),e.key===` `&&b.current&&e.preventDefault()},onClick(e){P.current=!1,!(e.type===`keydown`&&M.current===null)&&(s||e.type===`keydown`&&M.current===` `&&b.current||N.current!==`touch`&&!w||(M.current=null,I(e.nativeEvent)))},onPointerEnter(e){N.current=e.pointerType},onPointerDown(e){N.current=e.pointerType,P.current=!0},onMouseUp(){if(s)return;if(P.current){P.current=!1;return}let e=!y.current.allowSelectedMouseUp&&T,t=!y.current.allowUnselectedMouseUp&&!T;e||t||N.current!==`touch`&&!w||k.current?.click()}},ie=n(`div`,e,{ref:[ne,t,p.ref,k],state:j,props:[te,re,u,F]}),L=Q.useMemo(()=>({selected:T,indexRef:A,textRef:f,selectedByFocus:ee,hasRegistered:O}),[T,A,f,ee,O]);return(0,Z.jsx)(xn.Provider,{value:L,children:ie})})),wn=Q.forwardRef(function(e,t){let n=e.keepMounted??!1,{selected:r}=Sn();return n||r?(0,Z.jsx)(Tn,{...e,ref:t}):null}),Tn=Q.memo(Q.forwardRef((e,t)=>{let{render:r,className:i,style:a,keepMounted:o,...s}=e,{selected:c}=Sn(),l=Q.useRef(null),{transitionStatus:u,setMounted:d}=b(c),f=n(`span`,e,{ref:[t,l],state:{selected:c,transitionStatus:u},props:[{"aria-hidden":!0,children:`✔️`},s],stateAttributesMapping:N});return O({open:c,ref:l,onComplete(){c||d(!1)}}),f})),En=Q.memo(Q.forwardRef(function(e,t){let{indexRef:r,textRef:i,selectedByFocus:a,hasRegistered:o}=Sn(),{selectedItemTextRef:s}=dt(),{className:c,render:l,style:u,...d}=e;return n(`div`,e,{ref:[Q.useCallback(e=>{if(!e||!o)return;let t=s.current===null||!s.current.isConnected;(a||t&&r.current===0)&&(s.current=e)},[s,r,a,o]),t,i],props:d})})),Dn=Q.forwardRef(function(e,t){let{render:r,className:i,style:a,direction:o,keepMounted:s=!1,...c}=e,l=o===`up`,{store:u,popupRef:d,listRef:f,handleScrollArrowVisibility:p,scrollArrowsMountedCountRef:m}=dt(),{side:h,scrollDownArrowRef:g,scrollUpArrowRef:_}=Jt(),v=J(u,l?$.scrollUpArrowVisible:$.scrollDownArrowVisible),y=J(u,$.openMethod),x=v&&y!==`touch`,S=P(),C=l?_:g,{transitionStatus:w,setMounted:T}=b(x);X(()=>(m.current+=1,u.state.hasScrollArrows||u.set(`hasScrollArrows`,!0),()=>{m.current=Math.max(0,m.current-1),m.current===0&&u.state.hasScrollArrows&&u.set(`hasScrollArrows`,!1)}),[u,m]),O({open:x,ref:C,onComplete(){x||T(!1)}});let ee=n(`div`,e,{ref:[t,C],state:{direction:o,visible:x,side:h,transitionStatus:w},props:[{"aria-hidden":!0,children:l?`▲`:`▼`,style:{position:`absolute`},onMouseMove(e){if(e.movementX===0&&e.movementY===0||S.isStarted())return;u.set(`activeIndex`,null);function t(){let e=u.state.listElement??d.current;if(!e)return;u.set(`activeIndex`,null),p();let n=Et(e.scrollHeight,e.clientHeight),r=Dt(e.scrollTop,n),i=r===(l?0:n),a=f.current;if(r!==e.scrollTop&&(e.scrollTop=r),a.length===0&&u.set(l?`scrollUpArrowVisible`:`scrollDownArrowVisible`,!i),i){S.clear();return}if(a.length>0){let t=C.current?.offsetHeight||0;e.scrollTop=On(a,l,r,e.clientHeight,t,n)}S.start(40,t)}S.start(40,t)},onMouseLeave(){S.clear()}},c]});return x||s?ee:null});function On(e,t,n,r,i,a){if(t){let t=0,r=n+i-1;for(let n=0;n=r){t=n;break}}let o=Math.max(0,t-1),s=e[o];return os){o=Math.max(0,t-1);break}}let c=Math.min(e.length-1,o+1),l=e[c];return c>o&&l?Dt(l.offsetTop+l.offsetHeight-r+i,a):a}var kn=Q.forwardRef(function(e,t){return(0,Z.jsx)(Dn,{...e,ref:t,direction:`down`})}),An=Q.forwardRef(function(e,t){return(0,Z.jsx)(Dn,{...e,ref:t,direction:`up`})}),jn=Q.createContext(void 0);function Mn(){let e=Q.useContext(jn);if(e===void 0)throw Error(z(56));return e}var Nn=Q.forwardRef(function(e,t){let{className:r,render:i,style:a,...o}=e,[s,c]=Q.useState(),l=Q.useMemo(()=>({labelId:s,setLabelId:c}),[s,c]),u=n(`div`,e,{ref:t,props:[{role:`group`,"aria-labelledby":s},o]});return(0,Z.jsx)(jn.Provider,{value:l,children:u})}),Pn=Q.forwardRef(function(e,t){let{className:r,render:i,id:a,style:o,...s}=e,{setLabelId:c}=Mn(),l=k(a);return X(()=>{c(l)},[l,c]),n(`div`,e,{ref:t,props:[{id:l},s]})}),Fn=Ie(),In=Ot;function Ln(e){let t=(0,Fn.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=w(`scroll-my-1 p-1`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,Z.jsx)(Nn,{className:i,"data-slot":`select-group`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Rn(e){let t=(0,Fn.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=w(`flex flex-1 text-left`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,Z.jsx)(Lt,{className:i,"data-slot":`select-value`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function zn(e){let n=(0,Fn.c)(15),r,i,a,o,s;n[0]===e?(r=n[1],i=n[2],a=n[3],o=n[4],s=n[5]):({className:i,size:s,id:a,children:r,...o}=e,n[0]=e,n[1]=r,n[2]=i,n[3]=a,n[4]=o,n[5]=s);let c=s===void 0?`default`:s,l;n[6]===i?l=n[7]:(l=w(`flex w-fit items-center justify-between gap-1.5 rounded-md border border-input bg-input/20 px-2 py-1.5 text-xs/relaxed whitespace-nowrap transition-colors outline-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-7 data-[size=sm]:h-6 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5`,i),n[6]=i,n[7]=l);let u;n[8]===Symbol.for(`react.memo_cache_sentinel`)?(u=(0,Z.jsx)(Rt,{render:(0,Z.jsx)(t,{className:`pointer-events-none size-3.5 text-muted-foreground`})}),n[8]=u):u=n[8];let d;return n[9]!==r||n[10]!==a||n[11]!==o||n[12]!==c||n[13]!==l?(d=(0,Z.jsxs)(Ft,{className:l,"data-size":c,"data-slot":`select-trigger`,id:a,...o,children:[r,u]}),n[9]=r,n[10]=a,n[11]=o,n[12]=c,n[13]=l,n[14]=d):d=n[14],d}function Bn(e){let t=(0,Fn.c)(26),n,r,i,a,o,s,c,l;t[0]===e?(n=t[1],r=t[2],i=t[3],a=t[4],o=t[5],s=t[6],c=t[7],l=t[8]):({className:r,children:n,side:a,sideOffset:o,align:s,alignOffset:c,alignItemWithTrigger:l,...i}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i,t[4]=a,t[5]=o,t[6]=s,t[7]=c,t[8]=l);let u=a===void 0?`bottom`:a,d=o===void 0?4:o,f=s===void 0?`center`:s,p=c===void 0?0:c,m=l===void 0?!0:l,h;t[9]===r?h=t[10]:(h=w(`data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-closed:animate-out data-open:animate-in relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100`,r),t[9]=r,t[10]=h);let g;t[11]===Symbol.for(`react.memo_cache_sentinel`)?(g=(0,Z.jsx)(Wn,{}),t[11]=g):g=t[11];let _;t[12]===n?_=t[13]:(_=(0,Z.jsx)(vn,{children:n}),t[12]=n,t[13]=_);let v;t[14]===Symbol.for(`react.memo_cache_sentinel`)?(v=(0,Z.jsx)(Gn,{}),t[14]=v):v=t[14];let y;t[15]!==i||t[16]!==h||t[17]!==_?(y=(0,Z.jsxs)(un,{className:h,"data-slot":`select-content`,...i,children:[g,_,v]}),t[15]=i,t[16]=h,t[17]=_,t[18]=y):y=t[18];let b;return t[19]!==f||t[20]!==m||t[21]!==p||t[22]!==u||t[23]!==d||t[24]!==y?(b=(0,Z.jsx)(Bt,{children:(0,Z.jsx)(en,{align:f,alignItemWithTrigger:m,alignOffset:p,className:`isolate z-50`,side:u,sideOffset:d,children:y})}),t[19]=f,t[20]=m,t[21]=p,t[22]=u,t[23]=d,t[24]=y,t[25]=b):b=t[25],b}function Vn(e){let t=(0,Fn.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=w(`px-2 py-1.5 text-xs text-muted-foreground`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,Z.jsx)(Pn,{className:i,"data-slot":`select-label`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Hn(t){let n=(0,Fn.c)(13),r,i,a;n[0]===t?(r=n[1],i=n[2],a=n[3]):({className:i,children:r,...a}=t,n[0]=t,n[1]=r,n[2]=i,n[3]=a);let o;n[4]===i?o=n[5]:(o=w(`relative flex min-h-7 w-full cursor-default items-center gap-2 rounded-md px-2 py-1 text-xs/relaxed outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2`,i),n[4]=i,n[5]=o);let s;n[6]===r?s=n[7]:(s=(0,Z.jsx)(En,{className:`flex flex-1 shrink-0 gap-2 whitespace-nowrap`,children:r}),n[6]=r,n[7]=s);let c;n[8]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,Z.jsx)(wn,{render:(0,Z.jsx)(`span`,{className:`pointer-events-none absolute right-2 flex items-center justify-center`}),children:(0,Z.jsx)(e,{className:`pointer-events-none`})}),n[8]=c):c=n[8];let l;return n[9]!==a||n[10]!==o||n[11]!==s?(l=(0,Z.jsxs)(Cn,{className:o,"data-slot":`select-item`,...a,children:[s,c]}),n[9]=a,n[10]=o,n[11]=s,n[12]=l):l=n[12],l}function Un(e){let t=(0,Fn.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=w(`pointer-events-none -mx-1 my-1 h-px bg-border/50`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,Z.jsx)(We,{className:i,"data-slot":`select-separator`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Wn(e){let t=(0,Fn.c)(9),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=w(`top-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-3.5`,n),t[3]=n,t[4]=i);let a;t[5]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,Z.jsx)(Xe,{}),t[5]=a):a=t[5];let o;return t[6]!==r||t[7]!==i?(o=(0,Z.jsx)(An,{className:i,"data-slot":`select-scroll-up-button`,...r,children:a}),t[6]=r,t[7]=i,t[8]=o):o=t[8],o}function Gn(e){let n=(0,Fn.c)(9),r,i;n[0]===e?(r=n[1],i=n[2]):({className:r,...i}=e,n[0]=e,n[1]=r,n[2]=i);let a;n[3]===r?a=n[4]:(a=w(`bottom-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-3.5`,r),n[3]=r,n[4]=a);let o;n[5]===Symbol.for(`react.memo_cache_sentinel`)?(o=(0,Z.jsx)(t,{}),n[5]=o):o=n[5];let s;return n[6]!==i||n[7]!==a?(s=(0,Z.jsx)(kn,{className:a,"data-slot":`select-scroll-down-button`,...i,children:o}),n[6]=i,n[7]=a,n[8]=s):s=n[8],s}export{Vn as a,Rn as c,Hn as i,bn as l,Bn as n,Un as o,Ln as r,zn as s,In as t,Ut as u}; \ No newline at end of file +import{t as e}from"./check.js";import{t}from"./chevron-down.js";import{$a as n,Aa as r,Bi as i,Ca as a,Ci as o,Da as s,Di as c,Ea as l,Ei as u,Fa as d,Fi as f,Gi as p,Gr as m,Ha as h,Hi as g,Ia as _,Ir as v,Ji as y,Jo as b,Kr as x,La as S,Lr as C,Ma as w,Na as ee,Ni as T,Oa as E,Oi as D,Oo as O,Pa as k,Pi as A,Qi as te,Ra as j,Ri as M,Rr as N,Sa as ne,Si as P,Ta as re,Ti as F,Ui as I,Vi as L,Wi as ie,Wr as ae,Xa as R,Xi as z,Xr as B,Yi as V,Yr as H,Zi as U,_a as W,_i as G,_o as oe,ba as se,bi as K,bo as ce,ca as le,da as q,eo as J,fa as ue,ga as de,gi as Y,go as fe,ha as pe,hi as me,ho as he,ia as ge,ii as _e,ja as ve,ka as ye,ki as be,ko as xe,la as Se,ma as Ce,mi as we,mo as Te,no as Ee,oa as De,pa as Oe,pi as ke,po as Ae,qi as je,qr as Me,ra as Ne,sa as X,ta as Pe,to as Fe,ua as Ie,uo as Le,va as Re,vi as ze,vo as Be,wa as Ve,wi as He,xa as Ue,xi as We,xo as Ge,ya as Ke,yi as qe,yo as Je,zr as Ye}from"./index.js";var Xe=Le(`chevron-up`,[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]]),Z=O(),Q=b(xe()),Ze=Q.createContext({formRef:{current:{fields:new Map}},errors:{},clearErrors:fe,validationMode:`onSubmit`,submitAttemptedRef:{current:!1}});function Qe(){return Q.useContext(Ze)}function $e(e,t={}){let n=`rootStore`in e?e.rootStore:e,r=n.context.dataRef,{enabled:a=!0,event:o=`click`,toggle:c=!0,ignoreMouse:l=!1,stickIfOpen:u=!0,touchOpenDelay:d=0,reason:f=je}=t,p=Q.useRef(void 0),m=Ne(),h=ge(),g=Q.useMemo(()=>({onPointerDown(e){p.current=e.pointerType},onMouseDown(e){let t=p.current,a=e.nativeEvent,g=n.select(`open`);if(e.button!==0||o===`click`||Re(t,!0)&&l)return;let _=r.current.openEvent,v=_?.type,y=n.select(`domReferenceElement`)!==e.currentTarget,b=g&&y||!(g&&c&&(!(_&&u)||v===`click`||v===`mousedown`)),x=s(a);if(Ve(x)){let e=i(f,a,x);b&&t===`touch`&&d>0?h.start(d,()=>{n.setOpen(!0,e)}):n.setOpen(b,e);return}let S=e.currentTarget;m.request(()=>{let e=i(f,a,S);b&&t===`touch`&&d>0?h.start(d,()=>{n.setOpen(!0,e)}):n.setOpen(b,e)})},onClick(e){if(o===`mousedown-only`)return;let t=p.current;if(o===`mousedown`&&t){p.current=void 0;return}if(Re(t,!0)&&l)return;let a=n.select(`open`),s=r.current.openEvent,m=n.select(`domReferenceElement`)!==e.currentTarget,g=a&&m||!(a&&c&&(!(s&&u)||W(s))),_=i(f,e.nativeEvent,e.currentTarget);g&&t===`touch`&&d>0?h.start(d,()=>{n.setOpen(!0,_)}):n.setOpen(g,_)},onKeyDown(){p.current=void 0}}),[r,o,l,n,u,c,m,h,d,f]);return Q.useMemo(()=>a?{reference:g}:he,[a,g])}var et=`Escape`;function tt(e,t,n){switch(e){case`vertical`:return t;case`horizontal`:return n;default:return t||n}}function nt(e,t){return tt(t,e===`ArrowUp`||e===`ArrowDown`,e===`ArrowLeft`||e===`ArrowRight`)}function rt(e,t,n){return tt(t,e===`ArrowDown`,n?e===`ArrowLeft`:e===`ArrowRight`)||e===`Enter`||e===` `||e===``}function it(e,t,n){return tt(t,n?e===ye:e===r,e===E)}function at(e,t,n,i){return t===`both`||t===`horizontal`&&i&&i>1?e===et:tt(t,n?e===r:e===ye,e===ve)}function ot(e,t){let r=`rootStore`in e?e.rootStore:e,o=r.useState(`open`),c=r.useState(`floatingElement`),u=r.useState(`domReferenceElement`),d=r.context.dataRef,{listRef:f,activeIndex:p,onNavigate:m=()=>{},enabled:h=!0,selectedIndex:_=null,allowEscape:v=!1,loopFocus:y=!1,nested:b=!1,rtl:x=!1,virtual:S=!1,focusItemOnOpen:C=`auto`,focusItemOnHover:w=!0,openOnArrowKeyDown:T=!0,disabledIndices:E=void 0,orientation:O=`vertical`,parentOrientation:k,cols:A=1,id:te,resetOnPointerLeave:j=!0,externalTree:M}=t,N=D(ne(c)),I=We(),L=P(M);n(()=>{d.current.orientation=O},[d,O]);let ae=a(u),R=Q.useRef(C),z=Q.useRef(_??-1),B=Q.useRef(null),V=Q.useRef(!0),H=J(e=>{m(z.current===-1?null:z.current,e)}),U=Q.useRef(H),W=Q.useRef(!!c),G=Q.useRef(o),oe=Q.useRef(!1),K=Q.useRef(!1),ce=Q.useRef(null),de=D(E),Y=D(o),fe=D(_),me=D(j),he=J(()=>{function e(e){S?L?.events.emit(`virtualfocus`,e):ce.current=F(e,{sync:oe.current,preventScroll:!0})}let t=f.current[z.current],n=K.current;t&&e(t),(oe.current?e=>e():requestAnimationFrame)(()=>{let r=f.current[z.current]||t;r&&(t||e(r),ve&&(n||!V.current)&&r.scrollIntoView?.({block:`nearest`,inline:`nearest`}))})});n(()=>{h&&(o&&c?(z.current=_??-1,R.current&&_!=null&&(K.current=!0,H())):W.current&&(z.current=-1,U.current()))},[h,o,c,_,H]),n(()=>{if(h){if(!o){oe.current=!1;return}if(c)if(p==null){if(oe.current=!1,fe.current!=null)return;if(W.current&&(z.current=-1,he()),(!G.current||!W.current)&&R.current&&(B.current!=null||R.current===!0&&B.current==null)){let e=0,t=()=>{f.current[0]==null?(e<2&&(e?requestAnimationFrame:queueMicrotask)(t),e+=1):(z.current=B.current==null||rt(B.current,O,x)||b?ue(f):q(f),B.current=null,H())};t()}}else Ce(f.current,p)||(z.current=p,he(),K.current=!1)}},[h,o,c,p,fe,b,f,O,x,H,he,de]),n(()=>{if(!h||c||!L||S||!W.current)return;let e=L.nodesRef.current,t=e.find(e=>e.id===I)?.context?.elements.floating,n=re(ee(c)),r=e.some(e=>e.context&&l(e.context.elements.floating,n));t&&!r&&V.current&&t.focus({preventScroll:!0})},[h,c,L,I,S]),n(()=>{U.current=H,G.current=o,W.current=!!c}),n(()=>{o||(B.current=null,R.current=C)},[o,C]);let ge=p!=null,_e=J(e=>{if(!Y.current)return;let t=f.current.indexOf(e.currentTarget);t!==-1&&(z.current!==t||p!==t)&&(z.current=t,H(e))}),ve=Q.useMemo(()=>({onFocus(e){oe.current=!0,_e(e)},onClick:({currentTarget:e})=>e.focus({preventScroll:!0}),onMouseMove(e){oe.current=!0,K.current=!1,w&&_e(e)},onPointerLeave(e){if(!Y.current||!V.current||e.pointerType===`touch`)return;oe.current=!0;let t=e.relatedTarget;if(!(!w||f.current.includes(t))&&me.current&&(ce.current?.(),ce.current=null,z.current=-1,H(e),!S)){let e=N.current,t=re(ee(e));e&&l(e,t)&&e.focus({preventScroll:!0})}}}),[_e,Y,N,w,f,H,me,S]),ye=Q.useCallback(()=>k??L?.nodesRef.current.find(e=>e.id===I)?.context?.dataRef?.current.orientation,[I,L,k]),be=J(e=>{if(V.current=!1,oe.current=!0,e.which===229||!Y.current&&e.currentTarget===N.current)return;if(b&&at(e.key,O,x,A)){nt(e.key,ye())||Ue(e),r.setOpen(!1,i(ie,e.nativeEvent)),Ee(u)&&(S?L?.events.emit(`virtualfocus`,u):u.focus());return}let t=z.current,n=ue(f,E),a=q(f,E);if(ae||(e.key===`Home`&&(Ue(e),z.current=n,H(e)),e.key===`End`&&(Ue(e),z.current=a,H(e))),A>1){let t=Array.from({length:f.current.length},()=>({width:1,height:1})),r=De(t,A,!1),i=r.findIndex(e=>e!=null&&!pe(f.current,e,E)),o=r.reduce((e,t,n)=>t!=null&&!pe(f.current,t,E)?n:e,-1),s=r[Ie(r.map(e=>e==null?null:f.current[e]),{event:e,orientation:O,loopFocus:y,rtl:x,cols:A,disabledIndices:Se([...(typeof E==`function`?null:E)||f.current.map((e,t)=>pe(f.current,t,E)?t:void 0),void 0],r),minIndex:i,maxIndex:o,prevIndex:le(z.current>a?n:z.current,t,r,A,e.key===`ArrowDown`?`bl`:e.key===(x?`ArrowLeft`:`ArrowRight`)?`tr`:`tl`),stopEvent:!0})];if(s!=null&&(z.current=s,H(e)),O===`both`)return}if(nt(e.key,O)){if(Ue(e),o&&!S&&re(e.currentTarget.ownerDocument)===e.currentTarget){z.current=rt(e.key,O,x)?n:a,H(e);return}rt(e.key,O,x)?y?t>=a?v&&t!==f.current.length?z.current=-1:(oe.current=!1,z.current=n):z.current=X(f.current,{startingIndex:t,disabledIndices:E}):z.current=Math.min(a,X(f.current,{startingIndex:t,disabledIndices:E})):y?t<=n?v&&t!==-1?z.current=f.current.length:(oe.current=!1,z.current=a):z.current=X(f.current,{startingIndex:t,decrement:!0,disabledIndices:E}):z.current=Math.max(n,X(f.current,{startingIndex:t,decrement:!0,disabledIndices:E})),Ce(f.current,z.current)&&(z.current=-1),H(e)}}),xe=Q.useMemo(()=>S&&o&&ge&&{"aria-activedescendant":`${te}-${p}`},[S,o,ge,te,p]),we=Q.useMemo(()=>({"aria-orientation":O===`both`?void 0:O,...ae?{}:xe,onKeyDown(e){if(e.key===`Tab`&&e.shiftKey&&o&&!S){let t=s(e.nativeEvent);if(t&&!l(N.current,t))return;Ue(e),r.setOpen(!1,i(g,e.nativeEvent)),Ee(u)&&u.focus();return}be(e)},onPointerMove(){V.current=!0}}),[xe,be,N,O,ae,r,o,S,u]),Te=Q.useMemo(()=>{function e(e){C===`auto`&&Ke(e.nativeEvent)&&(R.current=!S)}function t(e){R.current=C,C===`auto`&&se(e.nativeEvent)&&(R.current=!0)}return{onKeyDown(e){let t=r.select(`open`);V.current=!1;let n=e.key.startsWith(`Arrow`),a=it(e.key,ye(),x),o=nt(e.key,O),s=(b?a:o)||e.key===`Enter`||e.key.trim()===``;if(S&&t)return be(e);if(!(!t&&!T&&n)){if(s){let t=nt(e.key,ye());B.current=b&&t?null:e.key}if(b){a&&(Ue(e),t?(z.current=ue(f,de.current),H(e)):r.setOpen(!0,i(ie,e.nativeEvent,e.currentTarget)));return}o&&(fe.current!=null&&(z.current=fe.current),Ue(e),!t&&T?r.setOpen(!0,i(ie,e.nativeEvent,e.currentTarget)):be(e),t&&H(e))}},onFocus(e){r.select(`open`)&&!S&&(z.current=-1,H(e))},onPointerDown:t,onPointerEnter:t,onMouseDown:e,onClick:e}},[be,de,C,f,b,H,r,T,O,ye,x,fe,S]),Oe=Q.useMemo(()=>({...xe,...Te}),[xe,Te]);return Q.useMemo(()=>h?{reference:Oe,floating:we,item:ve,trigger:Te}:{},[h,Oe,we,Te,ve])}function st(e,t){let r=`rootStore`in e?e.rootStore:e,i=r.context.dataRef,a=r.useState(`open`),{listRef:o,elementsRef:s,activeIndex:c,onMatch:u,onTypingChange:d,enabled:f=!0,resetMs:p=750,selectedIndex:m=null}=t,h=ge(),g=Q.useRef(``),_=Q.useRef(m??c??-1),v=Q.useRef(null);n(()=>{!a&&m!==null||(h.clear(),v.current=null,g.current!==``&&(g.current=``))},[a,m,h]),n(()=>{a&&g.current===``&&(_.current=m??c??-1)},[a,m,c]);let y=J(e=>{e?i.current.typing||(i.current.typing=e,d?.(e)):i.current.typing&&(i.current.typing=e,d?.(e))}),b=J(e=>{function t(e){let t=s?.current[e];return!t||Oe(t)}function n(e,n,r=0){if(e.length===0)return-1;let i=(r%e.length+e.length)%e.length,a=n.toLocaleLowerCase();for(let n=0;n0&&e.key===` `&&(Ue(e),y(!0)),g.current.length>0&&g.current[0]!==` `&&n(r,g.current)===-1&&e.key!==` `&&y(!1),r==null||e.key.length!==1||e.ctrlKey||e.metaKey||e.altKey)return;a&&e.key!==` `&&(Ue(e),y(!0));let i=g.current===``;i&&(_.current=m??c??-1),r.every(e=>e?e[0]?.toLocaleLowerCase()!==e[1]?.toLocaleLowerCase():!0)&&g.current===e.key&&(g.current=``,_.current=v.current),g.current+=e.key,h.start(p,()=>{g.current=``,_.current=v.current,y(!1)});let l=((i?m??c??-1:_.current)??0)+1,d=n(r,g.current,l);d===-1?e.key!==` `&&(g.current=``,y(!1)):(u?.(d),v.current=d)}),x=J(e=>{let t=e.relatedTarget,n=r.select(`domReferenceElement`),i=r.select(`floatingElement`),a=l(n,t),o=l(i,t);a||o||(h.clear(),g.current=``,_.current=v.current,y(!1))}),S=Q.useMemo(()=>({onKeyDown:b,onBlur:x}),[b,x]),C=Q.useMemo(()=>({onKeyDown:b,onBlur:x}),[b,x]);return Q.useMemo(()=>f?{reference:S,floating:C}:{},[f,S,C])}function ct(e){let[t,n]=Q.useState({current:e,previous:null});return e!==t.current&&n({current:e,previous:t.current}),t.previous}var lt=Q.createContext(null),ut=Q.createContext(null);function dt(){let e=Q.useContext(lt);if(e===null)throw Error(Je(60));return e}function ft(){let e=Q.useContext(ut);if(e===null)throw Error(Je(61));return e}var pt=(e,t)=>Object.is(e,t);function mt(e,t,n){return e==null||t==null?Object.is(e,t):n(e,t)}function ht(e,t,n){return!e||e.length===0?!1:e.some(e=>e===void 0?!1:mt(t,e,n))}function gt(e,t,n){return!e||e.length===0?-1:e.findIndex(e=>e===void 0?!1:mt(e,t,n))}function _t(e,t,n){return e.filter(e=>!mt(t,e,n))}function vt(e){if(e==null)return``;if(typeof e==`string`)return e;try{return JSON.stringify(e)}catch{return String(e)}}function yt(e){return e!=null&&e.length>0&&typeof e[0]==`object`&&e[0]!=null&&`items`in e[0]}function bt(e){if(!Array.isArray(e))return e!=null&&`null`in e;let t=e;if(yt(t)){for(let e of t)for(let t of e.items)if(t&&t.value==null&&t.label!=null)return!0;return!1}for(let e of t)if(e&&e.value==null&&e.label!=null)return!0;return!1}function xt(e,t){if(t&&e!=null)return t(e)??``;if(e&&typeof e==`object`){if(`label`in e&&e.label!=null)return String(e.label);if(`value`in e)return String(e.value)}return vt(e)}function St(e,t){return t&&e!=null?t(e)??``:e&&typeof e==`object`&&`value`in e&&`label`in e?vt(e.value):vt(e)}function Ct(e,t,n){function r(){return xt(e,n)}if(n&&e!=null)return n(e);if(e&&typeof e==`object`&&`label`in e&&e.label!=null)return e.label;if(t&&!Array.isArray(t))return t[e]??r();if(Array.isArray(t)){let n=t,i=yt(n)?n.flatMap(e=>e.items):n;if(typeof e!=`object`||!e){let t=i.find(t=>t.value===e);return t&&t.label!=null?t.label:r()}if(`value`in e){let t=i.find(t=>t&&t.value===e.value);if(t&&t.label!=null)return t.label}}return r()}function wt(e,t,n){return e.reduce((e,r,i)=>(i>0&&e.push(`, `),e.push((0,Z.jsx)(Q.Fragment,{children:Ct(r,t,n)},i)),e),[])}var $={id:G(e=>e.id),labelId:G(e=>e.labelId),modal:G(e=>e.modal),multiple:G(e=>e.multiple),items:G(e=>e.items),itemToStringLabel:G(e=>e.itemToStringLabel),itemToStringValue:G(e=>e.itemToStringValue),isItemEqualToValue:G(e=>e.isItemEqualToValue),value:G(e=>e.value),hasSelectedValue:G(e=>{let{value:t,multiple:n,itemToStringValue:r}=e;return t==null?!1:n&&Array.isArray(t)?t.length>0:St(t,r)!==``}),hasNullItemLabel:G((e,t)=>t?bt(e.items):!1),open:G(e=>e.open),mounted:G(e=>e.mounted),forceMount:G(e=>e.forceMount),transitionStatus:G(e=>e.transitionStatus),openMethod:G(e=>e.openMethod),activeIndex:G(e=>e.activeIndex),selectedIndex:G(e=>e.selectedIndex),isActive:G((e,t)=>e.activeIndex===t),isSelected:G((e,t,n)=>{let r=e.isItemEqualToValue,i=e.value;return e.multiple?Array.isArray(i)&&i.some(e=>mt(n,e,r)):e.selectedIndex===t&&e.selectedIndex!==null?!0:mt(n,i,r)}),isSelectedByFocus:G((e,t)=>e.selectedIndex===t),popupProps:G(e=>e.popupProps),triggerProps:G(e=>e.triggerProps),triggerElement:G(e=>e.triggerElement),positionerElement:G(e=>e.positionerElement),listElement:G(e=>e.listElement),scrollUpArrowVisible:G(e=>e.scrollUpArrowVisible),scrollDownArrowVisible:G(e=>e.scrollDownArrowVisible),hasScrollArrows:G(e=>e.hasScrollArrows)};function Tt(e,t=-(2**53-1),n=2**53-1){return Math.max(t,Math.min(e,n))}function Et(e,t){return Math.max(0,e-t)}function Dt(e,t){if(t<=0)return 0;let n=Tt(e,0,t),r=n,i=t-n,a=r<=1,o=i<=1;return a&&o?r<=i?0:t:a?0:o?t:n}function Ot(e){let{id:t,value:r,defaultValue:a=null,onValueChange:o,open:s,defaultOpen:l=!1,onOpenChange:d,name:f,form:h,autoComplete:g,disabled:_=!1,readOnly:v=!1,required:y=!1,modal:b=!0,actionsRef:x,inputRef:C,onOpenChangeComplete:w,items:ee,multiple:T=!1,itemToStringLabel:E,itemToStringValue:O,isItemEqualToValue:A=pt,highlightItemOnHover:j=!0,children:M}=e,{clearErrors:N}=Qe(),{setDirty:ne,setTouched:P,setFocused:re,shouldValidateOnChange:F,validityData:I,setFilled:L,name:ie,disabled:R,validation:B,validationMode:H}=S(),W=k({id:t}),G=R||_,se=ie??f,[K,le]=z({controlled:r,default:T?a??Te:a,name:`Select`,state:`value`}),[q,ue]=z({controlled:s,default:l,name:`Select`,state:`open`}),de=Q.useRef([]),fe=Q.useRef([]),pe=Q.useRef(null),ge=Q.useRef(null),_e=Q.useRef(0),ve=Q.useRef(null),ye=Q.useRef([]),be=Q.useRef(!1),xe=Q.useRef(!1),Se=Q.useRef(null),Ce=Q.useRef({allowSelectedMouseUp:!1,allowUnselectedMouseUp:!1}),Ee=Q.useRef(!1),{mounted:De,setMounted:Oe,transitionStatus:Ae}=U(q),{openMethod:je,triggerProps:Ne}=ae(q),X=Be(()=>new me({id:W,labelId:void 0,modal:b,multiple:T,itemToStringLabel:E,itemToStringValue:O,isItemEqualToValue:A,value:K,open:q,mounted:De,transitionStatus:Ae,items:ee,forceMount:!1,openMethod:null,activeIndex:null,selectedIndex:null,popupProps:{},triggerProps:{},triggerElement:null,positionerElement:null,listElement:null,scrollUpArrowVisible:!1,scrollDownArrowVisible:!1,hasScrollArrows:!1})).current,Pe=Y(X,$.activeIndex),Fe=Y(X,$.selectedIndex),Ie=Y(X,$.triggerElement),Le=Y(X,$.positionerElement),Re=ct(je),ze=je??Re,Ve=Q.useMemo(()=>T&&Array.isArray(K)&&K.length===0?``:St(K,O),[T,K,O]),He=Q.useMemo(()=>T&&Array.isArray(K)?K.map(e=>St(e,O)):St(K,O),[T,K,O]);V(D(X.state.triggerElement),{id:W,value:K,getValue:J(()=>He)});let Ue=Q.useRef(K);n(()=>{K!==Ue.current&&X.set(`forceMount`,!0)},[X,K]),n(()=>{L(T?Array.isArray(K)&&K.length>0:K!=null)},[T,K,L]),n(function(){if(q)return;let e=ye.current;if(T){let t=Array.isArray(K)?K:[];if(t.length===0){X.set(`selectedIndex`,null);return}let n=t[t.length-1],r=gt(e,n,A);X.set(`selectedIndex`,r===-1?null:r);return}let t=gt(e,K,A);X.set(`selectedIndex`,t===-1?null:t)},[T,q,K,ye,A,X]),m(K,()=>{N(se),ne(K!==I.initialValue),F()?B.commit(K):B.commit(K,!0)});let We=J((e,t)=>{if(d?.(e,t),!t.isCanceled&&(ue(e),!e&&(t.reason===`focus-out`||t.reason===`outside-press`)&&(P(!0),re(!1),H===`onBlur`&&B.commit(K)),!e&&X.state.activeIndex!==null)){let e=de.current[X.state.activeIndex];queueMicrotask(()=>{e?.setAttribute(`tabindex`,`-1`)})}}),Ge=J(()=>{Oe(!1),X.update({activeIndex:null,openMethod:null}),w?.(!1)});te({enabled:!x,open:q,ref:pe,onComplete(){q||Ge()}}),Q.useImperativeHandle(x,()=>({unmount:Ge}),[Ge]);let Ke=J((e,t)=>{o?.(e,t),!t.isCanceled&&le(e)}),Je=J(()=>{let e=X.state.listElement||pe.current;if(!e)return;let t=Et(e.scrollHeight,e.clientHeight),n=Dt(e.scrollTop,t),r=n>0,i=nce(Xe(),Ne,W?{id:W}:he),[Xe,Ne,W]);Me(()=>{X.update({popupProps:Ze(),triggerProps:tt})}),n(()=>{X.update({id:W,modal:b,multiple:T,value:K,open:q,mounted:De,transitionStatus:Ae,popupProps:Ze(),triggerProps:tt,items:ee,itemToStringLabel:E,itemToStringValue:O,isItemEqualToValue:A,openMethod:ze})},[X,W,b,T,K,q,De,Ae,Ze,tt,ee,E,O,A,ze]);let nt=Q.useMemo(()=>({store:X,name:se,required:y,disabled:G,readOnly:v,multiple:T,highlightItemOnHover:j,setValue:Ke,setOpen:We,listRef:de,popupRef:pe,scrollHandlerRef:ge,handleScrollArrowVisibility:Je,scrollArrowsMountedCountRef:_e,getItemProps:et,events:Ye.context.events,valueRef:ve,valuesRef:ye,labelsRef:fe,typingRef:be,selectionRef:Ce,selectedItemTextRef:Se,validation:B,onOpenChangeComplete:w,keyboardActiveRef:xe,alignItemWithTriggerActiveRef:Ee,initialValueRef:Ue}),[X,se,y,G,v,T,j,Ke,We,et,Ye.context.events,B,w,Je]),rt=oe(C,B.inputRef),it=T&&Array.isArray(K)&&K.length>0,at=T?void 0:se,dt=Q.useMemo(()=>!T||!Array.isArray(K)||!se?null:K.map(e=>{let t=St(e,O);return(0,Z.jsx)(`input`,{type:`hidden`,form:h,name:se,value:t},t)}),[T,K,h,se,O]);return(0,Z.jsx)(lt.Provider,{value:nt,children:(0,Z.jsxs)(ut.Provider,{value:Ye,children:[M,(0,Z.jsx)(`input`,{...B.getInputValidationProps({onFocus(){X.state.triggerElement?.focus({focusVisible:!0})},onChange(e){if(e.nativeEvent.defaultPrevented)return;let t=e.currentTarget.value,n=i(p,e.nativeEvent);function r(){if(T)return;let e=ye.current.find(e=>St(e,O).toLowerCase()===t.toLowerCase()||xt(e,E).toLowerCase()===t.toLowerCase());e!=null&&(ne(e!==I.initialValue),Ke(e,n),F()&&B.commit(e))}X.set(`forceMount`,!0),queueMicrotask(r)}}),id:W&&at==null?`${W}-hidden-input`:void 0,form:h,name:at,autoComplete:g,value:Ve,disabled:G,required:y&&!it,readOnly:v,ref:rt,style:se?c:u,tabIndex:-1,"aria-hidden":!0,suppressHydrationWarning:!0}),dt]})})}function kt(e,t){return e??t}function At(e){let t=e.getBoundingClientRect(),n=Fe(e),r=n.getComputedStyle(e,`::before`),i=n.getComputedStyle(e,`::after`);if(!(r.content!==`none`||i.content!==`none`))return t;let a=parseFloat(r.width)||0,o=parseFloat(r.height)||0,s=parseFloat(i.width)||0,c=parseFloat(i.height)||0,l=Math.max(t.width,a,s),u=Math.max(t.height,o,c),d=l-t.width,f=u-t.height;return{left:t.left-d/2,right:t.right+d/2,top:t.top-f/2,bottom:t.bottom+f/2}}var jt=2,Mt=400,Nt=200,Pt={...A,...j,value:()=>null},Ft=Q.forwardRef(function(e,t){let{render:n,className:r,id:a,disabled:o=!1,nativeButton:s=!0,style:c,...u}=e,{setTouched:f,setFocused:m,validationMode:h,state:g,disabled:_}=S(),{labelId:v}=d(),{store:y,setOpen:b,selectionRef:x,validation:C,readOnly:w,required:T,alignItemWithTriggerActiveRef:E,disabled:O,keyboardActiveRef:A}=dt(),te=_||O||o,j=Y(y,$.open),M=Y(y,$.value),N=Y(y,$.triggerProps),P=Y(y,$.positionerElement),re=Y(y,$.listElement),F=Y(y,$.id),I=Y(y,$.labelId),ie=Y(y,$.hasSelectedValue),ae=!ie&&j,z=Y(y,$.hasNullItemLabel,ae),B=a??F,V=kt(v,I);k({id:B});let H=D(P),U=Q.useRef(null),{getButtonProps:W,buttonRef:G}=R({disabled:te,native:s}),se=oe(t,U,G,J(e=>{y.set(`triggerElement`,e)})),K=ge(),le=ge(),q=ge(),ue=ge();Q.useEffect(()=>{if(j)return ie||z?ue.start(Nt,()=>{x.current.allowUnselectedMouseUp=!0,q.start(Nt,()=>{x.current.allowSelectedMouseUp=!0})}):q.start(Mt,()=>{x.current.allowUnselectedMouseUp=!0,x.current.allowSelectedMouseUp=!0}),()=>{q.clear(),ue.clear()};x.current={allowSelectedMouseUp:!1,allowUnselectedMouseUp:!1},le.clear()},[j,ie,z,x,le,q,ue]);let de=Q.useMemo(()=>re?.id??ne(P)?.id,[re,P]),fe=ce(N,{id:B,role:`combobox`,"aria-expanded":j?`true`:`false`,"aria-haspopup":`listbox`,"aria-controls":j?de:void 0,"aria-labelledby":V,"aria-readonly":w||void 0,"aria-required":T||void 0,tabIndex:te?-1:0,ref:se,onFocus(e){m(!0),j&&E.current&&b(!1,i(p,e.nativeEvent)),K.start(0,()=>{y.set(`forceMount`,!0)})},onBlur(e){l(P,e.relatedTarget)||(f(!0),m(!1),h===`onBlur`&&C.commit(M))},onPointerMove(){A.current=!1},onKeyDown(){A.current=!0},onMouseDown(e){if(j)return;let t=ee(e.currentTarget);function n(e){if(!U.current)return;let t=e.target;if(l(U.current,t)||l(H.current,t)||t===U.current)return;let n=At(U.current);e.clientX>=n.left-jt&&e.clientX<=n.right+jt&&e.clientY>=n.top-jt&&e.clientY<=n.bottom+jt||b(!1,i(L,e))}le.start(0,()=>{t.addEventListener(`mouseup`,n,{once:!0})})}},C.getValidationProps,u,W);fe.role=`combobox`;let pe={...g,open:j,disabled:te,value:M,readOnly:w,placeholder:!ie};return Ae(`button`,e,{ref:[t,U],state:pe,stateAttributesMapping:Pt,props:fe})}),It={value:()=>null},Lt=Q.forwardRef(function(e,t){let{className:n,render:r,children:i,placeholder:a,style:o,...s}=e,{store:c,valueRef:l}=dt(),u=Y(c,$.value),d=Y(c,$.items),f=Y(c,$.itemToStringLabel),p=Y(c,$.hasSelectedValue),m=!p&&a!=null&&i==null,h=Y(c,$.hasNullItemLabel,m),g={value:u,placeholder:!p},_=null;return _=typeof i==`function`?i(u):i??(!p&&a!=null&&!h?a:Array.isArray(u)?wt(u,d,f):Ct(u,d,f)),Ae(`span`,e,{state:g,ref:[t,l],props:[{children:_},s],stateAttributesMapping:It})}),Rt=Q.forwardRef(function(e,t){let{className:n,render:r,style:i,...a}=e,{store:o}=dt();return Ae(`span`,e,{state:{open:Y(o,$.open)},ref:t,props:[{"aria-hidden":!0,children:`▼`},a],stateAttributesMapping:f})}),zt=Q.createContext(void 0),Bt=Q.forwardRef(function(e,t){let{store:n}=dt(),r=Y(n,$.mounted),i=Y(n,$.forceMount);return r||i?(0,Z.jsx)(zt.Provider,{value:!0,children:(0,Z.jsx)(o,{ref:t,...e})}):null}),Vt=Q.createContext({register:()=>{},unregister:()=>{},subscribeMapChange:()=>()=>{},elementsRef:{current:[]},nextIndexRef:{current:0}});function Ht(){return Q.useContext(Vt)}function Ut(e){let{children:t,elementsRef:r,labelsRef:i,onMapChange:a}=e,o=J(a),s=Q.useRef(0),c=Be(Gt).current,l=Be(Wt).current,[u,d]=Q.useState(0),f=Q.useRef(u),p=J((e,t)=>{l.set(e,t??null),f.current+=1,d(f.current)}),m=J(e=>{l.delete(e),f.current+=1,d(f.current)}),h=Q.useMemo(()=>{let e=new Map;return Array.from(l.keys()).filter(e=>e.isConnected).sort(Kt).forEach((t,n)=>{let r=l.get(t)??{};e.set(t,{...r,index:n})}),e},[l,u]);n(()=>{if(typeof MutationObserver!=`function`||h.size===0)return;let e=new MutationObserver(e=>{let t=new Set,n=e=>t.has(e)?t.delete(e):t.add(e);e.forEach(e=>{e.removedNodes.forEach(n),e.addedNodes.forEach(n)}),t.size===0&&(f.current+=1,d(f.current))});return h.forEach((t,n)=>{n.parentElement&&e.observe(n.parentElement,{childList:!0})}),()=>{e.disconnect()}},[h]),n(()=>{f.current===u&&(r.current.length!==h.size&&(r.current.length=h.size),i&&i.current.length!==h.size&&(i.current.length=h.size),s.current=h.size),o(h)},[o,h,r,i,u]),n(()=>()=>{r.current=[]},[r]),n(()=>()=>{i&&(i.current=[])},[i]);let g=J(e=>(c.add(e),()=>{c.delete(e)}));n(()=>{c.forEach(e=>e(h))},[c,h]);let _=Q.useMemo(()=>({register:p,unregister:m,subscribeMapChange:g,elementsRef:r,labelsRef:i,nextIndexRef:s}),[p,m,g,r,i,s]);return(0,Z.jsx)(Vt.Provider,{value:_,children:t})}function Wt(){return new Map}function Gt(){return new Set}function Kt(e,t){let n=e.compareDocumentPosition(t);return n&Node.DOCUMENT_POSITION_FOLLOWING||n&Node.DOCUMENT_POSITION_CONTAINED_BY?-1:n&Node.DOCUMENT_POSITION_PRECEDING||n&Node.DOCUMENT_POSITION_CONTAINS?1:0}var qt=Q.createContext(void 0);function Jt(){let e=Q.useContext(qt);if(!e)throw Error(Je(59));return e}function Yt(e,t){e&&Object.assign(e.style,t)}var Xt={position:`relative`,maxHeight:`100%`,overflowX:`hidden`,overflowY:`auto`},Zt=20;function Qt(e,t,r,i){let[a,o]=Q.useState(!1);n(()=>{if(!e||!t||r==null){o(!1);return}let n=ee(r).documentElement.clientWidth,i=r.offsetWidth;o(n>0&&i>0&&i>=n-Zt)},[e,t,r]),x(e&&(!t||a),i)}var $t={position:`fixed`},en=Q.forwardRef(function(e,t){let{anchor:r,positionMethod:a=`absolute`,className:o,render:s,side:c=`bottom`,align:l=`center`,sideOffset:u=0,alignOffset:d=0,collisionBoundary:f=`clipping-ancestors`,collisionPadding:m,arrowPadding:h=5,sticky:g=!1,disableAnchorTracking:_,alignItemWithTrigger:y=!0,collisionAvoidance:b=He,style:x,...S}=e,{store:C,listRef:w,labelsRef:ee,alignItemWithTriggerActiveRef:T,selectedItemTextRef:E,valuesRef:D,initialValueRef:O,popupRef:k,setValue:A}=dt(),te=ft(),j=Y(C,$.open),M=Y(C,$.mounted),ne=Y(C,$.modal),P=Y(C,$.value),re=Y(C,$.openMethod),F=Y(C,$.positionerElement),I=Y(C,$.triggerElement),L=Y(C,$.isItemEqualToValue),ie=Y(C,$.transitionStatus),ae=Q.useRef(null),R=Q.useRef(null),[z,V]=Q.useState(y),U=M&&z&&re!==`touch`;!M&&z!==y&&V(y),n(()=>{M||($.scrollUpArrowVisible(C.state)&&C.set(`scrollUpArrowVisible`,!1),$.scrollDownArrowVisible(C.state)&&C.set(`scrollDownArrowVisible`,!1))},[C,M]),Q.useImperativeHandle(T,()=>U),Qt((U||ne)&&j,re===`touch`,F,I);let W=N({anchor:r,floatingRootContext:te,positionMethod:a,mounted:M,side:c,sideOffset:u,align:l,alignOffset:d,arrowPadding:h,collisionBoundary:f,collisionPadding:m,sticky:g,disableAnchorTracking:_??U,collisionAvoidance:b,keepMounted:!0}),G=U?`none`:W.side,oe=U?$t:W.positionerStyles,se=v(e,{open:j,side:G,align:W.align,anchorHidden:W.anchorHidden},{styles:oe,transitionStatus:ie,props:S,refs:[t,J(e=>{C.set(`positionerElement`,e)})],hidden:!M,inert:!j}),K=Q.useRef(0),ce=J(e=>{if(e.size===0&&K.current===0||D.current.length===0)return;let t=K.current;if(K.current=e.size,e.size===t)return;let n=i(p);if(t!==0&&!C.state.multiple&&P!==null&>(D.current,P,L)===-1){let e=O.current,t=e!=null&>(D.current,e,L)!==-1?e:null;A(t,n),t===null&&(C.set(`selectedIndex`,null),E.current=null)}if(t!==0&&C.state.multiple&&Array.isArray(P)){let e=e=>gt(D.current,e,L)!==-1,t=P.filter(t=>e(t));(t.length!==P.length||t.some(e=>!ht(P,e,L)))&&(A(t,n),t.length===0&&(C.set(`selectedIndex`,null),E.current=null))}if(j&&U){C.update({scrollUpArrowVisible:!1,scrollDownArrowVisible:!1});let e={height:``};Yt(F,e),Yt(k.current,e)}}),le=Q.useMemo(()=>({...W,side:G,alignItemWithTriggerActive:U,setControlledAlignItemWithTrigger:V,scrollUpArrowRef:ae,scrollDownArrowRef:R}),[W,G,U,V]);return(0,Z.jsx)(Ut,{elementsRef:w,labelsRef:ee,onMapChange:ce,children:(0,Z.jsxs)(qt.Provider,{value:le,children:[M&&ne&&(0,Z.jsx)(H,{inert:B(!j),cutout:I}),se]})})}),tn=`base-ui-disable-scrollbar`,nn={className:tn,getElement(e){return(0,Z.jsx)(`style`,{nonce:e,href:tn,precedence:`base-ui:low`,children:`.${tn}{scrollbar-width:none}.${tn}::-webkit-scrollbar{display:none}`})}},rn=Q.createContext(void 0);function an(e){let t=Q.useContext(rn);if(t===void 0&&!e)throw Error(Je(69));return t}var on=Q.createContext(void 0),sn={disableStyleElements:!1};function cn(){return Q.useContext(on)??sn}var ln={...T,...Pe},un=Q.forwardRef(function(e,t){let{render:r,className:a,style:o,finalFocus:s,...c}=e,{store:l,popupRef:u,onOpenChangeComplete:d,setOpen:f,valueRef:p,selectedItemTextRef:m,keyboardActiveRef:h,multiple:g,handleScrollArrowVisibility:_,scrollHandlerRef:v,listRef:b,highlightItemOnHover:x}=dt(),{side:S,align:T,alignItemWithTriggerActive:E,isPositioned:D,setControlledAlignItemWithTrigger:O,scrollDownArrowRef:k,scrollUpArrowRef:A}=Jt(),j=an(!0)!=null,M=ft(),N=Ye(),{nonce:ne,disableStyleElements:P}=cn(),re=Y(l,$.id),F=Y(l,$.open),I=Y(l,$.mounted),L=Y(l,$.popupProps),ie=Y(l,$.transitionStatus),ae=Y(l,$.triggerElement),R=Y(l,$.positionerElement),z=Y(l,$.listElement),B=Q.useRef(!1),V=Q.useRef(!1),H=Q.useRef({}),U=Ne(),W=J(e=>{if(!R||!u.current||!V.current)return;if(B.current||!E){_();return}let t=R.style.top===`0px`,n=R.style.bottom===`0px`;if(!t&&!n){_();return}let r=pn(R),i=mn(R.getBoundingClientRect().height,`y`,r),a=ee(R),o=getComputedStyle(R),s=parseFloat(o.marginTop),c=parseFloat(o.marginBottom),l=dn(getComputedStyle(u.current)),d=Math.min(a.documentElement.clientHeight-s-c,l),f=e.scrollTop,p=fn(e),m=0,h=null,g=!1,v=!1,y=e=>{R.style.height=`${e}px`},b=(t,n)=>{let r=Tt(t,0,d-i);r>0&&y(i+r),e.scrollTop=n,d-(i+r)<=1&&(B.current=!0),_()},x=t?p-f:f,S=Math.min(i+x,d);if(m=S,x<=1){b(x,t?p:0);return}if(d-S>1?t?v=!0:h=0:(g=!0,n&&f1&&(e.scrollTop=n)}(g||m>=d-1)&&(B.current=!0),_()});Q.useImperativeHandle(v,()=>W,[W]),te({open:F,ref:u,onComplete(){F&&d?.(!0)}});let G={open:F,transitionStatus:ie,side:S,align:T};n(()=>{!R||!u.current||Object.keys(H.current).length||(H.current={top:R.style.top||`0`,left:R.style.left||`0`,right:R.style.right,height:R.style.height,bottom:R.style.bottom,minHeight:R.style.minHeight,maxHeight:R.style.maxHeight,marginTop:R.style.marginTop,marginBottom:R.style.marginBottom})},[u,R]),n(()=>{F||E||(V.current=!1,B.current=!1,Yt(R,H.current))},[F,E,R,u]),n(()=>{let e=u.current;if(!F||!ae||!R||!e||E&&!D||l.state.transitionStatus===`ending`)return;if(!E){V.current=!0,U.request(_),e.style.removeProperty(`--transform-origin`);return}let t=_n(e);e.style.removeProperty(`--transform-origin`);try{let t=m.current,n=p.current,r=getComputedStyle(R),i=getComputedStyle(e),a=ee(ae),o=Fe(R),s=pn(ae),c=hn(ae.getBoundingClientRect(),s),u=hn(R.getBoundingClientRect(),s),d=c.height,f=z||e,h=f.scrollHeight,g=parseFloat(i.borderBottomWidth),v=parseFloat(r.marginTop)||10,y=parseFloat(r.marginBottom)||10,S=parseFloat(r.minHeight)||100,C=dn(i),T=a.documentElement.clientHeight-v-y,E=a.documentElement.clientWidth,D=T-c.bottom+d,k,A=N===`rtl`?c.right-u.width:c.left,te=0;if(t&&n){let e=hn(n.getBoundingClientRect(),s);k=hn(t.getBoundingClientRect(),s),A=u.left+(N===`rtl`?e.right-k.right:e.left-k.left);let r=e.top-c.top+e.height/2;te=k.top-u.top+k.height/2-r}let j=D+te+y+g,M=Math.min(T,j),ne=T-v-y,P=j-M,re=E-5;R.style.left=`${Tt(A,5,re-u.width)}px`,R.style.height=`${M}px`,R.style.maxHeight=`auto`,R.style.marginTop=`${v}px`,R.style.marginBottom=`${y}px`,e.style.height=`100%`;let F=fn(f),I=P>=F-1;I&&(M=Math.min(T,u.height)-(P-F));let L=c.top<20||c.bottom>T-20||Math.ceil(M)+1=ne?`0`:`${e}px`,R.style.height=`${M}px`,f.scrollTop=fn(f)}else R.style.bottom=`0`,f.scrollTop=P;if(k){let t=u.top,n=u.height,r=k.top+k.height/2,i=Tt(n>0?(r-t)/n*100:50,0,100);e.style.setProperty(`--transform-origin`,`50% ${i}%`)}(U===T||M>=C)&&(B.current=!0),_(),x&&l.state.selectedIndex===null&&l.state.activeIndex===null&&b.current[0]!=null&&l.set(`activeIndex`,0),V.current=!0}finally{t()}},[l,F,R,ae,p,m,u,_,E,O,U,k,A,z,b,x,N,D]),Q.useEffect(()=>{if(!E||!R||!F)return;let e=Fe(R);function t(e){f(!1,i(y,e))}return be(e,`resize`,t)},[f,E,R,F]);let oe={...z?{role:`presentation`,"aria-orientation":void 0}:{role:`listbox`,"aria-multiselectable":g||void 0,id:`${re}-list`},onKeyDown(e){h.current=!0,j&&_e.has(e.key)&&e.stopPropagation()},onMouseMove(){h.current=!1},onScroll(e){z||W(e.currentTarget)},...E&&{style:z?{height:`100%`}:Xt}},se=Ae(`div`,e,{ref:[t,u],state:G,stateAttributesMapping:ln,props:[L,oe,C(ie),{className:!z&&E?nn.className:void 0},c]});return(0,Z.jsxs)(Q.Fragment,{children:[!P&&nn.getElement(ne),(0,Z.jsx)(K,{context:M,modal:!1,disabled:!I,returnFocus:s,restoreFocus:!0,children:se})]})});function dn(e){let t=e.maxHeight||``;return t.endsWith(`px`)&&parseFloat(t)||1/0}function fn(e){return Et(e.scrollHeight,e.clientHeight)}function pn(e){return ze.getScale(e)}function mn(e,t,n){return e/n[t]}function hn(e,t){return de({x:mn(e.x,`x`,t),y:mn(e.y,`y`,t),width:mn(e.width,`x`,t),height:mn(e.height,`y`,t)})}var gn=[[`transform`,`none`],[`scale`,`1`],[`translate`,`0 0`]];function _n(e){let{style:t}=e,n={};for(let[e,r]of gn)n[e]=t.getPropertyValue(e),t.setProperty(e,r,`important`);return()=>{for(let[e]of gn){let r=n[e];r?t.setProperty(e,r):t.removeProperty(e)}}}var vn=Q.forwardRef(function(e,t){let{className:n,render:r,style:i,...a}=e,{store:o,scrollHandlerRef:s}=dt(),{alignItemWithTriggerActive:c}=Jt(),l=Y(o,$.hasScrollArrows),u=Y(o,$.openMethod),d=Y(o,$.multiple),f={id:`${Y(o,$.id)}-list`,role:`listbox`,"aria-multiselectable":d||void 0,onScroll(e){s.current?.(e.currentTarget)},...c&&{style:Xt},className:l&&u!==`touch`?nn.className:void 0};return Ae(`div`,e,{ref:[t,J(e=>{o.set(`listElement`,e)})],props:[f,a]})}),yn=function(e){return e[e.None=0]=`None`,e[e.GuessFromOrder=1]=`GuessFromOrder`,e}({});function bn(e={}){let{label:t,metadata:r,textRef:i,indexGuessBehavior:a,index:o}=e,{register:s,unregister:c,subscribeMapChange:l,elementsRef:u,labelsRef:d,nextIndexRef:f}=Ht(),p=Q.useRef(-1),[m,h]=Q.useState(o??(a===yn.GuessFromOrder?()=>{if(p.current===-1){let e=f.current;f.current+=1,p.current=e}return p.current}:-1)),g=Q.useRef(null),_=Q.useCallback(e=>{if(g.current=e,m!==-1&&e!==null&&(u.current[m]=e,d)){let n=t!==void 0;d.current[m]=n?t:i?.current?.textContent??e.textContent}},[m,u,d,t,i]);return n(()=>{if(o!=null)return;let e=g.current;if(e)return s(e,r),()=>{c(e)}},[o,s,c,r]),n(()=>{if(o==null)return l(e=>{let t=g.current?e.get(g.current)?.index:null;t!=null&&h(t)})},[o,l,h]),Q.useMemo(()=>({ref:_,index:m}),[m,_])}var xn=Q.createContext(void 0);function Sn(){let e=Q.useContext(xn);if(!e)throw Error(Je(57));return e}var Cn=Q.memo(Q.forwardRef(function(e,t){let{render:r,className:a,value:o=null,label:s,disabled:c=!1,nativeButton:l=!1,style:u,...d}=e,f=Q.useRef(null),p=bn({label:s,textRef:f,indexGuessBehavior:yn.GuessFromOrder}),{store:m,getItemProps:h,setOpen:g,setValue:_,selectionRef:v,typingRef:y,valuesRef:b,multiple:x,selectedItemTextRef:S}=dt(),C=Y(m,$.isActive,p.index),w=Y(m,$.isSelected,p.index,o),ee=Y(m,$.isSelectedByFocus,p.index),T=Y(m,$.isItemEqualToValue),E=p.index,O=E!==-1,k=Q.useRef(null),A=D(E);n(()=>{if(!O)return;let e=b.current;return e[E]=o,()=>{delete e[E]}},[O,E,o,b]),n(()=>{if(!O)return;let e=m.state.value,t=e;x&&Array.isArray(e)&&e.length>0&&(t=e[e.length-1]),t!==void 0&&mt(o,t,T)&&(m.set(`selectedIndex`,E),f.current&&(S.current=f.current))},[O,E,x,T,m,o,S]);let te={disabled:c,selected:w,highlighted:C},j=h({active:C,selected:w});j.id=void 0;let M=Q.useRef(null),N=Q.useRef(`mouse`),ne=Q.useRef(!1),{getButtonProps:P,buttonRef:re}=R({disabled:c,focusableWhenDisabled:!0,native:l,composite:!0});function F(e){let t=m.state.value;if(x){let n=Array.isArray(t)?t:[];_(w?_t(n,o,T):[...n,o],i(I,e))}else _(o,i(I,e)),g(!1,i(I,e))}let L={role:`option`,"aria-selected":w,tabIndex:C?0:-1,onTouchStart(){v.current={allowSelectedMouseUp:!1,allowUnselectedMouseUp:!1}},onKeyDown(e){M.current=e.key,m.set(`activeIndex`,E),e.key===` `&&y.current&&e.preventDefault()},onClick(e){ne.current=!1,!(e.type===`keydown`&&M.current===null)&&(c||e.type===`keydown`&&M.current===` `&&y.current||N.current!==`touch`&&!C||(M.current=null,F(e.nativeEvent)))},onPointerEnter(e){N.current=e.pointerType},onPointerDown(e){N.current=e.pointerType,ne.current=!0},onMouseUp(){if(c)return;if(ne.current){ne.current=!1;return}let e=!v.current.allowSelectedMouseUp&&w,t=!v.current.allowUnselectedMouseUp&&!w;e||t||N.current!==`touch`&&!C||k.current?.click()}},ie=Ae(`div`,e,{ref:[re,t,p.ref,k],state:te,props:[j,L,d,P]}),ae=Q.useMemo(()=>({selected:w,indexRef:A,textRef:f,selectedByFocus:ee,hasRegistered:O}),[w,A,f,ee,O]);return(0,Z.jsx)(xn.Provider,{value:ae,children:ie})})),wn=Q.forwardRef(function(e,t){let n=e.keepMounted??!1,{selected:r}=Sn();return n||r?(0,Z.jsx)(Tn,{...e,ref:t}):null}),Tn=Q.memo(Q.forwardRef((e,t)=>{let{render:n,className:r,style:i,keepMounted:a,...o}=e,{selected:s}=Sn(),c=Q.useRef(null),{transitionStatus:l,setMounted:u}=U(s),d=Ae(`span`,e,{ref:[t,c],state:{selected:s,transitionStatus:l},props:[{"aria-hidden":!0,children:`✔️`},o],stateAttributesMapping:Pe});return te({open:s,ref:c,onComplete(){s||u(!1)}}),d})),En=Q.memo(Q.forwardRef(function(e,t){let{indexRef:n,textRef:r,selectedByFocus:i,hasRegistered:a}=Sn(),{selectedItemTextRef:o}=dt(),{className:s,render:c,style:l,...u}=e;return Ae(`div`,e,{ref:[Q.useCallback(e=>{if(!e||!a)return;let t=o.current===null||!o.current.isConnected;(i||t&&n.current===0)&&(o.current=e)},[o,n,i,a]),t,r],props:u})})),Dn=Q.forwardRef(function(e,t){let{render:r,className:i,style:a,direction:o,keepMounted:s=!1,...c}=e,l=o===`up`,{store:u,popupRef:d,listRef:f,handleScrollArrowVisibility:p,scrollArrowsMountedCountRef:m}=dt(),{side:h,scrollDownArrowRef:g,scrollUpArrowRef:_}=Jt(),v=Y(u,l?$.scrollUpArrowVisible:$.scrollDownArrowVisible),y=Y(u,$.openMethod),b=v&&y!==`touch`,x=ge(),S=l?_:g,{transitionStatus:C,setMounted:w}=U(b);n(()=>(m.current+=1,u.state.hasScrollArrows||u.set(`hasScrollArrows`,!0),()=>{m.current=Math.max(0,m.current-1),m.current===0&&u.state.hasScrollArrows&&u.set(`hasScrollArrows`,!1)}),[u,m]),te({open:b,ref:S,onComplete(){b||w(!1)}});let ee=Ae(`div`,e,{ref:[t,S],state:{direction:o,visible:b,side:h,transitionStatus:C},props:[{"aria-hidden":!0,children:l?`▲`:`▼`,style:{position:`absolute`},onMouseMove(e){if(e.movementX===0&&e.movementY===0||x.isStarted())return;u.set(`activeIndex`,null);function t(){let e=u.state.listElement??d.current;if(!e)return;u.set(`activeIndex`,null),p();let n=Et(e.scrollHeight,e.clientHeight),r=Dt(e.scrollTop,n),i=r===(l?0:n),a=f.current;if(r!==e.scrollTop&&(e.scrollTop=r),a.length===0&&u.set(l?`scrollUpArrowVisible`:`scrollDownArrowVisible`,!i),i){x.clear();return}if(a.length>0){let t=S.current?.offsetHeight||0;e.scrollTop=On(a,l,r,e.clientHeight,t,n)}x.start(40,t)}x.start(40,t)},onMouseLeave(){x.clear()}},c]});return b||s?ee:null});function On(e,t,n,r,i,a){if(t){let t=0,r=n+i-1;for(let n=0;n=r){t=n;break}}let o=Math.max(0,t-1),s=e[o];return os){o=Math.max(0,t-1);break}}let c=Math.min(e.length-1,o+1),l=e[c];return c>o&&l?Dt(l.offsetTop+l.offsetHeight-r+i,a):a}var kn=Q.forwardRef(function(e,t){return(0,Z.jsx)(Dn,{...e,ref:t,direction:`down`})}),An=Q.forwardRef(function(e,t){return(0,Z.jsx)(Dn,{...e,ref:t,direction:`up`})}),jn=Q.createContext(void 0);function Mn(){let e=Q.useContext(jn);if(e===void 0)throw Error(Je(56));return e}var Nn=Q.forwardRef(function(e,t){let{className:n,render:r,style:i,...a}=e,[o,s]=Q.useState(),c=Q.useMemo(()=>({labelId:o,setLabelId:s}),[o,s]),l=Ae(`div`,e,{ref:t,props:[{role:`group`,"aria-labelledby":o},a]});return(0,Z.jsx)(jn.Provider,{value:c,children:l})}),Pn=Q.forwardRef(function(e,t){let{className:r,render:i,id:a,style:o,...s}=e,{setLabelId:c}=Mn(),l=_(a);return n(()=>{c(l)},[l,c]),Ae(`div`,e,{ref:t,props:[{id:l},s]})}),Fn=Ge(),In=Ot;function Ln(e){let t=(0,Fn.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=h(`scroll-my-1 p-1`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,Z.jsx)(Nn,{className:i,"data-slot":`select-group`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Rn(e){let t=(0,Fn.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=h(`flex flex-1 text-left`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,Z.jsx)(Lt,{className:i,"data-slot":`select-value`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function zn(e){let n=(0,Fn.c)(15),r,i,a,o,s;n[0]===e?(r=n[1],i=n[2],a=n[3],o=n[4],s=n[5]):({className:i,size:s,id:a,children:r,...o}=e,n[0]=e,n[1]=r,n[2]=i,n[3]=a,n[4]=o,n[5]=s);let c=s===void 0?`default`:s,l;n[6]===i?l=n[7]:(l=h(`flex w-fit items-center justify-between gap-1.5 rounded-md border border-input bg-input/20 px-2 py-1.5 text-xs/relaxed whitespace-nowrap transition-colors outline-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-7 data-[size=sm]:h-6 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5`,i),n[6]=i,n[7]=l);let u;n[8]===Symbol.for(`react.memo_cache_sentinel`)?(u=(0,Z.jsx)(Rt,{render:(0,Z.jsx)(t,{className:`pointer-events-none size-3.5 text-muted-foreground`})}),n[8]=u):u=n[8];let d;return n[9]!==r||n[10]!==a||n[11]!==o||n[12]!==c||n[13]!==l?(d=(0,Z.jsxs)(Ft,{className:l,"data-size":c,"data-slot":`select-trigger`,id:a,...o,children:[r,u]}),n[9]=r,n[10]=a,n[11]=o,n[12]=c,n[13]=l,n[14]=d):d=n[14],d}function Bn(e){let t=(0,Fn.c)(26),n,r,i,a,o,s,c,l;t[0]===e?(n=t[1],r=t[2],i=t[3],a=t[4],o=t[5],s=t[6],c=t[7],l=t[8]):({className:r,children:n,side:a,sideOffset:o,align:s,alignOffset:c,alignItemWithTrigger:l,...i}=e,t[0]=e,t[1]=n,t[2]=r,t[3]=i,t[4]=a,t[5]=o,t[6]=s,t[7]=c,t[8]=l);let u=a===void 0?`bottom`:a,d=o===void 0?4:o,f=s===void 0?`center`:s,p=c===void 0?0:c,m=l===void 0?!0:l,g;t[9]===r?g=t[10]:(g=h(`data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-closed:animate-out data-open:animate-in relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100`,r),t[9]=r,t[10]=g);let _;t[11]===Symbol.for(`react.memo_cache_sentinel`)?(_=(0,Z.jsx)(Wn,{}),t[11]=_):_=t[11];let v;t[12]===n?v=t[13]:(v=(0,Z.jsx)(vn,{children:n}),t[12]=n,t[13]=v);let y;t[14]===Symbol.for(`react.memo_cache_sentinel`)?(y=(0,Z.jsx)(Gn,{}),t[14]=y):y=t[14];let b;t[15]!==i||t[16]!==g||t[17]!==v?(b=(0,Z.jsxs)(un,{className:g,"data-slot":`select-content`,...i,children:[_,v,y]}),t[15]=i,t[16]=g,t[17]=v,t[18]=b):b=t[18];let x;return t[19]!==f||t[20]!==m||t[21]!==p||t[22]!==u||t[23]!==d||t[24]!==b?(x=(0,Z.jsx)(Bt,{children:(0,Z.jsx)(en,{align:f,alignItemWithTrigger:m,alignOffset:p,className:`isolate z-50`,side:u,sideOffset:d,children:b})}),t[19]=f,t[20]=m,t[21]=p,t[22]=u,t[23]=d,t[24]=b,t[25]=x):x=t[25],x}function Vn(e){let t=(0,Fn.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=h(`px-2 py-1.5 text-xs text-muted-foreground`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,Z.jsx)(Pn,{className:i,"data-slot":`select-label`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Hn(t){let n=(0,Fn.c)(13),r,i,a;n[0]===t?(r=n[1],i=n[2],a=n[3]):({className:i,children:r,...a}=t,n[0]=t,n[1]=r,n[2]=i,n[3]=a);let o;n[4]===i?o=n[5]:(o=h(`relative flex min-h-7 w-full cursor-default items-center gap-2 rounded-md px-2 py-1 text-xs/relaxed outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2`,i),n[4]=i,n[5]=o);let s;n[6]===r?s=n[7]:(s=(0,Z.jsx)(En,{className:`flex flex-1 shrink-0 gap-2 whitespace-nowrap`,children:r}),n[6]=r,n[7]=s);let c;n[8]===Symbol.for(`react.memo_cache_sentinel`)?(c=(0,Z.jsx)(wn,{render:(0,Z.jsx)(`span`,{className:`pointer-events-none absolute right-2 flex items-center justify-center`}),children:(0,Z.jsx)(e,{className:`pointer-events-none`})}),n[8]=c):c=n[8];let l;return n[9]!==a||n[10]!==o||n[11]!==s?(l=(0,Z.jsxs)(Cn,{className:o,"data-slot":`select-item`,...a,children:[s,c]}),n[9]=a,n[10]=o,n[11]=s,n[12]=l):l=n[12],l}function Un(e){let t=(0,Fn.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=h(`pointer-events-none -mx-1 my-1 h-px bg-border/50`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,Z.jsx)(M,{className:i,"data-slot":`select-separator`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Wn(e){let t=(0,Fn.c)(9),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=h(`top-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-3.5`,n),t[3]=n,t[4]=i);let a;t[5]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,Z.jsx)(Xe,{}),t[5]=a):a=t[5];let o;return t[6]!==r||t[7]!==i?(o=(0,Z.jsx)(An,{className:i,"data-slot":`select-scroll-up-button`,...r,children:a}),t[6]=r,t[7]=i,t[8]=o):o=t[8],o}function Gn(e){let n=(0,Fn.c)(9),r,i;n[0]===e?(r=n[1],i=n[2]):({className:r,...i}=e,n[0]=e,n[1]=r,n[2]=i);let a;n[3]===r?a=n[4]:(a=h(`bottom-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-3.5`,r),n[3]=r,n[4]=a);let o;n[5]===Symbol.for(`react.memo_cache_sentinel`)?(o=(0,Z.jsx)(t,{}),n[5]=o):o=n[5];let s;return n[6]!==i||n[7]!==a?(s=(0,Z.jsx)(kn,{className:a,"data-slot":`select-scroll-down-button`,...i,children:o}),n[6]=i,n[7]=a,n[8]=s):s=n[8],s}export{Vn as a,Rn as c,Hn as i,bn as l,Bn as n,Un as o,Ln as r,zn as s,In as t,Ut as u}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/service-metrics.js b/spinifex/services/spinifexui/frontend/dist/assets/service-metrics.js index 4a061e350..e13ea0e3b 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/service-metrics.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/service-metrics.js @@ -1 +1 @@ -import{t as e}from"./useQuery.js";import{Gn as t,do as n,mo as r,so as i}from"./index.js";import{t as a}from"./page-heading.js";import{n as o}from"./admin.js";import{t as s}from"./badge.js";import{a as c,o as l,r as u,t as d}from"./card.js";var f=i(),p=r();function m(){let r=(0,f.c)(46),{isAdmin:i}=t(),m;r[0]===i?m=r[1]:(m={...o,enabled:i,refetchInterval:5e3},r[0]=i,r[1]=m);let{data:y}=e(m);if(!i)throw n({to:`/`});let x=y?.encoding,S;r[2]===y?.db_nodes?S=r[3]:(S=y?.db_nodes??[],r[2]=y?.db_nodes,r[3]=S);let C=S,w;r[4]===y?.shard_nodes?w=r[5]:(w=y?.shard_nodes??[],r[4]=y?.shard_nodes,r[5]=w);let T=w,E;r[6]===C?E=r[7]:(E=C.length>0&&C.every(g),r[6]=C,r[7]=E);let D=E,O;r[8]===C?O=r[9]:(O=C.some(h),r[8]=C,r[9]=O);let k=O,A;r[10]===Symbol.for(`react.memo_cache_sentinel`)?(A=(0,p.jsx)(a,{title:`Service Metrics`}),r[10]=A):A=r[10];let j;r[11]===Symbol.for(`react.memo_cache_sentinel`)?(j=(0,p.jsx)(c,{children:(0,p.jsx)(l,{className:`text-sm`,children:`Predastore (S3) Overview`})}),r[11]=j):j=r[11];let M;r[12]===Symbol.for(`react.memo_cache_sentinel`)?(M=(0,p.jsx)(`span`,{className:`text-muted-foreground`,children:`Encoding`}),r[12]=M):M=r[12];let N;r[13]===x?N=r[14]:(N=(0,p.jsxs)(`div`,{children:[M,(0,p.jsx)(`div`,{className:`mt-1`,children:x?(0,p.jsxs)(s,{variant:`outline`,children:[x.type,` RS(`,x.data_shards,`,`,x.parity_shards,`)`]}):(0,p.jsx)(`span`,{className:`text-muted-foreground`,children:`-`})})]}),r[13]=x,r[14]=N);let P;r[15]===Symbol.for(`react.memo_cache_sentinel`)?(P=(0,p.jsx)(`span`,{className:`text-muted-foreground`,children:`DB Nodes`}),r[15]=P):P=r[15];let F;r[16]===C.length?F=r[17]:(F=(0,p.jsxs)(`div`,{children:[P,(0,p.jsx)(`div`,{className:`mt-1 font-mono font-medium`,children:C.length})]}),r[16]=C.length,r[17]=F);let I;r[18]===Symbol.for(`react.memo_cache_sentinel`)?(I=(0,p.jsx)(`span`,{className:`text-muted-foreground`,children:`Shard Nodes`}),r[18]=I):I=r[18];let L;r[19]===T.length?L=r[20]:(L=(0,p.jsxs)(`div`,{children:[I,(0,p.jsx)(`div`,{className:`mt-1 font-mono font-medium`,children:T.length})]}),r[19]=T.length,r[20]=L);let R;r[21]===Symbol.for(`react.memo_cache_sentinel`)?(R=(0,p.jsx)(`span`,{className:`text-muted-foreground`,children:`Cluster Health`}),r[21]=R):R=r[21];let z;r[22]!==D||r[23]!==k||r[24]!==C.length?(z=(0,p.jsxs)(`div`,{children:[R,(0,p.jsx)(`div`,{className:`mt-1`,children:(0,p.jsx)(_,{nodeCount:C.length,allHealthy:D,anyUnhealthy:k})})]}),r[22]=D,r[23]=k,r[24]=C.length,r[25]=z):z=r[25];let B;r[26]!==F||r[27]!==L||r[28]!==z||r[29]!==N?(B=(0,p.jsxs)(`div`,{className:`grid grid-cols-2 gap-4 text-xs md:grid-cols-4`,children:[N,F,L,z]}),r[26]=F,r[27]=L,r[28]=z,r[29]=N,r[30]=B):B=r[30];let V;r[31]===x?V=r[32]:(V=x&&(0,p.jsxs)(`p`,{className:`mt-3 text-[0.625rem] text-muted-foreground`,children:[`Reed-Solomon erasure coding: `,x.data_shards,` data shards + `,x.parity_shards,` parity`,` `,x.parity_shards===1?`shard`:`shards`,`. Can tolerate `,x.parity_shards,` shard`,` `,x.parity_shards===1?`failure`:`failures`,` without data loss.`]}),r[31]=x,r[32]=V);let H;r[33]!==B||r[34]!==V?(H=(0,p.jsxs)(d,{children:[j,(0,p.jsxs)(u,{children:[B,V]})]}),r[33]=B,r[34]=V,r[35]=H):H=r[35];let U;r[36]===Symbol.for(`react.memo_cache_sentinel`)?(U=(0,p.jsx)(c,{children:(0,p.jsx)(l,{className:`text-sm`,children:`DB Consensus Nodes (Raft)`})}),r[36]=U):U=r[36];let W;r[37]===C?W=r[38]:(W=(0,p.jsxs)(d,{children:[U,(0,p.jsx)(u,{children:C.length===0?(0,p.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No data`}):(0,p.jsx)(v,{nodes:C})})]}),r[37]=C,r[38]=W);let G;r[39]===Symbol.for(`react.memo_cache_sentinel`)?(G=(0,p.jsx)(c,{children:(0,p.jsx)(l,{className:`text-sm`,children:`Object Storage Shard Nodes`})}),r[39]=G):G=r[39];let K;r[40]===T?K=r[41]:(K=(0,p.jsxs)(d,{children:[G,(0,p.jsx)(u,{children:T.length===0?(0,p.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No data`}):(0,p.jsx)(b,{nodes:T})})]}),r[40]=T,r[41]=K);let q;return r[42]!==H||r[43]!==W||r[44]!==K?(q=(0,p.jsxs)(p.Fragment,{children:[A,(0,p.jsxs)(`div`,{className:`space-y-6`,children:[H,W,K]})]}),r[42]=H,r[43]=W,r[44]=K,r[45]=q):q=r[45],q}function h(e){return!e.healthy}function g(e){return e.healthy}function _(e){let t=(0,f.c)(4),{nodeCount:n,allHealthy:r,anyUnhealthy:i}=e;if(n===0){let e;return t[0]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,p.jsx)(s,{variant:`secondary`,children:`Unknown`}),t[0]=e):e=t[0],e}if(r){let e;return t[1]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,p.jsx)(s,{variant:`default`,children:`Healthy`}),t[1]=e):e=t[1],e}if(i){let e;return t[2]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,p.jsx)(s,{variant:`destructive`,children:`Degraded`}),t[2]=e):e=t[2],e}let a;return t[3]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,p.jsx)(s,{variant:`secondary`,children:`Unknown`}),t[3]=a):a=t[3],a}function v(e){let t=(0,f.c)(5),{nodes:n}=e,r;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,p.jsx)(`thead`,{children:(0,p.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Node`}),(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Host`}),(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Port`}),(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Health`}),(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`State`}),(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Leader`}),(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Term`}),(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Commit Index`}),(0,p.jsx)(`th`,{className:`pb-1 font-medium`,children:`Applied Index`})]})}),t[0]=r):r=t[0];let i;t[1]===n?i=t[2]:(i=n.map(y),t[1]=n,t[2]=i);let a;return t[3]===i?a=t[4]:(a=(0,p.jsx)(`div`,{className:`overflow-x-auto`,children:(0,p.jsxs)(`table`,{className:`w-full text-xs`,children:[r,(0,p.jsx)(`tbody`,{children:i})]})}),t[3]=i,t[4]=a),a}function y(e){return(0,p.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,p.jsx)(`td`,{className:`py-1.5 pr-4 font-mono font-medium`,children:e.id}),(0,p.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.host}),(0,p.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.port}),(0,p.jsx)(`td`,{className:`py-1.5 pr-4`,children:(0,p.jsx)(s,{variant:e.healthy?`default`:`destructive`,className:`text-[0.625rem]`,children:e.healthy?`Healthy`:`Unreachable`})}),(0,p.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.state?(0,p.jsx)(s,{variant:e.state===`Leader`?`default`:`secondary`,className:`text-[0.625rem]`,children:e.state}):(0,p.jsx)(`span`,{className:`text-muted-foreground`,children:`-`})}),(0,p.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.leader??`-`}),(0,p.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.term??`-`}),(0,p.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.commit_index??`-`}),(0,p.jsx)(`td`,{className:`py-1.5 font-mono`,children:e.applied_index??`-`})]},e.id)}function b(e){let t=(0,f.c)(5),{nodes:n}=e,r;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,p.jsx)(`thead`,{children:(0,p.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Node`}),(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Host`}),(0,p.jsx)(`th`,{className:`pb-1 font-medium`,children:`Port`})]})}),t[0]=r):r=t[0];let i;t[1]===n?i=t[2]:(i=n.map(x),t[1]=n,t[2]=i);let a;return t[3]===i?a=t[4]:(a=(0,p.jsx)(`div`,{className:`overflow-x-auto`,children:(0,p.jsxs)(`table`,{className:`w-full text-xs`,children:[r,(0,p.jsx)(`tbody`,{children:i})]})}),t[3]=i,t[4]=a),a}function x(e){return(0,p.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,p.jsx)(`td`,{className:`py-1.5 pr-4 font-mono font-medium`,children:e.id}),(0,p.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.host}),(0,p.jsx)(`td`,{className:`py-1.5 font-mono`,children:e.port})]},e.id)}export{m as component}; \ No newline at end of file +import{t as e}from"./useQuery.js";import{Oo as t,To as n,ar as r,xo as i}from"./index.js";import{t as a}from"./page-heading.js";import{n as o}from"./admin.js";import{t as s}from"./badge.js";import{a as c,o as l,r as u,t as d}from"./card.js";var f=i(),p=t();function m(){let t=(0,f.c)(46),{isAdmin:i}=r(),m;t[0]===i?m=t[1]:(m={...o,enabled:i,refetchInterval:5e3},t[0]=i,t[1]=m);let{data:y}=e(m);if(!i)throw n({to:`/`});let x=y?.encoding,S;t[2]===y?.db_nodes?S=t[3]:(S=y?.db_nodes??[],t[2]=y?.db_nodes,t[3]=S);let C=S,w;t[4]===y?.shard_nodes?w=t[5]:(w=y?.shard_nodes??[],t[4]=y?.shard_nodes,t[5]=w);let T=w,E;t[6]===C?E=t[7]:(E=C.length>0&&C.every(g),t[6]=C,t[7]=E);let D=E,O;t[8]===C?O=t[9]:(O=C.some(h),t[8]=C,t[9]=O);let k=O,A;t[10]===Symbol.for(`react.memo_cache_sentinel`)?(A=(0,p.jsx)(a,{title:`Service Metrics`}),t[10]=A):A=t[10];let j;t[11]===Symbol.for(`react.memo_cache_sentinel`)?(j=(0,p.jsx)(c,{children:(0,p.jsx)(l,{className:`text-sm`,children:`Predastore (S3) Overview`})}),t[11]=j):j=t[11];let M;t[12]===Symbol.for(`react.memo_cache_sentinel`)?(M=(0,p.jsx)(`span`,{className:`text-muted-foreground`,children:`Encoding`}),t[12]=M):M=t[12];let N;t[13]===x?N=t[14]:(N=(0,p.jsxs)(`div`,{children:[M,(0,p.jsx)(`div`,{className:`mt-1`,children:x?(0,p.jsxs)(s,{variant:`outline`,children:[x.type,` RS(`,x.data_shards,`,`,x.parity_shards,`)`]}):(0,p.jsx)(`span`,{className:`text-muted-foreground`,children:`-`})})]}),t[13]=x,t[14]=N);let P;t[15]===Symbol.for(`react.memo_cache_sentinel`)?(P=(0,p.jsx)(`span`,{className:`text-muted-foreground`,children:`DB Nodes`}),t[15]=P):P=t[15];let F;t[16]===C.length?F=t[17]:(F=(0,p.jsxs)(`div`,{children:[P,(0,p.jsx)(`div`,{className:`mt-1 font-mono font-medium`,children:C.length})]}),t[16]=C.length,t[17]=F);let I;t[18]===Symbol.for(`react.memo_cache_sentinel`)?(I=(0,p.jsx)(`span`,{className:`text-muted-foreground`,children:`Shard Nodes`}),t[18]=I):I=t[18];let L;t[19]===T.length?L=t[20]:(L=(0,p.jsxs)(`div`,{children:[I,(0,p.jsx)(`div`,{className:`mt-1 font-mono font-medium`,children:T.length})]}),t[19]=T.length,t[20]=L);let R;t[21]===Symbol.for(`react.memo_cache_sentinel`)?(R=(0,p.jsx)(`span`,{className:`text-muted-foreground`,children:`Cluster Health`}),t[21]=R):R=t[21];let z;t[22]!==D||t[23]!==k||t[24]!==C.length?(z=(0,p.jsxs)(`div`,{children:[R,(0,p.jsx)(`div`,{className:`mt-1`,children:(0,p.jsx)(_,{nodeCount:C.length,allHealthy:D,anyUnhealthy:k})})]}),t[22]=D,t[23]=k,t[24]=C.length,t[25]=z):z=t[25];let B;t[26]!==F||t[27]!==L||t[28]!==z||t[29]!==N?(B=(0,p.jsxs)(`div`,{className:`grid grid-cols-2 gap-4 text-xs md:grid-cols-4`,children:[N,F,L,z]}),t[26]=F,t[27]=L,t[28]=z,t[29]=N,t[30]=B):B=t[30];let V;t[31]===x?V=t[32]:(V=x&&(0,p.jsxs)(`p`,{className:`mt-3 text-[0.625rem] text-muted-foreground`,children:[`Reed-Solomon erasure coding: `,x.data_shards,` data shards + `,x.parity_shards,` parity`,` `,x.parity_shards===1?`shard`:`shards`,`. Can tolerate `,x.parity_shards,` shard`,` `,x.parity_shards===1?`failure`:`failures`,` without data loss.`]}),t[31]=x,t[32]=V);let H;t[33]!==B||t[34]!==V?(H=(0,p.jsxs)(d,{children:[j,(0,p.jsxs)(u,{children:[B,V]})]}),t[33]=B,t[34]=V,t[35]=H):H=t[35];let U;t[36]===Symbol.for(`react.memo_cache_sentinel`)?(U=(0,p.jsx)(c,{children:(0,p.jsx)(l,{className:`text-sm`,children:`DB Consensus Nodes (Raft)`})}),t[36]=U):U=t[36];let W;t[37]===C?W=t[38]:(W=(0,p.jsxs)(d,{children:[U,(0,p.jsx)(u,{children:C.length===0?(0,p.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No data`}):(0,p.jsx)(v,{nodes:C})})]}),t[37]=C,t[38]=W);let G;t[39]===Symbol.for(`react.memo_cache_sentinel`)?(G=(0,p.jsx)(c,{children:(0,p.jsx)(l,{className:`text-sm`,children:`Object Storage Shard Nodes`})}),t[39]=G):G=t[39];let K;t[40]===T?K=t[41]:(K=(0,p.jsxs)(d,{children:[G,(0,p.jsx)(u,{children:T.length===0?(0,p.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No data`}):(0,p.jsx)(b,{nodes:T})})]}),t[40]=T,t[41]=K);let q;return t[42]!==H||t[43]!==W||t[44]!==K?(q=(0,p.jsxs)(p.Fragment,{children:[A,(0,p.jsxs)(`div`,{className:`space-y-6`,children:[H,W,K]})]}),t[42]=H,t[43]=W,t[44]=K,t[45]=q):q=t[45],q}function h(e){return!e.healthy}function g(e){return e.healthy}function _(e){let t=(0,f.c)(4),{nodeCount:n,allHealthy:r,anyUnhealthy:i}=e;if(n===0){let e;return t[0]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,p.jsx)(s,{variant:`secondary`,children:`Unknown`}),t[0]=e):e=t[0],e}if(r){let e;return t[1]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,p.jsx)(s,{variant:`default`,children:`Healthy`}),t[1]=e):e=t[1],e}if(i){let e;return t[2]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,p.jsx)(s,{variant:`destructive`,children:`Degraded`}),t[2]=e):e=t[2],e}let a;return t[3]===Symbol.for(`react.memo_cache_sentinel`)?(a=(0,p.jsx)(s,{variant:`secondary`,children:`Unknown`}),t[3]=a):a=t[3],a}function v(e){let t=(0,f.c)(5),{nodes:n}=e,r;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,p.jsx)(`thead`,{children:(0,p.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Node`}),(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Host`}),(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Port`}),(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Health`}),(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`State`}),(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Leader`}),(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Term`}),(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Commit Index`}),(0,p.jsx)(`th`,{className:`pb-1 font-medium`,children:`Applied Index`})]})}),t[0]=r):r=t[0];let i;t[1]===n?i=t[2]:(i=n.map(y),t[1]=n,t[2]=i);let a;return t[3]===i?a=t[4]:(a=(0,p.jsx)(`div`,{className:`overflow-x-auto`,children:(0,p.jsxs)(`table`,{className:`w-full text-xs`,children:[r,(0,p.jsx)(`tbody`,{children:i})]})}),t[3]=i,t[4]=a),a}function y(e){return(0,p.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,p.jsx)(`td`,{className:`py-1.5 pr-4 font-mono font-medium`,children:e.id}),(0,p.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.host}),(0,p.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.port}),(0,p.jsx)(`td`,{className:`py-1.5 pr-4`,children:(0,p.jsx)(s,{variant:e.healthy?`default`:`destructive`,className:`text-[0.625rem]`,children:e.healthy?`Healthy`:`Unreachable`})}),(0,p.jsx)(`td`,{className:`py-1.5 pr-4`,children:e.state?(0,p.jsx)(s,{variant:e.state===`Leader`?`default`:`secondary`,className:`text-[0.625rem]`,children:e.state}):(0,p.jsx)(`span`,{className:`text-muted-foreground`,children:`-`})}),(0,p.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.leader??`-`}),(0,p.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.term??`-`}),(0,p.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.commit_index??`-`}),(0,p.jsx)(`td`,{className:`py-1.5 font-mono`,children:e.applied_index??`-`})]},e.id)}function b(e){let t=(0,f.c)(5),{nodes:n}=e,r;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,p.jsx)(`thead`,{children:(0,p.jsxs)(`tr`,{className:`border-b text-left text-muted-foreground`,children:[(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Node`}),(0,p.jsx)(`th`,{className:`pr-4 pb-1 font-medium`,children:`Host`}),(0,p.jsx)(`th`,{className:`pb-1 font-medium`,children:`Port`})]})}),t[0]=r):r=t[0];let i;t[1]===n?i=t[2]:(i=n.map(x),t[1]=n,t[2]=i);let a;return t[3]===i?a=t[4]:(a=(0,p.jsx)(`div`,{className:`overflow-x-auto`,children:(0,p.jsxs)(`table`,{className:`w-full text-xs`,children:[r,(0,p.jsx)(`tbody`,{children:i})]})}),t[3]=i,t[4]=a),a}function x(e){return(0,p.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,p.jsx)(`td`,{className:`py-1.5 pr-4 font-mono font-medium`,children:e.id}),(0,p.jsx)(`td`,{className:`py-1.5 pr-4 font-mono`,children:e.host}),(0,p.jsx)(`td`,{className:`py-1.5 font-mono`,children:e.port})]},e.id)}export{m as component}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/state-badge.js b/spinifex/services/spinifexui/frontend/dist/assets/state-badge.js index d96c233ca..dfc936031 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/state-badge.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/state-badge.js @@ -1 +1 @@ -import{Oa as e,mo as t,so as n}from"./index.js";var r=n(),i=t(),a=new Set([`running`,`available`,`completed`,`Active`]),o=new Set([`stopped`,`error`]),s=new Set([`pending`,`shutting-down`,`stopping`]);function c(e){return e&&a.has(e)?`bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-100`:e&&o.has(e)?`bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-100`:e&&s.has(e)?`bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-100`:e===`terminated`?`bg-zinc-100 text-zinc-500 dark:bg-zinc-800 dark:text-zinc-400`:`bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-100`}function l(t){let n=(0,r.c)(5),{state:a}=t,o;n[0]===a?o=n[1]:(o=e(`rounded-full px-2 py-1 text-xs`,c(a)),n[0]=a,n[1]=o);let s;return n[2]!==a||n[3]!==o?(s=(0,i.jsx)(`div`,{className:o,children:a}),n[2]=a,n[3]=o,n[4]=s):s=n[4],s}export{l as t}; \ No newline at end of file +import{Ha as e,Oo as t,xo as n}from"./index.js";var r=n(),i=t(),a=new Set([`running`,`available`,`completed`,`Active`]),o=new Set([`stopped`,`error`]),s=new Set([`pending`,`shutting-down`,`stopping`]);function c(e){return e&&a.has(e)?`bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-100`:e&&o.has(e)?`bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-100`:e&&s.has(e)?`bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-100`:e===`terminated`?`bg-zinc-100 text-zinc-500 dark:bg-zinc-800 dark:text-zinc-400`:`bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-100`}function l(t){let n=(0,r.c)(5),{state:a}=t,o;n[0]===a?o=n[1]:(o=e(`rounded-full px-2 py-1 text-xs`,c(a)),n[0]=a,n[1]=o);let s;return n[2]!==a||n[3]!==o?(s=(0,i.jsx)(`div`,{className:o,children:a}),n[2]=a,n[3]=o,n[4]=s):s=n[4],s}export{l as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/tabs.js b/spinifex/services/spinifexui/frontend/dist/assets/tabs.js index b98070ce3..d56c83bee 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/tabs.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/tabs.js @@ -1 +1 @@ -import{c as e,i as t,l as n,n as r,s as i,t as a,u as o}from"./select.js";import{$a as s,Ba as c,Bi as l,Br as u,Ei as d,Hr as f,Ia as p,Ii as m,Ir as h,Ji as g,Jr as _,Ki as v,Kr as y,La as b,Li as x,Oa as S,Po as C,Qi as w,Qr as T,Ra as E,Ri as D,Rr as O,Sa as k,Ta as A,Ti as j,Tr as M,Ur as N,Vi as P,Vr as F,Xi as I,Xr as L,Yi as R,Yr as z,Zi as B,Zr as ee,ao as V,da as H,ea as te,eo as U,fa as ne,ho as re,ji as W,mo as ie,pa as ae,qi as oe,qr as se,ro as G,so as ce,ta as K,to as le,ya as ue,za as q,zr as J}from"./index.js";import{a as de,r as fe,t as pe}from"./field.js";var Y=ce(),X=C(re(),1),Z=ie();function me(e,t){let n=new Map;for(let e of t)e.Key!==void 0&&n.set(e.Key,e.Value??``);let r={};for(let t of e)r[t.key]=n.get(t.key)??``;return r}function he(e,t){if(e.type===`int`){if(t.trim()===``)return`Value is required`;if(!/^-?\d+$/.test(t))return`Must be a whole number`;let n=Number(t);if(e.min!==void 0&&ne.max)return`Must be at most ${e.max}`}}function ge(t){let n=(0,Y.c)(56),{specs:o,attributes:s,onSubmit:c,isPending:l,error:u,isSuccess:d}=t,f;n[0]!==s||n[1]!==o?(f=me(o,s),n[0]=s,n[1]=o,n[2]=f):f=n[2];let p=f,[m,h]=(0,X.useState)(p),g;n[3]===Symbol.for(`react.memo_cache_sentinel`)?(g=(e,t)=>{h(n=>({...n,[e]:t}))},n[3]=g):g=n[3];let _=g,v;if(n[4]!==o||n[5]!==m){v={};for(let e of o)v[e.key]=he(e,m[e.key]??``);n[4]=o,n[5]=m,n[6]=v}else v=n[6];let y=Object.values(v).some(Boolean),b;if(n[7]!==p||n[8]!==o||n[9]!==m){let e;n[11]!==p||n[12]!==m?(e=e=>(m[e.key]??``)!==(p[e.key]??``),n[11]=p,n[12]=m,n[13]=e):e=n[13];let t;n[14]===m?t=n[15]:(t=e=>({key:e.key,value:m[e.key]??``}),n[14]=m,n[15]=t),b=o.filter(e).map(t),n[7]=p,n[8]=o,n[9]=m,n[10]=b}else b=n[10];let x=b,S;n[16]===p?S=n[17]:(S=()=>{h(p)},n[16]=p,n[17]=S);let C=S,w;n[18]!==x||n[19]!==y||n[20]!==c?(w=e=>{e.preventDefault(),!(y||x.length===0)&&c(x)},n[18]=x,n[19]=y,n[20]=c,n[21]=w):w=n[21];let T;n[22]===u?T=n[23]:(T=u&&(0,Z.jsx)(`div`,{className:`mb-4 rounded-md border border-destructive bg-destructive/10 p-3 text-sm text-destructive`,role:`alert`,children:u.message||`Failed to save attributes`}),n[22]=u,n[23]=T);let E;n[24]!==x.length||n[25]!==d?(E=d&&x.length===0&&(0,Z.jsx)(`div`,{className:`mb-4 rounded-md border border-emerald-500 bg-emerald-500/10 p-3 text-sm text-emerald-700 dark:text-emerald-400`,role:`status`,children:`Attributes saved.`}),n[24]=x.length,n[25]=d,n[26]=E):E=n[26];let D;if(n[27]!==v||n[28]!==o||n[29]!==m){let t;n[31]!==v||n[32]!==m?(t=t=>{let n=`attr-${t.key}`,o=m[t.key]??``,s=v[t.key];return(0,Z.jsxs)(pe,{children:[(0,Z.jsx)(de,{children:(0,Z.jsx)(`label`,{htmlFor:n,children:t.label})}),t.type===`bool`&&(0,Z.jsx)(`input`,{"aria-label":t.label,checked:o===`true`,id:n,onChange:e=>_(t.key,e.target.checked?`true`:`false`),type:`checkbox`}),t.type===`int`&&(0,Z.jsx)(j,{"aria-invalid":!!s,id:n,inputMode:`numeric`,onChange:e=>_(t.key,e.target.value),value:o}),t.type===`text`&&(0,Z.jsx)(j,{id:n,onChange:e=>_(t.key,e.target.value),placeholder:t.placeholder,value:o}),t.type===`select`&&(0,Z.jsxs)(a,{onValueChange:e=>_(t.key,e??``),value:o,children:[(0,Z.jsx)(i,{className:`w-full`,id:n,children:(0,Z.jsx)(e,{})}),(0,Z.jsx)(r,{children:t.options.map(_e)})]}),t.description&&(0,Z.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:t.description}),(0,Z.jsx)(fe,{errors:[s?{message:s}:void 0]})]},t.key)},n[31]=v,n[32]=m,n[33]=t):t=n[33],D=o.map(t),n[27]=v,n[28]=o,n[29]=m,n[30]=D}else D=n[30];let O;n[34]===D?O=n[35]:(O=(0,Z.jsx)(`div`,{className:`grid gap-4 p-4 sm:grid-cols-2`,children:D}),n[34]=D,n[35]=O);let k=x.length===0?`No changes`:`${x.length} change${x.length===1?``:`s`} pending`,M;n[36]===k?M=n[37]:(M=(0,Z.jsx)(`span`,{className:`mr-auto text-xs text-muted-foreground`,children:k}),n[36]=k,n[37]=M);let N=l||x.length===0,P;n[38]!==C||n[39]!==N?(P=(0,Z.jsx)(A,{disabled:N,onClick:C,size:`sm`,type:`button`,variant:`secondary`,children:`Reset`}),n[38]=C,n[39]=N,n[40]=P):P=n[40];let F=l||y||x.length===0,I=l?`Saving…`:`Save changes`,L;n[41]!==F||n[42]!==I?(L=(0,Z.jsx)(A,{disabled:F,size:`sm`,type:`submit`,children:I}),n[41]=F,n[42]=I,n[43]=L):L=n[43];let R;n[44]!==M||n[45]!==P||n[46]!==L?(R=(0,Z.jsxs)(`div`,{className:`flex items-center justify-end gap-2 border-t p-4`,children:[M,P,L]}),n[44]=M,n[45]=P,n[46]=L,n[47]=R):R=n[47];let z;n[48]!==R||n[49]!==O?(z=(0,Z.jsxs)(`div`,{className:`rounded-lg border bg-card`,children:[O,R]}),n[48]=R,n[49]=O,n[50]=z):z=n[50];let B;return n[51]!==z||n[52]!==w||n[53]!==T||n[54]!==E?(B=(0,Z.jsxs)(`form`,{onSubmit:w,children:[T,E,z]}),n[51]=z,n[52]=w,n[53]=T,n[54]=E,n[55]=B):B=n[55],B}function _e(e){return(0,Z.jsx)(t,{value:e,children:e},e)}var ve=[{key:`deletion_protection.enabled`,label:`Deletion protection`,type:`bool`},{key:`load_balancing.cross_zone.enabled`,label:`Cross-zone load balancing`,type:`bool`},{key:`idle_timeout.timeout_seconds`,label:`Idle timeout (s)`,type:`int`,min:1,max:4e3},{key:`client_keep_alive.seconds`,label:`Client keep-alive (s)`,type:`int`,min:60,max:604800},{key:`routing.http2.enabled`,label:`HTTP/2`,type:`bool`},{key:`routing.http.drop_invalid_header_fields.enabled`,label:`Drop invalid header fields`,type:`bool`},{key:`routing.http.preserve_host_header.enabled`,label:`Preserve host header`,type:`bool`},{key:`routing.http.xff_client_port.enabled`,label:`XFF client port`,type:`bool`},{key:`routing.http.xff_header_processing.mode`,label:`XFF header processing`,type:`select`,options:[`append`,`preserve`,`remove`]},{key:`routing.http.desync_mitigation_mode`,label:`Desync mitigation mode`,type:`select`,options:[`defensive`,`strictest`,`monitor`]},{key:`routing.http.x_amzn_tls_version_and_cipher_suite.enabled`,label:`Add TLS version & cipher headers`,type:`bool`},{key:`waf.fail_open.enabled`,label:`WAF fail open`,type:`bool`},{key:`zonal_shift.config.enabled`,label:`Zonal shift`,type:`bool`},{key:`access_logs.s3.enabled`,label:`Access logs: enabled`,type:`bool`},{key:`access_logs.s3.bucket`,label:`Access logs: S3 bucket`,type:`text`},{key:`access_logs.s3.prefix`,label:`Access logs: S3 prefix`,type:`text`},{key:`connection_logs.s3.enabled`,label:`Connection logs: enabled`,type:`bool`},{key:`connection_logs.s3.bucket`,label:`Connection logs: S3 bucket`,type:`text`},{key:`connection_logs.s3.prefix`,label:`Connection logs: S3 prefix`,type:`text`}],ye=[{key:`deregistration_delay.timeout_seconds`,label:`Deregistration delay (s)`,type:`int`,min:0,max:3600},{key:`stickiness.enabled`,label:`Stickiness`,type:`bool`},{key:`stickiness.type`,label:`Stickiness type`,type:`select`,options:[`lb_cookie`,`source_ip`]},{key:`stickiness.lb_cookie.duration_seconds`,label:`Stickiness lb_cookie duration (s)`,type:`int`,min:1,max:604800},{key:`load_balancing.cross_zone.enabled`,label:`Cross-zone load balancing`,type:`select`,options:[`true`,`false`,`use_load_balancer_configuration`]},{key:`load_balancing.algorithm.type`,label:`Load balancing algorithm`,type:`select`,options:[`round_robin`,`least_outstanding_requests`]},{key:`slow_start.duration_seconds`,label:`Slow start duration (s)`,type:`int`,min:0,max:900}],be=X.createContext(void 0);function Q(){let e=X.useContext(be);if(e===void 0)throw Error(V(64));return e}var xe=function(e){return e.activationDirection=`data-activation-direction`,e.orientation=`data-orientation`,e}({}),$={tabActivationDirection:e=>({[xe.activationDirection]:e})},Se=X.forwardRef(function(e,t){let{className:n,defaultValue:r=0,onValueChange:i,orientation:a=`horizontal`,render:l,value:u,style:d,...f}=e,p=Object.hasOwn(e,`defaultValue`),h=X.useRef([]),[g,_]=X.useState(()=>new Map),[v,y]=m({controlled:u,default:r,name:`Tabs`,state:`value`}),b=u!==void 0,[x,S]=X.useState(()=>new Map),C=X.useCallback(e=>{if(e===void 0)return null;for(let[t,n]of x.entries())if(n!=null&&e===(n.value??n.index))return t;return null},[x]),[w,T]=X.useState(()=>({previousValue:v,tabActivationDirection:`none`})),{previousValue:E,tabActivationDirection:D}=w,O=D,k=!1;E!==v&&(O=Ce(E,v,a,x),k=E!=null&&v!=null&&C(v)==null);let A=k?E:v,j=E!==A||D!==O;q(()=>{j&&T({previousValue:A,tabActivationDirection:O})},[A,j,O]);let M=c((e,t)=>{t.activationDirection=Ce(v,e,a,x),i?.(e,t),!t.isCanceled&&y(e)}),N=c((e,t)=>{_(n=>{if(n.get(e)===t)return n;let r=new Map(n);return r.set(e,t),r})}),P=c((e,t)=>{_(n=>{if(!n.has(e)||n.get(e)!==t)return n;let r=new Map(n);return r.delete(e),r})}),F=X.useCallback(e=>g.get(e),[g]),I=X.useCallback(e=>{for(let t of x.values())if(e===t?.value)return t?.id},[x]),L=X.useMemo(()=>({getTabElementBySelectedValue:C,getTabIdByPanelValue:I,getTabPanelIdByValue:F,onValueChange:M,orientation:a,registerMountedTabPanel:N,setTabMap:S,unregisterMountedTabPanel:P,tabActivationDirection:O,value:v}),[C,I,F,M,a,N,S,P,O,v]),R=X.useMemo(()=>{for(let e of x.values())if(e!=null&&e.value===v)return e},[x,v]),z=X.useMemo(()=>{for(let e of x.values())if(e!=null&&!e.disabled)return e.value},[x]);q(()=>{if(b||x.size===0)return;let e=R?.disabled;if(p&&e&&v===r||!e&&!(R==null&&v!==null))return;let t=z??null;v!==t&&(y(t),T(e=>e.tabActivationDirection===`none`?e:{...e,tabActivationDirection:`none`}))},[r,z,p,b,R,y,x,v]);let B=s(`div`,e,{state:{orientation:a,tabActivationDirection:O},ref:t,props:f,stateAttributesMapping:$});return(0,Z.jsx)(be.Provider,{value:L,children:(0,Z.jsx)(o,{elementsRef:h,children:B})})});function Ce(e,t,n,r){if(e==null||t==null)return`none`;let i=null,a=null;for(let[n,o]of r.entries()){if(o==null)continue;let r=o.value??o.index;if(e===r&&(i=n),t===r&&(a=n),i!=null&&a!=null)break}if(i==null||a==null)return i!==a&&(typeof e==`number`||typeof e==`string`)&&typeof e==typeof t?n===`horizontal`?t>e?`right`:`left`:t>e?`down`:`up`:`none`;let o=i.getBoundingClientRect(),s=a.getBoundingClientRect();if(n===`horizontal`){if(s.lefto.left)return`right`}else{if(s.topo.top)return`down`}return`none`}var we=`data-composite-item-active`;function Te(e={}){let{highlightItemOnHover:t,highlightedIndex:r,onHighlightedIndexChange:i}=E(),{ref:a,index:o}=n(e),s=r===o,c=X.useRef(null),l=G(a,c);return{compositeProps:X.useMemo(()=>({tabIndex:s?0:-1,onFocus(){i(o)},onMouseMove(){let e=c.current;if(!t||!e)return;let n=e.hasAttribute(`disabled`)||e.ariaDisabled===`true`;!s&&!n&&e.focus()}}),[s,i,o,t]),compositeRef:l,index:o}}var Ee=X.createContext(void 0);function De(){let e=X.useContext(Ee);if(e===void 0)throw Error(V(65));return e}var Oe=X.forwardRef(function(e,t){let{className:n,disabled:r=!1,render:i,value:a,id:o,nativeButton:c=!0,style:l,...u}=e,{value:f,getTabPanelIdByValue:m,orientation:h}=Q(),{activateOnFocus:g,highlightedTabIndex:_,onTabActivation:v,registerTabResizeObserverElement:y,setHighlightedTabIndex:b,tabsListElement:x}=De(),S=k(o),{compositeProps:C,compositeRef:w,index:T}=Te({metadata:X.useMemo(()=>({disabled:r,id:S,value:a}),[r,S,a])}),E=a===f,D=X.useRef(!1),O=X.useRef(null);X.useEffect(()=>{let e=O.current;if(e)return y(e)},[y]),q(()=>{if(D.current){D.current=!1;return}if(!(E&&T>-1&&_!==T))return;let e=x;if(e!=null){let t=H(ue(e));if(t&&ne(e,t))return}r||b(T)},[E,T,_,b,r,x]);let{getButtonProps:A,buttonRef:j}=p({disabled:r,native:c,focusableWhenDisabled:!0}),M=m(a),N=X.useRef(!1),P=X.useRef(!1);function F(e){E||r||v(a,d(W,e.nativeEvent,void 0,{activationDirection:`none`}))}function I(e){E||(T>-1&&!r&&b(T),!r&&g&&(!N.current||N.current&&P.current)&&v(a,d(W,e.nativeEvent,void 0,{activationDirection:`none`})))}function L(e){if(E||r)return;N.current=!0;function t(){N.current=!1,P.current=!1}(!e.button||e.button===0)&&(P.current=!0,ue(e.currentTarget).addEventListener(`pointerup`,t,{once:!0}))}return s(`button`,e,{state:{disabled:r,active:E,orientation:h},ref:[t,j,w,O],props:[C,{role:`tab`,"aria-controls":M,"aria-selected":E,id:S,onClick:F,onFocus:I,onPointerDown:L,[we]:E?``:void 0,onKeyDownCapture(){D.current=!0}},u,A]})}),ke=function(e){return e.index=`data-index`,e.activationDirection=`data-activation-direction`,e.orientation=`data-orientation`,e.hidden=`data-hidden`,e[e.startingStyle=l.startingStyle]=`startingStyle`,e[e.endingStyle=l.endingStyle]=`endingStyle`,e}({}),Ae={...$,...P},je=X.forwardRef(function(e,t){let{className:r,value:i,render:a,keepMounted:o=!1,style:c,...l}=e,{value:u,getTabIdByPanelValue:d,orientation:f,tabActivationDirection:p,registerMountedTabPanel:m,unregisterMountedTabPanel:g}=Q(),_=k(),{ref:v,index:y}=n({metadata:X.useMemo(()=>({id:_,value:i}),[_,i])}),b=i===u,{mounted:S,transitionStatus:C,setMounted:w}=x(b),T=!S,E=d(i),O={hidden:T,orientation:f,tabActivationDirection:p,transitionStatus:C},A=X.useRef(null),j=s(`div`,e,{state:O,ref:[t,v,A],props:[{"aria-labelledby":E,hidden:T,id:_,role:`tabpanel`,tabIndex:b?0:-1,inert:h(!b),[ke.index]:y},l],stateAttributesMapping:Ae});return D({open:b,ref:A,onComplete(){b||w(!1)}}),q(()=>{if(!(T&&!o)&&_!=null)return m(i,_),()=>{g(i,_)}},[T,o,i,_,m,g]),o||S?j:null});function Me(e){return e==null||e.hasAttribute(`disabled`)||e.getAttribute(`aria-disabled`)===`true`}var Ne=[];function Pe(e){let{itemSizes:t,cols:n=1,loopFocus:r=!0,onLoop:i,dense:a=!1,orientation:o=`both`,direction:s,highlightedIndex:l,onHighlightedIndexChange:d,rootRef:p,enableHomeAndEndKeys:m=!1,stopEventPropagation:h=!1,disabledIndices:_,modifierKeys:b=Ne}=e,[x,S]=X.useState(0),C=n>1,E=X.useRef(null),D=G(E,p),k=X.useRef([]),A=X.useRef(!1),j=l??x,M=c((e,t=!1)=>{if((d??S)(e),t){let t=k.current[e];T(E.current,t,s,o)}}),P=c(e=>{if(e.size===0||A.current)return;A.current=!0;let t=Array.from(e.keys()),n=t.find(e=>e?.hasAttribute(`data-composite-item-active`))??null,r=n?t.indexOf(n):-1;r!==-1&&M(r),T(E.current,n,s,o)}),V=c((e,t,n)=>i?i?.(e,t,n,k):n),H=X.useMemo(()=>({"aria-orientation":o===`both`?void 0:o,ref:D,onFocus(e){let t=E.current,n=ae(e.nativeEvent);!t||n==null||!ee(n)||n.setSelectionRange(0,n.value.length??0)},onKeyDown(e){let c=m?O:u;if(!c.has(e.key)||Fe(e,b)||!E.current)return;let l=s===`rtl`,d=l?F:f,p={horizontal:d,vertical:J,both:d}[o],x=l?f:F,S={horizontal:x,vertical:N,both:x}[o],T=ae(e.nativeEvent);if(T!=null&&ee(T)&&!Me(T)){let t=T.selectionStart,n=T.selectionEnd,r=T.value??``;if(t==null||e.shiftKey||t!==n||e.key!==S&&t0)return}let D=j,A=w(k,_),P=B(k,_);if(C){let i=t||Array.from({length:k.current.length},()=>({width:1,height:1})),s=v(i,n,a),c=s.findIndex(e=>e!=null&&!K(k.current,e,_)),u=s.reduce((e,t,n)=>t!=null&&!K(k.current,t,_)?n:e,-1);D=s[I(s.map(e=>e==null?null:k.current[e]),{event:e,orientation:o,loopFocus:r,onLoop:V,cols:n,disabledIndices:R([..._||k.current.map((e,t)=>K(k.current,t)?t:void 0),void 0],s),minIndex:c,maxIndex:u,prevIndex:g(j>P?A:j,i,s,n,e.key===`ArrowDown`?`bl`:e.key===`ArrowRight`?`tr`:`tl`),rtl:l})]}let H={horizontal:[d],vertical:[J],both:[d,J]}[o],U={horizontal:[x],vertical:[N],both:[x,N]}[o],ne=C?c:{horizontal:m?se:y,vertical:m?L:z,both:c}[o];m&&(e.key===`Home`?D=A:e.key===`End`&&(D=P)),D===j&&(H.includes(e.key)||U.includes(e.key))&&(r&&D===P&&H.includes(e.key)?(D=A,i&&(D=i(e,j,D,k))):r&&D===A&&U.includes(e.key)?(D=P,i&&(D=i(e,j,D,k))):D=oe(k.current,{startingIndex:D,decrement:U.includes(e.key),disabledIndices:_})),D!==j&&!te(k.current,D)&&(h&&e.stopPropagation(),ne.has(e.key)&&e.preventDefault(),M(D,!0),queueMicrotask(()=>{k.current[D]?.focus()}))}}),[n,a,s,_,k,m,j,C,t,r,i,V,D,b,M,o,h]);return X.useMemo(()=>({props:H,highlightedIndex:j,onHighlightedIndexChange:M,elementsRef:k,disabledIndices:_,onMapChange:P,relayKeyboardEvent:H.onKeyDown}),[H,j,M,k,_,P])}function Fe(e,t){for(let n of _.values())if(!t.includes(n)&&e.getModifierState(n))return!0;return!1}function Ie(e){let{render:t,className:n,style:r,refs:i=U,props:a=U,state:c=le,stateAttributesMapping:l,highlightedIndex:u,onHighlightedIndexChange:d,orientation:f,dense:p,itemSizes:m,loopFocus:h,onLoop:g,cols:_,enableHomeAndEndKeys:v,onMapChange:y,stopEventPropagation:x=!0,rootRef:S,disabledIndices:C,modifierKeys:w,highlightItemOnHover:T=!1,tag:E=`div`,...D}=e,{props:O,highlightedIndex:k,onHighlightedIndexChange:A,elementsRef:j,onMapChange:N,relayKeyboardEvent:P}=Pe({itemSizes:m,cols:_,loopFocus:h,onLoop:g,dense:p,orientation:f,highlightedIndex:u,onHighlightedIndexChange:d,rootRef:S,stopEventPropagation:x,enableHomeAndEndKeys:v,direction:M(),disabledIndices:C,modifierKeys:w}),F=s(E,e,{state:c,ref:i,props:[O,...a,D],stateAttributesMapping:l}),I=X.useMemo(()=>({highlightedIndex:k,onHighlightedIndexChange:A,highlightItemOnHover:T,relayKeyboardEvent:P}),[k,A,T,P]);return(0,Z.jsx)(b.Provider,{value:I,children:(0,Z.jsx)(o,{elementsRef:j,onMapChange:e=>{y?.(e),N(e)},children:F})})}var Le=X.forwardRef(function(e,t){let{activateOnFocus:n=!1,className:r,loopFocus:i=!0,render:a,style:o,...s}=e,{onValueChange:l,orientation:u,value:d,setTabMap:f,tabActivationDirection:p}=Q(),[m,h]=X.useState(0),[g,_]=X.useState(null),v=X.useRef(new Set),y=X.useRef(new Set),b=X.useRef(null),x=c(()=>{v.current.forEach(e=>{e()})});X.useEffect(()=>{if(typeof ResizeObserver>`u`)return;let e=new ResizeObserver(()=>{v.current.size&&x()});return b.current=e,g&&e.observe(g),y.current.forEach(t=>{e.observe(t)}),()=>{e.disconnect(),b.current=null}},[g,x]);let S=c(e=>(v.current.add(e),()=>{v.current.delete(e)})),C=c(e=>(y.current.add(e),b.current?.observe(e),()=>{y.current.delete(e),b.current?.unobserve(e)})),w=c((e,t)=>{e!==d&&l(e,t)}),T={orientation:u,tabActivationDirection:p},E={"aria-orientation":u===`vertical`?`vertical`:void 0,role:`tablist`},D=X.useMemo(()=>({activateOnFocus:n,highlightedTabIndex:m,registerIndicatorUpdateListener:S,registerTabResizeObserverElement:C,onTabActivation:w,setHighlightedTabIndex:h,tabsListElement:g}),[n,m,S,C,w,h,g]);return(0,Z.jsx)(Ee.Provider,{value:D,children:(0,Z.jsx)(Ie,{render:a,className:r,style:o,state:T,refs:[t,_],props:[E,s],stateAttributesMapping:$,highlightedIndex:m,enableHomeAndEndKeys:!0,loopFocus:i,orientation:u,onHighlightedIndexChange:h,onMapChange:f,disabledIndices:U})})});function Re(e){let t=(0,Y.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=S(`flex flex-col gap-4`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,Z.jsx)(Se,{className:i,"data-slot":`tabs`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function ze(e){let t=(0,Y.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=S(`inline-flex items-center gap-1 border-b`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,Z.jsx)(Le,{className:i,"data-slot":`tabs-list`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Be(e){let t=(0,Y.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=S(`inline-flex items-center justify-center border-b-2 border-transparent px-3 py-2 text-sm font-medium text-muted-foreground transition-colors hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/30 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50 data-selected:border-primary data-selected:text-foreground`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,Z.jsx)(Oe,{className:i,"data-slot":`tabs-tab`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Ve(e){let t=(0,Y.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=S(`focus-visible:outline-none`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,Z.jsx)(je,{className:i,"data-slot":`tabs-panel`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}export{ge as a,Be as i,ze as n,ve as o,Ve as r,ye as s,Re as t}; \ No newline at end of file +import{c as e,i as t,l as n,n as r,s as i,t as a,u as o}from"./select.js";import{t as s}from"./plus.js";import{t as c}from"./trash-2.js";import{$a as l,$r as u,Bi as d,Da as f,Ea as p,Gi as m,Ha as h,Ia as g,Jo as _,Na as v,Oo as y,Qa as b,Qi as x,Qr as S,Ta as C,Xa as w,Xi as T,Xr as E,Za as D,Zi as O,_o as k,ca as A,ci as j,da as M,di as N,ea as P,ei as F,eo as I,fa as L,fi as R,ha as z,ho as B,ko as V,la as H,li as ee,ma as U,mo as W,ni as G,oa as K,oi as q,po as J,ri as Y,sa as te,si as ne,ta as re,ti as ie,ua as ae,ui as oe,xo as se,yo as ce,za as X,zi as le,zr as ue}from"./index.js";import{a as de,r as fe,t as pe}from"./field.js";var Z=se(),Q=_(V(),1),$=y();function me(e,t){let n=new Map;for(let e of t)e.Key!==void 0&&n.set(e.Key,e.Value??``);let r={};for(let t of e)r[t.key]=n.get(t.key)??``;return r}function he(e,t){if(e.type===`int`){if(t.trim()===``)return`Value is required`;if(!/^-?\d+$/.test(t))return`Must be a whole number`;let n=Number(t);if(e.min!==void 0&&ne.max)return`Must be at most ${e.max}`}}function ge(t){let n=(0,Z.c)(56),{specs:o,attributes:s,onSubmit:c,isPending:l,error:u,isSuccess:d}=t,f;n[0]!==s||n[1]!==o?(f=me(o,s),n[0]=s,n[1]=o,n[2]=f):f=n[2];let p=f,[m,h]=(0,Q.useState)(p),g;n[3]===Symbol.for(`react.memo_cache_sentinel`)?(g=(e,t)=>{h(n=>({...n,[e]:t}))},n[3]=g):g=n[3];let _=g,v;if(n[4]!==o||n[5]!==m){v={};for(let e of o)v[e.key]=he(e,m[e.key]??``);n[4]=o,n[5]=m,n[6]=v}else v=n[6];let y=Object.values(v).some(Boolean),b;if(n[7]!==p||n[8]!==o||n[9]!==m){let e;n[11]!==p||n[12]!==m?(e=e=>(m[e.key]??``)!==(p[e.key]??``),n[11]=p,n[12]=m,n[13]=e):e=n[13];let t;n[14]===m?t=n[15]:(t=e=>({key:e.key,value:m[e.key]??``}),n[14]=m,n[15]=t),b=o.filter(e).map(t),n[7]=p,n[8]=o,n[9]=m,n[10]=b}else b=n[10];let x=b,S;n[16]===p?S=n[17]:(S=()=>{h(p)},n[16]=p,n[17]=S);let C=S,w;n[18]!==x||n[19]!==y||n[20]!==c?(w=e=>{e.preventDefault(),!(y||x.length===0)&&c(x)},n[18]=x,n[19]=y,n[20]=c,n[21]=w):w=n[21];let T;n[22]===u?T=n[23]:(T=u&&(0,$.jsx)(`div`,{className:`mb-4 rounded-md border border-destructive bg-destructive/10 p-3 text-sm text-destructive`,role:`alert`,children:u.message||`Failed to save attributes`}),n[22]=u,n[23]=T);let E;n[24]!==x.length||n[25]!==d?(E=d&&x.length===0&&(0,$.jsx)(`div`,{className:`mb-4 rounded-md border border-emerald-500 bg-emerald-500/10 p-3 text-sm text-emerald-700 dark:text-emerald-400`,role:`status`,children:`Attributes saved.`}),n[24]=x.length,n[25]=d,n[26]=E):E=n[26];let D;if(n[27]!==v||n[28]!==o||n[29]!==m){let t;n[31]!==v||n[32]!==m?(t=t=>{let n=`attr-${t.key}`,o=m[t.key]??``,s=v[t.key];return(0,$.jsxs)(pe,{children:[(0,$.jsx)(de,{children:(0,$.jsx)(`label`,{htmlFor:n,children:t.label})}),t.type===`bool`&&(0,$.jsx)(`input`,{"aria-label":t.label,checked:o===`true`,id:n,onChange:e=>_(t.key,e.target.checked?`true`:`false`),type:`checkbox`}),t.type===`int`&&(0,$.jsx)(le,{"aria-invalid":!!s,id:n,inputMode:`numeric`,onChange:e=>_(t.key,e.target.value),value:o}),t.type===`text`&&(0,$.jsx)(le,{id:n,onChange:e=>_(t.key,e.target.value),placeholder:t.placeholder,value:o}),t.type===`select`&&(0,$.jsxs)(a,{onValueChange:e=>_(t.key,e??``),value:o,children:[(0,$.jsx)(i,{className:`w-full`,id:n,children:(0,$.jsx)(e,{})}),(0,$.jsx)(r,{children:t.options.map(_e)})]}),t.description&&(0,$.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:t.description}),(0,$.jsx)(fe,{errors:[s?{message:s}:void 0]})]},t.key)},n[31]=v,n[32]=m,n[33]=t):t=n[33],D=o.map(t),n[27]=v,n[28]=o,n[29]=m,n[30]=D}else D=n[30];let O;n[34]===D?O=n[35]:(O=(0,$.jsx)(`div`,{className:`grid gap-4 p-4 sm:grid-cols-2`,children:D}),n[34]=D,n[35]=O);let k=x.length===0?`No changes`:`${x.length} change${x.length===1?``:`s`} pending`,A;n[36]===k?A=n[37]:(A=(0,$.jsx)(`span`,{className:`mr-auto text-xs text-muted-foreground`,children:k}),n[36]=k,n[37]=A);let j=l||x.length===0,M;n[38]!==C||n[39]!==j?(M=(0,$.jsx)(X,{disabled:j,onClick:C,size:`sm`,type:`button`,variant:`secondary`,children:`Reset`}),n[38]=C,n[39]=j,n[40]=M):M=n[40];let N=l||y||x.length===0,P=l?`Saving…`:`Save changes`,F;n[41]!==N||n[42]!==P?(F=(0,$.jsx)(X,{disabled:N,size:`sm`,type:`submit`,children:P}),n[41]=N,n[42]=P,n[43]=F):F=n[43];let I;n[44]!==A||n[45]!==M||n[46]!==F?(I=(0,$.jsxs)(`div`,{className:`flex items-center justify-end gap-2 border-t p-4`,children:[A,M,F]}),n[44]=A,n[45]=M,n[46]=F,n[47]=I):I=n[47];let L;n[48]!==I||n[49]!==O?(L=(0,$.jsxs)(`div`,{className:`rounded-lg border bg-card`,children:[O,I]}),n[48]=I,n[49]=O,n[50]=L):L=n[50];let R;return n[51]!==L||n[52]!==w||n[53]!==T||n[54]!==E?(R=(0,$.jsxs)(`form`,{onSubmit:w,children:[T,E,L]}),n[51]=L,n[52]=w,n[53]=T,n[54]=E,n[55]=R):R=n[55],R}function _e(e){return(0,$.jsx)(t,{value:e,children:e},e)}var ve=[{key:`deletion_protection.enabled`,label:`Deletion protection`,type:`bool`},{key:`load_balancing.cross_zone.enabled`,label:`Cross-zone load balancing`,type:`bool`},{key:`idle_timeout.timeout_seconds`,label:`Idle timeout (s)`,type:`int`,min:1,max:4e3},{key:`client_keep_alive.seconds`,label:`Client keep-alive (s)`,type:`int`,min:60,max:604800},{key:`routing.http2.enabled`,label:`HTTP/2`,type:`bool`},{key:`routing.http.drop_invalid_header_fields.enabled`,label:`Drop invalid header fields`,type:`bool`},{key:`routing.http.preserve_host_header.enabled`,label:`Preserve host header`,type:`bool`},{key:`routing.http.xff_client_port.enabled`,label:`XFF client port`,type:`bool`},{key:`routing.http.xff_header_processing.mode`,label:`XFF header processing`,type:`select`,options:[`append`,`preserve`,`remove`]},{key:`routing.http.desync_mitigation_mode`,label:`Desync mitigation mode`,type:`select`,options:[`defensive`,`strictest`,`monitor`]},{key:`routing.http.x_amzn_tls_version_and_cipher_suite.enabled`,label:`Add TLS version & cipher headers`,type:`bool`},{key:`waf.fail_open.enabled`,label:`WAF fail open`,type:`bool`},{key:`zonal_shift.config.enabled`,label:`Zonal shift`,type:`bool`},{key:`access_logs.s3.enabled`,label:`Access logs: enabled`,type:`bool`},{key:`access_logs.s3.bucket`,label:`Access logs: S3 bucket`,type:`text`},{key:`access_logs.s3.prefix`,label:`Access logs: S3 prefix`,type:`text`},{key:`connection_logs.s3.enabled`,label:`Connection logs: enabled`,type:`bool`},{key:`connection_logs.s3.bucket`,label:`Connection logs: S3 bucket`,type:`text`},{key:`connection_logs.s3.prefix`,label:`Connection logs: S3 prefix`,type:`text`}],ye=[{key:`deregistration_delay.timeout_seconds`,label:`Deregistration delay (s)`,type:`int`,min:0,max:3600},{key:`stickiness.enabled`,label:`Stickiness`,type:`bool`},{key:`stickiness.type`,label:`Stickiness type`,type:`select`,options:[`lb_cookie`,`source_ip`]},{key:`stickiness.lb_cookie.duration_seconds`,label:`Stickiness lb_cookie duration (s)`,type:`int`,min:1,max:604800},{key:`load_balancing.cross_zone.enabled`,label:`Cross-zone load balancing`,type:`select`,options:[`true`,`false`,`use_load_balancer_configuration`]},{key:`load_balancing.algorithm.type`,label:`Load balancing algorithm`,type:`select`,options:[`round_robin`,`least_outstanding_requests`]},{key:`slow_start.duration_seconds`,label:`Slow start duration (s)`,type:`int`,min:0,max:900}];function be(e){return e.map((e,t)=>({id:t,key:e.Key??``,value:e.Value??``}))}function xe(e){return e.map(e=>({key:e.key.trim(),value:e.value})).filter(e=>e.key.length>0)}function Se(e){let t=(0,Z.c)(66),{tags:n,onSubmit:r,isPending:i,error:a,isSuccess:o}=e,l;t[0]===n?l=t[1]:(l=be(n),t[0]=n,t[1]=l);let u=l,[d,f]=(0,Q.useState)(u),[p,m]=(0,Q.useState)(u.length),h;t[2]===Symbol.for(`react.memo_cache_sentinel`)?(h=(e,t)=>{f(n=>n.map(n=>n.id===e?{...n,...t}:n))},t[2]=h):h=t[2];let g=h,_;t[3]===p?_=t[4]:(_=()=>{f(e=>[...e,{id:p,key:``,value:``}]),m(Te)},t[3]=p,t[4]=_);let v=_,y;t[5]===Symbol.for(`react.memo_cache_sentinel`)?(y=e=>{f(t=>t.filter(t=>t.id!==e))},t[5]=y):y=t[5];let b=y,x;t[6]===u?x=t[7]:(x=()=>{f(u)},t[6]=u,t[7]=x);let S=x,C;t[8]===d?C=t[9]:(C=d.some(we),t[8]=d,t[9]=C);let w=C,T,E,D,O;if(t[10]!==w||t[11]!==d){D=xe(d);let e=D.map(Ce);T=new Set(e).size!==e.length,E=w||T,O=JSON.stringify(D),t[10]=w,t[11]=d,t[12]=T,t[13]=E,t[14]=D,t[15]=O}else T=t[12],E=t[13],D=t[14],O=t[15];let k;t[16]===u?k=t[17]:(k=JSON.stringify(xe(u)),t[16]=u,t[17]=k);let A=O!==k,j;t[18]!==A||t[19]!==E||t[20]!==D||t[21]!==r?(j=e=>{e.preventDefault(),!(E||!A)&&r(D)},t[18]=A,t[19]=E,t[20]=D,t[21]=r,t[22]=j):j=t[22];let M;t[23]===a?M=t[24]:(M=a&&(0,$.jsx)(`div`,{className:`mb-4 rounded-md border border-destructive bg-destructive/10 p-3 text-sm text-destructive`,role:`alert`,children:a.message||`Failed to save tags`}),t[23]=a,t[24]=M);let N;t[25]!==A||t[26]!==o?(N=o&&!A&&(0,$.jsx)(`div`,{className:`mb-4 rounded-md border border-emerald-500 bg-emerald-500/10 p-3 text-sm text-emerald-700 dark:text-emerald-400`,role:`status`,children:`Tags saved.`}),t[25]=A,t[26]=o,t[27]=N):N=t[27];let P;t[28]===d.length?P=t[29]:(P=d.length===0&&(0,$.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`No tags.`}),t[28]=d.length,t[29]=P);let F;if(t[30]!==d){let e;t[32]===Symbol.for(`react.memo_cache_sentinel`)?(e=e=>(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(le,{"aria-label":`Tag key`,onChange:t=>g(e.id,{key:t.target.value}),placeholder:`Key`,value:e.key}),(0,$.jsx)(le,{"aria-label":`Tag value`,onChange:t=>g(e.id,{value:t.target.value}),placeholder:`Value`,value:e.value}),(0,$.jsx)(X,{"aria-label":`Remove tag`,onClick:()=>b(e.id),size:`icon`,type:`button`,variant:`ghost`,children:(0,$.jsx)(c,{className:`size-4`})})]},e.id),t[32]=e):e=t[32],F=d.map(e),t[30]=d,t[31]=F}else F=t[31];let I;t[33]===Symbol.for(`react.memo_cache_sentinel`)?(I=(0,$.jsx)(s,{className:`size-4`}),t[33]=I):I=t[33];let L;t[34]===v?L=t[35]:(L=(0,$.jsx)(`div`,{children:(0,$.jsxs)(X,{onClick:v,size:`sm`,type:`button`,variant:`secondary`,children:[I,` Add tag`]})}),t[34]=v,t[35]=L);let R;t[36]===w?R=t[37]:(R=w&&(0,$.jsx)(`p`,{className:`text-xs text-destructive`,children:`Every tag with a value needs a key.`}),t[36]=w,t[37]=R);let z;t[38]===T?z=t[39]:(z=T&&(0,$.jsx)(`p`,{className:`text-xs text-destructive`,children:`Tag keys must be unique.`}),t[38]=T,t[39]=z);let B;t[40]!==P||t[41]!==F||t[42]!==L||t[43]!==R||t[44]!==z?(B=(0,$.jsxs)(`div`,{className:`flex flex-col gap-2 p-4`,children:[P,F,L,R,z]}),t[40]=P,t[41]=F,t[42]=L,t[43]=R,t[44]=z,t[45]=B):B=t[45];let V=A?`Unsaved changes`:`No changes`,H;t[46]===V?H=t[47]:(H=(0,$.jsx)(`span`,{className:`mr-auto text-xs text-muted-foreground`,children:V}),t[46]=V,t[47]=H);let ee=i||!A,U;t[48]!==S||t[49]!==ee?(U=(0,$.jsx)(X,{disabled:ee,onClick:S,size:`sm`,type:`button`,variant:`secondary`,children:`Reset`}),t[48]=S,t[49]=ee,t[50]=U):U=t[50];let W=i||E||!A,G=i?`Saving…`:`Save changes`,K;t[51]!==W||t[52]!==G?(K=(0,$.jsx)(X,{disabled:W,size:`sm`,type:`submit`,children:G}),t[51]=W,t[52]=G,t[53]=K):K=t[53];let q;t[54]!==H||t[55]!==U||t[56]!==K?(q=(0,$.jsxs)(`div`,{className:`flex items-center justify-end gap-2 border-t p-4`,children:[H,U,K]}),t[54]=H,t[55]=U,t[56]=K,t[57]=q):q=t[57];let J;t[58]!==B||t[59]!==q?(J=(0,$.jsxs)(`div`,{className:`rounded-lg border bg-card`,children:[B,q]}),t[58]=B,t[59]=q,t[60]=J):J=t[60];let Y;return t[61]!==M||t[62]!==N||t[63]!==J||t[64]!==j?(Y=(0,$.jsxs)(`form`,{onSubmit:j,children:[M,N,J]}),t[61]=M,t[62]=N,t[63]=J,t[64]=j,t[65]=Y):Y=t[65],Y}function Ce(e){return e.key}function we(e){return e.key.trim().length===0&&e.value.length>0}function Te(e){return e+1}var Ee=Q.createContext(void 0);function De(){let e=Q.useContext(Ee);if(e===void 0)throw Error(ce(64));return e}var Oe=function(e){return e.activationDirection=`data-activation-direction`,e.orientation=`data-orientation`,e}({}),ke={tabActivationDirection:e=>({[Oe.activationDirection]:e})},Ae=Q.forwardRef(function(e,t){let{className:n,defaultValue:r=0,onValueChange:i,orientation:a=`horizontal`,render:s,value:c,style:u,...d}=e,f=Object.hasOwn(e,`defaultValue`),p=Q.useRef([]),[m,h]=Q.useState(()=>new Map),[g,_]=T({controlled:c,default:r,name:`Tabs`,state:`value`}),v=c!==void 0,[y,b]=Q.useState(()=>new Map),x=Q.useCallback(e=>{if(e===void 0)return null;for(let[t,n]of y.entries())if(n!=null&&e===(n.value??n.index))return t;return null},[y]),[S,C]=Q.useState(()=>({previousValue:g,tabActivationDirection:`none`})),{previousValue:w,tabActivationDirection:E}=S,D=E,O=!1;w!==g&&(D=je(w,g,a,y),O=w!=null&&g!=null&&x(g)==null);let k=O?w:g,A=w!==k||E!==D;l(()=>{A&&C({previousValue:k,tabActivationDirection:D})},[k,A,D]);let j=I((e,t)=>{t.activationDirection=je(g,e,a,y),i?.(e,t),!t.isCanceled&&_(e)}),M=I((e,t)=>{h(n=>{if(n.get(e)===t)return n;let r=new Map(n);return r.set(e,t),r})}),N=I((e,t)=>{h(n=>{if(!n.has(e)||n.get(e)!==t)return n;let r=new Map(n);return r.delete(e),r})}),P=Q.useCallback(e=>m.get(e),[m]),F=Q.useCallback(e=>{for(let t of y.values())if(e===t?.value)return t?.id},[y]),L=Q.useMemo(()=>({getTabElementBySelectedValue:x,getTabIdByPanelValue:F,getTabPanelIdByValue:P,onValueChange:j,orientation:a,registerMountedTabPanel:M,setTabMap:b,unregisterMountedTabPanel:N,tabActivationDirection:D,value:g}),[x,F,P,j,a,M,b,N,D,g]),R=Q.useMemo(()=>{for(let e of y.values())if(e!=null&&e.value===g)return e},[y,g]),z=Q.useMemo(()=>{for(let e of y.values())if(e!=null&&!e.disabled)return e.value},[y]);l(()=>{if(v||y.size===0)return;let e=R?.disabled;if(f&&e&&g===r||!e&&!(R==null&&g!==null))return;let t=z??null;g!==t&&(_(t),C(e=>e.tabActivationDirection===`none`?e:{...e,tabActivationDirection:`none`}))},[r,z,f,v,R,_,y,g]);let B=J(`div`,e,{state:{orientation:a,tabActivationDirection:D},ref:t,props:d,stateAttributesMapping:ke});return(0,$.jsx)(Ee.Provider,{value:L,children:(0,$.jsx)(o,{elementsRef:p,children:B})})});function je(e,t,n,r){if(e==null||t==null)return`none`;let i=null,a=null;for(let[n,o]of r.entries()){if(o==null)continue;let r=o.value??o.index;if(e===r&&(i=n),t===r&&(a=n),i!=null&&a!=null)break}if(i==null||a==null)return i!==a&&(typeof e==`number`||typeof e==`string`)&&typeof e==typeof t?n===`horizontal`?t>e?`right`:`left`:t>e?`down`:`up`:`none`;let o=i.getBoundingClientRect(),s=a.getBoundingClientRect();if(n===`horizontal`){if(s.lefto.left)return`right`}else{if(s.topo.top)return`down`}return`none`}var Me=`data-composite-item-active`;function Ne(e={}){let{highlightItemOnHover:t,highlightedIndex:r,onHighlightedIndexChange:i}=b(),{ref:a,index:o}=n(e),s=r===o,c=Q.useRef(null),l=k(a,c);return{compositeProps:Q.useMemo(()=>({tabIndex:s?0:-1,onFocus(){i(o)},onMouseMove(){let e=c.current;if(!t||!e)return;let n=e.hasAttribute(`disabled`)||e.ariaDisabled===`true`;!s&&!n&&e.focus()}}),[s,i,o,t]),compositeRef:l,index:o}}var Pe=Q.createContext(void 0);function Fe(){let e=Q.useContext(Pe);if(e===void 0)throw Error(ce(65));return e}var Ie=Q.forwardRef(function(e,t){let{className:n,disabled:r=!1,render:i,value:a,id:o,nativeButton:s=!0,style:c,...u}=e,{value:f,getTabPanelIdByValue:h,orientation:_}=De(),{activateOnFocus:y,highlightedTabIndex:b,onTabActivation:x,registerTabResizeObserverElement:S,setHighlightedTabIndex:T,tabsListElement:E}=Fe(),D=g(o),{compositeProps:O,compositeRef:k,index:A}=Ne({metadata:Q.useMemo(()=>({disabled:r,id:D,value:a}),[r,D,a])}),j=a===f,M=Q.useRef(!1),N=Q.useRef(null);Q.useEffect(()=>{let e=N.current;if(e)return S(e)},[S]),l(()=>{if(M.current){M.current=!1;return}if(!(j&&A>-1&&b!==A))return;let e=E;if(e!=null){let t=C(v(e));if(t&&p(e,t))return}r||T(A)},[j,A,b,T,r,E]);let{getButtonProps:P,buttonRef:F}=w({disabled:r,native:s,focusableWhenDisabled:!0}),I=h(a),L=Q.useRef(!1),R=Q.useRef(!1);function z(e){j||r||x(a,d(m,e.nativeEvent,void 0,{activationDirection:`none`}))}function B(e){j||(A>-1&&!r&&T(A),!r&&y&&(!L.current||L.current&&R.current)&&x(a,d(m,e.nativeEvent,void 0,{activationDirection:`none`})))}function V(e){if(j||r)return;L.current=!0;function t(){L.current=!1,R.current=!1}(!e.button||e.button===0)&&(R.current=!0,v(e.currentTarget).addEventListener(`pointerup`,t,{once:!0}))}return J(`button`,e,{state:{disabled:r,active:j,orientation:_},ref:[t,F,k,N],props:[O,{role:`tab`,"aria-controls":I,"aria-selected":j,id:D,onClick:z,onFocus:B,onPointerDown:V,[Me]:j?``:void 0,onKeyDownCapture(){M.current=!0}},u,P]})}),Le=function(e){return e.index=`data-index`,e.activationDirection=`data-activation-direction`,e.orientation=`data-orientation`,e.hidden=`data-hidden`,e[e.startingStyle=P.startingStyle]=`startingStyle`,e[e.endingStyle=P.endingStyle]=`endingStyle`,e}({}),Re={...ke,...re},ze=Q.forwardRef(function(e,t){let{className:r,value:i,render:a,keepMounted:o=!1,style:s,...c}=e,{value:u,getTabIdByPanelValue:d,orientation:f,tabActivationDirection:p,registerMountedTabPanel:m,unregisterMountedTabPanel:h}=De(),_=g(),{ref:v,index:y}=n({metadata:Q.useMemo(()=>({id:_,value:i}),[_,i])}),b=i===u,{mounted:S,transitionStatus:C,setMounted:w}=O(b),T=!S,D=d(i),k={hidden:T,orientation:f,tabActivationDirection:p,transitionStatus:C},A=Q.useRef(null),j=J(`div`,e,{state:k,ref:[t,v,A],props:[{"aria-labelledby":D,hidden:T,id:_,role:`tabpanel`,tabIndex:b?0:-1,inert:E(!b),[Le.index]:y},c],stateAttributesMapping:Re});return x({open:b,ref:A,onComplete(){b||w(!1)}}),l(()=>{if(!(T&&!o)&&_!=null)return m(i,_),()=>{h(i,_)}},[T,o,i,_,m,h]),o||S?j:null});function Be(e){return e==null||e.hasAttribute(`disabled`)||e.getAttribute(`aria-disabled`)===`true`}var Ve=[];function He(e){let{itemSizes:t,cols:n=1,loopFocus:r=!0,onLoop:i,dense:a=!1,orientation:o=`both`,direction:s,highlightedIndex:c,onHighlightedIndexChange:l,rootRef:d,enableHomeAndEndKeys:p=!1,stopEventPropagation:m=!1,disabledIndices:h,modifierKeys:g=Ve}=e,[_,v]=Q.useState(0),y=n>1,b=Q.useRef(null),x=k(b,d),C=Q.useRef([]),w=Q.useRef(!1),T=c??_,E=I((e,t=!1)=>{if((l??v)(e),t){let t=C.current[e];R(b.current,t,s,o)}}),D=I(e=>{if(e.size===0||w.current)return;w.current=!0;let t=Array.from(e.keys()),n=t.find(e=>e?.hasAttribute(`data-composite-item-active`))??null,r=n?t.indexOf(n):-1;r!==-1&&E(r),R(b.current,n,s,o)}),O=I((e,t,n)=>i?i?.(e,t,n,C):n),j=Q.useMemo(()=>({"aria-orientation":o===`both`?void 0:o,ref:x,onFocus(e){let t=b.current,n=f(e.nativeEvent);!t||n==null||!N(n)||n.setSelectionRange(0,n.value.length??0)},onKeyDown(e){let c=p?S:F;if(!c.has(e.key)||Ue(e,g)||!b.current)return;let l=s===`rtl`,d=l?ie:G,_={horizontal:d,vertical:u,both:d}[o],v=l?G:ie,x={horizontal:v,vertical:Y,both:v}[o],w=f(e.nativeEvent);if(w!=null&&N(w)&&!Be(w)){let t=w.selectionStart,n=w.selectionEnd,r=w.value??``;if(t==null||e.shiftKey||t!==n||e.key!==x&&t0)return}let D=T,k=L(C,h),j=M(C,h);if(y){let i=t||Array.from({length:C.current.length},()=>({width:1,height:1})),s=K(i,n,a),c=s.findIndex(e=>e!=null&&!z(C.current,e,h)),u=s.reduce((e,t,n)=>t!=null&&!z(C.current,t,h)?n:e,-1);D=s[ae(s.map(e=>e==null?null:C.current[e]),{event:e,orientation:o,loopFocus:r,onLoop:O,cols:n,disabledIndices:H([...h||C.current.map((e,t)=>z(C.current,t)?t:void 0),void 0],s),minIndex:c,maxIndex:u,prevIndex:A(T>j?k:T,i,s,n,e.key===`ArrowDown`?`bl`:e.key===`ArrowRight`?`tr`:`tl`),rtl:l})]}let P={horizontal:[d],vertical:[u],both:[d,u]}[o],I={horizontal:[v],vertical:[Y],both:[v,Y]}[o],R=y?c:{horizontal:p?ne:q,vertical:p?oe:ee,both:c}[o];p&&(e.key===`Home`?D=k:e.key===`End`&&(D=j)),D===T&&(P.includes(e.key)||I.includes(e.key))&&(r&&D===j&&P.includes(e.key)?(D=k,i&&(D=i(e,T,D,C))):r&&D===k&&I.includes(e.key)?(D=j,i&&(D=i(e,T,D,C))):D=te(C.current,{startingIndex:D,decrement:I.includes(e.key),disabledIndices:h})),D!==T&&!U(C.current,D)&&(m&&e.stopPropagation(),R.has(e.key)&&e.preventDefault(),E(D,!0),queueMicrotask(()=>{C.current[D]?.focus()}))}}),[n,a,s,h,C,p,T,y,t,r,i,O,x,g,E,o,m]);return Q.useMemo(()=>({props:j,highlightedIndex:T,onHighlightedIndexChange:E,elementsRef:C,disabledIndices:h,onMapChange:D,relayKeyboardEvent:j.onKeyDown}),[j,T,E,C,h,D])}function Ue(e,t){for(let n of j.values())if(!t.includes(n)&&e.getModifierState(n))return!0;return!1}function We(e){let{render:t,className:n,style:r,refs:i=W,props:a=W,state:s=B,stateAttributesMapping:c,highlightedIndex:l,onHighlightedIndexChange:u,orientation:d,dense:f,itemSizes:p,loopFocus:m,onLoop:h,cols:g,enableHomeAndEndKeys:_,onMapChange:v,stopEventPropagation:y=!0,rootRef:b,disabledIndices:x,modifierKeys:S,highlightItemOnHover:C=!1,tag:w=`div`,...T}=e,{props:E,highlightedIndex:O,onHighlightedIndexChange:k,elementsRef:A,onMapChange:j,relayKeyboardEvent:M}=He({itemSizes:p,cols:g,loopFocus:m,onLoop:h,dense:f,orientation:d,highlightedIndex:l,onHighlightedIndexChange:u,rootRef:b,stopEventPropagation:y,enableHomeAndEndKeys:_,direction:ue(),disabledIndices:x,modifierKeys:S}),N=J(w,e,{state:s,ref:i,props:[E,...a,T],stateAttributesMapping:c}),P=Q.useMemo(()=>({highlightedIndex:O,onHighlightedIndexChange:k,highlightItemOnHover:C,relayKeyboardEvent:M}),[O,k,C,M]);return(0,$.jsx)(D.Provider,{value:P,children:(0,$.jsx)(o,{elementsRef:A,onMapChange:e=>{v?.(e),j(e)},children:N})})}var Ge=Q.forwardRef(function(e,t){let{activateOnFocus:n=!1,className:r,loopFocus:i=!0,render:a,style:o,...s}=e,{onValueChange:c,orientation:l,value:u,setTabMap:d,tabActivationDirection:f}=De(),[p,m]=Q.useState(0),[h,g]=Q.useState(null),_=Q.useRef(new Set),v=Q.useRef(new Set),y=Q.useRef(null),b=I(()=>{_.current.forEach(e=>{e()})});Q.useEffect(()=>{if(typeof ResizeObserver>`u`)return;let e=new ResizeObserver(()=>{_.current.size&&b()});return y.current=e,h&&e.observe(h),v.current.forEach(t=>{e.observe(t)}),()=>{e.disconnect(),y.current=null}},[h,b]);let x=I(e=>(_.current.add(e),()=>{_.current.delete(e)})),S=I(e=>(v.current.add(e),y.current?.observe(e),()=>{v.current.delete(e),y.current?.unobserve(e)})),C=I((e,t)=>{e!==u&&c(e,t)}),w={orientation:l,tabActivationDirection:f},T={"aria-orientation":l===`vertical`?`vertical`:void 0,role:`tablist`},E=Q.useMemo(()=>({activateOnFocus:n,highlightedTabIndex:p,registerIndicatorUpdateListener:x,registerTabResizeObserverElement:S,onTabActivation:C,setHighlightedTabIndex:m,tabsListElement:h}),[n,p,x,S,C,m,h]);return(0,$.jsx)(Pe.Provider,{value:E,children:(0,$.jsx)(We,{render:a,className:r,style:o,state:w,refs:[t,g],props:[T,s],stateAttributesMapping:ke,highlightedIndex:p,enableHomeAndEndKeys:!0,loopFocus:i,orientation:l,onHighlightedIndexChange:m,onMapChange:d,disabledIndices:W})})});function Ke(e){let t=(0,Z.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=h(`flex flex-col gap-4`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,$.jsx)(Ae,{className:i,"data-slot":`tabs`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function qe(e){let t=(0,Z.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=h(`inline-flex items-center gap-1 border-b`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,$.jsx)(Ge,{className:i,"data-slot":`tabs-list`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Je(e){let t=(0,Z.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=h(`inline-flex items-center justify-center border-b-2 border-transparent px-3 py-2 text-sm font-medium text-muted-foreground transition-colors hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/30 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50 data-selected:border-primary data-selected:text-foreground`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,$.jsx)(Ie,{className:i,"data-slot":`tabs-tab`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}function Ye(e){let t=(0,Z.c)(8),n,r;t[0]===e?(n=t[1],r=t[2]):({className:n,...r}=e,t[0]=e,t[1]=n,t[2]=r);let i;t[3]===n?i=t[4]:(i=h(`focus-visible:outline-none`,n),t[3]=n,t[4]=i);let a;return t[5]!==r||t[6]!==i?(a=(0,$.jsx)(ze,{className:i,"data-slot":`tabs-panel`,...r}),t[5]=r,t[6]=i,t[7]=a):a=t[7],a}export{Se as a,ye as c,Je as i,qe as n,ge as o,Ye as r,ve as s,Ke as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/target-group-form.js b/spinifex/services/spinifexui/frontend/dist/assets/target-group-form.js index c138cdd38..84fadbcb5 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/target-group-form.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/target-group-form.js @@ -1 +1 @@ -import{c as e,i as t,n as ee,s as te,t as ne}from"./select.js";import{t as n}from"./plus.js";import{t as re}from"./trash-2.js";import{Pa as r,Ta as ie,Ti as i,mo as ae,so as a}from"./index.js";import{a as o,r as s,t as c}from"./field.js";import{n as oe}from"./zod.js";import{n as se,r as ce,t as le}from"./collapsible.js";var l=a(),u=ae();function d(t){let r=(0,l.c)(174),{form:ae,vpcs:a}=t,{control:d,register:f,watch:fe,setValue:p,getValues:m,formState:h}=ae,{errors:g}=h,_,v,y,b,x,S,C,w,T;if(r[0]!==d||r[1]!==g.healthCheck?.healthyThresholdCount||r[2]!==g.healthCheck?.intervalSeconds||r[3]!==g.healthCheck?.matcher||r[4]!==g.healthCheck?.path||r[5]!==g.healthCheck?.port||r[6]!==g.healthCheck?.timeoutSeconds||r[7]!==g.healthCheck?.unhealthyThresholdCount||r[8]!==g.name||r[9]!==g.port||r[10]!==g.vpcId||r[11]!==m||r[12]!==f||r[13]!==p||r[14]!==a||r[15]!==fe){let t=fe(`tags`),n;r[25]===Symbol.for(`react.memo_cache_sentinel`)?(n=(0,u.jsx)(o,{children:(0,u.jsx)(`label`,{htmlFor:`tg-name`,children:`Name`})}),r[25]=n):n=r[25];let ae=!!g.name,l;r[26]===f?l=r[27]:(l=f(`name`),r[26]=f,r[27]=l);let h;r[28]!==ae||r[29]!==l?(h=(0,u.jsx)(i,{"aria-invalid":ae,id:`tg-name`,placeholder:`my-target-group`,...l}),r[28]=ae,r[29]=l,r[30]=h):h=r[30];let E;r[31]===g.name?E=r[32]:(E=(0,u.jsx)(s,{errors:[g.name]}),r[31]=g.name,r[32]=E),r[33]!==h||r[34]!==E?(x=(0,u.jsxs)(c,{children:[n,h,E]}),r[33]=h,r[34]=E,r[35]=x):x=r[35];let D;r[36]===Symbol.for(`react.memo_cache_sentinel`)?(D=(0,u.jsx)(o,{children:(0,u.jsx)(`label`,{htmlFor:`tg-protocol`,children:`Protocol`})}),r[36]=D):D=r[36],r[37]===d?S=r[38]:(S=(0,u.jsxs)(c,{children:[D,(0,u.jsx)(oe,{control:d,name:`protocol`,render:de})]}),r[37]=d,r[38]=S);let O;r[39]===Symbol.for(`react.memo_cache_sentinel`)?(O=(0,u.jsx)(o,{children:(0,u.jsx)(`label`,{htmlFor:`tg-port`,children:`Port`})}),r[39]=O):O=r[39];let k=!!g.port,A;r[40]===f?A=r[41]:(A=f(`port`,{valueAsNumber:!0}),r[40]=f,r[41]=A);let j;r[42]!==k||r[43]!==A?(j=(0,u.jsx)(i,{"aria-invalid":k,id:`tg-port`,inputMode:`numeric`,placeholder:`80`,type:`number`,...A}),r[42]=k,r[43]=A,r[44]=j):j=r[44];let M;r[45]===g.port?M=r[46]:(M=(0,u.jsx)(s,{errors:[g.port]}),r[45]=g.port,r[46]=M),r[47]!==j||r[48]!==M?(C=(0,u.jsxs)(c,{children:[O,j,M]}),r[47]=j,r[48]=M,r[49]=C):C=r[49];let pe;r[50]===Symbol.for(`react.memo_cache_sentinel`)?(pe=(0,u.jsx)(o,{children:(0,u.jsx)(`label`,{htmlFor:`tg-vpc`,children:`VPC`})}),r[50]=pe):pe=r[50];let N;r[51]!==g.vpcId||r[52]!==a?(N=t=>{let{field:n}=t;return(0,u.jsxs)(ne,{onValueChange:e=>n.onChange(e),value:n.value??``,children:[(0,u.jsx)(te,{"aria-invalid":!!g.vpcId,className:`w-full`,id:`tg-vpc`,children:(0,u.jsx)(e,{placeholder:`Select VPC`})}),(0,u.jsx)(ee,{children:a.map(ue)})]})},r[51]=g.vpcId,r[52]=a,r[53]=N):N=r[53];let P;r[54]!==d||r[55]!==N?(P=(0,u.jsx)(oe,{control:d,name:`vpcId`,render:N}),r[54]=d,r[55]=N,r[56]=P):P=r[56];let F;r[57]===g.vpcId?F=r[58]:(F=(0,u.jsx)(s,{errors:[g.vpcId]}),r[57]=g.vpcId,r[58]=F),r[59]!==P||r[60]!==F?(w=(0,u.jsxs)(c,{children:[pe,P,F]}),r[59]=P,r[60]=F,r[61]=w):w=r[61];let me;r[62]===Symbol.for(`react.memo_cache_sentinel`)?(me=(0,u.jsx)(ce,{className:`text-left text-sm font-medium text-muted-foreground hover:text-foreground`,render:(0,u.jsx)(`button`,{"aria-label":`Health check settings`,type:`button`}),children:`Health check settings`}),r[62]=me):me=r[62];let he;r[63]===Symbol.for(`react.memo_cache_sentinel`)?(he=(0,u.jsx)(o,{children:(0,u.jsx)(`label`,{htmlFor:`hc-path`,children:`Path`})}),r[63]=he):he=r[63];let ge=!!g.healthCheck?.path,I;r[64]===f?I=r[65]:(I=f(`healthCheck.path`),r[64]=f,r[65]=I);let L;r[66]!==ge||r[67]!==I?(L=(0,u.jsx)(i,{"aria-invalid":ge,id:`hc-path`,placeholder:`/`,...I}),r[66]=ge,r[67]=I,r[68]=L):L=r[68];let _e=g.healthCheck?.path,R;r[69]===_e?R=r[70]:(R=(0,u.jsx)(s,{errors:[_e]}),r[69]=_e,r[70]=R);let z;r[71]!==L||r[72]!==R?(z=(0,u.jsxs)(c,{children:[he,L,R]}),r[71]=L,r[72]=R,r[73]=z):z=r[73];let ve;r[74]===Symbol.for(`react.memo_cache_sentinel`)?(ve=(0,u.jsx)(o,{children:(0,u.jsx)(`label`,{htmlFor:`hc-port`,children:`Port`})}),r[74]=ve):ve=r[74];let ye=!!g.healthCheck?.port,B;r[75]===f?B=r[76]:(B=f(`healthCheck.port`),r[75]=f,r[76]=B);let V;r[77]!==ye||r[78]!==B?(V=(0,u.jsx)(i,{"aria-invalid":ye,id:`hc-port`,placeholder:`traffic-port or numeric`,...B}),r[77]=ye,r[78]=B,r[79]=V):V=r[79];let be=g.healthCheck?.port,xe;r[80]===be?xe=r[81]:(xe=(0,u.jsx)(s,{errors:[be]}),r[80]=be,r[81]=xe);let H;r[82]!==V||r[83]!==xe?(H=(0,u.jsxs)(c,{children:[ve,V,xe]}),r[82]=V,r[83]=xe,r[84]=H):H=r[84];let Se;r[85]===Symbol.for(`react.memo_cache_sentinel`)?(Se=(0,u.jsx)(o,{children:(0,u.jsx)(`label`,{htmlFor:`hc-interval`,children:`Interval (seconds)`})}),r[85]=Se):Se=r[85];let Ce=!!g.healthCheck?.intervalSeconds,U;r[86]===f?U=r[87]:(U=f(`healthCheck.intervalSeconds`,{valueAsNumber:!0}),r[86]=f,r[87]=U);let W;r[88]!==Ce||r[89]!==U?(W=(0,u.jsx)(i,{"aria-invalid":Ce,id:`hc-interval`,inputMode:`numeric`,type:`number`,...U}),r[88]=Ce,r[89]=U,r[90]=W):W=r[90];let we=g.healthCheck?.intervalSeconds,G;r[91]===we?G=r[92]:(G=(0,u.jsx)(s,{errors:[we]}),r[91]=we,r[92]=G);let K;r[93]!==W||r[94]!==G?(K=(0,u.jsxs)(c,{children:[Se,W,G]}),r[93]=W,r[94]=G,r[95]=K):K=r[95];let Te;r[96]===Symbol.for(`react.memo_cache_sentinel`)?(Te=(0,u.jsx)(o,{children:(0,u.jsx)(`label`,{htmlFor:`hc-timeout`,children:`Timeout (seconds)`})}),r[96]=Te):Te=r[96];let Ee=!!g.healthCheck?.timeoutSeconds,q;r[97]===f?q=r[98]:(q=f(`healthCheck.timeoutSeconds`,{valueAsNumber:!0}),r[97]=f,r[98]=q);let J;r[99]!==Ee||r[100]!==q?(J=(0,u.jsx)(i,{"aria-invalid":Ee,id:`hc-timeout`,inputMode:`numeric`,type:`number`,...q}),r[99]=Ee,r[100]=q,r[101]=J):J=r[101];let De=g.healthCheck?.timeoutSeconds,Y;r[102]===De?Y=r[103]:(Y=(0,u.jsx)(s,{errors:[De]}),r[102]=De,r[103]=Y);let X;r[104]!==J||r[105]!==Y?(X=(0,u.jsxs)(c,{children:[Te,J,Y]}),r[104]=J,r[105]=Y,r[106]=X):X=r[106];let Oe;r[107]===Symbol.for(`react.memo_cache_sentinel`)?(Oe=(0,u.jsx)(o,{children:(0,u.jsx)(`label`,{htmlFor:`hc-healthy`,children:`Healthy threshold`})}),r[107]=Oe):Oe=r[107];let ke=!!g.healthCheck?.healthyThresholdCount,Z;r[108]===f?Z=r[109]:(Z=f(`healthCheck.healthyThresholdCount`,{valueAsNumber:!0}),r[108]=f,r[109]=Z);let Q;r[110]!==ke||r[111]!==Z?(Q=(0,u.jsx)(i,{"aria-invalid":ke,id:`hc-healthy`,inputMode:`numeric`,type:`number`,...Z}),r[110]=ke,r[111]=Z,r[112]=Q):Q=r[112];let Ae=g.healthCheck?.healthyThresholdCount,je;r[113]===Ae?je=r[114]:(je=(0,u.jsx)(s,{errors:[Ae]}),r[113]=Ae,r[114]=je);let Me;r[115]!==Q||r[116]!==je?(Me=(0,u.jsxs)(c,{children:[Oe,Q,je]}),r[115]=Q,r[116]=je,r[117]=Me):Me=r[117];let Ne;r[118]===Symbol.for(`react.memo_cache_sentinel`)?(Ne=(0,u.jsx)(o,{children:(0,u.jsx)(`label`,{htmlFor:`hc-unhealthy`,children:`Unhealthy threshold`})}),r[118]=Ne):Ne=r[118];let Pe=!!g.healthCheck?.unhealthyThresholdCount,$;r[119]===f?$=r[120]:($=f(`healthCheck.unhealthyThresholdCount`,{valueAsNumber:!0}),r[119]=f,r[120]=$);let Fe;r[121]!==Pe||r[122]!==$?(Fe=(0,u.jsx)(i,{"aria-invalid":Pe,id:`hc-unhealthy`,inputMode:`numeric`,type:`number`,...$}),r[121]=Pe,r[122]=$,r[123]=Fe):Fe=r[123];let Ie=g.healthCheck?.unhealthyThresholdCount,Le;r[124]===Ie?Le=r[125]:(Le=(0,u.jsx)(s,{errors:[Ie]}),r[124]=Ie,r[125]=Le);let Re;r[126]!==Fe||r[127]!==Le?(Re=(0,u.jsxs)(c,{children:[Ne,Fe,Le]}),r[126]=Fe,r[127]=Le,r[128]=Re):Re=r[128];let ze;r[129]===Symbol.for(`react.memo_cache_sentinel`)?(ze=(0,u.jsx)(o,{children:(0,u.jsx)(`label`,{htmlFor:`hc-matcher`,children:`Matcher (HTTP codes)`})}),r[129]=ze):ze=r[129];let Be=!!g.healthCheck?.matcher,Ve;r[130]===f?Ve=r[131]:(Ve=f(`healthCheck.matcher`),r[130]=f,r[131]=Ve);let He;r[132]!==Be||r[133]!==Ve?(He=(0,u.jsx)(i,{"aria-invalid":Be,id:`hc-matcher`,placeholder:`200 or 200-299 or 200,201`,...Ve}),r[132]=Be,r[133]=Ve,r[134]=He):He=r[134];let Ue=g.healthCheck?.matcher,We;r[135]===Ue?We=r[136]:(We=(0,u.jsx)(s,{errors:[Ue]}),r[135]=Ue,r[136]=We);let Ge;r[137]!==He||r[138]!==We?(Ge=(0,u.jsxs)(c,{children:[ze,He,We]}),r[137]=He,r[138]=We,r[139]=Ge):Ge=r[139],r[140]!==z||r[141]!==H||r[142]!==K||r[143]!==X||r[144]!==Me||r[145]!==Re||r[146]!==Ge?(T=(0,u.jsxs)(le,{children:[me,(0,u.jsxs)(se,{className:`mt-3 space-y-4 border-l-2 border-muted pl-4`,children:[z,H,K,X,Me,Re,Ge]})]}),r[140]=z,r[141]=H,r[142]=K,r[143]=X,r[144]=Me,r[145]=Re,r[146]=Ge,r[147]=T):T=r[147],_=c,r[148]===Symbol.for(`react.memo_cache_sentinel`)?(b=(0,u.jsx)(o,{children:`Tags`}),r[148]=b):b=r[148],v=`space-y-2`;let Ke;r[149]!==m||r[150]!==f||r[151]!==p?(Ke=(e,t)=>(0,u.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,u.jsx)(i,{placeholder:`Key`,...f(`tags.${t}.key`)}),(0,u.jsx)(i,{placeholder:`Value`,...f(`tags.${t}.value`)}),(0,u.jsx)(ie,{onClick:()=>p(`tags`,m(`tags`).filter((e,ee)=>ee!==t)),size:`icon`,type:`button`,variant:`ghost`,children:(0,u.jsx)(re,{className:`size-3.5`})})]},t),r[149]=m,r[150]=f,r[151]=p,r[152]=Ke):Ke=r[152],y=t.map(Ke),r[0]=d,r[1]=g.healthCheck?.healthyThresholdCount,r[2]=g.healthCheck?.intervalSeconds,r[3]=g.healthCheck?.matcher,r[4]=g.healthCheck?.path,r[5]=g.healthCheck?.port,r[6]=g.healthCheck?.timeoutSeconds,r[7]=g.healthCheck?.unhealthyThresholdCount,r[8]=g.name,r[9]=g.port,r[10]=g.vpcId,r[11]=m,r[12]=f,r[13]=p,r[14]=a,r[15]=fe,r[16]=_,r[17]=v,r[18]=y,r[19]=b,r[20]=x,r[21]=S,r[22]=C,r[23]=w,r[24]=T}else _=r[16],v=r[17],y=r[18],b=r[19],x=r[20],S=r[21],C=r[22],w=r[23],T=r[24];let E;r[153]!==m||r[154]!==p?(E=()=>p(`tags`,[...m(`tags`),{key:``,value:``}]),r[153]=m,r[154]=p,r[155]=E):E=r[155];let D;r[156]===Symbol.for(`react.memo_cache_sentinel`)?(D=(0,u.jsx)(n,{className:`size-3.5`}),r[156]=D):D=r[156];let O;r[157]===E?O=r[158]:(O=(0,u.jsxs)(ie,{onClick:E,size:`sm`,type:`button`,variant:`outline`,children:[D,`Add tag`]}),r[157]=E,r[158]=O);let k;r[159]!==O||r[160]!==v||r[161]!==y?(k=(0,u.jsxs)(`div`,{className:v,children:[y,O]}),r[159]=O,r[160]=v,r[161]=y,r[162]=k):k=r[162];let A;r[163]!==_||r[164]!==k||r[165]!==b?(A=(0,u.jsxs)(_,{children:[b,k]}),r[163]=_,r[164]=k,r[165]=b,r[166]=A):A=r[166];let j;return r[167]!==A||r[168]!==x||r[169]!==S||r[170]!==C||r[171]!==w||r[172]!==T?(j=(0,u.jsxs)(u.Fragment,{children:[x,S,C,w,T,A]}),r[167]=A,r[168]=x,r[169]=S,r[170]=C,r[171]=w,r[172]=T,r[173]=j):j=r[173],j}function ue(e){let ee=r(e.Tags);return(0,u.jsx)(t,{value:e.VpcId??``,children:ee?`${e.VpcId} (${ee})`:`${e.VpcId} (${e.CidrBlock})`},e.VpcId)}function de(n){let{field:re}=n;return(0,u.jsxs)(ne,{onValueChange:re.onChange,value:re.value,children:[(0,u.jsx)(te,{className:`w-full`,id:`tg-protocol`,children:(0,u.jsx)(e,{})}),(0,u.jsx)(ee,{children:(0,u.jsx)(t,{value:`HTTP`,children:`HTTP`})})]})}export{d as t}; \ No newline at end of file +import{c as e,i as t,n as ee,s as te,t as ne}from"./select.js";import{t as re}from"./plus.js";import{t as ie}from"./trash-2.js";import{Ja as n,Oo as ae,xo as oe,za as se,zi as r}from"./index.js";import{a as i,r as a,t as o}from"./field.js";import{a as ce,n as le}from"./zod.js";import{n as ue,r as de,t as fe}from"./collapsible.js";var pe=oe(),s=ae();function c(t){let n=(0,pe.c)(151),{form:ae,vpcs:oe}=t,{control:c,register:l,setValue:u,getValues:d,formState:ge}=ae,{errors:f}=ge,_e;n[0]===c?_e=n[1]:(_e={control:c,name:`tags`},n[0]=c,n[1]=_e);let ve=ce(_e),ye;n[2]===Symbol.for(`react.memo_cache_sentinel`)?(ye=(0,s.jsx)(i,{children:(0,s.jsx)(`label`,{htmlFor:`tg-name`,children:`Name`})}),n[2]=ye):ye=n[2];let be=!!f.name,p;n[3]===l?p=n[4]:(p=l(`name`),n[3]=l,n[4]=p);let m;n[5]!==be||n[6]!==p?(m=(0,s.jsx)(r,{"aria-invalid":be,id:`tg-name`,placeholder:`my-target-group`,...p}),n[5]=be,n[6]=p,n[7]=m):m=n[7];let h;n[8]===f.name?h=n[9]:(h=(0,s.jsx)(a,{errors:[f.name]}),n[8]=f.name,n[9]=h);let g;n[10]!==m||n[11]!==h?(g=(0,s.jsxs)(o,{children:[ye,m,h]}),n[10]=m,n[11]=h,n[12]=g):g=n[12];let xe;n[13]===Symbol.for(`react.memo_cache_sentinel`)?(xe=(0,s.jsx)(i,{children:(0,s.jsx)(`label`,{htmlFor:`tg-protocol`,children:`Protocol`})}),n[13]=xe):xe=n[13];let _;n[14]===c?_=n[15]:(_=(0,s.jsxs)(o,{children:[xe,(0,s.jsx)(le,{control:c,name:`protocol`,render:he})]}),n[14]=c,n[15]=_);let Se;n[16]===Symbol.for(`react.memo_cache_sentinel`)?(Se=(0,s.jsx)(i,{children:(0,s.jsx)(`label`,{htmlFor:`tg-port`,children:`Port`})}),n[16]=Se):Se=n[16];let Ce=!!f.port,v;n[17]===l?v=n[18]:(v=l(`port`,{valueAsNumber:!0}),n[17]=l,n[18]=v);let y;n[19]!==Ce||n[20]!==v?(y=(0,s.jsx)(r,{"aria-invalid":Ce,id:`tg-port`,inputMode:`numeric`,placeholder:`80`,type:`number`,...v}),n[19]=Ce,n[20]=v,n[21]=y):y=n[21];let b;n[22]===f.port?b=n[23]:(b=(0,s.jsx)(a,{errors:[f.port]}),n[22]=f.port,n[23]=b);let x;n[24]!==y||n[25]!==b?(x=(0,s.jsxs)(o,{children:[Se,y,b]}),n[24]=y,n[25]=b,n[26]=x):x=n[26];let we;n[27]===Symbol.for(`react.memo_cache_sentinel`)?(we=(0,s.jsx)(i,{children:(0,s.jsx)(`label`,{htmlFor:`tg-vpc`,children:`VPC`})}),n[27]=we):we=n[27];let S;n[28]!==f.vpcId||n[29]!==oe?(S=t=>{let{field:re}=t;return(0,s.jsxs)(ne,{onValueChange:e=>re.onChange(e),value:re.value??``,children:[(0,s.jsx)(te,{"aria-invalid":!!f.vpcId,className:`w-full`,id:`tg-vpc`,children:(0,s.jsx)(e,{placeholder:`Select VPC`})}),(0,s.jsx)(ee,{children:oe.map(me)})]})},n[28]=f.vpcId,n[29]=oe,n[30]=S):S=n[30];let C;n[31]!==c||n[32]!==S?(C=(0,s.jsx)(le,{control:c,name:`vpcId`,render:S}),n[31]=c,n[32]=S,n[33]=C):C=n[33];let w;n[34]===f.vpcId?w=n[35]:(w=(0,s.jsx)(a,{errors:[f.vpcId]}),n[34]=f.vpcId,n[35]=w);let T;n[36]!==C||n[37]!==w?(T=(0,s.jsxs)(o,{children:[we,C,w]}),n[36]=C,n[37]=w,n[38]=T):T=n[38];let Te;n[39]===Symbol.for(`react.memo_cache_sentinel`)?(Te=(0,s.jsx)(de,{className:`text-left text-sm font-medium text-muted-foreground hover:text-foreground`,render:(0,s.jsx)(`button`,{"aria-label":`Health check settings`,type:`button`}),children:`Health check settings`}),n[39]=Te):Te=n[39];let Ee;n[40]===Symbol.for(`react.memo_cache_sentinel`)?(Ee=(0,s.jsx)(i,{children:(0,s.jsx)(`label`,{htmlFor:`hc-path`,children:`Path`})}),n[40]=Ee):Ee=n[40];let De=!!f.healthCheck?.path,E;n[41]===l?E=n[42]:(E=l(`healthCheck.path`),n[41]=l,n[42]=E);let D;n[43]!==De||n[44]!==E?(D=(0,s.jsx)(r,{"aria-invalid":De,id:`hc-path`,placeholder:`/`,...E}),n[43]=De,n[44]=E,n[45]=D):D=n[45];let Oe=f.healthCheck?.path,O;n[46]===Oe?O=n[47]:(O=(0,s.jsx)(a,{errors:[Oe]}),n[46]=Oe,n[47]=O);let k;n[48]!==D||n[49]!==O?(k=(0,s.jsxs)(o,{children:[Ee,D,O]}),n[48]=D,n[49]=O,n[50]=k):k=n[50];let ke;n[51]===Symbol.for(`react.memo_cache_sentinel`)?(ke=(0,s.jsx)(i,{children:(0,s.jsx)(`label`,{htmlFor:`hc-port`,children:`Port`})}),n[51]=ke):ke=n[51];let Ae=!!f.healthCheck?.port,A;n[52]===l?A=n[53]:(A=l(`healthCheck.port`),n[52]=l,n[53]=A);let j;n[54]!==Ae||n[55]!==A?(j=(0,s.jsx)(r,{"aria-invalid":Ae,id:`hc-port`,placeholder:`traffic-port or numeric`,...A}),n[54]=Ae,n[55]=A,n[56]=j):j=n[56];let je=f.healthCheck?.port,M;n[57]===je?M=n[58]:(M=(0,s.jsx)(a,{errors:[je]}),n[57]=je,n[58]=M);let Me;n[59]!==j||n[60]!==M?(Me=(0,s.jsxs)(o,{children:[ke,j,M]}),n[59]=j,n[60]=M,n[61]=Me):Me=n[61];let Ne;n[62]===Symbol.for(`react.memo_cache_sentinel`)?(Ne=(0,s.jsx)(i,{children:(0,s.jsx)(`label`,{htmlFor:`hc-interval`,children:`Interval (seconds)`})}),n[62]=Ne):Ne=n[62];let Pe=!!f.healthCheck?.intervalSeconds,N;n[63]===l?N=n[64]:(N=l(`healthCheck.intervalSeconds`,{valueAsNumber:!0}),n[63]=l,n[64]=N);let P;n[65]!==Pe||n[66]!==N?(P=(0,s.jsx)(r,{"aria-invalid":Pe,id:`hc-interval`,inputMode:`numeric`,type:`number`,...N}),n[65]=Pe,n[66]=N,n[67]=P):P=n[67];let Fe=f.healthCheck?.intervalSeconds,F;n[68]===Fe?F=n[69]:(F=(0,s.jsx)(a,{errors:[Fe]}),n[68]=Fe,n[69]=F);let I;n[70]!==P||n[71]!==F?(I=(0,s.jsxs)(o,{children:[Ne,P,F]}),n[70]=P,n[71]=F,n[72]=I):I=n[72];let Ie;n[73]===Symbol.for(`react.memo_cache_sentinel`)?(Ie=(0,s.jsx)(i,{children:(0,s.jsx)(`label`,{htmlFor:`hc-timeout`,children:`Timeout (seconds)`})}),n[73]=Ie):Ie=n[73];let Le=!!f.healthCheck?.timeoutSeconds,L;n[74]===l?L=n[75]:(L=l(`healthCheck.timeoutSeconds`,{valueAsNumber:!0}),n[74]=l,n[75]=L);let R;n[76]!==Le||n[77]!==L?(R=(0,s.jsx)(r,{"aria-invalid":Le,id:`hc-timeout`,inputMode:`numeric`,type:`number`,...L}),n[76]=Le,n[77]=L,n[78]=R):R=n[78];let Re=f.healthCheck?.timeoutSeconds,z;n[79]===Re?z=n[80]:(z=(0,s.jsx)(a,{errors:[Re]}),n[79]=Re,n[80]=z);let B;n[81]!==R||n[82]!==z?(B=(0,s.jsxs)(o,{children:[Ie,R,z]}),n[81]=R,n[82]=z,n[83]=B):B=n[83];let ze;n[84]===Symbol.for(`react.memo_cache_sentinel`)?(ze=(0,s.jsx)(i,{children:(0,s.jsx)(`label`,{htmlFor:`hc-healthy`,children:`Healthy threshold`})}),n[84]=ze):ze=n[84];let Be=!!f.healthCheck?.healthyThresholdCount,V;n[85]===l?V=n[86]:(V=l(`healthCheck.healthyThresholdCount`,{valueAsNumber:!0}),n[85]=l,n[86]=V);let H;n[87]!==Be||n[88]!==V?(H=(0,s.jsx)(r,{"aria-invalid":Be,id:`hc-healthy`,inputMode:`numeric`,type:`number`,...V}),n[87]=Be,n[88]=V,n[89]=H):H=n[89];let Ve=f.healthCheck?.healthyThresholdCount,U;n[90]===Ve?U=n[91]:(U=(0,s.jsx)(a,{errors:[Ve]}),n[90]=Ve,n[91]=U);let W;n[92]!==H||n[93]!==U?(W=(0,s.jsxs)(o,{children:[ze,H,U]}),n[92]=H,n[93]=U,n[94]=W):W=n[94];let He;n[95]===Symbol.for(`react.memo_cache_sentinel`)?(He=(0,s.jsx)(i,{children:(0,s.jsx)(`label`,{htmlFor:`hc-unhealthy`,children:`Unhealthy threshold`})}),n[95]=He):He=n[95];let Ue=!!f.healthCheck?.unhealthyThresholdCount,G;n[96]===l?G=n[97]:(G=l(`healthCheck.unhealthyThresholdCount`,{valueAsNumber:!0}),n[96]=l,n[97]=G);let K;n[98]!==Ue||n[99]!==G?(K=(0,s.jsx)(r,{"aria-invalid":Ue,id:`hc-unhealthy`,inputMode:`numeric`,type:`number`,...G}),n[98]=Ue,n[99]=G,n[100]=K):K=n[100];let We=f.healthCheck?.unhealthyThresholdCount,q;n[101]===We?q=n[102]:(q=(0,s.jsx)(a,{errors:[We]}),n[101]=We,n[102]=q);let J;n[103]!==K||n[104]!==q?(J=(0,s.jsxs)(o,{children:[He,K,q]}),n[103]=K,n[104]=q,n[105]=J):J=n[105];let Ge;n[106]===Symbol.for(`react.memo_cache_sentinel`)?(Ge=(0,s.jsx)(i,{children:(0,s.jsx)(`label`,{htmlFor:`hc-matcher`,children:`Matcher (HTTP codes)`})}),n[106]=Ge):Ge=n[106];let Ke=!!f.healthCheck?.matcher,Y;n[107]===l?Y=n[108]:(Y=l(`healthCheck.matcher`),n[107]=l,n[108]=Y);let X;n[109]!==Ke||n[110]!==Y?(X=(0,s.jsx)(r,{"aria-invalid":Ke,id:`hc-matcher`,placeholder:`200 or 200-299 or 200,201`,...Y}),n[109]=Ke,n[110]=Y,n[111]=X):X=n[111];let qe=f.healthCheck?.matcher,Z;n[112]===qe?Z=n[113]:(Z=(0,s.jsx)(a,{errors:[qe]}),n[112]=qe,n[113]=Z);let Q;n[114]!==X||n[115]!==Z?(Q=(0,s.jsxs)(o,{children:[Ge,X,Z]}),n[114]=X,n[115]=Z,n[116]=Q):Q=n[116];let $;n[117]!==k||n[118]!==Me||n[119]!==I||n[120]!==B||n[121]!==W||n[122]!==J||n[123]!==Q?($=(0,s.jsxs)(fe,{children:[Te,(0,s.jsxs)(ue,{className:`mt-3 space-y-4 border-l-2 border-muted pl-4`,children:[k,Me,I,B,W,J,Q]})]}),n[117]=k,n[118]=Me,n[119]=I,n[120]=B,n[121]=W,n[122]=J,n[123]=Q,n[124]=$):$=n[124];let Je;n[125]===Symbol.for(`react.memo_cache_sentinel`)?(Je=(0,s.jsx)(i,{children:`Tags`}),n[125]=Je):Je=n[125];let Ye;if(n[126]!==d||n[127]!==l||n[128]!==u||n[129]!==ve){let e;n[131]!==d||n[132]!==l||n[133]!==u?(e=(e,t)=>(0,s.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,s.jsx)(r,{placeholder:`Key`,...l(`tags.${t}.key`)}),(0,s.jsx)(r,{placeholder:`Value`,...l(`tags.${t}.value`)}),(0,s.jsx)(se,{onClick:()=>u(`tags`,d(`tags`).filter((e,ee)=>ee!==t)),size:`icon`,type:`button`,variant:`ghost`,children:(0,s.jsx)(ie,{className:`size-3.5`})})]},t),n[131]=d,n[132]=l,n[133]=u,n[134]=e):e=n[134],Ye=ve.map(e),n[126]=d,n[127]=l,n[128]=u,n[129]=ve,n[130]=Ye}else Ye=n[130];let Xe;n[135]!==d||n[136]!==u?(Xe=()=>u(`tags`,[...d(`tags`),{key:``,value:``}]),n[135]=d,n[136]=u,n[137]=Xe):Xe=n[137];let Ze;n[138]===Symbol.for(`react.memo_cache_sentinel`)?(Ze=(0,s.jsx)(re,{className:`size-3.5`}),n[138]=Ze):Ze=n[138];let Qe;n[139]===Xe?Qe=n[140]:(Qe=(0,s.jsxs)(se,{onClick:Xe,size:`sm`,type:`button`,variant:`outline`,children:[Ze,`Add tag`]}),n[139]=Xe,n[140]=Qe);let $e;n[141]!==Ye||n[142]!==Qe?($e=(0,s.jsxs)(o,{children:[Je,(0,s.jsxs)(`div`,{className:`space-y-2`,children:[Ye,Qe]})]}),n[141]=Ye,n[142]=Qe,n[143]=$e):$e=n[143];let et;return n[144]!==_||n[145]!==x||n[146]!==T||n[147]!==$||n[148]!==$e||n[149]!==g?(et=(0,s.jsxs)(s.Fragment,{children:[g,_,x,T,$,$e]}),n[144]=_,n[145]=x,n[146]=T,n[147]=$,n[148]=$e,n[149]=g,n[150]=et):et=n[150],et}function me(e){let ee=n(e.Tags);return(0,s.jsx)(t,{value:e.VpcId??``,children:ee?`${e.VpcId} (${ee})`:`${e.VpcId} (${e.CidrBlock})`},e.VpcId)}function he(re){let{field:ie}=re;return(0,s.jsxs)(ne,{onValueChange:ie.onChange,value:ie.value,children:[(0,s.jsx)(te,{className:`w-full`,id:`tg-protocol`,children:(0,s.jsx)(e,{})}),(0,s.jsx)(ee,{children:(0,s.jsx)(t,{value:`HTTP`,children:`HTTP`})})]})}export{c as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/textarea.js b/spinifex/services/spinifexui/frontend/dist/assets/textarea.js index c43115fcb..28c7afea0 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/textarea.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/textarea.js @@ -1 +1 @@ -import{Oa as e,mo as t,so as n}from"./index.js";var r=n(),i=t();function a(t){let n=(0,r.c)(8),a,o;n[0]===t?(a=n[1],o=n[2]):({className:a,...o}=t,n[0]=t,n[1]=a,n[2]=o);let s;n[3]===a?s=n[4]:(s=e(`flex field-sizing-content min-h-16 w-full resize-none rounded-md border border-input bg-input/20 px-2 py-2 text-sm transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 md:text-xs/relaxed dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40`,a),n[3]=a,n[4]=s);let c;return n[5]!==o||n[6]!==s?(c=(0,i.jsx)(`textarea`,{className:s,"data-slot":`textarea`,...o}),n[5]=o,n[6]=s,n[7]=c):c=n[7],c}export{a as t}; \ No newline at end of file +import{Ha as e,Oo as t,xo as n}from"./index.js";var r=n(),i=t();function a(t){let n=(0,r.c)(8),a,o;n[0]===t?(a=n[1],o=n[2]):({className:a,...o}=t,n[0]=t,n[1]=a,n[2]=o);let s;n[3]===a?s=n[4]:(s=e(`flex field-sizing-content min-h-16 w-full resize-none rounded-md border border-input bg-input/20 px-2 py-2 text-sm transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 md:text-xs/relaxed dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40`,a),n[3]=a,n[4]=s);let c;return n[5]!==o||n[6]!==s?(c=(0,i.jsx)(`textarea`,{className:s,"data-slot":`textarea`,...o}),n[5]=o,n[6]=s,n[7]=c):c=n[7],c}export{a as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/trash-2.js b/spinifex/services/spinifexui/frontend/dist/assets/trash-2.js index 0274eb82d..a8f3c1fc0 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/trash-2.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/trash-2.js @@ -1 +1 @@ -import{Xa as e}from"./index.js";var t=e(`trash-2`,[[`path`,{d:`M10 11v6`,key:`nco0om`}],[`path`,{d:`M14 11v6`,key:`outv1u`}],[`path`,{d:`M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6`,key:`miytrc`}],[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`,key:`e791ji`}]]);export{t}; \ No newline at end of file +import{uo as e}from"./index.js";var t=e(`trash-2`,[[`path`,{d:`M10 11v6`,key:`nco0om`}],[`path`,{d:`M14 11v6`,key:`outv1u`}],[`path`,{d:`M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6`,key:`miytrc`}],[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`,key:`e791ji`}]]);export{t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/triangle-alert.js b/spinifex/services/spinifexui/frontend/dist/assets/triangle-alert.js index ff9f4115c..0e16b3d69 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/triangle-alert.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/triangle-alert.js @@ -1 +1 @@ -import{Xa as e}from"./index.js";var t=e(`triangle-alert`,[[`path`,{d:`m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3`,key:`wmoenq`}],[`path`,{d:`M12 9v4`,key:`juzpu7`}],[`path`,{d:`M12 17h.01`,key:`p32p05`}]]);export{t}; \ No newline at end of file +import{uo as e}from"./index.js";var t=e(`triangle-alert`,[[`path`,{d:`m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3`,key:`wmoenq`}],[`path`,{d:`M12 9v4`,key:`juzpu7`}],[`path`,{d:`M12 17h.01`,key:`p32p05`}]]);export{t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/upload-button.js b/spinifex/services/spinifexui/frontend/dist/assets/upload-button.js index da89d51fd..cce84f5eb 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/upload-button.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/upload-button.js @@ -1 +1 @@ -import{t as e}from"./error-banner.js";import{t}from"./download.js";import{t as n}from"./trash-2.js";import{a as r,i,n as a}from"./s3.js";import{Bn as o,Fn as s,In as c,Ma as l,Po as u,Qn as d,Ta as f,Xa as p,ct as m,ho as h,ja as g,lo as _,mo as v,mt as y,so as b,vt as x}from"./index.js";import{t as S}from"./delete-confirmation-dialog.js";var C=p(`file`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}]]),w=p(`folder`,[[`path`,{d:`M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z`,key:`1kt360`}]]),T=p(`upload`,[[`path`,{d:`M12 3v12`,key:`1x0j5s`}],[`path`,{d:`m17 8-5-5-5 5`,key:`7q97r8`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}]]),E=e=>(e,t)=>async n=>{let r=await e(n),{response:i}=r;if(d.isInstance(i)&&i.headers.expires){i.headers.expiresstring=i.headers.expires;try{o(i.headers.expires)}catch(e){t.logger?.warn(`AWS SDK Warning for ${t.clientName}::${t.commandName} response parsing (${i.headers.expires}): ${e}`),delete i.headers.expires}}return r},D={tags:[`S3`],name:`s3ExpiresMiddleware`,override:!0,relation:`after`,toMiddleware:`deserializerMiddleware`},O=e=>({applyToStack:t=>{t.addRelativeTo(E(e),D)}}),k=class extends s.classBuilder().ep({...x,Bucket:{type:`contextParams`,name:`Bucket`},Key:{type:`contextParams`,name:`Key`}}).m(function(e,t,n,a){return[c(n,e.getEndpointParameterInstructions()),r(n,{requestChecksumRequired:!1,requestValidationModeMember:`ChecksumMode`,responseAlgorithms:[`CRC64NVME`,`CRC32`,`CRC32C`,`SHA256`,`SHA1`,`SHA512`,`MD5`,`XXHASH64`,`XXHASH3`,`XXHASH128`]}),i(n),O(n)]}).s(`AmazonS3`,`GetObject`,{}).n(`S3Client`,`GetObjectCommand`).sc(y).build(){},A=b(),j=v();function M(e){let t=(0,A.c)(9),{folderName:n,fullPrefix:r,bucketName:i}=e,a;t[0]!==i||t[1]!==r?(a={bucket:i,_splat:r},t[0]=i,t[1]=r,t[2]=a):a=t[2];let o;t[3]===Symbol.for(`react.memo_cache_sentinel`)?(o=(0,j.jsx)(w,{className:`size-5 text-muted-foreground`}),t[3]=o):o=t[3];let s;t[4]===n?s=t[5]:(s=(0,j.jsx)(`span`,{className:`font-medium`,children:n}),t[4]=n,t[5]=s);let c;return t[6]!==a||t[7]!==s?(c=(0,j.jsxs)(_,{className:`flex items-center gap-3 rounded-lg border bg-card p-4 transition-colors hover:bg-accent`,params:a,to:`/s3/ls/$bucket/$`,children:[o,s]}),t[6]=a,t[7]=s,t[8]=c):c=t[8],c}var N=u(h(),1);function P({object:r,bucketName:i,displayName:o,fullKey:s}){let[c,u]=(0,N.useState)(!1),[d,f]=(0,N.useState)(null),p=a();async function h(){f(null);try{let e=new k({Bucket:i,Key:s}),t=await m().send(e);if(t.Body){let e=await t.Body.transformToByteArray(),n=URL.createObjectURL(new Blob([e])),r=document.createElement(`a`);r.href=n,r.download=o,document.body.append(r),r.click(),r.remove(),URL.revokeObjectURL(n)}}catch(e){f(Error(`Failed to download object`,{cause:e}))}}async function _(){try{await p.mutateAsync({bucket:i,key:s})}finally{u(!1)}}return(0,j.jsxs)(`div`,{children:[p.error&&(0,j.jsx)(e,{error:p.error,msg:`Failed to delete object`}),d&&(0,j.jsx)(e,{error:d,msg:`Failed to download object`}),(0,j.jsxs)(`div`,{className:`flex items-center justify-between rounded-lg border bg-card p-4`,children:[(0,j.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,j.jsx)(C,{className:`size-5 text-muted-foreground`}),(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`h3`,{className:`font-medium`,children:o}),r.LastModified&&(0,j.jsxs)(`p`,{className:`text-sm text-muted-foreground`,children:[`Last Modified: `,g(r.LastModified)]})]})]}),(0,j.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,j.jsx)(`div`,{className:`text-sm text-muted-foreground`,children:l(r.Size??0)}),(0,j.jsx)(`button`,{"aria-label":`Download ${o}`,className:`rounded-md p-2 transition-colors hover:bg-accent`,onClick:h,type:`button`,children:(0,j.jsx)(t,{className:`size-4`})}),(0,j.jsx)(`button`,{"aria-label":`Delete ${o}`,className:`rounded-md p-2 text-destructive transition-colors hover:bg-accent`,onClick:()=>u(!0),type:`button`,children:(0,j.jsx)(n,{className:`size-4`})})]}),(0,j.jsx)(S,{description:(0,j.jsxs)(j.Fragment,{children:[`Are you sure you want to delete `,(0,j.jsx)(`strong`,{children:o}),`? This action cannot be undone.`]}),isPending:p.isPending,onConfirm:_,onOpenChange:u,open:c,title:`Delete Object`})]})]},r.Key)}function F({bucket:e,prefix:t=``,isPending:n,onUpload:r}){let i=(0,N.useRef)(null);async function a(n){let a=n.target.files;if(!(!a||a.length===0))try{await Promise.all([...a].map(async n=>await r({bucket:e,key:`${t}${n.name}`,file:n})))}finally{i.current&&(i.current.value=``)}}return(0,j.jsxs)(j.Fragment,{children:[(0,j.jsx)(`input`,{accept:`*/*`,"aria-label":`Choose files to upload`,className:`hidden`,multiple:!0,onChange:a,ref:i,type:`file`}),(0,j.jsxs)(f,{disabled:n,onClick:()=>i.current?.click(),size:`sm`,children:[(0,j.jsx)(T,{className:`mr-2 size-4`}),n?`Uploading…`:`Upload Files`]})]})}export{P as n,M as r,F as t}; \ No newline at end of file +import{t as e}from"./error-banner.js";import{t}from"./download.js";import{t as n}from"./trash-2.js";import{a as r,i,n as a}from"./s3.js";import{Bn as o,Co as s,Ga as c,Gn as l,Jo as u,Ka as d,Oo as f,Vn as p,bt as m,fr as h,gt as g,ko as _,uo as v,ut as y,xo as b,za as x}from"./index.js";import{t as S}from"./delete-confirmation-dialog.js";var C=v(`file`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}]]),w=v(`folder`,[[`path`,{d:`M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z`,key:`1kt360`}]]),T=v(`upload`,[[`path`,{d:`M12 3v12`,key:`1x0j5s`}],[`path`,{d:`m17 8-5-5-5 5`,key:`7q97r8`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}]]),E=e=>(e,t)=>async n=>{let r=await e(n),{response:i}=r;if(h.isInstance(i)&&i.headers.expires){i.headers.expiresstring=i.headers.expires;try{l(i.headers.expires)}catch(e){t.logger?.warn(`AWS SDK Warning for ${t.clientName}::${t.commandName} response parsing (${i.headers.expires}): ${e}`),delete i.headers.expires}}return r},D={tags:[`S3`],name:`s3ExpiresMiddleware`,override:!0,relation:`after`,toMiddleware:`deserializerMiddleware`},O=e=>({applyToStack:t=>{t.addRelativeTo(E(e),D)}}),k=class extends o.classBuilder().ep({...m,Bucket:{type:`contextParams`,name:`Bucket`},Key:{type:`contextParams`,name:`Key`}}).m(function(e,t,n,a){return[p(n,e.getEndpointParameterInstructions()),r(n,{requestChecksumRequired:!1,requestValidationModeMember:`ChecksumMode`,responseAlgorithms:[`CRC64NVME`,`CRC32`,`CRC32C`,`SHA256`,`SHA1`,`SHA512`,`MD5`,`XXHASH64`,`XXHASH3`,`XXHASH128`]}),i(n),O(n)]}).s(`AmazonS3`,`GetObject`,{}).n(`S3Client`,`GetObjectCommand`).sc(g).build(){},A=b(),j=f();function M(e){let t=(0,A.c)(9),{folderName:n,fullPrefix:r,bucketName:i}=e,a;t[0]!==i||t[1]!==r?(a={bucket:i,_splat:r},t[0]=i,t[1]=r,t[2]=a):a=t[2];let o;t[3]===Symbol.for(`react.memo_cache_sentinel`)?(o=(0,j.jsx)(w,{className:`size-5 text-muted-foreground`}),t[3]=o):o=t[3];let c;t[4]===n?c=t[5]:(c=(0,j.jsx)(`span`,{className:`font-medium`,children:n}),t[4]=n,t[5]=c);let l;return t[6]!==a||t[7]!==c?(l=(0,j.jsxs)(s,{className:`flex items-center gap-3 rounded-lg border bg-card p-4 transition-colors hover:bg-accent`,params:a,to:`/s3/ls/$bucket/$`,children:[o,c]}),t[6]=a,t[7]=c,t[8]=l):l=t[8],l}var N=u(_(),1);function P({object:r,bucketName:i,displayName:o,fullKey:s}){let[l,u]=(0,N.useState)(!1),[f,p]=(0,N.useState)(null),m=a();async function h(){p(null);try{let e=new k({Bucket:i,Key:s}),t=await y().send(e);if(t.Body){let e=await t.Body.transformToByteArray(),n=URL.createObjectURL(new Blob([e])),r=document.createElement(`a`);r.href=n,r.download=o,document.body.append(r),r.click(),r.remove(),URL.revokeObjectURL(n)}}catch(e){p(Error(`Failed to download object`,{cause:e}))}}async function g(){try{await m.mutateAsync({bucket:i,key:s})}finally{u(!1)}}return(0,j.jsxs)(`div`,{children:[m.error&&(0,j.jsx)(e,{error:m.error,msg:`Failed to delete object`}),f&&(0,j.jsx)(e,{error:f,msg:`Failed to download object`}),(0,j.jsxs)(`div`,{className:`flex items-center justify-between rounded-lg border bg-card p-4`,children:[(0,j.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,j.jsx)(C,{className:`size-5 text-muted-foreground`}),(0,j.jsxs)(`div`,{children:[(0,j.jsx)(`h3`,{className:`font-medium`,children:o}),r.LastModified&&(0,j.jsxs)(`p`,{className:`text-sm text-muted-foreground`,children:[`Last Modified: `,c(r.LastModified)]})]})]}),(0,j.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,j.jsx)(`div`,{className:`text-sm text-muted-foreground`,children:d(r.Size??0)}),(0,j.jsx)(`button`,{"aria-label":`Download ${o}`,className:`rounded-md p-2 transition-colors hover:bg-accent`,onClick:h,type:`button`,children:(0,j.jsx)(t,{className:`size-4`})}),(0,j.jsx)(`button`,{"aria-label":`Delete ${o}`,className:`rounded-md p-2 text-destructive transition-colors hover:bg-accent`,onClick:()=>u(!0),type:`button`,children:(0,j.jsx)(n,{className:`size-4`})})]}),(0,j.jsx)(S,{description:(0,j.jsxs)(j.Fragment,{children:[`Are you sure you want to delete `,(0,j.jsx)(`strong`,{children:o}),`? This action cannot be undone.`]}),isPending:m.isPending,onConfirm:g,onOpenChange:u,open:l,title:`Delete Object`})]})]},r.Key)}function F({bucket:e,prefix:t=``,isPending:n,onUpload:r}){let i=(0,N.useRef)(null);async function a(n){let a=n.target.files;if(!(!a||a.length===0))try{await Promise.all([...a].map(async n=>await r({bucket:e,key:`${t}${n.name}`,file:n})))}finally{i.current&&(i.current.value=``)}}return(0,j.jsxs)(j.Fragment,{children:[(0,j.jsx)(`input`,{accept:`*/*`,"aria-label":`Choose files to upload`,className:`hidden`,multiple:!0,onChange:a,ref:i,type:`file`}),(0,j.jsxs)(x,{disabled:n,onClick:()=>i.current?.click(),size:`sm`,children:[(0,j.jsx)(T,{className:`mr-2 size-4`}),n?`Uploading…`:`Upload Files`]})]})}export{P as n,M as r,F as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/use-copy-to-clipboard.js b/spinifex/services/spinifexui/frontend/dist/assets/use-copy-to-clipboard.js index fe4b7420d..69e506873 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/use-copy-to-clipboard.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/use-copy-to-clipboard.js @@ -1 +1 @@ -import{Po as e,ho as t,so as n}from"./index.js";var r=n(),i=e(t(),1),a=2e3;function o(){let e=(0,r.c)(5),[t,n]=(0,i.useState)(!1),o=(0,i.useRef)(null),s,c;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(s=()=>()=>{o.current&&clearTimeout(o.current)},c=[],e[0]=s,e[1]=c):(s=e[0],c=e[1]),(0,i.useEffect)(s,c);let l;e[2]===Symbol.for(`react.memo_cache_sentinel`)?(l=async e=>{await navigator.clipboard.writeText(e),n(!0),o.current&&clearTimeout(o.current),o.current=setTimeout(()=>n(!1),a)},e[2]=l):l=e[2];let u=l,d;return e[3]===t?d=e[4]:(d={copied:t,copy:u},e[3]=t,e[4]=d),d}export{o as t}; \ No newline at end of file +import{Jo as e,ko as t,xo as n}from"./index.js";var r=n(),i=e(t(),1),a=2e3;function o(){let e=(0,r.c)(5),[t,n]=(0,i.useState)(!1),o=(0,i.useRef)(null),s,c;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(s=()=>()=>{o.current&&clearTimeout(o.current)},c=[],e[0]=s,e[1]=c):(s=e[0],c=e[1]),(0,i.useEffect)(s,c);let l;e[2]===Symbol.for(`react.memo_cache_sentinel`)?(l=async e=>{await navigator.clipboard.writeText(e),n(!0),o.current&&clearTimeout(o.current),o.current=setTimeout(()=>n(!1),a)},e[2]=l):l=e[2];let u=l,d;return e[3]===t?d=e[4]:(d={copied:t,copy:u},e[3]=t,e[4]=d),d}export{o as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/useBaseQuery.js b/spinifex/services/spinifexui/frontend/dist/assets/useBaseQuery.js index 619f57d49..ff5ad288b 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/useBaseQuery.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/useBaseQuery.js @@ -1 +1 @@ -import{Ao as e,Co as t,Do as n,Eo as r,Mo as i,Oo as a,Po as o,So as s,To as c,_o as l,bo as u,ho as d,jo as f,ko as p,mo as m,po as h,vo as g,wo as _,yo as v}from"./index.js";var y=class extends i{constructor(e,t){super(),this.options=t,this.#e=e,this.#s=null,this.#o=v(),this.bindMethods(),this.setOptions(t)}#e;#t=void 0;#n=void 0;#r=void 0;#i;#a;#o;#s;#c;#l;#u;#d;#f;#p;#m=new Set;bindMethods(){this.refetch=this.refetch.bind(this)}onSubscribe(){this.listeners.size===1&&(this.#t.addObserver(this),x(this.#t,this.options)?this.#h():this.updateResult(),this.#y())}onUnsubscribe(){this.hasListeners()||this.destroy()}shouldFetchOnReconnect(){return S(this.#t,this.options,this.options.refetchOnReconnect)}shouldFetchOnWindowFocus(){return S(this.#t,this.options,this.options.refetchOnWindowFocus)}destroy(){this.listeners=new Set,this.#b(),this.#x(),this.#t.removeObserver(this)}setOptions(e){let t=this.options,i=this.#t;if(this.options=this.#e.defaultQueryOptions(e),this.options.enabled!==void 0&&typeof this.options.enabled!=`boolean`&&typeof this.options.enabled!=`function`&&typeof c(this.options.enabled,this.#t)!=`boolean`)throw Error(`Expected enabled to be a boolean or a callback that returns a boolean`);this.#S(),this.#t.setOptions(this.options),t._defaulted&&!n(this.options,t)&&this.#e.getQueryCache().notify({type:`observerOptionsUpdated`,query:this.#t,observer:this});let a=this.hasListeners();a&&C(this.#t,i,this.options,t)&&this.#h(),this.updateResult(),a&&(this.#t!==i||c(this.options.enabled,this.#t)!==c(t.enabled,this.#t)||r(this.options.staleTime,this.#t)!==r(t.staleTime,this.#t))&&this.#g();let o=this.#_();a&&(this.#t!==i||c(this.options.enabled,this.#t)!==c(t.enabled,this.#t)||o!==this.#p)&&this.#v(o)}getOptimisticResult(e){let t=this.#e.getQueryCache().build(this.#e,e),n=this.createResult(t,e);return T(this,n)&&(this.#r=n,this.#a=this.options,this.#i=this.#t.state),n}getCurrentResult(){return this.#r}trackResult(e,t){return new Proxy(e,{get:(e,n)=>(this.trackProp(n),t?.(n),n===`promise`&&(this.trackProp(`data`),!this.options.experimental_prefetchInRender&&this.#o.status===`pending`&&this.#o.reject(Error(`experimental_prefetchInRender feature flag is not enabled`))),Reflect.get(e,n))})}trackProp(e){this.#m.add(e)}getCurrentQuery(){return this.#t}refetch({...e}={}){return this.fetch({...e})}fetchOptimistic(e){let t=this.#e.defaultQueryOptions(e),n=this.#e.getQueryCache().build(this.#e,t);return n.fetch().then(()=>this.createResult(n,t))}fetch(e){return this.#h({...e,cancelRefetch:e.cancelRefetch??!0}).then(()=>(this.updateResult(),this.#r))}#h(e){this.#S();let n=this.#t.fetch(this.options,e);return e?.throwOnError||(n=n.catch(t)),n}#g(){this.#b();let t=r(this.options.staleTime,this.#t);if(u.isServer()||this.#r.isStale||!s(t))return;let n=p(this.#r.dataUpdatedAt,t)+1;this.#d=e.setTimeout(()=>{this.#r.isStale||this.updateResult()},n)}#_(){return(typeof this.options.refetchInterval==`function`?this.options.refetchInterval(this.#t):this.options.refetchInterval)??!1}#v(t){this.#x(),this.#p=t,!(u.isServer()||c(this.options.enabled,this.#t)===!1||!s(this.#p)||this.#p===0)&&(this.#f=e.setInterval(()=>{(this.options.refetchIntervalInBackground||f.isFocused())&&this.#h()},this.#p))}#y(){this.#g(),this.#v(this.#_())}#b(){this.#d!==void 0&&(e.clearTimeout(this.#d),this.#d=void 0)}#x(){this.#f!==void 0&&(e.clearInterval(this.#f),this.#f=void 0)}createResult(e,t){let n=this.#t,r=this.options,i=this.#r,a=this.#i,o=this.#a,s=e===n?this.#n:e.state,{state:u}=e,d={...u},f=!1,p;if(t._optimisticResults){let i=this.hasListeners(),a=!i&&x(e,t),o=i&&C(e,n,t,r);(a||o)&&(d={...d,...l(u.data,e.options)}),t._optimisticResults===`isRestoring`&&(d.fetchStatus=`idle`)}let{error:m,errorUpdatedAt:h,status:g}=d;p=d.data;let y=!1;if(t.placeholderData!==void 0&&p===void 0&&g===`pending`){let e;i?.isPlaceholderData&&t.placeholderData===o?.placeholderData?(e=i.data,y=!0):e=typeof t.placeholderData==`function`?t.placeholderData(this.#u?.state.data,this.#u):t.placeholderData,e!==void 0&&(g=`success`,p=_(i?.data,e,t),f=!0)}if(t.select&&p!==void 0&&!y)if(i&&p===a?.data&&t.select===this.#c)p=this.#l;else try{this.#c=t.select,p=t.select(p),p=_(i?.data,p,t),this.#l=p,this.#s=null}catch(e){this.#s=e}this.#s&&(m=this.#s,p=this.#l,h=Date.now(),g=`error`);let b=d.fetchStatus===`fetching`,S=g===`pending`,T=g===`error`,E=S&&b,D=p!==void 0,O={status:g,fetchStatus:d.fetchStatus,isPending:S,isSuccess:g===`success`,isError:T,isInitialLoading:E,isLoading:E,data:p,dataUpdatedAt:d.dataUpdatedAt,error:m,errorUpdatedAt:h,failureCount:d.fetchFailureCount,failureReason:d.fetchFailureReason,errorUpdateCount:d.errorUpdateCount,isFetched:e.isFetched(),isFetchedAfterMount:d.dataUpdateCount>s.dataUpdateCount||d.errorUpdateCount>s.errorUpdateCount,isFetching:b,isRefetching:b&&!S,isLoadingError:T&&!D,isPaused:d.fetchStatus===`paused`,isPlaceholderData:f,isRefetchError:T&&D,isStale:w(e,t),refetch:this.refetch,promise:this.#o,isEnabled:c(t.enabled,e)!==!1};if(this.options.experimental_prefetchInRender){let t=O.data!==void 0,r=O.status===`error`&&!t,i=e=>{r?e.reject(O.error):t&&e.resolve(O.data)},a=()=>{i(this.#o=O.promise=v())},o=this.#o;switch(o.status){case`pending`:e.queryHash===n.queryHash&&i(o);break;case`fulfilled`:(r||O.data!==o.value)&&a();break;case`rejected`:(!r||O.error!==o.reason)&&a();break}}return O}updateResult(){let e=this.#r,t=this.createResult(this.#t,this.options);this.#i=this.#t.state,this.#a=this.options,this.#i.data!==void 0&&(this.#u=this.#t),!n(t,e)&&(this.#r=t,this.#C({listeners:(()=>{if(!e)return!0;let{notifyOnChangeProps:t}=this.options,n=typeof t==`function`?t():t;if(n===`all`||!n&&!this.#m.size)return!0;let r=new Set(n??this.#m);return this.options.throwOnError&&r.add(`error`),Object.keys(this.#r).some(t=>{let n=t;return this.#r[n]!==e[n]&&r.has(n)})})()}))}#S(){let e=this.#e.getQueryCache().build(this.#e,this.options);if(e===this.#t)return;let t=this.#t;this.#t=e,this.#n=e.state,this.hasListeners()&&(t?.removeObserver(this),e.addObserver(this))}onQueryUpdate(){this.updateResult(),this.hasListeners()&&this.#y()}#C(e){g.batch(()=>{e.listeners&&this.listeners.forEach(e=>{e(this.#r)}),this.#e.getQueryCache().notify({query:this.#t,type:`observerResultsUpdated`})})}};function b(e,t){return c(t.enabled,e)!==!1&&e.state.data===void 0&&!(e.state.status===`error`&&c(t.retryOnMount,e)===!1)}function x(e,t){return b(e,t)||e.state.data!==void 0&&S(e,t,t.refetchOnMount)}function S(e,t,n){if(c(t.enabled,e)!==!1&&r(t.staleTime,e)!==`static`){let r=typeof n==`function`?n(e):n;return r===`always`||r!==!1&&w(e,t)}return!1}function C(e,t,n,r){return(e!==t||c(r.enabled,e)===!1)&&(!n.suspense||e.state.status!==`error`)&&w(e,n)}function w(e,t){return c(t.enabled,e)!==!1&&e.isStaleByTime(r(t.staleTime,e))}function T(e,t){return!n(e.getCurrentResult(),t)}m();var E=o(d(),1),D=E.createContext(!1),O=()=>E.useContext(D);D.Provider;function k(){let e=!1;return{clearReset:()=>{e=!1},reset:()=>{e=!0},isReset:()=>e}}var A=E.createContext(k()),j=()=>E.useContext(A),M=(e,t,n)=>{let r=n?.state.error&&typeof e.throwOnError==`function`?a(e.throwOnError,[n.state.error,n]):e.throwOnError;(e.suspense||e.experimental_prefetchInRender||r)&&(t.isReset()||(e.retryOnMount=!1))},N=e=>{E.useEffect(()=>{e.clearReset()},[e])},P=({result:e,errorResetBoundary:t,throwOnError:n,query:r,suspense:i})=>e.isError&&!t.isReset()&&!e.isFetching&&r&&(i&&e.data===void 0||a(n,[e.error,r])),F=(e,t)=>t.state.data===void 0,I=e=>{if(e.suspense){let t=1e3,n=e=>e===`static`?e:Math.max(e??t,t),r=e.staleTime;e.staleTime=typeof r==`function`?(...e)=>n(r(...e)):n(r),typeof e.gcTime==`number`&&(e.gcTime=Math.max(e.gcTime,t))}},L=(e,t)=>e.isLoading&&e.isFetching&&!t,R=(e,t)=>e?.suspense&&t.isPending,z=(e,t,n)=>t.fetchOptimistic(e).catch(()=>{n.clearReset()});function B(e,n,r){let i=O(),a=j(),o=h(r),s=o.defaultQueryOptions(e);o.getDefaultOptions().queries?._experimental_beforeQuery?.(s);let c=o.getQueryCache().get(s.queryHash);s._optimisticResults=i?`isRestoring`:`optimistic`,I(s),M(s,a,c),N(a);let l=!o.getQueryCache().get(s.queryHash),[d]=E.useState(()=>new n(o,s)),f=d.getOptimisticResult(s),p=!i&&e.subscribed!==!1;if(E.useSyncExternalStore(E.useCallback(e=>{let n=p?d.subscribe(g.batchCalls(e)):t;return d.updateResult(),n},[d,p]),()=>d.getCurrentResult(),()=>d.getCurrentResult()),E.useEffect(()=>{d.setOptions(s)},[s,d]),R(s,f))throw z(s,d,a);if(P({result:f,errorResetBoundary:a,throwOnError:s.throwOnError,query:c,suspense:s.suspense}))throw f.error;return o.getDefaultOptions().queries?._experimental_afterQuery?.(s,f),s.experimental_prefetchInRender&&!u.isServer()&&L(f,i)&&(l?z(s,d,a):c?.promise)?.catch(t).finally(()=>{d.updateResult()}),s.notifyOnChangeProps?f:d.trackResult(f)}export{F as n,y as r,B as t}; \ No newline at end of file +import{Bo as e,Do as t,Go as n,Ho as r,Io as i,Jo as a,Ko as o,Lo as s,Mo as c,No as l,Oo as u,Po as d,Ro as f,Uo as p,Vo as m,Wo as h,jo as g,ko as _,zo as v}from"./index.js";var y=class extends o{constructor(e,t){super(),this.options=t,this.#e=e,this.#s=null,this.#o=l(),this.bindMethods(),this.setOptions(t)}#e;#t=void 0;#n=void 0;#r=void 0;#i;#a;#o;#s;#c;#l;#u;#d;#f;#p;#m=new Set;bindMethods(){this.refetch=this.refetch.bind(this)}onSubscribe(){this.listeners.size===1&&(this.#t.addObserver(this),x(this.#t,this.options)?this.#h():this.updateResult(),this.#y())}onUnsubscribe(){this.hasListeners()||this.destroy()}shouldFetchOnReconnect(){return S(this.#t,this.options,this.options.refetchOnReconnect)}shouldFetchOnWindowFocus(){return S(this.#t,this.options,this.options.refetchOnWindowFocus)}destroy(){this.listeners=new Set,this.#b(),this.#x(),this.#t.removeObserver(this)}setOptions(t){let n=this.options,r=this.#t;if(this.options=this.#e.defaultQueryOptions(t),this.options.enabled!==void 0&&typeof this.options.enabled!=`boolean`&&typeof this.options.enabled!=`function`&&typeof v(this.options.enabled,this.#t)!=`boolean`)throw Error(`Expected enabled to be a boolean or a callback that returns a boolean`);this.#S(),this.#t.setOptions(this.options),n._defaulted&&!m(this.options,n)&&this.#e.getQueryCache().notify({type:`observerOptionsUpdated`,query:this.#t,observer:this});let i=this.hasListeners();i&&C(this.#t,r,this.options,n)&&this.#h(),this.updateResult(),i&&(this.#t!==r||v(this.options.enabled,this.#t)!==v(n.enabled,this.#t)||e(this.options.staleTime,this.#t)!==e(n.staleTime,this.#t))&&this.#g();let a=this.#_();i&&(this.#t!==r||v(this.options.enabled,this.#t)!==v(n.enabled,this.#t)||a!==this.#p)&&this.#v(a)}getOptimisticResult(e){let t=this.#e.getQueryCache().build(this.#e,e),n=this.createResult(t,e);return T(this,n)&&(this.#r=n,this.#a=this.options,this.#i=this.#t.state),n}getCurrentResult(){return this.#r}trackResult(e,t){return new Proxy(e,{get:(e,n)=>(this.trackProp(n),t?.(n),n===`promise`&&(this.trackProp(`data`),!this.options.experimental_prefetchInRender&&this.#o.status===`pending`&&this.#o.reject(Error(`experimental_prefetchInRender feature flag is not enabled`))),Reflect.get(e,n))})}trackProp(e){this.#m.add(e)}getCurrentQuery(){return this.#t}refetch({...e}={}){return this.fetch({...e})}fetchOptimistic(e){let t=this.#e.defaultQueryOptions(e),n=this.#e.getQueryCache().build(this.#e,t);return n.fetch().then(()=>this.createResult(n,t))}fetch(e){return this.#h({...e,cancelRefetch:e.cancelRefetch??!0}).then(()=>(this.updateResult(),this.#r))}#h(e){this.#S();let t=this.#t.fetch(this.options,e);return e?.throwOnError||(t=t.catch(s)),t}#g(){this.#b();let t=e(this.options.staleTime,this.#t);if(d.isServer()||this.#r.isStale||!i(t))return;let n=p(this.#r.dataUpdatedAt,t)+1;this.#d=h.setTimeout(()=>{this.#r.isStale||this.updateResult()},n)}#_(){return(typeof this.options.refetchInterval==`function`?this.options.refetchInterval(this.#t):this.options.refetchInterval)??!1}#v(e){this.#x(),this.#p=e,!(d.isServer()||v(this.options.enabled,this.#t)===!1||!i(this.#p)||this.#p===0)&&(this.#f=h.setInterval(()=>{(this.options.refetchIntervalInBackground||n.isFocused())&&this.#h()},this.#p))}#y(){this.#g(),this.#v(this.#_())}#b(){this.#d!==void 0&&(h.clearTimeout(this.#d),this.#d=void 0)}#x(){this.#f!==void 0&&(h.clearInterval(this.#f),this.#f=void 0)}createResult(e,t){let n=this.#t,r=this.options,i=this.#r,a=this.#i,o=this.#a,s=e===n?this.#n:e.state,{state:c}=e,u={...c},d=!1,p;if(t._optimisticResults){let i=this.hasListeners(),a=!i&&x(e,t),o=i&&C(e,n,t,r);(a||o)&&(u={...u,...g(c.data,e.options)}),t._optimisticResults===`isRestoring`&&(u.fetchStatus=`idle`)}let{error:m,errorUpdatedAt:h,status:_}=u;p=u.data;let y=!1;if(t.placeholderData!==void 0&&p===void 0&&_===`pending`){let e;i?.isPlaceholderData&&t.placeholderData===o?.placeholderData?(e=i.data,y=!0):e=typeof t.placeholderData==`function`?t.placeholderData(this.#u?.state.data,this.#u):t.placeholderData,e!==void 0&&(_=`success`,p=f(i?.data,e,t),d=!0)}if(t.select&&p!==void 0&&!y)if(i&&p===a?.data&&t.select===this.#c)p=this.#l;else try{this.#c=t.select,p=t.select(p),p=f(i?.data,p,t),this.#l=p,this.#s=null}catch(e){this.#s=e}this.#s&&(m=this.#s,p=this.#l,h=Date.now(),_=`error`);let b=u.fetchStatus===`fetching`,S=_===`pending`,T=_===`error`,E=S&&b,D=p!==void 0,O={status:_,fetchStatus:u.fetchStatus,isPending:S,isSuccess:_===`success`,isError:T,isInitialLoading:E,isLoading:E,data:p,dataUpdatedAt:u.dataUpdatedAt,error:m,errorUpdatedAt:h,failureCount:u.fetchFailureCount,failureReason:u.fetchFailureReason,errorUpdateCount:u.errorUpdateCount,isFetched:e.isFetched(),isFetchedAfterMount:u.dataUpdateCount>s.dataUpdateCount||u.errorUpdateCount>s.errorUpdateCount,isFetching:b,isRefetching:b&&!S,isLoadingError:T&&!D,isPaused:u.fetchStatus===`paused`,isPlaceholderData:d,isRefetchError:T&&D,isStale:w(e,t),refetch:this.refetch,promise:this.#o,isEnabled:v(t.enabled,e)!==!1};if(this.options.experimental_prefetchInRender){let t=O.data!==void 0,r=O.status===`error`&&!t,i=e=>{r?e.reject(O.error):t&&e.resolve(O.data)},a=()=>{i(this.#o=O.promise=l())},o=this.#o;switch(o.status){case`pending`:e.queryHash===n.queryHash&&i(o);break;case`fulfilled`:(r||O.data!==o.value)&&a();break;case`rejected`:(!r||O.error!==o.reason)&&a();break}}return O}updateResult(){let e=this.#r,t=this.createResult(this.#t,this.options);this.#i=this.#t.state,this.#a=this.options,this.#i.data!==void 0&&(this.#u=this.#t),!m(t,e)&&(this.#r=t,this.#C({listeners:(()=>{if(!e)return!0;let{notifyOnChangeProps:t}=this.options,n=typeof t==`function`?t():t;if(n===`all`||!n&&!this.#m.size)return!0;let r=new Set(n??this.#m);return this.options.throwOnError&&r.add(`error`),Object.keys(this.#r).some(t=>{let n=t;return this.#r[n]!==e[n]&&r.has(n)})})()}))}#S(){let e=this.#e.getQueryCache().build(this.#e,this.options);if(e===this.#t)return;let t=this.#t;this.#t=e,this.#n=e.state,this.hasListeners()&&(t?.removeObserver(this),e.addObserver(this))}onQueryUpdate(){this.updateResult(),this.hasListeners()&&this.#y()}#C(e){c.batch(()=>{e.listeners&&this.listeners.forEach(e=>{e(this.#r)}),this.#e.getQueryCache().notify({query:this.#t,type:`observerResultsUpdated`})})}};function b(e,t){return v(t.enabled,e)!==!1&&e.state.data===void 0&&!(e.state.status===`error`&&v(t.retryOnMount,e)===!1)}function x(e,t){return b(e,t)||e.state.data!==void 0&&S(e,t,t.refetchOnMount)}function S(t,n,r){if(v(n.enabled,t)!==!1&&e(n.staleTime,t)!==`static`){let e=typeof r==`function`?r(t):r;return e===`always`||e!==!1&&w(t,n)}return!1}function C(e,t,n,r){return(e!==t||v(r.enabled,e)===!1)&&(!n.suspense||e.state.status!==`error`)&&w(e,n)}function w(t,n){return v(n.enabled,t)!==!1&&t.isStaleByTime(e(n.staleTime,t))}function T(e,t){return!m(e.getCurrentResult(),t)}u();var E=a(_(),1),D=E.createContext(!1),O=()=>E.useContext(D);D.Provider;function k(){let e=!1;return{clearReset:()=>{e=!1},reset:()=>{e=!0},isReset:()=>e}}var A=E.createContext(k()),j=()=>E.useContext(A),M=(e,t,n)=>{let i=n?.state.error&&typeof e.throwOnError==`function`?r(e.throwOnError,[n.state.error,n]):e.throwOnError;(e.suspense||e.experimental_prefetchInRender||i)&&(t.isReset()||(e.retryOnMount=!1))},N=e=>{E.useEffect(()=>{e.clearReset()},[e])},P=({result:e,errorResetBoundary:t,throwOnError:n,query:i,suspense:a})=>e.isError&&!t.isReset()&&!e.isFetching&&i&&(a&&e.data===void 0||r(n,[e.error,i])),F=(e,t)=>t.state.data===void 0,I=e=>{if(e.suspense){let t=1e3,n=e=>e===`static`?e:Math.max(e??t,t),r=e.staleTime;e.staleTime=typeof r==`function`?(...e)=>n(r(...e)):n(r),typeof e.gcTime==`number`&&(e.gcTime=Math.max(e.gcTime,t))}},L=(e,t)=>e.isLoading&&e.isFetching&&!t,R=(e,t)=>e?.suspense&&t.isPending,z=(e,t,n)=>t.fetchOptimistic(e).catch(()=>{n.clearReset()});function B(e,n,r){let i=O(),a=j(),o=t(r),l=o.defaultQueryOptions(e);o.getDefaultOptions().queries?._experimental_beforeQuery?.(l);let u=o.getQueryCache().get(l.queryHash);l._optimisticResults=i?`isRestoring`:`optimistic`,I(l),M(l,a,u),N(a);let f=!o.getQueryCache().get(l.queryHash),[p]=E.useState(()=>new n(o,l)),m=p.getOptimisticResult(l),h=!i&&e.subscribed!==!1;if(E.useSyncExternalStore(E.useCallback(e=>{let t=h?p.subscribe(c.batchCalls(e)):s;return p.updateResult(),t},[p,h]),()=>p.getCurrentResult(),()=>p.getCurrentResult()),E.useEffect(()=>{p.setOptions(l)},[l,p]),R(l,m))throw z(l,p,a);if(P({result:m,errorResetBoundary:a,throwOnError:l.throwOnError,query:u,suspense:l.suspense}))throw m.error;return o.getDefaultOptions().queries?._experimental_afterQuery?.(l,m),l.experimental_prefetchInRender&&!d.isServer()&&L(m,i)&&(f?z(l,p,a):u?.promise)?.catch(s).finally(()=>{p.updateResult()}),l.notifyOnChangeProps?m:p.trackResult(m)}export{F as n,y as r,B as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/dist/assets/zod.js b/spinifex/services/spinifexui/frontend/dist/assets/zod.js index af7235b9c..dde481fe7 100644 --- a/spinifex/services/spinifexui/frontend/dist/assets/zod.js +++ b/spinifex/services/spinifexui/frontend/dist/assets/zod.js @@ -1 +1 @@ -import{Po as e,br as t,ho as n,xr as r,yr as i}from"./index.js";var a=e(n(),1),o=e=>e.type===`checkbox`,s=e=>e instanceof Date,c=e=>e==null,l=e=>typeof e==`object`,u=e=>!c(e)&&!Array.isArray(e)&&l(e)&&!s(e),d=e=>u(e)&&e.target?o(e.target)?e.target.checked:e.target.value:e,f=(e,t)=>{let n=t.split(`.`),r=[],i=n[0];for(let t=1;t{let t=e.constructor&&e.constructor.prototype;return u(t)&&t.hasOwnProperty(`isPrototypeOf`)},m=typeof window<`u`&&window.HTMLElement!==void 0&&typeof document<`u`;function h(e){if(e instanceof Date)return new Date(e);let t=typeof FileList<`u`&&e instanceof FileList;if(m&&(e instanceof Blob||t))return e;let n=Array.isArray(e);if(!n&&!(u(e)&&p(e)))return e;let r=n?[]:Object.create(Object.getPrototypeOf(e));for(let t in e)Object.prototype.hasOwnProperty.call(e,t)&&(r[t]=h(e[t]));return r}var g=e=>/^\w*$/.test(e),_=e=>e===void 0,v=e=>Array.isArray(e)?e.filter(Boolean):[],y=e=>v(e.replace(/["|']|\]/g,``).split(/\.|\[/)),b=(e,t,n)=>{if(!t||!u(e))return n;let r=(g(t)?[t]:y(t)).reduce((e,t)=>c(e)?void 0:e[t],e);return _(r)||r===e?_(e[t])?n:e[t]:r},x=e=>typeof e==`boolean`,S=e=>typeof e==`function`,C=(e,t,n)=>{let r=-1,i=g(t)?[t]:y(t),a=i.length,o=a-1;for(;++ra.useContext(k),j=(e,t,n,r=!0)=>{let i={};for(let a in e)Object.defineProperty(i,a,{get:()=>{let i=a;return t._proxyFormState[i]!==T.all&&(t._proxyFormState[i]=!r||T.all),n&&(n[i]=!0),e[i]}});return i},M=typeof window<`u`?a.useLayoutEffect:a.useEffect;function N(e){let t=A(),{control:n=t,disabled:r,name:i,exact:o}=e||{},[s,c]=a.useState(()=>({...n._formState,defaultValues:n._defaultValues})),l=a.useRef({isDirty:!1,isLoading:!1,dirtyFields:!1,touchedFields:!1,validatingFields:!1,isValidating:!1,isValid:!1,errors:!1});return M(()=>n._subscribe({name:i,formState:l.current,exact:o,callback:e=>{!r&&c({...n._formState,...e,defaultValues:n._defaultValues})}}),[i,r,o]),a.useEffect(()=>{l.current.isValid&&n._setValid(!0)},[n]),a.useMemo(()=>j(s,n,l.current,!1),[s,n])}var P=e=>typeof e==`string`,F=(e,t,n,r,i)=>P(e)?(r&&t.watch.add(e),b(n,e,i)):Array.isArray(e)?e.map(e=>(r&&t.watch.add(e),b(n,e))):(r&&(t.watchAll=!0),n),I=e=>c(e)||!l(e);function L(e,t,n=new WeakSet){if(e===t)return!0;if(I(e)||I(t))return Object.is(e,t);if(s(e)&&s(t))return Object.is(e.getTime(),t.getTime());let r=Object.keys(e),i=Object.keys(t);if(r.length!==i.length)return!1;if(n.has(e)||n.has(t))return!0;n.add(e),n.add(t);for(let i of r){let r=e[i];if(!(i in t))return!1;if(i!==`ref`){let e=t[i];if(s(r)&&s(e)||(u(r)||Array.isArray(r))&&(u(e)||Array.isArray(e))?!L(r,e,n):!Object.is(r,e))return!1}}return!0}function ee(e){let t=A(),{control:n=t,name:r,defaultValue:i,disabled:o,exact:s,compute:c}=e||{},l=a.useRef(i),u=a.useRef(c),d=a.useRef(void 0),f=a.useRef(n),p=a.useRef(r);u.current=c;let[m,h]=a.useState(()=>{let e=n._getWatch(r,l.current);return u.current?u.current(e):e}),g=a.useCallback(e=>{let t=F(r,n._names,e||n._formValues,!1,l.current);return u.current?u.current(t):t},[n._formValues,n._names,r]),_=a.useCallback(e=>{if(!o){let t=F(r,n._names,e||n._formValues,!1,l.current);if(u.current){let e=u.current(t);L(e,d.current)||(h(e),d.current=e)}else h(t)}},[n._formValues,n._names,o,r]);M(()=>((f.current!==n||!L(p.current,r))&&(f.current=n,p.current=r,_()),n._subscribe({name:r,formState:{values:!0},exact:s,callback:e=>{_(e.values)}})),[n,s,r,_]),a.useEffect(()=>n._removeUnmounted());let v=f.current!==n,y=p.current,b=a.useMemo(()=>{if(o)return null;let e=!v&&!L(y,r);return v||e?g():null},[o,v,r,y,g]);return b===null?m:b}function te(e){let t=A(),{name:n,disabled:r,control:i=t,shouldUnregister:o,defaultValue:s,exact:c=!0}=e,l=!!f(i._names.array,n).length,u=ee({control:i,name:n,defaultValue:a.useMemo(()=>b(i._formValues,n,b(i._defaultValues,n,s)),[i,n,s]),exact:c}),p=N({control:i,name:n,exact:c}),m=a.useRef(e),g=a.useRef(i.register(n,{...e.rules,value:u,...x(e.disabled)?{disabled:e.disabled}:{}}));m.current=e;let v=a.useMemo(()=>Object.defineProperties({},{invalid:{enumerable:!0,get:()=>!!b(p.errors,n)},isDirty:{enumerable:!0,get:()=>!!b(p.dirtyFields,n)},isTouched:{enumerable:!0,get:()=>!!b(p.touchedFields,n)},isValidating:{enumerable:!0,get:()=>!!b(p.validatingFields,n)},error:{enumerable:!0,get:()=>b(p.errors,n)}}),[p,n]),y=a.useCallback(e=>g.current.onChange({target:{value:d(e),name:n},type:w.CHANGE}),[n]),T=a.useCallback(()=>g.current.onBlur({target:{value:b(i._formValues,n),name:n},type:w.BLUR}),[n,i._formValues]),E=a.useCallback(e=>{let t=b(i._fields,n);t&&t._f&&e&&(t._f.ref={focus:()=>S(e.focus)&&e.focus(),select:()=>S(e.select)&&e.select(),setCustomValidity:t=>S(e.setCustomValidity)&&e.setCustomValidity(t),reportValidity:()=>S(e.reportValidity)&&e.reportValidity()})},[i._fields,n]),D=a.useMemo(()=>({name:n,value:u,...x(r)||p.disabled?{disabled:p.disabled||r}:{},onChange:y,onBlur:T,ref:E}),[n,r,p.disabled,y,T,E,u]);return a.useEffect(()=>{let e=i._options.shouldUnregister||o;i.register(n,{...m.current.rules,...x(m.current.disabled)?{disabled:m.current.disabled}:{}});let t=(e,t)=>{let n=b(i._fields,e);n&&n._f&&(n._f.mount=t)};if(t(n,!0),e){let e=h(b(i._defaultValues,n,b(i._options.defaultValues,n,m.current.defaultValue)));C(i._defaultValues,n,e),_(b(i._formValues,n))&&C(i._formValues,n,e)}return!l&&i.register(n),()=>{(l?e&&!i._state.action:e)?i.unregister(n):t(n,!1)}},[n,i,l,o]),a.useEffect(()=>{i._setDisabledField({disabled:r,name:n})},[r,n,i]),a.useMemo(()=>({field:D,formState:p,fieldState:v}),[D,p,v])}var R=e=>e.render(te(e)),z=a.createContext(null);z.displayName=`HookFormContext`;var ne=(e,t,n,r,i)=>t?{...n[e],types:{...n[e]&&n[e].types?n[e].types:{},[r]:i||!0}}:{},B=e=>Array.isArray(e)?e:[e],re=()=>{let e=[];return{get observers(){return e},next:t=>{for(let n of e)n.next&&n.next(t)},subscribe:t=>(e.push(t),{unsubscribe:()=>{e=e.filter(e=>e!==t)}}),unsubscribe:()=>{e=[]}}};function ie(e,t){let n={};for(let r in e)if(e.hasOwnProperty(r)){let i=e[r],a=t[r];if(i&&u(i)&&a){let e=ie(i,a);u(e)&&(n[r]=e)}else e[r]&&(n[r]=a)}return n}var V=e=>u(e)&&!Object.keys(e).length,ae=e=>e.type===`file`,oe=e=>{if(!m)return!1;let t=e?e.ownerDocument:0;return e instanceof(t&&t.defaultView?t.defaultView.HTMLElement:HTMLElement)},se=e=>e.type===`select-multiple`,ce=e=>e.type===`radio`,le=e=>ce(e)||o(e),ue=e=>oe(e)&&e.isConnected;function de(e,t){let n=t.slice(0,-1).length,r=0;for(;r{for(let t in e)if(S(e[t]))return!0;return!1};function me(e){return Array.isArray(e)||u(e)&&!pe(e)}function he(e,t={}){for(let n in e){let r=e[n];me(r)?(t[n]=Array.isArray(r)?[]:{},he(r,t[n])):_(r)||(t[n]=!0)}return t}function ge(e){if(e!==!1){if(e===!0)return!0;if(Array.isArray(e)){let t=e.map(e=>ge(e));return t.some(e=>e!==void 0)?t:void 0}if(u(e)){let t={};for(let n in e){let r=ge(e[n]);_(r)||(t[n]=r)}return Object.keys(t).length?t:void 0}}}function U(e,t,n){n||=he(t);for(let r in e){let i=e[r];if(me(i))_(t)||I(n[r])?n[r]=he(i,Array.isArray(i)?[]:{}):U(i,c(t)?{}:t[r],n[r]);else{let e=t[r];n[r]=!L(i,e)}}return ge(n)||{}}var W={value:!1,isValid:!1},_e={value:!0,isValid:!0},ve=e=>{if(Array.isArray(e)){if(e.length>1){let t=e.filter(e=>e&&e.checked&&!e.disabled).map(e=>e.value);return{value:t,isValid:!!t.length}}return e[0].checked&&!e[0].disabled?e[0].attributes&&!_(e[0].attributes.value)?_(e[0].value)||e[0].value===``?_e:{value:e[0].value,isValid:!0}:_e:W}return W},ye=(e,{valueAsNumber:t,valueAsDate:n,setValueAs:r})=>_(e)?e:t?e===``?NaN:e&&+e:n&&P(e)?new Date(e):r?r(e):e,G={isValid:!1,value:null},be=e=>Array.isArray(e)?e.reduce((e,t)=>t&&t.checked&&!t.disabled?{isValid:!0,value:t.value}:e,G):G;function xe(e){let t=e.ref;return ae(t)?t.files:ce(t)?be(e.refs).value:se(t)?[...t.selectedOptions].map(({value:e})=>e):o(t)?ve(e.refs).value:ye(_(t.value)?e.ref.value:t.value,e)}var Se=(e,t,n,r)=>{let i={};for(let n of e){let e=b(t,n);e&&C(i,n,e._f)}return{criteriaMode:n,names:[...e],fields:i,shouldUseNativeValidation:r}},K=e=>e instanceof RegExp,Ce=e=>_(e)?e:K(e)?e.source:u(e)?K(e.value)?e.value.source:e.value:e,q=e=>({isOnSubmit:!e||e===T.onSubmit,isOnBlur:e===T.onBlur,isOnChange:e===T.onChange,isOnAll:e===T.all,isOnTouch:e===T.onTouched}),we=`AsyncFunction`,Te=e=>!!e&&!!e.validate&&!!(S(e.validate)&&e.validate.constructor.name===we||u(e.validate)&&Object.values(e.validate).find(e=>e.constructor.name===we)),Ee=e=>e.mount&&(e.required||e.min||e.max||e.maxLength||e.minLength||e.pattern||e.validate),De=(e,t,n)=>!n&&(t.watchAll||t.watch.has(e)||[...t.watch].some(t=>e.startsWith(t)&&/^\.\w+/.test(e.slice(t.length)))),J=(e,t,n,r)=>{for(let i of n||Object.keys(e)){let n=b(e,i);if(n){let{_f:e,...a}=n;if(e){if(e.refs&&e.refs[0]&&t(e.refs[0],i)&&!r||e.ref&&t(e.ref,e.name)&&!r)return!0;if(J(a,t))break}else if(u(a)&&J(a,t))break}}};function Oe(e,t,n){let r=b(e,n);if(r||g(n))return{error:r,name:n};let i=n.split(`.`);for(;i.length;){let r=i.join(`.`),a=b(t,r),o=b(e,r);if(a&&!Array.isArray(a)&&n!==r)return{name:n};if(o&&o.type)return{name:r,error:o};if(o&&o.root&&o.root.type)return{name:`${r}.root`,error:o.root};i.pop()}return{name:n}}var ke=(e,t,n,r)=>{n(e);let{name:i,...a}=e;return V(a)||r&&Object.keys(a).length>=Object.keys(t).length||Object.keys(a).find(e=>t[e]===(!r||T.all))},Ae=(e,t,n)=>!e||!t||e===t||B(e).some(e=>e&&(n?e===t:e.startsWith(t)||t.startsWith(e))),je=(e,t,n,r,i)=>i.isOnAll?!1:!n&&i.isOnTouch?!(t||e):(n?r.isOnBlur:i.isOnBlur)?!e:(n?r.isOnChange:i.isOnChange)?e:!0,Me=(e,t)=>!v(b(e,t)).length&&H(e,t),Ne=(e,t,n)=>{let r=B(b(e,n));return C(r,O,t[n]),C(e,n,r),e};function Pe(e,t,n=`validate`){if(P(e)||Array.isArray(e)&&e.every(P)||x(e)&&!e)return{type:n,message:P(e)?e:``,ref:t}}var Y=e=>u(e)&&!K(e)?e:{value:e,message:``},Fe=async(e,t,n,r,i,a)=>{let{ref:s,refs:l,required:d,maxLength:f,minLength:p,min:m,max:h,pattern:g,validate:v,name:y,valueAsNumber:C,mount:w}=e._f,T=b(n,y);if(!w||t.has(y))return{};let D=l?l[0]:s,O=e=>{i&&D.reportValidity&&(D.setCustomValidity(x(e)?``:e||``),D.reportValidity())},k={},A=ce(s),j=o(s),M=A||j,N=(C||ae(s))&&_(s.value)&&_(T)||oe(s)&&s.value===``||T===``||Array.isArray(T)&&!T.length||C&&typeof T==`number`&&isNaN(T),F=ne.bind(null,y,r,k),I=(e,t,n,r=E.maxLength,i=E.minLength)=>{let a=e?t:n;k[y]={type:e?r:i,message:a,ref:s,...F(e?r:i,a)}};if(a?!Array.isArray(T)||!T.length:d&&(!M&&(N||c(T))||x(T)&&!T||j&&!ve(l).isValid||A&&!be(l).isValid)){let{value:e,message:t}=P(d)?{value:!!d,message:d}:Y(d);if(e&&(k[y]={type:E.required,message:t,ref:D,...F(E.required,t)},!r))return O(t),k}if(!N&&(!c(m)||!c(h))){let e,t,n=Y(h),i=Y(m);if(!c(T)&&!isNaN(T)){let r=s.valueAsNumber||T&&+T;c(n.value)||(e=r>n.value),c(i.value)||(t=rnew Date(new Date().toDateString()+` `+e),o=s.type==`time`,c=s.type==`week`;P(n.value)&&T&&(e=o?a(T)>a(n.value):c?T>n.value:r>new Date(n.value)),P(i.value)&&T&&(t=o?a(T)+e.value,i=!c(t.value)&&T.length<+t.value;if((n||i)&&(I(n,e.message,t.message),!r))return O(k[y].message),k}if(g&&!N&&P(T)){let{value:e,message:t}=Y(g);if(K(e)&&!T.match(e)&&(k[y]={type:E.pattern,message:t,ref:s,...F(E.pattern,t)},!r))return O(t),k}if(v){if(S(v)){let e=Pe(await v(T,n),D);if(e&&(k[y]={...e,...F(E.validate,e.message)},!r))return O(e.message),k}else if(u(v)){let e={};for(let t in v){if(!V(e)&&!r)break;let i=Pe(await v[t](T,n),D,t);i&&(e={...i,...F(t,i.message)},O(i.message),r&&(k[y]=e))}if(!V(e)&&(k[y]={ref:D,...e},!r))return k}}return O(!0),k},Ie={mode:T.onSubmit,reValidateMode:T.onChange,shouldFocusError:!0},Le={submitCount:0,isDirty:!1,isReady:!1,isValidating:!1,isSubmitted:!1,isSubmitting:!1,isSubmitSuccessful:!1,isValid:!1,touchedFields:{},dirtyFields:{},validatingFields:{}};function Re(e={}){let t={...Ie,...e},n={...h(Le),isLoading:S(t.defaultValues),errors:t.errors||{},disabled:t.disabled||!1},r={},i=(u(t.defaultValues)||u(t.values))&&h(t.defaultValues||t.values)||{},a=t.shouldUnregister?{}:h(i),l={action:!1,mount:!1,watch:!1,keepIsValid:!1},p={mount:new Set,disabled:new Set,unMount:new Set,array:new Set,watch:new Set,registerName:new Set},k,A=0,j={isDirty:!1,dirtyFields:!1,validatingFields:!1,touchedFields:!1,isValidating:!1,isValid:!1,errors:!1},M={...j},N={...M},I={array:re(),state:re()},ee=t.criteriaMode===T.all,te=e=>t=>{clearTimeout(A),A=setTimeout(e,t)},R=async e=>{if(!l.keepIsValid&&!t.disabled&&(M.isValid||N.isValid||e)){let e;t.resolver?(e=V((await W()).errors),z()):e=await G({fields:r,onlyCheckValid:!0,eventType:w.VALID}),e!==n.isValid&&I.state.next({isValid:e})}},z=(e,r)=>{!t.disabled&&(M.isValidating||M.validatingFields||N.isValidating||N.validatingFields)&&((e||Array.from(p.mount)).forEach(e=>{e&&(r?C(n.validatingFields,e,r):H(n.validatingFields,e))}),I.state.next({validatingFields:n.validatingFields,isValidating:!V(n.validatingFields)}))},ne=()=>{n.dirtyFields=U(i,a)},ce=(e,i=[],o,s,c=!0,u=!0)=>{if(s&&o&&!t.disabled){if(l.action=!0,u&&Array.isArray(b(r,e))){let t=o(b(r,e),s.argA,s.argB);c&&C(r,e,t)}if(u&&Array.isArray(b(n.errors,e))){let t=o(b(n.errors,e),s.argA,s.argB);c&&C(n.errors,e,t),Me(n.errors,e)}if((M.touchedFields||N.touchedFields)&&u&&Array.isArray(b(n.touchedFields,e))){let t=o(b(n.touchedFields,e),s.argA,s.argB);c&&C(n.touchedFields,e,t)}(M.dirtyFields||N.dirtyFields)&&ne(),I.state.next({name:e,isDirty:K(e,i),dirtyFields:n.dirtyFields,errors:n.errors,isValid:n.isValid})}else C(a,e,i)},de=(e,t)=>{C(n.errors,e,t),I.state.next({errors:n.errors})},fe=e=>{n.errors=e,I.state.next({errors:n.errors,isValid:!1})},pe=e=>{let t=g(e)?[e]:y(e),n=a,r=i;for(let e=0;e{let c=b(r,e);if(c){if(pe(e))return;let r=_(b(a,e)),u=b(a,e,_(o)?b(i,e):o);_(u)||s&&s.defaultChecked||t?C(a,e,t?u:xe(c._f)):Y(e,u),l.mount&&!l.action&&(R(),r&&n.isDirty&&(M.isDirty||N.isDirty)&&(K()||(n.isDirty=!1,I.state.next({...n}))))}},he=(e,r,o,s,c)=>{let l=!1,u=!1,d={name:e};if(!t.disabled){if(!o||s){(M.isDirty||N.isDirty)&&(u=n.isDirty,n.isDirty=d.isDirty=K(),l=u!==d.isDirty);let t=L(b(i,e),r);u=!!b(n.dirtyFields,e),t===n.isDirty?t?H(n.dirtyFields,e):C(n.dirtyFields,e,!0):n.dirtyFields=U(i,a),d.dirtyFields=n.dirtyFields,l||=(M.dirtyFields||N.dirtyFields)&&u!==!t}if(o){let t=b(n.touchedFields,e);t||(C(n.touchedFields,e,o),d.touchedFields=n.touchedFields,l||=(M.touchedFields||N.touchedFields)&&t!==o)}l&&c&&I.state.next(d)}return l?d:{}},ge=(e,r,i,a)=>{let o=b(n.errors,e),s=(M.isValid||N.isValid)&&x(r)&&n.isValid!==r;if(t.delayError&&i?(k=te(()=>de(e,i)),k(t.delayError)):(clearTimeout(A),k=null,i?C(n.errors,e,i):H(n.errors,e)),(i?!L(o,i):o)||!V(a)||s){let t={...a,...s&&x(r)?{isValid:r}:{},errors:n.errors,name:e};n={...n,...t},I.state.next(t)}},W=async e=>(z(e,!0),await t.resolver(a,t.context,Se(e||p.mount,r,t.criteriaMode,t.shouldUseNativeValidation))),_e=async e=>{let{errors:t}=await W(e);if(z(e),e)for(let r of e){let e=b(t,r);e?p.array.has(r)&&u(e)?Ne(n.errors,{[r]:e},r):C(n.errors,r,e):H(n.errors,r)}else n.errors=t;return t},ve=async({name:t,eventType:r})=>{if(e.validate){let i=await e.validate({formValues:a,formState:n,name:t,eventType:r});if(u(i))for(let e in i){let t=i[e];t&&Q(`${D}.${e}`,{message:P(t.message)?t.message:``,type:t.type||E.validate})}else P(i)||!i?Q(D,{message:i||``,type:E.validate}):We(D);return i}return!0},G=async({fields:r,onlyCheckValid:i,name:o,eventType:s,context:c={valid:!0,runRootValidation:!1}})=>{if(e.validate&&(c.runRootValidation=!0,!await ve({name:o,eventType:s})&&(c.valid=!1,i)))return c.valid;for(let o in r){let l=r[o];if(l){let{_f:r,...u}=l;if(r){let o=p.array.has(r.name),s=l._f&&Te(l._f),u=M.validatingFields||M.isValidating||N.validatingFields||N.isValidating;s&&u&&z([r.name],!0);let d=await Fe(l,p.disabled,a,ee,t.shouldUseNativeValidation&&!i,o);if(s&&u&&z([r.name]),d[r.name]&&(c.valid=!1,i)||(!i&&(b(d,r.name)?o?Ne(n.errors,d,r.name):C(n.errors,r.name,d[r.name]):H(n.errors,r.name)),e.shouldUseNativeValidation&&d[r.name]))break}!V(u)&&await G({context:c,onlyCheckValid:i,fields:u,name:o,eventType:s})}}return c.valid},be=()=>{for(let e of p.unMount){let t=b(r,e);t&&(t._f.refs?t._f.refs.every(e=>!ue(e)):!ue(t._f.ref))&&Je(e)}p.unMount=new Set},K=(e,n)=>!t.disabled&&(e&&n&&C(a,e,n),!L(He(),i)),we=(e,t,n)=>F(e,p,{...l.mount?a:_(t)?i:P(e)?{[e]:t}:t},n,t),Pe=e=>v(b(l.mount?a:i,e,t.shouldUnregister?b(i,e,[]):[])),Y=(e,t,n={})=>{let i=b(r,e),s=t;if(i){let n=i._f;n&&(!n.disabled&&C(a,e,ye(t,n)),s=oe(n.ref)&&c(t)?``:t,se(n.ref)?[...n.ref.options].forEach(e=>e.selected=s.includes(e.value)):n.refs?o(n.ref)?n.refs.forEach(e=>{(!e.defaultChecked||!e.disabled)&&(Array.isArray(s)?e.checked=!!s.find(t=>t===e.value):e.checked=s===e.value||!!s)}):n.refs.forEach(e=>e.checked=e.value===s):ae(n.ref)?n.ref.value=``:(n.ref.value=s,n.ref.type||I.state.next({name:e,values:h(a)})))}(n.shouldDirty||n.shouldTouch)&&he(e,s,n.shouldTouch,n.shouldDirty,!0),n.shouldValidate&&Z(e)},Re=(e,t,n)=>{for(let i in t){if(!t.hasOwnProperty(i))return;let a=t[i],o=e+`.`+i,c=b(r,o);(p.array.has(e)||u(a)||c&&!c._f)&&!s(a)?Re(o,a,n):Y(o,a,n)}},X=(e,t,i={})=>{let o=b(r,e),s=p.array.has(e),u=h(t),d=L(b(a,e),u);if(d||C(a,e,u),s)I.array.next({name:e,values:h(a)}),(M.isDirty||M.dirtyFields||N.isDirty||N.dirtyFields)&&i.shouldDirty&&(ne(),I.state.next({name:e,dirtyFields:n.dirtyFields,isDirty:K(e,u)}));else{let t=Array.isArray(u)&&!u.length||V(u);!o||o._f||c(u)||t?Y(e,u,i):Re(e,u,i)}if(!d){let t=De(e,p),r=h(a);if(!s)for(let t of f(p.array,e))I.array.next({name:t,values:r});I.state.next({...t&&n,name:l.mount||t?e:void 0,values:r})}},ze=e=>{let t=S(e)?e(a):e;if(!L(a,t)){a={...a,...t};for(let e of p.mount)X(e,b(t,e));I.state.next({...n,values:a})}},Be=async i=>{l.mount=!0;let o=i.target,c=o.name,u=!0,f=b(r,c),m=e=>{u=Number.isNaN(e)||s(e)&&isNaN(e.getTime())||L(e,b(a,c,e))},g=q(t.mode),_=q(t.reValidateMode);if(f){let s,l,v=o.type?xe(f._f):d(i),y=i.type===w.BLUR||i.type===w.FOCUS_OUT,x=!Ee(f._f)&&!e.validate&&!t.resolver&&!b(n.errors,c)&&!f._f.deps||je(y,b(n.touchedFields,c),n.isSubmitted,_,g),S=De(c,p,y);C(a,c,v),y?(!o||!o.readOnly)&&(f._f.onBlur&&f._f.onBlur(i),k&&k(0)):f._f.onChange&&f._f.onChange(i);let T=he(c,v,y),E=!V(T)||S;if(!y&&I.state.next({name:c,type:i.type,values:h(a)}),x)return(M.isValid||N.isValid)&&(t.mode===`onBlur`?y&&R():y||R()),E&&I.state.next({name:c,...S?{}:T});if(!t.resolver&&e.validate&&await ve({name:c,eventType:i.type}),!y&&S&&I.state.next({...n}),t.resolver){let{errors:e}=await W([c]);if(z([c]),m(v),u){let t=Oe(n.errors,r,c),i=Oe(e,r,t.name||c);s=i.error,c=i.name,l=V(e)}}else z([c],!0),s=(await Fe(f,p.disabled,a,ee,t.shouldUseNativeValidation))[c],z([c]),m(v),u&&(s?l=!1:(M.isValid||N.isValid)&&(l=await G({fields:r,onlyCheckValid:!0,name:c,eventType:i.type})));u&&(f._f.deps&&(!Array.isArray(f._f.deps)||f._f.deps.length>0)&&Z(f._f.deps),ge(c,l,s,T))}},Ve=(e,t)=>{if(b(n.errors,t)&&e.focus)return e.focus(),1},Z=async(e,i={})=>{let a,o,s=B(e);if(t.resolver){let t=await _e(_(e)?e:s);a=V(t),o=e?!s.some(e=>b(t,e)):a}else e?(o=(await Promise.all(s.map(async e=>{let t=b(r,e);return await G({fields:t&&t._f?{[e]:t}:t,eventType:w.TRIGGER})}))).every(Boolean),!(!o&&!n.isValid)&&R()):o=a=await G({fields:r,name:e,eventType:w.TRIGGER});return I.state.next({...!P(e)||(M.isValid||N.isValid)&&a!==n.isValid?{}:{name:e},...t.resolver||!e?{isValid:a}:{},errors:n.errors}),i.shouldFocus&&!o&&J(r,Ve,e?s:p.mount),o},He=(e,t)=>{let r={...l.mount?a:i};return t&&(r=ie(t.dirtyFields?n.dirtyFields:n.touchedFields,r)),_(e)?r:P(e)?b(r,e):e.map(e=>b(r,e))},Ue=(e,t)=>({invalid:!!b((t||n).errors,e),isDirty:!!b((t||n).dirtyFields,e),error:b((t||n).errors,e),isValidating:!!b(n.validatingFields,e),isTouched:!!b((t||n).touchedFields,e)}),We=e=>{let t=e?B(e):void 0;t?.forEach(e=>H(n.errors,e)),t?t.forEach(e=>{I.state.next({name:e,errors:n.errors})}):I.state.next({errors:{}})},Q=(e,t,i)=>{let a=(b(r,e,{_f:{}})._f||{}).ref,{ref:o,message:s,type:c,...l}=b(n.errors,e)||{};C(n.errors,e,{...l,...t,ref:a}),I.state.next({name:e,errors:n.errors,isValid:!1}),i&&i.shouldFocus&&a&&a.focus&&a.focus()},Ge=(e,t)=>S(e)?I.state.subscribe({next:n=>`values`in n&&e(n.values||we(void 0,t),n)}):we(e,t,!0),Ke=e=>I.state.subscribe({next:t=>{if(Ae(e.name,t.name,e.exact)&&ke(t,e.formState||M,rt,e.reRenderRoot)){let r={...a};e.callback({values:r,...n,...t,defaultValues:i})}}}).unsubscribe,qe=e=>(l.mount=!0,N={...N,...e.formState},Ke({...e,formState:{...j,...e.formState}})),Je=(e,o={})=>{for(let s of e?B(e):p.mount)p.mount.delete(s),p.array.delete(s),o.keepValue||(H(r,s),H(a,s)),!o.keepError&&H(n.errors,s),!o.keepDirty&&H(n.dirtyFields,s),!o.keepTouched&&H(n.touchedFields,s),!o.keepIsValidating&&H(n.validatingFields,s),!t.shouldUnregister&&!o.keepDefaultValue&&H(i,s);I.state.next({values:h(a)}),I.state.next({...n,...o.keepDirty?{isDirty:K()}:{}}),!o.keepIsValid&&R()},Ye=({disabled:e,name:t})=>{if(x(e)&&l.mount||e||p.disabled.has(t)){let n=p.disabled.has(t)!==!!e;e?p.disabled.add(t):p.disabled.delete(t),n&&l.mount&&!l.action&&R()}},$=(e,n={})=>{let a=b(r,e),o=x(n.disabled)||x(t.disabled),s=!p.registerName.has(e)&&a&&a._f&&!a._f.mount;return C(r,e,{...a||{},_f:{...a&&a._f?a._f:{ref:{name:e}},name:e,mount:!0,...n}}),p.mount.add(e),a&&!s?Ye({disabled:x(n.disabled)?n.disabled:t.disabled,name:e}):me(e,!0,n.value),{...o?{disabled:n.disabled||t.disabled}:{},...t.progressive?{required:!!n.required,min:Ce(n.min),max:Ce(n.max),minLength:Ce(n.minLength),maxLength:Ce(n.maxLength),pattern:Ce(n.pattern)}:{},name:e,onChange:Be,onBlur:Be,ref:o=>{if(o){p.registerName.add(e),$(e,n),p.registerName.delete(e),a=b(r,e);let t=_(o.value)&&o.querySelectorAll&&o.querySelectorAll(`input,select,textarea`)[0]||o,s=le(t),c=a._f.refs||[];if(s?c.find(e=>e===t):t===a._f.ref)return;C(r,e,{_f:{...a._f,...s?{refs:[...c.filter(ue),t,...Array.isArray(b(i,e))?[{}]:[]],ref:{type:t.type,name:e}}:{ref:t}}}),me(e,!1,void 0,t)}else a=b(r,e,{}),a._f&&(a._f.mount=!1),(t.shouldUnregister||n.shouldUnregister)&&!(f(p.array,e).length&&l.action)&&p.unMount.add(e)}}},Xe=()=>t.shouldFocusError&&!t.shouldUseNativeValidation&&J(r,Ve,p.mount),Ze=e=>{x(e)&&(I.state.next({disabled:e}),J(r,(t,n)=>{let i=b(r,n);i&&(t.disabled=i._f.disabled||e,Array.isArray(i._f.refs)&&i._f.refs.forEach(t=>{t.disabled=i._f.disabled||e}))},0,!1))},Qe=(e,i)=>async o=>{let s;o&&(o.preventDefault&&o.preventDefault(),o.persist&&o.persist());let c=h(a);if(I.state.next({isSubmitting:!0}),t.resolver){let{errors:e,values:t}=await W();z(),n.errors=e,c=h(t)}else await G({fields:r,eventType:w.SUBMIT});if(p.disabled.size)for(let e of p.disabled)H(c,e);if(H(n.errors,O),V(n.errors)){I.state.next({errors:{}});try{await e(c,o)}catch(e){s=e}}else i&&await i({...n.errors},o),Xe(),setTimeout(Xe);if(I.state.next({isSubmitted:!0,isSubmitting:!1,isSubmitSuccessful:V(n.errors)&&!s,submitCount:n.submitCount+1,errors:n.errors}),s)throw s},$e=(e,t={})=>{b(r,e)&&(_(t.defaultValue)?X(e,h(b(i,e))):(X(e,t.defaultValue),C(i,e,h(t.defaultValue))),t.keepTouched||H(n.touchedFields,e),t.keepDirty||(H(n.dirtyFields,e),n.isDirty=t.defaultValue?K(e,h(b(i,e))):K()),t.keepError||(H(n.errors,e),M.isValid&&R()),I.state.next({...n}))},et=(e,o={})=>{let s=e?h(e):i,c=h(s),u=V(e),d=u?i:c;if(o.keepDefaultValues||(i=s),!o.keepValues){if(o.keepDirtyValues){let e=new Set([...p.mount,...Object.keys(U(i,a))]);for(let t of Array.from(e)){let e=b(n.dirtyFields,t),r=b(a,t),i=b(d,t);e&&!_(r)?C(d,t,r):!e&&!_(i)&&X(t,i)}}else{if(m&&_(e))for(let e of p.mount){let t=b(r,e);if(t&&t._f){let e=Array.isArray(t._f.refs)?t._f.refs[0]:t._f.ref;if(oe(e)){let t=e.closest(`form`);if(t){t.reset();break}}}}if(o.keepFieldsRef)for(let e of p.mount)X(e,b(d,e));else r={}}a=t.shouldUnregister?o.keepDefaultValues?h(i):{}:h(d),I.array.next({values:{...d}}),I.state.next({values:{...d}})}p={mount:o.keepDirtyValues?p.mount:new Set,unMount:new Set,array:new Set,registerName:new Set,disabled:new Set,watch:new Set,watchAll:!1,focus:``},l.mount=!M.isValid||!!o.keepIsValid||!!o.keepDirtyValues||!t.shouldUnregister&&!V(d),l.watch=!!t.shouldUnregister,l.keepIsValid=!!o.keepIsValid,l.action=!1,o.keepErrors||(n.errors={}),I.state.next({submitCount:o.keepSubmitCount?n.submitCount:0,isDirty:u?!1:o.keepDirty?n.isDirty:!!(o.keepDefaultValues&&!L(e,i)),isSubmitted:o.keepIsSubmitted?n.isSubmitted:!1,dirtyFields:u?{}:o.keepDirtyValues?o.keepDefaultValues&&a?U(i,a):n.dirtyFields:o.keepDefaultValues&&e?U(i,e):o.keepDirty?n.dirtyFields:{},touchedFields:o.keepTouched?n.touchedFields:{},errors:o.keepErrors?n.errors:{},isSubmitSuccessful:o.keepIsSubmitSuccessful?n.isSubmitSuccessful:!1,isSubmitting:!1,defaultValues:i})},tt=(e,n)=>et(S(e)?e(a):e,{...t.resetOptions,...n}),nt=(e,t={})=>{let n=b(r,e),i=n&&n._f;if(i){let e=i.refs?i.refs[0]:i.ref;e.focus&&setTimeout(()=>{e.focus(),t.shouldSelect&&S(e.select)&&e.select()})}},rt=e=>{n={...n,...e}},it={control:{register:$,unregister:Je,getFieldState:Ue,handleSubmit:Qe,setError:Q,_subscribe:Ke,_runSchema:W,_updateIsValidating:z,_focusError:Xe,_getWatch:we,_getDirty:K,_setValid:R,_setFieldArray:ce,_setDisabledField:Ye,_setErrors:fe,_getFieldArray:Pe,_reset:et,_resetDefaultValues:()=>S(t.defaultValues)&&t.defaultValues().then(e=>{tt(e,t.resetOptions),I.state.next({isLoading:!1})}),_removeUnmounted:be,_disableForm:Ze,_subjects:I,_proxyFormState:M,get _fields(){return r},get _formValues(){return a},get _state(){return l},set _state(e){l=e},get _defaultValues(){return i},get _names(){return p},set _names(e){p=e},get _formState(){return n},get _options(){return t},set _options(e){t={...t,...e}}},subscribe:qe,trigger:Z,register:$,handleSubmit:Qe,watch:Ge,setValue:X,setValues:ze,getValues:He,reset:tt,resetField:$e,clearErrors:We,unregister:Je,setError:Q,setFocus:nt,getFieldState:Ue};return{...it,formControl:it}}var X=()=>{if(typeof crypto<`u`&&crypto.randomUUID)return crypto.randomUUID();let e=typeof performance>`u`?Date.now():performance.now()*1e3;return`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,t=>{let n=(Math.random()*16+e)%16|0;return(t==`x`?n:n&3|8).toString(16)})},ze=(e,t,n={})=>n.shouldFocus||_(n.shouldFocus)?n.focusName||`${e}.${_(n.focusIndex)?t:n.focusIndex}.`:``,Be=(e,t)=>[...e,...B(t)],Ve=e=>Array.isArray(e)?e.map(()=>void 0):void 0;function Z(e,t,n){return[...e.slice(0,t),...B(n),...e.slice(t)]}var He=(e,t,n)=>Array.isArray(e)?(_(e[n])&&(e[n]=void 0),e.splice(n,0,e.splice(t,1)[0]),e):[],Ue=(e,t)=>[...B(t),...B(e)];function We(e,t){let n=0,r=[...e];for(let e of t)r.splice(e-n,1),n++;return v(r).length?r:[]}var Q=(e,t)=>_(t)?[]:We(e,B(t).sort((e,t)=>e-t)),Ge=(e,t,n)=>{[e[t],e[n]]=[e[n],e[t]]},Ke=(e,t,n)=>(e[t]=n,e);function qe(e){let t=A(),{control:n=t,name:r,keyName:i=`id`,shouldUnregister:o,rules:s}=e,[c,l]=a.useState(n._getFieldArray(r)),u=a.useRef(n._getFieldArray(r).map(X)),d=a.useRef(!1);n._names.array.add(r),a.useMemo(()=>s&&c.length>=0&&n.register(r,s),[n,r,c.length,s]),M(()=>n._subjects.array.subscribe({next:({values:e,name:t})=>{if(t===r||!t){let t=b(e,r);Array.isArray(t)&&(l(t),u.current=t.map(X))}}}).unsubscribe,[n,r]);let f=a.useCallback(e=>{d.current=!0,n._setFieldArray(r,e)},[n,r]);return a.useEffect(()=>{n._state.action=!1,De(r,n._names)&&n._subjects.state.next({...n._formState});let e=q(n._options.mode);if(d.current&&(!e.isOnSubmit||n._formState.isSubmitted)&&!q(n._options.reValidateMode).isOnSubmit&&!e.isOnBlur)if(n._options.resolver)n._runSchema([r]).then(e=>{n._updateIsValidating([r]);let t=b(e.errors,r),i=b(n._formState.errors,r);(i?!t&&i.type||t&&(i.type!==t.type||i.message!==t.message):t&&t.type)&&(t?C(n._formState.errors,r,t):H(n._formState.errors,r),n._subjects.state.next({errors:n._formState.errors}))});else{let e=b(n._fields,r);e&&e._f&&!(q(n._options.reValidateMode).isOnSubmit&&q(n._options.mode).isOnSubmit)&&Fe(e,n._names.disabled,n._formValues,n._options.criteriaMode===T.all,n._options.shouldUseNativeValidation,!0).then(e=>!V(e)&&n._subjects.state.next({errors:Ne(n._formState.errors,e,r)}))}n._subjects.state.next({name:r,values:h(n._formValues)}),n._names.focus&&J(n._fields,(e,t)=>{if(n._names.focus&&t.startsWith(n._names.focus)&&e.focus)return e.focus(),1}),n._names.focus=``,n._setValid(),d.current=!1},[c,r,n]),a.useEffect(()=>(!b(n._formValues,r)&&n._setFieldArray(r),()=>{let e=!(n._options.shouldUnregister||o);d.current&&e&&n._subjects.state.next({name:r,values:h(n._formValues)}),e?((e,t)=>{let r=b(n._fields,e);r&&r._f&&(r._f.mount=t)})(r,!1):n.unregister(r)}),[r,n,i,o]),{swap:a.useCallback((e,t)=>{let i=n._getFieldArray(r);Ge(i,e,t),Ge(u.current,e,t),f(i),l(i),n._setFieldArray(r,i,Ge,{argA:e,argB:t},!1)},[f,r,n]),move:a.useCallback((e,t)=>{let i=n._getFieldArray(r);He(i,e,t),He(u.current,e,t),f(i),l(i),n._setFieldArray(r,i,He,{argA:e,argB:t},!1)},[f,r,n]),prepend:a.useCallback((e,t)=>{let i=B(h(e)),a=Ue(n._getFieldArray(r),i);n._names.focus=ze(r,0,t),u.current=Ue(u.current,i.map(X)),f(a),l(a),n._setFieldArray(r,a,Ue,{argA:Ve(e)})},[f,r,n]),append:a.useCallback((e,t)=>{let i=B(h(e)),a=Be(n._getFieldArray(r),i);n._names.focus=ze(r,a.length-1,t),u.current=Be(u.current,i.map(X)),f(a),l(a),n._setFieldArray(r,a,Be,{argA:Ve(e)})},[f,r,n]),remove:a.useCallback(e=>{let t=Q(n._getFieldArray(r),e);u.current=Q(u.current,e),f(t),l(t),!Array.isArray(b(n._fields,r))&&C(n._fields,r,void 0),n._setFieldArray(r,t,Q,{argA:e})},[f,r,n]),insert:a.useCallback((e,t,i)=>{let a=B(h(t)),o=Z(n._getFieldArray(r),e,a);n._names.focus=ze(r,e,i),u.current=Z(u.current,e,a.map(X)),f(o),l(o),n._setFieldArray(r,o,Z,{argA:e,argB:Ve(t)})},[f,r,n]),update:a.useCallback((e,t)=>{let i=h(t),a=Ke(n._getFieldArray(r),e,i);u.current=[...a].map((t,n)=>!t||n===e?X():u.current[n]),f(a),l([...a]),n._setFieldArray(r,a,Ke,{argA:e,argB:i},!0,!1)},[f,r,n]),replace:a.useCallback(e=>{let t=B(h(e));u.current=t.map(X),f([...t]),l([...t]),n._setFieldArray(r,[...t],e=>e,{},!0,!1)},[f,r,n]),fields:a.useMemo(()=>c.map((e,t)=>({...e,[i]:u.current[t]||X()})),[c,i])}}function Je(e={}){let t=a.useRef(void 0),n=a.useRef(void 0),[r,i]=a.useState(()=>({...h(Le),isLoading:S(e.defaultValues),errors:e.errors||{},disabled:e.disabled||!1,defaultValues:S(e.defaultValues)?void 0:e.defaultValues}));if(!t.current)if(e.formControl)t.current={...e.formControl,formState:r},e.defaultValues&&!S(e.defaultValues)&&e.formControl.reset(e.defaultValues,e.resetOptions);else{let{formControl:n,...i}=Re(e);t.current={...i,formState:r}}let o=t.current.control;return o._options=e,M(()=>{let e=o._subscribe({formState:o._proxyFormState,callback:()=>i({...o._formState,defaultValues:o._defaultValues}),reRenderRoot:!0});return i(e=>({...e,isReady:!0})),o._formState.isReady=!0,e},[o]),a.useEffect(()=>o._disableForm(e.disabled),[o,e.disabled]),a.useEffect(()=>{e.mode&&(o._options.mode=e.mode),e.reValidateMode&&(o._options.reValidateMode=e.reValidateMode)},[o,e.mode,e.reValidateMode]),a.useEffect(()=>{e.errors&&(o._setErrors(e.errors),o._focusError())},[o,e.errors]),a.useEffect(()=>{e.shouldUnregister&&o._subjects.state.next({values:o._getWatch()})},[o,e.shouldUnregister]),a.useEffect(()=>{if(o._proxyFormState.isDirty){let e=o._getDirty();e!==r.isDirty&&o._subjects.state.next({isDirty:e})}},[o,r.isDirty]),a.useEffect(()=>{e.values&&!L(e.values,n.current)?(o._reset(e.values,{keepFieldsRef:!0,...o._options.resetOptions}),o._options.resetOptions?.keepIsValid||o._setValid(),n.current=e.values,i(e=>({...e}))):o._resetDefaultValues()},[o,e.values]),a.useEffect(()=>{o._state.mount||(o._setValid(),o._state.mount=!0),o._state.watch&&(o._state.watch=!1,o._subjects.state.next({...o._formState})),o._removeUnmounted()}),t.current.formState=a.useMemo(()=>j(r,o),[o,r]),t.current}var Ye=(e,t,n)=>{if(e&&`reportValidity`in e){let r=b(n,t);e.setCustomValidity(r&&r.message||``),e.reportValidity()}},$=(e,t)=>{for(let n in t.fields){let r=t.fields[n];r&&r.ref&&`reportValidity`in r.ref?Ye(r.ref,n,e):r&&r.refs&&r.refs.forEach(t=>Ye(t,n,e))}},Xe=(e,t)=>{t.shouldUseNativeValidation&&$(e,t);let n={};for(let r in e){let i=b(t.fields,r),a=Object.assign(e[r]||{},{ref:i&&i.ref});if(Ze(t.names||Object.keys(e),r)){let e=Object.assign({},b(n,r));C(e,`root`,a),C(n,r,e)}else C(n,r,a)}return n},Ze=(e,t)=>{let n=Qe(t);return e.some(e=>Qe(e).match(`^${n}\\.\\d+`))};function Qe(e){return e.replace(/\]|\[/g,``)}function $e(e,t){try{var n=e()}catch(e){return t(e)}return n&&n.then?n.then(void 0,t):n}function et(e,t){for(var n={};e.length;){var r=e[0],i=r.code,a=r.message,o=r.path.join(`.`);if(!n[o])if(`unionErrors`in r){var s=r.unionErrors[0].errors[0];n[o]={message:s.message,type:s.code}}else n[o]={message:a,type:i};if(`unionErrors`in r&&r.unionErrors.forEach(function(t){return t.errors.forEach(function(t){return e.push(t)})}),t){var c=n[o].types,l=c&&c[r.code];n[o]=ne(o,t,n,i,l?[].concat(l,r.message):r.message)}e.shift()}return n}function tt(e,t){for(var n={};e.length;){var r=e[0],i=r.code,a=r.message,o=r.path.join(`.`);if(!n[o])if(r.code===`invalid_union`&&r.errors.length>0){var s=r.errors[0][0];n[o]={message:s.message,type:s.code}}else n[o]={message:a,type:i};if(r.code===`invalid_union`&&r.errors.forEach(function(t){return t.forEach(function(t){return e.push(t)})}),t){var c=n[o].types,l=c&&c[r.code];n[o]=ne(o,t,n,i,l?[].concat(l,r.message):r.message)}e.shift()}return n}function nt(e,n,a){if(a===void 0&&(a={}),function(e){return`_def`in e&&typeof e._def==`object`&&`typeName`in e._def}(e))return function(t,r,i){try{return Promise.resolve($e(function(){return Promise.resolve(e[a.mode===`sync`?`parse`:`parseAsync`](t,n)).then(function(e){return i.shouldUseNativeValidation&&$({},i),{errors:{},values:a.raw?Object.assign({},t):e}})},function(e){if(function(e){return Array.isArray(e?.issues)}(e))return{values:{},errors:Xe(et(e.errors,!i.shouldUseNativeValidation&&i.criteriaMode===`all`),i)};throw e}))}catch(e){return Promise.reject(e)}};if(function(e){return`_zod`in e&&typeof e._zod==`object`}(e))return function(o,s,c){try{return Promise.resolve($e(function(){return Promise.resolve((a.mode===`sync`?i:t)(e,o,n)).then(function(e){return c.shouldUseNativeValidation&&$({},c),{errors:{},values:a.raw?Object.assign({},o):e}})},function(e){if(function(e){return e instanceof r}(e))return{values:{},errors:Xe(tt(e.issues,!c.shouldUseNativeValidation&&c.criteriaMode===`all`),c)};throw e}))}catch(e){return Promise.reject(e)}};throw Error(`Invalid input: not a Zod schema`)}export{Je as i,R as n,qe as r,nt as t}; \ No newline at end of file +import{Fr as e,Jo as t,Nr as n,Pr as r,ko as i}from"./index.js";var a=t(i(),1),o=e=>e.type===`checkbox`,s=e=>e instanceof Date,c=e=>e==null,l=e=>typeof e==`object`,u=e=>!c(e)&&!Array.isArray(e)&&l(e)&&!s(e),d=e=>u(e)&&e.target?o(e.target)?e.target.checked:e.target.value:e,f=(e,t)=>{let n=t.split(`.`),r=[],i=n[0];for(let t=1;t{let t=e.constructor&&e.constructor.prototype;return u(t)&&t.hasOwnProperty(`isPrototypeOf`)},m=typeof window<`u`&&window.HTMLElement!==void 0&&typeof document<`u`;function h(e){if(e instanceof Date)return new Date(e);let t=typeof FileList<`u`&&e instanceof FileList;if(m&&(e instanceof Blob||t))return e;let n=Array.isArray(e);if(!n&&!(u(e)&&p(e)))return e;let r=n?[]:Object.create(Object.getPrototypeOf(e));for(let t in e)Object.prototype.hasOwnProperty.call(e,t)&&(r[t]=h(e[t]));return r}var g=e=>/^\w*$/.test(e),_=e=>e===void 0,v=e=>Array.isArray(e)?e.filter(Boolean):[],y=e=>v(e.replace(/["|']|\]/g,``).split(/\.|\[/)),b=(e,t,n)=>{if(!t||!u(e))return n;let r=(g(t)?[t]:y(t)).reduce((e,t)=>c(e)?void 0:e[t],e);return _(r)||r===e?_(e[t])?n:e[t]:r},x=e=>typeof e==`boolean`,S=e=>typeof e==`function`,C=(e,t,n)=>{let r=-1,i=g(t)?[t]:y(t),a=i.length,o=a-1;for(;++ra.useContext(k),j=(e,t,n,r=!0)=>{let i={};for(let a in e)Object.defineProperty(i,a,{get:()=>{let i=a;return t._proxyFormState[i]!==T.all&&(t._proxyFormState[i]=!r||T.all),n&&(n[i]=!0),e[i]}});return i},M=typeof window<`u`?a.useLayoutEffect:a.useEffect;function N(e){let t=A(),{control:n=t,disabled:r,name:i,exact:o}=e||{},[s,c]=a.useState(()=>({...n._formState,defaultValues:n._defaultValues})),l=a.useRef({isDirty:!1,isLoading:!1,dirtyFields:!1,touchedFields:!1,validatingFields:!1,isValidating:!1,isValid:!1,errors:!1});return M(()=>n._subscribe({name:i,formState:l.current,exact:o,callback:e=>{!r&&c({...n._formState,...e,defaultValues:n._defaultValues})}}),[i,r,o]),a.useEffect(()=>{l.current.isValid&&n._setValid(!0)},[n]),a.useMemo(()=>j(s,n,l.current,!1),[s,n])}var P=e=>typeof e==`string`,F=(e,t,n,r,i)=>P(e)?(r&&t.watch.add(e),b(n,e,i)):Array.isArray(e)?e.map(e=>(r&&t.watch.add(e),b(n,e))):(r&&(t.watchAll=!0),n),I=e=>c(e)||!l(e);function L(e,t,n=new WeakSet){if(e===t)return!0;if(I(e)||I(t))return Object.is(e,t);if(s(e)&&s(t))return Object.is(e.getTime(),t.getTime());let r=Object.keys(e),i=Object.keys(t);if(r.length!==i.length)return!1;if(n.has(e)||n.has(t))return!0;n.add(e),n.add(t);for(let i of r){let r=e[i];if(!(i in t))return!1;if(i!==`ref`){let e=t[i];if(s(r)&&s(e)||(u(r)||Array.isArray(r))&&(u(e)||Array.isArray(e))?!L(r,e,n):!Object.is(r,e))return!1}}return!0}function ee(e){let t=A(),{control:n=t,name:r,defaultValue:i,disabled:o,exact:s,compute:c}=e||{},l=a.useRef(i),u=a.useRef(c),d=a.useRef(void 0),f=a.useRef(n),p=a.useRef(r);u.current=c;let[m,h]=a.useState(()=>{let e=n._getWatch(r,l.current);return u.current?u.current(e):e}),g=a.useCallback(e=>{let t=F(r,n._names,e||n._formValues,!1,l.current);return u.current?u.current(t):t},[n._formValues,n._names,r]),_=a.useCallback(e=>{if(!o){let t=F(r,n._names,e||n._formValues,!1,l.current);if(u.current){let e=u.current(t);L(e,d.current)||(h(e),d.current=e)}else h(t)}},[n._formValues,n._names,o,r]);M(()=>((f.current!==n||!L(p.current,r))&&(f.current=n,p.current=r,_()),n._subscribe({name:r,formState:{values:!0},exact:s,callback:e=>{_(e.values)}})),[n,s,r,_]),a.useEffect(()=>n._removeUnmounted());let v=f.current!==n,y=p.current,b=a.useMemo(()=>{if(o)return null;let e=!v&&!L(y,r);return v||e?g():null},[o,v,r,y,g]);return b===null?m:b}function te(e){let t=A(),{name:n,disabled:r,control:i=t,shouldUnregister:o,defaultValue:s,exact:c=!0}=e,l=!!f(i._names.array,n).length,u=ee({control:i,name:n,defaultValue:a.useMemo(()=>b(i._formValues,n,b(i._defaultValues,n,s)),[i,n,s]),exact:c}),p=N({control:i,name:n,exact:c}),m=a.useRef(e),g=a.useRef(i.register(n,{...e.rules,value:u,...x(e.disabled)?{disabled:e.disabled}:{}}));m.current=e;let v=a.useMemo(()=>Object.defineProperties({},{invalid:{enumerable:!0,get:()=>!!b(p.errors,n)},isDirty:{enumerable:!0,get:()=>!!b(p.dirtyFields,n)},isTouched:{enumerable:!0,get:()=>!!b(p.touchedFields,n)},isValidating:{enumerable:!0,get:()=>!!b(p.validatingFields,n)},error:{enumerable:!0,get:()=>b(p.errors,n)}}),[p,n]),y=a.useCallback(e=>g.current.onChange({target:{value:d(e),name:n},type:w.CHANGE}),[n]),T=a.useCallback(()=>g.current.onBlur({target:{value:b(i._formValues,n),name:n},type:w.BLUR}),[n,i._formValues]),E=a.useCallback(e=>{let t=b(i._fields,n);t&&t._f&&e&&(t._f.ref={focus:()=>S(e.focus)&&e.focus(),select:()=>S(e.select)&&e.select(),setCustomValidity:t=>S(e.setCustomValidity)&&e.setCustomValidity(t),reportValidity:()=>S(e.reportValidity)&&e.reportValidity()})},[i._fields,n]),D=a.useMemo(()=>({name:n,value:u,...x(r)||p.disabled?{disabled:p.disabled||r}:{},onChange:y,onBlur:T,ref:E}),[n,r,p.disabled,y,T,E,u]);return a.useEffect(()=>{let e=i._options.shouldUnregister||o;i.register(n,{...m.current.rules,...x(m.current.disabled)?{disabled:m.current.disabled}:{}});let t=(e,t)=>{let n=b(i._fields,e);n&&n._f&&(n._f.mount=t)};if(t(n,!0),e){let e=h(b(i._defaultValues,n,b(i._options.defaultValues,n,m.current.defaultValue)));C(i._defaultValues,n,e),_(b(i._formValues,n))&&C(i._formValues,n,e)}return!l&&i.register(n),()=>{(l?e&&!i._state.action:e)?i.unregister(n):t(n,!1)}},[n,i,l,o]),a.useEffect(()=>{i._setDisabledField({disabled:r,name:n})},[r,n,i]),a.useMemo(()=>({field:D,formState:p,fieldState:v}),[D,p,v])}var R=e=>e.render(te(e)),z=a.createContext(null);z.displayName=`HookFormContext`;var ne=(e,t,n,r,i)=>t?{...n[e],types:{...n[e]&&n[e].types?n[e].types:{},[r]:i||!0}}:{},B=e=>Array.isArray(e)?e:[e],re=()=>{let e=[];return{get observers(){return e},next:t=>{for(let n of e)n.next&&n.next(t)},subscribe:t=>(e.push(t),{unsubscribe:()=>{e=e.filter(e=>e!==t)}}),unsubscribe:()=>{e=[]}}};function ie(e,t){let n={};for(let r in e)if(e.hasOwnProperty(r)){let i=e[r],a=t[r];if(i&&u(i)&&a){let e=ie(i,a);u(e)&&(n[r]=e)}else e[r]&&(n[r]=a)}return n}var V=e=>u(e)&&!Object.keys(e).length,ae=e=>e.type===`file`,oe=e=>{if(!m)return!1;let t=e?e.ownerDocument:0;return e instanceof(t&&t.defaultView?t.defaultView.HTMLElement:HTMLElement)},se=e=>e.type===`select-multiple`,ce=e=>e.type===`radio`,le=e=>ce(e)||o(e),ue=e=>oe(e)&&e.isConnected;function de(e,t){let n=t.slice(0,-1).length,r=0;for(;r{for(let t in e)if(S(e[t]))return!0;return!1};function me(e){return Array.isArray(e)||u(e)&&!pe(e)}function he(e,t={}){for(let n in e){let r=e[n];me(r)?(t[n]=Array.isArray(r)?[]:{},he(r,t[n])):_(r)||(t[n]=!0)}return t}function ge(e){if(e!==!1){if(e===!0)return!0;if(Array.isArray(e)){let t=e.map(e=>ge(e));return t.some(e=>e!==void 0)?t:void 0}if(u(e)){let t={};for(let n in e){let r=ge(e[n]);_(r)||(t[n]=r)}return Object.keys(t).length?t:void 0}}}function U(e,t,n){n||=he(t);for(let r in e){let i=e[r];if(me(i))_(t)||I(n[r])?n[r]=he(i,Array.isArray(i)?[]:{}):U(i,c(t)?{}:t[r],n[r]);else{let e=t[r];n[r]=!L(i,e)}}return ge(n)||{}}var W={value:!1,isValid:!1},_e={value:!0,isValid:!0},ve=e=>{if(Array.isArray(e)){if(e.length>1){let t=e.filter(e=>e&&e.checked&&!e.disabled).map(e=>e.value);return{value:t,isValid:!!t.length}}return e[0].checked&&!e[0].disabled?e[0].attributes&&!_(e[0].attributes.value)?_(e[0].value)||e[0].value===``?_e:{value:e[0].value,isValid:!0}:_e:W}return W},ye=(e,{valueAsNumber:t,valueAsDate:n,setValueAs:r})=>_(e)?e:t?e===``?NaN:e&&+e:n&&P(e)?new Date(e):r?r(e):e,G={isValid:!1,value:null},be=e=>Array.isArray(e)?e.reduce((e,t)=>t&&t.checked&&!t.disabled?{isValid:!0,value:t.value}:e,G):G;function xe(e){let t=e.ref;return ae(t)?t.files:ce(t)?be(e.refs).value:se(t)?[...t.selectedOptions].map(({value:e})=>e):o(t)?ve(e.refs).value:ye(_(t.value)?e.ref.value:t.value,e)}var Se=(e,t,n,r)=>{let i={};for(let n of e){let e=b(t,n);e&&C(i,n,e._f)}return{criteriaMode:n,names:[...e],fields:i,shouldUseNativeValidation:r}},K=e=>e instanceof RegExp,Ce=e=>_(e)?e:K(e)?e.source:u(e)?K(e.value)?e.value.source:e.value:e,q=e=>({isOnSubmit:!e||e===T.onSubmit,isOnBlur:e===T.onBlur,isOnChange:e===T.onChange,isOnAll:e===T.all,isOnTouch:e===T.onTouched}),we=`AsyncFunction`,Te=e=>!!e&&!!e.validate&&!!(S(e.validate)&&e.validate.constructor.name===we||u(e.validate)&&Object.values(e.validate).find(e=>e.constructor.name===we)),Ee=e=>e.mount&&(e.required||e.min||e.max||e.maxLength||e.minLength||e.pattern||e.validate),De=(e,t,n)=>!n&&(t.watchAll||t.watch.has(e)||[...t.watch].some(t=>e.startsWith(t)&&/^\.\w+/.test(e.slice(t.length)))),J=(e,t,n,r)=>{for(let i of n||Object.keys(e)){let n=b(e,i);if(n){let{_f:e,...a}=n;if(e){if(e.refs&&e.refs[0]&&t(e.refs[0],i)&&!r||e.ref&&t(e.ref,e.name)&&!r)return!0;if(J(a,t))break}else if(u(a)&&J(a,t))break}}};function Oe(e,t,n){let r=b(e,n);if(r||g(n))return{error:r,name:n};let i=n.split(`.`);for(;i.length;){let r=i.join(`.`),a=b(t,r),o=b(e,r);if(a&&!Array.isArray(a)&&n!==r)return{name:n};if(o&&o.type)return{name:r,error:o};if(o&&o.root&&o.root.type)return{name:`${r}.root`,error:o.root};i.pop()}return{name:n}}var ke=(e,t,n,r)=>{n(e);let{name:i,...a}=e;return V(a)||r&&Object.keys(a).length>=Object.keys(t).length||Object.keys(a).find(e=>t[e]===(!r||T.all))},Ae=(e,t,n)=>!e||!t||e===t||B(e).some(e=>e&&(n?e===t:e.startsWith(t)||t.startsWith(e))),je=(e,t,n,r,i)=>i.isOnAll?!1:!n&&i.isOnTouch?!(t||e):(n?r.isOnBlur:i.isOnBlur)?!e:(n?r.isOnChange:i.isOnChange)?e:!0,Me=(e,t)=>!v(b(e,t)).length&&H(e,t),Ne=(e,t,n)=>{let r=B(b(e,n));return C(r,O,t[n]),C(e,n,r),e};function Pe(e,t,n=`validate`){if(P(e)||Array.isArray(e)&&e.every(P)||x(e)&&!e)return{type:n,message:P(e)?e:``,ref:t}}var Y=e=>u(e)&&!K(e)?e:{value:e,message:``},Fe=async(e,t,n,r,i,a)=>{let{ref:s,refs:l,required:d,maxLength:f,minLength:p,min:m,max:h,pattern:g,validate:v,name:y,valueAsNumber:C,mount:w}=e._f,T=b(n,y);if(!w||t.has(y))return{};let D=l?l[0]:s,O=e=>{i&&D.reportValidity&&(D.setCustomValidity(x(e)?``:e||``),D.reportValidity())},k={},A=ce(s),j=o(s),M=A||j,N=(C||ae(s))&&_(s.value)&&_(T)||oe(s)&&s.value===``||T===``||Array.isArray(T)&&!T.length||C&&typeof T==`number`&&isNaN(T),F=ne.bind(null,y,r,k),I=(e,t,n,r=E.maxLength,i=E.minLength)=>{let a=e?t:n;k[y]={type:e?r:i,message:a,ref:s,...F(e?r:i,a)}};if(a?!Array.isArray(T)||!T.length:d&&(!M&&(N||c(T))||x(T)&&!T||j&&!ve(l).isValid||A&&!be(l).isValid)){let{value:e,message:t}=P(d)?{value:!!d,message:d}:Y(d);if(e&&(k[y]={type:E.required,message:t,ref:D,...F(E.required,t)},!r))return O(t),k}if(!N&&(!c(m)||!c(h))){let e,t,n=Y(h),i=Y(m);if(!c(T)&&!isNaN(T)){let r=s.valueAsNumber||T&&+T;c(n.value)||(e=r>n.value),c(i.value)||(t=rnew Date(new Date().toDateString()+` `+e),o=s.type==`time`,c=s.type==`week`;P(n.value)&&T&&(e=o?a(T)>a(n.value):c?T>n.value:r>new Date(n.value)),P(i.value)&&T&&(t=o?a(T)+e.value,i=!c(t.value)&&T.length<+t.value;if((n||i)&&(I(n,e.message,t.message),!r))return O(k[y].message),k}if(g&&!N&&P(T)){let{value:e,message:t}=Y(g);if(K(e)&&!T.match(e)&&(k[y]={type:E.pattern,message:t,ref:s,...F(E.pattern,t)},!r))return O(t),k}if(v){if(S(v)){let e=Pe(await v(T,n),D);if(e&&(k[y]={...e,...F(E.validate,e.message)},!r))return O(e.message),k}else if(u(v)){let e={};for(let t in v){if(!V(e)&&!r)break;let i=Pe(await v[t](T,n),D,t);i&&(e={...i,...F(t,i.message)},O(i.message),r&&(k[y]=e))}if(!V(e)&&(k[y]={ref:D,...e},!r))return k}}return O(!0),k},Ie={mode:T.onSubmit,reValidateMode:T.onChange,shouldFocusError:!0},Le={submitCount:0,isDirty:!1,isReady:!1,isValidating:!1,isSubmitted:!1,isSubmitting:!1,isSubmitSuccessful:!1,isValid:!1,touchedFields:{},dirtyFields:{},validatingFields:{}};function Re(e={}){let t={...Ie,...e},n={...h(Le),isLoading:S(t.defaultValues),errors:t.errors||{},disabled:t.disabled||!1},r={},i=(u(t.defaultValues)||u(t.values))&&h(t.defaultValues||t.values)||{},a=t.shouldUnregister?{}:h(i),l={action:!1,mount:!1,watch:!1,keepIsValid:!1},p={mount:new Set,disabled:new Set,unMount:new Set,array:new Set,watch:new Set,registerName:new Set},k,A=0,j={isDirty:!1,dirtyFields:!1,validatingFields:!1,touchedFields:!1,isValidating:!1,isValid:!1,errors:!1},M={...j},N={...M},I={array:re(),state:re()},ee=t.criteriaMode===T.all,te=e=>t=>{clearTimeout(A),A=setTimeout(e,t)},R=async e=>{if(!l.keepIsValid&&!t.disabled&&(M.isValid||N.isValid||e)){let e;t.resolver?(e=V((await W()).errors),z()):e=await G({fields:r,onlyCheckValid:!0,eventType:w.VALID}),e!==n.isValid&&I.state.next({isValid:e})}},z=(e,r)=>{!t.disabled&&(M.isValidating||M.validatingFields||N.isValidating||N.validatingFields)&&((e||Array.from(p.mount)).forEach(e=>{e&&(r?C(n.validatingFields,e,r):H(n.validatingFields,e))}),I.state.next({validatingFields:n.validatingFields,isValidating:!V(n.validatingFields)}))},ne=()=>{n.dirtyFields=U(i,a)},ce=(e,i=[],o,s,c=!0,u=!0)=>{if(s&&o&&!t.disabled){if(l.action=!0,u&&Array.isArray(b(r,e))){let t=o(b(r,e),s.argA,s.argB);c&&C(r,e,t)}if(u&&Array.isArray(b(n.errors,e))){let t=o(b(n.errors,e),s.argA,s.argB);c&&C(n.errors,e,t),Me(n.errors,e)}if((M.touchedFields||N.touchedFields)&&u&&Array.isArray(b(n.touchedFields,e))){let t=o(b(n.touchedFields,e),s.argA,s.argB);c&&C(n.touchedFields,e,t)}(M.dirtyFields||N.dirtyFields)&&ne(),I.state.next({name:e,isDirty:K(e,i),dirtyFields:n.dirtyFields,errors:n.errors,isValid:n.isValid})}else C(a,e,i)},de=(e,t)=>{C(n.errors,e,t),I.state.next({errors:n.errors})},fe=e=>{n.errors=e,I.state.next({errors:n.errors,isValid:!1})},pe=e=>{let t=g(e)?[e]:y(e),n=a,r=i;for(let e=0;e{let c=b(r,e);if(c){if(pe(e))return;let r=_(b(a,e)),u=b(a,e,_(o)?b(i,e):o);_(u)||s&&s.defaultChecked||t?C(a,e,t?u:xe(c._f)):Y(e,u),l.mount&&!l.action&&(R(),r&&n.isDirty&&(M.isDirty||N.isDirty)&&(K()||(n.isDirty=!1,I.state.next({...n}))))}},he=(e,r,o,s,c)=>{let l=!1,u=!1,d={name:e};if(!t.disabled){if(!o||s){(M.isDirty||N.isDirty)&&(u=n.isDirty,n.isDirty=d.isDirty=K(),l=u!==d.isDirty);let t=L(b(i,e),r);u=!!b(n.dirtyFields,e),t===n.isDirty?t?H(n.dirtyFields,e):C(n.dirtyFields,e,!0):n.dirtyFields=U(i,a),d.dirtyFields=n.dirtyFields,l||=(M.dirtyFields||N.dirtyFields)&&u!==!t}if(o){let t=b(n.touchedFields,e);t||(C(n.touchedFields,e,o),d.touchedFields=n.touchedFields,l||=(M.touchedFields||N.touchedFields)&&t!==o)}l&&c&&I.state.next(d)}return l?d:{}},ge=(e,r,i,a)=>{let o=b(n.errors,e),s=(M.isValid||N.isValid)&&x(r)&&n.isValid!==r;if(t.delayError&&i?(k=te(()=>de(e,i)),k(t.delayError)):(clearTimeout(A),k=null,i?C(n.errors,e,i):H(n.errors,e)),(i?!L(o,i):o)||!V(a)||s){let t={...a,...s&&x(r)?{isValid:r}:{},errors:n.errors,name:e};n={...n,...t},I.state.next(t)}},W=async e=>(z(e,!0),await t.resolver(a,t.context,Se(e||p.mount,r,t.criteriaMode,t.shouldUseNativeValidation))),_e=async e=>{let{errors:t}=await W(e);if(z(e),e)for(let r of e){let e=b(t,r);e?p.array.has(r)&&u(e)?Ne(n.errors,{[r]:e},r):C(n.errors,r,e):H(n.errors,r)}else n.errors=t;return t},ve=async({name:t,eventType:r})=>{if(e.validate){let i=await e.validate({formValues:a,formState:n,name:t,eventType:r});if(u(i))for(let e in i){let t=i[e];t&&Q(`${D}.${e}`,{message:P(t.message)?t.message:``,type:t.type||E.validate})}else P(i)||!i?Q(D,{message:i||``,type:E.validate}):We(D);return i}return!0},G=async({fields:r,onlyCheckValid:i,name:o,eventType:s,context:c={valid:!0,runRootValidation:!1}})=>{if(e.validate&&(c.runRootValidation=!0,!await ve({name:o,eventType:s})&&(c.valid=!1,i)))return c.valid;for(let o in r){let l=r[o];if(l){let{_f:r,...u}=l;if(r){let o=p.array.has(r.name),s=l._f&&Te(l._f),u=M.validatingFields||M.isValidating||N.validatingFields||N.isValidating;s&&u&&z([r.name],!0);let d=await Fe(l,p.disabled,a,ee,t.shouldUseNativeValidation&&!i,o);if(s&&u&&z([r.name]),d[r.name]&&(c.valid=!1,i)||(!i&&(b(d,r.name)?o?Ne(n.errors,d,r.name):C(n.errors,r.name,d[r.name]):H(n.errors,r.name)),e.shouldUseNativeValidation&&d[r.name]))break}!V(u)&&await G({context:c,onlyCheckValid:i,fields:u,name:o,eventType:s})}}return c.valid},be=()=>{for(let e of p.unMount){let t=b(r,e);t&&(t._f.refs?t._f.refs.every(e=>!ue(e)):!ue(t._f.ref))&&Je(e)}p.unMount=new Set},K=(e,n)=>!t.disabled&&(e&&n&&C(a,e,n),!L(He(),i)),we=(e,t,n)=>F(e,p,{...l.mount?a:_(t)?i:P(e)?{[e]:t}:t},n,t),Pe=e=>v(b(l.mount?a:i,e,t.shouldUnregister?b(i,e,[]):[])),Y=(e,t,n={})=>{let i=b(r,e),s=t;if(i){let n=i._f;n&&(!n.disabled&&C(a,e,ye(t,n)),s=oe(n.ref)&&c(t)?``:t,se(n.ref)?[...n.ref.options].forEach(e=>e.selected=s.includes(e.value)):n.refs?o(n.ref)?n.refs.forEach(e=>{(!e.defaultChecked||!e.disabled)&&(Array.isArray(s)?e.checked=!!s.find(t=>t===e.value):e.checked=s===e.value||!!s)}):n.refs.forEach(e=>e.checked=e.value===s):ae(n.ref)?n.ref.value=``:(n.ref.value=s,n.ref.type||I.state.next({name:e,values:h(a)})))}(n.shouldDirty||n.shouldTouch)&&he(e,s,n.shouldTouch,n.shouldDirty,!0),n.shouldValidate&&Z(e)},Re=(e,t,n)=>{for(let i in t){if(!t.hasOwnProperty(i))return;let a=t[i],o=e+`.`+i,c=b(r,o);(p.array.has(e)||u(a)||c&&!c._f)&&!s(a)?Re(o,a,n):Y(o,a,n)}},X=(e,t,i={})=>{let o=b(r,e),s=p.array.has(e),u=h(t),d=L(b(a,e),u);if(d||C(a,e,u),s)I.array.next({name:e,values:h(a)}),(M.isDirty||M.dirtyFields||N.isDirty||N.dirtyFields)&&i.shouldDirty&&(ne(),I.state.next({name:e,dirtyFields:n.dirtyFields,isDirty:K(e,u)}));else{let t=Array.isArray(u)&&!u.length||V(u);!o||o._f||c(u)||t?Y(e,u,i):Re(e,u,i)}if(!d){let t=De(e,p),r=h(a);if(!s)for(let t of f(p.array,e))I.array.next({name:t,values:r});I.state.next({...t&&n,name:l.mount||t?e:void 0,values:r})}},ze=e=>{let t=S(e)?e(a):e;if(!L(a,t)){a={...a,...t};for(let e of p.mount)X(e,b(t,e));I.state.next({...n,values:a})}},Be=async i=>{l.mount=!0;let o=i.target,c=o.name,u=!0,f=b(r,c),m=e=>{u=Number.isNaN(e)||s(e)&&isNaN(e.getTime())||L(e,b(a,c,e))},g=q(t.mode),_=q(t.reValidateMode);if(f){let s,l,v=o.type?xe(f._f):d(i),y=i.type===w.BLUR||i.type===w.FOCUS_OUT,x=!Ee(f._f)&&!e.validate&&!t.resolver&&!b(n.errors,c)&&!f._f.deps||je(y,b(n.touchedFields,c),n.isSubmitted,_,g),S=De(c,p,y);C(a,c,v),y?(!o||!o.readOnly)&&(f._f.onBlur&&f._f.onBlur(i),k&&k(0)):f._f.onChange&&f._f.onChange(i);let T=he(c,v,y),E=!V(T)||S;if(!y&&I.state.next({name:c,type:i.type,values:h(a)}),x)return(M.isValid||N.isValid)&&(t.mode===`onBlur`?y&&R():y||R()),E&&I.state.next({name:c,...S?{}:T});if(!t.resolver&&e.validate&&await ve({name:c,eventType:i.type}),!y&&S&&I.state.next({...n}),t.resolver){let{errors:e}=await W([c]);if(z([c]),m(v),u){let t=Oe(n.errors,r,c),i=Oe(e,r,t.name||c);s=i.error,c=i.name,l=V(e)}}else z([c],!0),s=(await Fe(f,p.disabled,a,ee,t.shouldUseNativeValidation))[c],z([c]),m(v),u&&(s?l=!1:(M.isValid||N.isValid)&&(l=await G({fields:r,onlyCheckValid:!0,name:c,eventType:i.type})));u&&(f._f.deps&&(!Array.isArray(f._f.deps)||f._f.deps.length>0)&&Z(f._f.deps),ge(c,l,s,T))}},Ve=(e,t)=>{if(b(n.errors,t)&&e.focus)return e.focus(),1},Z=async(e,i={})=>{let a,o,s=B(e);if(t.resolver){let t=await _e(_(e)?e:s);a=V(t),o=e?!s.some(e=>b(t,e)):a}else e?(o=(await Promise.all(s.map(async e=>{let t=b(r,e);return await G({fields:t&&t._f?{[e]:t}:t,eventType:w.TRIGGER})}))).every(Boolean),!(!o&&!n.isValid)&&R()):o=a=await G({fields:r,name:e,eventType:w.TRIGGER});return I.state.next({...!P(e)||(M.isValid||N.isValid)&&a!==n.isValid?{}:{name:e},...t.resolver||!e?{isValid:a}:{},errors:n.errors}),i.shouldFocus&&!o&&J(r,Ve,e?s:p.mount),o},He=(e,t)=>{let r={...l.mount?a:i};return t&&(r=ie(t.dirtyFields?n.dirtyFields:n.touchedFields,r)),_(e)?r:P(e)?b(r,e):e.map(e=>b(r,e))},Ue=(e,t)=>({invalid:!!b((t||n).errors,e),isDirty:!!b((t||n).dirtyFields,e),error:b((t||n).errors,e),isValidating:!!b(n.validatingFields,e),isTouched:!!b((t||n).touchedFields,e)}),We=e=>{let t=e?B(e):void 0;t?.forEach(e=>H(n.errors,e)),t?t.forEach(e=>{I.state.next({name:e,errors:n.errors})}):I.state.next({errors:{}})},Q=(e,t,i)=>{let a=(b(r,e,{_f:{}})._f||{}).ref,{ref:o,message:s,type:c,...l}=b(n.errors,e)||{};C(n.errors,e,{...l,...t,ref:a}),I.state.next({name:e,errors:n.errors,isValid:!1}),i&&i.shouldFocus&&a&&a.focus&&a.focus()},Ge=(e,t)=>S(e)?I.state.subscribe({next:n=>`values`in n&&e(n.values||we(void 0,t),n)}):we(e,t,!0),Ke=e=>I.state.subscribe({next:t=>{if(Ae(e.name,t.name,e.exact)&&ke(t,e.formState||M,rt,e.reRenderRoot)){let r={...a};e.callback({values:r,...n,...t,defaultValues:i})}}}).unsubscribe,qe=e=>(l.mount=!0,N={...N,...e.formState},Ke({...e,formState:{...j,...e.formState}})),Je=(e,o={})=>{for(let s of e?B(e):p.mount)p.mount.delete(s),p.array.delete(s),o.keepValue||(H(r,s),H(a,s)),!o.keepError&&H(n.errors,s),!o.keepDirty&&H(n.dirtyFields,s),!o.keepTouched&&H(n.touchedFields,s),!o.keepIsValidating&&H(n.validatingFields,s),!t.shouldUnregister&&!o.keepDefaultValue&&H(i,s);I.state.next({values:h(a)}),I.state.next({...n,...o.keepDirty?{isDirty:K()}:{}}),!o.keepIsValid&&R()},Ye=({disabled:e,name:t})=>{if(x(e)&&l.mount||e||p.disabled.has(t)){let n=p.disabled.has(t)!==!!e;e?p.disabled.add(t):p.disabled.delete(t),n&&l.mount&&!l.action&&R()}},$=(e,n={})=>{let a=b(r,e),o=x(n.disabled)||x(t.disabled),s=!p.registerName.has(e)&&a&&a._f&&!a._f.mount;return C(r,e,{...a||{},_f:{...a&&a._f?a._f:{ref:{name:e}},name:e,mount:!0,...n}}),p.mount.add(e),a&&!s?Ye({disabled:x(n.disabled)?n.disabled:t.disabled,name:e}):me(e,!0,n.value),{...o?{disabled:n.disabled||t.disabled}:{},...t.progressive?{required:!!n.required,min:Ce(n.min),max:Ce(n.max),minLength:Ce(n.minLength),maxLength:Ce(n.maxLength),pattern:Ce(n.pattern)}:{},name:e,onChange:Be,onBlur:Be,ref:o=>{if(o){p.registerName.add(e),$(e,n),p.registerName.delete(e),a=b(r,e);let t=_(o.value)&&o.querySelectorAll&&o.querySelectorAll(`input,select,textarea`)[0]||o,s=le(t),c=a._f.refs||[];if(s?c.find(e=>e===t):t===a._f.ref)return;C(r,e,{_f:{...a._f,...s?{refs:[...c.filter(ue),t,...Array.isArray(b(i,e))?[{}]:[]],ref:{type:t.type,name:e}}:{ref:t}}}),me(e,!1,void 0,t)}else a=b(r,e,{}),a._f&&(a._f.mount=!1),(t.shouldUnregister||n.shouldUnregister)&&!(f(p.array,e).length&&l.action)&&p.unMount.add(e)}}},Xe=()=>t.shouldFocusError&&!t.shouldUseNativeValidation&&J(r,Ve,p.mount),Ze=e=>{x(e)&&(I.state.next({disabled:e}),J(r,(t,n)=>{let i=b(r,n);i&&(t.disabled=i._f.disabled||e,Array.isArray(i._f.refs)&&i._f.refs.forEach(t=>{t.disabled=i._f.disabled||e}))},0,!1))},Qe=(e,i)=>async o=>{let s;o&&(o.preventDefault&&o.preventDefault(),o.persist&&o.persist());let c=h(a);if(I.state.next({isSubmitting:!0}),t.resolver){let{errors:e,values:t}=await W();z(),n.errors=e,c=h(t)}else await G({fields:r,eventType:w.SUBMIT});if(p.disabled.size)for(let e of p.disabled)H(c,e);if(H(n.errors,O),V(n.errors)){I.state.next({errors:{}});try{await e(c,o)}catch(e){s=e}}else i&&await i({...n.errors},o),Xe(),setTimeout(Xe);if(I.state.next({isSubmitted:!0,isSubmitting:!1,isSubmitSuccessful:V(n.errors)&&!s,submitCount:n.submitCount+1,errors:n.errors}),s)throw s},$e=(e,t={})=>{b(r,e)&&(_(t.defaultValue)?X(e,h(b(i,e))):(X(e,t.defaultValue),C(i,e,h(t.defaultValue))),t.keepTouched||H(n.touchedFields,e),t.keepDirty||(H(n.dirtyFields,e),n.isDirty=t.defaultValue?K(e,h(b(i,e))):K()),t.keepError||(H(n.errors,e),M.isValid&&R()),I.state.next({...n}))},et=(e,o={})=>{let s=e?h(e):i,c=h(s),u=V(e),d=u?i:c;if(o.keepDefaultValues||(i=s),!o.keepValues){if(o.keepDirtyValues){let e=new Set([...p.mount,...Object.keys(U(i,a))]);for(let t of Array.from(e)){let e=b(n.dirtyFields,t),r=b(a,t),i=b(d,t);e&&!_(r)?C(d,t,r):!e&&!_(i)&&X(t,i)}}else{if(m&&_(e))for(let e of p.mount){let t=b(r,e);if(t&&t._f){let e=Array.isArray(t._f.refs)?t._f.refs[0]:t._f.ref;if(oe(e)){let t=e.closest(`form`);if(t){t.reset();break}}}}if(o.keepFieldsRef)for(let e of p.mount)X(e,b(d,e));else r={}}a=t.shouldUnregister?o.keepDefaultValues?h(i):{}:h(d),I.array.next({values:{...d}}),I.state.next({values:{...d}})}p={mount:o.keepDirtyValues?p.mount:new Set,unMount:new Set,array:new Set,registerName:new Set,disabled:new Set,watch:new Set,watchAll:!1,focus:``},l.mount=!M.isValid||!!o.keepIsValid||!!o.keepDirtyValues||!t.shouldUnregister&&!V(d),l.watch=!!t.shouldUnregister,l.keepIsValid=!!o.keepIsValid,l.action=!1,o.keepErrors||(n.errors={}),I.state.next({submitCount:o.keepSubmitCount?n.submitCount:0,isDirty:u?!1:o.keepDirty?n.isDirty:!!(o.keepDefaultValues&&!L(e,i)),isSubmitted:o.keepIsSubmitted?n.isSubmitted:!1,dirtyFields:u?{}:o.keepDirtyValues?o.keepDefaultValues&&a?U(i,a):n.dirtyFields:o.keepDefaultValues&&e?U(i,e):o.keepDirty?n.dirtyFields:{},touchedFields:o.keepTouched?n.touchedFields:{},errors:o.keepErrors?n.errors:{},isSubmitSuccessful:o.keepIsSubmitSuccessful?n.isSubmitSuccessful:!1,isSubmitting:!1,defaultValues:i})},tt=(e,n)=>et(S(e)?e(a):e,{...t.resetOptions,...n}),nt=(e,t={})=>{let n=b(r,e),i=n&&n._f;if(i){let e=i.refs?i.refs[0]:i.ref;e.focus&&setTimeout(()=>{e.focus(),t.shouldSelect&&S(e.select)&&e.select()})}},rt=e=>{n={...n,...e}},it={control:{register:$,unregister:Je,getFieldState:Ue,handleSubmit:Qe,setError:Q,_subscribe:Ke,_runSchema:W,_updateIsValidating:z,_focusError:Xe,_getWatch:we,_getDirty:K,_setValid:R,_setFieldArray:ce,_setDisabledField:Ye,_setErrors:fe,_getFieldArray:Pe,_reset:et,_resetDefaultValues:()=>S(t.defaultValues)&&t.defaultValues().then(e=>{tt(e,t.resetOptions),I.state.next({isLoading:!1})}),_removeUnmounted:be,_disableForm:Ze,_subjects:I,_proxyFormState:M,get _fields(){return r},get _formValues(){return a},get _state(){return l},set _state(e){l=e},get _defaultValues(){return i},get _names(){return p},set _names(e){p=e},get _formState(){return n},get _options(){return t},set _options(e){t={...t,...e}}},subscribe:qe,trigger:Z,register:$,handleSubmit:Qe,watch:Ge,setValue:X,setValues:ze,getValues:He,reset:tt,resetField:$e,clearErrors:We,unregister:Je,setError:Q,setFocus:nt,getFieldState:Ue};return{...it,formControl:it}}var X=()=>{if(typeof crypto<`u`&&crypto.randomUUID)return crypto.randomUUID();let e=typeof performance>`u`?Date.now():performance.now()*1e3;return`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,t=>{let n=(Math.random()*16+e)%16|0;return(t==`x`?n:n&3|8).toString(16)})},ze=(e,t,n={})=>n.shouldFocus||_(n.shouldFocus)?n.focusName||`${e}.${_(n.focusIndex)?t:n.focusIndex}.`:``,Be=(e,t)=>[...e,...B(t)],Ve=e=>Array.isArray(e)?e.map(()=>void 0):void 0;function Z(e,t,n){return[...e.slice(0,t),...B(n),...e.slice(t)]}var He=(e,t,n)=>Array.isArray(e)?(_(e[n])&&(e[n]=void 0),e.splice(n,0,e.splice(t,1)[0]),e):[],Ue=(e,t)=>[...B(t),...B(e)];function We(e,t){let n=0,r=[...e];for(let e of t)r.splice(e-n,1),n++;return v(r).length?r:[]}var Q=(e,t)=>_(t)?[]:We(e,B(t).sort((e,t)=>e-t)),Ge=(e,t,n)=>{[e[t],e[n]]=[e[n],e[t]]},Ke=(e,t,n)=>(e[t]=n,e);function qe(e){let t=A(),{control:n=t,name:r,keyName:i=`id`,shouldUnregister:o,rules:s}=e,[c,l]=a.useState(n._getFieldArray(r)),u=a.useRef(n._getFieldArray(r).map(X)),d=a.useRef(!1);n._names.array.add(r),a.useMemo(()=>s&&c.length>=0&&n.register(r,s),[n,r,c.length,s]),M(()=>n._subjects.array.subscribe({next:({values:e,name:t})=>{if(t===r||!t){let t=b(e,r);Array.isArray(t)&&(l(t),u.current=t.map(X))}}}).unsubscribe,[n,r]);let f=a.useCallback(e=>{d.current=!0,n._setFieldArray(r,e)},[n,r]);return a.useEffect(()=>{n._state.action=!1,De(r,n._names)&&n._subjects.state.next({...n._formState});let e=q(n._options.mode);if(d.current&&(!e.isOnSubmit||n._formState.isSubmitted)&&!q(n._options.reValidateMode).isOnSubmit&&!e.isOnBlur)if(n._options.resolver)n._runSchema([r]).then(e=>{n._updateIsValidating([r]);let t=b(e.errors,r),i=b(n._formState.errors,r);(i?!t&&i.type||t&&(i.type!==t.type||i.message!==t.message):t&&t.type)&&(t?C(n._formState.errors,r,t):H(n._formState.errors,r),n._subjects.state.next({errors:n._formState.errors}))});else{let e=b(n._fields,r);e&&e._f&&!(q(n._options.reValidateMode).isOnSubmit&&q(n._options.mode).isOnSubmit)&&Fe(e,n._names.disabled,n._formValues,n._options.criteriaMode===T.all,n._options.shouldUseNativeValidation,!0).then(e=>!V(e)&&n._subjects.state.next({errors:Ne(n._formState.errors,e,r)}))}n._subjects.state.next({name:r,values:h(n._formValues)}),n._names.focus&&J(n._fields,(e,t)=>{if(n._names.focus&&t.startsWith(n._names.focus)&&e.focus)return e.focus(),1}),n._names.focus=``,n._setValid(),d.current=!1},[c,r,n]),a.useEffect(()=>(!b(n._formValues,r)&&n._setFieldArray(r),()=>{let e=!(n._options.shouldUnregister||o);d.current&&e&&n._subjects.state.next({name:r,values:h(n._formValues)}),e?((e,t)=>{let r=b(n._fields,e);r&&r._f&&(r._f.mount=t)})(r,!1):n.unregister(r)}),[r,n,i,o]),{swap:a.useCallback((e,t)=>{let i=n._getFieldArray(r);Ge(i,e,t),Ge(u.current,e,t),f(i),l(i),n._setFieldArray(r,i,Ge,{argA:e,argB:t},!1)},[f,r,n]),move:a.useCallback((e,t)=>{let i=n._getFieldArray(r);He(i,e,t),He(u.current,e,t),f(i),l(i),n._setFieldArray(r,i,He,{argA:e,argB:t},!1)},[f,r,n]),prepend:a.useCallback((e,t)=>{let i=B(h(e)),a=Ue(n._getFieldArray(r),i);n._names.focus=ze(r,0,t),u.current=Ue(u.current,i.map(X)),f(a),l(a),n._setFieldArray(r,a,Ue,{argA:Ve(e)})},[f,r,n]),append:a.useCallback((e,t)=>{let i=B(h(e)),a=Be(n._getFieldArray(r),i);n._names.focus=ze(r,a.length-1,t),u.current=Be(u.current,i.map(X)),f(a),l(a),n._setFieldArray(r,a,Be,{argA:Ve(e)})},[f,r,n]),remove:a.useCallback(e=>{let t=Q(n._getFieldArray(r),e);u.current=Q(u.current,e),f(t),l(t),!Array.isArray(b(n._fields,r))&&C(n._fields,r,void 0),n._setFieldArray(r,t,Q,{argA:e})},[f,r,n]),insert:a.useCallback((e,t,i)=>{let a=B(h(t)),o=Z(n._getFieldArray(r),e,a);n._names.focus=ze(r,e,i),u.current=Z(u.current,e,a.map(X)),f(o),l(o),n._setFieldArray(r,o,Z,{argA:e,argB:Ve(t)})},[f,r,n]),update:a.useCallback((e,t)=>{let i=h(t),a=Ke(n._getFieldArray(r),e,i);u.current=[...a].map((t,n)=>!t||n===e?X():u.current[n]),f(a),l([...a]),n._setFieldArray(r,a,Ke,{argA:e,argB:i},!0,!1)},[f,r,n]),replace:a.useCallback(e=>{let t=B(h(e));u.current=t.map(X),f([...t]),l([...t]),n._setFieldArray(r,[...t],e=>e,{},!0,!1)},[f,r,n]),fields:a.useMemo(()=>c.map((e,t)=>({...e,[i]:u.current[t]||X()})),[c,i])}}function Je(e={}){let t=a.useRef(void 0),n=a.useRef(void 0),[r,i]=a.useState(()=>({...h(Le),isLoading:S(e.defaultValues),errors:e.errors||{},disabled:e.disabled||!1,defaultValues:S(e.defaultValues)?void 0:e.defaultValues}));if(!t.current)if(e.formControl)t.current={...e.formControl,formState:r},e.defaultValues&&!S(e.defaultValues)&&e.formControl.reset(e.defaultValues,e.resetOptions);else{let{formControl:n,...i}=Re(e);t.current={...i,formState:r}}let o=t.current.control;return o._options=e,M(()=>{let e=o._subscribe({formState:o._proxyFormState,callback:()=>i({...o._formState,defaultValues:o._defaultValues}),reRenderRoot:!0});return i(e=>({...e,isReady:!0})),o._formState.isReady=!0,e},[o]),a.useEffect(()=>o._disableForm(e.disabled),[o,e.disabled]),a.useEffect(()=>{e.mode&&(o._options.mode=e.mode),e.reValidateMode&&(o._options.reValidateMode=e.reValidateMode)},[o,e.mode,e.reValidateMode]),a.useEffect(()=>{e.errors&&(o._setErrors(e.errors),o._focusError())},[o,e.errors]),a.useEffect(()=>{e.shouldUnregister&&o._subjects.state.next({values:o._getWatch()})},[o,e.shouldUnregister]),a.useEffect(()=>{if(o._proxyFormState.isDirty){let e=o._getDirty();e!==r.isDirty&&o._subjects.state.next({isDirty:e})}},[o,r.isDirty]),a.useEffect(()=>{e.values&&!L(e.values,n.current)?(o._reset(e.values,{keepFieldsRef:!0,...o._options.resetOptions}),o._options.resetOptions?.keepIsValid||o._setValid(),n.current=e.values,i(e=>({...e}))):o._resetDefaultValues()},[o,e.values]),a.useEffect(()=>{o._state.mount||(o._setValid(),o._state.mount=!0),o._state.watch&&(o._state.watch=!1,o._subjects.state.next({...o._formState})),o._removeUnmounted()}),t.current.formState=a.useMemo(()=>j(r,o),[o,r]),t.current}var Ye=(e,t,n)=>{if(e&&`reportValidity`in e){let r=b(n,t);e.setCustomValidity(r&&r.message||``),e.reportValidity()}},$=(e,t)=>{for(let n in t.fields){let r=t.fields[n];r&&r.ref&&`reportValidity`in r.ref?Ye(r.ref,n,e):r&&r.refs&&r.refs.forEach(t=>Ye(t,n,e))}},Xe=(e,t)=>{t.shouldUseNativeValidation&&$(e,t);let n={};for(let r in e){let i=b(t.fields,r),a=Object.assign(e[r]||{},{ref:i&&i.ref});if(Ze(t.names||Object.keys(e),r)){let e=Object.assign({},b(n,r));C(e,`root`,a),C(n,r,e)}else C(n,r,a)}return n},Ze=(e,t)=>{let n=Qe(t);return e.some(e=>Qe(e).match(`^${n}\\.\\d+`))};function Qe(e){return e.replace(/\]|\[/g,``)}function $e(e,t){try{var n=e()}catch(e){return t(e)}return n&&n.then?n.then(void 0,t):n}function et(e,t){for(var n={};e.length;){var r=e[0],i=r.code,a=r.message,o=r.path.join(`.`);if(!n[o])if(`unionErrors`in r){var s=r.unionErrors[0].errors[0];n[o]={message:s.message,type:s.code}}else n[o]={message:a,type:i};if(`unionErrors`in r&&r.unionErrors.forEach(function(t){return t.errors.forEach(function(t){return e.push(t)})}),t){var c=n[o].types,l=c&&c[r.code];n[o]=ne(o,t,n,i,l?[].concat(l,r.message):r.message)}e.shift()}return n}function tt(e,t){for(var n={};e.length;){var r=e[0],i=r.code,a=r.message,o=r.path.join(`.`);if(!n[o])if(r.code===`invalid_union`&&r.errors.length>0){var s=r.errors[0][0];n[o]={message:s.message,type:s.code}}else n[o]={message:a,type:i};if(r.code===`invalid_union`&&r.errors.forEach(function(t){return t.forEach(function(t){return e.push(t)})}),t){var c=n[o].types,l=c&&c[r.code];n[o]=ne(o,t,n,i,l?[].concat(l,r.message):r.message)}e.shift()}return n}function nt(t,i,a){if(a===void 0&&(a={}),function(e){return`_def`in e&&typeof e._def==`object`&&`typeName`in e._def}(t))return function(e,n,r){try{return Promise.resolve($e(function(){return Promise.resolve(t[a.mode===`sync`?`parse`:`parseAsync`](e,i)).then(function(t){return r.shouldUseNativeValidation&&$({},r),{errors:{},values:a.raw?Object.assign({},e):t}})},function(e){if(function(e){return Array.isArray(e?.issues)}(e))return{values:{},errors:Xe(et(e.errors,!r.shouldUseNativeValidation&&r.criteriaMode===`all`),r)};throw e}))}catch(e){return Promise.reject(e)}};if(function(e){return`_zod`in e&&typeof e._zod==`object`}(t))return function(o,s,c){try{return Promise.resolve($e(function(){return Promise.resolve((a.mode===`sync`?n:r)(t,o,i)).then(function(e){return c.shouldUseNativeValidation&&$({},c),{errors:{},values:a.raw?Object.assign({},o):e}})},function(t){if(function(t){return t instanceof e}(t))return{values:{},errors:Xe(tt(t.issues,!c.shouldUseNativeValidation&&c.criteriaMode===`all`),c)};throw t}))}catch(e){return Promise.reject(e)}};throw Error(`Invalid input: not a Zod schema`)}export{ee as a,Je as i,R as n,qe as r,nt as t}; \ No newline at end of file diff --git a/spinifex/services/spinifexui/frontend/package.json b/spinifex/services/spinifexui/frontend/package.json index 551e9c3c6..792fc95ab 100644 --- a/spinifex/services/spinifexui/frontend/package.json +++ b/spinifex/services/spinifexui/frontend/package.json @@ -14,6 +14,7 @@ }, "dependencies": { "@aws-crypto/sha256-browser": "^5.2.0", + "@aws-sdk/client-acm": "^3.1057.0", "@aws-sdk/client-ec2": "^3.1045.0", "@aws-sdk/client-elastic-load-balancing-v2": "^3.1045.0", "@aws-sdk/client-iam": "^3.1045.0", diff --git a/spinifex/services/spinifexui/frontend/pnpm-lock.yaml b/spinifex/services/spinifexui/frontend/pnpm-lock.yaml index 36755985c..276e4ccfe 100644 --- a/spinifex/services/spinifexui/frontend/pnpm-lock.yaml +++ b/spinifex/services/spinifexui/frontend/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@aws-crypto/sha256-browser': specifier: ^5.2.0 version: 5.2.0 + '@aws-sdk/client-acm': + specifier: ^3.1057.0 + version: 3.1057.0 '@aws-sdk/client-ec2': specifier: ^3.1045.0 version: 3.1045.0 @@ -179,6 +182,10 @@ packages: '@aws-crypto/util@5.2.0': resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + '@aws-sdk/client-acm@3.1057.0': + resolution: {integrity: sha512-CmYDvRAl+VVaBWpcH2nOjney8dFcS9SsbjNLjE9Ldqy5p+I2TpSJiAmysR8wvqFb3zzt3Ebt66oNPwLKcJx6bw==} + engines: {node: '>=20.0.0'} + '@aws-sdk/client-ec2@3.1045.0': resolution: {integrity: sha512-/ShpsuHZbpwiNBSRc6rupxFRh/NqKTaxAZv34w58tPFOgghpJ8vPX2VV+FZiZJWHqrdQfwk7PhStxRpOz+ru+w==} engines: {node: '>=20.0.0'} @@ -195,6 +202,10 @@ packages: resolution: {integrity: sha512-fsuO3Y6t+3Ro9Bsg41DKj4Sfy53CGSrhnMldNplWmG8Tx0UbYk+YDa4RD1hVlJpERw4JBmPkl0+J9qlxMh1pcA==} engines: {node: '>=20.0.0'} + '@aws-sdk/core@3.974.15': + resolution: {integrity: sha512-UpA0rTGW/tHGITcCqHisbuuEPraYg9GG+mWmXjY5+RxZBMLGe6aL9oe0ix50LztwAcPIkGZLH0yWdMIkCM10hw==} + engines: {node: '>=20.0.0'} + '@aws-sdk/core@3.974.8': resolution: {integrity: sha512-njR2qoG6ZuB0kvAS2FyICsFZJ6gmCcf2X/7JcD14sUvGDm26wiZ5BrA6LOiUxKFEF+IVe7kdroxyE00YlkiYsw==} engines: {node: '>=20.0.0'} @@ -207,34 +218,66 @@ packages: resolution: {integrity: sha512-XT0jtf8Fw9JE6ppsQeoNnZRiG+jqRixMT1v1ZR17G60UvVdsQmTG8nbEyHuEPfMxDXEhfdARaM/XiEhca4lGHQ==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-env@3.972.41': + resolution: {integrity: sha512-n1EbJ98yvPWWdHZZv8bRBMqqDQJrtgtxyJ4xLy2Uqrh25BCOZQ7nnS1CsFXvuH8r0b0KVHDZEGEH5FxmEMP8jg==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-http@3.972.36': resolution: {integrity: sha512-DPoGWfy7J7RKxvbf5kOKIGQkD2ek3dbKgzKIGrnLuvZBz5myU+Im/H6pmc14QcnFbqHMqxvtWSgRDSJW3qXLQg==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-http@3.972.43': + resolution: {integrity: sha512-TT76RN1NkI9WoyZqCNxOw6/WBMF7pYOTJcXbMokNFU+euSG40Kaf/t/FhDACVZWP+43wEM6ZynIPIkzS1wR1iA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-ini@3.972.38': resolution: {integrity: sha512-oDzUBu2MGJFgoar05sPMCwSrhw44ASyccrHzj66vO69OZqi7I6hZZxXfuPLC8OCzW7C+sU+bI73XHij41yekgQ==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-ini@3.972.46': + resolution: {integrity: sha512-hvcgcwOiS0nb2XFb5Op1Pz/vYaWz5K8kKullziGpdNRuG0NwzRXseuPt2CoBqknHGaSPVesu1aOn2OcctEYdCA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-login@3.972.38': resolution: {integrity: sha512-g1NosS8qe4OF++G2UFCM5ovSkgipC7YYor5KCWatG0UoMSO5YFj9C8muePlyVmOBV/WTI16Jo3/s1NUo/o1Bww==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-login@3.972.45': + resolution: {integrity: sha512-MZQv4SNjByk1iOKmrqmzcUF/uCB05wjvEHyXKxmGQTUANTIVayX6HPUF0bzkWLvtnkH7sAn9kUCfkXbSpj9sDA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-node@3.972.39': resolution: {integrity: sha512-HEswDQyxUtadoZ/bJsPPENHg7R0Lzym5LuMksJeHvqhCOpP+rtkDLKI4/ZChH4w3cf5kG8n6bZuI8PzajoiqMg==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-node@3.972.47': + resolution: {integrity: sha512-HrId+C0DWA5qDIyLG64/kjUB2RNtPypxmABnIctK+TA1P1kHlOYoE/Wf5T5tKOMKgb08P7k/zNyhvfJ3lh5Oag==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-process@3.972.34': resolution: {integrity: sha512-T3IFs4EVmVi1dVN5RciFnklCANSzvrQd/VuHY9ThHSQmYkTogjcGkoJEr+oNUPQZnso52183088NqysMPji1/Q==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-process@3.972.41': + resolution: {integrity: sha512-7I/n1zkysouLOWvkEhjNEP4vMnD2v4kzzr3/3QBdrripEpn7ap1/I5DF3Hou1SUqkKWo1f3oPGMyFAA1FAMvsQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-sso@3.972.38': resolution: {integrity: sha512-5ZxG+t0+3Q3QPh8KEjX6syskhgNf7I0MN7oGioTf6Lm1NTjfP7sIcYGNsthXC2qR8vcD3edNZwCr2ovfSSWuRA==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-sso@3.972.45': + resolution: {integrity: sha512-oHgbz/eFD8IKiksqDsz9ZMU4A59BpQq4QwJedBnGD80ZqYcHPPHZBwjBnxLVkB7iRVVHWpDclR8yWdD2PkQIUA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-web-identity@3.972.38': resolution: {integrity: sha512-lYHFF30DGI20jZcYX8cm6Ns0V7f1dDN6g/MBDLTyD/5iw+bXs3yBr2iAiHDkx4RFU5JgsnZvCHYKiRVPRdmOgw==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-web-identity@3.972.45': + resolution: {integrity: sha512-CDhzKdb2onv5bpnjn/acgdNmJOQthPDLsPizU7rZflsEcgMMp8Mlri+U5hdxf8ldvZJpvM3vLU6D56vfJm5AMQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/lib-storage@3.1045.0': resolution: {integrity: sha512-F7dp2ST/83Iz6JTMMmUYEXxg7R1JDewfvzJeWWiDTwe0vLsg67JTN7OsBe6G8DWYbLQ+EyPWkyc3oFnxOjCVfg==} engines: {node: '>=20.0.0'} @@ -285,6 +328,10 @@ packages: resolution: {integrity: sha512-iz+B29TXcAZsJpwB+AwG/TTGA5l/VnmMZ2UxtiySOZjI6gCdmviXPwdgzcmuazMy16rXoPY4mYCGe7zdNKfx5A==} engines: {node: '>=20.0.0'} + '@aws-sdk/nested-clients@3.997.13': + resolution: {integrity: sha512-2pA6eyb5nSo/ZD2cayhOTEMoGQYgspq0RI05GDLkzQ3ajZ6isS6waV6E92Am/hz4LIlLUTrbwPLurJ/fuiHvkg==} + engines: {node: '>=20.0.0'} + '@aws-sdk/nested-clients@3.997.6': resolution: {integrity: sha512-WBDnqatJl+kGObpfmfSxqnXeYTu3Me8wx8WCtvoxX3pfWrrTv8I4WTMSSs7PZqcRcVh8WeUKMgGFjMG+52SR1w==} engines: {node: '>=20.0.0'} @@ -297,10 +344,18 @@ packages: resolution: {integrity: sha512-+CMIt3e1VzlklAECmG+DtP1sV8iKq25FuA0OKpnJ4KA0kxUtd7CgClY7/RU6VzJBQwbN4EJ9Ue6plvqx1qGadw==} engines: {node: '>=20.0.0'} + '@aws-sdk/signature-v4-multi-region@3.996.30': + resolution: {integrity: sha512-HULDLMVzkmTSEv6//7kx2kRevp/VYUpm8hJNNFbmhxDn0fUiGTxVcM9yg31TukvTq8nyOBDUN2gH0o5IRbKjdw==} + engines: {node: '>=20.0.0'} + '@aws-sdk/token-providers@3.1041.0': resolution: {integrity: sha512-Th7kPI6YPtvJUcdznooXJMy+9rQWjmEF81LxaJssngBzuysK4a/x+l8kjm1zb7nYsUPbndnBdUnwng/3PLvtGw==} engines: {node: '>=20.0.0'} + '@aws-sdk/token-providers@3.1056.0': + resolution: {integrity: sha512-81duvlltQlsfn5K+o8zILcystBRdbT1G2JJYVCML5NZHBz4CL/zf+sAemCtBh/uh6RQUMyInGeZLQ7/8igZhbA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/types@3.973.6': resolution: {integrity: sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw==} engines: {node: '>=20.0.0'} @@ -309,6 +364,10 @@ packages: resolution: {integrity: sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw==} engines: {node: '>=20.0.0'} + '@aws-sdk/types@3.973.9': + resolution: {integrity: sha512-kuBfgQVdcz5Bmapc4A13YbpVw/pXkesfhetcFYwbntqas8sF41OHyd4o28+/TG2ZQdHBsv90Lsu5y6oitvYCdg==} + engines: {node: '>=20.0.0'} + '@aws-sdk/util-arn-parser@3.972.3': resolution: {integrity: sha512-HzSD8PMFrvgi2Kserxuff5VitNq2sgf3w9qxmskKDiDTThWfVteJxuCS9JXiPIPtmCrp+7N9asfIaVhBFORllA==} engines: {node: '>=20.0.0'} @@ -341,6 +400,10 @@ packages: resolution: {integrity: sha512-PMYKKtJd70IsSG0yHrdAbxBr+ZWBKLvzFZfD3/urxgf6hXVMzuU5M+3MJ5G67RpOmLBu1fAUN65SbWuKUCOlAA==} engines: {node: '>=20.0.0'} + '@aws-sdk/xml-builder@3.972.26': + resolution: {integrity: sha512-cDbrqvDS73whl6YAPSPq0U6whzG6UWI9PuWh0wrUuGoZexhWEqhdunbukV7iBoaWnFV1AODutM5hOD6rtn439g==} + engines: {node: '>=20.0.0'} + '@aws/lambda-invoke-store@0.2.4': resolution: {integrity: sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==} engines: {node: '>=18.0.0'} @@ -997,10 +1060,18 @@ packages: resolution: {integrity: sha512-x7BlLbUFL8NWCGjMF9C+1N5cVCxcPa7g6Tv9B4A2luWx3be3oU8hQ96wIwxe/s7OhIzvoJH73HAUSg5JXVlEtQ==} engines: {node: '>=18.0.0'} + '@smithy/core@3.24.5': + resolution: {integrity: sha512-Kt8phUg45M15EjhYAbZ+fFikYneijLu9Liugz8ZsYz2i8j0hzGv27LWKpEHYRfvj+LyCOSijpcR/2i8RouV+cA==} + engines: {node: '>=18.0.0'} + '@smithy/credential-provider-imds@4.2.14': resolution: {integrity: sha512-Au28zBN48ZAoXdooGUHemuVBrkE+Ie6RPmGNIAJsFqj33Vhb6xAgRifUydZ2aY+M+KaMAETAlKk5NC5h1G7wpg==} engines: {node: '>=18.0.0'} + '@smithy/credential-provider-imds@4.3.6': + resolution: {integrity: sha512-tHhdiWZfG1ZIh2YcRfPJmY2gHcBmqbAzqm3ER4TIDFYsSEqTD5tICT7cgQ/kI8LRakxp12myOYyK68XPn7MnHw==} + engines: {node: '>=18.0.0'} + '@smithy/eventstream-codec@4.2.14': resolution: {integrity: sha512-erZq0nOIpzfeZdCyzZjdJb4nVSKLUmSkaQUVkRGQTXs30gyUGeKnrYEg+Xe1W5gE3aReS7IgsvANwVPxSzY6Pw==} engines: {node: '>=18.0.0'} @@ -1025,6 +1096,10 @@ packages: resolution: {integrity: sha512-bXOvQzaSm6MnmLaWA1elgfQcAtN4UP3vXqV97bHuoOrHQOJiLT3ds6o9eo5bqd0TJfRFpzdGnDQdW3FACiAVdw==} engines: {node: '>=18.0.0'} + '@smithy/fetch-http-handler@5.4.5': + resolution: {integrity: sha512-SK3VMeH0fibgdTg2QeB+O4p7Yy/2E5HBOHJeC58FshkDdeuX8lOgO7PfjYfLyPLP1ch55j91cQqKBzDS0mRjSQ==} + engines: {node: '>=18.0.0'} + '@smithy/hash-blob-browser@4.2.15': resolution: {integrity: sha512-0PJ4Al3fg2nM4qKrAIxyNcApgqHAXcBkN8FeizOz69z0rb26uZ6lMESYtxegaTlXB5Hj84JfwMPavMrwDMjucA==} engines: {node: '>=18.0.0'} @@ -1081,6 +1156,10 @@ packages: resolution: {integrity: sha512-iB+orM4x3xrr57X3YaXazfKnntl0LHlZB1kcXSGzMV1Tt0+YwEjGlbjk/44qEGtBzXAz6yFDzkYTKSV6Pj2HUg==} engines: {node: '>=18.0.0'} + '@smithy/node-http-handler@4.7.5': + resolution: {integrity: sha512-3dA9TQ+ybRSZ/m0wnbZhiBy4Dezjgq1Ib/ZZrYTpJDBgpoLLU/SDzZc/g0x0MNAdOJe1wPcM+x2PBRmoOur+Sw==} + engines: {node: '>=18.0.0'} + '@smithy/property-provider@4.2.14': resolution: {integrity: sha512-WuM31CgfsnQ/10i7NYr0PyxqknD72Y5uMfUMVSniPjbEPceiTErb4eIqJQ+pdxNEAUEWrewrGjIRjVbVHsxZiQ==} engines: {node: '>=18.0.0'} @@ -1109,6 +1188,10 @@ packages: resolution: {integrity: sha512-1D9Y/nmlVjCeSivCbhZ7hgEpmHyY1h0GvpSZt3l0xcD9JjmjVC1CHOozS6+Gh+/ldMH8JuJ6cujObQqfayAVFA==} engines: {node: '>=18.0.0'} + '@smithy/signature-v4@5.4.5': + resolution: {integrity: sha512-QBJKWGqIknH0dc9LWpfH1mkdokAx6iXYN3UcQ3eY6uIEyScuoQAhfl94ge7ozUy9WgFUdE8xsvwBjaYBbWmPNA==} + engines: {node: '>=18.0.0'} + '@smithy/smithy-client@4.12.13': resolution: {integrity: sha512-y/Pcj1V9+qG98gyu1gvftHB7rDpdh+7kIBIggs55yGm3JdtBV8GT8IFF3a1qxZ79QnaJHX9GXzvBG6tAd+czJA==} engines: {node: '>=18.0.0'} @@ -1117,6 +1200,10 @@ packages: resolution: {integrity: sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg==} engines: {node: '>=18.0.0'} + '@smithy/types@4.14.2': + resolution: {integrity: sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw==} + engines: {node: '>=18.0.0'} + '@smithy/url-parser@4.2.14': resolution: {integrity: sha512-p06BiBigJ8bTA3MgnOfCtDUWnAMY0YfedO/GRpmc7p+wg3KW8vbXy1xwSu5ASy0wV7rRYtlfZOIKH4XqfhjSQQ==} engines: {node: '>=18.0.0'} @@ -1871,6 +1958,10 @@ packages: resolution: {integrity: sha512-P7oW7tLbYnhOLQk/Gv7cZgzgMPP/XN03K02/Jy6Y/NHzyIAIpxuZIM/YqAkfiXFPxA2CTm7NtCijK9EDu09u2w==} hasBin: true + fast-xml-parser@5.7.3: + resolution: {integrity: sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg==} + hasBin: true + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -2662,10 +2753,23 @@ snapshots: '@aws-crypto/util@5.2.0': dependencies: - '@aws-sdk/types': 3.973.6 + '@aws-sdk/types': 3.973.8 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 + '@aws-sdk/client-acm@3.1057.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.974.15 + '@aws-sdk/credential-provider-node': 3.972.47 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.5 + '@smithy/fetch-http-handler': 5.4.5 + '@smithy/node-http-handler': 4.7.5 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@aws-sdk/client-ec2@3.1045.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 @@ -2862,6 +2966,17 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/core@3.974.15': + dependencies: + '@aws-sdk/types': 3.973.9 + '@aws-sdk/xml-builder': 3.972.26 + '@aws/lambda-invoke-store': 0.2.4 + '@smithy/core': 3.24.5 + '@smithy/signature-v4': 5.4.5 + '@smithy/types': 4.14.2 + bowser: 2.14.1 + tslib: 2.8.1 + '@aws-sdk/core@3.974.8': dependencies: '@aws-sdk/types': 3.973.8 @@ -2892,6 +3007,14 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 + '@aws-sdk/credential-provider-env@3.972.41': + dependencies: + '@aws-sdk/core': 3.974.15 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.5 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@aws-sdk/credential-provider-http@3.972.36': dependencies: '@aws-sdk/core': 3.974.8 @@ -2905,6 +3028,16 @@ snapshots: '@smithy/util-stream': 4.5.25 tslib: 2.8.1 + '@aws-sdk/credential-provider-http@3.972.43': + dependencies: + '@aws-sdk/core': 3.974.15 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.5 + '@smithy/fetch-http-handler': 5.4.5 + '@smithy/node-http-handler': 4.7.5 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@aws-sdk/credential-provider-ini@3.972.38': dependencies: '@aws-sdk/core': 3.974.8 @@ -2924,6 +3057,22 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-ini@3.972.46': + dependencies: + '@aws-sdk/core': 3.974.15 + '@aws-sdk/credential-provider-env': 3.972.41 + '@aws-sdk/credential-provider-http': 3.972.43 + '@aws-sdk/credential-provider-login': 3.972.45 + '@aws-sdk/credential-provider-process': 3.972.41 + '@aws-sdk/credential-provider-sso': 3.972.45 + '@aws-sdk/credential-provider-web-identity': 3.972.45 + '@aws-sdk/nested-clients': 3.997.13 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.5 + '@smithy/credential-provider-imds': 4.3.6 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@aws-sdk/credential-provider-login@3.972.38': dependencies: '@aws-sdk/core': 3.974.8 @@ -2937,6 +3086,15 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-login@3.972.45': + dependencies: + '@aws-sdk/core': 3.974.15 + '@aws-sdk/nested-clients': 3.997.13 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.5 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@aws-sdk/credential-provider-node@3.972.39': dependencies: '@aws-sdk/credential-provider-env': 3.972.34 @@ -2954,6 +3112,20 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-node@3.972.47': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.41 + '@aws-sdk/credential-provider-http': 3.972.43 + '@aws-sdk/credential-provider-ini': 3.972.46 + '@aws-sdk/credential-provider-process': 3.972.41 + '@aws-sdk/credential-provider-sso': 3.972.45 + '@aws-sdk/credential-provider-web-identity': 3.972.45 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.5 + '@smithy/credential-provider-imds': 4.3.6 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@aws-sdk/credential-provider-process@3.972.34': dependencies: '@aws-sdk/core': 3.974.8 @@ -2963,6 +3135,14 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 + '@aws-sdk/credential-provider-process@3.972.41': + dependencies: + '@aws-sdk/core': 3.974.15 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.5 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@aws-sdk/credential-provider-sso@3.972.38': dependencies: '@aws-sdk/core': 3.974.8 @@ -2976,6 +3156,16 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-sso@3.972.45': + dependencies: + '@aws-sdk/core': 3.974.15 + '@aws-sdk/nested-clients': 3.997.13 + '@aws-sdk/token-providers': 3.1056.0 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.5 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@aws-sdk/credential-provider-web-identity@3.972.38': dependencies: '@aws-sdk/core': 3.974.8 @@ -2988,6 +3178,15 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-web-identity@3.972.45': + dependencies: + '@aws-sdk/core': 3.974.15 + '@aws-sdk/nested-clients': 3.997.13 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.5 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@aws-sdk/lib-storage@3.1045.0(@aws-sdk/client-s3@3.1045.0)': dependencies: '@aws-sdk/client-s3': 3.1045.0 @@ -3106,6 +3305,19 @@ snapshots: '@smithy/util-retry': 4.3.8 tslib: 2.8.1 + '@aws-sdk/nested-clients@3.997.13': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.974.15 + '@aws-sdk/signature-v4-multi-region': 3.996.30 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.5 + '@smithy/fetch-http-handler': 5.4.5 + '@smithy/node-http-handler': 4.7.5 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@aws-sdk/nested-clients@3.997.6': dependencies: '@aws-crypto/sha256-browser': 5.2.0 @@ -3167,6 +3379,13 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 + '@aws-sdk/signature-v4-multi-region@3.996.30': + dependencies: + '@aws-sdk/types': 3.973.9 + '@smithy/signature-v4': 5.4.5 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@aws-sdk/token-providers@3.1041.0': dependencies: '@aws-sdk/core': 3.974.8 @@ -3179,6 +3398,15 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/token-providers@3.1056.0': + dependencies: + '@aws-sdk/core': 3.974.15 + '@aws-sdk/nested-clients': 3.997.13 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.5 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@aws-sdk/types@3.973.6': dependencies: '@smithy/types': 4.14.1 @@ -3189,6 +3417,11 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 + '@aws-sdk/types@3.973.9': + dependencies: + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@aws-sdk/util-arn-parser@3.972.3': dependencies: tslib: 2.8.1 @@ -3235,6 +3468,12 @@ snapshots: fast-xml-parser: 5.7.2 tslib: 2.8.1 + '@aws-sdk/xml-builder@3.972.26': + dependencies: + '@smithy/types': 4.14.2 + fast-xml-parser: 5.7.3 + tslib: 2.8.1 + '@aws/lambda-invoke-store@0.2.4': {} '@babel/code-frame@7.29.0': @@ -3745,6 +3984,12 @@ snapshots: '@smithy/uuid': 1.1.2 tslib: 2.8.1 + '@smithy/core@3.24.5': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@smithy/credential-provider-imds@4.2.14': dependencies: '@smithy/node-config-provider': 4.3.14 @@ -3753,6 +3998,12 @@ snapshots: '@smithy/url-parser': 4.2.14 tslib: 2.8.1 + '@smithy/credential-provider-imds@4.3.6': + dependencies: + '@smithy/core': 3.24.5 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@smithy/eventstream-codec@4.2.14': dependencies: '@aws-crypto/crc32': 5.2.0 @@ -3791,6 +4042,12 @@ snapshots: '@smithy/util-base64': 4.3.2 tslib: 2.8.1 + '@smithy/fetch-http-handler@5.4.5': + dependencies: + '@smithy/core': 3.24.5 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@smithy/hash-blob-browser@4.2.15': dependencies: '@smithy/chunked-blob-reader': 5.2.2 @@ -3886,6 +4143,12 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 + '@smithy/node-http-handler@4.7.5': + dependencies: + '@smithy/core': 3.24.5 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@smithy/property-provider@4.2.14': dependencies: '@smithy/types': 4.14.1 @@ -3927,6 +4190,12 @@ snapshots: '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 + '@smithy/signature-v4@5.4.5': + dependencies: + '@smithy/core': 3.24.5 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + '@smithy/smithy-client@4.12.13': dependencies: '@smithy/core': 3.23.17 @@ -3941,6 +4210,10 @@ snapshots: dependencies: tslib: 2.8.1 + '@smithy/types@4.14.2': + dependencies: + tslib: 2.8.1 + '@smithy/url-parser@4.2.14': dependencies: '@smithy/querystring-parser': 4.2.14 @@ -4728,6 +5001,13 @@ snapshots: path-expression-matcher: 1.5.0 strnum: 2.3.0 + fast-xml-parser@5.7.3: + dependencies: + '@nodable/entities': 2.1.0 + fast-xml-builder: 1.2.0 + path-expression-matcher: 1.5.0 + strnum: 2.3.0 + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 diff --git a/spinifex/services/spinifexui/frontend/src/components/elbv2/certificate-import-dialog.tsx b/spinifex/services/spinifexui/frontend/src/components/elbv2/certificate-import-dialog.tsx new file mode 100644 index 000000000..1c5a65080 --- /dev/null +++ b/spinifex/services/spinifexui/frontend/src/components/elbv2/certificate-import-dialog.tsx @@ -0,0 +1,151 @@ +import { useState } from "react" + +import { ErrorBanner } from "@/components/error-banner" +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog" +import { Field, FieldTitle } from "@/components/ui/field" +import { Textarea } from "@/components/ui/textarea" +import { useImportCertificate } from "@/mutations/acm" + +interface CertificateImportDialogProps { + open: boolean + onOpenChange: (open: boolean) => void + // Called with the new certificate ARN once the import succeeds. + onImported: (certificateArn: string) => void +} + +export function CertificateImportDialog({ + open, + onOpenChange, + onImported, +}: CertificateImportDialogProps) { + const [certificate, setCertificate] = useState("") + const [privateKey, setPrivateKey] = useState("") + const [certificateChain, setCertificateChain] = useState("") + const importMutation = useImportCertificate() + + const reset = () => { + setCertificate("") + setPrivateKey("") + setCertificateChain("") + importMutation.reset() + } + + const handleOpenChange = (next: boolean) => { + if (!next) { + reset() + } + onOpenChange(next) + } + + const canSubmit = + certificate.trim().length > 0 && privateKey.trim().length > 0 + + const handleImport = async () => { + if (!canSubmit) { + return + } + try { + const result = await importMutation.mutateAsync({ + certificate, + privateKey, + certificateChain, + }) + if (result.CertificateArn) { + onImported(result.CertificateArn) + } + reset() + onOpenChange(false) + } catch { + // surfaced via importMutation.error + } + } + + return ( + + + + Import certificate + + Paste a PEM-encoded certificate and its private key. The optional + chain is appended for intermediate CAs. + + + + {importMutation.error && ( + + )} + +
+ + + + +