1.Compose.yaml

services:
  sub-store:
    image: xream/sub-store:latest
    container_name: sub-store
    restart: always
    volumes:
      - ./data:/opt/app/data
    environment:
      - SUB_STORE_FRONTEND_BACKEND_PATH=/oSa0gNr9tMYtdcaqteo8
    ports:
      - 3001:3001
    stdin_open: true
    tty: true

2.节点清洗

function operator(proxies = [], targetPlatform, context) {
  // === 第一阶段:建立 "IP -> 域名" 的映射字典 ===
  const ipToDomainMap = {};
  proxies.forEach(p => {
    if (p.server && p.servername) {
      ipToDomainMap[p.server] = p.servername;
    }
  });

  // === 第二阶段:遍历处理并返回全新排序的节点数组 ===
  return proxies.map(p => {
    // 1. 基础修正
    p['skip-cert-verify'] = true;
    p.udp = true; 

    // 清理冗余字段
    delete p._subName;
    delete p._subDisplayName;
    delete p._collectionName;
    delete p._collectionDisplayName;

    // 2. 协议专项定制
    if (p.type === 'tuic') {
      p.version = 5;
      p.tls = true; 
      delete p['udp-relay-mode']; 
      // TUIC 依赖 QUIC,优先 h3
      p.alpn = ['h3', 'h2', 'http/1.1'];
    }

    if (p.type === 'hysteria2') {
      p.tls = true; 
      // Hy2 依赖 QUIC,优先 h3
      p.alpn = ['h3', 'h2', 'http/1.1'];
    }

    if (p.type === 'trojan') {
      p.tls = true; 
      if (p.network === 'ws') {
        const domain = ipToDomainMap[p.server]; 
        
        if (domain) {
          p.port = 443;               
          p.servername = domain;      
          p.sni = domain;
          
          // 核心修改:WebSocket 强绑 http/1.1
          p.alpn = ['http/1.1'];

          if (!p['ws-opts']) p['ws-opts'] = {};
          if (!p['ws-opts'].headers) p['ws-opts'].headers = {};
          p['ws-opts'].headers['Host'] = domain;
        }
      }
    }

    // 3. 自动加国旗
    const match = p.name.match(/^([a-zA-Z0-9]+)-([a-zA-Z]{2})-(.+)$/);
    if (match) {
      const countryCode = match[2]; 
      const flag = ProxyUtils.getFlag(countryCode) || '🌍';
      p.name = `${flag} ${p.name}`;
    }

    // === 第三阶段:终极格式化 (拯救强迫症) ===
    const orderedProxy = {};
    
    // 定义你期望的完美 YAML 字段输出顺序
    const perfectOrder = [
      'name', 'type', 'server', 'port', 'password', 'uuid',
      'network', 'tls', 'servername', 'sni', 'alpn',
      'skip-cert-verify', 'udp', 'version', 'up', 'down', 'congestion-controller',
      'ws-opts'
    ];

    // 按照完美顺序挑拣属性
    perfectOrder.forEach(key => {
      if (p[key] !== undefined) {
        orderedProxy[key] = p[key];
      }
    });

    // 把其他没考虑到的生僻属性补在最后面,防止丢数据
    Object.keys(p).forEach(key => {
      if (orderedProxy[key] === undefined) {
        orderedProxy[key] = p[key];
      }
    });

    return orderedProxy;
  });
}

3. 基本配置调用

# ================= 基础设置 =================
mixed-port: 7890
allow-lan: true
bind-address: '*'
mode: rule
log-level: info
ipv6: false
external-controller: '0.0.0.0:9090'

# ================= DNS 配置 =================
dns:
  enable: true
  listen: 0.0.0.0:1053
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  default-nameserver:
    - 114.114.114.114
    - 119.29.29.29
    - 223.5.5.5
  nameserver:
    - https://doh.pub/dns-query
    - https://dns.alidns.com/dns-query
    - 223.5.5.5
    - 119.29.29.29
  fallback:
    - https://dns.google/dns-query
    - https://cloudflare-dns.com/dns-query
  fallback-filter:
    geoip: true
    geoip-code: CN
    ipcidr:
      - 240.0.0.0/4

# ================= 节点配置 =================
proxies: []
  
# ================= 策略组配置 =================
proxy-groups:
  # 1. 主干选择
  - name: "🚀 节点选择"
    type: select
    proxies:
      - "⚡ 全局最低延迟"
      # (我们会在最终脚本里,把生成的地区组动态插在这里)
      - "🎯 全球直连"

  # 2. 全局自动优选框架
  - name: "⚡ 全局最低延迟"
    type: url-test
    url: http://cp.cloudflare.com/generate_204
    interval: 300
    tolerance: 50
    proxies: [] # (最终脚本会自动把所有节点填入这里)

  # 4. 辅助兜底组
  - name: "🎯 全球直连"
    type: select
    proxies:
      - DIRECT

  - name: "🐟 漏网之鱼"
    type: select
    proxies:
      - "🚀 节点选择"
      - "🎯 全球直连"

# ================= 路由规则 =================
rules:
  - DOMAIN-SUFFIX,local,🎯 全球直连
  - DOMAIN-SUFFIX,localhost,🎯 全球直连
  - IP-CIDR,127.0.0.0/8,🎯 全球直连,no-resolve
  - IP-CIDR,192.168.0.0/16,🎯 全球直连,no-resolve
  - IP-CIDR,10.0.0.0/8,🎯 全球直连,no-resolve
  - IP-CIDR,172.16.0.0/12,🎯 全球直连,no-resolve
  - IP-CIDR,100.64.0.0/10,🎯 全球直连,no-resolve
  - IP-CIDR6,::1/128,🎯 全球直连,no-resolve
  - IP-CIDR6,fc00::/7,🎯 全球直连,no-resolve
  - IP-CIDR6,fe80::/10,🎯 全球直连,no-resolve
  - DOMAIN-KEYWORD,gemini,🚀 节点选择
  - DOMAIN-SUFFIX,generativelanguage.googleapis.com,🚀 节点选择
  - DOMAIN-SUFFIX,googleapis.com,🚀 节点选择
  - GEOSITE,google,🚀 节点选择
  - GEOSITE,openai,🚀 节点选择
  - DOMAIN-SUFFIX,ai.com,🚀 节点选择
  - GEOSITE,apple,🎯 全球直连
  - DOMAIN-SUFFIX,apple.com,🎯 全球直连
  - DOMAIN-SUFFIX,icloud.com,🎯 全球直连
  - DOMAIN-SUFFIX,mzstatic.com,🎯 全球直连
  - GEOSITE,cn,🎯 全球直连
  - GEOIP,CN,🎯 全球直连
  - MATCH,🐟 漏网之鱼

4. 节点组合

// 1. 读取基础配置
const baseStr = await produceArtifact({ type: 'file', name: '第 2 步节点清洗文件名称' });
const yamlObj = ProxyUtils.yaml.safeLoad(baseStr);

// 2. 获取清洗完毕的节点
let clashMetaProxies = await produceArtifact({
  type: 'collection',
  name: '组合订阅文件名称',
  platform: 'ClashMeta',
  produceType: 'internal'
});

// 写入节点列表
yamlObj.proxies = clashMetaProxies;
const allNodeNames = clashMetaProxies.map(p => p.name);

// 3. 实时解析节点名称并进行动态分组 (完美替代原有的黑科技)
const regionGroupsMap = {};
clashMetaProxies.forEach(p => {
  // 此时的 p.name 已经是加过国旗的,例如 "🇯🇵 AWS-JP-VLESS"
  // 我们用正则拆解出:Flag="🇯🇵", Provider="AWS", CountryCode="JP"
  const match = p.name.match(/^(.*?)\s+([a-zA-Z0-9]+)-([a-zA-Z]{2})-(.+)$/);
  
  if (match) {
    const flag = match[1];
    const provider = match[2];
    const countryCode = match[3];
    
    // 实时拼装出组名
    const groupName = `${flag} ${provider}-${countryCode}优选`;

    // 归类到对象中
    if (!regionGroupsMap[groupName]) {
      regionGroupsMap[groupName] = [];
    }
    regionGroupsMap[groupName].push(p.name);
  }
});

// 4. 将分组和节点注入到策略组中
const selectGroup = yamlObj['proxy-groups'].find(g => g.name === '🚀 节点选择');
const urlTestGroup = yamlObj['proxy-groups'].find(g => g.name === '⚡ 全局最低延迟');

// A. 填充“全局最低延迟”
urlTestGroup.proxies = allNodeNames;

// B. 动态生成地区优选组,并插入配置中
const regionGroupNames = Object.keys(regionGroupsMap);
regionGroupNames.forEach(groupName => {
  yamlObj['proxy-groups'].push({
    name: groupName,
    type: 'url-test',
    url: 'http://cp.cloudflare.com/generate_204',
    interval: 300,
    tolerance: 50,
    proxies: regionGroupsMap[groupName]
  });
  
  // 插入到 "🚀 节点选择" 中 (保持在 '🎯 全球直连' 前面)
  const directIndex = selectGroup.proxies.indexOf('🎯 全球直连');
  if (directIndex !== -1) {
    selectGroup.proxies.splice(directIndex, 0, groupName);
  } else {
    selectGroup.proxies.push(groupName);
  }
});

// 5. 导出干净的最终配置!
$content = ProxyUtils.yaml.dump(yamlObj); 


心之所向 素履以往