diff --git a/.github/update.log b/.github/update.log index 434a9bd568..101e5b0285 100644 --- a/.github/update.log +++ b/.github/update.log @@ -1324,3 +1324,4 @@ Update On Sun Apr 5 20:57:38 CEST 2026 Update On Mon Apr 6 21:13:19 CEST 2026 Update On Tue Apr 7 21:18:54 CEST 2026 Update On Wed Apr 8 21:30:11 CEST 2026 +Update On Thu Apr 9 21:21:01 CEST 2026 diff --git a/clash-meta/adapter/outbound/vless.go b/clash-meta/adapter/outbound/vless.go index 2c71ebb1e4..5050d758ff 100644 --- a/clash-meta/adapter/outbound/vless.go +++ b/clash-meta/adapter/outbound/vless.go @@ -6,6 +6,7 @@ import ( "fmt" "net" "strconv" + "time" "github.com/metacubex/mihomo/common/convert" N "github.com/metacubex/mihomo/common/net" @@ -21,6 +22,7 @@ import ( "github.com/metacubex/mihomo/transport/xhttp" "github.com/metacubex/http" + "github.com/metacubex/quic-go" vmessSing "github.com/metacubex/sing-vmess" "github.com/metacubex/sing-vmess/packetaddr" M "github.com/metacubex/sing/common/metadata" @@ -88,11 +90,12 @@ type XHTTPOptions struct { } type XHTTPReuseSettings struct { - MaxConnections string `proxy:"max-connections,omitempty"` MaxConcurrency string `proxy:"max-concurrency,omitempty"` + MaxConnections string `proxy:"max-connections,omitempty"` CMaxReuseTimes string `proxy:"c-max-reuse-times,omitempty"` HMaxRequestTimes string `proxy:"h-max-request-times,omitempty"` HMaxReusableSecs string `proxy:"h-max-reusable-secs,omitempty"` + HKeepAlivePeriod int `proxy:"h-keep-alive-period,omitempty"` } type XHTTPDownloadSettings struct { @@ -525,15 +528,18 @@ func NewVless(option VlessOption) (*Vless, error) { } } + var hKeepAlivePeriod time.Duration + var reuseCfg *xhttp.ReuseConfig if option.XHTTPOpts.ReuseSettings != nil { reuseCfg = &xhttp.ReuseConfig{ - MaxConnections: option.XHTTPOpts.ReuseSettings.MaxConnections, MaxConcurrency: option.XHTTPOpts.ReuseSettings.MaxConcurrency, + MaxConnections: option.XHTTPOpts.ReuseSettings.MaxConnections, CMaxReuseTimes: option.XHTTPOpts.ReuseSettings.CMaxReuseTimes, HMaxRequestTimes: option.XHTTPOpts.ReuseSettings.HMaxRequestTimes, HMaxReusableSecs: option.XHTTPOpts.ReuseSettings.HMaxReusableSecs, } + hKeepAlivePeriod = time.Duration(option.XHTTPOpts.ReuseSettings.HKeepAlivePeriod) * time.Second } cfg := &xhttp.Config{ @@ -555,7 +561,54 @@ func NewVless(option VlessOption) (*Vless, error) { func(ctx context.Context, raw net.Conn, isH2 bool) (net.Conn, error) { return v.streamTLSConn(ctx, raw, isH2) }, + func(ctx context.Context, cfg *quic.Config) (*quic.Conn, error) { + host, _, _ := net.SplitHostPort(v.addr) + tlsOpts := &vmess.TLSConfig{ + Host: host, + SkipCertVerify: v.option.SkipCertVerify, + FingerPrint: v.option.Fingerprint, + Certificate: v.option.Certificate, + PrivateKey: v.option.PrivateKey, + ClientFingerprint: v.option.ClientFingerprint, + ECH: v.echConfig, + Reality: v.realityConfig, + NextProtos: []string{"h3"}, + } + if v.option.ServerName != "" { + tlsOpts.Host = v.option.ServerName + } + if !v.option.TLS { + return nil, errors.New("xhttp HTTP/3 requires TLS") + } + if v.realityConfig != nil { + return nil, errors.New("xhttp HTTP/3 does not support reality") + } + tlsConfig, err := tlsOpts.ToStdConfig() + if err != nil { + return nil, err + } + + udpAddr, err := resolveUDPAddr(ctx, "udp", v.addr, v.prefer) + if err != nil { + return nil, err + } + err = v.echConfig.ClientHandle(ctx, tlsConfig) + if err != nil { + return nil, err + } + packetConn, err := v.dialer.ListenPacket(ctx, "udp", "", udpAddr.AddrPort()) + if err != nil { + return nil, err + } + quicConn, err := quic.DialEarly(ctx, packetConn, udpAddr, tlsConfig, cfg) + if err != nil { + _ = packetConn.Close() + return nil, err + } + return quicConn, nil + }, v.option.ALPN, + hKeepAlivePeriod, ) } var makeDownloadTransport func() http.RoundTripper @@ -601,15 +654,18 @@ func NewVless(option VlessOption) (*Vless, error) { } } + downloadHKeepAlivePeriod := hKeepAlivePeriod + downloadReuseCfg := reuseCfg if ds.ReuseSettings != nil { downloadReuseCfg = &xhttp.ReuseConfig{ - MaxConnections: ds.ReuseSettings.MaxConnections, MaxConcurrency: ds.ReuseSettings.MaxConcurrency, + MaxConnections: ds.ReuseSettings.MaxConnections, CMaxReuseTimes: ds.ReuseSettings.CMaxReuseTimes, HMaxRequestTimes: ds.ReuseSettings.HMaxRequestTimes, HMaxReusableSecs: ds.ReuseSettings.HMaxReusableSecs, } + downloadHKeepAlivePeriod = time.Duration(ds.ReuseSettings.HKeepAlivePeriod) * time.Second } cfg.DownloadConfig = &xhttp.Config{ @@ -657,7 +713,54 @@ func NewVless(option VlessOption) (*Vless, error) { return conn, nil }, + func(ctx context.Context, cfg *quic.Config) (*quic.Conn, error) { + host, _, _ := net.SplitHostPort(downloadAddr) + tlsOpts := &vmess.TLSConfig{ + Host: host, + SkipCertVerify: downloadSkipCertVerify, + FingerPrint: downloadFingerprint, + Certificate: downloadCertificate, + PrivateKey: downloadPrivateKey, + ClientFingerprint: downloadClientFingerprint, + ECH: downloadEchConfig, + Reality: downloadRealityCfg, + NextProtos: []string{"h3"}, + } + if downloadServerName != "" { + tlsOpts.Host = downloadServerName + } + if !downloadTLS { + return nil, errors.New("xhttp HTTP/3 requires TLS") + } + if downloadRealityCfg != nil { + return nil, errors.New("xhttp HTTP/3 does not support reality") + } + tlsConfig, err := tlsOpts.ToStdConfig() + if err != nil { + return nil, err + } + + udpAddr, err := resolveUDPAddr(ctx, "udp", downloadAddr, v.prefer) + if err != nil { + return nil, err + } + err = downloadEchConfig.ClientHandle(ctx, tlsConfig) + if err != nil { + return nil, err + } + packetConn, err := v.dialer.ListenPacket(ctx, "udp", "", udpAddr.AddrPort()) + if err != nil { + return nil, err + } + quicConn, err := quic.DialEarly(ctx, packetConn, udpAddr, tlsConfig, cfg) + if err != nil { + _ = packetConn.Close() + return nil, err + } + return quicConn, nil + }, downloadALPN, + downloadHKeepAlivePeriod, ) } } diff --git a/clash-meta/docs/config.yaml b/clash-meta/docs/config.yaml index d861eed241..fc9ebac649 100644 --- a/clash-meta/docs/config.yaml +++ b/clash-meta/docs/config.yaml @@ -807,8 +807,7 @@ proxies: # socks5 udp: true tls: true network: xhttp - alpn: - - h2 + alpn: [h2] # 默认仅支持h2,如果开启h3模式需要设置alpn: [h3],如果开启http1.1模式需要设置alpn: [http/1.1] # ech-opts: ... # reality-opts: ... # skip-cert-verify: false @@ -828,11 +827,12 @@ proxies: # socks5 # x-padding-bytes: "100-1000" # sc-max-each-post-bytes: 1000000 # reuse-settings: # aka XMUX - # max-connections: "16-32" - # max-concurrency: "0" + # max-concurrency: "16-32" + # max-connections: "0" # c-max-reuse-times: "0" # h-max-request-times: "600-900" # h-max-reusable-secs: "1800-3000" + # h-keep-alive-period: 0 # download-settings: # ## xhttp part # path: "/" @@ -843,17 +843,17 @@ proxies: # socks5 # x-padding-bytes: "100-1000" # sc-max-each-post-bytes: 1000000 # reuse-settings: # aka XMUX - # max-connections: "16-32" - # max-concurrency: "0" + # max-concurrency: "16-32" + # max-connections: "0" # c-max-reuse-times: "0" # h-max-request-times: "600-900" # h-max-reusable-secs: "1800-3000" + # h-keep-alive-period: 0 # ## proxy part # server: server # port: 443 # tls: true - # alpn: - # - h2 + # alpn: ... # ech-opts: ... # reality-opts: ... # skip-cert-verify: false diff --git a/clash-meta/listener/inbound/vless_test.go b/clash-meta/listener/inbound/vless_test.go index 6e0fbda204..a3e707a5c6 100644 --- a/clash-meta/listener/inbound/vless_test.go +++ b/clash-meta/listener/inbound/vless_test.go @@ -488,6 +488,42 @@ func TestInboundVless_XHTTP_Reality(t *testing.T) { } } +func TestInboundVless_XHTTP_PacketUp_H1(t *testing.T) { + getConfig := func() (inbound.VlessOption, outbound.VlessOption) { + inboundOptions := inbound.VlessOption{ + Certificate: tlsCertificate, + PrivateKey: tlsPrivateKey, + XHTTPConfig: inbound.XHTTPConfig{ + Path: "/vless-xhttp", + Host: "example.com", + Mode: "packet-up", + }, + } + outboundOptions := outbound.VlessOption{ + TLS: true, + Fingerprint: tlsFingerprint, + Network: "xhttp", + ALPN: []string{"http/1.1"}, + XHTTPOpts: outbound.XHTTPOptions{ + Path: "/vless-xhttp", + Host: "example.com", + Mode: "packet-up", + }, + } + return inboundOptions, outboundOptions + } + + t.Run("default", func(t *testing.T) { + inboundOptions, outboundOptions := getConfig() + testInboundVlessTLS(t, inboundOptions, outboundOptions, false) + }) + + t.Run("reuse", func(t *testing.T) { + inboundOptions, outboundOptions := getConfig() + testInboundVlessTLS(t, inboundOptions, withXHTTPReuse(outboundOptions), false) + }) +} + func withXHTTPReuse(out outbound.VlessOption) outbound.VlessOption { out.XHTTPOpts.ReuseSettings = &outbound.XHTTPReuseSettings{ MaxConnections: "0", diff --git a/clash-meta/transport/xhttp/client.go b/clash-meta/transport/xhttp/client.go index 39d0daa700..ae56970d96 100644 --- a/clash-meta/transport/xhttp/client.go +++ b/clash-meta/transport/xhttp/client.go @@ -11,15 +11,30 @@ import ( "net/url" "strconv" "sync" + "time" "github.com/metacubex/mihomo/common/httputils" "github.com/metacubex/http" + "github.com/metacubex/quic-go" + "github.com/metacubex/quic-go/http3" "github.com/metacubex/tls" + "golang.org/x/sync/semaphore" ) +// ConnIdleTimeout defines the maximum time an idle TCP session can survive in the tunnel, +// so it should be consistent across HTTP versions and with other transports. +const ConnIdleTimeout = 300 * time.Second + +// QuicgoH3KeepAlivePeriod consistent with quic-go +const QuicgoH3KeepAlivePeriod = 10 * time.Second + +// ChromeH2KeepAlivePeriod consistent with chrome +const ChromeH2KeepAlivePeriod = 45 * time.Second + type DialRawFunc func(ctx context.Context) (net.Conn, error) type WrapTLSFunc func(ctx context.Context, conn net.Conn, isH2 bool) (net.Conn, error) +type DialQUICFunc func(ctx context.Context, cfg *quic.Config) (*quic.Conn, error) type TransportMaker func() http.RoundTripper @@ -96,7 +111,56 @@ func (c *PacketUpWriter) Close() error { return nil } -func NewTransport(dialRaw DialRawFunc, wrapTLS WrapTLSFunc, alpn []string) http.RoundTripper { +func NewTransport(dialRaw DialRawFunc, wrapTLS WrapTLSFunc, dialQUIC DialQUICFunc, alpn []string, keepAlivePeriod time.Duration) http.RoundTripper { + if len(alpn) == 1 && alpn[0] == "h3" { // `alpn: [h3]` means using h3 mode + if keepAlivePeriod == 0 { + keepAlivePeriod = QuicgoH3KeepAlivePeriod + } + if keepAlivePeriod < 0 { + keepAlivePeriod = 0 + } + return &http3.Transport{ + QUICConfig: &quic.Config{ + MaxIncomingStreams: -1, // don't allow the server to create bidirectional streams + KeepAlivePeriod: keepAlivePeriod, + MaxIdleTimeout: ConnIdleTimeout, + }, + Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (*quic.Conn, error) { + return dialQUIC(ctx, cfg) + }, + } + } + if len(alpn) == 1 && alpn[0] == "http/1.1" { // `alpn: [http/1.1]` means using http/1.1 mode + w := semaphore.NewWeighted(20) // limit concurrent dialing to avoid WSAECONNREFUSED on Windows + dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) { + if err := w.Acquire(ctx, 1); err != nil { + return nil, err + } + defer w.Release(1) + raw, err := dialRaw(ctx) + if err != nil { + return nil, err + } + wrapped, err := wrapTLS(ctx, raw, false) + if err != nil { + _ = raw.Close() + return nil, err + } + return wrapped, nil + } + return &http.Transport{ + DialContext: dialContext, + DialTLSContext: dialContext, + IdleConnTimeout: ConnIdleTimeout, + ForceAttemptHTTP2: false, // only http/1.1 + } + } + if keepAlivePeriod == 0 { + keepAlivePeriod = ChromeH2KeepAlivePeriod + } + if keepAlivePeriod < 0 { + keepAlivePeriod = 0 + } return &http.Http2Transport{ DialTLSContext: func(ctx context.Context, network, addr string, _ *tls.Config) (net.Conn, error) { raw, err := dialRaw(ctx) @@ -110,6 +174,8 @@ func NewTransport(dialRaw DialRawFunc, wrapTLS WrapTLSFunc, alpn []string) http. } return wrapped, nil }, + IdleConnTimeout: ConnIdleTimeout, + ReadIdleTimeout: keepAlivePeriod, } } diff --git a/clash-meta/transport/xhttp/config.go b/clash-meta/transport/xhttp/config.go index f28470723b..e02529d94a 100644 --- a/clash-meta/transport/xhttp/config.go +++ b/clash-meta/transport/xhttp/config.go @@ -26,8 +26,8 @@ type Config struct { } type ReuseConfig struct { - MaxConnections string MaxConcurrency string + MaxConnections string CMaxReuseTimes string HMaxRequestTimes string HMaxReusableSecs string @@ -171,17 +171,17 @@ func (c *ReuseConfig) ResolveManagerConfig() (Range, Range, error) { return Range{}, Range{}, nil } - maxConnections, err := ParseRange(c.MaxConnections, "0") - if err != nil { - return Range{}, Range{}, fmt.Errorf("invalid max-connections: %w", err) - } - maxConcurrency, err := ParseRange(c.MaxConcurrency, "0") if err != nil { return Range{}, Range{}, fmt.Errorf("invalid max-concurrency: %w", err) } - return maxConnections, maxConcurrency, nil + maxConnections, err := ParseRange(c.MaxConnections, "0") + if err != nil { + return Range{}, Range{}, fmt.Errorf("invalid max-connections: %w", err) + } + + return maxConcurrency, maxConnections, nil } func (c *ReuseConfig) ResolveEntryConfig() (Range, Range, Range, error) { @@ -189,6 +189,11 @@ func (c *ReuseConfig) ResolveEntryConfig() (Range, Range, Range, error) { return Range{}, Range{}, Range{}, nil } + cMaxReuseTimes, err := ParseRange(c.CMaxReuseTimes, "0") + if err != nil { + return Range{}, Range{}, Range{}, fmt.Errorf("invalid c-max-reuse-times: %w", err) + } + hMaxRequestTimes, err := ParseRange(c.HMaxRequestTimes, "0") if err != nil { return Range{}, Range{}, Range{}, fmt.Errorf("invalid h-max-request-times: %w", err) @@ -199,12 +204,7 @@ func (c *ReuseConfig) ResolveEntryConfig() (Range, Range, Range, error) { return Range{}, Range{}, Range{}, fmt.Errorf("invalid h-max-reusable-secs: %w", err) } - cMaxReuseTimes, err := ParseRange(c.CMaxReuseTimes, "0") - if err != nil { - return Range{}, Range{}, Range{}, fmt.Errorf("invalid c-max-reuse-times: %w", err) - } - - return hMaxRequestTimes, hMaxReusableSecs, cMaxReuseTimes, nil + return cMaxReuseTimes, hMaxRequestTimes, hMaxReusableSecs, nil } func (c *Config) FillStreamRequest(req *http.Request, sessionID string) error { diff --git a/clash-meta/transport/xhttp/reuse.go b/clash-meta/transport/xhttp/reuse.go index 006056cd0c..83e4787bf6 100644 --- a/clash-meta/transport/xhttp/reuse.go +++ b/clash-meta/transport/xhttp/reuse.go @@ -55,11 +55,11 @@ func (rt *ReuseTransport) Close() error { var _ http.RoundTripper = (*ReuseTransport)(nil) type ReuseManager struct { - maxConnections int maxConcurrency int + maxConnections int + cMaxReuseTimes Range hMaxRequestTimes Range hMaxReusableSecs Range - cMaxReuseTimes Range maker TransportMaker mu sync.Mutex entries []*reuseEntry @@ -69,20 +69,20 @@ func NewReuseManager(cfg *ReuseConfig, makeTransport TransportMaker) (*ReuseMana if cfg == nil { return nil, nil } - connections, concurrency, err := cfg.ResolveManagerConfig() + concurrency, connections, err := cfg.ResolveManagerConfig() if err != nil { return nil, err } - hMaxRequestTimes, hMaxReusableSecs, cMaxReuseTimes, err := cfg.ResolveEntryConfig() + cMaxReuseTimes, hMaxRequestTimes, hMaxReusableSecs, err := cfg.ResolveEntryConfig() if err != nil { return nil, err } return &ReuseManager{ - maxConnections: connections.Rand(), maxConcurrency: concurrency.Rand(), + maxConnections: connections.Rand(), + cMaxReuseTimes: cMaxReuseTimes, hMaxRequestTimes: hMaxRequestTimes, hMaxReusableSecs: hMaxReusableSecs, - cMaxReuseTimes: cMaxReuseTimes, maker: makeTransport, entries: make([]*reuseEntry, 0), }, nil diff --git a/clash-meta/transport/xhttp/reuse_test.go b/clash-meta/transport/xhttp/reuse_test.go index b20320a946..1e676ee627 100644 --- a/clash-meta/transport/xhttp/reuse_test.go +++ b/clash-meta/transport/xhttp/reuse_test.go @@ -31,8 +31,8 @@ func TestManagerReuseSameEntry(t *testing.T) { var created atomic.Int64 manager, err := NewReuseManager(&ReuseConfig{ - MaxConnections: "1", MaxConcurrency: "1", + MaxConnections: "1", HMaxRequestTimes: "10", }, makeTestTransportFactory(&created)) if err != nil { @@ -65,8 +65,8 @@ func TestManagerRespectMaxConnections(t *testing.T) { var created atomic.Int64 manager, err := NewReuseManager(&ReuseConfig{ - MaxConnections: "2", MaxConcurrency: "1", + MaxConnections: "2", HMaxRequestTimes: "100", }, makeTestTransportFactory(&created)) if err != nil { @@ -110,8 +110,8 @@ func TestManagerRotateOnRequestLimit(t *testing.T) { var created atomic.Int64 manager, err := NewReuseManager(&ReuseConfig{ - MaxConnections: "1", MaxConcurrency: "1", + MaxConnections: "1", HMaxRequestTimes: "1", }, makeTestTransportFactory(&created)) if err != nil { @@ -144,8 +144,8 @@ func TestManagerRotateOnReusableSecs(t *testing.T) { var created atomic.Int64 manager, err := NewReuseManager(&ReuseConfig{ - MaxConnections: "1", MaxConcurrency: "1", + MaxConnections: "1", HMaxRequestTimes: "100", HMaxReusableSecs: "1", }, makeTestTransportFactory(&created)) @@ -180,8 +180,8 @@ func TestManagerRotateOnConnReuseLimit(t *testing.T) { var created atomic.Int64 manager, err := NewReuseManager(&ReuseConfig{ - MaxConnections: "1", MaxConcurrency: "1", + MaxConnections: "1", CMaxReuseTimes: "1", HMaxRequestTimes: "100", }, makeTestTransportFactory(&created)) diff --git a/clash-meta/transport/xhttp/server.go b/clash-meta/transport/xhttp/server.go index 4c68174a44..2f32bb31f5 100644 --- a/clash-meta/transport/xhttp/server.go +++ b/clash-meta/transport/xhttp/server.go @@ -75,7 +75,7 @@ func (c *httpServerConn) Wait() <-chan struct{} { } type httpSession struct { - uploadQueue *uploadQueue + uploadQueue *UploadQueue connected chan struct{} once sync.Once } diff --git a/clash-meta/transport/xhttp/upload_queue.go b/clash-meta/transport/xhttp/upload_queue.go index 3a5339627f..731f85bd98 100644 --- a/clash-meta/transport/xhttp/upload_queue.go +++ b/clash-meta/transport/xhttp/upload_queue.go @@ -8,11 +8,11 @@ import ( type Packet struct { Seq uint64 - Payload []byte + Payload []byte // UploadQueue will hold Payload, so never reuse it after UploadQueue.Push Reader io.ReadCloser } -type uploadQueue struct { +type UploadQueue struct { mu sync.Mutex cond *sync.Cond packets map[uint64][]byte @@ -22,15 +22,15 @@ type uploadQueue struct { reader io.ReadCloser } -func NewUploadQueue() *uploadQueue { - q := &uploadQueue{ +func NewUploadQueue() *UploadQueue { + q := &UploadQueue{ packets: make(map[uint64][]byte), } q.cond = sync.NewCond(&q.mu) return q } -func (q *uploadQueue) Push(p Packet) error { +func (q *UploadQueue) Push(p Packet) error { q.mu.Lock() defer q.mu.Unlock() @@ -48,14 +48,12 @@ func (q *uploadQueue) Push(p Packet) error { return nil } - cp := make([]byte, len(p.Payload)) - copy(cp, p.Payload) - q.packets[p.Seq] = cp + q.packets[p.Seq] = p.Payload q.cond.Broadcast() return nil } -func (q *uploadQueue) Read(b []byte) (int, error) { +func (q *UploadQueue) Read(b []byte) (int, error) { q.mu.Lock() for { @@ -87,7 +85,7 @@ func (q *uploadQueue) Read(b []byte) (int, error) { } } -func (q *uploadQueue) Close() error { +func (q *UploadQueue) Close() error { q.mu.Lock() defer q.mu.Unlock() diff --git a/clash-nyanpasu/backend/Cargo.lock b/clash-nyanpasu/backend/Cargo.lock index 1c3870004d..4aeb9ba501 100644 --- a/clash-nyanpasu/backend/Cargo.lock +++ b/clash-nyanpasu/backend/Cargo.lock @@ -379,7 +379,7 @@ dependencies = [ "objc2-foundation 0.3.2", "parking_lot", "percent-encoding", - "windows-sys 0.60.2", + "windows-sys 0.52.0", "wl-clipboard-rs", "x11rb", ] @@ -2354,7 +2354,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -2883,7 +2883,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] @@ -4907,7 +4907,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.3", + "windows-targets 0.48.5", ] [[package]] @@ -7289,7 +7289,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] @@ -8776,7 +8776,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -9969,9 +9969,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.51.0" +version = "1.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd1c4c0fc4a7ab90fc15ef6daaa3ec3b893f004f915f2392557ed23237820cd" +checksum = "f66bf9585cda4b724d3e78ab34b73fb2bbaba9011b9bfdf69dc836382ea13b8c" dependencies = [ "bytes", "libc", diff --git a/clash-nyanpasu/frontend/interface/package.json b/clash-nyanpasu/frontend/interface/package.json index bbe7cb5d74..68249166e5 100644 --- a/clash-nyanpasu/frontend/interface/package.json +++ b/clash-nyanpasu/frontend/interface/package.json @@ -17,7 +17,7 @@ "dayjs": "1.11.20", "lodash-es": "4.18.1", "ofetch": "1.5.1", - "react": "19.2.4", + "react": "19.2.5", "swr": "2.4.1" }, "devDependencies": { diff --git a/clash-nyanpasu/frontend/nyanpasu/package.json b/clash-nyanpasu/frontend/nyanpasu/package.json index 949de39e7c..a16e5cc72d 100644 --- a/clash-nyanpasu/frontend/nyanpasu/package.json +++ b/clash-nyanpasu/frontend/nyanpasu/package.json @@ -17,12 +17,12 @@ "@dnd-kit/utilities": "3.2.2", "@emotion/styled": "11.14.1", "@hookform/resolvers": "5.2.2", - "@inlang/paraglide-js": "2.15.2", + "@inlang/paraglide-js": "2.15.3", "@juggle/resize-observer": "3.4.0", "@material/material-color-utilities": "0.4.0", - "@mui/icons-material": "7.3.9", + "@mui/icons-material": "7.3.10", "@mui/lab": "7.0.0-beta.17", - "@mui/material": "7.3.9", + "@mui/material": "7.3.10", "@mui/x-date-pickers": "8.27.2", "@nyanpasu/interface": "workspace:^", "@nyanpasu/ui": "workspace:^", @@ -34,7 +34,7 @@ "@tanstack/router-zod-adapter": "1.81.5", "@tauri-apps/api": "2.10.1", "@uidotdev/usehooks": "2.4.1", - "@uiw/react-color": "2.10.0", + "@uiw/react-color": "2.10.1", "ahooks": "3.9.7", "allotment": "1.20.5", "class-variance-authority": "0.7.1", @@ -50,8 +50,8 @@ "monaco-editor": "0.55.1", "mui-color-input": "7.0.0", "radix-ui": "1.4.3", - "react": "19.2.4", - "react-dom": "19.2.4", + "react": "19.2.5", + "react-dom": "19.2.5", "react-error-boundary": "6.0.0", "react-fast-marquee": "1.6.5", "react-hook-form": "7.72.1", diff --git a/clash-nyanpasu/frontend/ui/package.json b/clash-nyanpasu/frontend/ui/package.json index 2d91f9c24a..dd84c166de 100644 --- a/clash-nyanpasu/frontend/ui/package.json +++ b/clash-nyanpasu/frontend/ui/package.json @@ -12,9 +12,9 @@ }, "dependencies": { "@material/material-color-utilities": "0.4.0", - "@mui/icons-material": "7.3.9", + "@mui/icons-material": "7.3.10", "@mui/lab": "7.0.0-beta.17", - "@mui/material": "7.3.9", + "@mui/material": "7.3.10", "@radix-ui/react-portal": "1.1.10", "@radix-ui/react-scroll-area": "1.2.10", "@tauri-apps/api": "2.10.1", @@ -24,8 +24,8 @@ "ahooks": "3.9.7", "d3": "7.9.0", "framer-motion": "12.38.0", - "react": "19.2.4", - "react-dom": "19.2.4", + "react": "19.2.5", + "react-dom": "19.2.5", "react-error-boundary": "6.0.0", "react-i18next": "15.7.4", "react-use": "17.6.0", diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json index 591b68bccf..de56ef6648 100644 --- a/clash-nyanpasu/manifest/version.json +++ b/clash-nyanpasu/manifest/version.json @@ -1,11 +1,11 @@ { "manifest_version": 1, "latest": { - "mihomo": "v1.19.22", - "mihomo_alpha": "alpha-5e8bd85", + "mihomo": "v1.19.23", + "mihomo_alpha": "alpha-d801e6b", "clash_rs": "v0.9.6", "clash_premium": "2023-09-05-gdcc8d87", - "clash_rs_alpha": "0.9.6-alpha+sha.c414fb7" + "clash_rs_alpha": "0.9.6-alpha+sha.415b05e" }, "arch_template": { "mihomo": { @@ -69,5 +69,5 @@ "linux-armv7hf": "clash-rs-armv7-unknown-linux-gnueabihf" } }, - "updated_at": "2026-04-07T22:24:28.715Z" + "updated_at": "2026-04-08T22:25:38.710Z" } diff --git a/clash-nyanpasu/package.json b/clash-nyanpasu/package.json index a2dfe34439..e7e69c962a 100644 --- a/clash-nyanpasu/package.json +++ b/clash-nyanpasu/package.json @@ -77,7 +77,7 @@ "postcss-import": "16.1.1", "postcss-scss": "4.0.9", "prettier": "3.8.1", - "prettier-plugin-ember-template-tag": "2.1.3", + "prettier-plugin-ember-template-tag": "2.1.4", "prettier-plugin-tailwindcss": "0.7.2", "prettier-plugin-toml": "2.0.6", "stylelint": "17.6.0", diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml index 6e8a7f2824..3ccfebae03 100644 --- a/clash-nyanpasu/pnpm-lock.yaml +++ b/clash-nyanpasu/pnpm-lock.yaml @@ -30,7 +30,7 @@ importers: version: 20.5.0 '@ianvs/prettier-plugin-sort-imports': specifier: 4.7.1 - version: 4.7.1(@prettier/plugin-oxc@0.1.3)(content-tag@4.0.0)(prettier-plugin-ember-template-tag@2.1.3(prettier@3.8.1))(prettier@3.8.1) + version: 4.7.1(@prettier/plugin-oxc@0.1.3)(content-tag@4.0.0)(prettier-plugin-ember-template-tag@2.1.4(prettier@3.8.1))(prettier@3.8.1) '@tauri-apps/cli': specifier: 2.10.1 version: 2.10.1 @@ -86,11 +86,11 @@ importers: specifier: 3.8.1 version: 3.8.1 prettier-plugin-ember-template-tag: - specifier: 2.1.3 - version: 2.1.3(prettier@3.8.1) + specifier: 2.1.4 + version: 2.1.4(prettier@3.8.1) prettier-plugin-tailwindcss: specifier: 0.7.2 - version: 0.7.2(@ianvs/prettier-plugin-sort-imports@4.7.1(@prettier/plugin-oxc@0.1.3)(content-tag@4.0.0)(prettier-plugin-ember-template-tag@2.1.3(prettier@3.8.1))(prettier@3.8.1))(@prettier/plugin-oxc@0.1.3)(@trivago/prettier-plugin-sort-imports@4.3.0(prettier@3.8.1))(prettier@3.8.1) + version: 0.7.2(@ianvs/prettier-plugin-sort-imports@4.7.1(@prettier/plugin-oxc@0.1.3)(content-tag@4.0.0)(prettier-plugin-ember-template-tag@2.1.4(prettier@3.8.1))(prettier@3.8.1))(@prettier/plugin-oxc@0.1.3)(@trivago/prettier-plugin-sort-imports@4.3.0(prettier@3.8.1))(prettier@3.8.1) prettier-plugin-toml: specifier: 2.0.6 version: 2.0.6(prettier@3.8.1) @@ -129,13 +129,13 @@ importers: dependencies: '@tanstack/react-query': specifier: 5.96.2 - version: 5.96.2(react@19.2.4) + version: 5.96.2(react@19.2.5) '@tauri-apps/api': specifier: 2.10.1 version: 2.10.1 ahooks: specifier: 3.9.7 - version: 3.9.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 3.9.7(react-dom@19.2.5(react@19.2.5))(react@19.2.5) dayjs: specifier: 1.11.20 version: 1.11.20 @@ -146,11 +146,11 @@ importers: specifier: 1.5.1 version: 1.5.1 react: - specifier: 19.2.4 - version: 19.2.4 + specifier: 19.2.5 + version: 19.2.5 swr: specifier: 2.4.1 - version: 2.4.1(react@19.2.4) + version: 2.4.1(react@19.2.5) devDependencies: '@types/lodash-es': specifier: 4.17.12 @@ -163,28 +163,28 @@ importers: dependencies: '@dnd-kit/core': specifier: 6.3.1 - version: 6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 6.3.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@dnd-kit/helpers': specifier: 0.3.2 version: 0.3.2 '@dnd-kit/react': specifier: 0.3.2 - version: 0.3.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 0.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@dnd-kit/sortable': specifier: 10.0.0 - version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) + version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5) '@dnd-kit/utilities': specifier: 3.2.2 - version: 3.2.2(react@19.2.4) + version: 3.2.2(react@19.2.5) '@emotion/styled': specifier: 11.14.1 - version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) '@hookform/resolvers': specifier: 5.2.2 - version: 5.2.2(react-hook-form@7.72.1(react@19.2.4)) + version: 5.2.2(react-hook-form@7.72.1(react@19.2.5)) '@inlang/paraglide-js': - specifier: 2.15.2 - version: 2.15.2(babel-plugin-macros@3.1.0) + specifier: 2.15.3 + version: 2.15.3(babel-plugin-macros@3.1.0) '@juggle/resize-observer': specifier: 3.4.0 version: 3.4.0 @@ -192,17 +192,17 @@ importers: specifier: 0.4.0 version: 0.4.0 '@mui/icons-material': - specifier: 7.3.9 - version: 7.3.9(@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + specifier: 7.3.10 + version: 7.3.10(@mui/material@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) '@mui/lab': specifier: 7.0.0-beta.17 - version: 7.0.0-beta.17(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 7.0.0-beta.17(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@mui/material@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@mui/material': - specifier: 7.3.9 - version: 7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: 7.3.10 + version: 7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@mui/x-date-pickers': specifier: 8.27.2 - version: 8.27.2(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@mui/system@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(dayjs@1.11.20)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 8.27.2(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@mui/material@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@mui/system@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(dayjs@1.11.20)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@nyanpasu/interface': specifier: workspace:^ version: link:../interface @@ -211,37 +211,37 @@ importers: version: link:../ui '@paper-design/shaders-react': specifier: 0.0.72 - version: 0.0.72(@types/react@19.2.14)(react@19.2.4) + version: 0.0.72(@types/react@19.2.14)(react@19.2.5) '@radix-ui/react-use-controllable-state': specifier: 1.2.2 - version: 1.2.2(@types/react@19.2.14)(react@19.2.4) + version: 1.2.2(@types/react@19.2.14)(react@19.2.5) '@tailwindcss/postcss': specifier: 4.2.2 version: 4.2.2 '@tanstack/react-table': specifier: 8.21.3 - version: 8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 8.21.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tanstack/react-virtual': specifier: 3.13.23 - version: 3.13.23(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 3.13.23(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tanstack/router-zod-adapter': specifier: 1.81.5 - version: 1.81.5(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(zod@4.3.6) + version: 1.81.5(@tanstack/react-router@1.168.10(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(zod@4.3.6) '@tauri-apps/api': specifier: 2.10.1 version: 2.10.1 '@uidotdev/usehooks': specifier: 2.4.1 - version: 2.4.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 2.4.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@uiw/react-color': - specifier: 2.10.0 - version: 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: 2.10.1 + version: 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) ahooks: specifier: 3.9.7 - version: 3.9.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 3.9.7(react-dom@19.2.5(react@19.2.5))(react@19.2.5) allotment: specifier: 1.20.5 - version: 1.20.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.20.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5) class-variance-authority: specifier: 0.7.1 version: 0.7.1 @@ -259,70 +259,70 @@ importers: version: 1.11.20 framer-motion: specifier: 12.38.0 - version: 12.38.0(@emotion/is-prop-valid@1.3.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 12.38.0(@emotion/is-prop-valid@1.3.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) i18next: specifier: 25.10.10 version: 25.10.10(typescript@5.9.3) jotai: specifier: 2.19.1 - version: 2.19.1(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.14)(react@19.2.4) + version: 2.19.1(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.14)(react@19.2.5) json-schema: specifier: 0.4.0 version: 0.4.0 material-react-table: specifier: npm:@greenhat616/material-react-table@4.0.0 - version: '@greenhat616/material-react-table@4.0.0(675c3bab767efe78ea23c1542e4b601d)' + version: '@greenhat616/material-react-table@4.0.0(c9750096c20c2934468ef5df5df5d693)' monaco-editor: specifier: 0.55.1 version: 0.55.1 mui-color-input: specifier: 7.0.0 - version: 7.0.0(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 7.0.0(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@mui/material@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) radix-ui: specifier: 1.4.3 - version: 1.4.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.4.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react: - specifier: 19.2.4 - version: 19.2.4 + specifier: 19.2.5 + version: 19.2.5 react-dom: - specifier: 19.2.4 - version: 19.2.4(react@19.2.4) + specifier: 19.2.5 + version: 19.2.5(react@19.2.5) react-error-boundary: specifier: 6.0.0 - version: 6.0.0(react@19.2.4) + version: 6.0.0(react@19.2.5) react-fast-marquee: specifier: 1.6.5 - version: 1.6.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.6.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react-hook-form: specifier: 7.72.1 - version: 7.72.1(react@19.2.4) + version: 7.72.1(react@19.2.5) react-hook-form-mui: specifier: 8.2.0 - version: 8.2.0(fddc180082ef55eb3a5d5e8b74a28cd6) + version: 8.2.0(ac03decca1a377e6c5f1d359ea093f97) react-i18next: specifier: 15.7.4 - version: 15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + version: 15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react-markdown: specifier: 10.1.0 - version: 10.1.0(@types/react@19.2.14)(react@19.2.4) + version: 10.1.0(@types/react@19.2.14)(react@19.2.5) react-split-grid: specifier: 1.0.4 - version: 1.0.4(react@19.2.4) + version: 1.0.4(react@19.2.5) react-use: specifier: 17.6.0 - version: 17.6.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 17.6.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) rxjs: specifier: 7.8.2 version: 7.8.2 swr: specifier: 2.4.1 - version: 2.4.1(react@19.2.4) + version: 2.4.1(react@19.2.5) vaul: specifier: 1.1.2 - version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) virtua: specifier: 0.46.6 - version: 0.46.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.5) + version: 0.46.6(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(solid-js@1.9.5) vite-bundle-visualizer: specifier: 1.2.1 version: 1.2.1(rollup@4.46.2) @@ -335,25 +335,25 @@ importers: version: 11.13.5 '@emotion/react': specifier: 11.14.0 - version: 11.14.0(@types/react@19.2.14)(react@19.2.4) + version: 11.14.0(@types/react@19.2.14)(react@19.2.5) '@iconify/json': specifier: 2.2.460 version: 2.2.460 '@monaco-editor/react': specifier: 4.7.0 - version: 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tanstack/react-query': specifier: 5.96.2 - version: 5.96.2(react@19.2.4) + version: 5.96.2(react@19.2.5) '@tanstack/react-router': specifier: 1.168.10 - version: 1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.168.10(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tanstack/react-router-devtools': specifier: 1.166.11 - version: 1.166.11(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.168.9)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.166.11(@tanstack/react-router@1.168.10(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@tanstack/router-core@1.168.9)(csstype@3.2.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tanstack/router-plugin': specifier: 1.167.12 - version: 1.167.12(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.2(@types/node@24.11.0)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 1.167.12(@tanstack/react-router@1.168.10(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(vite@7.3.2(@types/node@24.11.0)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.2)) '@tauri-apps/plugin-clipboard-manager': specifier: 2.3.2 version: 2.3.2 @@ -466,20 +466,20 @@ importers: specifier: 0.4.0 version: 0.4.0 '@mui/icons-material': - specifier: 7.3.9 - version: 7.3.9(@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + specifier: 7.3.10 + version: 7.3.10(@mui/material@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) '@mui/lab': specifier: 7.0.0-beta.17 - version: 7.0.0-beta.17(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 7.0.0-beta.17(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@mui/material@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@mui/material': - specifier: 7.3.9 - version: 7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: 7.3.10 + version: 7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@radix-ui/react-portal': specifier: 1.1.10 - version: 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@radix-ui/react-scroll-area': specifier: 1.2.10 - version: 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tauri-apps/api': specifier: 2.10.1 version: 2.10.1 @@ -494,28 +494,28 @@ importers: version: 5.2.0(vite@7.3.2(@types/node@24.11.0)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.2)) ahooks: specifier: 3.9.7 - version: 3.9.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 3.9.7(react-dom@19.2.5(react@19.2.5))(react@19.2.5) d3: specifier: 7.9.0 version: 7.9.0 framer-motion: specifier: 12.38.0 - version: 12.38.0(@emotion/is-prop-valid@1.3.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 12.38.0(@emotion/is-prop-valid@1.3.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react: - specifier: 19.2.4 - version: 19.2.4 + specifier: 19.2.5 + version: 19.2.5 react-dom: - specifier: 19.2.4 - version: 19.2.4(react@19.2.4) + specifier: 19.2.5 + version: 19.2.5(react@19.2.5) react-error-boundary: specifier: 6.0.0 - version: 6.0.0(react@19.2.4) + version: 6.0.0(react@19.2.5) react-i18next: specifier: 15.7.4 - version: 15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + version: 15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react-use: specifier: 17.6.0 - version: 17.6.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 17.6.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) tailwindcss: specifier: 4.2.2 version: 4.2.2 @@ -528,7 +528,7 @@ importers: devDependencies: '@emotion/react': specifier: 11.14.0 - version: 11.14.0(@types/react@19.2.14)(react@19.2.4) + version: 11.14.0(@types/react@19.2.14)(react@19.2.5) '@types/d3-interpolate-path': specifier: 2.0.3 version: 2.0.3 @@ -1233,10 +1233,6 @@ packages: resolution: {integrity: sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.5': - resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} - engines: {node: '>=6.9.0'} - '@babel/traverse@7.29.0': resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} @@ -1730,8 +1726,8 @@ packages: '@iconify/utils@3.1.0': resolution: {integrity: sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==} - '@inlang/paraglide-js@2.15.2': - resolution: {integrity: sha512-1S2jBvc8jzJAZFRf3gKu3Z2+9zQRhvIzALEE4vvWDNIoiiOn0vF3cJHf3xFqgfN/JY5IVS//zQsvAT0jWXH69g==} + '@inlang/paraglide-js@2.15.3': + resolution: {integrity: sha512-gneANUhYEPnSjxbKp3QCwmMqQecG+1QWuJSAl3jiPprn2+LeaZu3BgnofRKpo8gkYzB6oE3AY2ecZBXu3UrpOw==} hasBin: true '@inlang/recommend-sherlock@0.2.1': @@ -1812,14 +1808,14 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@mui/core-downloads-tracker@7.3.9': - resolution: {integrity: sha512-MOkOCTfbMJwLshlBCKJ59V2F/uaLYfmKnN76kksj6jlGUVdI25A9Hzs08m+zjBRdLv+sK7Rqdsefe8X7h/6PCw==} + '@mui/core-downloads-tracker@7.3.10': + resolution: {integrity: sha512-vrOpWRmPJSuwLo23J62wggEm/jvGdzqctej+UOCtgDUz6nZJQuj3ByPccVyaa7eQmwAzUwKN56FQPMKkqbj1GA==} - '@mui/icons-material@7.3.9': - resolution: {integrity: sha512-BT+zPJXss8Hg/oEMRmHl17Q97bPACG4ufFSfGEdhiE96jOyR5Dz1ty7ZWt1fVGR0y1p+sSgEwQT/MNZQmoWDCw==} + '@mui/icons-material@7.3.10': + resolution: {integrity: sha512-Au0ma4NSKGKNiimukj8UT/W1x2Qx6Qwn2RvFGykiSqVLYBNlIOPbjnIMvrwLGLu89EEpTVdu/ys/OduZR+tWqw==} engines: {node: '>=14.0.0'} peerDependencies: - '@mui/material': ^7.3.9 + '@mui/material': ^7.3.10 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: @@ -1847,13 +1843,13 @@ packages: '@types/react': optional: true - '@mui/material@7.3.9': - resolution: {integrity: sha512-I8yO3t4T0y7bvDiR1qhIN6iBWZOTBfVOnmLlM7K6h3dx5YX2a7rnkuXzc2UkZaqhxY9NgTnEbdPlokR1RxCNRQ==} + '@mui/material@7.3.10': + resolution: {integrity: sha512-cHvGOk2ZEfbQt3LnGe0ZKd/ETs9gsUpkW66DCO+GSjMZhpdKU4XsuIr7zJ/B/2XaN8ihxuzHfYAR4zPtCN4RYg==} engines: {node: '>=14.0.0'} peerDependencies: '@emotion/react': ^11.5.0 '@emotion/styled': ^11.3.0 - '@mui/material-pigment-css': ^7.3.9 + '@mui/material-pigment-css': ^7.3.10 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -1867,6 +1863,16 @@ packages: '@types/react': optional: true + '@mui/private-theming@7.3.10': + resolution: {integrity: sha512-j3EZN+zOctxUISvJSmsEPo5o2F8zse4l5vRkBY+ps6UtnL6J7o14kUaI4w7gwo73id9e3cDNMVQK/9BVaMHVBw==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@mui/private-theming@7.3.2': resolution: {integrity: sha512-ha7mFoOyZGJr75xeiO9lugS3joRROjc8tG1u4P50dH0KR7bwhHznVMcYg7MouochUy0OxooJm/OOSpJ7gKcMvg==} engines: {node: '>=14.0.0'} @@ -1877,14 +1883,17 @@ packages: '@types/react': optional: true - '@mui/private-theming@7.3.9': - resolution: {integrity: sha512-ErIyRQvsiQEq7Yvcvfw9UDHngaqjMy9P3JDPnRAaKG5qhpl2C4tX/W1S4zJvpu+feihmZJStjIyvnv6KDbIrlw==} + '@mui/styled-engine@7.3.10': + resolution: {integrity: sha512-WxE9SiF8xskAQqGjsp0poXCkCqsoXFEsSr0HBXfApmGHR+DBnXRp+z46Vsltg4gpPM4Z96DeAQRpeAOnhNg7Ng==} engines: {node: '>=14.0.0'} peerDependencies: - '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + '@emotion/react': ^11.4.1 + '@emotion/styled': ^11.3.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: - '@types/react': + '@emotion/react': + optional: true + '@emotion/styled': optional: true '@mui/styled-engine@7.3.2': @@ -1900,18 +1909,21 @@ packages: '@emotion/styled': optional: true - '@mui/styled-engine@7.3.9': - resolution: {integrity: sha512-JqujWt5bX4okjUPGpVof/7pvgClqh7HvIbsIBIOOlCh2u3wG/Bwp4+E1bc1dXSwkrkp9WUAoNdI5HEC+5HKvMw==} + '@mui/system@7.3.10': + resolution: {integrity: sha512-/sfPpdpJaQn7BSF+avjIdHSYmxHp0UOBYNxSG9QGKfMOD6sLANCpRPCnanq1Pe0lFf0NHkO2iUk0TNzdWC1USQ==} engines: {node: '>=14.0.0'} peerDependencies: - '@emotion/react': ^11.4.1 + '@emotion/react': ^11.5.0 '@emotion/styled': ^11.3.0 + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@emotion/react': optional: true '@emotion/styled': optional: true + '@types/react': + optional: true '@mui/system@7.3.2': resolution: {integrity: sha512-9d8JEvZW+H6cVkaZ+FK56R53vkJe3HsTpcjMUtH8v1xK6Y1TjzHdZ7Jck02mGXJsE6MQGWVs3ogRHTQmS9Q/rA==} @@ -1929,30 +1941,6 @@ packages: '@types/react': optional: true - '@mui/system@7.3.9': - resolution: {integrity: sha512-aL1q9am8XpRrSabv9qWf5RHhJICJql34wnrc1nz0MuOglPRYF/liN+c8VqZdTvUn9qg+ZjRVbKf4sJVFfIDtmg==} - engines: {node: '>=14.0.0'} - peerDependencies: - '@emotion/react': ^11.5.0 - '@emotion/styled': ^11.3.0 - '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@emotion/react': - optional: true - '@emotion/styled': - optional: true - '@types/react': - optional: true - - '@mui/types@7.4.11': - resolution: {integrity: sha512-fZ2xO9D08IKOxO2oUBi1nnVKH6oJUD+64cnv4YAaFoC0E5+i1+S5AHbNqqvZlYYsbPEQ6qEVwuBqY3jl5W4G+Q==} - peerDependencies: - '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@mui/types@7.4.12': resolution: {integrity: sha512-iKNAF2u9PzSIj40CjvKJWxFXJo122jXVdrmdh0hMYd+FR+NuJMkr/L88XwWLCRiJ5P1j+uyac25+Kp6YC4hu6w==} peerDependencies: @@ -1969,6 +1957,16 @@ packages: '@types/react': optional: true + '@mui/utils@7.3.10': + resolution: {integrity: sha512-7y2eIfy0h7JPz+Yy4pS+wgV68d46PuuxDqKBN4Q8VlPQSsCAGwroMCV6xWyc7g9dvEp8ZNFsknc59GHWO+r6Ow==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@mui/utils@7.3.2': resolution: {integrity: sha512-4DMWQGenOdLnM3y/SdFQFwKsCLM+mqxzvoWp9+x2XdEzXapkznauHLiXtSohHs/mc0+5/9UACt1GdugCX2te5g==} engines: {node: '>=14.0.0'} @@ -4457,151 +4455,151 @@ packages: react: '>=18.0.0' react-dom: '>=18.0.0' - '@uiw/color-convert@2.10.0': - resolution: {integrity: sha512-4woviyrzPi3Xauo12lnKTgNlugCk0su2PhjtZiHZuakK0yQNOMeN/QZi9W8ASb/DuRS7bSr8jSyIHLRYml90+g==} + '@uiw/color-convert@2.10.1': + resolution: {integrity: sha512-/Z3YfBiX+SErRM59yQH88Id+Xy/k10nnkfTuqhX6RB2yYUcG57DoFqb6FudhiQ5fwzKvKf1k4xq9lfT1UTFUKQ==} peerDependencies: '@babel/runtime': '>=7.19.0' - '@uiw/react-color-alpha@2.10.0': - resolution: {integrity: sha512-2uGoCuDlqBm3CN/RI3XbOwxIF7GJKwyUUpN/krMEOLg7HhIJMYWxrhDZ4SCQecGPeR/b8o3XTxV7+PHIZMcgMw==} + '@uiw/react-color-alpha@2.10.1': + resolution: {integrity: sha512-3mllAyb3TgC0lRWGMLiwawgCuv3jIQWnarnxwggZ87HWvL4GLCWuVRxheYdLJTjAc6qd4Cd+d0jHMfkKXIdMFA==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-block@2.10.0': - resolution: {integrity: sha512-uBwxbWwIdGqxbVbeXcDR7O4WT4wfLOfeDit+wogYxrwjLdd6txB1YX/x6ELtFiVx+BhSd9YyVvkPaJGabZhk0Q==} + '@uiw/react-color-block@2.10.1': + resolution: {integrity: sha512-nGfhUGZhCbYH/gVvD12H9wZ/NBiToiSyrSdbracyIbA01tZInmkRNmfzTCkPq7yoXMa09I9G8pPISoyHre4TQg==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-chrome@2.10.0': - resolution: {integrity: sha512-gfKr/pdFESqCx0PywmKHxYPd5NfyVnB0wgFhKsITH1EC7zgAkDxUB3gyA9ihNL53TpqN28O461G59CoaBVBPOg==} + '@uiw/react-color-chrome@2.10.1': + resolution: {integrity: sha512-V5Li6un5GOCVh+H1sCPSPHB3uQ/Cipm167C4aoHKVl6jb5oEeFM39p2egIP2+8HzuNHWzUnOKm1KphqTvAEyEw==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-circle@2.10.0': - resolution: {integrity: sha512-1E61c0nOqHijAXN+IsWSOer/asZj41gU+/Wda3XkUHWu219ZIhu/koTpvRLEFJKs5akvXLJlO0Oq4BqmugEiMQ==} + '@uiw/react-color-circle@2.10.1': + resolution: {integrity: sha512-f7/RPnpOGOktmuX1pdPBvXNRoq4irddKG3LU+6vETB7DI0aJiYZH+NXPSrdtNM9j5msdPVH6aGZmfOVJMfbx/g==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-colorful@2.10.0': - resolution: {integrity: sha512-eQVojLvOz+LNjBwIValgu2tNJfXEOvnXZDLCr6jlKYjofwgBluQ+Z2lRrfpfmS4auJmsZsQh5dUXrF8kEwnI6g==} + '@uiw/react-color-colorful@2.10.1': + resolution: {integrity: sha512-hjP7x/QMCYEO2bvjWQMGpjk3PUlqllwBF1432+qb705kB+HhjN5kucqQa9UZdoEiHfk10f91qAK9wCYXtNH8ZQ==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-compact@2.10.0': - resolution: {integrity: sha512-AI8OPFlj4mBCUjBP4EMU4CL5NxSN29LGqutwX8aWqRtSp1T7cLO+KfRFivyJHCvh4af2Wa+z+5ALRFgvzgeGDg==} + '@uiw/react-color-compact@2.10.1': + resolution: {integrity: sha512-//hw8rCyk4G1bLazeVIvZ9gZrhx60DMPYdXAESqM5gHMWC3RBxycWi6yagx2cXh6qTlUA3/MDwJWbDXXHjKUJQ==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-editable-input-hsla@2.10.0': - resolution: {integrity: sha512-nSful4fAAWuVXSVAk2Qqi5RQzVFtHLgUS1FsQ1fsUOsLSNS5KPkybCabzhaprEIiSMBDTNTyFe4K1SM+poHeiQ==} + '@uiw/react-color-editable-input-hsla@2.10.1': + resolution: {integrity: sha512-+n26sbqj5UYNer/QXdJCNJfmJTsLmA+eRiJEZd4fLBZ15eScPQFvmJojF4mSMTMksOGlkx4clsfk9P3Z5fXMiA==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-editable-input-rgba@2.10.0': - resolution: {integrity: sha512-e4pTP2CLnR4Ha6ZfP6q7GLFd3NkgsVRaO5lHEKljBPlGzPxJmMFlJ4VUHRxwHanISwQkJDmPaU8J3IBZyorPJA==} + '@uiw/react-color-editable-input-rgba@2.10.1': + resolution: {integrity: sha512-ffjmwu9aD3hiHKEV4toT0inRGChEVxx6zh7YLZoaYwLZaISEL7ohKGcY/WREckGojnlnDF79GYGKVGc/pu9q2A==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-editable-input@2.10.0': - resolution: {integrity: sha512-hMNnuSdr0mtKSyfYwjPODKP0ZJrPKWmUAf0QtlzSwQKkFxdW5hxyVR7aXB2cc+1j44kmTcSyKqQjNS5bx6nY/g==} + '@uiw/react-color-editable-input@2.10.1': + resolution: {integrity: sha512-jMim8eAw/5hz7gaZwBy3vM5wMxPMocOG+u1+wcKbqvavHaeg/wHq7Y29uRyFKj80s4FXvUKehXRQl0F68mA7jQ==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-github@2.10.0': - resolution: {integrity: sha512-dahUCuU63mHWFOwfRfEIOuzmV3h2O8vu8wRr4UXF62et6CCCfr+5ZF6Q/XxX1fjBA1TNbMOGnuI8knSEVAZhNg==} + '@uiw/react-color-github@2.10.1': + resolution: {integrity: sha512-iqJhIjRV/ZMFKYgQr8wDGwtkSNzGzuqedxBWwnEJOeDkYUYxU7xh2qqPoq5XpLdQjfa3IAtmXfMUb9fRNcdJCw==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-hue@2.10.0': - resolution: {integrity: sha512-C/l3UsHq/8Re7a5e4WI4lgMOeNQNNOMby10O/uOHUYbzWEd1zC1ZM9WhsN44ZXwR3FbaaQ01YenuXl9c19z77g==} + '@uiw/react-color-hue@2.10.1': + resolution: {integrity: sha512-88O/gDu68U0cJp9ijn3cfnPOQfTY0jGWKbyBCMnHTEeiePBo+oMyuWZ3YU3Vp1zOXRD0SWcp3wNfuIYLOl77yg==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-material@2.10.0': - resolution: {integrity: sha512-H0frUGmsx1qj/vtKRmPf6czu8KzJPnjL6x5fzOU4JhNkg73A5THPDEu+5IurSYII5+ChAYJ7LOwCUQGOd4paMQ==} + '@uiw/react-color-material@2.10.1': + resolution: {integrity: sha512-4KawXfzlR2JhFZAnqYaGkGJKptde++mx99P83b/4I7KdQReNMriWe1PIgv3fyU29lM9zM1ZhWMRwL/s/Ug0+Aw==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-name@2.10.0': - resolution: {integrity: sha512-KdJhTC51Blb22dXI303e2K1q6MrdOy0WWNAb2U71KMQaBSh3hB8olnsI6eF5MyxrV3dL+3AwN+p7s954QzeA2A==} + '@uiw/react-color-name@2.10.1': + resolution: {integrity: sha512-HiqGT6XTyqPA0mTJEh8An7rIJIpcndYw4iXgAQFnvAhKqEerUuAx4ScOOUDRw40mczcRdRGUSuyV57oXZouHUQ==} peerDependencies: '@babel/runtime': '>=7.19.0' - '@uiw/react-color-saturation@2.10.0': - resolution: {integrity: sha512-GDEdktEWsr0V/5Pi6QtFGrX/TwJ7ZE90nG7xFeuzSqxnVUqlbu0izKwt2Tyg254fFHSlEPv53CZgbyWZ0vpwLQ==} + '@uiw/react-color-saturation@2.10.1': + resolution: {integrity: sha512-d6aE8oR5RVtIwM6V5+pBkClhs33VyCKzUWXi+Gf4qNwPoOKD9mQ4pqGd3nvqBzwNtnnX1gzyGAN1vDdSh7cV1A==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-shade-slider@2.10.0': - resolution: {integrity: sha512-sdQ521RMl3u3U4oHuYPzoxuPayLCMjYHmDh6qsDqBzHLCF652MnLUmoHuSTQJQfPmKXB9AS5kI3YsI4Fqxdw0Q==} + '@uiw/react-color-shade-slider@2.10.1': + resolution: {integrity: sha512-kp+DY4SvVLvdZ+u9K3+oGzwLVyogQB0iVknRGxrP3tDmTP7GQxdgmQVNTEQRqXVHtmcsIOqiWTN1QJA4p5g6BA==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-sketch@2.10.0': - resolution: {integrity: sha512-keM9a95mX7HeHxtZ5rglsMdFfakNwFUSAeMkkR0fsV04lC4CgpO5Ou1UdaJx5pkJ/eKksJj0QgAYC1NY6urZMw==} + '@uiw/react-color-sketch@2.10.1': + resolution: {integrity: sha512-X8xojxEB0mLws19MWqAZzQ9N9m3cZh0WmQf1/yIiYLJNDtdrN+EKF2LM+5rc1IPmwuI4fYQAQlEqEwBpfJqvCA==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-slider@2.10.0': - resolution: {integrity: sha512-e/+/HHI+GLU1af3NBtSmskF3uyowI4PecDU4ysPtSjjYPFHkgb+aF9DhCysceQrcTaEZh+Pd7KcXCHWrW8nUXg==} + '@uiw/react-color-slider@2.10.1': + resolution: {integrity: sha512-JjKwHsQ5lfNDOKmZT9E34ON9EYoZAI2uP3oDYUcyfvW7yHR1MnYII1AMaeeWb1z5GXDgAAsn6b+iX78NOaev+w==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-swatch@2.10.0': - resolution: {integrity: sha512-2gyrqmkZrkV/ULXVzhyDv9AvORekeyxeMR+tbOTDQjoV5S/bozceHe0JvsJdisnml9Aq1viVg2x8JUE6LjJo9w==} + '@uiw/react-color-swatch@2.10.1': + resolution: {integrity: sha512-DuGlaIszNcvtsY8BfW+RiUkEK1yVmnAamkzc/S5cQZwaAA5bCKhwwyaKPqh1/XWs7pR4pysjSNlMaeqaSOO34A==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color-wheel@2.10.0': - resolution: {integrity: sha512-1bdFdUC+tsoNaSH3obKx3NjWG+kClccoUGAmZ8oeVw8kALvtlJ8GjLMPfQ8AuyztaLdwlaTx4BBh+34Mprw4nA==} + '@uiw/react-color-wheel@2.10.1': + resolution: {integrity: sha512-LnO7CAsfSDfOSUFUeedNycVtx+ODpkGgcgxAT4QindU2BplTcl3mxQJxC1SIszq9zFdGK+1nXhG8N8ZmgvmVYw==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-color@2.10.0': - resolution: {integrity: sha512-8YWAgEXen5FeFi6Qhd0SBYjEGntUZDt0vRExgkscjbkb3ACsY7nZrYNWDF8ED6jInpVp2+uYsOP4+MDubsUjsA==} + '@uiw/react-color@2.10.1': + resolution: {integrity: sha512-9npz9761fA9QxNekTeHvvYNsSMorRqUhaNH2NzN4mAJC0n1p4TZ07R2689ACduv1XZhABR7DREqG3++Peg06PQ==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' react-dom: '>=16.9.0' - '@uiw/react-drag-event-interactive@2.10.0': - resolution: {integrity: sha512-+TIgGJdvC87L6V5JEP5QJ01aVDHBoSQe1inc/fkkhdOQgnkXwWasqLaSrnpO71W0KYHgkMEfTtj8aZVLsUhtjA==} + '@uiw/react-drag-event-interactive@2.10.1': + resolution: {integrity: sha512-eArtX/XdSrg5aQs8CV0vne9vChybw2GkNZCP9H68zjBBzucuYgjURqKBJ/+3jid06YpRZ5zz/YTnAlySqOt0Ag==} peerDependencies: '@babel/runtime': '>=7.19.0' react: '>=16.9.0' @@ -6797,8 +6795,8 @@ packages: resolution: {integrity: sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==} engines: {node: ^10 || ^12 || >=14} - prettier-plugin-ember-template-tag@2.1.3: - resolution: {integrity: sha512-FfAvkU+fqDC3Zs8+qGhBHYuwq1DED+UTPMH33QXxivZxRekkItBNXfi1Y+YkIbhCnu6UeTE2aYdbQSLlkOC2bA==} + prettier-plugin-ember-template-tag@2.1.4: + resolution: {integrity: sha512-KMjDL4UFDuLpFD69SlhW2AB5YQ3AUS/1NNBjdY/rXko180eWo1VNeCvyZdqNR4Zamii/6Y/E3D/ey8BmhKLaJw==} engines: {node: 18.* || >= 20} peerDependencies: prettier: '>= 3.0.0' @@ -6911,10 +6909,10 @@ packages: '@types/react-dom': optional: true - react-dom@19.2.4: - resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + react-dom@19.2.5: + resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} peerDependencies: - react: ^19.2.4 + react: ^19.2.5 react-error-boundary@6.0.0: resolution: {integrity: sha512-gdlJjD7NWr0IfkPlaREN2d9uUZUlksrfOx7SX62VRerwXbMY6ftGCIZua1VG1aXFNOimhISsTq+Owp725b9SiA==} @@ -7036,8 +7034,8 @@ packages: react: '*' react-dom: '*' - react@19.2.4: - resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + react@19.2.5: + resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} engines: {node: '>=0.10.0'} read-cache@1.0.0: @@ -8984,18 +8982,6 @@ snapshots: - supports-color optional: true - '@babel/traverse@7.28.5': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.29.0 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.0 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - '@babel/traverse@7.29.0': dependencies: '@babel/code-frame': 7.29.0 @@ -9195,9 +9181,9 @@ snapshots: '@dnd-kit/state': 0.3.2 tslib: 2.8.1 - '@dnd-kit/accessibility@3.1.1(react@19.2.4)': + '@dnd-kit/accessibility@3.1.1(react@19.2.5)': dependencies: - react: 19.2.4 + react: 19.2.5 tslib: 2.8.1 '@dnd-kit/collision@0.3.2': @@ -9206,12 +9192,12 @@ snapshots: '@dnd-kit/geometry': 0.3.2 tslib: 2.8.1 - '@dnd-kit/core@6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@dnd-kit/core@6.3.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@dnd-kit/accessibility': 3.1.1(react@19.2.4) - '@dnd-kit/utilities': 3.2.2(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@dnd-kit/accessibility': 3.1.1(react@19.2.5) + '@dnd-kit/utilities': 3.2.2(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) tslib: 2.7.0 '@dnd-kit/dom@0.3.2': @@ -9232,20 +9218,20 @@ snapshots: '@dnd-kit/abstract': 0.3.2 tslib: 2.8.1 - '@dnd-kit/react@0.3.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@dnd-kit/react@0.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@dnd-kit/abstract': 0.3.2 '@dnd-kit/dom': 0.3.2 '@dnd-kit/state': 0.3.2 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) tslib: 2.8.1 - '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)': + '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)': dependencies: - '@dnd-kit/core': 6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@dnd-kit/utilities': 3.2.2(react@19.2.4) - react: 19.2.4 + '@dnd-kit/core': 6.3.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@dnd-kit/utilities': 3.2.2(react@19.2.5) + react: 19.2.5 tslib: 2.7.0 '@dnd-kit/state@0.3.2': @@ -9253,9 +9239,9 @@ snapshots: '@preact/signals-core': 1.14.0 tslib: 2.8.1 - '@dnd-kit/utilities@3.2.2(react@19.2.4)': + '@dnd-kit/utilities@3.2.2(react@19.2.5)': dependencies: - react: 19.2.4 + react: 19.2.5 tslib: 2.7.0 '@emnapi/core@1.5.0': @@ -9317,17 +9303,17 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4)': + '@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5)': dependencies: '@babel/runtime': 7.26.0 '@emotion/babel-plugin': 11.13.5 '@emotion/cache': 11.14.0 '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.4) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.5) '@emotion/utils': 1.4.2 '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 - react: 19.2.4 + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 transitivePeerDependencies: @@ -9343,16 +9329,16 @@ snapshots: '@emotion/sheet@1.4.0': {} - '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)': + '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5)': dependencies: '@babel/runtime': 7.27.6 '@emotion/babel-plugin': 11.13.5 '@emotion/is-prop-valid': 1.3.0 - '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.5) '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.4) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.5) '@emotion/utils': 1.4.2 - react: 19.2.4 + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 transitivePeerDependencies: @@ -9360,9 +9346,9 @@ snapshots: '@emotion/unitless@0.10.0': {} - '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.4)': + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.5)': dependencies: - react: 19.2.4 + react: 19.2.5 '@emotion/utils@1.4.2': {} @@ -9459,34 +9445,34 @@ snapshots: '@floating-ui/core': 1.7.3 '@floating-ui/utils': 0.2.10 - '@floating-ui/react-dom@2.1.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@floating-ui/react-dom@2.1.6(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@floating-ui/dom': 1.7.4 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) '@floating-ui/utils@0.2.10': {} - '@greenhat616/material-react-table@4.0.0(675c3bab767efe78ea23c1542e4b601d)': + '@greenhat616/material-react-table@4.0.0(c9750096c20c2934468ef5df5df5d693)': dependencies: - '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) - '@mui/icons-material': 7.3.9(@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) - '@mui/material': 7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@mui/x-date-pickers': 8.27.2(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@mui/system@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(dayjs@1.11.20)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.5) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) + '@mui/icons-material': 7.3.10(@mui/material@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) + '@mui/material': 7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@mui/x-date-pickers': 8.27.2(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@mui/material@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@mui/system@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(dayjs@1.11.20)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tanstack/match-sorter-utils': 8.19.4 - '@tanstack/react-table': 8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/react-virtual': 3.13.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-table': 8.21.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@tanstack/react-virtual': 3.13.9(react-dom@19.2.5(react@19.2.5))(react@19.2.5) highlight-words: 2.0.0 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@hookform/resolvers@5.2.2(react-hook-form@7.72.1(react@19.2.4))': + '@hookform/resolvers@5.2.2(react-hook-form@7.72.1(react@19.2.5))': dependencies: '@standard-schema/utils': 0.3.0 - react-hook-form: 7.72.1(react@19.2.4) + react-hook-form: 7.72.1(react@19.2.5) - '@ianvs/prettier-plugin-sort-imports@4.7.1(@prettier/plugin-oxc@0.1.3)(content-tag@4.0.0)(prettier-plugin-ember-template-tag@2.1.3(prettier@3.8.1))(prettier@3.8.1)': + '@ianvs/prettier-plugin-sort-imports@4.7.1(@prettier/plugin-oxc@0.1.3)(content-tag@4.0.0)(prettier-plugin-ember-template-tag@2.1.4(prettier@3.8.1))(prettier@3.8.1)': dependencies: '@babel/generator': 7.29.0 '@babel/parser': 7.29.0 @@ -9497,7 +9483,7 @@ snapshots: optionalDependencies: '@prettier/plugin-oxc': 0.1.3 content-tag: 4.0.0 - prettier-plugin-ember-template-tag: 2.1.3(prettier@3.8.1) + prettier-plugin-ember-template-tag: 2.1.4(prettier@3.8.1) transitivePeerDependencies: - supports-color @@ -9514,7 +9500,7 @@ snapshots: '@iconify/types': 2.0.0 mlly: 1.8.0 - '@inlang/paraglide-js@2.15.2(babel-plugin-macros@3.1.0)': + '@inlang/paraglide-js@2.15.3(babel-plugin-macros@3.1.0)': dependencies: '@inlang/recommend-sherlock': 0.2.1 '@inlang/sdk': 2.9.1(babel-plugin-macros@3.1.0) @@ -9635,79 +9621,79 @@ snapshots: dependencies: state-local: 1.0.7 - '@monaco-editor/react@4.7.0(monaco-editor@0.55.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@monaco-editor/react@4.7.0(monaco-editor@0.55.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@monaco-editor/loader': 1.5.0 monaco-editor: 0.55.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@mui/core-downloads-tracker@7.3.9': {} + '@mui/core-downloads-tracker@7.3.10': {} - '@mui/icons-material@7.3.9(@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)': + '@mui/icons-material@7.3.10(@mui/material@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/react@19.2.14)(react@19.2.5)': dependencies: - '@babel/runtime': 7.28.6 - '@mui/material': 7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 + '@babel/runtime': 7.29.2 + '@mui/material': 7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@mui/lab@7.0.0-beta.17(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@mui/lab@7.0.0-beta.17(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@mui/material@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.28.3 - '@mui/material': 7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@mui/system': 7.3.2(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + '@mui/material': 7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@mui/system': 7.3.2(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) '@mui/types': 7.4.6(@types/react@19.2.14) - '@mui/utils': 7.3.2(@types/react@19.2.14)(react@19.2.4) + '@mui/utils': 7.3.2(@types/react@19.2.14)(react@19.2.5) clsx: 2.1.1 prop-types: 15.8.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: - '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.5) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) '@types/react': 19.2.14 - '@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@mui/material@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@babel/runtime': 7.28.6 - '@mui/core-downloads-tracker': 7.3.9 - '@mui/system': 7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + '@babel/runtime': 7.29.2 + '@mui/core-downloads-tracker': 7.3.10 + '@mui/system': 7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) '@mui/types': 7.4.12(@types/react@19.2.14) - '@mui/utils': 7.3.9(@types/react@19.2.14)(react@19.2.4) + '@mui/utils': 7.3.10(@types/react@19.2.14)(react@19.2.5) '@popperjs/core': 2.11.8 '@types/react-transition-group': 4.4.12(@types/react@19.2.14) clsx: 2.1.1 csstype: 3.2.3 prop-types: 15.8.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) react-is: 19.2.4 - react-transition-group: 4.4.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react-transition-group: 4.4.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5) optionalDependencies: - '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.5) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) '@types/react': 19.2.14 - '@mui/private-theming@7.3.2(@types/react@19.2.14)(react@19.2.4)': + '@mui/private-theming@7.3.10(@types/react@19.2.14)(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@mui/utils': 7.3.8(@types/react@19.2.14)(react@19.2.4) + '@mui/utils': 7.3.10(@types/react@19.2.14)(react@19.2.5) prop-types: 15.8.1 - react: 19.2.4 + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@mui/private-theming@7.3.9(@types/react@19.2.14)(react@19.2.4)': + '@mui/private-theming@7.3.2(@types/react@19.2.14)(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@mui/utils': 7.3.9(@types/react@19.2.14)(react@19.2.4) + '@mui/utils': 7.3.9(@types/react@19.2.14)(react@19.2.5) prop-types: 15.8.1 - react: 19.2.4 + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@mui/styled-engine@7.3.2(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': + '@mui/styled-engine@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 '@emotion/cache': 11.14.0 @@ -9715,12 +9701,12 @@ snapshots: '@emotion/sheet': 1.4.0 csstype: 3.2.3 prop-types: 15.8.1 - react: 19.2.4 + react: 19.2.5 optionalDependencies: - '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.5) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) - '@mui/styled-engine@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': + '@mui/styled-engine@7.3.2(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 '@emotion/cache': 11.14.0 @@ -9728,47 +9714,41 @@ snapshots: '@emotion/sheet': 1.4.0 csstype: 3.2.3 prop-types: 15.8.1 - react: 19.2.4 + react: 19.2.5 optionalDependencies: - '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.5) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) - '@mui/system@7.3.2(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)': + '@mui/system@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@mui/private-theming': 7.3.2(@types/react@19.2.14)(react@19.2.4) - '@mui/styled-engine': 7.3.2(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) - '@mui/types': 7.4.11(@types/react@19.2.14) - '@mui/utils': 7.3.8(@types/react@19.2.14)(react@19.2.4) - clsx: 2.1.1 - csstype: 3.2.3 - prop-types: 15.8.1 - react: 19.2.4 - optionalDependencies: - '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) - '@types/react': 19.2.14 - - '@mui/system@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@babel/runtime': 7.29.2 - '@mui/private-theming': 7.3.9(@types/react@19.2.14)(react@19.2.4) - '@mui/styled-engine': 7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + '@mui/private-theming': 7.3.10(@types/react@19.2.14)(react@19.2.5) + '@mui/styled-engine': 7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@mui/types': 7.4.12(@types/react@19.2.14) - '@mui/utils': 7.3.9(@types/react@19.2.14)(react@19.2.4) + '@mui/utils': 7.3.10(@types/react@19.2.14)(react@19.2.5) clsx: 2.1.1 csstype: 3.2.3 prop-types: 15.8.1 - react: 19.2.4 + react: 19.2.5 optionalDependencies: - '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.5) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) '@types/react': 19.2.14 - '@mui/types@7.4.11(@types/react@19.2.14)': + '@mui/system@7.3.2(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 + '@mui/private-theming': 7.3.2(@types/react@19.2.14)(react@19.2.5) + '@mui/styled-engine': 7.3.2(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@mui/types': 7.4.12(@types/react@19.2.14) + '@mui/utils': 7.3.9(@types/react@19.2.14)(react@19.2.5) + clsx: 2.1.1 + csstype: 3.2.3 + prop-types: 15.8.1 + react: 19.2.5 optionalDependencies: + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.5) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) '@types/react': 19.2.14 '@mui/types@7.4.12(@types/react@19.2.14)': @@ -9783,69 +9763,81 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 - '@mui/utils@7.3.2(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@babel/runtime': 7.29.2 - '@mui/types': 7.4.11(@types/react@19.2.14) - '@types/prop-types': 15.7.15 - clsx: 2.1.1 - prop-types: 15.8.1 - react: 19.2.4 - react-is: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@mui/utils@7.3.8(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@babel/runtime': 7.29.2 - '@mui/types': 7.4.11(@types/react@19.2.14) - '@types/prop-types': 15.7.15 - clsx: 2.1.1 - prop-types: 15.8.1 - react: 19.2.4 - react-is: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@mui/utils@7.3.9(@types/react@19.2.14)(react@19.2.4)': + '@mui/utils@7.3.10(@types/react@19.2.14)(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 '@mui/types': 7.4.12(@types/react@19.2.14) '@types/prop-types': 15.7.15 clsx: 2.1.1 prop-types: 15.8.1 - react: 19.2.4 + react: 19.2.5 react-is: 19.2.4 optionalDependencies: '@types/react': 19.2.14 - '@mui/x-date-pickers@8.27.2(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@mui/system@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(dayjs@1.11.20)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@mui/utils@7.3.2(@types/react@19.2.14)(react@19.2.5)': + dependencies: + '@babel/runtime': 7.29.2 + '@mui/types': 7.4.12(@types/react@19.2.14) + '@types/prop-types': 15.7.15 + clsx: 2.1.1 + prop-types: 15.8.1 + react: 19.2.5 + react-is: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@mui/utils@7.3.8(@types/react@19.2.14)(react@19.2.5)': + dependencies: + '@babel/runtime': 7.29.2 + '@mui/types': 7.4.12(@types/react@19.2.14) + '@types/prop-types': 15.7.15 + clsx: 2.1.1 + prop-types: 15.8.1 + react: 19.2.5 + react-is: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@mui/utils@7.3.9(@types/react@19.2.14)(react@19.2.5)': + dependencies: + '@babel/runtime': 7.29.2 + '@mui/types': 7.4.12(@types/react@19.2.14) + '@types/prop-types': 15.7.15 + clsx: 2.1.1 + prop-types: 15.8.1 + react: 19.2.5 + react-is: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@mui/x-date-pickers@8.27.2(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@mui/material@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@mui/system@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(dayjs@1.11.20)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.28.6 - '@mui/material': 7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@mui/system': 7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) - '@mui/utils': 7.3.8(@types/react@19.2.14)(react@19.2.4) - '@mui/x-internals': 8.26.0(@types/react@19.2.14)(react@19.2.4) + '@mui/material': 7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@mui/system': 7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) + '@mui/utils': 7.3.8(@types/react@19.2.14)(react@19.2.5) + '@mui/x-internals': 8.26.0(@types/react@19.2.14)(react@19.2.5) '@types/react-transition-group': 4.4.12(@types/react@19.2.14) clsx: 2.1.1 prop-types: 15.8.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-transition-group: 4.4.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-transition-group: 4.4.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5) optionalDependencies: - '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.5) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) dayjs: 1.11.20 transitivePeerDependencies: - '@types/react' - '@mui/x-internals@8.26.0(@types/react@19.2.14)(react@19.2.4)': + '@mui/x-internals@8.26.0(@types/react@19.2.14)(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@mui/utils': 7.3.8(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 + '@mui/utils': 7.3.9(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 reselect: 5.1.1 - use-sync-external-store: 1.6.0(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.5) transitivePeerDependencies: - '@types/react' @@ -10366,10 +10358,10 @@ snapshots: '@oxlint/binding-win32-x64-msvc@1.59.0': optional: true - '@paper-design/shaders-react@0.0.72(@types/react@19.2.14)(react@19.2.4)': + '@paper-design/shaders-react@0.0.72(@types/react@19.2.14)(react@19.2.5)': dependencies: '@paper-design/shaders': 0.0.72 - react: 19.2.4 + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 @@ -10444,769 +10436,769 @@ snapshots: '@radix-ui/primitive@1.1.3': {} - '@radix-ui/react-accessible-icon@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-accessible-icon@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-aspect-ratio@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-aspect-ratio@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-avatar@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-avatar@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.5)': dependencies: - react: 19.2.4 + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-context-menu@2.2.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-context-menu@2.2.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.5)': dependencies: - react: 19.2.4 + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) aria-hidden: 1.2.6 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.5)': dependencies: - react: 19.2.4 + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.14)(react@19.2.5)': dependencies: - react: 19.2.4 + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-form@0.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-form@0.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-label': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-label': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-hover-card@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-hover-card@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.5)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-label@2.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-label@2.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) aria-hidden: 1.2.6 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-menubar@1.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-menubar@1.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-one-time-password-field@0.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-one-time-password-field@0.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': 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.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-password-toggle-field@0.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-password-toggle-field@0.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) aria-hidden: 1.2.6 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@floating-ui/react-dom': 2.1.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@floating-ui/react-dom': 2.1.6(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.5) '@radix-ui/rect': 1.1.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-portal@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-portal@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@radix-ui/react-slot': 1.2.4(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-slot': 1.2.4(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-progress@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-progress@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-radio-group@1.3.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-radio-group@1.3.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': 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.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) aria-hidden: 1.2.6 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-separator@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-separator@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-slider@1.3.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-slider@1.3.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': 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.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.5)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-slot@1.2.4(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-slot@1.2.4(@types/react@19.2.14)(react@19.2.5)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-toast@1.2.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-toast@1.2.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-toggle@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-toggle@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-toolbar@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-toolbar@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.14)(react@19.2.5)': dependencies: - react: 19.2.4 + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.5)': dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.5)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.14)(react@19.2.5)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.2.14)(react@19.2.5)': dependencies: - react: 19.2.4 - use-sync-external-store: 1.6.0(react@19.2.4) + react: 19.2.5 + use-sync-external-store: 1.6.0(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.5)': dependencies: - react: 19.2.4 + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.14)(react@19.2.5)': dependencies: - react: 19.2.4 + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.14)(react@19.2.5)': dependencies: '@radix-ui/rect': 1.1.1 - react: 19.2.4 + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.14)(react@19.2.4)': + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.14)(react@19.2.5)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) @@ -11585,55 +11577,55 @@ snapshots: '@tanstack/query-core@5.96.2': {} - '@tanstack/react-query@5.96.2(react@19.2.4)': + '@tanstack/react-query@5.96.2(react@19.2.5)': dependencies: '@tanstack/query-core': 5.96.2 - react: 19.2.4 + react: 19.2.5 - '@tanstack/react-router-devtools@1.166.11(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.168.9)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-router-devtools@1.166.11(@tanstack/react-router@1.168.10(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@tanstack/router-core@1.168.9)(csstype@3.2.3)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@tanstack/react-router': 1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-router': 1.168.10(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tanstack/router-devtools-core': 1.167.1(@tanstack/router-core@1.168.9)(csstype@3.2.3) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@tanstack/router-core': 1.168.9 transitivePeerDependencies: - csstype - '@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-router@1.168.10(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@tanstack/history': 1.161.6 - '@tanstack/react-store': 0.9.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-store': 0.9.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tanstack/router-core': 1.168.9 isbot: 5.1.28 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@tanstack/react-store@0.9.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-store@0.9.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@tanstack/store': 0.9.3 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - use-sync-external-store: 1.6.0(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + use-sync-external-store: 1.6.0(react@19.2.5) - '@tanstack/react-table@8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-table@8.21.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@tanstack/table-core': 8.21.3 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@tanstack/react-virtual@3.13.23(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-virtual@3.13.23(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@tanstack/virtual-core': 3.13.23 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@tanstack/react-virtual@3.13.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-virtual@3.13.9(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@tanstack/virtual-core': 3.13.9 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) '@tanstack/router-core@1.168.9': dependencies: @@ -11663,7 +11655,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.167.12(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.2(@types/node@24.11.0)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.2))': + '@tanstack/router-plugin@1.167.12(@tanstack/react-router@1.168.10(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(vite@7.3.2(@types/node@24.11.0)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.29.0) @@ -11679,7 +11671,7 @@ snapshots: unplugin: 2.3.11 zod: 3.25.76 optionalDependencies: - '@tanstack/react-router': 1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-router': 1.168.10(react-dom@19.2.5(react@19.2.5))(react@19.2.5) vite: 7.3.2(@types/node@24.11.0)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass-embedded@1.99.0)(sass@1.99.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color @@ -11698,9 +11690,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(zod@4.3.6)': + '@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.168.10(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(zod@4.3.6)': dependencies: - '@tanstack/react-router': 1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-router': 1.168.10(react-dom@19.2.5(react@19.2.5))(react@19.2.5) zod: 4.3.6 '@tanstack/store@0.9.3': {} @@ -12056,210 +12048,210 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@uidotdev/usehooks@2.4.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uidotdev/usehooks@2.4.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/color-convert@2.10.0(@babel/runtime@7.29.2)': + '@uiw/color-convert@2.10.1(@babel/runtime@7.29.2)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/react-color-alpha@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-alpha@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-drag-event-interactive': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-drag-event-interactive': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-block@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-block@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-color-editable-input': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-swatch': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-color-editable-input': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-swatch': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-chrome@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-chrome@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-color-alpha': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-editable-input': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-editable-input-hsla': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-editable-input-rgba': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-github': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-hue': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-saturation': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-color-alpha': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-editable-input': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-editable-input-hsla': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-editable-input-rgba': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-github': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-hue': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-saturation': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-circle@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-circle@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-color-swatch': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-color-swatch': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-colorful@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-colorful@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-color-alpha': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-hue': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-saturation': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-color-alpha': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-hue': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-saturation': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-compact@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-compact@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-color-editable-input': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-editable-input-rgba': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-swatch': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-color-editable-input': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-editable-input-rgba': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-swatch': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-editable-input-hsla@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-editable-input-hsla@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-color-editable-input-rgba': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-color-editable-input-rgba': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-editable-input-rgba@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-editable-input-rgba@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-color-editable-input': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-color-editable-input': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-editable-input@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-editable-input@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-github@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-github@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-color-swatch': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-color-swatch': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-hue@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-hue@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-color-alpha': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-color-alpha': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-material@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-material@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-color-editable-input': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-editable-input-rgba': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-color-editable-input': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-editable-input-rgba': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-name@2.10.0(@babel/runtime@7.29.2)': + '@uiw/react-color-name@2.10.1(@babel/runtime@7.29.2)': dependencies: '@babel/runtime': 7.29.2 colors-named: 1.0.4 colors-named-hex: 1.0.3 - '@uiw/react-color-saturation@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-saturation@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-drag-event-interactive': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-drag-event-interactive': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-shade-slider@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-shade-slider@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-color-alpha': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-color-alpha': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-sketch@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-sketch@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-color-alpha': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-editable-input': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-editable-input-rgba': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-hue': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-saturation': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-swatch': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-color-alpha': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-editable-input': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-editable-input-rgba': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-hue': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-saturation': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-swatch': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-slider@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-slider@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-color-alpha': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-color-alpha': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-swatch@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-swatch@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color-wheel@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color-wheel@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-drag-event-interactive': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-drag-event-interactive': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-color@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-color@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - '@uiw/color-convert': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-color-alpha': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-block': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-chrome': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-circle': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-colorful': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-compact': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-editable-input': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-editable-input-hsla': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-editable-input-rgba': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-github': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-hue': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-material': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-name': 2.10.0(@babel/runtime@7.29.2) - '@uiw/react-color-saturation': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-shade-slider': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-sketch': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-slider': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-swatch': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@uiw/react-color-wheel': 2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@uiw/color-convert': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-color-alpha': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-block': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-chrome': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-circle': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-colorful': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-compact': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-editable-input': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-editable-input-hsla': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-editable-input-rgba': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-github': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-hue': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-material': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-name': 2.10.1(@babel/runtime@7.29.2) + '@uiw/react-color-saturation': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-shade-slider': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-sketch': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-slider': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-swatch': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-color-wheel': 2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@uiw/react-drag-event-interactive@2.10.0(@babel/runtime@7.29.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@uiw/react-drag-event-interactive@2.10.1(@babel/runtime@7.29.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) '@ungap/structured-clone@1.2.0': {} @@ -12353,7 +12345,7 @@ snapshots: adm-zip@0.5.17: {} - ahooks@3.9.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + ahooks@3.9.7(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: '@babel/runtime': 7.29.2 '@types/js-cookie': 3.0.6 @@ -12361,8 +12353,8 @@ snapshots: intersection-observer: 0.12.2 js-cookie: 3.0.5 lodash: 4.17.21 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) react-fast-compare: 3.2.2 resize-observer-polyfill: 1.5.1 screenfull: 5.2.0 @@ -12399,16 +12391,16 @@ snapshots: alien-signals@0.4.14: {} - allotment@1.20.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + allotment@1.20.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: classnames: 2.5.1 eventemitter3: 5.0.1 fast-deep-equal: 3.1.3 lodash.clamp: 4.0.3 lodash.debounce: 4.0.8 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - usehooks-ts: 3.1.1(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + usehooks-ts: 3.1.1(react@19.2.5) ansi-escapes@7.0.0: dependencies: @@ -13312,15 +13304,15 @@ snapshots: fraction.js@5.3.4: {} - framer-motion@12.38.0(@emotion/is-prop-valid@1.3.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + framer-motion@12.38.0(@emotion/is-prop-valid@1.3.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: motion-dom: 12.38.0 motion-utils: 12.36.0 tslib: 2.8.1 optionalDependencies: '@emotion/is-prop-valid': 1.3.0 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) fs-extra@10.1.0: dependencies: @@ -13668,12 +13660,12 @@ snapshots: jju@1.4.0: {} - jotai@2.19.1(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.14)(react@19.2.4): + jotai@2.19.1(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.14)(react@19.2.5): optionalDependencies: '@babel/core': 7.29.0 '@babel/template': 7.28.6 '@types/react': 19.2.14 - react: 19.2.4 + react: 19.2.5 js-cookie@2.2.1: {} @@ -14247,26 +14239,26 @@ snapshots: muggle-string@0.4.1: {} - mui-color-input@7.0.0(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + mui-color-input@7.0.0(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@mui/material@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: '@ctrl/tinycolor': 4.1.0 - '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) - '@mui/material': 7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.5) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) + '@mui/material': 7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 - nano-css@5.6.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + nano-css@5.6.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: '@jridgewell/sourcemap-codec': 1.5.0 css-tree: 1.1.3 csstype: 3.2.3 fastest-stable-stringify: 2.0.2 inline-style-prefixer: 7.0.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) rtl-css-js: 1.16.1 stacktrace-js: 2.0.2 stylis: 4.3.2 @@ -14633,19 +14625,19 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - prettier-plugin-ember-template-tag@2.1.3(prettier@3.8.1): + prettier-plugin-ember-template-tag@2.1.4(prettier@3.8.1): dependencies: - '@babel/traverse': 7.28.5 + '@babel/traverse': 7.29.0 content-tag: 4.0.0 prettier: 3.8.1 transitivePeerDependencies: - supports-color - prettier-plugin-tailwindcss@0.7.2(@ianvs/prettier-plugin-sort-imports@4.7.1(@prettier/plugin-oxc@0.1.3)(content-tag@4.0.0)(prettier-plugin-ember-template-tag@2.1.3(prettier@3.8.1))(prettier@3.8.1))(@prettier/plugin-oxc@0.1.3)(@trivago/prettier-plugin-sort-imports@4.3.0(prettier@3.8.1))(prettier@3.8.1): + prettier-plugin-tailwindcss@0.7.2(@ianvs/prettier-plugin-sort-imports@4.7.1(@prettier/plugin-oxc@0.1.3)(content-tag@4.0.0)(prettier-plugin-ember-template-tag@2.1.4(prettier@3.8.1))(prettier@3.8.1))(@prettier/plugin-oxc@0.1.3)(@trivago/prettier-plugin-sort-imports@4.3.0(prettier@3.8.1))(prettier@3.8.1): dependencies: prettier: 3.8.1 optionalDependencies: - '@ianvs/prettier-plugin-sort-imports': 4.7.1(@prettier/plugin-oxc@0.1.3)(content-tag@4.0.0)(prettier-plugin-ember-template-tag@2.1.3(prettier@3.8.1))(prettier@3.8.1) + '@ianvs/prettier-plugin-sort-imports': 4.7.1(@prettier/plugin-oxc@0.1.3)(content-tag@4.0.0)(prettier-plugin-ember-template-tag@2.1.4(prettier@3.8.1))(prettier@3.8.1) '@prettier/plugin-oxc': 0.1.3 '@trivago/prettier-plugin-sort-imports': 4.3.0(prettier@3.8.1) @@ -14681,114 +14673,114 @@ snapshots: queue-microtask@1.2.3: {} - radix-ui@1.4.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + radix-ui@1.4.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-accessible-icon': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-aspect-ratio': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-avatar': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-form': 0.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-label': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-menubar': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-one-time-password-field': 0.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-password-toggle-field': 0.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-progress': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-select': 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slider': 1.3.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-switch': 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-toast': 1.2.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-toolbar': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-accessible-icon': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-aspect-ratio': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-avatar': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-form': 0.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-label': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-menubar': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-one-time-password-field': 0.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-password-toggle-field': 0.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-progress': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-select': 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-slider': 1.3.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-switch': 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-toast': 1.2.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-toolbar': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - react-dom@19.2.4(react@19.2.4): + react-dom@19.2.5(react@19.2.5): dependencies: - react: 19.2.4 + react: 19.2.5 scheduler: 0.27.0 - react-error-boundary@6.0.0(react@19.2.4): + react-error-boundary@6.0.0(react@19.2.5): dependencies: '@babel/runtime': 7.27.1 - react: 19.2.4 + react: 19.2.5 react-fast-compare@3.2.2: {} - react-fast-marquee@1.6.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-fast-marquee@1.6.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - react-hook-form-mui@8.2.0(fddc180082ef55eb3a5d5e8b74a28cd6): + react-hook-form-mui@8.2.0(ac03decca1a377e6c5f1d359ea093f97): dependencies: - '@mui/material': 7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-hook-form: 7.72.1(react@19.2.4) + '@mui/material': 7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-hook-form: 7.72.1(react@19.2.5) optionalDependencies: - '@mui/icons-material': 7.3.9(@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) - '@mui/x-date-pickers': 8.27.2(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@mui/material@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@mui/system@7.3.9(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(dayjs@1.11.20)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@mui/icons-material': 7.3.10(@mui/material@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@types/react@19.2.14)(react@19.2.5) + '@mui/x-date-pickers': 8.27.2(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@mui/material@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@mui/system@7.3.10(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(dayjs@1.11.20)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - react-hook-form@7.72.1(react@19.2.4): + react-hook-form@7.72.1(react@19.2.5): dependencies: - react: 19.2.4 + react: 19.2.5 - react-i18next@15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3): + react-i18next@15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: '@babel/runtime': 7.28.3 html-parse-stringify: 3.0.1 i18next: 25.10.10(typescript@5.9.3) - react: 19.2.4 + react: 19.2.5 optionalDependencies: - react-dom: 19.2.4(react@19.2.4) + react-dom: 19.2.5(react@19.2.5) typescript: 5.9.3 react-is@16.13.1: {} react-is@19.2.4: {} - react-markdown@10.1.0(@types/react@19.2.14)(react@19.2.4): + react-markdown@10.1.0(@types/react@19.2.14)(react@19.2.5): dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.3 @@ -14797,7 +14789,7 @@ snapshots: hast-util-to-jsx-runtime: 2.3.0 html-url-attributes: 3.0.0 mdast-util-to-hast: 13.1.0 - react: 19.2.4 + react: 19.2.5 remark-parse: 11.0.0 remark-rehype: 11.1.0 unified: 11.0.4 @@ -14808,54 +14800,54 @@ snapshots: react-refresh@0.18.0: {} - react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.4): + react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.5): dependencies: - react: 19.2.4 - react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.4) + react: 19.2.5 + react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.5) tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.14 - react-remove-scroll@2.7.2(@types/react@19.2.14)(react@19.2.4): + react-remove-scroll@2.7.2(@types/react@19.2.14)(react@19.2.5): dependencies: - react: 19.2.4 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.14)(react@19.2.4) - react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.4) + react: 19.2.5 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.14)(react@19.2.5) + react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.5) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.14)(react@19.2.4) - use-sidecar: 1.1.3(@types/react@19.2.14)(react@19.2.4) + use-callback-ref: 1.3.3(@types/react@19.2.14)(react@19.2.5) + use-sidecar: 1.1.3(@types/react@19.2.14)(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 - react-split-grid@1.0.4(react@19.2.4): + react-split-grid@1.0.4(react@19.2.5): dependencies: prop-types: 15.8.1 - react: 19.2.4 + react: 19.2.5 split-grid: 1.0.11 - react-style-singleton@2.2.3(@types/react@19.2.14)(react@19.2.4): + react-style-singleton@2.2.3(@types/react@19.2.14)(react@19.2.5): dependencies: get-nonce: 1.0.1 - react: 19.2.4 + react: 19.2.5 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.14 - react-transition-group@4.4.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-transition-group@4.4.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: '@babel/runtime': 7.29.2 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - react-universal-interface@0.6.2(react@19.2.4)(tslib@2.7.0): + react-universal-interface@0.6.2(react@19.2.5)(tslib@2.7.0): dependencies: - react: 19.2.4 + react: 19.2.5 tslib: 2.7.0 - react-use@17.6.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-use@17.6.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: '@types/js-cookie': 2.2.7 '@xobotyi/scrollbar-width': 1.9.5 @@ -14863,10 +14855,10 @@ snapshots: fast-deep-equal: 3.1.3 fast-shallow-equal: 1.0.0 js-cookie: 2.2.1 - nano-css: 5.6.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-universal-interface: 0.6.2(react@19.2.4)(tslib@2.7.0) + nano-css: 5.6.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-universal-interface: 0.6.2(react@19.2.5)(tslib@2.7.0) resize-observer-polyfill: 1.5.1 screenfull: 5.2.0 set-harmonic-interval: 1.0.1 @@ -14874,7 +14866,7 @@ snapshots: ts-easing: 0.2.0 tslib: 2.7.0 - react@19.2.4: {} + react@19.2.5: {} read-cache@1.0.0: dependencies: @@ -15454,11 +15446,11 @@ snapshots: svg-tags@1.0.0: {} - swr@2.4.1(react@19.2.4): + swr@2.4.1(react@19.2.5): dependencies: dequal: 2.0.3 - react: 19.2.4 - use-sync-external-store: 1.6.0(react@19.2.4) + react: 19.2.5 + use-sync-external-store: 1.6.0(react@19.2.5) sync-child-process@1.0.2: dependencies: @@ -15747,29 +15739,29 @@ snapshots: urlpattern-polyfill@10.1.0: {} - use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.4): + use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.5): dependencies: - react: 19.2.4 + react: 19.2.5 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.14 - use-sidecar@1.1.3(@types/react@19.2.14)(react@19.2.4): + use-sidecar@1.1.3(@types/react@19.2.14)(react@19.2.5): dependencies: detect-node-es: 1.1.0 - react: 19.2.4 + react: 19.2.5 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.14 - use-sync-external-store@1.6.0(react@19.2.4): + use-sync-external-store@1.6.0(react@19.2.5): dependencies: - react: 19.2.4 + react: 19.2.5 - usehooks-ts@3.1.1(react@19.2.4): + usehooks-ts@3.1.1(react@19.2.5): dependencies: lodash.debounce: 4.0.8 - react: 19.2.4 + react: 19.2.5 utf-8-validate@5.0.10: dependencies: @@ -15785,11 +15777,11 @@ snapshots: varint@6.0.0: {} - vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -15805,10 +15797,10 @@ snapshots: unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 - virtua@0.46.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.5): + virtua@0.46.6(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(solid-js@1.9.5): optionalDependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) solid-js: 1.9.5 vite-bundle-visualizer@1.2.1(rollup@4.46.2): diff --git a/lede/package/kernel/mac80211/Makefile b/lede/package/kernel/mac80211/Makefile index 342b426611..ff094d1241 100644 --- a/lede/package/kernel/mac80211/Makefile +++ b/lede/package/kernel/mac80211/Makefile @@ -24,7 +24,7 @@ PKG_SOURCE:=backports-$(PKG_VERSION).tar.xz PATCH_DIR:=./patches endif -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_LICENSE:=GPL-2.0-only PKG_LICENSE_FILES:=COPYING diff --git a/lede/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh b/lede/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh index 977ab7ca20..ed47b020b0 100644 --- a/lede/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh +++ b/lede/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh @@ -26,6 +26,7 @@ drv_mac80211_init_device_config() { hostapd_common_add_device_config config_add_string path phy 'macaddr:macaddr' + config_add_int radio config_add_string tx_burst config_add_string distance config_add_int beacon_int chanbw frag rts @@ -554,7 +555,7 @@ mac80211_hostapd_setup_bss() { } [ "$staidx" -gt 0 -o "$start_disabled" -eq 1 ] && append hostapd_cfg "start_disabled=1" "$N" - cat >> /var/run/hostapd-$phy.conf <> "$hostapd_conf_file" </dev/null 2>&1 + [ -n "$radio" ] && radioflag="radios $radio" + + iw phy "$phy" interface add "$ifname" type "$type" $wdsflag $radioflag >/dev/null 2>&1 rc="$?" [ "$rc" = 233 ] && { # Device might have just been deleted, give the kernel some time to finish cleaning it up sleep 1 - iw phy "$phy" interface add "$ifname" type "$type" $wdsflag >/dev/null 2>&1 + iw phy "$phy" interface add "$ifname" type "$type" $wdsflag $radioflag >/dev/null 2>&1 rc="$?" } @@ -680,7 +694,7 @@ mac80211_iw_interface_add() { [ "$?" = 0 ] && { sleep 1 - iw phy "$phy" interface add "$ifname" type "$type" $wdsflag >/dev/null 2>&1 + iw phy "$phy" interface add "$ifname" type "$type" $wdsflag $radioflag >/dev/null 2>&1 rc="$?" } } @@ -707,7 +721,13 @@ mac80211_prepare_vif() { json_get_vars ifname mode ssid wds powersave macaddr enable wpa_psk_file vlan_file - [ -n "$ifname" ] || ifname="wlan${phy#phy}${if_idx:+-$if_idx}" + [ -n "$ifname" ] || { + if [ -n "$radio" ]; then + ifname="wlan${phy#phy}-${radio}${if_idx:+-$if_idx}" + else + ifname="wlan${phy#phy}${if_idx:+-$if_idx}" + fi + } if_idx=$((${if_idx:-0} + 1)) set_default wds 0 @@ -736,7 +756,7 @@ mac80211_prepare_vif() { # It is far easier to delete and create the desired interface case "$mode" in adhoc) - mac80211_iw_interface_add "$phy" "$ifname" adhoc || return + mac80211_iw_interface_add "$phy" "$ifname" adhoc "" "$radio" || return ;; ap) # Hostapd will handle recreating the interface and @@ -756,16 +776,16 @@ mac80211_prepare_vif() { } ;; mesh) - mac80211_iw_interface_add "$phy" "$ifname" mp || return + mac80211_iw_interface_add "$phy" "$ifname" mp "" "$radio" || return ;; monitor) - mac80211_iw_interface_add "$phy" "$ifname" monitor || return + mac80211_iw_interface_add "$phy" "$ifname" monitor "" "$radio" || return ;; sta) local wdsflag= [ "$enable" = 0 ] || staidx="$(($staidx + 1))" [ "$wds" -gt 0 ] && wdsflag="4addr on" - mac80211_iw_interface_add "$phy" "$ifname" managed "$wdsflag" || return + mac80211_iw_interface_add "$phy" "$ifname" managed "$wdsflag" "$radio" || return if [ "$wds" -gt 0 ]; then iw "$ifname" set 4addr on else @@ -824,13 +844,13 @@ mac80211_setup_supplicant() { [ -z "$spobj" ] && add_sp=1 NEW_MD5_SP=$(test -e "${_config}" && md5sum ${_config}) - OLD_MD5_SP=$(uci -q -P /var/state get wireless._${phy}.md5_${ifname}) + OLD_MD5_SP=$(uci -q -P /var/state get wireless._${state_key}.md5_${ifname}) if [ "$add_sp" = "1" ]; then wpa_supplicant_run "$ifname" "$hostapd_ctrl" else [ "${NEW_MD5_SP}" == "${OLD_MD5_SP}" ] || ubus call $spobj reload fi - uci -q -P /var/state set wireless._${phy}.md5_${ifname}="${NEW_MD5_SP}" + uci -q -P /var/state set wireless._${state_key}.md5_${ifname}="${NEW_MD5_SP}" return 0 } @@ -1069,12 +1089,14 @@ mac80211_vap_cleanup() { mac80211_interface_cleanup() { local phy="$1" - local primary_ap=$(uci -q -P /var/state get wireless._${phy}.aplist) + local state_key="$2" + local state="wireless._${state_key}" + local primary_ap=$(uci -q -P /var/state get ${state}.aplist) primary_ap=${primary_ap%% *} mac80211_vap_cleanup hostapd "${primary_ap}" - mac80211_vap_cleanup wpa_supplicant "$(uci -q -P /var/state get wireless._${phy}.splist)" - mac80211_vap_cleanup none "$(uci -q -P /var/state get wireless._${phy}.umlist)" + mac80211_vap_cleanup wpa_supplicant "$(uci -q -P /var/state get ${state}.splist)" + mac80211_vap_cleanup none "$(uci -q -P /var/state get ${state}.umlist)" } mac80211_set_noscan() { @@ -1088,7 +1110,7 @@ drv_mac80211_cleanup() { drv_mac80211_setup() { json_select config json_get_vars \ - phy macaddr path \ + phy macaddr path radio \ country chanbw distance \ txpower antenna_gain \ rxantenna txantenna \ @@ -1103,30 +1125,35 @@ drv_mac80211_setup() { return 1 } - wireless_set_data phy="$phy" - [ -z "$(uci -q -P /var/state show wireless._${phy})" ] && uci -q -P /var/state set wireless._${phy}=phy + state_key="$(mac80211_get_state_key "$phy" "$radio")" + state="wireless._${state_key}" - OLDAPLIST=$(uci -q -P /var/state get wireless._${phy}.aplist) - OLDSPLIST=$(uci -q -P /var/state get wireless._${phy}.splist) - OLDUMLIST=$(uci -q -P /var/state get wireless._${phy}.umlist) + wireless_set_data phy="$phy" radio="$radio" state_key="$state_key" + [ -z "$(uci -q -P /var/state show ${state})" ] && uci -q -P /var/state set ${state}=phy + + OLDAPLIST=$(uci -q -P /var/state get ${state}.aplist) + OLDSPLIST=$(uci -q -P /var/state get ${state}.splist) + OLDUMLIST=$(uci -q -P /var/state get ${state}.umlist) local wdev local cwdev local found - for wdev in $(list_phy_interfaces "$phy"); do - found=0 - for cwdev in $OLDAPLIST $OLDSPLIST $OLDUMLIST; do - if [ "$wdev" = "$cwdev" ]; then - found=1 - break + [ -n "$radio" ] || { + for wdev in $(list_phy_interfaces "$phy"); do + found=0 + for cwdev in $OLDAPLIST $OLDSPLIST $OLDUMLIST; do + if [ "$wdev" = "$cwdev" ]; then + found=1 + break + fi + done + if [ "$found" = "0" ]; then + ip link set dev "$wdev" down + iw dev "$wdev" del fi done - if [ "$found" = "0" ]; then - ip link set dev "$wdev" down - iw dev "$wdev" del - fi - done + } # convert channel to frequency [ "$auto_channel" -gt 0 ] || freq="$(get_freq "$phy" "$channel" "$band")" @@ -1138,9 +1165,13 @@ drv_mac80211_setup() { } } - hostapd_conf_file="/var/run/hostapd-$phy.conf" + if [ -n "$radio" ]; then + hostapd_conf_file="/var/run/hostapd-${phy}.${radio}.conf" + else + hostapd_conf_file="/var/run/hostapd-${phy}.conf" + fi - macidx=0 + macidx="${radio:-0}" staidx=0 [ -n "$chanbw" ] && { @@ -1186,11 +1217,11 @@ drv_mac80211_setup() { NEWAPLIST= for_each_interface "ap" mac80211_prepare_vif NEW_MD5=$(test -e "${hostapd_conf_file}" && md5sum ${hostapd_conf_file}) - OLD_MD5=$(uci -q -P /var/state get wireless._${phy}.md5) + OLD_MD5=$(uci -q -P /var/state get ${state}.md5) if [ "${NEWAPLIST}" != "${OLDAPLIST}" ]; then mac80211_vap_cleanup hostapd "${OLDAPLIST}" fi - [ -n "${NEWAPLIST}" ] && mac80211_iw_interface_add "$phy" "${NEWAPLIST%% *}" __ap + [ -n "${NEWAPLIST}" ] && mac80211_iw_interface_add "$phy" "${NEWAPLIST%% *}" __ap "" "$radio" local add_ap=0 local primary_ap=${NEWAPLIST%% *} [ -n "$hostapd_ctrl" ] && { @@ -1202,10 +1233,10 @@ drv_mac80211_setup() { no_reload=$? if [ "$no_reload" != "0" ]; then mac80211_vap_cleanup hostapd "${OLDAPLIST}" - mac80211_vap_cleanup wpa_supplicant "$(uci -q -P /var/state get wireless._${phy}.splist)" - mac80211_vap_cleanup none "$(uci -q -P /var/state get wireless._${phy}.umlist)" + mac80211_vap_cleanup wpa_supplicant "$(uci -q -P /var/state get ${state}.splist)" + mac80211_vap_cleanup none "$(uci -q -P /var/state get ${state}.umlist)" sleep 2 - mac80211_iw_interface_add "$phy" "${NEWAPLIST%% *}" __ap + mac80211_iw_interface_add "$phy" "${NEWAPLIST%% *}" __ap "" "$radio" for_each_interface "sta adhoc mesh monitor" mac80211_prepare_vif fi } @@ -1222,8 +1253,8 @@ drv_mac80211_setup() { wireless_add_process "$(jsonfilter -s "$hostapd_res" -l 1 -e @.pid)" "/usr/sbin/hostapd" 1 1 fi } - uci -q -P /var/state set wireless._${phy}.aplist="${NEWAPLIST}" - uci -q -P /var/state set wireless._${phy}.md5="${NEW_MD5}" + uci -q -P /var/state set ${state}.aplist="${NEWAPLIST}" + uci -q -P /var/state set ${state}.md5="${NEW_MD5}" [ "${add_ap}" = 1 ] && sleep 1 for_each_interface "ap" mac80211_setup_vif @@ -1233,8 +1264,8 @@ drv_mac80211_setup() { for_each_interface "sta adhoc mesh monitor" mac80211_setup_vif - uci -q -P /var/state set wireless._${phy}.splist="${NEWSPLIST}" - uci -q -P /var/state set wireless._${phy}.umlist="${NEWUMLIST}" + uci -q -P /var/state set ${state}.splist="${NEWSPLIST}" + uci -q -P /var/state set ${state}.umlist="${NEWUMLIST}" local foundvap local dropvap="" @@ -1269,15 +1300,16 @@ list_phy_interfaces() { drv_mac80211_teardown() { json_select data - json_get_vars phy + json_get_vars phy radio state_key json_select .. [ -n "$phy" ] || { echo "Bug: PHY is undefined for device '$1'" return 1 } - mac80211_interface_cleanup "$phy" - uci -q -P /var/state revert wireless._${phy} + [ -n "$state_key" ] || state_key="$(mac80211_get_state_key "$phy" "$radio")" + mac80211_interface_cleanup "$phy" "$state_key" + uci -q -P /var/state revert wireless._${state_key} } add_driver mac80211 diff --git a/lede/package/kernel/mac80211/files/lib/wifi/mac80211.sh b/lede/package/kernel/mac80211/files/lib/wifi/mac80211.sh index 46ff38f2ef..b9c338927b 100644 --- a/lede/package/kernel/mac80211/files/lib/wifi/mac80211.sh +++ b/lede/package/kernel/mac80211/files/lib/wifi/mac80211.sh @@ -48,91 +48,359 @@ find_mac80211_phy() { } check_mac80211_device() { - config_get phy "$1" phy - [ -z "$phy" ] && { - find_mac80211_phy "$1" >/dev/null || return 0 - config_get phy "$1" phy + local cfg="$1" + local phy path macaddr radio + + [ -n "$check_radio" ] && { + config_get radio "$cfg" radio + [ "$radio" = "$check_radio" ] || return 0 } - [ "$phy" = "$dev" ] && found=1 + + config_get macaddr "$cfg" macaddr + [ -n "$macaddr" ] && [ -n "$check_macaddr" ] && { + macaddr="$(printf '%s' "$macaddr" | tr 'A-Z' 'a-z')" + [ "$macaddr" = "$check_macaddr" ] && { + found=1 + return 0 + } + } + + config_get phy "$cfg" phy + [ "$phy" = "$check_phy" ] && { + found=1 + return 0 + } + + config_get path "$cfg" path + [ -n "$path" ] && [ -n "$check_path" ] && case "$path" in + *"$check_path") + found=1 + return 0 + ;; + esac } +mac80211_board_json_get() { + local expr="$1" -__get_band_defaults() { + [ -s /etc/board.json ] || return 1 + command -v jsonfilter >/dev/null 2>&1 || return 1 + jsonfilter -i /etc/board.json -e "$expr" 2>/dev/null +} + +mac80211_get_defaults() { + local band="$1" + + default_country="$(mac80211_board_json_get '@.wlan.defaults.country')" + default_ssid="$(mac80211_board_json_get "@.wlan.defaults.ssids.${band}.ssid")" + default_encryption="$(mac80211_board_json_get "@.wlan.defaults.ssids.${band}.encryption")" + default_key="$(mac80211_board_json_get "@.wlan.defaults.ssids.${band}.key")" + default_mac_count="$(mac80211_board_json_get "@.wlan.defaults.ssids.${band}.mac_count")" + + [ -n "$default_ssid" ] || default_ssid="$(mac80211_board_json_get '@.wlan.defaults.ssids.all.ssid')" + [ -n "$default_encryption" ] || default_encryption="$(mac80211_board_json_get '@.wlan.defaults.ssids.all.encryption')" + [ -n "$default_key" ] || default_key="$(mac80211_board_json_get '@.wlan.defaults.ssids.all.key')" +} + +__get_band_capabilities() { local phy="$1" - ( iw phy "$phy" info; echo ) | awk ' -BEGIN { - bands = "" + iw phy "$phy" info | awk ' +function band_name(id) { + if (id == 1) return "2g" + if (id == 2) return "5g" + if (id == 3) return "60g" + if (id == 4) return "6g" + return "" } -($1 == "Band" || $1 == "") && band { - if (channel) { - mode="NOHT" - if (ht) mode="HT20" - if (vht && band != "1:") mode="VHT80" - if (he) mode="HE80" - if (he && band == "1:") mode="HE20" - sub("\\[", "", channel) - sub("\\]", "", channel) - bands = bands band channel ":" mode " " - } - band="" +function flush_band() { + if (!cur_band || !channel) + return + + printf "band|%s|%s|%s|%d|%d|%d|%d|%s|%s\n", + cur_band, channel, freq, ht, vht, he, eht, + (htcap ? htcap : "0"), (hephy ? hephy : "00") } $1 == "Band" { - band = $2 - channel = "" - vht = "" - ht = "" - he = "" + flush_band() + + id = $2 + sub(":", "", id) + cur_band = band_name(id + 0) + channel = "" + freq = "" + ht = 0 + vht = 0 + he = 0 + eht = 0 + htcap = "0" + hephy = "00" + next } -$0 ~ "Capabilities:" { - ht=1 +$1 == "Capabilities:" && cur_band { + ht = 1 + htcap = $2 + next } -$0 ~ "VHT Capabilities" { - vht=1 +$1 == "VHT" && $2 == "Capabilities" && cur_band { + vht = 1 + next } -$0 ~ "HE Iftypes" { - he=1 +$1 == "HE" && $2 == "Iftypes:" && cur_band { + he = 1 + next } -$1 == "*" && $3 == "MHz" && $0 !~ /disabled/ && band && !channel { - channel = $4 +$1 == "EHT" && $2 == "Iftypes:" && cur_band { + eht = 1 + next +} + +$1 == "HE" && $2 == "PHY" && $3 == "Capabilities:" && cur_band { + hephy = $0 + sub(/^.*\(0x/, "", hephy) + hephy = substr(hephy, 1, 2) + next +} + +$1 == "*" && $3 == "MHz" && cur_band && $0 !~ /disabled/ && !channel { + channel = $4 + gsub(/\[|\]/, "", channel) + freq = $2 + sub(/\..*$/, "", freq) + next } END { - print bands + flush_band() }' } -get_band_defaults() { +__get_band_channels() { local phy="$1" - for c in $(__get_band_defaults "$phy"); do - local band="${c%%:*}" - c="${c#*:}" - local chan="${c%%:*}" - c="${c#*:}" - local mode="${c%%:*}" + iw phy "$phy" info | awk ' +function band_name(id) { + if (id == 1) return "2g" + if (id == 2) return "5g" + if (id == 3) return "60g" + if (id == 4) return "6g" + return "" +} - case "$band" in - 1) band=2g;; - 2) band=5g;; - 3) band=60g;; - 4) band=6g;; - *) band="";; - esac +$1 == "Band" { + id = $2 + sub(":", "", id) + cur_band = band_name(id + 0) + next +} - [ -n "$band" ] || continue - [ -n "$mode_band" -a "$band" = "6g" ] && return +$1 == "*" && $3 == "MHz" && cur_band && $0 !~ /disabled/ { + channel = $4 + gsub(/\[|\]/, "", channel) + freq = $2 + sub(/\..*$/, "", freq) + printf "freq|%s|%s|%s\n", cur_band, channel, freq +}' +} - mode_band="$band" - channel="$chan" - htmode="$mode" +__get_radio_ranges() { + local phy="$1" + + iw phy "$phy" info | awk ' +$1 == "wiphy" && $2 == "radio" { + radio = $3 + sub(":", "", radio) + next +} + +$1 == "freq" && $2 == "range:" && radio != "" { + start = $3 + end = $6 + sub(/\..*$/, "", start) + sub(/\..*$/, "", end) + printf "radio|%s|%s|%s\n", radio, start, end +}' +} + +mac80211_get_band_width() { + local band="$1" + local vht="$2" + local htcap="$3" + local hephy="$4" + local htcap_mask=0 + local hephy_mask=0 + + [ "$band" = "2g" ] && { + echo 20 + return + } + + htcap_mask=$((htcap)) + hephy_mask=$((0x${hephy:-00})) + + if [ "$vht" = "1" ] || [ $((hephy_mask & 0x1c)) -gt 0 ]; then + echo 80 + elif [ $((htcap_mask & 0x2)) -gt 0 ] || [ $((hephy_mask & 0x2)) -gt 0 ]; then + echo 40 + else + echo 20 + fi +} + +mac80211_get_band_htmode() { + local band="$1" + local width="$2" + local ht="$3" + local vht="$4" + local he="$5" + local eht="$6" + local prefix="NOHT" + + [ "$ht" = "1" ] && prefix="HT" + [ "$vht" = "1" ] && [ "$band" != "2g" ] && prefix="VHT" + [ "$he" = "1" ] && prefix="HE" + [ "$eht" = "1" ] && prefix="EHT" + + [ "$prefix" = "NOHT" ] && { + echo "$prefix" + return + } + + echo "${prefix}${width}" +} + +mac80211_get_preferred_band() { + local band + + for band in 6g 5g 2g 60g; do + eval "[ -n \"\${band_${band}_channel}\" ]" && { + echo "$band" + return + } done + + for band in $band_list; do + echo "$band" + return + done +} + +mac80211_get_radio_list() { + local list="" kind radio start end + + while IFS='|' read -r kind radio start end; do + [ "$kind" = "radio" ] || continue + case " $list " in + *" $radio "*) ;; + *) list="$list $radio" ;; + esac + done <<-EOF + $radio_ranges + EOF + + echo "${list# }" +} + +mac80211_find_radio_band_channel() { + local radio="$1" + local band="$2" + local kind cur_radio start end cur_band channel freq + + while IFS='|' read -r kind cur_radio start end; do + [ "$kind" = "radio" ] || continue + [ "$cur_radio" = "$radio" ] || continue + + while IFS='|' read -r kind cur_band channel freq; do + [ "$kind" = "freq" ] || continue + [ "$cur_band" = "$band" ] || continue + [ "$freq" -ge "$start" ] && [ "$freq" -le "$end" ] && { + echo "$channel" + return + } + done <<-EOF_INNER + $band_channels + EOF_INNER + done <<-EOF + $radio_ranges + EOF +} + +mac80211_emit_detect() { + local dev="$1" + local path="$2" + local band="$3" + local channel="$4" + local htmode="$5" + local radio="$6" + local country encryption ssid key num_global_macaddr + local section="radio${devidx}" + local iface="default_radio${devidx}" + local dev_id + + mac80211_get_defaults "$band" + + country="$default_country" + encryption="$default_encryption" + ssid="$default_ssid" + key="$default_key" + num_global_macaddr="$default_mac_count" + + [ -n "$ssid" ] || ssid="LEDE" + [ -n "$country" ] || country="US" + + case "$band" in + 6g) + [ -n "$default_country" ] || country="00" + [ -n "$encryption" ] || encryption="owe" + ;; + *) + [ -n "$encryption" ] || encryption="none" + ;; + esac + + case "$dev" in + phy[0-9]*) + if [ -n "$path" ]; then + dev_id="set wireless.${section}.path='${path}'" + else + dev_id="set wireless.${section}.phy='${dev}'" + fi + ;; + *) + dev_id="set wireless.${section}.phy='${dev}'" + ;; + esac + + [ -n "$radio" ] && dev_id="${dev_id} + set wireless.${section}.radio='${radio}'" + + uci -q batch <<-EOF + set wireless.${section}=wifi-device + set wireless.${section}.type='mac80211' + ${dev_id} + set wireless.${section}.band='${band}' + set wireless.${section}.channel='${channel}' + set wireless.${section}.htmode='${htmode}' + set wireless.${section}.country='${country}' + set wireless.${section}.num_global_macaddr='${num_global_macaddr}' + set wireless.${section}.disabled='0' + + set wireless.${iface}=wifi-iface + set wireless.${iface}.device='${section}' + set wireless.${iface}.network='lan' + set wireless.${iface}.mode='ap' + set wireless.${iface}.ssid='${ssid}' + set wireless.${iface}.encryption='${encryption}' + set wireless.${iface}.key='${key}' + set wireless.${iface}.disabled='0' + EOF + uci -q commit wireless } detect_mac80211() { @@ -148,43 +416,75 @@ detect_mac80211() { [ -e "$_dev" ] || continue dev="${_dev##*/}" + path="$(iwinfo nl80211 path "$dev")" + check_macaddr="$(cat /sys/class/ieee80211/${dev}/macaddress)" + + band_list="" + band_caps="$(__get_band_capabilities "$dev")" + band_channels="$(__get_band_channels "$dev")" + radio_ranges="$(__get_radio_ranges "$dev")" + + while IFS='|' read -r kind band chan freq ht vht he eht htcap hephy; do + local width mode + + [ "$kind" = "band" ] || continue + width="$(mac80211_get_band_width "$band" "$vht" "$htcap" "$hephy")" + mode="$(mac80211_get_band_htmode "$band" "$width" "$ht" "$vht" "$he" "$eht")" + + append band_list "$band" + eval "band_${band}_channel='$chan'" + eval "band_${band}_htmode='$mode'" + done <<-EOF + $band_caps + EOF + + [ -n "$band_list" ] || continue + + radios="$(mac80211_get_radio_list)" + if [ -n "$radios" ]; then + for radio in $radios; do + selected_band="" + selected_channel="" + selected_htmode="" + + for candidate_band in 6g 5g 2g 60g; do + selected_channel="$(mac80211_find_radio_band_channel "$radio" "$candidate_band")" + [ -n "$selected_channel" ] || continue + + selected_band="$candidate_band" + eval "selected_htmode=\"\${band_${candidate_band}_htmode}\"" + break + done + + [ -n "$selected_band" ] || continue + + found=0 + check_phy="$dev" + check_path="$path" + check_radio="$radio" + config_foreach check_mac80211_device wifi-device + [ "$found" -gt 0 ] && continue + + mac80211_emit_detect "$dev" "$path" "$selected_band" "$selected_channel" "$selected_htmode" "$radio" + devidx=$(($devidx + 1)) + done + continue + fi found=0 + check_phy="$dev" + check_path="$path" + check_radio="" config_foreach check_mac80211_device wifi-device [ "$found" -gt 0 ] && continue - mode_band="" - channel="" - htmode="" - ht_capab="" + selected_band="$(mac80211_get_preferred_band)" + [ -n "$selected_band" ] || continue - get_band_defaults "$dev" + eval "selected_channel=\"\${band_${selected_band}_channel}\"" + eval "selected_htmode=\"\${band_${selected_band}_htmode}\"" - path="$(iwinfo nl80211 path "$dev")" - if [ -n "$path" ]; then - dev_id="set wireless.radio${devidx}.path='$path'" - else - dev_id="set wireless.radio${devidx}.macaddr=$(cat /sys/class/ieee80211/${dev}/macaddress)" - fi - - uci -q batch <<-EOF - set wireless.radio${devidx}=wifi-device - set wireless.radio${devidx}.type=mac80211 - ${dev_id} - set wireless.radio${devidx}.channel=${channel} - set wireless.radio${devidx}.band=${mode_band} - set wireless.radio${devidx}.htmode=$htmode - set wireless.radio${devidx}.disabled=0 - set wireless.radio${devidx}.country=US - - set wireless.default_radio${devidx}=wifi-iface - set wireless.default_radio${devidx}.device=radio${devidx} - set wireless.default_radio${devidx}.network=lan - set wireless.default_radio${devidx}.mode=ap - set wireless.default_radio${devidx}.ssid=LEDE - set wireless.default_radio${devidx}.encryption=none -EOF - uci -q commit wireless + mac80211_emit_detect "$dev" "$path" "$selected_band" "$selected_channel" "$selected_htmode" devidx=$(($devidx + 1)) done diff --git a/lede/tools/erofs-utils/Makefile b/lede/tools/erofs-utils/Makefile index 1fbe491a4a..32a9fff06d 100644 --- a/lede/tools/erofs-utils/Makefile +++ b/lede/tools/erofs-utils/Makefile @@ -7,17 +7,21 @@ include $(TOPDIR)/rules.mk PKG_NAME:=erofs-utils -PKG_VERSION:=1.8.10 -PKG_RELEASE:=1 +PKG_VERSION:=1.9.1 +PKG_RELEASE:=2 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL=https://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git/snapshot/ -PKG_HASH:=05eb4edebe11decce6ecb34e98d2f80c8cd283c2f2967d8ba7efd58418570514 +PKG_HASH:=a9ef5ab67c4b8d2d3e9ed71f39cd008bda653142a720d8a395a36f1110d0c432 +PKG_CPE_ID:=cpe:/a:erofs-utils_project:erofs-utils PKG_FIXUP:=autoreconf include $(INCLUDE_DIR)/host-build.mk +HOST_CONFIGURE_VARS += \ + LIBS="-llzma -luuid" + HOST_CONFIGURE_ARGS=\ --enable-multithreading \ --enable-lzma \ diff --git a/lede/tools/util-linux/Makefile b/lede/tools/util-linux/Makefile index fd90f31b5f..c91bf0d492 100644 --- a/lede/tools/util-linux/Makefile +++ b/lede/tools/util-linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2006-2015 OpenWrt.org +# Copyright (C) 2006-2025 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. @@ -7,49 +7,22 @@ include $(TOPDIR)/rules.mk PKG_NAME:=util-linux -PKG_VERSION:=2.41.1 +PKG_VERSION:=2.41.3 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=@KERNEL/linux/utils/$(PKG_NAME)/v2.41 -PKG_HASH:=be9ad9a276f4305ab7dd2f5225c8be1ff54352f565ff4dede9628c1aaa7dec57 +PKG_HASH:=3330d873f0fceb5560b89a7dc14e4f3288bbd880e96903ed9b50ec2b5799e58b PKG_CPE_ID:=cpe:/a:kernel:util-linux -PKG_FIXUP:=autoreconf - -HOST_BUILD_PARALLEL:=1 - include $(INCLUDE_DIR)/host-build.mk +include $(INCLUDE_DIR)/meson.mk -HOST_CONFIGURE_ARGS += \ - --with-pic \ - --disable-shared \ - --disable-nls \ - --disable-all-programs \ - --enable-hexdump \ - --enable-libuuid \ - --without-util \ - --without-selinux \ - --without-audit \ - --without-udev \ - --without-ncursesw \ - --without-ncurses \ - --without-slang \ - --without-tinfo \ - --without-readline \ - --without-utempter \ - --without-cap-ng \ - --without-libz \ - --without-libmagic \ - --without-user \ - --without-btrfs \ - --without-systemd \ - --without-smack \ - --without-econf \ - --without-python \ - --without-cryptsetup - -define Host/Uninstall - -$(call Host/Compile/Default,uninstall) -endef +MESON_HOST_ARGS += \ + $(if $(findstring y,$(YEAR_2038)),,-Dallow-32bit-time=true) \ + -Dauto_features=disabled \ + -Dbuild-hexdump=enabled \ + -Dbuild-libuuid=enabled \ + -Dncurses=enabled \ + -Dprogram-tests=false $(eval $(call HostBuild)) diff --git a/lede/tools/util-linux/patches/010-meson-curses.patch b/lede/tools/util-linux/patches/010-meson-curses.patch new file mode 100644 index 0000000000..9a5c72eace --- /dev/null +++ b/lede/tools/util-linux/patches/010-meson-curses.patch @@ -0,0 +1,24 @@ +From c1ca5ec4a5c6a0e4acbdcc6ff4e4fa2109c1ec24 Mon Sep 17 00:00:00 2001 +From: Rosen Penev +Date: Wed, 30 Jul 2025 14:13:07 -0700 +Subject: [PATCH] meson: use curses for the non wide version + +The curses dependency in meson in special in that it uses a combination +of pkg-config, config-tool, and various system lookups to find it. + +Signed-off-by: Rosen Penev +--- + meson.build | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/meson.build ++++ b/meson.build +@@ -289,7 +289,7 @@ if lib_ncursesw.found() + lib_ncurses = disabler() + else + lib_ncurses = dependency( +- 'ncurses', ++ 'curses', + disabler : true, + required : get_option('ncurses')) + headers += ['ncurses.h', diff --git a/lede/tools/util-linux/patches/102-macos-uuid-next.patch b/lede/tools/util-linux/patches/102-macos-uuid-next.patch new file mode 100644 index 0000000000..204c616492 --- /dev/null +++ b/lede/tools/util-linux/patches/102-macos-uuid-next.patch @@ -0,0 +1,13 @@ +--- a/libuuid/src/uuid.h ++++ b/libuuid/src/uuid.h +@@ -35,6 +35,10 @@ + #ifndef _UL_LIBUUID_UUID_H + #define _UL_LIBUUID_UUID_H + ++#if defined(__clang__) && defined(__APPLE__) ++#include_next ++#endif ++ + #include + #ifndef _WIN32 + #include diff --git a/lede/tools/xz/Makefile b/lede/tools/xz/Makefile index a90cec86bf..98681b56c6 100644 --- a/lede/tools/xz/Makefile +++ b/lede/tools/xz/Makefile @@ -7,12 +7,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=xz -PKG_VERSION:=5.4.6 +PKG_VERSION:=5.8.3 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 -PKG_SOURCE_URL:=@SF/lzmautils \ - http://tukaani.org/xz -PKG_HASH:=913851b274e8e1d31781ec949f1c23e8dbcf0ecf6e73a2436dc21769dd3e6f49 +PKG_SOURCE_URL:=https://github.com/tukaani-project/xz/releases/download/v$(PKG_VERSION) \ + @SF/lzmautils \ + http://tukaani.org/xz +PKG_HASH:=33bf69c0d6c698e83a68f77e6c1f465778e418ca0b3d59860d3ab446f4ac99a6 PKG_CPE_ID:=cpe:/a:tukaani:xz HOST_BUILD_PARALLEL:=1 diff --git a/mihomo/adapter/outbound/vless.go b/mihomo/adapter/outbound/vless.go index 2c71ebb1e4..5050d758ff 100644 --- a/mihomo/adapter/outbound/vless.go +++ b/mihomo/adapter/outbound/vless.go @@ -6,6 +6,7 @@ import ( "fmt" "net" "strconv" + "time" "github.com/metacubex/mihomo/common/convert" N "github.com/metacubex/mihomo/common/net" @@ -21,6 +22,7 @@ import ( "github.com/metacubex/mihomo/transport/xhttp" "github.com/metacubex/http" + "github.com/metacubex/quic-go" vmessSing "github.com/metacubex/sing-vmess" "github.com/metacubex/sing-vmess/packetaddr" M "github.com/metacubex/sing/common/metadata" @@ -88,11 +90,12 @@ type XHTTPOptions struct { } type XHTTPReuseSettings struct { - MaxConnections string `proxy:"max-connections,omitempty"` MaxConcurrency string `proxy:"max-concurrency,omitempty"` + MaxConnections string `proxy:"max-connections,omitempty"` CMaxReuseTimes string `proxy:"c-max-reuse-times,omitempty"` HMaxRequestTimes string `proxy:"h-max-request-times,omitempty"` HMaxReusableSecs string `proxy:"h-max-reusable-secs,omitempty"` + HKeepAlivePeriod int `proxy:"h-keep-alive-period,omitempty"` } type XHTTPDownloadSettings struct { @@ -525,15 +528,18 @@ func NewVless(option VlessOption) (*Vless, error) { } } + var hKeepAlivePeriod time.Duration + var reuseCfg *xhttp.ReuseConfig if option.XHTTPOpts.ReuseSettings != nil { reuseCfg = &xhttp.ReuseConfig{ - MaxConnections: option.XHTTPOpts.ReuseSettings.MaxConnections, MaxConcurrency: option.XHTTPOpts.ReuseSettings.MaxConcurrency, + MaxConnections: option.XHTTPOpts.ReuseSettings.MaxConnections, CMaxReuseTimes: option.XHTTPOpts.ReuseSettings.CMaxReuseTimes, HMaxRequestTimes: option.XHTTPOpts.ReuseSettings.HMaxRequestTimes, HMaxReusableSecs: option.XHTTPOpts.ReuseSettings.HMaxReusableSecs, } + hKeepAlivePeriod = time.Duration(option.XHTTPOpts.ReuseSettings.HKeepAlivePeriod) * time.Second } cfg := &xhttp.Config{ @@ -555,7 +561,54 @@ func NewVless(option VlessOption) (*Vless, error) { func(ctx context.Context, raw net.Conn, isH2 bool) (net.Conn, error) { return v.streamTLSConn(ctx, raw, isH2) }, + func(ctx context.Context, cfg *quic.Config) (*quic.Conn, error) { + host, _, _ := net.SplitHostPort(v.addr) + tlsOpts := &vmess.TLSConfig{ + Host: host, + SkipCertVerify: v.option.SkipCertVerify, + FingerPrint: v.option.Fingerprint, + Certificate: v.option.Certificate, + PrivateKey: v.option.PrivateKey, + ClientFingerprint: v.option.ClientFingerprint, + ECH: v.echConfig, + Reality: v.realityConfig, + NextProtos: []string{"h3"}, + } + if v.option.ServerName != "" { + tlsOpts.Host = v.option.ServerName + } + if !v.option.TLS { + return nil, errors.New("xhttp HTTP/3 requires TLS") + } + if v.realityConfig != nil { + return nil, errors.New("xhttp HTTP/3 does not support reality") + } + tlsConfig, err := tlsOpts.ToStdConfig() + if err != nil { + return nil, err + } + + udpAddr, err := resolveUDPAddr(ctx, "udp", v.addr, v.prefer) + if err != nil { + return nil, err + } + err = v.echConfig.ClientHandle(ctx, tlsConfig) + if err != nil { + return nil, err + } + packetConn, err := v.dialer.ListenPacket(ctx, "udp", "", udpAddr.AddrPort()) + if err != nil { + return nil, err + } + quicConn, err := quic.DialEarly(ctx, packetConn, udpAddr, tlsConfig, cfg) + if err != nil { + _ = packetConn.Close() + return nil, err + } + return quicConn, nil + }, v.option.ALPN, + hKeepAlivePeriod, ) } var makeDownloadTransport func() http.RoundTripper @@ -601,15 +654,18 @@ func NewVless(option VlessOption) (*Vless, error) { } } + downloadHKeepAlivePeriod := hKeepAlivePeriod + downloadReuseCfg := reuseCfg if ds.ReuseSettings != nil { downloadReuseCfg = &xhttp.ReuseConfig{ - MaxConnections: ds.ReuseSettings.MaxConnections, MaxConcurrency: ds.ReuseSettings.MaxConcurrency, + MaxConnections: ds.ReuseSettings.MaxConnections, CMaxReuseTimes: ds.ReuseSettings.CMaxReuseTimes, HMaxRequestTimes: ds.ReuseSettings.HMaxRequestTimes, HMaxReusableSecs: ds.ReuseSettings.HMaxReusableSecs, } + downloadHKeepAlivePeriod = time.Duration(ds.ReuseSettings.HKeepAlivePeriod) * time.Second } cfg.DownloadConfig = &xhttp.Config{ @@ -657,7 +713,54 @@ func NewVless(option VlessOption) (*Vless, error) { return conn, nil }, + func(ctx context.Context, cfg *quic.Config) (*quic.Conn, error) { + host, _, _ := net.SplitHostPort(downloadAddr) + tlsOpts := &vmess.TLSConfig{ + Host: host, + SkipCertVerify: downloadSkipCertVerify, + FingerPrint: downloadFingerprint, + Certificate: downloadCertificate, + PrivateKey: downloadPrivateKey, + ClientFingerprint: downloadClientFingerprint, + ECH: downloadEchConfig, + Reality: downloadRealityCfg, + NextProtos: []string{"h3"}, + } + if downloadServerName != "" { + tlsOpts.Host = downloadServerName + } + if !downloadTLS { + return nil, errors.New("xhttp HTTP/3 requires TLS") + } + if downloadRealityCfg != nil { + return nil, errors.New("xhttp HTTP/3 does not support reality") + } + tlsConfig, err := tlsOpts.ToStdConfig() + if err != nil { + return nil, err + } + + udpAddr, err := resolveUDPAddr(ctx, "udp", downloadAddr, v.prefer) + if err != nil { + return nil, err + } + err = downloadEchConfig.ClientHandle(ctx, tlsConfig) + if err != nil { + return nil, err + } + packetConn, err := v.dialer.ListenPacket(ctx, "udp", "", udpAddr.AddrPort()) + if err != nil { + return nil, err + } + quicConn, err := quic.DialEarly(ctx, packetConn, udpAddr, tlsConfig, cfg) + if err != nil { + _ = packetConn.Close() + return nil, err + } + return quicConn, nil + }, downloadALPN, + downloadHKeepAlivePeriod, ) } } diff --git a/mihomo/docs/config.yaml b/mihomo/docs/config.yaml index d861eed241..fc9ebac649 100644 --- a/mihomo/docs/config.yaml +++ b/mihomo/docs/config.yaml @@ -807,8 +807,7 @@ proxies: # socks5 udp: true tls: true network: xhttp - alpn: - - h2 + alpn: [h2] # 默认仅支持h2,如果开启h3模式需要设置alpn: [h3],如果开启http1.1模式需要设置alpn: [http/1.1] # ech-opts: ... # reality-opts: ... # skip-cert-verify: false @@ -828,11 +827,12 @@ proxies: # socks5 # x-padding-bytes: "100-1000" # sc-max-each-post-bytes: 1000000 # reuse-settings: # aka XMUX - # max-connections: "16-32" - # max-concurrency: "0" + # max-concurrency: "16-32" + # max-connections: "0" # c-max-reuse-times: "0" # h-max-request-times: "600-900" # h-max-reusable-secs: "1800-3000" + # h-keep-alive-period: 0 # download-settings: # ## xhttp part # path: "/" @@ -843,17 +843,17 @@ proxies: # socks5 # x-padding-bytes: "100-1000" # sc-max-each-post-bytes: 1000000 # reuse-settings: # aka XMUX - # max-connections: "16-32" - # max-concurrency: "0" + # max-concurrency: "16-32" + # max-connections: "0" # c-max-reuse-times: "0" # h-max-request-times: "600-900" # h-max-reusable-secs: "1800-3000" + # h-keep-alive-period: 0 # ## proxy part # server: server # port: 443 # tls: true - # alpn: - # - h2 + # alpn: ... # ech-opts: ... # reality-opts: ... # skip-cert-verify: false diff --git a/mihomo/listener/inbound/vless_test.go b/mihomo/listener/inbound/vless_test.go index 6e0fbda204..a3e707a5c6 100644 --- a/mihomo/listener/inbound/vless_test.go +++ b/mihomo/listener/inbound/vless_test.go @@ -488,6 +488,42 @@ func TestInboundVless_XHTTP_Reality(t *testing.T) { } } +func TestInboundVless_XHTTP_PacketUp_H1(t *testing.T) { + getConfig := func() (inbound.VlessOption, outbound.VlessOption) { + inboundOptions := inbound.VlessOption{ + Certificate: tlsCertificate, + PrivateKey: tlsPrivateKey, + XHTTPConfig: inbound.XHTTPConfig{ + Path: "/vless-xhttp", + Host: "example.com", + Mode: "packet-up", + }, + } + outboundOptions := outbound.VlessOption{ + TLS: true, + Fingerprint: tlsFingerprint, + Network: "xhttp", + ALPN: []string{"http/1.1"}, + XHTTPOpts: outbound.XHTTPOptions{ + Path: "/vless-xhttp", + Host: "example.com", + Mode: "packet-up", + }, + } + return inboundOptions, outboundOptions + } + + t.Run("default", func(t *testing.T) { + inboundOptions, outboundOptions := getConfig() + testInboundVlessTLS(t, inboundOptions, outboundOptions, false) + }) + + t.Run("reuse", func(t *testing.T) { + inboundOptions, outboundOptions := getConfig() + testInboundVlessTLS(t, inboundOptions, withXHTTPReuse(outboundOptions), false) + }) +} + func withXHTTPReuse(out outbound.VlessOption) outbound.VlessOption { out.XHTTPOpts.ReuseSettings = &outbound.XHTTPReuseSettings{ MaxConnections: "0", diff --git a/mihomo/transport/xhttp/client.go b/mihomo/transport/xhttp/client.go index 39d0daa700..ae56970d96 100644 --- a/mihomo/transport/xhttp/client.go +++ b/mihomo/transport/xhttp/client.go @@ -11,15 +11,30 @@ import ( "net/url" "strconv" "sync" + "time" "github.com/metacubex/mihomo/common/httputils" "github.com/metacubex/http" + "github.com/metacubex/quic-go" + "github.com/metacubex/quic-go/http3" "github.com/metacubex/tls" + "golang.org/x/sync/semaphore" ) +// ConnIdleTimeout defines the maximum time an idle TCP session can survive in the tunnel, +// so it should be consistent across HTTP versions and with other transports. +const ConnIdleTimeout = 300 * time.Second + +// QuicgoH3KeepAlivePeriod consistent with quic-go +const QuicgoH3KeepAlivePeriod = 10 * time.Second + +// ChromeH2KeepAlivePeriod consistent with chrome +const ChromeH2KeepAlivePeriod = 45 * time.Second + type DialRawFunc func(ctx context.Context) (net.Conn, error) type WrapTLSFunc func(ctx context.Context, conn net.Conn, isH2 bool) (net.Conn, error) +type DialQUICFunc func(ctx context.Context, cfg *quic.Config) (*quic.Conn, error) type TransportMaker func() http.RoundTripper @@ -96,7 +111,56 @@ func (c *PacketUpWriter) Close() error { return nil } -func NewTransport(dialRaw DialRawFunc, wrapTLS WrapTLSFunc, alpn []string) http.RoundTripper { +func NewTransport(dialRaw DialRawFunc, wrapTLS WrapTLSFunc, dialQUIC DialQUICFunc, alpn []string, keepAlivePeriod time.Duration) http.RoundTripper { + if len(alpn) == 1 && alpn[0] == "h3" { // `alpn: [h3]` means using h3 mode + if keepAlivePeriod == 0 { + keepAlivePeriod = QuicgoH3KeepAlivePeriod + } + if keepAlivePeriod < 0 { + keepAlivePeriod = 0 + } + return &http3.Transport{ + QUICConfig: &quic.Config{ + MaxIncomingStreams: -1, // don't allow the server to create bidirectional streams + KeepAlivePeriod: keepAlivePeriod, + MaxIdleTimeout: ConnIdleTimeout, + }, + Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (*quic.Conn, error) { + return dialQUIC(ctx, cfg) + }, + } + } + if len(alpn) == 1 && alpn[0] == "http/1.1" { // `alpn: [http/1.1]` means using http/1.1 mode + w := semaphore.NewWeighted(20) // limit concurrent dialing to avoid WSAECONNREFUSED on Windows + dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) { + if err := w.Acquire(ctx, 1); err != nil { + return nil, err + } + defer w.Release(1) + raw, err := dialRaw(ctx) + if err != nil { + return nil, err + } + wrapped, err := wrapTLS(ctx, raw, false) + if err != nil { + _ = raw.Close() + return nil, err + } + return wrapped, nil + } + return &http.Transport{ + DialContext: dialContext, + DialTLSContext: dialContext, + IdleConnTimeout: ConnIdleTimeout, + ForceAttemptHTTP2: false, // only http/1.1 + } + } + if keepAlivePeriod == 0 { + keepAlivePeriod = ChromeH2KeepAlivePeriod + } + if keepAlivePeriod < 0 { + keepAlivePeriod = 0 + } return &http.Http2Transport{ DialTLSContext: func(ctx context.Context, network, addr string, _ *tls.Config) (net.Conn, error) { raw, err := dialRaw(ctx) @@ -110,6 +174,8 @@ func NewTransport(dialRaw DialRawFunc, wrapTLS WrapTLSFunc, alpn []string) http. } return wrapped, nil }, + IdleConnTimeout: ConnIdleTimeout, + ReadIdleTimeout: keepAlivePeriod, } } diff --git a/mihomo/transport/xhttp/config.go b/mihomo/transport/xhttp/config.go index f28470723b..e02529d94a 100644 --- a/mihomo/transport/xhttp/config.go +++ b/mihomo/transport/xhttp/config.go @@ -26,8 +26,8 @@ type Config struct { } type ReuseConfig struct { - MaxConnections string MaxConcurrency string + MaxConnections string CMaxReuseTimes string HMaxRequestTimes string HMaxReusableSecs string @@ -171,17 +171,17 @@ func (c *ReuseConfig) ResolveManagerConfig() (Range, Range, error) { return Range{}, Range{}, nil } - maxConnections, err := ParseRange(c.MaxConnections, "0") - if err != nil { - return Range{}, Range{}, fmt.Errorf("invalid max-connections: %w", err) - } - maxConcurrency, err := ParseRange(c.MaxConcurrency, "0") if err != nil { return Range{}, Range{}, fmt.Errorf("invalid max-concurrency: %w", err) } - return maxConnections, maxConcurrency, nil + maxConnections, err := ParseRange(c.MaxConnections, "0") + if err != nil { + return Range{}, Range{}, fmt.Errorf("invalid max-connections: %w", err) + } + + return maxConcurrency, maxConnections, nil } func (c *ReuseConfig) ResolveEntryConfig() (Range, Range, Range, error) { @@ -189,6 +189,11 @@ func (c *ReuseConfig) ResolveEntryConfig() (Range, Range, Range, error) { return Range{}, Range{}, Range{}, nil } + cMaxReuseTimes, err := ParseRange(c.CMaxReuseTimes, "0") + if err != nil { + return Range{}, Range{}, Range{}, fmt.Errorf("invalid c-max-reuse-times: %w", err) + } + hMaxRequestTimes, err := ParseRange(c.HMaxRequestTimes, "0") if err != nil { return Range{}, Range{}, Range{}, fmt.Errorf("invalid h-max-request-times: %w", err) @@ -199,12 +204,7 @@ func (c *ReuseConfig) ResolveEntryConfig() (Range, Range, Range, error) { return Range{}, Range{}, Range{}, fmt.Errorf("invalid h-max-reusable-secs: %w", err) } - cMaxReuseTimes, err := ParseRange(c.CMaxReuseTimes, "0") - if err != nil { - return Range{}, Range{}, Range{}, fmt.Errorf("invalid c-max-reuse-times: %w", err) - } - - return hMaxRequestTimes, hMaxReusableSecs, cMaxReuseTimes, nil + return cMaxReuseTimes, hMaxRequestTimes, hMaxReusableSecs, nil } func (c *Config) FillStreamRequest(req *http.Request, sessionID string) error { diff --git a/mihomo/transport/xhttp/reuse.go b/mihomo/transport/xhttp/reuse.go index 006056cd0c..83e4787bf6 100644 --- a/mihomo/transport/xhttp/reuse.go +++ b/mihomo/transport/xhttp/reuse.go @@ -55,11 +55,11 @@ func (rt *ReuseTransport) Close() error { var _ http.RoundTripper = (*ReuseTransport)(nil) type ReuseManager struct { - maxConnections int maxConcurrency int + maxConnections int + cMaxReuseTimes Range hMaxRequestTimes Range hMaxReusableSecs Range - cMaxReuseTimes Range maker TransportMaker mu sync.Mutex entries []*reuseEntry @@ -69,20 +69,20 @@ func NewReuseManager(cfg *ReuseConfig, makeTransport TransportMaker) (*ReuseMana if cfg == nil { return nil, nil } - connections, concurrency, err := cfg.ResolveManagerConfig() + concurrency, connections, err := cfg.ResolveManagerConfig() if err != nil { return nil, err } - hMaxRequestTimes, hMaxReusableSecs, cMaxReuseTimes, err := cfg.ResolveEntryConfig() + cMaxReuseTimes, hMaxRequestTimes, hMaxReusableSecs, err := cfg.ResolveEntryConfig() if err != nil { return nil, err } return &ReuseManager{ - maxConnections: connections.Rand(), maxConcurrency: concurrency.Rand(), + maxConnections: connections.Rand(), + cMaxReuseTimes: cMaxReuseTimes, hMaxRequestTimes: hMaxRequestTimes, hMaxReusableSecs: hMaxReusableSecs, - cMaxReuseTimes: cMaxReuseTimes, maker: makeTransport, entries: make([]*reuseEntry, 0), }, nil diff --git a/mihomo/transport/xhttp/reuse_test.go b/mihomo/transport/xhttp/reuse_test.go index b20320a946..1e676ee627 100644 --- a/mihomo/transport/xhttp/reuse_test.go +++ b/mihomo/transport/xhttp/reuse_test.go @@ -31,8 +31,8 @@ func TestManagerReuseSameEntry(t *testing.T) { var created atomic.Int64 manager, err := NewReuseManager(&ReuseConfig{ - MaxConnections: "1", MaxConcurrency: "1", + MaxConnections: "1", HMaxRequestTimes: "10", }, makeTestTransportFactory(&created)) if err != nil { @@ -65,8 +65,8 @@ func TestManagerRespectMaxConnections(t *testing.T) { var created atomic.Int64 manager, err := NewReuseManager(&ReuseConfig{ - MaxConnections: "2", MaxConcurrency: "1", + MaxConnections: "2", HMaxRequestTimes: "100", }, makeTestTransportFactory(&created)) if err != nil { @@ -110,8 +110,8 @@ func TestManagerRotateOnRequestLimit(t *testing.T) { var created atomic.Int64 manager, err := NewReuseManager(&ReuseConfig{ - MaxConnections: "1", MaxConcurrency: "1", + MaxConnections: "1", HMaxRequestTimes: "1", }, makeTestTransportFactory(&created)) if err != nil { @@ -144,8 +144,8 @@ func TestManagerRotateOnReusableSecs(t *testing.T) { var created atomic.Int64 manager, err := NewReuseManager(&ReuseConfig{ - MaxConnections: "1", MaxConcurrency: "1", + MaxConnections: "1", HMaxRequestTimes: "100", HMaxReusableSecs: "1", }, makeTestTransportFactory(&created)) @@ -180,8 +180,8 @@ func TestManagerRotateOnConnReuseLimit(t *testing.T) { var created atomic.Int64 manager, err := NewReuseManager(&ReuseConfig{ - MaxConnections: "1", MaxConcurrency: "1", + MaxConnections: "1", CMaxReuseTimes: "1", HMaxRequestTimes: "100", }, makeTestTransportFactory(&created)) diff --git a/mihomo/transport/xhttp/server.go b/mihomo/transport/xhttp/server.go index 4c68174a44..2f32bb31f5 100644 --- a/mihomo/transport/xhttp/server.go +++ b/mihomo/transport/xhttp/server.go @@ -75,7 +75,7 @@ func (c *httpServerConn) Wait() <-chan struct{} { } type httpSession struct { - uploadQueue *uploadQueue + uploadQueue *UploadQueue connected chan struct{} once sync.Once } diff --git a/mihomo/transport/xhttp/upload_queue.go b/mihomo/transport/xhttp/upload_queue.go index 3a5339627f..731f85bd98 100644 --- a/mihomo/transport/xhttp/upload_queue.go +++ b/mihomo/transport/xhttp/upload_queue.go @@ -8,11 +8,11 @@ import ( type Packet struct { Seq uint64 - Payload []byte + Payload []byte // UploadQueue will hold Payload, so never reuse it after UploadQueue.Push Reader io.ReadCloser } -type uploadQueue struct { +type UploadQueue struct { mu sync.Mutex cond *sync.Cond packets map[uint64][]byte @@ -22,15 +22,15 @@ type uploadQueue struct { reader io.ReadCloser } -func NewUploadQueue() *uploadQueue { - q := &uploadQueue{ +func NewUploadQueue() *UploadQueue { + q := &UploadQueue{ packets: make(map[uint64][]byte), } q.cond = sync.NewCond(&q.mu) return q } -func (q *uploadQueue) Push(p Packet) error { +func (q *UploadQueue) Push(p Packet) error { q.mu.Lock() defer q.mu.Unlock() @@ -48,14 +48,12 @@ func (q *uploadQueue) Push(p Packet) error { return nil } - cp := make([]byte, len(p.Payload)) - copy(cp, p.Payload) - q.packets[p.Seq] = cp + q.packets[p.Seq] = p.Payload q.cond.Broadcast() return nil } -func (q *uploadQueue) Read(b []byte) (int, error) { +func (q *UploadQueue) Read(b []byte) (int, error) { q.mu.Lock() for { @@ -87,7 +85,7 @@ func (q *uploadQueue) Read(b []byte) (int, error) { } } -func (q *uploadQueue) Close() error { +func (q *UploadQueue) Close() error { q.mu.Lock() defer q.mu.Unlock() diff --git a/openclash/.github/workflows/compile_meta_core.yml b/openclash/.github/workflows/compile_meta_core.yml index fafdf794b3..a82774dbf8 100644 --- a/openclash/.github/workflows/compile_meta_core.yml +++ b/openclash/.github/workflows/compile_meta_core.yml @@ -391,46 +391,3 @@ jobs: else echo "No changes to commit." fi - - - name: Trim History to Last 10 Commits - run: | - MAX_COMMITS=20 - LIMIT_COMMITS=10 - count=$(git rev-list --count HEAD) - echo "Current commit count on core branch: $count" - if [ "$count" -le "$MAX_COMMITS" ]; then - echo "No trimming needed (commit count: $count <= $MAX_COMMITS)." - exit 0 - fi - - git config user.name 'github-actions[bot]' - git config user.email 'github-actions[bot]@users.noreply.github.com' - - recent_commits=($(git rev-list --max-count=$LIMIT_COMMITS HEAD)) - sync_commit=$(git log --grep='Release: Auto sync' --format='%H' | tail -n 1) - - keep_commits=("${recent_commits[@]}") - if [ -n "$sync_commit" ]; then - found=false - for c in "${recent_commits[@]}"; do - if [ "$c" = "$sync_commit" ]; then - found=true - break - fi - done - if [ "$found" = false ]; then - keep_commits+=("$sync_commit") - fi - fi - - git checkout -b __tmp_history_trim HEAD - for c in $(printf "%s\n" "${keep_commits[@]}" | tac); do - git checkout "$c" -- dev || true - [ -d master ] && git checkout "$c" -- master || true - git add dev || true - [ -d master ] && git add master || true - git commit --allow-empty --keep-redundant-commits --no-edit --author="github-actions[bot] " - done - git branch -M __tmp_history_trim core - git push --force origin core - echo "Trim complete. New commit count: $(git rev-list --count HEAD)" \ No newline at end of file diff --git a/openclash/.github/workflows/compile_new_ipk.yml b/openclash/.github/workflows/compile_new_ipk.yml index bcb61ac421..cb2f9ca866 100644 --- a/openclash/.github/workflows/compile_new_ipk.yml +++ b/openclash/.github/workflows/compile_new_ipk.yml @@ -191,55 +191,8 @@ jobs: cp ./luci-app-openclash-*.apk "./${{ github.ref_name }}/" rm -f ./luci-app-openclash_*.ipk rm -f ./luci-app-openclash-*.apk - sed -i -E "s/OpenClash\/tree\/v(.*)/OpenClash\/tree\/v${{ needs.Get-Version.outputs.version }}/g" ./${{ github.ref_name }}/README.md - sed -i -E "s/OpenClash\/releases\/tag\/v(.*)/OpenClash\/releases\/tag\/v${{ needs.Get-Version.outputs.version }}/g" ./${{ github.ref_name }}/README.md - sed -i -E "s/source code-v(.*)-green/source code-v${{ needs.Get-Version.outputs.version }}-green/g" ./${{ github.ref_name }}/README.md - sed -i -E "s/New Release-v(.*)-orange/New Release-v${{ needs.Get-Version.outputs.version }}-orange/g" ./${{ github.ref_name }}/README.md git config user.name 'github-actions[bot]' git config user.email 'github-actions[bot]@users.noreply.github.com' git add . git commit -m "Auto Release: v${{ needs.Get-Version.outputs.version }}" git push - - - name: Trim History to Last 30 Commits - run: | - MAX_COMMITS=50 - LIMIT_COMMITS=30 - count=$(git rev-list --count HEAD) - echo "Current commit count on package branch: $count" - if [ "$count" -le "$MAX_COMMITS" ]; then - echo "No trimming needed (commit count: $count <= $MAX_COMMITS)." - exit 0 - fi - - git config user.name 'github-actions[bot]' - git config user.email 'github-actions[bot]@users.noreply.github.com' - - recent_commits=($(git rev-list --max-count=$LIMIT_COMMITS HEAD)) - sync_commit=$(git log --grep='Release: Auto sync' --format='%H' | tail -n 1) - - keep_commits=("${recent_commits[@]}") - if [ -n "$sync_commit" ]; then - found=false - for c in "${recent_commits[@]}"; do - if [ "$c" = "$sync_commit" ]; then - found=true - break - fi - done - if [ "$found" = false ]; then - keep_commits+=("$sync_commit") - fi - fi - - git checkout -b __tmp_history_trim HEAD - for c in $(printf "%s\n" "${keep_commits[@]}" | tac); do - git checkout "$c" -- dev || true - [ -d master ] && git checkout "$c" -- master || true - git add dev || true - [ -d master ] && git add master || true - git commit --allow-empty --keep-redundant-commits --no-edit --author="github-actions[bot] " - done - git branch -M __tmp_history_trim package - git push --force origin package - echo "Trim complete. New commit count: $(git rev-list --count HEAD)" \ No newline at end of file diff --git a/openclash/.github/workflows/trim_core_package_history.yml b/openclash/.github/workflows/trim_core_package_history.yml new file mode 100644 index 0000000000..001b29775c --- /dev/null +++ b/openclash/.github/workflows/trim_core_package_history.yml @@ -0,0 +1,133 @@ +name: Trim Core and Package History + +on: + schedule: + - cron: "0 18 * * 3" + workflow_dispatch: + +jobs: + trim: + runs-on: ubuntu-latest + strategy: + matrix: + branch: [core, package] + steps: + - name: Apt Update + env: + DEBIAN_FRONTEND: noninteractive + run: | + sudo apt-get update + sudo apt-get -y install git + + - name: Trim History + env: + REPO_URL: https://github.com/vernesong/OpenClash.git + BRANCH: ${{ matrix.branch }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + + if [ "${BRANCH}" = "core" ]; then + MAX_COMMITS=20 + LIMIT_COMMITS=10 + else + MAX_COMMITS=50 + LIMIT_COMMITS=30 + fi + + echo "Start full clone for history check (branch: ${BRANCH})..." + mkdir -p ../full_clone_tmp + cd ../full_clone_tmp + git clone --branch "${BRANCH}" --single-branch --no-tags --progress --depth=1 "$REPO_URL" . + + MAX_FETCH_RETRIES=3 + FETCH_OK=false + for i in $(seq 1 $MAX_FETCH_RETRIES); do + if git fetch --unshallow; then + FETCH_OK=true + break + else + echo "git fetch --unshallow failed (attempt $i/$MAX_FETCH_RETRIES), retrying..." >&2 + sleep 2 + fi + done + if [ "$FETCH_OK" = false ]; then + echo "Warning: git fetch --unshallow failed after $MAX_FETCH_RETRIES attempts, proceeding with available history." >&2 + fi + + count=$(git rev-list --count HEAD 2>/dev/null || echo 0) + echo "Current commit count on ${BRANCH} branch: $count" + if [ "$count" -le "$MAX_COMMITS" ]; then + echo "No trimming needed (commit count: $count <= $MAX_COMMITS)." + cd .. + rm -rf full_clone_tmp + exit 0 + fi + + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + + echo "Collecting recent commits..." + mapfile -t recent_commits < <(git rev-list --max-count=$LIMIT_COMMITS HEAD) + + echo "Looking for sync commit (grep 'Release: Auto sync')..." + sync_commit=$(git log --grep='Release: Auto sync' --format='%H' | tail -n 1 || true) + + keep_commits=("${recent_commits[@]}") + if [ -n "$sync_commit" ]; then + found=false + for c in "${recent_commits[@]}"; do + if [ "$c" = "$sync_commit" ]; then + found=true + break + fi + done + if [ "$found" = false ]; then + keep_commits+=("$sync_commit") + fi + fi + + echo "Rebuilding trimmed branch from kept commits (no extra commits)..." + ORIG_HEAD=$(git rev-parse HEAD) + LAST_COMMIT="" + for c in $(printf "%s\n" "${keep_commits[@]}" | tac); do + echo "Processing commit $c ..." + git checkout -- . || true + git checkout "$c" -- . || true + git add -A || true + TREE_ID=$(git write-tree) + AUTHOR_NAME=$(git show -s --format='%an' $c) + AUTHOR_EMAIL=$(git show -s --format='%ae' $c) + COMMIT_DATE=$(git show -s --format='%ad' --date=iso-strict $c) + COMMIT_MSG=$(git log --format=%B -n 1 $c) + echo "Commit message for $c:" + printf "%s\n" "$COMMIT_MSG" + + MSG_FILE=$(mktemp) + printf "%s\n" "$COMMIT_MSG" > "$MSG_FILE" + + if [ -z "$LAST_COMMIT" ]; then + NEW_COMMIT=$(GIT_AUTHOR_NAME="$AUTHOR_NAME" GIT_AUTHOR_EMAIL="$AUTHOR_EMAIL" GIT_AUTHOR_DATE="$COMMIT_DATE" git commit-tree $TREE_ID -F "$MSG_FILE") + else + NEW_COMMIT=$(GIT_AUTHOR_NAME="$AUTHOR_NAME" GIT_AUTHOR_EMAIL="$AUTHOR_EMAIL" GIT_AUTHOR_DATE="$COMMIT_DATE" git commit-tree $TREE_ID -p "$LAST_COMMIT" -F "$MSG_FILE") + fi + rm -f "$MSG_FILE" + LAST_COMMIT=$NEW_COMMIT + done + + if [ -n "$LAST_COMMIT" ]; then + git update-ref refs/heads/__tmp_history_trim $LAST_COMMIT + echo "Built commit: $LAST_COMMIT" + + if [ -n "${GITHUB_TOKEN:-}" ]; then + git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/vernesong/OpenClash.git" + fi + + git push --force --quiet origin "$LAST_COMMIT:refs/heads/${BRANCH}" || true + echo "Trim complete. New commit count (remote unchanged locally until fetched): $(git rev-list --count HEAD)" + else + echo "No kept commits; skipping trim." >&2 + fi + + cd .. + rm -rf full_clone_tmp diff --git a/openclash/luci-app-openclash/root/usr/share/openclash/yml_rules_change.sh b/openclash/luci-app-openclash/root/usr/share/openclash/yml_rules_change.sh index 2fdcc150f0..1bb95bd379 100644 --- a/openclash/luci-app-openclash/root/usr/share/openclash/yml_rules_change.sh +++ b/openclash/luci-app-openclash/root/usr/share/openclash/yml_rules_change.sh @@ -272,7 +272,7 @@ yml_other_set() begin provider_configs = {'proxy-providers' => 'proxy_provider', 'rule-providers' => 'rule_provider'}; provider_configs.each do |provider_type, path_prefix| - if Value.key?(provider_type) then + if Value.key?(provider_type) && Value[provider_type].is_a?(Hash) then Value[provider_type].each{|name, config| threads << Thread.new { if config['path'] and not config['path'] =~ /.\/#{path_prefix}\/*/ then @@ -310,7 +310,7 @@ yml_other_set() # tolerance begin - if '$tolerance' != '0' and Value.key?('proxy-groups') then + if '$tolerance' != '0' and Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then Value['proxy-groups'].each{|group| threads << Thread.new { if group['type'] == 'url-test' then @@ -326,7 +326,7 @@ yml_other_set() # URL-Test interval begin if '$urltest_interval_mod' != '0' then - if Value.key?('proxy-groups') then + if Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then Value['proxy-groups'].each{|group| threads << Thread.new { if ['url-test', 'fallback', 'load-balance', 'smart'].include?(group['type']) then @@ -361,7 +361,7 @@ yml_other_set() }; }; end; - if Value.key?('proxy-groups') then + if Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then Value['proxy-groups'].each{|group| threads << Thread.new { if ['url-test', 'fallback', 'load-balance', 'smart'].include?(group['type']) then @@ -377,7 +377,7 @@ yml_other_set() # smart auto switch begin - if ('${8}' == '1' or '${9}' == '1' or '${11}' != '0' or '${12}' != '0' or '${12}' == '1' or '${13}' == '1') and Value.key?('proxy-groups') then + if ('${8}' == '1' or '${9}' == '1' or '${11}' != '0' or '${12}' != '0' or '${12}' == '1' or '${13}' == '1') and Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then Value['proxy-groups'].each{|group| threads << Thread.new { if '${8}' == '1' and ['url-test', 'load-balance'].include?(group['type']) then diff --git a/openwrt-packages/openlist2/Makefile b/openwrt-packages/openlist2/Makefile index ec5a61fda0..d53488823b 100644 --- a/openwrt-packages/openlist2/Makefile +++ b/openwrt-packages/openlist2/Makefile @@ -7,13 +7,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=openlist2 -PKG_VERSION:=4.1.10 -PKG_WEB_VERSION:=4.1.10 +PKG_VERSION:=4.2.1 +PKG_WEB_VERSION:=4.2.1 PKG_RELEASE:=1 PKG_SOURCE:=openlist-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/OpenListTeam/OpenList/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=0e85b2e9f97c819a79a054c2de1f505b0b0d78e1c8ce6783e12da85ea519840c +PKG_HASH:=95d4a30f9669837a4c92daf88f74d223eca773e3445c270681c67e2b3dc3ac31 PKG_BUILD_DIR:=$(BUILD_DIR)/OpenList-$(PKG_VERSION) @@ -24,7 +24,7 @@ PKG_MAINTAINER:=sbwml define Download/openlist-frontend FILE:=openlist-frontend-dist-lite-v$(PKG_WEB_VERSION).tar.gz URL:=https://github.com/OpenListTeam/OpenList-Frontend/releases/download/v$(PKG_WEB_VERSION)/ - HASH:=e662f28dfac4631d5cae242f30d2f2f4c16a424399e7850fd5309127c82e1a60 + HASH:=09e5afb62f567c12b3bced85dcbd419ac6b0e12acd8b25c53b3a5320d2730ee3 endef PKG_BUILD_DEPENDS:=golang/host diff --git a/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua b/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua index f045bc87f7..cb31a73744 100644 --- a/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua +++ b/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua @@ -120,14 +120,6 @@ if #ss_type > 0 or #trojan_type > 0 or #vmess_type > 0 or #vless_type > 0 or #hy translate("The configured type also applies to the core specified when manually importing nodes.")) end -o = s:option(ListValue, "domain_strategy", "Sing-box " .. translate("Domain Strategy"), translate("Set the default domain resolution strategy for the sing-box node.")) -o.default = "" -o:value("", translate("Auto")) -o:value("prefer_ipv4", translate("Prefer IPv4")) -o:value("prefer_ipv6", translate("Prefer IPv6")) -o:value("ipv4_only", translate("IPv4 Only")) -o:value("ipv6_only", translate("IPv6 Only")) - ---- Subscribe Delete All o = s:option(DummyValue, "_stop", translate("Delete All Subscribe Node")) o.rawhtml = true diff --git a/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua b/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua index a913865c48..56b9f1752b 100644 --- a/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua +++ b/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua @@ -133,6 +133,34 @@ o.validate = function(self, value) return value:gsub("%s+", ""):gsub("%z", "") end +o = s:option(ListValue, "domain_resolver", translate("Domain DNS Resolve")) +o.description = translate("If the node address is a domain name, this DNS will be used for resolution.") .. "
" .. + translate("Supports only Xray or Sing-box node types.") +o:value("", translate("Auto")) +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:value("https", "DoH") + +o = s:option(Value, "domain_resolver_dns", "DNS") +o.datatype = "or(ipaddr,ipaddrport)" +o:value("114.114.114.114") +o:value("223.5.5.5:53") +o.default = o.keylist[1] +o:depends({ domain_resolver = "tcp" }) +o:depends({ domain_resolver = "udp" }) + +o = s:option(Value, "domain_resolver_dns_https", "DNS") +o:value("https://120.53.53.53/dns-query", "DNSPod") +o:value("https://223.5.5.5/dns-query", "AliDNS") +o.default = o.keylist[1] +o:depends({ domain_resolver = "https" }) + +o = s:option(ListValue, "domain_strategy", translate("Domain Strategy"), translate("If is domain name, The requested domain name will be resolved to IP before connect.")) +o.default = "" +o:value("", translate("Auto")) +o:value("UseIPv4", translate("IPv4 Only")) +o:value("UseIPv6", translate("IPv6 Only")) + o = s:option(Flag, "allowInsecure", translate("allowInsecure")) o.default = "0" o.rmempty = false @@ -203,15 +231,6 @@ if #hysteria2_type > 0 then end end -o = s:option(ListValue, "domain_strategy", "Sing-box " .. translate("Domain Strategy"), translate("Set the default domain resolution strategy for the sing-box node.")) -o.default = "global" -o:value("global", translate("Use global config")) -o:value("", translate("Auto")) -o:value("prefer_ipv4", translate("Prefer IPv4")) -o:value("prefer_ipv6", translate("Prefer IPv6")) -o:value("ipv4_only", translate("IPv4 Only")) -o:value("ipv6_only", translate("IPv6 Only")) - o = s:option(Flag, "boot_update", translate("Update Once on Boot"), translate("Updates the subscription the first time PassWall runs automatically after each system boot.")) o.default = 0 diff --git a/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua b/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua index 891ed10211..7d1d9fdf22 100644 --- a/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua +++ b/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua @@ -240,16 +240,6 @@ o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) o = s:option(Value, _n("port"), translate("Port")) o.datatype = "port" -local protocols = s.fields[_n("protocol")].keylist -if #protocols > 0 then - for index, value in ipairs(protocols) do - if not value:find("^_") then - s.fields[_n("address")]:depends({ [_n("protocol")] = value }) - s.fields[_n("port")]:depends({ [_n("protocol")] = value }) - end - end -end - o = s:option(Value, _n("uuid"), translate("ID")) o.password = true o:depends({ [_n("protocol")] = "vmess" }) @@ -735,10 +725,46 @@ o.datatype = "uinteger" o.placeholder = 0 o:depends({ [_n("protocol")] = "vless" }) -for i, v in ipairs(s.fields[_n("protocol")].keylist) do - if not v:find("^_") and v ~= "hysteria2" then - s.fields[_n("tcp_fast_open")]:depends({ [_n("protocol")] = v }) - s.fields[_n("tcpMptcp")]:depends({ [_n("protocol")] = v }) +o = s:option(ListValue, _n("domain_resolver"), translate("Domain DNS Resolve"), translate("If the node address is a domain name, this DNS will be used for resolution.")) +o:value("", translate("Auto")) +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:value("https", "DoH") + +o = s:option(Value, _n("domain_resolver_dns"), "DNS") +o.datatype = "or(ipaddr,ipaddrport)" +o:value("114.114.114.114") +o:value("223.5.5.5:53") +o.default = o.keylist[1] +o:depends({ [_n("domain_resolver")] = "tcp" }) +o:depends({ [_n("domain_resolver")] = "udp" }) + +o = s:option(Value, _n("domain_resolver_dns_https"), "DNS") +o:value("https://120.53.53.53/dns-query", "DNSPod") +o:value("https://223.5.5.5/dns-query", "AliDNS") +o.default = o.keylist[1] +o:depends({ [_n("domain_resolver")] = "https" }) + +o = s:option(ListValue, _n("domain_strategy"), translate("Domain Strategy"), translate("If is domain name, The requested domain name will be resolved to IP before connect.")) +o.default = "" +o:value("", translate("Auto")) +o:value("UseIPv4", translate("IPv4 Only")) +o:value("UseIPv6", translate("IPv6 Only")) + +local protocols = s.fields[_n("protocol")].keylist +if #protocols > 0 then + for i, v in ipairs(protocols) do + if not v:find("^_") then + s.fields[_n("address")]:depends({ [_n("protocol")] = v }) + s.fields[_n("port")]:depends({ [_n("protocol")] = v }) + s.fields[_n("domain_resolver")]:depends({ [_n("protocol")] = v }) + s.fields[_n("domain_strategy")]:depends({ [_n("protocol")] = v }) + + if v ~= "hysteria2" then + s.fields[_n("tcp_fast_open")]:depends({ [_n("protocol")] = v }) + s.fields[_n("tcpMptcp")]:depends({ [_n("protocol")] = v }) + end + end end end end diff --git a/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua b/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua index 95c0a2a08e..eb9adbaad7 100644 --- a/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua +++ b/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua @@ -206,16 +206,6 @@ o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) o = s:option(Value, _n("port"), translate("Port")) o.datatype = "port" -local protocols = s.fields[_n("protocol")].keylist -if #protocols > 0 then - for index, value in ipairs(protocols) do - if not value:find("^_") then - s.fields[_n("address")]:depends({ [_n("protocol")] = value }) - s.fields[_n("port")]:depends({ [_n("protocol")] = value }) - end - end -end - o = s:option(Value, _n("uuid"), translate("ID")) o.password = true o:depends({ [_n("protocol")] = "vmess" }) @@ -742,6 +732,26 @@ o:value("v2ray-plugin") o = s:option(Value, _n("plugin_opts"), translate("opts")) o:depends({ [_n("plugin_enabled")] = true }) +o = s:option(ListValue, _n("domain_resolver"), translate("Domain DNS Resolve"), translate("If the node address is a domain name, this DNS will be used for resolution.")) +o:value("", translate("Auto")) +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:value("https", "DoH") + +o = s:option(Value, _n("domain_resolver_dns"), "DNS") +o.datatype = "or(ipaddr,ipaddrport)" +o:value("114.114.114.114") +o:value("223.5.5.5:53") +o.default = o.keylist[1] +o:depends({ [_n("domain_resolver")] = "tcp" }) +o:depends({ [_n("domain_resolver")] = "udp" }) + +o = s:option(Value, _n("domain_resolver_dns_https"), "DNS") +o:value("https://120.53.53.53/dns-query", "DNSPod") +o:value("https://223.5.5.5/dns-query", "AliDNS") +o.default = o.keylist[1] +o:depends({ [_n("domain_resolver")] = "https" }) + o = s:option(ListValue, _n("domain_strategy"), translate("Domain Strategy"), translate("If is domain name, The requested domain name will be resolved to IP before connect.")) o.default = "" o:value("", translate("Auto")) @@ -749,17 +759,19 @@ o:value("prefer_ipv4", translate("Prefer IPv4")) o:value("prefer_ipv6", translate("Prefer IPv6")) o:value("ipv4_only", translate("IPv4 Only")) o:value("ipv6_only", translate("IPv6 Only")) -o:depends({ [_n("protocol")] = "socks" }) -o:depends({ [_n("protocol")] = "http" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "trojan" }) -o:depends({ [_n("protocol")] = "wireguard" }) -o:depends({ [_n("protocol")] = "hysteria" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "tuic" }) -o:depends({ [_n("protocol")] = "hysteria2" }) -o:depends({ [_n("protocol")] = "anytls" }) + + +local protocols = s.fields[_n("protocol")].keylist +if #protocols > 0 then + for i, v in ipairs(protocols) do + if not v:find("^_") then + s.fields[_n("address")]:depends({ [_n("protocol")] = v }) + s.fields[_n("port")]:depends({ [_n("protocol")] = v }) + s.fields[_n("domain_resolver")]:depends({ [_n("protocol")] = v }) + s.fields[_n("domain_strategy")]:depends({ [_n("protocol")] = v }) + end + end +end end -- [[ Normal single node End ]] diff --git a/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_sing-box.lua index 35877c910b..e7d7e2c6d7 100644 --- a/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_sing-box.lua @@ -11,6 +11,10 @@ local ech_domain = {} local local_version = api.get_app_version("sing-box"):match("[^v]+") local version_ge_1_13_0 = api.compare_versions(local_version, ">=", "1.13.0") +local GLOBAL = { + DNS_SERVER = {} +} + local GEO_VAR = { OK = nil, DIR = nil, @@ -154,6 +158,47 @@ function gen_outbound(flag, node, tag, proxy_table) detour = node.detour, } + if api.datatypes.hostname(node.address) and node.domain_resolver and (node.domain_resolver_dns or node.domain_resolver_dns_https) then + local dns_tag = node_id .. "_dns" + local dns_proto = node.domain_resolver + local server_address + local server_port + local server_path + if dns_proto == "https" then + local _a = api.parseURL(node.domain_resolver_dns_https) + if _a then + server_address = _a.hostname + if _a.port then + server_port = _a.port + else + server_port = 443 + end + server_path = _a.pathname + end + else + server_address = node.domain_resolver_dns + server_port = 53 + local split = api.split(server_address, ":") + if #split > 1 then + server_address = split[1] + server_port = tonumber(split[#split]) + end + end + GLOBAL.DNS_SERVER[node_id] = { + server = { + tag = dns_tag, + type = dns_proto, + server = server_address, + server_port = server_port, + path = server_path, + domain_resolver = "direct", + detour = "direct" + }, + domain = node.address + } + result.domain_resolver.server = dns_tag + end + local tls = nil if node.protocol == "hysteria" or node.protocol == "hysteria2" or node.protocol == "tuic" or node.protocol == "naive" then node.tls = "1" @@ -1922,6 +1967,16 @@ function gen_config(var) } end + for i, v in pairs(GLOBAL.DNS_SERVER) do + table.insert(dns.servers, v.server) + if not dns.rules then dns.rules = {} end + table.insert(dns.rules, { + action = "route", + server = v.server.tag, + domain = v.domain, + }) + end + if next(ech_domain) ~= nil then table.insert(dns.servers, { tag = "ech-dns", @@ -1983,6 +2038,12 @@ function gen_config(var) if not value["_flag_proxy_tag"] and not value.detour and value["_id"] and value.server and (value.server_port or value.server_ports) and not no_run then sys.call(string.format("echo '%s' >> %s", value["_id"], api.TMP_PATH .. "/direct_node_list")) end + if not value.detour and value.server then + value.detour = "direct" + end + if value.server and not api.datatypes.hostname(value.server) then + value.domain_resolver = nil + end for k, v in pairs(config.outbounds[index]) do if k:find("_") == 1 then config.outbounds[index][k] = nil diff --git a/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_xray.lua b/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_xray.lua index 61c20127c3..7e0109937b 100644 --- a/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -6,6 +6,11 @@ local jsonc = api.jsonc local appname = "passwall" local fs = api.fs +local GLOBAL = { + DNS_SERVER = {}, + DNS_HOSTNAME = {} +} + local xray_version = api.get_app_version("xray") local function get_domain_excluded() @@ -134,6 +139,7 @@ function gen_outbound(flag, node, tag, proxy_table) streamSettings = (node.streamSettings or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan" or node.protocol == "hysteria") and { sockopt = { mark = 255, + domainStrategy = node.domain_strategy or "UseIP", tcpFastOpen = (node.tcp_fast_open == "1") and true or nil, tcpMptcp = (node.tcpMptcp == "1") and true or nil }, @@ -397,6 +403,48 @@ function gen_outbound(flag, node, tag, proxy_table) result.streamSettings.tlsSettings.alpn = alpn end end + + if api.datatypes.hostname(node.address) and node.domain_resolver and (node.domain_resolver_dns or node.domain_resolver_dns_https) then + local dns_tag = node_id .. "_dns" + local dns_proto = node.domain_resolver + local config_address + local config_port + if dns_proto == "https" then + local _a = api.parseURL(node.domain_resolver_dns_https) + if _a then + config_address = node.domain_resolver_dns_https + if _a.port then + config_port = _a.port + else + config_port = 443 + end + if _a.hostname then + if api.datatypes.hostname(_a.hostname) then + GLOBAL.DNS_HOSTNAME[_a.hostname] = true + end + end + end + else + local server_address = node.domain_resolver_dns + local config_port = 53 + local split = api.split(server_address, ":") + if #split > 1 then + server_address = split[1] + config_port = tonumber(split[#split]) + end + config_address = server_address + if dns_proto == "tcp" then + config_address = dns_proto .. "://" .. server_address .. ":" .. config_port + end + end + GLOBAL.DNS_SERVER[node_id] = { + tag = dns_tag, + queryStrategy = node.domain_strategy or "UseIP", + address = config_address, + port = config_port, + domains = {"full:" .. node.address} + } + end end return result end @@ -1437,7 +1485,15 @@ function gen_config(var) end end - if (remote_dns_udp_server and remote_dns_udp_port) or (remote_dns_tcp_server and remote_dns_tcp_port) then + local node_dns = {} + for i, v in pairs(GLOBAL.DNS_SERVER) do + table.insert(node_dns, { + server = v, + outboundTag = "direct" + }) + end + + if (remote_dns_udp_server and remote_dns_udp_port) or (remote_dns_tcp_server and remote_dns_tcp_port) or #node_dns > 0 then if not routing then routing = { domainStrategy = "IPOnDemand", @@ -1461,6 +1517,8 @@ function gen_config(var) queryStrategy = (direct_dns_query_strategy and direct_dns_query_strategy ~= "") and direct_dns_query_strategy or "UseIP" } + direct_dns_udp_server = (direct_dns_udp_server and direct_dns_udp_server ~= "") and direct_dns_udp_server or nil + if direct_dns_udp_server or direct_dns_tcp_server then local domain = {} local nodes_domain_text = sys.exec('uci show passwall | grep ".address=" | cut -d "\'" -f 2 | grep "[a-zA-Z]$" | sort -u') @@ -1489,14 +1547,12 @@ function gen_config(var) end end - local _remote_dns = { - --tag = "dns-global-remote", - queryStrategy = (remote_dns_query_strategy and remote_dns_query_strategy ~= "") and remote_dns_query_strategy or "UseIPv4", - } + local _remote_dns = {} + if remote_dns_udp_server then _remote_dns.address = remote_dns_udp_server _remote_dns.port = tonumber(remote_dns_udp_port) or 53 - else + elseif remote_dns_tcp_server then _remote_dns.address = "tcp://" .. remote_dns_tcp_server .. ":" .. tonumber(remote_dns_tcp_port) or 53 end @@ -1510,7 +1566,11 @@ function gen_config(var) _remote_dns.port = tonumber(remote_dns_doh_port) end - table.insert(dns.servers, _remote_dns) + if next(_remote_dns) then + -- _remote_dns.tag = "dns-global-remote" + _remote_dns.queryStrategy = (remote_dns_query_strategy and remote_dns_query_strategy ~= "") and remote_dns_query_strategy or "UseIPv4" + table.insert(dns.servers, _remote_dns) + end local _remote_fakedns = { --tag = "dns-global-remote-fakedns", @@ -1649,7 +1709,7 @@ function gen_config(var) dns_server = nil end if dns_server then - dns_server.finalQuery = true + --dns_server.finalQuery = true dns_server.domains = value.domain if value.shunt_rule_name then dns_server.tag = "dns-in-" .. value.shunt_rule_name @@ -1666,7 +1726,7 @@ function gen_config(var) end local _outboundTag - if not api.is_local_ip(_remote_dns.address) or dns_outbound_tag == "blackhole" then --dns为本地ip,不走代理 + if _remote_dns.address and not api.is_local_ip(_remote_dns.address) or dns_outbound_tag == "blackhole" then --dns为本地ip,不走代理 _outboundTag = dns_outbound_tag else _outboundTag = "direct" @@ -1698,6 +1758,37 @@ function gen_config(var) if dns_hosts_len == 0 then dns.hosts = nil end + + -- 自定义节点 DNS + if #node_dns > 0 and #dns.servers < 1 then + dns.servers = { "localhost" } + end + for i = #node_dns, 1, -1 do + local value = node_dns[i] + table.insert(routing.rules, 1, { + inboundTag = { + value.server.tag + }, + outboundTag = value.outboundTag, + }) + table.insert(dns.servers, 2, value.server) + end + if next(GLOBAL.DNS_HOSTNAME) then + local hostname = {} + for line, _ in pairs(GLOBAL.DNS_HOSTNAME) do + table.insert(hostname, line) + end + table.insert(dns.servers, 2, { + tag = "bootstrap", + address = "223.5.5.5", + queryStrategy = "UseIPv4", + domains = hostname + }) + table.insert(routing.rules, 1, { + inboundTag = { "bootstrap" }, + outboundTag = "direct" + }) + end end if inbounds or outbounds then diff --git a/openwrt-passwall/luci-app-passwall/po/zh-cn/passwall.po b/openwrt-passwall/luci-app-passwall/po/zh-cn/passwall.po index 93a40372db..3c15def467 100644 --- a/openwrt-passwall/luci-app-passwall/po/zh-cn/passwall.po +++ b/openwrt-passwall/luci-app-passwall/po/zh-cn/passwall.po @@ -1936,6 +1936,15 @@ msgstr "延迟(ms)" msgid "If is domain name, The requested domain name will be resolved to IP before connect." msgstr "如果是域名,域名将在请求发出之前解析为 IP。" +msgid "Domain DNS Resolve" +msgstr "域名 DNS 解析" + +msgid "If the node address is a domain name, this DNS will be used for resolution." +msgstr "如果节点地址是域名,则将使用此 DNS 进行解析。" + +msgid "Supports only Xray or Sing-box node types." +msgstr "仅支持 Xray 或 Sing-box 类型节点。" + msgid "Chain Proxy" msgstr "链式代理" @@ -1949,15 +1958,12 @@ msgid "" "Chained proxy works only with Xray or Sing-box nodes.
" "You can only use manual or imported nodes as chained nodes." msgstr "" -"链式代理仅支持 Xray 与 Sing-box 节点。
" +"链式代理仅支持 Xray 或 Sing-box 节点。
" "仅支持手动添加或导入的节点用作链式节点。" msgid "Only work with using the %s node." msgstr "与使用 %s 节点时生效。" -msgid "Set the default domain resolution strategy for the sing-box node." -msgstr "为 sing-box 节点设置默认的域名解析策略。" - msgid "Total Lines" msgstr "总行数:" diff --git a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/subscribe.lua b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/subscribe.lua index 4d12d6e394..56c6b682af 100755 --- a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/subscribe.lua +++ b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/subscribe.lua @@ -42,8 +42,7 @@ local core_has = { ["trojan-plus"] = has_trojan_plus, ["hysteria2"] = has_hysteria2 } ---- -local domain_strategy_default = uci:get(appname, "@global_subscribe[0]", "domain_strategy") or "" -local domain_strategy_node = "" +local domain_resolver, domain_resolver_dns, domain_resolver_dns_https, domain_strategy local preproxy_node_group, to_node_group, chain_node_type = "", "", "" -- 判断是否过滤节点关键字 local filter_keyword_mode_default = uci:get(appname, "@global_subscribe[0]", "filter_keyword_mode") or "0" @@ -1855,9 +1854,22 @@ local function update_node(manual) if kkk ~= "group" or vvv ~= "default" then uci:set(appname, cfgid, kkk, vvv) end - -- sing-box 域名解析策略 - if kkk == "type" and vvv == "sing-box" then - uci:set(appname, cfgid, "domain_strategy", domain_strategy_node) + -- sing-box/xray 节点域名解析 + if kkk == "type" and (vvv == "Xray" or vvv == "sing-box") then + if domain_resolver then + uci:set(appname, cfgid, "domain_resolver", domain_resolver) + if domain_resolver_dns then + uci:set(appname, cfgid, "domain_resolver_dns", domain_resolver_dns) + elseif domain_resolver_dns_https then + uci:set(appname, cfgid, "domain_resolver_dns_https", domain_resolver_dns_https) + end + end + if domain_strategy then + if vvv == "sing-box" then + domain_strategy = (domain_strategy == "UseIPv4" and "ipv4_only") or (domain_strategy == "UseIPv6" and "ipv6_only") or domain_strategy + end + uci:set(appname, cfgid, "domain_strategy", domain_strategy) + end end -- 订阅组链式代理 if chain_node_type ~= "" and kkk == "type" and (vvv == "Xray" or vvv == "sing-box") then @@ -2069,12 +2081,11 @@ local execute = function() if hysteria2_type ~= "global" and core_has[hysteria2_type] then hysteria2_type_default = hysteria2_type end - local domain_strategy = value.domain_strategy or "global" - if domain_strategy ~= "global" then - domain_strategy_node = domain_strategy - else - domain_strategy_node = domain_strategy_default - end + + domain_resolver = value.domain_resolver + domain_resolver_dns = value.domain_resolver_dns + domain_resolver_dns_https = value.domain_resolver_dns_https + domain_strategy = (value.domain_strategy == "UseIPv4" or value.domain_strategy == "UseIPv6") and value.domain_strategy or nil -- 订阅组链式代理 local function valid_chain_node(node) diff --git a/openwrt-passwall2/luci-app-passwall2/Makefile b/openwrt-passwall2/luci-app-passwall2/Makefile index dc04466d25..7afd2b027c 100644 --- a/openwrt-passwall2/luci-app-passwall2/Makefile +++ b/openwrt-passwall2/luci-app-passwall2/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 -PKG_VERSION:=26.4.5 +PKG_VERSION:=26.4.10 PKG_RELEASE:=1 PKG_PO_VERSION:=$(PKG_VERSION) diff --git a/openwrt-passwall2/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua b/openwrt-passwall2/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua index 9d3373af08..6096845db6 100644 --- a/openwrt-passwall2/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua +++ b/openwrt-passwall2/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua @@ -168,6 +168,19 @@ node_socks_bind_local:depends({ node = "", ["!reverse"] = true }) s:tab("DNS", translate("DNS")) +o = s:taboption("DNS", TextValue, "direct_dns_shunt", translate("Direct domain DNS routing")) +o.description = "
    " +.. "
  • " .. translate("Subdomain (recommended): Begining with 'domain:' and the rest is a domain. When the targeting domain is exactly the value, or is a subdomain of the value, this rule takes effect. Example: rule 'domain:v2ray.com' matches 'www.v2ray.com', 'v2ray.com', but not 'xv2ray.com'.") .. "
  • " +.. "
  • " .. translate("Full domain: Begining with 'full:' and the rest is a domain. When the targeting domain is exactly the value, the rule takes effect. Example: rule 'domain:v2ray.com' matches 'v2ray.com', but not 'www.v2ray.com'.") .. "
  • " +.. "
  • " .. translate("Such as:") .. "
  • " +.. "
  • " .. "domain:my-nodes.com tcp://223.5.5.5" .. "
  • " +.. "
  • " .. "domain:vpn.com udp://119.29.29.29:53" .. "
  • " +.. "
  • " .. "full:www.dnspod.com https://120.53.53.53/dns-query" .. "
  • " +.. "
  • " .. '' .. translate("Please note that the program will not start if the format is incorrect!") .. '' .. "
  • " +.. "
" +o.rows = 3 +o.wrap = "off" + o = s:taboption("DNS", ListValue, "direct_dns_query_strategy", translate("Direct Query Strategy")) o.default = "UseIP" o:value("UseIP") diff --git a/openwrt-passwall2/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua b/openwrt-passwall2/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua index ef70a93ccb..ac2a7b3490 100644 --- a/openwrt-passwall2/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua +++ b/openwrt-passwall2/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua @@ -238,16 +238,6 @@ o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) o = s:option(Value, _n("port"), translate("Port")) o.datatype = "port" -local protocols = s.fields[_n("protocol")].keylist -if #protocols > 0 then - for index, value in ipairs(protocols) do - if not value:find("^_") then - s.fields[_n("address")]:depends({ [_n("protocol")] = value }) - s.fields[_n("port")]:depends({ [_n("protocol")] = value }) - end - end -end - o = s:option(Value, _n("uuid"), translate("ID")) o.password = true o:depends({ [_n("protocol")] = "vmess" }) @@ -728,10 +718,46 @@ o.datatype = "uinteger" o.placeholder = 0 o:depends({ [_n("protocol")] = "vless" }) -for i, v in ipairs(s.fields[_n("protocol")].keylist) do - if not v:find("^_") and v ~= "hysteria2" then - s.fields[_n("tcp_fast_open")]:depends({ [_n("protocol")] = v }) - s.fields[_n("tcpMptcp")]:depends({ [_n("protocol")] = v }) +o = s:option(ListValue, _n("domain_resolver"), translate("Domain DNS Resolve"), translate("If the node address is a domain name, this DNS will be used for resolution.")) +o:value("", translate("Auto")) +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:value("https", "HTTPS") + +o = s:option(Value, _n("domain_resolver_dns"), "DNS") +o.datatype = "or(ipaddr,ipaddrport)" +o:value("114.114.114.114") +o:value("223.5.5.5:53") +o.default = o.keylist[1] +o:depends({ [_n("domain_resolver")] = "tcp" }) +o:depends({ [_n("domain_resolver")] = "udp" }) + +o = s:option(Value, _n("domain_resolver_dns_https"), "DNS") +o:value("https://120.53.53.53/dns-query", "DNSPod") +o:value("https://223.5.5.5/dns-query", "AliDNS") +o.default = o.keylist[1] +o:depends({ [_n("domain_resolver")] = "https" }) + +o = s:option(ListValue, _n("domain_strategy"), translate("Domain Strategy"), translate("If is domain name, The requested domain name will be resolved to IP before connect.")) +o.default = "" +o:value("", translate("Auto")) +o:value("UseIPv4", translate("IPv4 Only")) +o:value("UseIPv6", translate("IPv6 Only")) + +local protocols = s.fields[_n("protocol")].keylist +if #protocols > 0 then + for i, v in ipairs(protocols) do + if not v:find("^_") then + s.fields[_n("address")]:depends({ [_n("protocol")] = v }) + s.fields[_n("port")]:depends({ [_n("protocol")] = v }) + s.fields[_n("domain_resolver")]:depends({ [_n("protocol")] = v }) + s.fields[_n("domain_strategy")]:depends({ [_n("protocol")] = v }) + + if v ~= "hysteria2" then + s.fields[_n("tcp_fast_open")]:depends({ [_n("protocol")] = v }) + s.fields[_n("tcpMptcp")]:depends({ [_n("protocol")] = v }) + end + end end end end diff --git a/openwrt-passwall2/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua b/openwrt-passwall2/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua index a69ac4fd8a..42d39e8db4 100644 --- a/openwrt-passwall2/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua +++ b/openwrt-passwall2/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua @@ -209,16 +209,6 @@ o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) o = s:option(Value, _n("port"), translate("Port")) o.datatype = "port" -local protocols = s.fields[_n("protocol")].keylist -if #protocols > 0 then - for index, value in ipairs(protocols) do - if not value:find("^_") then - s.fields[_n("address")]:depends({ [_n("protocol")] = value }) - s.fields[_n("port")]:depends({ [_n("protocol")] = value }) - end - end -end - o = s:option(Value, _n("uuid"), translate("ID")) o.password = true o:depends({ [_n("protocol")] = "vmess" }) @@ -786,6 +776,26 @@ o:value("v2ray-plugin") o = s:option(Value, _n("plugin_opts"), translate("opts")) o:depends({ [_n("plugin_enabled")] = true }) +o = s:option(ListValue, _n("domain_resolver"), translate("Domain DNS Resolve"), translate("If the node address is a domain name, this DNS will be used for resolution.")) +o:value("", translate("Auto")) +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:value("https", "HTTPS") + +o = s:option(Value, _n("domain_resolver_dns"), "DNS") +o.datatype = "or(ipaddr,ipaddrport)" +o:value("114.114.114.114") +o:value("223.5.5.5:53") +o.default = o.keylist[1] +o:depends({ [_n("domain_resolver")] = "tcp" }) +o:depends({ [_n("domain_resolver")] = "udp" }) + +o = s:option(Value, _n("domain_resolver_dns_https"), "DNS") +o:value("https://120.53.53.53/dns-query", "DNSPod") +o:value("https://223.5.5.5/dns-query", "AliDNS") +o.default = o.keylist[1] +o:depends({ [_n("domain_resolver")] = "https" }) + o = s:option(ListValue, _n("domain_strategy"), translate("Domain Strategy"), translate("If is domain name, The requested domain name will be resolved to IP before connect.")) o.default = "" o:value("", translate("Auto")) @@ -793,18 +803,18 @@ o:value("prefer_ipv4", translate("Prefer IPv4")) o:value("prefer_ipv6", translate("Prefer IPv6")) o:value("ipv4_only", translate("IPv4 Only")) o:value("ipv6_only", translate("IPv6 Only")) -o:depends({ [_n("protocol")] = "socks" }) -o:depends({ [_n("protocol")] = "http" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "shadowsocksr" }) -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "trojan" }) -o:depends({ [_n("protocol")] = "wireguard" }) -o:depends({ [_n("protocol")] = "hysteria" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "tuic" }) -o:depends({ [_n("protocol")] = "hysteria2" }) -o:depends({ [_n("protocol")] = "anytls" }) + +local protocols = s.fields[_n("protocol")].keylist +if #protocols > 0 then + for i, v in ipairs(protocols) do + if not v:find("^_") then + s.fields[_n("address")]:depends({ [_n("protocol")] = v }) + s.fields[_n("port")]:depends({ [_n("protocol")] = v }) + s.fields[_n("domain_resolver")]:depends({ [_n("protocol")] = v }) + s.fields[_n("domain_strategy")]:depends({ [_n("protocol")] = v }) + end + end +end end -- [[ Normal single node End ]] diff --git a/openwrt-passwall2/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua b/openwrt-passwall2/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua index a76de67a6d..b454278d68 100644 --- a/openwrt-passwall2/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua +++ b/openwrt-passwall2/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua @@ -12,6 +12,10 @@ local ech_domain = {} local local_version = api.get_app_version("sing-box"):match("[^v]+") local version_ge_1_13_0 = api.compare_versions(local_version, ">=", "1.13.0") +local GLOBAL = { + DNS_SERVER = {} +} + local GEO_VAR = { OK = nil, DIR = nil, @@ -87,6 +91,34 @@ local function convert_geofile() convert(GEO_VAR.IP_PATH, "geoip", GEO_VAR.IP_TAGS) end +function parseDNS(str) + local result_dns_server + -- [proto]://[ip] + -- [proto]://[ip]:[port] + -- https://[ip]/[path] + -- https://[ip]:[port]/[path] + local _a = api.parseURL(str) + if _a then + if _a.protocol == "tcp" or _a.protocol == "udp" or _a.protocol == "https" then + result_dns_server = { + type = _a.protocol, + server = _a.hostname + } + if _a.port then + result_dns_server.server_port = _a.port + else + if _a.protocol == "https" then + result_dns_server.server_port = 443 + else + result_dns_server.server_port = 53 + end + end + result_dns_server.path = _a.pathname + end + end + return result_dns_server +end + function gen_outbound(flag, node, tag, proxy_table) local result = nil if node then @@ -159,6 +191,47 @@ function gen_outbound(flag, node, tag, proxy_table) detour = node.detour, } + if api.datatypes.hostname(node.address) and node.domain_resolver and (node.domain_resolver_dns or node.domain_resolver_dns_https) then + local dns_tag = node_id .. "_dns" + local dns_proto = node.domain_resolver + local server_address + local server_port + local server_path + if dns_proto == "https" then + local _a = api.parseURL(node.domain_resolver_dns_https) + if _a then + server_address = _a.hostname + if _a.port then + server_port = _a.port + else + server_port = 443 + end + server_path = _a.pathname + end + else + server_address = node.domain_resolver_dns + server_port = 53 + local split = api.split(server_address, ":") + if #split > 1 then + server_address = split[1] + server_port = tonumber(split[#split]) + end + end + GLOBAL.DNS_SERVER[node_id] = { + server = { + tag = dns_tag, + type = dns_proto, + server = server_address, + server_port = server_port, + path = server_path, + domain_resolver = "local", + detour = "direct" + }, + domain = node.address + } + result.domain_resolver.server = dns_tag + end + local tls = nil if node.protocol == "hysteria" or node.protocol == "hysteria2" or node.protocol == "tuic" or node.protocol == "naive" then node.tls = "1" @@ -1695,11 +1768,27 @@ function gen_config(var) reverse_mapping = true, -- After responding to a DNS query, a reverse mapping of the IP address is stored to provide the domain name for routing purposes. } + for i, v in pairs(GLOBAL.DNS_SERVER) do + table.insert(dns.servers, v.server) + table.insert(dns.rules, { + action = "route", + server = v.server.tag, + domain = v.domain, + }) + end + table.insert(dns.servers, { type = "local", tag = "local" }) + local direct_strategy = "prefer_ipv6" + if direct_dns_query_strategy == "UseIPv4" then + direct_strategy = "ipv4_only" + elseif direct_dns_query_strategy == "UseIPv6" then + direct_strategy = "ipv6_only" + end + if dns_listen_port then local dns_host = "" if flag == "global" then @@ -1837,13 +1926,6 @@ function gen_config(var) }) end - direct_strategy = "prefer_ipv6" - if direct_dns_query_strategy == "UseIPv4" then - direct_strategy = "ipv4_only" - elseif direct_dns_query_strategy == "UseIPv6" then - direct_strategy = "ipv6_only" - end - local server_port = tonumber(direct_dns_udp_port) or 53 table.insert(dns.servers, { @@ -1855,42 +1937,6 @@ function gen_config(var) }) end - local dnsmasq_server_domain = api.get_dnsmasq_server_domain() - if next(dnsmasq_server_domain) then - local new_dns_servers = {} - for domain, v in pairs(dnsmasq_server_domain) do - if not new_dns_servers[v.dnsmasq_dns] then - new_dns_servers[v.dnsmasq_dns] = { - server = { - tag = v.dnsmasq_dns, - type = "udp", - server = v.server, - server_port = v.port, - detour = "direct", - }, - rule = { - action = "route", - domain_suffix = {}, - server = v.dnsmasq_dns, - strategy = direct_strategy, - }, - } - end - table.insert(new_dns_servers[v.dnsmasq_dns].rule.domain_suffix, domain) - end - for k, v in pairs(new_dns_servers) do - table.insert(dns.servers, v.server) - table.insert(dns.rules, 1, v.rule) - table.insert(route.rules, 1, { - action = "route", - network = v.server.type, - ip_cidr = v.server.server, - port = v.server.server_port, - outbound = "direct", - }) - end - end - local default_dns_flag = "remote" if node_id and redir_port then local node = get_node_by_id(node_id) @@ -2083,7 +2129,10 @@ function gen_config(var) if not value["_flag_proxy_tag"] and not value.detour and value["_id"] and value.server and value.server_port and not no_run then sys.call(string.format("echo '%s' >> %s", value["_id"], api.TMP_PATH .. "/direct_node_list")) end - if value.detour then + if not value.detour and value.server then + value.detour = "direct" + end + if value.server and not api.datatypes.hostname(value.server) then value.domain_resolver = nil end for k, v in pairs(config.outbounds[index]) do @@ -2208,7 +2257,155 @@ function gen_proto_config(var) return jsonc.stringify(config, 1) end +function gen_front_dns_config(var) + local dns_listen_port = var["dns_listen_port"] + local direct_dns_udp_server = var["direct_dns_udp_server"] + local direct_dns_udp_port = var["direct_dns_udp_port"] + local direct_dns_query_strategy = var["direct_dns_query_strategy"] + local default_dns_udp_server = var["default_dns_udp_server"] + local default_dns_udp_port = var["default_dns_udp_port"] + + local dns = { + servers = {}, + rules = {} + } + local inbounds = {} + local outbounds = {} + local route = {} + + local direct_strategy = "prefer_ipv6" + if direct_dns_query_strategy == "UseIPv4" then + direct_strategy = "ipv4_only" + elseif direct_dns_query_strategy == "UseIPv6" then + direct_strategy = "ipv6_only" + end + + table.insert(outbounds, { + type = "direct", + tag = "direct", + routing_mark = 255, + domain_resolver = { + server = "direct", + strategy = direct_strategy + } + }) + + local direct_dns_shunt = uci:get(appname, "@global[0]", "direct_dns_shunt") or "" + if #direct_dns_shunt > 0 then + local dns_server = {} + string.gsub(direct_dns_shunt, '[^' .. "\r\n" .. ']+', function(w) + if w:find("#") == 1 then return end + local domain = sys.exec(string.format("echo -n $(echo %s | awk -F ' ' '{print $1}')", w)) + local dns = sys.exec(string.format("echo -n $(echo %s | awk -F ' ' '{print $2}')", w)) + if domain ~= "" and dns ~= "" then + local new_dns_server = parseDNS(dns) + if new_dns_server then + if not dns_server[dns] then + dns_server[dns] = {} + end + if not dns_server[dns].server then + dns_server[dns].server = new_dns_server + dns_server[dns].server.tag = dns + dns_server[dns].server.detour = "direct" + end + if not dns_server[dns].rule then + dns_server[dns].rule = { + action = "route", + server = dns, + domain = {}, + domain_suffix = {}, + domain_keyword = {} + } + end + if domain:find("full:") == 1 then + table.insert(dns_server[dns].rule.domain, domain:sub(1 + #"full:")) + elseif domain:find("domain:") == 1 then + table.insert(dns_server[dns].rule.domain_suffix, domain:sub(1 + #"domain:")) + else + table.insert(dns_server[dns].rule.domain_keyword, domain) + end + end + end + end) + for k, v in pairs(dns_server) do + table.insert(dns.servers, v.server) + if #v.rule.domain == 0 then v.rule.domain = nil end + if #v.rule.domain_suffix == 0 then v.rule.domain_suffix = nil end + if #v.rule.domain_keyword == 0 then v.rule.domain_keyword = nil end + table.insert(dns.rules, v.rule) + end + end + + if direct_dns_udp_server then + table.insert(dns.servers, { + tag = "direct", + type = "udp", + server = direct_dns_udp_server, + server_port = tonumber(direct_dns_udp_port) or 53, + detour = "direct" + }) + local node_domain = {} + local nodes_domain_text = sys.exec('uci show passwall2 | grep ".address=" | cut -d "\'" -f 2 | grep "[a-zA-Z]$" | sort -u') + string.gsub(nodes_domain_text, '[^' .. "\r\n" .. ']+', function(w) + table.insert(node_domain, w) + end) + if #node_domain > 0 then + table.insert(dns.rules, { + action = "route", + server = "direct", + domain = node_domain + }) + end + end + + if default_dns_udp_server then + table.insert(dns.servers, { + tag = "default", + type = "udp", + server = default_dns_udp_server, + server_port = tonumber(default_dns_udp_port) or 53, + detour = "direct" + }) + dns.final = "default" + else + dns.final = "direct" + end + + local dns_in_inbound = { + type = "direct", + tag = "dns-in", + listen = "127.0.0.1", + listen_port = tonumber(dns_listen_port), + } + table.insert(inbounds, dns_in_inbound) + + route.rules = {} + table.insert(route.rules, { + action = "hijack-dns", + inbound = dns_in_inbound.tag + }) + table.insert(route.rules, { + action = "sniff", + inbound = dns_in_inbound.tag + }) + route.final = "direct" + + local config = { + log = { + disabled = true, + level = "debug", + timestamp = true, + }, + dns = dns, + inbounds = inbounds, + outbounds = outbounds, + route = route + } + return jsonc.stringify(config, 1) +end + _G.gen_config = gen_config +_G.gen_front_dns_config = gen_front_dns_config _G.gen_proto_config = gen_proto_config _G.geo_convert_srs = geo_convert_srs diff --git a/openwrt-passwall2/luci-app-passwall2/luasrc/passwall2/util_xray.lua b/openwrt-passwall2/luci-app-passwall2/luasrc/passwall2/util_xray.lua index 81304d5777..b76714e825 100644 --- a/openwrt-passwall2/luci-app-passwall2/luasrc/passwall2/util_xray.lua +++ b/openwrt-passwall2/luci-app-passwall2/luasrc/passwall2/util_xray.lua @@ -7,6 +7,10 @@ local appname = api.appname local fs = api.fs local CACHE_PATH = api.CACHE_PATH +local GLOBAL = { + DNS_SERVER = {} +} + local xray_version = api.get_app_version("xray") local function get_domain_excluded() @@ -24,6 +28,35 @@ local function get_domain_excluded() return hosts end +function parseDNS(str) + local result_dns_server + -- [proto]://[ip] + -- [proto]://[ip]:[port] + -- https://[ip]/[path] + -- https://[ip]:[port]/[path] + local _a = api.parseURL(str) + if _a then + if _a.protocol == "tcp" or _a.protocol == "udp" or _a.protocol == "https" then + result_dns_server = { + address = str + } + if _a.protocol == "udp" then + result_dns_server.address = _a.hostname + end + if _a.port then + result_dns_server.port = _a.port + else + if _a.protocol == "https" then + result_dns_server.port = 443 + else + result_dns_server.port = 53 + end + end + end + end + return result_dns_server +end + function gen_outbound(flag, node, tag, proxy_table) local result = nil if node then @@ -130,6 +163,7 @@ function gen_outbound(flag, node, tag, proxy_table) streamSettings = (node.streamSettings or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan" or node.protocol == "hysteria") and { sockopt = { mark = 255, + domainStrategy = node.domain_strategy or "UseIP", tcpFastOpen = (node.tcp_fast_open == "1") and true or nil, tcpMptcp = (node.tcpMptcp == "1") and true or nil }, @@ -394,6 +428,43 @@ function gen_outbound(flag, node, tag, proxy_table) end end + if api.datatypes.hostname(node.address) and node.domain_resolver and (node.domain_resolver_dns or node.domain_resolver_dns_https) then + local dns_tag = node_id .. "_dns" + local dns_proto = node.domain_resolver + local config_address + local config_port + if dns_proto == "https" then + local _a = api.parseURL(node.domain_resolver_dns_https) + if _a then + config_address = node.domain_resolver_dns_https + if _a.port then + config_port = _a.port + else + config_port = 443 + end + end + else + local server_address = node.domain_resolver_dns + local config_port = 53 + local split = api.split(server_address, ":") + if #split > 1 then + server_address = split[1] + config_port = tonumber(split[#split]) + end + config_address = server_address + if dns_proto == "tcp" then + config_address = dns_proto .. "://" .. server_address .. ":" .. config_port + end + end + GLOBAL.DNS_SERVER[node_id] = { + tag = dns_tag, + queryStrategy = node.domain_strategy or "UseIP", + address = config_address, + port = config_port, + domains = {"full:" .. node.address} + } + end + end return result end @@ -1386,6 +1457,19 @@ function gen_config(var) end end + local dns_servers = {} + local direct_dns_tag = "dns-in-direct" + local remote_dns_tag = "dns-in-remote" + local remote_fakedns_tag = "dns-in-remote-fakedns" + local default_dns_tag = "dns-in-default" + + for i, v in pairs(GLOBAL.DNS_SERVER) do + table.insert(dns_servers, { + server = v, + outboundTag = "direct" + }) + end + dns = { tag = "dns-global", hosts = {}, @@ -1396,21 +1480,24 @@ function gen_config(var) queryStrategy = "UseIP" } - local dns_servers = {} - - table.insert(dns_servers, { - server = { - tag = "local", - address = "localhost" + local _direct_dns = nil + if direct_dns_udp_server then + _direct_dns = { + tag = direct_dns_tag, + address = direct_dns_udp_server, + port = tonumber(direct_dns_udp_port) or 53, + queryStrategy = (direct_dns_query_strategy and direct_dns_query_strategy ~= "") and direct_dns_query_strategy or "UseIP" } - }) + + if _direct_dns.address then + table.insert(dns_servers, { + outboundTag = "direct", + server = _direct_dns + }) + end + end if dns_listen_port then - local direct_dns_tag = "dns-in-direct" - local remote_dns_tag = "dns-in-remote" - local remote_fakedns_tag = "dns-in-remote-fakedns" - local default_dns_tag = "dns-in-default" - local _remote_dns_proto = "tcp" if not routing then @@ -1508,8 +1595,7 @@ function gen_config(var) server = _remote_fakedns }) end - - local _direct_dns = nil + if direct_dns_udp_server then local domain = {} local nodes_domain_text = sys.exec('uci show passwall2 | grep ".address=" | cut -d "\'" -f 2 | grep "[a-zA-Z]$" | sort -u') @@ -1517,57 +1603,10 @@ function gen_config(var) table.insert(domain, "full:" .. w) end) if #domain > 0 then - table.insert(dns_domain_rules, 1, { - shunt_rule_name = "logic-vpslist", - outboundTag = "direct", - domain = domain - }) - end - - _direct_dns = { - tag = direct_dns_tag, - address = direct_dns_udp_server, - port = tonumber(direct_dns_udp_port) or 53, - queryStrategy = (direct_dns_query_strategy and direct_dns_query_strategy ~= "") and direct_dns_query_strategy or "UseIP", - } - - if _direct_dns.address then - table.insert(dns_servers, { - outboundTag = "direct", - server = _direct_dns - }) - end - end - - local dnsmasq_server_domain = api.get_dnsmasq_server_domain() - if next(dnsmasq_server_domain) then - local new_dns_servers = {} - for domain, v in pairs(dnsmasq_server_domain) do - if not new_dns_servers[v.dnsmasq_dns] then - new_dns_servers[v.dnsmasq_dns] = { - server = { - tag = v.dnsmasq_dns, - address = v.server, - port = v.port, - queryStrategy = (direct_dns_query_strategy and direct_dns_query_strategy ~= "") and direct_dns_query_strategy or "UseIP" - }, - domain = {} - } - end - table.insert(new_dns_servers[v.dnsmasq_dns].domain, domain) - end - for k, v in pairs(new_dns_servers) do - table.insert(dns_domain_rules, 1, { - shunt_rule_name = k, - outboundTag = "direct", - dns_server = v.server, - domain = v.domain - }) - table.insert(routing.rules, 1, { - network = "udp", - ip = v.server.address, - port = v.server.port, - outboundTag = "direct" + table.insert(dns.servers, 1, { + tag = "local", + address = "localhost", + domains = domain }) end end @@ -1673,7 +1712,6 @@ function gen_config(var) dns_server = nil end if dns_server then - dns_server.finalQuery = true dns_server.domains = value.domain if value.shunt_rule_name then dns_server.tag = "dns-in-" .. value.shunt_rule_name @@ -1686,25 +1724,6 @@ function gen_config(var) end end end - - for i = #dns_servers, 1, -1 do - local value = dns_servers[i] - if value.server.tag ~= direct_dns_tag and value.server.tag ~= remote_dns_tag then - -- DNS rule must be at the front, prevents being matched by rules. - if value.outboundTag and value.server.address ~= "fakedns" then - table.insert(routing.rules, 1, { - inboundTag = { - value.server.tag - }, - outboundTag = value.outboundTag, - }) - end - if (value.server.domains and #value.server.domains > 0) or value.server.tag == default_dns_tag then - -- Only keep default DNS server or has domains DNS server. - table.insert(dns.servers, 1, value.server) - end - end - end end local default_rule_index = nil @@ -1759,6 +1778,40 @@ function gen_config(var) dns.hosts = nil end + for i = #dns_servers, 1, -1 do + local value = dns_servers[i] + if value.server.tag ~= direct_dns_tag and value.server.tag ~= remote_dns_tag then + -- DNS rule must be at the front, prevents being matched by rules. + if value.outboundTag and value.server.address ~= "fakedns" then + table.insert(routing.rules, 1, { + inboundTag = { + value.server.tag + }, + outboundTag = value.outboundTag, + }) + end + if (value.server.domains and #value.server.domains > 0) or value.server.tag == default_dns_tag then + -- Only keep default DNS server or has domains DNS server. + table.insert(dns.servers, 1, value.server) + end + end + end + + local has_default_dns_server = "0" + for index, value in ipairs(dns.servers) do + if value.domains == nil then + has_default_dns_server = "1" + break + end + end + + if #dns.servers == 0 or not has_default_server == "0" then + table.insert(dns.servers, 1, { + tag = "local", + address = "localhost" + }) + end + if redir_port then local inbound = { port = tonumber(redir_port), @@ -1980,250 +2033,154 @@ function gen_proto_config(var) return jsonc.stringify(config, 1) end -function gen_dns_config(var) +function gen_front_dns_config(var) local dns_listen_port = var["dns_listen_port"] - local dns_out_tag = var["dns_out_tag"] local direct_dns_udp_server = var["direct_dns_udp_server"] local direct_dns_udp_port = var["direct_dns_udp_port"] - local direct_dns_tcp_server = var["direct_dns_tcp_server"] - local direct_dns_tcp_port = var["direct_dns_tcp_port"] - local direct_dns_doh_url = var["direct_dns_doh_url"] - local direct_dns_doh_host = var["direct_dns_doh_host"] - local direct_dns_doh_ip = var["direct_dns_doh_ip"] - local direct_dns_doh_port = var["direct_dns_doh_port"] - local direct_dns_query_strategy = var["direct_dns_query_strategy"] - local remote_dns_udp_server = var["remote_dns_udp_server"] - local remote_dns_udp_port = var["remote_dns_udp_port"] - local remote_dns_tcp_server = var["remote_dns_tcp_server"] - local remote_dns_tcp_port = var["remote_dns_tcp_port"] - local remote_dns_doh_url = var["remote_dns_doh_url"] - local remote_dns_doh_host = var["remote_dns_doh_host"] - local remote_dns_doh_ip = var["remote_dns_doh_ip"] - local remote_dns_doh_port = var["remote_dns_doh_port"] - local remote_dns_query_strategy = var["remote_dns_query_strategy"] - local remote_dns_detour = var["remote_dns_detour"] - local remote_dns_client_ip = var["remote_dns_client_ip"] - local remote_dns_outbound_socks_address = var["remote_dns_outbound_socks_address"] - local remote_dns_outbound_socks_port = var["remote_dns_outbound_socks_port"] - local dns_cache = var["dns_cache"] - local loglevel = var["loglevel"] or "warning" - + local default_dns_udp_server = var["default_dns_udp_server"] + local default_dns_udp_port = var["default_dns_udp_port"] + + local queryStrategy = "UseIP" + local dns = { + tag = "dns-global-direct", + disableCache = false, + disableFallback = true, + disableFallbackIfMatch = true, + queryStrategy = queryStrategy, + servers = {} + } local inbounds = {} local outbounds = {} - local dns = nil - local routing = nil + local routing = { + rules = {} + } - if dns_listen_port then - routing = { - domainStrategy = "IPOnDemand", - rules = {} - } - - dns = { - tag = "dns-global", - hosts = {}, - disableCache = (dns_cache == "1") and false or true, - disableFallback = true, - disableFallbackIfMatch = true, - servers = {}, - clientIp = (remote_dns_client_ip and remote_dns_client_ip ~= "") and remote_dns_client_ip or nil, - } - - local other_type_dns_proto, other_type_dns_server, other_type_dns_port - - if dns_out_tag == "remote" then - dns.queryStrategy = (remote_dns_query_strategy and remote_dns_query_strategy ~= "") and remote_dns_query_strategy or "UseIPv4" - if remote_dns_detour == "direct" then - dns_out_tag = "direct" - table.insert(outbounds, 1, { - tag = dns_out_tag, - protocol = "freedom", - settings = { - domainStrategy = (direct_dns_query_strategy and direct_dns_query_strategy ~= "") and direct_dns_query_strategy or "UseIP" - }, - streamSettings = { - sockopt = { - mark = 255 - } - } - }) - else - if remote_dns_outbound_socks_address and remote_dns_outbound_socks_port then - table.insert(outbounds, 1, { - tag = dns_out_tag, - protocol = "socks", - streamSettings = { - network = "tcp", - security = "none" - }, - settings = { - servers = { - { - address = remote_dns_outbound_socks_address, - port = tonumber(remote_dns_outbound_socks_port) - } - } - } - }) - end - end - - local _remote_dns = { - tag = "dns-in-remote" + table.insert(outbounds, { + tag = "direct", + protocol = "freedom", + settings = { + domainStrategy = queryStrategy + }, + streamSettings = { + sockopt = { + mark = 255 } - - if remote_dns_udp_server then - _remote_dns.address = remote_dns_udp_server - _remote_dns.port = tonumber(remote_dns_udp_port) or 53 - - other_type_dns_proto = "udp" - other_type_dns_server = remote_dns_udp_server - other_type_dns_port = _remote_dns.port - end - - if remote_dns_tcp_server then - _remote_dns.address = "tcp://" .. remote_dns_tcp_server .. ":" .. tonumber(remote_dns_tcp_port) or 53 - _remote_dns.port = tonumber(remote_dns_tcp_port) or 53 - - other_type_dns_proto = "tcp" - other_type_dns_server = remote_dns_tcp_server - other_type_dns_port = _remote_dns.port - end - - if remote_dns_doh_url and remote_dns_doh_host then - if remote_dns_doh_ip and remote_dns_doh_host ~= remote_dns_doh_ip and not api.is_ip(remote_dns_doh_host) then - dns.hosts[remote_dns_doh_host] = remote_dns_doh_ip + } + }) + + if default_dns_udp_server then + table.insert(dns.servers, { + tag = "default", + address = default_dns_udp_server, + port = tonumber(default_dns_udp_port) or 53, + queryStrategy = queryStrategy, + }) + end + + local direct_dns_shunt = uci:get(appname, "@global[0]", "direct_dns_shunt") or "" + if #direct_dns_shunt > 0 then + local dns_server = {} + string.gsub(direct_dns_shunt, '[^' .. "\r\n" .. ']+', function(w) + if w:find("#") == 1 then return end + local domain = sys.exec(string.format("echo -n $(echo %s | awk -F ' ' '{print $1}')", w)) + local dns = sys.exec(string.format("echo -n $(echo %s | awk -F ' ' '{print $2}')", w)) + if domain ~= "" and dns ~= "" then + local new_dns_server = parseDNS(dns) + if new_dns_server then + if not dns_server[dns] then + dns_server[dns] = {} + end + dns_server[dns].tag = dns + dns_server[dns].queryStrategy = queryStrategy + dns_server[dns].address = new_dns_server.address + dns_server[dns].port = new_dns_server.port + dns_server[dns].finalQuery = true + if not dns_server[dns].domains then + dns_server[dns].domains = {} + end + table.insert(dns_server[dns].domains, domain) end - _remote_dns.address = remote_dns_doh_url - _remote_dns.port = tonumber(remote_dns_doh_port) or 443 end - - table.insert(dns.servers, _remote_dns) - elseif dns_out_tag == "direct" then - dns.queryStrategy = (direct_dns_query_strategy and direct_dns_query_strategy ~= "") and direct_dns_query_strategy or "UseIP" - table.insert(outbounds, 1, { - tag = dns_out_tag, - protocol = "freedom", - settings = { - domainStrategy = dns.queryStrategy + end) + for k, v in pairs(dns_server) do + table.insert(dns.servers, v) + table.insert(routing.rules, { + inboundTag = { + v.tag }, - streamSettings = { - sockopt = { - mark = 255 - } - } + outboundTag = "direct" }) - - local _direct_dns = { - tag = "dns-in-direct" - } - - if direct_dns_udp_server then - _direct_dns.address = direct_dns_udp_server - _direct_dns.port = tonumber(direct_dns_udp_port) or 53 - table.insert(routing.rules, 1, { - ip = { - direct_dns_udp_server - }, - port = tonumber(direct_dns_udp_port) or 53, - network = "udp", - outboundTag = "direct" - }) - - other_type_dns_proto = "udp" - other_type_dns_server = direct_dns_udp_server - other_type_dns_port = _direct_dns.port - end - - if direct_dns_tcp_server then - _direct_dns.address = "tcp+local://" .. direct_dns_tcp_server - _direct_dns.port = tonumber(direct_dns_tcp_port) or 53 - - other_type_dns_proto = "tcp" - other_type_dns_server = direct_dns_tcp_server - other_type_dns_port = _direct_dns.port - end - - if direct_dns_doh_url and direct_dns_doh_host then - if direct_dns_doh_ip and direct_dns_doh_host ~= direct_dns_doh_ip and not api.is_ip(direct_dns_doh_host) then - dns.hosts[direct_dns_doh_host] = direct_dns_doh_ip - end - _direct_dns.address = direct_dns_doh_url:gsub("https://", "https+local://") - _direct_dns.port = tonumber(direct_dns_doh_port) or 443 - end - - table.insert(dns.servers, _direct_dns) end - - local dns_hosts_len = 0 - for key, value in pairs(dns.hosts) do - dns_hosts_len = dns_hosts_len + 1 - end - - if dns_hosts_len == 0 then - dns.hosts = nil - end - - table.insert(inbounds, { - listen = "127.0.0.1", - port = tonumber(dns_listen_port), - protocol = "dokodemo-door", - tag = "dns-in", - settings = { - address = other_type_dns_server or "1.1.1.1", - port = other_type_dns_port or 53, - network = "tcp,udp" - } - }) - - table.insert(outbounds, { - tag = "dns-out", - protocol = "dns", - proxySettings = { - tag = dns_out_tag - }, - settings = { - address = other_type_dns_server or "1.1.1.1", - port = other_type_dns_port or 53, - network = other_type_dns_proto or "tcp", - nonIPQuery = "reject" - } - }) - - table.insert(routing.rules, 1, { - inboundTag = { - "dns-in" - }, - outboundTag = "dns-out" - }) - - table.insert(routing.rules, { - inboundTag = { - "dns-global" - }, - outboundTag = dns_out_tag - }) end - - if inbounds or outbounds then - local config = { - log = { - --dnsLog = true, - loglevel = loglevel - }, - dns = dns, - inbounds = inbounds, - outbounds = outbounds, - routing = routing + + if direct_dns_udp_server then + local node_domain = {} + local nodes_domain_text = sys.exec('uci show passwall2 | grep ".address=" | cut -d "\'" -f 2 | grep "[a-zA-Z]$" | sort -u') + string.gsub(nodes_domain_text, '[^' .. "\r\n" .. ']+', function(w) + table.insert(node_domain, "full:" .. w) + end) + if #node_domain > 0 then + table.insert(dns.servers, { + tag = "direct", + address = direct_dns_udp_server, + port = tonumber(direct_dns_udp_port) or 53, + queryStrategy = queryStrategy, + domains = node_domain + }) + end + end + + table.insert(inbounds, { + tag = "dns-in", + listen = "127.0.0.1", + port = tonumber(dns_listen_port), + protocol = "dokodemo-door", + settings = { + address = "0.0.0.0", + network = "tcp,udp" } - return jsonc.stringify(config, 1) - end - + }) + + table.insert(outbounds, { + tag = "dns-out", + protocol = "dns", + proxySettings = { + tag = "direct" + }, + settings = { + address = direct_dns_udp_server, + port = tonumber(direct_dns_udp_port) or 53, + network = "udp", + nonIPQuery = "skip", + blockTypes = { + 65 + } + } + }) + + table.insert(routing.rules, { + inboundTag = { + "dns-in" + }, + outboundTag = "dns-out" + }) + + local config = { + log = { + dnsLog = true, + loglevel = "debug" + }, + dns = dns, + inbounds = inbounds, + outbounds = outbounds, + routing = routing + } + return jsonc.stringify(config, 1) end _G.gen_config = gen_config +_G.gen_front_dns_config = gen_front_dns_config _G.gen_proto_config = gen_proto_config -_G.gen_dns_config = gen_dns_config if arg[1] then local func =_G[arg[1]] diff --git a/openwrt-passwall2/luci-app-passwall2/po/fa/passwall2.po b/openwrt-passwall2/luci-app-passwall2/po/fa/passwall2.po index 2d7dab7b4b..16d161f10a 100644 --- a/openwrt-passwall2/luci-app-passwall2/po/fa/passwall2.po +++ b/openwrt-passwall2/luci-app-passwall2/po/fa/passwall2.po @@ -121,6 +121,12 @@ msgstr "0 به معنای عدم استفاده است" msgid "Current node: %s" msgstr "گره فعلی: %s" +msgid "Direct domain DNS routing" +msgstr "مسیریابی مستقیم DNS دامنه" + +msgid "Please note that the program will not start if the format is incorrect!" +msgstr "لطفا توجه داشته باشید که اگر قالب نادرست باشد، برنامه شروع نخواهد شد!" + msgid "IP:Port mode acceptable, multi value split with english comma." msgstr "حالت IP:Port قابل قبول است، مقادیر متعدد را با کاما انگلیسی جدا کنید." @@ -1764,6 +1770,12 @@ msgstr "تاخیر (میلی‌ثانیه)" msgid "If is domain name, The requested domain name will be resolved to IP before connect." msgstr "اگر نام دامنه است، نام دامنه درخواست شده قبل از اتصال به IP حل می‌شود." +msgid "Domain DNS Resolve" +msgstr "حل مشکل DNS دامنه" + +msgid "If the node address is a domain name, this DNS will be used for resolution." +msgstr "اگر آدرس گره یک نام دامنه باشد، از این DNS برای حل مسئله استفاده خواهد شد." + msgid "Chain Proxy" msgstr "پروکسی زنجیره‌ای" diff --git a/openwrt-passwall2/luci-app-passwall2/po/ru/passwall2.po b/openwrt-passwall2/luci-app-passwall2/po/ru/passwall2.po index fd19b73739..d72e63e42d 100644 --- a/openwrt-passwall2/luci-app-passwall2/po/ru/passwall2.po +++ b/openwrt-passwall2/luci-app-passwall2/po/ru/passwall2.po @@ -118,6 +118,12 @@ msgstr "0 — отключить функцию" msgid "Current node: %s" msgstr "Текущий узел: %s" +msgid "Direct domain DNS routing" +msgstr "Прямая маршрутизация DNS домена" + +msgid "Please note that the program will not start if the format is incorrect!" +msgstr "Обратите внимание, что программа не запустится, если формат указан неверно!" + msgid "IP:Port mode acceptable, multi value split with english comma." msgstr "Допустим формат IP:Port. Несколько значений указывайте через запятую." @@ -1765,6 +1771,12 @@ msgstr "Задержка (мс)" msgid "If is domain name, The requested domain name will be resolved to IP before connect." msgstr "Если указано доменное имя, оно будет разрешено в IP-адрес перед подключением." +msgid "Domain DNS Resolve" +msgstr "Разрешение DNS-запросов для домена" + +msgid "If the node address is a domain name, this DNS will be used for resolution." +msgstr "Если адрес узла является доменным именем, для разрешения будет использоваться этот DNS-сервер." + msgid "Chain Proxy" msgstr "Цепочка прокси" diff --git a/openwrt-passwall2/luci-app-passwall2/po/zh-cn/passwall2.po b/openwrt-passwall2/luci-app-passwall2/po/zh-cn/passwall2.po index c9d5ec1d3b..c00f93809e 100644 --- a/openwrt-passwall2/luci-app-passwall2/po/zh-cn/passwall2.po +++ b/openwrt-passwall2/luci-app-passwall2/po/zh-cn/passwall2.po @@ -118,6 +118,12 @@ msgstr "0为不使用" msgid "Current node: %s" msgstr "当前节点:%s" +msgid "Direct domain DNS routing" +msgstr "直连域名 DNS 分流" + +msgid "Please note that the program will not start if the format is incorrect!" +msgstr "请注意,格式不正确将无法启动!" + msgid "IP:Port mode acceptable, multi value split with english comma." msgstr "接受 IP:Port 形式的输入,多个以英文逗号分隔。" @@ -1756,6 +1762,12 @@ msgstr "延迟(ms)" msgid "If is domain name, The requested domain name will be resolved to IP before connect." msgstr "如果是域名,域名将在请求发出之前解析为 IP。" +msgid "Domain DNS Resolve" +msgstr "域名 DNS 解析" + +msgid "If the node address is a domain name, this DNS will be used for resolution." +msgstr "如果节点地址是域名,则将使用此 DNS 进行解析。" + msgid "Chain Proxy" msgstr "链式代理" diff --git a/openwrt-passwall2/luci-app-passwall2/po/zh-tw/passwall2.po b/openwrt-passwall2/luci-app-passwall2/po/zh-tw/passwall2.po index 9ffae2b5bb..d3ca033e2e 100644 --- a/openwrt-passwall2/luci-app-passwall2/po/zh-tw/passwall2.po +++ b/openwrt-passwall2/luci-app-passwall2/po/zh-tw/passwall2.po @@ -118,6 +118,12 @@ msgstr "0為不使用" msgid "Current node: %s" msgstr "當前節點:%s" +msgid "Direct domain DNS routing" +msgstr "直連網域 DNS 分流" + +msgid "Please note that the program will not start if the format is incorrect!" +msgstr "請注意,格式不正確將無法啟動!" + msgid "IP:Port mode acceptable, multi value split with english comma." msgstr "接受 IP:Port 形式的輸入,多個以英文逗号分隔。" @@ -1756,6 +1762,12 @@ msgstr "延迟(ms)" msgid "If is domain name, The requested domain name will be resolved to IP before connect." msgstr "如果是域名,域名將在請求發出之前解析為 IP。" +msgid "Domain DNS Resolve" +msgstr "域名 DNS 解析" + +msgid "If the node address is a domain name, this DNS will be used for resolution." +msgstr "如果節點地址是域名,則將使用此 DNS 進行解析。" + msgid "Chain Proxy" msgstr "鏈式代理" diff --git a/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/app.sh b/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/app.sh index 1f5b73eb0f..c2bfcb04ee 100755 --- a/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/app.sh +++ b/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/app.sh @@ -106,14 +106,6 @@ run_xray() { [ -n "$dns_listen_port" ] && { json_add_string "dns_listen_port" "${dns_listen_port}" [ -n "$dns_cache" ] && json_add_string "dns_cache" "${dns_cache}" - - local _dns=$(get_first_dns AUTO_DNS 53 | sed 's/#/:/g') - local _dns_address=$(echo ${_dns} | awk -F ':' '{print $1}') - local _dns_port=$(echo ${_dns} | awk -F ':' '{print $2}') - - DIRECT_DNS_UDP_SERVER=${_dns_address} - DIRECT_DNS_UDP_PORT=${_dns_port} - [ "${node_protocol}" = "_shunt" ] && local write_ipset_direct=$(config_n_get $node write_ipset_direct 0) [ "${write_ipset_direct}" = "1" ] && { direct_dnsmasq_listen_port=$(get_new_port $(expr $dns_listen_port + 1) udp) @@ -188,38 +180,17 @@ run_xray() { [ -n "$remote_dns_client_ip" ] && json_add_string "remote_dns_client_ip" "${remote_dns_client_ip}" local _json2_arg="$(json_dump)" - local independent_dns - if [ -z "${independent_dns}" ]; then - local _json2_keys key - json_load "${_json2_arg}" - json_get_keys _json2_keys - for key in ${_json2_keys}; do - json_get_var "_json2_$key" "$key" - done - json_load "${_json1_arg}" - for key in ${_json2_keys}; do - eval "local _v=\$_json2_$key" - json_add_string "$key" "$_v" - done - else - dns_remote_listen_port=$(get_new_port $(expr ${direct_dnsmasq_listen_port:-${dns_listen_port}} + 1) udp) - V2RAY_DNS_REMOTE_CONFIG="${TMP_PATH}/${flag}_dns_remote.json" - V2RAY_DNS_REMOTE_LOG="${TMP_PATH}/${flag}_dns_remote.log" - V2RAY_DNS_REMOTE_LOG="/dev/null" - json_load "${_json2_arg}" - json_add_string "dns_out_tag" "remote" - json_add_string "dns_listen_port" "${dns_remote_listen_port}" - json_add_string "remote_dns_outbound_socks_address" "127.0.0.1" - json_add_string "remote_dns_outbound_socks_port" "${socks_port}" - _json2_arg="$(json_dump)" - lua $UTIL_XRAY gen_dns_config "${_json2_arg}" > $V2RAY_DNS_REMOTE_CONFIG - ln_run "$XRAY_BIN" "xray" $V2RAY_DNS_REMOTE_LOG run -c "$V2RAY_DNS_REMOTE_CONFIG" - - json_load "${_json1_arg}" - json_add_string "remote_dns_udp_port" "${dns_remote_listen_port}" - json_add_string "remote_dns_udp_server" "127.0.0.1" - json_add_string "remote_dns_query_strategy" "${remote_dns_query_strategy}" - fi + local _json2_keys key + json_load "${_json2_arg}" + json_get_keys _json2_keys + for key in ${_json2_keys}; do + json_get_var "_json2_$key" "$key" + done + json_load "${_json1_arg}" + for key in ${_json2_keys}; do + eval "local _v=\$_json2_$key" + json_add_string "$key" "$_v" + done } [ -n "${redir_port}" ] && { @@ -290,13 +261,6 @@ run_singbox() { } } [ -n "$dns_listen_port" ] && { - local _dns=$(get_first_dns AUTO_DNS 53 | sed 's/#/:/g') - local _dns_address=$(echo ${_dns} | awk -F ':' '{print $1}') - local _dns_port=$(echo ${_dns} | awk -F ':' '{print $2}') - - DIRECT_DNS_UDP_SERVER=${_dns_address} - DIRECT_DNS_UDP_PORT=${_dns_port} - [ "${node_protocol}" = "_shunt" ] && local write_ipset_direct=$(config_n_get $node write_ipset_direct 0) [ "${write_ipset_direct}" = "1" ] && { direct_dnsmasq_listen_port=$(get_new_port $(expr $dns_listen_port + 1) udp) @@ -633,8 +597,6 @@ run_global() { TYPE=$(echo $(config_n_get $NODE type) | tr 'A-Z' 'a-z') [ -z "$TYPE" ] && return 1 - mkdir -p ${GLOBAL_ACL_PATH} - if [ $PROXY_IPV6 == "1" ]; then log_i18n 0 "To enable experimental IPv6 transparent proxy (TProxy), please ensure your node and type support IPv6!" fi @@ -712,8 +674,62 @@ run_global() { return 1 fi + set_cache_var "ACL_GLOBAL_node" "$NODE" + set_cache_var "ACL_GLOBAL_redir_port" "$REDIR_PORT" +} + +run_front_dns() { + local switch=0 + direct_dns_shunt=$(config_t_get global direct_dns_shunt) + direct_dns_shunt=$(echo "${direct_dns_shunt}" | grep -v "^#") + [ -n "${direct_dns_shunt}" ] && switch=1 + [ "${switch}" == "1" ] && { + local config_file="${TMP_PATH}/direct_dns.json" + local log_file="${TMP_PATH}/direct_dns.log" + log_file="/dev/null" + local listen_port=$(get_new_port 10553) + json_init + json_add_string "dns_listen_port" "${listen_port}" + json_add_string "direct_dns_udp_server" "${DIRECT_DNS_UDP_SERVER}" + json_add_string "direct_dns_udp_port" "${DIRECT_DNS_UDP_PORT}" + json_add_string "direct_dns_query_strategy" "${DIRECT_DNS_QUERY_STRATEGY}" + [ -n "${ACL_GLOBAL_node}" ] && [ -n "${TUN_DNS_PORT}" ] && { + json_add_string "default_dns_udp_server" "127.0.0.1" + json_add_string "default_dns_udp_port" "${TUN_DNS_PORT}" + } + local _json_arg="$(json_dump)" + + local preferred_core="" + [ -n "${XRAY_BIN}" ] && preferred_core="xray" + [ -n "${SINGBOX_BIN}" ] && preferred_core="sing-box" + + if [ "${preferred_core}" = "xray" ]; then + lua $UTIL_XRAY gen_front_dns_config "${_json_arg}" > $config_file + ln_run "$XRAY_BIN" "xray" "${log_file}" run -c "$config_file" + elif [ "${preferred_core}" = "sing-box" ]; then + lua $UTIL_SINGBOX gen_front_dns_config "${_json_arg}" > $config_file + ln_run "$SINGBOX_BIN" "sing-box" "${log_file}" run -c "$config_file" + else + return 1 + fi + + FRONT_DNS_SERVER="127.0.0.1" + FRONT_DNS_PORT="${listen_port}" + } +} + +run_global_dnsmasq() { + [ -z "${ACL_GLOBAL_node}" ] && [ -z "${FRONT_DNS_PORT}" ] && return local RUN_NEW_DNSMASQ=1 RUN_NEW_DNSMASQ=${DNS_REDIRECT} + DNSMASQ_DEFAULT_DNS="${AUTO_DNS}" + DNSMASQ_LOCAL_DNS="${LOCAL_DNS:-${AUTO_DNS}}" + DNSMASQ_TUN_DNS="${TUN_DNS}" + [ -n "${FRONT_DNS_PORT}" ] && { + DNSMASQ_DEFAULT_DNS="${FRONT_DNS_SERVER}#${FRONT_DNS_PORT}" + DNSMASQ_LOCAL_DNS="${DNSMASQ_DEFAULT_DNS}" + DNSMASQ_TUN_DNS="${DNSMASQ_DEFAULT_DNS}" + } if [ "${RUN_NEW_DNSMASQ}" == "0" ]; then #The old logic will be removed in the future. #Run a copy dnsmasq instance, DNS hijack that don't need a proxy devices. @@ -738,9 +754,9 @@ run_global() { json_add_string "FLAG" "default" json_add_string "TMP_DNSMASQ_PATH" "${GLOBAL_DNSMASQ_CONF_PATH}" json_add_string "DNSMASQ_CONF_FILE" "${GLOBAL_DNSMASQ_CONF}" - json_add_string "DEFAULT_DNS" "${AUTO_DNS}" - json_add_string "LOCAL_DNS" "${LOCAL_DNS:-${AUTO_DNS}}" - json_add_string "TUN_DNS" "${TUN_DNS}" + json_add_string "DEFAULT_DNS" "${DNSMASQ_DEFAULT_DNS}" + json_add_string "LOCAL_DNS" "${DNSMASQ_LOCAL_DNS}" + json_add_string "TUN_DNS" "${DNSMASQ_TUN_DNS}" json_add_string "NFTFLAG" "${nftflag:-0}" json_add_string "NO_LOGIC_LOG" "${NO_LOGIC_LOG:-0}" lua $APP_PATH/helper_dnsmasq.lua add_rule "$(json_dump)" @@ -753,14 +769,11 @@ run_global() { else #Run a copy dnsmasq instance, DNS hijack for that need proxy devices. GLOBAL_DNSMASQ_PORT=$(get_new_port 11400) - run_copy_dnsmasq flag="default" listen_port=$GLOBAL_DNSMASQ_PORT tun_dns="${TUN_DNS}" + run_copy_dnsmasq flag="default" listen_port=$GLOBAL_DNSMASQ_PORT tun_dns="${DNSMASQ_TUN_DNS}" DNS_REDIRECT_PORT=${GLOBAL_DNSMASQ_PORT} #dhcp.leases to hosts $APP_PATH/lease2hosts.sh > /dev/null 2>&1 & fi - - set_cache_var "ACL_GLOBAL_node" "$NODE" - set_cache_var "ACL_GLOBAL_redir_port" "$REDIR_PORT" } start_socks() { @@ -1188,7 +1201,10 @@ start() { lua $APP_PATH/helper_dnsmasq.lua restart "$(json_dump)" } fi + mkdir -p ${GLOBAL_ACL_PATH} [ "$ENABLED_DEFAULT_ACL" == 1 ] && run_global + run_front_dns + run_global_dnsmasq [ -n "$USE_TABLES" ] && source $APP_PATH/${USE_TABLES}.sh start set_cache_var "USE_TABLES" "$USE_TABLES" if [ "$ENABLED_DEFAULT_ACL" == 1 ] || [ "$ENABLED_ACLS" == 1 ]; then @@ -1312,6 +1328,12 @@ get_config() { [ -z "${DEFAULT_DNS}" ] && DEFAULT_DNS=$(echo -n $ISP_DNS | tr ' ' '\n' | head -2 | tr '\n' ',' | sed 's/,$//') AUTO_DNS=${DEFAULT_DNS:-119.29.29.29} + local AUTO_DNS2=$(get_first_dns AUTO_DNS 53 | sed 's/#/:/g') + local AUTO_DNS_ADDRESS=$(echo ${AUTO_DNS2} | awk -F ':' '{print $1}') + local AUTO_DNS_PORT=$(echo ${AUTO_DNS2} | awk -F ':' '{print $2}') + DIRECT_DNS_UDP_SERVER=${AUTO_DNS_ADDRESS} + DIRECT_DNS_UDP_PORT=${AUTO_DNS_PORT} + DNSMASQ_CONF_DIR=/tmp/dnsmasq.d DEFAULT_DNSMASQ_CFGID="$(uci -q show "dhcp.@dnsmasq[0]" | awk 'NR==1 {split($0, conf, /[.=]/); print conf[2]}')" if [ -f "/tmp/etc/dnsmasq.conf.$DEFAULT_DNSMASQ_CFGID" ]; then diff --git a/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/helper_dnsmasq.lua b/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/helper_dnsmasq.lua index 9fab4d1030..c15d7d3726 100644 --- a/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/helper_dnsmasq.lua +++ b/openwrt-passwall2/luci-app-passwall2/root/usr/share/passwall2/helper_dnsmasq.lua @@ -272,7 +272,7 @@ function add_rule(var) local function process_address(address) if address == "engage.cloudflareclient.com" then return end if datatypes.hostname(address) then - --set_domain_dns(address, fwd_dns) + set_domain_dns(address, fwd_dns) set_domain_ipset(address, setflag_4 .. "passwall2_vps," .. setflag_6 .. "passwall2_vps6") end end diff --git a/shadowsocks-rust/Cargo.lock b/shadowsocks-rust/Cargo.lock index 6ec9abb131..5ae607cc2a 100644 --- a/shadowsocks-rust/Cargo.lock +++ b/shadowsocks-rust/Cargo.lock @@ -140,7 +140,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -151,7 +151,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -883,7 +883,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -996,7 +996,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -2245,7 +2245,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -2620,7 +2620,7 @@ dependencies = [ "once_cell", "socket2 0.5.10", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -2897,7 +2897,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -2956,7 +2956,7 @@ dependencies = [ "security-framework 3.5.1", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -3456,7 +3456,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -3602,7 +3602,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -3734,9 +3734,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.51.0" +version = "1.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd1c4c0fc4a7ab90fc15ef6daaa3ec3b893f004f915f2392557ed23237820cd" +checksum = "f66bf9585cda4b724d3e78ab34b73fb2bbaba9011b9bfdf69dc836382ea13b8c" dependencies = [ "bytes", "libc", diff --git a/small/luci-app-momo/Makefile b/small/luci-app-momo/Makefile index 4e2814bbe3..5b60a71ff1 100644 --- a/small/luci-app-momo/Makefile +++ b/small/luci-app-momo/Makefile @@ -1,6 +1,6 @@ include $(TOPDIR)/rules.mk -PKG_VERSION:=1.1.1 +PKG_VERSION:=1.2.0 LUCI_TITLE:=LuCI Support for momo LUCI_DEPENDS:=+luci-base +momo diff --git a/small/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js b/small/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js index 7d95b66069..27840a3cef 100644 --- a/small/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js +++ b/small/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js @@ -114,7 +114,7 @@ return view.extend({ o = s.option(form.Flag, 'scheduled_restart', _('Scheduled Restart')); o.rmempty = false; - o = s.option(form.Value, 'cron_expression', _('Cron Expression')); + o = s.option(form.Value, 'scheduled_restart_cron', _('Scheduled Restart Cron')); o.retain = true; o.rmempty = false; o.depends('scheduled_restart', '1'); diff --git a/small/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js b/small/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js index 22641512b8..7fdc9c5c63 100644 --- a/small/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js +++ b/small/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js @@ -24,35 +24,31 @@ return view.extend({ m = new form.Map('momo'); - s = m.section(form.NamedSection, 'log', 'log', _('Log Cleanup')); + s = m.section(form.NamedSection, 'log', 'log', _('Log')); - o = s.option(form.Flag, 'log_cleanup_enabled', _('Scheduled Log Cleanup')); + s.tab('log_config', _('Log Config')); + + o = s.taboption('log_config', form.Flag, 'scheduled_clear', _('Scheduled Clear')); o.rmempty = false; - - o = s.option(form.Value, 'log_cleanup_cron_expression', _('Log Cleanup Cron Expression')); + + o = s.taboption('log_config', form.Value, 'scheduled_clear_cron', _('Scheduled Clear Cron')); o.retain = true; o.rmempty = false; - o.placeholder = '0 4 * * *'; - o.depends('log_cleanup_enabled', '1'); - o.description = _('Run unconditional log cleanup at the configured cron schedule.'); + o.depends('scheduled_clear', '1'); - o = s.option(form.Flag, 'log_cleanup_size_enabled', _('Size-based Log Cleanup')); - o.rmempty = false; - - o = s.option(form.Value, 'log_cleanup_size_check_cron_expression', _('Log Size Check Cron Expression')); + o = s.taboption('log_config', form.Value, 'scheduled_clear_size_limit', _('Scheduled Clear Size Limit')); o.retain = true; o.rmempty = false; - o.placeholder = '*/30 * * * *'; - o.depends('log_cleanup_size_enabled', '1'); - o.description = _('Check log size at the configured cron schedule before cleaning up.'); - - o = s.option(form.Value, 'log_cleanup_size_mb', _('Log Cleanup Size Threshold (MB)')); o.datatype = 'uinteger'; - o.placeholder = '50'; - o.depends('log_cleanup_size_enabled', '1'); - o.description = _('Clear app, core and debug logs when their total size reaches this threshold.'); + o.depends('scheduled_clear', '1'); - s = m.section(form.NamedSection, 'placeholder', 'placeholder', _('Log')); + o = s.taboption('log_config', form.ListValue, 'scheduled_clear_size_limit_unit', _('Scheduled Clear Size Limit Unit')); + o.retain = true; + o.rmempty = false; + o.depends('scheduled_clear', '1'); + o.value('KB', 'KB'); + o.value('MB', 'MB'); + o.value('GB', 'GB'); s.tab('app_log', _('App Log')); diff --git a/small/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js b/small/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js new file mode 100644 index 0000000000..3bdc5e28c5 --- /dev/null +++ b/small/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js @@ -0,0 +1,154 @@ +'use strict'; +'require form'; +'require view'; +'require uci'; +'require fs'; +'require network'; +'require poll'; +'require tools.widgets as widgets'; +'require tools.momo as momo'; + +return view.extend({ + load: function () { + return Promise.all([ + uci.load('momo'), + ]); + }, + render: function (data) { + let m, s, o; + + m = new form.Map('momo'); + + s = m.section(form.NamedSection, 'mixin', 'mixin', _('Mixin Option')); + + s.tab('log', _('Log Config')); + + o = s.taboption('log', form.ListValue, 'log_disabled', _('Log Disabled')); + o.optional = true; + o.placeholder = _('Unmodified'); + o.value('0', _('Disable')); + o.value('1', _('Enable')); + + o = s.taboption('log', form.ListValue, 'log_level', _('Log Level')); + o.optional = true; + o.placeholder = _('Unmodified'); + o.value('panic'); + o.value('fatal'); + o.value('error'); + o.value('warn'); + o.value('info'); + o.value('debug'); + o.value('trace'); + + o = s.taboption('log', form.ListValue, 'log_timestamp', _('Log Timestamp')); + o.optional = true; + o.placeholder = _('Unmodified'); + o.value('0', _('Disable')); + o.value('1', _('Enable')); + + o = s.taboption('log', form.Value, 'log_output', _('Log Output')); + o.placeholder = _('Unmodified'); + + s.tab('dns', _('DNS Config')); + + o = s.taboption('dns', form.ListValue, 'dns_strategy', _('DNS Strategy')); + o.optional = true; + o.placeholder = _('Unmodified'); + o.value('prefer_ipv4', _('Prefer IPv4')); + o.value('prefer_ipv6', _('Prefer IPv6')); + o.value('ipv4_only', _('IPv4 Only')); + o.value('ipv6_only', _('IPv6 Only')); + + o = s.taboption('dns', form.ListValue, 'dns_disable_cache', _('DNS Disable Cache')); + o.optional = true; + o.placeholder = _('Unmodified'); + o.value('0', _('Disable')); + o.value('1', _('Enable')); + + o = s.taboption('dns', form.ListValue, 'dns_disable_expire', _('DNS Disable Expire')); + o.optional = true; + o.placeholder = _('Unmodified'); + o.value('0', _('Disable')); + o.value('1', _('Enable')); + + o = s.taboption('dns', form.ListValue, 'dns_independent_cache', _('DNS Independent Cache')); + o.optional = true; + o.placeholder = _('Unmodified'); + o.value('0', _('Disable')); + o.value('1', _('Enable')); + + o = s.taboption('dns', form.Value, 'dns_cache_capacity', _('DNS Cache Capacity')); + o.datatype = 'uinteger'; + o.placeholder = _('Unmodified'); + + o = s.taboption('dns', form.ListValue, 'dns_reverse_mapping', _('DNS Reverse Mapping')); + o.optional = true; + o.placeholder = _('Unmodified'); + o.value('0', _('Disable')); + o.value('1', _('Enable')); + + s.tab('ntp', _('NTP Config')); + + o = s.taboption('ntp', form.ListValue, 'ntp_enabled', _('NTP Enabled')); + o.optional = true; + o.placeholder = _('Unmodified'); + o.value('0', _('Disable')); + o.value('1', _('Enable')); + + o = s.taboption('ntp', form.Value, 'ntp_server', _('NTP Server')); + o.placeholder = _('Unmodified'); + + o = s.taboption('ntp', form.Value, 'ntp_server_port', _('NTP Server Port')); + o.datatype = 'port'; + o.placeholder = _('Unmodified'); + + o = s.taboption('ntp', form.Value, 'ntp_interval', _('NTP Interval')); + o.placeholder = _('Unmodified'); + + s.tab('cache', _('Cache Config')); + + o = s.taboption('cache', form.ListValue, 'cache_enabled', _('Cache Enabled')); + o.optional = true; + o.placeholder = _('Unmodified'); + o.value('0', _('Disable')); + o.value('1', _('Enable')); + + o = s.taboption('cache', form.Value, 'cache_path', _('Cache Path')); + o.placeholder = _('Unmodified'); + + o = s.taboption('cache', form.ListValue, 'cache_store_fakeip', _('Cache Store FakeIP')); + o.optional = true; + o.placeholder = _('Unmodified'); + o.value('0', _('Disable')); + o.value('1', _('Enable')); + + o = s.taboption('cache', form.ListValue, 'cache_store_rdrc', _('Cache Store RDRC')); + o.optional = true; + o.placeholder = _('Unmodified'); + o.value('0', _('Disable')); + o.value('1', _('Enable')); + + s.tab('external_control', _('External Control Config')); + + o = s.taboption('external_control', form.Value, 'external_control_ui_path', _('UI Path')); + o.placeholder = _('Unmodified'); + + o = s.taboption('external_control', form.Value, 'external_control_ui_download_url', _('UI Download Url')); + o.placeholder = _('Unmodified'); + o.value('https://github.com/Zephyruso/zashboard/releases/latest/download/dist-cdn-fonts.zip', 'Zashboard (CDN Fonts)'); + o.value('https://github.com/Zephyruso/zashboard/releases/latest/download/dist.zip', 'Zashboard'); + o.value('https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip', 'MetaCubeXD'); + o.value('https://github.com/MetaCubeX/Yacd-meta/archive/refs/heads/gh-pages.zip', 'YACD'); + o.value('https://github.com/MetaCubeX/Razord-meta/archive/refs/heads/gh-pages.zip', 'Razord'); + + o = s.taboption('external_control', form.Value, 'external_control_api_listen', _('API Listen')); + o.datatype = 'ipaddrport(1)'; + o.placeholder = _('Unmodified'); + + o = s.taboption('external_control', form.Value, 'external_control_api_secret', _('API Secret')); + o.password = true; + o.placeholder = _('Unmodified'); + + return m.render(); + } +}); \ No newline at end of file diff --git a/small/luci-app-momo/po/templates/momo.pot b/small/luci-app-momo/po/templates/momo.pot index 3b4e7bdee9..e84f1adc2c 100644 --- a/small/luci-app-momo/po/templates/momo.pot +++ b/small/luci-app-momo/po/templates/momo.pot @@ -1,6 +1,14 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:144 +msgid "API Listen" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:148 +msgid "API Secret" +msgstr "" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:69 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:122 msgid "Access Control" @@ -24,7 +32,7 @@ msgstr "" msgid "App Config" msgstr "" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:29 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:53 msgid "App Log" msgstr "" @@ -56,6 +64,26 @@ msgstr "" msgid "CGroup" msgstr "" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:108 +msgid "Cache Config" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:110 +msgid "Cache Enabled" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:116 +msgid "Cache Path" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:119 +msgid "Cache Store FakeIP" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:125 +msgid "Cache Store RDRC" +msgstr "" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/editor.js:27 msgid "Choose File" msgstr "" @@ -64,8 +92,8 @@ msgstr "" msgid "Choose Profile" msgstr "" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:33 -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:66 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:57 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:90 msgid "Clear Log" msgstr "" @@ -74,7 +102,7 @@ msgstr "" msgid "Commonly Used Port" msgstr "" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:62 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:86 msgid "Core Log" msgstr "" @@ -90,16 +118,40 @@ msgstr "" msgid "Core Version" msgstr "" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:117 -msgid "Cron Expression" -msgstr "" - #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:99 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:165 msgid "DNS" msgstr "" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:95 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:80 +msgid "DNS Cache Capacity" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:52 +msgid "DNS Config" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:62 +msgid "DNS Disable Cache" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:68 +msgid "DNS Disable Expire" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:74 +msgid "DNS Independent Cache" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:84 +msgid "DNS Reverse Mapping" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:54 +msgid "DNS Strategy" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:119 msgid "Debug Log" msgstr "" @@ -111,6 +163,16 @@ msgstr "" msgid "Destination UDP Port to Proxy" msgstr "" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:29 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:46 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:65 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:71 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:77 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:87 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:95 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:113 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:122 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:128 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:53 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:60 msgid "Disable" @@ -121,11 +183,21 @@ msgid "Edit Subscription" msgstr "" #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/editor.js:25 -#: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:37 +#: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:45 msgid "Editor" msgstr "" #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:96 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:30 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:47 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:66 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:72 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:78 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:88 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:96 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:114 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:123 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:129 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:33 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:66 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:77 @@ -138,6 +210,10 @@ msgstr "" msgid "Expire At" msgstr "" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:131 +msgid "External Control Config" +msgstr "" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:48 msgid "Fake-IP Ping Hijack" msgstr "" @@ -155,7 +231,7 @@ msgstr "" msgid "General Config" msgstr "" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:99 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:123 msgid "Generate & Download" msgstr "" @@ -183,6 +259,10 @@ msgstr "" msgid "IPv4 DNS Hijack" msgstr "" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:59 +msgid "IPv4 Only" +msgstr "" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:42 msgid "IPv4 Proxy" msgstr "" @@ -191,6 +271,10 @@ msgstr "" msgid "IPv6 DNS Hijack" msgstr "" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:60 +msgid "IPv6 Only" +msgstr "" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:45 msgid "IPv6 Proxy" msgstr "" @@ -208,19 +292,68 @@ msgid "Local" msgstr "" #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:27 -#: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:45 +#: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:53 msgid "Log" msgstr "" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:29 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:24 +msgid "Log Config" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:26 +msgid "Log Disabled" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:32 +msgid "Log Level" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:49 +msgid "Log Output" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:43 +msgid "Log Timestamp" +msgstr "" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:194 msgid "Misc" msgstr "" +#: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:29 +msgid "Mixin Config" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:22 +msgid "Mixin Option" +msgstr "" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:38 #: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:3 msgid "Momo" msgstr "" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:90 +msgid "NTP Config" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:92 +msgid "NTP Enabled" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:105 +msgid "NTP Interval" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:98 +msgid "NTP Server" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:101 +msgid "NTP Server Port" +msgstr "" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:15 msgid "Not Running" msgstr "" @@ -241,6 +374,14 @@ msgstr "" msgid "Prefer" msgstr "" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:57 +msgid "Prefer IPv4" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:58 +msgid "Prefer IPv6" +msgstr "" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/profile.js:21 #: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:21 msgid "Profile" @@ -257,7 +398,7 @@ msgstr "" #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:29 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:31 -#: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:29 +#: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:37 msgid "Proxy Config" msgstr "" @@ -297,12 +438,32 @@ msgstr "" msgid "Running" msgstr "" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:31 +msgid "Scheduled Clear" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:34 +msgid "Scheduled Clear Cron" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:39 +msgid "Scheduled Clear Size Limit" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:45 +msgid "Scheduled Clear Size Limit Unit" +msgstr "" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:114 msgid "Scheduled Restart" msgstr "" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:56 -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:89 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:117 +msgid "Scheduled Restart Cron" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:80 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:113 msgid "Scroll To Bottom" msgstr "" @@ -385,6 +546,14 @@ msgstr "" msgid "UDP Mode" msgstr "" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:136 +msgid "UI Download Url" +msgstr "" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:133 +msgid "UI Path" +msgstr "" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:139 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:143 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:147 @@ -394,6 +563,31 @@ msgstr "" msgid "Unlimited" msgstr "" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:28 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:34 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:45 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:50 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:56 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:64 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:70 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:76 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:82 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:86 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:94 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:99 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:103 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:106 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:112 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:117 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:121 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:127 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:134 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:137 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:146 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:150 +msgid "Unmodified" +msgstr "" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/profile.js:63 msgid "Update" msgstr "" @@ -425,39 +619,3 @@ msgstr "" #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:128 msgid "procd Config" msgstr "" - -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:47 -msgid "Check log size at the configured cron schedule before cleaning up." -msgstr "" - -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:53 -msgid "Clear app, core and debug logs when their total size reaches this threshold." -msgstr "" - -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:27 -msgid "Log Cleanup" -msgstr "" - -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:32 -msgid "Log Cleanup Cron Expression" -msgstr "" - -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:49 -msgid "Log Cleanup Size Threshold (MB)" -msgstr "" - -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:42 -msgid "Log Size Check Cron Expression" -msgstr "" - -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:37 -msgid "Run unconditional log cleanup at the configured cron schedule." -msgstr "" - -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:29 -msgid "Scheduled Log Cleanup" -msgstr "" - -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:39 -msgid "Size-based Log Cleanup" -msgstr "" diff --git a/small/luci-app-momo/po/zh_Hans/momo.po b/small/luci-app-momo/po/zh_Hans/momo.po index 6ee9ae138b..8e834d9558 100644 --- a/small/luci-app-momo/po/zh_Hans/momo.po +++ b/small/luci-app-momo/po/zh_Hans/momo.po @@ -8,6 +8,14 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:144 +msgid "API Listen" +msgstr "API 监听" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:148 +msgid "API Secret" +msgstr "API 密码" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:69 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:122 msgid "Access Control" @@ -31,7 +39,7 @@ msgstr "全部端口" msgid "App Config" msgstr "插件配置" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:29 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:53 msgid "App Log" msgstr "插件日志" @@ -63,6 +71,26 @@ msgstr "绕过 FWMark" msgid "CGroup" msgstr "控制组" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:108 +msgid "Cache Config" +msgstr "缓存配置" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:110 +msgid "Cache Enabled" +msgstr "启用缓存" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:116 +msgid "Cache Path" +msgstr "缓存文件路径" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:119 +msgid "Cache Store FakeIP" +msgstr "缓存 FakeIP" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:125 +msgid "Cache Store RDRC" +msgstr "缓存 RDRC" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/editor.js:27 msgid "Choose File" msgstr "选择文件" @@ -71,8 +99,8 @@ msgstr "选择文件" msgid "Choose Profile" msgstr "选择配置文件" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:33 -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:66 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:57 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:90 msgid "Clear Log" msgstr "清空日志" @@ -81,7 +109,7 @@ msgstr "清空日志" msgid "Commonly Used Port" msgstr "常用端口" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:62 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:86 msgid "Core Log" msgstr "核心日志" @@ -97,16 +125,40 @@ msgstr "核心状态" msgid "Core Version" msgstr "核心版本" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:117 -msgid "Cron Expression" -msgstr "Cron 表达式" - #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:99 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:165 msgid "DNS" msgstr "DNS" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:95 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:80 +msgid "DNS Cache Capacity" +msgstr "DNS 缓存容量" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:52 +msgid "DNS Config" +msgstr "DNS 配置" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:62 +msgid "DNS Disable Cache" +msgstr "禁用 DNS 缓存" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:68 +msgid "DNS Disable Expire" +msgstr "禁用 DNS 过期" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:74 +msgid "DNS Independent Cache" +msgstr "DNS 独立缓存" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:84 +msgid "DNS Reverse Mapping" +msgstr "DNS 反向映射" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:54 +msgid "DNS Strategy" +msgstr "DNS 策略" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:119 msgid "Debug Log" msgstr "调试日志" @@ -118,6 +170,16 @@ msgstr "要代理的 TCP 目标端口" msgid "Destination UDP Port to Proxy" msgstr "要代理的 UDP 目标端口" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:29 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:46 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:65 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:71 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:77 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:87 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:95 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:113 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:122 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:128 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:53 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:60 msgid "Disable" @@ -128,11 +190,21 @@ msgid "Edit Subscription" msgstr "编辑订阅" #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/editor.js:25 -#: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:37 +#: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:45 msgid "Editor" msgstr "编辑器" #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:96 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:30 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:47 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:66 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:72 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:78 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:88 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:96 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:114 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:123 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:129 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:33 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:66 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:77 @@ -145,6 +217,10 @@ msgstr "启用" msgid "Expire At" msgstr "到期时间" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:131 +msgid "External Control Config" +msgstr "外部控制配置" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:48 msgid "Fake-IP Ping Hijack" msgstr "Fake-IP Ping 劫持" @@ -162,7 +238,7 @@ msgstr "文件:" msgid "General Config" msgstr "全局配置" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:99 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:123 msgid "Generate & Download" msgstr "生成并下载" @@ -190,6 +266,10 @@ msgstr "使用说明" msgid "IPv4 DNS Hijack" msgstr "IPv4 DNS 劫持" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:59 +msgid "IPv4 Only" +msgstr "仅 IPv4" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:42 msgid "IPv4 Proxy" msgstr "IPv4 代理" @@ -198,6 +278,10 @@ msgstr "IPv4 代理" msgid "IPv6 DNS Hijack" msgstr "IPv6 DNS 劫持" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:60 +msgid "IPv6 Only" +msgstr "仅 IPv6" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:45 msgid "IPv6 Proxy" msgstr "IPv6 代理" @@ -215,19 +299,68 @@ msgid "Local" msgstr "本地" #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:27 -#: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:45 +#: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:53 msgid "Log" msgstr "日志" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:29 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:24 +msgid "Log Config" +msgstr "日志配置" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:26 +msgid "Log Disabled" +msgstr "禁用日志" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:32 +msgid "Log Level" +msgstr "日志级别" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:49 +msgid "Log Output" +msgstr "日志输出文件路径" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:43 +msgid "Log Timestamp" +msgstr "打印时间戳" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:194 msgid "Misc" msgstr "杂项" +#: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:29 +msgid "Mixin Config" +msgstr "混入配置" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:22 +msgid "Mixin Option" +msgstr "混入选项" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:38 #: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:3 msgid "Momo" msgstr "Momo" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:90 +msgid "NTP Config" +msgstr "NTP 配置" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:92 +msgid "NTP Enabled" +msgstr "启用 NTP" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:105 +msgid "NTP Interval" +msgstr "NTP 时间同步间隔" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:98 +msgid "NTP Server" +msgstr "NTP 服务地址" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:101 +msgid "NTP Server Port" +msgstr "NTP 服务端口" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:15 msgid "Not Running" msgstr "未在运行" @@ -248,6 +381,14 @@ msgstr "打开面板" msgid "Prefer" msgstr "优先" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:57 +msgid "Prefer IPv4" +msgstr "优先 IPv4" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:58 +msgid "Prefer IPv6" +msgstr "优先 IPv6" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/profile.js:21 #: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:21 msgid "Profile" @@ -264,7 +405,7 @@ msgstr "代理" #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:29 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/proxy.js:31 -#: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:29 +#: applications/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json:37 msgid "Proxy Config" msgstr "代理配置" @@ -304,12 +445,32 @@ msgstr "路由器代理" msgid "Running" msgstr "运行中" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:31 +msgid "Scheduled Clear" +msgstr "定时清除"" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:34 +msgid "Scheduled Clear Cron" +msgstr "Cron 表达式" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:39 +msgid "Scheduled Clear Size Limit" +msgstr "日志大小上限" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:45 +msgid "Scheduled Clear Size Limit Unit" +msgstr "日志大小上限单位" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:114 msgid "Scheduled Restart" msgstr "定时重启" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:56 -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:89 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:117 +msgid "Scheduled Restart Cron" +msgstr "Cron 表达式" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:80 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:113 msgid "Scroll To Bottom" msgstr "滚动到底部" @@ -392,6 +553,14 @@ msgstr "在 OpenWrt 上使用 sing-box 进行透明代理" msgid "UDP Mode" msgstr "UDP 模式" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:136 +msgid "UI Download Url" +msgstr "UI 下载地址" + +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:133 +msgid "UI Path" +msgstr "UI 路径" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:139 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:143 #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:147 @@ -401,6 +570,31 @@ msgstr "UDP 模式" msgid "Unlimited" msgstr "无限制" +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:28 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:34 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:45 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:50 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:56 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:64 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:70 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:76 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:82 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:86 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:94 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:99 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:103 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:106 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:112 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:117 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:121 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:127 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:134 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:137 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:146 +#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/mixin.js:150 +msgid "Unmodified" +msgstr "不修改" + #: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/profile.js:63 msgid "Update" msgstr "更新" @@ -433,38 +627,34 @@ msgstr "用户代理(UA)" msgid "procd Config" msgstr "procd 配置" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:47 -msgid "Check log size at the configured cron schedule before cleaning up." -msgstr "按设定的 Cron 周期检查日志大小,满足条件后再清理。" +#~ msgid "Cron Expression" +#~ msgstr "Cron 表达式" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:53 -msgid "Clear app, core and debug logs when their total size reaches this threshold." -msgstr "当插件日志、核心日志和调试日志总大小达到该阈值时自动清理。" +#~ msgid "Check log size at the configured cron schedule before cleaning up." +#~ msgstr "按设定的 Cron 周期检查日志大小,满足条件后再清理。" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:27 -msgid "Log Cleanup" -msgstr "日志清理" +#~ msgid "" +#~ "Clear app, core and debug logs when their total size reaches this " +#~ "threshold." +#~ msgstr "当插件日志、核心日志和调试日志总大小达到该阈值时自动清理。" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:32 -msgid "Log Cleanup Cron Expression" -msgstr "日志清理 Cron 表达式" +#~ msgid "Log Cleanup" +#~ msgstr "日志清理" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:49 -msgid "Log Cleanup Size Threshold (MB)" -msgstr "日志清理大小阈值(MB)" +#~ msgid "Log Cleanup Cron Expression" +#~ msgstr "日志清理 Cron 表达式" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:42 -msgid "Log Size Check Cron Expression" -msgstr "日志大小检查 Cron 表达式" +#~ msgid "Log Cleanup Size Threshold (MB)" +#~ msgstr "日志清理大小阈值(MB)" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:37 -msgid "Run unconditional log cleanup at the configured cron schedule." -msgstr "按设定的 Cron 时间无条件执行日志清理。" +#~ msgid "Log Size Check Cron Expression" +#~ msgstr "日志大小检查 Cron 表达式" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:29 -msgid "Scheduled Log Cleanup" -msgstr "定时日志清理" +#~ msgid "Run unconditional log cleanup at the configured cron schedule." +#~ msgstr "按设定的 Cron 时间无条件执行日志清理。" -#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:39 -msgid "Size-based Log Cleanup" -msgstr "按大小触发日志清理" +#~ msgid "Scheduled Log Cleanup" +#~ msgstr "定时日志清理" + +#~ msgid "Size-based Log Cleanup" +#~ msgstr "按大小触发日志清理" diff --git a/small/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json b/small/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json index af050de14b..b5feb63206 100644 --- a/small/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json +++ b/small/luci-app-momo/root/usr/share/luci/menu.d/luci-app-momo.json @@ -25,9 +25,17 @@ "path": "momo/profile" } }, + "admin/services/momo/mixin": { + "title": "Mixin Config", + "order": 30, + "action": { + "type": "view", + "path": "momo/mixin" + } + }, "admin/services/momo/proxy": { "title": "Proxy Config", - "order": 30, + "order": 40, "action": { "type": "view", "path": "momo/proxy" @@ -35,7 +43,7 @@ }, "admin/services/momo/editor": { "title": "Editor", - "order": 40, + "order": 50, "action": { "type": "view", "path": "momo/editor" @@ -43,7 +51,7 @@ }, "admin/services/momo/log": { "title": "Log", - "order": 50, + "order": 60, "action": { "type": "view", "path": "momo/log" diff --git a/small/luci-app-momo/root/usr/share/rpcd/ucode/luci.momo b/small/luci-app-momo/root/usr/share/rpcd/ucode/luci.momo index 9dce3295e1..667c616b39 100644 --- a/small/luci-app-momo/root/usr/share/rpcd/ucode/luci.momo +++ b/small/luci-app-momo/root/usr/share/rpcd/ucode/luci.momo @@ -2,8 +2,8 @@ 'use strict'; -import { access, popen, readfile, writefile } from 'fs'; -import { get_paths, merge_exists, get_users, get_groups, get_cgroups } from '/etc/momo/ucode/include.uc'; +import { access, popen, readfile } from 'fs'; +import { get_paths, merge_exists, get_users, get_groups, get_cgroups, load_profile, save_profile } from '/etc/momo/ucode/include.uc'; const methods = { get_paths: { @@ -40,9 +40,8 @@ const methods = { profile: { args: { defaults: {} }, call: function(req) { - const paths = get_paths(); const defaults = req.args?.defaults ?? {}; - const profile = json(readfile(paths.run_profile_path)); + const profile = load_profile(); return merge_exists(defaults, profile); } }, @@ -67,8 +66,7 @@ const methods = { const query = req.args?.query; const body = req.args?.body; - const paths = get_paths(); - const profile = json(readfile(paths.run_profile_path)); + const profile = load_profile(); const api_listen = profile['experimental']['clash_api']['external_controller']; const api_secret = profile['experimental']['clash_api']['secret']; diff --git a/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js b/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js index c1e51d79eb..943b7c0106 100644 --- a/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js +++ b/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js @@ -13,7 +13,6 @@ return view.extend({ return Promise.all([ uci.load('nikki'), network.getNetworks(), - ]); }, render: function (data) { diff --git a/small/luci-app-openclash/root/usr/share/openclash/yml_rules_change.sh b/small/luci-app-openclash/root/usr/share/openclash/yml_rules_change.sh index 2fdcc150f0..1bb95bd379 100644 --- a/small/luci-app-openclash/root/usr/share/openclash/yml_rules_change.sh +++ b/small/luci-app-openclash/root/usr/share/openclash/yml_rules_change.sh @@ -272,7 +272,7 @@ yml_other_set() begin provider_configs = {'proxy-providers' => 'proxy_provider', 'rule-providers' => 'rule_provider'}; provider_configs.each do |provider_type, path_prefix| - if Value.key?(provider_type) then + if Value.key?(provider_type) && Value[provider_type].is_a?(Hash) then Value[provider_type].each{|name, config| threads << Thread.new { if config['path'] and not config['path'] =~ /.\/#{path_prefix}\/*/ then @@ -310,7 +310,7 @@ yml_other_set() # tolerance begin - if '$tolerance' != '0' and Value.key?('proxy-groups') then + if '$tolerance' != '0' and Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then Value['proxy-groups'].each{|group| threads << Thread.new { if group['type'] == 'url-test' then @@ -326,7 +326,7 @@ yml_other_set() # URL-Test interval begin if '$urltest_interval_mod' != '0' then - if Value.key?('proxy-groups') then + if Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then Value['proxy-groups'].each{|group| threads << Thread.new { if ['url-test', 'fallback', 'load-balance', 'smart'].include?(group['type']) then @@ -361,7 +361,7 @@ yml_other_set() }; }; end; - if Value.key?('proxy-groups') then + if Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then Value['proxy-groups'].each{|group| threads << Thread.new { if ['url-test', 'fallback', 'load-balance', 'smart'].include?(group['type']) then @@ -377,7 +377,7 @@ yml_other_set() # smart auto switch begin - if ('${8}' == '1' or '${9}' == '1' or '${11}' != '0' or '${12}' != '0' or '${12}' == '1' or '${13}' == '1') and Value.key?('proxy-groups') then + if ('${8}' == '1' or '${9}' == '1' or '${11}' != '0' or '${12}' != '0' or '${12}' == '1' or '${13}' == '1') and Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then Value['proxy-groups'].each{|group| threads << Thread.new { if '${8}' == '1' and ['url-test', 'load-balance'].include?(group['type']) then diff --git a/small/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua b/small/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua index f045bc87f7..cb31a73744 100644 --- a/small/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua +++ b/small/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua @@ -120,14 +120,6 @@ if #ss_type > 0 or #trojan_type > 0 or #vmess_type > 0 or #vless_type > 0 or #hy translate("The configured type also applies to the core specified when manually importing nodes.")) end -o = s:option(ListValue, "domain_strategy", "Sing-box " .. translate("Domain Strategy"), translate("Set the default domain resolution strategy for the sing-box node.")) -o.default = "" -o:value("", translate("Auto")) -o:value("prefer_ipv4", translate("Prefer IPv4")) -o:value("prefer_ipv6", translate("Prefer IPv6")) -o:value("ipv4_only", translate("IPv4 Only")) -o:value("ipv6_only", translate("IPv6 Only")) - ---- Subscribe Delete All o = s:option(DummyValue, "_stop", translate("Delete All Subscribe Node")) o.rawhtml = true diff --git a/small/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua b/small/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua index a913865c48..56b9f1752b 100644 --- a/small/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua +++ b/small/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua @@ -133,6 +133,34 @@ o.validate = function(self, value) return value:gsub("%s+", ""):gsub("%z", "") end +o = s:option(ListValue, "domain_resolver", translate("Domain DNS Resolve")) +o.description = translate("If the node address is a domain name, this DNS will be used for resolution.") .. "
" .. + translate("Supports only Xray or Sing-box node types.") +o:value("", translate("Auto")) +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:value("https", "DoH") + +o = s:option(Value, "domain_resolver_dns", "DNS") +o.datatype = "or(ipaddr,ipaddrport)" +o:value("114.114.114.114") +o:value("223.5.5.5:53") +o.default = o.keylist[1] +o:depends({ domain_resolver = "tcp" }) +o:depends({ domain_resolver = "udp" }) + +o = s:option(Value, "domain_resolver_dns_https", "DNS") +o:value("https://120.53.53.53/dns-query", "DNSPod") +o:value("https://223.5.5.5/dns-query", "AliDNS") +o.default = o.keylist[1] +o:depends({ domain_resolver = "https" }) + +o = s:option(ListValue, "domain_strategy", translate("Domain Strategy"), translate("If is domain name, The requested domain name will be resolved to IP before connect.")) +o.default = "" +o:value("", translate("Auto")) +o:value("UseIPv4", translate("IPv4 Only")) +o:value("UseIPv6", translate("IPv6 Only")) + o = s:option(Flag, "allowInsecure", translate("allowInsecure")) o.default = "0" o.rmempty = false @@ -203,15 +231,6 @@ if #hysteria2_type > 0 then end end -o = s:option(ListValue, "domain_strategy", "Sing-box " .. translate("Domain Strategy"), translate("Set the default domain resolution strategy for the sing-box node.")) -o.default = "global" -o:value("global", translate("Use global config")) -o:value("", translate("Auto")) -o:value("prefer_ipv4", translate("Prefer IPv4")) -o:value("prefer_ipv6", translate("Prefer IPv6")) -o:value("ipv4_only", translate("IPv4 Only")) -o:value("ipv6_only", translate("IPv6 Only")) - o = s:option(Flag, "boot_update", translate("Update Once on Boot"), translate("Updates the subscription the first time PassWall runs automatically after each system boot.")) o.default = 0 diff --git a/small/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua b/small/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua index 891ed10211..7d1d9fdf22 100644 --- a/small/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua +++ b/small/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua @@ -240,16 +240,6 @@ o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) o = s:option(Value, _n("port"), translate("Port")) o.datatype = "port" -local protocols = s.fields[_n("protocol")].keylist -if #protocols > 0 then - for index, value in ipairs(protocols) do - if not value:find("^_") then - s.fields[_n("address")]:depends({ [_n("protocol")] = value }) - s.fields[_n("port")]:depends({ [_n("protocol")] = value }) - end - end -end - o = s:option(Value, _n("uuid"), translate("ID")) o.password = true o:depends({ [_n("protocol")] = "vmess" }) @@ -735,10 +725,46 @@ o.datatype = "uinteger" o.placeholder = 0 o:depends({ [_n("protocol")] = "vless" }) -for i, v in ipairs(s.fields[_n("protocol")].keylist) do - if not v:find("^_") and v ~= "hysteria2" then - s.fields[_n("tcp_fast_open")]:depends({ [_n("protocol")] = v }) - s.fields[_n("tcpMptcp")]:depends({ [_n("protocol")] = v }) +o = s:option(ListValue, _n("domain_resolver"), translate("Domain DNS Resolve"), translate("If the node address is a domain name, this DNS will be used for resolution.")) +o:value("", translate("Auto")) +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:value("https", "DoH") + +o = s:option(Value, _n("domain_resolver_dns"), "DNS") +o.datatype = "or(ipaddr,ipaddrport)" +o:value("114.114.114.114") +o:value("223.5.5.5:53") +o.default = o.keylist[1] +o:depends({ [_n("domain_resolver")] = "tcp" }) +o:depends({ [_n("domain_resolver")] = "udp" }) + +o = s:option(Value, _n("domain_resolver_dns_https"), "DNS") +o:value("https://120.53.53.53/dns-query", "DNSPod") +o:value("https://223.5.5.5/dns-query", "AliDNS") +o.default = o.keylist[1] +o:depends({ [_n("domain_resolver")] = "https" }) + +o = s:option(ListValue, _n("domain_strategy"), translate("Domain Strategy"), translate("If is domain name, The requested domain name will be resolved to IP before connect.")) +o.default = "" +o:value("", translate("Auto")) +o:value("UseIPv4", translate("IPv4 Only")) +o:value("UseIPv6", translate("IPv6 Only")) + +local protocols = s.fields[_n("protocol")].keylist +if #protocols > 0 then + for i, v in ipairs(protocols) do + if not v:find("^_") then + s.fields[_n("address")]:depends({ [_n("protocol")] = v }) + s.fields[_n("port")]:depends({ [_n("protocol")] = v }) + s.fields[_n("domain_resolver")]:depends({ [_n("protocol")] = v }) + s.fields[_n("domain_strategy")]:depends({ [_n("protocol")] = v }) + + if v ~= "hysteria2" then + s.fields[_n("tcp_fast_open")]:depends({ [_n("protocol")] = v }) + s.fields[_n("tcpMptcp")]:depends({ [_n("protocol")] = v }) + end + end end end end diff --git a/small/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua b/small/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua index 95c0a2a08e..eb9adbaad7 100644 --- a/small/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua +++ b/small/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua @@ -206,16 +206,6 @@ o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) o = s:option(Value, _n("port"), translate("Port")) o.datatype = "port" -local protocols = s.fields[_n("protocol")].keylist -if #protocols > 0 then - for index, value in ipairs(protocols) do - if not value:find("^_") then - s.fields[_n("address")]:depends({ [_n("protocol")] = value }) - s.fields[_n("port")]:depends({ [_n("protocol")] = value }) - end - end -end - o = s:option(Value, _n("uuid"), translate("ID")) o.password = true o:depends({ [_n("protocol")] = "vmess" }) @@ -742,6 +732,26 @@ o:value("v2ray-plugin") o = s:option(Value, _n("plugin_opts"), translate("opts")) o:depends({ [_n("plugin_enabled")] = true }) +o = s:option(ListValue, _n("domain_resolver"), translate("Domain DNS Resolve"), translate("If the node address is a domain name, this DNS will be used for resolution.")) +o:value("", translate("Auto")) +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:value("https", "DoH") + +o = s:option(Value, _n("domain_resolver_dns"), "DNS") +o.datatype = "or(ipaddr,ipaddrport)" +o:value("114.114.114.114") +o:value("223.5.5.5:53") +o.default = o.keylist[1] +o:depends({ [_n("domain_resolver")] = "tcp" }) +o:depends({ [_n("domain_resolver")] = "udp" }) + +o = s:option(Value, _n("domain_resolver_dns_https"), "DNS") +o:value("https://120.53.53.53/dns-query", "DNSPod") +o:value("https://223.5.5.5/dns-query", "AliDNS") +o.default = o.keylist[1] +o:depends({ [_n("domain_resolver")] = "https" }) + o = s:option(ListValue, _n("domain_strategy"), translate("Domain Strategy"), translate("If is domain name, The requested domain name will be resolved to IP before connect.")) o.default = "" o:value("", translate("Auto")) @@ -749,17 +759,19 @@ o:value("prefer_ipv4", translate("Prefer IPv4")) o:value("prefer_ipv6", translate("Prefer IPv6")) o:value("ipv4_only", translate("IPv4 Only")) o:value("ipv6_only", translate("IPv6 Only")) -o:depends({ [_n("protocol")] = "socks" }) -o:depends({ [_n("protocol")] = "http" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "trojan" }) -o:depends({ [_n("protocol")] = "wireguard" }) -o:depends({ [_n("protocol")] = "hysteria" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "tuic" }) -o:depends({ [_n("protocol")] = "hysteria2" }) -o:depends({ [_n("protocol")] = "anytls" }) + + +local protocols = s.fields[_n("protocol")].keylist +if #protocols > 0 then + for i, v in ipairs(protocols) do + if not v:find("^_") then + s.fields[_n("address")]:depends({ [_n("protocol")] = v }) + s.fields[_n("port")]:depends({ [_n("protocol")] = v }) + s.fields[_n("domain_resolver")]:depends({ [_n("protocol")] = v }) + s.fields[_n("domain_strategy")]:depends({ [_n("protocol")] = v }) + end + end +end end -- [[ Normal single node End ]] diff --git a/small/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/small/luci-app-passwall/luasrc/passwall/util_sing-box.lua index 35877c910b..e7d7e2c6d7 100644 --- a/small/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/small/luci-app-passwall/luasrc/passwall/util_sing-box.lua @@ -11,6 +11,10 @@ local ech_domain = {} local local_version = api.get_app_version("sing-box"):match("[^v]+") local version_ge_1_13_0 = api.compare_versions(local_version, ">=", "1.13.0") +local GLOBAL = { + DNS_SERVER = {} +} + local GEO_VAR = { OK = nil, DIR = nil, @@ -154,6 +158,47 @@ function gen_outbound(flag, node, tag, proxy_table) detour = node.detour, } + if api.datatypes.hostname(node.address) and node.domain_resolver and (node.domain_resolver_dns or node.domain_resolver_dns_https) then + local dns_tag = node_id .. "_dns" + local dns_proto = node.domain_resolver + local server_address + local server_port + local server_path + if dns_proto == "https" then + local _a = api.parseURL(node.domain_resolver_dns_https) + if _a then + server_address = _a.hostname + if _a.port then + server_port = _a.port + else + server_port = 443 + end + server_path = _a.pathname + end + else + server_address = node.domain_resolver_dns + server_port = 53 + local split = api.split(server_address, ":") + if #split > 1 then + server_address = split[1] + server_port = tonumber(split[#split]) + end + end + GLOBAL.DNS_SERVER[node_id] = { + server = { + tag = dns_tag, + type = dns_proto, + server = server_address, + server_port = server_port, + path = server_path, + domain_resolver = "direct", + detour = "direct" + }, + domain = node.address + } + result.domain_resolver.server = dns_tag + end + local tls = nil if node.protocol == "hysteria" or node.protocol == "hysteria2" or node.protocol == "tuic" or node.protocol == "naive" then node.tls = "1" @@ -1922,6 +1967,16 @@ function gen_config(var) } end + for i, v in pairs(GLOBAL.DNS_SERVER) do + table.insert(dns.servers, v.server) + if not dns.rules then dns.rules = {} end + table.insert(dns.rules, { + action = "route", + server = v.server.tag, + domain = v.domain, + }) + end + if next(ech_domain) ~= nil then table.insert(dns.servers, { tag = "ech-dns", @@ -1983,6 +2038,12 @@ function gen_config(var) if not value["_flag_proxy_tag"] and not value.detour and value["_id"] and value.server and (value.server_port or value.server_ports) and not no_run then sys.call(string.format("echo '%s' >> %s", value["_id"], api.TMP_PATH .. "/direct_node_list")) end + if not value.detour and value.server then + value.detour = "direct" + end + if value.server and not api.datatypes.hostname(value.server) then + value.domain_resolver = nil + end for k, v in pairs(config.outbounds[index]) do if k:find("_") == 1 then config.outbounds[index][k] = nil diff --git a/small/luci-app-passwall/luasrc/passwall/util_xray.lua b/small/luci-app-passwall/luasrc/passwall/util_xray.lua index 61c20127c3..7e0109937b 100644 --- a/small/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/small/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -6,6 +6,11 @@ local jsonc = api.jsonc local appname = "passwall" local fs = api.fs +local GLOBAL = { + DNS_SERVER = {}, + DNS_HOSTNAME = {} +} + local xray_version = api.get_app_version("xray") local function get_domain_excluded() @@ -134,6 +139,7 @@ function gen_outbound(flag, node, tag, proxy_table) streamSettings = (node.streamSettings or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan" or node.protocol == "hysteria") and { sockopt = { mark = 255, + domainStrategy = node.domain_strategy or "UseIP", tcpFastOpen = (node.tcp_fast_open == "1") and true or nil, tcpMptcp = (node.tcpMptcp == "1") and true or nil }, @@ -397,6 +403,48 @@ function gen_outbound(flag, node, tag, proxy_table) result.streamSettings.tlsSettings.alpn = alpn end end + + if api.datatypes.hostname(node.address) and node.domain_resolver and (node.domain_resolver_dns or node.domain_resolver_dns_https) then + local dns_tag = node_id .. "_dns" + local dns_proto = node.domain_resolver + local config_address + local config_port + if dns_proto == "https" then + local _a = api.parseURL(node.domain_resolver_dns_https) + if _a then + config_address = node.domain_resolver_dns_https + if _a.port then + config_port = _a.port + else + config_port = 443 + end + if _a.hostname then + if api.datatypes.hostname(_a.hostname) then + GLOBAL.DNS_HOSTNAME[_a.hostname] = true + end + end + end + else + local server_address = node.domain_resolver_dns + local config_port = 53 + local split = api.split(server_address, ":") + if #split > 1 then + server_address = split[1] + config_port = tonumber(split[#split]) + end + config_address = server_address + if dns_proto == "tcp" then + config_address = dns_proto .. "://" .. server_address .. ":" .. config_port + end + end + GLOBAL.DNS_SERVER[node_id] = { + tag = dns_tag, + queryStrategy = node.domain_strategy or "UseIP", + address = config_address, + port = config_port, + domains = {"full:" .. node.address} + } + end end return result end @@ -1437,7 +1485,15 @@ function gen_config(var) end end - if (remote_dns_udp_server and remote_dns_udp_port) or (remote_dns_tcp_server and remote_dns_tcp_port) then + local node_dns = {} + for i, v in pairs(GLOBAL.DNS_SERVER) do + table.insert(node_dns, { + server = v, + outboundTag = "direct" + }) + end + + if (remote_dns_udp_server and remote_dns_udp_port) or (remote_dns_tcp_server and remote_dns_tcp_port) or #node_dns > 0 then if not routing then routing = { domainStrategy = "IPOnDemand", @@ -1461,6 +1517,8 @@ function gen_config(var) queryStrategy = (direct_dns_query_strategy and direct_dns_query_strategy ~= "") and direct_dns_query_strategy or "UseIP" } + direct_dns_udp_server = (direct_dns_udp_server and direct_dns_udp_server ~= "") and direct_dns_udp_server or nil + if direct_dns_udp_server or direct_dns_tcp_server then local domain = {} local nodes_domain_text = sys.exec('uci show passwall | grep ".address=" | cut -d "\'" -f 2 | grep "[a-zA-Z]$" | sort -u') @@ -1489,14 +1547,12 @@ function gen_config(var) end end - local _remote_dns = { - --tag = "dns-global-remote", - queryStrategy = (remote_dns_query_strategy and remote_dns_query_strategy ~= "") and remote_dns_query_strategy or "UseIPv4", - } + local _remote_dns = {} + if remote_dns_udp_server then _remote_dns.address = remote_dns_udp_server _remote_dns.port = tonumber(remote_dns_udp_port) or 53 - else + elseif remote_dns_tcp_server then _remote_dns.address = "tcp://" .. remote_dns_tcp_server .. ":" .. tonumber(remote_dns_tcp_port) or 53 end @@ -1510,7 +1566,11 @@ function gen_config(var) _remote_dns.port = tonumber(remote_dns_doh_port) end - table.insert(dns.servers, _remote_dns) + if next(_remote_dns) then + -- _remote_dns.tag = "dns-global-remote" + _remote_dns.queryStrategy = (remote_dns_query_strategy and remote_dns_query_strategy ~= "") and remote_dns_query_strategy or "UseIPv4" + table.insert(dns.servers, _remote_dns) + end local _remote_fakedns = { --tag = "dns-global-remote-fakedns", @@ -1649,7 +1709,7 @@ function gen_config(var) dns_server = nil end if dns_server then - dns_server.finalQuery = true + --dns_server.finalQuery = true dns_server.domains = value.domain if value.shunt_rule_name then dns_server.tag = "dns-in-" .. value.shunt_rule_name @@ -1666,7 +1726,7 @@ function gen_config(var) end local _outboundTag - if not api.is_local_ip(_remote_dns.address) or dns_outbound_tag == "blackhole" then --dns为本地ip,不走代理 + if _remote_dns.address and not api.is_local_ip(_remote_dns.address) or dns_outbound_tag == "blackhole" then --dns为本地ip,不走代理 _outboundTag = dns_outbound_tag else _outboundTag = "direct" @@ -1698,6 +1758,37 @@ function gen_config(var) if dns_hosts_len == 0 then dns.hosts = nil end + + -- 自定义节点 DNS + if #node_dns > 0 and #dns.servers < 1 then + dns.servers = { "localhost" } + end + for i = #node_dns, 1, -1 do + local value = node_dns[i] + table.insert(routing.rules, 1, { + inboundTag = { + value.server.tag + }, + outboundTag = value.outboundTag, + }) + table.insert(dns.servers, 2, value.server) + end + if next(GLOBAL.DNS_HOSTNAME) then + local hostname = {} + for line, _ in pairs(GLOBAL.DNS_HOSTNAME) do + table.insert(hostname, line) + end + table.insert(dns.servers, 2, { + tag = "bootstrap", + address = "223.5.5.5", + queryStrategy = "UseIPv4", + domains = hostname + }) + table.insert(routing.rules, 1, { + inboundTag = { "bootstrap" }, + outboundTag = "direct" + }) + end end if inbounds or outbounds then diff --git a/small/luci-app-passwall/po/zh-cn/passwall.po b/small/luci-app-passwall/po/zh-cn/passwall.po index 93a40372db..3c15def467 100644 --- a/small/luci-app-passwall/po/zh-cn/passwall.po +++ b/small/luci-app-passwall/po/zh-cn/passwall.po @@ -1936,6 +1936,15 @@ msgstr "延迟(ms)" msgid "If is domain name, The requested domain name will be resolved to IP before connect." msgstr "如果是域名,域名将在请求发出之前解析为 IP。" +msgid "Domain DNS Resolve" +msgstr "域名 DNS 解析" + +msgid "If the node address is a domain name, this DNS will be used for resolution." +msgstr "如果节点地址是域名,则将使用此 DNS 进行解析。" + +msgid "Supports only Xray or Sing-box node types." +msgstr "仅支持 Xray 或 Sing-box 类型节点。" + msgid "Chain Proxy" msgstr "链式代理" @@ -1949,15 +1958,12 @@ msgid "" "Chained proxy works only with Xray or Sing-box nodes.
" "You can only use manual or imported nodes as chained nodes." msgstr "" -"链式代理仅支持 Xray 与 Sing-box 节点。
" +"链式代理仅支持 Xray 或 Sing-box 节点。
" "仅支持手动添加或导入的节点用作链式节点。" msgid "Only work with using the %s node." msgstr "与使用 %s 节点时生效。" -msgid "Set the default domain resolution strategy for the sing-box node." -msgstr "为 sing-box 节点设置默认的域名解析策略。" - msgid "Total Lines" msgstr "总行数:" diff --git a/small/luci-app-passwall/root/usr/share/passwall/app.sh b/small/luci-app-passwall/root/usr/share/passwall/app.sh index b0ddb2e8ad..ed1d842093 100755 --- a/small/luci-app-passwall/root/usr/share/passwall/app.sh +++ b/small/luci-app-passwall/root/usr/share/passwall/app.sh @@ -17,6 +17,8 @@ UTIL_TROJAN=$LUA_UTIL_PATH/util_trojan.lua UTIL_NAIVE=$LUA_UTIL_PATH/util_naiveproxy.lua UTIL_HYSTERIA2=$LUA_UTIL_PATH/util_hysteria2.lua UTIL_TUIC=$LUA_UTIL_PATH/util_tuic.lua +SINGBOX_BIN=$(first_type $(config_t_get global_app sing_box_file) sing-box) +XRAY_BIN=$(first_type $(config_t_get global_app xray_file) xray) check_run_environment() { local prefer_nft=$(config_t_get global_forwarding prefer_nft 1) @@ -102,11 +104,8 @@ run_singbox() { local loglevel log_file config_file server_host server_port no_run eval_set_val $@ [ -z "$type" ] && { - local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z') - if [ "$type" != "sing-box" ]; then - bin=$(first_type $(config_t_get global_app sing_box_file) sing-box) - [ -n "$bin" ] && type="sing-box" - fi + type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z') + [ "$type" != "sing-box" ] && [ -n "$SINGBOX_BIN" ] && type="sing-box" } [ -z "$type" ] && return 1 [ -n "$log_file" ] || local log_file="/dev/null" @@ -187,7 +186,7 @@ run_singbox() { [ -n "$no_run" ] && json_add_string "no_run" "1" local _json_arg="$(json_dump)" lua $UTIL_SINGBOX gen_config "${_json_arg}" > $config_file - [ -n "$no_run" ] || ln_run "$(first_type $(config_t_get global_app sing_box_file) sing-box)" "sing-box" $log_file run -c "$config_file" + [ -n "$no_run" ] || ln_run "$SINGBOX_BIN" "sing-box" $log_file run -c "$config_file" } run_xray() { @@ -196,11 +195,8 @@ run_xray() { local loglevel log_file config_file server_host server_port no_run eval_set_val $@ [ -z "$type" ] && { - local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z') - if [ "$type" != "xray" ]; then - bin=$(first_type $(config_t_get global_app xray_file) xray) - [ -n "$bin" ] && type="xray" - fi + type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z') + [ "$type" != "xray" ] && [ -n "$XRAY_BIN" ] && type="xray" } [ -z "$type" ] && return 1 json_init @@ -279,7 +275,7 @@ run_xray() { [ -n "$no_run" ] && json_add_string "no_run" "1" local _json_arg="$(json_dump)" lua $UTIL_XRAY gen_config "${_json_arg}" > $config_file - [ -n "$no_run" ] || ln_run "$(first_type $(config_t_get global_app ${type}_file) ${type})" ${type} $log_file run -c "$config_file" + [ -n "$no_run" ] || ln_run "$XRAY_BIN" "xray" $log_file run -c "$config_file" } run_dns2socks() { @@ -409,19 +405,20 @@ run_socks() { json_add_string "server_port" "${_socks_port}" json_add_string "server_username" "${_socks_username}" json_add_string "server_password" "${_socks_password}" - local bin=$(first_type $(config_t_get global_app sing_box_file) sing-box) - if [ -n "$bin" ]; then + if [ -n "${SINGBOX_BIN}" ]; then type="sing-box" - lua $UTIL_SINGBOX gen_proto_config "$(json_dump)" > $config_file - ln_run "$bin" ${type} $log_file run -c "$config_file" - else - bin=$(first_type $(config_t_get global_app xray_file) xray) - [ -n "$bin" ] && { - type="xray" - lua $UTIL_XRAY gen_proto_config "$(json_dump)" > $config_file - ln_run "$bin" ${type} $log_file run -c "$config_file" - } + local bin="${SINGBOX_BIN}" + local util="${UTIL_SINGBOX}" + elif [ -n "${XRAY_BIN}" ]; then + type="xray" + local bin="${XRAY_BIN}" + local util="${UTIL_XRAY}" fi + [ -n "${bin}" ] && [ -n "${util}" ] && { + lua ${util} gen_proto_config "$(json_dump)" > $config_file + [ -n "$no_run" ] || ln_run "$bin" $type $log_file run -c "$config_file" + } + unset bin util ;; sing-box) [ "$http_port" != "0" ] && { @@ -514,10 +511,7 @@ run_socks() { # http to socks [ -z "$http_flag" ] && [ "$http_port" != "0" ] && [ -n "$http_config_file" ] && [ "$type" != "sing-box" ] && [ "$type" != "xray" ] && [ "$type" != "socks" ] && { - local bin=$(first_type $(config_t_get global_app sing_box_file) sing-box) - json_add_null "node" - json_add_null "server_host" - json_add_null "server_port" + json_init json_add_string "local_http_address" "$bind" json_add_string "local_http_port" "$http_port" json_add_string "server_proto" "socks" @@ -525,17 +519,20 @@ run_socks() { json_add_string "server_port" "$socks_port" json_add_string "server_username" "$_username" json_add_string "server_password" "$_password" - if [ -n "$bin" ]; then + if [ -n "${SINGBOX_BIN}" ]; then type="sing-box" - lua $UTIL_SINGBOX gen_proto_config "$(json_dump)" > $http_config_file - [ -n "$no_run" ] || ln_run "$bin" ${type} /dev/null run -c "$http_config_file" - else - bin=$(first_type $(config_t_get global_app xray_file) xray) - [ -n "$bin" ] && type="xray" - [ -z "$type" ] && return 1 - lua $UTIL_XRAY gen_proto_config "$(json_dump)" > $http_config_file - [ -n "$no_run" ] || ln_run "$bin" ${type} /dev/null run -c "$http_config_file" + local bin="${SINGBOX_BIN}" + local util="${UTIL_SINGBOX}" + elif [ -n "${XRAY_BIN}" ]; then + type="xray" + local bin="${XRAY_BIN}" + local util="${UTIL_XRAY}" fi + [ -n "${bin}" ] && [ -n "${util}" ] && { + lua ${util} gen_proto_config "$(json_dump)" > $http_config_file + [ -n "$no_run" ] || ln_run "$bin" $type /dev/null run -c "$http_config_file" + } + unset bin util } unset http_flag diff --git a/small/luci-app-passwall/root/usr/share/passwall/subscribe.lua b/small/luci-app-passwall/root/usr/share/passwall/subscribe.lua index 4d12d6e394..8c49b2d9c4 100755 --- a/small/luci-app-passwall/root/usr/share/passwall/subscribe.lua +++ b/small/luci-app-passwall/root/usr/share/passwall/subscribe.lua @@ -42,8 +42,7 @@ local core_has = { ["trojan-plus"] = has_trojan_plus, ["hysteria2"] = has_hysteria2 } ---- -local domain_strategy_default = uci:get(appname, "@global_subscribe[0]", "domain_strategy") or "" -local domain_strategy_node = "" +local domain_resolver, domain_resolver_dns, domain_resolver_dns_https, domain_strategy local preproxy_node_group, to_node_group, chain_node_type = "", "", "" -- 判断是否过滤节点关键字 local filter_keyword_mode_default = uci:get(appname, "@global_subscribe[0]", "filter_keyword_mode") or "0" @@ -1855,9 +1854,22 @@ local function update_node(manual) if kkk ~= "group" or vvv ~= "default" then uci:set(appname, cfgid, kkk, vvv) end - -- sing-box 域名解析策略 - if kkk == "type" and vvv == "sing-box" then - uci:set(appname, cfgid, "domain_strategy", domain_strategy_node) + -- sing-box/xray 节点域名解析 + if kkk == "type" and (vvv == "Xray" or vvv == "sing-box") then + if domain_resolver then + uci:set(appname, cfgid, "domain_resolver", domain_resolver) + if domain_resolver_dns then + uci:set(appname, cfgid, "domain_resolver_dns", domain_resolver_dns) + elseif domain_resolver_dns_https then + uci:set(appname, cfgid, "domain_resolver_dns_https", domain_resolver_dns_https) + end + end + if domain_strategy then + if vvv == "sing-box" then + domain_strategy = (domain_strategy == "UseIPv4" and "ipv4_only") or (domain_strategy == "UseIPv6" and "ipv6_only") or domain_strategy + end + uci:set(appname, cfgid, "domain_strategy", domain_strategy) + end end -- 订阅组链式代理 if chain_node_type ~= "" and kkk == "type" and (vvv == "Xray" or vvv == "sing-box") then @@ -2069,12 +2081,11 @@ local execute = function() if hysteria2_type ~= "global" and core_has[hysteria2_type] then hysteria2_type_default = hysteria2_type end - local domain_strategy = value.domain_strategy or "global" - if domain_strategy ~= "global" then - domain_strategy_node = domain_strategy - else - domain_strategy_node = domain_strategy_default - end + + domain_resolver = value.domain_resolver + domain_resolver_dns = value.domain_resolver_dns + domain_resolver_dns_https = value.domain_resolver_dns_https + domain_strategy = value.domain_strategy -- 订阅组链式代理 local function valid_chain_node(node) diff --git a/small/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua b/small/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua index ef70a93ccb..ac2a7b3490 100644 --- a/small/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua +++ b/small/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua @@ -238,16 +238,6 @@ o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) o = s:option(Value, _n("port"), translate("Port")) o.datatype = "port" -local protocols = s.fields[_n("protocol")].keylist -if #protocols > 0 then - for index, value in ipairs(protocols) do - if not value:find("^_") then - s.fields[_n("address")]:depends({ [_n("protocol")] = value }) - s.fields[_n("port")]:depends({ [_n("protocol")] = value }) - end - end -end - o = s:option(Value, _n("uuid"), translate("ID")) o.password = true o:depends({ [_n("protocol")] = "vmess" }) @@ -728,10 +718,46 @@ o.datatype = "uinteger" o.placeholder = 0 o:depends({ [_n("protocol")] = "vless" }) -for i, v in ipairs(s.fields[_n("protocol")].keylist) do - if not v:find("^_") and v ~= "hysteria2" then - s.fields[_n("tcp_fast_open")]:depends({ [_n("protocol")] = v }) - s.fields[_n("tcpMptcp")]:depends({ [_n("protocol")] = v }) +o = s:option(ListValue, _n("domain_resolver"), translate("Domain DNS Resolve"), translate("If the node address is a domain name, this DNS will be used for resolution.")) +o:value("", translate("Auto")) +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:value("https", "HTTPS") + +o = s:option(Value, _n("domain_resolver_dns"), "DNS") +o.datatype = "or(ipaddr,ipaddrport)" +o:value("114.114.114.114") +o:value("223.5.5.5:53") +o.default = o.keylist[1] +o:depends({ [_n("domain_resolver")] = "tcp" }) +o:depends({ [_n("domain_resolver")] = "udp" }) + +o = s:option(Value, _n("domain_resolver_dns_https"), "DNS") +o:value("https://120.53.53.53/dns-query", "DNSPod") +o:value("https://223.5.5.5/dns-query", "AliDNS") +o.default = o.keylist[1] +o:depends({ [_n("domain_resolver")] = "https" }) + +o = s:option(ListValue, _n("domain_strategy"), translate("Domain Strategy"), translate("If is domain name, The requested domain name will be resolved to IP before connect.")) +o.default = "" +o:value("", translate("Auto")) +o:value("UseIPv4", translate("IPv4 Only")) +o:value("UseIPv6", translate("IPv6 Only")) + +local protocols = s.fields[_n("protocol")].keylist +if #protocols > 0 then + for i, v in ipairs(protocols) do + if not v:find("^_") then + s.fields[_n("address")]:depends({ [_n("protocol")] = v }) + s.fields[_n("port")]:depends({ [_n("protocol")] = v }) + s.fields[_n("domain_resolver")]:depends({ [_n("protocol")] = v }) + s.fields[_n("domain_strategy")]:depends({ [_n("protocol")] = v }) + + if v ~= "hysteria2" then + s.fields[_n("tcp_fast_open")]:depends({ [_n("protocol")] = v }) + s.fields[_n("tcpMptcp")]:depends({ [_n("protocol")] = v }) + end + end end end end diff --git a/small/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua b/small/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua index a69ac4fd8a..42d39e8db4 100644 --- a/small/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua +++ b/small/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua @@ -209,16 +209,6 @@ o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) o = s:option(Value, _n("port"), translate("Port")) o.datatype = "port" -local protocols = s.fields[_n("protocol")].keylist -if #protocols > 0 then - for index, value in ipairs(protocols) do - if not value:find("^_") then - s.fields[_n("address")]:depends({ [_n("protocol")] = value }) - s.fields[_n("port")]:depends({ [_n("protocol")] = value }) - end - end -end - o = s:option(Value, _n("uuid"), translate("ID")) o.password = true o:depends({ [_n("protocol")] = "vmess" }) @@ -786,6 +776,26 @@ o:value("v2ray-plugin") o = s:option(Value, _n("plugin_opts"), translate("opts")) o:depends({ [_n("plugin_enabled")] = true }) +o = s:option(ListValue, _n("domain_resolver"), translate("Domain DNS Resolve"), translate("If the node address is a domain name, this DNS will be used for resolution.")) +o:value("", translate("Auto")) +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:value("https", "HTTPS") + +o = s:option(Value, _n("domain_resolver_dns"), "DNS") +o.datatype = "or(ipaddr,ipaddrport)" +o:value("114.114.114.114") +o:value("223.5.5.5:53") +o.default = o.keylist[1] +o:depends({ [_n("domain_resolver")] = "tcp" }) +o:depends({ [_n("domain_resolver")] = "udp" }) + +o = s:option(Value, _n("domain_resolver_dns_https"), "DNS") +o:value("https://120.53.53.53/dns-query", "DNSPod") +o:value("https://223.5.5.5/dns-query", "AliDNS") +o.default = o.keylist[1] +o:depends({ [_n("domain_resolver")] = "https" }) + o = s:option(ListValue, _n("domain_strategy"), translate("Domain Strategy"), translate("If is domain name, The requested domain name will be resolved to IP before connect.")) o.default = "" o:value("", translate("Auto")) @@ -793,18 +803,18 @@ o:value("prefer_ipv4", translate("Prefer IPv4")) o:value("prefer_ipv6", translate("Prefer IPv6")) o:value("ipv4_only", translate("IPv4 Only")) o:value("ipv6_only", translate("IPv6 Only")) -o:depends({ [_n("protocol")] = "socks" }) -o:depends({ [_n("protocol")] = "http" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "shadowsocksr" }) -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "trojan" }) -o:depends({ [_n("protocol")] = "wireguard" }) -o:depends({ [_n("protocol")] = "hysteria" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "tuic" }) -o:depends({ [_n("protocol")] = "hysteria2" }) -o:depends({ [_n("protocol")] = "anytls" }) + +local protocols = s.fields[_n("protocol")].keylist +if #protocols > 0 then + for i, v in ipairs(protocols) do + if not v:find("^_") then + s.fields[_n("address")]:depends({ [_n("protocol")] = v }) + s.fields[_n("port")]:depends({ [_n("protocol")] = v }) + s.fields[_n("domain_resolver")]:depends({ [_n("protocol")] = v }) + s.fields[_n("domain_strategy")]:depends({ [_n("protocol")] = v }) + end + end +end end -- [[ Normal single node End ]] diff --git a/small/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua b/small/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua index a76de67a6d..8740556fed 100644 --- a/small/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua +++ b/small/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua @@ -12,6 +12,10 @@ local ech_domain = {} local local_version = api.get_app_version("sing-box"):match("[^v]+") local version_ge_1_13_0 = api.compare_versions(local_version, ">=", "1.13.0") +local GLOBAL = { + DNS_SERVER = {} +} + local GEO_VAR = { OK = nil, DIR = nil, @@ -159,6 +163,47 @@ function gen_outbound(flag, node, tag, proxy_table) detour = node.detour, } + if api.datatypes.hostname(node.address) and node.domain_resolver and (node.domain_resolver_dns or node.domain_resolver_dns_https) then + local dns_tag = node_id .. "_dns" + local dns_proto = node.domain_resolver + local server_address + local server_port + local server_path + if dns_proto == "https" then + local _a = api.parseURL(node.domain_resolver_dns_https) + if _a then + server_address = _a.hostname + if _a.port then + server_port = _a.port + else + server_port = 443 + end + server_path = _a.pathname + end + else + server_address = node.domain_resolver_dns + server_port = 53 + local split = api.split(server_address, ":") + if #split > 1 then + server_address = split[1] + server_port = tonumber(split[#split]) + end + end + GLOBAL.DNS_SERVER[node_id] = { + server = { + tag = dns_tag, + type = dns_proto, + server = server_address, + server_port = server_port, + path = server_path, + domain_resolver = "local", + detour = "direct" + }, + domain = node.address + } + result.domain_resolver.server = dns_tag + end + local tls = nil if node.protocol == "hysteria" or node.protocol == "hysteria2" or node.protocol == "tuic" or node.protocol == "naive" then node.tls = "1" @@ -1695,6 +1740,15 @@ function gen_config(var) reverse_mapping = true, -- After responding to a DNS query, a reverse mapping of the IP address is stored to provide the domain name for routing purposes. } + for i, v in pairs(GLOBAL.DNS_SERVER) do + table.insert(dns.servers, v.server) + table.insert(dns.rules, { + action = "route", + server = v.server.tag, + domain = v.domain, + }) + end + table.insert(dns.servers, { type = "local", tag = "local" @@ -1855,42 +1909,6 @@ function gen_config(var) }) end - local dnsmasq_server_domain = api.get_dnsmasq_server_domain() - if next(dnsmasq_server_domain) then - local new_dns_servers = {} - for domain, v in pairs(dnsmasq_server_domain) do - if not new_dns_servers[v.dnsmasq_dns] then - new_dns_servers[v.dnsmasq_dns] = { - server = { - tag = v.dnsmasq_dns, - type = "udp", - server = v.server, - server_port = v.port, - detour = "direct", - }, - rule = { - action = "route", - domain_suffix = {}, - server = v.dnsmasq_dns, - strategy = direct_strategy, - }, - } - end - table.insert(new_dns_servers[v.dnsmasq_dns].rule.domain_suffix, domain) - end - for k, v in pairs(new_dns_servers) do - table.insert(dns.servers, v.server) - table.insert(dns.rules, 1, v.rule) - table.insert(route.rules, 1, { - action = "route", - network = v.server.type, - ip_cidr = v.server.server, - port = v.server.server_port, - outbound = "direct", - }) - end - end - local default_dns_flag = "remote" if node_id and redir_port then local node = get_node_by_id(node_id) @@ -2083,7 +2101,10 @@ function gen_config(var) if not value["_flag_proxy_tag"] and not value.detour and value["_id"] and value.server and value.server_port and not no_run then sys.call(string.format("echo '%s' >> %s", value["_id"], api.TMP_PATH .. "/direct_node_list")) end - if value.detour then + if not value.detour and value.server then + value.detour = "direct" + end + if value.server and not api.datatypes.hostname(value.server) then value.domain_resolver = nil end for k, v in pairs(config.outbounds[index]) do diff --git a/small/luci-app-passwall2/luasrc/passwall2/util_xray.lua b/small/luci-app-passwall2/luasrc/passwall2/util_xray.lua index 81304d5777..039ee0d6e8 100644 --- a/small/luci-app-passwall2/luasrc/passwall2/util_xray.lua +++ b/small/luci-app-passwall2/luasrc/passwall2/util_xray.lua @@ -7,6 +7,10 @@ local appname = api.appname local fs = api.fs local CACHE_PATH = api.CACHE_PATH +local GLOBAL = { + DNS_SERVER = {} +} + local xray_version = api.get_app_version("xray") local function get_domain_excluded() @@ -130,6 +134,7 @@ function gen_outbound(flag, node, tag, proxy_table) streamSettings = (node.streamSettings or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan" or node.protocol == "hysteria") and { sockopt = { mark = 255, + domainStrategy = node.domain_strategy or "UseIP", tcpFastOpen = (node.tcp_fast_open == "1") and true or nil, tcpMptcp = (node.tcpMptcp == "1") and true or nil }, @@ -394,6 +399,43 @@ function gen_outbound(flag, node, tag, proxy_table) end end + if api.datatypes.hostname(node.address) and node.domain_resolver and (node.domain_resolver_dns or node.domain_resolver_dns_https) then + local dns_tag = node_id .. "_dns" + local dns_proto = node.domain_resolver + local config_address + local config_port + if dns_proto == "https" then + local _a = api.parseURL(node.domain_resolver_dns_https) + if _a then + config_address = node.domain_resolver_dns_https + if _a.port then + config_port = _a.port + else + config_port = 443 + end + end + else + local server_address = node.domain_resolver_dns + local config_port = 53 + local split = api.split(server_address, ":") + if #split > 1 then + server_address = split[1] + config_port = tonumber(split[#split]) + end + config_address = server_address + if dns_proto == "tcp" then + config_address = dns_proto .. "://" .. server_address .. ":" .. config_port + end + end + GLOBAL.DNS_SERVER[node_id] = { + tag = dns_tag, + queryStrategy = node.domain_strategy or "UseIP", + address = config_address, + port = config_port, + domains = {"full:" .. node.address} + } + end + end return result end @@ -1386,6 +1428,19 @@ function gen_config(var) end end + local dns_servers = {} + local direct_dns_tag = "dns-in-direct" + local remote_dns_tag = "dns-in-remote" + local remote_fakedns_tag = "dns-in-remote-fakedns" + local default_dns_tag = "dns-in-default" + + for i, v in pairs(GLOBAL.DNS_SERVER) do + table.insert(dns_servers, { + server = v, + outboundTag = "direct" + }) + end + dns = { tag = "dns-global", hosts = {}, @@ -1396,8 +1451,6 @@ function gen_config(var) queryStrategy = "UseIP" } - local dns_servers = {} - table.insert(dns_servers, { server = { tag = "local", @@ -1406,11 +1459,6 @@ function gen_config(var) }) if dns_listen_port then - local direct_dns_tag = "dns-in-direct" - local remote_dns_tag = "dns-in-remote" - local remote_fakedns_tag = "dns-in-remote-fakedns" - local default_dns_tag = "dns-in-default" - local _remote_dns_proto = "tcp" if not routing then @@ -1538,39 +1586,6 @@ function gen_config(var) }) end end - - local dnsmasq_server_domain = api.get_dnsmasq_server_domain() - if next(dnsmasq_server_domain) then - local new_dns_servers = {} - for domain, v in pairs(dnsmasq_server_domain) do - if not new_dns_servers[v.dnsmasq_dns] then - new_dns_servers[v.dnsmasq_dns] = { - server = { - tag = v.dnsmasq_dns, - address = v.server, - port = v.port, - queryStrategy = (direct_dns_query_strategy and direct_dns_query_strategy ~= "") and direct_dns_query_strategy or "UseIP" - }, - domain = {} - } - end - table.insert(new_dns_servers[v.dnsmasq_dns].domain, domain) - end - for k, v in pairs(new_dns_servers) do - table.insert(dns_domain_rules, 1, { - shunt_rule_name = k, - outboundTag = "direct", - dns_server = v.server, - domain = v.domain - }) - table.insert(routing.rules, 1, { - network = "udp", - ip = v.server.address, - port = v.server.port, - outboundTag = "direct" - }) - end - end if dns_listen_port then table.insert(inbounds, { @@ -1673,7 +1688,6 @@ function gen_config(var) dns_server = nil end if dns_server then - dns_server.finalQuery = true dns_server.domains = value.domain if value.shunt_rule_name then dns_server.tag = "dns-in-" .. value.shunt_rule_name @@ -1686,25 +1700,6 @@ function gen_config(var) end end end - - for i = #dns_servers, 1, -1 do - local value = dns_servers[i] - if value.server.tag ~= direct_dns_tag and value.server.tag ~= remote_dns_tag then - -- DNS rule must be at the front, prevents being matched by rules. - if value.outboundTag and value.server.address ~= "fakedns" then - table.insert(routing.rules, 1, { - inboundTag = { - value.server.tag - }, - outboundTag = value.outboundTag, - }) - end - if (value.server.domains and #value.server.domains > 0) or value.server.tag == default_dns_tag then - -- Only keep default DNS server or has domains DNS server. - table.insert(dns.servers, 1, value.server) - end - end - end end local default_rule_index = nil @@ -1759,6 +1754,25 @@ function gen_config(var) dns.hosts = nil end + for i = #dns_servers, 1, -1 do + local value = dns_servers[i] + if value.server.tag ~= direct_dns_tag and value.server.tag ~= remote_dns_tag then + -- DNS rule must be at the front, prevents being matched by rules. + if value.outboundTag and value.server.address ~= "fakedns" then + table.insert(routing.rules, 1, { + inboundTag = { + value.server.tag + }, + outboundTag = value.outboundTag, + }) + end + if (value.server.domains and #value.server.domains > 0) or value.server.tag == default_dns_tag then + -- Only keep default DNS server or has domains DNS server. + table.insert(dns.servers, 1, value.server) + end + end + end + if redir_port then local inbound = { port = tonumber(redir_port), diff --git a/small/luci-app-passwall2/po/fa/passwall2.po b/small/luci-app-passwall2/po/fa/passwall2.po index 2d7dab7b4b..46e41b8d3d 100644 --- a/small/luci-app-passwall2/po/fa/passwall2.po +++ b/small/luci-app-passwall2/po/fa/passwall2.po @@ -1764,6 +1764,12 @@ msgstr "تاخیر (میلی‌ثانیه)" msgid "If is domain name, The requested domain name will be resolved to IP before connect." msgstr "اگر نام دامنه است، نام دامنه درخواست شده قبل از اتصال به IP حل می‌شود." +msgid "Domain DNS Resolve" +msgstr "حل مشکل DNS دامنه" + +msgid "If the node address is a domain name, this DNS will be used for resolution." +msgstr "اگر آدرس گره یک نام دامنه باشد، از این DNS برای حل مسئله استفاده خواهد شد." + msgid "Chain Proxy" msgstr "پروکسی زنجیره‌ای" diff --git a/small/luci-app-passwall2/po/ru/passwall2.po b/small/luci-app-passwall2/po/ru/passwall2.po index fd19b73739..5013a33955 100644 --- a/small/luci-app-passwall2/po/ru/passwall2.po +++ b/small/luci-app-passwall2/po/ru/passwall2.po @@ -1765,6 +1765,12 @@ msgstr "Задержка (мс)" msgid "If is domain name, The requested domain name will be resolved to IP before connect." msgstr "Если указано доменное имя, оно будет разрешено в IP-адрес перед подключением." +msgid "Domain DNS Resolve" +msgstr "Разрешение DNS-запросов для домена" + +msgid "If the node address is a domain name, this DNS will be used for resolution." +msgstr "Если адрес узла является доменным именем, для разрешения будет использоваться этот DNS-сервер." + msgid "Chain Proxy" msgstr "Цепочка прокси" diff --git a/small/luci-app-passwall2/po/zh-cn/passwall2.po b/small/luci-app-passwall2/po/zh-cn/passwall2.po index c9d5ec1d3b..6e06ca3533 100644 --- a/small/luci-app-passwall2/po/zh-cn/passwall2.po +++ b/small/luci-app-passwall2/po/zh-cn/passwall2.po @@ -1756,6 +1756,12 @@ msgstr "延迟(ms)" msgid "If is domain name, The requested domain name will be resolved to IP before connect." msgstr "如果是域名,域名将在请求发出之前解析为 IP。" +msgid "Domain DNS Resolve" +msgstr "域名 DNS 解析" + +msgid "If the node address is a domain name, this DNS will be used for resolution." +msgstr "如果节点地址是域名,则将使用此 DNS 进行解析。" + msgid "Chain Proxy" msgstr "链式代理" diff --git a/small/luci-app-passwall2/po/zh-tw/passwall2.po b/small/luci-app-passwall2/po/zh-tw/passwall2.po index 9ffae2b5bb..938d43c0a1 100644 --- a/small/luci-app-passwall2/po/zh-tw/passwall2.po +++ b/small/luci-app-passwall2/po/zh-tw/passwall2.po @@ -1756,6 +1756,12 @@ msgstr "延迟(ms)" msgid "If is domain name, The requested domain name will be resolved to IP before connect." msgstr "如果是域名,域名將在請求發出之前解析為 IP。" +msgid "Domain DNS Resolve" +msgstr "域名 DNS 解析" + +msgid "If the node address is a domain name, this DNS will be used for resolution." +msgstr "如果節點地址是域名,則將使用此 DNS 進行解析。" + msgid "Chain Proxy" msgstr "鏈式代理" diff --git a/small/luci-app-passwall2/root/usr/share/passwall2/helper_dnsmasq.lua b/small/luci-app-passwall2/root/usr/share/passwall2/helper_dnsmasq.lua index 9fab4d1030..c15d7d3726 100644 --- a/small/luci-app-passwall2/root/usr/share/passwall2/helper_dnsmasq.lua +++ b/small/luci-app-passwall2/root/usr/share/passwall2/helper_dnsmasq.lua @@ -272,7 +272,7 @@ function add_rule(var) local function process_address(address) if address == "engage.cloudflareclient.com" then return end if datatypes.hostname(address) then - --set_domain_dns(address, fwd_dns) + set_domain_dns(address, fwd_dns) set_domain_ipset(address, setflag_4 .. "passwall2_vps," .. setflag_6 .. "passwall2_vps6") end end diff --git a/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua b/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua index 2a885cc4f7..807b81dc1e 100644 --- a/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua +++ b/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua @@ -5,6 +5,7 @@ require "nixio.fs" require "luci.sys" require "luci.http" require "luci.jsonc" +local nixio = require "nixio" require "luci.model.uci" local uci = require "luci.model.uci".cursor() @@ -146,11 +147,11 @@ local function set_apply_on_parse(map) end end -local has_xray = is_finded("xray") -local has_hysteria2 = is_finded("hysteria") - local has_ss_rust = is_finded("sslocal") or is_finded("ssserver") local has_ss_libev = is_finded("ss-redir") or is_finded("ss-local") +local has_trojan = is_finded("trojan") +local has_xray = is_finded("xray") +local has_hysteria2 = is_finded("hysteria") local server_table = {} local encrypt_methods = { @@ -277,25 +278,63 @@ o.value = sid -- 新增一个选择框,用于选择 Xray 或 Hysteria2 核心 o = s:option(ListValue, "_xray_hy2_type", string.format("%s", translatef("%s Node Use Type", "Hysteria2"))) o.description = translate("The configured type also applies to the core specified when manually importing nodes.") --- 设置默认 Xray 或 Hysteria2 核心 --- 动态添加选项 -if has_xray then - o:value("v2ray", translate("Xray (Hysteria2)")) -end +-- 注意:Auto 选项使用特殊字符串 "__auto__" 而不是空字符串 +o:value("__auto__", translate("Auto")) if has_hysteria2 then - o:value("hysteria2", translate("Hysteria2")) + o:value("hysteria2", translate("Hysteria2")) +end +if has_xray then + o:value("v2ray", translate("Xray (Hysteria2)")) end -- 读取全局 xray_hy2_type o.cfgvalue = function(self, section) - return self.map.uci:get("shadowsocksr", "@server_subscribe[0]", "xray_hy2_type") or "hysteria2" + local val = uci:get("shadowsocksr", "@server_subscribe[0]", "xray_hy2_type") + if val == nil or val == "" then + return "__auto__" -- 对应 Auto 选项 + end + return val end o.rmempty = true +-- 保存时更新全局配置 o.write = function(self, section, value) - -- 更新 server_subscribe 的 xray_hy2_type - local old_value = self.map.uci:get("shadowsocksr", "@server_subscribe[0]", "xray_hy2_type") - if old_value ~= value then - self.map.uci:set("shadowsocksr", "@server_subscribe[0]", "xray_hy2_type", value) - end + if value == "__auto__" then + -- 删除全局配置 + uci:delete("shadowsocksr", "@server_subscribe[0]", "xray_hy2_type") + else + -- 设置具体值 + uci:set("shadowsocksr", "@server_subscribe[0]", "xray_hy2_type", value) + end +end + +-- 新增一个选择框,用于选择 Xray 或 Trojan 核心 +o = s:option(ListValue, "_xray_tj_type", string.format("%s", translatef("%s Node Use Type", "Trojan"))) +o.description = translate("The configured type also applies to the core specified when manually importing nodes.") +-- 注意:Auto 选项使用特殊字符串 "__auto__" 而不是空字符串 +o:value("__auto__", translate("Auto")) +if has_hysteria2 then + o:value("trojan", translate("Trojan")) +end +if has_xray then + o:value("v2ray", translate("Xray (Trojan)")) +end +-- 读取全局 xray_tj_type +o.cfgvalue = function(self, section) + local val = uci:get("shadowsocksr", "@server_subscribe[0]", "xray_tj_type") + if val == nil or val == "" then + return "__auto__" -- 对应 Auto 选项 + end + return val +end +o.rmempty = true +-- 保存时更新全局配置 +o.write = function(self, section, value) + if value == "__auto__" then + -- 删除全局配置 + uci:delete("shadowsocksr", "@server_subscribe[0]", "xray_tj_type") + else + -- 设置具体值 + uci:set("shadowsocksr", "@server_subscribe[0]", "xray_tj_type", value) + end end o = s:option(ListValue, "type", translate("Server Node Type")) @@ -329,6 +368,29 @@ end if is_finded("redsocks2") then o:value("tun", translate("Network Tunnel")) end +local old_cfgvalue = o.cfgvalue +o.cfgvalue = function(self, section) + local val = self.map.uci:get("shadowsocksr", section, "type") + if val == "ss-rust" or val == "ss-libev" then + return "ss" + end + if old_cfgvalue then + return old_cfgvalue(self, section) + end + return val +end +-- 重写 write,当用户选择 "ss" 时不写入(由 _ss_core 负责写入具体核心) +local old_write = o.write +o.write = function(self, section, value) + if value == "ss" then + return -- 不做任何写入,等待 _ss_core 写入 + end + if old_write then + old_write(self, section, value) + else + self.map.uci:set("shadowsocksr", section, "type", value) + end +end o.description = translate("Using incorrect encryption mothod may causes service fail to start") @@ -343,29 +405,37 @@ end o:depends("type", "tun") o.description = translate("Redirect traffic to this network interface") --- 新增一个选择框,用于选择 Shadowsocks 版本 -o = s:option(ListValue, "_has_ss_type", string.format("%s", translatef("%s Node Use Version", "ShadowSocks"))) +-- 新增一个选择框,用于选择 Shadowsocks 具体版本(仅当节点类型为 ss 或其具体子类型时显示) +o = s:option(ListValue, "_ss_core", string.format("%s", translatef("%s Node Use Version", "ShadowSocks"))) o.description = translate("Selection ShadowSocks Node Use Version.") --- 设置默认 Shadowsocks 版本 --- 动态添加选项 if has_ss_rust then - o:value("ss-rust", translate("ShadowSocks-rust Version")) + o:value("ss-rust", translate("ShadowSocks-rust Version")) end if has_ss_libev then - o:value("ss-libev", translate("ShadowSocks-libev Version")) + o:value("ss-libev", translate("ShadowSocks-libev Version")) end --- 读取全局 ss_type o.cfgvalue = function(self, section) - return self.map.uci:get("shadowsocksr", "@server_subscribe[0]", "ss_type") or "ss-rust" + -- 读取当前节点的 type 值,如果已经是具体核心则显示对应的选项 + local node_type = self.map.uci:get("shadowsocksr", section, "type") + if node_type == "ss-rust" or node_type == "ss-libev" then + return node_type + end + -- 如果全局 ss_type 有值且为具体核心则返回该值 + local ss_type = self.map.uci:get("shadowsocksr", "@server_subscribe[0]", "ss_type") + if ss_type == "ss-rust" or ss_type == "ss-libev" then + return ss_type + end + -- 如果节点 type 是旧的 "ss",则返回空,手动选择 + return nil end +-- 显示条件:当节点类型为 "ss" 或其具体核心时显示 o:depends("type", "ss") o.rmempty = true +-- 保存时,将选择的值直接写入当前节点的 type 字段 o.write = function(self, section, value) - -- 更新 server_subscribe 的 ss_type - local old_value = self.map.uci:get("shadowsocksr", "@server_subscribe[0]", "ss_type") - if old_value ~= value then - self.map.uci:set("shadowsocksr", "@server_subscribe[0]", "ss_type", value) - end + if value and value ~= "" then + self.map.uci:set("shadowsocksr", section, "type", value) + end end o = s:option(ListValue, "v2ray_protocol", translate("V2Ray/XRay protocol")) @@ -539,7 +609,7 @@ o = s:option(Value, "port_range", translate("Port hopping range")) o.description = translate("Format as 10000:20000 or 10000-20000 Multiple groups are separated by commas (,).") o:depends({type = "hysteria2", flag_port_hopping = true}) o:depends({type = "v2ray", v2ray_protocol = "hysteria2", flag_port_hopping = true}) ---o.datatype = "portrange" +o.datatype = "or(uinteger,portrange)" o.rmempty = true o = s:option(Flag, "flag_transport", translate("Enable Transport Protocol Settings")) @@ -554,9 +624,10 @@ o.default = "udp" o.rmempty = true o = s:option(Value, "hopinterval", translate("Port Hopping Interval(Unit:Second)")) +o.description = translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5.") o:depends({type = "hysteria2", flag_transport = true, flag_port_hopping = true}) o:depends({type = "v2ray", v2ray_protocol = "hysteria2", flag_port_hopping = true}) -o.datatype = "uinteger" +o.datatype = "or(uinteger,portrange)" o.rmempty = true o.default = "30" diff --git a/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua b/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua index bb19eb7d30..1404134c05 100644 --- a/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua +++ b/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua @@ -294,4 +294,3 @@ if is_finded("chinadns-ng") then end return m - diff --git a/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua b/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua index 65d1a7f18b..07a742575f 100644 --- a/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua +++ b/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua @@ -70,9 +70,14 @@ local function set_apply_on_parse(map) end end +local has_ss_rust = is_finded("sslocal") or is_finded("ssserver") +local has_ss_libev = is_finded("ss-redir") or is_finded("ss-local") +local has_trojan = is_finded("trojan") local has_xray = is_finded("xray") local has_hysteria2 = is_finded("hysteria") +local ss_type_list = {} +local tj_type_list = {} local hy2_type_list = {} if has_hysteria2 then @@ -82,19 +87,12 @@ if has_xray then table.insert(hy2_type_list, { id = "v2ray", name = translate("Xray (Hysteria2)") }) end --- 如果用户没有手动设置,则自动选择 -if not xray_hy2_type or xray_hy2_type == "" then - if has_hysteria2 then - xray_hy2_type = "hysteria2" - elseif has_xray then - xray_hy2_type = "v2ray" - end +if has_trojan then + table.insert(tj_type_list, { id = "trojan", name = translate("Trojan") }) +end +if has_xray then + table.insert(tj_type_list, { id = "v2ray", name = translate("Xray (Trojan)") }) end - -local has_ss_rust = is_finded("sslocal") or is_finded("ssserver") -local has_ss_libev = is_finded("ss-redir") or is_finded("ss-local") - -local ss_type_list = {} if has_ss_rust then table.insert(ss_type_list, { id = "ss-rust", name = translate("ShadowSocks-rust Version") }) @@ -106,17 +104,6 @@ if has_xray then table.insert(ss_type_list, { id = "v2ray", name = translate("Xray (ShadowSocks)") }) end --- 如果用户没有手动设置,则自动选择 -if not ss_type or ss_type == "" then - if has_ss_rust then - ss_type = "ss-rust" - elseif has_ss_libev then - ss_type = "ss-libev" - elseif has_xray then - ss_type = "v2ray" - end -end - uci:foreach("shadowsocksr", "servers", function(s) server_count = server_count + 1 end) @@ -162,22 +149,87 @@ o:depends("auto_update", "1") -- 确保 hy2_type_list 不为空 if #hy2_type_list > 0 then + local sid = uci:get_first("shadowsocksr", "server_subscribe") + if not sid then + uci:foreach("shadowsocksr", "server_subscribe", function(section) + sid = section[".name"] + return false + end) + end + if sid then + local old_val = uci:get("shadowsocksr", sid, "xray_hy2_type") + if old_val and old_val ~= "" then + if (old_val == "hysteria2" and not has_hysteria2) or + (old_val == "v2ray" and not has_xray) then + -- 核心不可用,设置为空(删除配置) + uci:set("shadowsocksr", sid, "xray_hy2_type", "") + uci:commit("shadowsocksr") + end + end + end o = s:option(ListValue, "xray_hy2_type", string.format("%s", translatef("%s Node Use Type", "Hysteria2"))) o.description = translate("The configured type also applies to the core specified when manually importing nodes.") + o:value("", translate("Auto")) for _, v in ipairs(hy2_type_list) do o:value(v.id, v.name) -- 存储 "Xray" / "Hysteria2",但 UI 显示完整名称 end - o.default = xray_hy2_type -- 设置默认值 +end + +-- 确保 tj_type_list 不为空 +if #tj_type_list > 0 then + local sid = uci:get_first("shadowsocksr", "server_subscribe") + if not sid then + uci:foreach("shadowsocksr", "server_subscribe", function(section) + sid = section[".name"] + return false + end) + end + if sid then + local old_val = uci:get("shadowsocksr", sid, "xray_tj_type") + if old_val and old_val ~= "" then + if (old_val == "trojan" and not has_trojan) or + (old_val == "v2ray" and not has_xray) then + -- 核心不可用,设置为空(删除配置) + uci:set("shadowsocksr", sid, "xray_tj_type", "") + uci:commit("shadowsocksr") + end + end + end + o = s:option(ListValue, "xray_tj_type", string.format("%s", translatef("%s Node Use Type", "Trojan"))) + o.description = translate("The configured type also applies to the core specified when manually importing nodes.") + o:value("", translate("Auto")) + for _, v in ipairs(tj_type_list) do + o:value(v.id, v.name) -- 存储 "Xray" / "Trojan",但 UI 显示完整名称 + end end -- 确保 ss_type_list 不为空 if #ss_type_list > 0 then + local sid = uci:get_first("shadowsocksr", "server_subscribe") + if not sid then + uci:foreach("shadowsocksr", "server_subscribe", function(section) + sid = section[".name"] + return false + end) + end + if sid then + local old_val = uci:get("shadowsocksr", sid, "ss_type") + if old_val and old_val ~= "" then + if (old_val == "ss-rust" and not has_ss_rust) or + (old_val == "ss-libev" and not has_ss_libev) or + (old_val == "v2ray" and not has_xray) then + -- 核心不可用,设置为空(删除配置) + uci:set("shadowsocksr", sid, "ss_type", "") + uci:commit("shadowsocksr") + end + end + end o = s:option(ListValue, "ss_type", string.format("%s", translatef("%s Node Use Version", "ShadowSocks"))) o.description = translate("Selection ShadowSocks Node Use Version.") + o:value("", translate("Auto")) for _, v in ipairs(ss_type_list) do o:value(v.id, v.name) -- 存储 "ss-libev" / "ss-rust",但 UI 显示完整名称 end - o.default = ss_type -- 设置默认值 end o = s:option(DynamicList, "subscribe_url", translate("Subscribe URL")) diff --git a/small/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm b/small/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm index 0f3d6e36a6..b5610c2e36 100644 --- a/small/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm +++ b/small/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm @@ -3,11 +3,24 @@ local map = self.map local ss_type = map:get("@server_subscribe[0]", "ss_type") local xray_hy2_type = map:get("@server_subscribe[0]", "xray_hy2_type") +local xray_tj_type = map:get("@server_subscribe[0]", "xray_tj_type") + +local has_ss_rust = luci.sys.exec('type -t -p sslocal 2>/dev/null || type -t -p ssserver 2>/dev/null') ~= "" +local has_ss_libev = luci.sys.exec('type -t -p ss-redir 2>/dev/null || type -t -p ss-local 2>/dev/null') ~= "" +local has_hysteria = luci.sys.exec('type -t -p hysteria 2>/dev/null') ~= "" +local has_trojan = luci.sys.exec('type -t -p trojan 2>/dev/null') ~= "" +local has_xray = luci.sys.exec('type -t -p xray 2>/dev/null') ~= "" -%>