node.ts 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import { z } from 'zod';
  2. export const NodeRecordSchema = z.object({
  3. id: z.number(),
  4. name: z.string().optional(),
  5. remark: z.string().optional(),
  6. scheme: z.string().optional(),
  7. address: z.string().optional(),
  8. port: z.number().optional(),
  9. basePath: z.string().optional(),
  10. apiToken: z.string().optional(),
  11. enable: z.boolean().optional(),
  12. status: z.string().optional(),
  13. latencyMs: z.number().optional(),
  14. cpuPct: z.number().optional(),
  15. memPct: z.number().optional(),
  16. xrayVersion: z.string().optional(),
  17. panelVersion: z.string().optional(),
  18. uptimeSecs: z.number().optional(),
  19. inboundCount: z.number().optional(),
  20. clientCount: z.number().optional(),
  21. onlineCount: z.number().optional(),
  22. depletedCount: z.number().optional(),
  23. lastHeartbeat: z.number().optional(),
  24. lastError: z.string().optional(),
  25. // Xray state captured from the remote node's own /panel/api/server/status.
  26. // Lets the nodes list show a distinct indicator when the panel API is reachable
  27. // (status=online) but the Xray core on that node has failed.
  28. xrayState: z.string().optional(),
  29. xrayError: z.string().optional(),
  30. allowPrivateAddress: z.boolean().optional(),
  31. tlsVerifyMode: z.enum(['verify', 'skip', 'pin']).optional(),
  32. pinnedCertSha256: z.string().optional(),
  33. inboundSyncMode: z.enum(['all', 'selected']).optional(),
  34. // Backend serializes a nil []string as null for nodes saved before #5178.
  35. inboundTags: z.array(z.string()).nullish(),
  36. outboundTag: z.string().optional(),
  37. // Multi-hop node tree (#4983): a node's stable GUID, its parent's GUID, and
  38. // whether it's a read-only transitive sub-node surfaced from a downstream node.
  39. guid: z.string().optional(),
  40. parentGuid: z.string().optional(),
  41. transitive: z.boolean().optional(),
  42. }).loose();
  43. export const NodeListSchema = z.array(NodeRecordSchema);
  44. export const ProbeResultSchema = z.object({
  45. status: z.string(),
  46. latencyMs: z.number().optional(),
  47. xrayVersion: z.string().optional(),
  48. error: z.string().optional(),
  49. // Present on successful probe; used to surface "connected to panel, but xray failed on node".
  50. xrayState: z.string().optional(),
  51. xrayError: z.string().optional(),
  52. }).loose();
  53. export const NodeFormSchema = z.object({
  54. id: z.number().optional(),
  55. name: z.string().trim().min(1, 'pages.nodes.toasts.fillRequired'),
  56. remark: z.string().optional(),
  57. scheme: z.enum(['http', 'https']),
  58. address: z.string().trim().min(1, 'pages.nodes.toasts.fillRequired'),
  59. port: z.number().int().min(1).max(65535),
  60. basePath: z.string(),
  61. apiToken: z.string().trim().min(1, 'pages.nodes.toasts.fillRequired'),
  62. enable: z.boolean(),
  63. allowPrivateAddress: z.boolean(),
  64. tlsVerifyMode: z.enum(['verify', 'skip', 'pin']),
  65. pinnedCertSha256: z.string().optional().default(''),
  66. inboundSyncMode: z.enum(['all', 'selected']).optional().default('all'),
  67. // Unmounted when sync mode is "all" (absent from antd onFinish values) and
  68. // serialized as null by the backend for a nil slice — tolerate both.
  69. inboundTags: z.array(z.string()).nullish().transform((tags) => tags ?? []),
  70. outboundTag: z.string().optional(),
  71. });
  72. export type NodeRecord = z.infer<typeof NodeRecordSchema>;
  73. export type ProbeResult = z.infer<typeof ProbeResultSchema>;
  74. export type NodeFormValues = z.infer<typeof NodeFormSchema>;