diff --git a/src/lib/email/store.ts b/src/lib/email/store.ts index 299e4d0..fb3ca23 100644 --- a/src/lib/email/store.ts +++ b/src/lib/email/store.ts @@ -8,14 +8,60 @@ import { DEFAULT_EXTRACT_RESULT } from "@/types"; import type { Email, NewEmail } from "@/types"; -function replaceTemplateAdvanced(template: string, email: Email): string { - return template.replace(/{(\w+)}/g, (match, key) => { +function replaceVars(str: string, email: Email): string { + const fn = (_match: string, key: string): string => { const value = email[key as keyof Email]; if (value === null || value === undefined) { return ''; } - return JSON.stringify(String(value)).slice(1, -1); - }); + return String(value); + }; + return str + .replace(/\{\{(\w+)\}\}/g, fn) + .replace(/{(\w+)}/g, fn); +} + +function replaceInValue(value: unknown, email: Email): unknown { + if (typeof value === 'string') { + return replaceVars(value, email); + } + if (Array.isArray(value)) { + return value.map(item => replaceInValue(item, email)); + } + if (value !== null && typeof value === 'object') { + const result: Record = {}; + for (const [k, v] of Object.entries(value)) { + result[k] = replaceInValue(v, email); + } + return result; + } + return value; +} + +function processTemplate(template: string, email: Email): string { + // Try to parse as JSON, walk tree, replace vars in string values, then stringify. + // This avoids all escaping issues from CI/config pipeline. + for (const input of [template, template.replace(/\\+"/g, '"')]) { + try { + const parsed = JSON.parse(input); + return JSON.stringify(replaceInValue(parsed, email)); + } catch { + continue; + } + } + + // Fallback: raw string replacement with JSON-safe value escaping + return template + .replace(/\{\{(\w+)\}\}/g, (_match: string, key: string) => { + const value = email[key as keyof Email]; + if (value === null || value === undefined) return ''; + return JSON.stringify(String(value)).slice(1, -1); + }) + .replace(/{(\w+)}/g, (_match: string, key: string) => { + const value = email[key as keyof Email]; + if (value === null || value === undefined) return ''; + return JSON.stringify(String(value)).slice(1, -1); + }); } export default async function storeEmail( @@ -79,14 +125,16 @@ export default async function storeEmail( const res = await emailDB.create(env, emailData); - if (env.WEBHOOK_URL && env.WEBHOOK_TEMPLATE && env.WEBHOOK_TYPE.split(',').includes(emailData.emailType)) { - await sendWebhook(replaceTemplateAdvanced(env.WEBHOOK_TEMPLATE, res), env.WEBHOOK_URL); + if (env.WEBHOOK_URL && env.WEBHOOK_TEMPLATE && env.WEBHOOK_TYPE.split(',').map(t => t.trim()).includes(emailData.emailType)) { + const webhookPayload = processTemplate(env.WEBHOOK_TEMPLATE, res); + console.log('Sending webhook to:', env.WEBHOOK_URL, 'type:', emailData.emailType, 'payload:', webhookPayload); + await sendWebhook(webhookPayload, env.WEBHOOK_URL); } // 发送到Telegram Bot - if (env.TELEGRAM_BOT_TOKEN && env.TELEGRAM_CHAT_ID && env.TELEGRAM_TEMPLATE && env.TELEGRAM_TYPE && env.TELEGRAM_TYPE.split(',').includes(emailData.emailType)) { + if (env.TELEGRAM_BOT_TOKEN && env.TELEGRAM_CHAT_ID && env.TELEGRAM_TEMPLATE && env.TELEGRAM_TYPE && env.TELEGRAM_TYPE.split(',').map(t => t.trim()).includes(emailData.emailType)) { await sendTelegramMessage( - replaceTemplateAdvanced(env.TELEGRAM_TEMPLATE, res), + processTemplate(env.TELEGRAM_TEMPLATE, res), env.TELEGRAM_BOT_TOKEN, env.TELEGRAM_CHAT_ID ); diff --git a/src/lib/webhook/webhook.ts b/src/lib/webhook/webhook.ts index 2f30e46..13f289b 100644 --- a/src/lib/webhook/webhook.ts +++ b/src/lib/webhook/webhook.ts @@ -4,27 +4,39 @@ export default async function sendWebhook(payload: string, url: string): Promise return } - const requestHeaders = { - 'Content-Type': 'application/json', - } - try { const controller = new AbortController() - const timeoutId = setTimeout(() => controller.abort(), 5000) + const timeoutId = setTimeout(() => controller.abort(), 10000) const response = await fetch(url, { method: 'POST', - headers: requestHeaders, + headers: { + 'Content-Type': 'application/json', + }, body: payload, signal: controller.signal }) clearTimeout(timeoutId) + const resBody = await response.text() + if (!response.ok) { - const errorMsg = `HTTP ${response.status}: ${response.statusText}` - console.error('Webhook error:', errorMsg) + console.error('Webhook error:', `HTTP ${response.status}: ${response.statusText}`, resBody) + return } + + try { + const result = JSON.parse(resBody) + if (result.errcode !== undefined && result.errcode !== 0) { + console.error('Webhook API error:', result) + return + } + } catch { + // response is not JSON, ignore + } + + console.log('Webhook sent successfully:', url, resBody) } catch (error) { console.error('Webhook error:', error) } -} \ No newline at end of file +}