import { z } from "zod"; export const NOTIFICATION_TYPES = { email: "email", slack: "slack", discord: "discord", gotify: "gotify", ntfy: "ntfy", pushover: "pushover", telegram: "telegram", generic: "generic", custom: "custom", } as const; export type NotificationType = keyof typeof NOTIFICATION_TYPES; const headerNamePattern = /^[A-Za-z0-9-]+$/; const notificationHeaderSchema = z.string().refine((header) => { const [key, value] = header.split(":", 2); return !!key && headerNamePattern.test(key.trim()) && (value?.trim().length ?? 0) > 0; }, "Headers must use non-empty Key: Value format with valid header names"); export const emailNotificationConfigSchema = z.object({ type: z.literal("email"), smtpHost: z.string().min(1), smtpPort: z.number().int().min(1).max(65535), username: z.string().optional(), password: z.string().optional(), from: z.string().min(1), fromName: z.string().optional(), to: z.array(z.string()), useTLS: z.boolean(), }); export const slackNotificationConfigSchema = z.object({ type: z.literal("slack"), webhookUrl: z.string().min(1), username: z.string().optional(), iconEmoji: z.string().optional(), }); export const discordNotificationConfigSchema = z.object({ type: z.literal("discord"), webhookUrl: z.string().min(1), username: z.string().optional(), avatarUrl: z.string().optional(), threadId: z.string().optional(), }); export const gotifyNotificationConfigSchema = z.object({ type: z.literal("gotify"), serverUrl: z.string().min(1), token: z.string().min(1), path: z.string().optional(), priority: z.number().min(0).max(10), }); export const ntfyNotificationConfigSchema = z.object({ type: z.literal("ntfy"), serverUrl: z.string().optional(), topic: z.string().min(1), priority: z.enum(["max", "high", "default", "low", "min"]), username: z.string().optional(), password: z.string().optional(), accessToken: z.string().optional(), }); export const pushoverNotificationConfigSchema = z.object({ type: z.literal("pushover"), userKey: z.string().min(1), apiToken: z.string().min(1), devices: z.string().optional(), priority: z.union([z.literal(-1), z.literal(0), z.literal(1)]), }); export const telegramNotificationConfigSchema = z.object({ type: z.literal("telegram"), botToken: z.string().min(1), chatId: z.string().min(1), threadId: z.string().optional(), }); export const genericNotificationConfigSchema = z.object({ type: z.literal("generic"), url: z.string().min(1), method: z.enum(["GET", "POST"]), contentType: z.string().optional(), headers: z.array(notificationHeaderSchema).optional(), useJson: z.boolean().optional(), titleKey: z.string().optional(), messageKey: z.string().optional(), }); export const customNotificationConfigSchema = z.object({ type: z.literal("custom"), shoutrrrUrl: z.string().min(1), }); const notificationConfigSchemaBase = z.discriminatedUnion("type", [ emailNotificationConfigSchema, slackNotificationConfigSchema, discordNotificationConfigSchema, gotifyNotificationConfigSchema, ntfyNotificationConfigSchema, pushoverNotificationConfigSchema, telegramNotificationConfigSchema, genericNotificationConfigSchema, customNotificationConfigSchema, ]); export const notificationConfigSchema = notificationConfigSchemaBase; export type NotificationConfig = z.infer; const NOTIFICATION_EVENTS = { start: "start", success: "success", failure: "failure", warning: "warning", } as const; export type NotificationEvent = keyof typeof NOTIFICATION_EVENTS;