mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-30 08:59:34 +00:00
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).
This commit is contained in:
@@ -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>;
|
||||
|
||||
Reference in New Issue
Block a user