import { readFile } from "node:fs/promises" import path from "node:path" import { parse } from "yaml" import { z } from "zod" export const CONTACT_MAILER_CONFIG_PATH = path.join( process.cwd(), "config", "contact-mailer.yaml" ) export class ContactMailerConfigError extends Error {} function coerceBoolean(value: unknown) { if (typeof value === "boolean") { return value } if (typeof value === "string") { const normalized = value.trim().toLowerCase() if (normalized === "true") { return true } if (normalized === "false") { return false } } return value } function resolveEnvPlaceholders(value: unknown): unknown { if (typeof value === "string") { return value.replace(/\$\{([A-Z0-9_]+)(?::([^}]*))?\}/gi, (_, envName: string, fallback?: string) => { return process.env[envName] ?? fallback ?? "" }) } if (Array.isArray(value)) { return value.map(resolveEnvPlaceholders) } if (value && typeof value === "object") { return Object.fromEntries( Object.entries(value).map(([key, nestedValue]) => [key, resolveEnvPlaceholders(nestedValue)]) ) } return value } const contactMailerConfigSchema = z.object({ smtp: z.object({ host: z.string().trim().min(1, "SMTP host 未配置"), port: z.coerce.number().int().positive("SMTP port 未配置"), secure: z.preprocess(coerceBoolean, z.boolean()), auth: z.object({ user: z.string().trim().min(1, "SMTP 用户名未配置"), pass: z.string().min(1, "SMTP 密码未配置"), }), from: z.object({ email: z.string().email("发件邮箱格式不正确"), name: z.string().trim().min(1).default("智店软件官网"), }), }), notification: z.object({ to: z.array(z.string().email("通知邮箱格式不正确")).min(1).default(["bd@zhidiansoft.com"]), subjectPrefix: z.string().trim().min(1).default("官网线索"), }).default({ to: ["bd@zhidiansoft.com"], subjectPrefix: "官网线索", }), }) export type ContactMailerConfig = z.infer export async function loadContactMailerConfig() { try { const fileContent = await readFile(CONTACT_MAILER_CONFIG_PATH, "utf8") const parsed = parse(fileContent) ?? {} const resolved = resolveEnvPlaceholders(parsed) return contactMailerConfigSchema.parse(resolved) } catch (error) { if (error instanceof z.ZodError) { throw new ContactMailerConfigError( `contact-mailer.yaml 配置不完整:${error.issues.map((issue) => issue.message).join(";")}` ) } if (error instanceof Error) { throw new ContactMailerConfigError(`读取邮件配置失败:${error.message}`) } throw new ContactMailerConfigError("读取邮件配置失败") } }