client.ts 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. import { z } from 'zod';
  2. const nullableStringArray = z.array(z.string()).nullable().transform((v) => v ?? []);
  3. const nullableNumberArray = z.array(z.number()).nullable().transform((v) => v ?? []);
  4. export const ClientTrafficSchema = z.object({
  5. up: z.number().optional(),
  6. down: z.number().optional(),
  7. total: z.number().optional(),
  8. expiryTime: z.number().optional(),
  9. enable: z.boolean().optional(),
  10. lastOnline: z.number().optional(),
  11. });
  12. export const ClientRecordSchema = z.object({
  13. id: z.number().optional(),
  14. email: z.string(),
  15. subId: z.string().optional(),
  16. uuid: z.string().optional(),
  17. password: z.string().optional(),
  18. auth: z.string().optional(),
  19. flow: z.string().optional(),
  20. security: z.string().optional(),
  21. totalGB: z.number().optional(),
  22. expiryTime: z.number().optional(),
  23. limitIp: z.number().optional(),
  24. tgId: z.union([z.number(), z.string()]).optional(),
  25. group: z.string().optional(),
  26. comment: z.string().optional(),
  27. enable: z.boolean().optional(),
  28. reset: z.number().optional(),
  29. inboundIds: nullableNumberArray.optional(),
  30. traffic: ClientTrafficSchema.nullable().optional(),
  31. reverse: z.object({ tag: z.string().optional() }).loose().nullable().optional(),
  32. createdAt: z.number().optional(),
  33. updatedAt: z.number().optional(),
  34. }).loose();
  35. export const InboundOptionSchema = z.object({
  36. id: z.number(),
  37. remark: z.string().optional(),
  38. tag: z.string().optional(),
  39. protocol: z.string().optional(),
  40. port: z.number().optional(),
  41. tlsFlowCapable: z.boolean().optional(),
  42. ssMethod: z.string().optional(),
  43. // Hosting node id; absent/null for this panel's own inbounds (#4997).
  44. nodeId: z.number().nullable().optional(),
  45. }).loose();
  46. export const InboundOptionsSchema = z.array(InboundOptionSchema);
  47. export const ClientsSummarySchema = z.object({
  48. total: z.number(),
  49. active: z.number(),
  50. online: nullableStringArray,
  51. depleted: nullableStringArray,
  52. expiring: nullableStringArray,
  53. deactive: nullableStringArray,
  54. });
  55. const nullableClientArray = z.array(ClientRecordSchema).nullable().transform((v) => v ?? []);
  56. export const ClientPageResponseSchema = z.object({
  57. items: nullableClientArray,
  58. total: z.number(),
  59. filtered: z.number(),
  60. page: z.number(),
  61. pageSize: z.number(),
  62. summary: ClientsSummarySchema.nullable().optional(),
  63. groups: nullableStringArray.optional(),
  64. });
  65. export const ClientHydrateSchema = z.object({
  66. client: ClientRecordSchema,
  67. inboundIds: nullableNumberArray,
  68. });
  69. export const BulkAdjustResultSchema = z.object({
  70. adjusted: z.number(),
  71. skipped: z
  72. .array(z.object({ email: z.string(), reason: z.string() }))
  73. .optional(),
  74. });
  75. export const BulkDeleteResultSchema = z.object({
  76. deleted: z.number(),
  77. skipped: z
  78. .array(z.object({ email: z.string(), reason: z.string() }))
  79. .optional(),
  80. });
  81. export const BulkCreateResultSchema = z.object({
  82. created: z.number(),
  83. skipped: z
  84. .array(z.object({ email: z.string(), reason: z.string() }))
  85. .optional(),
  86. });
  87. export const DelDepletedResultSchema = z.object({
  88. deleted: z.number().optional(),
  89. });
  90. export const BulkAttachResultSchema = z.object({
  91. attached: z.array(z.string()).nullable().transform((v) => v ?? []),
  92. skipped: z.array(z.string()).nullable().transform((v) => v ?? []),
  93. errors: z.array(z.string()).nullable().transform((v) => v ?? []),
  94. });
  95. export const BulkDetachResultSchema = z.object({
  96. detached: z.array(z.string()).nullable().transform((v) => v ?? []),
  97. skipped: z.array(z.string()).nullable().transform((v) => v ?? []),
  98. errors: z.array(z.string()).nullable().transform((v) => v ?? []),
  99. });
  100. export const OnlinesSchema = nullableStringArray;
  101. export const OnlineByNodeSchema = z
  102. .record(z.string(), nullableStringArray)
  103. .nullable()
  104. .transform((v) => v ?? {});
  105. export const ActiveInboundsByNodeSchema = z
  106. .record(z.string(), nullableStringArray)
  107. .nullable()
  108. .transform((v) => v ?? {});
  109. export const GroupSummarySchema = z.object({
  110. name: z.string(),
  111. clientCount: z.number(),
  112. trafficUsed: z.number().nullable().transform((v) => v ?? 0),
  113. });
  114. export const GroupSummaryListSchema = z.array(GroupSummarySchema).nullable().transform((v) => v ?? []);
  115. export function hasForbiddenClientChars(value: string): boolean {
  116. if (value.includes('/') || value.includes('\\') || value.includes(' ')) return true;
  117. for (let i = 0; i < value.length; i++) {
  118. const code = value.charCodeAt(i);
  119. if (code < 0x20 || code === 0x7f) return true;
  120. }
  121. return false;
  122. }
  123. export const ClientFormSchema = z.object({
  124. email: z
  125. .string()
  126. .trim()
  127. .min(1, 'pages.clients.email')
  128. .refine((v) => !hasForbiddenClientChars(v), 'pages.clients.emailInvalidChars'),
  129. subId: z.string().refine((v) => !hasForbiddenClientChars(v), 'pages.clients.subIdInvalidChars'),
  130. uuid: z.string(),
  131. password: z.string(),
  132. auth: z.string(),
  133. flow: z.string(),
  134. security: z.string(),
  135. reverseTag: z.string(),
  136. totalGB: z.number().min(0),
  137. delayedStart: z.boolean(),
  138. delayedDays: z.number().int().min(0),
  139. reset: z.number().int().min(0),
  140. limitIp: z.number().int().min(0),
  141. tgId: z.number().int().min(0),
  142. group: z.string(),
  143. comment: z.string(),
  144. enable: z.boolean(),
  145. inboundIds: z.array(z.number()),
  146. });
  147. export const ClientCreateFormSchema = ClientFormSchema.extend({
  148. inboundIds: z.array(z.number()).min(1, 'pages.clients.selectInbound'),
  149. });
  150. export const ClientBulkAdjustFormSchema = z
  151. .object({
  152. addDays: z.number().int(),
  153. addGB: z.number(),
  154. })
  155. .refine((v) => v.addDays !== 0 || v.addGB !== 0, {
  156. message: 'pages.clients.bulkAdjustNothing',
  157. });
  158. export const ClientBulkAddFormSchema = z.object({
  159. emailMethod: z.number().int().min(0).max(4),
  160. firstNum: z.number().int().min(1),
  161. lastNum: z.number().int().min(1),
  162. emailPrefix: z.string(),
  163. emailPostfix: z.string(),
  164. quantity: z.number().int().min(1).max(1000),
  165. subId: z.string(),
  166. group: z.string(),
  167. comment: z.string(),
  168. flow: z.string(),
  169. limitIp: z.number().int().min(0),
  170. totalGB: z.number().min(0),
  171. expiryTime: z.number(),
  172. reset: z.number().int().min(0),
  173. inboundIds: z.array(z.number()).min(1, 'pages.clients.selectInbound'),
  174. });
  175. export type ClientRecord = z.infer<typeof ClientRecordSchema>;
  176. export type ClientTraffic = z.infer<typeof ClientTrafficSchema>;
  177. export type InboundOption = z.infer<typeof InboundOptionSchema>;
  178. export type ClientsSummary = z.infer<typeof ClientsSummarySchema>;
  179. export type ClientPageResponse = z.infer<typeof ClientPageResponseSchema>;
  180. export type ClientHydrate = z.infer<typeof ClientHydrateSchema>;
  181. export type BulkAdjustResult = z.infer<typeof BulkAdjustResultSchema>;
  182. export type BulkDeleteResult = z.infer<typeof BulkDeleteResultSchema>;
  183. export type BulkCreateResult = z.infer<typeof BulkCreateResultSchema>;
  184. export type BulkAttachResult = z.infer<typeof BulkAttachResultSchema>;
  185. export type BulkDetachResult = z.infer<typeof BulkDetachResultSchema>;
  186. export type ClientBulkAddFormValues = z.infer<typeof ClientBulkAddFormSchema>;
  187. export type ClientBulkAdjustFormValues = z.infer<typeof ClientBulkAdjustFormSchema>;
  188. export type ClientFormValues = z.infer<typeof ClientFormSchema>;
  189. export type GroupSummary = z.infer<typeof GroupSummarySchema>;