Procházet zdrojové kódy

fix(frontend): allow null slices in client/summary schemas

Go's encoding/json emits nil []T as null, not []. The initial
ClientPageResponseSchema and ClientHydrateSchema rejected null
inboundIds / summary.online / summary.depleted / etc., causing
[zod] warnings on every empty list.

Add nullableStringArray / nullableNumberArray helpers that accept
null and transform to [] so consuming code keeps seeing arrays.
Mark ClientRecord.traffic and .reverse nullable too (reverse is
explicitly null in MarshalJSON when storage is empty).
MHSanaei před 17 hodinami
rodič
revize
c16fb93899
1 změnil soubory, kde provedl 19 přidání a 11 odebrání
  1. 19 11
      frontend/src/schemas/client.ts

+ 19 - 11
frontend/src/schemas/client.ts

@@ -1,5 +1,8 @@
 import { z } from 'zod';
 
+const nullableStringArray = z.array(z.string()).nullable().transform((v) => v ?? []);
+const nullableNumberArray = z.array(z.number()).nullable().transform((v) => v ?? []);
+
 export const ClientTrafficSchema = z.object({
   up: z.number().optional(),
   down: z.number().optional(),
@@ -10,21 +13,24 @@ export const ClientTrafficSchema = z.object({
 });
 
 export const ClientRecordSchema = z.object({
+  id: z.number().optional(),
   email: z.string(),
   subId: z.string().optional(),
   uuid: z.string().optional(),
   password: z.string().optional(),
   auth: z.string().optional(),
   flow: z.string().optional(),
+  security: z.string().optional(),
   totalGB: z.number().optional(),
   expiryTime: z.number().optional(),
   limitIp: z.number().optional(),
   tgId: z.union([z.number(), z.string()]).optional(),
   comment: z.string().optional(),
   enable: z.boolean().optional(),
-  inboundIds: z.array(z.number()).optional(),
-  traffic: ClientTrafficSchema.optional(),
-  reverse: z.object({ tag: z.string().optional() }).loose().optional(),
+  reset: z.number().optional(),
+  inboundIds: nullableNumberArray.optional(),
+  traffic: ClientTrafficSchema.nullable().optional(),
+  reverse: z.object({ tag: z.string().optional() }).loose().nullable().optional(),
   createdAt: z.number().optional(),
   updatedAt: z.number().optional(),
 }).loose();
@@ -42,24 +48,26 @@ export const InboundOptionsSchema = z.array(InboundOptionSchema);
 export const ClientsSummarySchema = z.object({
   total: z.number(),
   active: z.number(),
-  online: z.array(z.string()),
-  depleted: z.array(z.string()),
-  expiring: z.array(z.string()),
-  deactive: z.array(z.string()),
+  online: nullableStringArray,
+  depleted: nullableStringArray,
+  expiring: nullableStringArray,
+  deactive: nullableStringArray,
 });
 
+const nullableClientArray = z.array(ClientRecordSchema).nullable().transform((v) => v ?? []);
+
 export const ClientPageResponseSchema = z.object({
-  items: z.array(ClientRecordSchema),
+  items: nullableClientArray,
   total: z.number(),
   filtered: z.number(),
   page: z.number(),
   pageSize: z.number(),
-  summary: ClientsSummarySchema.optional(),
+  summary: ClientsSummarySchema.nullable().optional(),
 });
 
 export const ClientHydrateSchema = z.object({
   client: ClientRecordSchema,
-  inboundIds: z.array(z.number()),
+  inboundIds: nullableNumberArray,
 });
 
 export const BulkAdjustResultSchema = z.object({
@@ -73,7 +81,7 @@ export const DelDepletedResultSchema = z.object({
   deleted: z.number().optional(),
 });
 
-export const OnlinesSchema = z.array(z.string());
+export const OnlinesSchema = nullableStringArray;
 
 export type ClientRecord = z.infer<typeof ClientRecordSchema>;
 export type ClientTraffic = z.infer<typeof ClientTrafficSchema>;