First link generator to leave the class hierarchy. genVmessLink takes a
typed Inbound + client args and returns the base64-encoded vmess://
URL. Internal helpers (buildXhttpExtra, applyXhttpExtraToObj,
applyFinalMaskToObj, applyExternalProxyTLSObj, serializeFinalMask,
hasShareableFinalMaskValue, externalProxyAlpn) port across from
XrayCommonClass — same logic, rewritten to read the Zod schemas'
Record<string, string> headers instead of the legacy HeaderEntry[].
Parity test (inbound-link.test.ts) loads each vmess fixture in
golden/fixtures/inbound-full, parses it with InboundSchema for the new
pure fn AND constructs LegacyInbound.fromJson(raw) for the class method,
then asserts the URLs match byte-for-byte. Drift between the two impls
fails here before the call sites in pages/inbounds/* get swapped.
Adds a small test setup file that aliases globalThis.window to globalThis
so Base64.encode's window.btoa works under Node — keeps the test env at
'node' and avoids pulling jsdom as a new dep.
A first vmess-tcp-tls full-inbound fixture pins the round-trip path.
Suite: 67 tests across 8 files; typecheck + lint clean. Five more link
generators (vless/trojan/ss/hysteria/wireguard) plus the orchestrator
(toShareLink, genAllLinks) follow in subsequent turns.