Proxy Chain
Proxy Chain
Section titled “Proxy Chain”Clash Nyanpasu inherits the proxy chain feature from Clash Verge and can implement a proxy chain through two types of chains: Script or Merge. The content of this section is adapted from Clash Verge documentation1.
What is a Proxy Chain?
Section titled “What is a Proxy Chain?”A proxy chain refers to the post-processing chain of a Profile. A profile can go through nodes such as A, B, C, or even more chain processing nodes, where the configuration is modified using scripts or expressions to generate a final proxy configuration. Multiple nodes are processed sequentially, forming a chain structure. You can customize the chain to enable certain nodes for different profiles or globally, thereby creating your own proxy chain.
The following diagram shows the current chain processing structure.
flowchart TD
A(Start)-->B["Load Profiles"]-->profile_chain-->global_chain-->G["Merge Protected Fields"]-->internal_chain-->J{"Enable Field Filtering?"}-->|Yes|K["Filter Fields"]-->L["Misc: Handle Tun, Sorting"]
J-->|No|L
L-->M[Generate Configuration]-->N(End)
subgraph profile_chain [Profile Chain]
C["..."]-->D["Processing Node n"]
end
subgraph global_chain [Global Chain]
E["..."]-->F["Processing Node n"]
end
subgraph internal_chain ["Internal Chain (For Compatible Scripts)"]
H["..."]-->I["Processing Node n"]
end
Merge Processing
Section titled “Merge Processing”This processing node provides configuration merging functionality similar to OpenClash. It achieves this by defining the following rules for overwriting configurations.
Merge Rules
Section titled “Merge Rules”append__x.y.z- Appends the content of thex.y.zfield to the end of the originalx.y.zlist. Ifx.y.zdoes not exist or is not an array, it will be ignored, and a log warning will be triggered.prepend__x.y.z- Adds the content of thex.y.zfield to the beginning of the originalx.y.zlist. Ifx.y.zdoes not exist or is not an array, it will be ignored, and a log warning will be triggered.override__x.y.z- Directly overrides the content of thex.y.zfield. Ifx.y.zdoes not exist, it will be ignored, and a log warning will be triggered.filter__x.y.z- Filters or modifies the content of thex.y.zfield. For supported types, refer tofilterSupported Operations.- Other fields - Fields are recursively merged and will not directly overwrite the original configuration.
More examples can be found in the Merge Unit Test Cases.
filter Supported Operations
Section titled “filter Supported Operations”Filtering Lists
Section titled “Filtering Lists”The filter__x.y.z: string operation filters a list using a Lua expression where item represents the current element. The expression must return a bool. If the expression encounters an error, a log warning will be triggered.
Here is an example of removing trojan proxies:
filter__proxies: | item.type ~= 'trojan'Modifying Lists Using Expressions
Section titled “Modifying Lists Using Expressions”This operation is similar to the map operation in other languages. It modifies matched items using the expr expression. The syntax is as follows:
filter__x.y.z: when: string # Lua expression, where item is the current element, returns a boolean value expr: string # Lua expression, where item is the current element, returns the modified itemHere’s an example of modifying the port of trojan proxies to 443:
filter__proxies: when: | item.type == 'trojan' expr: | item.port = 443 return itemMerging Fields
Section titled “Merging Fields”This operation is similar to the map operation in other languages, merging matched items using the merge table. The syntax is as follows:
filter__x.y.z: when: string # Lua expression, where item is the current element, returns a boolean value merge: object # Object to be merged recursively, future support for arrays might be consideredHere is an example of adding the icon field to the Spotify proxy group:
filter__proxy-groups: when: | item.name == 'Spotify' merge: icon: "https://example.com/spotify.png"Directly Overwriting Fields
Section titled “Directly Overwriting Fields”This operation is similar to the map operation in other languages but directly overwrites the matched item. The syntax is as follows:
filter__x.y.z: when: string # Lua expression, where item is the current element, returns a boolean value override: any # Value to overrideHere is an example of forcibly overriding the Spotify proxy group:
filter__proxy-groups: when: | item.name == 'Spotify' override: name: "Spotify" type: select proxies: - Proxies - DIRECT - HK - JP - SG - TW - USRemoving Fields
Section titled “Removing Fields”This operation is similar to the map operation in other languages but removes keys from the matched item using the remove field. The syntax is as follows:
filter__x.y.z: when: string # Lua expression, where item is the current element, returns a boolean value remove: Array<string | int> # List of keys to remove. Keys are strings for objects and numbers for arrays.Here’s an example of removing the first proxy from the proxies field of the Spotify proxy group:
filter__proxy-groups: when: | item.name == 'Spotify' remove: - proxies.0Chained Operations
Section titled “Chained Operations”The filter operation supports list types, where each element is a filter operation. This allows for chained processing of multiple operations.
Here’s an example that adds the icon field to both the Spotify and Netflix proxy groups:
filter__proxy-groups: - when: | item.name == 'Spotify' merge: icon: "https://example.com/spotify.png" - when: | item.name == 'Netflix' merge: icon: "https://example.com/netflix.png"Script Processing
Section titled “Script Processing”JavaScript Node
Section titled “JavaScript Node”This processing node currently provides JavaScript processing based on BoaJS, similar to the Mixins or preprocessing feature in CFW.
The script accepts a function with the signature export default function main(config: ClashConfig): ClashConfig, where ClashConfig is the Clash configuration type. The return value of the script will be used as the final configuration.
Here’s an example of adding rules through a script:
export default function main(config) { const rules = ["DOMAIN-SUFFIX,google.com,PROXY", "DOMAIN,example.org,PROXY"]; config.rules = [...config.rules, ...rules]; return config;}Lua Processing Node
Section titled “Lua Processing Node”This processing node provides Lua scripting functionality based on mlua, compatible with Lua 5.4 syntax, and includes a secure standard library preset.
The processing module exposes a config variable that contains the current Clash configuration. Users can modify the config variable, and the result will be used as the final configuration.
Here’s an example of adding rules through a Lua script:
local rules = { 'DOMAIN-SUFFIX,google.com,PROXY', 'DOMAIN,example.org,PROXY',}
for _, rule in ipairs(rules) do table.insert(config.rules, rule)end
return config