mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-10 06:14:33 +00:00
feat(frontend): stream extras + full InboundSchema with DU intersection
Step 3d's last scaffolding piece before link generators. Three new
stream-extras schemas land alongside the network/security DUs:
- finalmask: TcpMask[] + UdpMask[] + QuicParams. Mask `settings` stays
record<string, unknown> for now — there are 13 UDP mask types and 3
TCP mask types with distinct per-type setting shapes, and modeling
them all as DUs would dwarf the rest of stream/ without buying
anything the shadow harness doesn't already catch. Tightened in
Step 6.
- sockopt: 17 socket-tuning knobs (TCP keepalive, TFO, mark, tproxy,
mptcp, dialer proxy, IPv6-only, congestion). `interfaceName` field
matches the panel class naming; serializers rename to `interface` on
the wire.
- external-proxy: rows ship per inbound describing edge fronts (CDN
mirrors). Used by link generators to fan out share URLs.
schemas/api/inbound.ts composes the top-level wire shape with
intersection-of-DUs:
StreamSettingsSchema = NetworkSettingsSchema
.and(SecuritySettingsSchema)
.and(StreamExtrasSchema)
InboundSchema = InboundCoreSchema.and(InboundSettingsSchema)
A fixture (vless-ws-tls.json) exercises the full shape — protocol DU,
network DU, security DU, and TLS cert file branch in one round trip.
The snapshot pins the canonical parsed form so the upcoming link
extractor consumes typed input with no class hierarchy underneath.
Suite: 65 tests across 7 files; typecheck + lint clean. Zod 4
intersection-of-DUs works.
This commit is contained in:
88
frontend/src/test/__snapshots__/inbound-full.test.ts.snap
Normal file
88
frontend/src/test/__snapshots__/inbound-full.test.ts.snap
Normal file
@@ -0,0 +1,88 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`InboundSchema (full) fixtures > parses vless-ws-tls byte-stably 1`] = `
|
||||
{
|
||||
"down": 0,
|
||||
"enable": true,
|
||||
"expiryTime": 0,
|
||||
"id": 42,
|
||||
"listen": "",
|
||||
"port": 443,
|
||||
"protocol": "vless",
|
||||
"remark": "alice-vless-ws-tls",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{
|
||||
"comment": "",
|
||||
"email": "alice@example.test",
|
||||
"enable": true,
|
||||
"expiryTime": 0,
|
||||
"flow": "",
|
||||
"id": "8c14d6f7-2e3b-4a91-9d24-3f7a6b8c1e02",
|
||||
"limitIp": 0,
|
||||
"reset": 0,
|
||||
"subId": "abc123def",
|
||||
"tgId": 0,
|
||||
"totalGB": 0,
|
||||
},
|
||||
],
|
||||
"decryption": "none",
|
||||
"encryption": "none",
|
||||
"fallbacks": [],
|
||||
},
|
||||
"sniffing": {
|
||||
"destOverride": [
|
||||
"http",
|
||||
"tls",
|
||||
"quic",
|
||||
"fakedns",
|
||||
],
|
||||
"domainsExcluded": [],
|
||||
"enabled": true,
|
||||
"ipsExcluded": [],
|
||||
"metadataOnly": false,
|
||||
"routeOnly": false,
|
||||
},
|
||||
"streamSettings": {
|
||||
"network": "ws",
|
||||
"security": "tls",
|
||||
"tlsSettings": {
|
||||
"alpn": [
|
||||
"h2",
|
||||
"http/1.1",
|
||||
],
|
||||
"certificates": [
|
||||
{
|
||||
"buildChain": false,
|
||||
"certificateFile": "/etc/ssl/certs/cdn.example.test.crt",
|
||||
"keyFile": "/etc/ssl/private/cdn.example.test.key",
|
||||
"oneTimeLoading": false,
|
||||
"usage": "encipherment",
|
||||
},
|
||||
],
|
||||
"cipherSuites": "",
|
||||
"disableSystemRoot": false,
|
||||
"echServerKeys": "",
|
||||
"enableSessionResumption": false,
|
||||
"maxVersion": "1.3",
|
||||
"minVersion": "1.2",
|
||||
"rejectUnknownSni": false,
|
||||
"serverName": "cdn.example.test",
|
||||
"settings": {
|
||||
"echConfigList": "",
|
||||
"fingerprint": "chrome",
|
||||
},
|
||||
},
|
||||
"wsSettings": {
|
||||
"acceptProxyProtocol": false,
|
||||
"headers": {},
|
||||
"heartbeatPeriod": 0,
|
||||
"host": "cdn.example.test",
|
||||
"path": "/ws",
|
||||
},
|
||||
},
|
||||
"tag": "inbound-vless-1",
|
||||
"total": 0,
|
||||
"up": 0,
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"id": 42,
|
||||
"up": 0,
|
||||
"down": 0,
|
||||
"total": 0,
|
||||
"remark": "alice-vless-ws-tls",
|
||||
"enable": true,
|
||||
"expiryTime": 0,
|
||||
"listen": "",
|
||||
"port": 443,
|
||||
"tag": "inbound-vless-1",
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": ["http", "tls", "quic", "fakedns"],
|
||||
"metadataOnly": false,
|
||||
"routeOnly": false,
|
||||
"ipsExcluded": [],
|
||||
"domainsExcluded": []
|
||||
},
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{
|
||||
"id": "8c14d6f7-2e3b-4a91-9d24-3f7a6b8c1e02",
|
||||
"email": "alice@example.test",
|
||||
"flow": "",
|
||||
"limitIp": 0,
|
||||
"totalGB": 0,
|
||||
"expiryTime": 0,
|
||||
"enable": true,
|
||||
"tgId": 0,
|
||||
"subId": "abc123def",
|
||||
"comment": "",
|
||||
"reset": 0
|
||||
}
|
||||
],
|
||||
"decryption": "none",
|
||||
"encryption": "none",
|
||||
"fallbacks": []
|
||||
},
|
||||
"streamSettings": {
|
||||
"network": "ws",
|
||||
"wsSettings": {
|
||||
"acceptProxyProtocol": false,
|
||||
"path": "/ws",
|
||||
"host": "cdn.example.test",
|
||||
"headers": {},
|
||||
"heartbeatPeriod": 0
|
||||
},
|
||||
"security": "tls",
|
||||
"tlsSettings": {
|
||||
"serverName": "cdn.example.test",
|
||||
"minVersion": "1.2",
|
||||
"maxVersion": "1.3",
|
||||
"cipherSuites": "",
|
||||
"rejectUnknownSni": false,
|
||||
"disableSystemRoot": false,
|
||||
"enableSessionResumption": false,
|
||||
"certificates": [
|
||||
{
|
||||
"certificateFile": "/etc/ssl/certs/cdn.example.test.crt",
|
||||
"keyFile": "/etc/ssl/private/cdn.example.test.key",
|
||||
"oneTimeLoading": false,
|
||||
"usage": "encipherment",
|
||||
"buildChain": false
|
||||
}
|
||||
],
|
||||
"alpn": ["h2", "http/1.1"],
|
||||
"echServerKeys": "",
|
||||
"settings": {
|
||||
"fingerprint": "chrome",
|
||||
"echConfigList": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
frontend/src/test/inbound-full.test.ts
Normal file
31
frontend/src/test/inbound-full.test.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
/// <reference types="vite/client" />
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { InboundSchema } from '@/schemas/api/inbound';
|
||||
|
||||
// Full Inbound parse tests — exercises the intersection of network DU,
|
||||
// security DU, settings DU, and orthogonal extras in a single
|
||||
// round-trip. These fixtures are the input the link generators in
|
||||
// lib/xray/inbound-link.ts will consume once extracted.
|
||||
|
||||
const fixtures = import.meta.glob<unknown>(
|
||||
'./golden/fixtures/inbound-full/*.json',
|
||||
{ eager: true, import: 'default' },
|
||||
);
|
||||
|
||||
function fixtureName(path: string): string {
|
||||
const file = path.split('/').pop() ?? path;
|
||||
return file.replace(/\.json$/, '');
|
||||
}
|
||||
|
||||
describe('InboundSchema (full) fixtures', () => {
|
||||
const entries = Object.entries(fixtures).sort(([a], [b]) => a.localeCompare(b));
|
||||
expect(entries.length, 'expected at least one fixture under golden/fixtures/inbound-full').toBeGreaterThan(0);
|
||||
|
||||
for (const [path, raw] of entries) {
|
||||
it(`parses ${fixtureName(path)} byte-stably`, () => {
|
||||
const parsed = InboundSchema.parse(raw);
|
||||
expect(parsed).toMatchSnapshot();
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user