mihomo-config
v0.2.0
Published
Type-safe TypeScript library for generating mihomo (Clash Meta) proxy configuration
Readme
mihomo-config
Type-safe TypeScript library for generating mihomo (Clash Meta) proxy configuration dynamically. Runtime validation via Zod, YAML serialization via js-yaml.
Example
Install
npm install mihomo-configQuick Start
import {
vless, select, urlTest, loadBalance,
dns, sniffer, experimental,
ruleProvider, proxyProvider,
ruleSet, domainSuffix, ipCidr, match,
createConfig, toYaml,
} from 'mihomo-config'
const config = createConfig({
'log-level': 'warning',
'find-process-mode': 'off',
dns: dns({
enable: true,
listen: '0.0.0.0:53',
'enhanced-mode': 'redir-host',
nameserver: ['https://1.1.1.1/dns-query'],
}),
sniffer: sniffer({ enable: true }),
proxies: [
vless({
name: 'JP',
server: '1.2.3.4',
port: 443,
uuid: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
tls: true,
flow: 'xtls-rprx-vision',
network: 'tcp',
'reality-opts': { 'public-key': 'xxxxx', 'short-id': 'abc' },
}),
],
'proxy-groups': [
select({ name: '节点选择', type: 'select', proxies: ['JP', 'DIRECT'] }),
],
rules: [ruleSet('geosite_cn', 'DIRECT'), match('节点选择')],
'rule-providers': {
geosite_cn: ruleProvider({
type: 'http', behavior: 'domain', format: 'mrs',
interval: 3600, url: 'https://example.com/cn.mrs',
}),
},
experimental: experimental({ 'dialer-ip4p-convert': true }),
})
console.log(toYaml(config))API
Proxies
All proxy factories return validated objects with a type field. Each accepts an options object matching the mihomo config schema — keys use kebab-case (same as YAML).
import { vless, vmess, trojan, shadowsocks, hysteria2, tuic, wireguard } from 'mihomo-config'
vless({ name: '...', server: '...', port: 443, uuid: '...', /* ... */ })
vmess({ name: '...', server: '...', port: 443, uuid: '...', alterId: 0, cipher: 'auto', /* ... */ })
trojan({ name: '...', server: '...', port: 443, password: '...', /* ... */ })
shadowsocks({ name: '...', server: '...', port: 8388, password: '...', cipher: 'aes-256-gcm', /* ... */ })
hysteria2({ name: '...', server: '...', port: 443, password: '...', /* ... */ })
tuic({ name: '...', server: '...', port: 443, uuid: '...', password: '...', /* ... */ })
wireguard({ name: '...', server: '...', port: 51820, 'private-key': '...', ip: '...', /* ... */ })Additional proxy types: socks5, http, snell, ssh, anytls, shadowsocksr, heybox, direct.
Common options available on most proxies: udp, tfo, mptcp, interface-name, routing-mark, dialer-proxy, ip-version, client-fingerprint, plus transport sub-options (ws-opts, grpc-opts, http-opts, h2-opts, xhttp-opts).
heybox (小黑盒加速器)
heybox is the 小黑盒 accelerator outbound: sessions (session id / handshake key / node port) are issued atomically by the accelerator API and fetched lazily on first traffic, so there is no server/port. It is normally generated by a type: 'heybox' proxy provider rather than hand-written:
import { heybox, proxyProvider } from 'mihomo-config'
proxyProvider({
type: 'heybox',
'heybox-id': 16651571, // 小黑盒账号 ID (required)
pkey: 'MTc4...', // 登录凭据,每次登录轮换 (required)
games: [356], // 游戏 acc_id 列表,356 = Switch (required)
// isp: 'liantong', // 'all' | 'dianxin' | 'liantong' | 'yidong' | 'bgp'
// api: 'https://accapi.xiaoheihe.cn',
interval: 600, // 枚举刷新,默认 600s,无会话副作用
})
// 手写单条时(通常不必):除标注可选外均必填,上游严格解码器要求显式出现
heybox({
name: 'Switch-通用-日本3',
'heybox-id': 16651571,
pkey: 'MTc4...',
'acc-id': 356,
'game-id': 0,
'server-region': 1,
'node-name': '日本3', // 会话按此分配
'acc-mode': 1,
'transport-proto': 'udp',
// isp: 'liantong', // 可选
// 'node-ip': '1.2.3.4', 'echo-addr': '1.2.3.4:443', 'rtt-avg': 30,
})Health-check / group URL tests use the node-entry UDP echo (zero sessions, zero TCP) and health-check is ignored on heybox providers. Node names from the provider are {游戏名}-{节点名} (e.g. Switch-通用-日本3), filterable via filter/exclude-filter.
Proxy Groups
import { select, urlTest, fallback, loadBalance, relay } from 'mihomo-config'
select({ name: '节点选择', type: 'select', proxies: ['JP', 'DIRECT'] })
urlTest({ name: '日本自动', type: 'url-test', url: 'https://cp.cloudflare.com', interval: 300, tolerance: 100 })
fallback({ name: '回退', type: 'fallback', url: 'https://cp.cloudflare.com', interval: 300, proxies: ['JP', 'DIRECT'] })
loadBalance({ name: '负载均衡', type: 'load-balance', strategy: 'sticky-sessions', interval: 300, proxies: ['JP1', 'JP2'] })
relay({ name: '链路', type: 'relay', proxies: ['JP', 'US'] })DNS
import { dns } from 'mihomo-config'
dns({
enable: true,
listen: '0.0.0.0:53',
'enhanced-mode': 'redir-host', // 'normal' | 'fake-ip' | 'redir-host'
'cache-algorithm': 'arc', // 'lru' | 'arc'
nameserver: ['https://1.1.1.1/dns-query'],
'proxy-server-nameserver': ['https://223.5.5.5/dns-query'],
'direct-nameserver': ['https://120.53.53.53/dns-query'],
// IP 优选: DNS 答案命中 cidr 段时,替换为内嵌测速器筛出的优选池前 N 条
'preferred-ip': [
{
name: 'cloudflare', // 持久化键,不能重复
cidr: ['173.245.48.0/20', '103.21.244.0/22'],
ipv6: 'block', // 'replace' (默认) | 'block'
'answer-count': 5, // 改写后返回前 N 条,默认 5
'ttl-cap': 60, // 改写记录 TTL 上限(秒),默认 60
persist: true, // 持久化到 cache.db,默认 true
speedtest: {
url: '', // 留空用 speed.cloudflare.com
interval: '24h', // 定时重测,支持 '24h' 或秒数,默认 24h
'disable-download': false, // true 则仅按延迟排序
threads: 200, // tcping 并发,默认 200
'tcp-port': 443, // tcping 端口,默认 443
'ping-times': 4, // tcping 次数,默认 4
'download-count': 10, // 参与下载测速数量,默认 10
'download-time': '10s', // 单 IP 下载时长,默认 10s
'max-delay': '9999ms', // 平均延迟上限
// 'min-delay': '0ms', 'max-loss-rate': 1.0, 'min-speed': 0,
},
},
],
})Sniffer
import { sniffer } from 'mihomo-config'
sniffer({
enable: true,
'parse-pure-ip': true,
'force-domain': ['+.google.com'],
sniff: {
HTTP: { ports: ['80', '8080-8880'], 'override-destination': true },
TLS: { ports: ['443'] },
QUIC: { ports: ['443'] },
},
})TUN
import { tun } from 'mihomo-config'
tun({
enable: true,
stack: 'mixed', // 'gvisor' | 'system' | 'mixed'
'auto-route': true,
'auto-detect-interface': true,
'dns-hijack': ['any:53'],
})Rules
All rule functions return a RULE-TYPE,payload,target[,params...] string.
import {
domain, domainSuffix, domainKeyword, domainRegex,
geoSite, geoIp, ipCidr, srcIpCidr,
ruleSet, match, network, processName,
dstPort, srcPort, inPort, inType,
and, or, not, subRule,
} from 'mihomo-config'
domainSuffix('google.com', '节点选择') // DOMAIN-SUFFIX,google.com,节点选择
ipCidr('192.168.0.0/16', 'DIRECT', 'no-resolve') // IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
ruleSet('geosite_cn', 'DIRECT') // RULE-SET,geosite_cn,DIRECT
match('节点选择') // MATCH,节点选择Providers
import { ruleProvider, proxyProvider } from 'mihomo-config'
ruleProvider({
type: 'http',
behavior: 'domain', // 'domain' | 'ipcidr' | 'classical'
format: 'mrs', // 'mrs' | 'yaml' | 'text'
interval: 3600,
url: 'https://example.com/rule.mrs',
})
proxyProvider({
type: 'http',
interval: 86400,
url: 'https://example.com/sub',
})Listeners
import { listener } from 'mihomo-config'
listener({
type: 'mixed',
listen: '0.0.0.0:7893',
})Experimental
import { experimental } from 'mihomo-config'
experimental({
'dialer-ip4p-convert': true,
'quic-go-disable-gso': false,
'quic-go-disable-ecn': false,
})Top-level Config
createConfig() assembles all sections into a validated config object. Accepts all mihomo top-level keys.
import { createConfig } from 'mihomo-config'
const config = createConfig({
'mixed-port': 7890,
'allow-lan': true,
mode: 'rule',
'log-level': 'info',
dns: dns({ /* ... */ }),
sniffer: sniffer({ /* ... */ }),
tun: tun({ /* ... */ }),
proxies: [/* ... */],
'proxy-groups': [/* ... */],
'proxy-providers': { /* ... */ },
rules: [/* ... */],
'rule-providers': { /* ... */ },
experimental: experimental({ /* ... */ }),
})YAML Serialization
import { toYaml } from 'mihomo-config'
const yaml = toYaml(config) // stringDevelopment
npm install
npm run build # tsup → dist/
npm test # vitest
npm run typecheck # tsc --noEmitLicense
MIT
