@subconverter/core 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -219,6 +219,16 @@ function createRulesetConfig() {
219
219
  }
220
220
 
221
221
  // src/types/settings.ts
222
+ function parseClashFlavor(value) {
223
+ const normalized = (value ?? "").trim().toLowerCase();
224
+ if (normalized === "premium" || normalized === "original" || normalized === "classic" || normalized === "clash") {
225
+ return "premium";
226
+ }
227
+ if (normalized === "stash") {
228
+ return "stash";
229
+ }
230
+ return "mihomo";
231
+ }
222
232
  var TargetFormat = /* @__PURE__ */ ((TargetFormat2) => {
223
233
  TargetFormat2["Clash"] = "clash";
224
234
  TargetFormat2["ClashR"] = "clashr";
@@ -247,6 +257,7 @@ function createExtraSettings() {
247
257
  authorized: false,
248
258
  autoCountry: false,
249
259
  clashClassicalRuleset: false,
260
+ clashFlavor: "mihomo",
250
261
  clashNewFieldName: true,
251
262
  clashProxiesStyle: "flow",
252
263
  clashProxyGroupsStyle: "flow",
@@ -257,6 +268,7 @@ function createExtraSettings() {
257
268
  enableRuleGenerator: true,
258
269
  excludeCountries: [],
259
270
  excludeRemarks: [],
271
+ expandRulesets: true,
260
272
  filterDeprecated: false,
261
273
  includeCountries: [],
262
274
  includeRemarks: [],
@@ -272,6 +284,7 @@ function createExtraSettings() {
272
284
  sortFlag: false,
273
285
  sortScript: "",
274
286
  surgeSsrPath: "",
287
+ templateVars: {},
275
288
  tfo: void 0,
276
289
  tls13: void 0,
277
290
  udp: void 0
@@ -495,7 +508,7 @@ function toBool(value) {
495
508
  return false;
496
509
  }
497
510
  const normalized = value.trim().toLowerCase();
498
- return normalized === "true" || normalized === "1";
511
+ return normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on";
499
512
  }
500
513
  function strFind(haystack, needle) {
501
514
  return haystack.includes(needle);
@@ -644,6 +657,23 @@ function templateVariableNames(content) {
644
657
  }
645
658
 
646
659
  // src/settings/config.ts
660
+ var RULESET_TYPE_PREFIXES = [
661
+ ["surge:", "surge" /* Surge */],
662
+ ["quanx:", "quanx" /* QuantumultX */],
663
+ ["quantumultx:", "quanx" /* QuantumultX */],
664
+ ["clash-domain:", "clash-domain" /* ClashDomain */],
665
+ ["clash-ipcidr:", "clash-ipcidr" /* ClashIpCidr */],
666
+ ["clash-classic:", "clash-classical" /* ClashClassical */],
667
+ ["clash:", "clash-classical" /* ClashClassical */]
668
+ ];
669
+ function parseRulesetSource(source) {
670
+ for (const [prefix, type] of RULESET_TYPE_PREFIXES) {
671
+ if (source.toLowerCase().startsWith(prefix)) {
672
+ return { type, url: source.slice(prefix.length) };
673
+ }
674
+ }
675
+ return { url: source };
676
+ }
647
677
  var GROUP_TYPE_MAP = {
648
678
  fallback: "fallback" /* Fallback */,
649
679
  "load-balance": "load-balance" /* LoadBalance */,
@@ -928,12 +958,16 @@ function createRequestSettings() {
928
958
  appendType: false,
929
959
  autoCountry: false,
930
960
  autoExtract: false,
961
+ clashFlavor: "mihomo",
931
962
  clashScript: false,
932
963
  classicalRuleset: false,
933
964
  dedupe: false,
965
+ devId: "",
934
966
  emoji: [],
935
967
  excludeCountries: [],
936
968
  excludeRemarks: [],
969
+ expand: true,
970
+ filename: "",
937
971
  filterDeprecated: false,
938
972
  group: [],
939
973
  includeCountries: [],
@@ -954,6 +988,7 @@ function createRequestSettings() {
954
988
  script: "",
955
989
  scv: void 0,
956
990
  sort: false,
991
+ strict: false,
957
992
  target: "auto" /* Auto */,
958
993
  tfo: void 0,
959
994
  tls13: void 0,
@@ -982,6 +1017,11 @@ function parseRequestSettings(query) {
982
1017
  settings.filterDeprecated = boolArg(query, "filter_deprecated");
983
1018
  settings.newFieldName = resolveNewFieldName(query);
984
1019
  settings.classicalRuleset = boolArg(query, "classical");
1020
+ settings.clashFlavor = parseClashFlavor(firstArg(query, "flavor"));
1021
+ settings.expand = queryBoolFlag(query, "expand") ?? true;
1022
+ settings.strict = boolArg(query, "strict");
1023
+ settings.filename = firstArg(query, "filename");
1024
+ settings.devId = firstArg(query, "dev_id", "dev-id", "device_id", "device-id");
985
1025
  settings.insert = getUrlArg(query, "insert") !== "";
986
1026
  settings.clashScript = boolArg(query, "clash_script");
987
1027
  settings.autoExtract = boolArg(query, "auto_extract");
@@ -1874,485 +1914,493 @@ function explodeClash(root, nodes) {
1874
1914
  }
1875
1915
  let index = nodes.length;
1876
1916
  for (const single of list) {
1877
- const proxyType = asString(get(single, "type")).toLowerCase();
1878
- const ps = asString(get(single, "name"));
1879
- const server = asString(get(single, "server"));
1880
- const port = asString(get(single, "port"));
1881
- let underlyingProxy = asString(get(single, "underlying-proxy"));
1882
- if (underlyingProxy === "") {
1883
- underlyingProxy = asString(get(single, "dialer-proxy"));
1884
- }
1885
- if (port === "" || port === "0") {
1886
- continue;
1887
- }
1888
- const udp = asTri(get(single, "udp"));
1889
- const tfo = asTri(get(single, "fast-open"));
1890
- const scv = asTri(get(single, "skip-cert-verify"));
1891
- const node = createProxy();
1892
- let group2 = "";
1893
- switch (proxyType) {
1894
- case "vmess": {
1895
- group2 = DEFAULT_GROUPS.v2ray;
1896
- const id = asString(get(single, "uuid"));
1897
- const aid = asString(get(single, "alterId"));
1898
- const cipher = asString(get(single, "cipher"));
1899
- const net = get(single, "network") !== void 0 ? asString(get(single, "network")) : "tcp";
1900
- const sni = asString(get(single, "servername"));
1901
- let path = "";
1902
- let host = "";
1903
- let edge = "";
1904
- switch (net) {
1905
- case "http":
1906
- path = asString(get(get(get(single, "http-opts"), "path"), 0));
1907
- host = asString(get(get(get(get(single, "http-opts"), "headers"), "Host"), 0));
1908
- edge = "";
1909
- break;
1910
- case "ws":
1911
- if (get(single, "ws-opts") !== void 0) {
1912
- const wsOpts = get(single, "ws-opts");
1913
- path = get(wsOpts, "path") !== void 0 ? asString(get(wsOpts, "path")) : "/";
1914
- host = asString(get(get(wsOpts, "headers"), "Host"));
1915
- edge = asString(get(get(wsOpts, "headers"), "Edge"));
1916
- } else {
1917
- path = get(single, "ws-path") !== void 0 ? asString(get(single, "ws-path")) : "/";
1918
- host = asString(get(get(single, "ws-headers"), "Host"));
1919
- edge = asString(get(get(single, "ws-headers"), "Edge"));
1920
- }
1921
- break;
1922
- case "h2":
1923
- path = asString(get(get(single, "h2-opts"), "path"));
1924
- host = asString(get(get(get(single, "h2-opts"), "host"), 0));
1925
- edge = "";
1926
- break;
1927
- case "grpc":
1928
- host = asString(get(single, "servername"));
1929
- path = asString(get(get(single, "grpc-opts"), "grpc-service-name"));
1930
- edge = "";
1931
- break;
1932
- default:
1933
- break;
1934
- }
1935
- const tls = asBool(get(single, "tls")) ? "tls" : "";
1936
- vmessConstruct(node, {
1937
- add: server,
1938
- aid,
1939
- cipher,
1940
- edge,
1941
- group: group2,
1942
- host,
1943
- id,
1944
- net,
1945
- path,
1946
- port,
1947
- remark: ps,
1948
- scv,
1949
- sni,
1950
- tfo,
1951
- tls,
1952
- type: "",
1953
- udp,
1954
- underlyingProxy
1955
- });
1956
- break;
1917
+ try {
1918
+ if (parseClashNode(single, nodes, index)) {
1919
+ index += 1;
1957
1920
  }
1958
- case "ss": {
1959
- group2 = DEFAULT_GROUPS.ss;
1960
- let cipher = asString(get(single, "cipher"));
1961
- const password = asString(get(single, "password"));
1962
- let plugin = "";
1963
- let pluginOption = "";
1964
- let pluginMode = "";
1965
- let pluginHost = "";
1966
- let pluginMux = "";
1967
- let pluginTls = "";
1968
- let path = "";
1969
- if (get(single, "plugin") !== void 0) {
1970
- const pluginName = asString(get(single, "plugin")).toLowerCase();
1971
- const pluginOpts = get(single, "plugin-opts");
1972
- if (pluginName === "obfs") {
1973
- plugin = "obfs-local";
1974
- pluginMode = asString(get(pluginOpts, "mode"));
1975
- pluginHost = asString(get(pluginOpts, "host"));
1976
- } else if (pluginName === "v2ray-plugin") {
1977
- plugin = "v2ray-plugin";
1978
- pluginMode = asString(get(pluginOpts, "mode"));
1979
- pluginHost = asString(get(pluginOpts, "host"));
1980
- pluginTls = asBool(get(pluginOpts, "tls")) ? "tls;" : "";
1981
- path = asString(get(pluginOpts, "path"));
1982
- pluginMux = asBool(get(pluginOpts, "mux")) ? "mux=4;" : "";
1983
- }
1984
- } else if (get(single, "obfs") !== void 0) {
1985
- plugin = "obfs-local";
1986
- pluginMode = asString(get(single, "obfs"));
1987
- pluginHost = asString(get(single, "obfs-host"));
1988
- }
1989
- if (plugin === "simple-obfs" || plugin === "obfs-local") {
1990
- pluginOption = `obfs=${pluginMode}`;
1991
- pluginOption += pluginHost === "" ? "" : `;obfs-host=${pluginHost}`;
1992
- } else if (plugin === "v2ray-plugin") {
1993
- pluginOption = `mode=${pluginMode};${pluginTls}${pluginMux}`;
1994
- if (pluginHost !== "") {
1995
- pluginOption += `host=${pluginHost};`;
1996
- }
1997
- if (path !== "") {
1998
- pluginOption += `path=${path};`;
1999
- }
2000
- if (pluginMux !== "") {
2001
- pluginOption += `mux=${pluginMux};`;
1921
+ } catch {
1922
+ }
1923
+ }
1924
+ }
1925
+ function parseClashNode(single, nodes, index) {
1926
+ const proxyType = asString(get(single, "type")).toLowerCase();
1927
+ const ps = asString(get(single, "name"));
1928
+ const server = asString(get(single, "server"));
1929
+ const port = asString(get(single, "port"));
1930
+ let underlyingProxy = asString(get(single, "underlying-proxy"));
1931
+ if (underlyingProxy === "") {
1932
+ underlyingProxy = asString(get(single, "dialer-proxy"));
1933
+ }
1934
+ if (port === "" || port === "0") {
1935
+ return false;
1936
+ }
1937
+ const udp = asTri(get(single, "udp"));
1938
+ const tfo = asTri(get(single, "fast-open"));
1939
+ const scv = asTri(get(single, "skip-cert-verify"));
1940
+ const node = createProxy();
1941
+ let group2 = "";
1942
+ switch (proxyType) {
1943
+ case "vmess": {
1944
+ group2 = DEFAULT_GROUPS.v2ray;
1945
+ const id = asString(get(single, "uuid"));
1946
+ const aid = asString(get(single, "alterId"));
1947
+ const cipher = asString(get(single, "cipher"));
1948
+ const net = get(single, "network") !== void 0 ? asString(get(single, "network")) : "tcp";
1949
+ const sni = asString(get(single, "servername"));
1950
+ let path = "";
1951
+ let host = "";
1952
+ let edge = "";
1953
+ switch (net) {
1954
+ case "http":
1955
+ path = asString(get(get(get(single, "http-opts"), "path"), 0));
1956
+ host = asString(get(get(get(get(single, "http-opts"), "headers"), "Host"), 0));
1957
+ edge = "";
1958
+ break;
1959
+ case "ws":
1960
+ if (get(single, "ws-opts") !== void 0) {
1961
+ const wsOpts = get(single, "ws-opts");
1962
+ path = get(wsOpts, "path") !== void 0 ? asString(get(wsOpts, "path")) : "/";
1963
+ host = asString(get(get(wsOpts, "headers"), "Host"));
1964
+ edge = asString(get(get(wsOpts, "headers"), "Edge"));
1965
+ } else {
1966
+ path = get(single, "ws-path") !== void 0 ? asString(get(single, "ws-path")) : "/";
1967
+ host = asString(get(get(single, "ws-headers"), "Host"));
1968
+ edge = asString(get(get(single, "ws-headers"), "Edge"));
2002
1969
  }
2003
- }
2004
- if (cipher === "AEAD_CHACHA20_POLY1305") {
2005
- cipher = "chacha20-ietf-poly1305";
2006
- } else if (cipher.includes("AEAD")) {
2007
- cipher = cipher.replace(/AEAD_/g, "").replace(/_/g, "-").toLowerCase();
2008
- }
2009
- ssConstruct(node, {
2010
- group: group2,
2011
- method: cipher,
2012
- password,
2013
- plugin,
2014
- pluginOption,
2015
- port,
2016
- remark: ps,
2017
- scv,
2018
- server,
2019
- tfo,
2020
- udp,
2021
- underlyingProxy
2022
- });
2023
- break;
2024
- }
2025
- case "socks5": {
2026
- group2 = DEFAULT_GROUPS.socks;
2027
- const user = asString(get(single, "username"));
2028
- const password = asString(get(single, "password"));
2029
- socksConstruct(node, {
2030
- group: group2,
2031
- password,
2032
- port,
2033
- remark: ps,
2034
- server,
2035
- underlyingProxy,
2036
- username: user
2037
- });
2038
- break;
2039
- }
2040
- case "ssr": {
2041
- group2 = DEFAULT_GROUPS.ssr;
2042
- let cipher = asString(get(single, "cipher"));
2043
- if (cipher === "dummy") {
2044
- cipher = "none";
2045
- }
2046
- const password = asString(get(single, "password"));
2047
- const protocol = asString(get(single, "protocol"));
2048
- const obfs = asString(get(single, "obfs"));
2049
- const protocolParam = get(single, "protocol-param") !== void 0 ? asString(get(single, "protocol-param")) : asString(get(single, "protocolparam"));
2050
- const obfsParam = get(single, "obfs-param") !== void 0 ? asString(get(single, "obfs-param")) : asString(get(single, "obfsparam"));
2051
- ssrConstruct(node, {
2052
- group: group2,
2053
- method: cipher,
2054
- obfs,
2055
- obfsParam,
2056
- password,
2057
- port,
2058
- protocol,
2059
- protocolParam,
2060
- remark: ps,
2061
- scv,
2062
- server,
2063
- tfo,
2064
- udp,
2065
- underlyingProxy
2066
- });
2067
- break;
2068
- }
2069
- case "http": {
2070
- group2 = DEFAULT_GROUPS.http;
2071
- const user = asString(get(single, "username"));
2072
- const password = asString(get(single, "password"));
2073
- const tls = asString(get(single, "tls"));
2074
- httpConstruct(node, {
2075
- group: group2,
2076
- password,
2077
- port,
2078
- remark: ps,
2079
- scv,
2080
- server,
2081
- tfo,
2082
- tls: tls === "true",
2083
- underlyingProxy,
2084
- username: user
2085
- });
2086
- break;
1970
+ break;
1971
+ case "h2":
1972
+ path = asString(get(get(single, "h2-opts"), "path"));
1973
+ host = asString(get(get(get(single, "h2-opts"), "host"), 0));
1974
+ edge = "";
1975
+ break;
1976
+ case "grpc":
1977
+ host = asString(get(single, "servername"));
1978
+ path = asString(get(get(single, "grpc-opts"), "grpc-service-name"));
1979
+ edge = "";
1980
+ break;
1981
+ default:
1982
+ break;
2087
1983
  }
2088
- case "trojan": {
2089
- group2 = DEFAULT_GROUPS.trojan;
2090
- const password = asString(get(single, "password"));
2091
- const host = asString(get(single, "sni"));
2092
- let net = asString(get(single, "network"));
2093
- let path = "";
2094
- switch (net) {
2095
- case "grpc":
2096
- path = asString(get(get(single, "grpc-opts"), "grpc-service-name"));
2097
- break;
2098
- case "ws":
2099
- path = asString(get(get(single, "ws-opts"), "path"));
2100
- break;
2101
- default:
2102
- net = "tcp";
2103
- path = "";
2104
- break;
1984
+ const tls = asBool(get(single, "tls")) ? "tls" : "";
1985
+ vmessConstruct(node, {
1986
+ add: server,
1987
+ aid,
1988
+ cipher,
1989
+ edge,
1990
+ group: group2,
1991
+ host,
1992
+ id,
1993
+ net,
1994
+ path,
1995
+ port,
1996
+ remark: ps,
1997
+ scv,
1998
+ sni,
1999
+ tfo,
2000
+ tls,
2001
+ type: "",
2002
+ udp,
2003
+ underlyingProxy
2004
+ });
2005
+ break;
2006
+ }
2007
+ case "ss": {
2008
+ group2 = DEFAULT_GROUPS.ss;
2009
+ let cipher = asString(get(single, "cipher"));
2010
+ const password = asString(get(single, "password"));
2011
+ let plugin = "";
2012
+ let pluginOption = "";
2013
+ let pluginMode = "";
2014
+ let pluginHost = "";
2015
+ let pluginMux = "";
2016
+ let pluginTls = "";
2017
+ let path = "";
2018
+ if (get(single, "plugin") !== void 0) {
2019
+ const pluginName = asString(get(single, "plugin")).toLowerCase();
2020
+ const pluginOpts = get(single, "plugin-opts");
2021
+ if (pluginName === "obfs") {
2022
+ plugin = "obfs-local";
2023
+ pluginMode = asString(get(pluginOpts, "mode"));
2024
+ pluginHost = asString(get(pluginOpts, "host"));
2025
+ } else if (pluginName === "v2ray-plugin") {
2026
+ plugin = "v2ray-plugin";
2027
+ pluginMode = asString(get(pluginOpts, "mode"));
2028
+ pluginHost = asString(get(pluginOpts, "host"));
2029
+ pluginTls = asBool(get(pluginOpts, "tls")) ? "tls;" : "";
2030
+ path = asString(get(pluginOpts, "path"));
2031
+ pluginMux = asBool(get(pluginOpts, "mux")) ? "mux=4;" : "";
2105
2032
  }
2106
- trojanConstruct(node, {
2107
- group: group2,
2108
- host,
2109
- network: net,
2110
- password,
2111
- path,
2112
- port,
2113
- remark: ps,
2114
- scv,
2115
- server,
2116
- tfo,
2117
- tlsSecure: true,
2118
- udp,
2119
- underlyingProxy
2120
- });
2121
- break;
2122
- }
2123
- case "snell": {
2124
- group2 = DEFAULT_GROUPS.snell;
2125
- const password = asString(get(single, "psk"));
2126
- const obfs = asString(get(get(single, "obfs-opts"), "mode"));
2127
- const host = asString(get(get(single, "obfs-opts"), "host"));
2128
- const version = asString(get(single, "version"));
2129
- snellConstruct(node, {
2130
- group: group2,
2131
- host,
2132
- obfs,
2133
- password,
2134
- port,
2135
- remark: ps,
2136
- scv,
2137
- server,
2138
- tfo,
2139
- udp,
2140
- underlyingProxy,
2141
- version: toInt(version)
2142
- });
2143
- break;
2144
- }
2145
- case "wireguard": {
2146
- group2 = DEFAULT_GROUPS.wireguard;
2147
- const publicKey = asString(get(single, "public-key"));
2148
- const privateKey = asString(get(single, "private-key"));
2149
- const dns = get(single, "dns");
2150
- const dnsServers = Array.isArray(dns) ? dns.map((d) => String(d)) : dns ? [String(dns)] : [];
2151
- const mtu = asString(get(single, "mtu"));
2152
- const psk = asString(get(single, "preshared-key"));
2153
- const ip = asString(get(single, "ip"));
2154
- const ipv6 = asString(get(single, "ipv6"));
2155
- wireGuardConstruct(node, {
2156
- dnsServers,
2157
- group: group2,
2158
- keepAlive: "0",
2159
- mtu,
2160
- port,
2161
- preSharedKey: psk,
2162
- privateKey,
2163
- publicKey,
2164
- remark: ps,
2165
- selfIp: ip,
2166
- selfIpv6: ipv6,
2167
- server,
2168
- testUrl: "",
2169
- udp,
2170
- underlyingProxy
2171
- });
2172
- break;
2173
- }
2174
- case "hysteria": {
2175
- group2 = DEFAULT_GROUPS.hysteria;
2176
- const ports = asString(get(single, "ports"));
2177
- const protocol = asString(get(single, "protocol"));
2178
- const obfsProtocol = asString(get(single, "obfs-protocol"));
2179
- const up = asString(get(single, "up"));
2180
- const upSpeed = asString(get(single, "up-speed"));
2181
- const down = asString(get(single, "down"));
2182
- const downSpeed = asString(get(single, "down-speed"));
2183
- const auth = asString(get(single, "auth"));
2184
- let authStr = asString(get(single, "auth-str"));
2185
- if (authStr === "") {
2186
- authStr = asString(get(single, "auth_str"));
2033
+ } else if (get(single, "obfs") !== void 0) {
2034
+ plugin = "obfs-local";
2035
+ pluginMode = asString(get(single, "obfs"));
2036
+ pluginHost = asString(get(single, "obfs-host"));
2037
+ }
2038
+ if (plugin === "simple-obfs" || plugin === "obfs-local") {
2039
+ pluginOption = `obfs=${pluginMode}`;
2040
+ pluginOption += pluginHost === "" ? "" : `;obfs-host=${pluginHost}`;
2041
+ } else if (plugin === "v2ray-plugin") {
2042
+ pluginOption = `mode=${pluginMode};${pluginTls}${pluginMux}`;
2043
+ if (pluginHost !== "") {
2044
+ pluginOption += `host=${pluginHost};`;
2187
2045
  }
2188
- const obfs = asString(get(single, "obfs"));
2189
- const sni = asString(get(single, "sni"));
2190
- const fingerprint = asString(get(single, "fingerprint"));
2191
- const alpnValue = get(single, "alpn");
2192
- const alpn = Array.isArray(alpnValue) ? asString(alpnValue[0]) : asString(alpnValue);
2193
- const ca = asString(get(single, "ca"));
2194
- const caStr = asString(get(single, "ca-str"));
2195
- const recvWindowConn = asString(get(single, "recv-window-conn"));
2196
- const recvWindow = asString(get(single, "recv-window"));
2197
- let disableMtuDiscovery = asString(get(single, "disable-mtu-discovery"));
2198
- if (disableMtuDiscovery === "") {
2199
- disableMtuDiscovery = asString(get(single, "disable_mtu_discovery"));
2046
+ if (path !== "") {
2047
+ pluginOption += `path=${path};`;
2200
2048
  }
2201
- const hopInterval = asString(get(single, "hop-interval"));
2202
- hysteriaConstruct(node, {
2203
- alpn,
2204
- auth,
2205
- authStr,
2206
- ca,
2207
- caStr,
2208
- disableMtuDiscovery,
2209
- down,
2210
- downSpeed,
2211
- fingerprint,
2212
- group: group2,
2213
- hopInterval,
2214
- obfs,
2215
- obfsProtocol,
2216
- port,
2217
- ports,
2218
- protocol,
2219
- recvWindow,
2220
- recvWindowConn,
2221
- remark: ps,
2222
- scv,
2223
- server,
2224
- sni,
2225
- tfo,
2226
- underlyingProxy,
2227
- up,
2228
- upSpeed
2229
- });
2230
- break;
2231
- }
2232
- case "hysteria2": {
2233
- group2 = DEFAULT_GROUPS.hysteria2;
2234
- const ports = asString(get(single, "ports"));
2235
- const up = asString(get(single, "up"));
2236
- const down = asString(get(single, "down"));
2237
- let password = asString(get(single, "password"));
2238
- if (password === "") {
2239
- password = asString(get(single, "auth"));
2049
+ if (pluginMux !== "") {
2050
+ pluginOption += `mux=${pluginMux};`;
2240
2051
  }
2241
- const obfs = asString(get(single, "obfs"));
2242
- const obfsPassword = asString(get(single, "obfs-password"));
2243
- const sni = asString(get(single, "sni"));
2244
- const fingerprint = asString(get(single, "fingerprint"));
2245
- const alpnValue = get(single, "alpn");
2246
- const alpn = Array.isArray(alpnValue) ? asString(alpnValue[0]) : asString(alpnValue);
2247
- const ca = asString(get(single, "ca"));
2248
- const caStr = asString(get(single, "ca-str"));
2249
- const cwnd = asString(get(single, "cwnd"));
2250
- const hopInterval = asString(get(single, "hop-interval"));
2251
- hysteria2Construct(node, {
2252
- alpn,
2253
- ca,
2254
- caStr,
2255
- cwnd,
2256
- down,
2257
- fingerprint,
2258
- group: group2,
2259
- hopInterval,
2260
- obfs,
2261
- obfsPassword,
2262
- password,
2263
- port,
2264
- ports,
2265
- remark: ps,
2266
- scv,
2267
- server,
2268
- sni,
2269
- tfo,
2270
- underlyingProxy,
2271
- up
2272
- });
2273
- break;
2274
2052
  }
2275
- case "anytls": {
2276
- group2 = DEFAULT_GROUPS.anytls;
2277
- const password = asString(get(single, "password"));
2278
- const sni = asString(get(single, "sni"));
2279
- anyTlsConstruct(node, {
2280
- group: group2,
2281
- password,
2282
- port,
2283
- remark: ps,
2284
- scv,
2285
- server,
2286
- sni,
2287
- tfo,
2288
- udp,
2289
- underlyingProxy
2290
- });
2291
- break;
2053
+ if (cipher === "AEAD_CHACHA20_POLY1305") {
2054
+ cipher = "chacha20-ietf-poly1305";
2055
+ } else if (cipher.includes("AEAD")) {
2056
+ cipher = cipher.replace(/AEAD_/g, "").replace(/_/g, "-").toLowerCase();
2292
2057
  }
2293
- case "vless": {
2294
- group2 = DEFAULT_GROUPS.v2ray;
2295
- const userId = asString(get(single, "uuid"));
2296
- const net = asString(get(single, "network"));
2297
- const tls = asString(get(single, "tls"));
2298
- let path = "";
2299
- let host = "";
2300
- if (net === "ws") {
2301
- path = asString(get(get(single, "ws-opts"), "path"));
2302
- host = asString(get(get(get(single, "ws-opts"), "headers"), "Host"));
2303
- } else if (net === "grpc") {
2058
+ ssConstruct(node, {
2059
+ group: group2,
2060
+ method: cipher,
2061
+ password,
2062
+ plugin,
2063
+ pluginOption,
2064
+ port,
2065
+ remark: ps,
2066
+ scv,
2067
+ server,
2068
+ tfo,
2069
+ udp,
2070
+ underlyingProxy
2071
+ });
2072
+ break;
2073
+ }
2074
+ case "socks5": {
2075
+ group2 = DEFAULT_GROUPS.socks;
2076
+ const user = asString(get(single, "username"));
2077
+ const password = asString(get(single, "password"));
2078
+ socksConstruct(node, {
2079
+ group: group2,
2080
+ password,
2081
+ port,
2082
+ remark: ps,
2083
+ server,
2084
+ underlyingProxy,
2085
+ username: user
2086
+ });
2087
+ break;
2088
+ }
2089
+ case "ssr": {
2090
+ group2 = DEFAULT_GROUPS.ssr;
2091
+ let cipher = asString(get(single, "cipher"));
2092
+ if (cipher === "dummy") {
2093
+ cipher = "none";
2094
+ }
2095
+ const password = asString(get(single, "password"));
2096
+ const protocol = asString(get(single, "protocol"));
2097
+ const obfs = asString(get(single, "obfs"));
2098
+ const protocolParam = get(single, "protocol-param") !== void 0 ? asString(get(single, "protocol-param")) : asString(get(single, "protocolparam"));
2099
+ const obfsParam = get(single, "obfs-param") !== void 0 ? asString(get(single, "obfs-param")) : asString(get(single, "obfsparam"));
2100
+ ssrConstruct(node, {
2101
+ group: group2,
2102
+ method: cipher,
2103
+ obfs,
2104
+ obfsParam,
2105
+ password,
2106
+ port,
2107
+ protocol,
2108
+ protocolParam,
2109
+ remark: ps,
2110
+ scv,
2111
+ server,
2112
+ tfo,
2113
+ udp,
2114
+ underlyingProxy
2115
+ });
2116
+ break;
2117
+ }
2118
+ case "http": {
2119
+ group2 = DEFAULT_GROUPS.http;
2120
+ const user = asString(get(single, "username"));
2121
+ const password = asString(get(single, "password"));
2122
+ const tls = asString(get(single, "tls"));
2123
+ httpConstruct(node, {
2124
+ group: group2,
2125
+ password,
2126
+ port,
2127
+ remark: ps,
2128
+ scv,
2129
+ server,
2130
+ tfo,
2131
+ tls: tls === "true",
2132
+ underlyingProxy,
2133
+ username: user
2134
+ });
2135
+ break;
2136
+ }
2137
+ case "trojan": {
2138
+ group2 = DEFAULT_GROUPS.trojan;
2139
+ const password = asString(get(single, "password"));
2140
+ const host = asString(get(single, "sni"));
2141
+ let net = asString(get(single, "network"));
2142
+ let path = "";
2143
+ switch (net) {
2144
+ case "grpc":
2304
2145
  path = asString(get(get(single, "grpc-opts"), "grpc-service-name"));
2305
- }
2306
- const alpnValue = get(single, "alpn");
2307
- vlessConstruct(node, {
2308
- alpn: Array.isArray(alpnValue) ? alpnValue.map((a) => String(a)) : void 0,
2309
- encryption: asString(get(single, "encryption")),
2310
- fingerprint: asString(get(single, "client-fingerprint")),
2311
- flow: asString(get(single, "flow")),
2312
- group: group2,
2313
- host,
2314
- network: net,
2315
- path,
2316
- port,
2317
- remark: ps,
2318
- scv,
2319
- server,
2320
- sni: asString(get(single, "servername")),
2321
- tfo,
2322
- tls: tls === "true" ? "tls" : "",
2323
- udp,
2324
- underlyingProxy,
2325
- userId
2326
- });
2327
- break;
2328
- }
2329
- case "tuic": {
2330
- group2 = DEFAULT_GROUPS.v2ray;
2331
- const alpnValue = get(single, "alpn");
2332
- tuicConstruct(node, {
2333
- alpn: Array.isArray(alpnValue) ? alpnValue.map((a) => String(a)) : void 0,
2334
- congestionControl: asString(get(single, "congestion-controller")),
2335
- group: group2,
2336
- password: asString(get(single, "password")),
2337
- port,
2338
- remark: ps,
2339
- scv,
2340
- server,
2341
- sni: asString(get(single, "sni")),
2342
- tfo,
2343
- udp,
2344
- underlyingProxy,
2345
- userId: asString(get(single, "uuid"))
2346
- });
2347
- break;
2146
+ break;
2147
+ case "ws":
2148
+ path = asString(get(get(single, "ws-opts"), "path"));
2149
+ break;
2150
+ default:
2151
+ net = "tcp";
2152
+ path = "";
2153
+ break;
2348
2154
  }
2349
- default:
2350
- continue;
2155
+ trojanConstruct(node, {
2156
+ group: group2,
2157
+ host,
2158
+ network: net,
2159
+ password,
2160
+ path,
2161
+ port,
2162
+ remark: ps,
2163
+ scv,
2164
+ server,
2165
+ tfo,
2166
+ tlsSecure: true,
2167
+ udp,
2168
+ underlyingProxy
2169
+ });
2170
+ break;
2351
2171
  }
2352
- node.id = index;
2353
- nodes.push(node);
2354
- index += 1;
2172
+ case "snell": {
2173
+ group2 = DEFAULT_GROUPS.snell;
2174
+ const password = asString(get(single, "psk"));
2175
+ const obfs = asString(get(get(single, "obfs-opts"), "mode"));
2176
+ const host = asString(get(get(single, "obfs-opts"), "host"));
2177
+ const version = asString(get(single, "version"));
2178
+ snellConstruct(node, {
2179
+ group: group2,
2180
+ host,
2181
+ obfs,
2182
+ password,
2183
+ port,
2184
+ remark: ps,
2185
+ scv,
2186
+ server,
2187
+ tfo,
2188
+ udp,
2189
+ underlyingProxy,
2190
+ version: toInt(version)
2191
+ });
2192
+ break;
2193
+ }
2194
+ case "wireguard": {
2195
+ group2 = DEFAULT_GROUPS.wireguard;
2196
+ const publicKey = asString(get(single, "public-key"));
2197
+ const privateKey = asString(get(single, "private-key"));
2198
+ const dns = get(single, "dns");
2199
+ const dnsServers = Array.isArray(dns) ? dns.map((d) => String(d)) : dns ? [String(dns)] : [];
2200
+ const mtu = asString(get(single, "mtu"));
2201
+ const psk = asString(get(single, "preshared-key"));
2202
+ const ip = asString(get(single, "ip"));
2203
+ const ipv6 = asString(get(single, "ipv6"));
2204
+ wireGuardConstruct(node, {
2205
+ dnsServers,
2206
+ group: group2,
2207
+ keepAlive: "0",
2208
+ mtu,
2209
+ port,
2210
+ preSharedKey: psk,
2211
+ privateKey,
2212
+ publicKey,
2213
+ remark: ps,
2214
+ selfIp: ip,
2215
+ selfIpv6: ipv6,
2216
+ server,
2217
+ testUrl: "",
2218
+ udp,
2219
+ underlyingProxy
2220
+ });
2221
+ break;
2222
+ }
2223
+ case "hysteria": {
2224
+ group2 = DEFAULT_GROUPS.hysteria;
2225
+ const ports = asString(get(single, "ports"));
2226
+ const protocol = asString(get(single, "protocol"));
2227
+ const obfsProtocol = asString(get(single, "obfs-protocol"));
2228
+ const up = asString(get(single, "up"));
2229
+ const upSpeed = asString(get(single, "up-speed"));
2230
+ const down = asString(get(single, "down"));
2231
+ const downSpeed = asString(get(single, "down-speed"));
2232
+ const auth = asString(get(single, "auth"));
2233
+ let authStr = asString(get(single, "auth-str"));
2234
+ if (authStr === "") {
2235
+ authStr = asString(get(single, "auth_str"));
2236
+ }
2237
+ const obfs = asString(get(single, "obfs"));
2238
+ const sni = asString(get(single, "sni"));
2239
+ const fingerprint = asString(get(single, "fingerprint"));
2240
+ const alpnValue = get(single, "alpn");
2241
+ const alpn = Array.isArray(alpnValue) ? asString(alpnValue[0]) : asString(alpnValue);
2242
+ const ca = asString(get(single, "ca"));
2243
+ const caStr = asString(get(single, "ca-str"));
2244
+ const recvWindowConn = asString(get(single, "recv-window-conn"));
2245
+ const recvWindow = asString(get(single, "recv-window"));
2246
+ let disableMtuDiscovery = asString(get(single, "disable-mtu-discovery"));
2247
+ if (disableMtuDiscovery === "") {
2248
+ disableMtuDiscovery = asString(get(single, "disable_mtu_discovery"));
2249
+ }
2250
+ const hopInterval = asString(get(single, "hop-interval"));
2251
+ hysteriaConstruct(node, {
2252
+ alpn,
2253
+ auth,
2254
+ authStr,
2255
+ ca,
2256
+ caStr,
2257
+ disableMtuDiscovery,
2258
+ down,
2259
+ downSpeed,
2260
+ fingerprint,
2261
+ group: group2,
2262
+ hopInterval,
2263
+ obfs,
2264
+ obfsProtocol,
2265
+ port,
2266
+ ports,
2267
+ protocol,
2268
+ recvWindow,
2269
+ recvWindowConn,
2270
+ remark: ps,
2271
+ scv,
2272
+ server,
2273
+ sni,
2274
+ tfo,
2275
+ underlyingProxy,
2276
+ up,
2277
+ upSpeed
2278
+ });
2279
+ break;
2280
+ }
2281
+ case "hysteria2": {
2282
+ group2 = DEFAULT_GROUPS.hysteria2;
2283
+ const ports = asString(get(single, "ports"));
2284
+ const up = asString(get(single, "up"));
2285
+ const down = asString(get(single, "down"));
2286
+ let password = asString(get(single, "password"));
2287
+ if (password === "") {
2288
+ password = asString(get(single, "auth"));
2289
+ }
2290
+ const obfs = asString(get(single, "obfs"));
2291
+ const obfsPassword = asString(get(single, "obfs-password"));
2292
+ const sni = asString(get(single, "sni"));
2293
+ const fingerprint = asString(get(single, "fingerprint"));
2294
+ const alpnValue = get(single, "alpn");
2295
+ const alpn = Array.isArray(alpnValue) ? asString(alpnValue[0]) : asString(alpnValue);
2296
+ const ca = asString(get(single, "ca"));
2297
+ const caStr = asString(get(single, "ca-str"));
2298
+ const cwnd = asString(get(single, "cwnd"));
2299
+ const hopInterval = asString(get(single, "hop-interval"));
2300
+ hysteria2Construct(node, {
2301
+ alpn,
2302
+ ca,
2303
+ caStr,
2304
+ cwnd,
2305
+ down,
2306
+ fingerprint,
2307
+ group: group2,
2308
+ hopInterval,
2309
+ obfs,
2310
+ obfsPassword,
2311
+ password,
2312
+ port,
2313
+ ports,
2314
+ remark: ps,
2315
+ scv,
2316
+ server,
2317
+ sni,
2318
+ tfo,
2319
+ underlyingProxy,
2320
+ up
2321
+ });
2322
+ break;
2323
+ }
2324
+ case "anytls": {
2325
+ group2 = DEFAULT_GROUPS.anytls;
2326
+ const password = asString(get(single, "password"));
2327
+ const sni = asString(get(single, "sni"));
2328
+ anyTlsConstruct(node, {
2329
+ group: group2,
2330
+ password,
2331
+ port,
2332
+ remark: ps,
2333
+ scv,
2334
+ server,
2335
+ sni,
2336
+ tfo,
2337
+ udp,
2338
+ underlyingProxy
2339
+ });
2340
+ break;
2341
+ }
2342
+ case "vless": {
2343
+ group2 = DEFAULT_GROUPS.v2ray;
2344
+ const userId = asString(get(single, "uuid"));
2345
+ const net = asString(get(single, "network"));
2346
+ const tls = asString(get(single, "tls"));
2347
+ let path = "";
2348
+ let host = "";
2349
+ if (net === "ws") {
2350
+ path = asString(get(get(single, "ws-opts"), "path"));
2351
+ host = asString(get(get(get(single, "ws-opts"), "headers"), "Host"));
2352
+ } else if (net === "grpc") {
2353
+ path = asString(get(get(single, "grpc-opts"), "grpc-service-name"));
2354
+ }
2355
+ const alpnValue = get(single, "alpn");
2356
+ vlessConstruct(node, {
2357
+ alpn: Array.isArray(alpnValue) ? alpnValue.map((a) => String(a)) : void 0,
2358
+ encryption: asString(get(single, "encryption")),
2359
+ fingerprint: asString(get(single, "client-fingerprint")),
2360
+ flow: asString(get(single, "flow")),
2361
+ group: group2,
2362
+ host,
2363
+ network: net,
2364
+ path,
2365
+ port,
2366
+ remark: ps,
2367
+ scv,
2368
+ server,
2369
+ sni: asString(get(single, "servername")),
2370
+ tfo,
2371
+ tls: tls === "true" ? "tls" : "",
2372
+ udp,
2373
+ underlyingProxy,
2374
+ userId
2375
+ });
2376
+ break;
2377
+ }
2378
+ case "tuic": {
2379
+ group2 = DEFAULT_GROUPS.v2ray;
2380
+ const alpnValue = get(single, "alpn");
2381
+ tuicConstruct(node, {
2382
+ alpn: Array.isArray(alpnValue) ? alpnValue.map((a) => String(a)) : void 0,
2383
+ congestionControl: asString(get(single, "congestion-controller")),
2384
+ group: group2,
2385
+ password: asString(get(single, "password")),
2386
+ port,
2387
+ remark: ps,
2388
+ scv,
2389
+ server,
2390
+ sni: asString(get(single, "sni")),
2391
+ tfo,
2392
+ udp,
2393
+ underlyingProxy,
2394
+ userId: asString(get(single, "uuid"))
2395
+ });
2396
+ break;
2397
+ }
2398
+ default:
2399
+ return false;
2355
2400
  }
2401
+ node.id = index;
2402
+ nodes.push(node);
2403
+ return true;
2356
2404
  }
2357
2405
  function parseRawSections(text) {
2358
2406
  const sections = [];
@@ -3960,7 +4008,10 @@ function explodeSs(ss, node) {
3960
4008
  const secret = match[1];
3961
4009
  server = match[2];
3962
4010
  port = match[3];
3963
- const secretMatch = firstMatch(urlSafeBase64Decode(secret), "(\\S+?):(\\S+)");
4011
+ const raw = urlDecode(secret);
4012
+ const decoded = firstMatch(urlSafeBase64Decode(raw), "(\\S+?):(\\S+)");
4013
+ const plaintext = firstMatch(raw, "(\\S+?):(\\S+)");
4014
+ const secretMatch = decoded && isSsCipher(decoded[1]) ? decoded : plaintext ?? decoded;
3964
4015
  if (!secretMatch) {
3965
4016
  return;
3966
4017
  }
@@ -4425,6 +4476,157 @@ function explodeAnyTls(link, node) {
4425
4476
  udp: udp === "" ? void 0 : parseTri(udp)
4426
4477
  });
4427
4478
  }
4479
+ function explodeSnell(link, node) {
4480
+ let body = link.slice(8);
4481
+ let remark = "";
4482
+ let addition = "";
4483
+ const hashPos = body.lastIndexOf("#");
4484
+ if (hashPos !== -1) {
4485
+ remark = urlDecode(body.slice(hashPos + 1));
4486
+ body = body.slice(0, hashPos);
4487
+ }
4488
+ const qpos = body.lastIndexOf("?");
4489
+ if (qpos !== -1) {
4490
+ addition = body.slice(qpos + 1);
4491
+ body = body.slice(0, qpos);
4492
+ }
4493
+ const match = /^(.*?)@(.*)[:](\d+)$/.exec(body);
4494
+ if (!match) {
4495
+ return;
4496
+ }
4497
+ const password = match[1];
4498
+ const server = match[2];
4499
+ const port = match[3];
4500
+ if (password === "" || port === "" || port === "0") {
4501
+ return;
4502
+ }
4503
+ const obfs = getUrlArg(addition, "obfs");
4504
+ const host = getUrlArg(addition, "host");
4505
+ const version = getUrlArg(addition, "version");
4506
+ const udp = getUrlArg(addition, "udp");
4507
+ const tfo = getUrlArg(addition, "tfo");
4508
+ const scv = getUrlArg(addition, "skip-cert-verify");
4509
+ if (remark === "") {
4510
+ remark = `${server}:${port}`;
4511
+ }
4512
+ snellConstruct(node, {
4513
+ group: DEFAULT_GROUPS.snell,
4514
+ host,
4515
+ obfs: obfs === "" ? "none" : obfs,
4516
+ password,
4517
+ port,
4518
+ remark,
4519
+ scv: scv === "" ? void 0 : parseTri(scv),
4520
+ server,
4521
+ tfo: tfo === "" ? void 0 : parseTri(tfo),
4522
+ udp: udp === "" ? void 0 : parseTri(udp),
4523
+ version: version === "" ? 1 : toInt(version)
4524
+ });
4525
+ }
4526
+ function explodeHysteria(link, node) {
4527
+ let body = link.slice(11);
4528
+ let remark = "";
4529
+ let addition = "";
4530
+ const hashPos = body.lastIndexOf("#");
4531
+ if (hashPos !== -1) {
4532
+ remark = urlDecode(body.slice(hashPos + 1));
4533
+ body = body.slice(0, hashPos);
4534
+ }
4535
+ const qpos = body.lastIndexOf("?");
4536
+ if (qpos !== -1) {
4537
+ addition = body.slice(qpos + 1);
4538
+ body = body.slice(0, qpos);
4539
+ }
4540
+ const match = /^(.*)[:](\d+)$/.exec(body);
4541
+ if (!match) {
4542
+ return;
4543
+ }
4544
+ const server = match[1];
4545
+ const port = match[2];
4546
+ if (server === "" || port === "0") {
4547
+ return;
4548
+ }
4549
+ const auth = getUrlArg(addition, "auth");
4550
+ const protocol = getUrlArg(addition, "protocol");
4551
+ const upSpeed = getUrlArg(addition, "upmbps");
4552
+ const downSpeed = getUrlArg(addition, "downmbps");
4553
+ const alpn = getUrlArg(addition, "alpn");
4554
+ const obfs = getUrlArg(addition, "obfs");
4555
+ const obfsProtocol = getUrlArg(addition, "obfsParam");
4556
+ const sni = getUrlArg(addition, "peer");
4557
+ const insecure = getUrlArg(addition, "insecure");
4558
+ if (remark === "") {
4559
+ remark = `${server}:${port}`;
4560
+ }
4561
+ hysteriaConstruct(node, {
4562
+ alpn,
4563
+ authStr: auth,
4564
+ downSpeed,
4565
+ group: DEFAULT_GROUPS.hysteria,
4566
+ obfs,
4567
+ obfsProtocol,
4568
+ port,
4569
+ protocol: protocol === "" ? "udp" : protocol,
4570
+ remark,
4571
+ scv: insecure === "" ? void 0 : parseTri(insecure),
4572
+ server,
4573
+ sni: sni === "" ? server : sni,
4574
+ upSpeed
4575
+ });
4576
+ }
4577
+ function explodeWireguard(link, node) {
4578
+ const normalized = link.replace(/^(wg|wireguard):\/\//, "wireguard://");
4579
+ let body = normalized.slice(13);
4580
+ let remark = "";
4581
+ let addition = "";
4582
+ const hashPos = body.lastIndexOf("#");
4583
+ if (hashPos !== -1) {
4584
+ remark = urlDecode(body.slice(hashPos + 1));
4585
+ body = body.slice(0, hashPos);
4586
+ }
4587
+ const qpos = body.lastIndexOf("?");
4588
+ if (qpos !== -1) {
4589
+ addition = body.slice(qpos + 1);
4590
+ body = body.slice(0, qpos);
4591
+ }
4592
+ const match = /^(?:(.*)@)?\[?(.*?)]?:(\d+)$/.exec(body);
4593
+ if (!match) {
4594
+ return;
4595
+ }
4596
+ const server = match[2];
4597
+ const port = match[3];
4598
+ if (server === "" || port === "0") {
4599
+ return;
4600
+ }
4601
+ const privateKey = getUrlArg(addition, "privateKey") || getUrlArg(addition, "privatekey");
4602
+ const publicKey = getUrlArg(addition, "publicKey") || getUrlArg(addition, "publickey");
4603
+ if (privateKey === "" || publicKey === "") {
4604
+ return;
4605
+ }
4606
+ const presharedKey = getUrlArg(addition, "presharedKey");
4607
+ const selfIp = getUrlArg(addition, "selfIP");
4608
+ const selfIpv6 = getUrlArg(addition, "selfIPv6");
4609
+ const mtu = getUrlArg(addition, "mtu");
4610
+ const keepAlive = getUrlArg(addition, "keepAlive");
4611
+ const dns = getUrlArg(addition, "dns");
4612
+ if (remark === "") {
4613
+ remark = `${server}:${port}`;
4614
+ }
4615
+ wireGuardConstruct(node, {
4616
+ dnsServers: dns === "" ? ["1.1.1.1"] : dns.split(",").map((s) => s.trim()),
4617
+ group: DEFAULT_GROUPS.wireguard,
4618
+ keepAlive: keepAlive === "" ? 25 : toInt(keepAlive),
4619
+ mtu: mtu === "" ? 1420 : toInt(mtu),
4620
+ port,
4621
+ preSharedKey: presharedKey,
4622
+ privateKey,
4623
+ publicKey,
4624
+ remark,
4625
+ selfIp: selfIp === "" ? "10.0.0.2" : selfIp,
4626
+ selfIpv6,
4627
+ server
4628
+ });
4629
+ }
4428
4630
  function explodeVless(link, node) {
4429
4631
  let body = link.slice(8);
4430
4632
  let remark = "";
@@ -4548,6 +4750,12 @@ function explode(link, node) {
4548
4750
  explodeVless(link, node);
4549
4751
  } else if (startsWith(link, "tuic://")) {
4550
4752
  explodeTuic(link, node);
4753
+ } else if (startsWith(link, "snell://")) {
4754
+ explodeSnell(link, node);
4755
+ } else if (startsWith(link, "hysteria://")) {
4756
+ explodeHysteria(link, node);
4757
+ } else if (startsWith(link, "wg://") || startsWith(link, "wireguard://")) {
4758
+ explodeWireguard(link, node);
4551
4759
  } else if (link.includes("hysteria2://") || link.includes("hy2://")) {
4552
4760
  explodeHysteria2(link, node);
4553
4761
  } else if (startsWith(link, "anytls://")) {
@@ -5052,6 +5260,10 @@ function toRegex(pattern) {
5052
5260
  function regFind(value, pattern) {
5053
5261
  return toRegex(pattern).test(value);
5054
5262
  }
5263
+ var REGEX_BLACKLIST = ["(.*)*"];
5264
+ function isBlacklistedPattern(pattern) {
5265
+ return REGEX_BLACKLIST.includes(pattern);
5266
+ }
5055
5267
  function regMatch2(value, pattern) {
5056
5268
  const match = toRegex(pattern).exec(value);
5057
5269
  return match !== null && match[0] === value;
@@ -5423,12 +5635,59 @@ function stripBrackets(value) {
5423
5635
  function toTri(value) {
5424
5636
  return value;
5425
5637
  }
5638
+ var MIHOMO_PROTOCOLS = /* @__PURE__ */ new Set([
5639
+ "ss" /* Shadowsocks */,
5640
+ "ssr" /* ShadowsocksR */,
5641
+ "vmess" /* VMess */,
5642
+ "trojan" /* Trojan */,
5643
+ "snell" /* Snell */,
5644
+ "http" /* HTTP */,
5645
+ "https" /* HTTPS */,
5646
+ "socks5" /* SOCKS5 */,
5647
+ "wireguard" /* WireGuard */,
5648
+ "hysteria" /* Hysteria */,
5649
+ "hysteria2" /* Hysteria2 */,
5650
+ "vless" /* VLESS */,
5651
+ "anytls" /* AnyTLS */,
5652
+ "tuic" /* TUIC */
5653
+ ]);
5654
+ var PREMIUM_PROTOCOLS = /* @__PURE__ */ new Set([
5655
+ "ss" /* Shadowsocks */,
5656
+ "ssr" /* ShadowsocksR */,
5657
+ "vmess" /* VMess */,
5658
+ "trojan" /* Trojan */,
5659
+ "snell" /* Snell */,
5660
+ "http" /* HTTP */,
5661
+ "https" /* HTTPS */,
5662
+ "socks5" /* SOCKS5 */,
5663
+ "wireguard" /* WireGuard */
5664
+ ]);
5665
+ var STASH_PROTOCOLS = /* @__PURE__ */ new Set([
5666
+ ...PREMIUM_PROTOCOLS,
5667
+ "hysteria" /* Hysteria */,
5668
+ "hysteria2" /* Hysteria2 */,
5669
+ "vless" /* VLESS */,
5670
+ "tuic" /* TUIC */
5671
+ ]);
5672
+ function clashCapabilities(flavor) {
5673
+ if (flavor === "premium") {
5674
+ return { clientFingerprint: false, protocols: PREMIUM_PROTOCOLS, reality: false };
5675
+ }
5676
+ if (flavor === "stash") {
5677
+ return { clientFingerprint: false, protocols: STASH_PROTOCOLS, reality: true };
5678
+ }
5679
+ return { clientFingerprint: true, protocols: MIHOMO_PROTOCOLS, reality: true };
5680
+ }
5426
5681
  function buildClashProxy(x, settings, clashR, remark, skipCertVerify, tfo) {
5427
5682
  const proxy = {
5428
5683
  name: remark,
5429
5684
  port: x.port,
5430
5685
  server: stripBrackets(x.hostname)
5431
5686
  };
5687
+ const caps = clashCapabilities(settings.clashFlavor);
5688
+ if (!caps.protocols.has(x.type)) {
5689
+ return void 0;
5690
+ }
5432
5691
  switch (x.type) {
5433
5692
  case "ss" /* Shadowsocks */: {
5434
5693
  if (settings.filterDeprecated && x.encryptMethod === "chacha20") {
@@ -5678,7 +5937,7 @@ function buildClashProxy(x, settings, clashR, remark, skipCertVerify, tfo) {
5678
5937
  if (skipCertVerify !== void 0) {
5679
5938
  proxy["skip-cert-verify"] = skipCertVerify;
5680
5939
  }
5681
- if (x.fingerprint !== "") {
5940
+ if (x.fingerprint !== "" && caps.clientFingerprint) {
5682
5941
  proxy.fingerprint = x.fingerprint;
5683
5942
  }
5684
5943
  if (x.alpn.length > 0) {
@@ -5733,7 +5992,7 @@ function buildClashProxy(x, settings, clashR, remark, skipCertVerify, tfo) {
5733
5992
  if (skipCertVerify !== void 0) {
5734
5993
  proxy["skip-cert-verify"] = skipCertVerify;
5735
5994
  }
5736
- if (x.fingerprint !== "") {
5995
+ if (x.fingerprint !== "" && caps.clientFingerprint) {
5737
5996
  proxy.fingerprint = x.fingerprint;
5738
5997
  }
5739
5998
  if (x.alpn.length > 0) {
@@ -5772,10 +6031,13 @@ function buildClashProxy(x, settings, clashR, remark, skipCertVerify, tfo) {
5772
6031
  if (x.serverName !== "") {
5773
6032
  proxy.servername = x.serverName;
5774
6033
  }
5775
- if (x.fingerprint !== "") {
6034
+ if (x.fingerprint !== "" && caps.clientFingerprint) {
5776
6035
  proxy["client-fingerprint"] = x.fingerprint;
5777
6036
  }
5778
6037
  if (x.publicKey !== "" || x.shortId !== "") {
6038
+ if (!caps.reality) {
6039
+ return void 0;
6040
+ }
5779
6041
  const realityOpts = {};
5780
6042
  if (x.publicKey !== "") {
5781
6043
  realityOpts["public-key"] = x.publicKey;
@@ -7132,7 +7394,7 @@ function collectRuleLines(content, group2, noResolveOnly) {
7132
7394
  }
7133
7395
  return out;
7134
7396
  }
7135
- function rulesetToClashRules(rulesets) {
7397
+ function rulesetToClashRules(rulesets, classical = false) {
7136
7398
  const rules = [];
7137
7399
  for (const ruleset of rulesets) {
7138
7400
  const content = ruleset.content;
@@ -7148,7 +7410,10 @@ function rulesetToClashRules(rulesets) {
7148
7410
  rules.push(transformRuleToCommon(line, group2));
7149
7411
  continue;
7150
7412
  }
7151
- const converted = convertRuleset(content, ruleset.ruleType);
7413
+ const converted = convertRuleset(
7414
+ content,
7415
+ classical && /^payload:\r?\n/.test(content) ? "clash-classical" /* ClashClassical */ : ruleset.ruleType
7416
+ );
7152
7417
  for (const rawLine of converted.split(/\r?\n/)) {
7153
7418
  let line = rawLine.trim();
7154
7419
  if (!isRuleLine(line)) {
@@ -7165,7 +7430,7 @@ function rulesetToClashRules(rulesets) {
7165
7430
  }
7166
7431
  return rules;
7167
7432
  }
7168
- function rulesetToSurgeRules(rulesets, surgeVersion) {
7433
+ function rulesetToSurgeRules(rulesets, surgeVersion, expand = true) {
7169
7434
  let section;
7170
7435
  let allowed;
7171
7436
  let noResolveOnly = false;
@@ -7203,6 +7468,17 @@ function rulesetToSurgeRules(rulesets, surgeVersion) {
7203
7468
  continue;
7204
7469
  }
7205
7470
  const group2 = ruleset.ruleGroup;
7471
+ if (!expand && (surgeVersion > 2 || surgeVersion === -3)) {
7472
+ const { url } = parseRulesetSource(ruleset.rulePath);
7473
+ if (/^https?:\/\//i.test(url.trim()) && !ruleset.content.startsWith("[]")) {
7474
+ let line = `RULE-SET,${url.trim()},${group2}`;
7475
+ if (ruleset.updateInterval > 0) {
7476
+ line += `,update-interval=${ruleset.updateInterval}`;
7477
+ }
7478
+ lines.push(line);
7479
+ continue;
7480
+ }
7481
+ }
7206
7482
  if (ruleset.content.startsWith("[]")) {
7207
7483
  let line = ruleset.content.slice(2);
7208
7484
  if (line === "MATCH") {
@@ -7967,9 +8243,24 @@ function buildOutbound(x, settings, remark) {
7967
8243
  proxy = out;
7968
8244
  break;
7969
8245
  }
7970
- // sing-box has no SSR support — drop such nodes.
8246
+ // sing-box has no ShadowsocksR implementation (configs using it fail
8247
+ // at startup), so such nodes are dropped.
7971
8248
  case "ssr" /* ShadowsocksR */:
7972
8249
  return void 0;
8250
+ case "snell" /* Snell */: {
8251
+ const out = { ...common, psk: x.password, type: "snell" };
8252
+ if (x.snellVersion) {
8253
+ out.version = x.snellVersion;
8254
+ }
8255
+ if (x.obfs !== "" && x.obfs !== "none") {
8256
+ out.obfs_mode = x.obfs;
8257
+ }
8258
+ if (x.host !== "") {
8259
+ out.obfs_host = x.host;
8260
+ }
8261
+ proxy = out;
8262
+ break;
8263
+ }
7973
8264
  case "vmess" /* VMess */: {
7974
8265
  const out = {
7975
8266
  ...common,
@@ -8273,6 +8564,7 @@ function generate(nodes, options) {
8273
8564
  runPreprocess(nodes, settings);
8274
8565
  const groups = resolveGroups(options);
8275
8566
  const rulesets = resolveRulesets(options, settings);
8567
+ const baseConf = applyBaseTemplate(options.baseConf ?? "", settings);
8276
8568
  switch (options.target) {
8277
8569
  case "clash" /* Clash */:
8278
8570
  case "clashr" /* ClashR */: {
@@ -8282,9 +8574,9 @@ function generate(nodes, options) {
8282
8574
  }
8283
8575
  case "surge" /* Surge */: {
8284
8576
  const surgeVersion = options.surgeVersion ?? 5;
8285
- const rules = rulesets ? rulesetToSurgeRules(rulesets, surgeVersion) : void 0;
8577
+ const rules = rulesets ? rulesetToSurgeRules(rulesets, surgeVersion, settings.expandRulesets) : void 0;
8286
8578
  return toSurge(nodes, groups, settings, {
8287
- baseConf: options.baseConf ?? "",
8579
+ baseConf,
8288
8580
  nodeList: settings.nodeList,
8289
8581
  rules,
8290
8582
  version: surgeVersion
@@ -8293,7 +8585,7 @@ function generate(nodes, options) {
8293
8585
  case "quanx" /* QuantumultX */: {
8294
8586
  const rules = rulesets ? rulesetToSurgeRules(rulesets, -1) : void 0;
8295
8587
  return toQuanX(nodes, groups, settings, {
8296
- baseConf: options.baseConf ?? "",
8588
+ baseConf,
8297
8589
  nodeList: settings.nodeList,
8298
8590
  rules
8299
8591
  });
@@ -8301,7 +8593,7 @@ function generate(nodes, options) {
8301
8593
  case "quan" /* Quantumult */: {
8302
8594
  const rules = rulesets ? rulesetToSurgeRules(rulesets, -2) : void 0;
8303
8595
  return toQuan(nodes, groups, settings, {
8304
- baseConf: options.baseConf ?? "",
8596
+ baseConf,
8305
8597
  nodeList: settings.nodeList,
8306
8598
  rules
8307
8599
  });
@@ -8309,21 +8601,21 @@ function generate(nodes, options) {
8309
8601
  case "loon" /* Loon */: {
8310
8602
  const rules = rulesets ? rulesetToSurgeRules(rulesets, -4) : void 0;
8311
8603
  return toLoon(nodes, groups, settings, {
8312
- baseConf: options.baseConf ?? "",
8604
+ baseConf,
8313
8605
  nodeList: settings.nodeList,
8314
8606
  rules
8315
8607
  });
8316
8608
  }
8317
8609
  case "singbox" /* SingBox */:
8318
8610
  return toSingBox(nodes, groups, settings, {
8319
- baseConf: options.baseConf ?? "",
8611
+ baseConf,
8320
8612
  nodeList: settings.nodeList,
8321
8613
  overwriteOriginalRules: settings.overwriteOriginalRules,
8322
8614
  rulesets
8323
8615
  });
8324
8616
  case "mellow" /* Mellow */:
8325
8617
  return toMellow(nodes, groups, settings, {
8326
- baseConf: options.baseConf ?? "",
8618
+ baseConf,
8327
8619
  nodeList: settings.nodeList,
8328
8620
  overwriteOriginalRules: settings.overwriteOriginalRules,
8329
8621
  rulesets
@@ -8341,11 +8633,11 @@ function generate(nodes, options) {
8341
8633
  case "ssd" /* SSD */:
8342
8634
  return proxyToSsd(nodes, "", "");
8343
8635
  case "sssub" /* SSSub */:
8344
- return proxyToSsSub(nodes, options.baseConf ?? "");
8636
+ return proxyToSsSub(nodes, baseConf);
8345
8637
  case "surfboard" /* Surfboard */: {
8346
- const rules = rulesets ? rulesetToSurgeRules(rulesets, options.surgeVersion ?? 5) : void 0;
8638
+ const rules = rulesets ? rulesetToSurgeRules(rulesets, options.surgeVersion ?? 5, settings.expandRulesets) : void 0;
8347
8639
  return toSurfboard(nodes, groups, settings, {
8348
- baseConf: options.baseConf ?? "",
8640
+ baseConf,
8349
8641
  nodeList: settings.nodeList,
8350
8642
  rules
8351
8643
  });
@@ -8358,6 +8650,12 @@ function generate(nodes, options) {
8358
8650
  throw new Error(`Unsupported target format: ${options.target}`);
8359
8651
  }
8360
8652
  }
8653
+ function applyBaseTemplate(baseConf, settings) {
8654
+ if (baseConf === "" || !hasTemplatePlaceholders(baseConf)) {
8655
+ return baseConf;
8656
+ }
8657
+ return renderTemplate(baseConf, settings.templateVars);
8658
+ }
8361
8659
  function toSip008(nodes, baseConf = "") {
8362
8660
  return proxyToSsSub(nodes, baseConf);
8363
8661
  }
@@ -8387,7 +8685,7 @@ function attachClashRules(doc, settings, rulesets) {
8387
8685
  return;
8388
8686
  }
8389
8687
  const field = settings.clashNewFieldName ? "rules" : "Rule";
8390
- const generated = rulesetToClashRules(rulesets);
8688
+ const generated = rulesetToClashRules(rulesets, settings.clashClassicalRuleset);
8391
8689
  if (generated.length === 0) {
8392
8690
  return;
8393
8691
  }
@@ -8405,6 +8703,8 @@ export {
8405
8703
  ProxyGroupType,
8406
8704
  ProxyType,
8407
8705
  QUANX_RULE_TYPES,
8706
+ REGEX_BLACKLIST,
8707
+ RULESET_TYPE_PREFIXES,
8408
8708
  RulesetType,
8409
8709
  SING_BOX_RULE_TYPES,
8410
8710
  SSR_CIPHERS,
@@ -8436,12 +8736,14 @@ export {
8436
8736
  explodeClash,
8437
8737
  explodeHttp,
8438
8738
  explodeHttpSub,
8739
+ explodeHysteria,
8439
8740
  explodeHysteria2,
8440
8741
  explodeKitsunebi,
8441
8742
  explodeNetch,
8442
8743
  explodeNetchConf,
8443
8744
  explodeQuan,
8444
8745
  explodeShadowrocket,
8746
+ explodeSnell,
8445
8747
  explodeSocks,
8446
8748
  explodeSs,
8447
8749
  explodeSsAndroid,
@@ -8458,6 +8760,7 @@ export {
8458
8760
  explodeVless,
8459
8761
  explodeVmess,
8460
8762
  explodeVmessConf,
8763
+ explodeWireguard,
8461
8764
  filterNodes,
8462
8765
  filterNodesByCountry,
8463
8766
  findSection,
@@ -8481,6 +8784,7 @@ export {
8481
8784
  hysteria2Construct,
8482
8785
  hysteriaConstruct,
8483
8786
  inferUserinfoProviderFromUrl,
8787
+ isBlacklistedPattern,
8484
8788
  isBlank,
8485
8789
  isFlattenableSsr,
8486
8790
  isIp,
@@ -8498,6 +8802,7 @@ export {
8498
8802
  normalizeQueryKey,
8499
8803
  normalizeUserinfoProvider,
8500
8804
  pad2,
8805
+ parseClashFlavor,
8501
8806
  parseClashText,
8502
8807
  parseConfContent,
8503
8808
  parseCustomProxyGroup,
@@ -8512,6 +8817,7 @@ export {
8512
8817
  parseRegexMatch,
8513
8818
  parseRequestSettings,
8514
8819
  parseRulesetConfig,
8820
+ parseRulesetSource,
8515
8821
  parseSubscription,
8516
8822
  parseSubscriptionUserinfo,
8517
8823
  parseTriBool,