@gozargah/xray-schema 0.0.3

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.
@@ -0,0 +1,2894 @@
1
+ import z from "zod";
2
+ //#endregion
3
+ //#region src/transport/version/version.ts
4
+ const versionSchema = z.object({
5
+ min: z.string().optional(),
6
+ max: z.string().optional()
7
+ }).meta({ markdownDescription: "Controls the version on which this config can run. This prevents accidental running on unexpected client versions when sharing the config. The client will check if the current version matches this requirement at runtime.\n\nBoth `min` and `max` are optional. Not setting them or leaving them empty means no restrictions. It does not need to be an actual existing version, as long as it complies with the Xray version syntax x.y.z.\n\n**25.8.3** is the version where Xray added this feature. Setting a version lower than this is meaningless (older versions will not check it).\n\n[Documentation ↗](https://xtls.github.io/en/config/version.html)\n" });
8
+ //#endregion
9
+ //#region src/log/log.ts
10
+ const logSchema = z.object({
11
+ access: z.union([z.string(), z.literal("none")]).default("").optional().meta({ markdownDescription: "The file path for the access log.\n\nIts value must be a valid file path, such as\n\n- `\"/var/log/Xray/access.log\"` (Linux)\n- `\"C:\\\\Temp\\\\Xray\\\\_access.log\"` (Windows)\n\nWhen this item is unspecified or empty, logs are output to stdout.\n\nSpecial value `none`: disables the access log.\n" }),
12
+ error: z.union([z.string(), z.literal("none")]).optional().default("").optional().meta({ markdownDescription: "The file path for the error log.\n\nIts value must be a valid file path, such as\n\n- `\"/var/log/Xray/error.log\"` (Linux)\n- `\"C:\\\\Temp\\\\Xray\\\\_error.log\"` (Windows).\n\nWhen this item is unspecified or empty, logs are output to stdout.\n\nSpecial value `none`: disables the error log.\n" }),
13
+ loglevel: z.enum([
14
+ "debug",
15
+ "info",
16
+ "warning",
17
+ "error",
18
+ "none"
19
+ ]).default("warning").optional().meta({ markdownDescription: "The level of the error log, indicating the information that needs to be recorded. The default value is `\"warning\"`.\n\n- `\"debug\"`: Output information used for debugging. Includes all \"info\" content.\n- `\"info\"`: Runtime status information, etc., which does not affect normal usage. Includes all `\"warning\"` content.\n- `\"warning\"`: Information output when issues occur that do not affect normal operation but may impact user experience. Includes all `\"error\"` content.\n- `\"error\"`: Xray encountered a problem where it cannot operate normally and requires immediate resolution.\n- `\"none\"`: Do not record any content.\n" }),
20
+ dnsLog: z.boolean().optional().default(false).meta({ markdownDescription: "Whether to enable DNS query logs, for example: `DOH//doh.server got answer: domain.com -> [ip1, ip2] 2.333ms`\n" }).optional(),
21
+ maskAddress: z.union([
22
+ z.literal(""),
23
+ z.enum([
24
+ "quarter",
25
+ "half",
26
+ "full"
27
+ ]),
28
+ z.string().regex(/^\/(?:0|8|16|24|32)\+\/(?:12[0-8]|1[01][0-9]|[0-9]{1,2})$/)
29
+ ]).default("").optional().meta({ markdownDescription: "IP address mask. When enabled, it automatically replaces IP addresses appearing in the log to protect privacy when sharing logs.\n\nThe default is `'empty'` (disabled).\n\nCurrently, the available levels are `'quarter'`, `'half'`, and `'full'`.\n\nThe masking formats correspond as follows:\n\n- ipv4: `1.2.*.*` , `1.*.*.*` , `[Masked IPv4]`\n- ipv6: `1234:5678::/32` , `1234::/16` , `[Masked IPv6]`\n\nFor more specific requirements, you can use a custom format such as `/16+/32`. The format defines the number of bits to keep unmasked; the first number is for IPv4 and the second for IPv6. Note that the IPv4 value must be divisible by 8. Using /32 (IPv4) or /128 (IPv6) means no masking, while /0 will display as `[Masked IPv4/IPv6]`.\n\nHelp us improve this page on GitHub!\n" })
30
+ }).meta({ markdownDescription: "Log configuration controls how Xray outputs logs.\n\nXray has two types of logs:\n\n1. access logs\n2. error logs\n\nYou can configure the output method for each type independently.\n\n[Documentation ↗](https://xtls.github.io/en/config/log.html)\n" });
31
+ //#endregion
32
+ //#region src/api/api.md?raw
33
+ var api_default = "The API interface configuration provides [gRPC](https://grpc.io/)-based API interfaces for remote procedure calls.\n\nYou can enable the interface through the `api` configuration module. When the `api` configuration is enabled, Xray will automatically build an outbound proxy with the same name as the `tag`. You must manually route all API inbound connections to this outbound proxy via [Routing Configuration](https://xtls.github.io/en/config/routing.html). Please refer to [Relevant Configuration](https://xtls.github.io/en/config/api.html#relevant-configuration) in this section.\n\nSince [v1.8.12](https://github.com/XTLS/Xray-core/releases/tag/v1.8.12), a simplified configuration mode is supported. You only need to configure the ApiObject, without needing to configure `inbounds` and `routing`. However, when using the simplified configuration, the traffic statistics feature does not count the traffic of API inbound connections.\n\n[Documentation ↗](https://xtls.github.io/en/config/api.html)\n";
34
+ //#endregion
35
+ //#region src/api/listen.md?raw
36
+ var listen_default$1 = "The IP and port for the API service to listen on. This is an optional configuration item.\n\nIf this item is omitted, you need to add `inbounds` and `routing` configurations according to the example in [Relevant Configuration](https://xtls.github.io/en/config/api.html#relevant-configuration) below.\n";
37
+ //#endregion
38
+ //#region src/api/api.ts
39
+ const apiServices = z.union([
40
+ z.literal("HandlerService").meta({ markdownDescription: "APIs for modifying inbound and outbound proxies. Available functions are as follows:\n\n- Add a new inbound;\n- Add a new outbound;\n- Remove an existing inbound;\n- Remove an existing outbound;\n- List outbounds;\n- List inbounds;\n- Add a user to an inbound (supports VMess, VLESS, Trojan, Shadowsocks only);\n- Remove a user from an inbound (supports VMess, VLESS, Trojan, Shadowsocks only);\n" }),
41
+ z.literal("RoutingService").meta({ markdownDescription: "APIs for adding, removing, replacing routing rules, and querying balancer statistics. Available functions are as follows:\n\n- `adrules`: Add or replace routing configuration\n- `rmrules`: Remove routing rules\n- `sib`: Disconnect connections from a source IP\n- `bi`: Query balancer statistics\n- `bo`: Force balancer to select a specific `outboundTag`\n You can use commands like `./xray help api` bi to query specific usage.\n" }),
42
+ z.literal("LoggerService").meta({ markdownDescription: `Supports restarting the built-in Logger, which can be used with \`logrotate\` to perform operations on log files.` }),
43
+ z.literal("StatsService").meta({ markdownDescription: `Built-in data statistics service. See [Statistics](https://xtls.github.io/en/config/stats.html) for details.` }),
44
+ z.literal("ReflectionService").meta({ markdownDescription: `Allows gRPC clients to retrieve the list of APIs on the server.` })
45
+ ]);
46
+ const apiSchema = z.object({
47
+ tag: z.string().meta({ markdownDescription: "The identifier of the outbound proxy." }),
48
+ listen: z.string().optional().meta({ markdownDescription: listen_default$1 }),
49
+ services: z.array(apiServices).optional().meta({
50
+ uniqueItems: true,
51
+ markdownDescription: `The list of enabled APIs. See [API List](https://xtls.github.io/en/config/api.html#supported-api-list) for available values.`
52
+ })
53
+ }).meta({ markdownDescription: api_default });
54
+ //#endregion
55
+ //#region src/dns/dns.md?raw
56
+ var dns_default$1 = "Built-in DNS server. If this item is not configured, the system DNS settings are used.\n\nThe built-in DNS module in Xray has three main purposes:\n\n- **Routing Phase:** Resolves domain names to IPs and matches rules based on the resolved IPs for traffic splitting. Whether to resolve the domain and split traffic depends on the `domainStrategy` setting in the routing configuration module. The built-in DNS server is used for DNS queries only when the following two values are set:\n - `\"IPIfNonMatch\"`: When a domain is requested, Xray attempts to match it against the `domain` rules in the routing configuration. If no match is found, the built-in DNS server is used to resolve the domain, and the returned IP address is used to match against IP routing rules.\n - `\"IPOnDemand\"`: When any IP-based rule is encountered during matching, the domain is immediately resolved to an IP for matching.\n\n- **Resolving Target Addresses for Connections:**\n - For example, in a `freedom` outbound, if `domainStrategy` is set to `UseIP`, requests sent from this outbound will first resolve the domain to an IP using the built-in server before connecting.\n - For example, in `sockopt`, if `domainStrategy` is set to `UseIP`, system connections initiated by this outbound will first resolve to an IP using the built-in server before connecting.\n\n- **TUN/Transparent Proxy DNS Traffic Hijacking:** Combines routing with the DNS outbound to hijack DNS traffic into this module; or directly exposes port 53 to act as a recursive DNS server.\n\n#### TIP 1\n\nThe DNS server enters the routing system for matching by default unless it contains `+local`. When using domain names within it, be aware of potential routing loops; `hosts` may help.\n\n#### TIP 2\n\nOnly basic IP queries (A and AAAA records) are supported. CNAME records will be queried repeatedly until an A/AAAA record is returned. Other queries will not enter the built-in DNS server; instead, they may be discarded or transparently forwarded to other servers depending on your outbound configuration.\n\n## DNS Processing Flow\n\nThe domain first undergoes a Hosts mapping check (see the `hosts` field). If the required IP is not found, the DNS server is used for the query.\n\nThe core then begins to build a list of servers, sorting them according to the requested domain based on the following rules.\n\n- Build List 1: Contains servers where the `domains` field successfully matches the requested domain, in the order they appear in the configuration file.\n- Check `disableFallback`: If true, skip building List 2.\n- Check `disableFallbackIfMatch`: If true and List 1 is not empty, skip building List 2.\n- Build List 2: Contains servers not in List 1 where `skipFallback` is not true, in the order they appear in the configuration file.\n- Final Server List = List 1 + List 2.\n\nNote: Any DNS server with `FinalQuery` set to true will directly truncate the subsequent parts of the list.\n\nWhen executing a DNS query, the core will query the servers in the Final Server List sequentially. It filters the results using `expectedIPs` and `unexpectedIPs`; if the result is empty after filtering, it attempts the next server in the list. (Behavior differs slightly when `enableParallelQuery` is true; see its field description for details.)\n\n[Documentation ↗](https://xtls.github.io/en/config/dns.html)\n";
57
+ //#endregion
58
+ //#region src/dns/hosts.md?raw
59
+ var hosts_default = "## A static IP mapping. The value consists of entries in the form `\"domain\": \"address\"` or `\"domain\": [\"address 1\", \"address 2\"]`. Each address may be an IP or a domain name. When resolving a domain, the core will check all mapping entries and return all matched IP addresses. If nothing matches, the DNS query phase is entered.\n\n## The mapping target may be a domain name. When the core finishes matching and the mapping contains domain name(s), the behavior is slightly different:\n\n- If the mapping contains both IP addresses and domain names, the domain names are removed and only the IP addresses are returned.\n- If the mapping contains several domain names, the result is ambiguous: the match fails, is treated as a miss, and the DNS query phase is entered.\n- If the mapping contains exactly one domain name, that domain will be fed back into the Hosts module for recursive resolution, repeating the above steps with a maximum recursion depth of 5.\n- If the above recursive resolution yields no IPs, and the final resolution result contains exactly one domain name, that domain replaces the original requested domain and is sent to the DNS query phase.\n\n---\n\nThe matching format (`domain:`, `full:`, etc.) is the same as the domain in the commonly used [Routing System](https://xtls.github.io/en/config/routing.html#ruleobject). The difference is that without a prefix, it defaults to using the `full:` prefix (similar to the common hosts file syntax).\n";
60
+ //#endregion
61
+ //#region src/dns/servers.md?raw
62
+ var servers_default = "A list of DNS servers. Two types are supported: DNS address (string format) and [DnsServerObject](https://xtls.github.io/en/config/dns.html#dnsserverobject).\n\n## When the value is `\"localhost\"`, it indicates using the local machine's preset DNS configuration.\n\n## When the value is a DNS `\"IP:Port\"` address, such as `\"8.8.8.8:53\"`, Xray will use the specified UDP port of this address for DNS queries. The query follows routing rules. If no port is specified, port 53 is used by default.\n\n## When the value is in the form of `\"tcp://host:port\"`, such as `\"tcp://8.8.8.8:53\"`, Xray will use `DNS over TCP` for queries. The query follows routing rules. If no port is specified, port 53 is used by default.\n\n## When the value is in the form of `\"tcp+local://host:port\"`, such as `\"tcp+local://8.8.8.8:53\"`, Xray will use `TCP Local Mode (TCPL)` for queries. This means the DNS request will **not** pass through the routing component but will request directly via the Freedom outbound to reduce latency. If no port is specified, port 53 is used by default.\n\n## When the value is in the form of `\"https://host:port/dns-query\"`, such as `\"https://dns.google/dns-query\"`, Xray will use `DNS over HTTPS` (RFC8484, abbreviated as DOH) for queries. Some providers have certificates for IP aliases, so you can write the IP directly, such as `https://1.1.1.1/dns-query`. Non-standard ports and paths can also be used, such as `\"https://a.b.c.d:8443/my-dns-query\"`.\n\n## When the value is in the form of `\"h2c://host:port/dns-query\"`, such as `\"h2c://dns.google/dns-query\"`, Xray will use the `DNS over HTTPS` request format but will send the request in cleartext h2c. This cannot be used directly; in this case, you need to configure a Freedom outbound + streamSettings with TLS to wrap it into a normal DOH request. This is used for special purposes, such as customizing the SNI of DOH requests or using utls fingerprints.\n\n## When the value is in the form of `\"https+local://host:port/dns-query\"`, such as `\"https+local://dns.google/dns-query\"`, Xray will use `DOH Local Mode (DOHL)` for queries. This means the DOH request will **not** pass through the routing component but will request directly via the Freedom outbound to reduce latency. Generally suitable for server-side use. Non-standard ports and paths can also be used.\n\n## When the value is in the form of `\"quic+local://host\"`, such as `\"quic+local://dns.adguard.com\"`, Xray will use `DNS over QUIC Local Mode (DOQL)` for queries. This means the DNS request will **not** pass through the routing component but will request directly via the Freedom outbound. This method requires the DNS server to support DNS over QUIC. By default, port 853 is used for queries, and non-standard ports can be used.\n\n## When the value is `fakedns`, the FakeDNS feature will be used for queries.\n\n### TIP 1\n\nWhen using `localhost`, the local machine's DNS requests are not controlled by Xray. Additional configuration is required to forward DNS requests through Xray.\n\n### TIP 2\n\nThe DNS clients initialized by different rules will be shown in the Xray startup logs at the `info` level, such as `local DOH`, `remote DOH`, and `udp` modes.\n\n### TIP 3\n\n(v1.4.0+) You can enable DNS query logging in [Log](./log.md).\n";
63
+ //#endregion
64
+ //#region src/dns/clientIp.md?raw
65
+ var clientIp_default = "## The IP address used in the EDNS Client Subnet extension.\n\nMust be a valid IPv4 or IPv6 address. When actually sent, the last few bits will be automatically masked; IPv4 and IPv6 are sent with /24 and /96 subnets respectively.\n";
66
+ //#endregion
67
+ //#region src/dns/queryStrategy.md?raw
68
+ var queryStrategy_default$1 = "## Limits the capabilities of all servers in the DNS module and sets the default value for IP query types initiated by Xray itself.\n\n## The default value `UseIP` allows querying both A + AAAA records. When a query initiated by Xray itself does not specify an IP type, both A and AAAA records are queried from the upstream DNS server. `UseIPv4` only queries and allows querying A records; `UseIPv6` only queries and allows querying AAAA records.\n\n## `UseSystem` adapts to the operating system's network environment. Before querying, it checks whether there are IPv4 and IPv6 default gateways, thereby limiting the capabilities of all servers and setting the default query type. It checks in real-time on graphical OS environments and only once on command-line environments.\n\n---\n\n### TIP 1\n\n## The global `\"queryStrategy\"` value takes precedence. When the `\"queryStrategy\"` value in a sub-item conflicts with the global `\"queryStrategy\"` value, the query for that sub-item will return an empty response.\n\n### TIP 2\n\n## When the `\"queryStrategy\"` parameter is not written in a sub-item, the global `\"queryStrategy\"` parameter value is used. This behavior is the same as versions prior to Xray-core v1.8.6.\n\nFor example:<br>\nGlobal `\"queryStrategy\": \"UseIPv6\"` conflicts with sub-item `\"queryStrategy\": \"UseIPv4\"`.<br>\nGlobal `\"queryStrategy\": \"UseIPv4\"` conflicts with sub-item `\"queryStrategy\": \"UseIPv6\"`.<br>\nGlobal `\"queryStrategy\": \"UseIP\"` does not conflict with sub-item `\"queryStrategy\": \"UseIPv6\"`.<br>\nGlobal `\"queryStrategy\": \"UseIP\"` does not conflict with sub-item `\"queryStrategy\": \"UseIPv4\"`.\n\n---\n\n---\n\nThe sub-item query for the Netflix domain returns an empty response due to the conflicting `\"queryStrategy\"` value. The Netflix domain is then queried by `https://1.1.1.1/dns-query`, returning an A record.\n";
69
+ //#endregion
70
+ //#region src/dns/tag.md?raw
71
+ var tag_default$3 = "For query traffic generated by the built-in DNS, except for localhost, fakedns, TCPL, DOHL, and DOQL modes, this tag can be used in routing for matching via inboundTag.\n";
72
+ //#endregion
73
+ //#region src/dns/disableCache.md?raw
74
+ var disableCache_default = "`true` disables DNS caching. Defaults to `false` (not disabled).\n\nThis does not affect `localhost` DNS (system DNS), which always follows Golang's DNS caching behavior (cgo and pure go may differ slightly).\n";
75
+ //#endregion
76
+ //#region src/dns/disableFallback.md?raw
77
+ var disableFallback_default = "`true` disables DNS fallback queries. Defaults to `false` (not disabled).\n";
78
+ //#endregion
79
+ //#region src/dns/disableFallbackIfMatch.md?raw
80
+ var disableFallbackIfMatch_default = "`true` disables fallback queries when the DNS server's priority domain list is matched. Defaults to `false` (not disabled).\n";
81
+ //#endregion
82
+ //#region src/dns/useSystemHosts.md?raw
83
+ var useSystemHosts_default = "If true, appends the system hosts file to the built-in DNS hosts.\n";
84
+ //#endregion
85
+ //#region src/dns/enableParallelQuery.md?raw
86
+ var enableParallelQuery_default = "`true` enables parallel queries. Defaults to `false` (not enabled).\n\nDNS failover is serial by default, meaning a query is sent to the next server only after the selected DNS server fails or `expectedIPs` and `unexpectedIPs` do not match.\n\nWhen parallel query is enabled, queries are initiated asynchronously to all selected DNS servers in advance, executing a strategy of \"dynamic grouping, intra-group racing, and inter-group fallback\".\n\n**Dynamic Grouping**: Adjacent servers in the selected server list are considered the same group if their `clientIP`, `skipFallback`, `queryStrategy`, `tag`, `domains`, `expectedIPs`, and `unexpectedIPs` are **exactly** the same.\n\n**Intra-group Racing**: If any DNS server in the same group queries successfully and the IP matches `expectedIPs` and `unexpectedIPs`, the group is considered successful, and results from other servers in the group are ignored.\n\n**Inter-group Fallback**: If the first group is still querying, wait. If the first group succeeds, return the IP. If all servers in the first group fail or IPs do not match, fallback to the next group. Finally, if all groups fail, return an empty resolution.\n\n> `useSystemHosts`: true | false\n\nIf true, appends the system hosts file to the built-in DNS hosts.\n\n> `tag`: string\n\nFor query traffic generated by the built-in DNS, except for `localhost`, `fakedns`, `TCPL`, `DOHL`, and `DOQL` modes, this tag can be used in routing for matching via `inboundTag`.\n";
87
+ //#endregion
88
+ //#region src/dns/serveStale.md?raw
89
+ var serveStale_default = "`true` enables DNS optimistic caching. Defaults to `false` (not enabled).\n\nOnly effective when the server has DNS caching enabled (i.e., this option is constrained by `disableCache`).\n";
90
+ //#endregion
91
+ //#region src/dns/serveExpiredTTL.md?raw
92
+ var serveExpiredTTL_default = "Validity period for optimistic caching in seconds. Defaults to 0, meaning it never expires.\n\nIf the server has caching enabled and optimistic caching is turned on: when the cache has expired but the optimistic cache has not, the stale DNS record in the cache is returned immediately, and the cache is refreshed in the background. This can reduce latency.\n";
93
+ //#endregion
94
+ //#region src/dns/dnsObject/dnsObject.ts
95
+ const dnsObject = z.object({
96
+ address: z.string().meta({ markdownDescription: "## When the value is `\"localhost\"`, it indicates using the local machine's preset DNS configuration.\n\n## When the value is a DNS `\"IP\"` address, such as `\"8.8.8.8\"`, Xray will use the specified UDP port of this address for DNS queries. The query follows routing rules. Defaults to port 53.\n\n## When the value is in the form of `\"tcp://host\"`, such as `\"tcp://8.8.8.8\"`, Xray will use `DNS over TCP` for queries. The query follows routing rules. Defaults to port 53.\n\n## When the value is in the form of `\"tcp+local://host\"`, such as `\"tcp+local://8.8.8.8\"`, Xray will use `TCP Local Mode (TCPL)` for queries. This means the DNS request will **not** pass through the routing component but will request directly via the Freedom outbound to reduce latency. If no port is specified, port 53 is used by default.\n\n## When the value is in the form of `\"https://host:port/dns-query\"`, such as `\"https://dns.google/dns-query\"`, Xray will use `DNS over HTTPS` (RFC8484, abbreviated as DOH) for queries. Some providers have certificates for IP aliases, so you can write the IP directly, such as `https://1.1.1.1/dns-query`. Non-standard ports and paths can also be used, such as `\"https://a.b.c.d:8443/my-dns-query\"`.\n\n## When the value is in the form of `\"https+local://host:port/dns-query\"`, such as `\"https+local://dns.google/dns-query\"`, Xray will use `DOH Local Mode (DOHL)` for queries. This means the DOH request will **not** pass through the routing component but will request directly via the Freedom outbound to reduce latency. Generally suitable for server-side use. Non-standard ports and paths can also be used.\n\n## When the value is in the form of `\"quic+local://host:port\"`, such as `\"quic+local://dns.adguard.com\"`, Xray will use `DOQ Local Mode (DOQL)` for queries. This means the DNS request will **not** pass through the routing component but will request directly via the Freedom outbound. This method requires the DNS server to support DNS over QUIC. By default, port 853 is used for queries, and non-standard ports can be used.\n\n## When the value is `fakedns`, the FakeDNS feature will be used for queries.\n\n### About Local Mode and the Domain of the DNS Server Itself\n\n## There are two scenarios for DNS requests sent by the DNS module:\n\n## **Local Mode** connections are made directly outwards by the core. In this case, if the address is a domain name, it will be resolved by the system itself. The logic is relatively simple.\n\n## **Non-Local** modes will essentially be treated as requests coming from an inbound with the tag `dns.tag` (Don't know where it is? Ctrl+F in your browser to search for `inboundTag`). They will go through the normal core processing flow and may be assigned by the routing module to a local freedom or other remote outbounds. They will be resolved by the freedom's `domainStrategy` (beware of potential loops) or sent directly as domains to the remote end to be resolved according to the server's own resolution method.\n\n## Since it might be difficult for average users to clarify the logic involved, it is recommended (especially in a transparent proxy environment) to **directly set the corresponding IPs for servers with domain names in the host option of the DNS module** to prevent loops.\n\nIncidentally, DNS requests sent by the DNS module in non-local modes will automatically skip the `IPIfNonMatch` and `IPOnDemand` resolution processes in the routing module. This prevents their resolution from being sent back to the DNS module, causing a loop.\n" }),
97
+ port: z.number().optional().meta({ markdownDescription: "DNS server port, e.g., `53`. Defaults to `53` if omitted. This item is invalid when using DOH, DOHL, or DOQL modes; non-standard ports should be specified in the URL.\n" }),
98
+ domains: z.array(z.string()).optional().meta({ markdownDescription: "A list of domains. Domains included in this list will prioritize using this server for queries. The domain format is the same as in [Routing Configuration](https://xtls.github.io/en/config/routing.html#ruleobject).\n" }),
99
+ expectedIPs: z.array(z.string()).optional().meta({ markdownDescription: "A list of IP ranges. The format is the same as in [Routing Configuration](https://xtls.github.io/en/config/routing.html#ruleobject).\n\nWhen configured, Xray DNS will verify the returned IP and only return addresses included in the `expectedIPs` list.\n\nIf `*` exists in the list, and if no IP exists after filtering, the original IP is still returned so that the request does not fail.\n" }),
100
+ unexpectedIPs: z.array(z.string()).optional().meta({ markdownDescription: "The reverse version of `expectedIPs`. IPs included in this list are removed. The asterisk works the same way.\n" }),
101
+ skipFallback: z.boolean().default(false).optional().meta({ markdownDescription: "`true`: Skip this server during DNS fallback queries. Defaults to `false` (not skipped).\n" }),
102
+ finalQuery: z.boolean().default(false).optional().meta({ markdownDescription: "If set to true, the request to this DNS server will be the final attempt and will not trigger fallback behavior.\n" }),
103
+ tag: z.string().optional(),
104
+ clientIP: z.string().optional(),
105
+ queryStrategy: z.enum([
106
+ "UseIP",
107
+ "UseIPv4",
108
+ "UseIPv6",
109
+ "UseSystem"
110
+ ]).default("UseIP").optional().meta({ markdownDescription: "If not specified, it inherits from the global configuration; if specified, it allows further limiting the capabilities of this server and setting the default value for IP query types initiated by Xray itself.\n\nNote: It is always constrained by the global `queryStrategy`.\n\n### The following configuration items, if not specified, will inherit from the global configuration, or can override the global configuration here\n" }),
111
+ disableCache: z.boolean().default(false).optional()
112
+ });
113
+ //#endregion
114
+ //#region src/dns/dns.ts
115
+ const dnsSchema = z.object({
116
+ hosts: z.record(z.string(), z.union([z.string(), z.array(z.string())])).optional().meta({ markdownDescription: hosts_default }),
117
+ servers: z.array(z.union([z.string(), dnsObject])).optional().meta({ markdownDescription: servers_default }),
118
+ tag: z.string().optional().meta({ markdownDescription: tag_default$3 }),
119
+ clientIP: z.string().optional().meta({ markdownDescription: clientIp_default }),
120
+ queryStrategy: z.enum([
121
+ "UseIP",
122
+ "UseIPv4",
123
+ "UseIPv6",
124
+ "UseSystem"
125
+ ]).default("UseIP").optional().meta({ markdownDescription: queryStrategy_default$1 }),
126
+ disableCache: z.boolean().default(false).optional().meta({ markdownDescription: disableCache_default }),
127
+ disableFallback: z.boolean().default(false).optional().meta({ markdownDescription: disableFallback_default }),
128
+ disableFallbackIfMatch: z.boolean().default(false).optional().meta({ markdownDescription: disableFallbackIfMatch_default }),
129
+ useSystemHosts: z.boolean().default(false).optional().meta({ markdownDescription: useSystemHosts_default }),
130
+ enableParallelQuery: z.boolean().default(false).optional().meta({ markdownDescription: enableParallelQuery_default }),
131
+ serveStale: z.boolean().default(false).optional().meta({ markdownDescription: serveStale_default }),
132
+ serveExpiredTTL: z.number().default(0).optional().meta({ markdownDescription: serveExpiredTTL_default })
133
+ }).loose().meta({ markdownDescription: dns_default$1 });
134
+ //#endregion
135
+ //#region src/routing/routing.md?raw
136
+ var routing_default = "The routing module can send inbound data through different outbound connections based on different rules, achieving the purpose of on-demand proxying.\n\nA common usage is splitting traffic between domestic and foreign destinations. Xray can determine the region of the traffic through internal mechanisms and then send them to different outbound proxies.\n\nFor a more detailed analysis of the routing function: [Analysis of Routing (Part 1)](https://xtls.github.io/en/document/level-1/routing-lv1-part1.html).\n\n[Documentation ↗](https://xtls.github.io/en/config/routing.html)\n";
137
+ //#endregion
138
+ //#region src/routing/domainStrategy.md?raw
139
+ var domainStrategy_default$1 = "Domain resolution strategy. Different strategies are used based on different settings.\n\n- `\"AsIs\"`: No extra operation. Uses the domain in the destination address or the sniffed domain. Default value.\n- `\"IPIfNonMatch\"`: When no rule is matched after a full round of matching, resolve the domain to an IP and perform a second round of matching.\n- `\"IPOnDemand\"`: Before starting matching, resolve the domain to an IP immediately for matching.\n\nActual resolution behavior will be delayed until the first IP rule is encountered to reduce latency. The result will contain both IPv4 and IPv6 (you can further restrict this via `queryStrategy` in the built-in DNS). When a domain resolves to multiple IPs, each rule will try all IPs in turn. If any IP meets the requirement, the rule is considered matched.\n\nWhen `sniff` + `routeOnly` is enabled, allowing the routing system to see both IP and domain, if the aforementioned resolution occurs, the routing system can only see the IP resolved from the domain and cannot see the original destination IP, unless resolution fails.\n\nWhen two domains exist (target domain + sniffed result), the priority of the sniffed result is always higher, whether for resolution or domain matching.\n\nRegardless of whether resolution occurs, the routing system will not affect the actual destination address. The requested target remains the original target.\n";
140
+ //#endregion
141
+ //#region src/routing/rules.md?raw
142
+ var rules_default = "## Corresponds to an array, where each item is a rule.\n\n## For each connection, routing will judge these rules from top to bottom. When the first effective rule is encountered, the connection is forwarded to the `outboundTag` or `balancerTag` specified by it.\n\nWhen no rule is matched, traffic is sent via the first outbound by default.\n";
143
+ //#endregion
144
+ //#region src/routing/balancers.md?raw
145
+ var balancers_default = "An array, where each item is a load balancer configuration.\n\nWhen a rule points to a load balancer, Xray will select an outbound through this load balancer and then forward traffic using it.\n";
146
+ //#endregion
147
+ //#region src/routing/ruleObject/domain.md?raw
148
+ var domain_default$1 = "- **Pure string**: Same as substring below, but the `\"keyword:\"` prefix can be omitted.\n\n---\n\n- **Regular expression**: Starts with `\"regexp:\"`, the rest is a regular expression. The rule takes effect when the regular expression matches the target domain. For example, \"regexp:\\\\.goo.\\*\\\\.com$\" matches \"www.google.com\" and \"fonts.googleapis.com\", but not \"google.com\". Case sensitive.\n\n---\n\n- **Subdomain (Recommended)**: Starts with `\"domain:\"`, the rest is a domain name. The rule takes effect when the domain is the target domain or its subdomain. For example, \"domain:xray.com\" matches \"www.xray.com\" and \"xray.com\", but not \"wxray.com\".\n\n---\n\n- **Substring**: Starts with `\"keyword:\"`, the rest is a string. The rule takes effect when this string matches any part of the target domain. For example, \"keyword:sina.com\" matches \"sina.com\", \"sina.com.cn\", and \"www.sina.com\", but not \"sina.cn\".\n\n---\n\n- **Full match**: Starts with `\"full:\"`, the rest is a domain name. The rule takes effect when this domain exactly matches the target domain. For example, \"full:xray.com\" matches \"xray.com\" but not \"www.xray.com\".\n\n---\n\n- **Dotless domain**: Starts with `\"dotless:\"`, the rest is a string that cannot contain .. The rule takes effect when the domain contains no `.` and this string matches any part of the target domain. For example, \"dotless:pc-\" matches \"pc-alice\", \"mypc-alice\". Suitable for intranet NetBIOS domains, etc. Case sensitive.\n\n---\n\n- **Predefined domain list**: Starts with `\"geosite:\"`, the rest is a name, such as `geosite:google` or `geosite:cn`. Refer to Predefined Domain List for names and domain lists.\n\n---\n\n- **Load domains from file**: In the form of `\"ext:file:tag\"`. Must start with `ext:` (lowercase), followed by filename and tag. The file is stored in the [Resource Directory](https://xtls.github.io/en/config/features/env.html#resource-file-path). The file format is the same as `geosite.dat`, and the tag must exist in the file.\n\n---\n\n- `\"ext:geoip.dat:cn\"` is equivalent to `\"geoip:cn\"`\n";
149
+ //#endregion
150
+ //#region src/routing/ruleObject/ip.md?raw
151
+ var ip_default$1 = "An array, where each item represents an IP range. The rule takes effect when an item matches the target IP. Available forms:\n\n- **IP**: Like `\"127.0.0.1\"`.\n- **[CIDR](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing)**: Like `\"10.0.0.0/8\"`. You can also use `\"0.0.0.0/0\"` or `\"::/0\"` to specify all IPv4 or IPv6.\n- **Predefined IP list**: This list is pre-installed in every Xray installation package, named `geoip.dat`. Usage is like `\"geoip:cn\"`. Must start with `geoip:` (lowercase), followed by a two-character country code. Supports almost all countries with internet access.\n - **Special value**: `\"geoip:private\"`, includes all private addresses, such as `127.0.0.1`.\n- **Load IPs from file**: In the form of `\"ext:file:tag\"`. Must start with `ext:` (lowercase), followed by filename and tag. The file is stored in the [Resource Directory](https://xtls.github.io/en/config/features/env.html#resource-file-path). The file format is the same as `geoip.dat`, and the tag must exist in the file.\n- **Inverse selection `!`**: `\"!10.0.0.0/8\"` means anything not in `10.0.0.0/8`, and `\"!geoip:cn\"` means results not in `geoip:cn`. Multiple inverse options have an `AND` relationship, while positive options, or positive options together with all inverse options, have an `OR` relationship. For example, `ip: [\"!geoip:cn\", \"!geoip:us\", \"geoip:telegram\"]` matches IPs that are not from the US AND not from China, OR are Telegram IPs.\n";
152
+ //#endregion
153
+ //#region src/routing/ruleObject/port.md?raw
154
+ var port_default$1 = "Target port range. Three forms:\n\n- `\"a-b\"`: a and b are positive integers less than 65536. This is a closed interval. The rule takes effect when the target port falls within this range.\n- `a`: a is a positive integer less than 65536. The rule takes effect when the target port is a.\n- A mixture of the above two forms, separated by commas \",\". For example: `\"53,443,1000-2000\"`.\n";
155
+ //#endregion
156
+ //#region src/routing/ruleObject/sourcePort.md?raw
157
+ var sourcePort_default = "Source port. Three forms:\n\n- `\"a-b\"`: a and b are positive integers less than 65536. This is a closed interval. The rule takes effect when the source port falls within this range.\n- `a`: a is a positive integer less than 65536. The rule takes effect when the source port is a.\n- A mixture of the above two forms, separated by commas \",\". For example: `\"53,443,1000-2000\"`.\n";
158
+ //#endregion
159
+ //#region src/routing/ruleObject/network.md?raw
160
+ var network_default$1 = "Optional values are \"tcp\", \"udp\", or \"tcp,udp\". The rule takes effect when the connection method matches.\n\nSince the core obviously only supports TCP and UDP layer 4 protocols, a routing rule containing only `\"network\": \"tcp,udp\"` can be used as a \"catch-all\" to match any traffic. An example usage is placing it at the very end of all routing rules to specify the default outbound when no other rules match (otherwise the core defaults to the first outbound).\n\nOf course, other ways that obviously match any traffic, such as specifying ports 1-65535, have a similar effect.\n";
161
+ //#endregion
162
+ //#region src/routing/ruleObject/sourceIP.md?raw
163
+ var sourceIP_default = "An array, where each item represents an IP range. Forms include IP, CIDR, GeoIP, and loading IPs from a file. The rule takes effect when an item matches the source IP.\n\n---\n\nAlias: `source`\n";
164
+ //#endregion
165
+ //#region src/routing/ruleObject/ruleObject.ts
166
+ const routingRule = z.object({
167
+ domain: z.array(z.string()).optional().meta({ markdownDescription: domain_default$1 }),
168
+ ip: z.array(z.string()).optional().meta({ markdownDescription: ip_default$1 }),
169
+ port: z.union([z.string(), z.number()]).optional().meta({ markdownDescription: port_default$1 }),
170
+ sourcePort: z.union([z.string(), z.number()]).optional().meta({ markdownDescription: sourcePort_default }),
171
+ network: z.enum([
172
+ "tcp",
173
+ "udp",
174
+ "tcp,udp"
175
+ ]).optional().meta({ markdownDescription: network_default$1 }),
176
+ source: z.array(z.string()).optional().meta({ markdownDescription: sourceIP_default }),
177
+ sourceIP: z.array(z.string()).optional().meta({ markdownDescription: sourceIP_default }),
178
+ user: z.array(z.string()).optional().meta({ markdownDescription: "An array, where each item is an email address. The rule takes effect when an item matches the source user.\n\nSimilar to domains, it also supports regex matching starting with `regexp:`. (Similarly, need to replace `\\` with `\\\\`, see explanation in domain section).\n" }),
179
+ vlessRoute: z.string().optional().meta({ markdownDescription: "VLESS inbound allows the client to modify the 7th and 8th bytes of the configured UUID to any bytes. The server routing will use this as `vlessRoute` data, allowing users to customize parts of the server routing based on needs without changing any external fields.\n\n```\n--------------↓↓↓↓------------------\nxxxxxxxx-xxxx-0000-xxxx-xxxxxxxxxxxx\n```\n\nThe configuration uses data after Big-Endian encoding to uint16 (if you don't understand, treat these four digits as a hexadecimal number and convert to decimal). E.g., `0001→1`, `000e→14`, `38b2→14514`. The reason for this is that the syntax here is the same as `port`; you can freely specify many segments for routing just like specifying ports.\n" }),
180
+ inboundTag: z.array(z.string()).optional().meta({ markdownDescription: "An array, where each item is an identifier. The rule takes effect when an item matches the identifier of the inbound protocol.\n" }),
181
+ protocol: z.array(z.string()).optional().meta({ markdownDescription: "An array, where each item represents a protocol. The rule takes effect when a protocol matches the protocol type of the current connection.\n\n- `http` only supports 1.0 and 1.1; h2 is not supported yet (plaintext h2 traffic is also very rare).\n\n---\n\n- `tls` TLS 1.0 ~ 1.3.\n\n---\n\n- `quic` Due to the complexity of this protocol, sniffing may sometimes fail.\n\n---\n\n- `bittorrent` Only has the most basic sniffing; may not work for much encrypted and obfuscated traffic.\n\n---\n\nYou must enable the `sniffing` option in the inbound proxy to sniff the protocol type used by the connection.\n" }),
182
+ attrs: z.record(z.string(), z.unknown()).optional().meta({ markdownDescription: "A JSON object where keys and values are strings. Used to detect HTTP traffic attribute values (due to obvious reasons, only supports 1.0 and 1.1). The rule is matched when HTTP headers contain all specified keys and values contain the specified substrings. Keys are case-insensitive. Values support regular expressions.\n\nIt also supports pseudo-headers like `:method` and `:path` from h2 for matching methods and paths (although these headers do not exist in HTTP/1.1).\n\nFor non-CONNECT methods of HTTP inbounds, `attrs` can be obtained directly. For other inbounds, sniffing must be enabled to obtain these values for matching.\n\nExample:\n\n- Detect HTTP GET: `{\":method\": \"GET\"}`\n- Detect HTTP Path: `{\":path\": \"/test\"}`\n- Detect Content Type: `{\"accept\": \"text/html\"}`\n" }),
183
+ process: z.array(z.string()).optional().meta({ markdownDescription: "If the connection originates from the local machine, match its process. If not from local, it is directly regarded as a match failure. Only supports Windows and Linux.\n\nThis option is an array, where each item has three matching modes.\n\n1. **No slash**: Matches process name.\n2. **Contains slash, does not end with slash**: Matches absolute path.\n3. **Contains slash, ends with slash**: Matches folder; all processes under this folder are considered a match.\n\nNote:\n\n- All options are case-sensitive.\n- On Windows, use backslash `\\` for paths. Here it is uniformly required to use forward slash `/`, e.g., `C:/Windows/System32/curl.exe`, because backslashes are treated as escape characters in JSON, which is inconvenient (unless you choose to double the backslashes, which also works).\n- When matching by process name, the core automatically removes the `.exe` suffix. Similarly, `[\"curl\"]` can match curl on both Linux and Windows. When using absolute paths, the `.exe` suffix cannot be ignored.\n\nSpecial syntax sugar:\n\n- `self/`: Matches the current core process, very useful for avoiding routing loops.\n- `xray/`: Will be replaced by the absolute path where the current core resides, matching all Xray processes started from this binary.\n" }),
184
+ outboundTag: z.string().optional().meta({ markdownDescription: "Corresponds to an outbound identifier.\n" }),
185
+ balancerTag: z.string().optional().meta({ markdownDescription: "## Corresponds to a Balancer identifier.\n\nYou must choose one between `balancerTag` and `outboundTag`. When both are specified, `outboundTag` takes effect.\n" }),
186
+ ruleTag: z.string().optional().meta({ markdownDescription: "Optional. No actual effect, only used to identify the name of this rule.\n\nIf set, information regarding this rule will be output at the Info level when the rule is matched, used for debugging which specific rule was hit.\n" }),
187
+ webhook: z.object({
188
+ url: z.string().meta({ markdownDescription: "The URL to which the notification will be sent. Both standard web addresses and local Unix socket paths are supported.\n\n- `https://api.example.com/alert` — a standard URL for sending notifications via HTTP(S). Used for integration with external web services or APIs.\n- `/var/run/webhook.sock` — sends the notification via a Unix socket, with the POST request directed to the root path `/` of the socket.\n- `/var/run/webhook.sock:/alert` — sends the notification via a Unix socket to a specific endpoint `/alert`. This allows direct integration with local services without using a network interface.\n- `@abstract:/webhook` — abstract socket (lock-free, Linux/Android only).\n- `@@padded:/webhook` — abstract socket with padding for HAProxy compatibility.\n" }),
189
+ deduplication: z.number().optional().meta({ markdownDescription: "The time (in seconds) for event deduplication. If multiple events are triggered within this period, duplicate requests are ignored.\n" }),
190
+ headers: z.object().loose().meta({ markdownDescription: `HTTP request headers.` })
191
+ }).optional()
192
+ }).loose();
193
+ //#endregion
194
+ //#region src/routing/balancerObject/tag.md?raw
195
+ var tag_default$2 = "The identifier of this load balancer, used to match `balancerTag` in `RuleObject`.\n";
196
+ //#endregion
197
+ //#region src/routing/balancerObject/selector.md?raw
198
+ var selector_default = "An array of strings. Each string is used for prefix matching against outbound identifiers. Among the following outbound identifiers: `[ \"a\", \"ab\", \"c\", \"ba\" ]`, `\"selector\": [\"a\"]` will match `[ \"a\", \"ab\" ]`.\n\nGenerally matches multiple outbounds to distribute load among them.\n";
199
+ //#endregion
200
+ //#region src/routing/balancerObject/fallbackTag.md?raw
201
+ var fallbackTag_default = "If all outbounds cannot be connected based on observation results, the outbound specified by this configuration item is used.\n";
202
+ //#endregion
203
+ //#region src/routing/balancerObject/strategyObject/random.md?raw
204
+ var random_default = "Default value. Randomly selects a matched outbound proxy.\n\nThis can optionally use an observatory. If `fallbackTag` is set and an observatory is present, outbounds observed as unavailable will be automatically excluded (those without observation data are assumed to be alive).\n";
205
+ //#endregion
206
+ //#region src/routing/balancerObject/strategyObject/roundRobin.md?raw
207
+ var roundRobin_default = "Selects matched outbound proxies in order.\n\nThis can optionally use an observatory. If `fallbackTag` is set and an observatory is present, outbounds observed as unavailable will be automatically excluded (those without observation data are assumed to be alive).\n";
208
+ //#endregion
209
+ //#region src/routing/balancerObject/strategyObject/leastPing.md?raw
210
+ var leastPing_default = "Selects the matched outbound proxy with the lowest latency based on observation results.\n\nThis strategy must be used with an observatory, and nodes not covered by the observatory will be directly excluded. If all are unavailable and `fallbackTag` is not set, the default outbound will be selected.\n";
211
+ //#endregion
212
+ //#region src/routing/balancerObject/strategyObject/leastLoad.md?raw
213
+ var leastLoad_default = "Selects the most stable outbound proxy based on observation results.\n\nThis strategy must be used with an observatory, and nodes not covered by the observatory will be directly excluded. If all are unavailable and `fallbackTag` is not set, the default outbound will be selected.\n";
214
+ //#endregion
215
+ //#region src/routing/balancerObject/strategyObject/leastLoadSettingsObject.ts
216
+ const costsObject = z.object({
217
+ regexp: z.boolean().default(false).optional().meta({ markdownDescription: `Whether to use regular expressions to select outbound \`Tag\`.` }),
218
+ match: z.string().optional().meta({ markdownDescription: `Matches outbound \`Tag\`.` }),
219
+ value: z.float32().optional().meta({ markdownDescription: `Weight value. The larger the value, the less likely the corresponding node is to be selected.` })
220
+ });
221
+ const leastLoadSettingsObject = z.object({
222
+ expected: z.number().optional().meta({ markdownDescription: `The number of optimal nodes selected by the load balancer. Traffic will be randomly distributed among these nodes.` }),
223
+ maxRTT: z.string().optional().meta({ markdownDescription: `The maximum acceptable RTT duration for speed tests.` }),
224
+ tolerance: z.float32().optional().meta({ markdownDescription: `The maximum acceptable failure rate for speed tests. For example, 0.01 means accepting a 1% failure rate. (Seemingly unimplemented).` }),
225
+ baselines: z.array(z.string()).optional().meta({ markdownDescription: `The maximum acceptable standard deviation duration for RTT speed tests.` }),
226
+ costs: z.array(costsObject).default([]).optional().meta({ markdownDescription: `Optional configuration item. An array to assign weights to all outbounds.` })
227
+ }).meta({ markdownDescription: `The configuration format varies for different load balancing strategies. Currently, only the leastLoad strategy supports this item.` });
228
+ //#endregion
229
+ //#region src/routing/balancerObject/strategyObject/strategyObject.ts
230
+ const strategyObject = z.discriminatedUnion("type", [
231
+ z.object({ type: z.literal("random").meta({ markdownDescription: random_default }) }),
232
+ z.object({ type: z.literal("roundRobin").meta({ markdownDescription: roundRobin_default }) }),
233
+ z.object({ type: z.literal("leastPing").meta({ markdownDescription: leastPing_default }) }),
234
+ z.object({
235
+ type: z.literal("leastLoad").meta({ markdownDescription: leastLoad_default }),
236
+ settings: leastLoadSettingsObject.optional()
237
+ })
238
+ ]);
239
+ //#endregion
240
+ //#region src/routing/balancerObject/balancerObject.ts
241
+ const balancerObject = z.object({
242
+ tag: z.string().optional().meta({ markdownDescription: tag_default$2 }),
243
+ selector: z.array(z.string()).optional().meta({ markdownDescription: selector_default }),
244
+ fallbackTag: z.string().optional().meta({ markdownDescription: fallbackTag_default }),
245
+ strategy: strategyObject
246
+ });
247
+ //#endregion
248
+ //#region src/routing/routing.ts
249
+ const routingSchema = z.object({
250
+ domainStrategy: z.union([
251
+ z.literal("AsIs").meta({ markdownDescription: "No extra operation. Uses the domain in the destination address or the sniffed domain. Default value." }),
252
+ z.literal("IPIfNonMatch").meta({ markdownDescription: "When no rule is matched after a full round of matching, resolve the domain to an IP and perform a second round of matching." }),
253
+ z.literal("IPOnDemand").meta({ markdownDescription: "Before starting matching, resolve the domain to an IP immediately for matching." })
254
+ ]).optional().meta({ markdownDescription: domainStrategy_default$1 }),
255
+ rules: z.array(routingRule).optional().meta({ markdownDescription: rules_default }),
256
+ balancers: z.array(balancerObject).optional().meta({ markdownDescription: balancers_default })
257
+ }).loose().meta({ markdownDescription: routing_default });
258
+ //#endregion
259
+ //#region src/policy/policy.ts
260
+ const policySchema = z.object({
261
+ levels: z.record(z.string(), z.object({
262
+ handshake: z.number().default(4).optional().meta({ markdownDescription: `Handshake time limit when establishing a connection. Unit is seconds. Default value is \`4\`. When an inbound proxy processes a new connection, if the time used during the handshake phase exceeds this time, the connection is interrupted.` }),
263
+ connIdle: z.number().default(300).optional().meta({ markdownDescription: `Connection idle time limit. Unit is seconds. Default value is \`300\`. When an inbound/outbound processes a connection, if no data is transferred (including uplink and downlink data) within the \`connIdle\` time, the connection is interrupted.` }),
264
+ uplinkOnly: z.number().default(2).optional().meta({ markdownDescription: `Time limit after the downlink connection is closed. Unit is seconds. Default value is \`2\`. When the server (such as a remote website) closes the downlink connection, the outbound proxy will interrupt the connection after waiting for the \`uplinkOnly\` time.` }),
265
+ downlinkOnly: z.number().default(5).optional().meta({ markdownDescription: `Time limit after the uplink connection is closed. Unit is seconds. Default value is \`5\`. When the client (such as a browser) closes the uplink connection, the inbound proxy will interrupt the connection after waiting for the \`downlinkOnly\` time.
266
+ ---
267
+ In HTTP browsing scenarios, \`uplinkOnly\` and \`downlinkOnly\` can be set to 0 to improve connection closing efficiency.` }),
268
+ statsUserUplink: z.boolean().default(false).optional().meta({ markdownDescription: `When set to \`true\`, enables uplink traffic statistics for all users of the current level.` }),
269
+ statsUserDownlink: z.boolean().default(false).optional().meta({ markdownDescription: `When set to \`true\`, enables downlink traffic statistics for all users of the current level.` }),
270
+ statsUserOnline: z.boolean().default(false).optional().meta({ markdownDescription: `When set to \`true\`, enables online user count statistics for all users of the current level. (Online criteria: connection activity within 20 seconds).` }),
271
+ bufferSize: z.number().optional().meta({ markdownDescription: "## The internal buffer size for each request, in KB. Note that multiple requests may be carried on the same connection via multiplexing (e.g., when using mux.cool or gRPC). This means that even if they share an underlying connection, their buffer pools are independent.\n\n## When the internal buffer is larger than this value, the next write operation will only be performed after the internal buffer is sent out until it is less than or equal to this value.\n\n## Note that for a UDP request, if a write attempt is made while the buffer is full, the write operation will not be blocked but discarded. If set too low or to 0, it may cause unexpected bandwidth waste.\n\nDefault values:\n\n- On ARM, MIPS, MIPSLE platforms, the default value is `0`.\n- On ARM64, MIPS64, MIPS64LE platforms, the default value is `4`.\n- On other platforms, the default value is `512`.\n\n---\n\nThe default value can be set via the environment variable `XRAY_RAY_BUFFER_SIZE`. Note that the unit in the environment variable is MB (setting the environment variable to 1 is equivalent to setting the config to 1024).\n" })
272
+ })).optional().meta({ markdownDescription: `A set of key-value pairs, where each key is a number in string format (required by JSON), such as \`"0"\`, \`"1"\`, etc. The double quotes cannot be omitted. This number corresponds to the user level. Each value is a [LevelPolicyObject](https://xtls.github.io/en/config/policy.html#levelpolicyobject).` }),
273
+ system: z.object({
274
+ statsInboundUplink: z.boolean().default(false).optional().meta({ markdownDescription: `When set to \`true\`, enables uplink traffic statistics for all inbound proxies.` }),
275
+ statsInboundDownlink: z.boolean().default(false).optional().meta({ markdownDescription: `When set to \`true\`, enables downlink traffic statistics for all inbound proxies.` }),
276
+ statsOutboundUplink: z.boolean().default(false).optional().meta({ markdownDescription: `When set to \`true\`, enables uplink traffic statistics for all outbound proxies.` }),
277
+ statsOutboundDownlink: z.boolean().default(false).optional().meta({ markdownDescription: `When set to \`true\`, enables downlink traffic statistics for all outbound proxies.` })
278
+ }).optional().meta({ markdownDescription: `Xray system-level policies.` })
279
+ }).meta({ markdownDescription: `Local policy allows setting different user levels and corresponding policy settings, such as connection timeout settings. Every connection processed by Xray corresponds to a user, and different policies are applied according to the user's level.
280
+
281
+
282
+ [Documentation ↗](https://xtls.github.io/en/config/policy.html)` });
283
+ //#endregion
284
+ //#region src/inbounds/sniffing/sniffing.ts
285
+ const sniffingSchema = z.object({
286
+ enabled: z.boolean().default(true).optional().meta({ markdownDescription: "Whether to enable traffic sniffing.\n" }),
287
+ destOverride: z.array(z.enum([
288
+ "http",
289
+ "tls",
290
+ "quic",
291
+ "fakedns"
292
+ ])).default([
293
+ "http",
294
+ "tls",
295
+ "fakedns"
296
+ ]).meta({ markdownDescription: "When the traffic is of the specified type, reset the destination of the current connection based on the destination address contained within it.\n\n### TIP\n\nXray will only sniff the domains of protocols in `destOverride` for routing purposes. If you only want to sniff for routing but do not want to reset the destination address (e.g., resetting the destination address when using the Tor browser will cause connection failure), please add the corresponding protocol here and enable `routeOnly`.\n" }),
297
+ metadataOnly: z.boolean().default(false).optional().meta({ markdownDescription: "When enabled, only the connection metadata will be used to sniff the destination address. At this time, sniffers other than `fakedns` will not be activated.\n\nIf disabled (using more than just metadata to infer the destination address), the client must send data first before the proxy server actually establishes a connection. This behavior is incompatible with protocols where the server must initiate the first message, such as the SMTP protocol.\n" }),
298
+ domainsExcluded: z.array(z.string()).default([]).optional().meta({ markdownDescription: "A list of domains. If the result of traffic sniffing is in this list, the destination address will **not** be reset. The domain format is the same as in [Routing Configuration](https://xtls.github.io/en/config/routing.html#ruleobject).\n\n### TIP\n\nFilling in some domains may solve issues with iOS push notifications, Mijia smart devices, and voice chat in certain games (Rainbow Six). \nIf you need to troubleshoot the cause of certain problems, you can test by disabling `\"sniffing\"` or enabling `\"routeOnly\"`.\n" }),
299
+ ipsExcluded: z.array(z.string()).default([]).optional().meta({ markdownDescription: "A list of IPs. If the destination address is in this list, the destination address will **not** be reset. The format is the same as in [Routing Configuration](https://xtls.github.io/en/config/routing.html#ruleobject).\n" }),
300
+ routeOnly: z.boolean().default(false).optional().meta({ markdownDescription: "Use the sniffed domain only for routing; the proxy destination address remains the IP. The default value is `false`.\n\nThis item requires `destOverride` to be enabled to work.\n\n### TIP\n\nWhen it is guaranteed that **the proxied connection can obtain correct DNS resolution**, using `routeOnly` while enabling `destOverride`, and setting the routing matching strategy `domainStrategy` to `AsIs`, allows for domain and IP traffic splitting without DNS resolution throughout the process. In this case, the IP used when matching IP rules is the original IP of the domain name.\n" })
301
+ });
302
+ //#endregion
303
+ //#region src/transport/raw/raw.md?raw
304
+ var raw_default = "Renamed from the former TCP transport layer (as the original name was ambiguous), the outbound RAW transport layer directly sends TCP or UDP data wrapped by the proxy protocol. The core does not use other transport layers (such as [XHTTP](https://github.com/XTLS/Xray-core/discussions/4113)) to carry its traffic.\n\nIt can be combined with various protocols in multiple modes.\n\n[Documentation ↗](https://xtls.github.io/en/config/transports/raw.html)\n";
305
+ //#endregion
306
+ //#region src/transport/raw/rawSettings.md?raw
307
+ var rawSettings_default = "`RawObject` corresponds to the `rawSettings` item in [StreamSettingsObject](https://xtls.github.io/en/config/transport.html#streamsettingsobject).\n";
308
+ //#endregion
309
+ //#region src/transport/raw/acceptProxyProtocol.md?raw
310
+ var acceptProxyProtocol_default$3 = "Only used for inbound; indicates whether to accept PROXY protocol.\n\n[PROXY protocol](https://www.haproxy.org/download/2.2/doc/proxy-protocol.txt) is dedicated to passing the real source IP and port of the request. If you don't know what it is, please ignore this item for now.\n\nCommon reverse proxy software (such as HAProxy, Nginx) can be configured to send it. VLESS fallbacks xver can also send it.\n\nWhen set to `true`, after the underlying TCP connection is established, the requester must send PROXY protocol v1 or v2 first; otherwise, the connection will be closed.\n\nDefault value is `false`.\n";
311
+ //#endregion
312
+ //#region src/transport/raw/header.md?raw
313
+ var header_default = "Packet header obfuscation settings. Default value is `NoneHeaderObject`.\n\n### TIP\n\nHTTP obfuscation cannot be traffic-split by other HTTP servers (like Nginx), but can be split by VLESS fallbacks path.\n";
314
+ //#endregion
315
+ //#region src/transport/raw/noneHeader.md?raw
316
+ var noneHeader_default = "No obfuscation.\n\n`type`: \"none\"\n\nSpecifies no obfuscation.\n";
317
+ //#endregion
318
+ //#region src/transport/raw/httpHeader.md?raw
319
+ var httpHeader_default = "HTTP obfuscation configuration must be configured on the corresponding inbound and outbound connections simultaneously, and the content must be consistent.\n\n`type`: \"http\"\n\nSpecifies HTTP obfuscation.\n";
320
+ //#endregion
321
+ //#region src/transport/raw/request.md?raw
322
+ var request_default = "HTTP Request.\n";
323
+ //#endregion
324
+ //#region src/transport/raw/response.md?raw
325
+ var response_default$1 = "HTTP Response.\n";
326
+ //#endregion
327
+ //#region src/transport/raw/version.md?raw
328
+ var version_default$1 = "HTTP version. Default value is `\"1.1\"`.\n";
329
+ //#endregion
330
+ //#region src/transport/raw/method.md?raw
331
+ var method_default$1 = "HTTP method. Default value is `\"GET\"`.\n";
332
+ //#endregion
333
+ //#region src/transport/raw/path.md?raw
334
+ var path_default$3 = "Path, an array of strings. Default value is `[\"/\"]`. When there are multiple values, one is randomly selected for each request.\n";
335
+ //#endregion
336
+ //#region src/transport/raw/headers.md?raw
337
+ var headers_default$3 = "HTTP headers. A key-value pair, where each key represents the name of an HTTP header, and the corresponding value is an array.\n\nAll keys will be attached to every request, and one corresponding value will be randomly selected. See the example above for default values.\n";
338
+ //#endregion
339
+ //#region src/transport/raw/status.md?raw
340
+ var status_default = "HTTP status code. Default value is `\"200\"`.\n";
341
+ //#endregion
342
+ //#region src/transport/raw/reason.md?raw
343
+ var reason_default = "HTTP status reason phrase. Default value is `\"OK\"`.\n";
344
+ //#endregion
345
+ //#region src/transport/networkField.md?raw
346
+ var networkField_default = "Transport method used by the data stream. The default value is `raw`.\n";
347
+ //#endregion
348
+ //#region src/transport/rawSettingsField.md?raw
349
+ var rawSettingsField_default = "RAW configuration for the data stream. Only valid when `network` is `raw`.\n";
350
+ //#endregion
351
+ //#region src/transport/tcpSettingsField.md?raw
352
+ var tcpSettingsField_default = "TCP configuration for the data stream. Only valid when `network` is `tcp` or `raw`.\n";
353
+ //#endregion
354
+ //#region src/transport/finalmask/customSettingsObject.md?raw
355
+ var customSettingsObject_default = "`header-custom` settings object used by FinalMask.\n\nIt defines one packet layer entry with optional delay, random padding, packet encoding type, and fixed packet data.\n\nFields:\n\n- `delay`: delay in milliseconds. When it is `0`, the data is sent together with the previous packet.\n- `rand`: adds a specified number of random bytes. Conflicts with `packet`.\n- `randRange`: range of random-byte values. The default is `0-255`.\n- `type`: the type of `packet`. Supported values are `array`, `str`, `hex`, and `base64`. The default is `array`.\n- `packet`: adds fixed data. Conflicts with `rand`.\n";
356
+ //#endregion
357
+ //#region src/transport/finalmask/delay.md?raw
358
+ var delay_default = "Delay in milliseconds. When it is `0`, the data is sent together with the previous packet.\n";
359
+ //#endregion
360
+ //#region src/transport/finalmask/rand.md?raw
361
+ var rand_default = "Adds a specified number of random bytes. Conflicts with `packet`.\n";
362
+ //#endregion
363
+ //#region src/transport/finalmask/randRange.md?raw
364
+ var randRange_default = "Range of random-byte values. The default is `0-255`.\n";
365
+ //#endregion
366
+ //#region src/transport/finalmask/type.md?raw
367
+ var type_default$2 = "Type of `packet`. Supported values are `array`, `str`, `hex`, and `base64`. The default is `array`.\n";
368
+ //#endregion
369
+ //#region src/transport/finalmask/packet.md?raw
370
+ var packet_default = "Adds fixed data. Conflicts with `rand`.\n";
371
+ //#endregion
372
+ //#region src/transport/finalmask/customSettingsObject.ts
373
+ const headerCustomSettingsObject = z.object({
374
+ delay: z.int().default(0).optional().meta({ markdownDescription: delay_default }),
375
+ rand: z.int().default(0).optional().meta({ markdownDescription: rand_default }),
376
+ randRange: z.string().default("0-255").optional().meta({ markdownDescription: randRange_default }),
377
+ type: z.enum([
378
+ "array",
379
+ "str",
380
+ "hex",
381
+ "base64"
382
+ ]).default("array").optional().meta({ markdownDescription: type_default$2 }),
383
+ packet: z.array(z.any()).optional().meta({ markdownDescription: packet_default })
384
+ }).meta({ markdownDescription: customSettingsObject_default });
385
+ //#endregion
386
+ //#region src/transport/finalmask/sudoku.md?raw
387
+ var sudoku_default = "FinalMask Sudoku camouflage layer.\n\nThe same meanings as in the TCP and UDP versions apply here.\n\nUse together with the upstream Sudoku ASCII configuration format.\n\n[Documentation ↗](https://xtls.github.io/en/config/transports/finalmask.html#sudoku)\n";
388
+ //#endregion
389
+ //#region src/transport/finalmask/password.md?raw
390
+ var password_default$2 = "Password for Sudoku and related camouflage settings.\n";
391
+ //#endregion
392
+ //#region src/transport/finalmask/sudoku.ts
393
+ const sudoku = z.object({
394
+ type: z.literal("sudoku"),
395
+ settings: z.object({
396
+ password: z.string().meta({ markdownDescription: password_default$2 }),
397
+ ascii: z.string().meta({ markdownDescription: "ASCII mapping or symbol table used by Sudoku camouflage.\n" }),
398
+ customTable: z.string().meta({ markdownDescription: "Custom table used by Sudoku camouflage.\n" }),
399
+ customTables: z.array(z.string()).meta({ markdownDescription: "Custom tables used by Sudoku camouflage.\n" }),
400
+ paddingMin: z.int().meta({ markdownDescription: "Minimum padding value used by Sudoku camouflage.\n" }),
401
+ paddingMax: z.int().meta({ markdownDescription: "Maximum padding value used by Sudoku camouflage.\n" })
402
+ }).meta({ markdownDescription: sudoku_default })
403
+ }).meta({ markdownDescription: sudoku_default });
404
+ //#endregion
405
+ //#region src/transport/finalmask/tcpFinalmask.md?raw
406
+ var tcpFinalmask_default = "TCP FinalMask layers are applied in order, with the first item being the outermost camouflage layer.\n\nUsed together with `raw`, `httpupgrade`, `websocket`, `grpc`, and `xhttp`.\n\nSupported TCP layer types:\n\n- `header-custom`\n- `fragment`\n- `sudoku`\n";
407
+ //#endregion
408
+ //#region src/transport/finalmask/tcpType.md?raw
409
+ var tcpType_default = "TCP FinalMask layer type.\n\nSupported values are `header-custom`, `fragment`, and `sudoku`.\n";
410
+ //#endregion
411
+ //#region src/transport/finalmask/headerCustomTcp.md?raw
412
+ var headerCustomTcp_default = "TCP `header-custom` uses layered client, server, and error packet sequences.\n\nEach outer array entry is a camouflage layer, and each inner entry is a `header-custom` packet object defined by `customSettingsObject`.\n";
413
+ //#endregion
414
+ //#region src/transport/finalmask/fragment.md?raw
415
+ var fragment_default = "A TCP fragmentation layer.\n\nFields:\n\n- `packets`: packet preset. Supported values are `1-3` and `tlshello`.\n- `length`: packet length or range.\n- `delay`: delay range in milliseconds.\n- `maxSplit`: maximum split count range.\n\nThe project ships a snippet for `tlshello` with `100-200` length, `10-20` delay, and `3-6` max split.\n";
416
+ //#endregion
417
+ //#region src/transport/finalmask/packets.md?raw
418
+ var packets_default = "Packet preset for the TCP fragment layer.\n\nSupported values are `1-3` and `tlshello`.\n";
419
+ //#endregion
420
+ //#region src/transport/finalmask/length.md?raw
421
+ var length_default = "Packet length or range used by the TCP fragment layer.\n";
422
+ //#endregion
423
+ //#region src/transport/finalmask/maxSplit.md?raw
424
+ var maxSplit_default = "Maximum split count range used by the TCP fragment layer.\n";
425
+ //#endregion
426
+ //#region src/transport/finalmask/tcpFinalmask.ts
427
+ const tcpHeaderCustom$1 = z.object({
428
+ type: z.literal("header-custom").meta({ markdownDescription: tcpType_default }),
429
+ settings: z.object({
430
+ clients: z.array(z.array(headerCustomSettingsObject)),
431
+ servers: z.array(z.array(headerCustomSettingsObject)),
432
+ errors: z.array(z.array(headerCustomSettingsObject))
433
+ }).meta({ markdownDescription: headerCustomTcp_default })
434
+ }).meta({ markdownDescription: headerCustomTcp_default });
435
+ const tcpFragment = z.object({
436
+ type: z.literal("fragment").meta({ markdownDescription: tcpType_default }),
437
+ settings: z.object({
438
+ packets: z.enum(["1-3", "tlshello"]).meta({ markdownDescription: packets_default }),
439
+ length: z.string().meta({ markdownDescription: length_default }),
440
+ delay: z.string().meta({ markdownDescription: delay_default }),
441
+ maxSplit: z.string().meta({ markdownDescription: maxSplit_default })
442
+ }).meta({
443
+ defaultSnippets: [{
444
+ label: "tlshello 100-200",
445
+ description: "a fragmentation example from docs",
446
+ body: {
447
+ packets: "tlshello",
448
+ length: "100-200",
449
+ delay: "10-20",
450
+ maxSplit: "3-6"
451
+ }
452
+ }],
453
+ markdownDescription: fragment_default
454
+ })
455
+ }).meta({ markdownDescription: fragment_default });
456
+ const tcpFinalmask = z.array(z.discriminatedUnion("type", [
457
+ tcpHeaderCustom$1,
458
+ tcpFragment,
459
+ sudoku
460
+ ])).meta({ markdownDescription: tcpFinalmask_default });
461
+ //#endregion
462
+ //#region src/transport/finalmask/udpFinalmask.md?raw
463
+ var udpFinalmask_default = "UDP FinalMask layers are applied in order, with the first item being the outermost camouflage layer.\n\nUsed together with `raw` UDP, `kcp`, `hysteria`, and `xhttp` H3.\n\nSupported UDP layer types:\n\n- `header-custom`\n- `header-dns`\n- `header-dtls`\n- `header-srtp`\n- `header-utp`\n- `header-wechat`\n- `header-wireguard`\n- `mkcp-original`\n- `mkcp-aes128gcm`\n- `noise`\n- `salamander`\n- `sudoku`\n- `xdns`\n- `xicmp`\n- `realm`\n";
464
+ //#endregion
465
+ //#region src/transport/finalmask/udpType.md?raw
466
+ var udpType_default = "UDP FinalMask layer type.\n\nSupported values are `header-custom`, `header-dns`, `header-dtls`, `header-srtp`, `header-utp`, `header-wechat`, `header-wireguard`, `mkcp-original`, `mkcp-aes128gcm`, `noise`, `salamander`, `sudoku`, `xdns`, and `xicmp`.\n";
467
+ //#endregion
468
+ //#region src/transport/finalmask/headerCustomUdp.md?raw
469
+ var headerCustomUdp_default = "UDP `header-custom` uses layered client and server packet sequences.\n\nEach inner entry is a `header-custom` packet object defined by `customSettingsObject`.\n";
470
+ //#endregion
471
+ //#region src/transport/finalmask/headerDns.md?raw
472
+ var headerDns_default = "UDP DNS camouflage header.\n\n`domain` is the DNS name used by the camouflage layer.\n";
473
+ //#endregion
474
+ //#region src/transport/finalmask/mkcpAes128gcm.md?raw
475
+ var mkcpAes128gcm_default = "Old mKCP `seed` feature compatibility layer.\n\n`password` is the obfuscation password.\n";
476
+ //#endregion
477
+ //#region src/transport/finalmask/noise.md?raw
478
+ var noise_default = "Noise camouflage for UDP.\n\nFields:\n\n- `reset`: reset marker for the noise sequence.\n- `noise`: array of noise packets.\n\nEach noise packet can set random payload size, byte range, packet data, packet type, and delay.\n";
479
+ //#endregion
480
+ //#region src/transport/finalmask/noiseItems.md?raw
481
+ var noiseItems_default = "Noise packet entries used by the UDP noise camouflage layer.\n\nEach entry can set random payload size, byte range, packet type, packet data, and delay.\n";
482
+ //#endregion
483
+ //#region src/transport/finalmask/salamander.md?raw
484
+ var salamander_default = "Salamander obfuscation from Hysteria2.\n\n`password` is the obfuscation password.\n";
485
+ //#endregion
486
+ //#region src/transport/finalmask/xdns.md?raw
487
+ var xdns_default = "Transmits data through DNS queries in a way similar to DNSTT.\n\n`domain` is the DNS name used for the tunnel.\n";
488
+ //#endregion
489
+ //#region src/transport/finalmask/xicmp.md?raw
490
+ var xicmp_default = "ICMP camouflage layer.\n\n### xicmp\n\n```json\n{\n \"dgram\": false,\n \"ips\": []\n}\n```\n\n- `dgram`: Lower permissions, client-side only (Linux, Mac, iOS).\n- `ips`: A list of IP addresses.\n";
491
+ //#endregion
492
+ //#region src/transport/finalmask/xicmpDgram.md?raw
493
+ var xicmpDgram_default = "Lower permissions, client-side only (Linux, Mac, iOS).\n";
494
+ //#endregion
495
+ //#region src/transport/finalmask/xicmpIps.md?raw
496
+ var xicmpIps_default = "A list of IP addresses.\n";
497
+ //#endregion
498
+ //#region src/transport/finalmask/realm.md?raw
499
+ var realm_default = "Self-built [Hysteria Realm](https://github.com/apernet/hysteria-realm-server) camouflage layer.\n\nConnection failures require debug-level logging. Possible contributing factors include the STUN provider, the Realm provider, and punch packets affecting the QUIC handshake (extremely low probability).\n";
500
+ //#endregion
501
+ //#region src/transport/finalmask/realmUrl.md?raw
502
+ var realmUrl_default = "Format: `realm[+http]://token@host[:port]/id`\n";
503
+ //#endregion
504
+ //#region src/transport/finalmask/realmStunServers.md?raw
505
+ var realmStunServers_default = "Multiple IPv4/IPv6 addresses are used for NAT port prediction.\n";
506
+ //#endregion
507
+ //#region src/transport/finalmask/realmTlsConfig.md?raw
508
+ var realmTlsConfig_default = "Same as tlsSettings.\n";
509
+ //#endregion
510
+ //#region src/transport/finalmask/domain.md?raw
511
+ var domain_default = "Domain name used by the camouflage layer.\n";
512
+ //#endregion
513
+ //#region src/transport/finalmask/xdnsDomains.md?raw
514
+ var xdnsDomains_default = "`domains`: used on the server side. A list of domains. It supports specifying a query type as `domain:method`, where method can be `txt`, `a`, or `aaaa`. If omitted, the query type is unrestricted.\n";
515
+ //#endregion
516
+ //#region src/transport/finalmask/resolvers.md?raw
517
+ var resolvers_default = "`resolvers` used on the client side. A list of DNS resolvers. The format is `domain[:method]+udp://server:port`, where `method` can be `txt` (default), `a`, or `aaaa`.\n";
518
+ //#endregion
519
+ //#region src/transport/finalmask/reset.md?raw
520
+ var reset_default = "Reset marker for the UDP noise sequence.\n";
521
+ //#endregion
522
+ //#region src/transport/finalmask/udpFinalmask.ts
523
+ const tcpHeaderCustom = z.object({
524
+ type: z.literal("header-custom").meta({ markdownDescription: udpType_default }),
525
+ settings: z.object({
526
+ client: z.array(headerCustomSettingsObject),
527
+ server: z.array(headerCustomSettingsObject)
528
+ }).meta({ markdownDescription: headerCustomUdp_default })
529
+ }).meta({ markdownDescription: headerCustomUdp_default });
530
+ const headerDns = z.object({
531
+ type: z.literal("header-dns").meta({ markdownDescription: udpType_default }),
532
+ settings: z.object({ domain: z.string().meta({ markdownDescription: domain_default }) }).meta({ markdownDescription: headerDns_default })
533
+ }).meta({ markdownDescription: headerDns_default });
534
+ const mkcpAes128gcm = z.object({
535
+ type: z.literal("mkcp-aes128gcm").meta({ markdownDescription: udpType_default }),
536
+ settings: z.object({ password: z.string().meta({ markdownDescription: password_default$2 }) }).meta({ markdownDescription: mkcpAes128gcm_default })
537
+ }).meta({ markdownDescription: mkcpAes128gcm_default });
538
+ const noise$1 = z.object({
539
+ type: z.literal("noise").meta({ markdownDescription: udpType_default }),
540
+ settings: z.object({
541
+ reset: z.int().meta({ markdownDescription: reset_default }),
542
+ noise: z.array(z.object({
543
+ rand: z.string().meta({ markdownDescription: rand_default }),
544
+ randRange: z.string().meta({ markdownDescription: randRange_default }),
545
+ type: z.string().meta({ markdownDescription: type_default$2 }),
546
+ packet: z.array(z.any()).meta({ markdownDescription: packet_default }),
547
+ delay: z.string().meta({ markdownDescription: delay_default })
548
+ }).meta({
549
+ defaultSnippets: [{
550
+ label: "noise 1-8192",
551
+ description: "noise example from the docs",
552
+ body: {
553
+ rand: "1-8192",
554
+ randRange: "0-255",
555
+ type: "",
556
+ packet: [],
557
+ delay: "10-20"
558
+ }
559
+ }],
560
+ markdownDescription: noiseItems_default
561
+ })).meta({ markdownDescription: noiseItems_default })
562
+ }).meta({ markdownDescription: noise_default })
563
+ }).meta({ markdownDescription: noise_default });
564
+ const salamander = z.object({
565
+ type: z.literal("salamander").meta({ markdownDescription: udpType_default }),
566
+ settings: z.object({ password: z.string().meta({ markdownDescription: password_default$2 }) }).meta({ markdownDescription: salamander_default })
567
+ }).meta({ markdownDescription: salamander_default });
568
+ const xdns = z.object({
569
+ type: z.literal("xdns").meta({ markdownDescription: udpType_default }),
570
+ settings: z.object({ domains: z.array(z.string()).min(1).meta({ markdownDescription: xdnsDomains_default }) }).or(z.object({ resolvers: z.array(z.string()).min(1).meta({ markdownDescription: resolvers_default }) })).meta({ markdownDescription: xdns_default })
571
+ }).meta({ markdownDescription: xdns_default });
572
+ const xicmp = z.object({
573
+ type: z.literal("xicmp").meta({ markdownDescription: udpType_default }),
574
+ settings: z.object({
575
+ dgram: z.boolean().default(false).optional().meta({ markdownDescription: xicmpDgram_default }),
576
+ ips: z.array(z.string()).default([]).optional().meta({ markdownDescription: xicmpIps_default })
577
+ }).meta({ markdownDescription: xicmp_default })
578
+ }).meta({ markdownDescription: xicmp_default });
579
+ const realm = z.object({
580
+ type: z.literal("realm").meta({ markdownDescription: udpType_default }),
581
+ settings: z.object({
582
+ url: z.string().min(1).meta({ markdownDescription: realmUrl_default }),
583
+ stunServers: z.array(z.string()).min(1).meta({ markdownDescription: realmStunServers_default }),
584
+ tlsConfig: z.object({}).loose().meta({ markdownDescription: realmTlsConfig_default })
585
+ }).meta({ markdownDescription: realm_default })
586
+ }).meta({ markdownDescription: realm_default });
587
+ const udpFinalmask = z.array(z.discriminatedUnion("type", [
588
+ tcpHeaderCustom,
589
+ headerDns,
590
+ mkcpAes128gcm,
591
+ noise$1,
592
+ salamander,
593
+ sudoku,
594
+ xdns,
595
+ xicmp,
596
+ realm
597
+ ])).meta({ markdownDescription: udpFinalmask_default });
598
+ //#endregion
599
+ //#region src/transport/finalmask/quicParams.md?raw
600
+ var quicParams_default = "Used for QUIC parameter tuning in XHTTP H3 and Hysteria.\n\nFields:\n\n- `congestion`: congestion-control algorithm. Supported values are `reno`, `bbr`, `brutal`, and `force-brutal`.\n- `debug`: enable logging for the `bbr` and `brutal` congestion-control implementations.\n- `brutalUp`: upload rate limit. The default is `0`.\n- `brutalDown`: download rate limit. The default is `0`.\n- `udpHop`: UDP port-hopping configuration.\n- `initStreamReceiveWindow`: low-level QUIC stream receive window.\n- `maxStreamReceiveWindow`: low-level QUIC stream receive window.\n- `initConnectionReceiveWindow`: low-level QUIC connection receive window.\n- `maxConnectionReceiveWindow`: low-level QUIC connection receive window.\n- `maxIdleTimeout`: maximum idle timeout in seconds.\n- `keepAlivePeriod`: QUIC KeepAlive interval in seconds.\n- `disablePathMTUDiscovery`: whether to disable path MTU discovery.\n- `maxIncomingStreams`: server-side maximum incoming streams.\n";
601
+ //#endregion
602
+ //#region src/transport/finalmask/congestion.md?raw
603
+ var congestion_default$1 = "Congestion-control algorithm. Supported values are `reno`, `bbr`, `brutal`, and `force-brutal`.\n";
604
+ //#endregion
605
+ //#region src/transport/finalmask/bbrProfile.md?raw
606
+ var bbrProfile_default = "When QUIC congestion control is set to BBR, this controls the BBR preset. The default is `standard`. `conservative` is slightly more cautious, while `aggressive` is slightly more aggressive.\n";
607
+ //#endregion
608
+ //#region src/transport/finalmask/debug.md?raw
609
+ var debug_default = "Enable logging for the `bbr` and `brutal` congestion-control implementations.\n";
610
+ //#endregion
611
+ //#region src/transport/finalmask/brutalUp.md?raw
612
+ var brutalUp_default = "Upload rate limit. The default value is `0`.\n\nThe format supports common bit-rate forms such as `1000000`, `100kb`, `20 mb`, `100 mbps`, `1g`, and `1 tbps`.\n";
613
+ //#endregion
614
+ //#region src/transport/finalmask/brutalDown.md?raw
615
+ var brutalDown_default = "Download rate limit. The default value is `0`.\n\nThe format supports common bit-rate forms such as `1000000`, `100kb`, `20 mb`, `100 mbps`, `1g`, and `1 tbps`.\n";
616
+ //#endregion
617
+ //#region src/transport/finalmask/udpHop.md?raw
618
+ var udpHop_default = "UDP port-hopping configuration.\n\n`ports` specifies the hopping range. It can be a single numeric string like `\"1234\"`, or a range like `\"1145-1919\"`, which means ports 1145 through 1919. Commas can be used to combine ranges, for example `11,13,15-17`.\n\n`interval` is the port-hopping interval in seconds. The minimum is 5. The default is 30 seconds.\n";
619
+ //#endregion
620
+ //#region src/transport/finalmask/udpHopPorts.md?raw
621
+ var udpHopPorts_default = "UDP port range for hopping. It can be a single numeric string like `\"1234\"`, or a range like `\"1145-1919\"`. Commas can be used to combine ranges.\n";
622
+ //#endregion
623
+ //#region src/transport/finalmask/udpHopInterval.md?raw
624
+ var udpHopInterval_default = "UDP port-hopping interval in seconds. The minimum is `5`. The default is `30` seconds.\n";
625
+ //#endregion
626
+ //#region src/transport/finalmask/initStreamReceiveWindow.md?raw
627
+ var initStreamReceiveWindow_default = "Low-level QUIC initial stream receive window. Do not change it unless you fully understand what you are doing.\n";
628
+ //#endregion
629
+ //#region src/transport/finalmask/maxStreamReceiveWindow.md?raw
630
+ var maxStreamReceiveWindow_default = "Low-level QUIC maximum stream receive window. Do not change it unless you fully understand what you are doing.\n";
631
+ //#endregion
632
+ //#region src/transport/finalmask/initConnectionReceiveWindow.md?raw
633
+ var initConnectionReceiveWindow_default = "Low-level QUIC initial connection receive window. Do not change it unless you fully understand what you are doing.\n";
634
+ //#endregion
635
+ //#region src/transport/finalmask/maxConnectionReceiveWindow.md?raw
636
+ var maxConnectionReceiveWindow_default = "Low-level QUIC maximum connection receive window. Do not change it unless you fully understand what you are doing.\n";
637
+ //#endregion
638
+ //#region src/transport/finalmask/maxIdleTimeout.md?raw
639
+ var maxIdleTimeout_default = "Maximum idle timeout in seconds. The supported range is 4 to 120 seconds. The default is 30 seconds.\n";
640
+ //#endregion
641
+ //#region src/transport/finalmask/keepAlivePeriod.md?raw
642
+ var keepAlivePeriod_default = "QUIC KeepAlive interval in seconds. The supported range is 2 to 60 seconds. Disabled by default.\n";
643
+ //#endregion
644
+ //#region src/transport/finalmask/disablePathMTUDiscovery.md?raw
645
+ var disablePathMTUDiscovery_default = "Whether to disable path MTU discovery.\n\nIf your operating system is outside Linux, Windows, and Darwin, you may need to disable it manually.\n";
646
+ //#endregion
647
+ //#region src/transport/finalmask/maxIncomingStreams.md?raw
648
+ var maxIncomingStreams_default = "Server-side only. If set, it must not be smaller than `8`.\n";
649
+ //#endregion
650
+ //#region src/transport/finalmask/quicParams.ts
651
+ const udpHop = z.object({
652
+ ports: z.string().meta({ markdownDescription: udpHopPorts_default }),
653
+ interval: z.number().or(z.string()).default(30).optional().meta({ markdownDescription: udpHopInterval_default })
654
+ }).meta({ markdownDescription: udpHop_default });
655
+ const quicParams = z.object({
656
+ congestion: z.enum([
657
+ "reno",
658
+ "bbr",
659
+ "brutal",
660
+ "force-brutal"
661
+ ]).optional().meta({ markdownDescription: congestion_default$1 }),
662
+ bbrProfile: z.enum([
663
+ "conservative",
664
+ "standard",
665
+ "aggressive"
666
+ ]).optional().meta({ markdownDescription: bbrProfile_default }),
667
+ debug: z.boolean().default(false).optional().meta({ markdownDescription: debug_default }),
668
+ brutalUp: z.string().or(z.int()).default(0).optional().meta({ markdownDescription: brutalUp_default }),
669
+ brutalDown: z.string().or(z.int()).default(0).optional().meta({ markdownDescription: brutalDown_default }),
670
+ udpHop: udpHop.optional().meta({ markdownDescription: udpHop_default }),
671
+ initStreamReceiveWindow: z.int().default(8388608).optional().meta({ markdownDescription: initStreamReceiveWindow_default }),
672
+ maxStreamReceiveWindow: z.int().default(8388608).optional().meta({ markdownDescription: maxStreamReceiveWindow_default }),
673
+ initConnectionReceiveWindow: z.int().default(20971520).optional().meta({ markdownDescription: initConnectionReceiveWindow_default }),
674
+ maxConnectionReceiveWindow: z.int().default(20971520).optional().meta({ markdownDescription: maxConnectionReceiveWindow_default }),
675
+ maxIdleTimeout: z.int().default(30).optional().meta({ markdownDescription: maxIdleTimeout_default }),
676
+ keepAlivePeriod: z.int().default(0).optional().meta({ markdownDescription: keepAlivePeriod_default }),
677
+ disablePathMTUDiscovery: z.boolean().default(false).optional().meta({ markdownDescription: disablePathMTUDiscovery_default }),
678
+ maxIncomingStreams: z.int().min(8).default(1024).optional().meta({ markdownDescription: maxIncomingStreams_default })
679
+ }).meta({ markdownDescription: quicParams_default });
680
+ //#endregion
681
+ //#region src/transport/finalmask/finalmask.md?raw
682
+ var finalmask_default = "FinalMask performs the last stage of traffic obfuscation after the core has already processed transport-layer security, including TLS and REALITY.\n\nIt can be used for multiple kinds of TCP and UDP camouflage, as well as QUIC-related parameter tuning.\n\n[Documentation ↗](https://xtls.github.io/en/config/transports/finalmask.html)\n";
683
+ //#endregion
684
+ //#region src/transport/finalmask/finalmaskObject.md?raw
685
+ var finalmaskObject_default = "`FinalMaskObject` corresponds to the `finalmask` item in `StreamSettingsObject`.\n\n[Documentation ↗](https://xtls.github.io/en/config/transports/finalmask.html)\n";
686
+ //#endregion
687
+ //#region src/transport/finalmask/finalmask.ts
688
+ const finalmask = z.object({
689
+ tcp: tcpFinalmask.optional().meta({ markdownDescription: finalmaskObject_default }),
690
+ udp: udpFinalmask.optional().meta({ markdownDescription: finalmaskObject_default }),
691
+ quicParams: quicParams.optional().meta({ markdownDescription: finalmaskObject_default })
692
+ }).meta({ markdownDescription: finalmask_default });
693
+ //#endregion
694
+ //#region src/transport/sockopt/sockopt.md?raw
695
+ var sockopt_default = "Sockopt is used to configure low-level network behavior.\n\nIt can be used to tune transparent proxying, DNS resolution strategy, and many other socket-level options.\n\n[Documentation ↗](https://xtls.github.io/en/config/transports/sockopt.html)\n";
696
+ //#endregion
697
+ //#region src/transport/sockopt/happyEyeballs.md?raw
698
+ var happyEyeballs_default = "An RFC 8305 Happy Eyeballs implementation for TCP connections.\n\nWhen the target is a domain name, it races the resolved addresses and chooses the first successful one. It only works when `Sockopt.domainStrategy` is not `AsIs`.\n\n### WARNING\n\nDo not use this together with the `domainStrategy` on a `Freedom` outbound, because then `Sockopt` only sees the final IP after replacement.\n";
699
+ //#endregion
700
+ //#region src/transport/sockopt/tryDelayMs.md?raw
701
+ var tryDelayMs_default = "Delay between each racing attempt, in milliseconds. The default is `0`, which disables the feature. A recommended value is `250`.\n";
702
+ //#endregion
703
+ //#region src/transport/sockopt/prioritizeIPv6.md?raw
704
+ var prioritizeIPv6_default = "Controls which IP family comes first after sorting. The default is `false`, meaning IPv4 comes first.\n";
705
+ //#endregion
706
+ //#region src/transport/sockopt/interleave.md?raw
707
+ var interleave_default = "The RFC 8305 `First Address Family Count`. The default value is `1`. It controls how IPv4 and IPv6 addresses are interleaved.\n\nFor example, the waiting dial queue may be ordered as `46464646` when this is `1`, or `44664466` when it is `2`, where `6` means an IPv6 address and `4` means an IPv4 address.\n";
708
+ //#endregion
709
+ //#region src/transport/sockopt/maxConcurrentTry.md?raw
710
+ var maxConcurrentTry_default = "Maximum number of concurrent attempts. This prevents the core from launching too many connections when a domain resolves to many addresses and all of them fail.\n\nThe default is `4`. Setting it to `0` disables Happy Eyeballs.\n";
711
+ //#endregion
712
+ //#region src/transport/sockopt/mark.md?raw
713
+ var mark_default = "An integer. When non-zero, outbound connections are marked with this value through `SO_MARK`.\n\n- Linux only.\n- Requires `CAP_NET_ADMIN`.\n";
714
+ //#endregion
715
+ //#region src/transport/sockopt/tcpMaxSeg.md?raw
716
+ var tcpMaxSeg_default = "Used to set the maximum segment size of TCP packets.\n";
717
+ //#endregion
718
+ //#region src/transport/sockopt/tcpFastOpen.md?raw
719
+ var tcpFastOpen_default = "Whether to enable TCP Fast Open.\n\nWhen set to `true` or a positive integer, TFO is enabled. When set to `false` or a negative value, TFO is forcibly disabled. When the field is absent or `0`, the system default is used. This option is available for both inbound and outbound.\n";
720
+ //#endregion
721
+ //#region src/transport/sockopt/tproxy.md?raw
722
+ var tproxy_default = "Whether to enable transparent proxying. Linux only.\n\n- `\"redirect\"`: transparent proxy in Redirect mode, supporting all IPv4 and IPv6 TCP connections\n- `\"tproxy\"`: transparent proxy in TProxy mode, supporting all IPv4 and IPv6 TCP and UDP connections\n- `\"off\"`: disable transparent proxying\n\nTransparent proxying requires root or `CAP_NET_ADMIN`.\n\n### DANGER\n\nWhen `Dokodemo-door` has `followRedirect` set to `true`, and `tproxy` is empty in Sockopt, the `tproxy` value is set to `\"redirect\"`.\n";
723
+ //#endregion
724
+ //#region src/transport/sockopt/domainStrategy.md?raw
725
+ var domainStrategy_default = "When the target address is a domain name, this field controls how outbound connections resolve and use that target.\n\nThe default value is `\"AsIs\"`.\n\n- `\"AsIs\"`: Xray does not specially handle the domain name. In the end it uses Go's built-in dialer directly.\n- Any other value: Xray uses the built-in DNS server for resolution. If there is no `DNSObject`, system DNS is used. If multiple IP addresses match, the core randomly picks one target IP.\n- `\"IPv4\"` means try IPv4 only. `\"IPv4v6\"` means try IPv4 or IPv6, but for dual-stack domains prefer IPv4. The same logic applies to the IPv6-first variants.\n\nWhen built-in DNS also sets `queryStrategy`, the actual behavior is the intersection of the two settings.\n\n### DANGER\n\nImproper use of this feature can create an infinite loop when routing DNS traffic through the proxy itself.\n";
726
+ //#endregion
727
+ //#region src/transport/sockopt/dialerProxy.md?raw
728
+ var dialerProxy_default = "An outbound identifier. When non-empty, the specified outbound is used to establish the connection. It can be used for chained forwarding that still respects transport configuration.\n\n### DANGER\n\nThis option is incompatible with `ProxySettingsObject.Tag`.\n";
729
+ //#endregion
730
+ //#region src/transport/sockopt/acceptProxyProtocol.md?raw
731
+ var acceptProxyProtocol_default$2 = "Inbound-only. Controls whether PROXY protocol is accepted.\n\nIf you do not know what it is, ignore this option.\n\nWhen set to `true`, the peer must send PROXY protocol v1 or v2 immediately after the underlying TCP connection is established, otherwise the connection is closed.\n";
732
+ //#endregion
733
+ //#region src/transport/sockopt/trustedXForwardedFor.md?raw
734
+ var trustedXForwardedFor_default = "Only applies to the three HTTP-based inbounds: `XHTTP`, `WebSocket`, and `HTTPUpgrade`.\n\nIt controls when Xray trusts `X-Forwarded-For` and uses it to overwrite `SourceIP`.\n\nIf left unset, the old behavior remains: as long as the request contains `X-Forwarded-For`, Xray reads it.\n\nAfter setting this field, each array item is treated as an additional required header name. Xray trusts `X-Forwarded-For` only when the request also contains at least one of those headers. The header values do not matter; only the presence of the key is checked.\n";
735
+ //#endregion
736
+ //#region src/transport/sockopt/tcpKeepAliveIdle.md?raw
737
+ var tcpKeepAliveIdle_default = "TCP idle threshold in seconds. Once a TCP connection has been idle for this long, Keep-Alive probes begin.\n\nFor outbound, Xray uses Chrome's default values, where both idle and interval are 45 seconds. Setting either this field or `tcpKeepAliveInterval` to a negative value disables that default keepalive; a positive value overrides it.\n\nFor inbound, Keep-Alive is disabled by default. It becomes enabled when either this field or `tcpKeepAliveInterval` is non-zero. If only one is set, the other follows the operating-system default.\n";
738
+ //#endregion
739
+ //#region src/transport/sockopt/tcpKeepAliveInterval.md?raw
740
+ var tcpKeepAliveInterval_default = "Time interval in seconds between Keep-Alive probes after TCP enters Keep-Alive state. The rest of the behavior is described in `tcpKeepAliveIdle`.\n";
741
+ //#endregion
742
+ //#region src/transport/sockopt/tcpUserTimeout.md?raw
743
+ var tcpUserTimeout_default = "TCP user timeout, in milliseconds.\n\nSee the gRPC proposal for the underlying socket option behavior.\n";
744
+ //#endregion
745
+ //#region src/transport/sockopt/tcpcongestion.md?raw
746
+ var tcpcongestion_default = "TCP congestion-control algorithm. Linux only. When unset, the operating-system default is used.\n\nCommon algorithms include `bbr` (recommended), `cubic`, and `reno`.\n";
747
+ //#endregion
748
+ //#region src/transport/sockopt/interface.md?raw
749
+ var interface_default = "Bind the outbound connection to a specific network-interface name. Supported on Linux, iOS, macOS, and Windows.\n";
750
+ //#endregion
751
+ //#region src/transport/sockopt/V6Only.md?raw
752
+ var V6Only_default = "When set to `true`, listening on `::` accepts only IPv6 connections. Linux only.\n";
753
+ //#endregion
754
+ //#region src/transport/sockopt/tcpWindowClamp.md?raw
755
+ var tcpWindowClamp_default = "Bind the advertised TCP window size to this value. The kernel chooses the larger value between this and `SOCK_MIN_RCVBUF / 2`.\n";
756
+ //#endregion
757
+ //#region src/transport/sockopt/tcpMptcp.md?raw
758
+ var tcpMptcp_default = "When set to `true`, Multipath TCP is enabled. This is client-only, because starting with Go 1.24 MPTCP is enabled by default when listening. It currently requires Linux kernel 5.6 or later.\n";
759
+ //#endregion
760
+ //#region src/transport/sockopt/addressPortStrategy.md?raw
761
+ var addressPortStrategy_default = "Use SRV records or TXT records to specify the target address and or port used by outbound. The default value is `none`, which disables the feature.\n\nThese lookups go through system DNS rather than Xray's built-in DNS. The queried name is the outbound domain name. If the lookup fails, the request is sent using the original address and port.\n\n`Srv*` means querying SRV records in their standard format. `Txt*` means querying TXT records in a format such as `127.0.0.1:80`.\n\n`PortOnly` resets only the port. `AddressOnly` resets only the address. `PortAndAddress` resets both.\n";
762
+ //#endregion
763
+ //#region src/transport/sockopt/customSockopt.md?raw
764
+ var customSockopt_default = "An array for advanced users to specify any needed socket option.\n\nIn theory, all connection-related settings above can be expressed here, and you can also set other socket options that exist but are not exposed directly by the core. It currently supports Linux, Windows, and Darwin.\n\n### WARNING\n\nMake sure you understand socket programming before using it.\n";
765
+ //#endregion
766
+ //#region src/transport/sockopt/system.md?raw
767
+ var system_default = "Optional. Restricts the option to a specific operating system. If the current system does not match, the option is skipped. Supported values are `linux`, `windows`, and `darwin`, all in lowercase. If left empty, the option is applied directly.\n";
768
+ //#endregion
769
+ //#region src/transport/sockopt/type.md?raw
770
+ var type_default$1 = "Required. The value type to set. Currently `int` and `str` are supported.\n";
771
+ //#endregion
772
+ //#region src/transport/sockopt/level.md?raw
773
+ var level_default$1 = "Optional. Protocol level. The default is `6`, which means TCP.\n";
774
+ //#endregion
775
+ //#region src/transport/sockopt/opt.md?raw
776
+ var opt_default = "The option number to operate on, in decimal. In the example above, `13` is the decimal form of `TCP_CONGESTION`, whose hexadecimal value is `0xd`.\n";
777
+ //#endregion
778
+ //#region src/transport/sockopt/value.md?raw
779
+ var value_default = "The value to set. In the example above, the value is `bbr`.\n\nWhen `type` is `int`, the value must be a decimal number.\n";
780
+ //#endregion
781
+ //#region src/transport/sockopt/sockopt.ts
782
+ const happyEyeballs = z.object({
783
+ tryDelayMs: z.int().default(0).optional().meta({ markdownDescription: tryDelayMs_default }),
784
+ prioritizeIPv6: z.boolean().default(false).optional().meta({ markdownDescription: prioritizeIPv6_default }),
785
+ interleave: z.int().default(1).optional().meta({ markdownDescription: interleave_default }),
786
+ maxConcurrentTry: z.int().default(4).optional().meta({ markdownDescription: maxConcurrentTry_default })
787
+ }).meta({ markdownDescription: happyEyeballs_default });
788
+ const customSockoptObject = z.object({
789
+ system: z.enum([
790
+ "linux",
791
+ "windows",
792
+ "darwin",
793
+ ""
794
+ ]).or(z.string()).optional().meta({ markdownDescription: system_default }),
795
+ type: z.enum(["int", "str"]).meta({ markdownDescription: type_default$1 }),
796
+ level: z.string().or(z.int()).default("6").optional().meta({ markdownDescription: level_default$1 }),
797
+ opt: z.string().or(z.int()).meta({ markdownDescription: opt_default }),
798
+ value: z.string().or(z.int()).meta({ markdownDescription: value_default })
799
+ }).meta({ markdownDescription: customSockopt_default });
800
+ const sockopt = z.object({
801
+ mark: z.int().optional().meta({ markdownDescription: mark_default }),
802
+ tcpMaxSeg: z.int().optional().meta({ markdownDescription: tcpMaxSeg_default }),
803
+ tcpFastOpen: z.boolean().or(z.number()).optional().meta({ markdownDescription: tcpFastOpen_default }),
804
+ tproxy: z.enum([
805
+ "redirect",
806
+ "tproxy",
807
+ "off"
808
+ ]).default("off").optional().meta({ markdownDescription: tproxy_default }),
809
+ domainStrategy: z.enum([
810
+ "AsIs",
811
+ "UseIP",
812
+ "UseIPv6v4",
813
+ "UseIPv6",
814
+ "UseIPv4v6",
815
+ "UseIPv4",
816
+ "ForceIP",
817
+ "ForceIPv6v4",
818
+ "ForceIPv6",
819
+ "ForceIPv4v6",
820
+ "ForceIPv4"
821
+ ]).default("AsIs").optional().meta({ markdownDescription: domainStrategy_default }),
822
+ happyEyeballs: happyEyeballs.default({}).optional().meta({ markdownDescription: happyEyeballs_default }),
823
+ dialerProxy: z.string().optional().meta({ markdownDescription: dialerProxy_default }),
824
+ acceptProxyProtocol: z.boolean().default(false).optional().meta({ markdownDescription: acceptProxyProtocol_default$2 }),
825
+ trustedXForwardedFor: z.array(z.string()).optional().meta({ markdownDescription: trustedXForwardedFor_default }),
826
+ tcpKeepAliveInterval: z.int().optional().meta({ markdownDescription: tcpKeepAliveInterval_default }),
827
+ tcpKeepAliveIdle: z.int().optional().meta({ markdownDescription: tcpKeepAliveIdle_default }),
828
+ tcpUserTimeout: z.int().optional().meta({ markdownDescription: tcpUserTimeout_default }),
829
+ tcpcongestion: z.enum([
830
+ "bbr",
831
+ "cubic",
832
+ "reno",
833
+ ""
834
+ ]).optional().meta({ markdownDescription: tcpcongestion_default }),
835
+ interface: z.string().optional().meta({ markdownDescription: interface_default }),
836
+ V6Only: z.boolean().default(false).optional().meta({ markdownDescription: V6Only_default }),
837
+ tcpWindowClamp: z.int().optional().meta({ markdownDescription: tcpWindowClamp_default }),
838
+ tcpMptcp: z.boolean().default(false).optional().meta({ markdownDescription: tcpMptcp_default }),
839
+ addressPortStrategy: z.enum([
840
+ "none",
841
+ "SrvPortOnly",
842
+ "SrvAddressOnly",
843
+ "SrvPortAndAddress",
844
+ "TxtPortOnly",
845
+ "TxtAddressOnly",
846
+ "TxtPortAndAddress",
847
+ "none"
848
+ ]).default("none").optional().meta({ markdownDescription: addressPortStrategy_default }),
849
+ customSockopt: z.array(customSockoptObject).optional().meta({ markdownDescription: customSockopt_default })
850
+ }).meta({ markdownDescription: sockopt_default });
851
+ //#endregion
852
+ //#region src/transport/base.ts
853
+ const transportBase = z.object({
854
+ finalmask: finalmask.optional().meta({ markdownDescription: "FinalMask configuration, used for the final stage of traffic obfuscation.\n" }),
855
+ sockopt: sockopt.optional().meta({ markdownDescription: "Configuration related to low-level network behavior.\n" })
856
+ });
857
+ //#endregion
858
+ //#region src/transport/raw/raw.ts
859
+ const nonHeaderSchema = z.object({ type: z.literal("none").meta({ markdownDescription: noneHeader_default }) });
860
+ const httpHeaderRequestSchema = z.object({
861
+ version: z.string().default("1.1").optional().meta({ markdownDescription: version_default$1 }),
862
+ method: z.string().default("GET").optional().meta({ markdownDescription: method_default$1 }),
863
+ path: z.array(z.string()).default(["/"]).optional().meta({ markdownDescription: path_default$3 }),
864
+ headers: z.record(z.string(), z.union([z.string(), z.array(z.string())])).default({}).optional().meta({ markdownDescription: headers_default$3 })
865
+ }).meta({ markdownDescription: request_default });
866
+ const httpHeaderResponseSchema = z.object({
867
+ version: z.string().default("1.1").optional().meta({ markdownDescription: version_default$1 }),
868
+ status: z.string().default("200").optional().meta({ markdownDescription: status_default }),
869
+ reason: z.string().default("OK").optional().meta({ markdownDescription: reason_default }),
870
+ headers: z.record(z.string(), z.union([z.string(), z.array(z.string())])).default({}).optional().meta({ markdownDescription: headers_default$3 })
871
+ }).meta({ markdownDescription: response_default$1 });
872
+ const httpHeaderSchema = z.object({
873
+ type: z.literal("http").meta({ markdownDescription: httpHeader_default }),
874
+ request: httpHeaderRequestSchema.default({}).optional().meta({ markdownDescription: request_default }),
875
+ response: httpHeaderResponseSchema.default({}).optional().meta({ markdownDescription: response_default$1 })
876
+ });
877
+ const rawSettingsHeaderSchema = z.discriminatedUnion("type", [nonHeaderSchema, httpHeaderSchema]);
878
+ const rawSettings = z.object({
879
+ acceptProxyProtocol: z.boolean().default(false).optional().meta({ markdownDescription: acceptProxyProtocol_default$3 }),
880
+ header: rawSettingsHeaderSchema.default({ type: "none" }).optional().meta({ markdownDescription: header_default })
881
+ }).optional().meta({ markdownDescription: rawSettings_default });
882
+ const rawStream = transportBase.extend({
883
+ network: z.literal("raw").meta({ markdownDescription: networkField_default }),
884
+ rawSettings: rawSettings.meta({ markdownDescription: rawSettingsField_default })
885
+ }).meta({ markdownDescription: raw_default });
886
+ const tcpStream = transportBase.extend({
887
+ network: z.literal("tcp").optional().meta({ markdownDescription: networkField_default }),
888
+ tcpSettings: rawSettings.meta({ markdownDescription: tcpSettingsField_default })
889
+ }).meta({ markdownDescription: raw_default });
890
+ //#endregion
891
+ //#region src/transport/mkcp/mkcp.ts
892
+ const mkcpStream = transportBase.extend({
893
+ network: z.literal("kcp").or(z.literal("mkcp")).meta({ markdownDescription: networkField_default }),
894
+ kcpSettings: z.object({
895
+ mtu: z.number().int().nonnegative().default(1350).optional().meta({ markdownDescription: "Maximum Transmission Unit. Please select a value between 576 and 1460.\n\nDefault value is `1350`.\n" }),
896
+ tti: z.number().int().nonnegative().default(50).optional().meta({ markdownDescription: "Transmission Time Interval, in milliseconds (ms). mKCP will send data at this frequency. Please select a value between 10 and 5000.\n\nDefault value is `50`.\n" }),
897
+ uplinkCapacity: z.number().int().nonnegative().default(5).optional().meta({ markdownDescription: "Uplink capacity, i.e., the maximum bandwidth used by the host to send data. The unit is MB/s. Note that it is Byte, not bit. Can be set to 0, representing a very small bandwidth.\n\nDefault value is `5`.\n\n**TIP:**\n\n`uplinkCapacity` and `downlinkCapacity` determine the transmission speed of mKCP. Taking a client sending data as an example, the client's `uplinkCapacity` specifies the speed of sending data, while the server's `downlinkCapacity` specifies the speed of receiving data. The actual speed will be the smaller of the two values.\n\nIt is recommended to set `downlinkCapacity` to a larger value, such as 100, and set `uplinkCapacity` to the actual network speed. When the speed is insufficient, you can gradually increase the value of `uplinkCapacity` until it is about twice the bandwidth.\n" }),
898
+ downlinkCapacity: z.number().int().nonnegative().default(20).optional().meta({ markdownDescription: "Downlink capacity, i.e., the maximum bandwidth used by the host to receive data. The unit is MB/s. Note that it is Byte, not bit. Can be set to 0, representing a very small bandwidth.\n\nDefault value is `20`.\n\n**TIP:**\n\n`uplinkCapacity` and `downlinkCapacity` determine the transmission speed of mKCP. Taking a client sending data as an example, the client's `uplinkCapacity` specifies the speed of sending data, while the server's `downlinkCapacity` specifies the speed of receiving data. The actual speed will be the smaller of the two values.\n\nIt is recommended to set `downlinkCapacity` to a larger value, such as 100, and set `uplinkCapacity` to the actual network speed. When the speed is insufficient, you can gradually increase the value of `uplinkCapacity` until it is about twice the bandwidth.\n" }),
899
+ congestion: z.boolean().default(false).optional().meta({ markdownDescription: "Whether to enable congestion control.\n\nWhen congestion control is enabled, Xray automatically monitors network quality. When packet loss is severe, it automatically reduces throughput; when the network is smooth, it appropriately increases throughput.\n\nDefault value is `false`.\n" }),
900
+ readBufferSize: z.number().int().nonnegative().default(2).optional().meta({ markdownDescription: "The read buffer size for a single connection, in MB.\n\nDefault value is `2`.\n\n**TIP:**\n\n`readBufferSize` and `writeBufferSize` specify the memory size used by a single connection. When high-speed transmission is required, specifying larger `readBufferSize` and `writeBufferSize` will improve speed to a certain extent, but it will also use more memory.\n\nWhen the network speed does not exceed 20MB/s, the default value of 1MB can meet the demand; beyond that, you can appropriately increase the values of `readBufferSize` and `writeBufferSize`, and then manually balance the relationship between speed and memory.\n" }),
901
+ writeBufferSize: z.number().int().nonnegative().default(2).optional().meta({ markdownDescription: "The write buffer size for a single connection, in MB.\n\nDefault value is `2`.\n\n**TIP:**\n\n`readBufferSize` and `writeBufferSize` specify the memory size used by a single connection. When high-speed transmission is required, specifying larger `readBufferSize` and `writeBufferSize` will improve speed to a certain extent, but it will also use more memory.\n\nWhen the network speed does not exceed 20MB/s, the default value of 1MB can meet the demand; beyond that, you can appropriately increase the values of `readBufferSize` and `writeBufferSize`, and then manually balance the relationship between speed and memory.\n" })
902
+ }).optional().meta({ markdownDescription: "`KcpObject` corresponds to the `kcpSettings` item in [StreamSettingsObject](https://xtls.github.io/en/config/transport.html#streamsettingsobject).\n\n### TIP\n\nThe `header` and `seed` fields have been removed. Please use [FinalMask](https://xtls.github.io/en/config/transports/finalmask.html#finalmaskobject) for configuration. Additionally, the previously default mKCP obfuscation has also been removed. To connect to a legacy server, you need to configure `mkcp-original` in FinalMask.\n" })
903
+ }).meta({ markdownDescription: "mKCP uses UDP to simulate TCP connections.\n\nmKCP sacrifices bandwidth to reduce latency. To transmit the same amount of content, mKCP generally consumes more traffic than TCP.\n\n### TIP\n\nPlease ensure that the firewall configuration on the host is correct.\n\n[Documentation ↗](https://xtls.github.io/en/config/transports/mkcp.html)\n" });
904
+ //#endregion
905
+ //#region src/transport/websocket/websocket.ts
906
+ const websocketStream = transportBase.extend({
907
+ network: z.literal("websocket").or(z.literal("ws")).meta({ markdownDescription: networkField_default }),
908
+ wsSettings: z.object({
909
+ acceptProxyProtocol: z.boolean().default(false).optional().meta({ markdownDescription: "Only used for inbound, indicating whether to receive PROXY protocol.\n\n[PROXY protocol](https://www.haproxy.org/download/2.2/doc/proxy-protocol.txt) is specifically used to pass the real source IP and port of the request. If you don't understand it, please ignore this item.\n\nCommon reverse proxy software (such as HAProxy, Nginx) can be configured to send it, and VLESS fallbacks xver can also send it.\n\nWhen set to `true`, after the underlying TCP connection is established, the requester must send PROXY protocol v1 or v2 first; otherwise, the connection will be closed.\n" }),
910
+ path: z.string().default("/").optional().meta({ markdownDescription: "The HTTP protocol path used by WebSocket. The default value is `\"/\"`.\n\nIf the client path contains the `ed` parameter (e.g., `/mypath?ed=2560`), `Early Data` will be enabled to reduce latency. It uses the `Sec-WebSocket-Protocol` header to carry the first packet data during the upgrade, where the value represents the first packet length threshold. If the length of the first packet exceeds this value, `Early Data` will not be enabled. The recommended value is 2560, and the maximum value is 8192. Excessively large values may cause some compatibility issues. If you encounter compatibility issues, try lowering the threshold.\n" }),
911
+ host: z.string().default("").optional().meta({ markdownDescription: "The host sent in the WebSocket HTTP request. Default value is empty. If the server-side value is empty, the host value sent by the client is not verified.\n\nWhen this value is specified on the server side, or `host` is specified in `headers`, it will verify whether it matches the client request host.\n\nClient priority for sending host: `host` > `headers` > `address`.\n" }),
912
+ headers: z.record(z.string(), z.string()).default({}).optional().meta({ markdownDescription: "Client only. Custom HTTP headers, key-value pairs. Each key represents the name of an HTTP header, and the corresponding value is a string.\n\nDefault is empty.\n" }),
913
+ heartbeatPeriod: z.number().int().nonnegative().default(0).optional().meta({ markdownDescription: "Specifies a fixed time interval to send a Ping message to keep the connection alive. If not specified or set to 0, no Ping message is sent, which is the current default behavior.\n" })
914
+ }).optional().meta({ markdownDescription: "WebSocket configuration for the data stream. Only valid when `network` is `websocket`.\n\n### TIP\n\nIt is recommended to switch to XHTTP to avoid significant traffic characteristics like WebSocket \"ALPN is http/1.1\".\n" })
915
+ }).meta({
916
+ markdownDescription: "Uses standard WebSocket to transport data.\n\nWebSocket connections can be routed by other HTTP servers (such as Nginx) or by VLESS fallbacks path.\n\n### DANGER\n\nIt is recommended to switch to [XHTTP](https://github.com/XTLS/Xray-core/discussions/4113) to avoid significant traffic characteristics like WebSocket \"ALPN is http/1.1\".\n\n### TIP\n\nWebSocket will recognize the `X-Forwarded-For` header in HTTP requests to overwrite the source address of the traffic, which has higher priority than the PROXY protocol.\n\n[Documentation ↗](https://xtls.github.io/en/config/transports/websocket.html)\n",
917
+ deprecated: true,
918
+ deprecationMessage: `It is recommended to switch to XHTTP to avoid significant traffic characteristics like WebSocket "ALPN is http/1.1".`
919
+ });
920
+ //#endregion
921
+ //#region src/transport/grpc/grpc.ts
922
+ const grpcStream = transportBase.extend({
923
+ network: z.literal("grpc").meta({ markdownDescription: networkField_default }),
924
+ grpcSettings: z.object({
925
+ authority: z.string().optional().meta({ markdownDescription: "A string. Can be used as Host to achieve some other purposes.\n" }),
926
+ serviceName: z.string().default("").optional().meta({ markdownDescription: "A string. Specifies the service name, similar to Path in HTTP/2. The client uses this name for communication, and the server verifies if the service name matches.\n\n### TIP\n\nWhen `serviceName` starts with a slash, you can customize the path. It requires at least two slashes. For example, fill in `\"serviceName\": \"/my/sample/path1|path2\"` on the server side, and the client can fill in `\"serviceName\": \"/my/sample/path1\"` or `\"/my/sample/path2\"`.\n" }),
927
+ multiMode: z.boolean().default(false).optional().meta({ markdownDescription: "`true` enables `multiMode`. Default value: `false`.\n\nThis is an experimental option. It may not be kept long-term and cross-version compatibility is not guaranteed. This mode can bring about a 20% performance improvement in test environments, but actual results vary depending on transfer rates.\n\n### TIP\n\nOnly needs to be configured on outbound (client).\n" }),
928
+ user_agent: z.string().optional().meta({ markdownDescription: "### TIP\n\nOnly needs to be configured on outbound (client).\n\nSet the User-Agent for gRPC. This may prevent some CDNs from blocking gRPC traffic.\n" }),
929
+ idle_timeout: z.number().int().nonnegative().transform((t) => t && t < 10 ? 10 : t).optional().meta({ markdownDescription: "Unit: seconds. When there is no data transmission during this period, a health check will be performed. If this value is set below `10`, `10` will be used (the minimum value).\n\n### TIP\n\nIf you are not using reverse proxy tools like Caddy or Nginx (usually not), and set this below `60`, the server might send unexpected h2 GOAWAY frames to close existing connections.\n\nHealth checks are disabled by default.\n\n### TIP\n\nOnly needs to be configured on outbound (client).\n\n### TIP\n\nMay resolve some \"disconnection\" issues.\n" }),
930
+ health_check_timeout: z.number().int().nonnegative().default(20).optional().meta({ markdownDescription: "Unit: seconds. The timeout for health checks. If the health check is not completed within this time, and there is still no data transmission, the health check is considered failed. Default value is `20`.\n\n### TIP\n\nOnly needs to be configured on outbound (client).\n" }),
931
+ permit_without_stream: z.boolean().default(false).optional().meta({ markdownDescription: "`true` allows health checks when there are no sub-connections (streams). Default value is `false`.\n\n### TIP\n\nOnly needs to be configured on outbound (client).\n" }),
932
+ initial_windows_size: z.number().int().nonnegative().default(0).optional().meta({ markdownDescription: "Initial window size for h2 Stream. When the value is less than or equal to `0`, this feature does not take effect. When the value is greater than `65535`, the Dynamic Window mechanism will be disabled. Default value is `0` (disabled).\n\n### TIP\n\nOnly needs to be configured on outbound (client).\n\n### TIP\n\nWhen going through Cloudflare CDN, you can set the value to `65536` or higher (disabling Dynamic Window) to prevent Cloudflare CDN from sending unexpected h2 GOAWAY frames to close existing connections.\n" })
933
+ }).optional().meta({ markdownDescription: "gRPC configuration for the data stream. Only valid when `network` is `grpc`.\n" })
934
+ }).meta({ markdownDescription: "A transport protocol based on gRPC.\n\nIt is based on the HTTP/2 protocol and, theoretically, can be relayed through other servers that support HTTP/2 (such as Nginx). gRPC (HTTP/2) has built-in multiplexing. It is not recommended to enable mux.cool when using gRPC and HTTP/2.\n\n### DANGER\n\nIt is recommended to switch to [XHTTP](https://github.com/XTLS/Xray-core/discussions/4113). Its advantages over gRPC are noted in the STREAM-UP/ONE section.\n\n### WARNING\n\n- gRPC does not support specifying Host. Please fill in the correct domain name in the outbound proxy address, or fill in `ServerName` in `(x)tlsSettings`, otherwise the connection will fail.\n- gRPC does not support falling back to other services.\n- gRPC services are at risk of active probing. It is recommended to use reverse proxy tools such as Caddy or Nginx to split traffic via Path prefix.\n\n### TIP\n\nIf you use reverse proxies like Caddy or Nginx, please note the following:\n\n- Ensure the reverse proxy server has enabled HTTP/2.\n- Use HTTP/2 or h2c (Caddy), grpc_pass (Nginx) to connect to Xray.\n- The Path for normal mode is `/${serviceName}/Tun`, and for Multi mode is `/${serviceName}/TunMulti`.\n- If you need to receive the client IP, you can pass the client IP by having Caddy / Nginx send the `X-Real-IP` header.\n\n### TIP\n\nIf you are using fallback, please note the following:\n\n- Falling back to gRPC is not recommended due to the risk of active probing.\n- Please ensure `h2` is in the first position in `(x)tlsSettings.alpn`, otherwise gRPC (HTTP/2) may fail to complete the TLS handshake.\n- gRPC cannot be split by Path.\n\n[Documentation ↗](https://xtls.github.io/en/config/transports/grpc.html)\n" });
935
+ //#endregion
936
+ //#region src/transport/hysteria/hysteria.md?raw
937
+ var hysteria_default$2 = "Xray implementation of the underlying QUIC transport for Hysteria2, typically used with hysteria [outbound](https://xtls.github.io/en/config/outbounds/hysteria.html) and hysteria [inbound](https://xtls.github.io/en/config/inbounds/hysteria.html), and is compatible with the official implementation in this case.\n\n[Documentation ↗](https://xtls.github.io/en/config/transports/hysteria.html)\n";
938
+ //#endregion
939
+ //#region src/transport/hysteria/version.md?raw
940
+ var version_default = "Hysteria version, must be 2.\n";
941
+ //#endregion
942
+ //#region src/transport/hysteria/auth.md?raw
943
+ var auth_default$1 = "Hysteria authentication password. Must be consistent between the server and the client.\n\nWhen used with `hysteria inbound`, it will be overridden by `users` (if it exists).\n";
944
+ //#endregion
945
+ //#region src/transport/hysteria/udpIdleTimeout.md?raw
946
+ var udpIdleTimeout_default = "Unit: seconds, default 60.\n\nIdle wait time for a single `quic native udp` connection. If this time is too long, it may not be strictly adhered to and may be terminated by the policy first.\n";
947
+ //#endregion
948
+ //#region src/transport/hysteria/masquerade.md?raw
949
+ var masquerade_default = "HTTP/3 page masquerading.\n";
950
+ //#endregion
951
+ //#region src/transport/hysteria/type.md?raw
952
+ var type_default = "If left blank, the default 404 page will be displayed.\n";
953
+ //#endregion
954
+ //#region src/transport/hysteria/dir.md?raw
955
+ var dir_default = "Configuration items when type is file.\n";
956
+ //#endregion
957
+ //#region src/transport/hysteria/url.md?raw
958
+ var url_default = "Configuration items when type is proxy.\n";
959
+ //#endregion
960
+ //#region src/transport/hysteria/rewriteHost.md?raw
961
+ var rewriteHost_default = "Configuration items when type is proxy.\n";
962
+ //#endregion
963
+ //#region src/transport/hysteria/insecure.md?raw
964
+ var insecure_default = "Configuration items when type is proxy.\n";
965
+ //#endregion
966
+ //#region src/transport/hysteria/content.md?raw
967
+ var content_default = "Configuration items when type is string.\n";
968
+ //#endregion
969
+ //#region src/transport/hysteria/headers.md?raw
970
+ var headers_default$1 = "Configuration items when type is string.\n";
971
+ //#endregion
972
+ //#region src/transport/hysteria/statusCode.md?raw
973
+ var statusCode_default = "Configuration items when type is string.\n";
974
+ //#endregion
975
+ //#region src/transport/hysteriaSettingsField.md?raw
976
+ var hysteriaSettingsField_default = "Hysteria configuration for the data stream. Only valid when `network` is `hysteria`.\n";
977
+ //#endregion
978
+ //#region src/transport/hysteria/hysteria.ts
979
+ const masquerade = z.object({
980
+ type: z.enum([
981
+ "file",
982
+ "proxy",
983
+ "string",
984
+ ""
985
+ ]).default("").optional().meta({ markdownDescription: type_default }),
986
+ dir: z.string().default("").optional().meta({ markdownDescription: dir_default }),
987
+ url: z.string().default("").optional().meta({ markdownDescription: url_default }),
988
+ rewriteHost: z.boolean().default(false).optional().meta({ markdownDescription: rewriteHost_default }),
989
+ insecure: z.boolean().default(false).optional().meta({ markdownDescription: insecure_default }),
990
+ content: z.string().default("").optional().meta({ markdownDescription: content_default }),
991
+ headers: z.record(z.string(), z.string()).default({}).optional().meta({ markdownDescription: headers_default$1 }),
992
+ statusCode: z.number().int().default(0).optional().meta({ markdownDescription: statusCode_default })
993
+ }).meta({ markdownDescription: masquerade_default });
994
+ const hysteriaStream = transportBase.extend({
995
+ network: z.literal("hysteria").meta({ markdownDescription: networkField_default }),
996
+ hysteriaSettings: z.object({
997
+ version: z.literal(2).default(2).meta({ markdownDescription: version_default }),
998
+ auth: z.string().meta({ markdownDescription: auth_default$1 }),
999
+ udpIdleTimeout: z.number().int().nonnegative().default(60).optional().meta({ markdownDescription: udpIdleTimeout_default }),
1000
+ masquerade: masquerade.optional()
1001
+ }).optional().meta({ markdownDescription: hysteriaSettingsField_default })
1002
+ }).meta({ markdownDescription: hysteria_default$2 });
1003
+ //#endregion
1004
+ //#region src/transport/httpupgrade/httpupgrade.ts
1005
+ const httpUpgradeStream = transportBase.extend({
1006
+ network: z.literal("httpupgrade").meta({ markdownDescription: networkField_default }),
1007
+ httpupgradeSettings: z.object({
1008
+ acceptProxyProtocol: z.boolean().default(false).optional().meta({ markdownDescription: "Only used for inbound; indicates whether to accept PROXY protocol.\n\n[PROXY protocol](https://www.haproxy.org/download/2.2/doc/proxy-protocol.txt) is dedicated to passing the real source IP and port of the request. If you don't know what it is, please ignore this item for now.\n\nCommon reverse proxy software (such as HAProxy, Nginx) can be configured to send it. VLESS fallbacks xver can also send it.\n\nWhen set to `true`, after the underlying TCP connection is established, the requester must send PROXY protocol v1 or v2 first; otherwise, the connection will be closed.\n" }),
1009
+ path: z.string().default("/").optional().meta({ markdownDescription: "The HTTP path used by HTTPUpgrade. Default value is `\"/\"`.\n\nIf the client path contains the `ed` parameter (e.g., `/mypath?ed=2560`), `Early Data` will be enabled to reduce latency. The value represents the threshold for the first packet length. If the first packet length exceeds this value, `Early Data` will not be enabled. The recommended value is 2560.\n" }),
1010
+ host: z.string().default("").optional().meta({ markdownDescription: "The host sent in the HTTP request of HTTPUpgrade. Default value is empty. If the server-side value is empty, the host value sent by the client is not verified.\n\nWhen this value is specified on the server, or specified in `headers`, it will verify whether it is consistent with the host requested by the client.\n\nPriority of the host sent by the client: `host` > `headers` > `address`.\n" }),
1011
+ headers: z.record(z.string(), z.string()).default({}).optional().meta({ markdownDescription: "Client-only. Custom HTTP headers. A key-value pair, where each key represents the name of an HTTP header, and the corresponding value is a string.\n\nDefault value is empty.\n" })
1012
+ }).optional().meta({ markdownDescription: "HTTPUpgrade configuration for the data stream. Only valid when `network` is `httpupgrade`.\n\n### TIP\n\nIt is recommended to switch to XHTTP to avoid significant traffic fingerprints such as HTTPUpgrade's \"ALPN is http/1.1\".\n" })
1013
+ }).meta({
1014
+ markdownDescription: "A protocol that implements HTTP 1.1 upgrade requests and responses similar to WebSocket. This allows it to be reverse-proxied by CDNs or Nginx just like WebSocket, but without the need to implement other parts of the WebSocket protocol, resulting in higher efficiency. Its design is not recommended for standalone use; instead, it is intended to work with security protocols like TLS.\n\n### DANGER\n\nIt is recommended to switch to [XHTTP](https://github.com/XTLS/Xray-core/discussions/4113) to avoid significant traffic fingerprints such as HTTPUpgrade's \"ALPN is http/1.1\".\n\n[Documentation ↗](https://xtls.github.io/en/config/transports/httpupgrade.html)\n",
1015
+ deprecated: true,
1016
+ deprecationMessage: `It is recommended to switch to XHTTP to avoid significant traffic fingerprints such as HTTPUpgrade's "ALPN is http/1.1".`
1017
+ });
1018
+ //#endregion
1019
+ //#region src/transport/securityField.md?raw
1020
+ var securityField_default = "Whether to enable transport security. Supported options are:\n\n- `\"none\"` means disabled (default).\n- `\"reality\"` means using REALITY.\n- `\"tls\"` means using [TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security).\n";
1021
+ //#endregion
1022
+ //#region src/transport/security/fingerprint.ts
1023
+ const fingerprintSchema = z.enum([
1024
+ "chrome",
1025
+ "firefox",
1026
+ "safari",
1027
+ "ios",
1028
+ "android",
1029
+ "edge",
1030
+ "360",
1031
+ "qq",
1032
+ "random",
1033
+ "randomized"
1034
+ ]).or(z.string());
1035
+ //#endregion
1036
+ //#region src/transport/security/tls/tls.md?raw
1037
+ var tls_default = "TLS is a common transport-security mechanism.\n\nIt can be used to configure transport-layer encryption, certificate verification, client fingerprints, and related certificate settings.\n\nIt supports use with `RAW`, `XHTTP`, `mKCP`, `gRPC`, `WebSocket`, `HTTPUpgrade`, and `Hysteria` transport methods.\n\n[Documentation ↗](https://xtls.github.io/en/config/transports/tls.html)\n";
1038
+ //#endregion
1039
+ //#region src/transport/security/tls/tlsSettings.md?raw
1040
+ var tlsSettings_default = "`TLSObject` corresponds to the `tlsSettings` item in `StreamSettingsObject`.\n\n[Documentation ↗](https://xtls.github.io/en/config/transports/tls.html)\n";
1041
+ //#endregion
1042
+ //#region src/transport/security/tls/certificateObject.md?raw
1043
+ var certificateObject_default = "`CertificateObject` represents a certificate and key pair used by TLS.\n\nServer certificates are hot-reloaded every 3600 seconds (once per hour).\n\n[Documentation ↗](https://xtls.github.io/en/config/transports/tls.html#certificateobject)\n";
1044
+ //#endregion
1045
+ //#region src/transport/security/tls/ocspStapling.md?raw
1046
+ var ocspStapling_default = "OCSP stapling refresh interval in seconds. The default value is `0`. Any non-zero value enables OCSP stapling and also replaces the default 3600-second certificate hot-reload interval; reloading and OCSP stapling happen together.\n";
1047
+ //#endregion
1048
+ //#region src/transport/security/tls/oneTimeLoading.md?raw
1049
+ var oneTimeLoading_default = "Load only once. The default is `false`. When set to `true`, both certificate hot reload and OCSP stapling are disabled.\n";
1050
+ //#endregion
1051
+ //#region src/transport/security/tls/usage.md?raw
1052
+ var usage_default$1 = "Certificate usage. The default value is `\"encipherment\"`.\n\n- `\"encipherment\"`: the certificate is used for TLS authentication and encryption\n- `\"verify\"`: the certificate is used to verify remote TLS certificates; in this case it must be a CA certificate\n- `\"issue\"`: the certificate is used to issue other certificates; in this case it must also be a CA certificate\n\n### TIP\n\nOn Windows, you can install a self-signed CA certificate into the system store to verify remote TLS certificates.\n\n### TIP\n\nWhen a new client request arrives, suppose the specified `serverName` is `\"xray.com\"`. Xray first looks through the certificate list for a certificate usable for `\"xray.com\"`. If none is found, it uses any certificate whose `usage` is `\"issue\"` to issue one suitable for `\"xray.com\"` with a one-hour validity period, then adds that new certificate to the list for later use.\n\n### TIP\n\nYou can generate a self-signed CA certificate with `xray tls cert`.\n\n### TIP\n\nIf you already own a domain name, you can conveniently obtain free third-party certificates with tools such as [acme.sh](https://github.com/acmesh-official/acme.sh).\n";
1053
+ //#endregion
1054
+ //#region src/transport/security/tls/buildChain.md?raw
1055
+ var buildChain_default = "Only takes effect when the certificate usage is `issue`. If set to `true`, the CA certificate is embedded into the issued certificate chain.\n\n### TIP\n\nYou should not embed a root certificate into the chain. This option is suitable only when the signing CA certificate is an intermediate certificate.\n";
1056
+ //#endregion
1057
+ //#region src/transport/security/tls/certificateFile.md?raw
1058
+ var certificateFile_default = "Path to the certificate file, for example a `.crt` file generated by OpenSSL.\n\n### TIP\n\nWhen both `certificateFile` and `certificate` are specified, Xray prefers `certificateFile`.\n";
1059
+ //#endregion
1060
+ //#region src/transport/security/tls/keyFile.md?raw
1061
+ var keyFile_default = "Path to the private-key file, for example a `.key` file generated by OpenSSL. Password-protected key files are not currently supported.\n\n### TIP\n\nWhen both `keyFile` and `key` are specified, Xray prefers `keyFile`.\n";
1062
+ //#endregion
1063
+ //#region src/transport/security/tls/certificate.md?raw
1064
+ var certificate_default = "An array of strings representing the certificate content, in the same format as PEM-encoded certificates. Choose either `certificate` or `certificateFile`.\n";
1065
+ //#endregion
1066
+ //#region src/transport/security/tls/key.md?raw
1067
+ var key_default = "An array of strings representing the private-key content, in the same format as PEM-encoded private keys. Choose either `key` or `keyFile`.\n\n### TIP\n\nWhen `usage` is `\"verify\"`, both `keyFile` and `key` may be empty.\n";
1068
+ //#endregion
1069
+ //#region src/transport/security/tls/serverName.md?raw
1070
+ var serverName_default$1 = "Server name. The server certificate's SAN must contain this value. It can be a domain name or an IP address. If it is a domain name, it will be sent in the SNI extension of the Client Hello. IP addresses will not send the SNI extension, because SNI does not allow IP addresses. If you fill in an IPv6 address, wrap it in `[]`.\n\nWhen left empty, the value in `address` is used automatically if that value is a domain name.\n\nSpecial value `\"FromMitM\"` causes Xray to use the SNI extracted from TLS decrypted by a `dokodemo-door` inbound.\n";
1071
+ //#endregion
1072
+ //#region src/transport/security/tls/verifyPeerCertByName.md?raw
1073
+ var verifyPeerCertByName_default = "Client-only. The SNI used for certificate verification. Multiple domain names can be separated with `,`; it is enough for any one SAN in the certificate to match one of them. This overrides the `serverName` used for verification and is intended for special cases such as domain fronting.\n\nSpecial value `\"FromMitM\"` causes Xray to additionally include the SNI extracted from TLS decrypted by a `dokodemo-door` inbound.\n";
1074
+ //#endregion
1075
+ //#region src/transport/security/tls/rejectUnknownSni.md?raw
1076
+ var rejectUnknownSni_default = "When set to `true`, the server rejects the TLS handshake if the received SNI does not match the certificate domain. The default is `false`.\n";
1077
+ //#endregion
1078
+ //#region src/transport/security/tls/alpn.md?raw
1079
+ var alpn_default = "An array of strings that specifies the ALPN values used during TLS handshake. The default value is `[\"h2\", \"http/1.1\"]`.\n\nSpecial value `[\"FromMitM\"]`, when it is the only element, causes outbound TLS to reuse the ALPN from the TLS connection decrypted by a `dokodemo-door` inbound.\n";
1080
+ //#endregion
1081
+ //#region src/transport/security/tls/minVersion.md?raw
1082
+ var minVersion_default = "`minVersion` is the minimum acceptable TLS version.\n";
1083
+ //#endregion
1084
+ //#region src/transport/security/tls/maxVersion.md?raw
1085
+ var maxVersion_default = "`maxVersion` is the maximum acceptable TLS version.\n";
1086
+ //#endregion
1087
+ //#region src/transport/security/tls/cipherSuites.md?raw
1088
+ var cipherSuites_default = "`cipherSuites` configures the list of supported cipher suites, separated by `:`.\n\nYou can find Go cipher-suite names and descriptions in the Go source code.\n\n### DANGER\n\nThese options are not required in normal cases and usually do not affect security. If left unset, Go chooses automatically according to the platform. If you are not familiar with them, do not configure them.\n";
1089
+ //#endregion
1090
+ //#region src/transport/security/tls/certificates.md?raw
1091
+ var certificates_default = "Certificate list. Each item represents one certificate. A full chain is recommended.\n\n### TIP\n\nIf you want an A or A+ rating from tools such as ssllibs or myssl, a full chain certificate is recommended.\n";
1092
+ //#endregion
1093
+ //#region src/transport/security/tls/disableSystemRoot.md?raw
1094
+ var disableSystemRoot_default = "Whether to disable the operating system's built-in CA certificates. The default value is `false`.\n\nWhen set to `true`, Xray uses only the certificates specified in `certificates` during TLS handshake. When set to `false`, Xray uses only the operating system's built-in CA certificates during TLS handshake.\n";
1095
+ //#endregion
1096
+ //#region src/transport/security/tls/enableSessionResumption.md?raw
1097
+ var enableSessionResumption_default = "Whether to enable session resumption. It is disabled by default, and session resumption is only attempted when both the server and the client enable it.\n\nIf negotiation succeeds, certificates do not need to be transmitted during the handshake. This saves a tiny amount of handshake time, which is usually negligible.\n\nNote that this is not TLS 0-RTT. `gotls` does not support that feature yet, so this does not reduce TLS handshake RTT.\n";
1098
+ //#endregion
1099
+ //#region src/transport/security/tls/fingerprint.md?raw
1100
+ var fingerprint_default$1 = "This parameter configures the fingerprint of the `TLS Client Hello`. The default value is `chrome`. To revert to native Go TLS, set it to `unsafe`. When enabled, Xray uses the uTLS library to simulate a TLS fingerprint, or generates one randomly. Three configuration styles are supported:\n\n1. TLS fingerprints of the latest versions of common browsers:\n - `\"chrome\"`, `\"firefox\"`, `\"safari\"`, `\"ios\"`, `\"android\"`, `\"edge\"`, `\"360\"`, `\"qq\"`\n\n2. Automatically generate a fingerprint when Xray starts:\n - `\"random\"`: randomly choose one from newer browser versions\n - `\"randomized\"`: generate a completely random unique fingerprint that fully supports TLS 1.3 with X25519\n\n3. Use native uTLS hello names such as `\"HelloRandomizedNoALPN\"` or `\"HelloChrome_106_Shuffle\"`. See the full list in the [uTLS library](https://github.com/refraction-networking/utls/blob/master/u_common.go#L434).\n\n### TIP\n\nThis feature only simulates the `TLS Client Hello` fingerprint. Behavior and other fingerprints remain the same as Go. If you want more complete browser-like TLS fingerprints and behavior, use Browser Dialer.\n\n### TIP\n\nWhen this feature is enabled, some TLS options that affect TLS fingerprints are overridden by the uTLS library and stop taking effect.\nThe parameters still passed through are: `\"serverName\" \"disableSystemRoot\" \"pinnedPeerCertSha256\" \"masterKeyLog\"`.\n\nALPN has special behavior.\n\nBy default, the most common `h2,http/1.1` is forced as ALPN. For WebSocket and HttpUpgrade transports, `http/1.1` is used by default — otherwise negotiating to `h2` would prevent the connection from succeeding — but you may manually set it to `h2,http/1.1` if you are sure the server supports completing the handshake with this ALPN.\n\nIf ECH is enabled, the outer ALPN is always shown as `h2,http/1.1`. The inner ALPN is forced to `http/1.1` for WebSocket or HttpUpgrade transports to allow the handshake to complete; for other protocols the user-configured ALPN is honored.\n";
1101
+ //#endregion
1102
+ //#region src/transport/security/tls/pinnedPeerCertSha256.md?raw
1103
+ var pinnedPeerCertSha256_default = "Used to specify the SHA-256 hash of the remote server certificate. It uses hexadecimal encoding and is case-insensitive, for example `e8e2d387fdbffeb38e9c9065cf30a97ee23c0e3d32ee6f78ffae40966befccc9`. Multiple hash values can be joined with `,`, and verification succeeds if any one of them matches.\n\nThis encoding matches the SHA-256 certificate fingerprint shown by the Chrome certificate viewer and the SHA-256 certificate fingerprint format used on crt.sh.\n\nYou can compute it with `xray tls hash --cert <cert.pem>`, or with `openssl x509 -noout -fingerprint -sha256 -in cert.pem`. `xray tls ping` also prints the SHA-256 hash of the remote certificate.\n\nThis check overrides normal certificate validation. There are two cases:\n\n- If the core finds that the matching hash belongs to a leaf certificate, verification succeeds immediately.\n- If the core finds that the matching hash belongs to a CA certificate, whether root or intermediate, it uses the value in `serverName` to verify that the leaf certificate is signed by that CA.\n";
1104
+ //#endregion
1105
+ //#region src/transport/security/tls/curvePreferences.md?raw
1106
+ var curvePreferences_default = "An array of strings that specifies the curves supported when performing ECDHE during TLS handshake. Supported values are:\n\n- `CurveP256`\n- `CurveP384`\n- `CurveP521`\n- `X25519`\n- `X25519MLKEM768`\n- `SecP256r1MLKEM768*`\n- `SecP384r1MLKEM1024*`\n\n(\\*: not supported by uTLS)\n\nAs of Go 1.26, the default includes all curves above. Changing the order does not force either side to prefer a specific curve; the actual curve is negotiated by the key-exchange mechanism itself.\n";
1107
+ //#endregion
1108
+ //#region src/transport/security/tls/masterKeyLog.md?raw
1109
+ var masterKeyLog_default = "Path to a `(Pre)-Master-Secret` log file. It can be used by software such as Wireshark to decrypt TLS connections sent by Xray.\n";
1110
+ //#endregion
1111
+ //#region src/transport/security/tls/echServerKeys.md?raw
1112
+ var echServerKeys_default = "Server-only parameter used to enable Encrypted Client Hello on the server.\n\nUse `xray tls ech --serverName example.com` to generate an ECH Server Key and its corresponding Config. `example.com` is the SNI exposed to the outside when SNI is encrypted, and can be any value. The Server Key includes the ECHConfig. If you lose the client-side Config, you can recover it with `xray tls ech -i \"your server key\"`. You can publish it in a DNS HTTPS record; see the format in RFC 9460.\n\nNote that after ECH is configured, the server still accepts normal non-ECH connections.\n";
1113
+ //#endregion
1114
+ //#region src/transport/security/tls/echConfigList.md?raw
1115
+ var echConfigList_default = "Client-only parameter that configures ECHConfig. A non-empty value means the client enables Encrypted Client Hello. Two formats are supported.\n\nThe first is a fixed ECHConfig string.\n\nThe second is querying a DNS server. For example, when using a CDN, you can dynamically obtain ECHConfig from HTTPS records. If a valid ECH Config is obtained, Xray obeys the TTL returned by the server. The query target is the configured SNI, or the configured server domain name if SNI is empty and the target is a domain name.\n\nThe basic format is `\"udp://1.1.1.1\"`, meaning query ECHConfig through UDP DNS 1.1.1.1. You can also use `\"https://1.1.1.1/dns-query\"` or `h2c://` to query via DoH or h2c. All of these support an explicit port, such as `udp://1.1.1.1:53`. If omitted, the default port is 53 or 443 according to the protocol.\n\nYou can also specify a dedicated domain for the ECHConfig lookup in the form `\"example.com+https://1.1.1.1/dns-query\"`. In that case Xray forcibly uses the ECHConfig from the DNS records of `example.com` for the connection. This is useful if you want to obtain ECHConfig from DNS without exposing that you are querying the target domain's HTTPS record, or when you do not want to publish HTTPS records under that domain.\n";
1116
+ //#endregion
1117
+ //#region src/transport/security/tls/echSockopt.md?raw
1118
+ var echSockopt_default = "Adjusts the underlying socket options of the connection used when querying DNS for ECH records.\n";
1119
+ //#endregion
1120
+ //#region src/transport/security/tls/tls.ts
1121
+ const certificateObject = z.object({
1122
+ ocspStapling: z.number().int().nonnegative().default(0).optional().meta({ markdownDescription: ocspStapling_default }),
1123
+ oneTimeLoading: z.boolean().default(false).optional().meta({ markdownDescription: oneTimeLoading_default }),
1124
+ usage: z.enum([
1125
+ "encipherment",
1126
+ "verify",
1127
+ "issue"
1128
+ ]).default("encipherment").optional().meta({ markdownDescription: usage_default$1 }),
1129
+ buildChain: z.boolean().default(false).optional().meta({ markdownDescription: buildChain_default }),
1130
+ certificateFile: z.string().optional().meta({ markdownDescription: certificateFile_default }),
1131
+ keyFile: z.string().optional().meta({ markdownDescription: keyFile_default }),
1132
+ certificate: z.array(z.string()).optional().meta({ markdownDescription: certificate_default }),
1133
+ key: z.array(z.string()).optional().meta({ markdownDescription: key_default })
1134
+ }).meta({ markdownDescription: certificateObject_default });
1135
+ const tls = z.object({
1136
+ security: z.literal("tls").meta({ markdownDescription: securityField_default }),
1137
+ tlsSettings: z.object({
1138
+ serverName: z.string().or(z.literal("fromMitm")).default("").optional().meta({ markdownDescription: serverName_default$1 }),
1139
+ verifyPeerCertByName: z.string().or(z.literal("fromMitm")).optional().meta({ markdownDescription: verifyPeerCertByName_default }),
1140
+ rejectUnknownSni: z.boolean().default(false).optional().meta({ markdownDescription: rejectUnknownSni_default }),
1141
+ allowInsecure: z.boolean().default(false).optional().meta({
1142
+ deprecated: true,
1143
+ deprecationMessage: `This option is deprecated. Use \`pinnedPeerCertSha256\` to specify the certificate manually instead.`
1144
+ }),
1145
+ alpn: z.array(z.enum([
1146
+ "http/1.1",
1147
+ "h2",
1148
+ "h3",
1149
+ "fromMitm"
1150
+ ])).default(["h2", "http/1.1"]).optional().meta({ markdownDescription: alpn_default }),
1151
+ minVersion: z.string().optional().meta({ markdownDescription: minVersion_default }),
1152
+ maxVersion: z.string().optional().meta({ markdownDescription: maxVersion_default }),
1153
+ cipherSuites: z.string().optional().meta({ markdownDescription: cipherSuites_default }),
1154
+ certificates: z.array(certificateObject).optional().meta({ markdownDescription: certificates_default }),
1155
+ disableSystemRoot: z.boolean().default(false).optional().meta({ markdownDescription: disableSystemRoot_default }),
1156
+ enableSessionResumption: z.boolean().default(false).optional().meta({ markdownDescription: enableSessionResumption_default }),
1157
+ fingerprint: fingerprintSchema.optional().meta({ markdownDescription: fingerprint_default$1 }),
1158
+ pinnedPeerCertSha256: z.string().optional().meta({ markdownDescription: pinnedPeerCertSha256_default }),
1159
+ curvePreferences: z.array(z.enum([
1160
+ "CurveP256",
1161
+ "CurveP384",
1162
+ "CurveP521",
1163
+ "X25519",
1164
+ "X25519MLKEM768",
1165
+ "SecP256r1MLKEM768*",
1166
+ "SecP384r1MLKEM1024*"
1167
+ ])).optional().meta({ markdownDescription: curvePreferences_default }),
1168
+ masterKeyLog: z.string().optional().meta({ markdownDescription: masterKeyLog_default }),
1169
+ echServerKeys: z.string().optional().meta({ markdownDescription: echServerKeys_default }),
1170
+ echConfigList: z.string().optional().meta({ markdownDescription: echConfigList_default }),
1171
+ echSockopt: sockopt.optional().meta({ markdownDescription: echSockopt_default })
1172
+ }).optional().meta({ markdownDescription: tlsSettings_default })
1173
+ }).meta({ markdownDescription: tls_default });
1174
+ //#endregion
1175
+ //#region src/transport/security/reality/reality.md?raw
1176
+ var reality_default = "REALITY is a modified form of TLS that uses the appearance and handshake characteristics of a target site as camouflage.\n\nREALITY can only be used together with the `RAW`, `XHTTP`, and `gRPC` transport methods.\n\n[Documentation ↗](https://xtls.github.io/en/config/transports/reality.html)\n";
1177
+ //#endregion
1178
+ //#region src/transport/security/reality/realitySettings.md?raw
1179
+ var realitySettings_default = "`RealityObject` corresponds to the `realitySettings`.\n\nThe object supports both inbound (server-side) settings and outbound (client-side) settings.\n\n[Documentation ↗](https://xtls.github.io/en/config/transports/reality.html)\n";
1180
+ //#endregion
1181
+ //#region src/transport/security/reality/show.md?raw
1182
+ var show_default = "When set to `true`, debug information is printed.\n\n### TIP\n\nThis field is for inbound (server-side) configuration.\n";
1183
+ //#endregion
1184
+ //#region src/transport/security/reality/target.md?raw
1185
+ var target_default = "Required inbound (server-side) target destination.\n\nThe format is the same as VLESS fallback `dest`. The old name was `dest`; in current versions the two fields are aliases.\n\nThe core decides whether the current configuration is client-side or server-side based on whether this field exists. Do not fill it in on the client side, or it will cause incorrect detection.\n\nIf `target` supports the post-quantum key-exchange algorithm `X25519MLKEM768`, the REALITY client also automatically uses that algorithm for key negotiation.\n\nYou can check support with `xray tls ping cloudflare.com`, replacing the domain with your `target` and optionally including a port.\n\n### WARNING\n\nFor camouflage reasons, Xray directly forwards traffic that fails authentication to `target`. If the IP address of the target site is special, your server may effectively become a port forwarder for that service and may be abused after scanning.\n";
1186
+ //#endregion
1187
+ //#region src/transport/security/reality/xver.md?raw
1188
+ var xver_default = "Optional version field for fallback behavior.\n\nThe format is the same as VLESS fallback `xver`.\n";
1189
+ //#endregion
1190
+ //#region src/transport/security/reality/serverNames.md?raw
1191
+ var serverNames_default = "Required inbound (server-side) list of allowed `serverName` values for clients.\n\n`*` wildcards are not supported.\n\nUsually this should stay consistent with `target`. Valid values are any SNI accepted by the server according to the behavior of `target`, and typically refer to the SAN values on the returned certificate.\n\nThe list may contain an empty string `\"\"`, meaning connections without SNI are accepted. In that case, the client-side `serverName` cannot be empty and should instead be filled with any valid IP address as a placeholder.\n";
1192
+ //#endregion
1193
+ //#region src/transport/security/reality/privateKey.md?raw
1194
+ var privateKey_default = "Required server-side private key.\n\nGenerate it with `./xray x25519`.\n";
1195
+ //#endregion
1196
+ //#region src/transport/security/reality/minClientVer.md?raw
1197
+ var minClientVer_default = "Optional minimum Xray client version in `x.y.z` format.\n";
1198
+ //#endregion
1199
+ //#region src/transport/security/reality/maxClientVer.md?raw
1200
+ var maxClientVer_default = "Optional maximum Xray client version in `x.y.z` format.\n";
1201
+ //#endregion
1202
+ //#region src/transport/security/reality/maxTimeDiff.md?raw
1203
+ var maxTimeDiff_default = "Optional maximum allowed time difference, in milliseconds.\n";
1204
+ //#endregion
1205
+ //#region src/transport/security/reality/shortIds.md?raw
1206
+ var shortIds_default = "Required server-side list of available `shortId` values for clients.\n\nSee the `shortId` field for the required format.\n\nIf the list contains an empty string, the client-side `shortId` may also be empty.\n";
1207
+ //#endregion
1208
+ //#region src/transport/security/reality/mldsa65Seed.md?raw
1209
+ var mldsa65Seed_default = "Server-side private key used to add an extra post-quantum signature to the certificate sent to the REALITY client, using ML-DSA-65.\n\nGenerate the keypair with `xray mldsa65`.\n\nAfter the server is configured with the private key, the signature is added only as a certificate extension, so it does not affect old clients or clients that do not enable this feature.\n\nThe target certificate must be larger than 3500 bytes because the post-quantum signature makes the temporary REALITY certificate larger.\n\nTo avoid becoming a fingerprint, the `target` certificate also needs to be large.\n";
1210
+ //#endregion
1211
+ //#region src/transport/security/reality/limitFallbackObject.md?raw
1212
+ var limitFallbackObject_default = "Optional rate-limit settings for fallback REALITY connections that fail verification.\n\nThis object is used for both upload and download fallback limits.\n\nThe limiter starts after the specified number of bytes has been transmitted. The bucket capacity is `burstBytesPerSec`. Each transmitted byte consumes one token. The bucket starts full with `burstBytesPerSec` tokens and is refilled with `bytesPerSec` tokens every second until full.\n\n### WARNING\n\nFallback rate limiting is itself a fingerprint and is not recommended unless you need it.\n";
1213
+ //#endregion
1214
+ //#region src/transport/security/reality/limitFallbackUpload.md?raw
1215
+ var limitFallbackUpload_default = "Optional rate limit for fallback REALITY connections that fail verification.\n\nThis object applies to upload traffic.\n\nThe rate limiter starts after the specified number of bytes has been transmitted. The bucket capacity is `burstBytesPerSec`. Each transmitted byte consumes one token. The bucket starts full with `burstBytesPerSec` tokens and is refilled with `bytesPerSec` tokens every second until full.\n\n### WARNING\n\nFallback rate limiting is itself a fingerprint and is not recommended unless you need it.\n";
1216
+ //#endregion
1217
+ //#region src/transport/security/reality/limitFallbackDownload.md?raw
1218
+ var limitFallbackDownload_default = "Optional rate limit for fallback REALITY connections that fail verification.\n\nThis object applies to download traffic.\n\nThe rate limiter starts after the specified number of bytes has been transmitted. The bucket capacity is `burstBytesPerSec`. Each transmitted byte consumes one token. The bucket starts full with `burstBytesPerSec` tokens and is refilled with `bytesPerSec` tokens every second until full.\n\n### WARNING\n\nFallback rate limiting is itself a fingerprint and is not recommended unless you need it.\n";
1219
+ //#endregion
1220
+ //#region src/transport/security/reality/afterBytes.md?raw
1221
+ var afterBytes_default = "Starts rate limiting fallback REALITY connections only after the specified number of bytes has been transmitted. The default is `0`.\n";
1222
+ //#endregion
1223
+ //#region src/transport/security/reality/bytesPerSec.md?raw
1224
+ var bytesPerSec_default = "Base rate limit for fallback REALITY connections, in bytes per second. The default is `0`, meaning disabled.\n";
1225
+ //#endregion
1226
+ //#region src/transport/security/reality/burstBytesPerSec.md?raw
1227
+ var burstBytesPerSec_default = "Burst rate limit for fallback REALITY connections, in bytes per second. It takes effect when it is greater than `bytesPerSec`.\n\nIf you do not want bursts, set this field to `0`.\n";
1228
+ //#endregion
1229
+ //#region src/transport/security/reality/serverName.md?raw
1230
+ var serverName_default = "Outbound client-side `serverName`.\n\nOne of the server-side `serverNames`.\n\nThe client can also set this to any IP address. In that case Xray sends a Client Hello without an SNI extension. To use this feature, the server-side `serverNames` must contain an empty string `\"\"`.\n";
1231
+ //#endregion
1232
+ //#region src/transport/security/reality/fingerprint.md?raw
1233
+ var fingerprint_default = "Required outbound client-side fingerprint.\n\nSame as `TLSObject`. Note that `unsafe`, which disables uTLS for TLS, is not supported here because REALITY relies on that library to manipulate lower-level TLS parameters.\n\n### TIP\n\nWhen enabled, some TLS options that affect TLS fingerprints are overridden by the underlying uTLS behavior.\n";
1234
+ //#endregion
1235
+ //#region src/transport/security/reality/shortId.md?raw
1236
+ var shortId_default = "Outbound client-side `shortId`.\n\nOne of the server-side `shortIds`.\n\nIts length is 8 bytes, which means up to 16 hexadecimal characters in the range `0` to `f`. It may be shorter than 16 characters, and the core pads trailing zeroes automatically, but the number of characters must be even.\n\nIf the server-side `shortIds` contains an empty string, the client-side value may also be empty.\n";
1237
+ //#endregion
1238
+ //#region src/transport/security/reality/password.md?raw
1239
+ var password_default$1 = "Required outbound client-side public key corresponding to the server private key.\n\nGenerate it with `./xray x25519 -i \"server private key\"`.\n\nThe old field name was `publicKey`, but it was renamed to avoid misunderstanding.\n";
1240
+ //#endregion
1241
+ //#region src/transport/security/reality/publicKey.md?raw
1242
+ var publicKey_default = "Deprecated alias for the outbound client-side public key corresponding to the server private key.\n\nGenerate it with `./xray x25519 -i \"server private key\"`.\n\nUse `password` instead.\n";
1243
+ //#endregion
1244
+ //#region src/transport/security/reality/mldsa65Verify.md?raw
1245
+ var mldsa65Verify_default = "Optional public key used for `mldsa65` signature verification.\n\nWhen non-empty, Xray uses it to verify the certificate returned by the server.\n";
1246
+ //#endregion
1247
+ //#region src/transport/security/reality/spiderX.md?raw
1248
+ var spiderX_default = "Initial crawler path and parameters.\n\nIt is recommended that each client use a different value.\n";
1249
+ //#endregion
1250
+ //#region src/transport/security/reality/reality.ts
1251
+ const limitFallbackObject = z.object({
1252
+ afterBytes: z.number().int().nonnegative().default(0).optional().meta({ markdownDescription: afterBytes_default }),
1253
+ bytesPerSec: z.number().int().nonnegative().default(0).optional().meta({ markdownDescription: bytesPerSec_default }),
1254
+ burstBytesPerSec: z.number().int().nonnegative().default(0).optional().meta({ markdownDescription: burstBytesPerSec_default })
1255
+ }).optional().meta({ markdownDescription: limitFallbackObject_default });
1256
+ const realitySettingsServer = z.object({
1257
+ show: z.boolean().default(false).optional().meta({ markdownDescription: show_default }),
1258
+ target: z.string().min(1).optional().meta({ markdownDescription: target_default }),
1259
+ dest: z.string().min(1).optional().meta({ markdownDescription: target_default }),
1260
+ xver: z.number().default(0).optional().meta({ markdownDescription: xver_default }),
1261
+ serverNames: z.array(z.string()).min(1).meta({ markdownDescription: serverNames_default }),
1262
+ privateKey: z.string().min(1).meta({ markdownDescription: privateKey_default }),
1263
+ minClientVer: z.string().optional().meta({ markdownDescription: minClientVer_default }),
1264
+ maxClientVer: z.string().optional().meta({ markdownDescription: maxClientVer_default }),
1265
+ maxTimeDiff: z.number().int().nonnegative().default(0).optional().meta({ markdownDescription: maxTimeDiff_default }),
1266
+ shortIds: z.array(z.string()).min(1).meta({ markdownDescription: shortIds_default }),
1267
+ mldsa65Seed: z.string().default("").optional().meta({ markdownDescription: mldsa65Seed_default }),
1268
+ limitFallbackUpload: limitFallbackObject.optional().meta({ markdownDescription: limitFallbackUpload_default }),
1269
+ limitFallbackDownload: limitFallbackObject.optional().meta({ markdownDescription: limitFallbackDownload_default })
1270
+ });
1271
+ const base = z.object({
1272
+ serverName: z.string().optional().meta({ markdownDescription: serverName_default }),
1273
+ fingerprint: fingerprintSchema.optional().meta({ markdownDescription: fingerprint_default }),
1274
+ shortId: z.string().meta({ markdownDescription: shortId_default }),
1275
+ mldsa65Verify: z.string().optional().meta({ markdownDescription: mldsa65Verify_default }),
1276
+ spiderX: z.string().optional().meta({ markdownDescription: spiderX_default })
1277
+ });
1278
+ const realitySettingsClient = z.union([base.merge(z.object({ password: z.string().meta({ markdownDescription: password_default$1 }) })), base.merge(z.object({ publicKey: z.string().meta({ markdownDescription: publicKey_default }) }))]);
1279
+ const reality = z.object({
1280
+ security: z.literal("reality").meta({ markdownDescription: securityField_default }),
1281
+ realitySettings: realitySettingsServer.or(realitySettingsClient).meta({ markdownDescription: realitySettings_default })
1282
+ }).meta({ markdownDescription: reality_default });
1283
+ //#endregion
1284
+ //#region src/transport/xhttp/xhttp.md?raw
1285
+ var xhttp_default = "XHTTP provides HTTP-based transport with full upstream/downstream separation, header padding, and XMUX multiplexing. It supports multiple modes and is designed to bypass HTTP middleboxes while maintaining high downstream efficiency.\n\nDefaults are tuned for practical use. In most cases, setting `path` is sufficient.\n\nXHTTP defaults to multiplexing and typically yields lower latency than Vision; multithread throughput can be improved by setting XMUX `maxConcurrency` to 1 for speed tests.\n\nFor maximum compatibility with HTTP middleboxes or reverse proxies, prefer the `packet-up` mode.\n\nDo not enable mux.cool when using XHTTP; the server only accepts pure XUDP.\n\nIf you need to confirm the HTTP version, host, XHTTP mode, or upstream/downstream separation, set the log level to `info`.\n\nXHTTP is currently documented in the upstream discussion: https://github.com/XTLS/Xray-core/discussions/4113\n";
1286
+ //#endregion
1287
+ //#region src/transport/xhttp/xhttpSettings.md?raw
1288
+ var xhttpSettings_default = "`XHTTPObject` corresponds to the `xhttpSettings` item in `StreamSettingsObject`.\n\nOnly `host`, `path`, and `mode` are used directly; all other parameters must be provided through `extra`.\n";
1289
+ //#endregion
1290
+ //#region src/transport/xhttp/host.md?raw
1291
+ var host_default = "Host behavior matches other HTTP-based transports. Client send priority is `host` > `serverName` > `address`.\n\nIf the server sets `host`, it will verify the client value matches; otherwise it will not check.\n\n`host` must not be set inside `headers`, and it is generally recommended to leave it unset unless needed.\n";
1292
+ //#endregion
1293
+ //#region src/transport/xhttp/path.md?raw
1294
+ var path_default = "The path used by XHTTP. In most cases, only `path` needs to be set.\n\nFor stream-one, a trailing `/` is required and will be added automatically if missing.\n\nIn packet-up and stream-up, the UUID and sequence are encoded in the path (not in the query string) to avoid compatibility issues.\n";
1295
+ //#endregion
1296
+ //#region src/transport/xhttp/mode.md?raw
1297
+ var mode_default = "`mode` controls how XHTTP uploads. For maximum compatibility with middleboxes/CDNs, use `\"packet-up\"`.\n\nDefault `auto` behavior:\n\n- Client: TLS H2 uses `stream-up`; REALITY uses `stream-one` (but uses `stream-up` when `downloadSettings` is present); otherwise uses `packet-up`.\n- Server: accepts all three modes by default. If set to a specific mode, it only accepts that mode, except `\"stream-up\"` also accepts `\"stream-one\"`.\n";
1298
+ //#endregion
1299
+ //#region src/transport/xhttp/extra.md?raw
1300
+ var extra_default = "`extra` is a raw JSON sharing bundle for all parameters except `host`, `path`, and `mode`.\n\nWhen `extra` is present, only `host`, `path`, `mode`, and `extra` itself take effect. The extra parameters are intended to be provided by the service operator and not edited by clients.\n";
1301
+ //#endregion
1302
+ //#region src/transport/xhttp/extraHeaders.md?raw
1303
+ var extraHeaders_default = "Additional HTTP headers. `host` must not be set here.\n";
1304
+ //#endregion
1305
+ //#region src/transport/xhttp/xPaddingBytes.md?raw
1306
+ var xPaddingBytes_default = "Header padding length for request and response headers. Default range is `\"100-1000\"`, randomized per request/response.\n\nRequest padding is included in `Referer: ...?x_padding=...` and response padding is in `X-Padding`.\n\nIn packet-up mode, the Referer padding can produce long logs; consider suppressing those logs in reverse proxies.\n";
1307
+ //#endregion
1308
+ //#region src/transport/xhttp/noGRPCHeader.md?raw
1309
+ var noGRPCHeader_default = "Client-only. When `false` (default), stream-up/stream-one uploads include `Content-Type: application/grpc` for camouflage.\n\nSet to `true` to disable the gRPC header.\n";
1310
+ //#endregion
1311
+ //#region src/transport/xhttp/noSSEHeader.md?raw
1312
+ var noSSEHeader_default = "Server-only. When `false` (default), downstream responses include `Content-Type: text/event-stream` for compatibility.\n\nSet to `true` to disable the SSE header.\n";
1313
+ //#endregion
1314
+ //#region src/transport/xhttp/scMaxEachPostBytes.md?raw
1315
+ var scMaxEachPostBytes_default = "Packet-up only. Maximum bytes per POST. Default is `1000000` (1 MB). Must be smaller than the CDN/middlebox maximum; the server rejects larger posts.\n\nSupports a range string (for example `\"500000-1000000\"`) to randomize per request.\n";
1316
+ //#endregion
1317
+ //#region src/transport/xhttp/scMinPostsIntervalMs.md?raw
1318
+ var scMinPostsIntervalMs_default = "Packet-up, client-only. Minimum interval between POSTs for a single proxy request. Default is `30` ms.\n\nSupports a range string to randomize per request.\n";
1319
+ //#endregion
1320
+ //#region src/transport/xhttp/scMaxBufferedPosts.md?raw
1321
+ var scMaxBufferedPosts_default = "Packet-up, server-only. Maximum buffered POSTs per single proxy request. Default is `30`; exceeding it drops the connection.\n";
1322
+ //#endregion
1323
+ //#region src/transport/xhttp/scStreamUpServerSecs.md?raw
1324
+ var scStreamUpServerSecs_default = "Stream-up, server-only. Default is `\"20-80\"` seconds; the server sends `xPaddingBytes` periodically to keep downstream alive.\n\nSet to `-1` to disable; the server may delay response headers to match earlier behavior.\n";
1325
+ //#endregion
1326
+ //#region src/transport/xhttp/xmux.md?raw
1327
+ var xmux_default = "XMUX controls H2/H3 multiplexing for XHTTP. All XMUX fields are client-only and can be randomized using range strings where allowed.\n\nDefaults apply only when **all** XMUX fields are `0`. If any field is set, the others have no defaults and must be provided.\n\nDo not enable mux.cool with XHTTP; server only accepts pure XUDP.\n";
1328
+ //#endregion
1329
+ //#region src/transport/xhttp/maxConcurrency.md?raw
1330
+ var maxConcurrency_default = "Maximum concurrent proxy requests per TCP/QUIC connection. When reached, the core opens a new connection.\n\nDefault (when all XMUX fields are `0`) is `\"16-32\"`, randomized.\n";
1331
+ //#endregion
1332
+ //#region src/transport/xhttp/maxConnections.md?raw
1333
+ var maxConnections_default = "Maximum simultaneous connections. Before this limit is reached, each new proxy request opens a new connection. Conflicts with `maxConcurrency`.\n\nDefault is `0` (no limit). Supports range strings.\n";
1334
+ //#endregion
1335
+ //#region src/transport/xhttp/cMaxReuseTimes.md?raw
1336
+ var cMaxReuseTimes_default = "Maximum reuse count for a connection. After reaching this number, the connection receives no new requests and closes after the last internal request.\n\nDefault is `0` (no limit). Supports range strings.\n";
1337
+ //#endregion
1338
+ //#region src/transport/xhttp/hMaxRequestTimes.md?raw
1339
+ var hMaxRequestTimes_default = "Maximum HTTP requests per TCP/QUIC connection. This counts HTTP requests (stream-one = 1, stream-up = 2, packet-up = N).\n\nDefault (when all XMUX fields are `0`) is `\"600-900\"`, randomized. Otherwise default is `0` (no limit).\n\nCounting is not strict and GET retries may occur, so avoid setting the maximum too tightly.\n";
1340
+ //#endregion
1341
+ //#region src/transport/xhttp/hMaxReusableSecs.md?raw
1342
+ var hMaxReusableSecs_default = "Maximum time (seconds) a connection can be reused. After this time, it will receive no new requests and closes after the last request.\n\nDefault (when all XMUX fields are `0`) is `\"1800-3000\"`, randomized. Otherwise default is `0` (no limit).\n";
1343
+ //#endregion
1344
+ //#region src/transport/xhttp/hKeepAlivePeriod.md?raw
1345
+ var hKeepAlivePeriod_default = "Idle keepalive period in seconds for H2/H3. Default is `0` (Chrome H2 45s or quic-go H3 10s).\n\nThis field cannot be a range; negative values are allowed (for example `-1` disables idle keepalives). Recommended to keep `0`.\n";
1346
+ //#endregion
1347
+ //#region src/transport/xhttp/downloadSettings.md?raw
1348
+ var downloadSettings_default = "Client-only. Separate downstream `streamSettings` for upstream/downstream separation, with `address` and `port` pointing to another entry.\n\n`network` must be `\"xhttp\"` and cannot be omitted. `security` must be `\"tls\"` or `\"reality\"`.\n\n`xhttpSettings.path` must match the upstream `path`. Downstream settings are independent from upstream except for the `sockopt.penetrate` override behavior.\n";
1349
+ //#endregion
1350
+ //#region src/transport/xhttp/downloadHost.md?raw
1351
+ var downloadHost_default = "Download-side `host` behaves the same as the main `host` field. Client send priority is `host` > `serverName` > `address`.\n\nIf the server sets `host`, it will verify the client value matches; otherwise it will not check.\n\n`host` must not be set inside `headers`, and it is generally recommended to leave it unset unless needed.\n";
1352
+ //#endregion
1353
+ //#region src/transport/xhttp/downloadPath.md?raw
1354
+ var downloadPath_default = "Download-side path for XHTTP. It must match the upstream `path`.\n";
1355
+ //#endregion
1356
+ //#region src/transport/xhttp/downloadMode.md?raw
1357
+ var downloadMode_default = "Download-side mode uses the same rules as the main `mode` field.\n";
1358
+ //#endregion
1359
+ //#region src/transport/xhttp/downloadAddress.md?raw
1360
+ var downloadAddress_default = "Downstream target address for separation. This points to another entry for the download path.\n";
1361
+ //#endregion
1362
+ //#region src/transport/xhttp/downloadPort.md?raw
1363
+ var downloadPort_default = "Downstream target port for separation.\n";
1364
+ //#endregion
1365
+ //#region src/transport/xhttp/downloadNetwork.md?raw
1366
+ var downloadNetwork_default = "Must be `\"xhttp\"` and cannot be omitted.\n";
1367
+ //#endregion
1368
+ //#region src/transport/xhttp/downloadXhttpSettings.md?raw
1369
+ var downloadXhttpSettings_default = "Download-side XHTTP settings. `path` must match the upstream `path`.\n";
1370
+ //#endregion
1371
+ //#region src/transport/xhttp/downloadSockopt.md?raw
1372
+ var downloadSockopt_default = "Sockopt for the download side. If the upload side sets `sockopt.penetrate` to `true`, it overrides this download-side sockopt.\n";
1373
+ //#endregion
1374
+ //#region src/transport/xhttpSettingsField.md?raw
1375
+ var xhttpSettingsField_default = "XHTTP configuration for the data stream. Only valid when `network` is `xhttp`.\n";
1376
+ //#endregion
1377
+ //#region src/transport/xhttp/xhttp.ts
1378
+ const intOrRange = z.union([z.number().int(), z.string().regex(/^-?\d+-\d+$/)]);
1379
+ const xmux = z.object({
1380
+ maxConcurrency: intOrRange.default("16-32").optional().meta({ markdownDescription: maxConcurrency_default }),
1381
+ maxConnections: intOrRange.default(0).optional().meta({ markdownDescription: maxConnections_default }),
1382
+ cMaxReuseTimes: intOrRange.default(0).optional().meta({ markdownDescription: cMaxReuseTimes_default }),
1383
+ hMaxRequestTimes: intOrRange.optional().meta({ markdownDescription: hMaxRequestTimes_default }),
1384
+ hMaxReusableSecs: intOrRange.optional().meta({ markdownDescription: hMaxReusableSecs_default }),
1385
+ hKeepAlivePeriod: z.number().int().default(0).optional().meta({ markdownDescription: hKeepAlivePeriod_default })
1386
+ }).meta({ markdownDescription: xmux_default });
1387
+ const downloadXhttpSettings = z.object({
1388
+ host: z.string().default("").optional().meta({ markdownDescription: downloadHost_default }),
1389
+ path: z.string().default("/").optional().meta({ markdownDescription: downloadPath_default }),
1390
+ mode: z.enum([
1391
+ "auto",
1392
+ "packet-up",
1393
+ "stream-up",
1394
+ "stream-one"
1395
+ ]).default("auto").optional().meta({ markdownDescription: downloadMode_default })
1396
+ }).meta({ markdownDescription: downloadXhttpSettings_default });
1397
+ const xhttpSettingsCommonFields = z.object({
1398
+ address: z.string().meta({ markdownDescription: downloadAddress_default }),
1399
+ port: z.number().int().nonnegative().meta({ markdownDescription: downloadPort_default }),
1400
+ network: z.literal("xhttp").meta({ markdownDescription: downloadNetwork_default }),
1401
+ xhttpSettings: downloadXhttpSettings.optional().meta({ markdownDescription: downloadXhttpSettings_default }),
1402
+ sockopt: sockopt.optional().meta({ markdownDescription: downloadSockopt_default })
1403
+ });
1404
+ const downloadSettings = z.discriminatedUnion("security", [tls.merge(xhttpSettingsCommonFields), reality.merge(xhttpSettingsCommonFields)]).optional();
1405
+ const extra = z.object({
1406
+ headers: z.record(z.string(), z.string()).optional().meta({ markdownDescription: extraHeaders_default }),
1407
+ xPaddingBytes: intOrRange.default("100-1000").optional().meta({ markdownDescription: xPaddingBytes_default }),
1408
+ noGRPCHeader: z.boolean().default(false).optional().meta({ markdownDescription: noGRPCHeader_default }),
1409
+ noSSEHeader: z.boolean().default(false).optional().meta({ markdownDescription: noSSEHeader_default }),
1410
+ scMaxEachPostBytes: intOrRange.optional().meta({ markdownDescription: scMaxEachPostBytes_default }),
1411
+ scMinPostsIntervalMs: intOrRange.optional().meta({ markdownDescription: scMinPostsIntervalMs_default }),
1412
+ scMaxBufferedPosts: z.number().int().optional().meta({ markdownDescription: scMaxBufferedPosts_default }),
1413
+ scStreamUpServerSecs: intOrRange.optional().meta({ markdownDescription: scStreamUpServerSecs_default }),
1414
+ xmux: xmux.optional().meta({ markdownDescription: xmux_default }),
1415
+ downloadSettings: downloadSettings.optional().meta({ markdownDescription: downloadSettings_default })
1416
+ }).passthrough().optional().meta({ markdownDescription: extra_default });
1417
+ const xhttpSettings = z.object({
1418
+ host: z.string().default("").optional().meta({ markdownDescription: host_default }),
1419
+ path: z.string().default("/").optional().meta({ markdownDescription: path_default }),
1420
+ mode: z.enum([
1421
+ "auto",
1422
+ "packet-up",
1423
+ "stream-up",
1424
+ "stream-one"
1425
+ ]).default("auto").optional().meta({ markdownDescription: mode_default }),
1426
+ extra
1427
+ }).meta({ markdownDescription: xhttpSettings_default });
1428
+ const xhttpStream = transportBase.extend({
1429
+ network: z.literal("xhttp").meta({ markdownDescription: networkField_default }),
1430
+ xhttpSettings: xhttpSettings.optional().meta({ markdownDescription: xhttpSettingsField_default })
1431
+ }).meta({ markdownDescription: xhttp_default });
1432
+ const splithttpStream = transportBase.extend({
1433
+ network: z.literal("splithttp").meta({ markdownDescription: networkField_default }),
1434
+ xhttpSettings: xhttpSettings.optional().meta({ markdownDescription: xhttpSettingsField_default })
1435
+ }).meta({ markdownDescription: xhttp_default });
1436
+ //#endregion
1437
+ //#region src/transport/transport.md?raw
1438
+ var transport_default = "Transport configuration controls how the current Xray instance communicates with its peer. That peer may be another Xray node, or it may simply be any ordinary public network target.\n\nIt covers the part below the proxy protocol itself, including transport methods, transport security, and additional low-level behavior.\n\nThese three categories belong to different layers and can usually be combined:\n\n- Transport methods specify how the data stream is carried, such as RAW, WebSocket, gRPC, Hysteria, and others.\n- Transport security specifies the protection mechanism used during transport, such as TLS or REALITY.\n- Additional configuration supplements low-level network behavior and final traffic obfuscation.\n\nSome transport settings directly affect how a connection is established with the remote side. For settings that require negotiation, both sides usually need compatible configurations. For example, if one side uses WebSocket, the other side must also use WebSocket, otherwise the connection cannot be established.\n\nFor direct outbounds such as [Freedom](https://xtls.github.io/en/config/outbounds/freedom.html), the peer is usually any ordinary public network target, such as Amazon's website or WeChat's servers. In that case, transport configuration does not need to negotiate with the other side, and generally cannot do so either. Instead, it is used to control how the local connection is sent. In that scenario, only `sockopt` is available.\n\n[Documentation ↗](https://xtls.github.io/en/config/transport.html)\n";
1439
+ //#endregion
1440
+ //#region src/transport/transport.ts
1441
+ const noSecurity = z.object({ security: z.literal("none").optional().meta({ markdownDescription: securityField_default }) });
1442
+ const mergeStreamWithOtherFields = (schema) => {
1443
+ return [
1444
+ z.object({
1445
+ ...schema.shape,
1446
+ ...reality.shape
1447
+ }),
1448
+ z.object({
1449
+ ...schema.shape,
1450
+ ...tls.shape
1451
+ }),
1452
+ z.object({
1453
+ ...schema.shape,
1454
+ ...noSecurity.shape
1455
+ })
1456
+ ];
1457
+ };
1458
+ const streamSettings = z.union([
1459
+ ...mergeStreamWithOtherFields(tcpStream),
1460
+ ...mergeStreamWithOtherFields(rawStream),
1461
+ ...mergeStreamWithOtherFields(mkcpStream),
1462
+ ...mergeStreamWithOtherFields(websocketStream),
1463
+ ...mergeStreamWithOtherFields(grpcStream),
1464
+ ...mergeStreamWithOtherFields(hysteriaStream),
1465
+ ...mergeStreamWithOtherFields(httpUpgradeStream),
1466
+ ...mergeStreamWithOtherFields(xhttpStream),
1467
+ ...mergeStreamWithOtherFields(splithttpStream)
1468
+ ]).meta({
1469
+ ifThenLogic: true,
1470
+ discriminator: "network",
1471
+ secondaryDiscriminator: "security",
1472
+ markdownDescription: transport_default
1473
+ });
1474
+ //#endregion
1475
+ //#region src/inbounds/baseInbound/tag.md?raw
1476
+ var tag_default$1 = "The identifier of this inbound connection, used to locate this connection in other configurations.\n\n### DANGER\n\nWhen it is not empty, its value must be **unique** among all `tag`s.\n";
1477
+ //#endregion
1478
+ //#region src/inbounds/baseInbound/listen.md?raw
1479
+ var listen_default = "The listening address, which can be an IP address or a Unix domain socket. The default value is `\"0.0.0.0\"`, which means listening on all network interfaces.\n\nYou can specify an IP address available on the system.\n\n`\"::\"` is equivalent to `\"0.0.0.0\"`; both will listen on IPv6 and IPv4 simultaneously. However, if you only want to listen on IPv6, you can set `v6only` in `sockopt` to true. If you only want to listen on IPv4, you can use commands like `ip a` to view the specific IP on the network card (usually the machine's public IP address or a private network address like 10.x.x.x) and listen on that. Of course, you can do the same for IPv6.\n\nNote that because UDP is not connection-oriented, if the inbound is based on UDP and there are multiple IP addresses on the network card, and the external connection is to a non-preferred address on the card, Xray might incorrectly use the preferred address as the source address for the reply instead of the target of the external connection, causing the connection to fail. The solution is not to listen on `0.0.0.0` but to listen on the specific IP address on the network card.\n\nSupports Unix domain sockets in absolute path format, such as `\"/dev/shm/domain.socket\"`. You can add `@` at the beginning to represent [abstract](https://www.man7.org/linux/man-pages/man7/unix.7.html), and `@@` for abstract with padding.\n\nWhen filling in a Unix domain socket, `port` and `allocate` will be ignored. The protocol can currently be VLESS, VMess, or Trojan, and applies only to TCP-based transport methods, such as `tcp`, `websocket`, `grpc`. UDP-based transports like `mkcp` are not supported.\n\nWhen filling in a Unix domain socket, you can use the format `\"/dev/shm/domain.socket,0666\"`, i.e., adding a comma and access permission indicators after the socket, to specify the access permissions of the socket. This can be used to solve socket permission issues that occur by default.\n";
1480
+ //#endregion
1481
+ //#region src/inbounds/baseInbound/port.md?raw
1482
+ var port_default = "Port. Accepted formats are as follows:\n\n- Integer value: The actual port number.\n- Environment variable: Starts with `\"env:\"`, followed by the name of an environment variable, such as `\"env:PORT\"`. Xray will parse this environment variable as a string.\n- String: Can be a numeric string, such as `\"1234\"`; or a numerical range, such as `\"5-10\"` indicating ports 5 to 10 (6 ports in total). Commas can be used for segmentation, such as `11,13,15-17` indicating port 11, port 13, and ports 15 to 17 (5 ports in total).\n\nWhen only one port is specified, Xray will listen for inbound connections on this port. When a port range is specified, Xray will listen on all ports within the range.\n\nNote that listening on a port is a relatively expensive operation. Listening on a port range that is too large may cause a significant increase in resource usage or even cause Xray to fail to work properly. Generally speaking, problems may begin to appear when the number of listening ports approaches four digits. If you need to use a very large range, please consider using iptables for redirection instead of setting it here.\n";
1483
+ //#endregion
1484
+ //#region src/inbounds/baseInbound/streamSettings.md?raw
1485
+ var streamSettings_default$1 = "Transport configuration for this inbound.\n";
1486
+ //#endregion
1487
+ //#region src/inbounds/baseInbound/sniffing.md?raw
1488
+ var sniffing_default = "Traffic sniffing is mainly used for transparent proxies and similar purposes. A typical flow is as follows:\n\n1. If a device accesses the internet and visits abc.com, the device first queries DNS to get the IP of abc.com as 1.2.3.4, and then the device initiates a connection to 1.2.3.4.\n2. If sniffing is not configured, the connection request received by Xray is for 1.2.3.4, which cannot be used for routing traffic based on domain rules.\n3. When `enabled` in sniffing is set to `true`, Xray will sniff the domain name, i.e., abc.com, from the traffic data when processing this connection.\n4. Xray will reset 1.2.3.4 to abc.com. The routing can then divert traffic according to the domain rules.\n\nBecause it becomes a connection requesting abc.com, more things can be done. Besides routing domain rule diversion, it can also re-perform DNS resolution and other tasks.\n\nWhen `enabled` in sniffing is set to `true`, it can also sniff Bittorrent type traffic. Then you can configure the `protocol` item in routing to set rules for handling unencrypted BT traffic. For example, the server side can be used to intercept unencrypted BT traffic, or the client side can fixedly forward BT traffic to a certain VPS, etc.\n\nNote: Newer browsers may use ECH to encrypt the Client Hello. In this case, Xray can only see the domain in the Outer Hello. You may need to consider hijacking DNS or manually disabling ECH in the browser configuration.\n\n[Documentation ↗](https://xtls.github.io/en/config/inbound.html#sniffingobject)\n";
1489
+ //#endregion
1490
+ //#region src/inbounds/baseInbound/baseInbound.ts
1491
+ const portLikeSchema = z.union([
1492
+ z.number().int().min(1).max(65535),
1493
+ z.string().regex(/^\d+(?:-\d+)?(?:,\d+(?:-\d+)?)*$/),
1494
+ z.string().regex(/^env:[A-Za-z_][A-Za-z0-9_]*$/)
1495
+ ]);
1496
+ const generalInboundSchema = z.object({
1497
+ tag: z.string().optional().meta({ markdownDescription: tag_default$1 }),
1498
+ listen: z.string().optional().meta({ markdownDescription: listen_default }),
1499
+ port: portLikeSchema.optional().meta({ markdownDescription: port_default }),
1500
+ streamSettings: streamSettings.optional().meta({ markdownDescription: streamSettings_default$1 }),
1501
+ sniffing: sniffingSchema.optional().meta({ markdownDescription: sniffing_default })
1502
+ });
1503
+ //#endregion
1504
+ //#region src/inbounds/protocols/http/http.md?raw
1505
+ var http_default = "HTTP protocol.\n\n### DANGER\n\n**The HTTP protocol does not encrypt traffic and is not suitable for transmission over the public internet. Using it exposes you to the risk of becoming a zombie for attacks.**\n\nA more meaningful usage of `http` inbound is to listen within a LAN or on the local machine to provide local services for other programs.\n\n### TIP 1\n\n`http proxy` can only proxy the TCP protocol; UDP-based protocols are not supported.\n\n### TIP 2\n\nUse the following environment variables in Linux to enable a global HTTP proxy for the current session (supported by many software, but not all).\n\n- `export http_proxy=http://127.0.0.1:8080/` (Address must be changed to your configured HTTP inbound proxy address)\n- `export https_proxy=$http_proxy`\n\n[Documentation ↗](https://xtls.github.io/en/config/inbounds/http.html)\n";
1506
+ //#endregion
1507
+ //#region src/inbounds/protocols/http/httpSettings.md?raw
1508
+ var httpSettings_default = "`InboundConfigurationObject` corresponds to the `settings` item in [`InboundObject`](https://xtls.github.io/en/config/inbound.html).\n";
1509
+ //#endregion
1510
+ //#region src/inbounds/protocols/http/users.md?raw
1511
+ var users_default$3 = "An array where each element is a user account. Default value is empty.\n\nWhen `users` is not empty, the HTTP proxy will perform Basic Authentication on inbound connections.\n";
1512
+ //#endregion
1513
+ //#region src/inbounds/protocols/http/allowTransparent.md?raw
1514
+ var allowTransparent_default = "When set to `true`, all HTTP requests will be forwarded, not just proxy requests.\n\n### TIP\n\nIf configured improperly, enabling this option can cause infinite loops.\n";
1515
+ //#endregion
1516
+ //#region src/inbounds/protocols/http/userLevel.md?raw
1517
+ var userLevel_default$4 = "User level. Connections will use the [Local Policy](https://xtls.github.io/en/config/policy.html#levelpolicyobject) corresponding to this user level.\n\nThe value of `userLevel` corresponds to the value of `level` in [policy](https://xtls.github.io/en/config/policy.html#policyobject). If not specified, the default is 0.\n";
1518
+ //#endregion
1519
+ //#region src/inbounds/protocols/http/http.ts
1520
+ const httpUserSchema = z.object({
1521
+ user: z.string().min(1).meta({ markdownDescription: "Username, string type. Required.\n" }),
1522
+ pass: z.string().min(1).meta({ markdownDescription: "Password, string type. Required.\n" })
1523
+ });
1524
+ const httpSettingsSchema = z.object({
1525
+ users: z.array(httpUserSchema).default([]).optional().meta({ markdownDescription: users_default$3 }),
1526
+ allowTransparent: z.boolean().default(false).optional().meta({ markdownDescription: allowTransparent_default }),
1527
+ userLevel: z.number().default(0).optional().meta({ markdownDescription: userLevel_default$4 })
1528
+ }).meta({ markdownDescription: httpSettings_default });
1529
+ const httpInboundSchema = generalInboundSchema.extend({
1530
+ protocol: z.literal("http"),
1531
+ settings: httpSettingsSchema.optional()
1532
+ }).meta({ markdownDescription: http_default });
1533
+ //#endregion
1534
+ //#region src/inbounds/protocols/dokodemo-door/tunnel.md?raw
1535
+ var tunnel_default = "Tunnel, formerly known as dokodemo-door (Arbitrary Door), can listen on multiple local ports and send all received data to a specific port on a specified server via an outbound, thereby achieving the effect of port mapping.\n\n[Documentation ↗](https://xtls.github.io/en/config/inbounds/tunnel.html)\n";
1536
+ //#endregion
1537
+ //#region src/inbounds/protocols/dokodemo-door/tunnelSettings.md?raw
1538
+ var tunnelSettings_default = "`InboundConfigurationObject` corresponds to the `settings` item in [`InboundObject`](https://xtls.github.io/en/config/inbound.html).\n";
1539
+ //#endregion
1540
+ //#region src/inbounds/protocols/dokodemo-door/allowedNetwork.md?raw
1541
+ var allowedNetwork_default = "Accepted network protocol types. For example, when specified as `\"tcp\"`, only TCP traffic will be received. Default value is `\"tcp\"`.\n";
1542
+ //#endregion
1543
+ //#region src/inbounds/protocols/dokodemo-door/rewriteAddress.md?raw
1544
+ var rewriteAddress_default = "Forward traffic to this address. It can be an IP address, like `\"1.2.3.4\"`, or a domain name, like `\"xray.com\"`. String type, defaults to `\"localhost\"`.\n";
1545
+ //#endregion
1546
+ //#region src/inbounds/protocols/dokodemo-door/rewritePort.md?raw
1547
+ var rewritePort_default = "Forward traffic to the specified port of the target address. Range `[0, 65535]`, numeric type. If omitted or 0, it defaults to the listening port.\n";
1548
+ //#endregion
1549
+ //#region src/inbounds/protocols/dokodemo-door/portMap.md?raw
1550
+ var portMap_default = "A map mapping local ports to required remote addresses/ports (if the inbound listens on multiple ports). If the local port is not included in this map, it is handled according to the `rewriteAddress`/`rewritePort` settings.\n";
1551
+ //#endregion
1552
+ //#region src/inbounds/protocols/dokodemo-door/followRedirect.md?raw
1553
+ var followRedirect_default = "When set to `true`, dokodemo-door will recognize data forwarded by iptables and forward it to the corresponding target address.\n\nPlease refer to the `tproxy` setting in [Sockopt](https://xtls.github.io/en/config/transports/sockopt.html#sockoptobject).\n";
1554
+ //#endregion
1555
+ //#region src/inbounds/protocols/dokodemo-door/userLevel.md?raw
1556
+ var userLevel_default$3 = "User level. Connections will use the [Local Policy](https://xtls.github.io/en/config/policy.html#levelpolicyobject) corresponding to this user level.\n\nThe value of `userLevel` corresponds to the value of `level` in [policy](https://xtls.github.io/en/config/policy.html#policyobject). If not specified, it defaults to 0.\n";
1557
+ //#endregion
1558
+ //#region src/inbounds/protocols/dokodemo-door/usage.md?raw
1559
+ var usage_default = "## Usage\n\nThe \"Arbitrary Door\" has two main uses: one is for transparent proxy (see below), and the other is for mapping a port.\n\nSometimes some services do not support forward proxies like Socks5, and using Tun or Tproxy is overkill. If these services only communicate with a single IP and port (e.g., iperf, Minecraft server, Wireguard endpoint), you can use dokodemo-door.\n\nIn this case, the core will listen on the configured local address/port and forward it to the target address/port via the default outbound. Connecting to the local address/port is equivalent to connecting to the target via a proxy.\n";
1560
+ //#endregion
1561
+ //#region src/inbounds/protocols/dokodemo-door/transparentProxy.md?raw
1562
+ var transparentProxy_default = "## Transparent Proxy Configuration Example\n\nFor this section, please refer to [Transparent Proxy (TProxy) Configuration Tutorial](https://xtls.github.io/en/document/level-2/tproxy.html).\n";
1563
+ //#endregion
1564
+ //#region src/inbounds/protocols/dokodemo-door/dokodemo-door.ts
1565
+ const tunnelSettingsSchema = z.object({
1566
+ allowedNetwork: z.enum([
1567
+ "tcp",
1568
+ "udp",
1569
+ "tcp,udp"
1570
+ ]).default("tcp").optional().meta({ markdownDescription: allowedNetwork_default }),
1571
+ rewriteAddress: z.string().default("localhost").optional().meta({ markdownDescription: rewriteAddress_default }),
1572
+ rewritePort: z.number().int().min(0).max(65535).optional().meta({ markdownDescription: rewritePort_default }),
1573
+ portMap: z.record(z.string(), z.string()).optional().meta({ markdownDescription: portMap_default }),
1574
+ followRedirect: z.boolean().default(false).optional().meta({ markdownDescription: followRedirect_default }),
1575
+ userLevel: z.number().default(0).optional().meta({ markdownDescription: userLevel_default$3 })
1576
+ }).meta({ markdownDescription: tunnelSettings_default });
1577
+ const dokodemoDoorInboundSchema = generalInboundSchema.extend({
1578
+ protocol: z.literal("dokodemo-door").or(z.literal("tunnel")),
1579
+ settings: tunnelSettingsSchema
1580
+ }).meta({ markdownDescription: [
1581
+ tunnel_default,
1582
+ "\n",
1583
+ usage_default,
1584
+ "\n",
1585
+ transparentProxy_default
1586
+ ].join("\n") });
1587
+ //#endregion
1588
+ //#region src/inbounds/protocols/socks/socks.md?raw
1589
+ var socks_default$1 = "Standard Socks protocol inbound, compatible with [Socks 4](http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol), [Socks 4a](https://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4A.protocol), Socks 5, and **HTTP**.\n\n**DANGER**: The Socks protocol does not encrypt transmission and is not suitable for the public internet.\n\n[Documentation ↗](https://xtls.github.io/en/config/inbounds/socks.html)\n";
1590
+ //#endregion
1591
+ //#region src/inbounds/protocols/socks/socksSettings.md?raw
1592
+ var socksSettings_default$1 = "`InboundConfigurationObject` corresponds to the `settings` item in [`InboundObject`](https://xtls.github.io/en/config/inbound.html).\n";
1593
+ //#endregion
1594
+ //#region src/inbounds/protocols/socks/auth.md?raw
1595
+ var auth_default = "Authentication method. Supports `\"noauth\"` (anonymous) and `\"password\"` (user/password).\n\nWhen using `\"password\"`, HTTP requests sent to this inbound also require the same account and password.\n\nDefault value is `\"noauth\"`.\n";
1596
+ //#endregion
1597
+ //#region src/inbounds/protocols/socks/users.md?raw
1598
+ var users_default$2 = "Array of Socks user accounts. Only valid when `auth` is set to `\"password\"`.\n\nDefault value is an empty array.\n";
1599
+ //#endregion
1600
+ //#region src/inbounds/protocols/socks/udp.md?raw
1601
+ var udp_default = "Whether to enable UDP protocol support.\n\nDefault value is `false`.\n";
1602
+ //#endregion
1603
+ //#region src/inbounds/protocols/socks/ip.md?raw
1604
+ var ip_default = "When UDP is enabled, Xray needs to know the IP address of the local machine.\n\nThe IP address should be the address the client can use to reach the server when initiating a UDP connection. By default, it is the local IP used by the TCP connection.\n\nIf your machine has multiple IP addresses, be aware of the UDP listening behavior for `0.0.0.0` described in [Inbound Listening](https://xtls.github.io/en/config/inbound.html#inboundobject).\n";
1605
+ //#endregion
1606
+ //#region src/inbounds/protocols/socks/userLevel.md?raw
1607
+ var userLevel_default$2 = "User level for connections. The value maps to the `level` field in [Policy](https://xtls.github.io/en/config/policy.html#policyobject).\n\nDefault value is `0`.\n";
1608
+ //#endregion
1609
+ //#region src/inbounds/protocols/socks/user.md?raw
1610
+ var user_default = "Username for Socks authentication. Required.\n";
1611
+ //#endregion
1612
+ //#region src/inbounds/protocols/socks/pass.md?raw
1613
+ var pass_default = "Password for Socks authentication. Required.\n";
1614
+ //#endregion
1615
+ //#region src/inbounds/protocols/socks/socks.ts
1616
+ const socksSettingsBaseSchema = z.object({
1617
+ udp: z.boolean().default(false).optional().meta({ markdownDescription: udp_default }),
1618
+ ip: z.string().optional().meta({ markdownDescription: ip_default }),
1619
+ userLevel: z.number().default(0).optional().meta({ markdownDescription: userLevel_default$2 })
1620
+ });
1621
+ const socksAccount = z.object({
1622
+ user: z.string().min(1).meta({ markdownDescription: user_default }),
1623
+ pass: z.string().min(1).meta({ markdownDescription: pass_default })
1624
+ });
1625
+ const socksSettingsSchema = z.discriminatedUnion("auth", [socksSettingsBaseSchema.extend({ auth: z.literal("noauth").meta({ markdownDescription: auth_default }).optional() }).loose(), socksSettingsBaseSchema.extend({
1626
+ auth: z.literal("password").meta({ markdownDescription: auth_default }),
1627
+ users: z.array(socksAccount).default([]).optional().meta({ markdownDescription: users_default$2 })
1628
+ }).loose()]).meta({ markdownDescription: socksSettings_default$1 });
1629
+ const socksInboundSchema = generalInboundSchema.extend({
1630
+ protocol: z.literal("socks").or(z.literal("mixed")),
1631
+ settings: socksSettingsSchema.optional()
1632
+ }).meta({ markdownDescription: socks_default$1 });
1633
+ //#endregion
1634
+ //#region src/inbounds/snippets/inbound-snippets.ts
1635
+ const snippetModules = /* #__PURE__ */ Object.assign({
1636
+ "../protocols/dokodemo-door/snippets/dokodemo-door-basic.json": {
1637
+ label: "Tunnel (dokodemo-door)",
1638
+ description: "Simple port mapping inbound",
1639
+ body: {
1640
+ "protocol": "tunnel",
1641
+ "listen": "127.0.0.1",
1642
+ "port": 8080,
1643
+ "tag": "TUNNEL-IN",
1644
+ "settings": {
1645
+ "allowedNetwork": "tcp",
1646
+ "rewriteAddress": "${1:example.com}",
1647
+ "rewritePort": "${2:80}",
1648
+ "followRedirect": false,
1649
+ "userLevel": 0
1650
+ }
1651
+ }
1652
+ },
1653
+ "../protocols/hysteria/snippets/hysteria2-server.json": {
1654
+ label: "Hysteria2 + TLS (server)",
1655
+ description: "Hysteria2 minimal server inbound (Xray-examples)",
1656
+ body: {
1657
+ "protocol": "hysteria",
1658
+ "listen": "0.0.0.0",
1659
+ "port": 11451,
1660
+ "tag": "IN-Hysteria2",
1661
+ "settings": { "version": 2 },
1662
+ "streamSettings": {
1663
+ "network": "hysteria",
1664
+ "security": "tls",
1665
+ "tlsSettings": {
1666
+ "serverName": "${1:example.com}",
1667
+ "alpn": ["h3"],
1668
+ "certificates": [{
1669
+ "usage": "encipherment",
1670
+ "certificateFile": "${2:/path/to/cert.pem}",
1671
+ "keyFile": "${3:/path/to/key.pem}"
1672
+ }]
1673
+ },
1674
+ "hysteriaSettings": {
1675
+ "version": 2,
1676
+ "auth": "${4:password}"
1677
+ }
1678
+ }
1679
+ }
1680
+ },
1681
+ "../protocols/shadowsocks/snippets/shadowsocks-2022-tcp.json": {
1682
+ label: "Shadowsocks (2022-blake3-aes-128-gcm)",
1683
+ description: "Shadowsocks 2022 AEAD inbound",
1684
+ body: {
1685
+ "protocol": "shadowsocks",
1686
+ "listen": "0.0.0.0",
1687
+ "port": 8388,
1688
+ "tag": "SS-2022-TCP",
1689
+ "settings": {
1690
+ "network": "tcp,udp",
1691
+ "method": "2022-blake3-aes-128-gcm",
1692
+ "password": "${1:base64key}",
1693
+ "level": 0,
1694
+ "users": []
1695
+ },
1696
+ "sniffing": {
1697
+ "enabled": true,
1698
+ "routeOnly": true,
1699
+ "destOverride": [
1700
+ "http",
1701
+ "tls",
1702
+ "quic",
1703
+ "fakedns"
1704
+ ]
1705
+ }
1706
+ }
1707
+ },
1708
+ "../protocols/shadowsocks/snippets/shadowsocks-aes-128-gcm-tcp.json": {
1709
+ label: "Shadowsocks (aes-128-gcm)",
1710
+ description: "Shadowsocks AEAD inbound over TCP",
1711
+ body: {
1712
+ "protocol": "shadowsocks",
1713
+ "listen": "0.0.0.0",
1714
+ "port": 8388,
1715
+ "tag": "SS-AES128-TCP",
1716
+ "settings": {
1717
+ "network": "tcp,udp",
1718
+ "method": "aes-128-gcm"
1719
+ },
1720
+ "sniffing": {
1721
+ "enabled": true,
1722
+ "routeOnly": true,
1723
+ "destOverride": [
1724
+ "http",
1725
+ "tls",
1726
+ "quic",
1727
+ "fakedns"
1728
+ ]
1729
+ }
1730
+ }
1731
+ },
1732
+ "../protocols/shadowsocks/snippets/shadowsocks-none-tcp.json": {
1733
+ label: "Shadowsocks (none)",
1734
+ description: "Shadowsocks inbound with no encryption (not for public networks)",
1735
+ body: {
1736
+ "protocol": "shadowsocks",
1737
+ "listen": "0.0.0.0",
1738
+ "port": 8388,
1739
+ "tag": "SS-NONE-TCP",
1740
+ "settings": {
1741
+ "network": "tcp,udp",
1742
+ "method": "none"
1743
+ },
1744
+ "sniffing": {
1745
+ "enabled": true,
1746
+ "routeOnly": true,
1747
+ "destOverride": [
1748
+ "http",
1749
+ "tls",
1750
+ "quic",
1751
+ "fakedns"
1752
+ ]
1753
+ }
1754
+ }
1755
+ },
1756
+ "../protocols/socks/snippets/socks-local-7890.json": {
1757
+ label: "Socks (127.0.0.1:7890)",
1758
+ description: "Local SOCKS inbound",
1759
+ body: {
1760
+ "protocol": "socks",
1761
+ "listen": "127.0.0.1",
1762
+ "port": 7890,
1763
+ "tag": "SOCKS-LOCAL",
1764
+ "settings": {
1765
+ "auth": "noauth",
1766
+ "udp": true
1767
+ },
1768
+ "sniffing": {
1769
+ "enabled": true,
1770
+ "routeOnly": true,
1771
+ "destOverride": [
1772
+ "http",
1773
+ "tls",
1774
+ "quic",
1775
+ "fakedns"
1776
+ ]
1777
+ }
1778
+ }
1779
+ },
1780
+ "../protocols/trojan/snippets/trojan-grpc-tls.json": {
1781
+ label: "Trojan + gRPC + TLS",
1782
+ description: "Trojan inbound over gRPC with TLS",
1783
+ body: {
1784
+ "protocol": "trojan",
1785
+ "listen": "0.0.0.0",
1786
+ "port": 443,
1787
+ "tag": "TROJAN-GRPC-TLS",
1788
+ "settings": { "users": [] },
1789
+ "streamSettings": {
1790
+ "network": "grpc",
1791
+ "security": "tls",
1792
+ "tlsSettings": { "serverName": "${3:example.com}" },
1793
+ "grpcSettings": { "serviceName": "${4:grpc}" }
1794
+ },
1795
+ "sniffing": {
1796
+ "enabled": true,
1797
+ "routeOnly": true,
1798
+ "destOverride": [
1799
+ "http",
1800
+ "tls",
1801
+ "quic",
1802
+ "fakedns"
1803
+ ]
1804
+ }
1805
+ }
1806
+ },
1807
+ "../protocols/trojan/snippets/trojan-ws-tls.json": {
1808
+ label: "Trojan + WS + TLS",
1809
+ description: "Trojan inbound over WebSocket with TLS",
1810
+ body: {
1811
+ "protocol": "trojan",
1812
+ "listen": "0.0.0.0",
1813
+ "port": 443,
1814
+ "tag": "TROJAN-WS-TLS",
1815
+ "settings": { "users": [] },
1816
+ "streamSettings": {
1817
+ "network": "websocket",
1818
+ "security": "tls",
1819
+ "tlsSettings": {
1820
+ "serverName": "${3:example.com}",
1821
+ "alpn": ["h2"]
1822
+ },
1823
+ "wsSettings": {
1824
+ "path": "${4:/ws}",
1825
+ "host": "${5:example.com}"
1826
+ }
1827
+ },
1828
+ "sniffing": {
1829
+ "enabled": true,
1830
+ "routeOnly": true,
1831
+ "destOverride": [
1832
+ "http",
1833
+ "tls",
1834
+ "quic",
1835
+ "fakedns"
1836
+ ]
1837
+ }
1838
+ }
1839
+ },
1840
+ "../protocols/tun/snippets/tun-basic.json": {
1841
+ label: "TUN",
1842
+ description: "Basic TUN inbound",
1843
+ body: {
1844
+ "protocol": "tun",
1845
+ "listen": "0.0.0.0",
1846
+ "tag": "TUN-IN",
1847
+ "settings": {
1848
+ "name": "xray0",
1849
+ "mtu": 1500,
1850
+ "gateway": ["10.0.0.1/16", "fc00::1/64"],
1851
+ "dns": ["1.1.1.1", "8.8.8.8"],
1852
+ "userLevel": 0,
1853
+ "autoSystemRoutingTable": ["0.0.0.0/0", "::/0"],
1854
+ "autoOutboundsInterface": "auto"
1855
+ }
1856
+ }
1857
+ },
1858
+ "../protocols/vless/snippets/vless-grpc-tls.json": {
1859
+ label: "VLESS + gRPC + TLS",
1860
+ description: "VLESS inbound over gRPC with TLS",
1861
+ body: {
1862
+ "protocol": "vless",
1863
+ "listen": "0.0.0.0",
1864
+ "port": 443,
1865
+ "tag": "VLESS-GRPC-TLS",
1866
+ "settings": {
1867
+ "clients": [],
1868
+ "decryption": "none"
1869
+ },
1870
+ "streamSettings": {
1871
+ "network": "grpc",
1872
+ "security": "tls",
1873
+ "tlsSettings": { "serverName": "${2:example.com}" },
1874
+ "grpcSettings": { "serviceName": "${3:grpc}" }
1875
+ },
1876
+ "sniffing": {
1877
+ "enabled": true,
1878
+ "routeOnly": true,
1879
+ "destOverride": [
1880
+ "http",
1881
+ "tls",
1882
+ "quic",
1883
+ "fakedns"
1884
+ ]
1885
+ }
1886
+ }
1887
+ },
1888
+ "../protocols/vless/snippets/vless-tcp-tls.json": {
1889
+ label: "VLESS + TCP + TLS",
1890
+ description: "Minimal VLESS inbound over TCP with TLS",
1891
+ body: {
1892
+ "protocol": "vless",
1893
+ "listen": "0.0.0.0",
1894
+ "port": 443,
1895
+ "tag": "VLESS-TCP-TLS",
1896
+ "settings": {
1897
+ "clients": [],
1898
+ "decryption": "none"
1899
+ },
1900
+ "streamSettings": {
1901
+ "network": "tcp",
1902
+ "security": "tls",
1903
+ "tlsSettings": {
1904
+ "serverName": "${2:example.com}",
1905
+ "alpn": ["http/1.1", "h2"]
1906
+ }
1907
+ },
1908
+ "sniffing": {
1909
+ "enabled": true,
1910
+ "routeOnly": true,
1911
+ "destOverride": [
1912
+ "http",
1913
+ "tls",
1914
+ "quic",
1915
+ "fakedns"
1916
+ ]
1917
+ }
1918
+ }
1919
+ },
1920
+ "../protocols/vless/snippets/vless-ws-tls.json": {
1921
+ label: "VLESS + WS + TLS",
1922
+ description: "VLESS inbound over WebSocket with TLS",
1923
+ body: {
1924
+ "protocol": "vless",
1925
+ "listen": "0.0.0.0",
1926
+ "port": 443,
1927
+ "tag": "VLESS-WS-TLS",
1928
+ "settings": {
1929
+ "clients": [],
1930
+ "decryption": "none"
1931
+ },
1932
+ "streamSettings": {
1933
+ "network": "websocket",
1934
+ "security": "tls",
1935
+ "tlsSettings": {
1936
+ "serverName": "${2:example.com}",
1937
+ "alpn": ["http/1.1", "h2"]
1938
+ },
1939
+ "wsSettings": {
1940
+ "path": "${3:/ws}",
1941
+ "host": "${4:example.com}"
1942
+ }
1943
+ },
1944
+ "sniffing": {
1945
+ "enabled": true,
1946
+ "routeOnly": true,
1947
+ "destOverride": [
1948
+ "http",
1949
+ "tls",
1950
+ "quic",
1951
+ "fakedns"
1952
+ ]
1953
+ }
1954
+ }
1955
+ },
1956
+ "../protocols/vless/snippets/vless-xhttp-tls.json": {
1957
+ label: "VLESS + XHTTP + TLS",
1958
+ description: "VLESS inbound over XHTTP with TLS",
1959
+ body: {
1960
+ "protocol": "vless",
1961
+ "listen": "0.0.0.0",
1962
+ "port": 443,
1963
+ "tag": "VLESS-XHTTP-TLS",
1964
+ "settings": {
1965
+ "clients": [],
1966
+ "decryption": "none"
1967
+ },
1968
+ "streamSettings": {
1969
+ "network": "xhttp",
1970
+ "security": "tls",
1971
+ "tlsSettings": { "serverName": "${2:example.com}" },
1972
+ "xhttpSettings": { "path": "${3:/xhttp}" }
1973
+ },
1974
+ "sniffing": {
1975
+ "enabled": true,
1976
+ "routeOnly": true,
1977
+ "destOverride": [
1978
+ "http",
1979
+ "tls",
1980
+ "quic",
1981
+ "fakedns"
1982
+ ]
1983
+ }
1984
+ }
1985
+ },
1986
+ "../protocols/vmess/snippets/vmess-tcp-tls.json": {
1987
+ label: "VMess + TCP + TLS",
1988
+ description: "VMess inbound over TCP with TLS",
1989
+ body: {
1990
+ "protocol": "vmess",
1991
+ "listen": "0.0.0.0",
1992
+ "port": 443,
1993
+ "tag": "VMESS-TCP-TLS",
1994
+ "settings": { "clients": [] },
1995
+ "streamSettings": {
1996
+ "network": "tcp",
1997
+ "security": "tls",
1998
+ "tlsSettings": {
1999
+ "serverName": "${3:example.com}",
2000
+ "alpn": ["http/1.1", "h2"]
2001
+ }
2002
+ },
2003
+ "sniffing": {
2004
+ "enabled": true,
2005
+ "routeOnly": true,
2006
+ "destOverride": [
2007
+ "http",
2008
+ "tls",
2009
+ "quic",
2010
+ "fakedns"
2011
+ ]
2012
+ }
2013
+ }
2014
+ },
2015
+ "../protocols/vmess/snippets/vmess-ws-tls.json": {
2016
+ label: "VMess + WS + TLS",
2017
+ description: "VMess inbound over WebSocket with TLS",
2018
+ body: {
2019
+ "protocol": "vmess",
2020
+ "listen": "0.0.0.0",
2021
+ "port": 443,
2022
+ "tag": "VMESS-WS-TLS",
2023
+ "settings": { "clients": [] },
2024
+ "streamSettings": {
2025
+ "network": "websocket",
2026
+ "security": "tls",
2027
+ "tlsSettings": {
2028
+ "serverName": "${3:example.com}",
2029
+ "alpn": ["http/1.1", "h2"]
2030
+ },
2031
+ "wsSettings": {
2032
+ "path": "${4:/ws}",
2033
+ "host": "${5:example.com}"
2034
+ }
2035
+ },
2036
+ "sniffing": {
2037
+ "enabled": true,
2038
+ "routeOnly": true,
2039
+ "destOverride": [
2040
+ "http",
2041
+ "tls",
2042
+ "quic",
2043
+ "fakedns"
2044
+ ]
2045
+ }
2046
+ }
2047
+ },
2048
+ "../protocols/wireguard/snippets/wireguard-basic.json": {
2049
+ label: "WireGuard",
2050
+ description: "Minimal WireGuard inbound setup",
2051
+ body: {
2052
+ "protocol": "wireguard",
2053
+ "listen": "0.0.0.0",
2054
+ "port": 51820,
2055
+ "tag": "WG-INBOUND",
2056
+ "settings": {
2057
+ "secretKey": "${1:private_key}",
2058
+ "mtu": 1420,
2059
+ "peers": []
2060
+ }
2061
+ }
2062
+ }
2063
+ });
2064
+ const protocolOrder = [
2065
+ "vless",
2066
+ "trojan",
2067
+ "vmess",
2068
+ "shadowsocks",
2069
+ "socks",
2070
+ "hysteria",
2071
+ "tun"
2072
+ ];
2073
+ const inboundSnippets = Object.values(snippetModules).sort((a, b) => {
2074
+ const protocolA = typeof a?.body?.protocol === "string" ? a.body.protocol : "";
2075
+ const protocolB = typeof b?.body?.protocol === "string" ? b.body.protocol : "";
2076
+ const orderA = protocolOrder.indexOf(protocolA);
2077
+ const orderB = protocolOrder.indexOf(protocolB);
2078
+ if (orderA !== orderB) return (orderA === -1 ? Number.POSITIVE_INFINITY : orderA) - (orderB === -1 ? Number.POSITIVE_INFINITY : orderB);
2079
+ const labelA = typeof a?.label === "string" ? a.label : "";
2080
+ const labelB = typeof b?.label === "string" ? b.label : "";
2081
+ return labelA.localeCompare(labelB);
2082
+ });
2083
+ //#endregion
2084
+ //#region src/inbounds/protocols/shadowsocks/shadowsocks.md?raw
2085
+ var shadowsocks_default$1 = "The [Shadowsocks](https://zh.wikipedia.org/wiki/Shadowsocks) protocol, compatible with most other version implementations.\n\nCurrent compatibility is as follows:\n\n- Supports TCP and UDP packet forwarding, where UDP can be optionally disabled;\n- Recommended encryption methods:\n - 2022-blake3-aes-128-gcm\n - 2022-blake3-aes-256-gcm\n - 2022-blake3-chacha20-poly1305\n- Other encryption methods:\n - aes-256-gcm\n - aes-128-gcm\n - chacha20-poly1305 (or chacha20-ietf-poly1305)\n - xchacha20-poly1305 (or xchacha20-ietf-poly1305)\n - none (or plain)\n\nThe Shadowsocks 2022 new protocol format improves performance and includes complete replay protection, resolving the following security issues of the old protocol:\n\n- [Severe vulnerabilities in the design of Shadowsocks AEAD encryption, unable to guarantee communication reliability](https://github.com/shadowsocks/shadowsocks-org/issues/183)\n- The false positive rate of the original TCP replay filter increases over time\n- No UDP replay protection\n- TCP behavior that can be used for active probing\n\n### DANGER\n\nUnder the \"none\" encryption method, traffic will be transmitted in plain text. To ensure security, do not use it on public networks.\n\n[Documentation ↗](https://xtls.github.io/en/config/inbounds/shadowsocks.html)\n";
2086
+ //#endregion
2087
+ //#region src/inbounds/protocols/shadowsocks/shadowsocksSettings.md?raw
2088
+ var shadowsocksSettings_default = "`InboundConfigurationObject` corresponds to the `settings` item in [`InboundObject`](https://xtls.github.io/en/config/inbound.html).\n";
2089
+ //#endregion
2090
+ //#region src/inbounds/protocols/shadowsocks/network.md?raw
2091
+ var network_default = "The network type that the server port listens on. Default value is `\"tcp\"`.\n\nThis is only for listening; it mainly affects native UDP transmission. Setting it to `\"tcp\"` does not mean the inbound will reject UDP proxy requests. UDP proxy requests can still be wrapped into TCP packets by Shadowsocks outbound features like UoT or mux.cool and sent to the server.\n";
2092
+ //#endregion
2093
+ //#region src/inbounds/protocols/shadowsocks/method.md?raw
2094
+ var method_default = "Encryption method. See the recommended and supported options in the protocol description above.\n";
2095
+ //#endregion
2096
+ //#region src/inbounds/protocols/shadowsocks/password.md?raw
2097
+ var password_default = "Required.\n\n### Shadowsocks 2022\n\nUses a pre-shared key similar to WireGuard as the password.\n\nUse `openssl rand -base64 <length>` to generate a key compatible with shadowsocks-rust. The length depends on the encryption method used:\n\n- 2022-blake3-aes-128-gcm: 16\n- 2022-blake3-aes-256-gcm: 32\n- 2022-blake3-chacha20-poly1305: 32\n\nIn the Go implementation, 32-byte keys always work.\n\n### Other encryption methods\n\nAny string. There is no limit on password length, but short passwords are more likely to be cracked. It is recommended to use passwords of 16 characters or longer.\n";
2098
+ //#endregion
2099
+ //#region src/inbounds/protocols/shadowsocks/level.md?raw
2100
+ var level_default = "User level. The connection will use the [Local Policy](https://xtls.github.io/en/config/policy.html#levelpolicyobject) corresponding to this user level. The value of `level` corresponds to the `level` value in [policy](https://xtls.github.io/en/config/policy.html#levelpolicyobject). If not specified, the default is 0.\n";
2101
+ //#endregion
2102
+ //#region src/inbounds/protocols/shadowsocks/email.md?raw
2103
+ var email_default = "User email, used to distinguish traffic from different users (logs, statistics).\n";
2104
+ //#endregion
2105
+ //#region src/inbounds/protocols/shadowsocks/users.md?raw
2106
+ var users_default$1 = "An array representing a group of users recognized by the server. Each item is a [UserObject](https://xtls.github.io/en/config/inbounds/shadowsocks.html#userobject).\n\nWhen this option exists, it indicates that multi-user mode is enabled.\n";
2107
+ //#endregion
2108
+ //#region src/inbounds/protocols/shadowsocks/userMethod.md?raw
2109
+ var userMethod_default = "When the `method` in `InboundConfigurationObject` is not an SS2022 option, you can specify `method` for each user here (only non-SS2022 options are supported) together with `password`. In that case, the `password` set in `InboundConfigurationObject` will be ignored.\n\nWhen the `method` in `InboundConfigurationObject` is an SS2022 option, setting `method` for individual users is not supported; it is unified to the method specified in `InboundConfigurationObject`.\n";
2110
+ //#endregion
2111
+ //#region src/inbounds/protocols/shadowsocks/userPassword.md?raw
2112
+ var userPassword_default$1 = "Note that SS2022 does not ignore the upper-level `password` like the old SS did. The correct password format for the client should be `ServerPassword:UserPassword`. For example: `\"password\": \"114514:1919810\"`.\n";
2113
+ //#endregion
2114
+ //#region src/inbounds/protocols/shadowsocks/userLevel.md?raw
2115
+ var userLevel_default$1 = "Same meaning as `level` in `InboundConfigurationObject`.\n";
2116
+ //#endregion
2117
+ //#region src/inbounds/protocols/shadowsocks/userEmail.md?raw
2118
+ var userEmail_default$1 = "Same meaning as `email` in `InboundConfigurationObject`.\n";
2119
+ //#endregion
2120
+ //#region src/inbounds/protocols/shadowsocks/shadowsocks.ts
2121
+ const ss22Methods = z.enum([
2122
+ "2022-blake3-aes-128-gcm",
2123
+ "2022-blake3-aes-256-gcm",
2124
+ "2022-blake3-chacha20-poly1305"
2125
+ ]);
2126
+ const ss22UserSchema = z.object({
2127
+ password: z.string().optional().meta({ markdownDescription: userPassword_default$1 }),
2128
+ level: z.number().default(0).optional().meta({ markdownDescription: userLevel_default$1 }),
2129
+ email: z.string().min(1).meta({ markdownDescription: userEmail_default$1 })
2130
+ });
2131
+ const ssMethods = z.enum([
2132
+ "aes-256-gcm",
2133
+ "aes-128-gcm",
2134
+ "chacha20-poly1305",
2135
+ "chacha20-ietf-poly1305",
2136
+ "xchacha20-poly1305",
2137
+ "xchacha20-ietf-poly1305",
2138
+ "none",
2139
+ ""
2140
+ ]);
2141
+ const ssUserSchema = z.object({
2142
+ password: z.string().optional().meta({ markdownDescription: userPassword_default$1 }),
2143
+ level: z.number().default(0).optional().meta({ markdownDescription: userLevel_default$1 }),
2144
+ email: z.string().min(1).meta({ markdownDescription: userEmail_default$1 }),
2145
+ method: ssMethods.optional().meta({ markdownDescription: userMethod_default })
2146
+ });
2147
+ const ssSettingsBaseSchema = z.object({
2148
+ network: z.enum([
2149
+ "tcp",
2150
+ "udp",
2151
+ "tcp,udp"
2152
+ ]).default("tcp").optional().meta({ markdownDescription: network_default }),
2153
+ level: z.number().int().default(0).optional().meta({ markdownDescription: level_default }),
2154
+ password: z.string().min(1).meta({ markdownDescription: password_default }).optional(),
2155
+ email: z.string().meta({ markdownDescription: email_default }).optional()
2156
+ });
2157
+ const shadowsocksSettingsSchema = z.discriminatedUnion("method", [ssSettingsBaseSchema.extend({
2158
+ method: ss22Methods.meta({ markdownDescription: method_default }),
2159
+ password: z.string().min(1).meta({ markdownDescription: password_default }),
2160
+ users: z.array(ss22UserSchema).optional().meta({ markdownDescription: users_default$1 })
2161
+ }), ssSettingsBaseSchema.extend({
2162
+ method: ssMethods.meta({ markdownDescription: method_default }),
2163
+ users: z.array(ssUserSchema).optional().meta({ markdownDescription: users_default$1 })
2164
+ })]).meta({ markdownDescription: shadowsocksSettings_default });
2165
+ const shadowsocksInboundSchema = generalInboundSchema.extend({
2166
+ protocol: z.literal("shadowsocks"),
2167
+ settings: shadowsocksSettingsSchema
2168
+ }).meta({ markdownDescription: shadowsocks_default$1 });
2169
+ //#endregion
2170
+ //#region src/inbounds/protocols/vless/vless.md?raw
2171
+ var vless_default$1 = "VLESS is a stateless, lightweight transport protocol. It is divided into inbound and outbound parts and can serve as a bridge between Xray clients and servers.\n\nUnlike [VMess](https://xtls.github.io/en/config/inbounds/vmess.html), VLESS does not depend on system time. The authentication method is also UUID.\n\n[Documentation ↗](https://xtls.github.io/en/config/inbounds/vless.html)\n";
2172
+ //#endregion
2173
+ //#region src/inbounds/protocols/vless/vlessSettings.md?raw
2174
+ var vlessSettings_default$1 = "`InboundConfigurationObject` corresponds to the `settings` item in [`InboundObject`](https://xtls.github.io/en/config/inbound.html).\n";
2175
+ //#endregion
2176
+ //#region src/inbounds/protocols/vless/vlessUsers.md?raw
2177
+ var vlessUsers_default = "An array representing a group of users approved by the server. Each item is a [UserObject](https://xtls.github.io/en/config/inbounds/vless.html#userobject).\n";
2178
+ //#endregion
2179
+ //#region src/inbounds/protocols/vless/vlessDecryption.md?raw
2180
+ var vlessDecryption_default = "VLESS Encryption settings. Cannot be left empty; to disable, explicitly set it to `\"none\"`.\n\nIt is recommended for most users to use the `xray vlessenc` command to automatically generate this field to avoid configuration mistakes. The detailed configuration below is recommended for advanced users only.\n\nDetailed configuration format is a string of blocks connected by dots, for example:\n\n`mlkem768x25519plus.native.600s.100-111-1111.75-0-111.50-0-3333.ptjHQxBQxTJ9MWr2cd5qWIflBSACHOevTauCQwa_71U`\n\nThis document refers to the individual parts separated by dots as blocks.\n\n- The 1st block is the handshake method. Currently, there is only `mlkem768x25519plus`. Requires the server and client to match.\n- The 2nd block is the encryption method. Options are `native`/`xorpub`/`random`, corresponding to: raw format packets / raw format + obfuscated public key part / full random numbers (similar to VMess/Shadowsocks). Requires the server and client to match.\n- The 3rd block is the session resumption ticket validity time. Format is `600s` or `100-500s`. The former will pick a random time between that duration and half of that duration (e.g., `600s` = `300-600s`); the latter manually specifies a random range.\n\nFollowing this is padding. After the connection is established, the server sends garbage data to obfuscate length characteristics. This does not need to be the same as the client (the same part in the outbound is the padding sent from the client to the server). It is a variable-length part, formatted as `padding.delay.padding` + `(.delay.padding)*n`. Multiple paddings can be inserted, requiring a delay block between two padding blocks.\n\n- The `padding` format is `probability-min-max`, e.g., `100-111-1111` means 100% probability of sending a padding with a length of 111~1111.\n- The `delay` format is also `probability-min-max`, e.g., `75-0-111` means 75% probability of waiting for 0~111 milliseconds.\n\nThe first padding block has special requirements: it requires 100% probability and a minimum length greater than 0. If no padding exists, the core automatically uses `100-111-1111.75-0-111.50-0-3333` as the padding setting.\n\nThe last block is identified by the core as the parameter used to authenticate the client. It can be generated using `./xray x25519` (using the PrivateKey part) or `./xray mlkem768` (using the Seed part). It must correspond to the client. `mlkem768` is a post-quantum algorithm that prevents the private key from being cracked by quantum computers (in the future) to impersonate the server if client parameters are leaked. This parameter is only used for verification; the handshake process is post-quantum secure regardless, and existing encrypted data cannot be cracked by future quantum computers.\n";
2181
+ //#endregion
2182
+ //#region src/inbounds/protocols/vless/vlessFallbacks.md?raw
2183
+ var vlessFallbacks_default = "An array containing a series of powerful fallback distribution configurations (optional). For specific fallback configurations, see [FallbackObject](https://xtls.github.io/en/config/features/fallback.html#fallbacks-configuration).\n";
2184
+ //#endregion
2185
+ //#region src/inbounds/protocols/vless/vless.ts
2186
+ const vlessClient = z.object({
2187
+ id: z.string().min(1).meta({ markdownDescription: "The user ID for VLESS. It can be any string less than 30 bytes or a valid UUID. A custom string and its mapped UUID are equivalent.\n\nMapping standard: [VLESS UUID Mapping Standard: Mapping Custom Strings to a UUIDv5](https://github.com/XTLS/Xray-core/issues/158).\n\nUse `xray uuid -i \"custom string\"` to generate the mapped UUID, or `xray uuid` to generate a random UUID.\n" }),
2188
+ level: z.number().default(0).optional().meta({ markdownDescription: "User level. The connection will use the [Local Policy](https://xtls.github.io/en/config/policy.html#levelpolicyobject) corresponding to this user level.\n\nThe value of `level` corresponds to the `level` value in [policy](https://xtls.github.io/en/config/policy.html#policyobject). If not specified, the default is 0.\n" }),
2189
+ email: z.string().optional().meta({ markdownDescription: "User email, used to distinguish traffic from different users (reflected in logs and statistics).\n" }),
2190
+ flow: z.enum(["", "xtls-rprx-vision"]).default("").optional().meta({ markdownDescription: "Flow control mode, used to select the XTLS algorithm.\n\nAvailable inbound flow control modes:\n\n- Empty string: use standard TLS proxy.\n- `xtls-rprx-vision`: use the new XTLS mode, including inner handshake random padding.\n\nXTLS is only available under the following combinations:\n\n- TCP+TLS/REALITY: In this case, if transmitting TLS 1.3, the core will attempt to Splice encrypted data at the bottom layer. If successful, it saves all core IO overhead.\n- VLESS Encryption: no underlying transport restrictions. If the underlying layer does not support direct copying (see above), it only penetrates Encryption.\n" }),
2191
+ reverse: z.object({ tag: z.string().min(1).optional().meta({ markdownDescription: "`tag` is the outbound proxy tag for this reverse proxy. Routing traffic to this outbound using routing rules will forward it through the reverse proxy to the connected client's routing system (see VLESS outbound for client configuration details).\n\nWhen multiple different connections (potentially from different devices) are connected, the core randomly selects one to dispatch reverse proxy data for each request.\n" }) }).default({}).optional().meta({ markdownDescription: "VLESS simplified reverse proxy configuration.\n\nThe presence of this item indicates that connections from this user can be used to establish a reverse proxy tunnel, while disabling normal forward proxy usage.\n\n### TIP\n\nFull tutorial: [VLESS Reverse Proxy Examples](https://xtls.github.io/en/document/level-2/vless_reverse.html)\n" })
2192
+ });
2193
+ const vlessFallbackSchema = z.object({
2194
+ name: z.string().default("").optional(),
2195
+ alpn: z.string().default("").optional(),
2196
+ path: z.string().default("").optional(),
2197
+ dest: z.string().or(z.number()).optional(),
2198
+ xver: z.number().default(0).optional()
2199
+ });
2200
+ const baseVlessSettings = z.object({
2201
+ decryption: z.literal("none").or(z.string()).meta({ markdownDescription: vlessDecryption_default }),
2202
+ fallbacks: z.array(vlessFallbackSchema).optional().meta({ markdownDescription: vlessFallbacks_default })
2203
+ });
2204
+ const vlessInboundSchema = generalInboundSchema.extend({
2205
+ protocol: z.literal("vless"),
2206
+ settings: baseVlessSettings.extend({ users: z.array(vlessClient.loose()).default([]).optional().meta({ markdownDescription: vlessUsers_default }) }).or(baseVlessSettings.extend({ clients: z.array(vlessClient.loose()).default([]).optional().meta({ markdownDescription: vlessUsers_default }) })).meta({ markdownDescription: vlessSettings_default$1 })
2207
+ }).meta({ markdownDescription: vless_default$1 });
2208
+ //#endregion
2209
+ //#region src/inbounds/protocols/vmess/vmess.md?raw
2210
+ var vmess_default$1 = "[VMess](https://xtls.github.io/en/development/protocols/vmess.html) is an encrypted transport protocol, commonly acting as a bridge between the Xray client and server.\n\n### DANGER\n\nVMess depends on system time. Please ensure that the system UTC time of the device running Xray is within 120 seconds of the actual time, regardless of the time zone. On Linux systems, you can install the `ntp` service to automatically synchronize system time.\n\n[Documentation ↗](https://xtls.github.io/en/config/inbounds/vmess.html)\n";
2211
+ //#endregion
2212
+ //#region src/inbounds/protocols/vmess/vmessSettings.md?raw
2213
+ var vmessSettings_default$1 = "`InboundConfigurationObject` corresponds to the `settings` item in [`InboundObject`](https://xtls.github.io/en/config/inbound.html).\n";
2214
+ //#endregion
2215
+ //#region src/inbounds/protocols/vmess/vmessUsers.md?raw
2216
+ var vmessUsers_default = "An array representing a group of users accepted by the server. Each item is a UserObject.\n\nWhen this configuration is used for dynamic ports, Xray will automatically create users.\n";
2217
+ //#endregion
2218
+ //#region src/inbounds/protocols/vmess/vmessDefault.md?raw
2219
+ var vmessDefault_default = "Optional. Default configuration for `users`. Only valid when used in conjunction with `detour`.\n";
2220
+ //#endregion
2221
+ //#region src/inbounds/protocols/vmess/vmessUserId.md?raw
2222
+ var vmessUserId_default = "User ID for VMess. It can be any string less than 30 bytes, or a valid UUID.\n\n### TIP\n\nA custom string and its mapped UUID are equivalent. This means you can identify the same user in the configuration file by writing the ID in either way.\n\nMapping standard: [VLESS UUID Mapping Standard: Mapping Custom Strings to UUIDv5](https://github.com/XTLS/Xray-core/issues/158).\n\nUse `xray uuid -i \"custom string\"` to generate the mapped UUID, or `xray uuid` to generate a random UUID.\n";
2223
+ //#endregion
2224
+ //#region src/inbounds/protocols/vmess/vmessUserLevel.md?raw
2225
+ var vmessUserLevel_default = "User level. The connection will use the [Local Policy](https://xtls.github.io/en/config/policy.html#levelpolicyobject) corresponding to this user level.\n\nThe value of `level` corresponds to the value of `level` in [policy](https://xtls.github.io/en/config/policy.html#policyobject). If not specified, it defaults to 0.\n";
2226
+ //#endregion
2227
+ //#region src/inbounds/protocols/vmess/vmess.ts
2228
+ const vmessClients = z.object({
2229
+ id: z.string().min(1).meta({ markdownDescription: vmessUserId_default }),
2230
+ level: z.number().optional().meta({ markdownDescription: vmessUserLevel_default }),
2231
+ email: z.string().optional().meta({ markdownDescription: "User email address, used to distinguish traffic from different users.\n" })
2232
+ });
2233
+ const baseVmessSettings = z.object({ default: z.object({ level: z.number().meta({ markdownDescription: vmessUserLevel_default }) }).optional().meta({ markdownDescription: vmessDefault_default }) });
2234
+ const vmessInboundSchema = generalInboundSchema.extend({
2235
+ protocol: z.literal("vmess"),
2236
+ settings: baseVmessSettings.extend({ clients: z.array(vmessClients).default([]).optional().meta({ markdownDescription: vmessUsers_default }) }).or(baseVmessSettings.extend({ users: z.array(vmessClients).default([]).optional().meta({ markdownDescription: vmessUsers_default }) })).meta({ markdownDescription: vmessSettings_default$1 })
2237
+ }).meta({ markdownDescription: vmess_default$1 });
2238
+ //#endregion
2239
+ //#region src/inbounds/protocols/wireguard/wireguard.md?raw
2240
+ var wireguard_default$1 = "User-space WireGuard protocol implementation.\n\n### DANGER\n\n**The WireGuard protocol is not designed specifically for bypassing firewalls. If used as the outer layer to cross the firewall, its distinct characteristics may lead to the server being blocked.**\n\n[Documentation ↗](https://xtls.github.io/en/config/inbounds/wireguard.html)\n";
2241
+ //#endregion
2242
+ //#region src/inbounds/protocols/wireguard/wireguardSettings.md?raw
2243
+ var wireguardSettings_default$1 = "`InboundConfigurationObject` corresponds to the `settings` item in [`InboundObject`](https://xtls.github.io/en/config/inbound.html).\n";
2244
+ //#endregion
2245
+ //#region src/inbounds/protocols/wireguard/wireguardSecretKey.md?raw
2246
+ var wireguardSecretKey_default$1 = "Private key. Required.\n";
2247
+ //#endregion
2248
+ //#region src/inbounds/protocols/wireguard/wireguardPeers.md?raw
2249
+ var wireguardPeers_default$1 = "List of peers, where each item is a peer configuration.\n";
2250
+ //#endregion
2251
+ //#region src/inbounds/protocols/wireguard/wireguardPeerPublicKey.md?raw
2252
+ var wireguardPeerPublicKey_default$1 = "Public key, used for verification.\n";
2253
+ //#endregion
2254
+ //#region src/inbounds/protocols/wireguard/wireguardPeerAllowedIPs.md?raw
2255
+ var wireguardPeerAllowedIPs_default$1 = "Allowed source IPs.\n";
2256
+ //#endregion
2257
+ //#region src/inbounds/protocols/wireguard/wireguardMtu.md?raw
2258
+ var wireguardMtu_default$1 = "The MTU size of the underlying WireGuard TUN.\n\nMethod to Calculate MTU\n\n- 20-byte IPv4 header or 40 byte IPv6 header\n- 8-byte UDP header\n- 4-byte type\n- 4-byte key index\n- 8-byte nonce\n- N-byte encrypted data\n- 16-byte authentication tag\n\n`N-byte encrypted data` is the MTU value needed. Depending on whether the endpoint is IPv4 or IPv6, the specific value can be 1440 (IPv4) or 1420 (IPv6). If you are in a special network environment, you may need to subtract more (e.g., home broadband PPPoE requires an extra -8).\n";
2259
+ //#endregion
2260
+ //#region src/inbounds/protocols/wireguard/wireguard.ts
2261
+ const wireguardPeerSchema = z.object({
2262
+ publicKey: z.string().min(1).meta({ markdownDescription: wireguardPeerPublicKey_default$1 }),
2263
+ allowedIPs: z.array(z.string().min(1)).meta({ markdownDescription: wireguardPeerAllowedIPs_default$1 })
2264
+ });
2265
+ const wireguardInboundSchema = generalInboundSchema.extend({
2266
+ protocol: z.literal("wireguard"),
2267
+ settings: z.object({
2268
+ secretKey: z.string().meta({ markdownDescription: wireguardSecretKey_default$1 }),
2269
+ peers: z.array(wireguardPeerSchema).default([]).optional().meta({ markdownDescription: wireguardPeers_default$1 }),
2270
+ mtu: z.number().default(1420).optional().meta({ markdownDescription: wireguardMtu_default$1 })
2271
+ }).meta({ markdownDescription: wireguardSettings_default$1 })
2272
+ }).meta({ markdownDescription: wireguard_default$1 });
2273
+ //#endregion
2274
+ //#region src/inbounds/protocols/trojan/trojan.md?raw
2275
+ var trojan_default$1 = "[Trojan](https://trojan-gfw.github.io/trojan/protocol) protocol.\n\n### DANGER\n\nTrojan is designed to work over correctly configured encrypted TLS tunnels.\n\n[Documentation ↗](https://xtls.github.io/en/config/inbounds/trojan.html)\n";
2276
+ //#endregion
2277
+ //#region src/inbounds/protocols/trojan/trojanSettings.md?raw
2278
+ var trojanSettings_default$1 = "`InboundConfigurationObject` corresponds to the `settings` item in [`InboundObject`](https://xtls.github.io/en/config/inbound.html).\n";
2279
+ //#endregion
2280
+ //#region src/inbounds/protocols/trojan/users.md?raw
2281
+ var users_default = "An array representing a group of users accepted by the server. Each item is a [UserObjects](https://xtls.github.io/en/config/inbounds/trojan.html#userobject).\n";
2282
+ //#endregion
2283
+ //#region src/inbounds/protocols/trojan/fallbacks.md?raw
2284
+ var fallbacks_default = "An array containing a series of powerful fallback configurations (optional). For specific configuration of fallbacks, see [FallbackObject](https://xtls.github.io/en/config/features/fallback.html#fallbackobject).\n\n### TIP\n\nXray's Trojan has complete support for fallbacks, and the configuration method is exactly the same as VLESS. The conditions for triggering fallback are also similar to VLESS: the length of the first packet < 58, OR the 57th byte is not `\\r` (because Trojan has no protocol version), OR authentication fails.\n";
2285
+ //#endregion
2286
+ //#region src/inbounds/protocols/trojan/trojan.ts
2287
+ const trojanUser = z.object({
2288
+ email: z.string().min(1).meta({ markdownDescription: "Email address, optional, used to identify the user.\n\n### DANGER\n\nIf there are multiple [UserObjects](https://xtls.github.io/en/config/inbounds/trojan.html#userobject), please note that emails must not be duplicated.\n" }),
2289
+ password: z.string().min(1).meta({ markdownDescription: "Required, any string.\n" }),
2290
+ level: z.number().int().default(0).optional().meta({ markdownDescription: "User level. Connections will use the [Local Policy](https://xtls.github.io/en/config/policy.html#levelpolicyobject) corresponding to this user level.\n\nThe value of `userLevel` corresponds to the value of `level` in [policy](https://xtls.github.io/en/config/policy.html#policyobject). If not specified, it defaults to 0.\n" })
2291
+ });
2292
+ const trojanFallback = z.object({
2293
+ name: z.string().default("").optional(),
2294
+ alpn: z.string().default("").optional(),
2295
+ path: z.string().default("").optional(),
2296
+ dest: z.string().or(z.number()).optional(),
2297
+ xver: z.number().default(0).optional()
2298
+ });
2299
+ const trojanInboundSchema = generalInboundSchema.extend({
2300
+ protocol: z.literal("trojan"),
2301
+ settings: z.object({
2302
+ users: z.array(trojanUser).default([]).optional().meta({ markdownDescription: users_default }),
2303
+ fallbacks: z.array(trojanFallback).optional().meta({ markdownDescription: fallbacks_default })
2304
+ }).meta({ markdownDescription: trojanSettings_default$1 })
2305
+ }).meta({ markdownDescription: trojan_default$1 });
2306
+ //#endregion
2307
+ //#region src/inbounds/protocols/tun/tun.ts
2308
+ const tunInboundSchema = generalInboundSchema.extend({
2309
+ protocol: z.literal("tun"),
2310
+ settings: z.object({
2311
+ name: z.string().default("xray0").optional().meta({ markdownDescription: "The name of the created TUN interface. Default is `\"xray0\"`.\n" }),
2312
+ mtu: z.number().int().default(1500).optional().meta({ markdownDescription: "The MTU of the interface. The default is `1500`.\n" }),
2313
+ userLevel: z.number().int().default(0).optional().meta({ markdownDescription: "User level. The connection will use the [Local Policy](https://xtls.github.io/en/config/policy.html#levelpolicyobject) corresponding to this user level.\n\nThe value of `userLevel` corresponds to the value of `level` in [policy](https://xtls.github.io/en/config/policy.html#policyobject). If not specified, the default is 0.\n" }),
2314
+ gateway: z.array(z.string()).meta({ markdownDescription: "The list of address prefixes assigned to the TUN interface, usually one for IPv4 and one for IPv6, such as `\"10.0.0.1/16\"` and `\"fc00::1/64\"`.\n" }),
2315
+ dns: z.array(z.string()).default(["1.1.1.1", "8.8.8.8"]).meta({ markdownDescription: "The list of DNS servers assigned to the TUN interface, such as `\"1.1.1.1\"` and `\"8.8.8.8\"`.\n" }),
2316
+ autoSystemRoutingTable: z.array(z.string()).optional().meta({ markdownDescription: "The list of destination prefixes that Xray should add to the system routing table automatically so that the traffic is directed into this TUN interface. Each item is a CIDR. For example, `\"0.0.0.0/0\"` means all IPv4 traffic, and `\"::/0\"` means all IPv6 traffic.\n\nCurrently only supported on Windows. On other systems, the routing table must be configured manually.\n" }),
2317
+ autoOutboundsInterface: z.string().or(z.literal("auto")).nullable().default(null).optional().meta({ markdownDescription: "Automatically binds Xray outbounds to a physical network interface, so that traffic generated by Xray itself is not sent back into the TUN interface and looped.\n\nThe default value is `null`, which means not configured. You can specify an interface name explicitly, or use `\"auto\"` to let Xray choose one automatically. If `autoSystemRoutingTable` is configured but this field is omitted, Xray treats it as `\"auto\"`.\n" })
2318
+ }).meta({ markdownDescription: "`InboundConfigurationObject` corresponds to the `settings` item in [`InboundObject`](https://xtls.github.io/en/config/inbound.html).\n" })
2319
+ }).meta({ markdownDescription: [
2320
+ "Creates a TUN interface; traffic sent to this interface will be processed by Xray. Currently, Windows, Linux, macOS, and FreeBSD are supported.\n\nOn Android, the TUN FD must be passed in from an external app, which uses VPN Service to redirect traffic. It cannot run standalone and only serves as a way for an app to feed traffic into Xray.\n\n[Documentation ↗](https://xtls.github.io/en/config/inbounds/tun.html)\n",
2321
+ "\n",
2322
+ "## Usage Tips\n\nIf `autoSystemRoutingTable` is not configured, you still need to add routes manually to direct traffic to the created TUN interface; otherwise, it remains just an interface.\n\nWhen `gateway`, `dns`, `autoSystemRoutingTable`, and `autoOutboundsInterface` are configured, Xray can perform part of the system-side setup automatically on supported platforms. If your platform does not implement these automatic settings yet, or if you need more fine-grained policy routing, you still need to configure the OS manually.\n\nIf you only want to proxy specific process(es), the process name routing in the Xray routing system will be very useful.\n\n### WARNING\n\nBe aware of potential traffic loop issues. After setting routes, requests initiated by Xray might be sent back to Xray, causing a loop. Prefer `autoOutboundsInterface` to avoid this problem. If you need manual control, you can still use `interface` in `sockopt` to bind to the actual physical network interface. `ipconfig` (Windows) or `ip a` (Linux) will help you find the interface name you need. Alternatively, use the outbound `sendThrough` setting. It is available directly in `OutboundObject` without the deep nesting level of `sockOpt.interface`. Here you need to use the IP address on the network card, such as 192.168.1.2 (As you can see, its disadvantage is that it cannot automatically support dual-stack; please choose according to the IP actually used for your outbound connection).\n"
2323
+ ].join("\n") });
2324
+ //#endregion
2325
+ //#region src/inbounds/protocols/hysteria/hysteria.md?raw
2326
+ var hysteria_default$1 = "### TIP\n\nThe `hysteria` protocol itself has no authentication; `users` only take effect when used with the `hysteria` transport layer.\n\n[Documentation ↗](https://xtls.github.io/en/config/inbounds/hysteria.html)\n";
2327
+ //#endregion
2328
+ //#region src/inbounds/protocols/hysteria/hysteriaSettings.md?raw
2329
+ var hysteriaSettings_default$1 = "`InboundConfigurationObject` corresponds to the `settings` item in [`InboundObject`](https://xtls.github.io/en/config/inbound.html).\n";
2330
+ //#endregion
2331
+ //#region src/inbounds/protocols/hysteria/hysteriaVersion.md?raw
2332
+ var hysteriaVersion_default$1 = "Hysteria version, must be 2.\n";
2333
+ //#endregion
2334
+ //#region src/inbounds/protocols/hysteria/hysteriaUsers.md?raw
2335
+ var hysteriaUsers_default = "An array representing a group of users approved by the server.\n";
2336
+ //#endregion
2337
+ //#region src/inbounds/protocols/hysteria/hysteria.ts
2338
+ const hysteriaUser = z.object({
2339
+ auth: z.string().min(1).meta({ markdownDescription: "A string of any length.\n" }),
2340
+ email: z.string().min(1).meta({ markdownDescription: "User email, used to distinguish traffic from different users (reflected in logs and statistics).\n" }),
2341
+ level: z.number().int().default(0).optional().meta({ markdownDescription: "User level. The connection will use the [Local Policy](https://xtls.github.io/en/config/policy.html#levelpolicyobject) corresponding to this user level.\n\nThe value of `level` corresponds to the value of `level` in [policy](https://xtls.github.io/en/config/policy.html#policyobject). If not specified, the default is 0.\n" })
2342
+ });
2343
+ const hysteriaInboundSchema = generalInboundSchema.extend({
2344
+ protocol: z.literal("hysteria"),
2345
+ settings: z.object({
2346
+ version: z.literal(2).meta({ markdownDescription: hysteriaVersion_default$1 }),
2347
+ users: z.array(hysteriaUser).default([]).optional().meta({ markdownDescription: hysteriaUsers_default })
2348
+ }).meta({ markdownDescription: hysteriaSettings_default$1 })
2349
+ }).meta({ markdownDescription: hysteria_default$1 });
2350
+ //#endregion
2351
+ //#region src/inbounds/inbounds.ts
2352
+ const inbound = z.discriminatedUnion("protocol", [
2353
+ dokodemoDoorInboundSchema,
2354
+ httpInboundSchema,
2355
+ socksInboundSchema,
2356
+ shadowsocksInboundSchema,
2357
+ vlessInboundSchema,
2358
+ vmessInboundSchema,
2359
+ wireguardInboundSchema,
2360
+ trojanInboundSchema,
2361
+ tunInboundSchema,
2362
+ hysteriaInboundSchema
2363
+ ]).meta({
2364
+ ifThenLogic: true,
2365
+ discriminatedFields: ["settings"],
2366
+ defaultSnippets: inboundSnippets
2367
+ });
2368
+ //#endregion
2369
+ //#region src/stats/stats.ts
2370
+ const stats = z.looseObject({}).meta({ markdownDescription: `Currently, statistics do not require any parameters. As long as the StatsObject item exists, internal statistics are enabled.
2371
+
2372
+ After enabling statistics, you only need to enable the corresponding items in Policy to collect the corresponding data.` });
2373
+ //#endregion
2374
+ //#region src/metrics/metrics.ts
2375
+ const listenDescription = `Directly listen on an address and port to provide the service.
2376
+ ---
2377
+ [Usage ↗](https://xtls.github.io/en/config/metrics.html#usage)`;
2378
+ const tagDescription = `The outbound proxy tag corresponding to metrics. You can access it by setting up a dokodemo-door inbound + routing rules that point the dokodemo-door to this outbound.`;
2379
+ const metrics = z.object({
2380
+ tag: z.string().meta({ markdownDescription: tagDescription }),
2381
+ listen: z.string().optional().meta({ markdownDescription: listenDescription })
2382
+ }).or(z.object({
2383
+ tag: z.string().optional().meta({ markdownDescription: tagDescription }),
2384
+ listen: z.string().meta({ markdownDescription: listenDescription })
2385
+ })).meta({ markdownDescription: `A more direct (and hopefully better) way to export statistics.
2386
+
2387
+
2388
+ [Documentation ↗](https://xtls.github.io/en/config/metrics.html)` });
2389
+ //#endregion
2390
+ //#region src/observatory/observatory.ts
2391
+ const observatory = z.object({
2392
+ subjectSelector: z.array(z.string()).meta({ markdownDescription: `An array of strings, where each string is used for prefix matching against outbound proxy tags. Given the following outbound proxy tags: \`[ "a", "ab", "c", "ba" ]\`, \`"subjectSelector": ["a"]\` will match \`[ "a", "ab" ]\`.` }),
2393
+ probeUrl: z.string().default("https://www.google.com/generate_204").meta({ markdownDescription: `The URL used to probe the connection status of the outbound proxy.` }),
2394
+ probeInterval: z.string().meta({ markdownDescription: `The interval for initiating probes. The time format is number + unit, such as \`"10s"\`, \`"2h45m"\`. Supported time units are \`ns\`, \`us\`, \`ms\`, \`s\`, \`m\`, \`h\`, corresponding to nanoseconds, microseconds, milliseconds, seconds, minutes, and hours respectively.
2395
+
2396
+ Note that since the request interval is fixed, periodic fixed requests might lead to behavioral fingerprinting. Using protocols with multiplexing or enabling \`mux\` can alleviate this issue.` }),
2397
+ enableConcurrency: z.boolean().default(false).optional().meta({ markdownDescription: `- \`true\`: Probe all matched outbound proxies concurrently. Pauses for the time set in \`probeInterval\` after all are completed.
2398
+ - \`false\`: Probe matched outbound proxies one by one. Pauses for the time set in \`probeInterval\` after each outbound proxy is probed.
2399
+ ` })
2400
+ }).meta({ markdownDescription: `The Observatory component uses HTTPing to probe the connection status of outbound proxies. The observation results can be used by other components, such as the Load Balancer. Currently, there are two types: [observatory](https://xtls.github.io/en/config/observatory.html#observatoryobject) (Background Connection Observatory) and [burstObservatory](https://xtls.github.io/en/config/observatory.html#burstobservatoryobject) (Burst Connection Observatory). Choose one according to your needs.` });
2401
+ //#endregion
2402
+ //#region src/burstObservatory/burstObservatory.ts
2403
+ const durationSchema = z.templateLiteral([z.number().int().nonnegative().min(1), z.literal([
2404
+ "ns",
2405
+ "us",
2406
+ "ms",
2407
+ "s",
2408
+ "m",
2409
+ "h"
2410
+ ])]);
2411
+ const burstObservatoryPingConfig = z.object({
2412
+ destination: z.string().default("https://connectivitycheck.gstatic.com/generate_204").optional().meta({ markdownDescription: `The URL used to probe the connection status of the outbound proxy. This URL should return an HTTP 204 success status code.` }),
2413
+ connectivity: z.string().default("").optional().meta({ markdownDescription: `The URL used to check local network connectivity. This URL should return an HTTP 204 success status code.
2414
+
2415
+ An empty string indicates no local network connectivity check.
2416
+
2417
+ This probe is executed only when the \`destination\` probe fails. This makes the cause of network failure clearer in the logs.
2418
+
2419
+ Note: In transparent proxy mode, this request might be captured by the transparent proxy and re-enter Xray for routing (depending on your configuration). You need to use extra means to ensure it is not captured by the transparent proxy, such as bypassing based on the URL IP, or using cgroup/pid routing to completely prevent Xray's requests from being captured. Alternatively, you can choose a URL that matches a direct connection rule and allow this request to be captured by the transparent proxy.
2420
+ ` }),
2421
+ interval: durationSchema.default("1m").optional().meta({ markdownDescription: `The expected **average** probe interval for each outbound proxy.
2422
+
2423
+ The time format is number + unit, such as \`"10s"\`, \`"2h45m"\`. Supported time units are \`ns\`, \`us\`, \`ms\`, \`s\`, \`m\`, \`h\`, corresponding to nanoseconds, microseconds, milliseconds, seconds, minutes, and hours respectively.
2424
+ Minimum allowed value is \`"10s"\`. If less is specified, \`"10s"\` will be used.
2425
+ ` }),
2426
+ sampling: z.number().int().nonnegative().default(10).optional().meta({ markdownDescription: `The number of recent probe results to keep` }),
2427
+ timeout: durationSchema.default("5s").optional().meta({ markdownDescription: `Probe timeout. Format is the same as interval above.
2428
+ The time format is number + unit, such as \`"10s"\`, \`"2h45m"\`. Supported time units are \`ns\`, \`us\`, \`ms\`, \`s\`, \`m\`, \`h\`, corresponding to nanoseconds, microseconds, milliseconds, seconds, minutes, and hours respectively.` }),
2429
+ httpMethod: z.enum([
2430
+ "GET",
2431
+ "POST",
2432
+ "HEAD",
2433
+ "DELETE",
2434
+ "PATCH",
2435
+ "PUT"
2436
+ ]).default("HEAD").optional().meta({ markdownDescription: `The HTTP method used for probing (e.g. \`"HEAD"\`, \`"GET"\`)` })
2437
+ });
2438
+ const burstObservatory = z.object({
2439
+ subjectSelector: z.array(z.string()).meta({ markdownDescription: `An array of strings, where each string is used for prefix matching against outbound proxy tags. Given the following outbound proxy tags: \`[ "a", "ab", "c", "ba" ]\`, \`"subjectSelector": ["a"]\` will match \`[ "a", "ab" ]\`.` }),
2440
+ pingConfig: burstObservatoryPingConfig.optional()
2441
+ }).meta({ markdownDescription: `The Observatory component uses HTTPing to probe the connection status of outbound proxies. The observation results can be used by other components, such as the Load Balancer. Currently, there are two types: [observatory](https://xtls.github.io/en/config/observatory.html#observatoryobject) (Background Connection Observatory) and [burstObservatory](https://xtls.github.io/en/config/observatory.html#burstobservatoryobject) (Burst Connection Observatory). Choose one according to your needs.` });
2442
+ //#endregion
2443
+ //#region src/reverse/reverse.md?raw
2444
+ var reverse_default = "A reverse proxy can forward traffic from the server side to the client side, effectively performing reverse traffic forwarding.\n\nThis reverse proxy is a general-purpose reverse proxy (it does not limit the proxy protocol type). The configuration is more complex. Do not confuse it with the VLESS simplified reverse configuration (refer to the relevant sections in the VLESS inbound/outbound documentation).\n\nIts underlying protocol is Mux.cool, but the direction is reversed: the server initiates requests to the client.\n\nThe general working principle of the reverse proxy is as follows:\n\n- Assume there is a web server on Host A. This host does not have a public IP and cannot be accessed directly from the public internet. There is another Host B, which is accessible from the public internet. We need to use B as the entry point to forward traffic from B to A.\n - Configure Xray on Host B to receive external requests; this is called the `portal`.\n - Configure Xray on Host A to bridge the forwarding from B to the web server; this is called the `bridge`.\n\n- `bridge`\n - The `bridge` actively establishes a connection to the `portal` to register a reverse tunnel. The destination address (domain) of this connection can be defined by the user.\n - After receiving public traffic forwarded by the `portal`, the `bridge` sends it intact to the web server on Host A. Naturally, this step requires configuration in the routing module.\n - Upon receiving a response, the `bridge` returns the response intact to the `portal`.\n\n- `portal`\n - If the `portal` receives a request and the domain matches, it indicates response data sent by the `bridge`. This connection will be used to establish the reverse tunnel.\n - If the `portal` receives a request and the domain does _not_ match, it indicates a connection from a public user. This connection data will be forwarded to the bridge.\n\n- The `bridge` performs dynamic load balancing based on traffic volume.\n\nAs mentioned above, the reverse proxy has [Mux](https://xtls.github.io/en/development/protocols/muxcool.html) enabled by default. Please do not enable Mux again on the outbounds used by it.\n\nThe reverse proxy function is currently in the testing stage and may have some issues.\n";
2445
+ //#endregion
2446
+ //#region src/reverse/reverse.ts
2447
+ const bridgeObject = z.object({
2448
+ tag: z.string().optional().meta({ markdownDescription: `All connections initiated by the \`bridge\` will carry this tag. It can be identified using \`inboundTag\` in the [Routing Configuration](https://xtls.github.io/en/config/routing.html).` }),
2449
+ domain: z.string().optional().meta({ markdownDescription: `Specifies a domain name. Connections established by the \`bridge\` to the \`portal\` will be sent using this domain.
2450
+ This domain is used solely for communication between the \`bridge\` and the \`portal\` and does not need to exist in reality.` })
2451
+ }).meta({ markdownDescription: `An array, where each item represents a \`bridge\`. The configuration for each \`bridge\` is a [BridgeObject](https://xtls.github.io/en/config/reverse.html#bridgeobject).` });
2452
+ const portalObject = z.object({
2453
+ tag: z.string().optional().meta({ markdownDescription: `The identifier for the \`portal\`. Use \`outboundTag\` in the [Routing Configuration](https://xtls.github.io/en/config/routing.html) to forward traffic to this \`portal\`.` }),
2454
+ domain: z.string().optional().meta({ markdownDescription: `A domain name. When the \`portal\` receives traffic, if the target domain of the traffic matches this domain, the \`portal\` considers the current connection to be a communication connection sent by the \`bridge\`. Other traffic will be treated as traffic that needs to be forwarded. The job of the \`portal\` is to identify these two types of connections and perform the corresponding forwarding.
2455
+
2456
+ A single Xray instance can act as a \`bridge\`, a \`portal\`, or both simultaneously to suit different scenario requirements.` })
2457
+ }).meta({ markdownDescription: `An array, where each item represents a \`portal\`. The configuration for each \`portal\` is a [PortalObject](https://xtls.github.io/en/config/reverse.html#bridgeobject).` });
2458
+ const reverse = z.object({
2459
+ bridges: z.array(bridgeObject).optional(),
2460
+ portals: z.array(portalObject).min(1)
2461
+ }).or(z.object({
2462
+ bridges: z.array(bridgeObject).min(1),
2463
+ portals: z.array(portalObject).optional()
2464
+ })).meta({
2465
+ markdownDescription: reverse_default,
2466
+ deprecated: true,
2467
+ deprecationMessage: `This feature has been deprecated. Please use the VLESS reverse proxy.`
2468
+ });
2469
+ //#endregion
2470
+ //#region src/outbounds/baseOutbound/baseOutbound.ts
2471
+ const outboundSchemaBase = z.object({
2472
+ sendThrough: z.string().or(z.enum(["origin", "srcip"])).optional().meta({ markdownDescription: "The IP address used to send data. This is effective when the host has multiple IP addresses. The default value is `\"0.0.0.0\"`.\n\nYou can enter an IPv6 CIDR block (e.g., `114:514:1919:810::/64`), and Xray will use a random IP address from the address block to initiate external connections. You need to correctly configure the network access method, routing table, and kernel parameters to allow Xray to bind to any IP within the address block.\n\nFor networks using NDP access, it is not recommended to set a subnet smaller than `/120`. Otherwise, it may cause issues such as NDP flooding, leading to the router's neighbor cache becoming full.\n\nSpecial value `origin`: If this value is used, the request will be sent using the IP address of the local machine that received the connection.\n\nSpecial value `srcip`: If this value is used, the request will be sent using the source IP address of the inbound connection.\n\nFor example, if the machine has a full IPv4 range `11.4.5.0/24` and listens on `0.0.0.0` (all IPv4 and IPv6 on the network interface), if a client connects to the local machine via `11.4.5.14`, the outbound request will also be sent via `11.4.5.14`. If the client connects via `11.4.5.10`, the outbound request will also be sent via `11.4.5.10`. This also applies to cases where the machine has a full range/multiple IPv6 addresses.\n\nAs mentioned in the inbound introduction, because of the connectionless nature of UDP, Xray cannot know the original destination IP where the request entered the core (for example, in the same QUIC connection, it might even change), so this feature cannot take effect for UDP.\n" }),
2473
+ tag: z.string().optional().meta({ markdownDescription: "The identifier for this outbound connection, used to locate this connection in other configurations.\n\n### DANGER\n\nWhen not empty, its value must be **unique** among all `tag`s.\n" }),
2474
+ streamSettings: streamSettings.optional().meta({ markdownDescription: "Transport configuration for this outbound.\n" }),
2475
+ targetStrategy: z.enum([
2476
+ "AsIs",
2477
+ "UseIP",
2478
+ "UseIPv6v4",
2479
+ "UseIPv6",
2480
+ "UseIPv4v6",
2481
+ "UseIPv4",
2482
+ "ForceIP",
2483
+ "ForceIPv6v4",
2484
+ "ForceIPv6",
2485
+ "ForceIPv4v6",
2486
+ "ForceIPv4"
2487
+ ]).default("AsIs").optional().meta({ markdownDescription: "If this outbound attempts to send a domain request, this controls whether it is resolved/how it is resolved to an IP before sending.\n\nThe default value is `AsIs`, meaning it is sent to the remote server as is. All parameter meanings are roughly equivalent to `domainStrategy` in [Sockopt](https://xtls.github.io/en/config/transports/sockopt.html#sockoptobject).\n\n### TIP\n\nThis controls **proxied requests**. If the address of the outbound proxy server is a domain name, and you need to select a resolution strategy for the domain name itself, you should configure `domainStrategy` in [Sockopt](https://xtls.github.io/en/config/transports/sockopt.html#sockoptobject).\n" }),
2488
+ proxySettings: z.object({
2489
+ tag: z.string().min(1).meta({ markdownDescription: "When the identifier of another outbound is specified, data sent by this outbound will be forwarded to the specified outbound for transmission.\n\n### DANGER\n\nThis option conflicts with [Sockopt.dialerProxy](https://xtls.github.io/en/config/transports/sockopt.html#sockoptobject). Choose one as needed.\n\nBy default, this forwarding method **ignores** this outbound's own transport configuration (such as XHTTP, REALITY, or Sockopt), meaning the `streamSettings` of this outbound will not take effect. \nIf you need forwarding that works together with `streamSettings`, please use `Sockopt.dialerProxy` instead or set `transportLayer` to `true` here.\n" }),
2490
+ transportLayer: z.boolean().default(false).optional().meta({ markdownDescription: "`true` converts this setting to `Sockopt.dialerProxy` so the forwarding can use this outbound's `streamSettings`. The default is `false`.\n" })
2491
+ }).optional().meta({ markdownDescription: "Outbound proxy configuration.\n" }),
2492
+ mux: z.object({
2493
+ enabled: z.boolean().default(false).optional().meta({ markdownDescription: "Whether to enable Mux for forwarding requests. Default is `false`.\n" }),
2494
+ concurrency: z.int().optional().meta({ markdownDescription: "Maximum concurrent connections. Minimum `1`, maximum `128`. If omitted or set to `0`, it equals `8`. Values greater than `128` are treated as 128, because once a connection reaches the maximum reuse count of 128, it will no longer be assigned any new sub-connections.\n\nThis value represents the maximum number of sub-connections carried on a single TCP connection. For example, if `concurrency=8` is set, when the client issues 8 TCP requests, Xray will only issue one actual TCP connection, and all 8 requests from the client are transmitted over this TCP connection.\n\nWhen the maximum sub-connection capacity of all Mux connections is fully occupied, the core will initiate new connections to carry sub-connections. If a large number of sub-connections are concurrent in a short time and subsequently decrease, the internal scheduler of the core will tend to distribute requests to 2 connections alternately and leave other connections idle, waiting for all their sub-connections to end naturally before closing them to save resources. If the total number of sub-connections continues to be lower than `concurrency` for a long time, after one of the connections reaches the maximum reuse count, the core will revert to a single connection state.\n\n### TIP\n\nWhen set to a negative number, such as `-1`, the Mux module is not used to carry TCP traffic.\n" }),
2495
+ xudpConcurrency: z.int().optional().meta({ markdownDescription: "Use a new XUDP aggregation tunnel (i.e., another Mux connection) to proxy UDP traffic. Fill in the maximum number of concurrent sub-UoT. Minimum `1`, maximum `1024`. If omitted or set to `0`, it will follow the same path as TCP traffic, which is the traditional behavior.\n\n### TIP\n\nWhen set to a negative number, such as `-1`, the Mux module is not used to carry UDP traffic. The proxy protocol's original UDP transmission method will be used. For example, `Shadowsocks` will use native UDP, and `VLESS` will use UoT.\n" }),
2496
+ xudpProxyUDP443: z.enum([
2497
+ "reject",
2498
+ "allow",
2499
+ "skip"
2500
+ ]).default("reject").optional().meta({ markdownDescription: "Controls how Mux handles proxied UDP/443 (QUIC) traffic:\n\n- Default `reject`: Rejects traffic (browsers typically fall back to TCP HTTP2 automatically).\n- `allow`: Allows traffic to go through the Mux connection.\n- `skip`: Does not use the Mux module to carry UDP 443 traffic. The proxy protocol's original UDP transmission method will be used. For example, `Shadowsocks` will use native UDP, and `VLESS` will use UoT.\n" })
2501
+ }).optional().meta({ markdownDescription: "The Mux function distributes data from multiple TCP connections over a single TCP connection. For implementation details, see [Mux.Cool](https://xtls.github.io/en/development/protocols/muxcool.html). Mux is designed to reduce TCP handshake latency, not to increase connection throughput. Using Mux for watching videos, downloading, or speed testing usually has a negative effect. Mux only needs to be enabled on the client side; the server side adapts automatically. The second use of Mux is to distribute multiple UDP connections, i.e., XUDP.\n\n`MuxObject` corresponds to the `mux` item in `OutboundObject`.\n" })
2502
+ });
2503
+ //#endregion
2504
+ //#region src/outbounds/blackhole/blackhole.ts
2505
+ const blackhole = outboundSchemaBase.extend({
2506
+ protocol: z.literal("blackhole").or(z.literal("block")),
2507
+ settings: z.object({ response: z.object({ type: z.enum(["none", "http"]).default("none").optional().meta({ markdownDescription: "When `type` is `\"none\"` (default value), Blackhole will close the connection immediately.\n\nWhen `type` is `\"http\"`, Blackhole will send back a simple HTTP 403 response packet, then close the connection.\n" }) }).optional().meta({ markdownDescription: "Configures the response data of the Blackhole.\n\nAfter receiving data to be forwarded, Blackhole will send the specified response data, then close the connection. The data to be forwarded will be discarded. If this item is not specified, Blackhole will close the connection immediately.\n" }) }).optional().meta({ markdownDescription: "`OutboundConfigurationObject` corresponds to the `settings` item in [`OutboundObject`](https://xtls.github.io/en/config/outbound.html).\n" })
2508
+ }).meta({ markdownDescription: "Blackhole is an outbound data protocol that blocks all outbound data. When used in conjunction with [Routing Configuration](https://xtls.github.io/en/config/routing.html), it can achieve the effect of blocking access to certain websites.\n\n[Documentation ↗](https://xtls.github.io/en/config/outbounds/blackhole.html)\n" });
2509
+ //#endregion
2510
+ //#region src/outbounds/freedom/freedom.md?raw
2511
+ var freedom_default = "Freedom is an outbound protocol used to send (normal) TCP or UDP data to any network.\n\n### WARNING\n\nThis outbound has a default safety policy in server-side and reverse-proxy scenarios, which may block some targets. See `finalRules` below for how to allow them.\n\n[Documentation ↗](https://xtls.github.io/en/config/outbounds/freedom.html)\n";
2512
+ //#endregion
2513
+ //#region src/outbounds/freedom/freedomSettings.md?raw
2514
+ var freedomSettings_default = "`OutboundConfigurationObject` corresponds to the `settings` item in [`OutboundObject`](https://xtls.github.io/en/config/outbound.html).\n";
2515
+ //#endregion
2516
+ //#region src/outbounds/freedom/freedomDomainStrategy.md?raw
2517
+ var freedomDomainStrategy_default = "Default value `\"AsIs\"`.\n\nThe meanings of all parameters are roughly equivalent to `domainStrategy` in [Sockopt](https://xtls.github.io/en/config/transports/sockopt.html#sockoptobject).\n\nOnly using `\"AsIs\"` here allows passing the domain name to the subsequent `sockopt` module. If set to non-`\"AsIs\"` here, causing the domain to be resolved to a specific IP, it will invalidate the subsequent `sockopt.domainStrategy` and its related `happyEyeballs`. (There is no negative impact if these two settings are not adjusted).\n\nWhen sending UDP, Freedom ignores `domainStrategy` in `sockopt` for some reasons and forcibly prefers IPv4 by default.\n";
2518
+ //#endregion
2519
+ //#region src/outbounds/freedom/freedomRedirect.md?raw
2520
+ var freedomRedirect_default = "Freedom will forcibly send all data to the specified address (instead of the address specified by the inbound).\n\nThe value is a string, e.g., `\"127.0.0.1:80\"`, `\":1234\"`.\n\nWhen the address is not specified, e.g., `\":443\"`, Freedom will not modify the original destination address. When the port is `0`, e.g., `\"xray.com:0\"`, Freedom will not modify the original port.\n";
2521
+ //#endregion
2522
+ //#region src/outbounds/freedom/freedomUserLevel.md?raw
2523
+ var freedomUserLevel_default = "User level. Connections will use the [Local Policy](https://xtls.github.io/en/config/policy.html#levelpolicyobject) corresponding to this user level.\n\nThe value of `userLevel` corresponds to the value of `level` in [policy](https://xtls.github.io/en/config/policy.html#policyobject). If not specified, it defaults to 0.\n";
2524
+ //#endregion
2525
+ //#region src/outbounds/freedom/freedomFragment.md?raw
2526
+ var freedomFragment_default = "A set of key-value configuration items used to control outgoing TCP fragmentation. In some cases, it can deceive censorship systems, such as bypassing SNI blacklists.\n\n`\"length\"` and `\"interval\"` are both [Int32Range](https://xtls.github.io/en/development/intro/guide.html#int32range) types.\n\n`\"packets\"`: Supports two fragmentation modes. `\"1-3\"` is TCP stream slicing, applied to the 1st through 3rd data writes by the client. `\"tlshello\"` is TLS handshake packet slicing.\n\n`\"length\"`: Fragment packet length (byte).\n\n`\"interval\"`: Fragment interval (ms).\n\nWhen `interval` is 0 and `\"packets\": \"tlshello\"` is set, the fragmented Client Hello will be sent in one TCP packet (provided its original size does not exceed MSS or MTU causing automatic system fragmentation).\n";
2527
+ //#endregion
2528
+ //#region src/outbounds/freedom/freedomNoises.md?raw
2529
+ var freedomNoises_default = "UDP noise, used to send some random data as \"noise\" before sending a UDP connection. Presence of this structure implies enablement. It might deceive sniffers, or it might disrupt normal connections. _Use at your own risk._ For this reason, it bypasses port 53 because that breaks DNS.\n\nIt is an array where multiple noise packets to be sent can be defined. A single element in the array is defined as follows:\n\n`\"type\"`: Noise packet type. Currently supports `\"rand\"` (random data), `\"str\"` (user-defined string), `\"base64\"` (base64 encoded custom binary data).\n\n`\"packet\"`: The content of the packet to be sent based on the preceding `type`.\n\n- When `type` is `rand`, this specifies the length of the random data. It can be a fixed value `\"100\"` or a floating range `\"50-150\"`.\n- When `type` is `str`, this specifies the string to be sent.\n- When `type` is `hex`, this specifies binary data in hex format.\n- When `type` is `base64`, this specifies base64 encoded binary data.\n\n`\"delay\"`: Delay in milliseconds. After sending this noise packet, the core will wait for this time before sending the next noise packet or real data. Defaults to no wait. It is an [Int32Range](https://xtls.github.io/en/development/intro/guide.html#int32range) type.\n";
2530
+ //#endregion
2531
+ //#region src/outbounds/freedom/freedomProxyProtocol.md?raw
2532
+ var freedomProxyProtocol_default = "PROXY protocol is usually used with `redirect` to redirect traffic to Nginx or other backend services that have the PROXY protocol enabled. If the backend service does not support PROXY protocol, the connection will be disconnected.\n\nThe value of `proxyProtocol` is the PROXY protocol version number. Options are `1` or `2`. If not specified, it defaults to `0` (disabled).\n";
2533
+ //#endregion
2534
+ //#region src/outbounds/freedom/freedomFinalRules.md?raw
2535
+ var freedomFinalRules_default = "Matches Freedom final outbound rules in order, and allows or blocks connection targets.\n\nCompared with blocking in `routing`, `finalRules` applies at Freedom's final outbound stage: matching happens after the final IP is resolved and before dialing; in addition, UDP is also matched packet by packet during send and receive, making it stricter and more thorough. Each rule match takes about 50-150 ns.\n\nNote: whenever Freedom needs to apply `finalRules`, if `domainStrategy` is `AsIs` and the target is a domain, Freedom still resolves the target to an IP through the operating system DNS before matching rules. At that point the target is no longer a domain, so the later `sockopt.domainStrategy` and its `happyEyeballs` no longer take effect.\n\n### WARNING\n\nThere is a default fallback safety policy for server-side and reverse-proxy scenarios:\n\nIf no explicit rule matches, the built-in fallback rule is used: traffic from the VLESS reverse proxy blocks all targets by default; traffic from `VLESS`, `VMess`, `Trojan`, `Shadowsocks`, `Hysteria`, or `WireGuard` inbounds blocks private and reserved IP ranges by default; other traffic is fully allowed by default.\n\nIf the server needs to allow clients to access some internal services, explicitly configure `allow` rules and limit them to the necessary `network`, `ip`, and `port` whenever possible.\n\nIf the server also needs features that rely on passing the domain to `sockopt` (such as `sockopt.domainStrategy` or `happyEyeballs`), it cannot continue relying on this default safety policy. You can configure the first rule as an `allow` rule without any matching conditions to restore the previous behavior; this is also equivalent to disabling this default safety policy, so evaluate the security impact yourself.\n";
2536
+ //#endregion
2537
+ //#region src/outbounds/freedom/freedomFinalRule.md?raw
2538
+ var freedomFinalRule_default = "All matching conditions in a rule are combined with AND logic. If a condition is omitted, that condition is not restricted.\n";
2539
+ //#endregion
2540
+ //#region src/outbounds/freedom/freedomFinalRuleAction.md?raw
2541
+ var freedomFinalRuleAction_default = "Defines the action to take when the rule matches.\n\n- `allow`: Allows the target.\n- `block`: Blocks the target.\n";
2542
+ //#endregion
2543
+ //#region src/outbounds/freedom/freedomFinalRuleNetwork.md?raw
2544
+ var freedomFinalRuleNetwork_default = "Matches the network type. The rule takes effect when the connection method matches. It can also be written as a string array, such as `[\"tcp\", \"udp\"]`. If omitted, all networks are matched.\n";
2545
+ //#endregion
2546
+ //#region src/outbounds/freedom/freedomFinalRulePort.md?raw
2547
+ var freedomFinalRulePort_default = "Target port range. The syntax is the same as [`port` in routing rules](https://xtls.github.io/en/config/routing.html#ruleobject). If omitted, all ports are matched.\n";
2548
+ //#endregion
2549
+ //#region src/outbounds/freedom/freedomFinalRuleIp.md?raw
2550
+ var freedomFinalRuleIp_default = "An array where each item represents an IP range. The rule takes effect when an item matches the target IP. The syntax is the same as [`ip` in routing rules](https://xtls.github.io/en/config/routing.html#ruleobject). If omitted, all IPs are matched.\n";
2551
+ //#endregion
2552
+ //#region src/outbounds/freedom/freedomFinalRuleBlockDelay.md?raw
2553
+ var freedomFinalRuleBlockDelay_default = "Sets how long the blackhole state lasts after a blocking rule matches.\n\nWhen a rule's `action` is `block` and the target matches, Freedom puts the connection into a blackhole state and closes it after this duration expires. The unit is seconds. It can be written as a fixed value or a range, for example `30` or `30-90`. If omitted, it defaults to `30-90`, which means a random value within that range.\n";
2554
+ //#endregion
2555
+ //#region src/outbounds/freedom/freedom.ts
2556
+ const fragment = z.object({
2557
+ length: z.int().or(z.string()),
2558
+ interval: z.int().or(z.string()),
2559
+ packets: z.literal("tlshello").or(z.string())
2560
+ }).meta({ markdownDescription: freedomFragment_default });
2561
+ const noise = z.object({
2562
+ type: z.enum([
2563
+ "rand",
2564
+ "str",
2565
+ "base64"
2566
+ ]),
2567
+ packet: z.string(),
2568
+ delay: z.int().or(z.string()).optional()
2569
+ });
2570
+ const finalRule = z.object({
2571
+ action: z.enum(["allow", "block"]).meta({ markdownDescription: freedomFinalRuleAction_default }),
2572
+ network: z.enum([
2573
+ "tcp",
2574
+ "udp",
2575
+ "tcp,udp"
2576
+ ]).meta({ markdownDescription: freedomFinalRuleNetwork_default }),
2577
+ port: portLikeSchema.meta({ markdownDescription: freedomFinalRulePort_default }),
2578
+ ip: z.array(z.string()).optional().meta({ markdownDescription: freedomFinalRuleIp_default }),
2579
+ blockDelay: z.string().optional().meta({ markdownDescription: freedomFinalRuleBlockDelay_default })
2580
+ }).meta({ markdownDescription: freedomFinalRule_default });
2581
+ const freedom = outboundSchemaBase.extend({
2582
+ protocol: z.literal("freedom").or(z.literal("direct")),
2583
+ settings: z.object({
2584
+ domainStrategy: z.enum([
2585
+ "AsIs",
2586
+ "UseIP",
2587
+ "UseIPv6v4",
2588
+ "UseIPv6",
2589
+ "UseIPv4v6",
2590
+ "UseIPv4",
2591
+ "ForceIP",
2592
+ "ForceIPv6v4",
2593
+ "ForceIPv6",
2594
+ "ForceIPv4v6",
2595
+ "ForceIPv4"
2596
+ ]).default("AsIs").optional().meta({ markdownDescription: freedomDomainStrategy_default }),
2597
+ redirect: z.string().optional().meta({ markdownDescription: freedomRedirect_default }),
2598
+ userLevel: z.int().default(0).optional().meta({ markdownDescription: freedomUserLevel_default }),
2599
+ fragment: fragment.optional(),
2600
+ noises: z.array(noise).optional().meta({ markdownDescription: freedomNoises_default }),
2601
+ proxyProtocol: z.literal(0).or(z.literal(1)).or(z.literal(2)).default(0).optional().meta({ markdownDescription: freedomProxyProtocol_default }),
2602
+ finalRules: z.array(finalRule).default([]).optional().meta({ markdownDescription: freedomFinalRules_default })
2603
+ }).optional().meta({ markdownDescription: freedomSettings_default })
2604
+ }).meta({ markdownDescription: freedom_default });
2605
+ //#endregion
2606
+ //#region src/outbounds/dns/dns.md?raw
2607
+ var dns_default = "DNS is an outbound protocol used to receive DNS queries sent in by routing, then forward or process them according to rules.\n\nThis outbound only supports traditional plaintext DNS queries over UDP and TCP; non-plaintext DNS protocols such as DoH, DoT, and DoQ are not applicable to this outbound. Common scenarios include TUN, transparent proxy, or `dokodemo-door` receiving DNS traffic and then routing sending that traffic to this outbound.\n\nIt can allow queries to the target DNS server, `hijack` them to the built-in [DNS server](https://xtls.github.io/en/config/dns.html) for further processing, drop them, or return responses with a specified RCODE according to rules. It can also rewrite the target address, port, and transport protocol.\n\n[Documentation ↗](https://xtls.github.io/en/config/outbounds/dns.html)\n";
2608
+ //#endregion
2609
+ //#region src/outbounds/dns/dnsSettings.md?raw
2610
+ var dnsSettings_default = "`OutboundConfigurationObject` corresponds to the `settings` item in [`OutboundObject`](https://xtls.github.io/en/config/outbound.html).\n";
2611
+ //#endregion
2612
+ //#region src/outbounds/dns/dnsRewriteNetwork.md?raw
2613
+ var dnsRewriteNetwork_default = "Modifies the transport protocol used for DNS traffic. Available values are `\"tcp\"` and `\"udp\"`. If omitted, the original transport method is preserved.\n";
2614
+ //#endregion
2615
+ //#region src/outbounds/dns/dnsRewriteAddress.md?raw
2616
+ var dnsRewriteAddress_default = "Modifies the DNS server address. If omitted, the address specified by the source is preserved.\n";
2617
+ //#endregion
2618
+ //#region src/outbounds/dns/dnsRewritePort.md?raw
2619
+ var dnsRewritePort_default = "Modifies the DNS server port. If omitted, the port specified by the source is preserved.\n";
2620
+ //#endregion
2621
+ //#region src/outbounds/dns/dnsUserLevel.md?raw
2622
+ var dnsUserLevel_default = "User level. Connections will use the [local policy](https://xtls.github.io/en/config/policy.html#levelpolicyobject) corresponding to this user level.\n\nThe value of `userLevel` corresponds to the `level` value in [policy](https://xtls.github.io/en/config/policy.html#policyobject). If omitted, it defaults to `0`.\n";
2623
+ //#endregion
2624
+ //#region src/outbounds/dns/dnsRules.md?raw
2625
+ var dnsRules_default = "Matches DNS query rules in order, and supports fine-grained control by `qtype` and `domain`.\n\nIf no rule is matched, the built-in fallback rule is used: A and AAAA queries are imported into the built-in DNS module, while other query types return an empty response with RCODE `0`.\n";
2626
+ //#endregion
2627
+ //#region src/outbounds/dns/dns.ts
2628
+ const dnsRule = z.object({
2629
+ action: z.enum([
2630
+ "direct",
2631
+ "hijack",
2632
+ "drop",
2633
+ "return"
2634
+ ]).meta({ markdownDescription: "Defines the action to take when the rule matches.\n\n- `direct`: Allows the query directly to the target DNS server. If outbound-level `rewriteNetwork`, `rewriteAddress`, or `rewritePort` is also configured, the query is forwarded to the rewritten target.\n- `hijack`: Imports the query into the built-in [DNS server](https://xtls.github.io/en/config/dns.html) for further processing. This can be used for additional routing based on the built-in DNS configuration. Currently, only A and AAAA records are supported.\n- `drop`: Drops the request directly without returning a response.\n- `return`: Returns a DNS response whose response code is specified by `rCode`. Compared with `drop`, this can prevent some applications from waiting too long for a DNS timeout or repeatedly retrying.\n" }),
2635
+ qtype: z.number().or(z.string()).optional().meta({ markdownDescription: "Matches DNS query types. The forms are as follows:\n\n- Integer value: a specific query type, such as `\"qtype\": 1` for an A query, or `\"qtype\": 28` for an AAAA query.\n- String: can be a digits-only string such as `\"qtype\": \"28\"`, or a numeric range such as `\"qtype\": \"5-10\"`, which represents the 6 types from type 5 to type 10. Commas can be used for segmentation, such as `11,13,15-17`, which represents the 5 types: type 11, type 13, and type 15 to type 17.\n\nFor specific type numbers, refer to the [IANA documentation](https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml).\n" }),
2636
+ rCode: z.number().optional().meta({ markdownDescription: "The DNS RCODE used when returning a response, in the range `0` to `65535`. It only takes effect when `action` is `return`; if omitted, it defaults to `0`.\n" }),
2637
+ domain: z.array(z.string()).meta({ markdownDescription: "Matches a list of domains. The syntax is the same as [`domain` in routing rules](https://xtls.github.io/en/config/routing.html#ruleobject).\n" })
2638
+ }).meta({ markdownDescription: "All matching conditions in a rule are combined with AND logic. If a condition is omitted, that condition is not restricted.\n" });
2639
+ const dns = outboundSchemaBase.extend({
2640
+ protocol: z.literal("dns"),
2641
+ settings: z.object({
2642
+ rewriteNetwork: z.enum(["tcp", "udp"]).optional().meta({ markdownDescription: dnsRewriteNetwork_default }),
2643
+ rewriteAddress: z.string().optional().meta({ markdownDescription: dnsRewriteAddress_default }),
2644
+ rewritePort: z.string().optional().meta({ markdownDescription: dnsRewritePort_default }),
2645
+ userLevel: z.int().default(0).optional().meta({ markdownDescription: dnsUserLevel_default }),
2646
+ rules: z.array(dnsRule).default([]).optional().meta({ markdownDescription: dnsRules_default })
2647
+ }).meta({ markdownDescription: dnsSettings_default })
2648
+ }).meta({ markdownDescription: dns_default });
2649
+ //#endregion
2650
+ //#region src/outbounds/hysteria/hysteria.ts
2651
+ const hysteria = outboundSchemaBase.extend({
2652
+ protocol: z.literal("hysteria"),
2653
+ settings: z.object({
2654
+ version: z.literal(2).meta({ markdownDescription: "Hysteria version, must be 2.\n" }),
2655
+ address: z.string().meta({ markdownDescription: "Hysteria proxy server address, required.\n" }),
2656
+ port: portLikeSchema.meta({ markdownDescription: "Hysteria proxy server port, required.\n" })
2657
+ }).meta({ markdownDescription: "`OutboundConfigurationObject` corresponds to the `settings` item in [`OutboundObject`](https://xtls.github.io/en/config/outbound.html).\n" })
2658
+ }).meta({ markdownDescription: "Client implementation of the Hysteria protocol.\n\nThis page is very simple because the Hysteria protocol is actually composed of a simple proxy control protocol and a tuned QUIC transport implementation. In Xray, the proxy protocol and transport configuration are separated. For more details (such as `brutal`), please refer to transport configuration items [hysteriaSettings](https://xtls.github.io/en/config/transports/hysteria.html) and [FinalMask.quicParams](https://xtls.github.io/en/config/transports/finalmask.html#quicparams).\n\n### TIP\n\nThe `hysteria protocol` itself has no authentication. When using with a non `hysteria` transport layer, it will be unable to proxy `udp`, and using it with other transport layers is not recommended.\n\n[Documentation ↗](https://xtls.github.io/en/config/outbounds/hysteria.html)\n" });
2659
+ //#endregion
2660
+ //#region src/outbounds/loopback/loopback.ts
2661
+ const loopback = outboundSchemaBase.extend({
2662
+ protocol: z.literal("loopback"),
2663
+ settings: z.object({ inboundTag: z.string().meta({ markdownDescription: "The inbound protocol identifier used for re-routing.\n\nThis identifier can be used for `inboundTag` in routing rules, indicating that data from this outbound can be processed again by the corresponding routing rules.\n" }) }).meta({ markdownDescription: "`OutboundConfigurationObject` corresponds to the `settings` item in [`OutboundObject`](https://xtls.github.io/en/config/outbound.html).\n" })
2664
+ }).meta({ markdownDescription: "Loopback is an outbound data protocol. Its function is to re-inject data sent through this outbound back into the routing inbound, allowing the data to be processed by the routing system again without leaving Xray-core.\n\n[Documentation ↗](https://xtls.github.io/en/config/outbounds/loopback.html)\n" });
2665
+ //#endregion
2666
+ //#region src/outbounds/shadowsocks/shadowsocks.md?raw
2667
+ var shadowsocks_default = "The [Shadowsocks](https://en.wikipedia.org/wiki/Shadowsocks) protocol, compatible with most other version implementations.\n\nCurrent compatibility is as follows:\n\n- Supports TCP and UDP packet forwarding, where UDP can be optionally disabled;\n- Recommended encryption methods:\n - 2022-blake3-aes-128-gcm\n - 2022-blake3-aes-256-gcm\n - 2022-blake3-chacha20-poly1305\n- Other encryption methods:\n - aes-256-gcm\n - aes-128-gcm\n - chacha20-poly1305 (or chacha20-ietf-poly1305)\n - xchacha20-poly1305 (or xchacha20-ietf-poly1305)\n - none (or plain)\n\nThe Shadowsocks 2022 new protocol format improves performance and includes complete replay protection, resolving the following security issues of the old protocol:\n\n- [Severe vulnerabilities in the design of Shadowsocks AEAD encryption, unable to guarantee communication reliability](https://github.com/shadowsocks/shadowsocks-org/issues/183)\n- The false positive rate of the original TCP replay filter increases over time\n- No UDP replay protection\n- TCP behavior that can be used for active probing\n\n### DANGER\n\nUnder the \"none\" encryption method, traffic will be transmitted in plain text. To ensure security, do not use it on public networks.\n\n[Documentation ↗](https://xtls.github.io/en/config/outbounds/shadowsocks.html)\n";
2668
+ //#endregion
2669
+ //#region src/outbounds/shadowsocks/shadowsocks.ts
2670
+ const shadowsocksServerSettings = z.object({
2671
+ address: z.string().meta({ markdownDescription: "Shadowsocks server address. Supports IPv4, IPv6, and domain names. Required.\n" }),
2672
+ port: portLikeSchema.meta({ markdownDescription: "Shadowsocks server port. Required.\n" }),
2673
+ email: z.string().optional().meta({ markdownDescription: "Email address, optional, used to identify the user.\n" }),
2674
+ password: z.string().default("").meta({ markdownDescription: "Shadowsocks authentication password. Required.\n\n- Shadowsocks 2022\n\nUses a pre-shared key similar to WireGuard as the password.\n\nUse `openssl rand -base64 <length>` to generate a key compatible with shadowsocks-rust. The length depends on the encryption method used.\n\n| Encryption Method | Key Length |\n| ----------------------------- | ---------- |\n| 2022-blake3-aes-128-gcm | 16 |\n| 2022-blake3-aes-256-gcm | 32 |\n| 2022-blake3-chacha20-poly1305 | 32 |\n\nIn the Go implementation, 32-byte keys always work.\n\n- Other encryption methods\n\nAny string. There is no limit on password length, but short passwords are more likely to be cracked. It is recommended to use passwords of 16 characters or longer.\n" }),
2675
+ method: z.union([ss22Methods, ssMethods]).meta({ markdownDescription: "Shadowsocks encryption method. Required.\n\nRecommended encryption methods:\n\n- 2022-blake3-aes-128-gcm\n- 2022-blake3-aes-256-gcm\n- 2022-blake3-chacha20-poly1305\n\nOther encryption methods:\n\n- aes-256-gcm\n- aes-128-gcm\n- chacha20-poly1305 (or chacha20-ietf-poly1305)\n- xchacha20-poly1305 (or xchacha20-ietf-poly1305)\n- none (or plain)\n" }),
2676
+ uot: z.boolean().default(true).optional().meta({ markdownDescription: "Enable `udp over tcp`.\n" }),
2677
+ UoTVersion: z.literal(1).or(z.literal(2)).default(2).optional().meta({ markdownDescription: "Implementation version of `UDP over TCP`.\n\nCurrent optional values: `1`, `2`.\n" }),
2678
+ level: z.int().default(0).optional().meta({ markdownDescription: "User level. The connection will use the [local policy](https://xtls.github.io/en/config/policy.html#levelpolicyobject) corresponding to this user level.\n\nThe value of `level` corresponds to the `level` value in [policy](https://xtls.github.io/en/config/policy.html#policyobject). If not specified, the default is 0.\n" })
2679
+ });
2680
+ const shadowsocks = outboundSchemaBase.extend({
2681
+ protocol: z.literal("shadowsocks"),
2682
+ settings: shadowsocksServerSettings.or(z.object({ servers: z.array(shadowsocksServerSettings) }))
2683
+ }).meta({ markdownDescription: shadowsocks_default });
2684
+ //#endregion
2685
+ //#region src/outbounds/socks/socks.md?raw
2686
+ var socks_default = "Standard Socks protocol implementation, compatible with Socks 5.\n\n### DANGER\n\n**The Socks protocol does not encrypt transmission and is not suitable for transmission over the public internet.**\n\n[Documentation ↗](https://xtls.github.io/en/config/outbounds/socks.html)\n";
2687
+ //#endregion
2688
+ //#region src/outbounds/socks/socks.ts
2689
+ const socksServerSettings = z.object({
2690
+ address: z.string().meta({ markdownDescription: "Server address. Required.\n\n### TIP\n\nOnly connections to Socks 5 servers are supported.\n" }),
2691
+ port: portLikeSchema.meta({ markdownDescription: "Server port. Required.\n" }),
2692
+ user: z.string().optional().meta({ markdownDescription: "Username, string type. Required if the remote server requires authentication; otherwise, do not include this item.\n" }),
2693
+ pass: z.string().optional().meta({ markdownDescription: "Password, string type. Required if the remote server requires authentication; otherwise, do not include this item.\n" }),
2694
+ level: z.int().default(0).optional().meta({ markdownDescription: "User level. The connection will use the [local policy](https://xtls.github.io/en/config/policy.html#levelpolicyobject) corresponding to this user level.\n\nThe value of `userLevel` corresponds to the value of `level` in [policy](https://xtls.github.io/en/config/policy.html#policyobject). If not specified, the default is 0.\n" }),
2695
+ email: z.string().optional().meta({ markdownDescription: "Email address, used to identify the user.\n" })
2696
+ }).meta({ markdownDescription: "`OutboundConfigurationObject` corresponds to the `settings` item in [`OutboundObject`](https://xtls.github.io/en/config/outbound.html).\n" });
2697
+ const socks = outboundSchemaBase.extend({
2698
+ protocol: z.literal("socks"),
2699
+ settings: socksServerSettings.or(z.object({ servers: z.array(socksServerSettings) })).optional()
2700
+ }).meta({ markdownDescription: socks_default });
2701
+ //#endregion
2702
+ //#region src/outbounds/trojan/trojan.md?raw
2703
+ var trojan_default = "[Trojan](https://trojan-gfw.github.io/trojan/protocol) protocol.\n\n### DANGER\n\nTrojan is designed to work over a correctly configured encrypted TLS tunnel.\n\n[Documentation ↗](https://xtls.github.io/en/config/outbounds/trojan.html)\n";
2704
+ //#endregion
2705
+ //#region src/outbounds/trojan/trojanSettings.md?raw
2706
+ var trojanSettings_default = "`OutboundConfigurationObject` corresponds to the `settings` item in [`OutboundObject`](https://xtls.github.io/en/config/outbound.html).\n";
2707
+ //#endregion
2708
+ //#region src/outbounds/trojan/trojanAddress.md?raw
2709
+ var trojanAddress_default = "Server address. Supports IPv4, IPv6, and domain names. Required.\n";
2710
+ //#endregion
2711
+ //#region src/outbounds/trojan/trojanPort.md?raw
2712
+ var trojanPort_default = "Server port. Usually the same as the port the server is listening on.\n";
2713
+ //#endregion
2714
+ //#region src/outbounds/trojan/trojanPassword.md?raw
2715
+ var trojanPassword_default = "Password. Required, any string.\n";
2716
+ //#endregion
2717
+ //#region src/outbounds/trojan/trojanEmail.md?raw
2718
+ var trojanEmail_default = "Email address. Optional, used to identify the user.\n";
2719
+ //#endregion
2720
+ //#region src/outbounds/trojan/trojanLevel.md?raw
2721
+ var trojanLevel_default = "User level. Connections will use the [Local Policy](https://xtls.github.io/en/config/policy.html#levelpolicyobject) corresponding to this user level.\n\nThe value of `level` corresponds to the value of `level` in [policy](https://xtls.github.io/en/config/policy.html#policyobject). If not specified, it defaults to 0.\n";
2722
+ //#endregion
2723
+ //#region src/outbounds/trojan/trojanServers.md?raw
2724
+ var trojanServers_default = "An array of Trojan server configurations.\n";
2725
+ //#endregion
2726
+ //#region src/outbounds/trojan/trojan.ts
2727
+ const trojanServerSettings = z.object({
2728
+ address: z.string().meta({ markdownDescription: trojanAddress_default }),
2729
+ port: portLikeSchema.optional().meta({ markdownDescription: trojanPort_default }),
2730
+ email: z.string().optional().meta({ markdownDescription: trojanEmail_default }),
2731
+ password: z.string().meta({ markdownDescription: trojanPassword_default }),
2732
+ level: z.int().default(0).optional().meta({ markdownDescription: trojanLevel_default })
2733
+ });
2734
+ const trojan = outboundSchemaBase.extend({
2735
+ protocol: z.literal("trojan"),
2736
+ settings: trojanServerSettings.or(z.object({ servers: z.array(trojanServerSettings).meta({ markdownDescription: trojanServers_default }) })).meta({ markdownDescription: trojanSettings_default })
2737
+ }).meta({ markdownDescription: trojan_default });
2738
+ //#endregion
2739
+ //#region src/outbounds/vless/vless.ts
2740
+ const vless = outboundSchemaBase.extend({
2741
+ protocol: z.literal("vless"),
2742
+ settings: z.object({
2743
+ address: z.string().meta({ markdownDescription: "Server address, points to the server. Supports domain names, IPv4, and IPv6.\n" }),
2744
+ port: portLikeSchema.meta({ markdownDescription: "Server port, usually the same as the port the server is listening on.\n" }),
2745
+ id: z.string().meta({ markdownDescription: "User ID for VLESS. It can be any string less than 30 bytes, or a valid UUID. A custom string and its mapped UUID are equivalent.\n\nThe mapping standard is described in [VLESS UUID Mapping Standard: Mapping Custom Strings to UUIDv5](https://github.com/XTLS/Xray-core/issues/158).\n\nYou can use the command `xray uuid -i \"custom string\"` to generate the UUID mapped from a custom string, or use the command `xray uuid` to generate a random UUID.\n" }),
2746
+ encryption: z.string().default("none").meta({ markdownDescription: "[VLESS Encryption](https://github.com/XTLS/Xray-core/pull/5067) settings. Cannot be left empty; to disable, explicitly set to `\"none\"`.\n\nIt is recommended for most users to use the `xray vlessenc` command to automatically generate this field to avoid configuration mistakes. The detailed configuration below is recommended only for advanced users.\n\nIts format is a detailed configuration string of fields connected by `.`. For example: `mlkem768x25519plus.native.0rtt.100-111-1111.75-0-111.50-0-3333.ptjHQxBQxTJ9MWr2cd5qWIflBSACHOevTauCQwa_71U`. This document will refer to the separate parts separated by dots as \"blocks\".\n\n- **The 1st block** is the handshake method. Currently, there is only `mlkem768x25519plus`. Requires consistency between server and client.\n- **The 2nd block** is the encryption method. Options are `native`/`xorpub`/`random`, corresponding to: raw format packet / raw format + obfuscated public key part / fully random numbers (similar to VMESS/Shadowsocks). Requires consistency between server and client.\n- **The 3rd block** is session resumption. Choosing `0rtt` will follow the server settings to attempt to use previously generated tickets to skip the handshake for fast connection (can be manually disabled by the server). Choosing `1rtt` will force a 1-RTT handshake process. The meaning here differs from the server setting; see VLESS Inbound `decryption` settings for details.\n\nFollowing blocks are **padding**. After the connection is established, the client sends some garbage data to obfuscate length characteristics. It does not need to be the same as the server (the corresponding part in the inbound is the padding sent from the server to the client). It is a variable-length part with the format `padding.delay.padding` + `(.delay.padding)` x n (multiple padding blocks can be inserted, requiring a delay block between two padding blocks).\n\n- `padding` format is `probability-min-max`. E.g., `100-111-1111` means 100% probability to send a padding of length 111~1111.\n- `delay` format is also `probability-min-max`. E.g., `75-0-111` means 75% probability to wait 0~111 milliseconds.\n\nThe first padding block has special requirements: probability must be 100% and minimum length greater than 0. If no padding exists, the core automatically uses `100-111-1111.75-0-111.50-0-3333` as the padding setting.\n\n**The last block** will be recognized by the core as the parameter used to authenticate the server. It can be generated by `./xray x25519` (using the Password part) or `./xray mlkem768` (using the Client part). It must correspond to the server. `mlkem768` belongs to post-quantum algorithms, preventing (future) client parameter leaks from allowing quantum computers to crack the private key and impersonate the server. This parameter is only used for verification; the handshake process is post-quantum secure regardless, and existing encrypted data cannot be decrypted by future quantum computers.\n" }),
2747
+ flow: z.enum([
2748
+ "",
2749
+ "xtls-rprx-vision",
2750
+ "xtls-rprx-vision-udp443"
2751
+ ]).optional().meta({ markdownDescription: "Flow control mode, used to select the XTLS algorithm.\n\nCurrently, the following flow control modes are available in the outbound protocol:\n\n- **No `flow` or empty string**: Use standard TLS proxy.\n- **`xtls-rprx-vision`**: Use XTLS, including inner handshake random padding. Will intercept UDP traffic targeting port 443 (QUIC) to force browsers to use standard HTTPS, increasing traffic that can be Spliced.\n- **`xtls-rprx-vision-udp443`**: Same as `xtls-rprx-vision`, but does not intercept UDP 443. Used when a program forces the use of QUIC and would fail to work if intercepted.\n\nXTLS is available only in the following combinations:\n\n- **TCP+TLS/REALITY**: In this case, if transmitting TLS 1.3, the core will attempt to Splice encrypted data at the bottom layer. If successful, it saves all core IO overhead.\n- **VLESS Encryption**: No underlying transport restrictions. If the underlying transport is not TCP, it only attempts to penetrate Encryption, saving Encryption overhead. If it is TCP, it will still attempt to perform Splice.\n\n### TIP\n\nSplice is a function provided by the Linux Kernel. The system kernel forwards TCP directly, no longer passing through Xray's memory, greatly reducing data copying and CPU context switching.\n\nWhen using Vision mode, Splice is automatically enabled if the following conditions are met:\n\n- Linux environment.\n- Inbound protocol is a pure TCP connection like `Dokodemo door`, `Socks`, `HTTP`, or other inbound protocols using XTLS.\n- Outbound protocol is VLESS + XTLS.\n\nWhen using Splice, the network speed display will lag and will only be counted after the connection is disconnected because the core cannot know the traffic situation while the kernel takes over the connection.\n" }),
2752
+ level: z.int().default(0).optional().meta({ markdownDescription: "User level. The connection will use the [Local Policy](https://xtls.github.io/en/config/policy.html#levelpolicyobject) corresponding to this user level.\n\nThe value of `level` corresponds to the value of `level` in [policy](https://xtls.github.io/en/config/policy.html#policyobject). If not specified, it defaults to 0.\n" }),
2753
+ reverse: z.object({
2754
+ tag: z.string().meta({ markdownDescription: "The inbound proxy tag for this reverse proxy. When the server dispatches a reverse proxy request, it enters the routing system from the inbound using this tag, and the routing system routes it to the outbound you need.\n" }),
2755
+ sniffing: sniffingSchema.optional()
2756
+ }).optional().meta({ markdownDescription: "VLESS minimalist reverse proxy configuration. It preserves the real source IP information from the public-facing side.\n\nThe existence of this item indicates that this outbound can be used as a VLESS reverse proxy outbound, and it will automatically establish a connection to the server to register the reverse proxy tunnel.\n\n`tag` is the inbound proxy tag for this reverse proxy. When the server dispatches a reverse proxy request, it enters the routing system from the inbound using this tag, and the routing system routes it to the outbound you need.\n\nThe UUID used must be one that is also configured with `reverse` on the server side (see VLESS Inbound for details).\n\n`sniffing` see [SniffingObject](https://xtls.github.io/en/config/inbound.html#sniffingobject), performs sniffing on requests entering through this reverse proxy.\n\n### TIP\n\nFull tutorial: [VLESS Reverse Proxy Examples](https://xtls.github.io/en/document/level-2/vless_reverse.html)\n" })
2757
+ }).meta({ markdownDescription: "`OutboundConfigurationObject` corresponds to the `settings` item in [`OutboundObject`](https://xtls.github.io/en/config/outbound.html).\n" })
2758
+ }).meta({ markdownDescription: "VLESS is a stateless lightweight transport protocol. It consists of inbound and outbound parts and can serve as a bridge between the Xray client and server.\n\nUnlike [VMess](https://xtls.github.io/en/config/outbounds/vmess.html), VLESS does not depend on system time. The authentication method is also UUID.\n\n[Documentation ↗](https://xtls.github.io/en/config/outbounds/vless.html)\n" });
2759
+ //#endregion
2760
+ //#region src/outbounds/vmess/vmess.ts
2761
+ const vmess = outboundSchemaBase.extend({
2762
+ protocol: z.literal("vmess"),
2763
+ settings: z.object({
2764
+ address: z.string().meta({ markdownDescription: "Server address, supports IP address or domain name.\n" }),
2765
+ port: portLikeSchema.meta({ markdownDescription: "The port number the server is listening on. Required.\n" }),
2766
+ id: z.string().meta({ markdownDescription: "VMess User ID. It can be any string less than 30 bytes or a valid UUID.\n\nA custom string and its mapped UUID are equivalent. This means you can identify the same user in the configuration file like this:\n\n- Write `\"id\": \"我爱🍉老师1314\"`,\n- Or write `\"id\": \"5783a3e7-e373-51cd-8642-c83782b807c5\"` (This UUID is the UUID mapping of `我爱🍉老师1314`)\n\nThe mapping standard is described in [VLESS UUID Mapping Standard: Mapping Custom Strings to a UUIDv5](https://github.com/XTLS/Xray-core/issues/158).\n\nYou can use the command `xray uuid -i \"custom string\"` to generate the UUID mapped from the custom string. You can also use the command `xray uuid` to generate a random UUID.\n" }),
2767
+ security: z.enum([
2768
+ "aes-128-gcm",
2769
+ "chacha20-poly1305",
2770
+ "auto",
2771
+ "none",
2772
+ "zero"
2773
+ ]).optional().meta({ markdownDescription: "Encryption method. The client will use the configured encryption method to send data, and the server will automatically identify it without configuration.\n\n- `\"aes-128-gcm\"`: Use AES-128-GCM algorithm.\n- `\"chacha20-poly1305\"`: Use Chacha20-Poly1305 algorithm.\n- `\"auto\"`: Default value. Automatically selected (uses aes-128-gcm encryption when the running framework is AMD64, ARM64, or s390x; uses Chacha20-Poly1305 encryption in other cases).\n- `\"none\"`: No encryption, maintains the VMess message structure.\n- `\"zero\"`: No encryption, direct stream copy (similar to VLESS).\n\nIt is not recommended to use `\"none\"` or `\"zero\"` pseudo-encryption methods without enabling TLS encryption and enforcing certificate verification. Regardless of the encryption method used, the VMess packet header is protected by encryption and authentication.\n\nNote: `\"auto\"` only determines the AES hardware acceleration support status of the _client_. If the _server_ does not support AES hardware acceleration, you still need to manually set it to `chacha20-poly1305`. This is very important because Chacha20-Poly1305 takes about 48% more time than AES-128-GCM on platforms supporting AES acceleration, but on platforms _without_ AES acceleration, AES-128-GCM takes over 2000% more time than Chacha20-Poly1305.\n" }),
2774
+ level: z.int().default(0).optional().meta({ markdownDescription: "User level. The connection will use the [local policy](https://xtls.github.io/en/config/policy.html#levelpolicyobject) corresponding to this user level.\n\nThe value of `level` corresponds to the value of `level` in [policy](https://xtls.github.io/en/config/policy.html#policyobject). If not specified, the default is 0.\n" }),
2775
+ experiments: z.enum([
2776
+ "AuthenticatedLength",
2777
+ "NoTerminationSignal",
2778
+ "AuthenticatedLength|NoTerminationSignal"
2779
+ ]).optional().meta({ markdownDescription: "Enabled VMess protocol experimental features. (Features here are unstable and may be removed at any time). Multiple enabled experiments can be separated by the `|` character, such as `\"AuthenticatedLength|NoTerminationSignal\"`.\n\n- `\"AuthenticatedLength\"`: Enable authenticated packet length experiment. This experiment requires both the client and server to enable it simultaneously and run the same version of the program.\n- `\"NoTerminationSignal\"`: Enable not sending the disconnection signal. This feature is now enabled by default.\n" })
2780
+ }).meta({ markdownDescription: "`OutboundConfigurationObject` corresponds to the `settings` item in [`OutboundObject`](https://xtls.github.io/en/config/outbound.html).\n" })
2781
+ }).meta({ markdownDescription: "[VMess](https://xtls.github.io/en/development/protocols/vmess.html) is an encrypted transport protocol, usually serving as a bridge between the Xray client and server.\n\n### DANGER\n\nVMess depends on system time. Please ensure that the UTC time of the system running Xray is within 120 seconds of the actual time, independent of the time zone. On Linux systems, you can install the `ntp` service to automatically synchronize the system time.\n\n[Documentation ↗](https://xtls.github.io/en/config/outbounds/vmess.html)\n" });
2782
+ //#endregion
2783
+ //#region src/outbounds/wireguard/wireguard.md?raw
2784
+ var wireguard_default = "Standard Wireguard protocol implementation.\n\n### DANGER\n\n**The Wireguard protocol is not designed specifically for bypassing firewalls. If used at the outermost layer to cross the Great Firewall, distinctive characteristics may lead to the server being blocked.**\n\n### TIP\n\nCurrently, configuring `streamSettings` is not supported in the Wireguard protocol outbound.\n\n[Documentation ↗](https://xtls.github.io/en/config/outbounds/wireguard.html)\n";
2785
+ //#endregion
2786
+ //#region src/outbounds/wireguard/wireguardSettings.md?raw
2787
+ var wireguardSettings_default = "`OutboundConfigurationObject` corresponds to the `settings` item in [`OutboundObject`](https://xtls.github.io/en/config/outbound.html).\n";
2788
+ //#endregion
2789
+ //#region src/outbounds/wireguard/wireguardSecretKey.md?raw
2790
+ var wireguardSecretKey_default = "User private key. Required.\n";
2791
+ //#endregion
2792
+ //#region src/outbounds/wireguard/wireguardAddress.md?raw
2793
+ var wireguardAddress_default = "Wireguard will start a virtual network interface (tun) locally. Use one or more IP addresses; IPv6 is supported.\n";
2794
+ //#endregion
2795
+ //#region src/outbounds/wireguard/wireguardNoKernelTun.md?raw
2796
+ var wireguardNoKernelTun_default = "By default, the core detects if it is running on Linux and if the current user has `CAP_NET_ADMIN` permissions to decide whether to enable the system virtual network interface; otherwise, it uses gVisor. Using the system virtual interface offers relatively higher performance. Note that this is only for processing IP packets and has nothing to do with the wireguard kernel module.\n\nThis detection may not always be accurate. For example, some LXC virtualization environments may not have TUN permissions at all, causing the outbound to fail. Therefore, you can set this option to manually disable it.\n\nWhen using the system virtual interface, it occupies IPv6 routing table number `10230`. Each additional Wireguard outbound will use subsequent routing tables sequentially; for example, the second one will use routing table `10231`, and so on.\n\nNote that if a second Xray instance is started on the same machine, it will not assign the next routing table number but will continue trying to use routing table `10230`. Since it is already occupied by the first Xray instance, it will fail to connect. If absolutely needed, you must set this option to disable the system virtual interface.\n";
2797
+ //#endregion
2798
+ //#region src/outbounds/wireguard/wireguardMtu.md?raw
2799
+ var wireguardMtu_default = "MTU size of the underlying Wireguard tun.\n\nThe structure of a Wireguard packet is as follows:\n\n- 20-byte IPv4 header or 40 byte IPv6 header\n- 8-byte UDP header\n- 4-byte type\n- 4-byte key index\n- 8-byte nonce\n- N-byte encrypted data\n- 16-byte authentication tag\n\n`N-byte encrypted data` is the MTU value we need. Depending on whether the endpoint is IPv4 or IPv6, the specific value can be 1440 (IPv4) or 1420 (IPv6). If in a special environment, subtract further (e.g., home broadband PPPoE requires an extra -8).\n";
2800
+ //#endregion
2801
+ //#region src/outbounds/wireguard/wireguardReserved.md?raw
2802
+ var wireguardReserved_default = "Wireguard reserved bytes, fill as needed.\n";
2803
+ //#endregion
2804
+ //#region src/outbounds/wireguard/wireguardWorkers.md?raw
2805
+ var wireguardWorkers_default = "Number of threads used by Wireguard. Defaults to the number of system cores.\n";
2806
+ //#endregion
2807
+ //#region src/outbounds/wireguard/wireguardPeers.md?raw
2808
+ var wireguardPeers_default = "List of Wireguard servers, where each item is a server configuration.\n";
2809
+ //#endregion
2810
+ //#region src/outbounds/wireguard/wireguardDomainStrategy.md?raw
2811
+ var wireguardDomainStrategy_default = "Controls the domain resolution strategy when the Wireguard server address is a domain name or the target address of the proxied traffic is a domain name.\n\nUnlike most proxy protocols, Wireguard does not allow passing domain names as targets. Therefore, if the incoming target is a domain, it needs to be resolved to an IP address before transmission. This is handled by Xray's built-in DNS. The meaning of this field is the same as `domainStrategy` in `Freedom` outbound. The default value is `ForceIP`.\n\nThe `domainStrategy` of `Freedom` outbound includes options like `UseIP`, which are not provided here because Wireguard must obtain a usable IP and cannot perform the behavior of falling back to a domain name after `UseIP` resolution fails.\n\nNote: When applied to proxied traffic, this option is also constrained by the `address` option. For example, if you set `ForceIPv6v4` but no IPv6 address is set in `address`, even if the target domain has AAAA records, they will not be resolved/used.\n";
2812
+ //#endregion
2813
+ //#region src/outbounds/wireguard/wireguard.ts
2814
+ const peer = z.object({
2815
+ endpoint: z.string().meta({ markdownDescription: "Server address, required.\n\nURL:Port format, e.g., `engage.cloudflareclient.com:2408`\nIP:Port format, e.g., `162.159.192.1:2408` or `[2606:4700:d0::a29f:c001]:2408`\n" }),
2816
+ publicKey: z.string().meta({ markdownDescription: "Server public key, used for verification, required.\n" }),
2817
+ preSharedKey: z.string().optional().meta({ markdownDescription: "Additional symmetric encryption key.\n" }),
2818
+ keepAlive: z.int().default(0).optional().meta({ markdownDescription: "Heartbeat interval in seconds. Default is 0, meaning no heartbeat.\n" }),
2819
+ allowedIPs: z.array(z.string()).default(["0.0.0.0/0", "::/0"]).optional().meta({ markdownDescription: "Wireguard only allows traffic from specific source IPs.\n" })
2820
+ });
2821
+ const wireguard = outboundSchemaBase.extend({
2822
+ protocol: z.literal("wireguard"),
2823
+ settings: z.object({
2824
+ secretKey: z.string().meta({ markdownDescription: wireguardSecretKey_default }),
2825
+ address: z.array(z.string()).min(1).meta({ markdownDescription: wireguardAddress_default }),
2826
+ peers: z.array(peer).min(1).meta({ markdownDescription: wireguardPeers_default }),
2827
+ noKernelTun: z.boolean().default(false).optional().meta({ markdownDescription: wireguardNoKernelTun_default }),
2828
+ mtu: z.int().default(1420).meta({ markdownDescription: wireguardMtu_default }),
2829
+ reserved: z.array(z.int()).default([]).optional().meta({ markdownDescription: wireguardReserved_default }),
2830
+ workers: z.int().optional().meta({ markdownDescription: wireguardWorkers_default }),
2831
+ domainStrategy: z.enum([
2832
+ "ForceIPv6v4",
2833
+ "ForceIPv6",
2834
+ "ForceIPv4v6",
2835
+ "ForceIPv4",
2836
+ "ForceIP"
2837
+ ]).default("ForceIP").optional().meta({ markdownDescription: wireguardDomainStrategy_default })
2838
+ }).meta({ markdownDescription: wireguardSettings_default })
2839
+ }).meta({ markdownDescription: wireguard_default });
2840
+ //#endregion
2841
+ //#region src/outbounds/outbounds.ts
2842
+ const outbound = z.discriminatedUnion("protocol", [
2843
+ blackhole,
2844
+ freedom,
2845
+ dns,
2846
+ hysteria,
2847
+ loopback,
2848
+ shadowsocks,
2849
+ socks,
2850
+ trojan,
2851
+ vless,
2852
+ vmess,
2853
+ wireguard
2854
+ ]).meta({
2855
+ ifThenLogic: true,
2856
+ discriminatedFields: ["settings"]
2857
+ });
2858
+ //#endregion
2859
+ //#region src/fakedns/fakedns.ts
2860
+ const fakednsObject = z.object({
2861
+ ipPool: z.string().meta({ markdownDescription: `CIDR, FakeDNS will allocate addresses using the IP block specified in this option.` }),
2862
+ poolSize: z.int().meta({ markdownDescription: `Specifies the maximum number of Domain-IP mappings stored by FakeDNS. When the number of mappings exceeds this value, mappings will be evicted according to LRU rules. Default is \`65535\`.
2863
+
2864
+ ### Warning
2865
+ \`poolSize\` must be less than or equal to the total number of addresses in the \`ipPool\`.` }).default(65535).optional()
2866
+ });
2867
+ const fakedns = fakednsObject.or(z.array(fakednsObject)).meta({ markdownDescription: `FakeDNS obtains target domain names by forging DNS responses. It can reduce latency during DNS queries and assist transparent proxies in acquiring target domain names.
2868
+
2869
+ ### Warning
2870
+ FakeDNS may pollute the local DNS cache, causing "no network access" after Xray is closed.
2871
+
2872
+
2873
+ [Documentation ↗](https://xtls.github.io/en/config/fakedns.html)
2874
+ ` });
2875
+ //#endregion
2876
+ //#region src/schema.ts
2877
+ const xraySchema = z.object({
2878
+ version: versionSchema.optional(),
2879
+ log: logSchema.optional(),
2880
+ api: apiSchema.optional(),
2881
+ dns: dnsSchema.optional(),
2882
+ routing: routingSchema.optional(),
2883
+ fakedns: fakedns.optional(),
2884
+ policy: policySchema.optional(),
2885
+ stats: stats.optional(),
2886
+ metrics: metrics.optional(),
2887
+ observatory: observatory.optional(),
2888
+ burstObservatory: burstObservatory.optional(),
2889
+ reverse: reverse.optional(),
2890
+ inbounds: z.array(inbound).optional(),
2891
+ outbounds: z.array(outbound).optional()
2892
+ }).loose();
2893
+ //#endregion
2894
+ export { xraySchema };