inbound.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import { z } from 'zod';
  2. import { InboundPortSchema, SniffingSchema } from '@/schemas/primitives';
  3. import { InboundSettingsSchema } from '@/schemas/protocols/inbound';
  4. import { SecuritySettingsSchema } from '@/schemas/protocols/security';
  5. import { NetworkSettingsSchema, StreamExtrasSchema } from '@/schemas/protocols/stream';
  6. // Top-level inbound shape on the wire. Composes:
  7. // - Per-protocol settings via the InboundSettingsSchema discriminated
  8. // union (10 protocols, tagged-wrapper {protocol, settings}).
  9. // - StreamSettings as an intersection of the network DU (6 branches),
  10. // security DU (3 branches), and the orthogonal extras (finalmask,
  11. // sockopt, externalProxy). Zod 4 supports DU intersection — each
  12. // branch validates its slice of the same input object.
  13. //
  14. // The id/up/down/total/expiryTime fields are int64 on the Go side but
  15. // the panel ships them as JS numbers. Numbers above Number.MAX_SAFE_INTEGER
  16. // (~9e15) lose precision; the panel works around this for the traffic
  17. // counters by stringifying them at the API edge. Not modeled here.
  18. export const StreamSettingsSchema = NetworkSettingsSchema
  19. .and(SecuritySettingsSchema)
  20. .and(StreamExtrasSchema);
  21. export type StreamSettings = z.infer<typeof StreamSettingsSchema>;
  22. export const InboundCoreSchema = z.object({
  23. id: z.number().int().optional(),
  24. up: z.number().int().min(0).default(0),
  25. down: z.number().int().min(0).default(0),
  26. total: z.number().int().min(0).default(0),
  27. remark: z.string().default(''),
  28. enable: z.boolean().default(true),
  29. expiryTime: z.number().int().default(0),
  30. listen: z.string().default(''),
  31. port: InboundPortSchema,
  32. tag: z.string().default(''),
  33. shareAddrStrategy: z.enum(['node', 'listen', 'custom']).default('node'),
  34. shareAddr: z.string().default(''),
  35. sniffing: SniffingSchema.default({
  36. enabled: false,
  37. destOverride: ['http', 'tls', 'quic', 'fakedns'],
  38. metadataOnly: false,
  39. routeOnly: false,
  40. ipsExcluded: [],
  41. domainsExcluded: [],
  42. }),
  43. streamSettings: StreamSettingsSchema.optional(),
  44. clientStats: z.string().optional(),
  45. });
  46. export type InboundCore = z.infer<typeof InboundCoreSchema>;
  47. // Full Inbound = core fields + the protocol/settings discriminated union.
  48. // Consumers narrow on `.protocol` to access the matching `.settings`
  49. // branch with full type safety.
  50. export const InboundSchema = InboundCoreSchema.and(InboundSettingsSchema);
  51. export type Inbound = z.infer<typeof InboundSchema>;
  52. // SlimInbound is the list-view projection — same shape minus settings
  53. // and streamSettings (the list endpoint omits both to keep payload
  54. // small). Used by InboundsPage list rendering.
  55. export const SlimInboundSchema = InboundCoreSchema.omit({
  56. streamSettings: true,
  57. }).extend({
  58. protocol: z.string(),
  59. });
  60. export type SlimInbound = z.infer<typeof SlimInboundSchema>;