@subconverter/core 0.2.1 → 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,16 +257,21 @@ 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",
253
264
  clashScript: false,
254
- countryLocale: "zh-CN",
255
265
  countryResolver: void 0,
256
266
  dedupe: false,
257
267
  emojiArray: [],
258
268
  enableRuleGenerator: true,
269
+ excludeCountries: [],
270
+ excludeRemarks: [],
271
+ expandRulesets: true,
259
272
  filterDeprecated: false,
273
+ includeCountries: [],
274
+ includeRemarks: [],
260
275
  managedConfigPrefix: "",
261
276
  nameRegexArray: [],
262
277
  nameRemove: [],
@@ -269,6 +284,7 @@ function createExtraSettings() {
269
284
  sortFlag: false,
270
285
  sortScript: "",
271
286
  surgeSsrPath: "",
287
+ templateVars: {},
272
288
  tfo: void 0,
273
289
  tls13: void 0,
274
290
  udp: void 0
@@ -492,7 +508,7 @@ function toBool(value) {
492
508
  return false;
493
509
  }
494
510
  const normalized = value.trim().toLowerCase();
495
- return normalized === "true" || normalized === "1";
511
+ return normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on";
496
512
  }
497
513
  function strFind(haystack, needle) {
498
514
  return haystack.includes(needle);
@@ -641,6 +657,23 @@ function templateVariableNames(content) {
641
657
  }
642
658
 
643
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
+ }
644
677
  var GROUP_TYPE_MAP = {
645
678
  fallback: "fallback" /* Fallback */,
646
679
  "load-balance": "load-balance" /* LoadBalance */,
@@ -742,8 +775,10 @@ function parseExternalConfig(content) {
742
775
  baseFiles: {},
743
776
  emoji: [],
744
777
  enableRuleGenerator: true,
778
+ excludeCountries: [],
745
779
  excludeRemarks: [],
746
780
  groups: [],
781
+ includeCountries: [],
747
782
  includeRemarks: [],
748
783
  nameRegex: [],
749
784
  nameRemove: [],
@@ -812,6 +847,22 @@ function parseExternalConfig(content) {
812
847
  result.includeRemarks.push(value);
813
848
  }
814
849
  break;
850
+ case "include_country":
851
+ for (const fragment of value.split(",")) {
852
+ const trimmed = fragment.trim().toUpperCase();
853
+ if (trimmed !== "") {
854
+ result.includeCountries.push(trimmed);
855
+ }
856
+ }
857
+ break;
858
+ case "exclude_country":
859
+ for (const fragment of value.split(",")) {
860
+ const trimmed = fragment.trim().toUpperCase();
861
+ if (trimmed !== "") {
862
+ result.excludeCountries.push(trimmed);
863
+ }
864
+ }
865
+ break;
815
866
  case "exclude_remarks":
816
867
  case "exclude":
817
868
  if (value !== "") {
@@ -866,6 +917,9 @@ function listArg(query, key) {
866
917
  const value = getUrlArg(query, key);
867
918
  return value === "" ? [] : value.split(",");
868
919
  }
920
+ function countryListArg(query, key) {
921
+ return getAllUrlArgs(query, key).flatMap((raw) => raw.split(",")).map((raw) => raw.trim().toUpperCase()).filter((raw) => raw !== "");
922
+ }
869
923
  function resolveNewFieldName(query) {
870
924
  if (boolArg(query, "legacy") || boolArg(query, "legacy_field_name") || boolArg(query, "legacy-field-name")) {
871
925
  return false;
@@ -904,13 +958,19 @@ function createRequestSettings() {
904
958
  appendType: false,
905
959
  autoCountry: false,
906
960
  autoExtract: false,
961
+ clashFlavor: "mihomo",
907
962
  clashScript: false,
908
963
  classicalRuleset: false,
909
964
  dedupe: false,
965
+ devId: "",
910
966
  emoji: [],
967
+ excludeCountries: [],
911
968
  excludeRemarks: [],
969
+ expand: true,
970
+ filename: "",
912
971
  filterDeprecated: false,
913
972
  group: [],
973
+ includeCountries: [],
914
974
  includeRemarks: [],
915
975
  insert: false,
916
976
  interval: 0,
@@ -928,6 +988,7 @@ function createRequestSettings() {
928
988
  script: "",
929
989
  scv: void 0,
930
990
  sort: false,
991
+ strict: false,
931
992
  target: "auto" /* Auto */,
932
993
  tfo: void 0,
933
994
  tls13: void 0,
@@ -956,6 +1017,11 @@ function parseRequestSettings(query) {
956
1017
  settings.filterDeprecated = boolArg(query, "filter_deprecated");
957
1018
  settings.newFieldName = resolveNewFieldName(query);
958
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");
959
1025
  settings.insert = getUrlArg(query, "insert") !== "";
960
1026
  settings.clashScript = boolArg(query, "clash_script");
961
1027
  settings.autoExtract = boolArg(query, "auto_extract");
@@ -971,6 +1037,8 @@ function parseRequestSettings(query) {
971
1037
  settings.proxyGroupsStyle = getUrlArg(query, "proxy_groups_style") || "flow";
972
1038
  settings.includeRemarks = listArg(query, "include");
973
1039
  settings.excludeRemarks = listArg(query, "exclude");
1040
+ settings.includeCountries = countryListArg(query, "include_country");
1041
+ settings.excludeCountries = countryListArg(query, "exclude_country");
974
1042
  settings.userinfoUrl = firstArg(query, "userinfo_url", "userinfo-url", "userinfo");
975
1043
  settings.userinfoProvider = firstArg(
976
1044
  query,
@@ -1846,485 +1914,493 @@ function explodeClash(root, nodes) {
1846
1914
  }
1847
1915
  let index = nodes.length;
1848
1916
  for (const single of list) {
1849
- const proxyType = asString(get(single, "type")).toLowerCase();
1850
- const ps = asString(get(single, "name"));
1851
- const server = asString(get(single, "server"));
1852
- const port = asString(get(single, "port"));
1853
- let underlyingProxy = asString(get(single, "underlying-proxy"));
1854
- if (underlyingProxy === "") {
1855
- underlyingProxy = asString(get(single, "dialer-proxy"));
1856
- }
1857
- if (port === "" || port === "0") {
1858
- continue;
1859
- }
1860
- const udp = asTri(get(single, "udp"));
1861
- const tfo = asTri(get(single, "fast-open"));
1862
- const scv = asTri(get(single, "skip-cert-verify"));
1863
- const node = createProxy();
1864
- let group2 = "";
1865
- switch (proxyType) {
1866
- case "vmess": {
1867
- group2 = DEFAULT_GROUPS.v2ray;
1868
- const id = asString(get(single, "uuid"));
1869
- const aid = asString(get(single, "alterId"));
1870
- const cipher = asString(get(single, "cipher"));
1871
- const net = get(single, "network") !== void 0 ? asString(get(single, "network")) : "tcp";
1872
- const sni = asString(get(single, "servername"));
1873
- let path = "";
1874
- let host = "";
1875
- let edge = "";
1876
- switch (net) {
1877
- case "http":
1878
- path = asString(get(get(get(single, "http-opts"), "path"), 0));
1879
- host = asString(get(get(get(get(single, "http-opts"), "headers"), "Host"), 0));
1880
- edge = "";
1881
- break;
1882
- case "ws":
1883
- if (get(single, "ws-opts") !== void 0) {
1884
- const wsOpts = get(single, "ws-opts");
1885
- path = get(wsOpts, "path") !== void 0 ? asString(get(wsOpts, "path")) : "/";
1886
- host = asString(get(get(wsOpts, "headers"), "Host"));
1887
- edge = asString(get(get(wsOpts, "headers"), "Edge"));
1888
- } else {
1889
- path = get(single, "ws-path") !== void 0 ? asString(get(single, "ws-path")) : "/";
1890
- host = asString(get(get(single, "ws-headers"), "Host"));
1891
- edge = asString(get(get(single, "ws-headers"), "Edge"));
1892
- }
1893
- break;
1894
- case "h2":
1895
- path = asString(get(get(single, "h2-opts"), "path"));
1896
- host = asString(get(get(get(single, "h2-opts"), "host"), 0));
1897
- edge = "";
1898
- break;
1899
- case "grpc":
1900
- host = asString(get(single, "servername"));
1901
- path = asString(get(get(single, "grpc-opts"), "grpc-service-name"));
1902
- edge = "";
1903
- break;
1904
- default:
1905
- break;
1906
- }
1907
- const tls = asBool(get(single, "tls")) ? "tls" : "";
1908
- vmessConstruct(node, {
1909
- add: server,
1910
- aid,
1911
- cipher,
1912
- edge,
1913
- group: group2,
1914
- host,
1915
- id,
1916
- net,
1917
- path,
1918
- port,
1919
- remark: ps,
1920
- scv,
1921
- sni,
1922
- tfo,
1923
- tls,
1924
- type: "",
1925
- udp,
1926
- underlyingProxy
1927
- });
1928
- break;
1917
+ try {
1918
+ if (parseClashNode(single, nodes, index)) {
1919
+ index += 1;
1929
1920
  }
1930
- case "ss": {
1931
- group2 = DEFAULT_GROUPS.ss;
1932
- let cipher = asString(get(single, "cipher"));
1933
- const password = asString(get(single, "password"));
1934
- let plugin = "";
1935
- let pluginOption = "";
1936
- let pluginMode = "";
1937
- let pluginHost = "";
1938
- let pluginMux = "";
1939
- let pluginTls = "";
1940
- let path = "";
1941
- if (get(single, "plugin") !== void 0) {
1942
- const pluginName = asString(get(single, "plugin")).toLowerCase();
1943
- const pluginOpts = get(single, "plugin-opts");
1944
- if (pluginName === "obfs") {
1945
- plugin = "obfs-local";
1946
- pluginMode = asString(get(pluginOpts, "mode"));
1947
- pluginHost = asString(get(pluginOpts, "host"));
1948
- } else if (pluginName === "v2ray-plugin") {
1949
- plugin = "v2ray-plugin";
1950
- pluginMode = asString(get(pluginOpts, "mode"));
1951
- pluginHost = asString(get(pluginOpts, "host"));
1952
- pluginTls = asBool(get(pluginOpts, "tls")) ? "tls;" : "";
1953
- path = asString(get(pluginOpts, "path"));
1954
- pluginMux = asBool(get(pluginOpts, "mux")) ? "mux=4;" : "";
1955
- }
1956
- } else if (get(single, "obfs") !== void 0) {
1957
- plugin = "obfs-local";
1958
- pluginMode = asString(get(single, "obfs"));
1959
- pluginHost = asString(get(single, "obfs-host"));
1960
- }
1961
- if (plugin === "simple-obfs" || plugin === "obfs-local") {
1962
- pluginOption = `obfs=${pluginMode}`;
1963
- pluginOption += pluginHost === "" ? "" : `;obfs-host=${pluginHost}`;
1964
- } else if (plugin === "v2ray-plugin") {
1965
- pluginOption = `mode=${pluginMode};${pluginTls}${pluginMux}`;
1966
- if (pluginHost !== "") {
1967
- pluginOption += `host=${pluginHost};`;
1968
- }
1969
- if (path !== "") {
1970
- pluginOption += `path=${path};`;
1971
- }
1972
- if (pluginMux !== "") {
1973
- 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"));
1974
1969
  }
1975
- }
1976
- if (cipher === "AEAD_CHACHA20_POLY1305") {
1977
- cipher = "chacha20-ietf-poly1305";
1978
- } else if (cipher.includes("AEAD")) {
1979
- cipher = cipher.replace(/AEAD_/g, "").replace(/_/g, "-").toLowerCase();
1980
- }
1981
- ssConstruct(node, {
1982
- group: group2,
1983
- method: cipher,
1984
- password,
1985
- plugin,
1986
- pluginOption,
1987
- port,
1988
- remark: ps,
1989
- scv,
1990
- server,
1991
- tfo,
1992
- udp,
1993
- underlyingProxy
1994
- });
1995
- break;
1996
- }
1997
- case "socks5": {
1998
- group2 = DEFAULT_GROUPS.socks;
1999
- const user = asString(get(single, "username"));
2000
- const password = asString(get(single, "password"));
2001
- socksConstruct(node, {
2002
- group: group2,
2003
- password,
2004
- port,
2005
- remark: ps,
2006
- server,
2007
- underlyingProxy,
2008
- username: user
2009
- });
2010
- break;
2011
- }
2012
- case "ssr": {
2013
- group2 = DEFAULT_GROUPS.ssr;
2014
- let cipher = asString(get(single, "cipher"));
2015
- if (cipher === "dummy") {
2016
- cipher = "none";
2017
- }
2018
- const password = asString(get(single, "password"));
2019
- const protocol = asString(get(single, "protocol"));
2020
- const obfs = asString(get(single, "obfs"));
2021
- const protocolParam = get(single, "protocol-param") !== void 0 ? asString(get(single, "protocol-param")) : asString(get(single, "protocolparam"));
2022
- const obfsParam = get(single, "obfs-param") !== void 0 ? asString(get(single, "obfs-param")) : asString(get(single, "obfsparam"));
2023
- ssrConstruct(node, {
2024
- group: group2,
2025
- method: cipher,
2026
- obfs,
2027
- obfsParam,
2028
- password,
2029
- port,
2030
- protocol,
2031
- protocolParam,
2032
- remark: ps,
2033
- scv,
2034
- server,
2035
- tfo,
2036
- udp,
2037
- underlyingProxy
2038
- });
2039
- break;
2040
- }
2041
- case "http": {
2042
- group2 = DEFAULT_GROUPS.http;
2043
- const user = asString(get(single, "username"));
2044
- const password = asString(get(single, "password"));
2045
- const tls = asString(get(single, "tls"));
2046
- httpConstruct(node, {
2047
- group: group2,
2048
- password,
2049
- port,
2050
- remark: ps,
2051
- scv,
2052
- server,
2053
- tfo,
2054
- tls: tls === "true",
2055
- underlyingProxy,
2056
- username: user
2057
- });
2058
- 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;
2059
1983
  }
2060
- case "trojan": {
2061
- group2 = DEFAULT_GROUPS.trojan;
2062
- const password = asString(get(single, "password"));
2063
- const host = asString(get(single, "sni"));
2064
- let net = asString(get(single, "network"));
2065
- let path = "";
2066
- switch (net) {
2067
- case "grpc":
2068
- path = asString(get(get(single, "grpc-opts"), "grpc-service-name"));
2069
- break;
2070
- case "ws":
2071
- path = asString(get(get(single, "ws-opts"), "path"));
2072
- break;
2073
- default:
2074
- net = "tcp";
2075
- path = "";
2076
- 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;" : "";
2077
2032
  }
2078
- trojanConstruct(node, {
2079
- group: group2,
2080
- host,
2081
- network: net,
2082
- password,
2083
- path,
2084
- port,
2085
- remark: ps,
2086
- scv,
2087
- server,
2088
- tfo,
2089
- tlsSecure: true,
2090
- udp,
2091
- underlyingProxy
2092
- });
2093
- break;
2094
- }
2095
- case "snell": {
2096
- group2 = DEFAULT_GROUPS.snell;
2097
- const password = asString(get(single, "psk"));
2098
- const obfs = asString(get(get(single, "obfs-opts"), "mode"));
2099
- const host = asString(get(get(single, "obfs-opts"), "host"));
2100
- const version = asString(get(single, "version"));
2101
- snellConstruct(node, {
2102
- group: group2,
2103
- host,
2104
- obfs,
2105
- password,
2106
- port,
2107
- remark: ps,
2108
- scv,
2109
- server,
2110
- tfo,
2111
- udp,
2112
- underlyingProxy,
2113
- version: toInt(version)
2114
- });
2115
- break;
2116
- }
2117
- case "wireguard": {
2118
- group2 = DEFAULT_GROUPS.wireguard;
2119
- const publicKey = asString(get(single, "public-key"));
2120
- const privateKey = asString(get(single, "private-key"));
2121
- const dns = get(single, "dns");
2122
- const dnsServers = Array.isArray(dns) ? dns.map((d) => String(d)) : dns ? [String(dns)] : [];
2123
- const mtu = asString(get(single, "mtu"));
2124
- const psk = asString(get(single, "preshared-key"));
2125
- const ip = asString(get(single, "ip"));
2126
- const ipv6 = asString(get(single, "ipv6"));
2127
- wireGuardConstruct(node, {
2128
- dnsServers,
2129
- group: group2,
2130
- keepAlive: "0",
2131
- mtu,
2132
- port,
2133
- preSharedKey: psk,
2134
- privateKey,
2135
- publicKey,
2136
- remark: ps,
2137
- selfIp: ip,
2138
- selfIpv6: ipv6,
2139
- server,
2140
- testUrl: "",
2141
- udp,
2142
- underlyingProxy
2143
- });
2144
- break;
2145
- }
2146
- case "hysteria": {
2147
- group2 = DEFAULT_GROUPS.hysteria;
2148
- const ports = asString(get(single, "ports"));
2149
- const protocol = asString(get(single, "protocol"));
2150
- const obfsProtocol = asString(get(single, "obfs-protocol"));
2151
- const up = asString(get(single, "up"));
2152
- const upSpeed = asString(get(single, "up-speed"));
2153
- const down = asString(get(single, "down"));
2154
- const downSpeed = asString(get(single, "down-speed"));
2155
- const auth = asString(get(single, "auth"));
2156
- let authStr = asString(get(single, "auth-str"));
2157
- if (authStr === "") {
2158
- 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};`;
2159
2045
  }
2160
- const obfs = asString(get(single, "obfs"));
2161
- const sni = asString(get(single, "sni"));
2162
- const fingerprint = asString(get(single, "fingerprint"));
2163
- const alpnValue = get(single, "alpn");
2164
- const alpn = Array.isArray(alpnValue) ? asString(alpnValue[0]) : asString(alpnValue);
2165
- const ca = asString(get(single, "ca"));
2166
- const caStr = asString(get(single, "ca-str"));
2167
- const recvWindowConn = asString(get(single, "recv-window-conn"));
2168
- const recvWindow = asString(get(single, "recv-window"));
2169
- let disableMtuDiscovery = asString(get(single, "disable-mtu-discovery"));
2170
- if (disableMtuDiscovery === "") {
2171
- disableMtuDiscovery = asString(get(single, "disable_mtu_discovery"));
2046
+ if (path !== "") {
2047
+ pluginOption += `path=${path};`;
2172
2048
  }
2173
- const hopInterval = asString(get(single, "hop-interval"));
2174
- hysteriaConstruct(node, {
2175
- alpn,
2176
- auth,
2177
- authStr,
2178
- ca,
2179
- caStr,
2180
- disableMtuDiscovery,
2181
- down,
2182
- downSpeed,
2183
- fingerprint,
2184
- group: group2,
2185
- hopInterval,
2186
- obfs,
2187
- obfsProtocol,
2188
- port,
2189
- ports,
2190
- protocol,
2191
- recvWindow,
2192
- recvWindowConn,
2193
- remark: ps,
2194
- scv,
2195
- server,
2196
- sni,
2197
- tfo,
2198
- underlyingProxy,
2199
- up,
2200
- upSpeed
2201
- });
2202
- break;
2203
- }
2204
- case "hysteria2": {
2205
- group2 = DEFAULT_GROUPS.hysteria2;
2206
- const ports = asString(get(single, "ports"));
2207
- const up = asString(get(single, "up"));
2208
- const down = asString(get(single, "down"));
2209
- let password = asString(get(single, "password"));
2210
- if (password === "") {
2211
- password = asString(get(single, "auth"));
2049
+ if (pluginMux !== "") {
2050
+ pluginOption += `mux=${pluginMux};`;
2212
2051
  }
2213
- const obfs = asString(get(single, "obfs"));
2214
- const obfsPassword = asString(get(single, "obfs-password"));
2215
- const sni = asString(get(single, "sni"));
2216
- const fingerprint = asString(get(single, "fingerprint"));
2217
- const alpnValue = get(single, "alpn");
2218
- const alpn = Array.isArray(alpnValue) ? asString(alpnValue[0]) : asString(alpnValue);
2219
- const ca = asString(get(single, "ca"));
2220
- const caStr = asString(get(single, "ca-str"));
2221
- const cwnd = asString(get(single, "cwnd"));
2222
- const hopInterval = asString(get(single, "hop-interval"));
2223
- hysteria2Construct(node, {
2224
- alpn,
2225
- ca,
2226
- caStr,
2227
- cwnd,
2228
- down,
2229
- fingerprint,
2230
- group: group2,
2231
- hopInterval,
2232
- obfs,
2233
- obfsPassword,
2234
- password,
2235
- port,
2236
- ports,
2237
- remark: ps,
2238
- scv,
2239
- server,
2240
- sni,
2241
- tfo,
2242
- underlyingProxy,
2243
- up
2244
- });
2245
- break;
2246
- }
2247
- case "anytls": {
2248
- group2 = DEFAULT_GROUPS.anytls;
2249
- const password = asString(get(single, "password"));
2250
- const sni = asString(get(single, "sni"));
2251
- anyTlsConstruct(node, {
2252
- group: group2,
2253
- password,
2254
- port,
2255
- remark: ps,
2256
- scv,
2257
- server,
2258
- sni,
2259
- tfo,
2260
- udp,
2261
- underlyingProxy
2262
- });
2263
- break;
2264
2052
  }
2265
- case "vless": {
2266
- group2 = DEFAULT_GROUPS.v2ray;
2267
- const userId = asString(get(single, "uuid"));
2268
- const net = asString(get(single, "network"));
2269
- const tls = asString(get(single, "tls"));
2270
- let path = "";
2271
- let host = "";
2272
- if (net === "ws") {
2273
- path = asString(get(get(single, "ws-opts"), "path"));
2274
- host = asString(get(get(get(single, "ws-opts"), "headers"), "Host"));
2275
- } else if (net === "grpc") {
2276
- path = asString(get(get(single, "grpc-opts"), "grpc-service-name"));
2277
- }
2278
- const alpnValue = get(single, "alpn");
2279
- vlessConstruct(node, {
2280
- alpn: Array.isArray(alpnValue) ? alpnValue.map((a) => String(a)) : void 0,
2281
- encryption: asString(get(single, "encryption")),
2282
- fingerprint: asString(get(single, "client-fingerprint")),
2283
- flow: asString(get(single, "flow")),
2284
- group: group2,
2285
- host,
2286
- network: net,
2287
- path,
2288
- port,
2289
- remark: ps,
2290
- scv,
2291
- server,
2292
- sni: asString(get(single, "servername")),
2293
- tfo,
2294
- tls: tls === "true" ? "tls" : "",
2295
- udp,
2296
- underlyingProxy,
2297
- userId
2298
- });
2299
- 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();
2300
2057
  }
2301
- case "tuic": {
2302
- group2 = DEFAULT_GROUPS.v2ray;
2303
- const alpnValue = get(single, "alpn");
2304
- tuicConstruct(node, {
2305
- alpn: Array.isArray(alpnValue) ? alpnValue.map((a) => String(a)) : void 0,
2306
- congestionControl: asString(get(single, "congestion-controller")),
2307
- group: group2,
2308
- password: asString(get(single, "password")),
2309
- port,
2310
- remark: ps,
2311
- scv,
2312
- server,
2313
- sni: asString(get(single, "sni")),
2314
- tfo,
2315
- udp,
2316
- underlyingProxy,
2317
- userId: asString(get(single, "uuid"))
2318
- });
2319
- break;
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":
2145
+ path = asString(get(get(single, "grpc-opts"), "grpc-service-name"));
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;
2320
2154
  }
2321
- default:
2322
- 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;
2323
2171
  }
2324
- node.id = index;
2325
- nodes.push(node);
2326
- 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;
2327
2400
  }
2401
+ node.id = index;
2402
+ nodes.push(node);
2403
+ return true;
2328
2404
  }
2329
2405
  function parseRawSections(text) {
2330
2406
  const sections = [];
@@ -3932,7 +4008,10 @@ function explodeSs(ss, node) {
3932
4008
  const secret = match[1];
3933
4009
  server = match[2];
3934
4010
  port = match[3];
3935
- 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;
3936
4015
  if (!secretMatch) {
3937
4016
  return;
3938
4017
  }
@@ -4397,6 +4476,157 @@ function explodeAnyTls(link, node) {
4397
4476
  udp: udp === "" ? void 0 : parseTri(udp)
4398
4477
  });
4399
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
+ }
4400
4630
  function explodeVless(link, node) {
4401
4631
  let body = link.slice(8);
4402
4632
  let remark = "";
@@ -4520,6 +4750,12 @@ function explode(link, node) {
4520
4750
  explodeVless(link, node);
4521
4751
  } else if (startsWith(link, "tuic://")) {
4522
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);
4523
4759
  } else if (link.includes("hysteria2://") || link.includes("hy2://")) {
4524
4760
  explodeHysteria2(link, node);
4525
4761
  } else if (startsWith(link, "anytls://")) {
@@ -4916,7 +5152,11 @@ function normalizeRegionCode(code) {
4916
5152
  const upper = code.trim().toUpperCase();
4917
5153
  return /^[A-Z]{2}$/.test(upper) ? upper : "";
4918
5154
  }
4919
- function regionDisplayName(code, locale = "zh-CN") {
5155
+ function normalizeCountryCode(code) {
5156
+ const upper = normalizeRegionCode(code);
5157
+ return upper !== "" && isRegionCode(upper) ? upper : void 0;
5158
+ }
5159
+ function displayName(code, locale) {
4920
5160
  const upper = normalizeRegionCode(code);
4921
5161
  if (upper === "") {
4922
5162
  return code.trim();
@@ -4959,8 +5199,8 @@ function buildAliasRegex() {
4959
5199
  }
4960
5200
  };
4961
5201
  for (const code of REGION_CODES) {
4962
- add(regionDisplayName(code, "zh-CN"));
4963
- add(regionDisplayName(code, "en"));
5202
+ add(displayName(code, "zh-CN"));
5203
+ add(displayName(code, "en"));
4964
5204
  add(regionFlag(code));
4965
5205
  }
4966
5206
  for (const alias of EXTRA_ALIASES) {
@@ -5000,13 +5240,13 @@ function hasRegionName(remark) {
5000
5240
  }
5001
5241
  return false;
5002
5242
  }
5003
- function formatCountryRemark(remark, code, locale = "zh-CN") {
5004
- const name = regionDisplayName(code, locale);
5243
+ function formatCountryRemark(remark, code) {
5244
+ const normalized = normalizeCountryCode(code);
5005
5245
  const trimmed = remark.trim();
5006
- if (name === "") {
5246
+ if (normalized === void 0) {
5007
5247
  return trimmed;
5008
5248
  }
5009
- return trimmed === "" ? name : `${name}-${trimmed}`;
5249
+ return trimmed === "" ? normalized : `${normalized}-${trimmed}`;
5010
5250
  }
5011
5251
 
5012
5252
  // src/generator/nodes.ts
@@ -5020,6 +5260,10 @@ function toRegex(pattern) {
5020
5260
  function regFind(value, pattern) {
5021
5261
  return toRegex(pattern).test(value);
5022
5262
  }
5263
+ var REGEX_BLACKLIST = ["(.*)*"];
5264
+ function isBlacklistedPattern(pattern) {
5265
+ return REGEX_BLACKLIST.includes(pattern);
5266
+ }
5023
5267
  function regMatch2(value, pattern) {
5024
5268
  const match = toRegex(pattern).exec(value);
5025
5269
  return match !== null && match[0] === value;
@@ -5265,7 +5509,7 @@ function nodeRename(node, renameArray) {
5265
5509
  node.remark = original;
5266
5510
  }
5267
5511
  }
5268
- function addCountryPrefix(node, resolve, locale = "zh-CN") {
5512
+ function addCountryPrefix(node, resolve) {
5269
5513
  const remark = node.remark.trim();
5270
5514
  if (hasRegionName(remark)) {
5271
5515
  return node.remark;
@@ -5274,7 +5518,31 @@ function addCountryPrefix(node, resolve, locale = "zh-CN") {
5274
5518
  if (code === void 0 || code === "") {
5275
5519
  return node.remark;
5276
5520
  }
5277
- return formatCountryRemark(remark, code, locale);
5521
+ return formatCountryRemark(remark, code);
5522
+ }
5523
+ function filterNodesByCountry(nodes, resolve, include, exclude) {
5524
+ const includeSet = new Set(
5525
+ include.map((code) => normalizeCountryCode(code)).filter((code) => code !== void 0)
5526
+ );
5527
+ const excludeSet = new Set(
5528
+ exclude.map((code) => normalizeCountryCode(code)).filter((code) => code !== void 0)
5529
+ );
5530
+ if (includeSet.size === 0 && excludeSet.size === 0) {
5531
+ return;
5532
+ }
5533
+ const kept = [];
5534
+ for (const node of nodes) {
5535
+ const code = resolve ? normalizeCountryCode(resolve(node) ?? "") : void 0;
5536
+ if (includeSet.size > 0 && (code === void 0 || !includeSet.has(code))) {
5537
+ continue;
5538
+ }
5539
+ if (code !== void 0 && excludeSet.has(code)) {
5540
+ continue;
5541
+ }
5542
+ kept.push(node);
5543
+ }
5544
+ nodes.length = 0;
5545
+ nodes.push(...kept);
5278
5546
  }
5279
5547
  function preprocessNodes(nodes, options) {
5280
5548
  for (const node of nodes) {
@@ -5292,13 +5560,25 @@ function preprocessNodes(nodes, options) {
5292
5560
  node.remark = addEmoji(node, options.emojiArray);
5293
5561
  }
5294
5562
  if (options.autoCountry && options.countryResolver) {
5295
- node.remark = addCountryPrefix(
5296
- node,
5297
- options.countryResolver,
5298
- options.countryLocale ?? "zh-CN"
5299
- );
5563
+ node.remark = addCountryPrefix(node, options.countryResolver);
5300
5564
  }
5301
5565
  }
5566
+ filterNodesByCountry(
5567
+ nodes,
5568
+ options.countryResolver,
5569
+ options.includeCountries ?? [],
5570
+ options.excludeCountries ?? []
5571
+ );
5572
+ const includeRemarks = options.includeRemarks ?? [];
5573
+ const excludeRemarks = options.excludeRemarks ?? [];
5574
+ if (includeRemarks.length > 0 || excludeRemarks.length > 0) {
5575
+ const kept = nodes.filter((node) => !checkIgnore(node, excludeRemarks, includeRemarks));
5576
+ kept.forEach((node, index) => {
5577
+ node.id = index;
5578
+ });
5579
+ nodes.length = 0;
5580
+ nodes.push(...kept);
5581
+ }
5302
5582
  if (options.sortFlag) {
5303
5583
  nodes.sort((a, b) => a.remark < b.remark ? -1 : a.remark > b.remark ? 1 : 0);
5304
5584
  }
@@ -5355,12 +5635,59 @@ function stripBrackets(value) {
5355
5635
  function toTri(value) {
5356
5636
  return value;
5357
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
+ }
5358
5681
  function buildClashProxy(x, settings, clashR, remark, skipCertVerify, tfo) {
5359
5682
  const proxy = {
5360
5683
  name: remark,
5361
5684
  port: x.port,
5362
5685
  server: stripBrackets(x.hostname)
5363
5686
  };
5687
+ const caps = clashCapabilities(settings.clashFlavor);
5688
+ if (!caps.protocols.has(x.type)) {
5689
+ return void 0;
5690
+ }
5364
5691
  switch (x.type) {
5365
5692
  case "ss" /* Shadowsocks */: {
5366
5693
  if (settings.filterDeprecated && x.encryptMethod === "chacha20") {
@@ -5610,7 +5937,7 @@ function buildClashProxy(x, settings, clashR, remark, skipCertVerify, tfo) {
5610
5937
  if (skipCertVerify !== void 0) {
5611
5938
  proxy["skip-cert-verify"] = skipCertVerify;
5612
5939
  }
5613
- if (x.fingerprint !== "") {
5940
+ if (x.fingerprint !== "" && caps.clientFingerprint) {
5614
5941
  proxy.fingerprint = x.fingerprint;
5615
5942
  }
5616
5943
  if (x.alpn.length > 0) {
@@ -5665,7 +5992,7 @@ function buildClashProxy(x, settings, clashR, remark, skipCertVerify, tfo) {
5665
5992
  if (skipCertVerify !== void 0) {
5666
5993
  proxy["skip-cert-verify"] = skipCertVerify;
5667
5994
  }
5668
- if (x.fingerprint !== "") {
5995
+ if (x.fingerprint !== "" && caps.clientFingerprint) {
5669
5996
  proxy.fingerprint = x.fingerprint;
5670
5997
  }
5671
5998
  if (x.alpn.length > 0) {
@@ -5704,10 +6031,13 @@ function buildClashProxy(x, settings, clashR, remark, skipCertVerify, tfo) {
5704
6031
  if (x.serverName !== "") {
5705
6032
  proxy.servername = x.serverName;
5706
6033
  }
5707
- if (x.fingerprint !== "") {
6034
+ if (x.fingerprint !== "" && caps.clientFingerprint) {
5708
6035
  proxy["client-fingerprint"] = x.fingerprint;
5709
6036
  }
5710
6037
  if (x.publicKey !== "" || x.shortId !== "") {
6038
+ if (!caps.reality) {
6039
+ return void 0;
6040
+ }
5711
6041
  const realityOpts = {};
5712
6042
  if (x.publicKey !== "") {
5713
6043
  realityOpts["public-key"] = x.publicKey;
@@ -7064,7 +7394,7 @@ function collectRuleLines(content, group2, noResolveOnly) {
7064
7394
  }
7065
7395
  return out;
7066
7396
  }
7067
- function rulesetToClashRules(rulesets) {
7397
+ function rulesetToClashRules(rulesets, classical = false) {
7068
7398
  const rules = [];
7069
7399
  for (const ruleset of rulesets) {
7070
7400
  const content = ruleset.content;
@@ -7080,7 +7410,10 @@ function rulesetToClashRules(rulesets) {
7080
7410
  rules.push(transformRuleToCommon(line, group2));
7081
7411
  continue;
7082
7412
  }
7083
- 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
+ );
7084
7417
  for (const rawLine of converted.split(/\r?\n/)) {
7085
7418
  let line = rawLine.trim();
7086
7419
  if (!isRuleLine(line)) {
@@ -7097,7 +7430,7 @@ function rulesetToClashRules(rulesets) {
7097
7430
  }
7098
7431
  return rules;
7099
7432
  }
7100
- function rulesetToSurgeRules(rulesets, surgeVersion) {
7433
+ function rulesetToSurgeRules(rulesets, surgeVersion, expand = true) {
7101
7434
  let section;
7102
7435
  let allowed;
7103
7436
  let noResolveOnly = false;
@@ -7135,6 +7468,17 @@ function rulesetToSurgeRules(rulesets, surgeVersion) {
7135
7468
  continue;
7136
7469
  }
7137
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
+ }
7138
7482
  if (ruleset.content.startsWith("[]")) {
7139
7483
  let line = ruleset.content.slice(2);
7140
7484
  if (line === "MATCH") {
@@ -7899,9 +8243,24 @@ function buildOutbound(x, settings, remark) {
7899
8243
  proxy = out;
7900
8244
  break;
7901
8245
  }
7902
- // 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.
7903
8248
  case "ssr" /* ShadowsocksR */:
7904
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
+ }
7905
8264
  case "vmess" /* VMess */: {
7906
8265
  const out = {
7907
8266
  ...common,
@@ -8184,9 +8543,12 @@ function runPreprocess(nodes, settings) {
8184
8543
  preprocessNodes(nodes, {
8185
8544
  addEmoji: settings.addEmoji,
8186
8545
  autoCountry: settings.autoCountry,
8187
- countryLocale: settings.countryLocale,
8188
8546
  countryResolver: settings.countryResolver,
8189
8547
  emojiArray: settings.emojiArray,
8548
+ excludeCountries: settings.excludeCountries,
8549
+ excludeRemarks: settings.excludeRemarks,
8550
+ includeCountries: settings.includeCountries,
8551
+ includeRemarks: settings.includeRemarks,
8190
8552
  nameRegexArray: settings.nameRegexArray,
8191
8553
  nameRemove: settings.nameRemove,
8192
8554
  removeEmoji: settings.removeEmoji,
@@ -8202,6 +8564,7 @@ function generate(nodes, options) {
8202
8564
  runPreprocess(nodes, settings);
8203
8565
  const groups = resolveGroups(options);
8204
8566
  const rulesets = resolveRulesets(options, settings);
8567
+ const baseConf = applyBaseTemplate(options.baseConf ?? "", settings);
8205
8568
  switch (options.target) {
8206
8569
  case "clash" /* Clash */:
8207
8570
  case "clashr" /* ClashR */: {
@@ -8211,9 +8574,9 @@ function generate(nodes, options) {
8211
8574
  }
8212
8575
  case "surge" /* Surge */: {
8213
8576
  const surgeVersion = options.surgeVersion ?? 5;
8214
- const rules = rulesets ? rulesetToSurgeRules(rulesets, surgeVersion) : void 0;
8577
+ const rules = rulesets ? rulesetToSurgeRules(rulesets, surgeVersion, settings.expandRulesets) : void 0;
8215
8578
  return toSurge(nodes, groups, settings, {
8216
- baseConf: options.baseConf ?? "",
8579
+ baseConf,
8217
8580
  nodeList: settings.nodeList,
8218
8581
  rules,
8219
8582
  version: surgeVersion
@@ -8222,7 +8585,7 @@ function generate(nodes, options) {
8222
8585
  case "quanx" /* QuantumultX */: {
8223
8586
  const rules = rulesets ? rulesetToSurgeRules(rulesets, -1) : void 0;
8224
8587
  return toQuanX(nodes, groups, settings, {
8225
- baseConf: options.baseConf ?? "",
8588
+ baseConf,
8226
8589
  nodeList: settings.nodeList,
8227
8590
  rules
8228
8591
  });
@@ -8230,7 +8593,7 @@ function generate(nodes, options) {
8230
8593
  case "quan" /* Quantumult */: {
8231
8594
  const rules = rulesets ? rulesetToSurgeRules(rulesets, -2) : void 0;
8232
8595
  return toQuan(nodes, groups, settings, {
8233
- baseConf: options.baseConf ?? "",
8596
+ baseConf,
8234
8597
  nodeList: settings.nodeList,
8235
8598
  rules
8236
8599
  });
@@ -8238,21 +8601,21 @@ function generate(nodes, options) {
8238
8601
  case "loon" /* Loon */: {
8239
8602
  const rules = rulesets ? rulesetToSurgeRules(rulesets, -4) : void 0;
8240
8603
  return toLoon(nodes, groups, settings, {
8241
- baseConf: options.baseConf ?? "",
8604
+ baseConf,
8242
8605
  nodeList: settings.nodeList,
8243
8606
  rules
8244
8607
  });
8245
8608
  }
8246
8609
  case "singbox" /* SingBox */:
8247
8610
  return toSingBox(nodes, groups, settings, {
8248
- baseConf: options.baseConf ?? "",
8611
+ baseConf,
8249
8612
  nodeList: settings.nodeList,
8250
8613
  overwriteOriginalRules: settings.overwriteOriginalRules,
8251
8614
  rulesets
8252
8615
  });
8253
8616
  case "mellow" /* Mellow */:
8254
8617
  return toMellow(nodes, groups, settings, {
8255
- baseConf: options.baseConf ?? "",
8618
+ baseConf,
8256
8619
  nodeList: settings.nodeList,
8257
8620
  overwriteOriginalRules: settings.overwriteOriginalRules,
8258
8621
  rulesets
@@ -8270,11 +8633,11 @@ function generate(nodes, options) {
8270
8633
  case "ssd" /* SSD */:
8271
8634
  return proxyToSsd(nodes, "", "");
8272
8635
  case "sssub" /* SSSub */:
8273
- return proxyToSsSub(nodes, options.baseConf ?? "");
8636
+ return proxyToSsSub(nodes, baseConf);
8274
8637
  case "surfboard" /* Surfboard */: {
8275
- const rules = rulesets ? rulesetToSurgeRules(rulesets, options.surgeVersion ?? 5) : void 0;
8638
+ const rules = rulesets ? rulesetToSurgeRules(rulesets, options.surgeVersion ?? 5, settings.expandRulesets) : void 0;
8276
8639
  return toSurfboard(nodes, groups, settings, {
8277
- baseConf: options.baseConf ?? "",
8640
+ baseConf,
8278
8641
  nodeList: settings.nodeList,
8279
8642
  rules
8280
8643
  });
@@ -8287,6 +8650,12 @@ function generate(nodes, options) {
8287
8650
  throw new Error(`Unsupported target format: ${options.target}`);
8288
8651
  }
8289
8652
  }
8653
+ function applyBaseTemplate(baseConf, settings) {
8654
+ if (baseConf === "" || !hasTemplatePlaceholders(baseConf)) {
8655
+ return baseConf;
8656
+ }
8657
+ return renderTemplate(baseConf, settings.templateVars);
8658
+ }
8290
8659
  function toSip008(nodes, baseConf = "") {
8291
8660
  return proxyToSsSub(nodes, baseConf);
8292
8661
  }
@@ -8316,7 +8685,7 @@ function attachClashRules(doc, settings, rulesets) {
8316
8685
  return;
8317
8686
  }
8318
8687
  const field = settings.clashNewFieldName ? "rules" : "Rule";
8319
- const generated = rulesetToClashRules(rulesets);
8688
+ const generated = rulesetToClashRules(rulesets, settings.clashClassicalRuleset);
8320
8689
  if (generated.length === 0) {
8321
8690
  return;
8322
8691
  }
@@ -8334,6 +8703,8 @@ export {
8334
8703
  ProxyGroupType,
8335
8704
  ProxyType,
8336
8705
  QUANX_RULE_TYPES,
8706
+ REGEX_BLACKLIST,
8707
+ RULESET_TYPE_PREFIXES,
8337
8708
  RulesetType,
8338
8709
  SING_BOX_RULE_TYPES,
8339
8710
  SSR_CIPHERS,
@@ -8365,12 +8736,14 @@ export {
8365
8736
  explodeClash,
8366
8737
  explodeHttp,
8367
8738
  explodeHttpSub,
8739
+ explodeHysteria,
8368
8740
  explodeHysteria2,
8369
8741
  explodeKitsunebi,
8370
8742
  explodeNetch,
8371
8743
  explodeNetchConf,
8372
8744
  explodeQuan,
8373
8745
  explodeShadowrocket,
8746
+ explodeSnell,
8374
8747
  explodeSocks,
8375
8748
  explodeSs,
8376
8749
  explodeSsAndroid,
@@ -8387,7 +8760,9 @@ export {
8387
8760
  explodeVless,
8388
8761
  explodeVmess,
8389
8762
  explodeVmessConf,
8763
+ explodeWireguard,
8390
8764
  filterNodes,
8765
+ filterNodesByCountry,
8391
8766
  findSection,
8392
8767
  fnv1a64,
8393
8768
  fnv1a64Hex,
@@ -8409,6 +8784,7 @@ export {
8409
8784
  hysteria2Construct,
8410
8785
  hysteriaConstruct,
8411
8786
  inferUserinfoProviderFromUrl,
8787
+ isBlacklistedPattern,
8412
8788
  isBlank,
8413
8789
  isFlattenableSsr,
8414
8790
  isIp,
@@ -8422,9 +8798,11 @@ export {
8422
8798
  nodeNameRegex,
8423
8799
  nodeNameRemove,
8424
8800
  nodeRename,
8801
+ normalizeCountryCode,
8425
8802
  normalizeQueryKey,
8426
8803
  normalizeUserinfoProvider,
8427
8804
  pad2,
8805
+ parseClashFlavor,
8428
8806
  parseClashText,
8429
8807
  parseConfContent,
8430
8808
  parseCustomProxyGroup,
@@ -8439,6 +8817,7 @@ export {
8439
8817
  parseRegexMatch,
8440
8818
  parseRequestSettings,
8441
8819
  parseRulesetConfig,
8820
+ parseRulesetSource,
8442
8821
  parseSubscription,
8443
8822
  parseSubscriptionUserinfo,
8444
8823
  parseTriBool,
@@ -8451,8 +8830,6 @@ export {
8451
8830
  queryBoolFlag,
8452
8831
  regMatch,
8453
8832
  regReplace,
8454
- regionDisplayName,
8455
- regionFlag,
8456
8833
  removeEmoji,
8457
8834
  renderRawIni,
8458
8835
  renderTemplate,