From 5859bfad2e4bc109ed383903daa3b90714fa0337 Mon Sep 17 00:00:00 2001 From: RyanVan <150385913+Ryson-32@users.noreply.github.com> Date: Wed, 24 Jun 2026 18:31:51 +0800 Subject: [PATCH 1/2] fix: narrow custom proxy group defaults --- .../core/src/generator/proxy-groups.test.ts | 71 ++++++++++++++++--- packages/core/src/generator/proxy-groups.ts | 7 +- .../actions/custom-actions.test.ts | 2 +- .../config-store/actions/custom-actions.ts | 2 +- 4 files changed, 65 insertions(+), 17 deletions(-) diff --git a/packages/core/src/generator/proxy-groups.test.ts b/packages/core/src/generator/proxy-groups.test.ts index cd7f7db..07a881a 100644 --- a/packages/core/src/generator/proxy-groups.test.ts +++ b/packages/core/src/generator/proxy-groups.test.ts @@ -141,7 +141,55 @@ describe("proxy group generator", () => { }); }); - it("keeps filtered-node custom groups node-scoped while exposing them as policy members", () => { + it("defaults ordinary custom groups to node-only members without adding them to node select", () => { + const groups = generateProxyGroups({ + nodes: [node("Node A"), node("Node B")], + enabledModules: ["select", "auto"], + ruleProviderBaseUrl: "https://rules.example.com", + testUrl: "https://probe.example.com/204", + testInterval: 120, + customProxyGroups: [ + customGroup("one", "select"), + customGroup("two", "select"), + customGroup("direct", "direct-first"), + customGroup("reject", "reject-first"), + ], + }); + + expect(groups.find((group) => group.name === "🚀 节点选择")?.proxies).toEqual([ + "⚡ 自动选择", + "DIRECT", + "REJECT", + "Node A", + "Node B", + ]); + expect(groups.find((group) => group.name === "Custom one")?.proxies).toEqual([ + "DIRECT", + "REJECT", + "Node A", + "Node B", + ]); + expect(groups.find((group) => group.name === "Custom two")?.proxies).toEqual([ + "DIRECT", + "REJECT", + "Node A", + "Node B", + ]); + expect(groups.find((group) => group.name === "Custom direct")?.proxies).toEqual([ + "DIRECT", + "REJECT", + "Node A", + "Node B", + ]); + expect(groups.find((group) => group.name === "Custom reject")?.proxies).toEqual([ + "REJECT", + "DIRECT", + "Node A", + "Node B", + ]); + }); + + it("keeps filtered-node custom groups node-scoped while exposing them as non-select policy members", () => { const groups = generateProxyGroups({ nodes: [node("Node A"), node("Node B"), node("Filtered")], proxyProviderNames: ["remote"], @@ -152,7 +200,7 @@ describe("proxy group generator", () => { customProxyGroups: [ { id: "filtered", - name: "Filtered", + name: "Filtered Group", emoji: "", memberSource: "filtered-nodes", includeInGroupMembers: true, @@ -163,25 +211,26 @@ describe("proxy group generator", () => { ], }); - expect(groups[0]?.name).toBe("Filtered"); - expect(groups.find((group) => group.name === "Filtered")?.proxies).toEqual([ + expect(groups[0]?.name).toBe("Filtered Group"); + expect(groups.find((group) => group.name === "Filtered Group")?.proxies).toEqual([ "DIRECT", "REJECT", "Node A", "Filtered", ]); - expect(groups.find((group) => group.name === "Filtered")).not.toHaveProperty("use"); - expect(groups.find((group) => group.name === "Filtered")?.proxies).not.toContain("Custom normal"); - expect(groups.find((group) => group.name === "Filtered")?.proxies).not.toContain("🚀 节点选择"); - expect(groups.find((group) => group.name === "Custom normal")?.proxies).toContain("Filtered"); + expect(groups.find((group) => group.name === "Filtered Group")).not.toHaveProperty("use"); + expect(groups.find((group) => group.name === "Filtered Group")?.proxies).not.toContain("Custom normal"); + expect(groups.find((group) => group.name === "Filtered Group")?.proxies).not.toContain("🚀 节点选择"); + expect(groups.find((group) => group.name === "Custom normal")?.proxies).not.toContain("Filtered Group"); + expect(groups.find((group) => group.name === "Custom normal")?.proxies).not.toContain("🚀 节点选择"); expect(groups.find((group) => group.name === "Custom normal")?.proxies).not.toContain("Custom normal"); expect(groups.find((group) => group.name === "Custom normal")).toMatchObject({ use: ["remote"] }); - expect(groups.find((group) => group.name === "🚀 节点选择")?.proxies).toContain("Filtered"); - expect(groups.find((group) => group.name === "🚀 节点选择")?.proxies).toContain("Custom normal"); + expect(groups.find((group) => group.name === "🚀 节点选择")?.proxies).not.toContain("Filtered Group"); + expect(groups.find((group) => group.name === "🚀 节点选择")?.proxies).not.toContain("Custom normal"); expect(groups.find((group) => group.name === "🏠 私有网络")?.proxies?.slice(0, 5)).toEqual([ "DIRECT", "REJECT", - "Filtered", + "Filtered Group", "Custom normal", "🚀 节点选择", ]); diff --git a/packages/core/src/generator/proxy-groups.ts b/packages/core/src/generator/proxy-groups.ts index edc7c2f..63d56d5 100644 --- a/packages/core/src/generator/proxy-groups.ts +++ b/packages/core/src/generator/proxy-groups.ts @@ -197,7 +197,7 @@ export function generateProxyGroups(options: GenerateOptions): ProxyGroup[] { "DIRECT", "REJECT" ); - const customBaseProxies = moduleBaseProxies; + const customBaseProxies = fallbackTargets("DIRECT", "REJECT", ...filteredNodeNames); const availableMemberProxyNames = fallbackTargets( "DIRECT", "REJECT", @@ -252,7 +252,6 @@ export function generateProxyGroups(options: GenerateOptions): ProxyGroup[] { autoTarget, "DIRECT", "REJECT", - ...customGroupNames, ...nodeNames ); groups.push({ @@ -408,7 +407,7 @@ export function generateProxyGroups(options: GenerateOptions): ProxyGroup[] { name: customGroup.name, type: "select", proxies: resolveCustom( - fallbackTargets("DIRECT", "REJECT", selectTarget, autoTarget, ...filteredNodeNames).filter( + fallbackTargets("DIRECT", "REJECT", ...filteredNodeNames).filter( (target) => target !== customGroup.name ) ), @@ -420,7 +419,7 @@ export function generateProxyGroups(options: GenerateOptions): ProxyGroup[] { name: customGroup.name, type: "select", proxies: resolveCustom( - fallbackTargets("REJECT", "DIRECT", selectTarget).filter( + fallbackTargets("REJECT", "DIRECT", ...filteredNodeNames).filter( (target) => target !== customGroup.name ) ), diff --git a/packages/ui/src/store/config-store/actions/custom-actions.test.ts b/packages/ui/src/store/config-store/actions/custom-actions.test.ts index 0658668..0404386 100644 --- a/packages/ui/src/store/config-store/actions/custom-actions.test.ts +++ b/packages/ui/src/store/config-store/actions/custom-actions.test.ts @@ -85,7 +85,7 @@ describe("custom config-store actions", () => { const groupId = getState().customProxyGroups[0].id; expect(groupId).toBe("custom-group-1767225600000"); expect(getState().customProxyGroups[0]).toEqual( - expect.objectContaining({ includeInGroupMembers: true }) + expect.objectContaining({ includeInGroupMembers: false }) ); actions.updateCustomProxyGroup(groupId, { diff --git a/packages/ui/src/store/config-store/actions/custom-actions.ts b/packages/ui/src/store/config-store/actions/custom-actions.ts index 4a3cc8b..a92dd87 100644 --- a/packages/ui/src/store/config-store/actions/custom-actions.ts +++ b/packages/ui/src/store/config-store/actions/custom-actions.ts @@ -140,7 +140,7 @@ export function createCustomActions( ...(typeof group.description === "string" ? { description: group.description.trim() } : {}), ...(group.memberSource === "filtered-nodes" ? { memberSource: "filtered-nodes" as const } : {}), includeInGroupMembers: - typeof group.includeInGroupMembers === "boolean" ? group.includeInGroupMembers : true, + typeof group.includeInGroupMembers === "boolean" ? group.includeInGroupMembers : false, groupType: group.groupType, ...(group.groupType === "load-balance" && group.strategy ? { strategy: group.strategy } : {}), ...(group.advanced ? { advanced: normalizeProxyGroupAdvancedConfig(group.advanced) } : {}), From c06bf1b099c5658cc140d71323f8125938a3ca43 Mon Sep 17 00:00:00 2001 From: RyanVan <150385913+Ryson-32@users.noreply.github.com> Date: Wed, 24 Jun 2026 18:51:37 +0800 Subject: [PATCH 2/2] chore: bump public version to v2.5.1 --- README-CN.md | 2 +- README.md | 2 +- docs/release-notes.md | 40 +++++++++++++++++----------------------- local/package.json | 2 +- package-lock.json | 6 +++--- package.json | 2 +- 6 files changed, 24 insertions(+), 30 deletions(-) diff --git a/README-CN.md b/README-CN.md index 6497d91..421d12d 100644 --- a/README-CN.md +++ b/README-CN.md @@ -4,7 +4,7 @@
-
+
diff --git a/README.md b/README.md
index 54eeac5..27a159c 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
-
+
diff --git a/docs/release-notes.md b/docs/release-notes.md
index a15cf83..7c045e0 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -1,49 +1,43 @@
-# SubBoost v2.5.0
+# SubBoost v2.5.1
## 中文
### 更新重点
-SubBoost v2.5.0 主要改善代理组编辑、自部署更新和订阅生成稳定性。建议 v2.4.0 用户升级。
+SubBoost v2.5.1 是一个修复版本,主要修复自定义代理组的默认成员逻辑,并提升自部署安装、更新时的版本来源稳定性。建议 v2.5.0 用户升级。
### 主要变化
-- **移除筛选代理组**,相关功能转移到分流代理组高级模式和自定义分流组。
-- 分流代理组高级模式支持按来源、地区、关键词和排除条件整理节点。
-- 订阅生成更稳,规则顺序、代理组输出和常见 Mihomo 字段处理减少了意外变化。
-- 节点导入兼容性更好,覆盖更多常见节点链接和 Mihomo YAML 配置。
-- 自部署安装和更新流程更可靠,`subboost update`、状态检查和失败提示都有改进。
-- Dashboard 下载订阅 YAML 的行为更接近直接访问订阅链接,文件名和响应头更稳定。
-- 首次安装后的管理员初始化、登录和数据库连接更稳,减少安装完成后进不去后台的情况。
-- 安全和发布检查加强,降低公开包、安装资产和更新流程出错的风险。
+- 修复新建自定义代理组时默认成员过宽的问题,避免默认生成出“节点选择”和自定义组互相引用的循环配置。
+- `🚀 节点选择` 默认不再自动包含自定义代理组,减少代理组套娃导致配置异常或预览卡顿的风险。
+- 新建普通自定义代理组默认只包含 `DIRECT`、`REJECT` 和真实节点,保留高级模式里的手动配置能力。
+- 改进自部署安装和 `subboost update` 的版本来源处理,稳定版安装资产会默认固定到对应 release 版本。
+- 改进自部署管理脚本的更新来源,减少从指定版本更新时意外跟随其它发布通道的风险。
### 升级说明
- 建议升级前备份 `/opt/subboost/.env` 和数据库,方便需要时回滚。
-- 已安装 v2.4.0 的自部署实例可以继续使用 `subboost update` 更新。
+- 已安装 v2.5.0 的自部署实例可以继续使用 `subboost update` 更新。
- 普通订阅转换、模板和规则功能不需要手动改环境变量。
-- 如果你在 v2.4.0 使用过筛选代理组,请升级后到自定义代理组或分流代理组高级模式里重新配置。
+- 已经手动配置过的高级代理组不会被自动改写;本次主要改变新建和默认生成行为。
## English
### Highlights
-SubBoost v2.5.0 mainly improves proxy group editing, self-hosted updates, and subscription generation stability. v2.4.0 users are encouraged to upgrade.
+SubBoost v2.5.1 is a patch release that fixes default custom proxy group membership and improves version-source stability for self-hosted install and update flows. v2.5.0 users are encouraged to upgrade.
### Main Changes
-- Removed filtered proxy groups. Related features have moved to proxy group advanced mode and custom proxy groups.
-- Proxy group advanced mode supports organizing nodes by source, region, keyword, and exclusion rules.
-- Made subscription generation more stable, reducing unexpected changes in rule order, proxy group output, and common Mihomo fields.
-- Improved node import compatibility for more common node links and Mihomo YAML configurations.
-- Made self-hosted install and update flows more reliable, including `subboost update`, status checks, and failure messages.
-- Dashboard YAML downloads now behave more like direct subscription links, with steadier filenames and response headers.
-- Improved first-install admin setup, login, and database connection reliability to reduce post-install access issues.
-- Strengthened safety and release checks to reduce the risk of problems in public packages, install assets, and updates.
+- Fixed overly broad default members for newly created custom proxy groups, preventing default configurations where node selection and custom groups reference each other in a loop.
+- `🚀 节点选择` no longer automatically includes custom proxy groups by default, reducing the risk of nested proxy group loops causing invalid output or preview slowdowns.
+- Newly created normal custom proxy groups now default to `DIRECT`, `REJECT`, and real nodes only, while manual advanced configuration remains available.
+- Improved self-hosted install and `subboost update` version-source handling so stable release assets stay pinned to the matching release version by default.
+- Improved the self-hosted manager update source to reduce the risk of a pinned-version update unexpectedly following another release channel.
### Upgrade Notes
- Back up `/opt/subboost/.env` and the database before upgrading so rollback is easier if needed.
-- Existing v2.4.0 self-hosted installations can continue to update with `subboost update`.
+- Existing v2.5.0 self-hosted installations can continue to update with `subboost update`.
- Normal subscription conversion, templates, and rules do not require manual environment-variable changes.
-- If you used filtered proxy groups in v2.4.0, reconfigure them after upgrading through custom proxy groups or proxy group advanced mode.
+- Manually configured advanced proxy groups are not rewritten automatically; this release mainly changes new and default generated behavior.
diff --git a/local/package.json b/local/package.json
index a57f440..86c48f8 100644
--- a/local/package.json
+++ b/local/package.json
@@ -1,6 +1,6 @@
{
"name": "@subboost/local",
- "version": "2.5.0",
+ "version": "2.5.1",
"license": "AGPL-3.0-only",
"private": true,
"type": "module",
diff --git a/package-lock.json b/package-lock.json
index 3340d5f..ec0d0d6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "subboost",
- "version": "2.5.0",
+ "version": "2.5.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "subboost",
- "version": "2.5.0",
+ "version": "2.5.1",
"license": "AGPL-3.0-only",
"workspaces": [
"packages/*",
@@ -67,7 +67,7 @@
},
"local": {
"name": "@subboost/local",
- "version": "2.5.0",
+ "version": "2.5.1",
"license": "AGPL-3.0-only",
"dependencies": {
"@prisma/adapter-pg": "^7.8.0",
diff --git a/package.json b/package.json
index def6930..795f5dc 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "subboost",
- "version": "2.5.0",
+ "version": "2.5.1",
"license": "AGPL-3.0-only",
"private": true,
"engines": {