import { z } from "zod"; import { BlockStreamingCoalesceSchema, DmConfigSchema, DmPolicySchema, GroupPolicySchema, } from "./zod-schema.core.js"; export const WhatsAppAccountSchema = z .object({ name: z.string().optional(), capabilities: z.array(z.string()).optional(), configWrites: z.boolean().optional(), enabled: z.boolean().optional(), sendReadReceipts: z.boolean().optional(), messagePrefix: z.string().optional(), /** Override auth directory for this WhatsApp account (Baileys multi-file auth state). */ authDir: z.string().optional(), dmPolicy: DmPolicySchema.optional().default("pairing"), selfChatMode: z.boolean().optional(), allowFrom: z.array(z.string()).optional(), groupAllowFrom: z.array(z.string()).optional(), groupPolicy: GroupPolicySchema.optional().default("allowlist"), historyLimit: z.number().int().min(0).optional(), dmHistoryLimit: z.number().int().min(0).optional(), dms: z.record(z.string(), DmConfigSchema.optional()).optional(), textChunkLimit: z.number().int().positive().optional(), mediaMaxMb: z.number().int().positive().optional(), blockStreaming: z.boolean().optional(), blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(), groups: z .record( z.string(), z .object({ requireMention: z.boolean().optional(), }) .optional(), ) .optional(), ackReaction: z .object({ emoji: z.string().optional(), direct: z.boolean().optional().default(true), group: z.enum(["always", "mentions", "never"]).optional().default("mentions"), }) .optional(), debounceMs: z.number().int().nonnegative().optional().default(0), }) .superRefine((value, ctx) => { if (value.dmPolicy !== "open") return; const allow = (value.allowFrom ?? []).map((v) => String(v).trim()).filter(Boolean); if (allow.includes("*")) return; ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["allowFrom"], message: 'channels.whatsapp.accounts.*.dmPolicy="open" requires allowFrom to include "*"', }); }); export const WhatsAppConfigSchema = z .object({ accounts: z.record(z.string(), WhatsAppAccountSchema.optional()).optional(), capabilities: z.array(z.string()).optional(), configWrites: z.boolean().optional(), sendReadReceipts: z.boolean().optional(), dmPolicy: DmPolicySchema.optional().default("pairing"), messagePrefix: z.string().optional(), selfChatMode: z.boolean().optional(), allowFrom: z.array(z.string()).optional(), groupAllowFrom: z.array(z.string()).optional(), groupPolicy: GroupPolicySchema.optional().default("allowlist"), historyLimit: z.number().int().min(0).optional(), dmHistoryLimit: z.number().int().min(0).optional(), dms: z.record(z.string(), DmConfigSchema.optional()).optional(), textChunkLimit: z.number().int().positive().optional(), mediaMaxMb: z.number().int().positive().optional().default(50), blockStreaming: z.boolean().optional(), blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(), actions: z .object({ reactions: z.boolean().optional(), sendMessage: z.boolean().optional(), polls: z.boolean().optional(), }) .optional(), groups: z .record( z.string(), z .object({ requireMention: z.boolean().optional(), }) .optional(), ) .optional(), ackReaction: z .object({ emoji: z.string().optional(), direct: z.boolean().optional().default(true), group: z.enum(["always", "mentions", "never"]).optional().default("mentions"), }) .optional(), debounceMs: z.number().int().nonnegative().optional().default(0), }) .superRefine((value, ctx) => { if (value.dmPolicy !== "open") return; const allow = (value.allowFrom ?? []).map((v) => String(v).trim()).filter(Boolean); if (allow.includes("*")) return; ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["allowFrom"], message: 'channels.whatsapp.dmPolicy="open" requires channels.whatsapp.allowFrom to include "*"', }); });