diff --git a/.github/update.log b/.github/update.log
index cd3014c89f..8cde6690f3 100644
--- a/.github/update.log
+++ b/.github/update.log
@@ -1216,3 +1216,4 @@ Update On Mon Dec 15 19:43:13 CET 2025
Update On Tue Dec 16 19:42:39 CET 2025
Update On Wed Dec 17 19:43:54 CET 2025
Update On Thu Dec 18 19:42:36 CET 2025
+Update On Fri Dec 19 19:41:31 CET 2025
diff --git a/clash-meta/component/ca/config.go b/clash-meta/component/ca/config.go
index 9cc8839f40..f50780af9f 100644
--- a/clash-meta/component/ca/config.go
+++ b/clash-meta/component/ca/config.go
@@ -10,7 +10,6 @@ import (
"sync"
"github.com/metacubex/mihomo/common/once"
- C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/ntp"
"github.com/metacubex/tls"
@@ -107,12 +106,13 @@ func GetTLSConfig(opt Option) (tlsConfig *tls.Config, err error) {
}
if len(opt.Certificate) > 0 || len(opt.PrivateKey) > 0 {
- var cert tls.Certificate
- cert, err = LoadTLSKeyPair(opt.Certificate, opt.PrivateKey, C.Path)
+ certLoader, err := NewTLSKeyPairLoader(opt.Certificate, opt.PrivateKey)
if err != nil {
return nil, err
}
- tlsConfig.Certificates = []tls.Certificate{cert}
+ tlsConfig.GetClientCertificate = func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
+ return certLoader()
+ }
}
return tlsConfig, nil
}
diff --git a/clash-meta/component/ca/keypair.go b/clash-meta/component/ca/keypair.go
index 13b38dc11f..ff9086d1b7 100644
--- a/clash-meta/component/ca/keypair.go
+++ b/clash-meta/component/ca/keypair.go
@@ -12,67 +12,80 @@ import (
"fmt"
"math/big"
"os"
+ "runtime"
+ "sync"
"time"
+ C "github.com/metacubex/mihomo/constant"
+
+ "github.com/metacubex/fswatch"
"github.com/metacubex/tls"
)
-type Path interface {
- Resolve(path string) string
- IsSafePath(path string) bool
- ErrNotSafePath(path string) error
-}
-
-// LoadTLSKeyPair loads a TLS key pair from the provided certificate and private key data or file paths, supporting fallback resolution.
-// Returns a tls.Certificate and an error, where the error indicates issues during parsing or file loading.
+// NewTLSKeyPairLoader creates a loader function for TLS key pairs from the provided certificate and private key data or file paths.
// If both certificate and privateKey are empty, generates a random TLS RSA key pair.
-// Accepts a Path interface for resolving file paths when necessary.
-func LoadTLSKeyPair(certificate, privateKey string, path Path) (tls.Certificate, error) {
+func NewTLSKeyPairLoader(certificate, privateKey string) (func() (*tls.Certificate, error), error) {
if certificate == "" && privateKey == "" {
var err error
certificate, privateKey, _, err = NewRandomTLSKeyPair(KeyPairTypeRSA)
if err != nil {
- return tls.Certificate{}, err
+ return nil, err
}
}
cert, painTextErr := tls.X509KeyPair([]byte(certificate), []byte(privateKey))
if painTextErr == nil {
- return cert, nil
- }
- if path == nil {
- return tls.Certificate{}, painTextErr
+ return func() (*tls.Certificate, error) {
+ return &cert, nil
+ }, nil
}
- certificate = path.Resolve(certificate)
- privateKey = path.Resolve(privateKey)
+ certificate = C.Path.Resolve(certificate)
+ privateKey = C.Path.Resolve(privateKey)
var loadErr error
- if !path.IsSafePath(certificate) {
- loadErr = path.ErrNotSafePath(certificate)
- } else if !path.IsSafePath(privateKey) {
- loadErr = path.ErrNotSafePath(privateKey)
+ if !C.Path.IsSafePath(certificate) {
+ loadErr = C.Path.ErrNotSafePath(certificate)
+ } else if !C.Path.IsSafePath(privateKey) {
+ loadErr = C.Path.ErrNotSafePath(privateKey)
} else {
cert, loadErr = tls.LoadX509KeyPair(certificate, privateKey)
}
if loadErr != nil {
- return tls.Certificate{}, fmt.Errorf("parse certificate failed, maybe format error:%s, or path error: %s", painTextErr.Error(), loadErr.Error())
+ return nil, fmt.Errorf("parse certificate failed, maybe format error:%s, or path error: %s", painTextErr.Error(), loadErr.Error())
}
- return cert, nil
+ gcFlag := new(os.File)
+ updateMutex := sync.RWMutex{}
+ if watcher, err := fswatch.NewWatcher(fswatch.Options{Path: []string{certificate, privateKey}, Callback: func(path string) {
+ updateMutex.Lock()
+ defer updateMutex.Unlock()
+ if newCert, err := tls.LoadX509KeyPair(certificate, privateKey); err == nil {
+ cert = newCert
+ }
+ }}); err == nil {
+ if err = watcher.Start(); err == nil {
+ runtime.SetFinalizer(gcFlag, func(f *os.File) {
+ _ = watcher.Close()
+ })
+ }
+ }
+ return func() (*tls.Certificate, error) {
+ defer runtime.KeepAlive(gcFlag)
+ updateMutex.RLock()
+ defer updateMutex.RUnlock()
+ return &cert, nil
+ }, nil
}
-func LoadCertificates(certificate string, path Path) (*x509.CertPool, error) {
+func LoadCertificates(certificate string) (*x509.CertPool, error) {
pool := x509.NewCertPool()
if pool.AppendCertsFromPEM([]byte(certificate)) {
return pool, nil
}
painTextErr := fmt.Errorf("invalid certificate: %s", certificate)
- if path == nil {
- return nil, painTextErr
- }
- certificate = path.Resolve(certificate)
+ certificate = C.Path.Resolve(certificate)
var loadErr error
- if !path.IsSafePath(certificate) {
- loadErr = path.ErrNotSafePath(certificate)
+ if !C.Path.IsSafePath(certificate) {
+ loadErr = C.Path.ErrNotSafePath(certificate)
} else {
certPEMBlock, err := os.ReadFile(certificate)
if pool.AppendCertsFromPEM(certPEMBlock) {
@@ -83,6 +96,9 @@ func LoadCertificates(certificate string, path Path) (*x509.CertPool, error) {
if loadErr != nil {
return nil, fmt.Errorf("parse certificate failed, maybe format error:%s, or path error: %s", painTextErr.Error(), loadErr.Error())
}
+ //TODO: support dynamic update pool too
+ // blocked by: https://github.com/golang/go/issues/64796
+ // maybe we can direct add `GetRootCAs` and `GetClientCAs` to ourselves tls fork
return pool, nil
}
diff --git a/clash-meta/component/ech/key.go b/clash-meta/component/ech/key.go
index b0d572d628..4911b90f4c 100644
--- a/clash-meta/component/ech/key.go
+++ b/clash-meta/component/ech/key.go
@@ -8,9 +8,12 @@ import (
"errors"
"fmt"
"os"
+ "runtime"
+ "sync"
- "github.com/metacubex/mihomo/component/ca"
+ C "github.com/metacubex/mihomo/constant"
+ "github.com/metacubex/fswatch"
"github.com/metacubex/tls"
"golang.org/x/crypto/cryptobyte"
)
@@ -104,40 +107,65 @@ func UnmarshalECHKeys(raw []byte) ([]tls.EncryptedClientHelloKey, error) {
return keys, nil
}
-func LoadECHKey(key string, tlsConfig *tls.Config, path ca.Path) error {
+func LoadECHKey(key string, tlsConfig *tls.Config) error {
if key == "" {
return nil
}
- painTextErr := loadECHKey([]byte(key), tlsConfig)
+ echKeys, painTextErr := loadECHKey([]byte(key))
if painTextErr == nil {
+ tlsConfig.GetEncryptedClientHelloKeys = func(info *tls.ClientHelloInfo) ([]tls.EncryptedClientHelloKey, error) {
+ return echKeys, nil
+ }
return nil
}
- key = path.Resolve(key)
+ key = C.Path.Resolve(key)
var loadErr error
- if !path.IsSafePath(key) {
- loadErr = path.ErrNotSafePath(key)
+ if !C.Path.IsSafePath(key) {
+ loadErr = C.Path.ErrNotSafePath(key)
} else {
var echKey []byte
echKey, loadErr = os.ReadFile(key)
if loadErr == nil {
- loadErr = loadECHKey(echKey, tlsConfig)
+ echKeys, loadErr = loadECHKey(echKey)
}
}
if loadErr != nil {
return fmt.Errorf("parse ECH keys failed, maybe format error:%s, or path error: %s", painTextErr.Error(), loadErr.Error())
}
+ gcFlag := new(os.File)
+ updateMutex := sync.RWMutex{}
+ if watcher, err := fswatch.NewWatcher(fswatch.Options{Path: []string{key}, Callback: func(path string) {
+ updateMutex.Lock()
+ defer updateMutex.Unlock()
+ if echKey, err := os.ReadFile(key); err == nil {
+ if newEchKeys, err := loadECHKey(echKey); err == nil {
+ echKeys = newEchKeys
+ }
+ }
+ }}); err == nil {
+ if err = watcher.Start(); err == nil {
+ runtime.SetFinalizer(gcFlag, func(f *os.File) {
+ _ = watcher.Close()
+ })
+ }
+ }
+ tlsConfig.GetEncryptedClientHelloKeys = func(info *tls.ClientHelloInfo) ([]tls.EncryptedClientHelloKey, error) {
+ defer runtime.KeepAlive(gcFlag)
+ updateMutex.RLock()
+ defer updateMutex.RUnlock()
+ return echKeys, nil
+ }
return nil
}
-func loadECHKey(echKey []byte, tlsConfig *tls.Config) error {
+func loadECHKey(echKey []byte) ([]tls.EncryptedClientHelloKey, error) {
block, rest := pem.Decode(echKey)
if block == nil || block.Type != "ECH KEYS" || len(rest) > 0 {
- return errors.New("invalid ECH keys pem")
+ return nil, errors.New("invalid ECH keys pem")
}
echKeys, err := UnmarshalECHKeys(block.Bytes)
if err != nil {
- return fmt.Errorf("parse ECH keys: %w", err)
+ return nil, fmt.Errorf("parse ECH keys: %w", err)
}
- tlsConfig.EncryptedClientHelloKeys = echKeys
- return nil
+ return echKeys, err
}
diff --git a/clash-meta/component/tls/utls.go b/clash-meta/component/tls/utls.go
index 2b33d323dd..d8ca9716c5 100644
--- a/clash-meta/component/tls/utls.go
+++ b/clash-meta/component/tls/utls.go
@@ -1,7 +1,10 @@
package tls
import (
+ "context"
"net"
+ "reflect"
+ "unsafe"
"github.com/metacubex/mihomo/common/once"
"github.com/metacubex/mihomo/common/utils"
@@ -126,8 +129,11 @@ type EncryptedClientHelloKey = utls.EncryptedClientHelloKey
type Config = utls.Config
+var tlsCertificateRequestInfoCtxOffset = utils.MustOK(reflect.TypeOf((*tls.CertificateRequestInfo)(nil)).Elem().FieldByName("ctx")).Offset
+var tlsClientHelloInfoCtxOffset = utils.MustOK(reflect.TypeOf((*tls.ClientHelloInfo)(nil)).Elem().FieldByName("ctx")).Offset
+
func UConfig(config *tls.Config) *utls.Config {
- return &utls.Config{
+ cfg := &utls.Config{
Rand: config.Rand,
Time: config.Time,
Certificates: utils.Map(config.Certificates, UCertificate),
@@ -147,6 +153,52 @@ func UConfig(config *tls.Config) *utls.Config {
SessionTicketsDisabled: config.SessionTicketsDisabled,
Renegotiation: utls.RenegotiationSupport(config.Renegotiation),
}
+ if config.GetClientCertificate != nil {
+ cfg.GetClientCertificate = func(info *utls.CertificateRequestInfo) (*utls.Certificate, error) {
+ tlsInfo := &tls.CertificateRequestInfo{
+ AcceptableCAs: info.AcceptableCAs,
+ SignatureSchemes: utils.Map(info.SignatureSchemes, func(it utls.SignatureScheme) tls.SignatureScheme {
+ return tls.SignatureScheme(it)
+ }),
+ Version: info.Version,
+ }
+ *(*context.Context)(unsafe.Add(unsafe.Pointer(tlsInfo), tlsCertificateRequestInfoCtxOffset)) = info.Context() // for tlsInfo.ctx
+ cert, err := config.GetClientCertificate(tlsInfo)
+ if err != nil {
+ return nil, err
+ }
+ uCert := UCertificate(*cert)
+ return &uCert, err
+ }
+ }
+ if config.GetCertificate != nil {
+ cfg.GetCertificate = func(info *utls.ClientHelloInfo) (*utls.Certificate, error) {
+ tlsInfo := &tls.ClientHelloInfo{
+ CipherSuites: info.CipherSuites,
+ ServerName: info.ServerName,
+ SupportedCurves: utils.Map(info.SupportedCurves, func(it utls.CurveID) tls.CurveID {
+ return tls.CurveID(it)
+ }),
+ SupportedPoints: info.SupportedPoints,
+ SignatureSchemes: utils.Map(info.SignatureSchemes, func(it utls.SignatureScheme) tls.SignatureScheme {
+ return tls.SignatureScheme(it)
+ }),
+ SupportedProtos: info.SupportedProtos,
+ SupportedVersions: info.SupportedVersions,
+ Extensions: info.Extensions,
+ Conn: info.Conn,
+ //HelloRetryRequest: info.HelloRetryRequest,
+ }
+ *(*context.Context)(unsafe.Add(unsafe.Pointer(tlsInfo), tlsClientHelloInfoCtxOffset)) = info.Context() // for tlsInfo.ctx
+ cert, err := config.GetCertificate(tlsInfo)
+ if err != nil {
+ return nil, err
+ }
+ uCert := UCertificate(*cert)
+ return &uCert, err
+ }
+ }
+ return cfg
}
// BuildWebsocketHandshakeState it will only send http/1.1 in its ALPN.
diff --git a/clash-meta/config/config.go b/clash-meta/config/config.go
index 301126a61e..c2b5664d3d 100644
--- a/clash-meta/config/config.go
+++ b/clash-meta/config/config.go
@@ -1292,7 +1292,7 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rulePro
}
kLower := strings.ToLower(k)
if strings.Contains(kLower, ",") {
- if strings.Contains(kLower, "geosite:") {
+ if strings.HasPrefix(kLower, "geosite:") {
subkeys := strings.Split(k, ":")
subkeys = subkeys[1:]
subkeys = strings.Split(subkeys[0], ",")
@@ -1300,7 +1300,7 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rulePro
newKey := "geosite:" + subkey
policy = append(policy, dns.Policy{Domain: newKey, NameServers: nameservers})
}
- } else if strings.Contains(kLower, "rule-set:") {
+ } else if strings.HasPrefix(kLower, "rule-set:") {
subkeys := strings.Split(k, ":")
subkeys = subkeys[1:]
subkeys = strings.Split(subkeys[0], ",")
@@ -1315,9 +1315,9 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rulePro
}
}
} else {
- if strings.Contains(kLower, "geosite:") {
+ if strings.HasPrefix(kLower, "geosite:") {
policy = append(policy, dns.Policy{Domain: "geosite:" + k[8:], NameServers: nameservers})
- } else if strings.Contains(kLower, "rule-set:") {
+ } else if strings.HasPrefix(kLower, "rule-set:") {
policy = append(policy, dns.Policy{Domain: "rule-set:" + k[9:], NameServers: nameservers})
} else {
policy = append(policy, dns.Policy{Domain: k, NameServers: nameservers})
@@ -1712,7 +1712,7 @@ func parseSniffer(snifferRaw RawSniffer, ruleProviders map[string]P.RuleProvider
}
snifferConfig.SkipSrcAddress = skipSrcAddress
- skipDstAddress, err := parseIPCIDR(snifferRaw.SkipDstAddress, nil, "sniffer.skip-src-address", ruleProviders)
+ skipDstAddress, err := parseIPCIDR(snifferRaw.SkipDstAddress, nil, "sniffer.skip-dst-address", ruleProviders)
if err != nil {
return nil, fmt.Errorf("error in skip-dst-address, error:%w", err)
}
@@ -1731,7 +1731,7 @@ func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string
var matcher C.IpMatcher
for _, ipcidr := range addresses {
ipcidrLower := strings.ToLower(ipcidr)
- if strings.Contains(ipcidrLower, "geoip:") {
+ if strings.HasPrefix(ipcidrLower, "geoip:") {
subkeys := strings.Split(ipcidr, ":")
subkeys = subkeys[1:]
subkeys = strings.Split(subkeys[0], ",")
@@ -1742,7 +1742,7 @@ func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string
}
matchers = append(matchers, matcher)
}
- } else if strings.Contains(ipcidrLower, "rule-set:") {
+ } else if strings.HasPrefix(ipcidrLower, "rule-set:") {
subkeys := strings.Split(ipcidr, ":")
subkeys = subkeys[1:]
subkeys = strings.Split(subkeys[0], ",")
@@ -1778,7 +1778,7 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapte
var matcher C.DomainMatcher
for _, domain := range domains {
domainLower := strings.ToLower(domain)
- if strings.Contains(domainLower, "geosite:") {
+ if strings.HasPrefix(domainLower, "geosite:") {
subkeys := strings.Split(domain, ":")
subkeys = subkeys[1:]
subkeys = strings.Split(subkeys[0], ",")
@@ -1789,7 +1789,7 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapte
}
matchers = append(matchers, matcher)
}
- } else if strings.Contains(domainLower, "rule-set:") {
+ } else if strings.HasPrefix(domainLower, "rule-set:") {
subkeys := strings.Split(domain, ":")
subkeys = subkeys[1:]
subkeys = strings.Split(subkeys[0], ",")
diff --git a/clash-meta/hub/route/server.go b/clash-meta/hub/route/server.go
index 6c47d67294..4e0d0c93f5 100644
--- a/clash-meta/hub/route/server.go
+++ b/clash-meta/hub/route/server.go
@@ -191,7 +191,7 @@ func startTLS(cfg *Config) {
// handle tlsAddr
if len(cfg.TLSAddr) > 0 {
- cert, err := ca.LoadTLSKeyPair(cfg.Certificate, cfg.PrivateKey, C.Path)
+ certLoader, err := ca.NewTLSKeyPairLoader(cfg.Certificate, cfg.PrivateKey)
if err != nil {
log.Errorln("External controller tls listen error: %s", err)
return
@@ -206,7 +206,9 @@ func startTLS(cfg *Config) {
log.Infoln("RESTful API tls listening at: %s", l.Addr().String())
tlsConfig := &tls.Config{Time: ntp.Now}
tlsConfig.NextProtos = []string{"h2", "http/1.1"}
- tlsConfig.Certificates = []tls.Certificate{cert}
+ tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
+ return certLoader()
+ }
tlsConfig.ClientAuth = ca.ClientAuthTypeFromString(cfg.ClientAuthType)
if len(cfg.ClientAuthCert) > 0 {
if tlsConfig.ClientAuth == tls.NoClientCert {
@@ -214,7 +216,7 @@ func startTLS(cfg *Config) {
}
}
if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert {
- pool, err := ca.LoadCertificates(cfg.ClientAuthCert, C.Path)
+ pool, err := ca.LoadCertificates(cfg.ClientAuthCert)
if err != nil {
log.Errorln("External controller tls listen error: %s", err)
return
@@ -223,7 +225,7 @@ func startTLS(cfg *Config) {
}
if cfg.EchKey != "" {
- err = ech.LoadECHKey(cfg.EchKey, tlsConfig, C.Path)
+ err = ech.LoadECHKey(cfg.EchKey, tlsConfig)
if err != nil {
log.Errorln("External controller tls serve error: %s", err)
return
diff --git a/clash-meta/listener/anytls/server.go b/clash-meta/listener/anytls/server.go
index 731f13947e..0d35d4d6af 100644
--- a/clash-meta/listener/anytls/server.go
+++ b/clash-meta/listener/anytls/server.go
@@ -45,14 +45,16 @@ func New(config LC.AnyTLSServer, tunnel C.Tunnel, additions ...inbound.Addition)
tlsConfig := &tls.Config{Time: ntp.Now}
if config.Certificate != "" && config.PrivateKey != "" {
- cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
+ certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey)
if err != nil {
return nil, err
}
- tlsConfig.Certificates = []tls.Certificate{cert}
+ tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
+ return certLoader()
+ }
if config.EchKey != "" {
- err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
+ err = ech.LoadECHKey(config.EchKey, tlsConfig)
if err != nil {
return nil, err
}
@@ -65,7 +67,7 @@ func New(config LC.AnyTLSServer, tunnel C.Tunnel, additions ...inbound.Addition)
}
}
if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert {
- pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
+ pool, err := ca.LoadCertificates(config.ClientAuthCert)
if err != nil {
return nil, err
}
@@ -108,7 +110,7 @@ func New(config LC.AnyTLSServer, tunnel C.Tunnel, additions ...inbound.Addition)
if err != nil {
return nil, err
}
- if len(tlsConfig.Certificates) > 0 {
+ if tlsConfig.GetCertificate != nil {
l = tls.NewListener(l, tlsConfig)
} else {
return nil, errors.New("disallow using AnyTLS without certificates config")
diff --git a/clash-meta/listener/http/server.go b/clash-meta/listener/http/server.go
index 2aba6fda4d..2c537dedd0 100644
--- a/clash-meta/listener/http/server.go
+++ b/clash-meta/listener/http/server.go
@@ -71,14 +71,16 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
var realityBuilder *reality.Builder
if config.Certificate != "" && config.PrivateKey != "" {
- cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
+ certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey)
if err != nil {
return nil, err
}
- tlsConfig.Certificates = []tls.Certificate{cert}
+ tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
+ return certLoader()
+ }
if config.EchKey != "" {
- err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
+ err = ech.LoadECHKey(config.EchKey, tlsConfig)
if err != nil {
return nil, err
}
@@ -91,14 +93,14 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
}
}
if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert {
- pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
+ pool, err := ca.LoadCertificates(config.ClientAuthCert)
if err != nil {
return nil, err
}
tlsConfig.ClientCAs = pool
}
if config.RealityConfig.PrivateKey != "" {
- if tlsConfig.Certificates != nil {
+ if tlsConfig.GetCertificate != nil {
return nil, errors.New("certificate is unavailable in reality")
}
if tlsConfig.ClientAuth != tls.NoClientCert {
@@ -112,7 +114,7 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
if realityBuilder != nil {
l = realityBuilder.NewListener(l)
- } else if len(tlsConfig.Certificates) > 0 {
+ } else if tlsConfig.GetCertificate != nil {
l = tls.NewListener(l, tlsConfig)
}
diff --git a/clash-meta/listener/mixed/mixed.go b/clash-meta/listener/mixed/mixed.go
index 995822b0cf..bc67a476e2 100644
--- a/clash-meta/listener/mixed/mixed.go
+++ b/clash-meta/listener/mixed/mixed.go
@@ -67,14 +67,16 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
var realityBuilder *reality.Builder
if config.Certificate != "" && config.PrivateKey != "" {
- cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
+ certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey)
if err != nil {
return nil, err
}
- tlsConfig.Certificates = []tls.Certificate{cert}
+ tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
+ return certLoader()
+ }
if config.EchKey != "" {
- err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
+ err = ech.LoadECHKey(config.EchKey, tlsConfig)
if err != nil {
return nil, err
}
@@ -87,14 +89,14 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
}
}
if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert {
- pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
+ pool, err := ca.LoadCertificates(config.ClientAuthCert)
if err != nil {
return nil, err
}
tlsConfig.ClientCAs = pool
}
if config.RealityConfig.PrivateKey != "" {
- if tlsConfig.Certificates != nil {
+ if tlsConfig.GetCertificate != nil {
return nil, errors.New("certificate is unavailable in reality")
}
if tlsConfig.ClientAuth != tls.NoClientCert {
@@ -108,7 +110,7 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
if realityBuilder != nil {
l = realityBuilder.NewListener(l)
- } else if len(tlsConfig.Certificates) > 0 {
+ } else if tlsConfig.GetCertificate != nil {
l = tls.NewListener(l, tlsConfig)
}
diff --git a/clash-meta/listener/sing_hysteria2/server.go b/clash-meta/listener/sing_hysteria2/server.go
index becb06b115..493607d525 100644
--- a/clash-meta/listener/sing_hysteria2/server.go
+++ b/clash-meta/listener/sing_hysteria2/server.go
@@ -56,15 +56,17 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi
sl = &Listener{false, config, nil, nil}
- cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
- if err != nil {
- return nil, err
- }
tlsConfig := &tls.Config{
Time: ntp.Now,
MinVersion: tls.VersionTLS13,
}
- tlsConfig.Certificates = []tls.Certificate{cert}
+ certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey)
+ if err != nil {
+ return nil, err
+ }
+ tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
+ return certLoader()
+ }
tlsConfig.ClientAuth = ca.ClientAuthTypeFromString(config.ClientAuthType)
if len(config.ClientAuthCert) > 0 {
if tlsConfig.ClientAuth == tls.NoClientCert {
@@ -72,7 +74,7 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi
}
}
if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert {
- pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
+ pool, err := ca.LoadCertificates(config.ClientAuthCert)
if err != nil {
return nil, err
}
@@ -80,7 +82,7 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi
}
if config.EchKey != "" {
- err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
+ err = ech.LoadECHKey(config.EchKey, tlsConfig)
if err != nil {
return nil, err
}
diff --git a/clash-meta/listener/sing_vless/server.go b/clash-meta/listener/sing_vless/server.go
index 049f5eb1d9..83ba577924 100644
--- a/clash-meta/listener/sing_vless/server.go
+++ b/clash-meta/listener/sing_vless/server.go
@@ -81,14 +81,16 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
var httpServer http.Server
if config.Certificate != "" && config.PrivateKey != "" {
- cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
+ certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey)
if err != nil {
return nil, err
}
- tlsConfig.Certificates = []tls.Certificate{cert}
+ tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
+ return certLoader()
+ }
if config.EchKey != "" {
- err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
+ err = ech.LoadECHKey(config.EchKey, tlsConfig)
if err != nil {
return nil, err
}
@@ -101,14 +103,14 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
}
}
if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert {
- pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
+ pool, err := ca.LoadCertificates(config.ClientAuthCert)
if err != nil {
return nil, err
}
tlsConfig.ClientCAs = pool
}
if config.RealityConfig.PrivateKey != "" {
- if tlsConfig.Certificates != nil {
+ if tlsConfig.GetCertificate != nil {
return nil, errors.New("certificate is unavailable in reality")
}
if tlsConfig.ClientAuth != tls.NoClientCert {
@@ -153,7 +155,7 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
}
if realityBuilder != nil {
l = realityBuilder.NewListener(l)
- } else if len(tlsConfig.Certificates) > 0 {
+ } else if tlsConfig.GetCertificate != nil {
l = tls.NewListener(l, tlsConfig)
} else if sl.decryption == nil {
return nil, errors.New("disallow using Vless without any certificates/reality/decryption config")
diff --git a/clash-meta/listener/sing_vmess/server.go b/clash-meta/listener/sing_vmess/server.go
index 956aa70871..7dd0a163ba 100644
--- a/clash-meta/listener/sing_vmess/server.go
+++ b/clash-meta/listener/sing_vmess/server.go
@@ -81,14 +81,16 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition)
var httpServer http.Server
if config.Certificate != "" && config.PrivateKey != "" {
- cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
+ certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey)
if err != nil {
return nil, err
}
- tlsConfig.Certificates = []tls.Certificate{cert}
+ tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
+ return certLoader()
+ }
if config.EchKey != "" {
- err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
+ err = ech.LoadECHKey(config.EchKey, tlsConfig)
if err != nil {
return nil, err
}
@@ -101,14 +103,14 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition)
}
}
if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert {
- pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
+ pool, err := ca.LoadCertificates(config.ClientAuthCert)
if err != nil {
return nil, err
}
tlsConfig.ClientCAs = pool
}
if config.RealityConfig.PrivateKey != "" {
- if tlsConfig.Certificates != nil {
+ if tlsConfig.GetCertificate != nil {
return nil, errors.New("certificate is unavailable in reality")
}
if tlsConfig.ClientAuth != tls.NoClientCert {
@@ -153,7 +155,7 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition)
}
if realityBuilder != nil {
l = realityBuilder.NewListener(l)
- } else if len(tlsConfig.Certificates) > 0 {
+ } else if tlsConfig.GetCertificate != nil {
l = tls.NewListener(l, tlsConfig)
}
sl.listeners = append(sl.listeners, l)
diff --git a/clash-meta/listener/socks/tcp.go b/clash-meta/listener/socks/tcp.go
index 55e9e59439..45de213530 100644
--- a/clash-meta/listener/socks/tcp.go
+++ b/clash-meta/listener/socks/tcp.go
@@ -66,14 +66,16 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
var realityBuilder *reality.Builder
if config.Certificate != "" && config.PrivateKey != "" {
- cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
+ certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey)
if err != nil {
return nil, err
}
- tlsConfig.Certificates = []tls.Certificate{cert}
+ tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
+ return certLoader()
+ }
if config.EchKey != "" {
- err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
+ err = ech.LoadECHKey(config.EchKey, tlsConfig)
if err != nil {
return nil, err
}
@@ -86,14 +88,14 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
}
}
if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert {
- pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
+ pool, err := ca.LoadCertificates(config.ClientAuthCert)
if err != nil {
return nil, err
}
tlsConfig.ClientCAs = pool
}
if config.RealityConfig.PrivateKey != "" {
- if tlsConfig.Certificates != nil {
+ if tlsConfig.GetCertificate != nil {
return nil, errors.New("certificate is unavailable in reality")
}
if tlsConfig.ClientAuth != tls.NoClientCert {
@@ -107,7 +109,7 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A
if realityBuilder != nil {
l = realityBuilder.NewListener(l)
- } else if len(tlsConfig.Certificates) > 0 {
+ } else if tlsConfig.GetCertificate != nil {
l = tls.NewListener(l, tlsConfig)
}
diff --git a/clash-meta/listener/trojan/server.go b/clash-meta/listener/trojan/server.go
index 6155d20927..e3c1002c9f 100644
--- a/clash-meta/listener/trojan/server.go
+++ b/clash-meta/listener/trojan/server.go
@@ -76,14 +76,16 @@ func New(config LC.TrojanServer, tunnel C.Tunnel, additions ...inbound.Addition)
var httpServer http.Server
if config.Certificate != "" && config.PrivateKey != "" {
- cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
+ certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey)
if err != nil {
return nil, err
}
- tlsConfig.Certificates = []tls.Certificate{cert}
+ tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
+ return certLoader()
+ }
if config.EchKey != "" {
- err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
+ err = ech.LoadECHKey(config.EchKey, tlsConfig)
if err != nil {
return nil, err
}
@@ -96,14 +98,14 @@ func New(config LC.TrojanServer, tunnel C.Tunnel, additions ...inbound.Addition)
}
}
if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert {
- pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
+ pool, err := ca.LoadCertificates(config.ClientAuthCert)
if err != nil {
return nil, err
}
tlsConfig.ClientCAs = pool
}
if config.RealityConfig.PrivateKey != "" {
- if tlsConfig.Certificates != nil {
+ if tlsConfig.GetCertificate != nil {
return nil, errors.New("certificate is unavailable in reality")
}
if tlsConfig.ClientAuth != tls.NoClientCert {
@@ -148,7 +150,7 @@ func New(config LC.TrojanServer, tunnel C.Tunnel, additions ...inbound.Addition)
}
if realityBuilder != nil {
l = realityBuilder.NewListener(l)
- } else if len(tlsConfig.Certificates) > 0 {
+ } else if tlsConfig.GetCertificate != nil {
l = tls.NewListener(l, tlsConfig)
} else if !config.TrojanSSOption.Enabled {
return nil, errors.New("disallow using Trojan without both certificates/reality/ss config")
diff --git a/clash-meta/listener/tuic/server.go b/clash-meta/listener/tuic/server.go
index 30845515e7..7e659e596a 100644
--- a/clash-meta/listener/tuic/server.go
+++ b/clash-meta/listener/tuic/server.go
@@ -49,15 +49,17 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) (
return nil, err
}
- cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path)
- if err != nil {
- return nil, err
- }
tlsConfig := &tls.Config{
Time: ntp.Now,
MinVersion: tls.VersionTLS13,
}
- tlsConfig.Certificates = []tls.Certificate{cert}
+ certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey)
+ if err != nil {
+ return nil, err
+ }
+ tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
+ return certLoader()
+ }
tlsConfig.ClientAuth = ca.ClientAuthTypeFromString(config.ClientAuthType)
if len(config.ClientAuthCert) > 0 {
if tlsConfig.ClientAuth == tls.NoClientCert {
@@ -65,7 +67,7 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) (
}
}
if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert {
- pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path)
+ pool, err := ca.LoadCertificates(config.ClientAuthCert)
if err != nil {
return nil, err
}
@@ -73,7 +75,7 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) (
}
if config.EchKey != "" {
- err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path)
+ err = ech.LoadECHKey(config.EchKey, tlsConfig)
if err != nil {
return nil, err
}
diff --git a/clash-nyanpasu/.github/workflows/ci.yml b/clash-nyanpasu/.github/workflows/ci.yml
index 8f644fac29..f88103e3e0 100644
--- a/clash-nyanpasu/.github/workflows/ci.yml
+++ b/clash-nyanpasu/.github/workflows/ci.yml
@@ -27,8 +27,8 @@ jobs:
- uses: actions/checkout@v5
- name: Rust
run: |
- rustup toolchain install stable --profile minimal --no-self-update
- rustup default stable
+ rustup toolchain install nightly --profile minimal --no-self-update
+ rustup default nightly
rustup component add clippy rustfmt
rustc --version
cargo --version
diff --git a/clash-nyanpasu/.github/workflows/deps-build-linux.yaml b/clash-nyanpasu/.github/workflows/deps-build-linux.yaml
index 1eb8d6ba6e..27d467b1b1 100644
--- a/clash-nyanpasu/.github/workflows/deps-build-linux.yaml
+++ b/clash-nyanpasu/.github/workflows/deps-build-linux.yaml
@@ -49,10 +49,10 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v5
- - name: Install Rust stable
+ - name: Install Rust nightly
run: |
- rustup install stable --profile minimal --no-self-update
- rustup default stable
+ rustup install nightly --profile minimal --no-self-update
+ rustup default nightly
- name: Setup Cargo binstall
if: ${{ inputs.arch != 'x86_64' }}
diff --git a/clash-nyanpasu/.github/workflows/deps-build-macos.yaml b/clash-nyanpasu/.github/workflows/deps-build-macos.yaml
index 0be70ff28f..0a9ab05d74 100644
--- a/clash-nyanpasu/.github/workflows/deps-build-macos.yaml
+++ b/clash-nyanpasu/.github/workflows/deps-build-macos.yaml
@@ -51,10 +51,10 @@ jobs:
with:
xcode-version: 16
- - name: install Rust stable
+ - name: install Rust nightly
run: |
- rustup install stable --profile minimal --no-self-update
- rustup default stable
+ rustup install nightly --profile minimal --no-self-update
+ rustup default nightly
- name: Install Rust intel target
if: ${{ inputs.aarch64 == false }}
diff --git a/clash-nyanpasu/.github/workflows/deps-build-windows-nsis.yaml b/clash-nyanpasu/.github/workflows/deps-build-windows-nsis.yaml
index e1ab01827f..3c45d78377 100644
--- a/clash-nyanpasu/.github/workflows/deps-build-windows-nsis.yaml
+++ b/clash-nyanpasu/.github/workflows/deps-build-windows-nsis.yaml
@@ -75,10 +75,10 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v5
- - name: Install Rust stable
+ - name: Install Rust nightly
run: |
- rustup install stable --profile minimal --no-self-update
- rustup default stable
+ rustup install nightly --profile minimal --no-self-update
+ rustup default nightly
- name: Setup Rust target
if: ${{ inputs.arch != 'x86_64' }}
diff --git a/clash-nyanpasu/.github/workflows/macos-aarch64.yaml b/clash-nyanpasu/.github/workflows/macos-aarch64.yaml
index 1b27b62e21..c23c06c1de 100644
--- a/clash-nyanpasu/.github/workflows/macos-aarch64.yaml
+++ b/clash-nyanpasu/.github/workflows/macos-aarch64.yaml
@@ -13,15 +13,15 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v5
- - name: install Rust stable
+ - name: install Rust nightly
run: |
- rustup install stable --profile minimal --no-self-update
- rustup default stable
+ rustup install nightly --profile minimal --no-self-update
+ rustup default nightly
- uses: Swatinem/rust-cache@v2
with:
workspaces: './backend/'
- prefix-key: 'rust-stable'
+ prefix-key: 'rust-nightly'
key: 'macos-13'
shared-key: 'release'
- uses: maxim-lobanov/setup-xcode@v1
diff --git a/clash-nyanpasu/.lintstagedrc.js b/clash-nyanpasu/.lintstagedrc.js
index 330d341d70..278366d955 100644
--- a/clash-nyanpasu/.lintstagedrc.js
+++ b/clash-nyanpasu/.lintstagedrc.js
@@ -1,5 +1,19 @@
export default {
- '*.{js,cjs,.mjs,jsx}': ['prettier --write', 'eslint --cache --fix'],
+ '*.{js,cjs,.mjs,jsx}': (filenames) => {
+ const configFiles = [
+ 'eslint.config.js',
+ '.lintstagedrc.js',
+ 'commitlint.config.js',
+ ]
+ const filtered = filenames.filter(
+ (file) => !configFiles.some((config) => file.endsWith(config)),
+ )
+ if (filtered.length === 0) return []
+ return [
+ `prettier --write ${filtered.join(' ')}`,
+ `eslint --cache --fix ${filtered.join(' ')}`,
+ ]
+ },
'scripts/**/*.{ts,tsx}': [
'prettier --write',
'eslint --cache --fix',
diff --git a/clash-nyanpasu/.prettierignore b/clash-nyanpasu/.prettierignore
index 8b9a24961f..c048b5bab3 100644
--- a/clash-nyanpasu/.prettierignore
+++ b/clash-nyanpasu/.prettierignore
@@ -8,4 +8,5 @@ pnpm-lock.yaml
*.wxs
frontend/nyanpasu/src/route-tree.gen.ts
frontend/nyanpasu/auto-imports.d.ts
+frontend/nyanpasu/src/paraglide/
backend/tauri/gen/schemas/
diff --git a/clash-nyanpasu/backend/Cargo.lock b/clash-nyanpasu/backend/Cargo.lock
index 3030173d8e..f3ac23b084 100644
--- a/clash-nyanpasu/backend/Cargo.lock
+++ b/clash-nyanpasu/backend/Cargo.lock
@@ -4457,7 +4457,7 @@ checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408"
[[package]]
name = "include-compress-bytes"
version = "0.1.0"
-source = "git+https://github.com/libnyanpasu/include-compress-bytes?rev=250a12c#250a12c13a8fed1cd2c0476e01c3dd89555840d2"
+source = "git+https://github.com/libnyanpasu/include-compress-bytes?rev=4e4f25b#4e4f25b794ed0b9a323a893bcdaf22f5024ab58a"
dependencies = [
"brotli",
"cargo-emit 0.2.1",
@@ -4470,7 +4470,7 @@ dependencies = [
[[package]]
name = "include_url_macro"
version = "0.1.0"
-source = "git+https://github.com/libnyanpasu/include_url_macro?rev=b0b88e5#b0b88e5dd0685e607c6d965420fc2a035b4a0efe"
+source = "git+https://github.com/libnyanpasu/include_url_macro?rev=fbe47bd#fbe47bd71047892a218e3166a2a1bac474488218"
dependencies = [
"brotli",
"bytes",
diff --git a/clash-nyanpasu/backend/boa_utils/Cargo.toml b/clash-nyanpasu/backend/boa_utils/Cargo.toml
index a705bac3dd..6c05a5fdd3 100644
--- a/clash-nyanpasu/backend/boa_utils/Cargo.toml
+++ b/clash-nyanpasu/backend/boa_utils/Cargo.toml
@@ -24,8 +24,8 @@ tracing = "0.1"
url = "2"
log = "0.4"
anyhow = "1.0"
-include_url_macro = { git = "https://github.com/libnyanpasu/include_url_macro", rev = "b0b88e5" }
-include-compress-bytes = { git = "https://github.com/libnyanpasu/include-compress-bytes", rev = "250a12c" }
+include_url_macro = { git = "https://github.com/libnyanpasu/include_url_macro", rev = "fbe47bd" }
+include-compress-bytes = { git = "https://github.com/libnyanpasu/include-compress-bytes", rev = "4e4f25b" }
phf = { version = "0.13.1", features = ["macros"] }
# for cacheing
diff --git a/clash-nyanpasu/eslint.config.js b/clash-nyanpasu/eslint.config.js
index ceb584891e..e39731a8ff 100644
--- a/clash-nyanpasu/eslint.config.js
+++ b/clash-nyanpasu/eslint.config.js
@@ -31,6 +31,10 @@ const ignores = [
'dist/',
'backend/',
'backend/**/target',
+ 'scripts/deno/**',
+ 'eslint.config.js',
+ '.lintstagedrc.js',
+ 'commitlint.config.js',
]
export default tseslint.config(
@@ -80,7 +84,12 @@ export default tseslint.config(
{
files: ['**/*.{ts,tsx,mtsx}'],
extends: [...tseslint.configs.recommended],
- ignores: [...ignores, '**/vite.config.ts', '**/tailwind.config.ts'],
+ ignores: [
+ ...ignores,
+ 'frontend/nyanpasu/vite.config.ts',
+ 'frontend/nyanpasu/tailwind.config.ts',
+ 'frontend/ui/vite.config.ts',
+ ],
rules: {
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
@@ -93,7 +102,10 @@ export default tseslint.config(
},
},
{
- files: ['**/vite.config.ts', '**/tailwind.config.ts'],
+ files: [
+ 'frontend/nyanpasu/vite.config.ts',
+ 'frontend/nyanpasu/tailwind.config.ts',
+ ],
extends: [...tseslint.configs.recommended],
rules: {
'@typescript-eslint/no-unused-vars': 'warn',
@@ -105,6 +117,19 @@ export default tseslint.config(
},
},
},
+ {
+ files: ['frontend/ui/vite.config.ts'],
+ extends: [...tseslint.configs.recommended],
+ rules: {
+ '@typescript-eslint/no-unused-vars': 'warn',
+ '@typescript-eslint/no-explicit-any': 'warn',
+ },
+ languageOptions: {
+ parserOptions: {
+ project: './frontend/ui/tsconfig.json',
+ },
+ },
+ },
{
files: ['**/*.{jsx,mjsx,tsx,mtsx}'],
languageOptions: {
diff --git a/clash-nyanpasu/frontend/nyanpasu/messages/en.json b/clash-nyanpasu/frontend/nyanpasu/messages/en.json
index ec447d095a..d97c5ba8bd 100644
--- a/clash-nyanpasu/frontend/nyanpasu/messages/en.json
+++ b/clash-nyanpasu/frontend/nyanpasu/messages/en.json
@@ -17,5 +17,18 @@
"settings_system_proxy_proxy_bypass_label": "System Proxy Bypass",
"settings_system_proxy_current_system_proxy_label": "Current System Proxy",
"settings_user_interface_title": "User Interface",
- "unit_seconds": "s"
+ "settings_user_interface_language_label": "Language",
+ "settings_user_interface_theme_mode_label": "Theme Mode",
+ "settings_user_interface_theme_mode_light": "Light",
+ "settings_user_interface_theme_mode_dark": "Dark",
+ "settings_user_interface_theme_mode_system": "System",
+ "settings_user_interface_theme_color_label": "Theme Color",
+ "settings_clash_settings_title": "Clash Settings",
+ "settings_clash_settings_allow_lan_label": "Allow LAN",
+ "settings_clash_settings_ipv6_label": "Enable IPv6",
+ "settings_clash_settings_tun_stack_label": "TUN Stack",
+ "settings_clash_settings_log_level_label": "Log Level",
+ "unit_seconds": "s",
+ "common_submit": "Submit",
+ "common_cancel": "Cancel"
}
diff --git a/clash-nyanpasu/frontend/nyanpasu/messages/ru.json b/clash-nyanpasu/frontend/nyanpasu/messages/ru.json
index 353f3fc9d0..c756167bb6 100644
--- a/clash-nyanpasu/frontend/nyanpasu/messages/ru.json
+++ b/clash-nyanpasu/frontend/nyanpasu/messages/ru.json
@@ -17,5 +17,18 @@
"settings_system_proxy_proxy_bypass_label": "Обход прокси",
"settings_system_proxy_current_system_proxy_label": "Текущий системный прокси",
"settings_user_interface_title": "Интерфейс пользователя",
- "unit_seconds": "секунды"
+ "settings_user_interface_language_label": "Язык",
+ "settings_user_interface_theme_mode_label": "Режим темы",
+ "settings_user_interface_theme_mode_light": "Светлый",
+ "settings_user_interface_theme_mode_dark": "Темный",
+ "settings_user_interface_theme_mode_system": "Системный",
+ "settings_user_interface_theme_color_label": "Цвет темы",
+ "settings_clash_settings_title": "Настройки Clash",
+ "settings_clash_settings_allow_lan_label": "Разрешить LAN",
+ "settings_clash_settings_ipv6_label": "Включить IPv6",
+ "settings_clash_settings_tun_stack_label": "TUN Stack",
+ "settings_clash_settings_log_level_label": "Уровень журнала",
+ "unit_seconds": "секунды",
+ "common_submit": "Отправить",
+ "common_cancel": "Отменить"
}
diff --git a/clash-nyanpasu/frontend/nyanpasu/messages/zh-cn.json b/clash-nyanpasu/frontend/nyanpasu/messages/zh-cn.json
index d731200aab..b795099c0a 100644
--- a/clash-nyanpasu/frontend/nyanpasu/messages/zh-cn.json
+++ b/clash-nyanpasu/frontend/nyanpasu/messages/zh-cn.json
@@ -17,5 +17,18 @@
"settings_system_proxy_proxy_bypass_label": "系统代理绕过",
"settings_system_proxy_current_system_proxy_label": "当前系统代理",
"settings_user_interface_title": "用户界面",
- "unit_seconds": "秒"
+ "settings_user_interface_language_label": "语言",
+ "settings_user_interface_theme_mode_label": "主题模式",
+ "settings_user_interface_theme_mode_light": "浅色",
+ "settings_user_interface_theme_mode_dark": "深色",
+ "settings_user_interface_theme_mode_system": "跟随系统",
+ "settings_user_interface_theme_color_label": "主题颜色",
+ "settings_clash_settings_title": "Clash 设置",
+ "settings_clash_settings_allow_lan_label": "允许局域网连接",
+ "settings_clash_settings_ipv6_label": "启用 IPv6",
+ "settings_clash_settings_tun_stack_label": "TUN 堆栈",
+ "settings_clash_settings_log_level_label": "日志级别",
+ "unit_seconds": "秒",
+ "common_submit": "提交",
+ "common_cancel": "取消"
}
diff --git a/clash-nyanpasu/frontend/nyanpasu/messages/zh-tw.json b/clash-nyanpasu/frontend/nyanpasu/messages/zh-tw.json
index 1a3dbaf0f9..7e2b14594f 100644
--- a/clash-nyanpasu/frontend/nyanpasu/messages/zh-tw.json
+++ b/clash-nyanpasu/frontend/nyanpasu/messages/zh-tw.json
@@ -17,5 +17,18 @@
"settings_system_proxy_proxy_bypass_label": "系統代理繞過",
"settings_system_proxy_current_system_proxy_label": "當前系統代理",
"settings_user_interface_title": "使用者介面",
- "unit_seconds": "秒"
+ "settings_user_interface_language_label": "語言",
+ "settings_user_interface_theme_mode_label": "主題模式",
+ "settings_user_interface_theme_mode_light": "淺色",
+ "settings_user_interface_theme_mode_dark": "深色",
+ "settings_user_interface_theme_mode_system": "跟隨系統",
+ "settings_user_interface_theme_color_label": "主題顏色",
+ "settings_clash_settings_title": "Clash 設置",
+ "settings_clash_settings_allow_lan_label": "允許區域網路連線",
+ "settings_clash_settings_ipv6_label": "啟用 IPv6",
+ "settings_clash_settings_tun_stack_label": "TUN 堆棧",
+ "settings_clash_settings_log_level_label": "日誌級別",
+ "unit_seconds": "秒",
+ "common_submit": "提交",
+ "common_cancel": "取消"
}
diff --git a/clash-nyanpasu/frontend/nyanpasu/package.json b/clash-nyanpasu/frontend/nyanpasu/package.json
index 99c06ffc43..1cc8f99ff6 100644
--- a/clash-nyanpasu/frontend/nyanpasu/package.json
+++ b/clash-nyanpasu/frontend/nyanpasu/package.json
@@ -23,14 +23,18 @@
"@mui/x-date-pickers": "8.17.0",
"@nyanpasu/interface": "workspace:^",
"@nyanpasu/ui": "workspace:^",
+ "@radix-ui/react-dropdown-menu": "2.1.16",
"@radix-ui/react-scroll-area": "1.2.10",
+ "@radix-ui/react-select": "2.2.6",
"@radix-ui/react-slot": "1.2.4",
- "@radix-ui/react-switch": "^1.2.6",
+ "@radix-ui/react-switch": "1.2.6",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
"@tailwindcss/postcss": "4.1.17",
"@tanstack/router-zod-adapter": "1.81.5",
"@tauri-apps/api": "2.8.0",
"@types/json-schema": "7.0.15",
"@uidotdev/usehooks": "2.4.1",
+ "@uiw/react-color": "2.9.2",
"ahooks": "3.9.6",
"allotment": "1.20.4",
"class-variance-authority": "0.7.1",
@@ -93,7 +97,7 @@
"shiki": "2.5.0",
"unplugin-auto-import": "20.3.0",
"unplugin-icons": "22.5.0",
- "validator": "13.15.23",
+ "validator": "13.15.26",
"vite": "7.2.4",
"vite-plugin-html": "3.2.2",
"vite-plugin-sass-dts": "1.3.34",
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/providers/language-provider.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/providers/language-provider.tsx
new file mode 100644
index 0000000000..21233dc992
--- /dev/null
+++ b/clash-nyanpasu/frontend/nyanpasu/src/components/providers/language-provider.tsx
@@ -0,0 +1,44 @@
+import { createContext, PropsWithChildren, useContext, useEffect } from 'react'
+import { useLockFn } from '@/hooks/use-lock-fn'
+import { getLocale, Locale, setLocale } from '@/paraglide/runtime'
+import { useSetting } from '@nyanpasu/interface'
+
+const LanguageContext = createContext<{
+ language?: Locale
+ setLanguage: (value: Locale) => Promise
+} | null>(null)
+
+export const useLanguage = () => {
+ const context = useContext(LanguageContext)
+
+ if (!context) {
+ throw new Error('useLanguage must be used within a LanguageProvider')
+ }
+
+ return context
+}
+
+export const LanguageProvider = ({ children }: PropsWithChildren) => {
+ const language = useSetting('language')
+
+ const setLanguage = useLockFn(async (value: Locale) => {
+ await language.upsert(value)
+ })
+
+ useEffect(() => {
+ if (language.value && language.value !== getLocale()) {
+ setLocale(language.value as Locale)
+ }
+ }, [language.value])
+
+ return (
+
+ {children}
+
+ )
+}
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/providers/theme-provider.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/providers/theme-provider.tsx
index aa08f80436..77c59f2e8f 100644
--- a/clash-nyanpasu/frontend/nyanpasu/src/components/providers/theme-provider.tsx
+++ b/clash-nyanpasu/frontend/nyanpasu/src/components/providers/theme-provider.tsx
@@ -14,10 +14,19 @@ import {
themeFromSourceColor,
} from '@material/material-color-utilities'
import { useSetting } from '@nyanpasu/interface'
+import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
import { useLocalStorage } from '@uidotdev/usehooks'
+const appWindow = getCurrentWebviewWindow()
+
export const DEFAULT_COLOR = '#1867C0'
+export enum ThemeMode {
+ LIGHT = 'light',
+ DARK = 'dark',
+ SYSTEM = 'system',
+}
+
const CUSTOM_THEME_KEY = 'custom-theme' as const
const THEME_PALETTE_KEY = 'theme-palette-v1' as const
@@ -52,11 +61,29 @@ const generateThemeCssVars = ({ schemes }: Theme) => {
return lightCssVars + darkCssVars
}
+const changeHtmlThemeMode = (mode: Omit) => {
+ const root = document.documentElement
+
+ if (mode === ThemeMode.DARK) {
+ root.classList.add(ThemeMode.DARK)
+ } else {
+ root.classList.remove(ThemeMode.DARK)
+ }
+
+ if (mode === ThemeMode.LIGHT) {
+ root.classList.add(ThemeMode.LIGHT)
+ } else {
+ root.classList.remove(ThemeMode.LIGHT)
+ }
+}
+
const ThemeContext = createContext<{
themePalette: Theme
themeCssVars: string
themeColor: string
- setTheme: (color: string) => void
+ setThemeColor: (color: string) => Promise
+ themeMode: ThemeMode
+ setThemeMode: (mode: ThemeMode) => Promise
} | null>(null)
export function useExperimentalThemeContext() {
@@ -72,13 +99,15 @@ export function useExperimentalThemeContext() {
}
export function ExperimentalThemeProvider({ children }: PropsWithChildren) {
- const { value: themeColor } = useSetting('theme_color')
+ const themeMode = useSetting('theme_mode')
+
+ const themeColor = useSetting('theme_color')
const [cachedThemePalette, setCachedThemePalette] = useLocalStorage(
THEME_PALETTE_KEY,
themeFromSourceColor(
// use default color if theme color is not set
- argbFromHex(themeColor || DEFAULT_COLOR),
+ argbFromHex(themeColor.value || DEFAULT_COLOR),
),
)
@@ -93,10 +122,12 @@ export function ExperimentalThemeProvider({ children }: PropsWithChildren) {
insertStyle(CUSTOM_THEME_KEY, cachedThemeCssVars)
}, [cachedThemeCssVars])
- const setTheme = useCallback(
- (color: string) => {
- if (color === themeColor) {
+ const setThemeColor = useCallback(
+ async (color: string) => {
+ if (color === themeColor.value) {
return
+ } else {
+ await themeColor.upsert(color)
}
const materialColor = themeFromSourceColor(
@@ -121,13 +152,42 @@ export function ExperimentalThemeProvider({ children }: PropsWithChildren) {
],
)
+ // listen to theme changed event and change html theme mode
+ useEffect(() => {
+ const unlisten = appWindow.onThemeChanged((e) => {
+ if (themeMode.value === ThemeMode.SYSTEM) {
+ changeHtmlThemeMode(e.payload)
+ }
+ })
+
+ return () => {
+ unlisten.then((fn) => fn())
+ }
+ }, [themeMode.value])
+
+ const setThemeMode = useCallback(
+ async (mode: ThemeMode) => {
+ // if theme mode is not system, change html theme mode
+ if (mode !== ThemeMode.SYSTEM) {
+ changeHtmlThemeMode(mode)
+ }
+
+ if (mode !== themeMode.value) {
+ await themeMode.upsert(mode)
+ }
+ },
+ [themeMode],
+ )
+
return (
{children}
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-ui.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-ui.tsx
index 7ddbb04c2e..2533df5bf8 100644
--- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-ui.tsx
+++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-nyanpasu-ui.tsx
@@ -4,11 +4,13 @@ import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { isHexColor } from 'validator'
import { atomIsDrawerOnlyIcon } from '@/store'
+import { setEnabledExperimentalRouter } from '@/utils/experimental'
import { languageOptions } from '@/utils/language'
import Done from '@mui/icons-material/Done'
import { Button, List, ListItem, ListItemText } from '@mui/material'
import { useSetting } from '@nyanpasu/interface'
import { BaseCard, Expand, MenuItem, SwitchItem } from '@nyanpasu/ui'
+import { useNavigate } from '@tanstack/react-router'
import { DEFAULT_COLOR } from '../layout/use-custom-theme'
const commonSx = {
@@ -106,6 +108,25 @@ const ThemeColor = () => {
)
}
+const ExperimentalSwitch = () => {
+ const navigate = useNavigate()
+
+ const handleClick = () => {
+ setEnabledExperimentalRouter(true)
+ navigate({ to: '/experimental/dashboard' })
+ }
+
+ return (
+
+
+
+
+
+ )
+}
+
export const SettingNyanpasuUI = () => {
const { t } = useTranslation()
@@ -125,6 +146,8 @@ export const SettingNyanpasuUI = () => {
checked={onlyIcon}
onChange={() => setOnlyIcon(!onlyIcon)}
/>
+
+
)
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/settings/system-proxy.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/settings/system-proxy.tsx
index b49ff06dd5..60fbe32037 100644
--- a/clash-nyanpasu/frontend/nyanpasu/src/components/settings/system-proxy.tsx
+++ b/clash-nyanpasu/frontend/nyanpasu/src/components/settings/system-proxy.tsx
@@ -21,7 +21,7 @@ const ProxyButton = ({
className={cn(
'group h-16 rounded-3xl font-bold',
'flex items-center justify-between gap-2',
- 'data-[active=false]:bg-black',
+ 'data-[active=false]:bg-white dark:data-[active=false]:bg-black',
className,
)}
data-active={String(Boolean(isActive))}
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/ui/dropdown-menu.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/ui/dropdown-menu.tsx
new file mode 100644
index 0000000000..bb3595012e
--- /dev/null
+++ b/clash-nyanpasu/frontend/nyanpasu/src/components/ui/dropdown-menu.tsx
@@ -0,0 +1,259 @@
+import Check from '~icons/material-symbols/check-rounded'
+import RadioChecked from '~icons/material-symbols/radio-button-checked'
+import Radio from '~icons/material-symbols/radio-button-unchecked'
+import { AnimatePresence, motion } from 'framer-motion'
+import { ComponentProps, createContext, useContext } from 'react'
+import { cn } from '@nyanpasu/ui'
+import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
+import { useControllableState } from '@radix-ui/react-use-controllable-state'
+
+const DropdownMenuContext = createContext<{
+ open: boolean
+} | null>(null)
+
+const useDropdownMenuContext = () => {
+ const context = useContext(DropdownMenuContext)
+
+ if (context === null) {
+ throw new Error(
+ 'DropdownMenu compound components cannot be rendered outside the DropdownMenu component',
+ )
+ }
+
+ return context
+}
+
+export const DropdownMenu = ({
+ open: inputOpen,
+ defaultOpen,
+ onOpenChange,
+ ...props
+}: ComponentProps) => {
+ const [open, setOpen] = useControllableState({
+ prop: inputOpen,
+ defaultProp: defaultOpen ?? false,
+ onChange: onOpenChange,
+ })
+
+ return (
+
+
+
+ )
+}
+
+export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
+
+export const DropdownMenuGroup = DropdownMenuPrimitive.Group
+
+export const DropdownMenuPortal = DropdownMenuPrimitive.Portal
+
+export const DropdownMenuSub = DropdownMenuPrimitive.Sub
+
+const DropdownMenuRadioGroupContext = createContext<{
+ value: string | null
+}>({ value: null })
+
+const useDropdownMenuRadioGroupContext = () => {
+ const context = useContext(DropdownMenuRadioGroupContext)
+
+ if (context === undefined) {
+ throw new Error(
+ 'DropdownMenuRadioGroup compound components cannot be rendered outside the DropdownMenuRadioGroup component',
+ )
+ }
+
+ return context
+}
+
+export const DropdownMenuRadioGroup = ({
+ value: inputValue,
+ defaultValue,
+ onValueChange,
+ ...props
+}: ComponentProps) => {
+ const [value, setValue] = useControllableState({
+ prop: inputValue,
+ defaultProp: String(defaultValue),
+ onChange: onValueChange,
+ })
+
+ return (
+
+
+
+ )
+}
+
+export const DropdownMenuSubTrigger = DropdownMenuPrimitive.SubTrigger
+
+export const DropdownMenuSubContent = DropdownMenuPrimitive.SubContent
+
+export const DropdownMenuContent = ({
+ children,
+ className,
+ ...props
+}: ComponentProps) => {
+ const { open } = useDropdownMenuContext()
+
+ return (
+
+ {open && (
+
+
+
+ {children}
+
+
+
+ )}
+
+ )
+}
+
+export const DropdownMenuItem = ({
+ className,
+ ...props
+}: ComponentProps) => {
+ return (
+
+ )
+}
+
+export const DropdownMenuCheckboxItem = ({
+ children,
+ className,
+ ...props
+}: ComponentProps) => {
+ return (
+
+ {children}
+
+
+
+
+
+ )
+}
+
+export const DropdownMenuRadioItem = ({
+ value,
+ children,
+ className,
+ ...props
+}: ComponentProps) => {
+ const context = useDropdownMenuRadioGroupContext()
+
+ const selected = context.value === value
+
+ return (
+
+
+
+
+
+ {!selected && (
+
+
+
+ )}
+
+ {children}
+
+ )
+}
+
+export const DropdownMenuLabel = ({
+ className,
+ ...props
+}: ComponentProps) => {
+ return (
+
+ )
+}
+
+export const DropdownMenuSeparator = ({
+ className,
+ ...props
+}: ComponentProps) => {
+ return (
+
+ )
+}
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/ui/select.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/ui/select.tsx
new file mode 100644
index 0000000000..f74277ddc2
--- /dev/null
+++ b/clash-nyanpasu/frontend/nyanpasu/src/components/ui/select.tsx
@@ -0,0 +1,505 @@
+import ArrowDropDown from '~icons/material-symbols/arrow-drop-down-rounded'
+import Check from '~icons/material-symbols/check-rounded'
+import { cva, type VariantProps } from 'class-variance-authority'
+import { AnimatePresence, motion } from 'framer-motion'
+import {
+ ComponentProps,
+ createContext,
+ useCallback,
+ useContext,
+ useEffect,
+ useState,
+} from 'react'
+import { chains } from '@/utils/chain'
+import { cn } from '@nyanpasu/ui'
+import * as SelectPrimitive from '@radix-ui/react-select'
+import { useControllableState } from '@radix-ui/react-use-controllable-state'
+
+export const selectTriggerVariants = cva(
+ [
+ 'group relative box-border inline-flex w-full flex-auto items-baseline',
+ 'cursor-pointer',
+ 'px-4 py-4 outline-hidden',
+ // TODO: size variants, fix this
+ 'flex items-center justify-between h-14',
+ 'dark:text-on-surface',
+ ],
+ {
+ variants: {
+ variant: {
+ filled: 'rounded-t bg-surface-variant dark:bg-on-surface-variant',
+ // outlined use selectValuePlaceholderFieldsetVariants
+ outlined: '',
+ },
+ },
+ defaultVariants: {
+ variant: 'filled',
+ },
+ },
+)
+
+export type SelectTriggerVariants = VariantProps
+
+export const selectLineVariants = cva('', {
+ variants: {
+ variant: {
+ filled: [
+ 'absolute inset-x-0 bottom-0 w-full border-b border-on-primary-container',
+ 'transition-all duration-200',
+
+ // pseudo elements be overlay parent element, will not affect the box size
+ 'after:absolute after:inset-x-0 after:bottom-0 after:z-10',
+ "after:scale-x-0 after:border-b-2 after:opacity-0 after:content-['']",
+ 'after:transition-all after:duration-200',
+ 'after:border-primary dark:after:border-on-primary-container',
+
+ // sync parent group state, state from radix-ui
+ 'group-data-[state=open]:border-b-0',
+ 'group-data-[state=open]:after:scale-x-100',
+ 'group-data-[state=open]:after:opacity-100',
+ 'peer-focus:border-b-0',
+ 'peer-focus:after:scale-x-100',
+ 'peer-focus:after:opacity-100',
+ ],
+ // hidden line for outlined variant
+ outlined: 'hidden',
+ },
+ },
+ defaultVariants: {
+ variant: 'filled',
+ },
+})
+
+export type SelectLineVariants = VariantProps
+
+export const selectValueVariants = cva('pointer-events-none', {
+ variants: {
+ variant: {
+ filled: '',
+ outlined: '',
+ },
+ haveValue: {
+ true: '',
+ false: '',
+ },
+ },
+ compoundVariants: [
+ {
+ variant: 'filled',
+ haveValue: true,
+ className: 'mt-3',
+ },
+ ],
+ defaultVariants: {
+ variant: 'filled',
+ haveValue: false,
+ },
+})
+
+export type SelectValueVariants = VariantProps
+
+export const selectValuePlaceholderVariants = cva(
+ [
+ 'absolute',
+ 'left-4 top-4',
+ 'pointer-events-none',
+ 'text-base select-none',
+ // TODO: only transition position, not text color
+ 'transition-all duration-200',
+ ],
+ {
+ variants: {
+ variant: {
+ filled: [
+ 'group-data-[state=open]:top-2 group-data-[state=open]:dark:text-surface',
+ 'group-data-[state=open]:text-xs group-data-[state=open]:text-primary',
+ ],
+ outlined: [
+ 'group-data-[state=open]:-top-2',
+ 'group-data-[state=open]:text-sm',
+ 'group-data-[state=open]:text-primary',
+
+ 'dark:group-data-[state=open]:text-inverse-primary',
+ 'dark:group-data-[state=closed]:text-on-primary-container',
+ ],
+ },
+ focus: {
+ true: '',
+ false: '',
+ },
+ },
+ compoundVariants: [
+ {
+ variant: 'filled',
+ focus: true,
+ className: 'top-2 text-xs',
+ },
+ {
+ variant: 'outlined',
+ focus: true,
+ className: '-top-2 text-sm',
+ },
+ ],
+ defaultVariants: {
+ variant: 'filled',
+ focus: false,
+ },
+ },
+)
+
+export type SelectValuePlaceholderVariants = VariantProps<
+ typeof selectValuePlaceholderVariants
+>
+
+export const selectValuePlaceholderFieldsetVariants = cva(
+ 'pointer-events-none',
+ {
+ variants: {
+ variant: {
+ // only for outlined variant
+ filled: 'hidden',
+ outlined: [
+ 'absolute inset-0 text-left',
+ 'rounded transition-all duration-200',
+ // may open border width will be 1.5, idk
+ 'group-data-[state=closed]:border',
+ 'group-data-[state=open]:border-2',
+ 'peer-not-focus:border',
+ 'peer-focus:border-2',
+ // different material web border color, i think this looks better
+ 'group-data-[state=closed]:border-outline-variant',
+ 'group-data-[state=open]:border-primary',
+ 'peer-not-focus:border-primary-container',
+ 'peer-focus:border-primary',
+ // dark must be prefixed
+ 'dark:group-data-[state=closed]:border-outline-variant',
+ 'dark:group-data-[state=open]:border-primary-container',
+ 'dark:peer-not-focus:border-outline-variant',
+ 'dark:peer-focus:border-primary-container',
+ ],
+ },
+ },
+ defaultVariants: {
+ variant: 'filled',
+ },
+ },
+)
+
+export type SelectValuePlaceholderFieldsetVariants = VariantProps<
+ typeof selectValuePlaceholderFieldsetVariants
+>
+
+export const selectValuePlaceholderLegendVariants = cva('', {
+ variants: {
+ variant: {
+ // only for outlined variant
+ filled: 'hidden',
+ outlined: 'invisible ml-2 px-2 text-sm h-0',
+ },
+ haveValue: {
+ true: '',
+ false: '',
+ },
+ },
+ compoundVariants: [
+ {
+ variant: 'outlined',
+ haveValue: false,
+ className: 'group-data-[state=closed]:hidden group-not-focus:hidden',
+ },
+ ],
+ defaultVariants: {
+ variant: 'filled',
+ haveValue: false,
+ },
+})
+
+export type SelectValuePlaceholderLegendVariants = VariantProps<
+ typeof selectValuePlaceholderLegendVariants
+>
+
+export const selectContentVariants = cva(
+ [
+ 'relative w-full overflow-auto rounded shadow-container z-50',
+ 'bg-inverse-on-surface dark:bg-surface',
+ 'dark:text-on-surface',
+ ],
+ {
+ variants: {
+ variant: {
+ filled: 'rounded-t-none',
+ outlined: '',
+ },
+ },
+ defaultVariants: {
+ variant: 'filled',
+ },
+ },
+)
+
+export type SelectContentVariants = VariantProps
+
+type SelectContextType = {
+ haveValue?: boolean
+ open?: boolean
+} & SelectTriggerVariants
+
+const SelectContext = createContext(null)
+
+const useSelectContext = () => {
+ const context = useContext(SelectContext)
+
+ if (!context) {
+ throw new Error('useSelectContext must be used within a SelectProvider')
+ }
+
+ return context
+}
+
+export const SelectLine = ({ className, ...props }: ComponentProps<'div'>) => {
+ const { variant } = useSelectContext()
+
+ return (
+
+ )
+}
+
+export const Select = ({
+ onValueChange,
+ variant,
+ open: inputOpen,
+ defaultOpen,
+ onOpenChange,
+ ...props
+}: React.ComponentProps &
+ SelectTriggerVariants) => {
+ const [open, setOpen] = useControllableState({
+ prop: inputOpen,
+ defaultProp: defaultOpen ?? false,
+ onChange: onOpenChange,
+ })
+
+ const [haveValue, setHaveValue] = useState(
+ Boolean(props.value || props.defaultValue),
+ )
+
+ const handleOnChange = useCallback((value?: string) => {
+ setHaveValue(Boolean(value))
+ }, [])
+
+ useEffect(() => {
+ setHaveValue(Boolean(props.value || props.defaultValue))
+ }, [props.value, props.defaultValue])
+
+ return (
+
+
+
+ )
+}
+
+export type SelectProps = ComponentProps
+
+export const SelectValue = ({
+ className,
+ placeholder,
+ ...props
+}: ComponentProps) => {
+ const { haveValue, open, variant } = useSelectContext()
+
+ return (
+ <>
+
+
+
+
+
+
+
+ {placeholder}
+
+ >
+ )
+}
+
+export const SelectGroup = (
+ props: ComponentProps,
+) => {
+ return
+}
+
+export const SelectLabel = ({
+ className,
+ ...props
+}: ComponentProps) => {
+ return (
+
+ )
+}
+
+export const SelectTrigger = ({
+ className,
+ children,
+ ...props
+}: ComponentProps) => {
+ const { variant } = useSelectContext()
+
+ return (
+
+ {children}
+
+
+
+
+
+ )
+}
+
+export const SelectIcon = ({
+ asChild,
+ children,
+ className,
+ ...props
+}: ComponentProps) => {
+ return (
+
+ {asChild ? children : }
+
+ )
+}
+
+export const SelectContent = ({
+ className,
+ children,
+ ...props
+}: ComponentProps) => {
+ const { open, variant } = useSelectContext()
+
+ return (
+
+ {open && (
+
+
+
+ {children}
+
+
+
+ )}
+
+ )
+}
+
+export const SelectItem = ({
+ className,
+ children,
+ ...props
+}: ComponentProps) => {
+ return (
+
+ {children}
+
+
+
+
+
+ )
+}
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/clash-settings/_modules/allow-lan-switch.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/clash-settings/_modules/allow-lan-switch.tsx
new file mode 100644
index 0000000000..fbaff318b3
--- /dev/null
+++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/clash-settings/_modules/allow-lan-switch.tsx
@@ -0,0 +1,43 @@
+import { useMemo } from 'react'
+import { Switch } from '@/components/ui/switch'
+import { useLockFn } from '@/hooks/use-lock-fn'
+import { m } from '@/paraglide/messages'
+import { message } from '@/utils/notification'
+import { useClashConfig } from '@nyanpasu/interface'
+import { SettingsCard, SettingsCardContent } from '../../_modules/settings-card'
+
+export default function AllowLanSwitch() {
+ const { query, upsert } = useClashConfig()
+
+ const value = useMemo(() => query.data?.['allow-lan'], [query.data])
+
+ const handleAllowLan = useLockFn(async (input: boolean) => {
+ try {
+ await upsert.mutateAsync({
+ 'allow-lan': input,
+ })
+ } catch (error) {
+ message(`Activation Allow LAN failed!`, {
+ title: 'Error',
+ kind: 'error',
+ })
+ }
+ })
+
+ return (
+
+
+ {m.settings_clash_settings_allow_lan_label()}
+
+
+
+
+ )
+}
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/clash-settings/_modules/ipv6-switch.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/clash-settings/_modules/ipv6-switch.tsx
new file mode 100644
index 0000000000..40bae59583
--- /dev/null
+++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/clash-settings/_modules/ipv6-switch.tsx
@@ -0,0 +1,43 @@
+import { useMemo } from 'react'
+import { Switch } from '@/components/ui/switch'
+import { useLockFn } from '@/hooks/use-lock-fn'
+import { m } from '@/paraglide/messages'
+import { message } from '@/utils/notification'
+import { useClashConfig } from '@nyanpasu/interface'
+import { SettingsCard, SettingsCardContent } from '../../_modules/settings-card'
+
+export default function IPv6Switch() {
+ const { query, upsert } = useClashConfig()
+
+ const value = useMemo(() => query.data?.['ipv6'], [query.data])
+
+ const handleIPv6 = useLockFn(async (input: boolean) => {
+ try {
+ await upsert.mutateAsync({
+ ipv6: input,
+ })
+ } catch (error) {
+ message(`Activation IPv6 failed!`, {
+ title: 'Error',
+ kind: 'error',
+ })
+ }
+ })
+
+ return (
+
+
+ {m.settings_clash_settings_ipv6_label()}
+
+
+
+
+ )
+}
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/clash-settings/_modules/log-level-selector.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/clash-settings/_modules/log-level-selector.tsx
new file mode 100644
index 0000000000..add776ca33
--- /dev/null
+++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/clash-settings/_modules/log-level-selector.tsx
@@ -0,0 +1,68 @@
+import { useCallback, useMemo } from 'react'
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select'
+import { m } from '@/paraglide/messages'
+import { useClashConfig } from '@nyanpasu/interface'
+import { SettingsCard, SettingsCardContent } from '../../_modules/settings-card'
+
+const LOG_LEVEL_OPTIONS = {
+ debug: 'Debug',
+ info: 'Info',
+ warning: 'Warn',
+ error: 'Error',
+ silent: 'Silent',
+} as const
+
+export default function LogLevelSelector() {
+ const { query, upsert } = useClashConfig()
+
+ const value = useMemo(
+ () => query.data?.['log-level'] as keyof typeof LOG_LEVEL_OPTIONS,
+ [query.data],
+ )
+
+ const handleLogLevelChange = useCallback(
+ async (value: string) => {
+ await upsert.mutateAsync({
+ 'log-level': value as string,
+ })
+ },
+ [upsert],
+ )
+
+ return (
+
+
+
+
+
+ )
+}
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/clash-settings/_modules/tun-stack-selector.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/clash-settings/_modules/tun-stack-selector.tsx
new file mode 100644
index 0000000000..2cc221a1ce
--- /dev/null
+++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/clash-settings/_modules/tun-stack-selector.tsx
@@ -0,0 +1,101 @@
+import { useCallback, useMemo } from 'react'
+import {
+ Select,
+ SelectContent,
+ SelectGroup,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select'
+import { useCoreType } from '@/hooks/use-store'
+import { m } from '@/paraglide/messages'
+import { formatError } from '@/utils'
+import { message } from '@/utils/notification'
+import { TunStack, useRuntimeProfile, useSetting } from '@nyanpasu/interface'
+import { SettingsCard, SettingsCardContent } from '../../_modules/settings-card'
+
+export default function TunStackSelector() {
+ const [coreType] = useCoreType()
+
+ const tunStack = useSetting('tun_stack')
+
+ const enableTunMode = useSetting('enable_tun_mode')
+
+ const runtimeProfile = useRuntimeProfile()
+
+ const tunStackOptions = useMemo(() => {
+ const options: {
+ [key: string]: string
+ } = {
+ system: 'System',
+ gvisor: 'gVisor',
+ mixed: 'Mixed',
+ }
+
+ // clash not support mixed
+ if (coreType === 'clash') {
+ delete options.mixed
+ }
+ return options
+ }, [coreType])
+
+ const currentTunStack = useMemo(() => {
+ const stack = tunStack.value || 'gvisor'
+ return stack in tunStackOptions ? stack : 'gvisor'
+ }, [tunStackOptions, tunStack.value])
+
+ const handleTunStackChange = useCallback(
+ async (value: string) => {
+ try {
+ await tunStack.upsert(value as TunStack)
+
+ if (enableTunMode.value) {
+ // just to reload clash config
+ await enableTunMode.upsert(true)
+ }
+
+ // need manual mutate to refetch runtime profile
+ await runtimeProfile.refetch()
+ } catch (error) {
+ message(`Change Tun Stack failed ! \n Error: ${formatError(error)}`, {
+ title: 'Error',
+ kind: 'error',
+ })
+ }
+ },
+ [tunStack, enableTunMode, runtimeProfile],
+ )
+
+ return (
+
+
+
+
+
+ )
+}
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/clash-settings/route.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/clash-settings/route.tsx
index 232ec76daa..6a9789595f 100644
--- a/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/clash-settings/route.tsx
+++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/clash-settings/route.tsx
@@ -1,4 +1,13 @@
+import { m } from '@/paraglide/messages'
import { createFileRoute } from '@tanstack/react-router'
+import {
+ SettingsTitle,
+ SettingsTitlePlaceholder,
+} from '../_modules/settings-title'
+import AllowLanSwitch from './_modules/allow-lan-switch'
+import IPv6Switch from './_modules/ipv6-switch'
+import LogLevelSelector from './_modules/log-level-selector'
+import TunStackSelector from './_modules/tun-stack-selector'
export const Route = createFileRoute(
'/(experimental)/experimental/settings/clash-settings',
@@ -8,6 +17,17 @@ export const Route = createFileRoute(
function RouteComponent() {
return (
- Hello "/(experimental)/experimental/settings/clash-settings"!
+ <>
+
+ {m.settings_system_proxy_title()}
+
+
+
+
+
+
+
+
+ >
)
}
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/user-interface/_modules/experimental-switch.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/user-interface/_modules/experimental-switch.tsx
new file mode 100644
index 0000000000..792d40103d
--- /dev/null
+++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/user-interface/_modules/experimental-switch.tsx
@@ -0,0 +1,27 @@
+import { Button } from '@/components/ui/button'
+import { setEnabledExperimentalRouter } from '@/utils/experimental'
+import { useNavigate } from '@tanstack/react-router'
+import { SettingsCard, SettingsCardContent } from '../../_modules/settings-card'
+
+export default function ExperimentalSwitch() {
+ const navigate = useNavigate()
+ const handleClick = () => {
+ setEnabledExperimentalRouter(false)
+ navigate({ to: '/' })
+ }
+
+ return (
+
+
+ Switch to Legacy UI
+
+
+
+
+ )
+}
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/user-interface/_modules/language-selector.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/user-interface/_modules/language-selector.tsx
new file mode 100644
index 0000000000..85b5d1b89e
--- /dev/null
+++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/user-interface/_modules/language-selector.tsx
@@ -0,0 +1,50 @@
+import { useLanguage } from '@/components/providers/language-provider'
+import { Button } from '@/components/ui/button'
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuTrigger,
+} from '@/components/ui/dropdown-menu'
+import { m } from '@/paraglide/messages'
+import { Locale, locales } from '@/paraglide/runtime'
+import { SettingsCard, SettingsCardContent } from '../../_modules/settings-card'
+
+export default function LanguageSelector() {
+ const { language, setLanguage } = useLanguage()
+
+ const handleLanguageChange = (value: string) => {
+ setLanguage(value as Locale)
+ }
+
+ return (
+
+
+ {m.settings_user_interface_language_label()}
+
+
+
+
+
+
+
+
+ {locales.map((value) => (
+
+ {m.language(value, { locale: value })}
+
+ ))}
+
+
+
+
+
+ )
+}
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/user-interface/_modules/theme-color-config.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/user-interface/_modules/theme-color-config.tsx
new file mode 100644
index 0000000000..552b1eb47a
--- /dev/null
+++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/user-interface/_modules/theme-color-config.tsx
@@ -0,0 +1,68 @@
+import Check from '~icons/material-symbols/check-rounded'
+import { useCallback, useState } from 'react'
+import { useExperimentalThemeContext } from '@/components/providers/theme-provider'
+import { Button } from '@/components/ui/button'
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuTrigger,
+} from '@/components/ui/dropdown-menu'
+import { m } from '@/paraglide/messages'
+import { Wheel } from '@uiw/react-color'
+import { SettingsCard, SettingsCardContent } from '../../_modules/settings-card'
+
+export default function ThemeColorConfig() {
+ const { themeColor, setThemeColor } = useExperimentalThemeContext()
+
+ const [open, setOpen] = useState(false)
+
+ const [cachedThemeColor, setCachedThemeColor] = useState(themeColor)
+
+ const handleSubmit = useCallback(async () => {
+ setOpen(false)
+ await setThemeColor(cachedThemeColor)
+ }, [cachedThemeColor, setThemeColor])
+
+ return (
+
+
+ {m.settings_user_interface_theme_color_label()}
+
+
+
+
+
+
+
+ {
+ setCachedThemeColor(color.hex)
+ }}
+ />
+
+
+
+
+
+
+ )
+}
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/user-interface/_modules/theme-mode-selector.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/user-interface/_modules/theme-mode-selector.tsx
new file mode 100644
index 0000000000..60df50da67
--- /dev/null
+++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/user-interface/_modules/theme-mode-selector.tsx
@@ -0,0 +1,58 @@
+import {
+ ThemeMode,
+ useExperimentalThemeContext,
+} from '@/components/providers/theme-provider'
+import { Button } from '@/components/ui/button'
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuTrigger,
+} from '@/components/ui/dropdown-menu'
+import { m } from '@/paraglide/messages'
+import { SettingsCard, SettingsCardContent } from '../../_modules/settings-card'
+
+export default function ThemeModeSelector() {
+ const { themeMode, setThemeMode } = useExperimentalThemeContext()
+
+ const handleThemeModeChange = (value: string) => {
+ setThemeMode(value as ThemeMode)
+ }
+
+ const messages = {
+ [ThemeMode.LIGHT]: m.settings_user_interface_theme_mode_light(),
+ [ThemeMode.DARK]: m.settings_user_interface_theme_mode_dark(),
+ [ThemeMode.SYSTEM]: m.settings_user_interface_theme_mode_system(),
+ } satisfies Record
+
+ return (
+
+
+ {m.settings_user_interface_theme_mode_label()}
+
+
+
+
+
+
+
+
+ {Object.values(ThemeMode).map((value) => (
+
+ {value}
+
+ ))}
+
+
+
+
+
+ )
+}
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/user-interface/route.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/user-interface/route.tsx
index 989b75c2b2..685e07198d 100644
--- a/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/user-interface/route.tsx
+++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/user-interface/route.tsx
@@ -4,6 +4,10 @@ import {
SettingsTitle,
SettingsTitlePlaceholder,
} from '../_modules/settings-title'
+import ExperimentalSwitch from './_modules/experimental-switch'
+import LanguageSelector from './_modules/language-selector'
+import ThemeColorConfig from './_modules/theme-color-config'
+import ThemeModeSelector from './_modules/theme-mode-selector'
export const Route = createFileRoute(
'/(experimental)/experimental/settings/user-interface',
@@ -23,6 +27,14 @@ function RouteComponent() {
<>
{m.settings_user_interface_title()}
+
+
+
+
+
+
+
+
>
)
}
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/__root.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/__root.tsx
index 60e5a4b17f..8784a2512d 100644
--- a/clash-nyanpasu/frontend/nyanpasu/src/pages/__root.tsx
+++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/__root.tsx
@@ -19,6 +19,7 @@ import customParseFormat from 'dayjs/plugin/customParseFormat'
import relativeTime from 'dayjs/plugin/relativeTime'
import { lazy } from 'react'
import { BlockTaskProvider } from '@/components/providers/block-task-provider'
+import { LanguageProvider } from '@/components/providers/language-provider'
import { ExperimentalThemeProvider } from '@/components/providers/theme-provider'
import { NyanpasuProvider } from '@nyanpasu/interface'
import styles from './-__root.module.scss'
@@ -74,17 +75,19 @@ export default function App() {
return (
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
-
+
+
)
diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json
index 19a40a9d45..d34d1057a9 100644
--- a/clash-nyanpasu/manifest/version.json
+++ b/clash-nyanpasu/manifest/version.json
@@ -2,7 +2,7 @@
"manifest_version": 1,
"latest": {
"mihomo": "v1.19.17",
- "mihomo_alpha": "alpha-bc8f0dc",
+ "mihomo_alpha": "alpha-17966b5",
"clash_rs": "v0.9.3",
"clash_premium": "2023-09-05-gdcc8d87",
"clash_rs_alpha": "0.9.3-alpha+sha.a6538ac"
@@ -69,5 +69,5 @@
"linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf"
}
},
- "updated_at": "2025-12-17T22:21:31.955Z"
+ "updated_at": "2025-12-18T22:21:30.469Z"
}
diff --git a/clash-nyanpasu/package.json b/clash-nyanpasu/package.json
index 260cfc6ee1..125c058a2d 100644
--- a/clash-nyanpasu/package.json
+++ b/clash-nyanpasu/package.json
@@ -35,6 +35,7 @@
"fmt": "run-p fmt:*",
"fmt:backend": "cargo fmt --manifest-path ./backend/Cargo.toml --all",
"fmt:prettier": "prettier --write .",
+ "fmt:eslint": "eslint --cache --fix . eslint.config.js",
"updater": "tsx scripts/updater.ts",
"updater:nightly": "tsx scripts/updater-nightly.ts",
"send-notify": "tsx scripts/telegram-notify.ts",
@@ -71,7 +72,7 @@
"autoprefixer": "10.4.23",
"conventional-changelog-conventionalcommits": "9.1.0",
"cross-env": "10.1.0",
- "dedent": "1.7.0",
+ "dedent": "1.7.1",
"eslint": "9.39.2",
"eslint-config-prettier": "10.1.8",
"eslint-import-resolver-alias": "1.1.2",
@@ -108,7 +109,7 @@
"typescript": "5.9.3",
"typescript-eslint": "8.50.0"
},
- "packageManager": "pnpm@10.20.0",
+ "packageManager": "pnpm@10.26.1",
"engines": {
"node": "22.21.1"
},
diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml
index 781b65607e..eebb4d699d 100644
--- a/clash-nyanpasu/pnpm-lock.yaml
+++ b/clash-nyanpasu/pnpm-lock.yaml
@@ -65,8 +65,8 @@ importers:
specifier: 10.1.0
version: 10.1.0
dedent:
- specifier: 1.7.0
- version: 1.7.0(babel-plugin-macros@3.1.0)
+ specifier: 1.7.1
+ version: 1.7.1(babel-plugin-macros@3.1.0)
eslint:
specifier: 9.39.2
version: 9.39.2(jiti@2.6.1)
@@ -248,15 +248,24 @@ importers:
'@nyanpasu/ui':
specifier: workspace:^
version: link:../ui
+ '@radix-ui/react-dropdown-menu':
+ specifier: 2.1.16
+ version: 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-scroll-area':
specifier: 1.2.10
version: 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-select':
+ specifier: 2.2.6
+ version: 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-slot':
specifier: 1.2.4
version: 1.2.4(@types/react@19.2.7)(react@19.2.0)
'@radix-ui/react-switch':
- specifier: ^1.2.6
+ specifier: 1.2.6
version: 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-use-controllable-state':
+ specifier: 1.2.2
+ version: 1.2.2(@types/react@19.2.7)(react@19.2.0)
'@tailwindcss/postcss':
specifier: 4.1.17
version: 4.1.17
@@ -272,6 +281,9 @@ importers:
'@uidotdev/usehooks':
specifier: 2.4.1
version: 2.4.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color':
+ specifier: 2.9.2
+ version: 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
ahooks:
specifier: 3.9.6
version: 3.9.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
@@ -454,8 +466,8 @@ importers:
specifier: 22.5.0
version: 22.5.0(@svgr/core@8.1.0(typescript@5.9.3))
validator:
- specifier: 13.15.23
- version: 13.15.23
+ specifier: 13.15.26
+ version: 13.15.26
vite:
specifier: 7.2.4
version: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1)
@@ -612,8 +624,8 @@ importers:
specifier: 3.4.2
version: 3.4.2
fs-extra:
- specifier: 11.3.2
- version: 11.3.2
+ specifier: 11.3.3
+ version: 11.3.3
octokit:
specifier: 5.0.5
version: 5.0.5
@@ -1806,6 +1818,21 @@ packages:
resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
engines: {node: '>=14'}
+ '@floating-ui/core@1.7.3':
+ resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==}
+
+ '@floating-ui/dom@1.7.4':
+ resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==}
+
+ '@floating-ui/react-dom@2.1.6':
+ resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==}
+ peerDependencies:
+ react: '>=16.8.0'
+ react-dom: '>=16.8.0'
+
+ '@floating-ui/utils@0.2.10':
+ resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==}
+
'@greenhat616/material-react-table@4.0.0':
resolution: {integrity: sha512-CGjE4MaM2Pamdgli7gJCx0PCimq1qlnKl3/AlFLsdgGMzVyJHmghQ0rL11TS95i3UEPNsPCFTmtUHU4sCJhDHA==}
engines: {node: '>=16'}
@@ -2653,6 +2680,32 @@ packages:
'@radix-ui/primitive@1.1.3':
resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==}
+ '@radix-ui/react-arrow@1.1.7':
+ resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@radix-ui/react-collection@1.1.7':
+ resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
'@radix-ui/react-compose-refs@1.1.2':
resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==}
peerDependencies:
@@ -2680,6 +2733,89 @@ packages:
'@types/react':
optional: true
+ '@radix-ui/react-dismissable-layer@1.1.11':
+ resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@radix-ui/react-dropdown-menu@2.1.16':
+ resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@radix-ui/react-focus-guards@1.1.3':
+ resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@radix-ui/react-focus-scope@1.1.7':
+ resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@radix-ui/react-id@1.1.1':
+ resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@radix-ui/react-menu@2.1.16':
+ resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@radix-ui/react-popper@1.2.8':
+ resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
'@radix-ui/react-portal@1.1.10':
resolution: {integrity: sha512-4kY9IVa6+9nJPsYmngK5Uk2kUmZnv7ChhHAFeQ5oaj8jrR1bIi3xww8nH71pz1/Ve4d/cXO3YxT8eikt1B0a8w==}
peerDependencies:
@@ -2693,6 +2829,19 @@ packages:
'@types/react-dom':
optional: true
+ '@radix-ui/react-portal@1.1.9':
+ resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
'@radix-ui/react-presence@1.1.5':
resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==}
peerDependencies:
@@ -2732,6 +2881,19 @@ packages:
'@types/react-dom':
optional: true
+ '@radix-ui/react-roving-focus@1.1.11':
+ resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
'@radix-ui/react-scroll-area@1.2.10':
resolution: {integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==}
peerDependencies:
@@ -2745,6 +2907,19 @@ packages:
'@types/react-dom':
optional: true
+ '@radix-ui/react-select@2.2.6':
+ resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
'@radix-ui/react-slot@1.2.3':
resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==}
peerDependencies:
@@ -2803,6 +2978,15 @@ packages:
'@types/react':
optional: true
+ '@radix-ui/react-use-escape-keydown@1.1.1':
+ resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@radix-ui/react-use-layout-effect@1.1.1':
resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==}
peerDependencies:
@@ -2821,6 +3005,15 @@ packages:
'@types/react':
optional: true
+ '@radix-ui/react-use-rect@1.1.1':
+ resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@radix-ui/react-use-size@1.1.1':
resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==}
peerDependencies:
@@ -2830,6 +3023,22 @@ packages:
'@types/react':
optional: true
+ '@radix-ui/react-visually-hidden@1.2.3':
+ resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@radix-ui/rect@1.1.1':
+ resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==}
+
'@rolldown/pluginutils@1.0.0-beta.47':
resolution: {integrity: sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==}
@@ -3811,6 +4020,156 @@ packages:
react: '>=18.0.0'
react-dom: '>=18.0.0'
+ '@uiw/color-convert@2.9.2':
+ resolution: {integrity: sha512-ibw9OS29S7GlL+vDwU3p5XG3vhR7XdzUecydpZbakUeg2Td6nfsnrCAX9sbLwQ73p0abO42v+V4qRaWq+7/BjQ==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+
+ '@uiw/react-color-alpha@2.9.2':
+ resolution: {integrity: sha512-a2ACkE2vZIS4xnN9DaRfkQtAX/t8oK5NRSbX2QeOL23WIMHP1VNs7Yq5gXB68RHYenFgvs2JHuMOxZ2mK1W5Mw==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-block@2.9.2':
+ resolution: {integrity: sha512-0EIZTELA5pnxyMlBOFo3hrpy73db+Qeq6E+QptNfD/8izor8OvY1Uquj2VqD6gDz+iVHMELIoKxpaQ8sZR7NOg==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-chrome@2.9.2':
+ resolution: {integrity: sha512-p7OZB7VWrkVbHxcTHsAq5U2vt3hAP3VvKEiDi592LKxS11IMnSd15ta8ngbJaXZWatqEpJSNgj12581yHtx+Bg==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-circle@2.9.2':
+ resolution: {integrity: sha512-7XaeX3LfCRkZKffHL/KtYps7I9hNpmx9sJOuwi0ML+3urToFD8s7Iuq3upYZt8REYt1Y84SBjuUqx2YYmjUEjA==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-colorful@2.9.2':
+ resolution: {integrity: sha512-tz/xeHayna2wpLipkZmcMgL1rmLMxfAmlOyBhUeWrpvqb9Fx59C/wL+5IYJA4rdsQvr9WyWjWmU/GhVKsEkW9w==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-compact@2.9.2':
+ resolution: {integrity: sha512-fSSgRRBjkYuGRebZ7XM5XGVFvFwEyEGaV6mOhUpr3JFKhIES0/9oPbd80GDbRdj57Zxxrj76MCtd/aCFfwQSWA==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-editable-input-hsla@2.9.2':
+ resolution: {integrity: sha512-kZfj3W20msLeP8/HY498rG30eBHRPAyxduhu94HLa9XggT/0ogwA9xZJZgWd6B7FYPeRlhRDY7dnF7caND63GQ==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-editable-input-rgba@2.9.2':
+ resolution: {integrity: sha512-sQW3tSao754954aQuVK4qvn1i+KC2piE4UftaBubD3QxC02gg5VfgZRoI6AV+nLr73Ifv3mCXewjN1BcP/+x4A==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-editable-input@2.9.2':
+ resolution: {integrity: sha512-DY7pu12+LDRn6cxDMvsy1/quaPTxicAPz/kfODV7KBf8+Hq4rFWeJ4KS6m22IKIbQxrBQgmQG0WFJLaPeY7cPw==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-github@2.9.2':
+ resolution: {integrity: sha512-pKR94swzWxqRFUEZJBQ8WHcw6CklxLWhDyjvGpxiieAlwUAL0mlmtCcctRgsmJRuAKQlZx4WNslRgNX5aVcoZw==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-hue@2.9.2':
+ resolution: {integrity: sha512-vDGN5YCzw09BfxkQeDvAeQ7zAy141uJ3HkFk1lsXL7ha8xZ35AItE1s/C6d60vFjGdoloKShh0yA7df3pnjmxA==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-material@2.9.2':
+ resolution: {integrity: sha512-R9MI9IlTof/L1rdxUFQAWgAgUSNJGXQsPujo8UGpwR7o5d+A3wwybUnPBsGKRnZwDy5zW7x+lPxY46GXE9aU9Q==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-name@2.9.2':
+ resolution: {integrity: sha512-knqRUkAe3pv6rB+tGzaURtwQkBqjRG62YNlzUx8Ty7g+pskWpLSPiMikW+9H5sLPq7wU3ichZiygqIp4BRgQzA==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+
+ '@uiw/react-color-saturation@2.9.2':
+ resolution: {integrity: sha512-w1aUU+g6Axwbr1nLvF8k/zg5v7UW8z80eH6C7w+tdiOFOQKkKQlXqeOG0IIUUIj3v/ji+yM90IuOH+Ku7zsJrg==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-shade-slider@2.9.2':
+ resolution: {integrity: sha512-VE59rWv5ixqCN2CTpoe33j4SOCGU62bKguizx4HxgKczE/X0ySeEas8iP5XLg/4fYWl3EZN4uI+M8mNRnB0DPw==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-sketch@2.9.2':
+ resolution: {integrity: sha512-PEvwaqDVDdBI/+fWASBWQOvx3ows7dIcv6Z06VHgEXk2chi95Fkrbd0YUUXMcp7ESsmUK1j5ozGMLAf9Nvx6Nw==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-slider@2.9.2':
+ resolution: {integrity: sha512-vsi0AwmFJpb+flF8XCkacbX+MwLGOzrDKMqR29XE5sO8ERaezoT5mmYXzXXFcjyZYIuXse4C3JT38nsmOBp1vQ==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-swatch@2.9.2':
+ resolution: {integrity: sha512-6zBy+E9NzZR672M2wPsbbNRqKy9Wi9jOuuxxyzov1CEZp+pPX7UwMlCX6RUhKdO0PzTSPCVQmbz5bplu5vsW0w==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color-wheel@2.9.2':
+ resolution: {integrity: sha512-ayGzQyMZM3Cp+sX7LNElQ/QQWMO7YG4k/RQwVJAhxNQ+4lJ/p4LLSnI85D7NxILkk+jiXnjxRroxxZ2eJhWo+g==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-color@2.9.2':
+ resolution: {integrity: sha512-nIrw4Ol6boAkr1CUcCAkrUFVrKbT9T7/0qaSDpXmiDgKYf77gbXTWTsqVuXVDCSoCn28LvurpASS4AW8oiSBtg==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@uiw/react-drag-event-interactive@2.9.2':
+ resolution: {integrity: sha512-6gxQz+Ij7JkXlEOpfZhOu+Gdp/sI9VnMeDl8AJeYl3+0YXP31lXGmyb0NkNYnoUmJO+RrAf68c1raMpaDWs+Ow==}
+ peerDependencies:
+ '@babel/runtime': '>=7.19.0'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
'@ungap/structured-clone@1.2.0':
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
@@ -4055,6 +4414,10 @@ packages:
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ aria-hidden@1.2.6:
+ resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
+ engines: {node: '>=10'}
+
array-buffer-byte-length@1.0.1:
resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==}
engines: {node: '>= 0.4'}
@@ -4384,6 +4747,14 @@ packages:
colorjs.io@0.5.2:
resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==}
+ colors-named-hex@1.0.3:
+ resolution: {integrity: sha512-vhUoMdCdOKgD9Ni3p6uV3ET1JJCHzlcK6lN3/yl+6TUHinDE6HUFlmnvkh/NDZ2M9049Ipn3mX85qu6akRiC1g==}
+ engines: {node: '>=14.16'}
+
+ colors-named@1.0.4:
+ resolution: {integrity: sha512-R254qrKSxFJNa7QmM7vrRaz5Hygr7MIaNbXcIx7WfmlYJ9OjZQ+aczGlnKS8lLtNT0GM9aGZ4EcmNXrh5ttv6g==}
+ engines: {node: '>=14.16'}
+
comma-separated-tokens@2.0.3:
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
@@ -4795,8 +5166,8 @@ packages:
babel-plugin-macros:
optional: true
- dedent@1.7.0:
- resolution: {integrity: sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==}
+ dedent@1.7.1:
+ resolution: {integrity: sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==}
peerDependencies:
babel-plugin-macros: ^3.1.0
peerDependenciesMeta:
@@ -4840,6 +5211,9 @@ packages:
resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
engines: {node: '>=8'}
+ detect-node-es@1.1.0:
+ resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
+
devlop@1.1.0:
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
@@ -5396,8 +5770,8 @@ packages:
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
engines: {node: '>=12'}
- fs-extra@11.3.2:
- resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==}
+ fs-extra@11.3.3:
+ resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==}
engines: {node: '>=14.14'}
fs.realpath@1.0.0:
@@ -5450,6 +5824,10 @@ packages:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'}
+ get-nonce@1.0.1:
+ resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
+ engines: {node: '>=6'}
+
get-proto@1.0.1:
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
engines: {node: '>= 0.4'}
@@ -7105,11 +7483,41 @@ packages:
resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==}
engines: {node: '>=0.10.0'}
+ react-remove-scroll-bar@2.3.8:
+ resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ react-remove-scroll@2.7.2:
+ resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
react-split-grid@1.0.4:
resolution: {integrity: sha512-RMEzFFnntgn+u5GFq+ognmv30CsTgrR97zB4RkMx2VSX9Sw8A7fjzCUfw/Avj7m8GCEw19GIjoUQGOQUOOjlcA==}
peerDependencies:
react: '*'
+ react-style-singleton@2.2.3:
+ resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
react-transition-group@4.4.5:
resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
peerDependencies:
@@ -8153,12 +8561,32 @@ packages:
urlpattern-polyfill@10.1.0:
resolution: {integrity: sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==}
+ use-callback-ref@1.3.3:
+ resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
use-resize-observer@9.1.0:
resolution: {integrity: sha512-R25VqO9Wb3asSD4eqtcxk8sJalvIOYBqS8MNZlpDSQ4l4xMQxC/J7Id9HoTqPq8FwULIn0PVW+OAqF2dyYbjow==}
peerDependencies:
react: 16.8.0 - 18
react-dom: 16.8.0 - 18
+ use-sidecar@1.1.3:
+ resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
use-sync-external-store@1.5.0:
resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==}
peerDependencies:
@@ -8180,8 +8608,8 @@ packages:
resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
hasBin: true
- validator@13.15.23:
- resolution: {integrity: sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw==}
+ validator@13.15.26:
+ resolution: {integrity: sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==}
engines: {node: '>= 0.10'}
varint@6.0.0:
@@ -10003,6 +10431,23 @@ snapshots:
'@fastify/busboy@2.1.1': {}
+ '@floating-ui/core@1.7.3':
+ dependencies:
+ '@floating-ui/utils': 0.2.10
+
+ '@floating-ui/dom@1.7.4':
+ dependencies:
+ '@floating-ui/core': 1.7.3
+ '@floating-ui/utils': 0.2.10
+
+ '@floating-ui/react-dom@2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@floating-ui/dom': 1.7.4
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@floating-ui/utils@0.2.10': {}
+
'@greenhat616/material-react-table@4.0.0(5aa790633df21c14482e4378d5c119ba)':
dependencies:
'@emotion/react': 11.14.0(@types/react@19.2.7)(react@19.2.0)
@@ -10848,6 +11293,27 @@ snapshots:
'@radix-ui/primitive@1.1.3': {}
+ '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+ optionalDependencies:
+ '@types/react': 19.2.7
+ '@types/react-dom': 19.2.3(@types/react@19.2.7)
+
+ '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+ optionalDependencies:
+ '@types/react': 19.2.7
+ '@types/react-dom': 19.2.3(@types/react@19.2.7)
+
'@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.7)(react@19.2.0)':
dependencies:
react: 19.2.0
@@ -10866,6 +11332,102 @@ snapshots:
optionalDependencies:
'@types/react': 19.2.7
+ '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+ optionalDependencies:
+ '@types/react': 19.2.7
+ '@types/react-dom': 19.2.3(@types/react@19.2.7)
+
+ '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+ optionalDependencies:
+ '@types/react': 19.2.7
+ '@types/react-dom': 19.2.3(@types/react@19.2.7)
+
+ '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.7)(react@19.2.0)':
+ dependencies:
+ react: 19.2.0
+ optionalDependencies:
+ '@types/react': 19.2.7
+
+ '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+ optionalDependencies:
+ '@types/react': 19.2.7
+ '@types/react-dom': 19.2.3(@types/react@19.2.7)
+
+ '@radix-ui/react-id@1.1.1(@types/react@19.2.7)(react@19.2.0)':
+ dependencies:
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ react: 19.2.0
+ optionalDependencies:
+ '@types/react': 19.2.7
+
+ '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ aria-hidden: 1.2.6
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+ react-remove-scroll: 2.7.2(@types/react@19.2.7)(react@19.2.0)
+ optionalDependencies:
+ '@types/react': 19.2.7
+ '@types/react-dom': 19.2.3(@types/react@19.2.7)
+
+ '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@floating-ui/react-dom': 2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/rect': 1.1.1
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+ optionalDependencies:
+ '@types/react': 19.2.7
+ '@types/react-dom': 19.2.3(@types/react@19.2.7)
+
'@radix-ui/react-portal@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
@@ -10876,6 +11438,16 @@ snapshots:
'@types/react': 19.2.7
'@types/react-dom': 19.2.3(@types/react@19.2.7)
+ '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+ optionalDependencies:
+ '@types/react': 19.2.7
+ '@types/react-dom': 19.2.3(@types/react@19.2.7)
+
'@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0)
@@ -10904,6 +11476,23 @@ snapshots:
'@types/react': 19.2.7
'@types/react-dom': 19.2.3(@types/react@19.2.7)
+ '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+ optionalDependencies:
+ '@types/react': 19.2.7
+ '@types/react-dom': 19.2.3(@types/react@19.2.7)
+
'@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/number': 1.1.1
@@ -10921,6 +11510,35 @@ snapshots:
'@types/react': 19.2.7
'@types/react-dom': 19.2.3(@types/react@19.2.7)
+ '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@radix-ui/number': 1.1.1
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ aria-hidden: 1.2.6
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+ react-remove-scroll: 2.7.2(@types/react@19.2.7)(react@19.2.0)
+ optionalDependencies:
+ '@types/react': 19.2.7
+ '@types/react-dom': 19.2.3(@types/react@19.2.7)
+
'@radix-ui/react-slot@1.2.3(@types/react@19.2.7)(react@19.2.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0)
@@ -10971,6 +11589,13 @@ snapshots:
optionalDependencies:
'@types/react': 19.2.7
+ '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.7)(react@19.2.0)':
+ dependencies:
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0)
+ react: 19.2.0
+ optionalDependencies:
+ '@types/react': 19.2.7
+
'@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.7)(react@19.2.0)':
dependencies:
react: 19.2.0
@@ -10983,6 +11608,13 @@ snapshots:
optionalDependencies:
'@types/react': 19.2.7
+ '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.7)(react@19.2.0)':
+ dependencies:
+ '@radix-ui/rect': 1.1.1
+ react: 19.2.0
+ optionalDependencies:
+ '@types/react': 19.2.7
+
'@radix-ui/react-use-size@1.1.1(@types/react@19.2.7)(react@19.2.0)':
dependencies:
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0)
@@ -10990,6 +11622,17 @@ snapshots:
optionalDependencies:
'@types/react': 19.2.7
+ '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+ optionalDependencies:
+ '@types/react': 19.2.7
+ '@types/react-dom': 19.2.3(@types/react@19.2.7)
+
+ '@radix-ui/rect@1.1.1': {}
+
'@rolldown/pluginutils@1.0.0-beta.47': {}
'@rollup/pluginutils@4.2.1':
@@ -11080,7 +11723,7 @@ snapshots:
ajv: 8.13.0
ajv-draft-04: 1.0.0(ajv@8.13.0)
ajv-formats: 3.0.1(ajv@8.13.0)
- fs-extra: 11.3.2
+ fs-extra: 11.3.3
import-lazy: 4.0.0
jju: 1.4.0
resolve: 1.22.8
@@ -12019,6 +12662,206 @@ snapshots:
react: 19.2.0
react-dom: 19.2.0(react@19.2.0)
+ '@uiw/color-convert@2.9.2(@babel/runtime@7.28.4)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+
+ '@uiw/react-color-alpha@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-drag-event-interactive': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-block@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-color-editable-input': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-swatch': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-chrome@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-color-alpha': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-editable-input': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-editable-input-hsla': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-editable-input-rgba': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-github': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-hue': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-saturation': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-circle@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-color-swatch': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-colorful@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-color-alpha': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-hue': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-saturation': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-compact@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-color-editable-input': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-editable-input-rgba': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-swatch': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-editable-input-hsla@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-color-editable-input-rgba': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-editable-input-rgba@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-color-editable-input': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-editable-input@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-github@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-color-swatch': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-hue@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-color-alpha': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-material@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-color-editable-input': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-editable-input-rgba': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-name@2.9.2(@babel/runtime@7.28.4)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ colors-named: 1.0.4
+ colors-named-hex: 1.0.3
+
+ '@uiw/react-color-saturation@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-drag-event-interactive': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-shade-slider@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-color-alpha': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-sketch@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-color-alpha': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-editable-input': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-editable-input-rgba': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-hue': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-saturation': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-swatch': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-slider@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-color-alpha': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-swatch@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color-wheel@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-drag-event-interactive': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-color@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@uiw/color-convert': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-color-alpha': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-block': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-chrome': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-circle': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-colorful': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-compact': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-editable-input': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-editable-input-hsla': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-editable-input-rgba': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-github': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-hue': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-material': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-name': 2.9.2(@babel/runtime@7.28.4)
+ '@uiw/react-color-saturation': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-shade-slider': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-sketch': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-slider': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-swatch': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@uiw/react-color-wheel': 2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
+ '@uiw/react-drag-event-interactive@2.9.2(@babel/runtime@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+
'@ungap/structured-clone@1.2.0': {}
'@unrs/resolver-binding-android-arm-eabi@1.10.1':
@@ -12270,6 +13113,10 @@ snapshots:
argparse@2.0.1: {}
+ aria-hidden@1.2.6:
+ dependencies:
+ tslib: 2.8.1
+
array-buffer-byte-length@1.0.1:
dependencies:
call-bind: 1.0.8
@@ -12661,6 +13508,10 @@ snapshots:
colorjs.io@0.5.2: {}
+ colors-named-hex@1.0.3: {}
+
+ colors-named@1.0.4: {}
+
comma-separated-tokens@2.0.3: {}
commander@11.1.0: {}
@@ -13058,7 +13909,7 @@ snapshots:
optionalDependencies:
babel-plugin-macros: 3.1.0
- dedent@1.7.0(babel-plugin-macros@3.1.0):
+ dedent@1.7.1(babel-plugin-macros@3.1.0):
optionalDependencies:
babel-plugin-macros: 3.1.0
@@ -13093,6 +13944,8 @@ snapshots:
detect-libc@2.0.4: {}
+ detect-node-es@1.1.0: {}
+
devlop@1.1.0:
dependencies:
dequal: 2.0.3
@@ -13905,7 +14758,7 @@ snapshots:
jsonfile: 6.1.0
universalify: 2.0.1
- fs-extra@11.3.2:
+ fs-extra@11.3.3:
dependencies:
graceful-fs: 4.2.11
jsonfile: 6.1.0
@@ -13979,6 +14832,8 @@ snapshots:
hasown: 2.0.2
math-intrinsics: 1.1.0
+ get-nonce@1.0.1: {}
+
get-proto@1.0.1:
dependencies:
dunder-proto: 1.0.1
@@ -15731,12 +16586,39 @@ snapshots:
react-refresh@0.18.0: {}
+ react-remove-scroll-bar@2.3.8(@types/react@19.2.7)(react@19.2.0):
+ dependencies:
+ react: 19.2.0
+ react-style-singleton: 2.2.3(@types/react@19.2.7)(react@19.2.0)
+ tslib: 2.8.1
+ optionalDependencies:
+ '@types/react': 19.2.7
+
+ react-remove-scroll@2.7.2(@types/react@19.2.7)(react@19.2.0):
+ dependencies:
+ react: 19.2.0
+ react-remove-scroll-bar: 2.3.8(@types/react@19.2.7)(react@19.2.0)
+ react-style-singleton: 2.2.3(@types/react@19.2.7)(react@19.2.0)
+ tslib: 2.8.1
+ use-callback-ref: 1.3.3(@types/react@19.2.7)(react@19.2.0)
+ use-sidecar: 1.1.3(@types/react@19.2.7)(react@19.2.0)
+ optionalDependencies:
+ '@types/react': 19.2.7
+
react-split-grid@1.0.4(react@19.2.0):
dependencies:
prop-types: 15.8.1
react: 19.2.0
split-grid: 1.0.11
+ react-style-singleton@2.2.3(@types/react@19.2.7)(react@19.2.0):
+ dependencies:
+ get-nonce: 1.0.1
+ react: 19.2.0
+ tslib: 2.8.1
+ optionalDependencies:
+ '@types/react': 19.2.7
+
react-transition-group@4.4.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
dependencies:
'@babel/runtime': 7.28.4
@@ -16984,12 +17866,27 @@ snapshots:
urlpattern-polyfill@10.1.0: {}
+ use-callback-ref@1.3.3(@types/react@19.2.7)(react@19.2.0):
+ dependencies:
+ react: 19.2.0
+ tslib: 2.8.1
+ optionalDependencies:
+ '@types/react': 19.2.7
+
use-resize-observer@9.1.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
dependencies:
'@juggle/resize-observer': 3.4.0
react: 19.2.0
react-dom: 19.2.0(react@19.2.0)
+ use-sidecar@1.1.3(@types/react@19.2.7)(react@19.2.0):
+ dependencies:
+ detect-node-es: 1.1.0
+ react: 19.2.0
+ tslib: 2.8.1
+ optionalDependencies:
+ '@types/react': 19.2.7
+
use-sync-external-store@1.5.0(react@19.2.0):
dependencies:
react: 19.2.0
@@ -17006,7 +17903,7 @@ snapshots:
uuid@10.0.0: {}
- validator@13.15.23: {}
+ validator@13.15.26: {}
varint@6.0.0: {}
diff --git a/clash-nyanpasu/scripts/package.json b/clash-nyanpasu/scripts/package.json
index 97132203bc..fcde64aa22 100644
--- a/clash-nyanpasu/scripts/package.json
+++ b/clash-nyanpasu/scripts/package.json
@@ -19,7 +19,7 @@
"adm-zip": "0.5.16",
"colorize-template": "1.0.0",
"consola": "3.4.2",
- "fs-extra": "11.3.2",
+ "fs-extra": "11.3.3",
"octokit": "5.0.5",
"picocolors": "1.1.1",
"tar": "7.5.2",
diff --git a/clash-verge-rev/.github/ISSUE_TEMPLATE/bug_report.yml b/clash-verge-rev/.github/ISSUE_TEMPLATE/bug_report.yml
index d22312b0ed..30c2a2e6f1 100644
--- a/clash-verge-rev/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/clash-verge-rev/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -11,11 +11,11 @@ body:
## 在提交问题之前,请确认以下事项:
1. 请 **确保** 您已经查阅了 [Clash Verge Rev 官方文档](https://clash-verge-rev.github.io/guide/term.html) 以及 [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
- 2. 请 **确保** [已有的问题](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue) 中没有人提交过相似issue,否则请在已有的issue下进行讨论
- 3. 请 **务必** 给issue填写一个简洁明了的标题,以便他人快速检索
+ 2. 请 **确保** [已有的问题](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue) 中没有人提交过相似 issue,否则请在已有的 issue 下进行讨论
+ 3. 请 **务必** 给 issue 填写一个简洁明了的标题,以便他人快速检索
4. 请 **务必** 查看 [AutoBuild](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/autobuild) 版本更新日志
5. 请 **务必** 尝试 [AutoBuild](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/autobuild) 版本,确定问题是否仍然存在
- 6. 请 **务必** 按照模板规范详细描述问题以及尝试更新 Alpha 版本,否则issue将会被直接关闭
+ 6. 请 **务必** 按照模板规范详细描述问题以及尝试更新 AutoBuild 版本,否则 issue 将会被直接关闭
## Before submitting the issue, please make sure of the following checklist:
diff --git a/clash-verge-rev/.github/ISSUE_TEMPLATE/feature_request.yml b/clash-verge-rev/.github/ISSUE_TEMPLATE/feature_request.yml
index aaa60d9b5d..dc5a460d93 100644
--- a/clash-verge-rev/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/clash-verge-rev/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -10,10 +10,10 @@ body:
value: |
## 在提交问题之前,请确认以下事项:
1. 请 **确保** 您已经查阅了 [Clash Verge Rev 官方文档](https://clash-verge-rev.github.io/guide/term.html) 确认软件不存在类似的功能
- 2. 请 **确保** [已有的问题](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue) 中没有人提交过相似issue,否则请在已有的issue下进行讨论
+ 2. 请 **确保** [已有的问题](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue) 中没有人提交过相似 issue,否则请在已有的 issue 下进行讨论
3. 请 **务必** 给issue填写一个简洁明了的标题,以便他人快速检索
4. 请 **务必** 先下载 [AutoBuild](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/autobuild) 版本测试,确保该功能还未实现
- 5. 请 **务必** 按照模板规范详细描述问题,否则issue将会被关闭
+ 5. 请 **务必** 按照模板规范详细描述问题,否则 issue 将会被关闭
## Before submitting the issue, please make sure of the following checklist:
1. Please make sure you have read the [Clash Verge Rev official documentation](https://clash-verge-rev.github.io/guide/term.html) to confirm that the software does not have similar functions
2. Please make sure there is no similar issue in the [existing issues](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue), otherwise please discuss under the existing issue
diff --git a/clash-verge-rev/.github/workflows/alpha.yml b/clash-verge-rev/.github/workflows/alpha.yml
index cec7440ae7..425a663995 100644
--- a/clash-verge-rev/.github/workflows/alpha.yml
+++ b/clash-verge-rev/.github/workflows/alpha.yml
@@ -307,7 +307,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
- uses: pnpm/action-setup@v4
name: Install pnpm
@@ -377,7 +377,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
- name: Install pnpm
uses: pnpm/action-setup@v4
@@ -505,7 +505,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
- uses: pnpm/action-setup@v4
name: Install pnpm
@@ -522,8 +522,8 @@ jobs:
- name: Download WebView2 Runtime
run: |
- invoke-webrequest -uri https://github.com/westinyang/WebView2RuntimeArchive/releases/download/109.0.1518.78/Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -outfile Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab
- Expand .\Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -F:* ./src-tauri
+ invoke-webrequest -uri https://github.com/westinyang/WebView2RuntimeArchive/releases/download/133.0.3065.92/Microsoft.WebView2.FixedVersionRuntime.133.0.3065.92.${{ matrix.arch }}.cab -outfile Microsoft.WebView2.FixedVersionRuntime.133.0.3065.92.${{ matrix.arch }}.cab
+ Expand .\Microsoft.WebView2.FixedVersionRuntime.133.0.3065.92.${{ matrix.arch }}.cab -F:* ./src-tauri
Remove-Item .\src-tauri\tauri.windows.conf.json
Rename-Item .\src-tauri\webview2.${{ matrix.arch }}.json tauri.windows.conf.json
diff --git a/clash-verge-rev/.github/workflows/autobuild.yml b/clash-verge-rev/.github/workflows/autobuild.yml
index fd43e28b1b..aa983dc65d 100644
--- a/clash-verge-rev/.github/workflows/autobuild.yml
+++ b/clash-verge-rev/.github/workflows/autobuild.yml
@@ -46,7 +46,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
- name: Install dependencies
run: pnpm install --frozen-lockfile
@@ -187,11 +187,11 @@ jobs:
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
cache: "pnpm"
- name: Pnpm Cache
- uses: actions/cache@v4
+ uses: actions/cache@v5
with:
path: ~/.pnpm-store
key: "pnpm-shared-stable-${{ matrix.os }}-${{ matrix.target }}"
@@ -220,12 +220,12 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- # APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
- # APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
- # APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
- # APPLE_ID: ${{ secrets.APPLE_ID }}
- # APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
- # APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
+ APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
+ APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
+ APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
+ APPLE_ID: ${{ secrets.APPLE_ID }}
+ APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
+ APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
with:
tagName: ${{ env.TAG_NAME }}
releaseName: "Clash Verge Rev ${{ env.TAG_CHANNEL }}"
@@ -283,11 +283,11 @@ jobs:
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
cache: "pnpm"
- name: Pnpm Cache
- uses: actions/cache@v4
+ uses: actions/cache@v5
with:
path: ~/.pnpm-store
key: "pnpm-shared-stable-${{ matrix.os }}-${{ matrix.target }}"
@@ -433,11 +433,11 @@ jobs:
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
cache: "pnpm"
- name: Pnpm Cache
- uses: actions/cache@v4
+ uses: actions/cache@v5
with:
path: ~/.pnpm-store
key: "pnpm-shared-stable-${{ matrix.os }}-${{ matrix.target }}"
@@ -454,8 +454,8 @@ jobs:
- name: Download WebView2 Runtime
run: |
- invoke-webrequest -uri https://github.com/westinyang/WebView2RuntimeArchive/releases/download/109.0.1518.78/Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -outfile Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab
- Expand .\Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -F:* ./src-tauri
+ invoke-webrequest -uri https://github.com/westinyang/WebView2RuntimeArchive/releases/download/133.0.3065.92/Microsoft.WebView2.FixedVersionRuntime.133.0.3065.92.${{ matrix.arch }}.cab -outfile Microsoft.WebView2.FixedVersionRuntime.133.0.3065.92.${{ matrix.arch }}.cab
+ Expand .\Microsoft.WebView2.FixedVersionRuntime.133.0.3065.92.${{ matrix.arch }}.cab -F:* ./src-tauri
Remove-Item .\src-tauri\tauri.windows.conf.json
Rename-Item .\src-tauri\webview2.${{ matrix.arch }}.json tauri.windows.conf.json
@@ -535,7 +535,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
- uses: pnpm/action-setup@v4.2.0
name: Install pnpm
diff --git a/clash-verge-rev/.github/workflows/cross_check.yaml b/clash-verge-rev/.github/workflows/cross_check.yaml
index 06eeb91551..af9651a39e 100644
--- a/clash-verge-rev/.github/workflows/cross_check.yaml
+++ b/clash-verge-rev/.github/workflows/cross_check.yaml
@@ -43,7 +43,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
- uses: pnpm/action-setup@v4
name: Install pnpm
diff --git a/clash-verge-rev/.github/workflows/dev.yml b/clash-verge-rev/.github/workflows/dev.yml
index 74c7dd01f6..cbf96f9b51 100644
--- a/clash-verge-rev/.github/workflows/dev.yml
+++ b/clash-verge-rev/.github/workflows/dev.yml
@@ -103,11 +103,11 @@ jobs:
if: github.event.inputs[matrix.input] == 'true'
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
cache: "pnpm"
- name: Pnpm Cache
- uses: actions/cache@v4
+ uses: actions/cache@v5
with:
path: ~/.pnpm-store
key: "pnpm-shared-stable-${{ matrix.os }}-${{ matrix.target }}"
@@ -141,19 +141,19 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- # APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
- # APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
- # APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
- # APPLE_ID: ${{ secrets.APPLE_ID }}
- # APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
- # APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
+ APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
+ APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
+ APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
+ APPLE_ID: ${{ secrets.APPLE_ID }}
+ APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
+ APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
with:
tauriScript: pnpm
args: --target ${{ matrix.target }} -b ${{ matrix.bundle }}
- name: Upload Artifacts (macOS)
if: matrix.os == 'macos-latest' && github.event.inputs[matrix.input] == 'true'
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v6
with:
name: ${{ matrix.target }}
path: target/${{ matrix.target }}/release/bundle/dmg/*.dmg
@@ -161,7 +161,7 @@ jobs:
- name: Upload Artifacts (Windows)
if: matrix.os == 'windows-latest' && github.event.inputs[matrix.input] == 'true'
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v6
with:
name: ${{ matrix.target }}
path: target/${{ matrix.target }}/release/bundle/nsis/*.exe
@@ -169,7 +169,7 @@ jobs:
- name: Upload Artifacts (Linux)
if: matrix.os == 'ubuntu-22.04' && github.event.inputs[matrix.input] == 'true'
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v6
with:
name: ${{ matrix.target }}
path: target/${{ matrix.target }}/release/bundle/deb/*.deb
diff --git a/clash-verge-rev/.github/workflows/frontend-check.yml b/clash-verge-rev/.github/workflows/frontend-check.yml
index 4bb8455bdf..4649ce87d4 100644
--- a/clash-verge-rev/.github/workflows/frontend-check.yml
+++ b/clash-verge-rev/.github/workflows/frontend-check.yml
@@ -47,12 +47,12 @@ jobs:
- uses: actions/setup-node@v6
if: steps.check_frontend.outputs.frontend == 'true'
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
cache: "pnpm"
- name: Restore pnpm cache
if: steps.check_frontend.outputs.frontend == 'true'
- uses: actions/cache@v4
+ uses: actions/cache@v5
with:
path: ~/.pnpm-store
key: "pnpm-shared-stable-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}"
diff --git a/clash-verge-rev/.github/workflows/release.yml b/clash-verge-rev/.github/workflows/release.yml
index f3f2b271fc..4fd48c8b48 100644
--- a/clash-verge-rev/.github/workflows/release.yml
+++ b/clash-verge-rev/.github/workflows/release.yml
@@ -121,6 +121,7 @@ jobs:
### 稳定机场VPN推荐
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
+
Created at ${{ env.BUILDTIME }}.
EOF
@@ -159,7 +160,10 @@ jobs:
uses: actions/checkout@v6
- name: Install Rust Stable
- uses: dtolnay/rust-toolchain@stable
+ uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: "1.91.0"
+ targets: ${{ matrix.target }}
- name: Add Rust Target
run: rustup target add ${{ matrix.target }}
@@ -167,8 +171,13 @@ jobs:
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
- workspaces: src-tauri
- save-if: false
+ save-if: ${{ github.ref == 'refs/heads/dev' }}
+ prefix-key: "v1-rust"
+ key: "rust-shared-stable-${{ matrix.os }}-${{ matrix.target }}"
+ workspaces: |
+ . -> target
+ cache-all-crates: true
+ cache-workspace-crates: true
- name: Install dependencies (ubuntu only)
if: matrix.os == 'ubuntu-22.04'
@@ -188,7 +197,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
- uses: pnpm/action-setup@v4
name: Install pnpm
@@ -200,6 +209,13 @@ jobs:
pnpm i
pnpm run prebuild ${{ matrix.target }}
+ - name: Add Rust Target
+ run: |
+ # Ensure cross target is installed for the pinned toolchain; fallback without explicit toolchain if needed
+ rustup target add ${{ matrix.target }} --toolchain 1.91.0 || rustup target add ${{ matrix.target }}
+ rustup target list --installed
+ echo "Rust target ${{ matrix.target }} installed."
+
- name: Tauri build
# 上游 5.24 修改了 latest.json 的生成逻辑,且依赖 tauri-plugin-update 2.10.0 暂未发布,故锁定在 0.5.23 版本
uses: tauri-apps/tauri-action@v0.6.0
@@ -243,7 +259,10 @@ jobs:
uses: actions/checkout@v6
- name: Install Rust Stable
- uses: dtolnay/rust-toolchain@stable
+ uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: "1.91.0"
+ targets: ${{ matrix.target }}
- name: Add Rust Target
run: rustup target add ${{ matrix.target }}
@@ -251,13 +270,18 @@ jobs:
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
- workspaces: src-tauri
- save-if: false
+ save-if: ${{ github.ref == 'refs/heads/dev' }}
+ prefix-key: "v1-rust"
+ key: "rust-shared-stable-${{ matrix.os }}-${{ matrix.target }}"
+ workspaces: |
+ . -> target
+ cache-all-crates: true
+ cache-workspace-crates: true
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
- name: Install pnpm
uses: pnpm/action-setup@v4
@@ -313,6 +337,13 @@ jobs:
gcc-arm-linux-gnueabihf \
g++-arm-linux-gnueabihf
+ - name: Add Rust Target
+ run: |
+ # Ensure cross target is installed for the pinned toolchain; fallback without explicit toolchain if needed
+ rustup target add ${{ matrix.target }} --toolchain 1.91.0 || rustup target add ${{ matrix.target }}
+ rustup target list --installed
+ echo "Rust target ${{ matrix.target }} installed."
+
- name: Build for Linux
run: |
export PKG_CONFIG_ALLOW_CROSS=1
@@ -345,8 +376,8 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
prerelease: ${{ contains(github.ref_name, '-rc') }}
files: |
- src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
- src-tauri/target/${{ matrix.target }}/release/bundle/rpm/*.rpm
+ target/${{ matrix.target }}/release/bundle/deb/*.deb
+ target/${{ matrix.target }}/release/bundle/rpm/*.rpm
release-for-fixed-webview2:
name: Release Build for Fixed WebView2
@@ -366,19 +397,30 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@v6
+ - name: Install Rust Stable
+ uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: "1.91.0"
+ targets: ${{ matrix.target }}
+
- name: Add Rust Target
run: rustup target add ${{ matrix.target }}
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
- workspaces: src-tauri
- save-if: false
+ save-if: ${{ github.ref == 'refs/heads/dev' }}
+ prefix-key: "v1-rust"
+ key: "rust-shared-stable-${{ matrix.os }}-${{ matrix.target }}"
+ workspaces: |
+ . -> target
+ cache-all-crates: true
+ cache-workspace-crates: true
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
- uses: pnpm/action-setup@v4
name: Install pnpm
@@ -392,14 +434,20 @@ jobs:
- name: Download WebView2 Runtime
run: |
- invoke-webrequest -uri https://github.com/westinyang/WebView2RuntimeArchive/releases/download/109.0.1518.78/Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -outfile Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab
- Expand .\Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -F:* ./src-tauri
+ invoke-webrequest -uri https://github.com/westinyang/WebView2RuntimeArchive/releases/download/133.0.3065.92/Microsoft.WebView2.FixedVersionRuntime.133.0.3065.92.${{ matrix.arch }}.cab -outfile Microsoft.WebView2.FixedVersionRuntime.133.0.3065.92.${{ matrix.arch }}.cab
+ Expand .\Microsoft.WebView2.FixedVersionRuntime.133.0.3065.92.${{ matrix.arch }}.cab -F:* ./src-tauri
Remove-Item .\src-tauri\tauri.windows.conf.json
Rename-Item .\src-tauri\webview2.${{ matrix.arch }}.json tauri.windows.conf.json
+ - name: Add Rust Target
+ run: |
+ # Ensure cross target is installed for the pinned toolchain; fallback without explicit toolchain if needed
+ rustup target add ${{ matrix.target }} --toolchain 1.91.0 || rustup target add ${{ matrix.target }}
+ rustup target list --installed
+ echo "Rust target ${{ matrix.target }} installed."
+
- name: Tauri build
id: build
- # 上游 5.24 修改了 latest.json 的生成逻辑,且依赖 tauri-plugin-update 2.10.0 暂未发布,故锁定在 0.5.23 版本
uses: tauri-apps/tauri-action@v0.6.0
env:
NODE_OPTIONS: "--max_old_space_size=4096"
@@ -438,7 +486,7 @@ jobs:
body: "See release notes for detailed changelog."
token: ${{ secrets.GITHUB_TOKEN }}
prerelease: ${{ contains(github.ref_name, '-rc') }}
- files: src-tauri/target/${{ matrix.target }}/release/bundle/nsis/*setup*
+ files: target/${{ matrix.target }}/release/bundle/nsis/*setup*
- name: Portable Bundle
run: pnpm portable-fixed-webview2 ${{ matrix.target }}
@@ -457,7 +505,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
- uses: pnpm/action-setup@v4
name: Install pnpm
@@ -483,7 +531,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
- uses: pnpm/action-setup@v4
name: Install pnpm
@@ -545,7 +593,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
- uses: pnpm/action-setup@v4
name: Install pnpm
@@ -599,6 +647,7 @@ jobs:
### 稳定机场VPN推荐
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
+
Created at ${{ env.BUILDTIME }}.
EOF
diff --git a/clash-verge-rev/.github/workflows/updater.yml b/clash-verge-rev/.github/workflows/updater.yml
index 1e182197cb..a2fdc8611c 100644
--- a/clash-verge-rev/.github/workflows/updater.yml
+++ b/clash-verge-rev/.github/workflows/updater.yml
@@ -15,7 +15,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
- uses: pnpm/action-setup@v4
name: Install pnpm
@@ -39,7 +39,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v6
with:
- node-version: "24.11.1"
+ node-version: "24.12.0"
- uses: pnpm/action-setup@v4
name: Install pnpm
diff --git a/clash-verge-rev/.husky/pre-commit b/clash-verge-rev/.husky/pre-commit
index 4c21a04538..ea74c92fcd 100755
--- a/clash-verge-rev/.husky/pre-commit
+++ b/clash-verge-rev/.husky/pre-commit
@@ -28,24 +28,18 @@ pnpm exec lint-staged
RUST_FILES="$(git diff --cached --name-only --diff-filter=ACMR | grep -E '^src-tauri/.*\.rs$' || true)"
if [ -n "$RUST_FILES" ]; then
echo "[pre-commit] Formatting Rust changes with cargo fmt..."
- (
- cd src-tauri
- cargo fmt
- )
+ cargo fmt
while IFS= read -r file; do
[ -n "$file" ] && git add "$file"
done <<< "$RUST_FILES"
echo "[pre-commit] Linting Rust changes with cargo clippy..."
- (
- cd src-tauri
- cargo clippy-all
- if ! command -v clash-verge-logging-check >/dev/null 2>&1; then
- echo "[pre-commit] Installing clash-verge-logging-check..."
- cargo install --git https://github.com/clash-verge-rev/clash-verge-logging-check.git
- fi
- clash-verge-logging-check
- )
+ cargo clippy-all
+ if ! command -v clash-verge-logging-check >/dev/null 2>&1; then
+ echo "[pre-commit] Installing clash-verge-logging-check..."
+ cargo install --git https://github.com/clash-verge-rev/clash-verge-logging-check.git
+ fi
+ clash-verge-logging-check
fi
TS_FILES="$(git diff --cached --name-only --diff-filter=ACMR | grep -E '\.(ts|tsx)$' || true)"
diff --git a/clash-verge-rev/.husky/pre-push b/clash-verge-rev/.husky/pre-push
index 4f2a6a6b70..e1781c43ff 100644
--- a/clash-verge-rev/.husky/pre-push
+++ b/clash-verge-rev/.husky/pre-push
@@ -25,16 +25,10 @@ pnpm typecheck
if command -v cargo >/dev/null 2>&1; then
echo "[pre-push] Verifying Rust formatting..."
- (
- cd src-tauri
- cargo fmt --check
- )
+ cargo fmt --check
echo "[pre-push] Running cargo clippy..."
- (
- cd src-tauri
- cargo clippy-all
- )
+ cargo clippy-all
else
echo "[pre-push] ⚠️ cargo not found; skipping Rust checks."
fi
diff --git a/clash-verge-rev/CONTRIBUTING.md b/clash-verge-rev/CONTRIBUTING.md
index 833289ad41..9b9b2d32b9 100644
--- a/clash-verge-rev/CONTRIBUTING.md
+++ b/clash-verge-rev/CONTRIBUTING.md
@@ -119,13 +119,17 @@ cargo fmt
pnpm format
```
+### Signing your commit
+
+Signed commits are required to verify authorship and ensure your contributions can be merged. Reference signing-commits [here](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits).
+
### Submitting Your Changes
1. Fork the repository.
2. Create a new branch for your feature or bug fix.
-3. Commit your changes with clear messages.
+3. Commit your changes with clear messages and make sure it's signed.
4. Push your branch and submit a pull request.
diff --git a/clash-verge-rev/Cargo.lock b/clash-verge-rev/Cargo.lock
index cc3352a4dc..865975717b 100644
--- a/clash-verge-rev/Cargo.lock
+++ b/clash-verge-rev/Cargo.lock
@@ -588,7 +588,7 @@ dependencies = [
"axum-core 0.5.5",
"bytes",
"futures-util",
- "http 1.3.1",
+ "http 1.4.0",
"http-body 1.0.1",
"http-body-util",
"itoa",
@@ -629,7 +629,7 @@ checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22"
dependencies = [
"bytes",
"futures-core",
- "http 1.3.1",
+ "http 1.4.0",
"http-body 1.0.1",
"http-body-util",
"mime",
@@ -1002,9 +1002,9 @@ dependencies = [
[[package]]
name = "camino"
-version = "1.2.1"
+version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609"
+checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48"
dependencies = [
"serde_core",
]
@@ -1059,9 +1059,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.2.47"
+version = "1.2.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07"
+checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215"
dependencies = [
"find-msvc-tools",
"jobserver",
@@ -1186,7 +1186,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
[[package]]
name = "clash-verge"
-version = "2.4.4"
+version = "2.4.4-rc.1"
dependencies = [
"aes-gcm",
"anyhow",
@@ -1285,10 +1285,7 @@ version = "0.1.0"
dependencies = [
"clash-verge-logging",
"log",
- "signal-hook 0.3.18",
- "tauri",
"tokio",
- "windows-sys 0.61.2",
]
[[package]]
@@ -1302,8 +1299,8 @@ dependencies = [
[[package]]
name = "clash_verge_logger"
-version = "0.2.1"
-source = "git+https://github.com/clash-verge-rev/clash-verge-logger#955f1b709890640ff01fd30009df0f35816bbca6"
+version = "0.2.2"
+source = "git+https://github.com/clash-verge-rev/clash-verge-logger#e4768e3852c4868ed86e7210df82c1178467820d"
dependencies = [
"arraydeque",
"compact_str",
@@ -1315,8 +1312,8 @@ dependencies = [
[[package]]
name = "clash_verge_service_ipc"
-version = "2.0.21"
-source = "git+https://github.com/clash-verge-rev/clash-verge-service-ipc#da00a684c2b9723d647ed4992714eb669fcbd8a2"
+version = "2.0.26"
+source = "git+https://github.com/clash-verge-rev/clash-verge-service-ipc#37b9964a9bce767b5b95ea2be75613b23400c9f0"
dependencies = [
"anyhow",
"compact_str",
@@ -1602,9 +1599,9 @@ dependencies = [
[[package]]
name = "crc"
-version = "3.3.0"
+version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675"
+checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d"
dependencies = [
"crc-catalog",
]
@@ -2137,9 +2134,9 @@ dependencies = [
[[package]]
name = "dlopen2"
-version = "0.8.0"
+version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b54f373ccf864bf587a89e880fb7610f8d73f3045f13580948ccbcaff26febff"
+checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4"
dependencies = [
"dlopen2_derive",
"libc",
@@ -2149,9 +2146,9 @@ dependencies = [
[[package]]
name = "dlopen2_derive"
-version = "0.4.1"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4"
+checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f"
dependencies = [
"proc-macro2",
"quote",
@@ -2287,9 +2284,9 @@ dependencies = [
[[package]]
name = "endi"
-version = "1.1.0"
+version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf"
+checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099"
[[package]]
name = "enumflags2"
@@ -3178,7 +3175,7 @@ dependencies = [
"fnv",
"futures-core",
"futures-sink",
- "http 1.3.1",
+ "http 1.4.0",
"indexmap 2.12.1",
"slab",
"tokio",
@@ -3267,7 +3264,7 @@ dependencies = [
"base64 0.22.1",
"bytes",
"headers-core",
- "http 1.3.1",
+ "http 1.4.0",
"httpdate",
"mime",
"sha1",
@@ -3279,7 +3276,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
dependencies = [
- "http 1.3.1",
+ "http 1.4.0",
]
[[package]]
@@ -3355,12 +3352,11 @@ dependencies = [
[[package]]
name = "http"
-version = "1.3.1"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
+checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
dependencies = [
"bytes",
- "fnv",
"itoa",
]
@@ -3382,7 +3378,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [
"bytes",
- "http 1.3.1",
+ "http 1.4.0",
]
[[package]]
@@ -3393,7 +3389,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
dependencies = [
"bytes",
"futures-core",
- "http 1.3.1",
+ "http 1.4.0",
"http-body 1.0.1",
"pin-project-lite",
]
@@ -3463,7 +3459,7 @@ dependencies = [
"futures-channel",
"futures-core",
"h2 0.4.12",
- "http 1.3.1",
+ "http 1.4.0",
"http-body 1.0.1",
"httparse",
"httpdate",
@@ -3481,7 +3477,7 @@ version = "0.27.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
dependencies = [
- "http 1.3.1",
+ "http 1.4.0",
"hyper 1.8.1",
"hyper-util",
"rustls",
@@ -3535,16 +3531,16 @@ dependencies = [
[[package]]
name = "hyper-util"
-version = "0.1.18"
+version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56"
+checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f"
dependencies = [
"base64 0.22.1",
"bytes",
"futures-channel",
"futures-core",
"futures-util",
- "http 1.3.1",
+ "http 1.4.0",
"http-body 1.0.1",
"hyper 1.8.1",
"ipnet",
@@ -3996,9 +3992,9 @@ dependencies = [
[[package]]
name = "js-sys"
-version = "0.3.82"
+version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
+checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
dependencies = [
"once_cell",
"wasm-bindgen",
@@ -4039,13 +4035,13 @@ dependencies = [
[[package]]
name = "kode-bridge"
-version = "0.3.4"
+version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b158d8b9ab9f07c892a3f1b5d44a79e6c74e97541bf66488025796d429cf7aac"
+checksum = "0ba2fd0531052f4438d171509ee7686b6b2207314366a5e2dde80586f6d6a09b"
dependencies = [
"bytes",
"futures",
- "http 1.3.1",
+ "http 1.4.0",
"httparse",
"interprocess",
"libc",
@@ -4161,9 +4157,9 @@ dependencies = [
[[package]]
name = "libz-rs-sys"
-version = "0.5.2"
+version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "840db8cf39d9ec4dd794376f38acc40d0fc65eec2a8f484f7fd375b84602becd"
+checksum = "15413ef615ad868d4d65dce091cb233b229419c7c0c4bcaa746c0901c49ff39c"
dependencies = [
"zlib-rs",
]
@@ -4274,9 +4270,9 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "mac-notification-sys"
-version = "0.6.8"
+version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ee70bb2bba058d58e252d2944582d634fc884fc9c489a966d428dedcf653e97"
+checksum = "65fd3f75411f4725061682ed91f131946e912859d0044d39c4ec0aac818d7621"
dependencies = [
"cc",
"objc2 0.6.3",
@@ -4425,9 +4421,9 @@ dependencies = [
[[package]]
name = "mio"
-version = "1.1.0"
+version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
+checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
dependencies = [
"libc",
"wasi 0.11.1+wasi-snapshot-preview1",
@@ -4436,9 +4432,9 @@ dependencies = [
[[package]]
name = "moxcms"
-version = "0.7.9"
+version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fbdd3d7436f8b5e892b8b7ea114271ff0fa00bc5acae845d53b07d498616ef6"
+checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97"
dependencies = [
"num-traits",
"pxfm",
@@ -4817,7 +4813,7 @@ dependencies = [
"objc2-core-text",
"objc2-core-video",
"objc2-foundation 0.3.2",
- "objc2-quartz-core 0.3.2",
+ "objc2-quartz-core",
]
[[package]]
@@ -4972,18 +4968,6 @@ dependencies = [
"objc2-core-foundation",
]
-[[package]]
-name = "objc2-metal"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
-dependencies = [
- "bitflags 2.10.0",
- "block2 0.5.1",
- "objc2 0.5.2",
- "objc2-foundation 0.2.2",
-]
-
[[package]]
name = "objc2-osa-kit"
version = "0.3.2"
@@ -4996,19 +4980,6 @@ dependencies = [
"objc2-foundation 0.3.2",
]
-[[package]]
-name = "objc2-quartz-core"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
-dependencies = [
- "bitflags 2.10.0",
- "block2 0.5.1",
- "objc2 0.5.2",
- "objc2-foundation 0.2.2",
- "objc2-metal",
-]
-
[[package]]
name = "objc2-quartz-core"
version = "0.3.2"
@@ -5017,6 +4988,7 @@ checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f"
dependencies = [
"bitflags 2.10.0",
"objc2 0.6.3",
+ "objc2-core-foundation",
"objc2-foundation 0.3.2",
]
@@ -5780,7 +5752,7 @@ version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
dependencies = [
- "toml_edit 0.23.7",
+ "toml_edit 0.23.9",
]
[[package]]
@@ -5924,9 +5896,9 @@ dependencies = [
[[package]]
name = "pxfm"
-version = "0.1.25"
+version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3cbdf373972bf78df4d3b518d07003938e2c7d1fb5891e55f9cb6df57009d84"
+checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8"
dependencies = [
"num-traits",
]
@@ -6274,9 +6246,9 @@ checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6"
[[package]]
name = "reqwest"
-version = "0.12.24"
+version = "0.12.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f"
+checksum = "b6eff9328d40131d43bd911d42d79eb6a47312002a4daefc9e37f17e74a7701a"
dependencies = [
"base64 0.22.1",
"bytes",
@@ -6286,7 +6258,7 @@ dependencies = [
"futures-core",
"futures-util",
"h2 0.4.12",
- "http 1.3.1",
+ "http 1.4.0",
"http-body 1.0.1",
"http-body-util",
"hyper 1.8.1",
@@ -6311,7 +6283,7 @@ dependencies = [
"tokio-rustls",
"tokio-util",
"tower 0.5.2",
- "tower-http 0.6.6",
+ "tower-http 0.6.8",
"tower-service",
"url",
"wasm-bindgen",
@@ -6330,7 +6302,7 @@ dependencies = [
"async-trait",
"chrono",
"digest_auth",
- "http 1.3.1",
+ "http 1.4.0",
"httpdate",
"reqwest",
"serde",
@@ -6589,9 +6561,9 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
-version = "1.13.0"
+version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a"
+checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c"
dependencies = [
"web-time",
"zeroize",
@@ -6912,9 +6884,9 @@ dependencies = [
[[package]]
name = "serde_with"
-version = "3.16.0"
+version = "3.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10574371d41b0d9b2cff89418eda27da52bcaff2cc8741db26382a77c29131f1"
+checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7"
dependencies = [
"base64 0.22.1",
"chrono",
@@ -6931,9 +6903,9 @@ dependencies = [
[[package]]
name = "serde_with_macros"
-version = "3.16.0"
+version = "3.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08a72d8216842fdd57820dc78d840bef99248e35fb2554ff923319e60f2d686b"
+checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c"
dependencies = [
"darling",
"proc-macro2",
@@ -7112,9 +7084,9 @@ dependencies = [
[[package]]
name = "simd-adler32"
-version = "0.3.7"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
+checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
[[package]]
name = "siphasher"
@@ -7210,24 +7182,24 @@ dependencies = [
[[package]]
name = "softbuffer"
-version = "0.4.6"
+version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08"
+checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3"
dependencies = [
"bytemuck",
- "cfg_aliases",
- "core-graphics",
- "foreign-types 0.5.0",
"js-sys",
- "log",
- "objc2 0.5.2",
- "objc2-foundation 0.2.2",
- "objc2-quartz-core 0.2.2",
+ "ndk",
+ "objc2 0.6.3",
+ "objc2-core-foundation",
+ "objc2-core-graphics",
+ "objc2-foundation 0.3.2",
+ "objc2-quartz-core",
"raw-window-handle",
"redox_syscall",
+ "tracing",
"wasm-bindgen",
"web-sys",
- "windows-sys 0.59.0",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -7413,8 +7385,8 @@ dependencies = [
[[package]]
name = "sysproxy"
-version = "0.4.0"
-source = "git+https://github.com/clash-verge-rev/sysproxy-rs#0f844dd2639b0ac74da4548b1325335844947420"
+version = "0.4.2"
+source = "git+https://github.com/clash-verge-rev/sysproxy-rs#51256d5921a01bbcf24fe5629296d2bfe493329d"
dependencies = [
"interfaces",
"iptools",
@@ -7543,9 +7515,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "tauri"
-version = "2.9.4"
+version = "2.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15524fc7959bfcaa051ba6d0b3fb1ef18e978de2176c7c6acb977f7fd14d35c7"
+checksum = "8a3868da5508446a7cd08956d523ac3edf0a8bc20bf7e4038f9a95c2800d2033"
dependencies = [
"anyhow",
"bytes",
@@ -7557,7 +7529,7 @@ dependencies = [
"glob",
"gtk",
"heck 0.5.0",
- "http 1.3.1",
+ "http 1.4.0",
"http-range",
"image",
"jni",
@@ -7660,9 +7632,9 @@ dependencies = [
[[package]]
name = "tauri-plugin"
-version = "2.5.1"
+version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "076c78a474a7247c90cad0b6e87e593c4c620ed4efdb79cbe0214f0021f6c39d"
+checksum = "0e1d0a4860b7ff570c891e1d2a586bf1ede205ff858fbc305e0b5ae5d14c1377"
dependencies = [
"anyhow",
"glob",
@@ -7828,7 +7800,7 @@ dependencies = [
"bytes",
"cookie_store",
"data-url",
- "http 1.3.1",
+ "http 1.4.0",
"regex",
"reqwest",
"schemars 0.8.22",
@@ -7846,11 +7818,11 @@ dependencies = [
[[package]]
name = "tauri-plugin-mihomo"
version = "0.1.1"
-source = "git+https://github.com/clash-verge-rev/tauri-plugin-mihomo#24586eb0721314f88e65460b4ac01933b3376d3c"
+source = "git+https://github.com/clash-verge-rev/tauri-plugin-mihomo#153f16f7b3f979aa130a2d3d7c39a52a39987288"
dependencies = [
"base64 0.22.1",
"futures-util",
- "http 1.3.1",
+ "http 1.4.0",
"httparse",
"log",
"pin-project",
@@ -7928,7 +7900,7 @@ dependencies = [
"dirs 6.0.0",
"flate2",
"futures-util",
- "http 1.3.1",
+ "http 1.4.0",
"infer",
"log",
"minisign-verify",
@@ -7974,7 +7946,7 @@ dependencies = [
"cookie",
"dpi",
"gtk",
- "http 1.3.1",
+ "http 1.4.0",
"jni",
"objc2 0.6.3",
"objc2-ui-kit",
@@ -7992,12 +7964,12 @@ dependencies = [
[[package]]
name = "tauri-runtime-wry"
-version = "2.9.2"
+version = "2.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7950f3bde6bcca6655bc5e76d3d6ec587ceb81032851ab4ddbe1f508bdea2729"
+checksum = "187a3f26f681bdf028f796ccf57cf478c1ee422c50128e5a0a6ebeb3f5910065"
dependencies = [
"gtk",
- "http 1.3.1",
+ "http 1.4.0",
"jni",
"log",
"objc2 0.6.3",
@@ -8031,7 +8003,7 @@ dependencies = [
"dunce",
"glob",
"html5ever",
- "http 1.3.1",
+ "http 1.4.0",
"infer",
"json-patch",
"kuchikiki",
@@ -8444,7 +8416,7 @@ dependencies = [
"toml_datetime 0.7.3",
"toml_parser",
"toml_writer",
- "winnow 0.7.13",
+ "winnow 0.7.14",
]
[[package]]
@@ -8498,19 +8470,19 @@ dependencies = [
"serde_spanned 0.6.9",
"toml_datetime 0.6.11",
"toml_write",
- "winnow 0.7.13",
+ "winnow 0.7.14",
]
[[package]]
name = "toml_edit"
-version = "0.23.7"
+version = "0.23.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d"
+checksum = "5d7cbc3b4b49633d57a0509303158ca50de80ae32c265093b24c414705807832"
dependencies = [
"indexmap 2.12.1",
"toml_datetime 0.7.3",
"toml_parser",
- "winnow 0.7.13",
+ "winnow 0.7.14",
]
[[package]]
@@ -8519,7 +8491,7 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e"
dependencies = [
- "winnow 0.7.13",
+ "winnow 0.7.14",
]
[[package]]
@@ -8572,7 +8544,7 @@ dependencies = [
"base64 0.22.1",
"bytes",
"h2 0.4.12",
- "http 1.3.1",
+ "http 1.4.0",
"http-body 1.0.1",
"http-body-util",
"hyper 1.8.1",
@@ -8693,14 +8665,14 @@ dependencies = [
[[package]]
name = "tower-http"
-version = "0.6.6"
+version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
+checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
dependencies = [
"bitflags 2.10.0",
"bytes",
"futures-util",
- "http 1.3.1",
+ "http 1.4.0",
"http-body 1.0.1",
"iri-string",
"pin-project-lite",
@@ -8723,9 +8695,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]]
name = "tracing"
-version = "0.1.41"
+version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647"
dependencies = [
"log",
"pin-project-lite",
@@ -8735,9 +8707,9 @@ dependencies = [
[[package]]
name = "tracing-attributes"
-version = "0.1.30"
+version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
@@ -8746,9 +8718,9 @@ dependencies = [
[[package]]
name = "tracing-core"
-version = "0.1.34"
+version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
+checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c"
dependencies = [
"once_cell",
"valuable",
@@ -8767,9 +8739,9 @@ dependencies = [
[[package]]
name = "tracing-subscriber"
-version = "0.3.20"
+version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
+checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
dependencies = [
"matchers",
"nu-ansi-term",
@@ -8863,7 +8835,7 @@ checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442"
dependencies = [
"bytes",
"data-encoding",
- "http 1.3.1",
+ "http 1.4.0",
"httparse",
"log",
"rand 0.9.2",
@@ -9044,13 +9016,13 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
-version = "1.18.1"
+version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2"
+checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
dependencies = [
"getrandom 0.3.4",
"js-sys",
- "serde",
+ "serde_core",
"wasm-bindgen",
]
@@ -9147,7 +9119,7 @@ dependencies = [
"bytes",
"futures-util",
"headers",
- "http 1.3.1",
+ "http 1.4.0",
"http-body 1.0.1",
"http-body-util",
"hyper 1.8.1",
@@ -9190,9 +9162,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
-version = "0.2.105"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
+checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
dependencies = [
"cfg-if",
"once_cell",
@@ -9203,9 +9175,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.55"
+version = "0.4.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0"
+checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c"
dependencies = [
"cfg-if",
"js-sys",
@@ -9216,9 +9188,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.105"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
+checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -9226,9 +9198,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.105"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
+checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
dependencies = [
"bumpalo",
"proc-macro2",
@@ -9239,9 +9211,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.105"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
+checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
dependencies = [
"unicode-ident",
]
@@ -9334,9 +9306,9 @@ dependencies = [
[[package]]
name = "web-sys"
-version = "0.3.82"
+version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1"
+checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -10049,9 +10021,9 @@ dependencies = [
[[package]]
name = "winnow"
-version = "0.7.13"
+version = "0.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
+checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
dependencies = [
"memchr",
]
@@ -10093,15 +10065,14 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
[[package]]
name = "wl-clipboard-rs"
-version = "0.9.2"
+version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e5ff8d0e60065f549fafd9d6cb626203ea64a798186c80d8e7df4f8af56baeb"
+checksum = "e9651471a32e87d96ef3a127715382b2d11cc7c8bb9822ded8a7cc94072eb0a3"
dependencies = [
"libc",
"log",
"os_pipe",
- "rustix 0.38.44",
- "tempfile",
+ "rustix 1.1.2",
"thiserror 2.0.17",
"tree_magic_mini",
"wayland-backend",
@@ -10138,7 +10109,7 @@ dependencies = [
"gdkx11",
"gtk",
"html5ever",
- "http 1.3.1",
+ "http 1.4.0",
"javascriptcore-rs",
"jni",
"kuchikiki",
@@ -10292,7 +10263,7 @@ dependencies = [
"uds_windows",
"uuid",
"windows-sys 0.61.2",
- "winnow 0.7.13",
+ "winnow 0.7.14",
"zbus_macros",
"zbus_names",
"zvariant",
@@ -10321,24 +10292,24 @@ checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97"
dependencies = [
"serde",
"static_assertions",
- "winnow 0.7.13",
+ "winnow 0.7.14",
"zvariant",
]
[[package]]
name = "zerocopy"
-version = "0.8.28"
+version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43fa6694ed34d6e57407afbccdeecfa268c470a7d2a5b0cf49ce9fcc345afb90"
+checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
-version = "0.8.28"
+version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c640b22cd9817fae95be82f0d2f90b11f7605f6c319d16705c459b27ac2cbc26"
+checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a"
dependencies = [
"proc-macro2",
"quote",
@@ -10461,9 +10432,9 @@ dependencies = [
[[package]]
name = "zlib-rs"
-version = "0.5.2"
+version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2"
+checksum = "51f936044d677be1a1168fae1d03b583a285a5dd9d8cbf7b24c23aa1fc775235"
[[package]]
name = "zopfli"
@@ -10530,7 +10501,7 @@ dependencies = [
"enumflags2",
"serde",
"url",
- "winnow 0.7.13",
+ "winnow 0.7.14",
"zvariant_derive",
"zvariant_utils",
]
@@ -10558,5 +10529,5 @@ dependencies = [
"quote",
"serde",
"syn 2.0.111",
- "winnow 0.7.13",
+ "winnow 0.7.14",
]
diff --git a/clash-verge-rev/Cargo.toml b/clash-verge-rev/Cargo.toml
index dd4607e89b..77c5657f19 100644
--- a/clash-verge-rev/Cargo.toml
+++ b/clash-verge-rev/Cargo.toml
@@ -9,9 +9,6 @@ members = [
]
resolver = "2"
-[workspace.package]
-edition = "2024"
-rust-version = "1.91"
[profile.release]
panic = "abort"
@@ -49,7 +46,7 @@ clash-verge-signal = { path = "crates/clash-verge-signal" }
clash-verge-types = { path = "crates/clash-verge-types" }
tauri-plugin-clash-verge-sysinfo = { path = "crates/tauri-plugin-clash-verge-sysinfo" }
-tauri = { version = "2.9.4" }
+tauri = { version = "2.9.5" }
tauri-plugin-clipboard-manager = "2.3.2"
parking_lot = { version = "0.12.5", features = ["hardware-lock-elision"] }
anyhow = "1.0.100"
diff --git a/clash-verge-rev/Changelog.md b/clash-verge-rev/Changelog.md
index f786ab6ef2..46dbd71b35 100644
--- a/clash-verge-rev/Changelog.md
+++ b/clash-verge-rev/Changelog.md
@@ -2,10 +2,6 @@
- **Mihomo(Meta) 内核升级至 v1.19.17**
-> [!WARNING]
-> Apple 公证服务故障,临时暂停 macOS 签名
-> macOS 跳过签名,终端执行 `sudo xattr -rd com.apple.quarantine /Applications/Clash\ Verge.app/`
-
### 🐞 修复问题
- Linux 无法切换 TUN 堆栈
@@ -17,7 +13,6 @@
- Monaco 编辑器的行数上限
- 已删除节点在手动分组中导致配置无法加载
- 仪表盘与托盘状态不同步
-- 修复重启或退出应用,关闭系统时无法记忆用户行为
- 彻底修复 macOS 连接页面显示异常
- windows 端监听关机信号失败
- 修复代理按钮和高亮状态不同步
@@ -27,6 +22,14 @@
- 修复在搜索框输入不完整正则直接崩溃
- 修复创建窗口时在非简体中文环境或深色主题下的短暂闪烁
- 修复更新时加载进度条异常
+- 升级内核失败导致内核不可用问题
+- 修复 macOS 在安装和卸载服务时提示与操作不匹配
+- 修复菜单排序模式拖拽异常
+- 修复托盘菜单代理组前的异常勾选状态
+- 修复 Windows 下自定义标题栏按钮在最小化 / 关闭后 hover 状态残留
+- 修复直接覆盖 `config.yaml` 使用时无法展开代理组
+- 修复 macOS 下应用启动时系统托盘图标颜色闪烁
+- 修复应用静默启动模式下非全局热键一直抢占其他应用按键问题
✨ 新增功能
@@ -36,6 +39,9 @@
- 连接页面支持查看已关闭的连接(最近最多 500 个已关闭连接)
- 日志页面支持按时间倒序
- 增加「重新激活订阅」的全局快捷键
+- WebView2 Runtime 修复构建升级到 133.0.3065.92
+- 侧边栏右键新增「恢复默认排序」
+- Linux 下新增对 TUN 「自动重定向」(`auto-redirect` 字段)的配置支持,默认关闭
@@ -47,7 +53,7 @@
- 替换前端信息编辑组件,提供更好性能
- 优化后端内存和性能表现
- 防止退出时可能的禁用 TUN 失败
-- i18n 支持
+- 全新 i18n 支持方式
- 优化备份设置布局
- 优化流量图性能表现,实现动态 FPS 和窗口失焦自动暂停
- 性能优化系统状态获取
@@ -58,6 +64,11 @@
- 优化前端数据刷新
- 优化流量采样和数据处理
- 优化应用重启/退出时的资源清理性能, 大幅缩短执行时间
+- 优化前端 WebSocket 连接机制
+- 改进旧版 Service 需要重新安装检测流程
+- 优化 macOS, Linux 和 Windows 系统信号处理
+- 链式代理仅显示 Selector 类型规则组
+- 优化 Windows 系统代理设置,不再依赖 `sysproxy.exe` 来设置代理
diff --git a/clash-verge-rev/README.md b/clash-verge-rev/README.md
index b7e70f7dfe..761dce423e 100644
--- a/clash-verge-rev/README.md
+++ b/clash-verge-rev/README.md
@@ -16,7 +16,8 @@ A Clash Meta GUI based on TauriEspañol ·
Русский ·
日本語 ·
- 한국어
+ 한국어 ·
+ فارسی
## Preview
@@ -47,17 +48,23 @@ Supports Windows (x64/x86), Linux (x64/arm64) and macOS 10.15+ (intel/apple).
## Promotion
-#### [狗狗加速 —— 技术流机场 Doggygo VPN](https://verge.dginv.click/#/register?code=oaxsAGo6)
+### ✈️ [狗狗加速 —— 技术流机场 Doggygo VPN](https://verge.dginv.click/#/register?code=oaxsAGo6)
-- 高性能海外机场,免费试用,优惠套餐,解锁流媒体,全球首家支持 Hysteria 协议。
-- 使用 Clash Verge 专属邀请链接注册送 3 天,每天 1G 流量免费试用:[点此注册](https://verge.dginv.click/#/register?code=oaxsAGo6)
-- Clash Verge 专属 8 折优惠码: verge20 (仅有 500 份)
-- 优惠套餐每月仅需 15.8 元,160G 流量,年付 8 折
-- 海外团队,无跑路风险,高达 50% 返佣
-- 集群负载均衡设计,高速专线(兼容老客户端),极低延迟,无视晚高峰,4K 秒开
-- 全球首家 Hysteria 协议机场,现已上线更快的 `Hysteria2` 协议(Clash Verge 客户端最佳搭配)
-- 解锁流媒体及 ChatGPT
-- 官网:[https://狗狗加速.com](https://verge.dginv.click/#/register?code=oaxsAGo6)
+🚀 高性能海外技术流机场,支持免费试用与优惠套餐,全面解锁流媒体及 AI 服务,全球首家采用 **QUIC 协议**。
+
+🎁 使用 **Clash Verge 专属邀请链接** 注册即送 **3 天免费试用**,每日 **1GB 流量**:👉 [点此注册](https://verge.dginv.click/#/register?code=oaxsAGo6)
+
+#### **核心优势:**
+
+- 📱 自研 iOS 客户端(业内"唯一")技术经得起考验,极大**持续研发**投入
+- 🧑💻 **12小时真人客服**(顺带解决 Clash Verge 使用问题)
+- 💰 优惠套餐每月**仅需 21 元,160G 流量,年付 8 折**
+- 🌍 海外团队,无跑路风险,高达 50% 返佣
+- ⚙️ **集群负载均衡**设计,**负载监控和随时扩容**,高速专线(兼容老客户端),极低延迟,无视晚高峰,4K 秒开
+- ⚡ 全球首家**Quic 协议机场**,现已上线更快的 Tuic 协议(Clash Verge 客户端最佳搭配)
+- 🎬 解锁**流媒体及 主流 AI**
+
+🌐 官网:👉 [https://狗狗加速.com](https://verge.dginv.click/#/register?code=oaxsAGo6)
#### 本项目的构建与发布环境由 [YXVM](https://yxvm.com/aff.php?aff=827) 独立服务器全力支持,
diff --git a/clash-verge-rev/crates/clash-verge-logging/src/lib.rs b/clash-verge-rev/crates/clash-verge-logging/src/lib.rs
index bb8672f538..a30c15ee74 100644
--- a/clash-verge-rev/crates/clash-verge-logging/src/lib.rs
+++ b/clash-verge-rev/crates/clash-verge-logging/src/lib.rs
@@ -18,6 +18,7 @@ pub enum Type {
Config,
Setup,
System,
+ SystemSignal,
Service,
Hotkey,
Window,
@@ -42,6 +43,7 @@ impl fmt::Display for Type {
Self::Config => write!(f, "[Config]"),
Self::Setup => write!(f, "[Setup]"),
Self::System => write!(f, "[System]"),
+ Self::SystemSignal => write!(f, "[SysSignal]"),
Self::Service => write!(f, "[Service]"),
Self::Hotkey => write!(f, "[Hotkey]"),
Self::Window => write!(f, "[Window]"),
diff --git a/clash-verge-rev/crates/clash-verge-signal/Cargo.toml b/clash-verge-rev/crates/clash-verge-signal/Cargo.toml
index 2781509f29..ef3b129836 100644
--- a/clash-verge-rev/crates/clash-verge-signal/Cargo.toml
+++ b/clash-verge-rev/crates/clash-verge-signal/Cargo.toml
@@ -1,26 +1,13 @@
[package]
name = "clash-verge-signal"
version = "0.1.0"
-edition.workspace = true
-rust-version.workspace = true
+edition = "2024"
+rust-version = "1.91"
[dependencies]
clash-verge-logging = { workspace = true }
log = { workspace = true }
tokio = { workspace = true }
-[target.'cfg(unix)'.dependencies]
-signal-hook = "0.3.18"
-
-[target.'cfg(windows)'.dependencies]
-tauri = { workspace = true }
-windows-sys = { version = "0.61.2", features = [
- "Win32_Foundation",
- "Win32_Graphics_Gdi",
- "Win32_System_SystemServices",
- "Win32_UI_WindowsAndMessaging",
-] }
-
-
[lints]
workspace = true
diff --git a/clash-verge-rev/crates/clash-verge-signal/src/lib.rs b/clash-verge-rev/crates/clash-verge-signal/src/lib.rs
index a7b7671bc9..46b559d33e 100644
--- a/clash-verge-rev/crates/clash-verge-signal/src/lib.rs
+++ b/clash-verge-rev/crates/clash-verge-signal/src/lib.rs
@@ -9,7 +9,7 @@ mod windows;
pub(crate) static RUNTIME: OnceLock