This is an automated email from the ASF dual-hosted git repository.

zhongxjian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo-kubernetes.git


The following commit(s) were added to refs/heads/master by this push:
     new 020d3aaf [navi] add discovery init mesh config v1 (#768)
020d3aaf is described below

commit 020d3aaf3b478f7d1987cdd3b638aae49df81cb3
Author: Jian Zhong <[email protected]>
AuthorDate: Sun Aug 3 02:40:15 2025 +0800

    [navi] add discovery init mesh config v1 (#768)
---
 go.mod                                       |  45 +-----
 go.sum                                       |  88 +----------
 navigator/pkg/bootstrap/mesh.go              |   6 +-
 navigator/pkg/features/navigator.go          |   3 +
 pkg/config/mesh/kubemesh/watcher.go          |  21 ++-
 pkg/config/schema/gvr/resource.gen.go        |   6 +
 pkg/config/schema/kubeclient/common.go       | 187 ++++++++++++++++++++++++
 pkg/config/schema/kubeclient/resource.gen.go |  15 ++
 pkg/config/schema/kubetypes/common.go        |  38 +++++
 pkg/config/schema/kubetypes/resources.gen.go |  12 ++
 pkg/kube/client.go                           |  82 ++++++++++-
 pkg/kube/controllers/common.go               |  15 ++
 pkg/kube/kclient/client.go                   | 209 +++++++++++++++++++++++++++
 pkg/kube/kclient/interfaces.go               |  43 ++++++
 pkg/kube/krt/collection.go                   | 178 +++++++++++++++++++++++
 pkg/kube/krt/core.go                         |  37 ++---
 pkg/kube/krt/files/files.go                  |  49 ++++++-
 pkg/kube/krt/filter.go                       |  12 +-
 pkg/kube/krt/helpers.go                      |  29 ++++
 pkg/kube/krt/informer.go                     |  50 +++++++
 pkg/kube/krt/internal.go                     |  11 +-
 pkg/kube/krt/options.go                      |   4 +
 pkg/kube/krt/recomputetrigger.go             |  86 +++++++++++
 pkg/kube/krt/singleton.go                    | 206 +++++++++++++++++++++++++-
 pkg/kube/kubetypes/types.go                  |  56 ++++++-
 pkg/mesh/meshwatcher/collection.go           |   1 -
 pkg/ptr/pointer.go                           |  19 +++
 pkg/sleep/sleep.go                           |  23 +++
 pkg/typemap/map.go                           |  27 ++++
 pkg/util/smallset/smallset.go                | 108 ++++++++++++++
 30 files changed, 1487 insertions(+), 179 deletions(-)

diff --git a/go.mod b/go.mod
index 07787406..79b2cd06 100644
--- a/go.mod
+++ b/go.mod
@@ -30,6 +30,7 @@ require (
        github.com/docker/docker-credential-helpers v0.9.3
        github.com/docker/go-connections v0.5.0
        github.com/fatih/color v1.18.0
+       github.com/fsnotify/fsnotify v1.9.0
        github.com/go-git/go-billy/v5 v5.6.2
        github.com/go-git/go-git/v5 v5.13.1
        github.com/golang/protobuf v1.5.4
@@ -43,6 +44,7 @@ require (
        github.com/spf13/cobra v1.9.1
        github.com/spf13/pflag v1.0.6
        github.com/tmc/langchaingo v0.1.13
+       go.uber.org/atomic v1.11.0
        golang.org/x/crypto v0.40.0
        golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6
        golang.org/x/net v0.42.0
@@ -61,7 +63,6 @@ require (
 )
 
 require (
-       cel.dev/expr v0.24.0 // indirect
        dario.cat/mergo v1.0.2 // indirect
        github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
        github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // 
indirect
@@ -82,7 +83,6 @@ require (
        github.com/ProtonMail/go-crypto v1.1.3 // indirect
        github.com/VividCortex/ewma v1.2.0 // indirect
        github.com/agext/levenshtein v1.2.3 // indirect
-       github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
        github.com/apex/log v1.9.0 // indirect
        github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect
        github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect
@@ -100,21 +100,17 @@ require (
        github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
        github.com/aws/smithy-go v1.20.3 // indirect
        github.com/awslabs/amazon-ecr-credential-helper/ecr-login 
v0.0.0-20230522190001-adf1bafd791a // indirect
-       github.com/beorn7/perks v1.0.1 // indirect
        github.com/blang/semver/v4 v4.0.0 // indirect
        github.com/buildpacks/imgutil v0.0.0-20230626185301-726f02e4225c // 
indirect
        github.com/buildpacks/lifecycle v0.17.0 // indirect
        github.com/cespare/xxhash v1.1.0 // indirect
-       github.com/cespare/xxhash/v2 v2.3.0 // indirect
        github.com/chrismellard/docker-credential-acr-env 
v0.0.0-20230304212654-82a0ddb27589 // indirect
        github.com/cloudflare/circl v1.3.7 // indirect
-       github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
        github.com/containerd/containerd v1.7.27 // indirect
        github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
        github.com/containerd/typeurl/v2 v2.2.3 // indirect
        github.com/cyphar/filepath-securejoin v0.4.1 // indirect
        github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // 
indirect
-       github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
        github.com/dgraph-io/ristretto v0.0.1 // indirect
        github.com/dimchansky/utfbom v1.1.1 // indirect
        github.com/dlclark/regexp2 v1.10.0 // indirect
@@ -123,33 +119,25 @@ require (
        github.com/dustin/go-humanize v1.0.1 // indirect
        github.com/emicklei/go-restful/v3 v3.12.2 // indirect
        github.com/emirpasic/gods v1.18.1 // indirect
-       github.com/envoyproxy/go-control-plane/contrib 
v1.32.5-0.20250627145903-197b96a9c7f8 // indirect
-       github.com/envoyproxy/go-control-plane/envoy 
v1.32.5-0.20250627145903-197b96a9c7f8 // indirect
-       github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
-       github.com/fsnotify/fsnotify v1.9.0 // indirect
        github.com/fxamacker/cbor/v2 v2.8.0 // indirect
        github.com/gdamore/encoding v1.0.0 // indirect
        github.com/gdamore/tcell/v2 v2.6.0 // indirect
        github.com/go-errors/errors v1.5.1 // indirect
        github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
        github.com/go-logr/logr v1.4.3 // indirect
-       github.com/go-logr/stdr v1.2.2 // indirect
        github.com/go-openapi/jsonpointer v0.21.1 // indirect
        github.com/go-openapi/jsonreference v0.21.0 // indirect
        github.com/go-openapi/swag v0.23.1 // indirect
        github.com/gobwas/glob v0.2.3 // indirect
-       github.com/goccy/go-json v0.10.5 // indirect
        github.com/gogo/protobuf v1.3.2 // indirect
        github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
        github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // 
indirect
        github.com/google/btree v1.1.3 // indirect
-       github.com/google/cel-go v0.25.0 // indirect
        github.com/google/gnostic-models v0.6.9 // indirect
        github.com/google/go-cmp v0.7.0 // indirect
        github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
        github.com/google/uuid v1.6.0 // indirect
        github.com/goph/emperror v0.17.2 // indirect
-       github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // 
indirect
        github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // 
indirect
        github.com/hashicorp/errwrap v1.1.0 // indirect
        github.com/hashicorp/hcl v1.0.0 // indirect
@@ -163,12 +151,6 @@ require (
        github.com/kevinburke/ssh_config v1.2.0 // indirect
        github.com/klauspost/compress v1.18.0 // indirect
        github.com/klauspost/pgzip v1.2.6 // indirect
-       github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
-       github.com/lestrrat-go/blackmagic v1.0.3 // indirect
-       github.com/lestrrat-go/httpcc v1.0.1 // indirect
-       github.com/lestrrat-go/iter v1.0.2 // indirect
-       github.com/lestrrat-go/jwx v1.2.31 // indirect
-       github.com/lestrrat-go/option v1.0.1 // indirect
        github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
        github.com/magiconair/properties v1.8.7 // indirect
        github.com/mailru/easyjson v0.9.0 // indirect
@@ -184,7 +166,6 @@ require (
        github.com/moby/buildkit v0.21.1 // indirect
        github.com/moby/docker-image-spec v1.3.1 // indirect
        github.com/moby/patternmatcher v0.6.0 // indirect
-       github.com/moby/spdystream v0.5.0 // indirect
        github.com/moby/sys/capability v0.4.0 // indirect
        github.com/moby/sys/mountinfo v0.7.2 // indirect
        github.com/moby/sys/sequential v0.6.0 // indirect
@@ -195,8 +176,9 @@ require (
        github.com/monochromegane/go-gitignore 
v0.0.0-20200626010858-205db1a8cc00 // indirect
        github.com/morikuni/aec v1.0.0 // indirect
        github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 
indirect
-       github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // 
indirect
        github.com/nikolalohinski/gonja v1.5.3 // indirect
+       github.com/onsi/ginkgo/v2 v2.23.4 // indirect
+       github.com/onsi/gomega v1.37.0 // indirect
        github.com/opencontainers/go-digest v1.0.0 // indirect
        github.com/opencontainers/image-spec v1.1.1 // indirect
        github.com/opencontainers/runc v1.1.7 // indirect
@@ -208,7 +190,6 @@ require (
        github.com/pjbgf/sha1cd v0.3.0 // indirect
        github.com/pkoukk/tiktoken-go v0.1.6 // indirect
        github.com/planetscale/vtprotobuf v0.6.1-0.20240409071808-615f978279ca 
// indirect
-       github.com/prometheus/client_golang v1.22.0 // indirect
        github.com/prometheus/client_model v0.6.2 // indirect
        github.com/prometheus/common v0.65.0 // indirect
        github.com/prometheus/procfs v0.16.1 // indirect
@@ -223,7 +204,6 @@ require (
        github.com/spf13/afero v1.14.0 // indirect
        github.com/spf13/cast v1.8.0 // indirect
        github.com/spf13/jwalterweatherman v1.1.0 // indirect
-       github.com/stoewer/go-strcase v1.3.0 // indirect
        github.com/subosito/gotenv v1.6.0 // indirect
        github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 // 
indirect
        github.com/ulikunitz/xz v0.5.12 // indirect
@@ -235,18 +215,7 @@ require (
        github.com/xeipuuv/gojsonschema v1.2.0 // indirect
        github.com/xlab/treeprint v1.2.0 // indirect
        github.com/yargevad/filepathx v1.0.0 // indirect
-       go.opentelemetry.io/auto/sdk v1.1.0 // indirect
-       go.opentelemetry.io/otel v1.36.0 // indirect
-       go.opentelemetry.io/otel/exporters/prometheus v0.57.0 // indirect
-       go.opentelemetry.io/otel/metric v1.36.0 // indirect
-       go.opentelemetry.io/otel/sdk v1.36.0 // indirect
-       go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect
-       go.opentelemetry.io/otel/trace v1.36.0 // indirect
-       go.opentelemetry.io/proto/otlp v1.7.0 // indirect
        go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 // indirect
-       go.uber.org/atomic v1.11.0 // indirect
-       go.uber.org/multierr v1.11.0 // indirect
-       go.uber.org/zap v1.27.0 // indirect
        go.yaml.in/yaml/v2 v2.4.2 // indirect
        go.yaml.in/yaml/v3 v3.0.3 // indirect
        golang.org/x/mod v0.25.0 // indirect
@@ -261,21 +230,15 @@ require (
        gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
        gopkg.in/inf.v0 v0.9.1 // indirect
        gopkg.in/ini.v1 v1.67.0 // indirect
-       gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
        gopkg.in/warnings.v0 v0.1.2 // indirect
        gopkg.in/yaml.v2 v2.4.0 // indirect
-       istio.io/client-go v1.26.0-alpha.0.0.20250731213105-2f06e3d976fe // 
indirect
-       k8s.io/apiserver v0.33.2 // indirect
        k8s.io/cli-runtime v0.33.2 // indirect
        k8s.io/klog/v2 v2.130.1 // indirect
        k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
        k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 // indirect
-       sigs.k8s.io/gateway-api v1.3.0 // indirect
-       sigs.k8s.io/gateway-api-inference-extension v0.5.0 // indirect
        sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
        sigs.k8s.io/kustomize/api v0.19.0 // indirect
        sigs.k8s.io/kustomize/kyaml v0.19.0 // indirect
-       sigs.k8s.io/mcs-api v0.1.1-0.20240624222831-d7001fe1d21c // indirect
        sigs.k8s.io/randfill v1.0.0 // indirect
        sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
 )
diff --git a/go.sum b/go.sum
index 82d02396..70985dec 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,3 @@
-cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
-cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
 cloud.google.com/go v0.26.0/go.mod 
h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.114.0 h1:OIPFAdfrFDFO2ve2U7r/H5SwSbBzEdrBdE7xkgwc+kY=
 cloud.google.com/go v0.114.0/go.mod 
h1:ZV9La5YYxctro1HTPug5lXH/GefROyW8PPD4T8n9J8E=
@@ -89,8 +87,6 @@ github.com/andybalholm/cascadia v1.3.2 
h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsVi
 github.com/andybalholm/cascadia v1.3.2/go.mod 
h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be 
h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod 
h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
-github.com/antlr4-go/antlr/v4 v4.13.1 
h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
-github.com/antlr4-go/antlr/v4 v4.13.1/go.mod 
h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
 github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0=
 github.com/apex/log v1.9.0/go.mod 
h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA=
 github.com/apex/logs v1.0.0/go.mod 
h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
@@ -164,8 +160,6 @@ github.com/buildpacks/pack v0.30.0 
h1:1beK8QAp7By4K40QigYl9JG/Os4nA93dQxYR/GMMbT
 github.com/buildpacks/pack v0.30.0/go.mod 
h1:ZtkyUJKcTdWgEDFi0KOmtHQAOkeQeOeJ2wre1+0ipnA=
 github.com/cenkalti/backoff v2.2.1+incompatible 
h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
 github.com/cenkalti/backoff v2.2.1+incompatible/go.mod 
h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
-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/census-instrumentation/opencensus-proto v0.2.1/go.mod 
h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/certifi/gocertifi v0.0.0-20190105021004-abcd57078448/go.mod 
h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
 github.com/cespare/xxhash v1.1.0 
h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
@@ -188,8 +182,6 @@ github.com/chzyer/test v1.0.0/go.mod 
h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38
 github.com/client9/misspell v0.3.4/go.mod 
h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cloudflare/circl v1.3.7 
h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
 github.com/cloudflare/circl v1.3.7/go.mod 
h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
-github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 
h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls=
-github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod 
h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
 github.com/containerd/containerd v1.7.27 
h1:yFyEyojddO3MIGVER2xJLWoCIn+Up4GaHFquP7hsFII=
 github.com/containerd/containerd v1.7.27/go.mod 
h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0=
 github.com/containerd/continuity v0.4.5 
h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
@@ -213,8 +205,6 @@ github.com/davecgh/go-spew v1.1.0/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
 github.com/davecgh/go-spew v1.1.1/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc 
h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 
h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod 
h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
 github.com/dgraph-io/ristretto v0.0.1 
h1:cJwdnj42uV8Jg4+KLrYovLiCgIfz9wtWm6E6KA+1tLs=
 github.com/dgraph-io/ristretto v0.0.1/go.mod 
h1:T40EBc7CJke8TkpiYfGGKAeFjSaxuFXhuXRyumBd6RE=
 github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 
h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
@@ -249,13 +239,7 @@ github.com/emicklei/go-restful/v3 v3.12.2/go.mod 
h1:6n3XBCmQQb25CM2LCACGz8ukIrRr
 github.com/emirpasic/gods v1.18.1 
h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
 github.com/emirpasic/gods v1.18.1/go.mod 
h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
 github.com/envoyproxy/go-control-plane 
v0.9.1-0.20191026205805-5f8ba28d4473/go.mod 
h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane/contrib 
v1.32.5-0.20250627145903-197b96a9c7f8 
h1:KXgXPtBofHkRHr+8dO058dGZnLHapW7m0yJEgSYdAFA=
-github.com/envoyproxy/go-control-plane/contrib 
v1.32.5-0.20250627145903-197b96a9c7f8/go.mod 
h1:Nx/YcyEeIcgjT13QwKHdcPmS060urxZ835MeO8cLOrg=
-github.com/envoyproxy/go-control-plane/envoy 
v1.32.5-0.20250627145903-197b96a9c7f8 
h1:/F9jLyfDeNr4iZxyibtKlZxCDqCFEhoYiLdc9VOZT2E=
-github.com/envoyproxy/go-control-plane/envoy 
v1.32.5-0.20250627145903-197b96a9c7f8/go.mod 
h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod 
h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/envoyproxy/protoc-gen-validate v1.2.1 
h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
-github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod 
h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
 github.com/fatih/color v1.7.0/go.mod 
h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
 github.com/fatih/color v1.18.0/go.mod 
h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
@@ -292,7 +276,6 @@ github.com/go-git/go-git-fixtures/v4 
v4.3.2-0.20231010084843-55a94097c399/go.mod
 github.com/go-git/go-git/v5 v5.13.1 
h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M=
 github.com/go-git/go-git/v5 v5.13.1/go.mod 
h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc=
 github.com/go-logfmt/logfmt v0.4.0/go.mod 
h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
-github.com/go-logr/logr v1.2.2/go.mod 
h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
 github.com/go-logr/logr v1.4.3/go.mod 
h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
@@ -305,13 +288,10 @@ github.com/go-openapi/swag v0.23.1 
h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZ
 github.com/go-openapi/swag v0.23.1/go.mod 
h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
 github.com/go-sql-driver/mysql v1.7.1 
h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
 github.com/go-sql-driver/mysql v1.7.1/go.mod 
h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
-github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 
h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
 github.com/go-task/slim-sprig/v3 v3.0.0 
h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
 github.com/go-task/slim-sprig/v3 v3.0.0/go.mod 
h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
 github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
 github.com/gobwas/glob v0.2.3/go.mod 
h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
-github.com/goccy/go-json v0.10.5 
h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
-github.com/goccy/go-json v0.10.5/go.mod 
h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
 github.com/gofrs/uuid v3.2.0+incompatible/go.mod 
h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod 
h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -339,8 +319,6 @@ github.com/golang/protobuf v1.5.4 
h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
 github.com/golang/protobuf v1.5.4/go.mod 
h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
 github.com/google/btree v1.1.3/go.mod 
h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
-github.com/google/cel-go v0.25.0 
h1:jsFw9Fhn+3y2kBbltZR4VEz5xKkcIFRPDnuEzAGv5GY=
-github.com/google/cel-go v0.25.0/go.mod 
h1:hjEb6r5SuOSlhCHmFoLzu8HGCERvIsDAbxDAyNU/MmI=
 github.com/google/generative-ai-go v0.15.1 
h1:n8aQUpvhPOlGVuM2DRkJ2jvx04zpp42B778AROJa+pQ=
 github.com/google/generative-ai-go v0.15.1/go.mod 
h1:AAucpWZjXsDKhQYWvCYuP6d0yB1kX998pJlOW1rAesw=
 github.com/google/gnostic-models v0.6.9 
h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
@@ -360,8 +338,8 @@ github.com/google/go-containerregistry v0.20.3/go.mod 
h1:w00pIgBRDVUDFM6bq+Qx8lw
 github.com/google/go-querystring v1.1.0 
h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
 github.com/google/go-querystring v1.1.0/go.mod 
h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
 github.com/google/gofuzz v1.0.0/go.mod 
h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20250501235452-c0086092b71a 
h1:rDA3FfmxwXR+BVKKdz55WwMJ1pD2hJQNW31d+l3mPk4=
-github.com/google/pprof v0.0.0-20250501235452-c0086092b71a/go.mod 
h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
+github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 
h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
+github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod 
h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
 github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
 github.com/google/s2a-go v0.1.9/go.mod 
h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 
h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
@@ -380,13 +358,8 @@ github.com/gorilla/css v1.0.0 
h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
 github.com/gorilla/css v1.0.0/go.mod 
h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
 github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
 github.com/gorilla/mux v1.8.1/go.mod 
h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
-github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 
h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
-github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod 
h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
 github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 
h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
 github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod 
h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0 
h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 
h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod 
h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
 github.com/hashicorp/errwrap v1.0.0/go.mod 
h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
 github.com/hashicorp/errwrap v1.1.0 
h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
 github.com/hashicorp/errwrap v1.1.0/go.mod 
h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -437,23 +410,8 @@ github.com/kr/pty v1.1.1/go.mod 
h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod 
h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod 
h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/kylelemons/godebug v1.1.0 
h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
-github.com/kylelemons/godebug v1.1.0/go.mod 
h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
 github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 
h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
 github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod 
h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
-github.com/lestrrat-go/backoff/v2 v2.0.8 
h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A=
-github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod 
h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y=
-github.com/lestrrat-go/blackmagic v1.0.3 
h1:94HXkVLxkZO9vJI/w2u1T0DAoprShFd13xtnSINtDWs=
-github.com/lestrrat-go/blackmagic v1.0.3/go.mod 
h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw=
-github.com/lestrrat-go/httpcc v1.0.1 
h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
-github.com/lestrrat-go/httpcc v1.0.1/go.mod 
h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
-github.com/lestrrat-go/iter v1.0.2 
h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
-github.com/lestrrat-go/iter v1.0.2/go.mod 
h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
-github.com/lestrrat-go/jwx v1.2.31 
h1:/OM9oNl/fzyldpv5HKZ9m7bTywa7COUfg8gujd9nJ54=
-github.com/lestrrat-go/jwx v1.2.31/go.mod 
h1:eQJKoRwWcLg4PfD5CFA5gIZGxhPgoPYq9pZISdxLf0c=
-github.com/lestrrat-go/option v1.0.0/go.mod 
h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
-github.com/lestrrat-go/option v1.0.1 
h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
-github.com/lestrrat-go/option v1.0.1/go.mod 
h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
 github.com/lucasb-eyer/go-colorful v1.2.0 
h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod 
h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
 github.com/magiconair/properties v1.8.1/go.mod 
h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -494,8 +452,6 @@ github.com/moby/docker-image-spec v1.3.1 
h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N
 github.com/moby/docker-image-spec v1.3.1/go.mod 
h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
 github.com/moby/patternmatcher v0.6.0 
h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
 github.com/moby/patternmatcher v0.6.0/go.mod 
h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
-github.com/moby/spdystream v0.5.0 
h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
-github.com/moby/spdystream v0.5.0/go.mod 
h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
 github.com/moby/sys/capability v0.4.0 
h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk=
 github.com/moby/sys/capability v0.4.0/go.mod 
h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I=
 github.com/moby/sys/mountinfo v0.7.2 
h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
@@ -519,13 +475,10 @@ github.com/morikuni/aec v1.0.0 
h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
 github.com/morikuni/aec v1.0.0/go.mod 
h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
 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/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f 
h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
-github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod 
h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
 github.com/nikolalohinski/gonja v1.5.3 
h1:GsA+EEaZDZPGJ8JtpeGN78jidhOlxeJROpqMT9fTj9c=
 github.com/nikolalohinski/gonja v1.5.3/go.mod 
h1:RmjwxNiXAEqcq1HeK5SSMmqFJvKOfTfXhkJv6YBtPa4=
 github.com/onsi/ginkgo v1.6.0/go.mod 
h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.8.0/go.mod 
h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
 github.com/onsi/ginkgo/v2 v2.23.4 
h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
 github.com/onsi/ginkgo/v2 v2.23.4/go.mod 
h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
 github.com/onsi/gomega v1.5.0/go.mod 
h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -623,8 +576,6 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod 
h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0
 github.com/spf13/pflag v1.0.3/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
 github.com/spf13/pflag v1.0.6/go.mod 
h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/stoewer/go-strcase v1.3.0 
h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
-github.com/stoewer/go-strcase v1.3.0/go.mod 
h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
 github.com/stretchr/objx v0.1.0/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod 
h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@@ -638,7 +589,6 @@ github.com/stretchr/testify v1.6.1/go.mod 
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.0/go.mod 
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod 
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod 
h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1/go.mod 
h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/stretchr/testify v1.8.2/go.mod 
h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/stretchr/testify v1.10.0 
h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
 github.com/stretchr/testify v1.10.0/go.mod 
h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
@@ -694,16 +644,10 @@ go.opentelemetry.io/auto/sdk v1.1.0 
h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS
 go.opentelemetry.io/auto/sdk v1.1.0/go.mod 
h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc 
v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE=
 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc 
v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 
h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod 
h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 
h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod 
h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I=
 go.opentelemetry.io/otel v1.36.0 
h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
 go.opentelemetry.io/otel v1.36.0/go.mod 
h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 
h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod 
h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 
h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod 
h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
-go.opentelemetry.io/otel/exporters/prometheus v0.57.0 
h1:AHh/lAP1BHrY5gBwk8ncc25FXWm/gmmY3BX258z5nuk=
-go.opentelemetry.io/otel/exporters/prometheus v0.57.0/go.mod 
h1:QpFWz1QxqevfjwzYdbMb4Y1NnlJvqSGwyuU0B4iuc9c=
 go.opentelemetry.io/otel/metric v1.36.0 
h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
 go.opentelemetry.io/otel/metric v1.36.0/go.mod 
h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
 go.opentelemetry.io/otel/sdk v1.36.0 
h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
@@ -712,8 +656,6 @@ go.opentelemetry.io/otel/sdk/metric v1.36.0 
h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFw
 go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod 
h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
 go.opentelemetry.io/otel/trace v1.36.0 
h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
 go.opentelemetry.io/otel/trace v1.36.0/go.mod 
h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
-go.opentelemetry.io/proto/otlp v1.7.0 
h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
-go.opentelemetry.io/proto/otlp v1.7.0/go.mod 
h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
 go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 
h1:Ss6D3hLXTM0KobyBYEAygXzFfGcjnmfEJOBgSbemCtg=
 go.starlark.net v0.0.0-20230302034142-4b1e35fe2254/go.mod 
h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
 go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
@@ -722,10 +664,6 @@ go.uber.org/automaxprocs v1.6.0 
h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
 go.uber.org/automaxprocs v1.6.0/go.mod 
h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
 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.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
-go.uber.org/multierr v1.11.0/go.mod 
h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
-go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
-go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
 go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
 go.yaml.in/yaml/v2 v2.4.2/go.mod 
h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
 go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE=
@@ -881,8 +819,6 @@ gopkg.in/inf.v0 v0.9.1/go.mod 
h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
 gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
 gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/natefinch/lumberjack.v2 v2.2.1 
h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
-gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod 
h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod 
h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
 gopkg.in/warnings.v0 v0.1.2/go.mod 
h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
@@ -904,24 +840,16 @@ honnef.co/go/tools 
v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 istio.io/api v1.26.3 h1:/TiA7bJi24yBQSgpLy5vHhFkobf4DWS1L+CuUxNk4os=
 istio.io/api v1.26.3/go.mod h1:DTVGH6CLXj5W8FF9JUD3Tis78iRgT1WeuAnxfTz21Wg=
-istio.io/client-go v1.26.0-alpha.0.0.20250731213105-2f06e3d976fe 
h1:A3m5j1PRh1J/Y1YkDHP7wqaaIoxdK0NuFFNewwEqNHQ=
-istio.io/client-go v1.26.0-alpha.0.0.20250731213105-2f06e3d976fe/go.mod 
h1:QE8FEo9JtZNOrXjzYTsKq8kzb9f3xt/Mkp0XXUvg5Hc=
-istio.io/istio v0.0.0-20250801115405-9aa2567b5daf 
h1:nAxrB4KVuux87MkeVn2wYtXDdgTNQdmRsg7qlSk/lvE=
-istio.io/istio v0.0.0-20250801115405-9aa2567b5daf/go.mod 
h1:n2Rl5PCQ3uQOAFYZqeXTA4z/oVvc1Fj1VfkBs+qRS2Q=
 k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
 k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
 k8s.io/apiextensions-apiserver v0.33.2 
h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8=
 k8s.io/apiextensions-apiserver v0.33.2/go.mod 
h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8=
 k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
 k8s.io/apimachinery v0.33.2/go.mod 
h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
-k8s.io/apiserver v0.33.2 h1:KGTRbxn2wJagJowo29kKBp4TchpO1DRO3g+dB/KOJN4=
-k8s.io/apiserver v0.33.2/go.mod h1:9qday04wEAMLPWWo9AwqCZSiIn3OYSZacDyu/AcoM/M=
 k8s.io/cli-runtime v0.33.2 h1:koNYQKSDdq5AExa/RDudXMhhtFasEg48KLS2KSAU74Y=
 k8s.io/cli-runtime v0.33.2/go.mod 
h1:gnhsAWpovqf1Zj5YRRBBU7PFsRc6NkEkwYNQE+mXL88=
 k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
 k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
-k8s.io/component-base v0.33.2 h1:sCCsn9s/dG3ZrQTX/Us0/Sx2R0G5kwa0wbZFYoVp/+0=
-k8s.io/component-base v0.33.2/go.mod 
h1:/41uw9wKzuelhN+u+/C59ixxf4tYQKW7p32ddkYNe2k=
 k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
 k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
 k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff 
h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
@@ -932,20 +860,12 @@ k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 
h1:jgJW5IePPXLGB8e/1wvd0Ich9QE97
 k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979/go.mod 
h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
 nhooyr.io/websocket v1.8.7/go.mod 
h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.1 
h1:Cf+ed5N8038zbsaXFO7mKQDi/+VcSRafb0jM84KX5so=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.1/go.mod 
h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
-sigs.k8s.io/gateway-api v1.3.0 h1:q6okN+/UKDATola4JY7zXzx40WO4VISk7i9DIfOvr9M=
-sigs.k8s.io/gateway-api v1.3.0/go.mod 
h1:d8NV8nJbaRbEKem+5IuxkL8gJGOZ+FJ+NvOIltV8gDk=
-sigs.k8s.io/gateway-api-inference-extension v0.5.0 
h1:bYtXffUF1WUUFT2gYXaQBXIEXxXq/ZZLP9gqQweTrBI=
-sigs.k8s.io/gateway-api-inference-extension v0.5.0/go.mod 
h1:lki0jx1qysZSZT4Ai2BxuAcpx6G8g5oBgOGuuJzjy/k=
 sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 
h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
 sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod 
h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
 sigs.k8s.io/kustomize/api v0.19.0 
h1:F+2HB2mU1MSiR9Hp1NEgoU2q9ItNOaBJl0I4Dlus5SQ=
 sigs.k8s.io/kustomize/api v0.19.0/go.mod 
h1:/BbwnivGVcBh1r+8m3tH1VNxJmHSk1PzP5fkP6lbL1o=
 sigs.k8s.io/kustomize/kyaml v0.19.0 
h1:RFge5qsO1uHhwJsu3ipV7RNolC7Uozc0jUBC/61XSlA=
 sigs.k8s.io/kustomize/kyaml v0.19.0/go.mod 
h1:FeKD5jEOH+FbZPpqUghBP8mrLjJ3+zD3/rf9NNu1cwY=
-sigs.k8s.io/mcs-api v0.1.1-0.20240624222831-d7001fe1d21c 
h1:F7hIEutAxtXDOQX9NXFdvhWmWETu2zmUPHuPPcAez7g=
-sigs.k8s.io/mcs-api v0.1.1-0.20240624222831-d7001fe1d21c/go.mod 
h1:DPFniRsBzCeLB4ANjlPEvQQt9QGIX489d1faK+GPvI4=
 sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod 
h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
 sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
 sigs.k8s.io/randfill v1.0.0/go.mod 
h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
diff --git a/navigator/pkg/bootstrap/mesh.go b/navigator/pkg/bootstrap/mesh.go
index 224f79ec..ffe293c7 100644
--- a/navigator/pkg/bootstrap/mesh.go
+++ b/navigator/pkg/bootstrap/mesh.go
@@ -61,9 +61,9 @@ func (s *Server) getConfigurationSources(args *NaviArgs, 
fileWatcher filewatcher
        if s.kubeClient == nil {
                return nil
        }
-       // configMapName := getMeshConfigMapName("")
-       // primary := kubemesh.NewConfigMapSource(s.kubeClient, args.Namespace, 
configMapName, cmKey, opts)
-       return nil
+       configMapName := getMeshConfigMapName("")
+       primary := kubemesh.NewConfigMapSource(s.kubeClient, args.Namespace, 
configMapName, cmKey, opts)
+       return toSources(primary, userMeshConfig)
 }
 
 func toSources(base meshwatcher.MeshConfigSource, user 
*meshwatcher.MeshConfigSource) []meshwatcher.MeshConfigSource {
diff --git a/navigator/pkg/features/navigator.go 
b/navigator/pkg/features/navigator.go
index 7b2d29ac..6db8bf75 100644
--- a/navigator/pkg/features/navigator.go
+++ b/navigator/pkg/features/navigator.go
@@ -31,6 +31,9 @@ var (
                "If enabled, addition runtime asserts will be performed. "+
                        "These checks are both expensive and panic on failure. 
As a result, this should be used only for testing.",
        ).Get()
+       InformerWatchNamespace = env.Register("DUBBO_WATCH_NAMESPACE", "",
+               "If set, limit Kubernetes watches to a single namespace. "+
+                       "Warning: only a single namespace can be set.").Get()
        ClusterName = env.Register("CLUSTER_ID", constants.DefaultClusterName,
                "Defines the cluster and service registry that this Dubbod 
instance belongs to").Get()
 )
diff --git a/pkg/config/mesh/kubemesh/watcher.go 
b/pkg/config/mesh/kubemesh/watcher.go
index f6713668..18ef0db6 100644
--- a/pkg/config/mesh/kubemesh/watcher.go
+++ b/pkg/config/mesh/kubemesh/watcher.go
@@ -18,10 +18,16 @@
 package kubemesh
 
 import (
+       "fmt"
        "github.com/apache/dubbo-kubernetes/pkg/kube"
+       "github.com/apache/dubbo-kubernetes/pkg/kube/kclient"
        "github.com/apache/dubbo-kubernetes/pkg/kube/krt"
        "github.com/apache/dubbo-kubernetes/pkg/mesh/meshwatcher"
+       "github.com/apache/dubbo-kubernetes/pkg/ptr"
        v1 "k8s.io/api/core/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/fields"
+       "k8s.io/apimachinery/pkg/types"
 )
 
 const (
@@ -29,8 +35,19 @@ const (
        MeshNetworksKey = "meshNetworks"
 )
 
-func NewConfigMapSource(client kube.Client, namespace, name, key string, opts 
krt.OptionsBuilder) meshwatcher.MeshConfigResource {
-       return meshwatcher.MeshConfigResource{}
+// NewConfigMapSource builds a MeshConfigSource reading from ConfigMap "name" 
with key "key".
+func NewConfigMapSource(client kube.Client, namespace, name, key string, opts 
krt.OptionsBuilder) meshwatcher.MeshConfigSource {
+       clt := kclient.NewFiltered[*v1.ConfigMap](client, kclient.Filter{
+               Namespace:     namespace,
+               FieldSelector: 
fields.OneTermEqualSelector(metav1.ObjectNameField, name).String(),
+       })
+       cms := krt.WrapClient(clt, opts.WithName("ConfigMap_"+name)...)
+       clt.Start(opts.Stop())
+       cmKey := types.NamespacedName{Namespace: namespace, Name: name}.String()
+       return krt.NewSingleton(func(ctx krt.HandlerContext) *string {
+               cm := ptr.Flatten(krt.FetchOne(ctx, cms, krt.FilterKey(cmKey)))
+               return meshConfigMapData(cm, key)
+       }, opts.WithName(fmt.Sprintf("ConfigMap_%s_%s", name, key))...)
 }
 
 func meshConfigMapData(cm *v1.ConfigMap, key string) *string {
diff --git a/pkg/config/schema/gvr/resource.gen.go 
b/pkg/config/schema/gvr/resource.gen.go
index f5f1bbaf..beb02e96 100644
--- a/pkg/config/schema/gvr/resource.gen.go
+++ b/pkg/config/schema/gvr/resource.gen.go
@@ -18,3 +18,9 @@ var (
        Service                        = schema.GroupVersionResource{Group: "", 
Version: "v1", Resource: "services"}
        ServiceAccount                 = schema.GroupVersionResource{Group: "", 
Version: "v1", Resource: "serviceaccounts"}
 )
+
+func IsClusterScoped(g schema.GroupVersionResource) bool {
+       switch g {
+       }
+       return false
+}
diff --git a/pkg/config/schema/kubeclient/common.go 
b/pkg/config/schema/kubeclient/common.go
new file mode 100644
index 00000000..5fbd1b4d
--- /dev/null
+++ b/pkg/config/schema/kubeclient/common.go
@@ -0,0 +1,187 @@
+package kubeclient
+
+import (
+       "context"
+       "fmt"
+       "github.com/apache/dubbo-kubernetes/pkg/config/schema/kubetypes"
+       "github.com/apache/dubbo-kubernetes/pkg/kube/informerfactory"
+       ktypes "github.com/apache/dubbo-kubernetes/pkg/kube/kubetypes"
+       "github.com/apache/dubbo-kubernetes/pkg/typemap"
+       kubeext "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/runtime/schema"
+       "k8s.io/apimachinery/pkg/watch"
+       "k8s.io/client-go/dynamic"
+       "k8s.io/client-go/kubernetes"
+       "k8s.io/client-go/metadata"
+       "k8s.io/client-go/tools/cache"
+)
+
+type ClientGetter interface {
+       // Ext returns the API extensions client.
+       Ext() kubeext.Interface
+
+       // Kube returns the core kube client
+       Kube() kubernetes.Interface
+
+       // Dynamic client.
+       Dynamic() dynamic.Interface
+
+       // Metadata returns the Metadata kube client.
+       Metadata() metadata.Interface
+
+       // Informers returns an informer factory.
+       Informers() informerfactory.InformerFactory
+}
+
+type TypeRegistration[T runtime.Object] interface {
+       kubetypes.RegisterType[T]
+
+       // ListWatchFunc provides the necessary methods for list and
+       // watch for the informer
+       ListWatch(c ClientGetter, opts ktypes.InformerOptions) 
cache.ListerWatcher
+}
+
+var registerTypes = typemap.NewTypeMap()
+
+func GetInformerFiltered[T runtime.Object](
+       c ClientGetter,
+       opts ktypes.InformerOptions,
+       gvr schema.GroupVersionResource,
+) informerfactory.StartableInformer {
+       reg := typemap.Get[TypeRegistration[T]](registerTypes)
+       if reg != nil {
+               // This is registered type
+               tr := *reg
+               return c.Informers().InformerFor(tr.GetGVR(), opts, func() 
cache.SharedIndexInformer {
+                       inf := cache.NewSharedIndexInformer(
+                               tr.ListWatch(c, opts),
+                               tr.Object(),
+                               0,
+                               cache.Indexers{cache.NamespaceIndex: 
cache.MetaNamespaceIndexFunc},
+                       )
+                       setupInformer(opts, inf)
+                       return inf
+               })
+       }
+       return GetInformerFilteredFromGVR(c, opts, gvr)
+}
+
+func setupInformer(opts ktypes.InformerOptions, inf cache.SharedIndexInformer) 
{
+       if opts.ObjectTransform != nil {
+               _ = inf.SetTransform(opts.ObjectTransform)
+       } else {
+               _ = inf.SetTransform(stripUnusedFields)
+       }
+}
+
+func GetInformerFilteredFromGVR(c ClientGetter, opts ktypes.InformerOptions, g 
schema.GroupVersionResource) informerfactory.StartableInformer {
+       switch opts.InformerType {
+       case ktypes.DynamicInformer:
+               return getInformerFilteredDynamic(c, opts, g)
+       case ktypes.MetadataInformer:
+               return getInformerFilteredMetadata(c, opts, g)
+       default:
+               return getInformerFiltered(c, opts, g)
+       }
+}
+
+func getInformerFilteredDynamic(c ClientGetter, opts ktypes.InformerOptions, g 
schema.GroupVersionResource) informerfactory.StartableInformer {
+       return c.Informers().InformerFor(g, opts, func() 
cache.SharedIndexInformer {
+               inf := cache.NewSharedIndexInformerWithOptions(
+                       &cache.ListWatch{
+                               ListFunc: func(options metav1.ListOptions) 
(runtime.Object, error) {
+                                       options.FieldSelector = 
opts.FieldSelector
+                                       options.LabelSelector = 
opts.LabelSelector
+                                       return 
c.Dynamic().Resource(g).Namespace(opts.Namespace).List(context.Background(), 
options)
+                               },
+                               WatchFunc: func(options metav1.ListOptions) 
(watch.Interface, error) {
+                                       options.FieldSelector = 
opts.FieldSelector
+                                       options.LabelSelector = 
opts.LabelSelector
+                                       return 
c.Dynamic().Resource(g).Namespace(opts.Namespace).Watch(context.Background(), 
options)
+                               },
+                       },
+                       &unstructured.Unstructured{},
+                       cache.SharedIndexInformerOptions{
+                               ResyncPeriod:      0,
+                               Indexers:          
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
+                               ObjectDescription: g.String(),
+                       },
+               )
+               setupInformer(opts, inf)
+               return inf
+       })
+}
+
+func getInformerFilteredMetadata(c ClientGetter, opts ktypes.InformerOptions, 
g schema.GroupVersionResource) informerfactory.StartableInformer {
+       return c.Informers().InformerFor(g, opts, func() 
cache.SharedIndexInformer {
+               inf := cache.NewSharedIndexInformerWithOptions(
+                       &cache.ListWatch{
+                               ListFunc: func(options metav1.ListOptions) 
(runtime.Object, error) {
+                                       options.FieldSelector = 
opts.FieldSelector
+                                       options.LabelSelector = 
opts.LabelSelector
+                                       return 
c.Metadata().Resource(g).Namespace(opts.Namespace).List(context.Background(), 
options)
+                               },
+                               WatchFunc: func(options metav1.ListOptions) 
(watch.Interface, error) {
+                                       options.FieldSelector = 
opts.FieldSelector
+                                       options.LabelSelector = 
opts.LabelSelector
+                                       return 
c.Metadata().Resource(g).Namespace(opts.Namespace).Watch(context.Background(), 
options)
+                               },
+                       },
+                       &metav1.PartialObjectMetadata{},
+                       cache.SharedIndexInformerOptions{
+                               ResyncPeriod:      0,
+                               Indexers:          
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
+                               ObjectDescription: g.String(),
+                       },
+               )
+               setupInformer(opts, inf)
+               return inf
+       })
+}
+
+func stripUnusedFields(obj any) (any, error) {
+       t, ok := obj.(metav1.ObjectMetaAccessor)
+       if !ok {
+               // shouldn't happen
+               return obj, nil
+       }
+       // ManagedFields is large and we never use it
+       t.GetObjectMeta().SetManagedFields(nil)
+       return obj, nil
+}
+
+func getInformerFiltered(c ClientGetter, opts ktypes.InformerOptions, g 
schema.GroupVersionResource) informerfactory.StartableInformer {
+       var l func(options metav1.ListOptions) (runtime.Object, error)
+       var w func(options metav1.ListOptions) (watch.Interface, error)
+       return c.Informers().InformerFor(g, opts, func() 
cache.SharedIndexInformer {
+               inf := cache.NewSharedIndexInformer(
+                       &cache.ListWatch{
+                               ListFunc: func(options metav1.ListOptions) 
(runtime.Object, error) {
+                                       options.FieldSelector = 
opts.FieldSelector
+                                       options.LabelSelector = 
opts.LabelSelector
+                                       return l(options)
+                               },
+                               WatchFunc: func(options metav1.ListOptions) 
(watch.Interface, error) {
+                                       options.FieldSelector = 
opts.FieldSelector
+                                       options.LabelSelector = 
opts.LabelSelector
+                                       return w(options)
+                               },
+                       },
+                       gvrToObject(g),
+                       0,
+                       cache.Indexers{cache.NamespaceIndex: 
cache.MetaNamespaceIndexFunc},
+               )
+               setupInformer(opts, inf)
+               return inf
+       })
+}
+
+func gvrToObject(g schema.GroupVersionResource) runtime.Object {
+       switch g {
+       default:
+               panic(fmt.Sprintf("Unknown type %v", g))
+       }
+}
diff --git a/pkg/config/schema/kubeclient/resource.gen.go 
b/pkg/config/schema/kubeclient/resource.gen.go
new file mode 100644
index 00000000..b44b608e
--- /dev/null
+++ b/pkg/config/schema/kubeclient/resource.gen.go
@@ -0,0 +1,15 @@
+package kubeclient
+
+import (
+       "fmt"
+       ktypes "github.com/apache/dubbo-kubernetes/pkg/kube/kubetypes"
+       "github.com/apache/dubbo-kubernetes/pkg/ptr"
+       "k8s.io/apimachinery/pkg/runtime"
+)
+
+func GetWriteClient[T runtime.Object](c ClientGetter, namespace string) 
ktypes.WriteAPI[T] {
+       switch any(ptr.Empty[T]()).(type) {
+       default:
+               panic(fmt.Sprintf("Unknown type %T", ptr.Empty[T]()))
+       }
+}
diff --git a/pkg/config/schema/kubetypes/common.go 
b/pkg/config/schema/kubetypes/common.go
new file mode 100644
index 00000000..5864cc47
--- /dev/null
+++ b/pkg/config/schema/kubetypes/common.go
@@ -0,0 +1,38 @@
+package kubetypes
+
+import (
+       "github.com/apache/dubbo-kubernetes/operator/pkg/config"
+       "github.com/apache/dubbo-kubernetes/pkg/config/schema/gvk"
+       "github.com/apache/dubbo-kubernetes/pkg/ptr"
+       "github.com/apache/dubbo-kubernetes/pkg/typemap"
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+func MustGVKFromType[T runtime.Object]() (cfg config.GroupVersionKind) {
+       if gvk, ok := getGvk(ptr.Empty[T]()); ok {
+               return gvk
+       }
+       if rp := typemap.Get[RegisterType[T]](registeredTypes); rp != nil {
+               return (*rp).GetGVK()
+       }
+       panic("unknown kind: " + cfg.String())
+}
+
+func MustToGVR[T runtime.Object](cfg config.GroupVersionKind) 
schema.GroupVersionResource {
+       if r, ok := gvk.ToGVR(cfg); ok {
+               return r
+       }
+       if rp := typemap.Get[RegisterType[T]](registeredTypes); rp != nil {
+               return (*rp).GetGVR()
+       }
+       panic("unknown kind: " + cfg.String())
+}
+
+var registeredTypes = typemap.NewTypeMap()
+
+type RegisterType[T runtime.Object] interface {
+       GetGVK() config.GroupVersionKind
+       GetGVR() schema.GroupVersionResource
+       Object() T
+}
diff --git a/pkg/config/schema/kubetypes/resources.gen.go 
b/pkg/config/schema/kubetypes/resources.gen.go
new file mode 100644
index 00000000..7458225d
--- /dev/null
+++ b/pkg/config/schema/kubetypes/resources.gen.go
@@ -0,0 +1,12 @@
+package kubetypes
+
+import (
+       "github.com/apache/dubbo-kubernetes/operator/pkg/config"
+)
+
+func getGvk(obj any) (config.GroupVersionKind, bool) {
+       switch obj.(type) {
+       default:
+               return config.GroupVersionKind{}, false
+       }
+}
diff --git a/pkg/kube/client.go b/pkg/kube/client.go
index b49a8c97..82babef7 100644
--- a/pkg/kube/client.go
+++ b/pkg/kube/client.go
@@ -20,14 +20,19 @@ package kube
 import (
        "fmt"
        "github.com/apache/dubbo-kubernetes/operator/pkg/config"
+       "github.com/apache/dubbo-kubernetes/pkg/cluster"
        "github.com/apache/dubbo-kubernetes/pkg/kube/collections"
        "github.com/apache/dubbo-kubernetes/pkg/kube/informerfactory"
        "github.com/apache/dubbo-kubernetes/pkg/lazy"
+       "github.com/apache/dubbo-kubernetes/pkg/sleep"
        kubeExtClient 
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
        "k8s.io/apimachinery/pkg/api/meta"
        "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
        "k8s.io/apimachinery/pkg/runtime/schema"
        kubeVersion "k8s.io/apimachinery/pkg/version"
+       "k8s.io/client-go/metadata"
+       "k8s.io/client-go/tools/cache"
+
        // "k8s.io/client-go/discovery"
        "k8s.io/client-go/dynamic"
        "k8s.io/client-go/kubernetes"
@@ -47,15 +52,23 @@ type client struct {
        dynamic         dynamic.Interface
        kube            kubernetes.Interface
        mapper          meta.ResettableRESTMapper
+       metadata        metadata.Interface
        http            *http.Client
+       clusterID       cluster.ID
 }
 
 type Client interface {
-       // Ext returns the API extensions client.
        Ext() kubeExtClient.Interface
 
-       // Kube returns the core kube client
        Kube() kubernetes.Interface
+
+       ClusterID() cluster.ID
+
+       Dynamic() dynamic.Interface
+
+       Metadata() metadata.Interface
+
+       Informers() informerfactory.InformerFactory
 }
 
 type CLIClient interface {
@@ -135,6 +148,22 @@ func (c *client) Kube() kubernetes.Interface {
        return c.kube
 }
 
+func (c *client) ClusterID() cluster.ID {
+       return c.clusterID
+}
+
+func (c *client) Dynamic() dynamic.Interface {
+       return c.dynamic
+}
+
+func (c *client) Metadata() metadata.Interface {
+       return c.metadata
+}
+
+func (c *client) Informers() informerfactory.InformerFactory {
+       return c.informerFactory
+}
+
 func (c *client) DynamicClientFor(gvk schema.GroupVersionKind, obj 
*unstructured.Unstructured, namespace string) (dynamic.ResourceInterface, 
error) {
        gvr, namespaced := c.bestEffortToGVR(gvk, obj, namespace)
        var dr dynamic.ResourceInterface
@@ -179,3 +208,52 @@ func WithRevision(revision string) ClientOption {
                return client
        }
 }
+
+func WithCluster(id cluster.ID) ClientOption {
+       return func(c CLIClient) CLIClient {
+               client := c.(*client)
+               client.clusterID = id
+               return client
+       }
+}
+
+func WaitForCacheSync(name string, stop <-chan struct{}, cacheSyncs 
...cache.InformerSynced) (r bool) {
+       _ = time.Now()
+       maximum := time.Millisecond * 100
+       delay := time.Millisecond
+       f := func() bool {
+               for _, syncFunc := range cacheSyncs {
+                       if !syncFunc() {
+                               return false
+                       }
+               }
+               return true
+       }
+       attempt := 0
+       defer func() {
+               if r {
+               } else {
+               }
+       }()
+       for {
+               select {
+               case <-stop:
+                       return false
+               default:
+               }
+               attempt++
+               res := f()
+               if res {
+                       return true
+               }
+               delay *= 2
+               if delay > maximum {
+                       delay = maximum
+               }
+               if attempt%50 == 0 {
+               }
+               if !sleep.Until(stop, delay) {
+                       return false
+               }
+       }
+}
diff --git a/pkg/kube/controllers/common.go b/pkg/kube/controllers/common.go
index dc460a41..c9f23028 100644
--- a/pkg/kube/controllers/common.go
+++ b/pkg/kube/controllers/common.go
@@ -1,5 +1,10 @@
 package controllers
 
+import (
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/runtime"
+)
+
 type EventType int
 
 const (
@@ -27,3 +32,13 @@ func (event EventType) String() string {
        }
        return out
 }
+
+type ComparableObject interface {
+       comparable
+       Object
+}
+
+type Object interface {
+       metav1.Object
+       runtime.Object
+}
diff --git a/pkg/kube/kclient/client.go b/pkg/kube/kclient/client.go
new file mode 100644
index 00000000..64429208
--- /dev/null
+++ b/pkg/kube/kclient/client.go
@@ -0,0 +1,209 @@
+package kclient
+
+import (
+       "context"
+       "fmt"
+       "github.com/apache/dubbo-kubernetes/navigator/pkg/features"
+       dubbogvr "github.com/apache/dubbo-kubernetes/pkg/config/schema/gvr"
+       "github.com/apache/dubbo-kubernetes/pkg/config/schema/kubeclient"
+       types "github.com/apache/dubbo-kubernetes/pkg/config/schema/kubetypes"
+       "github.com/apache/dubbo-kubernetes/pkg/kube"
+       "github.com/apache/dubbo-kubernetes/pkg/kube/controllers"
+       "github.com/apache/dubbo-kubernetes/pkg/kube/informerfactory"
+       "github.com/apache/dubbo-kubernetes/pkg/kube/kubetypes"
+       "github.com/apache/dubbo-kubernetes/pkg/ptr"
+       "github.com/apache/dubbo-kubernetes/pkg/util/sets"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       klabels "k8s.io/apimachinery/pkg/labels"
+       "k8s.io/apimachinery/pkg/runtime/schema"
+       apitypes "k8s.io/apimachinery/pkg/types"
+       "k8s.io/client-go/tools/cache"
+       "sync"
+)
+
+type fullClient[T controllers.Object] struct {
+       writeClient[T]
+       Informer[T]
+}
+
+type writeClient[T controllers.Object] struct {
+       client kube.Client
+}
+
+func NewFiltered[T controllers.ComparableObject](c kube.Client, filter Filter) 
Client[T] {
+       gvr := types.MustToGVR[T](types.MustGVKFromType[T]())
+       inf := kubeclient.GetInformerFiltered[T](c, ToOpts(c, gvr, filter), gvr)
+       return &fullClient[T]{
+               writeClient: writeClient[T]{client: c},
+               Informer:    newInformerClient[T](gvr, inf, filter),
+       }
+}
+
+type Filter = kubetypes.Filter
+
+func ToOpts(c kube.Client, gvr schema.GroupVersionResource, filter Filter) 
kubetypes.InformerOptions {
+       ns := filter.Namespace
+       if !dubbogvr.IsClusterScoped(gvr) && ns == "" {
+               ns = features.InformerWatchNamespace
+       }
+       return kubetypes.InformerOptions{
+               LabelSelector:   filter.LabelSelector,
+               FieldSelector:   filter.FieldSelector,
+               Namespace:       ns,
+               ObjectTransform: filter.ObjectTransform,
+               Cluster:         c.ClusterID(),
+       }
+}
+
+type handlerRegistration struct {
+       registration cache.ResourceEventHandlerRegistration
+       // handler is the actual handler. Note this does NOT have the filtering 
applied.
+       handler cache.ResourceEventHandler
+}
+
+type informerClient[T controllers.Object] struct {
+       informer      cache.SharedIndexInformer
+       startInformer func(stopCh <-chan struct{})
+       filter        func(t any) bool
+
+       handlerMu          sync.RWMutex
+       registeredHandlers []handlerRegistration
+}
+
+func newInformerClient[T controllers.ComparableObject](
+       gvr schema.GroupVersionResource,
+       inf informerfactory.StartableInformer,
+       filter Filter,
+) Informer[T] {
+       ic := &informerClient[T]{
+               informer:      inf.Informer,
+               startInformer: inf.Start,
+       }
+       if filter.ObjectFilter != nil {
+               applyDynamicFilter(filter, gvr, ic)
+       }
+       return ic
+}
+
+func applyDynamicFilter[T controllers.ComparableObject](filter Filter, gvr 
schema.GroupVersionResource, ic *informerClient[T]) {
+       if filter.ObjectFilter != nil {
+               ic.filter = filter.ObjectFilter.Filter
+               filter.ObjectFilter.AddHandler(func(added, removed sets.String) 
{
+                       ic.handlerMu.RLock()
+                       defer ic.handlerMu.RUnlock()
+                       if gvr == dubbogvr.Namespace {
+                               for _, item := range 
ic.ListUnfiltered(metav1.NamespaceAll, klabels.Everything()) {
+                                       if !added.Contains(item.GetName()) {
+                                               continue
+                                       }
+                                       for _, c := range ic.registeredHandlers 
{
+                                               c.handler.OnAdd(item, false)
+                                       }
+                               }
+                       } else {
+                               for ns := range added {
+                                       for _, item := range 
ic.ListUnfiltered(ns, klabels.Everything()) {
+                                               for _, c := range 
ic.registeredHandlers {
+                                                       c.handler.OnAdd(item, 
false)
+                                               }
+                                       }
+                               }
+                               for ns := range removed {
+                                       for _, item := range 
ic.ListUnfiltered(ns, klabels.Everything()) {
+                                               for _, c := range 
ic.registeredHandlers {
+                                                       c.handler.OnDelete(item)
+                                               }
+                                       }
+                               }
+                       }
+               })
+       }
+}
+
+func (n *informerClient[T]) ListUnfiltered(namespace string, selector 
klabels.Selector) []T {
+       var res []T
+       err := cache.ListAllByNamespace(n.informer.GetIndexer(), namespace, 
selector, func(i any) {
+               cast := i.(T)
+               res = append(res, cast)
+       })
+
+       // Should never happen
+       if err != nil && features.EnableUnsafeAssertions {
+               fmt.Printf("lister returned err for %v: %v", namespace, err)
+       }
+       return res
+}
+
+func (n *informerClient[T]) Start(stopCh <-chan struct{}) {
+       n.startInformer(stopCh)
+}
+
+func (n *informerClient[T]) Get(name, namespace string) T {
+       obj, exists, err := n.informer.GetIndexer().GetByKey(keyFunc(name, 
namespace))
+       if err != nil {
+               return ptr.Empty[T]()
+       }
+       if !exists {
+               return ptr.Empty[T]()
+       }
+       cast := obj.(T)
+       if !n.applyFilter(cast) {
+               return ptr.Empty[T]()
+       }
+       return cast
+}
+
+func keyFunc(name, namespace string) string {
+       if len(namespace) == 0 {
+               return name
+       }
+       return namespace + "/" + name
+}
+
+func (n *informerClient[T]) applyFilter(t T) bool {
+       if n.filter == nil {
+               return true
+       }
+       return n.filter(t)
+}
+
+func (n *writeClient[T]) Create(object T) (T, error) {
+       api := kubeclient.GetWriteClient[T](n.client, object.GetNamespace())
+       return api.Create(context.Background(), object, metav1.CreateOptions{})
+}
+
+func (n *writeClient[T]) Update(object T) (T, error) {
+       api := kubeclient.GetWriteClient[T](n.client, object.GetNamespace())
+       return api.Update(context.Background(), object, metav1.UpdateOptions{})
+}
+
+func (n *writeClient[T]) Patch(name, namespace string, pt apitypes.PatchType, 
data []byte) (T, error) {
+       api := kubeclient.GetWriteClient[T](n.client, namespace)
+       return api.Patch(context.Background(), name, pt, data, 
metav1.PatchOptions{})
+}
+
+func (n *writeClient[T]) PatchStatus(name, namespace string, pt 
apitypes.PatchType, data []byte) (T, error) {
+       api := kubeclient.GetWriteClient[T](n.client, namespace)
+       return api.Patch(context.Background(), name, pt, data, 
metav1.PatchOptions{}, "status")
+}
+
+func (n *writeClient[T]) ApplyStatus(name, namespace string, pt 
apitypes.PatchType, data []byte, fieldManager string) (T, error) {
+       api := kubeclient.GetWriteClient[T](n.client, namespace)
+       return api.Patch(context.Background(), name, pt, data, 
metav1.PatchOptions{
+               Force:        ptr.Of(true),
+               FieldManager: fieldManager,
+       }, "status")
+}
+
+func (n *writeClient[T]) UpdateStatus(object T) (T, error) {
+       api, ok := kubeclient.GetWriteClient[T](n.client, 
object.GetNamespace()).(kubetypes.WriteStatusAPI[T])
+       if !ok {
+               return ptr.Empty[T](), fmt.Errorf("%T does not support 
UpdateStatus", object)
+       }
+       return api.UpdateStatus(context.Background(), object, 
metav1.UpdateOptions{})
+}
+
+func (n *writeClient[T]) Delete(name, namespace string) error {
+       api := kubeclient.GetWriteClient[T](n.client, namespace)
+       return api.Delete(context.Background(), name, metav1.DeleteOptions{})
+}
diff --git a/pkg/kube/kclient/interfaces.go b/pkg/kube/kclient/interfaces.go
new file mode 100644
index 00000000..819f002f
--- /dev/null
+++ b/pkg/kube/kclient/interfaces.go
@@ -0,0 +1,43 @@
+package kclient
+
+import (
+       "github.com/apache/dubbo-kubernetes/pkg/kube/controllers"
+       klabels "k8s.io/apimachinery/pkg/labels"
+       apitypes "k8s.io/apimachinery/pkg/types"
+)
+
+type Reader[T controllers.Object] interface {
+       // Get looks up an object by name and namespace. If it does not exist, 
nil is returned
+       Get(name, namespace string) T
+       // List looks up an object by namespace and labels.
+       // Use metav1.NamespaceAll and klabels.Everything() to select 
everything.
+       List(namespace string, selector klabels.Selector) []T
+}
+
+type Writer[T controllers.Object] interface {
+       // Create creates a resource, returning the newly applied resource.
+       Create(object T) (T, error)
+       // Update updates a resource, returning the newly applied resource.
+       Update(object T) (T, error)
+       // UpdateStatus updates a resource's status, returning the newly 
applied resource.
+       UpdateStatus(object T) (T, error)
+       // Patch patches the resource, returning the newly applied resource.
+       Patch(name, namespace string, pt apitypes.PatchType, data []byte) (T, 
error)
+       // PatchStatus patches the resource's status, returning the newly 
applied resource.
+       PatchStatus(name, namespace string, pt apitypes.PatchType, data []byte) 
(T, error)
+       // ApplyStatus does a server-side Apply of the the resource's status, 
returning the newly applied resource.
+       // fieldManager is a required field; see 
https://kubernetes.io/docs/reference/using-api/server-side-apply/#managers.
+       ApplyStatus(name, namespace string, pt apitypes.PatchType, data []byte, 
fieldManager string) (T, error)
+       // Delete removes a resource.
+       Delete(name, namespace string) error
+}
+
+type Informer[T controllers.Object] interface {
+       Start(stop <-chan struct{})
+}
+
+type Client[T controllers.Object] interface {
+       Reader[T]
+       Writer[T]
+       Informer[T]
+}
diff --git a/pkg/kube/krt/collection.go b/pkg/kube/krt/collection.go
new file mode 100644
index 00000000..0aaccc36
--- /dev/null
+++ b/pkg/kube/krt/collection.go
@@ -0,0 +1,178 @@
+package krt
+
+import (
+       "fmt"
+       "github.com/apache/dubbo-kubernetes/pkg/ptr"
+       "github.com/apache/dubbo-kubernetes/pkg/util/sets"
+       "k8s.io/apimachinery/pkg/util/wait"
+       "sync"
+)
+
+type indexedDependencyType uint8
+
+type Key[O any] string
+
+const (
+       unknownIndexType indexedDependencyType = iota
+       indexType        indexedDependencyType = iota
+       getKeyType       indexedDependencyType = iota
+)
+
+type indexedDependency struct {
+       id  collectionUID
+       key string
+       typ indexedDependencyType
+}
+
+type extractorKey struct {
+       uid       collectionUID
+       filterUID collectionUID
+       typ       indexedDependencyType
+}
+
+type objectKeyExtractor = func(o any) []string
+
+type multiIndex[I, O any] struct {
+       outputs  map[Key[O]]O
+       inputs   map[Key[I]]I
+       mappings map[Key[I]]sets.Set[Key[O]]
+}
+
+type collectionIndex[I, O any] struct {
+       extract func(o O) []string
+       index   map[string]sets.Set[Key[O]]
+       parent  *manyCollection[I, O]
+}
+
+type dependencyState[I any] struct {
+       collectionDependencies       sets.Set[collectionUID]
+       objectDependencies           map[Key[I]][]*dependency
+       indexedDependencies          map[indexedDependency]sets.Set[Key[I]]
+       indexedDependenciesExtractor map[extractorKey]objectKeyExtractor
+}
+
+type handlerSet[O any] struct {
+       mu sync.RWMutex
+       wg wait.Group
+}
+
+func newHandlerSet[O any]() *handlerSet[O] {
+       return &handlerSet[O]{}
+}
+
+func NewCollection[I, O any](c Collection[I], hf TransformationSingle[I, O], 
opts ...CollectionOption) Collection[O] {
+       hm := func(ctx HandlerContext, i I) []O {
+               res := hf(ctx, i)
+               if res == nil {
+                       return nil
+               }
+               return []O{*res}
+       }
+       o := buildCollectionOptions(opts...)
+       if o.name == "" {
+               o.name = fmt.Sprintf("Collection[%v,%v]", ptr.TypeName[I](), 
ptr.TypeName[O]())
+       }
+       return newManyCollection(c, hm, o, nil)
+}
+
+func newManyCollection[I, O any](
+       cc Collection[I],
+       hf TransformationMulti[I, O],
+       opts collectionOptions,
+       onPrimaryInputEventHandler func([]Event[I]),
+) Collection[O] {
+       c := cc.(internalCollection[I])
+
+       h := &manyCollection[I, O]{
+               transformation: hf,
+               collectionName: opts.name,
+               id:             nextUID(),
+               parent:         c,
+               dependencyState: dependencyState[I]{
+                       collectionDependencies:       sets.New[collectionUID](),
+                       objectDependencies:           
map[Key[I]][]*dependency{},
+                       indexedDependencies:          
map[indexedDependency]sets.Set[Key[I]]{},
+                       indexedDependenciesExtractor: map[extractorKey]func(o 
any) []string{},
+               },
+               collectionState: multiIndex[I, O]{
+                       inputs:   map[Key[I]]I{},
+                       outputs:  map[Key[O]]O{},
+                       mappings: map[Key[I]]sets.Set[Key[O]]{},
+               },
+               indexes:                    make(map[string]collectionIndex[I, 
O]),
+               eventHandlers:              newHandlerSet[O](),
+               augmentation:               opts.augmentation,
+               synced:                     make(chan struct{}),
+               stop:                       opts.stop,
+               onPrimaryInputEventHandler: onPrimaryInputEventHandler,
+       }
+
+       if opts.metadata != nil {
+               h.metadata = opts.metadata
+       }
+
+       return nil
+}
+
+type internalCollection[T any] interface {
+       Collection[T]
+
+       // Name is a human facing name for this collection.
+       // Note this may not be universally unique
+       name() string
+       // Uid is an internal unique ID for this collection. MUST be globally 
unique
+       uid() collectionUID
+
+       dump() CollectionDump
+
+       // Augment mutates an object for use in various function calls. See 
WithObjectAugmentation
+       augment(any) any
+
+       // Create a new index into the collection
+       index(name string, extract func(o T) []string) indexer[T]
+}
+
+type CollectionDump struct {
+       // Map of output key -> output
+       Outputs map[string]any `json:"outputs,omitempty"`
+       // Name of the input collection
+       InputCollection string `json:"inputCollection,omitempty"`
+       // Map of input key -> info
+       Inputs map[string]InputDump `json:"inputs,omitempty"`
+       // Synced returns whether the collection is synced or not
+       Synced bool `json:"synced"`
+}
+
+type InputDump struct {
+       Outputs      []string `json:"outputs,omitempty"`
+       Dependencies []string `json:"dependencies,omitempty"`
+}
+
+type manyCollection[I, O any] struct {
+       // collectionName provides the collectionName for this collection.
+       collectionName string
+       id             collectionUID
+       // parent is the input collection we are building off of.
+       parent          Collection[I]
+       mu              sync.RWMutex
+       collectionState multiIndex[I, O]
+       dependencyState dependencyState[I]
+       // internal indexes
+       indexes map[string]collectionIndex[I, O]
+
+       // eventHandlers is a list of event handlers registered for the 
collection. On any changes, each will be notified.
+       eventHandlers *handlerSet[O]
+
+       transformation TransformationMulti[I, O]
+
+       // augmentation allows transforming an object into another for usage 
throughout the library. See WithObjectAugmentation.
+       augmentation func(a any) any
+       synced       chan struct{}
+       stop         <-chan struct{}
+       metadata     Metadata
+
+       // onPrimaryInputEventHandler is a specialized internal handler that 
runs synchronously when a primary input changes
+       onPrimaryInputEventHandler func(o []Event[I])
+
+       syncer Syncer
+}
diff --git a/pkg/kube/krt/core.go b/pkg/kube/krt/core.go
index fa267fc1..49635f16 100644
--- a/pkg/kube/krt/core.go
+++ b/pkg/kube/krt/core.go
@@ -5,34 +5,28 @@ import 
"github.com/apache/dubbo-kubernetes/pkg/kube/controllers"
 type FetchOption func(*dependency)
 
 type HandlerContext interface {
-       // DiscardResult triggers the result of this invocation to be skipped
-       // This allows a collection to mark that the current state is *invalid* 
and should use the last-known state.
-       //
-       // Note: this differs from returning `nil`, which would otherwise wipe 
out the last known state.
-       //
-       // Note: if the current resource has never been computed, the result 
will not be discarded if it is non-nil. This allows
-       // setting a default. For example, you may always return a static 
default config if the initial results are invalid,
-       // but not revert to this config if later results are invalid. Results 
can unconditionally be discarded by returning nil.
        DiscardResult()
-       // _internalHandler is an interface that can only be implemented by 
this package.
        _internalHandler()
 }
 
 type (
-       TransformationEmpty[T any] func(ctx HandlerContext) *T
+       TransformationEmpty[T any]     func(ctx HandlerContext) *T
+       TransformationMulti[I, O any]  func(ctx HandlerContext, i I) []O
+       TransformationSingle[I, O any] func(ctx HandlerContext, i I) *O
 )
 
 type Metadata map[string]any
 
 type Event[T any] struct {
-       // Old object, set on Update or Delete.
-       Old *T
-       // New object, set on Add or Update
-       New *T
-       // Event is the change type
+       Old   *T
+       New   *T
        Event controllers.EventType
 }
 
+type indexer[T any] interface {
+       Lookup(key string) []T
+}
+
 type EventStream[T any] interface {
        Syncer
        Register(f func(o Event[T])) HandlerRegistration
@@ -57,27 +51,14 @@ type HandlerRegistration interface {
 }
 
 type Collection[T any] interface {
-       // GetKey returns an object by its key, if present. Otherwise, nil is 
returned.
        GetKey(k string) *T
-
-       // List returns all objects in the collection.
-       // Order of the list is undefined.
        List() []T
-
-       // EventStream provides event handling capabilities for the collection, 
allowing clients to subscribe to changes
-       // and receive notifications when objects are added, modified, or 
removed.
        EventStream[T]
-
-       // Metadata returns the metadata associated with this collection.
-       // This can be used to store and retrieve arbitrary key-value pairs
-       // that provide additional context or configuration for the collection.
        Metadata() Metadata
 }
 
 type Singleton[T any] interface {
-       // Get returns the object, or nil if there is none.
        Get() *T
-       // Register adds an event watcher to the object. Any time it changes, 
the handler will be called
        Register(f func(o Event[T])) HandlerRegistration
        AsCollection() Collection[T]
        Metadata() Metadata
diff --git a/pkg/kube/krt/files/files.go b/pkg/kube/krt/files/files.go
index d00aaf19..8ab08ceb 100644
--- a/pkg/kube/krt/files/files.go
+++ b/pkg/kube/krt/files/files.go
@@ -3,6 +3,8 @@ package files
 import (
        "github.com/apache/dubbo-kubernetes/pkg/filewatcher"
        "github.com/apache/dubbo-kubernetes/pkg/kube/krt"
+       "go.uber.org/atomic"
+       "time"
 )
 
 type FileSingleton[T any] struct {
@@ -14,6 +16,49 @@ func NewFileSingleton[T any](
        filename string,
        readFile func(filename string) (T, error),
        opts ...krt.CollectionOption,
-) {
-       return
+) (FileSingleton[T], error) {
+       cfg, err := readFile(filename)
+       if err != nil {
+               return FileSingleton[T]{}, err
+       }
+
+       stop := krt.GetStop(opts...)
+
+       cur := atomic.NewPointer(&cfg)
+       trigger := krt.NewRecomputeTrigger(true, opts...)
+       sc := krt.NewSingleton[T](func(ctx krt.HandlerContext) *T {
+               trigger.MarkDependant(ctx)
+               return cur.Load()
+       }, opts...)
+       sc.AsCollection().WaitUntilSynced(stop)
+       watchFile(fileWatcher, filename, stop, func() {
+               cfg, err := readFile(filename)
+               if err != nil {
+                       log.Warnf("failed to update: %v", err)
+                       return
+               }
+               cur.Store(&cfg)
+               trigger.TriggerRecomputation()
+       })
+       return FileSingleton[T]{sc}, nil
+}
+
+func watchFile(fileWatcher filewatcher.FileWatcher, file string, stop <-chan 
struct{}, callback func()) {
+       _ = fileWatcher.Add(file)
+       go func() {
+               var timerC <-chan time.Time
+               for {
+                       select {
+                       case <-stop:
+                               return
+                       case <-timerC:
+                               timerC = nil
+                               callback()
+                       case <-fileWatcher.Events(file):
+                               if timerC == nil {
+                                       timerC = time.After(100 * 
time.Millisecond)
+                               }
+                       }
+               }
+       }()
 }
diff --git a/pkg/kube/krt/filter.go b/pkg/kube/krt/filter.go
index 4545782b..2bb04cdc 100644
--- a/pkg/kube/krt/filter.go
+++ b/pkg/kube/krt/filter.go
@@ -1,3 +1,13 @@
 package krt
 
-type filter struct{}
+import "github.com/apache/dubbo-kubernetes/pkg/util/smallset"
+
+type filter struct {
+       keys smallset.Set[string]
+}
+
+func FilterKey(k string) FetchOption {
+       return func(h *dependency) {
+               h.filter.keys = smallset.New(k)
+       }
+}
diff --git a/pkg/kube/krt/helpers.go b/pkg/kube/krt/helpers.go
new file mode 100644
index 00000000..9b3f14ce
--- /dev/null
+++ b/pkg/kube/krt/helpers.go
@@ -0,0 +1,29 @@
+package krt
+
+import (
+       "time"
+)
+
+func waitForCacheSync(name string, stop <-chan struct{}, collections ...<-chan 
struct{}) (r bool) {
+       t := time.NewTicker(time.Second * 5)
+       defer t.Stop()
+       _ = time.Now()
+       defer func() {
+               if r {
+               } else {
+               }
+       }()
+       for _, col := range collections {
+               for {
+                       select {
+                       case <-t.C:
+                               continue
+                       case <-stop:
+                               return false
+                       case <-col:
+                       }
+                       break
+               }
+       }
+       return true
+}
diff --git a/pkg/kube/krt/informer.go b/pkg/kube/krt/informer.go
new file mode 100644
index 00000000..3a64e3b7
--- /dev/null
+++ b/pkg/kube/krt/informer.go
@@ -0,0 +1,50 @@
+package krt
+
+import (
+       "fmt"
+       "github.com/apache/dubbo-kubernetes/pkg/kube/controllers"
+       "github.com/apache/dubbo-kubernetes/pkg/kube/kclient"
+       "github.com/apache/dubbo-kubernetes/pkg/ptr"
+)
+
+type informer[I controllers.ComparableObject] struct {
+       inf            kclient.Informer[I]
+       collectionName string
+       id             collectionUID
+       augmentation   func(a any) any
+       synced         chan struct{}
+       baseSyncer     Syncer
+       metadata       Metadata
+}
+
+type channelSyncer struct {
+       name   string
+       synced <-chan struct{}
+}
+
+func WrapClient[I controllers.ComparableObject](c kclient.Informer[I], opts 
...CollectionOption) Collection[I] {
+       o := buildCollectionOptions(opts...)
+       if o.name == "" {
+               o.name = fmt.Sprintf("Informer[%v]", ptr.TypeName[I]())
+       }
+       h := &informer[I]{
+               inf:            c,
+               collectionName: o.name,
+               id:             nextUID(),
+               augmentation:   o.augmentation,
+               synced:         make(chan struct{}),
+       }
+       h.baseSyncer = channelSyncer{
+               name:   h.collectionName,
+               synced: h.synced,
+       }
+
+       if o.metadata != nil {
+               h.metadata = o.metadata
+       }
+       return nil
+}
+
+func (c channelSyncer) WaitUntilSynced(stop <-chan struct{}) bool {
+       return waitForCacheSync(c.name, stop, c.synced)
+}
diff --git a/pkg/kube/krt/internal.go b/pkg/kube/krt/internal.go
index 58f83b12..291c4f3a 100644
--- a/pkg/kube/krt/internal.go
+++ b/pkg/kube/krt/internal.go
@@ -1,10 +1,11 @@
 package krt
 
+import "go.uber.org/atomic"
+
 type dependency struct {
        id             collectionUID
        collectionName string
-       // Filter over the collection
-       filter *filter
+       filter         *filter
 }
 
 type collectionUID uint64
@@ -24,3 +25,9 @@ func buildCollectionOptions(opts ...CollectionOption) 
collectionOptions {
        }
        return *c
 }
+
+var globalUIDCounter = atomic.NewUint64(1)
+
+func nextUID() collectionUID {
+       return collectionUID(globalUIDCounter.Inc())
+}
diff --git a/pkg/kube/krt/options.go b/pkg/kube/krt/options.go
index c7446c88..6f076e6e 100644
--- a/pkg/kube/krt/options.go
+++ b/pkg/kube/krt/options.go
@@ -14,6 +14,10 @@ func NewOptionsBuilder(stop <-chan struct{}, namePrefix 
string) OptionsBuilder {
        }
 }
 
+func (k OptionsBuilder) Stop() <-chan struct{} {
+       return k.stop
+}
+
 func (k OptionsBuilder) WithName(n string) []CollectionOption {
        name := n
        if k.namePrefix != "" {
diff --git a/pkg/kube/krt/recomputetrigger.go b/pkg/kube/krt/recomputetrigger.go
new file mode 100644
index 00000000..9d41eedb
--- /dev/null
+++ b/pkg/kube/krt/recomputetrigger.go
@@ -0,0 +1,86 @@
+package krt
+
+import (
+       "github.com/apache/dubbo-kubernetes/pkg/ptr"
+       "go.uber.org/atomic"
+)
+
+type RecomputeProtected[T any] struct {
+       trigger *RecomputeTrigger
+       data    T
+}
+
+// Get marks us as dependent on the value and fetches it.
+func (c RecomputeProtected[T]) Get(ctx HandlerContext) T {
+       c.trigger.MarkDependant(ctx)
+       return c.data
+}
+
+// TriggerRecomputation tells all dependants to recompute
+func (c RecomputeProtected[T]) TriggerRecomputation() {
+       c.trigger.TriggerRecomputation()
+}
+
+// MarkSynced marks this trigger as ready. Before this is called, dependant 
collections will be blocked.
+// This ensures initial state is populated.
+func (c RecomputeProtected[T]) MarkSynced() {
+       c.trigger.MarkSynced()
+}
+
+// Modify modifies the object and triggers a recompution.
+func (c RecomputeProtected[T]) Modify(fn func(*T)) {
+       fn(&c.data)
+       c.TriggerRecomputation()
+}
+
+// AccessUnprotected returns the data without marking as dependant. This must 
be used with caution; any use within a collection
+// is likely broken
+func (c RecomputeProtected[T]) AccessUnprotected() T {
+       return c.data
+}
+
+// NewRecomputeProtected builds a RecomputeProtected which wraps some data, 
ensuring it is always MarkDependant when accessed
+func NewRecomputeProtected[T any](initialData T, startSynced bool, opts 
...CollectionOption) RecomputeProtected[T] {
+       trigger := NewRecomputeTrigger(startSynced, opts...)
+       return RecomputeProtected[T]{
+               trigger: trigger,
+               data:    initialData,
+       }
+}
+
+// RecomputeTrigger trigger provides an escape hatch to allow krt 
transformations to depend on external state and recompute
+// correctly when those change.
+// Typically, all state is registered and fetched through krt.Fetch. Through 
this mechanism, any changes are automatically
+// propagated through the system to dependencies.
+// In some cases, it may not be feasible to get all state into krt; hopefully, 
this is a temporary state.
+// RecomputeTrigger works around this by allowing an explicit call to 
recompute a collection; the caller must be sure to call Trigger()
+// any time the state changes.
+type RecomputeTrigger struct {
+       inner StaticSingleton[int32]
+       // krt will suppress events for unchanged resources. To workaround 
this, we constantly change and int each time TriggerRecomputation
+       // is called to ensure our event is not suppressed.
+       i *atomic.Int32
+}
+
+func NewRecomputeTrigger(startSynced bool, opts ...CollectionOption) 
*RecomputeTrigger {
+       inner := NewStatic[int32](ptr.Of(int32(0)), startSynced, opts...)
+       return &RecomputeTrigger{inner: inner, i: atomic.NewInt32(0)}
+}
+
+// TriggerRecomputation tells all dependants to recompute
+func (r *RecomputeTrigger) TriggerRecomputation() {
+       v := r.i.Inc()
+       r.inner.Set(ptr.Of(v))
+}
+
+// MarkDependant marks the given context as depending on this trigger. This 
registers it to be recomputed when TriggerRecomputation
+// is called.
+func (r *RecomputeTrigger) MarkDependant(ctx HandlerContext) {
+       _ = Fetch(ctx, r.inner.AsCollection())
+}
+
+// MarkSynced marks this trigger as ready. Before this is called, dependant 
collections will be blocked.
+// This ensures initial state is populated.
+func (r *RecomputeTrigger) MarkSynced() {
+       r.inner.MarkSynced()
+}
diff --git a/pkg/kube/krt/singleton.go b/pkg/kube/krt/singleton.go
index 414641f3..b9e56d66 100644
--- a/pkg/kube/krt/singleton.go
+++ b/pkg/kube/krt/singleton.go
@@ -1,17 +1,200 @@
 package krt
 
-func NewSingleton[O any](hf TransformationEmpty[O], opts ...CollectionOption) 
Singleton[O] {
-       return nil
-}
+import (
+       "fmt"
+       "github.com/apache/dubbo-kubernetes/pkg/kube/controllers"
+       "github.com/apache/dubbo-kubernetes/pkg/ptr"
+       "github.com/apache/dubbo-kubernetes/pkg/util/slices"
 
-var (
-       _ Singleton[any] = &collectionAdapter[any]{}
+       "sync/atomic"
 )
 
+type dummyValue struct{}
+
+func (d dummyValue) ResourceName() string {
+       return ""
+}
+
+type StaticSingleton[T any] interface {
+       Singleton[T]
+       Set(*T)
+       MarkSynced()
+}
+
+func NewStatic[T any](initial *T, startSynced bool, opts ...CollectionOption) 
StaticSingleton[T] {
+       val := new(atomic.Pointer[T])
+       val.Store(initial)
+       x := &static[T]{
+               val:           val,
+               synced:        &atomic.Bool{},
+               id:            nextUID(),
+               eventHandlers: &handlers[T]{},
+       }
+       x.synced.Store(startSynced)
+       o := buildCollectionOptions(opts...)
+       if o.name == "" {
+               o.name = fmt.Sprintf("Static[%v]", ptr.TypeName[T]())
+       }
+       x.collectionName = o.name
+       x.syncer = pollSyncer{
+               name: x.collectionName,
+               f: func() bool {
+                       return x.synced.Load()
+               },
+       }
+       if o.metadata != nil {
+               x.metadata = o.metadata
+       }
+       maybeRegisterCollectionForDebugging(x, o.debugger)
+       return collectionAdapter[T]{x}
+}
+
+type static[T any] struct {
+       val            *atomic.Pointer[T]
+       synced         *atomic.Bool
+       id             collectionUID
+       eventHandlers  *handlers[T]
+       collectionName string
+       syncer         Syncer
+       metadata       Metadata
+}
+
+func (d *static[T]) GetKey(k string) *T {
+       return d.val.Load()
+}
+
+func (d *static[T]) List() []T {
+       v := d.val.Load()
+       if v == nil {
+               return nil
+       }
+       return []T{*v}
+}
+
+func (d *static[T]) Metadata() Metadata {
+       return d.metadata
+}
+
+func (d *static[T]) Register(f func(o Event[T])) HandlerRegistration {
+       return registerHandlerAsBatched[T](d, f)
+}
+
+func (d *static[T]) RegisterBatch(f func(o []Event[T]), runExistingState bool) 
HandlerRegistration {
+       reg := d.eventHandlers.Insert(f)
+       if runExistingState {
+               v := d.val.Load()
+               if v != nil {
+                       f([]Event[T]{{
+                               New:   v,
+                               Event: controllers.EventAdd,
+                       }})
+               }
+       }
+
+       return staticHandler{Syncer: d.syncer, remove: func() {
+               d.eventHandlers.Delete(reg)
+       }}
+}
+
+type staticHandler struct {
+       Syncer
+       remove func()
+}
+
+func (s staticHandler) UnregisterHandler() {
+       s.remove()
+}
+
+func (d *static[T]) Synced() Syncer {
+       return pollSyncer{
+               name: d.collectionName,
+               f: func() bool {
+                       return d.synced.Load()
+               },
+       }
+}
+
+func (d *static[T]) HasSynced() bool {
+       return d.syncer.HasSynced()
+}
+
+func (d *static[T]) WaitUntilSynced(stop <-chan struct{}) bool {
+       return d.syncer.WaitUntilSynced(stop)
+}
+
+func (d *static[T]) Set(now *T) {
+       old := d.val.Swap(now)
+       if old == now {
+               return
+       }
+       for _, h := range d.eventHandlers.Get() {
+               h([]Event[T]{toEvent[T](old, now)})
+       }
+}
+
+// nolint: unused // (not true, its to implement an interface)
+func (d *static[T]) dump() CollectionDump {
+       return CollectionDump{
+               Outputs: map[string]any{
+                       "static": d.val.Load(),
+               },
+               Synced: d.HasSynced(),
+       }
+}
+
+// nolint: unused // (not true, its to implement an interface)
+func (d *static[T]) augment(a any) any {
+       // not supported in this collection type
+       return a
+}
+
+// nolint: unused // (not true, its to implement an interface)
+func (d *static[T]) name() string {
+       return d.collectionName
+}
+
+// nolint: unused // (not true, its to implement an interface)
+func (d *static[T]) uid() collectionUID {
+       return d.id
+}
+
+func (d *static[T]) index(name string, extract func(o T) []string) indexer[T] {
+       panic("TODO")
+}
+
+func toEvent[T any](old, now *T) Event[T] {
+       if old == nil {
+               return Event[T]{
+                       New:   now,
+                       Event: controllers.EventAdd,
+               }
+       } else if now == nil {
+               return Event[T]{
+                       Old:   old,
+                       Event: controllers.EventDelete,
+               }
+       }
+       return Event[T]{
+               New:   now,
+               Old:   old,
+               Event: controllers.EventUpdate,
+       }
+}
+
+var _ Collection[dummyValue] = &static[dummyValue]{}
+
 type collectionAdapter[T any] struct {
        c Collection[T]
 }
 
+func (c collectionAdapter[T]) MarkSynced() {
+       c.c.(*static[T]).synced.Store(true)
+}
+
+func (c collectionAdapter[T]) Set(t *T) {
+       c.c.(*static[T]).Set(t)
+}
+
 func (c collectionAdapter[T]) Get() *T {
        // Guaranteed to be 0 or 1 len
        res := c.c.List()
@@ -33,3 +216,16 @@ func (c collectionAdapter[T]) Register(f func(o Event[T])) 
HandlerRegistration {
 func (c collectionAdapter[T]) AsCollection() Collection[T] {
        return c.c
 }
+
+var (
+       _ Singleton[any] = &collectionAdapter[any]{}
+)
+
+func NewSingleton[O any](hf TransformationEmpty[O], opts ...CollectionOption) 
Singleton[O] {
+       staticOpts := append(slices.Clone(opts), nil)
+       dummyCollection := NewStatic[dummyValue](&dummyValue{}, true, 
staticOpts...).AsCollection()
+       col := NewCollection[dummyValue, O](dummyCollection, func(ctx 
HandlerContext, _ dummyValue) *O {
+               return hf(ctx)
+       }, opts...)
+       return collectionAdapter[O]{col}
+}
diff --git a/pkg/kube/kubetypes/types.go b/pkg/kube/kubetypes/types.go
index eecccd3e..989de8c2 100644
--- a/pkg/kube/kubetypes/types.go
+++ b/pkg/kube/kubetypes/types.go
@@ -17,14 +17,54 @@
 
 package kubetypes
 
+import (
+       "context"
+       "github.com/apache/dubbo-kubernetes/pkg/cluster"
+       "github.com/apache/dubbo-kubernetes/pkg/util/sets"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/types"
+)
+
+type InformerType int
+
+const (
+       StandardInformer InformerType = iota
+       DynamicInformer
+       MetadataInformer
+)
+
+type WriteAPI[T runtime.Object] interface {
+       Create(ctx context.Context, object T, opts metav1.CreateOptions) (T, 
error)
+       Patch(ctx context.Context, name string, pt types.PatchType, data 
[]byte, opts metav1.PatchOptions, subresources ...string) (result T, err error)
+       Update(ctx context.Context, object T, opts metav1.UpdateOptions) (T, 
error)
+       Delete(ctx context.Context, name string, opts metav1.DeleteOptions) 
error
+}
+
+type WriteStatusAPI[T runtime.Object] interface {
+       UpdateStatus(ctx context.Context, object T, opts metav1.UpdateOptions) 
(T, error)
+}
+
 type InformerOptions struct {
-       // A selector to restrict the list of returned objects by their labels.
-       LabelSelector string
-       // A selector to restrict the list of returned objects by their fields.
-       FieldSelector string
-       // Namespace to watch.
-       Namespace string
-       // ObjectTransform allows arbitrarily modifying objects stored in the 
underlying cache.
-       // If unset, a default transform is provided to remove ManagedFields 
(high cost, low value)
+       LabelSelector   string
+       FieldSelector   string
+       Namespace       string
+       ObjectTransform func(obj any) (any, error)
+       Cluster         cluster.ID
+       InformerType    InformerType
+}
+
+type Filter struct {
+       LabelSelector   string
+       FieldSelector   string
+       Namespace       string
+       ObjectFilter    DynamicObjectFilter
        ObjectTransform func(obj any) (any, error)
 }
+
+type DynamicObjectFilter interface {
+       // Filter returns true if the input object or namespace string resides 
in a namespace selected for discovery
+       Filter(obj any) bool
+       // AddHandler registers a handler on namespace, which will be triggered 
when namespace selected or deselected.
+       AddHandler(func(selected, deselected sets.String))
+}
diff --git a/pkg/mesh/meshwatcher/collection.go 
b/pkg/mesh/meshwatcher/collection.go
index 04090d47..d1e93be9 100644
--- a/pkg/mesh/meshwatcher/collection.go
+++ b/pkg/mesh/meshwatcher/collection.go
@@ -6,7 +6,6 @@ import (
        "github.com/apache/dubbo-kubernetes/pkg/kube/krt"
        krtfiles "github.com/apache/dubbo-kubernetes/pkg/kube/krt/files"
        "github.com/apache/dubbo-kubernetes/pkg/mesh"
-
        "os"
        "path"
 )
diff --git a/pkg/ptr/pointer.go b/pkg/ptr/pointer.go
index 5388152e..6f40c108 100644
--- a/pkg/ptr/pointer.go
+++ b/pkg/ptr/pointer.go
@@ -1,5 +1,24 @@
 package ptr
 
+import "fmt"
+
 func Of[T any](t T) *T {
        return &t
 }
+
+func Empty[T any]() T {
+       var empty T
+       return empty
+}
+
+func Flatten[T any](t **T) *T {
+       if t == nil {
+               return nil
+       }
+       return *t
+}
+
+func TypeName[T any]() string {
+       var empty T
+       return fmt.Sprintf("%T", empty)
+}
diff --git a/pkg/sleep/sleep.go b/pkg/sleep/sleep.go
new file mode 100644
index 00000000..f959876a
--- /dev/null
+++ b/pkg/sleep/sleep.go
@@ -0,0 +1,23 @@
+package sleep
+
+import (
+       "context"
+       "time"
+)
+
+func UntilContext(ctx context.Context, d time.Duration) bool {
+       return Until(ctx.Done(), d)
+}
+
+func Until(ch <-chan struct{}, d time.Duration) bool {
+       timer := time.NewTimer(d)
+       select {
+       case <-ch:
+               if !timer.Stop() {
+                       <-timer.C
+               }
+               return false
+       case <-timer.C:
+               return true
+       }
+}
diff --git a/pkg/typemap/map.go b/pkg/typemap/map.go
new file mode 100644
index 00000000..037cd278
--- /dev/null
+++ b/pkg/typemap/map.go
@@ -0,0 +1,27 @@
+package typemap
+
+import (
+       "github.com/apache/dubbo-kubernetes/pkg/ptr"
+       "reflect"
+)
+
+type TypeMap struct {
+       inner map[reflect.Type]any
+}
+
+func NewTypeMap() TypeMap {
+       return TypeMap{make(map[reflect.Type]any)}
+}
+
+func Set[T any](t TypeMap, v T) {
+       interfaceType := reflect.TypeOf((*T)(nil)).Elem()
+       t.inner[interfaceType] = v
+}
+
+func Get[T any](t TypeMap) *T {
+       v, f := t.inner[reflect.TypeFor[T]()]
+       if f {
+               return ptr.Of(v.(T))
+       }
+       return nil
+}
diff --git a/pkg/util/smallset/smallset.go b/pkg/util/smallset/smallset.go
new file mode 100644
index 00000000..5adbfa78
--- /dev/null
+++ b/pkg/util/smallset/smallset.go
@@ -0,0 +1,108 @@
+package smallset
+
+import (
+       "cmp"
+       "fmt"
+       "github.com/apache/dubbo-kubernetes/pkg/util/slices"
+)
+
+// Set is an immutable set optimized for *small number of items*. For general 
purposes, Sets is likely better
+//
+// *Set construction*: sets is roughly 1kb allocations per 250 items. 
smallsets is 0.
+// *Contains* sets is O(1). smallsets is O(logn). smallsets is typically 
faster up to about 5 elements.
+//
+//     At 1000 items, it is roughly 5x slower (30ns vs 5ns).
+type Set[T cmp.Ordered] struct {
+       items []T
+}
+
+// NewPresorted creates a new Set with the given items.
+// If items is not sorted or contains duplicates, this gives undefined 
behavior; use New instead.
+func NewPresorted[T cmp.Ordered](items ...T) Set[T] {
+       return Set[T]{items: items}
+}
+
+// New creates a new Set with the given items.
+// Duplicates are removed
+func New[T cmp.Ordered](items ...T) Set[T] {
+       if len(items) == 1 {
+               return Set[T]{items: items}
+       }
+       slices.Sort(items)
+       items = slices.FilterDuplicatesPresorted(items)
+       return Set[T]{items: items}
+}
+
+// CopyAndInsert builds a *new* with all the current items plus new items
+func (s Set[T]) CopyAndInsert(items ...T) Set[T] {
+       slices.Sort(items)
+       // This is basically the 'merge' part of merge sort.
+       a := s.items
+       b := items
+       nl := make([]T, 0, len(a)+len(b))
+       i, j := 0, 0
+       appendIfUnique := func(t T) []T {
+               l := len(nl)
+               if l == 0 {
+                       nl = append(nl, t)
+               } else {
+                       last := nl[l-1]
+                       if last != t {
+                               nl = append(nl, t)
+                       }
+               }
+               return nl
+       }
+       for i < len(a) && j < len(b) {
+               if a[i] < b[j] {
+                       nl = appendIfUnique(a[i])
+                       i++
+               } else {
+                       nl = appendIfUnique(b[j])
+                       j++
+               }
+       }
+       for ; i < len(a); i++ {
+               nl = appendIfUnique(a[i])
+       }
+       for ; j < len(b); j++ {
+               nl = appendIfUnique(b[j])
+       }
+       // we already know they are sorted+unique
+       return Set[T]{items: nl}
+}
+
+// List returns the underlying slice. Must not be modified
+func (s Set[T]) List() []T {
+       return s.items
+}
+
+// Contains returns whether the given item is in the set.
+func (s Set[T]) Contains(item T) bool {
+       _, f := slices.BinarySearch(s.items, item)
+       return f
+}
+
+// Len returns the number of elements in this Set.
+func (s Set[T]) Len() int {
+       return len(s.items)
+}
+
+// IsEmpty indicates whether the set is the empty set.
+func (s Set[T]) IsEmpty() bool {
+       return len(s.items) == 0
+}
+
+// IsNil indicates whether the set is nil. This is different from an empty set.
+// 'var smallset.Set': nil
+// smallset.New(): nil
+// smallset.New(emptyList...): not nil
+func (s Set[T]) IsNil() bool {
+       return s.items == nil
+}
+
+// String returns a string representation of the set.
+// Use it only for debugging and logging.
+func (s Set[T]) String() string {
+       return fmt.Sprintf("%v", s.items)
+}


Reply via email to