Selaa lähdekoodia

feat(upstream): added dynamic resolver

0xJacky 3 viikkoa sitten
vanhempi
commit
4a513229da

+ 7 - 20
go.mod

@@ -15,11 +15,12 @@ require (
 	github.com/dustin/go-humanize v1.0.1
 	github.com/elliotchance/orderedmap/v3 v3.1.0
 	github.com/fsnotify/fsnotify v1.9.0
+	github.com/gabriel-vasile/mimetype v1.4.9
 	github.com/gin-contrib/cors v1.7.6
 	github.com/gin-contrib/pprof v1.5.3
 	github.com/gin-contrib/static v1.1.5
 	github.com/gin-gonic/gin v1.10.1
-	github.com/go-acme/lego/v4 v4.0.1-0.20250715122445-8b40479678cb
+	github.com/go-acme/lego/v4 v4.24.1-0.20250718170347-cb602702d26c
 	github.com/go-co-op/gocron/v2 v2.16.2
 	github.com/go-gormigrate/gormigrate/v2 v2.1.4
 	github.com/go-playground/validator/v10 v10.27.0
@@ -84,14 +85,12 @@ require (
 	github.com/RoaringBitmap/roaring/v2 v2.8.0 // indirect
 	github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect
 	github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
-	github.com/alibabacloud-go/alidns-20150109/v4 v4.5.10 // indirect
 	github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.8 // indirect
 	github.com/alibabacloud-go/debug v1.0.1 // indirect
 	github.com/alibabacloud-go/endpoint-util v1.1.1 // indirect
 	github.com/alibabacloud-go/openapi-util v0.1.1 // indirect
 	github.com/alibabacloud-go/tea v1.3.9 // indirect
 	github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect
-	github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
 	github.com/aliyun/aliyun-log-go-sdk v0.1.102 // indirect
 	github.com/aliyun/credentials-go v1.4.6 // indirect
 	github.com/aws/aws-sdk-go-v2 v1.36.5 // indirect
@@ -139,7 +138,6 @@ require (
 	github.com/cenkalti/backoff v2.2.1+incompatible // indirect
 	github.com/cenkalti/backoff/v4 v4.3.0 // indirect
 	github.com/cespare/xxhash/v2 v2.3.0 // indirect
-	github.com/civo/civogo v0.6.1 // indirect
 	github.com/clbanning/mxj/v2 v2.7.0 // indirect
 	github.com/cloudwego/base64x v0.1.5 // indirect
 	github.com/containerd/errdefs v1.0.0 // indirect
@@ -158,9 +156,10 @@ require (
 	github.com/fatih/structs v1.1.0 // indirect
 	github.com/felixge/httpsnoop v1.0.4 // indirect
 	github.com/fxamacker/cbor/v2 v2.9.0 // indirect
-	github.com/gabriel-vasile/mimetype v1.4.9 // indirect
 	github.com/ghodss/yaml v1.0.0 // indirect
 	github.com/gin-contrib/sse v1.1.0 // indirect
+	github.com/go-acme/alidns-20150109/v4 v4.5.10 // indirect
+	github.com/go-acme/tencentclouddnspod v1.0.1208 // indirect
 	github.com/go-errors/errors v1.5.1 // indirect
 	github.com/go-ini/ini v1.67.0 // indirect
 	github.com/go-jose/go-jose/v4 v4.1.1 // indirect
@@ -219,11 +218,6 @@ require (
 	github.com/labbsr0x/goh v1.0.1 // indirect
 	github.com/leodido/go-urn v1.4.0 // indirect
 	github.com/lib/pq v1.10.9 // indirect
-	github.com/libdns/alidns v1.0.4 // indirect
-	github.com/libdns/cloudflare v0.2.1 // indirect
-	github.com/libdns/huaweicloud v1.0.0-beta.2 // indirect
-	github.com/libdns/libdns v1.1.0 // indirect
-	github.com/libdns/tencentcloud v1.4.1 // indirect
 	github.com/linode/linodego v1.53.0 // indirect
 	github.com/liquidweb/liquidweb-cli v0.7.0 // indirect
 	github.com/liquidweb/liquidweb-go v1.6.4 // indirect
@@ -259,6 +253,8 @@ require (
 	github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.95.1 // indirect
 	github.com/nrdcg/porkbun v0.4.0 // indirect
 	github.com/nzdjb/go-metaname v1.0.0 // indirect
+	github.com/onsi/ginkgo/v2 v2.21.0 // indirect
+	github.com/onsi/gomega v1.35.1 // indirect
 	github.com/opencontainers/go-digest v1.0.0 // indirect
 	github.com/opencontainers/image-spec v1.1.1 // indirect
 	github.com/ovh/go-ovh v1.9.0 // indirect
@@ -303,8 +299,7 @@ require (
 	github.com/stretchr/objx v0.5.2 // indirect
 	github.com/subosito/gotenv v1.6.0 // indirect
 	github.com/technoweenie/multipartstreamer v1.0.1 // indirect
-	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1207 // indirect
-	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1200 // indirect
+	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1208 // indirect
 	github.com/timtadh/data-structures v0.6.2 // indirect
 	github.com/timtadh/lexmachine v0.2.3 // indirect
 	github.com/tinylib/msgp v1.3.0 // indirect
@@ -339,7 +334,6 @@ require (
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/ratelimit v0.3.1 // indirect
 	go.uber.org/zap v1.27.0 // indirect
-	go.yaml.in/yaml/v2 v2.4.2 // indirect
 	golang.org/x/arch v0.19.0 // indirect
 	golang.org/x/mod v0.26.0 // indirect
 	golang.org/x/oauth2 v0.30.0 // indirect
@@ -353,7 +347,6 @@ require (
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
 	google.golang.org/grpc v1.73.0 // indirect
 	google.golang.org/protobuf v1.36.6 // indirect
-	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
 	gopkg.in/ns1/ns1-go.v2 v2.14.4 // indirect
 	gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
@@ -363,14 +356,8 @@ require (
 	gorm.io/driver/mysql v1.6.0 // indirect
 	gorm.io/driver/postgres v1.5.9 // indirect
 	gorm.io/hints v1.1.2 // indirect
-	k8s.io/api v0.33.2 // indirect
 	k8s.io/apimachinery v0.33.2 // indirect
-	k8s.io/klog/v2 v2.130.1 // indirect
 	k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
-	sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
-	sigs.k8s.io/randfill v1.0.0 // indirect
-	sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
-	sigs.k8s.io/yaml v1.5.0 // indirect
 )
 
 replace (

+ 29 - 147
go.sum

@@ -612,8 +612,6 @@ github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 h1:Dy3M9aegiI7d7PF1LUdjbVigJReo+QOceYs
 github.com/AdamSLevy/jsonrpc2/v14 v14.1.0/go.mod h1:ZakZtbCXxCz82NJvq7MoREtiQesnDfrtF6RFUGzQfLo=
 github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
 github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 h1:Wc1ml6QlJs2BHQ/9Bqu1jiyggbsSjramq2oUmp5WeIo=
 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4=
@@ -683,8 +681,6 @@ github.com/Netflix/go-env v0.0.0-20220526054621-78278af1949d/go.mod h1:9XMFaCeRy
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 h1:xPMsUicZ3iosVPSIP7bW5EcGUzjiiMl1OYTe14y/R24=
 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
-github.com/RoaringBitmap/roaring/v2 v2.6.0 h1:Ip8+kROnvVVcry+ESkfFdTPoLeKcoj7vhL2wJJKx2QA=
-github.com/RoaringBitmap/roaring/v2 v2.6.0/go.mod h1:FiJcsfkGje/nZBZgCu0ZxCPOKD/hVXDS2dXi7/eUFE0=
 github.com/RoaringBitmap/roaring/v2 v2.8.0 h1:y1rdtixfXvaITKzkfiKvScI0hlBJHe9sfzJp8cgeM7w=
 github.com/RoaringBitmap/roaring/v2 v2.8.0/go.mod h1:FiJcsfkGje/nZBZgCu0ZxCPOKD/hVXDS2dXi7/eUFE0=
 github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
@@ -706,33 +702,31 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
 github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0=
 github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs=
+github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 h1:eIf+iGJxdU4U9ypaUfbtOWCsZSbTb8AUHvyPrxu6mAA=
 github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do24zMOGGqYVWgw0s9NtiylnJglOeEB5UJo=
-github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo=
 github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
 github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8=
 github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g=
-github.com/alibabacloud-go/alidns-20150109/v4 v4.5.10 h1:lEYfSDh8puQigWN2pyOxE1gaI6o2bxFhJSSeX+ZJSf4=
-github.com/alibabacloud-go/alidns-20150109/v4 v4.5.10/go.mod h1:EdHRU3Y2j8OXc2ljp00A0zMLQ8sORHxI4yPnODNztRc=
+github.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY=
 github.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI=
+github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE=
 github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8=
+github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc=
 github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc=
-github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.4 h1:7Q2FEyqxeZeIkwYMwRC3uphxV4i7O2eV4ETe21d6lS4=
-github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.4/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
 github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.11/go.mod h1:wHxkgZT1ClZdcwEVP/pDgYK/9HucsnCfMipmJgCz4xY=
 github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.8 h1:AL+nH363NJFS1NXIjCdmj5MOElgKEqgFeoq7vjje350=
 github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.8/go.mod h1:d+z3ScRqc7PFzg4h9oqE3h8yunRZvAvU7u+iuPYEhpU=
+github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
 github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
+github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
 github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
-github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 h1:NqugFkGxx1TXSh/pBcU00Y6bljgDPaFdh5MUSeJ7e50=
 github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
 github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
 github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg=
 github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
-github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=
 github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
 github.com/alibabacloud-go/endpoint-util v1.1.1 h1:ZkBv2/jnghxtU0p+upSU0GGzW1VL9GQdZO3mcSUTUy8=
 github.com/alibabacloud-go/endpoint-util v1.1.1/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
-github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY=
 github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
 github.com/alibabacloud-go/openapi-util v0.1.1 h1:ujGErJjG8ncRW6XtBBMphzHTvCxn4DjrVw4m04HsS28=
 github.com/alibabacloud-go/openapi-util v0.1.1/go.mod h1:/UehBSE2cf1gYT43GV4E+RxTdLRzURImCYY0aRmlXpw=
@@ -743,27 +737,18 @@ github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeG
 github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
 github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
 github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
-github.com/alibabacloud-go/tea v1.1.19 h1:Xroq0M+pr0mC834Djj3Fl4ZA8+GGoA0i7aWse1vmgf4=
-github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
 github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
 github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
 github.com/alibabacloud-go/tea v1.3.9 h1:bjgt1bvdY780vz/17iWNNtbXl4A77HWntWMeaUF3So0=
 github.com/alibabacloud-go/tea v1.3.9/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
-github.com/alibabacloud-go/tea-utils v1.3.1 h1:iWQeRzRheqCMuiF3+XkfybB3kTgUXkXX+JMrqfLeB2I=
 github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
-github.com/alibabacloud-go/tea-utils/v2 v2.0.1 h1:K6kwgo+UiYx+/kr6CO0PN5ACZDzE3nnn9d77215AkTs=
-github.com/alibabacloud-go/tea-utils/v2 v2.0.1/go.mod h1:U5MTY10WwlquGPS34DOeomUGBB0gXbLueiq5Trwu0C4=
 github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4=
 github.com/alibabacloud-go/tea-utils/v2 v2.0.6/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
 github.com/alibabacloud-go/tea-utils/v2 v2.0.7 h1:WDx5qW3Xa5ZgJ1c8NfqJkF6w+AU5wB8835UdhPr6Ax0=
 github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
-github.com/alibabacloud-go/tea-xml v1.1.2 h1:oLxa7JUXm2EDFzMg+7oRsYc+kutgCVwm+bZlhhmvW5M=
-github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
-github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0=
 github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
 github.com/aliyun/aliyun-log-go-sdk v0.1.102 h1:93SswdufRjZ6Hf97Q22pDjWaa/LCwur/mX8jVZcFgow=
 github.com/aliyun/aliyun-log-go-sdk v0.1.102/go.mod h1:7QcyHasd4WLdC+lx4uCmdIBcl7WcgRHctwz8t1zAuPo=
-github.com/aliyun/credentials-go v1.1.2 h1:qU1vwGIBb3UJ8BwunHDRFtAhS6jnQLnde/yk0+Ih2GY=
 github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
 github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
 github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=
@@ -783,8 +768,6 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
 github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
 github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
-github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE=
-github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
 github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
 github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0=
 github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0=
@@ -820,8 +803,6 @@ github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw=
 github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
 github.com/aziontech/azionapi-go-sdk v0.142.0 h1:1NOHXlC0/7VgbfbTIGVpsYn1THCugM4/SCOXVdUHQ+A=
 github.com/aziontech/azionapi-go-sdk v0.142.0/go.mod h1:cA5DY/VP4X5Eu11LpQNzNn83ziKjja7QVMIl4J45feA=
-github.com/baidubce/bce-sdk-go v0.9.233 h1:nq5PL+G2+JIkox98GN0UEkNdh8G+j4cmyJxbzoFNgec=
-github.com/baidubce/bce-sdk-go v0.9.233/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
 github.com/baidubce/bce-sdk-go v0.9.234 h1:HK4xGxUCka+TuSCqeMmza5Iz2T+op5nR9s7J8+XdYKM=
 github.com/baidubce/bce-sdk-go v0.9.234/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
 github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 h1:6df1vn4bBlDDo4tARvBm7l6KA9iVMnE3NWizDeWSrps=
@@ -890,8 +871,6 @@ github.com/bsm/redislock v0.9.4/go.mod h1:Epf7AJLiSFwLCiZcfi6pWFO/8eAYrYpQXFxEDP
 github.com/bytedance/sonic v1.13.3 h1:MS8gmaH16Gtirygw7jV91pDCN33NyMrPbN7qiYhEsF0=
 github.com/bytedance/sonic v1.13.3/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
 github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
-github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
-github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
 github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
 github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
 github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
@@ -907,10 +886,11 @@ github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInq
 github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
 github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
+github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
+github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
-github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -922,11 +902,7 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
 github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
-github.com/civo/civogo v0.6.1 h1:PFOh7rBU0vmj7LTDIv3z7l9uXG4SZyyzScCl3wyTFSc=
-github.com/civo/civogo v0.6.1/go.mod h1:LaEbkszc+9nXSh4YNG0sYXFGYqdQFmXXzQg0gESs2hc=
-github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I=
 github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
-github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E=
 github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
 github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
 github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
@@ -1002,8 +978,6 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
 github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
 github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
-github.com/ebitengine/purego v0.9.0-alpha.8 h1:CPF4uX051zsUnPwi43RumsgSBax76KH14F8NwrKNsHU=
-github.com/ebitengine/purego v0.9.0-alpha.8/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
 github.com/ebitengine/purego v0.9.0-alpha.9 h1:+OPDXjPESTGhQ/2zO0aQeUR8r4o1feLMSDQzkA6z9ug=
 github.com/ebitengine/purego v0.9.0-alpha.9/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
 github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
@@ -1024,8 +998,6 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
 github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
 github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=
 github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
-github.com/exoscale/egoscale/v3 v3.1.22 h1:Dq6g9MlbKjRU4cnjrZOzNJ9Bwy2L4LnJBGcsJ9U/kc8=
-github.com/exoscale/egoscale/v3 v3.1.22/go.mod h1:A53enXfm8nhVMpIYw0QxiwQ2P6AdCF4F/nVYChNEzdE=
 github.com/exoscale/egoscale/v3 v3.1.23 h1:OYVM9nDA4YmJnukEd1bzHE0xuX7HMdHH84jH4TRUERw=
 github.com/exoscale/egoscale/v3 v3.1.23/go.mod h1:A53enXfm8nhVMpIYw0QxiwQ2P6AdCF4F/nVYChNEzdE=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
@@ -1053,8 +1025,6 @@ github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5
 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
 github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
 github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
-github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
-github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
 github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
 github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
 github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
@@ -1071,8 +1041,12 @@ github.com/gin-contrib/static v1.1.5 h1:bAPqT4KTZN+4uDY1b90eSrD1t8iNzod7Jj8njwmn
 github.com/gin-contrib/static v1.1.5/go.mod h1:8JSEXwZHcQ0uCrLPcsvnAJ4g+ODxeupP8Zetl9fd8wM=
 github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
 github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
-github.com/go-acme/lego/v4 v4.0.1-0.20250715122445-8b40479678cb h1:vfUVXlT/S//URM6L2ccfjfN2o113bp8TWrFO85qKs1A=
-github.com/go-acme/lego/v4 v4.0.1-0.20250715122445-8b40479678cb/go.mod h1:SBFndxs8A0zGTT+7nIMAuFK9NmSbctX3rwclvqMD59U=
+github.com/go-acme/alidns-20150109/v4 v4.5.10 h1:epLD0VaHR5XUpiM6mjm4MzQFICrk+zpuqDz2aO1/R/k=
+github.com/go-acme/alidns-20150109/v4 v4.5.10/go.mod h1:qGRq8kD0xVgn82qRSQmhHwh/oWxKRjF4Db5OI4ScV5g=
+github.com/go-acme/lego/v4 v4.24.1-0.20250718170347-cb602702d26c h1:oTEMkBFoMpFQ4sMcKe9EvXGBeLxtHv0fbHfub49dFsk=
+github.com/go-acme/lego/v4 v4.24.1-0.20250718170347-cb602702d26c/go.mod h1:stLS6xRlNXy3TWClDtjwrn7pcb/TPNmzlGtdNhF5Gjc=
+github.com/go-acme/tencentclouddnspod v1.0.1208 h1:xAVy1lmg2KcKKeYmFSBQUttwc1o1S++9QTjAotGC+BM=
+github.com/go-acme/tencentclouddnspod v1.0.1208/go.mod h1:yxG02mkbbVd7lTb97nOn7oj09djhm7hAwxNQw4B9dpQ=
 github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
 github.com/go-co-op/gocron/v2 v2.16.2 h1:r08P663ikXiulLT9XaabkLypL/W9MoCIbqgQoAutyX4=
 github.com/go-co-op/gocron/v2 v2.16.2/go.mod h1:4YTLGCCAH75A5RlQ6q+h+VacO7CgjkgP0EJ+BEOXRSI=
@@ -1141,16 +1115,10 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
 github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
 github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU=
 github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
-github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk=
-github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
 github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
 github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
-github.com/go-webauthn/webauthn v0.13.1 h1:Q3/GLXsckVJUPE+BGR6ex26yRIiZ/X2ITaMeSkOftuc=
-github.com/go-webauthn/webauthn v0.13.1/go.mod h1:HeaBromTjgMg1sHZOzyjEiqcrk4Og7mxafDTWDepaXI=
 github.com/go-webauthn/webauthn v0.13.3 h1:rvX539Gy9U4xAuFQRFJtkgoH5E1GEUyIVbHUDC89Mo4=
 github.com/go-webauthn/webauthn v0.13.3/go.mod h1:H9EdVnxXFMMJyx8Nd/OL3aFFEop3Rb+Af1naR0IbuUQ=
-github.com/go-webauthn/x v0.1.22 h1:rHilV/rYXawarI0uA3uZ5nhLb30Ex8RgbVAsOSt/57o=
-github.com/go-webauthn/x v0.1.22/go.mod h1:+iV9BF4OsvLYzETdc0lmQO2webTos10oH6QydSoWxDM=
 github.com/go-webauthn/x v0.1.23 h1:9lEO0s+g8iTyz5Vszlg/rXTGrx3CjcD0RZQ1GPZCaxI=
 github.com/go-webauthn/x v0.1.23/go.mod h1:AJd3hI7NfEp/4fI6T4CHD753u91l510lglU7/NMN6+E=
 github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
@@ -1172,8 +1140,6 @@ github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw
 github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
 github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
-github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
-github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
 github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0=
 github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
 github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
@@ -1273,9 +1239,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe
 github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
-github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
 github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a h1://KbezygeMJZCSHH+HgUZiTeSoiuFspbMg1ge+eFj18=
+github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
 github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
@@ -1304,8 +1269,6 @@ github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMd
 github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
 github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
 github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
-github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0=
-github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w=
 github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
 github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
 github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
@@ -1477,7 +1440,6 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
 github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
 github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
-github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
 github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
 github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
 github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
@@ -1520,8 +1482,6 @@ github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zt
 github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
 github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU=
-github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
 github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
 github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
 github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
@@ -1557,15 +1517,6 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
 github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/libdns/alidns v1.0.4/go.mod h1:e18uAG6GanfRhcJj6/tps2rCMzQJaYVcGKT+ELjdjGE=
-github.com/libdns/cloudflare v0.2.1/go.mod h1:Aq4IXdjalB6mD0ELvKqJiIGim8zSC6mlIshRPMOAb5w=
-github.com/libdns/huaweicloud v1.0.0-beta.2 h1:50gUOOj5suqZtC2Cj6fAnjFgXboWgT6O8aHa+6BNy7s=
-github.com/libdns/huaweicloud v1.0.0-beta.2/go.mod h1:MQ+HiuzS6RjqBaZquZICMM9rEfKPTRuo+MhIJ05m8Bw=
-github.com/libdns/libdns v0.2.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
-github.com/libdns/libdns v1.0.0/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
-github.com/libdns/libdns v1.1.0 h1:9ze/tWvt7Df6sbhOJRB8jT33GHEHpEQXdtkE3hPthbU=
-github.com/libdns/libdns v1.1.0/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
-github.com/libdns/tencentcloud v1.4.1/go.mod h1:Be9gY3tDa12DuAPU79RV9NZIcjY6qg5s7zKPsP26yAM=
 github.com/linode/linodego v1.53.0 h1:UWr7bUUVMtcfsuapC+6blm6+jJLPd7Tf9MZUpdOERnI=
 github.com/linode/linodego v1.53.0/go.mod h1:bI949fZaVchjWyKIA08hNyvAcV6BAS+PM2op3p7PAWA=
 github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
@@ -1583,8 +1534,6 @@ github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WV
 github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
 github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
-github.com/mark3labs/mcp-go v0.33.0 h1:naxhjnTIs/tyPZmWUZFuG0lDmdA6sUyYGGf3gsHvTCc=
-github.com/mark3labs/mcp-go v0.33.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4=
 github.com/mark3labs/mcp-go v0.34.0 h1:eWy7WBGvhk6EyAAyVzivTCprE52iXJwNtvHV6Cv3bR0=
 github.com/mark3labs/mcp-go v0.34.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -1626,8 +1575,6 @@ github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKju
 github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
 github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
 github.com/miekg/dns v1.1.47/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
-github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE=
-github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE=
 github.com/miekg/dns v1.1.67 h1:kg0EHj0G4bfT5/oOys6HhZw4vmMlnoZ+gDu8tJ/AlI0=
 github.com/miekg/dns v1.1.67/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
 github.com/mimuret/golang-iij-dpf v0.9.1 h1:Gj6EhHJkOhr+q2RnvRPJsPMcjuVnWPSccEHyoEehU34=
@@ -1648,6 +1595,8 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
+github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
 github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
 github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
@@ -1693,20 +1642,12 @@ github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1t
 github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
 github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
 github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
-github.com/nginxui/alidns v0.0.0-20250710121130-078ef8f94363 h1:9ZJ6riejuh1GUl5YByR7mboHHStqfDEsGSCtPR2l9o4=
-github.com/nginxui/alidns v0.0.0-20250710121130-078ef8f94363/go.mod h1:nluLPCeflqaXDdPTpGD/wes5C+Occ1FgQUSR0AX4SnM=
-github.com/nginxui/cloudflare v0.0.0-20250710120913-9a0967becf83 h1:+tH6/nmJfJlkVNTwD87KvhR+OewrHOPASt8arly61Sc=
-github.com/nginxui/cloudflare v0.0.0-20250710120913-9a0967becf83/go.mod h1:w9uTmRCDlAoafAsTPnn2nJ0XHK/eaUMh86DUk8BWi60=
-github.com/nginxui/lego/v4 v4.0.1-0.20250711080916-db2f7bf33bf7 h1:7dq0V+o6igkgChtsZoDVfA8SOvcfOTAfWFTMpZ9u7oc=
-github.com/nginxui/lego/v4 v4.0.1-0.20250711080916-db2f7bf33bf7/go.mod h1:TWjrVFmnC37jngSEtih/IH87/9HQZVu8iGAlkGPjRgs=
 github.com/nginxui/notify v0.0.0-20250509000747-c76622723eb1 h1:tTFu+N3ukz73Lv4LKLdNAL6EItcdn31vpy12SLwLjlU=
 github.com/nginxui/notify v0.0.0-20250509000747-c76622723eb1/go.mod h1:5xiIPJd5HveRkca2gA8K//HLdupJuB7uHHBdzDQQN6g=
 github.com/nginxui/risefront v1.2.3 h1:UXVt+yzGtWyFHQsnLG3HJNv+RHllVyUEG7zHZryOpxE=
 github.com/nginxui/risefront v1.2.3/go.mod h1:QX3OyvazX3Mi/X2NZKl9ylDrFVUeaogwSMKyEsnRCHE=
 github.com/nginxui/selfupdate v0.0.0-20250508140228-a7dab39cec4a h1:KNDT8WAMtclTjmHtlqvy02sXUPNxErKNcyB3bjTRsEM=
 github.com/nginxui/selfupdate v0.0.0-20250508140228-a7dab39cec4a/go.mod h1:bO02GTIPCMQFTEvE5h4DjYB58bCoZ35XLeBf0buTDdM=
-github.com/nginxui/tencentcloud v0.0.0-20250510022134-62ee21b1b93a h1:T1NrD1DZ+jHuvHRwIEg77V4WIfvKg1SPLbC8UAyjQD8=
-github.com/nginxui/tencentcloud v0.0.0-20250510022134-62ee21b1b93a/go.mod h1:Be9gY3tDa12DuAPU79RV9NZIcjY6qg5s7zKPsP26yAM=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nrdcg/auroradns v1.1.0 h1:KekGh8kmf2MNwqZVVYo/fw/ZONt8QMEmbMFOeljteWo=
 github.com/nrdcg/auroradns v1.1.0/go.mod h1:O7tViUZbAcnykVnrGkXzIJTHoQCHcgalgAe6X1mzHfk=
@@ -1728,12 +1669,8 @@ github.com/nrdcg/namesilo v0.2.1 h1:kLjCjsufdW/IlC+iSfAqj0iQGgKjlbUUeDJio5Y6eMg=
 github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
 github.com/nrdcg/nodion v0.1.0 h1:zLKaqTn2X0aDuBHHfyA1zFgeZfiCpmu/O9DM73okavw=
 github.com/nrdcg/nodion v0.1.0/go.mod h1:inbuh3neCtIWlMPZHtEpe43TmRXxHV6+hk97iCZicms=
-github.com/nrdcg/oci-go-sdk/common/v1065 v1065.95.0 h1:COzvb58Oc7/ADt3699jzLMJd0HOW/v2tG9b+74IFhrA=
-github.com/nrdcg/oci-go-sdk/common/v1065 v1065.95.0/go.mod h1:O6osg9dPzXq7H2ib/1qzimzG5oXSJFgccR7iawg7SwA=
 github.com/nrdcg/oci-go-sdk/common/v1065 v1065.95.1 h1:ESqvRPqkFz9vjB7rHuxGE9+zIiwc6vhPlgtT3Uz0muA=
 github.com/nrdcg/oci-go-sdk/common/v1065 v1065.95.1/go.mod h1:7wISRWgDQxF+J6h9L6pNoK8/ZRSRLMG0blcApqurGFs=
-github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.95.0 h1:KWGOjA6n7R2VSarQsQNakP8gGCZNFgnv3zxc4edqLjo=
-github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.95.0/go.mod h1:iM3irKzFqd/xGZUWA+k93N3Sy+G+4KBqqQp2GBeBqeg=
 github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.95.1 h1:AVC+eDU5+qqwZREJ9ae3MN6+33kEbAkCZzT/rlsN4Ow=
 github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.95.1/go.mod h1:9d5zUJ2PrT8+10Sl5kie1B4QZb93fNSQBGkkhn1+cjY=
 github.com/nrdcg/porkbun v0.4.0 h1:rWweKlwo1PToQ3H+tEO9gPRW0wzzgmI/Ob3n2Guticw=
@@ -1746,9 +1683,8 @@ github.com/nzdjb/go-metaname v1.0.0 h1:sNASlZC1RM3nSudtBTE1a3ZVTDyTpjqI5WXRPrdZ9
 github.com/nzdjb/go-metaname v1.0.0/go.mod h1:0GR0LshZax1Lz4VrOrfNSE4dGvTp7HGjiemdczXT2H4=
 github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
-github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
-github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
 github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
+github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
@@ -1794,7 +1730,6 @@ github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2
 github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
 github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
 github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
-github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
 github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
 github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
 github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
@@ -1859,13 +1794,10 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
 github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
 github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
-github.com/prometheus/prometheus v0.304.2 h1:HhjbaAwet87x8Be19PFI/5W96UMubGy3zt24kayEuh4=
-github.com/prometheus/prometheus v0.304.2/go.mod h1:ioGx2SGKTY+fLnJSQCdTHqARVldGNS8OlIe3kvp98so=
 github.com/prometheus/prometheus v0.305.0 h1:UO/LsM32/E9yBDtvQj8tN+WwhbyWKR10lO35vmFLx0U=
 github.com/prometheus/prometheus v0.305.0/go.mod h1:JG+jKIDUJ9Bn97anZiCjwCxRyAx+lpcEQ0QnZlUlbwY=
-github.com/prometheus/sigv4 v0.1.2 h1:R7570f8AoM5YnTUPFm3mjZH5q2k4D+I/phCWvZ4PXG8=
-github.com/prometheus/sigv4 v0.1.2/go.mod h1:GF9fwrvLgkQwDdQ5BXeV9XUSCH/IPNqzvAoaohfjqMU=
 github.com/prometheus/sigv4 v0.2.0 h1:qDFKnHYFswJxdzGeRP63c4HlH3Vbn1Yf/Ao2zabtVXk=
+github.com/prometheus/sigv4 v0.2.0/go.mod h1:D04rqmAaPPEUkjRQxGqjoxdyJuyCh6E0M18fZr0zBiE=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
 github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
@@ -1911,13 +1843,9 @@ github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFT
 github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk=
 github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI=
 github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
-github.com/sashabaranov/go-openai v1.40.4 h1:IiUPA8785KKhBGyQMyZa8LXGikGZkIVYyCk7BzhIx90=
-github.com/sashabaranov/go-openai v1.40.4/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
 github.com/sashabaranov/go-openai v1.40.5 h1:SwIlNdWflzR1Rxd1gv3pUg6pwPc6cQ2uMoHs8ai+/NY=
 github.com/sashabaranov/go-openai v1.40.5/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
 github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33 h1:KhF0WejiUTDbL5X55nXowP7zNopwpowa6qaMAWyIE+0=
-github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33/go.mod h1:792k1RTU+5JeMXm35/e2Wgp71qPH/DmDoZrRc+EFZDk=
 github.com/scaleway/scaleway-sdk-go v1.0.0-beta.34 h1:48+VFHsyVcAHIN2v1Ao9v1/RkjJS5AwctFucBrfYNIA=
 github.com/scaleway/scaleway-sdk-go v1.0.0-beta.34/go.mod h1:zFWiHphneiey3s8HOtAEnGrRlWivNaxW5T6d5Xfco7g=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
@@ -2017,11 +1945,8 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8
 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
 github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
 github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1200/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1207 h1:NnhRF9rIUwQtcvn1kTwPwcBXTlN3EtbCjvY+oL+Nxgc=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1207/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1200 h1:MLBJK3cFuU1UNn80NYFX1lZ2F9QrWUCrdfufXAZ0UF8=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1200/go.mod h1:YcA1Y4DrRnNy5A7RQ629VxssdxSy/hvzOKcRdOeT6GM=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1208 h1:hE2rM9GoqISu4lgQVbx9+bTlPOB000pdUfbT9lwrC50=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1208/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
 github.com/timtadh/data-structures v0.5.3/go.mod h1:9R4XODhJ8JdWFEI8P/HJKqxuJctfBQw6fDibMQny2oU=
 github.com/timtadh/data-structures v0.6.1/go.mod h1:uYUnI1cQi/5yMCc7s23I+x8Mn8BCMf4WgK+7/4QSEk4=
 github.com/timtadh/data-structures v0.6.2 h1:zybDnU5NLjJ7WKMDJpvVwczQuf1wSLBgdRHZ9O4AqJ0=
@@ -2032,7 +1957,6 @@ github.com/timtadh/lexmachine v0.2.3 h1:ZqlfHnfMcAygtbNM5Gv7jQf8hmM8LfVzDjfCrq23
 github.com/timtadh/lexmachine v0.2.3/go.mod h1:oK1NW+93fQSIF6s+J6sXBFWsCPCFbNmrwKV1i0aqvW0=
 github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww=
 github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
-github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM=
 github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
 github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
 github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
@@ -2052,8 +1976,6 @@ github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA
 github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
 github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec h1:2s/ghQ8wKE+UzD/hf3P4Gd1j0JI9ncbxv+nsypPoUYI=
 github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec/go.mod h1:BZr7Qs3ku1ckpqed8tCRSqTlp8NAeZfAVpfx4OzXMss=
-github.com/uozi-tech/cosy v1.24.2 h1:PN8aP5W3iQZiVQZI7A/XROAZOREeKLcgDtAOW1m2V0g=
-github.com/uozi-tech/cosy v1.24.2/go.mod h1:+5JxLnqqUB1pFr0G2kSbIRan9gHj0+dAsiEMeECVchY=
 github.com/uozi-tech/cosy v1.24.5 h1:ZY9dzUrQrkdzL1Qx03e3eE8xphqBnbtpO1SImgIZHhE=
 github.com/uozi-tech/cosy v1.24.5/go.mod h1:h0ViTCx65zdRTW0nL+t96WKUi8cW5ThbE+ciKzsWjsY=
 github.com/uozi-tech/cosy-driver-mysql v0.2.2 h1:22S/XNIvuaKGqxQPsYPXN8TZ8hHjCQdcJKVQ83Vzxoo=
@@ -2067,8 +1989,6 @@ github.com/urfave/cli/v3 v3.3.8 h1:BzolUExliMdet9NlJ/u4m5vHSotJ3PzEqSAZ1oPMa/E=
 github.com/urfave/cli/v3 v3.3.8/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
 github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4ulRMcQ=
 github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q=
-github.com/volcengine/volc-sdk-golang v1.0.214 h1:70M2qibj0UeSjO9r+CRf/UuFqh/Iu0J86NSKUD6EEtc=
-github.com/volcengine/volc-sdk-golang v1.0.214/go.mod h1:zHJlaqiMbIB+0mcrsZPTwOb3FB7S/0MCfqlnO8R7hlM=
 github.com/volcengine/volc-sdk-golang v1.0.215 h1:rtFy0n0rORHttu8pih2A1q+c29L0FFwpqiaCyfvd+yE=
 github.com/volcengine/volc-sdk-golang v1.0.215/go.mod h1:zHJlaqiMbIB+0mcrsZPTwOb3FB7S/0MCfqlnO8R7hlM=
 github.com/vultr/govultr/v3 v3.21.0 h1:G/gOmCT7MGlII+iI98DjPdt/8IytC26oNcuk0LpJ8Y4=
@@ -2140,12 +2060,10 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/X
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY=
 go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
 go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 h1:dNzwXjZKpMpE2JhmO+9HsPl42NIXFIFSUSSs0fiqra0=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0/go.mod h1:90PoxvaEB5n6AOdZvi+yWJQoE95U8Dhhw2bSyRqnTD0=
 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0 h1:nRVXXvf78e00EwY6Wp0YII8ww2JVWshZ20HfTlE11AM=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0/go.mod h1:r49hO7CgrxY9Voaj3Xe8pANWtr0Oq916d0XAmOoCZAQ=
 go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
 go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
 go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
@@ -2157,9 +2075,8 @@ go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXe
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
 go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
-go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
-go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
 go.opentelemetry.io/proto/otlp v1.6.0 h1:jQjP+AQyTf+Fe7OKj/MfkDrmK4MNVtw2NpXsf9fefDI=
+go.opentelemetry.io/proto/otlp v1.6.0/go.mod h1:cicgGehlFuNdgZkcALOCh3VE6K/u2tAjzlRhDwmVpZc=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@@ -2193,10 +2110,6 @@ go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
 go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
 go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
 go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
-go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
-go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
-golang.org/x/arch v0.18.0 h1:WN9poc33zL4AzGxqf8VtpKUnGvMi8O9lhNyBMF/85qc=
-golang.org/x/arch v0.18.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
 golang.org/x/arch v0.19.0 h1:LmbDQUodHThXE+htjrnmVD73M//D9GTH6wFZjyDkjyU=
 golang.org/x/arch v0.19.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -2242,8 +2155,6 @@ golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZP
 golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
 golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
 golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
-golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
-golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
 golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
 golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
 golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -2308,8 +2219,6 @@ golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
-golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
 golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
 golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -2397,8 +2306,6 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
 golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
 golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
-golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
-golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
 golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
 golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -2451,8 +2358,6 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
 golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
-golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
 golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -2582,8 +2487,6 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
-golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
 golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
@@ -2607,6 +2510,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
 golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
 golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
 golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
+golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
+golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -2628,8 +2533,6 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
-golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
-golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
 golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
 golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -2719,8 +2622,6 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
 golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
-golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
-golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
 golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
 golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
 golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -2799,8 +2700,6 @@ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60c
 google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0=
 google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
 google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms=
-google.golang.org/api v0.240.0 h1:PxG3AA2UIqT1ofIzWV2COM3j3JagKTKSwy7L6RHNXNU=
-google.golang.org/api v0.240.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
 google.golang.org/api v0.241.0 h1:QKwqWQlkc6O895LchPEDUSYr22Xp3NCxpQRiWTB6avE=
 google.golang.org/api v0.241.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@@ -2943,14 +2842,10 @@ google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOl
 google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
 google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
 google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
-google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78=
-google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
-google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 h1:vPV0tzlsK6EzEDHNNH5sa7Hs9bd7iXR7B1tSiPepkV0=
-google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:pKLAc5OolXC3ViWGI62vvC0n10CpwAtRcTNCFwTKBEw=
+google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
+google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s=
 google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 h1:FiusG7LWj+4byqhbvmB+Q93B/mOxJLN2DTozDuZm4EU=
 google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -3030,8 +2925,6 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
 gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0=
 gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
 gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
-gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
-gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
 gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@@ -3094,12 +2987,11 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt
 honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
-k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
-k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
 k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
 k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
 k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU=
 k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY=
+k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
 k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
 k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
 k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
@@ -3143,14 +3035,4 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
-sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
-sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
-sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
-sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
-sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
-sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
-sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
-sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
-sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ=
-sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4=

+ 0 - 222
internal/upstream/consul_resolver.go

@@ -1,222 +0,0 @@
-package upstream
-
-import (
-	"context"
-	"fmt"
-	"net"
-	"strings"
-	"time"
-)
-
-// ConsulResolver handles DNS resolution through consul
-type ConsulResolver struct {
-	resolver string // e.g., "127.0.0.1:8600"
-}
-
-// NewConsulResolver creates a new consul resolver
-func NewConsulResolver(resolver string) *ConsulResolver {
-	return &ConsulResolver{
-		resolver: resolver,
-	}
-}
-
-// ResolveService resolves a consul service to actual IP addresses and ports
-func (cr *ConsulResolver) ResolveService(serviceURL string) ([]string, error) {
-	// Parse consul service URL (e.g., "service.consul service=redacted-net resolve")
-	serviceName := cr.extractServiceName(serviceURL)
-	if serviceName == "" {
-		return nil, fmt.Errorf("could not extract service name from: %s", serviceURL)
-	}
-
-	// Create a custom resolver that uses the consul DNS server
-	dialer := &net.Dialer{
-		Timeout: 5 * time.Second,
-	}
-
-	resolver := &net.Resolver{
-		PreferGo: true,
-		Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
-			return dialer.DialContext(ctx, network, cr.resolver)
-		},
-	}
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	defer cancel()
-
-	// Query consul for service SRV records
-	_, srvRecords, err := resolver.LookupSRV(ctx, "", "", serviceName+".service.consul")
-	if err != nil {
-		// Fallback to A record lookup if SRV fails
-		ips, err := resolver.LookupIPAddr(ctx, serviceName+".service.consul")
-		if err != nil {
-			return nil, fmt.Errorf("failed to resolve service %s: %v", serviceName, err)
-		}
-
-		// Return IP addresses with default port (80)
-		var addresses []string
-		for _, ip := range ips {
-			addresses = append(addresses, fmt.Sprintf("%s:80", ip.IP.String()))
-		}
-		return addresses, nil
-	}
-
-	// Convert SRV records to address:port format
-	var addresses []string
-	for _, srv := range srvRecords {
-		// Resolve the target hostname to IP
-		ips, err := resolver.LookupIPAddr(ctx, srv.Target)
-		if err != nil {
-			continue // Skip this record if resolution fails
-		}
-
-		for _, ip := range ips {
-			addresses = append(addresses, fmt.Sprintf("%s:%d", ip.IP.String(), srv.Port))
-		}
-	}
-
-	if len(addresses) == 0 {
-		return nil, fmt.Errorf("no addresses found for service %s", serviceName)
-	}
-
-	return addresses, nil
-}
-
-// extractServiceName extracts the service name from consul service URL
-func (cr *ConsulResolver) extractServiceName(serviceURL string) string {
-	serviceURL = strings.TrimSpace(serviceURL)
-
-	// Handle empty input
-	if serviceURL == "" {
-		return ""
-	}
-
-	// Parse "service.consul service=redacted-net resolve" format
-	if strings.Contains(serviceURL, "service=") {
-		parts := strings.Fields(serviceURL)
-		for _, part := range parts {
-			if strings.HasPrefix(part, "service=") {
-				serviceName := strings.TrimPrefix(part, "service=")
-				// Handle edge cases like "service=" or "service=  "
-				serviceName = strings.TrimSpace(serviceName)
-				if serviceName == "" {
-					return ""
-				}
-				return serviceName
-			}
-		}
-	}
-
-	// Fallback: try to extract from hostname format like "my-service.service.consul"
-	if strings.Contains(serviceURL, ".service.consul") {
-		parts := strings.Split(serviceURL, ".")
-		if len(parts) > 0 {
-			serviceName := strings.TrimSpace(parts[0])
-			if serviceName == "" {
-				return ""
-			}
-			return serviceName
-		}
-	}
-
-	return ""
-}
-
-// TestConsulTargets performs availability test specifically for consul targets
-func TestConsulTargets(consulTargets []ProxyTarget) map[string]*Status {
-	result := make(map[string]*Status)
-
-	// Group consul targets by resolver
-	consulTargetsByResolver := make(map[string][]ProxyTarget)
-	for _, target := range consulTargets {
-		if target.Resolver != "" {
-			consulTargetsByResolver[target.Resolver] = append(consulTargetsByResolver[target.Resolver], target)
-		} else {
-			// No resolver specified, mark as offline
-			key := target.Host + ":" + target.Port
-			result[key] = &Status{
-				Online:  false,
-				Latency: 0,
-			}
-		}
-	}
-
-	// Test each resolver group
-	for resolver, targets := range consulTargetsByResolver {
-		consulResolver := NewConsulResolver(resolver)
-
-		for _, target := range targets {
-			key := target.Host + ":" + target.Port
-
-			// Try to resolve the consul service
-			addresses, err := consulResolver.ResolveService(target.ServiceURL)
-			if err != nil {
-				// If resolution fails, mark as offline
-				result[key] = &Status{
-					Online:  false,
-					Latency: 0,
-				}
-				continue
-			}
-
-			// Test the first resolved address as representative
-			if len(addresses) > 0 {
-				addressResults := AvailabilityTest(addresses[:1])
-
-				if status, exists := addressResults[addresses[0]]; exists {
-					result[key] = status
-				} else {
-					result[key] = &Status{
-						Online:  false,
-						Latency: 0,
-					}
-				}
-			} else {
-				result[key] = &Status{
-					Online:  false,
-					Latency: 0,
-				}
-			}
-		}
-	}
-
-	return result
-}
-
-// EnhancedAvailabilityTest performs availability test with consul resolution support
-// Deprecated: Use TestConsulTargets for consul targets and AvailabilityTest for regular targets
-func EnhancedAvailabilityTest(targets []ProxyTarget) map[string]*Status {
-	result := make(map[string]*Status)
-
-	// Group targets by type
-	consulTargets := make([]ProxyTarget, 0)
-	regularTargets := make([]string, 0)
-
-	for _, target := range targets {
-		if target.IsConsul && target.Resolver != "" {
-			consulTargets = append(consulTargets, target)
-		} else {
-			// Regular target - use existing format for traditional AvailabilityTest
-			key := target.Host + ":" + target.Port
-			regularTargets = append(regularTargets, key)
-		}
-	}
-
-	// Use traditional AvailabilityTest for regular targets (more efficient)
-	if len(regularTargets) > 0 {
-		regularResults := AvailabilityTest(regularTargets)
-		// Merge results
-		for k, v := range regularResults {
-			result[k] = v
-		}
-	}
-
-	// Test consul targets with DNS resolution
-	if len(consulTargets) > 0 {
-		consulResults := TestConsulTargets(consulTargets)
-		for k, v := range consulResults {
-			result[k] = v
-		}
-	}
-
-	return result
-}

+ 0 - 496
internal/upstream/consul_resolver_test.go

@@ -1,496 +0,0 @@
-package upstream
-
-import (
-	"testing"
-)
-
-// TestParseProxyTargetsWithConsulResolver tests parsing of nginx config with consul DNS resolver
-func TestParseProxyTargetsWithConsulResolver(t *testing.T) {
-	config := `upstream redacted-net {
-    zone upstream_web 128k;
-    resolver 127.0.0.1:8600 valid=5s;
-    resolver_timeout 2s;
-    server service.consul service=redacted-net resolve;
-}
-server {
-    listen 80;
-    listen [::]:80;
-    server_name redacted.net;
-    location / {
-        proxy_pass http://redacted-net;
-    }
-}`
-
-	targets := ParseProxyTargetsFromRawContent(config)
-
-	// Print actual results for debugging
-	t.Logf("Found %d targets:", len(targets))
-	for i, target := range targets {
-		t.Logf("Target %d: Host=%s, Port=%s, Type=%s, Resolver=%s, IsConsul=%v",
-			i+1, target.Host, target.Port, target.Type, target.Resolver, target.IsConsul)
-	}
-
-	// Expected behavior:
-	// - Should parse "service.consul" as host with dynamic port
-	// - Should identify this as an upstream target with consul service discovery
-	// - Should capture resolver information
-	// - proxy_pass http://redacted-net should be ignored since it references upstream
-	expectedTargets := []ProxyTarget{
-		{
-			Host:       "service.consul",
-			Port:       "dynamic",
-			Type:       "upstream",
-			Resolver:   "127.0.0.1:8600",
-			IsConsul:   true,
-			ServiceURL: "service.consul service=redacted-net resolve",
-		},
-	}
-
-	if len(targets) != len(expectedTargets) {
-		t.Errorf("Expected %d targets, got %d", len(expectedTargets), len(targets))
-		return
-	}
-
-	// Create a map for easier comparison
-	targetMap := make(map[string]ProxyTarget)
-	for _, target := range targets {
-		key := target.Host + ":" + target.Port + ":" + target.Type + ":" + target.Resolver
-		if target.IsConsul {
-			key += ":consul:" + target.ServiceURL
-		}
-		targetMap[key] = target
-	}
-
-	for _, expected := range expectedTargets {
-		key := expected.Host + ":" + expected.Port + ":" + expected.Type + ":" + expected.Resolver
-		if expected.IsConsul {
-			key += ":consul:" + expected.ServiceURL
-		}
-		if _, found := targetMap[key]; !found {
-			t.Errorf("Expected target not found: %+v", expected)
-		}
-	}
-}
-
-// TestConsulResolverExtractServiceName tests service name extraction
-func TestConsulResolverExtractServiceName(t *testing.T) {
-	resolver := NewConsulResolver("127.0.0.1:8600")
-
-	tests := []struct {
-		serviceURL   string
-		expectedName string
-	}{
-		{
-			serviceURL:   "service.consul service=redacted-net resolve",
-			expectedName: "redacted-net",
-		},
-		{
-			serviceURL:   "service.consul service=web-service resolve",
-			expectedName: "web-service",
-		},
-		{
-			serviceURL:   "service.consul service=api-backend resolve",
-			expectedName: "api-backend",
-		},
-		{
-			serviceURL:   "my-service.service.consul",
-			expectedName: "my-service",
-		},
-		{
-			serviceURL:   "invalid-format",
-			expectedName: "",
-		},
-	}
-
-	for _, test := range tests {
-		result := resolver.extractServiceName(test.serviceURL)
-		if result != test.expectedName {
-			t.Errorf("extractServiceName(%q) = %q, expected %q", test.serviceURL, result, test.expectedName)
-		}
-	}
-}
-
-// TestConsulResolverResolveService tests the actual resolution functionality
-func TestConsulResolverResolveService(t *testing.T) {
-	// Test with a mock resolver that should fail (127.0.0.1:8600 is consul default but likely not running)
-	t.Run("ResolutionWithMockConsul", func(t *testing.T) {
-		resolver := NewConsulResolver("127.0.0.1:8600")
-
-		addresses, err := resolver.ResolveService("service.consul service=test-service resolve")
-
-		// We expect this to fail since there's no real consul server
-		if err == nil {
-			t.Logf("Unexpected success: resolved addresses %v (maybe there's a real consul server?)", addresses)
-		} else {
-			t.Logf("Expected failure: %v", err)
-		}
-	})
-
-	// Test with invalid service URL
-	t.Run("InvalidServiceURL", func(t *testing.T) {
-		resolver := NewConsulResolver("127.0.0.1:8600")
-
-		addresses, err := resolver.ResolveService("invalid-service-url")
-
-		if err == nil {
-			t.Errorf("Expected error for invalid service URL, got addresses: %v", addresses)
-		}
-
-		if len(addresses) != 0 {
-			t.Errorf("Expected no addresses for invalid service URL, got %v", addresses)
-		}
-	})
-
-	// Test with invalid resolver address
-	t.Run("InvalidResolverAddress", func(t *testing.T) {
-		resolver := NewConsulResolver("192.168.254.254:8600") // Unreachable IP
-
-		addresses, err := resolver.ResolveService("service.consul service=test-service resolve")
-
-		// Should fail due to unreachable resolver
-		if err == nil {
-			t.Errorf("Expected error for unreachable resolver, got addresses: %v", addresses)
-		}
-	})
-
-	// Test service name extraction edge cases
-	t.Run("ServiceNameExtractionEdgeCases", func(t *testing.T) {
-		resolver := NewConsulResolver("127.0.0.1:8600")
-
-		testCases := []struct {
-			serviceURL   string
-			expectedName string
-		}{
-			{"", ""},
-			{"service.consul", ""},
-			{"service.consul resolve", ""},
-			{"service.consul service= resolve", ""},
-			{"service.consul service=  resolve", ""}, // Empty service name
-			{"my-service.service.consul", "my-service"},
-			{"complex-service-name.service.consul", "complex-service-name"},
-		}
-
-		for _, tc := range testCases {
-			result := resolver.extractServiceName(tc.serviceURL)
-			if result != tc.expectedName {
-				t.Errorf("extractServiceName(%q) = %q, expected %q", tc.serviceURL, result, tc.expectedName)
-			}
-		}
-	})
-}
-
-// TestTestConsulTargets tests the new dedicated consul testing function
-func TestTestConsulTargets(t *testing.T) {
-	// Test 1: Valid consul targets with resolver
-	t.Run("ValidConsulTargets", func(t *testing.T) {
-		consulTargets := []ProxyTarget{
-			{
-				Host:       "service.consul",
-				Port:       "dynamic",
-				Type:       "upstream",
-				Resolver:   "127.0.0.1:8600",
-				IsConsul:   true,
-				ServiceURL: "service.consul service=test-service resolve",
-			},
-		}
-
-		results := TestConsulTargets(consulTargets)
-
-		// Should have exactly 1 result
-		if len(results) != 1 {
-			t.Errorf("Expected 1 result, got %d", len(results))
-		}
-
-		// Check the result exists with correct key
-		key := "service.consul:dynamic"
-		if status, found := results[key]; found {
-			// The status doesn't matter much (likely offline without real consul)
-			// What matters is that the function processes the target correctly
-			t.Logf("Consul target %s processed: Online=%v, Latency=%.2f", key, status.Online, status.Latency)
-		} else {
-			t.Errorf("Expected result for key %s not found", key)
-		}
-	})
-
-	// Test 2: Consul target without resolver should be marked offline
-	t.Run("ConsulTargetWithoutResolver", func(t *testing.T) {
-		consulTargets := []ProxyTarget{
-			{
-				Host: "service.consul",
-				Port: "dynamic",
-				Type: "upstream",
-				// No resolver - should be marked offline immediately
-				IsConsul:   true,
-				ServiceURL: "service.consul service=no-resolver resolve",
-			},
-		}
-
-		results := TestConsulTargets(consulTargets)
-
-		if len(results) != 1 {
-			t.Errorf("Expected 1 result, got %d", len(results))
-		}
-
-		key := "service.consul:dynamic"
-		if status, found := results[key]; found {
-			if status.Online {
-				t.Errorf("Expected consul target without resolver to be offline, but it's online")
-			}
-			if status.Latency != 0 {
-				t.Errorf("Expected latency to be 0 for offline target, got %.2f", status.Latency)
-			}
-		} else {
-			t.Errorf("Expected result for key %s not found", key)
-		}
-	})
-
-	// Test 3: Multiple consul targets with different resolvers
-	t.Run("MultipleConsulTargetsWithDifferentResolvers", func(t *testing.T) {
-		consulTargets := []ProxyTarget{
-			{
-				Host:       "web-service.consul",
-				Port:       "dynamic",
-				Type:       "upstream",
-				Resolver:   "127.0.0.1:8600",
-				IsConsul:   true,
-				ServiceURL: "service.consul service=web-service resolve",
-			},
-			{
-				Host:       "api-service.consul",
-				Port:       "dynamic",
-				Type:       "upstream",
-				Resolver:   "127.0.0.1:8500", // Different resolver
-				IsConsul:   true,
-				ServiceURL: "service.consul service=api-service resolve",
-			},
-		}
-
-		results := TestConsulTargets(consulTargets)
-
-		// Should have 2 results
-		if len(results) != 2 {
-			t.Errorf("Expected 2 results, got %d", len(results))
-		}
-
-		// Check both results exist
-		expectedKeys := []string{
-			"web-service.consul:dynamic",
-			"api-service.consul:dynamic",
-		}
-
-		for _, key := range expectedKeys {
-			if _, found := results[key]; !found {
-				t.Errorf("Expected result for key %s not found", key)
-			}
-		}
-	})
-
-	// Test 4: Empty consul targets should return empty results
-	t.Run("EmptyConsulTargets", func(t *testing.T) {
-		consulTargets := []ProxyTarget{}
-		results := TestConsulTargets(consulTargets)
-
-		if len(results) != 0 {
-			t.Errorf("Expected 0 results for empty targets, got %d", len(results))
-		}
-	})
-}
-
-// TestSimplifiedArchitecture tests the new simplified architecture
-func TestSimplifiedArchitecture(t *testing.T) {
-	service := GetUpstreamService()
-	service.ClearTargets()
-
-	// Mix of traditional and consul targets
-	mixedTargets := []ProxyTarget{
-		// Traditional targets
-		{Host: "127.0.0.1", Port: "80", Type: "upstream"},
-		{Host: "192.168.1.100", Port: "8080", Type: "upstream"},
-		// Consul targets
-		{
-			Host:       "service.consul",
-			Port:       "dynamic",
-			Type:       "upstream",
-			Resolver:   "127.0.0.1:8600",
-			IsConsul:   true,
-			ServiceURL: "service.consul service=my-service resolve",
-		},
-	}
-
-	service.updateTargetsFromConfig("test-config.conf", mixedTargets)
-
-	// Verify targets are correctly stored
-	service.targetsMutex.RLock()
-	traditionalCount := 0
-	consulCount := 0
-	for _, targetInfo := range service.targets {
-		if targetInfo.ProxyTarget.IsConsul {
-			consulCount++
-		} else {
-			traditionalCount++
-		}
-	}
-	service.targetsMutex.RUnlock()
-
-	if traditionalCount != 2 {
-		t.Errorf("Expected 2 traditional targets, got %d", traditionalCount)
-	}
-	if consulCount != 1 {
-		t.Errorf("Expected 1 consul target, got %d", consulCount)
-	}
-
-	t.Logf("Architecture correctly separated %d traditional and %d consul targets", traditionalCount, consulCount)
-
-	// Clean up
-	service.ClearTargets()
-}
-
-// TestEnhancedAvailabilityTest tests the enhanced availability testing with mixed targets
-func TestEnhancedAvailabilityTest(t *testing.T) {
-	targets := []ProxyTarget{
-		// Regular target
-		{
-			Host: "127.0.0.1",
-			Port: "22", // SSH port might be available
-			Type: "upstream",
-		},
-		// Consul target (will fail since no real consul)
-		{
-			Host:       "service.consul",
-			Port:       "dynamic",
-			Type:       "upstream",
-			Resolver:   "127.0.0.1:8600",
-			IsConsul:   true,
-			ServiceURL: "service.consul service=test-service resolve",
-		},
-		// Invalid regular target
-		{
-			Host: "192.168.254.254",
-			Port: "9999",
-			Type: "upstream",
-		},
-	}
-
-	results := EnhancedAvailabilityTest(targets)
-
-	t.Logf("Found %d test results:", len(results))
-	for key, status := range results {
-		t.Logf("Target %s: Online=%v, Latency=%.2f", key, status.Online, status.Latency)
-	}
-
-	// Verify we have results for all targets
-	expectedKeys := []string{
-		"127.0.0.1:22",
-		"service.consul:dynamic",
-		"192.168.254.254:9999",
-	}
-
-	for _, key := range expectedKeys {
-		if _, found := results[key]; !found {
-			t.Errorf("Expected result for key %s not found", key)
-		}
-	}
-
-	// Test that consul target is processed (result doesn't matter, we just verify the flow works)
-	if status, found := results["service.consul:dynamic"]; found {
-		t.Logf("Consul target processed: Online=%v, Latency=%.2f", status.Online, status.Latency)
-	}
-
-	// Test that unreachable target is properly handled
-	if status, found := results["192.168.254.254:9999"]; found {
-		// This should be offline due to unreachable IP, but we verify the function handles it
-		t.Logf("Unreachable target processed: Online=%v, Latency=%.2f", status.Online, status.Latency)
-		// Most likely offline, but we don't assume - we just verify it was processed
-	}
-}
-
-// TestTraditionalAvailabilityTestUsage tests that traditional AvailabilityTest is used when no consul targets
-func TestTraditionalAvailabilityTestUsage(t *testing.T) {
-	// Test with only traditional targets
-	targets := []ProxyTarget{
-		{
-			Host: "127.0.0.1",
-			Port: "80",
-			Type: "upstream",
-		},
-		{
-			Host: "192.168.254.254",
-			Port: "9999",
-			Type: "upstream",
-		},
-	}
-
-	// Test enhanced version with traditional targets only
-	enhancedResults := EnhancedAvailabilityTest(targets)
-
-	// Test traditional version directly
-	traditionalKeys := []string{"127.0.0.1:80", "192.168.254.254:9999"}
-	traditionalResults := AvailabilityTest(traditionalKeys)
-
-	t.Logf("Enhanced results: %d items", len(enhancedResults))
-	t.Logf("Traditional results: %d items", len(traditionalResults))
-
-	// Both should have same number of results
-	if len(enhancedResults) != len(traditionalResults) {
-		t.Errorf("Expected same number of results, enhanced=%d, traditional=%d",
-			len(enhancedResults), len(traditionalResults))
-		return
-	}
-
-	// Results should be consistent
-	for key, traditionalStatus := range traditionalResults {
-		if enhancedStatus, found := enhancedResults[key]; found {
-			if traditionalStatus.Online != enhancedStatus.Online {
-				t.Errorf("Inconsistent online status for %s: traditional=%v, enhanced=%v",
-					key, traditionalStatus.Online, enhancedStatus.Online)
-			}
-		} else {
-			t.Errorf("Key %s missing in enhanced results", key)
-		}
-	}
-
-	t.Logf("Enhanced test correctly delegated to traditional test for non-consul targets")
-}
-
-// TestUpstreamServiceSimplifiedFlow tests the new simplified flow in UpstreamService
-func TestUpstreamServiceSimplifiedFlow(t *testing.T) {
-	service := GetUpstreamService()
-	service.ClearTargets()
-
-	// Add mixed targets
-	mixedTargets := []ProxyTarget{
-		{Host: "127.0.0.1", Port: "80", Type: "upstream"},
-		{
-			Host:       "service.consul",
-			Port:       "dynamic",
-			Type:       "upstream",
-			Resolver:   "127.0.0.1:8600",
-			IsConsul:   true,
-			ServiceURL: "service.consul service=test resolve",
-		},
-	}
-
-	service.updateTargetsFromConfig("test-config.conf", mixedTargets)
-
-	// This would trigger the simplified flow
-	service.PerformAvailabilityTest()
-
-	results := service.GetAvailabilityMap()
-	t.Logf("Simplified flow generated %d results:", len(results))
-	for key, status := range results {
-		t.Logf("Result %s: Online=%v, Latency=%.2f", key, status.Online, status.Latency)
-	}
-
-	// Should have results for both targets
-	expectedKeys := []string{"127.0.0.1:80", "service.consul:dynamic"}
-	for _, key := range expectedKeys {
-		if _, found := results[key]; !found {
-			t.Errorf("Expected result for key %s not found", key)
-		}
-	}
-
-	t.Logf("Simplified architecture correctly processed mixed targets")
-
-	// Clean up
-	service.ClearTargets()
-}

+ 332 - 0
internal/upstream/dynamic_resolver.go

@@ -0,0 +1,332 @@
+package upstream
+
+// Package upstream provides DNS resolution and availability testing for nginx upstream targets,
+// with special support for dynamic service discovery and nginx-style SRV record resolution.
+//
+// # SRV Record Resolution (nginx.org compliant)
+//
+// This package implements nginx's SRV record resolution rules as documented at nginx.org.
+// The service=name parameter enables resolving of DNS SRV records and sets the service name.
+//
+// Rules for SRV record construction:
+//
+//  1. If the service name does not contain a dot ("."), then the RFC-compliant name is constructed
+//     and the TCP protocol is added to the service prefix.
+//     Example: "backend.example.com service=http resolve" -> "_http._tcp.backend.example.com"
+//
+//  2. If the service name contains one or more dots, then the name is constructed by joining
+//     the service prefix and the server name.
+//     Example: "backend.example.com service=_http._tcp resolve" -> "_http._tcp.backend.example.com"
+//     Example: "example.com service=server1.backend resolve" -> "server1.backend.example.com"
+//
+// # Dynamic DNS Integration
+//
+// The resolver supports various DNS interfaces for service discovery:
+// - DNS servers (e.g., Consul DNS on 127.0.0.1:8600, CoreDNS, etc.)
+// - Service registration and health checking
+// - SRV record-based load balancing with proper priority handling
+//
+// # Usage Examples
+//
+//	// Create resolver with DNS server
+//	resolver := NewDynamicResolver("127.0.0.1:8600")
+//
+//	// Resolve nginx-style service URL
+//	addresses, err := resolver.ResolveService("backend.example.com service=http resolve")
+//	// This queries "_http._tcp.backend.example.com" SRV records
+//
+//	// Resolve with dotted service name
+//	addresses, err := resolver.ResolveService("example.com service=server1.backend resolve")
+//	// This queries "server1.backend.example.com" SRV records
+
+import (
+	"context"
+	"fmt"
+	"net"
+	"strings"
+	"time"
+)
+
+// DynamicResolver handles DNS resolution through dynamic DNS servers
+type DynamicResolver struct {
+	resolver string // e.g., "127.0.0.1:8600"
+}
+
+// NewDynamicResolver creates a new dynamic resolver
+func NewDynamicResolver(resolver string) *DynamicResolver {
+	return &DynamicResolver{
+		resolver: resolver,
+	}
+}
+
+// ServiceInfo contains parsed service information from nginx config
+type ServiceInfo struct {
+	Hostname    string // e.g., "backend.example.com" or "service.consul"
+	ServiceName string // e.g., "http", "_http._tcp", "server1.backend"
+}
+
+// ResolveService resolves a nginx service to actual IP addresses and ports
+func (dr *DynamicResolver) ResolveService(serviceURL string) ([]string, error) {
+	// Parse service URL to extract hostname and service name
+	serviceInfo, err := dr.parseServiceURL(serviceURL)
+	if err != nil {
+		return nil, fmt.Errorf("failed to parse service URL %s: %v", serviceURL, err)
+	}
+
+	// Create a custom resolver that uses the DNS server
+	dialer := &net.Dialer{
+		Timeout: 5 * time.Second,
+	}
+
+	resolver := &net.Resolver{
+		PreferGo: true,
+		Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
+			return dialer.DialContext(ctx, network, dr.resolver)
+		},
+	}
+
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel()
+
+	// Construct SRV query domain according to nginx rules
+	srvDomain := dr.constructSRVDomain(serviceInfo)
+
+	// Query for service SRV records
+	_, srvRecords, err := resolver.LookupSRV(ctx, "", "", srvDomain)
+	if err != nil {
+		// Fallback to A record lookup if SRV fails
+		ips, err := resolver.LookupIPAddr(ctx, srvDomain)
+		if err != nil {
+			return nil, fmt.Errorf("failed to resolve service %s: %v", srvDomain, err)
+		}
+
+		// Return IP addresses with default port (80)
+		var addresses []string
+		for _, ip := range ips {
+			addresses = append(addresses, fmt.Sprintf("%s:80", ip.IP.String()))
+		}
+		return addresses, nil
+	}
+
+	// Convert SRV records to address:port format
+	var addresses []string
+	for _, srv := range srvRecords {
+		// Resolve the target hostname to IP
+		ips, err := resolver.LookupIPAddr(ctx, srv.Target)
+		if err != nil {
+			continue // Skip this record if resolution fails
+		}
+
+		for _, ip := range ips {
+			addresses = append(addresses, fmt.Sprintf("%s:%d", ip.IP.String(), srv.Port))
+		}
+	}
+
+	if len(addresses) == 0 {
+		return nil, fmt.Errorf("no addresses found for service %s", srvDomain)
+	}
+
+	return addresses, nil
+}
+
+// parseServiceURL parses nginx service URL and extracts hostname and service name
+func (dr *DynamicResolver) parseServiceURL(serviceURL string) (*ServiceInfo, error) {
+	serviceURL = strings.TrimSpace(serviceURL)
+	if serviceURL == "" {
+		return nil, fmt.Errorf("empty service URL")
+	}
+
+	// Parse nginx format: "hostname service=servicename resolve"
+	parts := strings.Fields(serviceURL)
+	if len(parts) < 3 {
+		return nil, fmt.Errorf("invalid service URL format: %s", serviceURL)
+	}
+
+	hostname := parts[0]
+	var serviceName string
+
+	// Find service=name parameter
+	for _, part := range parts[1:] {
+		if strings.HasPrefix(part, "service=") {
+			serviceName = strings.TrimPrefix(part, "service=")
+			serviceName = strings.TrimSpace(serviceName)
+			break
+		}
+	}
+
+	if serviceName == "" {
+		return nil, fmt.Errorf("service parameter not found in: %s", serviceURL)
+	}
+
+	return &ServiceInfo{
+		Hostname:    hostname,
+		ServiceName: serviceName,
+	}, nil
+}
+
+// constructSRVDomain constructs SRV query domain according to nginx.org rules
+func (dr *DynamicResolver) constructSRVDomain(serviceInfo *ServiceInfo) string {
+	// According to nginx.org documentation:
+	// 1. If service name does not contain a dot ("."), then RFC-compliant name is constructed
+	//    and TCP protocol is added to the service prefix.
+	//    Example: service=http -> _http._tcp.hostname
+	// 2. If service name contains one or more dots, then the name is constructed by joining
+	//    the service prefix and the server name.
+	//    Example: service=_http._tcp -> _http._tcp.hostname
+	//    Example: service=server1.backend -> server1.backend.hostname
+
+	if !strings.Contains(serviceInfo.ServiceName, ".") {
+		// Case 1: No dots - construct RFC-compliant name with TCP protocol
+		return fmt.Sprintf("_%s._tcp.%s", serviceInfo.ServiceName, serviceInfo.Hostname)
+	} else {
+		// Case 2: Contains dots - join service prefix and hostname
+		return fmt.Sprintf("%s.%s", serviceInfo.ServiceName, serviceInfo.Hostname)
+	}
+}
+
+// extractServiceName extracts the service name from service URL
+// Deprecated: Use parseServiceURL instead for proper nginx-style parsing
+func (dr *DynamicResolver) extractServiceName(serviceURL string) string {
+	serviceInfo, err := dr.parseServiceURL(serviceURL)
+	if err != nil {
+		// Fallback to old parsing logic for backward compatibility
+		serviceURL = strings.TrimSpace(serviceURL)
+
+		// Handle empty input
+		if serviceURL == "" {
+			return ""
+		}
+
+		// Parse "service.consul service=redacted-net resolve" format
+		if strings.Contains(serviceURL, "service=") {
+			parts := strings.Fields(serviceURL)
+			for _, part := range parts {
+				if strings.HasPrefix(part, "service=") {
+					serviceName := strings.TrimPrefix(part, "service=")
+					// Handle edge cases like "service=" or "service=  "
+					serviceName = strings.TrimSpace(serviceName)
+					if serviceName == "" {
+						return ""
+					}
+					return serviceName
+				}
+			}
+		}
+
+		// Fallback: try to extract from hostname format like "my-service.service.consul"
+		if strings.Contains(serviceURL, ".service.consul") {
+			parts := strings.Split(serviceURL, ".")
+			if len(parts) > 0 {
+				serviceName := strings.TrimSpace(parts[0])
+				if serviceName == "" {
+					return ""
+				}
+				return serviceName
+			}
+		}
+
+		return ""
+	}
+
+	return serviceInfo.ServiceName
+}
+
+// TestDynamicTargets performs availability test specifically for dynamic DNS targets
+func TestDynamicTargets(dynamicTargets []ProxyTarget) map[string]*Status {
+	result := make(map[string]*Status)
+
+	// Group dynamic targets by resolver
+	dynamicTargetsByResolver := make(map[string][]ProxyTarget)
+	for _, target := range dynamicTargets {
+		if target.Resolver != "" {
+			dynamicTargetsByResolver[target.Resolver] = append(dynamicTargetsByResolver[target.Resolver], target)
+		} else {
+			// No resolver specified, mark as offline
+			key := target.Host + ":" + target.Port
+			result[key] = &Status{
+				Online:  false,
+				Latency: 0,
+			}
+		}
+	}
+
+	// Test each resolver group
+	for resolver, targets := range dynamicTargetsByResolver {
+		dynamicResolver := NewDynamicResolver(resolver)
+
+		for _, target := range targets {
+			key := target.Host + ":" + target.Port
+
+			// Try to resolve the service
+			addresses, err := dynamicResolver.ResolveService(target.ServiceURL)
+			if err != nil {
+				// If resolution fails, mark as offline
+				result[key] = &Status{
+					Online:  false,
+					Latency: 0,
+				}
+				continue
+			}
+
+			// Test the first resolved address as representative
+			if len(addresses) > 0 {
+				addressResults := AvailabilityTest(addresses[:1])
+
+				if status, exists := addressResults[addresses[0]]; exists {
+					result[key] = status
+				} else {
+					result[key] = &Status{
+						Online:  false,
+						Latency: 0,
+					}
+				}
+			} else {
+				result[key] = &Status{
+					Online:  false,
+					Latency: 0,
+				}
+			}
+		}
+	}
+
+	return result
+}
+
+// EnhancedAvailabilityTest performs availability test with dynamic DNS resolution support
+// Deprecated: Use TestDynamicTargets for dynamic targets and AvailabilityTest for regular targets
+func EnhancedAvailabilityTest(targets []ProxyTarget) map[string]*Status {
+	result := make(map[string]*Status)
+
+	// Group targets by type
+	dynamicTargets := make([]ProxyTarget, 0)
+	regularTargets := make([]string, 0)
+
+	for _, target := range targets {
+		if target.IsConsul && target.Resolver != "" {
+			dynamicTargets = append(dynamicTargets, target)
+		} else {
+			// Regular target - use existing format for traditional AvailabilityTest
+			key := target.Host + ":" + target.Port
+			regularTargets = append(regularTargets, key)
+		}
+	}
+
+	// Use traditional AvailabilityTest for regular targets (more efficient)
+	if len(regularTargets) > 0 {
+		regularResults := AvailabilityTest(regularTargets)
+		// Merge results
+		for k, v := range regularResults {
+			result[k] = v
+		}
+	}
+
+	// Test dynamic targets with DNS resolution
+	if len(dynamicTargets) > 0 {
+		dynamicResults := TestDynamicTargets(dynamicTargets)
+		for k, v := range dynamicResults {
+			result[k] = v
+		}
+	}
+
+	return result
+}

+ 683 - 0
internal/upstream/dynamic_resolver_test.go

@@ -0,0 +1,683 @@
+package upstream
+
+import (
+	"context"
+	"fmt"
+	"net"
+	"sort"
+	"strings"
+	"testing"
+)
+
+// MockDNSServer simulates DNS responses for testing
+type MockDNSServer struct {
+	srvRecords map[string][]*net.SRV
+	aRecords   map[string][]net.IPAddr
+}
+
+// NewMockDNSServer creates a mock DNS server for testing
+func NewMockDNSServer() *MockDNSServer {
+	return &MockDNSServer{
+		srvRecords: make(map[string][]*net.SRV),
+		aRecords:   make(map[string][]net.IPAddr),
+	}
+}
+
+// AddSRVRecord adds a SRV record to the mock DNS server
+func (m *MockDNSServer) AddSRVRecord(domain string, priority, weight uint16, port uint16, target string) {
+	m.srvRecords[domain] = append(m.srvRecords[domain], &net.SRV{
+		Priority: priority,
+		Weight:   weight,
+		Port:     port,
+		Target:   target,
+	})
+}
+
+// AddARecord adds an A record to the mock DNS server
+func (m *MockDNSServer) AddARecord(domain string, ip string) {
+	m.aRecords[domain] = append(m.aRecords[domain], net.IPAddr{
+		IP: net.ParseIP(ip),
+	})
+}
+
+// MockResolver is a custom resolver that uses our mock DNS server
+type MockResolver struct {
+	mockServer *MockDNSServer
+}
+
+// LookupSRV simulates SRV record lookup with proper priority sorting
+func (mr *MockResolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*net.SRV, error) {
+	domain := name
+	if service != "" || proto != "" {
+		domain = fmt.Sprintf("_%s._%s.%s", service, proto, name)
+	}
+
+	if records, exists := mr.mockServer.srvRecords[domain]; exists {
+		// Sort SRV records by priority (lowest first), then by weight (highest first)
+		// This follows RFC 2782 and nginx behavior
+		sortedRecords := make([]*net.SRV, len(records))
+		copy(sortedRecords, records)
+
+		sort.Slice(sortedRecords, func(i, j int) bool {
+			if sortedRecords[i].Priority != sortedRecords[j].Priority {
+				return sortedRecords[i].Priority < sortedRecords[j].Priority
+			}
+			// For same priority, higher weight comes first (but this is simplified for testing)
+			return sortedRecords[i].Weight > sortedRecords[j].Weight
+		})
+
+		return "", sortedRecords, nil
+	}
+	return "", nil, fmt.Errorf("no SRV records for %s", domain)
+}
+
+// LookupIPAddr simulates A record lookup
+func (mr *MockResolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error) {
+	if records, exists := mr.mockServer.aRecords[host]; exists {
+		return records, nil
+	}
+	return nil, fmt.Errorf("no A records for %s", host)
+}
+
+// TestParseServiceURL tests the parseServiceURL function with nginx compliance
+func TestParseServiceURL(t *testing.T) {
+	tests := []struct {
+		name        string
+		input       string
+		expectedErr bool
+		expected    *ServiceInfo
+	}{
+		{
+			name:  "Valid nginx service URL - simple service name",
+			input: "backend.example.com service=http resolve",
+			expected: &ServiceInfo{
+				Hostname:    "backend.example.com",
+				ServiceName: "http",
+			},
+		},
+		{
+			name:  "Valid nginx service URL - service name with underscores",
+			input: "backend.example.com service=_http._tcp resolve",
+			expected: &ServiceInfo{
+				Hostname:    "backend.example.com",
+				ServiceName: "_http._tcp",
+			},
+		},
+		{
+			name:  "Valid nginx service URL - service name with dots",
+			input: "example.com service=server1.backend resolve",
+			expected: &ServiceInfo{
+				Hostname:    "example.com",
+				ServiceName: "server1.backend",
+			},
+		},
+		{
+			name:  "Consul service example",
+			input: "service.consul service=web-service resolve",
+			expected: &ServiceInfo{
+				Hostname:    "service.consul",
+				ServiceName: "web-service",
+			},
+		},
+		{
+			name:        "Empty input",
+			input:       "",
+			expectedErr: true,
+		},
+		{
+			name:        "Missing resolve parameter",
+			input:       "backend.example.com service=http",
+			expectedErr: true,
+		},
+		{
+			name:        "Missing service parameter",
+			input:       "backend.example.com resolve",
+			expectedErr: true,
+		},
+		{
+			name:        "Empty service name",
+			input:       "backend.example.com service= resolve",
+			expectedErr: true,
+		},
+		{
+			name:        "Only hostname",
+			input:       "backend.example.com",
+			expectedErr: true,
+		},
+	}
+
+	resolver := NewDynamicResolver("127.0.0.1:8600")
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			result, err := resolver.parseServiceURL(tt.input)
+
+			if tt.expectedErr {
+				if err == nil {
+					t.Errorf("Expected error but got none")
+				}
+				return
+			}
+
+			if err != nil {
+				t.Errorf("Unexpected error: %v", err)
+				return
+			}
+
+			if result.Hostname != tt.expected.Hostname {
+				t.Errorf("Expected hostname %s, got %s", tt.expected.Hostname, result.Hostname)
+			}
+
+			if result.ServiceName != tt.expected.ServiceName {
+				t.Errorf("Expected service name %s, got %s", tt.expected.ServiceName, result.ServiceName)
+			}
+		})
+	}
+}
+
+// TestConstructSRVDomain tests SRV domain construction according to nginx.org rules
+func TestConstructSRVDomain(t *testing.T) {
+	tests := []struct {
+		name     string
+		input    *ServiceInfo
+		expected string
+		rule     string
+	}{
+		{
+			name: "Rule 1: Service name without dots - http",
+			input: &ServiceInfo{
+				Hostname:    "backend.example.com",
+				ServiceName: "http",
+			},
+			expected: "_http._tcp.backend.example.com",
+			rule:     "nginx rule 1: no dots, add TCP protocol",
+		},
+		{
+			name: "Rule 1: Service name without dots - https",
+			input: &ServiceInfo{
+				Hostname:    "api.example.com",
+				ServiceName: "https",
+			},
+			expected: "_https._tcp.api.example.com",
+			rule:     "nginx rule 1: no dots, add TCP protocol",
+		},
+		{
+			name: "Rule 1: Service name without dots - mysql",
+			input: &ServiceInfo{
+				Hostname:    "db.example.com",
+				ServiceName: "mysql",
+			},
+			expected: "_mysql._tcp.db.example.com",
+			rule:     "nginx rule 1: no dots, add TCP protocol",
+		},
+		{
+			name: "Rule 2: Service name with dots - _http._tcp",
+			input: &ServiceInfo{
+				Hostname:    "backend.example.com",
+				ServiceName: "_http._tcp",
+			},
+			expected: "_http._tcp.backend.example.com",
+			rule:     "nginx rule 2: contains dots, join directly",
+		},
+		{
+			name: "Rule 2: Service name with dots - server1.backend",
+			input: &ServiceInfo{
+				Hostname:    "example.com",
+				ServiceName: "server1.backend",
+			},
+			expected: "server1.backend.example.com",
+			rule:     "nginx rule 2: contains dots, join directly",
+		},
+		{
+			name: "Rule 2: Complex service name with underscores and dots",
+			input: &ServiceInfo{
+				Hostname:    "dc1.consul",
+				ServiceName: "_api._tcp.production",
+			},
+			expected: "_api._tcp.production.dc1.consul",
+			rule:     "nginx rule 2: contains dots, join directly",
+		},
+		{
+			name: "Consul example - simple service",
+			input: &ServiceInfo{
+				Hostname:    "service.consul",
+				ServiceName: "web",
+			},
+			expected: "_web._tcp.service.consul",
+			rule:     "nginx rule 1: no dots, add TCP protocol",
+		},
+	}
+
+	resolver := NewDynamicResolver("127.0.0.1:8600")
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			result := resolver.constructSRVDomain(tt.input)
+			if result != tt.expected {
+				t.Errorf("Expected SRV domain %s, got %s (rule: %s)", tt.expected, result, tt.rule)
+			}
+		})
+	}
+}
+
+// TestNginxOfficialExamples tests the exact examples from nginx.org documentation
+func TestNginxOfficialExamples(t *testing.T) {
+	tests := []struct {
+		name          string
+		nginxConfig   string
+		expectedQuery string
+		description   string
+	}{
+		{
+			name:          "Official Example 1",
+			nginxConfig:   "backend.example.com service=http resolve",
+			expectedQuery: "_http._tcp.backend.example.com",
+			description:   "To look up _http._tcp.backend.example.com SRV record",
+		},
+		{
+			name:          "Official Example 2",
+			nginxConfig:   "backend.example.com service=_http._tcp resolve",
+			expectedQuery: "_http._tcp.backend.example.com",
+			description:   "Service name already contains dots, join directly",
+		},
+		{
+			name:          "Official Example 3",
+			nginxConfig:   "example.com service=server1.backend resolve",
+			expectedQuery: "server1.backend.example.com",
+			description:   "Service name contains dots, join directly",
+		},
+	}
+
+	resolver := NewDynamicResolver("127.0.0.1:8600")
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			serviceInfo, err := resolver.parseServiceURL(tt.nginxConfig)
+			if err != nil {
+				t.Fatalf("Failed to parse nginx config: %v", err)
+			}
+
+			result := resolver.constructSRVDomain(serviceInfo)
+			if result != tt.expectedQuery {
+				t.Errorf("nginx.org example failed: expected %s, got %s (%s)",
+					tt.expectedQuery, result, tt.description)
+			}
+		})
+	}
+}
+
+// TestSRVRecordResolutionWithMockDNS tests actual SRV record resolution using mock DNS
+func TestSRVRecordResolutionWithMockDNS(t *testing.T) {
+	// Create mock DNS server
+	mockDNS := NewMockDNSServer()
+
+	// Add SRV records for _http._tcp.backend.example.com
+	mockDNS.AddSRVRecord("_http._tcp.backend.example.com", 10, 60, 8080, "web1.backend.example.com")
+	mockDNS.AddSRVRecord("_http._tcp.backend.example.com", 10, 40, 8080, "web2.backend.example.com")
+	mockDNS.AddSRVRecord("_http._tcp.backend.example.com", 20, 100, 8080, "web3.backend.example.com")
+
+	// Add A records for the targets
+	mockDNS.AddARecord("web1.backend.example.com", "192.168.1.10")
+	mockDNS.AddARecord("web2.backend.example.com", "192.168.1.11")
+	mockDNS.AddARecord("web3.backend.example.com", "192.168.1.12")
+
+	t.Run("SRV record resolution", func(t *testing.T) {
+		mockResolver := &MockResolver{mockServer: mockDNS}
+
+		// Test SRV lookup
+		_, srvRecords, err := mockResolver.LookupSRV(context.Background(), "", "", "_http._tcp.backend.example.com")
+		if err != nil {
+			t.Fatalf("SRV lookup failed: %v", err)
+		}
+
+		if len(srvRecords) != 3 {
+			t.Errorf("Expected 3 SRV records, got %d", len(srvRecords))
+		}
+
+		// Verify priority ordering (lowest priority first) and weight ordering (highest weight first within same priority)
+		expectedPriorities := []uint16{10, 10, 20}
+		expectedWeights := []uint16{60, 40, 100} // For priorities [10, 10, 20], weights should be [60, 40, 100]
+		expectedTargets := []string{"web1.backend.example.com", "web2.backend.example.com", "web3.backend.example.com"}
+
+		for i, srv := range srvRecords {
+			if srv.Priority != expectedPriorities[i] {
+				t.Errorf("Expected priority %d at index %d, got %d", expectedPriorities[i], i, srv.Priority)
+			}
+			if srv.Weight != expectedWeights[i] {
+				t.Errorf("Expected weight %d at index %d, got %d", expectedWeights[i], i, srv.Weight)
+			}
+			if srv.Target != expectedTargets[i] {
+				t.Errorf("Expected target %s at index %d, got %s", expectedTargets[i], i, srv.Target)
+			}
+		}
+
+		// Test A record resolution for each target
+		for _, srv := range srvRecords {
+			ips, err := mockResolver.LookupIPAddr(context.Background(), srv.Target)
+			if err != nil {
+				t.Errorf("A record lookup failed for %s: %v", srv.Target, err)
+				continue
+			}
+
+			if len(ips) != 1 {
+				t.Errorf("Expected 1 IP for %s, got %d", srv.Target, len(ips))
+			}
+		}
+	})
+}
+
+// TestSRVPriorityHandling tests nginx SRV priority handling as per nginx.org documentation
+func TestSRVPriorityHandling(t *testing.T) {
+	// Create mock DNS server
+	mockDNS := NewMockDNSServer()
+
+	// Add SRV records with different priorities to test primary/backup server logic
+	// Priority 5 (highest priority / primary servers)
+	mockDNS.AddSRVRecord("_http._tcp.app.example.com", 5, 100, 8080, "primary1.app.example.com")
+	mockDNS.AddSRVRecord("_http._tcp.app.example.com", 5, 50, 8080, "primary2.app.example.com")
+	// Priority 10 (backup servers)
+	mockDNS.AddSRVRecord("_http._tcp.app.example.com", 10, 80, 8080, "backup1.app.example.com")
+	// Priority 15 (lower priority backup servers)
+	mockDNS.AddSRVRecord("_http._tcp.app.example.com", 15, 200, 8080, "backup2.app.example.com")
+
+	// Add A records
+	mockDNS.AddARecord("primary1.app.example.com", "10.0.1.1")
+	mockDNS.AddARecord("primary2.app.example.com", "10.0.1.2")
+	mockDNS.AddARecord("backup1.app.example.com", "10.0.2.1")
+	mockDNS.AddARecord("backup2.app.example.com", "10.0.3.1")
+
+	t.Run("SRV priority handling", func(t *testing.T) {
+		mockResolver := &MockResolver{mockServer: mockDNS}
+
+		// Test SRV lookup
+		_, srvRecords, err := mockResolver.LookupSRV(context.Background(), "", "", "_http._tcp.app.example.com")
+		if err != nil {
+			t.Fatalf("SRV lookup failed: %v", err)
+		}
+
+		if len(srvRecords) != 4 {
+			t.Errorf("Expected 4 SRV records, got %d", len(srvRecords))
+		}
+
+		// According to nginx.org: "Highest-priority SRV records (records with the same lowest-number priority value)
+		// are resolved as primary servers, the rest of SRV records are resolved as backup servers"
+		expectedOrder := []struct {
+			priority   uint16
+			weight     uint16
+			target     string
+			serverType string
+		}{
+			{5, 100, "primary1.app.example.com", "primary"}, // Highest priority (lowest number)
+			{5, 50, "primary2.app.example.com", "primary"},  // Same priority, lower weight
+			{10, 80, "backup1.app.example.com", "backup"},   // Lower priority (backup)
+			{15, 200, "backup2.app.example.com", "backup"},  // Lowest priority (backup)
+		}
+
+		for i, srv := range srvRecords {
+			expected := expectedOrder[i]
+			if srv.Priority != expected.priority {
+				t.Errorf("Record %d: expected priority %d, got %d", i, expected.priority, srv.Priority)
+			}
+			if srv.Weight != expected.weight {
+				t.Errorf("Record %d: expected weight %d, got %d", i, expected.weight, srv.Weight)
+			}
+			if srv.Target != expected.target {
+				t.Errorf("Record %d: expected target %s, got %s", i, expected.target, srv.Target)
+			}
+
+			// Log the server type for documentation
+			t.Logf("Record %d: Priority %d, Weight %d, Target %s (%s server)",
+				i, srv.Priority, srv.Weight, srv.Target, expected.serverType)
+		}
+
+		// Verify primary servers come first (lowest priority numbers)
+		primaryCount := 0
+		for _, srv := range srvRecords {
+			if srv.Priority == 5 { // Primary servers have priority 5
+				primaryCount++
+			} else {
+				break // Once we hit a non-primary, all following should be backups
+			}
+		}
+
+		if primaryCount != 2 {
+			t.Errorf("Expected 2 primary servers at the beginning, got %d", primaryCount)
+		}
+	})
+}
+
+// TestARecordFallback tests A record fallback when SRV lookup fails
+func TestARecordFallback(t *testing.T) {
+	mockDNS := NewMockDNSServer()
+
+	// Only add A record, no SRV record
+	mockDNS.AddARecord("_http._tcp.backend.example.com", "192.168.1.100")
+
+	t.Run("A record fallback", func(t *testing.T) {
+		mockResolver := &MockResolver{mockServer: mockDNS}
+
+		// SRV lookup should fail
+		_, srvRecords, err := mockResolver.LookupSRV(context.Background(), "", "", "_http._tcp.backend.example.com")
+		if err == nil {
+			t.Error("Expected SRV lookup to fail")
+		}
+		if len(srvRecords) != 0 {
+			t.Errorf("Expected 0 SRV records, got %d", len(srvRecords))
+		}
+
+		// A record lookup should succeed
+		ips, err := mockResolver.LookupIPAddr(context.Background(), "_http._tcp.backend.example.com")
+		if err != nil {
+			t.Fatalf("A record lookup failed: %v", err)
+		}
+
+		if len(ips) != 1 {
+			t.Errorf("Expected 1 IP, got %d", len(ips))
+		}
+
+		expectedIP := "192.168.1.100"
+		if ips[0].IP.String() != expectedIP {
+			t.Errorf("Expected IP %s, got %s", expectedIP, ips[0].IP.String())
+		}
+	})
+}
+
+// TestComplexNginxScenarios tests more complex real-world nginx scenarios
+func TestComplexNginxScenarios(t *testing.T) {
+	tests := []struct {
+		name        string
+		nginxLine   string
+		expectedSRV string
+		scenario    string
+	}{
+		{
+			name:        "Load balancer with HTTP service",
+			nginxLine:   "api.microservices.local service=http resolve",
+			expectedSRV: "_http._tcp.api.microservices.local",
+			scenario:    "Microservices API load balancing",
+		},
+		{
+			name:        "Database connection",
+			nginxLine:   "db.cluster.local service=mysql resolve",
+			expectedSRV: "_mysql._tcp.db.cluster.local",
+			scenario:    "Database cluster connection",
+		},
+		{
+			name:        "WebSocket service",
+			nginxLine:   "chat.app.local service=ws resolve",
+			expectedSRV: "_ws._tcp.chat.app.local",
+			scenario:    "WebSocket service discovery",
+		},
+		{
+			name:        "Custom protocol with dots",
+			nginxLine:   "service.consul service=_grpc._tcp resolve",
+			expectedSRV: "_grpc._tcp.service.consul",
+			scenario:    "gRPC service via Consul",
+		},
+		{
+			name:        "Multi-level service hierarchy",
+			nginxLine:   "consul.local service=api.v1.production resolve",
+			expectedSRV: "api.v1.production.consul.local",
+			scenario:    "Multi-level service naming",
+		},
+		{
+			name:        "Kubernetes style service",
+			nginxLine:   "cluster.local service=_http._tcp.nginx.default resolve",
+			expectedSRV: "_http._tcp.nginx.default.cluster.local",
+			scenario:    "Kubernetes service discovery",
+		},
+	}
+
+	resolver := NewDynamicResolver("127.0.0.1:8600")
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			serviceInfo, err := resolver.parseServiceURL(tt.nginxLine)
+			if err != nil {
+				t.Fatalf("Failed to parse nginx line: %v", err)
+			}
+
+			result := resolver.constructSRVDomain(serviceInfo)
+			if result != tt.expectedSRV {
+				t.Errorf("Scenario '%s' failed: expected %s, got %s",
+					tt.scenario, tt.expectedSRV, result)
+			}
+		})
+	}
+}
+
+// TestBackwardCompatibility tests backward compatibility with old format
+func TestBackwardCompatibility(t *testing.T) {
+	tests := []struct {
+		name     string
+		input    string
+		expected string
+	}{
+		{
+			name:     "New nginx format should work",
+			input:    "backend.example.com service=http resolve",
+			expected: "http",
+		},
+		{
+			name:     "New nginx format with dots",
+			input:    "example.com service=_http._tcp resolve",
+			expected: "_http._tcp",
+		},
+		{
+			name:     "Old consul format should still work as fallback",
+			input:    "test-service.service.consul",
+			expected: "test-service",
+		},
+		{
+			name:     "Invalid format should return empty",
+			input:    "invalid format without proper structure",
+			expected: "",
+		},
+	}
+
+	resolver := NewDynamicResolver("127.0.0.1:8600")
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			result := resolver.extractServiceName(tt.input)
+			if result != tt.expected {
+				t.Errorf("Expected %s, got %s", tt.expected, result)
+			}
+		})
+	}
+}
+
+// TestDynamicTargetsFunction tests the TestDynamicTargets function
+func TestDynamicTargetsFunction(t *testing.T) {
+	t.Run("Valid dynamic targets", func(t *testing.T) {
+		targets := []ProxyTarget{
+			{
+				Host:       "service.consul",
+				Port:       "dynamic",
+				Type:       "upstream",
+				Resolver:   "127.0.0.1:8600",
+				IsConsul:   true,
+				ServiceURL: "backend.example.com service=http resolve",
+			},
+		}
+
+		results := TestDynamicTargets(targets)
+
+		if len(results) != 1 {
+			t.Errorf("Expected 1 result, got %d", len(results))
+		}
+
+		key := "service.consul:dynamic"
+		if _, found := results[key]; !found {
+			t.Errorf("Expected result for key %s not found", key)
+		}
+	})
+
+	t.Run("Target without resolver should be offline", func(t *testing.T) {
+		targets := []ProxyTarget{
+			{
+				Host:       "service.consul",
+				Port:       "dynamic",
+				Type:       "upstream",
+				IsConsul:   true,
+				ServiceURL: "backend.example.com service=http resolve",
+				// No resolver specified
+			},
+		}
+
+		results := TestDynamicTargets(targets)
+
+		key := "service.consul:dynamic"
+		if status, found := results[key]; found {
+			if status.Online {
+				t.Error("Expected target without resolver to be offline")
+			}
+			if status.Latency != 0 {
+				t.Errorf("Expected latency 0 for offline target, got %.2f", status.Latency)
+			}
+		} else {
+			t.Errorf("Expected result for key %s", key)
+		}
+	})
+}
+
+// TestIntegrationWithProxyParser tests integration with the proxy parser
+func TestIntegrationWithProxyParser(t *testing.T) {
+	config := `upstream web-backend {
+    zone upstream_web 128k;
+    resolver 127.0.0.1:8600 valid=5s;
+    resolver_timeout 2s;
+    server backend.example.com service=http resolve;
+}
+server {
+    listen 80;
+    server_name example.com;
+    location / {
+        proxy_pass http://web-backend;
+    }
+}`
+
+	targets := ParseProxyTargetsFromRawContent(config)
+
+	// Should find the dynamic DNS target
+	found := false
+	for _, target := range targets {
+		if target.IsConsul && strings.Contains(target.ServiceURL, "service=http") {
+			found = true
+
+			// Verify the target is correctly parsed
+			if target.Resolver != "127.0.0.1:8600" {
+				t.Errorf("Expected resolver 127.0.0.1:8600, got %s", target.Resolver)
+			}
+
+			if target.ServiceURL != "backend.example.com service=http resolve" {
+				t.Errorf("Expected service URL 'backend.example.com service=http resolve', got %s", target.ServiceURL)
+			}
+			break
+		}
+	}
+
+	if !found {
+		t.Error("Dynamic DNS target not found in parsed config")
+	}
+}

+ 7 - 1
internal/upstream/proxy_parser.go

@@ -255,8 +255,14 @@ func parseServerAddress(serverAddr string, targetType string, ctx *UpstreamConte
 	return target
 }
 
-// isConsulServiceDiscovery checks if the server address is a consul service discovery configuration
+// isConsulServiceDiscovery checks if the server address is a dynamic service discovery configuration
+// This includes both Consul and standard nginx service= configurations
 func isConsulServiceDiscovery(serverAddr string) bool {
+	// Standard nginx service= format: "hostname service=name resolve"
+	if strings.Contains(serverAddr, "service=") && strings.Contains(serverAddr, "resolve") {
+		return true
+	}
+	// Legacy consul format: "service.consul service=name resolve" 
 	return strings.Contains(serverAddr, "service.consul") &&
 		(strings.Contains(serverAddr, "service=") || strings.Contains(serverAddr, "resolve"))
 }

+ 1 - 1
internal/upstream/service.go

@@ -232,7 +232,7 @@ func (s *UpstreamService) PerformAvailabilityTest() {
 	// Test consul targets using consul-specific logic
 	if len(consulTargets) > 0 {
 		// logger.Debug("Testing", len(consulTargets), "consul targets")
-		consulResults := TestConsulTargets(consulTargets)
+		consulResults := TestDynamicTargets(consulTargets)
 		for k, v := range consulResults {
 			results[k] = v
 		}