| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- import { z } from 'zod';
- import { PortSchema, SniffingSchema } from '@/schemas/primitives';
- import { InboundSettingsSchema } from '@/schemas/protocols/inbound';
- import { SecuritySettingsSchema } from '@/schemas/protocols/security';
- import { NetworkSettingsSchema, StreamExtrasSchema } from '@/schemas/protocols/stream';
- // InboundFormValues = the values shape Form.useForm<T>() carries in
- // InboundFormModal. Mirrors the wire shape (so submission can hand
- // values straight to Schema.parse + POST) plus the DB-side fields that
- // the panel's /panel/api/inbounds/add endpoint expects alongside.
- //
- // Differences from schemas/api/inbound.ts InboundSchema:
- // - settings/streamSettings/sniffing are nested OBJECTS here, not the
- // JSON strings the endpoint accepts. The form holds typed data; the
- // submit handler stringifies right before POSTing.
- // - Adds DB fields not in InboundSchema: up, down, total, trafficReset,
- // lastTrafficResetTime, nodeId. These flow through the DBInbound row,
- // not the xray-config slice.
- export const InboundStreamFormSchema = NetworkSettingsSchema
- .and(SecuritySettingsSchema)
- .and(StreamExtrasSchema);
- export type InboundStreamFormValues = z.infer<typeof InboundStreamFormSchema>;
- export const TrafficResetSchema = z.enum(['never', 'hourly', 'daily', 'weekly', 'monthly']);
- export type TrafficReset = z.infer<typeof TrafficResetSchema>;
- // Db-side fields layered on top of the xray slice. These mirror the
- // DBInbound model — they live in the SQL row, not in xray's config.
- export const InboundDbFieldsSchema = z.object({
- up: z.number().int().min(0).default(0),
- down: z.number().int().min(0).default(0),
- total: z.number().int().min(0).default(0),
- trafficReset: TrafficResetSchema.default('never'),
- lastTrafficResetTime: z.number().int().default(0),
- nodeId: z.number().int().nullable().optional(),
- });
- export type InboundDbFields = z.infer<typeof InboundDbFieldsSchema>;
- // Base fields that apply to every inbound regardless of protocol or
- // transport. The protocol-specific `settings` and the transport-specific
- // `streamSettings` are layered on via intersection below.
- export const InboundFormBaseSchema = z.object({
- remark: z.string().default(''),
- enable: z.boolean().default(true),
- port: PortSchema,
- listen: z.string().default(''),
- tag: z.string().default(''),
- expiryTime: z.number().int().default(0),
- clientStats: z.string().optional(),
- sniffing: SniffingSchema.default({
- enabled: false,
- destOverride: ['http', 'tls', 'quic', 'fakedns'],
- metadataOnly: false,
- routeOnly: false,
- ipsExcluded: [],
- domainsExcluded: [],
- }),
- streamSettings: InboundStreamFormSchema.optional(),
- });
- export type InboundFormBase = z.infer<typeof InboundFormBaseSchema>;
- // Full form values = base + db fields + protocol-discriminated settings.
- // Consumers narrow on `.protocol` to access the matching settings branch.
- export const InboundFormSchema = InboundFormBaseSchema
- .and(InboundDbFieldsSchema)
- .and(InboundSettingsSchema);
- export type InboundFormValues = z.infer<typeof InboundFormSchema>;
- // Fallback rows ride alongside the inbound submission for VLESS/Trojan
- // hosts. They're saved via a separate endpoint after the main inbound
- // POST returns, so the schema lives here but is not part of the wire
- // inbound payload.
- export const FallbackRowSchema = z.object({
- rowKey: z.string(),
- childId: z.number().int().nullable(),
- name: z.string().default(''),
- alpn: z.string().default(''),
- path: z.string().default(''),
- xver: z.number().int().min(0).max(2).default(0),
- });
- export type FallbackRow = z.infer<typeof FallbackRowSchema>;
|