import * as v from "valibot"; export const telegramEventKeys = [ "taskCreated", "taskStatusChanged", "taskPriorityChanged", "taskTitleChanged", "taskDescriptionChanged", "taskCommentCreated", ] as const; export type TelegramEventKey = (typeof telegramEventKeys)[number]; export const telegramEventsSchema = v.object( Object.fromEntries( telegramEventKeys.map((key) => [key, v.optional(v.boolean())]), ) as Record< TelegramEventKey, v.OptionalSchema, never> >, ); const telegramBotTokenSchema = v.pipe( v.string(), v.regex(/^\d{8,10}:[A-Za-z0-9_-]{35}$/, "Enter a valid Telegram bot token"), ); const telegramChatIdSchema = v.pipe( v.string(), v.trim(), v.minLength(1, "Chat ID is required"), ); export const telegramConfigSchema = v.object({ botToken: telegramBotTokenSchema, chatId: telegramChatIdSchema, threadId: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1))), chatLabel: v.optional(v.string()), events: v.optional(telegramEventsSchema), }); export type TelegramConfig = v.InferOutput; export const defaultTelegramEvents: Record = { taskCreated: true, taskStatusChanged: true, taskPriorityChanged: false, taskTitleChanged: false, taskDescriptionChanged: false, taskCommentCreated: true, }; export function normalizeTelegramConfig( config: TelegramConfig, ): TelegramConfig { return { ...config, threadId: typeof config.threadId === "number" && Number.isFinite(config.threadId) ? config.threadId : undefined, chatLabel: config.chatLabel?.trim() || undefined, events: { ...defaultTelegramEvents, ...(config.events ?? {}), }, }; } export function validateTelegramConfig(config: unknown): { valid: boolean; errors?: string[]; } { try { const parsed = v.parse(telegramConfigSchema, config); normalizeTelegramConfig(parsed); return { valid: true }; } catch (error) { if (error instanceof v.ValiError) { return { valid: false, errors: error.issues.map((issue) => issue.message), }; } return { valid: false, errors: [error instanceof Error ? error.message : "Invalid config"], }; } }