Quellcode durchsuchen

feat(frontend): InboundFormValues schema for Pattern A rewrite

Foundation for the InboundFormModal rewrite. Mirrors the wire Inbound
shape (intersection of core fields + protocol settings DU + stream/security
DUs) plus the DB-side fields (up/down/total/trafficReset/nodeId/...) that
flow through DBInbound rather than the xray config slice.

InboundStreamFormSchema is exported separately so individual sub-form
sections can rule against just the stream portion when needed.

FallbackRowSchema is co-located here even though fallbacks save via a
distinct endpoint after the main POST — they belong to the same form
state from the user's perspective.

No modal changes in this commit. Foundation only; subsequent turns swap
the modal's `inboundRef`/`dbFormRef` mutable-class state for
Form.useForm<InboundFormValues>().
MHSanaei vor 23 Stunden
Ursprung
Commit
d2f3a7baa7
1 geänderte Dateien mit 83 neuen und 0 gelöschten Zeilen
  1. 83 0
      frontend/src/schemas/forms/inbound-form.ts

+ 83 - 0
frontend/src/schemas/forms/inbound-form.ts

@@ -0,0 +1,83 @@
+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>;