Repository: zeromicro/go-zero
Pull request #4197 (2024-06-19 08:01:30)

feat(tsgen): tsgen export buildTypes function

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/zeromicro/go-zero/pull/4197?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zeromicro) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 95.13%. Comparing base [(`8690859`)](https://app.codecov.io/gh/zeromicro/go-zero/commit/8690859c7d1c9461bdc422c3c65608bde30904db?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zeromicro) to head [(`5b569e1`)](https://app.codecov.io/gh/zeromicro/go-zero/commit/5b569e153298bf70ab7b54c3a3df4965f47b86ab?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zeromicro).
> Report is 66 commits behind head on master.

<details><summary>Additional details and impacted files</summary>



[see 255 files with indirect coverage changes](https://app.codecov.io/gh/zeromicro/go-zero/pull/4197/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zeromicro)

</details>
kevwan: Why to export it? Would you please describe it in details?

Patch:
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index 5523ad2c..4ff218ee 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1,3 +1,3 @@
 # These are supported funding model platforms
 
-github: kevwan
+github: [zeromicro]
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index d2f5af0f..bdcd1f90 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -17,7 +17,7 @@ jobs:
       - name: Set up Go 1.x
         uses: actions/setup-go@v5
         with:
-          go-version: '1.19'
+          go-version: '1.20'
           check-latest: true
           cache: true
         id: go
@@ -52,8 +52,8 @@ jobs:
       - name: Set up Go 1.x
         uses: actions/setup-go@v5
         with:
-          # use 1.19 to guarantee Go 1.19 compatibility
-          go-version: '1.19'
+          # use 1.20 to guarantee Go 1.20 compatibility
+          go-version: '1.20'
           check-latest: true
           cache: true
 
diff --git a/core/bloom/bloom.go b/core/bloom/bloom.go
index 68f22812..08f2741c 100644
--- a/core/bloom/bloom.go
+++ b/core/bloom/bloom.go
@@ -105,7 +105,7 @@ func newRedisBitSet(store *redis.Redis, key string, bits uint) *redisBitSet {
 }
 
 func (r *redisBitSet) buildOffsetArgs(offsets []uint) ([]string, error) {
-	var args []string
+	args := make([]string, 0, len(offsets))
 
 	for _, offset := range offsets {
 		if offset >= r.bits {
diff --git a/core/breaker/breaker.go b/core/breaker/breaker.go
index cbcede46..c6626f79 100644
--- a/core/breaker/breaker.go
+++ b/core/breaker/breaker.go
@@ -269,7 +269,7 @@ func (ew *errorWindow) add(reason string) {
 }
 
 func (ew *errorWindow) String() string {
-	var reasons []string
+	reasons := make([]string, 0, ew.count)
 
 	ew.lock.Lock()
 	// reverse order
diff --git a/core/filex/file.go b/core/filex/file.go
index e82fd8c8..442f6274 100644
--- a/core/filex/file.go
+++ b/core/filex/file.go
@@ -35,6 +35,7 @@ func firstLine(file *os.File) (string, error) {
 	for {
 		buf := make([]byte, bufSize)
 		n, err := file.ReadAt(buf, offset)
+
 		if err != nil && err != io.EOF {
 			return "", err
 		}
@@ -45,6 +46,10 @@ func firstLine(file *os.File) (string, error) {
 			}
 		}
 
+		if err == io.EOF {
+			return string(append(first, buf[:n]...)), nil
+		}
+
 		first = append(first, buf[:n]...)
 		offset += bufSize
 	}
@@ -57,30 +62,42 @@ func lastLine(filename string, file *os.File) (string, error) {
 	}
 
 	var last []byte
+	bufLen := int64(bufSize)
 	offset := info.Size()
-	for {
-		offset -= bufSize
-		if offset < 0 {
+
+	for offset > 0 {
+		if offset < bufLen {
+			bufLen = offset
 			offset = 0
+		} else {
+			offset -= bufLen
 		}
-		buf := make([]byte, bufSize)
+
+		buf := make([]byte, bufLen)
 		n, err := file.ReadAt(buf, offset)
 		if err != nil && err != io.EOF {
 			return "", err
 		}
 
+		if n == 0 {
+			break
+		}
+
 		if buf[n-1] == '\n' {
 			buf = buf[:n-1]
 			n--
 		} else {
 			buf = buf[:n]
 		}
-		for n--; n >= 0; n-- {
-			if buf[n] == '\n' {
-				return string(append(buf[n+1:], last...)), nil
+
+		for i := n - 1; i >= 0; i-- {
+			if buf[i] == '\n' {
+				return string(append(buf[i+1:], last...)), nil
 			}
 		}
 
 		last = append(buf, last...)
 	}
+
+	return string(last), nil
 }
diff --git a/core/fx/stream.go b/core/fx/stream.go
index e0c3cd28..03b0fce3 100644
--- a/core/fx/stream.go
+++ b/core/fx/stream.go
@@ -84,10 +84,10 @@ func Range(source <-chan any) Stream {
 	}
 }
 
-// AllMach returns whether all elements of this stream match the provided predicate.
+// AllMatch returns whether all elements of this stream match the provided predicate.
 // May not evaluate the predicate on all elements if not necessary for determining the result.
 // If the stream is empty then true is returned and the predicate is not evaluated.
-func (s Stream) AllMach(predicate func(item any) bool) bool {
+func (s Stream) AllMatch(predicate func(item any) bool) bool {
 	for item := range s.source {
 		if !predicate(item) {
 			// make sure the former goroutine not block, and current func returns fast.
@@ -99,10 +99,10 @@ func (s Stream) AllMach(predicate func(item any) bool) bool {
 	return true
 }
 
-// AnyMach returns whether any elements of this stream match the provided predicate.
+// AnyMatch returns whether any elements of this stream match the provided predicate.
 // May not evaluate the predicate on all elements if not necessary for determining the result.
 // If the stream is empty then false is returned and the predicate is not evaluated.
-func (s Stream) AnyMach(predicate func(item any) bool) bool {
+func (s Stream) AnyMatch(predicate func(item any) bool) bool {
 	for item := range s.source {
 		if predicate(item) {
 			// make sure the former goroutine not block, and current func returns fast.
diff --git a/core/logx/logs.go b/core/logx/logs.go
index 9cf3a791..627bab9b 100644
--- a/core/logx/logs.go
+++ b/core/logx/logs.go
@@ -52,6 +52,26 @@ type (
 	}
 )
 
+// AddWriter adds a new writer.
+// If there is already a writer, the new writer will be added to the writer chain.
+// For example, to write logs to both file and console, if there is already a file writer,
+// ```go
+// logx.AddWriter(logx.NewWriter(os.Stdout))
+// ```
+func AddWriter(w Writer) {
+	ow := Reset()
+	if ow == nil {
+		SetWriter(w)
+	} else {
+		// no need to check if the existing writer is a comboWriter,
+		// because it is not common to add more than one writer.
+		// even more than one writer, the behavior is the same.
+		SetWriter(comboWriter{
+			writers: []Writer{ow, w},
+		})
+	}
+}
+
 // Alert alerts v in alert level, and the message is written to error log.
 func Alert(v string) {
 	getWriter().Alert(v)
diff --git a/core/logx/writer.go b/core/logx/writer.go
index 09ae34b7..520b063a 100644
--- a/core/logx/writer.go
+++ b/core/logx/writer.go
@@ -13,6 +13,7 @@ import (
 
 	fatihcolor "github.com/fatih/color"
 	"github.com/zeromicro/go-zero/core/color"
+	"github.com/zeromicro/go-zero/core/errorx"
 )
 
 type (
@@ -33,6 +34,10 @@ type (
 		lock   sync.RWMutex
 	}
 
+	comboWriter struct {
+		writers []Writer
+	}
+
 	concreteWriter struct {
 		infoLog   io.WriteCloser
 		errorLog  io.WriteCloser
@@ -88,6 +93,62 @@ func (w *atomicWriter) Swap(v Writer) Writer {
 	return old
 }
 
+func (c comboWriter) Alert(v any) {
+	for _, w := range c.writers {
+		w.Alert(v)
+	}
+}
+
+func (c comboWriter) Close() error {
+	var be errorx.BatchError
+	for _, w := range c.writers {
+		be.Add(w.Close())
+	}
+	return be.Err()
+}
+
+func (c comboWriter) Debug(v any, fields ...LogField) {
+	for _, w := range c.writers {
+		w.Debug(v, fields...)
+	}
+}
+
+func (c comboWriter) Error(v any, fields ...LogField) {
+	for _, w := range c.writers {
+		w.Error(v, fields...)
+	}
+}
+
+func (c comboWriter) Info(v any, fields ...LogField) {
+	for _, w := range c.writers {
+		w.Info(v, fields...)
+	}
+}
+
+func (c comboWriter) Severe(v any) {
+	for _, w := range c.writers {
+		w.Severe(v)
+	}
+}
+
+func (c comboWriter) Slow(v any, fields ...LogField) {
+	for _, w := range c.writers {
+		w.Slow(v, fields...)
+	}
+}
+
+func (c comboWriter) Stack(v any) {
+	for _, w := range c.writers {
+		w.Stack(v)
+	}
+}
+
+func (c comboWriter) Stat(v any, fields ...LogField) {
+	for _, w := range c.writers {
+		w.Stat(v, fields...)
+	}
+}
+
 func newConsoleWriter() Writer {
 	outLog := newLogWriter(log.New(fatihcolor.Output, "", flags))
 	errLog := newLogWriter(log.New(fatihcolor.Error, "", flags))
diff --git a/core/mr/mapreduce.go b/core/mr/mapreduce.go
index edb32808..a56a82fe 100644
--- a/core/mr/mapreduce.go
+++ b/core/mr/mapreduce.go
@@ -363,9 +363,7 @@ func newGuardedWriter[T any](ctx context.Context, channel chan<- T, done <-chan
 func (gw guardedWriter[T]) Write(v T) {
 	select {
 	case <-gw.ctx.Done():
-		return
 	case <-gw.done:
-		return
 	default:
 		gw.channel <- v
 	}
diff --git a/core/stores/mon/collection.go b/core/stores/mon/collection.go
index e6f7e702..3509129b 100644
--- a/core/stores/mon/collection.go
+++ b/core/stores/mon/collection.go
@@ -2,6 +2,7 @@ package mon
 
 import (
 	"context"
+	"errors"
 	"time"
 
 	"github.com/zeromicro/go-zero/core/breaker"
@@ -15,7 +16,8 @@ import (
 const (
 	defaultSlowThreshold = time.Millisecond * 500
 	// spanName is the span name of the mongo calls.
-	spanName = "mongo"
+	spanName         = "mongo"
+	duplicateKeyCode = 11000
 
 	// mongodb method names
 	aggregate              = "Aggregate"
@@ -527,10 +529,20 @@ func (p keepablePromise) keep(err error) error {
 }
 
 func acceptable(err error) bool {
-	return err == nil || errorx.In(err, mongo.ErrNoDocuments, mongo.ErrNilValue,
-		mongo.ErrNilDocument, mongo.ErrNilCursor, mongo.ErrEmptySlice,
-		// session errors
-		session.ErrSessionEnded, session.ErrNoTransactStarted, session.ErrTransactInProgress,
-		session.ErrAbortAfterCommit, session.ErrAbortTwice, session.ErrCommitAfterAbort,
-		session.ErrUnackWCUnsupported, session.ErrSnapshotTransaction)
+	return err == nil || isDupKeyError(err) ||
+		errorx.In(err, mongo.ErrNoDocuments, mongo.ErrNilValue,
+			mongo.ErrNilDocument, mongo.ErrNilCursor, mongo.ErrEmptySlice,
+			// session errors
+			session.ErrSessionEnded, session.ErrNoTransactStarted, session.ErrTransactInProgress,
+			session.ErrAbortAfterCommit, session.ErrAbortTwice, session.ErrCommitAfterAbort,
+			session.ErrUnackWCUnsupported, session.ErrSnapshotTransaction)
+}
+
+func isDupKeyError(err error) bool {
+	var e mongo.WriteException
+	if !errors.As(err, &e) {
+		return false
+	}
+
+	return e.HasErrorCode(duplicateKeyCode)
 }
diff --git a/core/stores/redis/redis.go b/core/stores/redis/redis.go
index 76265c5a..3758877f 100644
--- a/core/stores/redis/redis.go
+++ b/core/stores/redis/redis.go
@@ -90,6 +90,18 @@ type (
 	StringCmd = red.StringCmd
 	// Script is an alias of redis.Script.
 	Script = red.Script
+
+	// Hook is an alias of redis.Hook.
+	Hook = red.Hook
+	// DialHook is an alias of redis.DialHook.
+	DialHook = red.DialHook
+	// ProcessHook is an alias of redis.ProcessHook.
+	ProcessHook = red.ProcessHook
+	// ProcessPipelineHook is an alias of redis.ProcessPipelineHook.
+	ProcessPipelineHook = red.ProcessPipelineHook
+
+	// Cmder is an alias of redis.Cmder.
+	Cmder = red.Cmder
 )
 
 // MustNewRedis returns a Redis with given options.
@@ -2363,9 +2375,9 @@ func WithTLS() Option {
 	}
 }
 
-// withHook customizes the given Redis with given durationHook, only for private use now,
+// WithHook customizes the given Redis with given durationHook, only for private use now,
 // maybe expose later.
-func withHook(hook red.Hook) Option {
+func WithHook(hook Hook) Option {
 	return func(r *Redis) {
 		r.hooks = append(r.hooks, hook)
 	}
diff --git a/core/stores/sqlc/cachedsql.go b/core/stores/sqlc/cachedsql.go
index 8b81e925..addf3b40 100644
--- a/core/stores/sqlc/cachedsql.go
+++ b/core/stores/sqlc/cachedsql.go
@@ -190,6 +190,17 @@ func (cc CachedConn) QueryRowNoCacheCtx(ctx context.Context, v any, q string,
 	return cc.db.QueryRowCtx(ctx, v, q, args...)
 }
 
+// QueryRowPartialNoCache unmarshals into v with given statement.
+func (cc CachedConn) QueryRowPartialNoCache(v any, q string, args ...any) error {
+	return cc.QueryRowPartialNoCacheCtx(context.Background(), v, q, args...)
+}
+
+// QueryRowPartialNoCacheCtx unmarshals into v with given statement.
+func (cc CachedConn) QueryRowPartialNoCacheCtx(ctx context.Context, v any, q string,
+	args ...any) error {
+	return cc.db.QueryRowPartialCtx(ctx, v, q, args...)
+}
+
 // QueryRowsNoCache unmarshals into v with given statement.
 // It doesn't use cache, because it might cause consistency problem.
 func (cc CachedConn) QueryRowsNoCache(v any, q string, args ...any) error {
@@ -203,6 +214,19 @@ func (cc CachedConn) QueryRowsNoCacheCtx(ctx context.Context, v any, q string,
 	return cc.db.QueryRowsCtx(ctx, v, q, args...)
 }
 
+// QueryRowsPartialNoCache unmarshals into v with given statement.
+// It doesn't use cache, because it might cause consistency problem.
+func (cc CachedConn) QueryRowsPartialNoCache(v any, q string, args ...any) error {
+	return cc.QueryRowsPartialNoCacheCtx(context.Background(), v, q, args...)
+}
+
+// QueryRowsPartialNoCacheCtx unmarshals into v with given statement.
+// It doesn't use cache, because it might cause consistency problem.
+func (cc CachedConn) QueryRowsPartialNoCacheCtx(ctx context.Context, v any, q string,
+	args ...any) error {
+	return cc.db.QueryRowsPartialCtx(ctx, v, q, args...)
+}
+
 // SetCache sets v into cache with given key.
 func (cc CachedConn) SetCache(key string, val any) error {
 	return cc.SetCacheCtx(context.Background(), key, val)
diff --git a/go.mod b/go.mod
index fe9b425f..c9ef88a5 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module github.com/zeromicro/go-zero
 
-go 1.19
+go 1.20
 
 require (
 	github.com/DATA-DOG/go-sqlmock v1.5.2
@@ -12,32 +12,32 @@ require (
 	github.com/golang/mock v1.6.0
 	github.com/golang/protobuf v1.5.4
 	github.com/google/uuid v1.6.0
-	github.com/jackc/pgx/v5 v5.5.5
+	github.com/jackc/pgx/v5 v5.6.0
 	github.com/jhump/protoreflect v1.16.0
 	github.com/olekukonko/tablewriter v0.0.5
 	github.com/pelletier/go-toml/v2 v2.2.2
-	github.com/prometheus/client_golang v1.18.0
-	github.com/redis/go-redis/v9 v9.5.3
+	github.com/prometheus/client_golang v1.19.1
+	github.com/redis/go-redis/v9 v9.6.0
 	github.com/spaolacci/murmur3 v1.1.0
 	github.com/stretchr/testify v1.9.0
 	go.etcd.io/etcd/api/v3 v3.5.14
 	go.etcd.io/etcd/client/v3 v3.5.14
-	go.mongodb.org/mongo-driver v1.13.1
-	go.opentelemetry.io/otel v1.19.0
+	go.mongodb.org/mongo-driver v1.16.0
+	go.opentelemetry.io/otel v1.24.0
 	go.opentelemetry.io/otel/exporters/jaeger v1.17.0
-	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0
-	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0
-	go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0
-	go.opentelemetry.io/otel/exporters/zipkin v1.19.0
-	go.opentelemetry.io/otel/sdk v1.19.0
-	go.opentelemetry.io/otel/trace v1.19.0
+	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0
+	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0
+	go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0
+	go.opentelemetry.io/otel/exporters/zipkin v1.24.0
+	go.opentelemetry.io/otel/sdk v1.24.0
+	go.opentelemetry.io/otel/trace v1.24.0
 	go.uber.org/automaxprocs v1.5.3
-	go.uber.org/goleak v1.2.1
-	golang.org/x/net v0.26.0
-	golang.org/x/sys v0.21.0
+	go.uber.org/goleak v1.3.0
+	golang.org/x/net v0.27.0
+	golang.org/x/sys v0.22.0
 	golang.org/x/time v0.5.0
-	google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237
-	google.golang.org/grpc v1.64.0
+	google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d
+	google.golang.org/grpc v1.65.0
 	google.golang.org/protobuf v1.34.2
 	gopkg.in/cheggaaa/pb.v1 v1.0.28
 	gopkg.in/h2non/gock.v1 v1.1.2
@@ -45,7 +45,7 @@ require (
 	k8s.io/api v0.29.3
 	k8s.io/apimachinery v0.29.4
 	k8s.io/client-go v0.29.3
-	k8s.io/utils v0.0.0-20230726121419-3b25d923346b
+	k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
 )
 
 require (
@@ -53,9 +53,9 @@ require (
 	github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/bufbuild/protocompile v0.10.0 // indirect
-	github.com/cenkalti/backoff/v4 v4.2.1 // indirect
-	github.com/cespare/xxhash/v2 v2.2.0 // indirect
-	github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50 // indirect
+	github.com/cenkalti/backoff/v4 v4.3.0 // indirect
+	github.com/cespare/xxhash/v2 v2.3.0 // indirect
+	github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b // indirect
 	github.com/coreos/go-semver v0.3.1 // indirect
 	github.com/coreos/go-systemd/v22 v22.5.0 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
@@ -63,7 +63,7 @@ require (
 	github.com/emicklei/go-restful/v3 v3.11.0 // indirect
 	github.com/envoyproxy/go-control-plane v0.12.0 // indirect
 	github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect
-	github.com/go-logr/logr v1.3.0 // indirect
+	github.com/go-logr/logr v1.4.2 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/go-openapi/jsonpointer v0.19.6 // indirect
 	github.com/go-openapi/jsonreference v0.20.2 // indirect
@@ -73,48 +73,47 @@ require (
 	github.com/google/gnostic-models v0.6.8 // indirect
 	github.com/google/go-cmp v0.6.0 // indirect
 	github.com/google/gofuzz v1.2.0 // indirect
-	github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 // indirect
+	github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
 	github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
 	github.com/jackc/pgpassfile v1.0.0 // indirect
-	github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
+	github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
 	github.com/jackc/puddle/v2 v2.2.1 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
-	github.com/klauspost/compress v1.16.7 // indirect
+	github.com/klauspost/compress v1.17.8 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/mattn/go-runewidth v0.0.15 // indirect
-	github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
-	github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
+	github.com/montanaflynn/stats v0.7.1 // indirect
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
-	github.com/openzipkin/zipkin-go v0.4.2 // indirect
+	github.com/openzipkin/zipkin-go v0.4.3 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/prometheus/client_model v0.5.0 // indirect
-	github.com/prometheus/common v0.45.0 // indirect
+	github.com/prometheus/common v0.48.0 // indirect
 	github.com/prometheus/procfs v0.12.0 // indirect
 	github.com/rivo/uniseg v0.2.0 // indirect
+	github.com/stretchr/objx v0.5.2 // indirect
 	github.com/xdg-go/pbkdf2 v1.0.0 // indirect
 	github.com/xdg-go/scram v1.1.2 // indirect
 	github.com/xdg-go/stringprep v1.0.4 // indirect
 	github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
 	github.com/yuin/gopher-lua v1.1.1 // indirect
 	go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect
-	go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
-	go.opentelemetry.io/otel/metric v1.19.0 // indirect
-	go.opentelemetry.io/proto/otlp v1.0.0 // indirect
+	go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect
+	go.opentelemetry.io/otel/metric v1.24.0 // indirect
+	go.opentelemetry.io/proto/otlp v1.3.1 // indirect
 	go.uber.org/atomic v1.10.0 // indirect
 	go.uber.org/multierr v1.9.0 // indirect
 	go.uber.org/zap v1.24.0 // indirect
-	golang.org/x/crypto v0.24.0 // indirect
-	golang.org/x/oauth2 v0.18.0 // indirect
+	golang.org/x/crypto v0.25.0 // indirect
+	golang.org/x/oauth2 v0.20.0 // indirect
 	golang.org/x/sync v0.7.0 // indirect
-	golang.org/x/term v0.21.0 // indirect
+	golang.org/x/term v0.22.0 // indirect
 	golang.org/x/text v0.16.0 // indirect
-	google.golang.org/appengine v1.6.8 // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	k8s.io/klog/v2 v2.110.1 // indirect
diff --git a/go.sum b/go.sum
index 721b4415..b8f692ca 100644
--- a/go.sum
+++ b/go.sum
@@ -13,12 +13,12 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
 github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
 github.com/bufbuild/protocompile v0.10.0 h1:+jW/wnLMLxaCEG8AX9lD0bQ5v9h1RUiMKOBOT5ll9dM=
 github.com/bufbuild/protocompile v0.10.0/go.mod h1:G9qQIQo0xZ6Uyj6CMNz0saGmx2so+KONo8/KrELABiY=
-github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
-github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
-github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
-github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50 h1:DBmgJDC9dTfkVyGgipamEh2BpGYxScCH1TOF1LL1cXc=
-github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM=
+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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw=
+github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
 github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
 github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
 github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
@@ -40,8 +40,9 @@ github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLg
 github.com/fullstorydev/grpcurl v1.9.1 h1:YxX1aCcCc4SDBQfj9uoWcTLe8t4NWrZe1y+mk83BQgo=
 github.com/fullstorydev/grpcurl v1.9.1/go.mod h1:i8gKLIC6s93WdU3LSmkE5vtsCxyRmihUj5FK1cNW5EM=
 github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
 github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
 github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
 github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
@@ -59,20 +60,14 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
 github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
-github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68=
 github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
 github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
 github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
-github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
 github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
 github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
-github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@@ -82,16 +77,16 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
 github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
 github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
 github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
 github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
 github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
-github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
-github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
-github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
-github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
+github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
+github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
+github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
+github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
 github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
 github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
 github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg=
@@ -103,9 +98,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE=
-github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
-github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
-github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
+github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
 github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -122,15 +116,13 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
 github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
 github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
-github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
-github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
+github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
+github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
@@ -139,24 +131,24 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N
 github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
 github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
 github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
-github.com/openzipkin/zipkin-go v0.4.2 h1:zjqfqHjUpPmB3c1GlCvvgsM1G4LkvqQbBDueDOCg/jA=
-github.com/openzipkin/zipkin-go v0.4.2/go.mod h1:ZeVkFjuuBiSy13y8vpSDCjMi9GoI3hPpCJSBx/EYFhY=
+github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg=
+github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c=
 github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
 github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
-github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
-github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
+github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
+github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
 github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
 github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
-github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
-github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
+github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
+github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
 github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
 github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
-github.com/redis/go-redis/v9 v9.5.3 h1:fOAp1/uJG+ZtcITgZOfYFmTKPE7n4Vclj1wZFgRciUU=
-github.com/redis/go-redis/v9 v9.5.3/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
+github.com/redis/go-redis/v9 v9.6.0 h1:NLck+Rab3AOTHw21CGRpvQpgTrAU4sgdCswqGtlhGRA=
+github.com/redis/go-redis/v9 v9.6.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
 github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
@@ -182,7 +174,6 @@ github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
 github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
 github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
 github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
-github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
 github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
 github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -197,36 +188,36 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxv
 go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI=
 go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg=
 go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk=
-go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk=
-go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo=
-go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
-go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
+go.mongodb.org/mongo-driver v1.16.0 h1:tpRsfBJMROVHKpdGyc1BBEzzjDUWjItxbVSZ8Ls4BQ4=
+go.mongodb.org/mongo-driver v1.16.0/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw=
+go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
+go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
 go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4=
 go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
-go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0 h1:Nw7Dv4lwvGrI68+wULbcq7su9K2cebeCUrDjVrUJHxM=
-go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0/go.mod h1:1MsF6Y7gTqosgoZvHlzcaaM8DIMNZgJh87ykokoNH7Y=
-go.opentelemetry.io/otel/exporters/zipkin v1.19.0 h1:EGY0h5mGliP9o/nIkVuLI0vRiQqmsYOcbwCuotksO1o=
-go.opentelemetry.io/otel/exporters/zipkin v1.19.0/go.mod h1:JQgTGJP11yi3o4GHzIWYodhPisxANdqxF1eHwDSnJrI=
-go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE=
-go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8=
-go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o=
-go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
-go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg=
-go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
-go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
-go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 h1:s0PHtIkN+3xrbDOpt2M8OTG92cWqUESvzh2MxiR5xY8=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0/go.mod h1:hZlFbDbRt++MMPCCfSJfmhkGIWnX1h3XjkfxZUjLrIA=
+go.opentelemetry.io/otel/exporters/zipkin v1.24.0 h1:3evrL5poBuh1KF51D9gO/S+N/1msnm4DaBqs/rpXUqY=
+go.opentelemetry.io/otel/exporters/zipkin v1.24.0/go.mod h1:0EHgD8R0+8yRhUYJOGR8Hfg2dpiJQxDOszd5smVO9wM=
+go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
+go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
+go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
+go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
+go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
+go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
+go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
+go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
 go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
 go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
 go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
 go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
-go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
-go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
 go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
 go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
 go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
@@ -236,9 +227,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
-golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
+golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
+golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -249,12 +239,11 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
-golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
-golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
-golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
+golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
+golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
+golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
+golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -267,25 +256,22 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
-golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
+golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
-golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
+golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
+golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
-golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
 golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
 golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
@@ -301,16 +287,12 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
-google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
-google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4=
-google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
-google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
-google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d h1:kHjw/5UfflP/L5EbledDrcG4C2597RtymmGRZvHiCuY=
+google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
+google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
+google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
 google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
 google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -338,8 +320,8 @@ k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
 k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
 k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
 k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
-k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
-k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
 sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
 sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
diff --git a/readme-cn.md b/readme-cn.md
index d59dd163..44b44f11 100644
--- a/readme-cn.md
+++ b/readme-cn.md
@@ -118,18 +118,13 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/zeromicro
     # For Mac
     brew install goctl
     
-    # docker for amd64 architecture
+    # docker for all platforms
     docker pull kevinwan/goctl
-    # run goctl like
+    # run goctl
     docker run --rm -it -v `pwd`:/app kevinwan/goctl --help
-    
-    # docker for arm64(Mac) architecture
-    docker pull kevinwan/goctl:latest-arm64
-    # run goctl like
-    docker run --rm -it -v `pwd`:/app kevinwan/goctl:latest-arm64 --help
     ```
     
-    确保 goctl 可执行
+    确保 goctl 可执行，并且在 $PATH 环境变量里。
     
 2. 快速生成 api 服务
 
@@ -333,8 +328,8 @@ go-zero 收录在 [CNCF Cloud Native 云原生技术全景图](https://landscape
 
 <img src="https://raw.githubusercontent.com/zeromicro/zero-doc/main/doc/images/wechat.jpg" alt="wechat" width="300" />
 
-## 13. 赞助一下👍
+## 13. 知识星球
 
-如果觉得项目有帮助，可以请作者喝杯咖啡 🍹
+官方团队运营的知识星球
 
-<img src="https://raw.githubusercontent.com/zeromicro/zero-doc/main/doc/images/sponsor.png" alt="wechat" width="300" />
+<img src="https://raw.githubusercontent.com/zeromicro/zero-doc/main/doc/images/zsxq.jpg" alt="知识星球" width="300" />
diff --git a/readme.md b/readme.md
index c01048aa..1bf00776 100644
--- a/readme.md
+++ b/readme.md
@@ -125,18 +125,13 @@ go get -u github.com/zeromicro/go-zero
    # For Mac
    brew install goctl
    
-   # docker for amd64 architecture
+   # docker for all platforms
    docker pull kevinwan/goctl
-   # run goctl like
+   # run goctl
    docker run --rm -it -v `pwd`:/app kevinwan/goctl --help
-   
-   # docker for arm64(Mac) architecture
-   docker pull kevinwan/goctl:latest-arm64
-   # run goctl like
-   docker run --rm -it -v `pwd`:/app kevinwan/goctl:latest-arm64 --help
    ```
    
-   make sure goctl is executable.
+   make sure goctl is executable and in your $PATH.
    
 3. Create the API file, like greet.api, you can install the plugin of goctl in vs code, api syntax is supported.
 
diff --git a/rest/httpc/requests.go b/rest/httpc/requests.go
index defe2599..181b53e8 100644
--- a/rest/httpc/requests.go
+++ b/rest/httpc/requests.go
@@ -143,7 +143,7 @@ func fillPath(u *nurl.URL, val map[string]any) error {
 			delete(val, key)
 		}
 
-		var unused []string
+		unused := make([]string, 0, len(val))
 		for key := range val {
 			unused = append(unused, key)
 		}
diff --git a/rest/internal/fileserver/filehandler.go b/rest/internal/fileserver/filehandler.go
new file mode 100644
index 00000000..163cdea4
--- /dev/null
+++ b/rest/internal/fileserver/filehandler.go
@@ -0,0 +1,79 @@
+package fileserver
+
+import (
+	"net/http"
+	"strings"
+	"sync"
+)
+
+// Middleware returns a middleware that serves files from the given file system.
+func Middleware(path string, fs http.FileSystem) func(http.HandlerFunc) http.HandlerFunc {
+	fileServer := http.FileServer(fs)
+	pathWithoutTrailSlash := ensureNoTrailingSlash(path)
+	canServe := createServeChecker(path, fs)
+
+	return func(next http.HandlerFunc) http.HandlerFunc {
+		return func(w http.ResponseWriter, r *http.Request) {
+			if canServe(r) {
+				r.URL.Path = r.URL.Path[len(pathWithoutTrailSlash):]
+				fileServer.ServeHTTP(w, r)
+			} else {
+				next(w, r)
+			}
+		}
+	}
+}
+
+func createFileChecker(fs http.FileSystem) func(string) bool {
+	var lock sync.RWMutex
+	fileChecker := make(map[string]bool)
+
+	return func(path string) bool {
+		lock.RLock()
+		exist, ok := fileChecker[path]
+		lock.RUnlock()
+		if ok {
+			return exist
+		}
+
+		lock.Lock()
+		defer lock.Unlock()
+
+		file, err := fs.Open(path)
+		exist = err == nil
+		fileChecker[path] = exist
+		if err != nil {
+			return false
+		}
+
+		_ = file.Close()
+		return true
+	}
+}
+
+func createServeChecker(path string, fs http.FileSystem) func(r *http.Request) bool {
+	pathWithTrailSlash := ensureTrailingSlash(path)
+	fileChecker := createFileChecker(fs)
+
+	return func(r *http.Request) bool {
+		return r.Method == http.MethodGet &&
+			strings.HasPrefix(r.URL.Path, pathWithTrailSlash) &&
+			fileChecker(r.URL.Path[len(pathWithTrailSlash):])
+	}
+}
+
+func ensureTrailingSlash(path string) string {
+	if strings.HasSuffix(path, "/") {
+		return path
+	}
+
+	return path + "/"
+}
+
+func ensureNoTrailingSlash(path string) string {
+	if strings.HasSuffix(path, "/") {
+		return path[:len(path)-1]
+	}
+
+	return path
+}
diff --git a/rest/server.go b/rest/server.go
index bbf6ff39..747bb2c3 100644
--- a/rest/server.go
+++ b/rest/server.go
@@ -13,6 +13,7 @@ import (
 	"github.com/zeromicro/go-zero/rest/httpx"
 	"github.com/zeromicro/go-zero/rest/internal"
 	"github.com/zeromicro/go-zero/rest/internal/cors"
+	"github.com/zeromicro/go-zero/rest/internal/fileserver"
 	"github.com/zeromicro/go-zero/rest/router"
 )
 
@@ -85,7 +86,7 @@ func (s *Server) PrintRoutes() {
 
 // Routes returns the HTTP routers that registered in the server.
 func (s *Server) Routes() []Route {
-	var routes []Route
+	routes := make([]Route, 0, len(s.ngin.routes))
 
 	for _, r := range s.ngin.routes {
 		routes = append(routes, r.routes...)
@@ -170,6 +171,13 @@ func WithCustomCors(middlewareFn func(header http.Header), notAllowedFn func(htt
 	}
 }
 
+// WithFileServer returns a RunOption to serve files from given dir with given path.
+func WithFileServer(path string, fs http.FileSystem) RunOption {
+	return func(server *Server) {
+		server.router = newFileServingRouter(server.router, path, fs)
+	}
+}
+
 // WithJwt returns a func to enable jwt authentication in given route.
 func WithJwt(secret string) RouteOption {
 	return func(r *featuredRoutes) {
@@ -241,7 +249,7 @@ func WithNotAllowedHandler(handler http.Handler) RunOption {
 // WithPrefix adds group as a prefix to the route paths.
 func WithPrefix(group string) RouteOption {
 	return func(r *featuredRoutes) {
-		var routes []Route
+		routes := make([]Route, 0, len(r.routes))
 		for _, rt := range r.routes {
 			p := path.Join(group, rt.Path)
 			routes = append(routes, Route{
@@ -337,3 +345,19 @@ func newCorsRouter(router httpx.Router, headerFn func(http.Header), origins ...s
 func (c *corsRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	c.middleware(c.Router.ServeHTTP)(w, r)
 }
+
+type fileServingRouter struct {
+	httpx.Router
+	middleware Middleware
+}
+
+func newFileServingRouter(router httpx.Router, path string, fs http.FileSystem) httpx.Router {
+	return &fileServingRouter{
+		Router:     router,
+		middleware: fileserver.Middleware(path, fs),
+	}
+}
+
+func (f *fileServingRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	f.middleware(f.Router.ServeHTTP)(w, r)
+}
diff --git a/tools/goctl/api/dartgen/gendata.go b/tools/goctl/api/dartgen/gendata.go
index 7f21b42a..0e01447b 100644
--- a/tools/goctl/api/dartgen/gendata.go
+++ b/tools/goctl/api/dartgen/gendata.go
@@ -1,6 +1,7 @@
 package dartgen
 
 import (
+	"bytes"
 	"os"
 	"strings"
 	"text/template"
@@ -8,8 +9,8 @@ import (
 	"github.com/zeromicro/go-zero/tools/goctl/api/spec"
 )
 
-const dataTemplate = `// --{{with .Info}}{{.Title}}{{end}}--
-{{ range .Types}}
+const dataTemplate = `// --{{with .APISpec.Info}}{{.Title}}{{end}}--
+{{ range .APISpec.Types}}
 class {{.Name}}{
 	{{range .Members}}
 	/// {{.Comment}}
@@ -28,12 +29,16 @@ class {{.Name}}{
 			'{{getPropertyFromMember .}}': {{if isDirectType .Type.Name}}{{lowCamelCase .Name}}{{else if isClassListType .Type.Name}}{{lowCamelCase .Name}}.map((i) => i.toJson()){{else}}{{lowCamelCase .Name}}.toJson(){{end}},{{end}}
 		};
 	}
+
+	{{ range $.InnerClassList}}
+	{{.}}
+	{{end}}
 }
 {{end}}
 `
 
-const dataTemplateV2 = `// --{{with .Info}}{{.Title}}{{end}}--
-{{ range .Types}}
+const dataTemplateV2 = `// --{{with .APISpec.Info}}{{.Title}}{{end}}--
+{{ range .APISpec.Types}}
 class {{.Name}} {
 	{{range .Members}}
 	{{if .Comment}}{{.Comment}}{{end}}
@@ -73,9 +78,18 @@ class {{.Name}} {
 			,{{end}}
 		};
 	}
+
+	{{ range $.InnerClassList}}
+	{{.}}
+	{{end}}
 }
 {{end}}`
 
+type DartSpec struct {
+	APISpec        *spec.ApiSpec
+	InnerClassList []string
+}
+
 func genData(dir string, api *spec.ApiSpec, isLegacy bool) error {
 	err := os.MkdirAll(dir, 0o755)
 	if err != nil {
@@ -104,12 +118,12 @@ func genData(dir string, api *spec.ApiSpec, isLegacy bool) error {
 		return err
 	}
 
-	err = convertDataType(api)
+	err, dartSpec := convertDataType(api, isLegacy)
 	if err != nil {
 		return err
 	}
 
-	return t.Execute(file, api)
+	return t.Execute(file, dartSpec)
 }
 
 func genTokens(dir string, isLeagcy bool) error {
@@ -132,24 +146,61 @@ func genTokens(dir string, isLeagcy bool) error {
 	return err
 }
 
-func convertDataType(api *spec.ApiSpec) error {
+func convertDataType(api *spec.ApiSpec, isLegacy bool) (error, *DartSpec) {
+	var result DartSpec
 	types := api.Types
 	if len(types) == 0 {
-		return nil
+		return nil, &result
 	}
 
 	for _, ty := range types {
 		defineStruct, ok := ty.(spec.DefineStruct)
 		if ok {
 			for index, member := range defineStruct.Members {
-				tp, err := specTypeToDart(member.Type)
-				if err != nil {
-					return err
+				structMember, ok := member.Type.(spec.DefineStruct)
+				if ok && structMember.IsNestedStruct() {
+					defineStruct.Members[index].Type = spec.PrimitiveType{RawName: member.Name}
+					t := template.New("dataTemplate")
+					t = t.Funcs(funcMap)
+					tpl := dataTemplateV2
+					if isLegacy {
+						tpl = dataTemplate
+					}
+					t, err := t.Parse(tpl)
+					if err != nil {
+						return err, nil
+					}
+
+					var innerClassSpec = &spec.ApiSpec{
+						Types: []spec.Type{
+							spec.DefineStruct{
+								RawName: member.Name,
+								Members: structMember.Members,
+							},
+						},
+					}
+					err, dartSpec := convertDataType(innerClassSpec, isLegacy)
+					if err != nil {
+						return err, nil
+					}
+
+					writer := bytes.NewBuffer(nil)
+					err = t.Execute(writer, dartSpec)
+					if err != nil {
+						return err, nil
+					}
+					result.InnerClassList = append(result.InnerClassList, writer.String())
+				} else {
+					tp, err := specTypeToDart(member.Type)
+					if err != nil {
+						return err, nil
+					}
+					defineStruct.Members[index].Type = buildSpecType(member.Type, tp)
 				}
-				defineStruct.Members[index].Type = buildSpecType(member.Type, tp)
 			}
 		}
 	}
+	result.APISpec = api
 
-	return nil
+	return nil, &result
 }
diff --git a/tools/goctl/api/gogen/gentypes.go b/tools/goctl/api/gogen/gentypes.go
index 36e3fe92..6ddcbbfd 100644
--- a/tools/goctl/api/gogen/gentypes.go
+++ b/tools/goctl/api/gogen/gentypes.go
@@ -74,8 +74,21 @@ func writeType(writer io.Writer, tp spec.Type) error {
 		return fmt.Errorf("unspport struct type: %s", tp.Name())
 	}
 
-	fmt.Fprintf(writer, "type %s struct {\n", util.Title(tp.Name()))
-	for _, member := range structType.Members {
+	_, err := fmt.Fprintf(writer, "type %s struct {\n", util.Title(tp.Name()))
+	if err != nil {
+		return err
+	}
+
+	if err := writeMember(writer, structType.Members); err != nil {
+		return err
+	}
+
+	_, err = fmt.Fprintf(writer, "}")
+	return err
+}
+
+func writeMember(writer io.Writer, members []spec.Member) error {
+	for _, member := range members {
 		if member.IsInline {
 			if _, err := fmt.Fprintf(writer, "%s\n", strings.Title(member.Type.Name())); err != nil {
 				return err
@@ -88,6 +101,5 @@ func writeType(writer io.Writer, tp spec.Type) error {
 			return err
 		}
 	}
-	fmt.Fprintf(writer, "}")
 	return nil
 }
diff --git a/tools/goctl/api/gogen/util.go b/tools/goctl/api/gogen/util.go
index 5a9bc6c8..847197bf 100644
--- a/tools/goctl/api/gogen/util.go
+++ b/tools/goctl/api/gogen/util.go
@@ -59,16 +59,59 @@ func genFile(c fileGenConfig) error {
 
 func writeProperty(writer io.Writer, name, tag, comment string, tp spec.Type, indent int) error {
 	util.WriteIndent(writer, indent)
-	var err error
+	var (
+		err            error
+		isNestedStruct bool
+	)
+	structType, ok := tp.(spec.DefineStruct)
+	if ok && structType.IsNestedStruct() {
+		isNestedStruct = true
+	}
 	if len(comment) > 0 {
 		comment = strings.TrimPrefix(comment, "//")
 		comment = "//" + comment
-		_, err = fmt.Fprintf(writer, "%s %s %s %s\n", strings.Title(name), tp.Name(), tag, comment)
+	}
+
+	if isNestedStruct {
+		_, err = fmt.Fprintf(writer, "%s struct {\n", strings.Title(name))
+		if err != nil {
+			return err
+		}
+
+		if err := writeMember(writer, structType.Members); err != nil {
+			return err
+		}
+
+		_, err := fmt.Fprintf(writer, "} %s", tag)
+		if err != nil {
+			return err
+		}
+
+		if len(comment) > 0 {
+			_, err = fmt.Fprintf(writer, " %s", comment)
+			if err != nil {
+				return err
+			}
+		}
+		_, err = fmt.Fprint(writer, "\n")
+		if err != nil {
+			return err
+		}
 	} else {
-		_, err = fmt.Fprintf(writer, "%s %s %s\n", strings.Title(name), tp.Name(), tag)
+		if len(comment) > 0 {
+			_, err = fmt.Fprintf(writer, "%s %s %s %s\n", strings.Title(name), tp.Name(), tag, comment)
+			if err != nil {
+				return err
+			}
+		} else {
+			_, err = fmt.Fprintf(writer, "%s %s %s\n", strings.Title(name), tp.Name(), tag)
+			if err != nil {
+				return err
+			}
+		}
 	}
 
-	return err
+	return nil
 }
 
 func getAuths(api *spec.ApiSpec) []string {
diff --git a/tools/goctl/api/parser/g4/ast/import.go b/tools/goctl/api/parser/g4/ast/import.go
index 374e16fb..d6b7cff3 100644
--- a/tools/goctl/api/parser/g4/ast/import.go
+++ b/tools/goctl/api/parser/g4/ast/import.go
@@ -1,8 +1,6 @@
 package ast
 
-import (
-	"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
-)
+import "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
 
 // ImportExpr defines import syntax for api
 type ImportExpr struct {
diff --git a/tools/goctl/api/parser/g4/ast/info.go b/tools/goctl/api/parser/g4/ast/info.go
index b086fb9e..09277eb6 100644
--- a/tools/goctl/api/parser/g4/ast/info.go
+++ b/tools/goctl/api/parser/g4/ast/info.go
@@ -1,8 +1,6 @@
 package ast
 
-import (
-	"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
-)
+import "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
 
 // InfoExpr defines info syntax for api
 type InfoExpr struct {
diff --git a/tools/goctl/api/parser/g4/ast/syntax.go b/tools/goctl/api/parser/g4/ast/syntax.go
index a543a784..b72427a6 100644
--- a/tools/goctl/api/parser/g4/ast/syntax.go
+++ b/tools/goctl/api/parser/g4/ast/syntax.go
@@ -1,8 +1,6 @@
 package ast
 
-import (
-	"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
-)
+import "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
 
 // SyntaxExpr describes syntax for api
 type SyntaxExpr struct {
diff --git a/tools/goctl/api/spec/name.go b/tools/goctl/api/spec/name.go
index 9b561058..6c0c8557 100644
--- a/tools/goctl/api/spec/name.go
+++ b/tools/goctl/api/spec/name.go
@@ -30,6 +30,11 @@ func (t DefineStruct) Documents() []string {
 	return t.Docs
 }
 
+// IsNestedStruct returns whether the structure is nested.
+func (t DefineStruct) IsNestedStruct() bool {
+	return len(t.Members) > 0
+}
+
 // Name returns a map string, such as map[string]int
 func (t MapType) Name() string {
 	return t.RawName
diff --git a/tools/goctl/api/tsgen/gencomponents.go b/tools/goctl/api/tsgen/gencomponents.go
index aabd704f..ceac13ee 100644
--- a/tools/goctl/api/tsgen/gencomponents.go
+++ b/tools/goctl/api/tsgen/gencomponents.go
@@ -62,3 +62,7 @@ func buildTypes(types []spec.Type) (string, error) {
 
 	return builder.String(), nil
 }
+
+func BuildTypes(types []spec.Type) (string, error) {
+	return buildTypes(types)
+}
diff --git a/tools/goctl/api/tsgen/util.go b/tools/goctl/api/tsgen/util.go
index a37961f7..328d8715 100644
--- a/tools/goctl/api/tsgen/util.go
+++ b/tools/goctl/api/tsgen/util.go
@@ -1,6 +1,7 @@
 package tsgen
 
 import (
+	"bytes"
 	"errors"
 	"fmt"
 	"io"
@@ -19,7 +20,7 @@ const (
 
 func writeProperty(writer io.Writer, member spec.Member, indent int) error {
 	writeIndent(writer, indent)
-	ty, err := genTsType(member)
+	ty, err := genTsType(member, indent)
 	if err != nil {
 		return err
 	}
@@ -40,7 +41,7 @@ func writeProperty(writer io.Writer, member spec.Member, indent int) error {
 	}
 	if len(member.Docs) > 0 {
 		fmt.Fprintf(writer, "%s\n", strings.Join(member.Docs, ""))
-		writeIndent(writer, 1)
+		writeIndent(writer, indent)
 	}
 	_, err = fmt.Fprintf(writer, "%s%s: %s%s\n", name, optionalTag, ty, comment)
 	return err
@@ -52,7 +53,27 @@ func writeIndent(writer io.Writer, indent int) {
 	}
 }
 
-func genTsType(m spec.Member) (ty string, err error) {
+func genTsType(m spec.Member, indent int) (ty string, err error) {
+	v, ok := m.Type.(spec.DefineStruct)
+	if ok && v.IsNestedStruct() {
+		writer := bytes.NewBuffer(nil)
+		_, err := fmt.Fprintf(writer, "{\n")
+		if err != nil {
+			return "", err
+		}
+
+		if err := writeMembers(writer, v, false, indent+1); err != nil {
+			return "", err
+		}
+
+		writeIndent(writer, indent)
+		_, err = fmt.Fprintf(writer, "}")
+		if err != nil {
+			return "", err
+		}
+		return writer.String(), nil
+	}
+
 	ty, err = goTypeToTs(m.Type, false)
 	if enums := m.GetEnumOptions(); enums != nil {
 		if ty == "string" {
@@ -130,7 +151,7 @@ func primitiveType(tp string) (string, bool) {
 
 func writeType(writer io.Writer, tp spec.Type) error {
 	fmt.Fprintf(writer, "export interface %s {\n", util.Title(tp.Name()))
-	if err := writeMembers(writer, tp, false); err != nil {
+	if err := writeMembers(writer, tp, false, 1); err != nil {
 		return err
 	}
 
@@ -166,12 +187,12 @@ func genParamsTypesIfNeed(writer io.Writer, tp spec.Type) error {
 	return nil
 }
 
-func writeMembers(writer io.Writer, tp spec.Type, isParam bool) error {
+func writeMembers(writer io.Writer, tp spec.Type, isParam bool, indent int) error {
 	definedType, ok := tp.(spec.DefineStruct)
 	if !ok {
 		pointType, ok := tp.(spec.PointerType)
 		if ok {
-			return writeMembers(writer, pointType.Type, isParam)
+			return writeMembers(writer, pointType.Type, isParam, indent)
 		}
 
 		return fmt.Errorf("type %s not supported", tp.Name())
@@ -183,13 +204,13 @@ func writeMembers(writer io.Writer, tp spec.Type, isParam bool) error {
 	}
 	for _, member := range members {
 		if member.IsInline {
-			if err := writeMembers(writer, member.Type, isParam); err != nil {
+			if err := writeMembers(writer, member.Type, isParam, indent); err != nil {
 				return err
 			}
 			continue
 		}
 
-		if err := writeProperty(writer, member, 1); err != nil {
+		if err := writeProperty(writer, member, indent); err != nil {
 			return apiutil.WrapErr(err, " type "+tp.Name())
 		}
 	}
diff --git a/tools/goctl/example/rpc/hello/client/greet/greet.go b/tools/goctl/example/rpc/hello/client/greet/greet.go
index ec9d3c18..99af623b 100644
--- a/tools/goctl/example/rpc/hello/client/greet/greet.go
+++ b/tools/goctl/example/rpc/hello/client/greet/greet.go
@@ -7,7 +7,6 @@ import (
 	"context"
 
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hello/pb/hello"
-
 	"github.com/zeromicro/go-zero/zrpc"
 	"google.golang.org/grpc"
 )
diff --git a/tools/goctl/example/rpc/hello/hello.go b/tools/goctl/example/rpc/hello/hello.go
index dd92f637..df7705af 100644
--- a/tools/goctl/example/rpc/hello/hello.go
+++ b/tools/goctl/example/rpc/hello/hello.go
@@ -4,13 +4,12 @@ import (
 	"flag"
 	"fmt"
 
+	"github.com/zeromicro/go-zero/core/conf"
+	"github.com/zeromicro/go-zero/core/service"
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hello/internal/config"
 	greetServer "github.com/zeromicro/go-zero/tools/goctl/example/rpc/hello/internal/server/greet"
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hello/internal/svc"
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hello/pb/hello"
-
-	"github.com/zeromicro/go-zero/core/conf"
-	"github.com/zeromicro/go-zero/core/service"
 	"github.com/zeromicro/go-zero/zrpc"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/reflection"
diff --git a/tools/goctl/example/rpc/hello/internal/logic/greet/sayhellologic.go b/tools/goctl/example/rpc/hello/internal/logic/greet/sayhellologic.go
index c94994e4..6bf3cfda 100644
--- a/tools/goctl/example/rpc/hello/internal/logic/greet/sayhellologic.go
+++ b/tools/goctl/example/rpc/hello/internal/logic/greet/sayhellologic.go
@@ -3,10 +3,9 @@ package greetlogic
 import (
 	"context"
 
+	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hello/internal/svc"
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hello/pb/hello"
-
-	"github.com/zeromicro/go-zero/core/logx"
 )
 
 type SayHelloLogic struct {
diff --git a/tools/goctl/example/rpc/hi/client/event/event.go b/tools/goctl/example/rpc/hi/client/event/event.go
index 7a346baa..df88758c 100644
--- a/tools/goctl/example/rpc/hi/client/event/event.go
+++ b/tools/goctl/example/rpc/hi/client/event/event.go
@@ -7,7 +7,6 @@ import (
 	"context"
 
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hi/pb/hi"
-
 	"github.com/zeromicro/go-zero/zrpc"
 	"google.golang.org/grpc"
 )
diff --git a/tools/goctl/example/rpc/hi/client/greet/greet.go b/tools/goctl/example/rpc/hi/client/greet/greet.go
index 3c0b15b6..366f9ed6 100644
--- a/tools/goctl/example/rpc/hi/client/greet/greet.go
+++ b/tools/goctl/example/rpc/hi/client/greet/greet.go
@@ -7,7 +7,6 @@ import (
 	"context"
 
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hi/pb/hi"
-
 	"github.com/zeromicro/go-zero/zrpc"
 	"google.golang.org/grpc"
 )
diff --git a/tools/goctl/example/rpc/hi/hi.go b/tools/goctl/example/rpc/hi/hi.go
index 9e6cc0d0..75cebb15 100644
--- a/tools/goctl/example/rpc/hi/hi.go
+++ b/tools/goctl/example/rpc/hi/hi.go
@@ -4,14 +4,13 @@ import (
 	"flag"
 	"fmt"
 
+	"github.com/zeromicro/go-zero/core/conf"
+	"github.com/zeromicro/go-zero/core/service"
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hi/internal/config"
 	eventServer "github.com/zeromicro/go-zero/tools/goctl/example/rpc/hi/internal/server/event"
 	greetServer "github.com/zeromicro/go-zero/tools/goctl/example/rpc/hi/internal/server/greet"
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hi/internal/svc"
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hi/pb/hi"
-
-	"github.com/zeromicro/go-zero/core/conf"
-	"github.com/zeromicro/go-zero/core/service"
 	"github.com/zeromicro/go-zero/zrpc"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/reflection"
diff --git a/tools/goctl/example/rpc/hi/internal/logic/event/askquestionlogic.go b/tools/goctl/example/rpc/hi/internal/logic/event/askquestionlogic.go
index 697ade52..9360bd33 100644
--- a/tools/goctl/example/rpc/hi/internal/logic/event/askquestionlogic.go
+++ b/tools/goctl/example/rpc/hi/internal/logic/event/askquestionlogic.go
@@ -3,10 +3,9 @@ package eventlogic
 import (
 	"context"
 
+	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hi/internal/svc"
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hi/pb/hi"
-
-	"github.com/zeromicro/go-zero/core/logx"
 )
 
 type AskQuestionLogic struct {
diff --git a/tools/goctl/example/rpc/hi/internal/logic/greet/sayhellologic.go b/tools/goctl/example/rpc/hi/internal/logic/greet/sayhellologic.go
index 51dec93a..11c9f868 100644
--- a/tools/goctl/example/rpc/hi/internal/logic/greet/sayhellologic.go
+++ b/tools/goctl/example/rpc/hi/internal/logic/greet/sayhellologic.go
@@ -3,10 +3,9 @@ package greetlogic
 import (
 	"context"
 
+	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hi/internal/svc"
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hi/pb/hi"
-
-	"github.com/zeromicro/go-zero/core/logx"
 )
 
 type SayHelloLogic struct {
diff --git a/tools/goctl/example/rpc/hi/internal/logic/greet/sayhilogic.go b/tools/goctl/example/rpc/hi/internal/logic/greet/sayhilogic.go
index 80c08fcb..f97eca7a 100644
--- a/tools/goctl/example/rpc/hi/internal/logic/greet/sayhilogic.go
+++ b/tools/goctl/example/rpc/hi/internal/logic/greet/sayhilogic.go
@@ -3,10 +3,9 @@ package greetlogic
 import (
 	"context"
 
+	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hi/internal/svc"
 	"github.com/zeromicro/go-zero/tools/goctl/example/rpc/hi/pb/hi"
-
-	"github.com/zeromicro/go-zero/core/logx"
 )
 
 type SayHiLogic struct {
diff --git a/tools/goctl/go.mod b/tools/goctl/go.mod
index e6d784e6..21afc7e2 100644
--- a/tools/goctl/go.mod
+++ b/tools/goctl/go.mod
@@ -1,6 +1,6 @@
 module github.com/zeromicro/go-zero/tools/goctl
 
-go 1.19
+go 1.20
 
 require (
 	github.com/DATA-DOG/go-sqlmock v1.5.2
@@ -9,32 +9,33 @@ require (
 	github.com/go-sql-driver/mysql v1.8.1
 	github.com/gookit/color v1.5.4
 	github.com/iancoleman/strcase v0.3.0
-	github.com/spf13/cobra v1.8.0
+	github.com/spf13/cobra v1.8.1
 	github.com/spf13/pflag v1.0.5
 	github.com/stretchr/testify v1.9.0
 	github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1
 	github.com/zeromicro/antlr v0.0.1
 	github.com/zeromicro/ddl-parser v1.0.5
-	github.com/zeromicro/go-zero v1.6.4
-	golang.org/x/text v0.14.0
-	google.golang.org/grpc v1.63.2
-	google.golang.org/protobuf v1.33.0
+	github.com/zeromicro/go-zero v1.6.6
+	golang.org/x/text v0.16.0
+	google.golang.org/grpc v1.65.0
+	google.golang.org/protobuf v1.34.2
+	gopkg.in/yaml.v2 v2.4.0
 )
 
 require (
 	filippo.io/edwards25519 v1.1.0 // indirect
 	github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect
-	github.com/alicebob/miniredis/v2 v2.32.1 // indirect
+	github.com/alicebob/miniredis/v2 v2.33.0 // indirect
 	github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cenkalti/backoff/v4 v4.2.1 // indirect
-	github.com/cespare/xxhash/v2 v2.2.0 // indirect
+	github.com/cespare/xxhash/v2 v2.3.0 // indirect
 	github.com/coreos/go-semver v0.3.1 // indirect
 	github.com/coreos/go-systemd/v22 v22.5.0 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
 	github.com/emicklei/go-restful/v3 v3.11.0 // indirect
-	github.com/fatih/color v1.16.0 // indirect
+	github.com/fatih/color v1.17.0 // indirect
 	github.com/go-logr/logr v1.3.0 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/go-openapi/jsonpointer v0.19.6 // indirect
@@ -64,19 +65,19 @@ require (
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
 	github.com/openzipkin/zipkin-go v0.4.2 // indirect
-	github.com/pelletier/go-toml/v2 v2.2.0 // indirect
+	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/prometheus/client_golang v1.18.0 // indirect
 	github.com/prometheus/client_model v0.5.0 // indirect
 	github.com/prometheus/common v0.45.0 // indirect
 	github.com/prometheus/procfs v0.12.0 // indirect
-	github.com/redis/go-redis/v9 v9.4.0 // indirect
+	github.com/redis/go-redis/v9 v9.5.3 // indirect
 	github.com/spaolacci/murmur3 v1.1.0 // indirect
 	github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
 	github.com/yuin/gopher-lua v1.1.1 // indirect
-	go.etcd.io/etcd/api/v3 v3.5.13 // indirect
-	go.etcd.io/etcd/client/pkg/v3 v3.5.13 // indirect
-	go.etcd.io/etcd/client/v3 v3.5.13 // indirect
+	go.etcd.io/etcd/api/v3 v3.5.14 // indirect
+	go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect
+	go.etcd.io/etcd/client/v3 v3.5.14 // indirect
 	go.opentelemetry.io/otel v1.19.0 // indirect
 	go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
 	go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
@@ -92,22 +93,19 @@ require (
 	go.uber.org/automaxprocs v1.5.3 // indirect
 	go.uber.org/multierr v1.9.0 // indirect
 	go.uber.org/zap v1.24.0 // indirect
-	golang.org/x/crypto v0.22.0 // indirect
-	golang.org/x/net v0.24.0 // indirect
-	golang.org/x/oauth2 v0.17.0 // indirect
-	golang.org/x/sync v0.6.0 // indirect
-	golang.org/x/sys v0.19.0 // indirect
-	golang.org/x/term v0.19.0 // indirect
+	golang.org/x/crypto v0.25.0 // indirect
+	golang.org/x/net v0.27.0 // indirect
+	golang.org/x/oauth2 v0.20.0 // indirect
+	golang.org/x/sync v0.7.0 // indirect
+	golang.org/x/sys v0.22.0 // indirect
+	golang.org/x/term v0.22.0 // indirect
 	golang.org/x/time v0.5.0 // indirect
-	google.golang.org/appengine v1.6.8 // indirect
-	google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
-	google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
-	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	k8s.io/api v0.29.3 // indirect
-	k8s.io/apimachinery v0.29.3 // indirect
+	k8s.io/apimachinery v0.29.4 // indirect
 	k8s.io/client-go v0.29.3 // indirect
 	k8s.io/klog/v2 v2.110.1 // indirect
 	k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
diff --git a/tools/goctl/go.sum b/tools/goctl/go.sum
index a8a223f5..7041e5d9 100644
--- a/tools/goctl/go.sum
+++ b/tools/goctl/go.sum
@@ -2,11 +2,11 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
 filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
 github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
 github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
-github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
 github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE=
 github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
-github.com/alicebob/miniredis/v2 v2.32.1 h1:Bz7CciDnYSaa0mX5xODh6GUITRSx+cVhjNoOR4JssBo=
-github.com/alicebob/miniredis/v2 v2.32.1/go.mod h1:AqkLNAfUm0K07J28hnAyyQKf/x0YkCY/g5DCtuL01Mw=
+github.com/alicebob/miniredis/v2 v2.33.0 h1:uvTF0EDeu9RLnUEG27Db5I68ESoIxTiXbNUiji6lZrA=
+github.com/alicebob/miniredis/v2 v2.33.0/go.mod h1:MhP4a3EU7aENRi9aO+tHfTBZicLqQevyi/DJpoj6mi0=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec h1:EEyRvzmpEUZ+I8WmD5cw/vY8EqhambkOqy5iFr0908A=
 github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
 github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
@@ -16,8 +16,8 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
 github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
 github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
 github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
-github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
-github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -25,7 +25,7 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr
 github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
 github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
 github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
-github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -36,10 +36,11 @@ github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxER
 github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
 github.com/emicklei/proto v1.13.2 h1:z/etSFO3uyXeuEsVPzfl56WNgzcvIr42aQazXaQmFZY=
 github.com/emicklei/proto v1.13.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
-github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
-github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
+github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
+github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
 github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
 github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
+github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
 github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
 github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -58,16 +59,14 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
-github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68=
+github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
 github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
 github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
 github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@@ -75,10 +74,12 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
 github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
 github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
+github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
 github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk=
 github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
@@ -96,8 +97,10 @@ github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk
 github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE=
@@ -116,6 +119,7 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
 github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
 github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -125,13 +129,15 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
 github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
 github.com/openzipkin/zipkin-go v0.4.2 h1:zjqfqHjUpPmB3c1GlCvvgsM1G4LkvqQbBDueDOCg/jA=
 github.com/openzipkin/zipkin-go v0.4.2/go.mod h1:ZeVkFjuuBiSy13y8vpSDCjMi9GoI3hPpCJSBx/EYFhY=
-github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo=
-github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
+github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
+github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
@@ -143,14 +149,15 @@ github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lne
 github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
 github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
 github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
-github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk=
-github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
+github.com/redis/go-redis/v9 v9.5.3 h1:fOAp1/uJG+ZtcITgZOfYFmTKPE7n4Vclj1wZFgRciUU=
+github.com/redis/go-redis/v9 v9.5.3/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
 github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
-github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
+github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
+github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -173,21 +180,22 @@ github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1z
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
 github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
 github.com/zeromicro/antlr v0.0.1 h1:CQpIn/dc0pUjgGQ81y98s/NGOm2Hfru2NNio2I9mQgk=
 github.com/zeromicro/antlr v0.0.1/go.mod h1:nfpjEwFR6Q4xGDJMcZnCL9tEfQRgszMwu3rDz2Z+p5M=
+github.com/zeromicro/antlr v1.0.0 h1:XqOf69i6619D3FveNpToDbqkLckw06o9M0+6E1R3jVE=
+github.com/zeromicro/antlr v1.0.0/go.mod h1:nfpjEwFR6Q4xGDJMcZnCL9tEfQRgszMwu3rDz2Z+p5M=
 github.com/zeromicro/ddl-parser v1.0.5 h1:LaVqHdzMTjasua1yYpIYaksxKqRzFrEukj2Wi2EbWaQ=
 github.com/zeromicro/ddl-parser v1.0.5/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8=
-github.com/zeromicro/go-zero v1.6.4 h1:GvZXxxwl1Lby/gIHxHwN/ZNmXl1WFJa1DvoVgqgttUs=
-github.com/zeromicro/go-zero v1.6.4/go.mod h1:dQ39Zoz20/6x/SUhFXyEEg8lWjl+CO3dzg8Je2xG63Q=
-go.etcd.io/etcd/api/v3 v3.5.13 h1:8WXU2/NBge6AUF1K1gOexB6e07NgsN1hXK0rSTtgSp4=
-go.etcd.io/etcd/api/v3 v3.5.13/go.mod h1:gBqlqkcMMZMVTMm4NDZloEVJzxQOQIls8splbqBDa0c=
-go.etcd.io/etcd/client/pkg/v3 v3.5.13 h1:RVZSAnWWWiI5IrYAXjQorajncORbS0zI48LQlE2kQWg=
-go.etcd.io/etcd/client/pkg/v3 v3.5.13/go.mod h1:XxHT4u1qU12E2+po+UVPrEeL94Um6zL58ppuJWXSAB8=
-go.etcd.io/etcd/client/v3 v3.5.13 h1:o0fHTNJLeO0MyVbc7I3fsCf6nrOqn5d+diSarKnB2js=
-go.etcd.io/etcd/client/v3 v3.5.13/go.mod h1:cqiAeY8b5DEEcpxvgWKsbLIWNM/8Wy2xJSDMtioMcoI=
+github.com/zeromicro/go-zero v1.6.6 h1:nZTVYObklHiBdYJ/nPoAZ8kGVAplWSDjT7DGE7ur0uk=
+github.com/zeromicro/go-zero v1.6.6/go.mod h1:olKf1/hELbSmuIgLgJeoeNVp3tCbLqj6UmO7ATSta4A=
+go.etcd.io/etcd/api/v3 v3.5.14 h1:vHObSCxyB9zlF60w7qzAdTcGaglbJOpSj1Xj9+WGxq0=
+go.etcd.io/etcd/api/v3 v3.5.14/go.mod h1:BmtWcRlQvwa1h3G2jvKYwIQy4PkHlDej5t7uLMUdJUU=
+go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxvuWxQ=
+go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI=
+go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg=
+go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk=
 go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
 go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
 go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4=
@@ -222,55 +230,43 @@ go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
-golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
+golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
+golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
-golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
-golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ=
-golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA=
+golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
+golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
+golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
+golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
-golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
-golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
+golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
-golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
+golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
+golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
+golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
 golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
 golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -278,26 +274,19 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
-google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
-google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
-google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
-google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0=
-google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
-google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
-google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
-google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw=
+google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d h1:JU0iKnSg02Gmb5ZdV8nYsKEKsP6o/FGVWTrw4i1DA9A=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
+google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
+google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -312,8 +301,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw=
 k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80=
-k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU=
-k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU=
+k8s.io/apimachinery v0.29.4 h1:RaFdJiDmuKs/8cm1M6Dh1Kvyh59YQFDcFuFTSmXes6Q=
+k8s.io/apimachinery v0.29.4/go.mod h1:i3FJVwhvSp/6n8Fl4K97PJEP8C+MM+aoDq4+ZJBf70Y=
 k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg=
 k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0=
 k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
diff --git a/tools/goctl/internal/version/version.go b/tools/goctl/internal/version/version.go
index 2fa070e5..f9bac47e 100644
--- a/tools/goctl/internal/version/version.go
+++ b/tools/goctl/internal/version/version.go
@@ -6,7 +6,7 @@ import (
 )
 
 // BuildVersion is the version of goctl.
-const BuildVersion = "1.6.5"
+const BuildVersion = "1.7.0"
 
 var tag = map[string]int{"pre-alpha": 0, "alpha": 1, "pre-bata": 2, "beta": 3, "released": 4, "": 5}
 
diff --git a/tools/goctl/model/sql/builderx/builder.go b/tools/goctl/model/sql/builderx/builder.go
index 5a038284..f5aa3f77 100644
--- a/tools/goctl/model/sql/builderx/builder.go
+++ b/tools/goctl/model/sql/builderx/builder.go
@@ -1,8 +1,6 @@
 package builderx
 
-import (
-	"github.com/zeromicro/go-zero/core/stores/builder"
-)
+import "github.com/zeromicro/go-zero/core/stores/builder"
 
 // Deprecated: Use github.com/zeromicro/go-zero/core/stores/builder.RawFieldNames instead.
 func FieldNames(in any) []string {
diff --git a/tools/goctl/model/sql/command/command.go b/tools/goctl/model/sql/command/command.go
index e29a3092..2b4e49e4 100644
--- a/tools/goctl/model/sql/command/command.go
+++ b/tools/goctl/model/sql/command/command.go
@@ -7,7 +7,6 @@ import (
 
 	"github.com/go-sql-driver/mysql"
 	"github.com/spf13/cobra"
-
 	"github.com/zeromicro/go-zero/core/collection"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/core/stores/postgres"
diff --git a/tools/goctl/pkg/parser/api/ast/servicestatement.go b/tools/goctl/pkg/parser/api/ast/servicestatement.go
index 05b6d3ae..ba0b704d 100644
--- a/tools/goctl/pkg/parser/api/ast/servicestatement.go
+++ b/tools/goctl/pkg/parser/api/ast/servicestatement.go
@@ -575,3 +575,7 @@ func (e *BodyExpr) Pos() token.Position {
 }
 
 func (e *BodyExpr) exprNode() {}
+
+func (e *BodyExpr) IsArrayType() bool {
+	return e.LBrack != nil
+}
diff --git a/tools/goctl/pkg/parser/api/parser/analyzer.go b/tools/goctl/pkg/parser/api/parser/analyzer.go
index fc90164b..2b1c302a 100644
--- a/tools/goctl/pkg/parser/api/parser/analyzer.go
+++ b/tools/goctl/pkg/parser/api/parser/analyzer.go
@@ -42,15 +42,33 @@ func (a *Analyzer) astTypeToSpec(in ast.DataType) (spec.Type, error) {
 	case *ast.AnyDataType:
 		return nil, ast.SyntaxError(v.Pos(), "unsupported any type")
 	case *ast.StructDataType:
-		// TODO(keson) feature: can be extended
+		var members []spec.Member
+		for _, item := range v.Elements {
+			m, err := a.fieldToMember(item)
+			if err != nil {
+				return nil, err
+			}
+			members = append(members, m)
+		}
+		if v.RawText() == "{}" {
+			return nil, ast.SyntaxError(v.Pos(), "unsupported empty struct")
+		}
+
+		return spec.DefineStruct{
+			RawName: v.RawText(),
+			Members: members,
+		}, nil
 	case *ast.InterfaceDataType:
 		return spec.InterfaceType{RawName: v.RawText()}, nil
 	case *ast.MapDataType:
 		if !isLiteralType(v.Key) {
-			return nil, ast.SyntaxError(v.Pos(), "expected literal type, got <%T>", v)
+			return nil, ast.SyntaxError(v.Pos(), "expected literal type, got <%T>", v.Key)
 		}
 		if !v.Key.CanEqual() {
-			return nil, ast.SyntaxError(v.Pos(), "map key <%T> must be equal data type", v)
+			return nil, ast.SyntaxError(v.Pos(), "map key <%T> must be equal data type", v.Key)
+		}
+		if v.Value.ContainsStruct() {
+			return nil, ast.SyntaxError(v.Pos(), "map value unsupported nested struct")
 		}
 
 		value, err := a.astTypeToSpec(v.Value)
@@ -80,9 +98,11 @@ func (a *Analyzer) astTypeToSpec(in ast.DataType) (spec.Type, error) {
 		}, nil
 	case *ast.ArrayDataType:
 		if v.Length.Token.Type == token.ELLIPSIS {
-			return nil, ast.SyntaxError(v.Pos(), "Array: unsupported dynamic length")
+			return nil, ast.SyntaxError(v.Pos(), "array length unsupported dynamic length")
+		}
+		if v.ContainsStruct() {
+			return nil, ast.SyntaxError(v.Pos(), "array elements unsupported nested struct")
 		}
-
 		value, err := a.astTypeToSpec(v.DataType)
 		if err != nil {
 			return nil, err
@@ -93,6 +113,10 @@ func (a *Analyzer) astTypeToSpec(in ast.DataType) (spec.Type, error) {
 			Value:   value,
 		}, nil
 	case *ast.SliceDataType:
+		if v.ContainsStruct() {
+			return nil, ast.SyntaxError(v.Pos(), "slice elements unsupported nested struct")
+		}
+
 		value, err := a.astTypeToSpec(v.DataType)
 		if err != nil {
 			return nil, err
@@ -244,14 +268,14 @@ func (a *Analyzer) fillService() error {
 			}
 
 			if astRoute.Route.Request != nil && astRoute.Route.Request.Body != nil {
-				requestType, err := a.getType(astRoute.Route.Request)
+				requestType, err := a.getType(astRoute.Route.Request, true)
 				if err != nil {
 					return err
 				}
 				route.RequestType = requestType
 			}
 			if astRoute.Route.Response != nil && astRoute.Route.Response.Body != nil {
-				responseType, err := a.getType(astRoute.Route.Response)
+				responseType, err := a.getType(astRoute.Route.Response, false)
 				if err != nil {
 					return err
 				}
@@ -323,12 +347,14 @@ func (a *Analyzer) fillTypes() error {
 			for _, member := range v.Members {
 				switch v := member.Type.(type) {
 				case spec.DefineStruct:
-					tp, err := a.findDefinedType(v.RawName)
-					if err != nil {
-						return err
-					}
+					if !v.IsNestedStruct() {
+						tp, err := a.findDefinedType(v.RawName)
+						if err != nil {
+							return err
+						}
 
-					member.Type = tp
+						member.Type = tp
+					}
 				}
 				members = append(members, member)
 			}
@@ -378,8 +404,12 @@ func (a *Analyzer) findDefinedType(name string) (spec.Type, error) {
 	return nil, fmt.Errorf("type %s not defined", name)
 }
 
-func (a *Analyzer) getType(expr *ast.BodyStmt) (spec.Type, error) {
+func (a *Analyzer) getType(expr *ast.BodyStmt, req bool) (spec.Type, error) {
 	body := expr.Body
+	if req && body.IsArrayType() {
+		return nil, ast.SyntaxError(body.Pos(), "request body must be struct")
+	}
+
 	var tp spec.Type
 	var err error
 	var rawText = body.Format("")
diff --git a/tools/goctl/rpc/generator/mkdir.go b/tools/goctl/rpc/generator/mkdir.go
index 163f904a..d35780e4 100644
--- a/tools/goctl/rpc/generator/mkdir.go
+++ b/tools/goctl/rpc/generator/mkdir.go
@@ -1,13 +1,13 @@
 package generator
 
 import (
-	"github.com/zeromicro/go-zero/tools/goctl/util/format"
 	"path/filepath"
 	"strings"
 
 	conf "github.com/zeromicro/go-zero/tools/goctl/config"
 	"github.com/zeromicro/go-zero/tools/goctl/rpc/parser"
 	"github.com/zeromicro/go-zero/tools/goctl/util/ctx"
+	"github.com/zeromicro/go-zero/tools/goctl/util/format"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/stringx"
 )
diff --git a/tools/goctl/util/pathx/file.go b/tools/goctl/util/pathx/file.go
index 50823b39..778ecd69 100644
--- a/tools/goctl/util/pathx/file.go
+++ b/tools/goctl/util/pathx/file.go
@@ -98,11 +98,12 @@ func GetGoctlHome() (home string, err error) {
 
 // GetDefaultGoctlHome returns the path value of the goctl home where Join $HOME with .goctl.
 func GetDefaultGoctlHome() (string, error) {
+	var goctlHomeDir = goctlDir
 	home, err := os.UserHomeDir()
-	if err != nil {
-		return "", err
+	if err == nil {
+		goctlHomeDir = filepath.Join(home, goctlDir)
 	}
-	goctlHomeDir := filepath.Join(home, goctlDir)
+
 	_ = MkdirIfNotExist(goctlHomeDir)
 	return goctlHomeDir, nil
 }
diff --git a/zrpc/internal/balancer/p2c/p2c.go b/zrpc/internal/balancer/p2c/p2c.go
index 08ea1aad..b57f0c44 100644
--- a/zrpc/internal/balancer/p2c/p2c.go
+++ b/zrpc/internal/balancer/p2c/p2c.go
@@ -22,13 +22,20 @@ const (
 	// Name is the name of p2c balancer.
 	Name = "p2c_ewma"
 
-	decayTime       = int64(time.Second * 10) // default value from finagle
-	forcePick       = int64(time.Second)
-	initSuccess     = 1000
+	// default value from finagle
+	decayTime = int64(time.Second * 10)
+	// if a node is not selected for a period of time, it is forcibly selected.
+	forcePick = int64(time.Second)
+	// initial success count
+	initSuccess = 1000
+	// success count to trigger throttling
 	throttleSuccess = initSuccess / 2
-	penalty         = int64(math.MaxInt32)
-	pickTimes       = 3
-	logInterval     = time.Minute
+	// penalty value for load calculation
+	penalty = int64(math.MaxInt32)
+	// number of pick attempts
+	pickTimes = 3
+	// log interval for statistics
+	logInterval = time.Minute
 )
 
 var emptyPickResult balancer.PickResult
@@ -45,7 +52,7 @@ func (b *p2cPickerBuilder) Build(info base.PickerBuildInfo) balancer.Picker {
 		return base.NewErrPicker(balancer.ErrNoSubConnAvailable)
 	}
 
-	var conns []*subConn
+	conns := make([]*subConn, 0, len(readySCs))
 	for conn, connInfo := range readySCs {
 		conns = append(conns, &subConn{
 			addr:    connInfo.Address,
@@ -121,6 +128,11 @@ func (p *p2cPicker) buildDoneFunc(c *subConn) func(info balancer.DoneInfo) {
 		if td < 0 {
 			td = 0
 		}
+
+		// As the td/decayTime value increases, indicating an increase in delay,
+		// the value of w (y-axis) will decrease, inversely proportional.
+		// The function curve of y = x^(-x) is as follows:
+		// https://github.com/zeromicro/zero-doc/blob/main/doc/images/y_e_x.png?raw=true
 		w := math.Exp(float64(-td) / float64(decayTime))
 		lag := int64(now) - start
 		if lag < 0 {
@@ -130,6 +142,8 @@ func (p *p2cPicker) buildDoneFunc(c *subConn) func(info balancer.DoneInfo) {
 		if olag == 0 {
 			w = 0
 		}
+
+		// The smaller the value of w, the lower the impact of historical data.
 		atomic.StoreUint64(&c.lag, uint64(float64(olag)*w+float64(lag)*(1-w)))
 		success := initSuccess
 		if info.Err != nil && !codes.Acceptable(info.Err) {
@@ -168,7 +182,7 @@ func (p *p2cPicker) choose(c1, c2 *subConn) *subConn {
 }
 
 func (p *p2cPicker) logStats() {
-	var stats []string
+	stats := make([]string, 0, len(p.conns))
 
 	p.lock.Lock()
 	defer p.lock.Unlock()
@@ -182,7 +196,11 @@ func (p *p2cPicker) logStats() {
 }
 
 type subConn struct {
-	lag      uint64
+	// The request latency measured by the weighted moving average algorithm.
+	lag uint64
+
+	// The value represents the number of requests that are either pending or just
+	// starting at the current node, and it is obtained through atomic addition.
 	inflight int64
 	success  uint64
 	requests int64
diff --git a/zrpc/resolver/internal/discovbuilder.go b/zrpc/resolver/internal/discovbuilder.go
index cf432e23..ed377d13 100644
--- a/zrpc/resolver/internal/discovbuilder.go
+++ b/zrpc/resolver/internal/discovbuilder.go
@@ -22,8 +22,9 @@ func (b *discovBuilder) Build(target resolver.Target, cc resolver.ClientConn, _
 	}
 
 	update := func() {
-		var addrs []resolver.Address
-		for _, val := range subset(sub.Values(), subsetSize) {
+		vals := subset(sub.Values(), subsetSize)
+		addrs := make([]resolver.Address, 0, len(vals))
+		for _, val := range vals {
 			addrs = append(addrs, resolver.Address{
 				Addr: val,
 			})
diff --git a/zrpc/resolver/internal/kubebuilder.go b/zrpc/resolver/internal/kubebuilder.go
index 63900377..a4a9c3b7 100644
--- a/zrpc/resolver/internal/kubebuilder.go
+++ b/zrpc/resolver/internal/kubebuilder.go
@@ -69,8 +69,9 @@ func (b *kubeBuilder) Build(target resolver.Target, cc resolver.ClientConn,
 	}
 
 	handler := kube.NewEventHandler(func(endpoints []string) {
-		var addrs []resolver.Address
-		for _, val := range subset(endpoints, subsetSize) {
+		endpoints = subset(endpoints, subsetSize)
+		addrs := make([]resolver.Address, 0, len(endpoints))
+		for _, val := range endpoints {
 			addrs = append(addrs, resolver.Address{
 				Addr: fmt.Sprintf("%s:%d", val, svc.Port),
 			})


Test patch:
diff --git a/core/breaker/breakers_test.go b/core/breaker/breakers_test.go
index af7cb8cc..58d2364d 100644
--- a/core/breaker/breakers_test.go
+++ b/core/breaker/breakers_test.go
@@ -135,5 +135,5 @@ func verify(t *testing.T, fn func() bool) {
 			count++
 		}
 	}
-	assert.True(t, count >= 80, fmt.Sprintf("should be greater than 80, actual %d", count))
+	assert.True(t, count >= 75, fmt.Sprintf("should be greater than 75, actual %d", count))
 }
diff --git a/core/filex/file_test.go b/core/filex/file_test.go
index d79e06a8..76cc78d0 100644
--- a/core/filex/file_test.go
+++ b/core/filex/file_test.go
@@ -52,6 +52,7 @@ last line`
 second line
 last line
 `
+	emptyContent = ``
 )
 
 func TestFirstLine(t *testing.T) {
@@ -79,6 +80,26 @@ func TestFirstLineError(t *testing.T) {
 	assert.Error(t, err)
 }
 
+func TestFirstLineEmptyFile(t *testing.T) {
+	filename, err := fs.TempFilenameWithText(emptyContent)
+	assert.Nil(t, err)
+	defer os.Remove(filename)
+
+	val, err := FirstLine(filename)
+	assert.Nil(t, err)
+	assert.Equal(t, "", val)
+}
+
+func TestFirstLineWithoutNewline(t *testing.T) {
+	filename, err := fs.TempFilenameWithText(longLine)
+	assert.Nil(t, err)
+	defer os.Remove(filename)
+
+	val, err := FirstLine(filename)
+	assert.Nil(t, err)
+	assert.Equal(t, longLine, val)
+}
+
 func TestLastLine(t *testing.T) {
 	filename, err := fs.TempFilenameWithText(text)
 	assert.Nil(t, err)
@@ -99,6 +120,16 @@ func TestLastLineWithLastNewline(t *testing.T) {
 	assert.Equal(t, longLine, val)
 }
 
+func TestLastLineWithoutLastNewline(t *testing.T) {
+	filename, err := fs.TempFilenameWithText(longLine)
+	assert.Nil(t, err)
+	defer os.Remove(filename)
+
+	val, err := LastLine(filename)
+	assert.Nil(t, err)
+	assert.Equal(t, longLine, val)
+}
+
 func TestLastLineShort(t *testing.T) {
 	filename, err := fs.TempFilenameWithText(shortText)
 	assert.Nil(t, err)
@@ -123,3 +154,67 @@ func TestLastLineError(t *testing.T) {
 	_, err := LastLine("/tmp/does-not-exist")
 	assert.Error(t, err)
 }
+
+func TestLastLineEmptyFile(t *testing.T) {
+	filename, err := fs.TempFilenameWithText(emptyContent)
+	assert.Nil(t, err)
+	defer os.Remove(filename)
+
+	val, err := LastLine(filename)
+	assert.Nil(t, err)
+	assert.Equal(t, "", val)
+}
+
+func TestFirstLineExactlyBufSize(t *testing.T) {
+	content := make([]byte, bufSize)
+	for i := range content {
+		content[i] = 'a'
+	}
+	content[bufSize-1] = '\n' // Ensure there is a newline at the edge
+
+	filename, err := fs.TempFilenameWithText(string(content))
+	assert.Nil(t, err)
+	defer os.Remove(filename)
+
+	val, err := FirstLine(filename)
+	assert.Nil(t, err)
+	assert.Equal(t, string(content[:bufSize-1]), val)
+}
+
+func TestLastLineExactlyBufSize(t *testing.T) {
+	content := make([]byte, bufSize)
+	for i := range content {
+		content[i] = 'a'
+	}
+	content[bufSize-1] = '\n' // Ensure there is a newline at the edge
+
+	filename, err := fs.TempFilenameWithText(string(content))
+	assert.Nil(t, err)
+	defer os.Remove(filename)
+
+	val, err := LastLine(filename)
+	assert.Nil(t, err)
+	assert.Equal(t, string(content[:bufSize-1]), val)
+}
+
+func TestFirstLineLargeFile(t *testing.T) {
+	content := text + text + text + "\n" + "extra"
+	filename, err := fs.TempFilenameWithText(content)
+	assert.Nil(t, err)
+	defer os.Remove(filename)
+
+	val, err := FirstLine(filename)
+	assert.Nil(t, err)
+	assert.Equal(t, "first line", val)
+}
+
+func TestLastLineLargeFile(t *testing.T) {
+	content := text + text + text + "\n" + "extra"
+	filename, err := fs.TempFilenameWithText(content)
+	assert.Nil(t, err)
+	defer os.Remove(filename)
+
+	val, err := LastLine(filename)
+	assert.Nil(t, err)
+	assert.Equal(t, "extra", val)
+}
diff --git a/core/fx/stream_test.go b/core/fx/stream_test.go
index c6eaef56..4536f1af 100644
--- a/core/fx/stream_test.go
+++ b/core/fx/stream_test.go
@@ -398,16 +398,16 @@ func TestWalk(t *testing.T) {
 
 func TestStream_AnyMach(t *testing.T) {
 	runCheckedTest(t, func(t *testing.T) {
-		assetEqual(t, false, Just(1, 2, 3).AnyMach(func(item any) bool {
+		assetEqual(t, false, Just(1, 2, 3).AnyMatch(func(item any) bool {
 			return item.(int) == 4
 		}))
-		assetEqual(t, false, Just(1, 2, 3).AnyMach(func(item any) bool {
+		assetEqual(t, false, Just(1, 2, 3).AnyMatch(func(item any) bool {
 			return item.(int) == 0
 		}))
-		assetEqual(t, true, Just(1, 2, 3).AnyMach(func(item any) bool {
+		assetEqual(t, true, Just(1, 2, 3).AnyMatch(func(item any) bool {
 			return item.(int) == 2
 		}))
-		assetEqual(t, true, Just(1, 2, 3).AnyMach(func(item any) bool {
+		assetEqual(t, true, Just(1, 2, 3).AnyMatch(func(item any) bool {
 			return item.(int) == 2
 		}))
 	})
@@ -416,17 +416,17 @@ func TestStream_AnyMach(t *testing.T) {
 func TestStream_AllMach(t *testing.T) {
 	runCheckedTest(t, func(t *testing.T) {
 		assetEqual(
-			t, true, Just(1, 2, 3).AllMach(func(item any) bool {
+			t, true, Just(1, 2, 3).AllMatch(func(item any) bool {
 				return true
 			}),
 		)
 		assetEqual(
-			t, false, Just(1, 2, 3).AllMach(func(item any) bool {
+			t, false, Just(1, 2, 3).AllMatch(func(item any) bool {
 				return false
 			}),
 		)
 		assetEqual(
-			t, false, Just(1, 2, 3).AllMach(func(item any) bool {
+			t, false, Just(1, 2, 3).AllMatch(func(item any) bool {
 				return item.(int) == 1
 			}),
 		)
diff --git a/core/logx/logs_test.go b/core/logx/logs_test.go
index 5d46b7b9..4c831a7c 100644
--- a/core/logx/logs_test.go
+++ b/core/logx/logs_test.go
@@ -679,6 +679,10 @@ func TestSetup(t *testing.T) {
 
 func TestDisable(t *testing.T) {
 	Disable()
+	defer func() {
+		SetLevel(InfoLevel)
+		atomic.StoreUint32(&encoding, jsonEncodingType)
+	}()
 
 	var opt logOptions
 	WithKeepDays(1)(&opt)
@@ -701,6 +705,17 @@ func TestDisableStat(t *testing.T) {
 	assert.Equal(t, 0, w.builder.Len())
 }
 
+func TestAddWriter(t *testing.T) {
+	const message = "hello there"
+	w := new(mockWriter)
+	AddWriter(w)
+	w1 := new(mockWriter)
+	AddWriter(w1)
+	Error(message)
+	assert.Contains(t, w.String(), message)
+	assert.Contains(t, w1.String(), message)
+}
+
 func TestSetWriter(t *testing.T) {
 	atomic.StoreUint32(&logLevel, 0)
 	Reset()
diff --git a/core/logx/writer_test.go b/core/logx/writer_test.go
index 6ac98bc1..7d223dd4 100644
--- a/core/logx/writer_test.go
+++ b/core/logx/writer_test.go
@@ -9,6 +9,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
 )
 
 func TestNewWriter(t *testing.T) {
@@ -254,6 +255,117 @@ func TestLogWithLimitContentLength(t *testing.T) {
 	})
 }
 
+func TestComboWriter(t *testing.T) {
+	var mockWriters []Writer
+	for i := 0; i < 3; i++ {
+		mockWriters = append(mockWriters, new(tracedWriter))
+	}
+
+	cw := comboWriter{
+		writers: mockWriters,
+	}
+
+	t.Run("Alert", func(t *testing.T) {
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).On("Alert", "test alert").Once()
+		}
+		cw.Alert("test alert")
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).AssertCalled(t, "Alert", "test alert")
+		}
+	})
+
+	t.Run("Close", func(t *testing.T) {
+		for i := range cw.writers {
+			if i == 1 {
+				cw.writers[i].(*tracedWriter).On("Close").Return(errors.New("error")).Once()
+			} else {
+				cw.writers[i].(*tracedWriter).On("Close").Return(nil).Once()
+			}
+		}
+		err := cw.Close()
+		assert.Error(t, err)
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).AssertCalled(t, "Close")
+		}
+	})
+
+	t.Run("Debug", func(t *testing.T) {
+		fields := []LogField{{Key: "key", Value: "value"}}
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).On("Debug", "test debug", fields).Once()
+		}
+		cw.Debug("test debug", fields...)
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).AssertCalled(t, "Debug", "test debug", fields)
+		}
+	})
+
+	t.Run("Error", func(t *testing.T) {
+		fields := []LogField{{Key: "key", Value: "value"}}
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).On("Error", "test error", fields).Once()
+		}
+		cw.Error("test error", fields...)
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).AssertCalled(t, "Error", "test error", fields)
+		}
+	})
+
+	t.Run("Info", func(t *testing.T) {
+		fields := []LogField{{Key: "key", Value: "value"}}
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).On("Info", "test info", fields).Once()
+		}
+		cw.Info("test info", fields...)
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).AssertCalled(t, "Info", "test info", fields)
+		}
+	})
+
+	t.Run("Severe", func(t *testing.T) {
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).On("Severe", "test severe").Once()
+		}
+		cw.Severe("test severe")
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).AssertCalled(t, "Severe", "test severe")
+		}
+	})
+
+	t.Run("Slow", func(t *testing.T) {
+		fields := []LogField{{Key: "key", Value: "value"}}
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).On("Slow", "test slow", fields).Once()
+		}
+		cw.Slow("test slow", fields...)
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).AssertCalled(t, "Slow", "test slow", fields)
+		}
+	})
+
+	t.Run("Stack", func(t *testing.T) {
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).On("Stack", "test stack").Once()
+		}
+		cw.Stack("test stack")
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).AssertCalled(t, "Stack", "test stack")
+		}
+	})
+
+	t.Run("Stat", func(t *testing.T) {
+		fields := []LogField{{Key: "key", Value: "value"}}
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).On("Stat", "test stat", fields).Once()
+		}
+		cw.Stat("test stat", fields...)
+		for _, mw := range cw.writers {
+			mw.(*tracedWriter).AssertCalled(t, "Stat", "test stat", fields)
+		}
+	})
+}
+
 type mockedEntry struct {
 	Level     string `json:"level"`
 	Content   string `json:"content"`
@@ -285,3 +397,44 @@ type hardToWriteWriter struct{}
 func (h hardToWriteWriter) Write(_ []byte) (_ int, _ error) {
 	return 0, errors.New("write error")
 }
+
+type tracedWriter struct {
+	mock.Mock
+}
+
+func (w *tracedWriter) Alert(v any) {
+	w.Called(v)
+}
+
+func (w *tracedWriter) Close() error {
+	args := w.Called()
+	return args.Error(0)
+}
+
+func (w *tracedWriter) Debug(v any, fields ...LogField) {
+	w.Called(v, fields)
+}
+
+func (w *tracedWriter) Error(v any, fields ...LogField) {
+	w.Called(v, fields)
+}
+
+func (w *tracedWriter) Info(v any, fields ...LogField) {
+	w.Called(v, fields)
+}
+
+func (w *tracedWriter) Severe(v any) {
+	w.Called(v)
+}
+
+func (w *tracedWriter) Slow(v any, fields ...LogField) {
+	w.Called(v, fields)
+}
+
+func (w *tracedWriter) Stack(v any) {
+	w.Called(v)
+}
+
+func (w *tracedWriter) Stat(v any, fields ...LogField) {
+	w.Called(v, fields)
+}
diff --git a/core/stores/mon/clientmanager_test.go b/core/stores/mon/clientmanager_test.go
index 9c3eae5c..f4aa5537 100644
--- a/core/stores/mon/clientmanager_test.go
+++ b/core/stores/mon/clientmanager_test.go
@@ -7,6 +7,10 @@ import (
 	"go.mongodb.org/mongo-driver/mongo/integration/mtest"
 )
 
+func init() {
+	_ = mtest.Setup()
+}
+
 func TestClientManger_getClient(t *testing.T) {
 	mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
 	mt.Run("test", func(mt *mtest.T) {
diff --git a/core/stores/mon/collection_test.go b/core/stores/mon/collection_test.go
index 4a3f3b56..575aa4fe 100644
--- a/core/stores/mon/collection_test.go
+++ b/core/stores/mon/collection_test.go
@@ -15,6 +15,7 @@ import (
 	"go.mongodb.org/mongo-driver/mongo"
 	"go.mongodb.org/mongo-driver/mongo/integration/mtest"
 	mopt "go.mongodb.org/mongo-driver/mongo/options"
+	"go.mongodb.org/mongo-driver/x/mongo/driver/session"
 )
 
 var errDummy = errors.New("dummy")
@@ -572,6 +573,56 @@ func TestDecoratedCollection_LogDuration(t *testing.T) {
 	assert.Contains(t, buf.String(), "slowcall")
 }
 
+func TestAcceptable(t *testing.T) {
+	tests := []struct {
+		name string
+		err  error
+		want bool
+	}{
+		{"NilError", nil, true},
+		{"NoDocuments", mongo.ErrNoDocuments, true},
+		{"NilValue", mongo.ErrNilValue, true},
+		{"NilDocument", mongo.ErrNilDocument, true},
+		{"NilCursor", mongo.ErrNilCursor, true},
+		{"EmptySlice", mongo.ErrEmptySlice, true},
+		{"SessionEnded", session.ErrSessionEnded, true},
+		{"NoTransactStarted", session.ErrNoTransactStarted, true},
+		{"TransactInProgress", session.ErrTransactInProgress, true},
+		{"AbortAfterCommit", session.ErrAbortAfterCommit, true},
+		{"AbortTwice", session.ErrAbortTwice, true},
+		{"CommitAfterAbort", session.ErrCommitAfterAbort, true},
+		{"UnackWCUnsupported", session.ErrUnackWCUnsupported, true},
+		{"SnapshotTransaction", session.ErrSnapshotTransaction, true},
+		{"DuplicateKeyError", mongo.WriteException{WriteErrors: []mongo.WriteError{{Code: duplicateKeyCode}}}, true},
+		{"OtherError", errors.New("other error"), false},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			assert.Equal(t, tt.want, acceptable(tt.err))
+		})
+	}
+}
+
+func TestIsDupKeyError(t *testing.T) {
+	tests := []struct {
+		name string
+		err  error
+		want bool
+	}{
+		{"NilError", nil, false},
+		{"NonDupKeyError", errors.New("some other error"), false},
+		{"DupKeyError", mongo.WriteException{WriteErrors: []mongo.WriteError{{Code: duplicateKeyCode}}}, true},
+		{"OtherMongoError", mongo.WriteException{WriteErrors: []mongo.WriteError{{Code: 12345}}}, false},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			assert.Equal(t, tt.want, isDupKeyError(tt.err))
+		})
+	}
+}
+
 type mockPromise struct {
 	accepted bool
 	reason   string
diff --git a/core/stores/redis/redis_test.go b/core/stores/redis/redis_test.go
index 4ddd2bfd..032ac6b8 100644
--- a/core/stores/redis/redis_test.go
+++ b/core/stores/redis/redis_test.go
@@ -160,7 +160,7 @@ func TestRedis_NonBlock(t *testing.T) {
 			Host:     s.Addr(),
 			NonBlock: true,
 			Type:     NodeType,
-		}, withHook(myHook{includePing: true}))
+		}, WithHook(myHook{includePing: true}))
 		assert.NoError(t, err)
 	})
 
@@ -170,7 +170,7 @@ func TestRedis_NonBlock(t *testing.T) {
 			Host:     s.Addr(),
 			NonBlock: false,
 			Type:     NodeType,
-		}, withHook(myHook{includePing: true}))
+		}, WithHook(myHook{includePing: true}))
 		assert.ErrorContains(t, err, "redis connect error")
 	})
 }
diff --git a/core/stores/sqlc/cachedsql_test.go b/core/stores/sqlc/cachedsql_test.go
index 84b04402..5ebb56d4 100644
--- a/core/stores/sqlc/cachedsql_test.go
+++ b/core/stores/sqlc/cachedsql_test.go
@@ -579,6 +579,48 @@ func TestQueryRowNoCache(t *testing.T) {
 	assert.True(t, ran)
 }
 
+func TestQueryRowPartialNoCache(t *testing.T) {
+	r := redistest.CreateRedis(t)
+
+	const (
+		key   = "user"
+		value = "any"
+	)
+	var user string
+	var ran bool
+	conn := dummySqlConn{queryRow: func(v any, q string, args ...any) error {
+		user = value
+		ran = true
+		return nil
+	}}
+	c := NewNodeConn(&conn, r, cache.WithExpiry(time.Second*30))
+	err := c.QueryRowPartialNoCache(&user, key)
+	assert.Nil(t, err)
+	assert.Equal(t, value, user)
+	assert.True(t, ran)
+}
+
+func TestQueryRowsPartialNoCache(t *testing.T) {
+	r := redistest.CreateRedis(t)
+
+	var (
+		key    = "user"
+		values = []string{"any", "any"}
+	)
+	var users []string
+	var ran bool
+	conn := dummySqlConn{queryRows: func(v any, q string, args ...any) error {
+		users = values
+		ran = true
+		return nil
+	}}
+	c := NewNodeConn(&conn, r, cache.WithExpiry(time.Second*30))
+	err := c.QueryRowsPartialNoCache(&users, key)
+	assert.Nil(t, err)
+	assert.Equal(t, values, users)
+	assert.True(t, ran)
+}
+
 func TestNewConnWithCache(t *testing.T) {
 	r := redistest.CreateRedis(t)
 
@@ -716,7 +758,8 @@ func resetStats() {
 }
 
 type dummySqlConn struct {
-	queryRow func(any, string, ...any) error
+	queryRow  func(any, string, ...any) error
+	queryRows func(any, string, ...any) error
 }
 
 func (d dummySqlConn) ExecCtx(_ context.Context, _ string, _ ...any) (sql.Result, error) {
@@ -727,7 +770,11 @@ func (d dummySqlConn) PrepareCtx(_ context.Context, _ string) (sqlx.StmtSession,
 	return nil, nil
 }
 
-func (d dummySqlConn) QueryRowPartialCtx(_ context.Context, _ any, _ string, _ ...any) error {
+func (d dummySqlConn) QueryRowPartialCtx(_ context.Context, v any, query string, args ...any) error {
+	if d.queryRow != nil {
+		return d.queryRow(v, query, args...)
+	}
+
 	return nil
 }
 
@@ -735,7 +782,11 @@ func (d dummySqlConn) QueryRowsCtx(_ context.Context, _ any, _ string, _ ...any)
 	return nil
 }
 
-func (d dummySqlConn) QueryRowsPartialCtx(_ context.Context, _ any, _ string, _ ...any) error {
+func (d dummySqlConn) QueryRowsPartialCtx(_ context.Context, v any, query string, args ...any) error {
+	if d.queryRows != nil {
+		return d.queryRows(v, query, args...)
+	}
+
 	return nil
 }
 
diff --git a/core/trace/message_test.go b/core/trace/message_test.go
index 290158f8..b1de2391 100644
--- a/core/trace/message_test.go
+++ b/core/trace/message_test.go
@@ -5,6 +5,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"go.opentelemetry.io/otel"
 	"go.opentelemetry.io/otel/attribute"
 	"go.opentelemetry.io/otel/codes"
 	"go.opentelemetry.io/otel/trace"
@@ -13,8 +14,9 @@ import (
 )
 
 func TestMessageType_Event(t *testing.T) {
-	var span mockSpan
-	ctx := trace.ContextWithSpan(context.Background(), &span)
+	ctx, s := otel.Tracer(TraceName).Start(context.Background(), "test")
+	span := mockSpan{Span: s}
+	ctx = trace.ContextWithSpan(ctx, &span)
 	MessageReceived.Event(ctx, 1, "foo")
 	assert.Equal(t, messageEvent, span.name)
 	assert.NotEmpty(t, span.options)
@@ -30,6 +32,7 @@ func TestMessageType_EventProtoMessage(t *testing.T) {
 }
 
 type mockSpan struct {
+	trace.Span
 	name    string
 	options []trace.EventOption
 }
diff --git a/rest/internal/fileserver/filehandler_test.go b/rest/internal/fileserver/filehandler_test.go
new file mode 100644
index 00000000..37308f72
--- /dev/null
+++ b/rest/internal/fileserver/filehandler_test.go
@@ -0,0 +1,122 @@
+package fileserver
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestMiddleware(t *testing.T) {
+	tests := []struct {
+		name            string
+		path            string
+		dir             string
+		requestPath     string
+		expectedStatus  int
+		expectedContent string
+	}{
+		{
+			name:            "Serve static file",
+			path:            "/static/",
+			dir:             "./testdata",
+			requestPath:     "/static/example.txt",
+			expectedStatus:  http.StatusOK,
+			expectedContent: "1",
+		},
+		{
+			name:           "Pass through non-matching path",
+			path:           "/static/",
+			dir:            "./testdata",
+			requestPath:    "/other/path",
+			expectedStatus: http.StatusAlreadyReported,
+		},
+		{
+			name:            "Directory with trailing slash",
+			path:            "/assets",
+			dir:             "testdata",
+			requestPath:     "/assets/sample.txt",
+			expectedStatus:  http.StatusOK,
+			expectedContent: "2",
+		},
+		{
+			name:           "Not exist file",
+			path:           "/assets",
+			dir:            "testdata",
+			requestPath:    "/assets/not-exist.txt",
+			expectedStatus: http.StatusAlreadyReported,
+		},
+		{
+			name:           "Not exist file in root",
+			path:           "/",
+			dir:            "testdata",
+			requestPath:    "/not-exist.txt",
+			expectedStatus: http.StatusAlreadyReported,
+		},
+		{
+			name:           "websocket request",
+			path:           "/",
+			dir:            "testdata",
+			requestPath:    "/ws",
+			expectedStatus: http.StatusAlreadyReported,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			middleware := Middleware(tt.path, http.Dir(tt.dir))
+			nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+				w.WriteHeader(http.StatusAlreadyReported)
+			})
+
+			handlerToTest := middleware(nextHandler)
+
+			for i := 0; i < 2; i++ {
+				req := httptest.NewRequest(http.MethodGet, tt.requestPath, nil)
+				rr := httptest.NewRecorder()
+
+				handlerToTest.ServeHTTP(rr, req)
+
+				assert.Equal(t, tt.expectedStatus, rr.Code)
+				if len(tt.expectedContent) > 0 {
+					assert.Equal(t, tt.expectedContent, rr.Body.String())
+				}
+			}
+		})
+	}
+}
+
+func TestEnsureTrailingSlash(t *testing.T) {
+	tests := []struct {
+		input    string
+		expected string
+	}{
+		{"path", "path/"},
+		{"path/", "path/"},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.input, func(t *testing.T) {
+			result := ensureTrailingSlash(tt.input)
+			assert.Equal(t, tt.expected, result)
+		})
+	}
+}
+
+func TestEnsureNoTrailingSlash(t *testing.T) {
+	tests := []struct {
+		input    string
+		expected string
+	}{
+		{"path", "path"},
+		{"path/", "path"},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.input, func(t *testing.T) {
+			result := ensureNoTrailingSlash(tt.input)
+			assert.Equal(t, tt.expected, result)
+		})
+	}
+}
diff --git a/rest/internal/fileserver/testdata/example.txt b/rest/internal/fileserver/testdata/example.txt
new file mode 100644
index 00000000..56a6051c
--- /dev/null
+++ b/rest/internal/fileserver/testdata/example.txt
@@ -0,0 +1,1 @@
+1
\ No newline at end of file
diff --git a/rest/internal/fileserver/testdata/sample.txt b/rest/internal/fileserver/testdata/sample.txt
new file mode 100644
index 00000000..d8263ee9
--- /dev/null
+++ b/rest/internal/fileserver/testdata/sample.txt
@@ -0,0 +1,1 @@
+2
\ No newline at end of file
diff --git a/rest/server_test.go b/rest/server_test.go
index 3a4bdded..3f01fd3f 100644
--- a/rest/server_test.go
+++ b/rest/server_test.go
@@ -2,8 +2,10 @@ package rest
 
 import (
 	"crypto/tls"
+	"embed"
 	"fmt"
 	"io"
+	"io/fs"
 	"net/http"
 	"net/http/httptest"
 	"os"
@@ -21,6 +23,11 @@ import (
 	"github.com/zeromicro/go-zero/rest/router"
 )
 
+const (
+	exampleContent = "example content"
+	sampleContent  = "sample content"
+)
+
 func TestNewServer(t *testing.T) {
 	logtest.Discard(t)
 
@@ -184,6 +191,56 @@ func TestWithMiddleware(t *testing.T) {
 	}, m)
 }
 
+func TestWithFileServerMiddleware(t *testing.T) {
+	tests := []struct {
+		name            string
+		path            string
+		dir             string
+		requestPath     string
+		expectedStatus  int
+		expectedContent string
+	}{
+		{
+			name:            "Serve static file",
+			path:            "/assets/",
+			dir:             "./testdata",
+			requestPath:     "/assets/example.txt",
+			expectedStatus:  http.StatusOK,
+			expectedContent: exampleContent,
+		},
+		{
+			name:           "Pass through non-matching path",
+			path:           "/static/",
+			dir:            "./testdata",
+			requestPath:    "/other/path",
+			expectedStatus: http.StatusNotFound,
+		},
+		{
+			name:            "Directory with trailing slash",
+			path:            "/static",
+			dir:             "testdata",
+			requestPath:     "/static/sample.txt",
+			expectedStatus:  http.StatusOK,
+			expectedContent: sampleContent,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			server := MustNewServer(RestConf{}, WithFileServer(tt.path, http.Dir(tt.dir)))
+			req := httptest.NewRequest(http.MethodGet, tt.requestPath, nil)
+			rr := httptest.NewRecorder()
+
+			server.ServeHTTP(rr, req)
+
+			assert.Equal(t, tt.expectedStatus, rr.Code)
+			if len(tt.expectedContent) > 0 {
+				assert.Equal(t, tt.expectedContent, rr.Body.String())
+			}
+		})
+	}
+}
+
 func TestMultiMiddlewares(t *testing.T) {
 	m := make(map[string]string)
 	rt := router.NewRouter()
@@ -638,3 +695,18 @@ Port: 54321
 		})
 	}
 }
+
+//go:embed testdata
+var content embed.FS
+
+func TestServerEmbedFileSystem(t *testing.T) {
+	filesys, err := fs.Sub(content, "testdata")
+	assert.NoError(t, err)
+
+	server := MustNewServer(RestConf{}, WithFileServer("/assets", http.FS(filesys)))
+	req, err := http.NewRequest(http.MethodGet, "/assets/sample.txt", http.NoBody)
+	assert.Nil(t, err)
+	rr := httptest.NewRecorder()
+	server.ServeHTTP(rr, req)
+	assert.Equal(t, sampleContent, rr.Body.String())
+}
diff --git a/rest/testdata/example.txt b/rest/testdata/example.txt
new file mode 100644
index 00000000..76b3034f
--- /dev/null
+++ b/rest/testdata/example.txt
@@ -0,0 +1,1 @@
+example content
\ No newline at end of file
diff --git a/rest/testdata/sample.txt b/rest/testdata/sample.txt
new file mode 100644
index 00000000..0d6f364b
--- /dev/null
+++ b/rest/testdata/sample.txt
@@ -0,0 +1,1 @@
+sample content
\ No newline at end of file
diff --git a/tools/goctl/api/gogen/gen_test.go b/tools/goctl/api/gogen/gen_test.go
index 349312e5..56d5f925 100644
--- a/tools/goctl/api/gogen/gen_test.go
+++ b/tools/goctl/api/gogen/gen_test.go
@@ -57,6 +57,8 @@ var (
 	importTwiceApi string
 	//go:embed testdata/another_import_api.api
 	anotherImportApi string
+	//go:embed testdata/example.api
+	exampleApi string
 )
 
 func TestParser(t *testing.T) {
@@ -316,15 +318,32 @@ func TestCamelStyle(t *testing.T) {
 	validateWithCamel(t, filename, "GoZero")
 }
 
+func TestExampleGen(t *testing.T) {
+	env.Set(t, env.GoctlExperimental, env.ExperimentalOn)
+	filename := "greet.api"
+	err := os.WriteFile(filename, []byte(exampleApi), os.ModePerm)
+	assert.Nil(t, err)
+	t.Cleanup(func() {
+		_ = os.Remove(filename)
+	})
+
+	spec, err := parser.Parse(filename)
+	assert.Nil(t, err)
+	assert.Equal(t, len(spec.Types), 10)
+
+	validate(t, filename)
+}
+
 func validate(t *testing.T, api string) {
 	validateWithCamel(t, api, "gozero")
 }
 
 func validateWithCamel(t *testing.T, api, camel string) {
 	dir := "workspace"
-	defer func() {
-		os.RemoveAll(dir)
-	}()
+	t.Cleanup(func() {
+		_ = os.RemoveAll(dir)
+	})
+
 	err := pathx.MkdirIfNotExist(dir)
 	assert.Nil(t, err)
 	err = initMod(dir)
diff --git a/tools/goctl/api/gogen/testdata/example.api b/tools/goctl/api/gogen/testdata/example.api
new file mode 100644
index 00000000..656f632f
--- /dev/null
+++ b/tools/goctl/api/gogen/testdata/example.api
@@ -0,0 +1,99 @@
+syntax = "v1"
+
+info(
+    title: "demo title"
+    desc: "demo desc"
+    author: "keson.an"
+    date: "2024-06-25"
+    version: "v1"
+)
+
+// empty structure
+type Foo {
+}
+
+// type lit
+type Bar {
+    Foo int `json:"foo"`
+    Bar bool `json:"bar"`
+    Baz []string `json:"baz"`
+    Qux map[string]string `json:"qux"`
+}
+
+type Baz {
+    Foo    `json:"foo"`
+    // array type
+    Arr [2]int `json:"arr"`
+    // nested type
+    Bar {
+        Foo string `json:"foo"`
+        Bar bool `json:"bar"`
+        Baz {
+            Foo string `json:"foo"`
+            Bar bool `json:"bar"`
+        }
+        Qux {
+            Foo string `json:"foo"`
+            Bar bool `json:"bar"`
+        } `json:"qux"`
+    } `json:"bar"`
+}
+
+
+type UpdateReq {
+    Arg1 string `json:"arg1"`
+}
+
+type ListItem {
+    Value1 string `json:"value1"`
+}
+
+type LoginReq {
+    Username string `json:"username"`
+    Password string `json:"password"`
+}
+
+type LoginResp {
+    Name string `json:"name"`
+}
+
+type FormExampleReq {
+    Name string `form:"name"`
+}
+
+type PathExampleReq {
+    ID string `path:"id"`
+}
+
+type PathExampleResp {
+    Name string `json:"name"`
+}
+
+@server(
+    jwt: Auth
+    prefix:     /v1
+    group: g1
+    timeout:    3s
+    middleware: AuthInterceptor
+    maxBytes:   1048576
+)
+service Foo {
+    @handler ping
+    get /ping
+
+    @handler update
+    post /update (UpdateReq)
+
+    @handler list
+    get /list returns ([]ListItem)
+
+    @handler login
+    post /login (LoginReq) returns (LoginResp)
+
+    @handler formExample
+    post /form/example (FormExampleReq)
+
+    @handler pathExample
+    get /path/example/:id (PathExampleReq) returns (PathExampleResp)
+}
+
diff --git a/tools/goctl/api/tsgen/util_test.go b/tools/goctl/api/tsgen/util_test.go
index d9e88969..076dee42 100644
--- a/tools/goctl/api/tsgen/util_test.go
+++ b/tools/goctl/api/tsgen/util_test.go
@@ -16,14 +16,14 @@ func TestGenTsType(t *testing.T) {
 		Docs:     nil,
 		IsInline: false,
 	}
-	ty, err := genTsType(member)
+	ty, err := genTsType(member, 1)
 	if err != nil {
 		t.Fatal(err)
 	}
 	assert.Equal(t, `'foo' | 'bar' | 'options' | '123'`, ty)
 
 	member.IsInline = true
-	ty, err = genTsType(member)
+	ty, err = genTsType(member, 1)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -31,7 +31,7 @@ func TestGenTsType(t *testing.T) {
 
 	member.Type = spec.PrimitiveType{RawName: "int"}
 	member.Tag = `json:"foo,options=1|3|4|123"`
-	ty, err = genTsType(member)
+	ty, err = genTsType(member, 1)
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/tools/goctl/model/sql/command/command_test.go b/tools/goctl/model/sql/command/command_test.go
index fa85e6e8..b80298a1 100644
--- a/tools/goctl/model/sql/command/command_test.go
+++ b/tools/goctl/model/sql/command/command_test.go
@@ -9,7 +9,6 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
-
 	"github.com/zeromicro/go-zero/tools/goctl/config"
 	"github.com/zeromicro/go-zero/tools/goctl/model/sql/gen"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
diff --git a/tools/goctl/model/sql/gen/gen_test.go b/tools/goctl/model/sql/gen/gen_test.go
index 721a7e38..ded112af 100644
--- a/tools/goctl/model/sql/gen/gen_test.go
+++ b/tools/goctl/model/sql/gen/gen_test.go
@@ -12,7 +12,6 @@ import (
 
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
-
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/core/stores/builder"
 	"github.com/zeromicro/go-zero/core/stringx"
diff --git a/tools/goctl/model/sql/parser/parser_test.go b/tools/goctl/model/sql/parser/parser_test.go
index 3f67a81d..74442a86 100644
--- a/tools/goctl/model/sql/parser/parser_test.go
+++ b/tools/goctl/model/sql/parser/parser_test.go
@@ -7,7 +7,6 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
-
 	"github.com/zeromicro/go-zero/tools/goctl/model/sql/model"
 	"github.com/zeromicro/go-zero/tools/goctl/model/sql/util"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
diff --git a/tools/goctl/pkg/parser/api/parser/testdata/invalid.api b/tools/goctl/pkg/parser/api/parser/testdata/invalid.api
index cf58be84..f14f2f67 100644
--- a/tools/goctl/pkg/parser/api/parser/testdata/invalid.api
+++ b/tools/goctl/pkg/parser/api/parser/testdata/invalid.api
@@ -95,13 +95,6 @@ type Foo {
     Bar *map[[]int]string  `json:"bar"`
 }
 
------
-// test case:  map valu expected literal type
-syntax = "v1"
-type Foo {
-    Bar *map[string]{}  `json:"bar"`
-}
-
 -----
 // test case:  invalid slice
 syntax = "v1"
@@ -123,10 +116,90 @@ type Foo {
     Bar any  `json:"bar"`
 }
 
+-----
+// test case:  invalid map key
+syntax = "v1"
+type Foo {
+  M map[{}]string `json:"m"`
+}
+
+-----
+// test case:  invalid map key
+syntax = "v1"
+type Foo {
+M map[{
+  Foo string `json:"foo"`
+}]string `json:"m"`
+}
+
+-----
+// test case:  invalid map value
+syntax = "v1"
+type Foo {
+M map[int]{} `json:"m"`
+}
+
+-----
+// test case:  invalid map value
+syntax = "v1"
+type Foo {
+M map[int]{
+  Foo int `json:"foo"`
+} `json:"m"`
+}
+
+-----
+// test case:  invalid array element
+syntax = "v1"
+type Foo {
+  Array [3]{} `json:"array"`
+}
+
+-----
+// test case:  invalid array element
+syntax = "v1"
+type Foo {
+Array [3]{
+Foo int `json:"foo"`
+} `json:"array"`
+}
+
+-----
+// test case:  invalid array element
+syntax = "v1"
+type Foo {
+Array []{} `json:"array"`
+}
+
+-----
+// test case:  invalid slice element
+syntax = "v1"
+type Foo {
+Array []{
+Foo int `json:"foo"`
+} `json:"array"`
+}
+
 -----
 // test case:  unresolved type
 syntax = "v1"
 service example {
     @handler nestDemo
     post /example/nest (NestDemoReq) returns (NestDemoResp)
+}
+
+-----
+// test case:  unsupported array object request body
+syntax = "v1"
+service example {
+    @handler nestDemo
+    post /example/nest ([]NestDemoReq) returns (NestDemoResp)
+}
+
+-----
+    // test case:  unsupported array request body
+syntax = "v1"
+service example {
+    @handler nestDemo2
+    post /example/nest2 ([]string) returns (NestDemoResp)
 }
\ No newline at end of file