// Native fetch available in Node 20+ import { getSystemConfig } from '../admin/system-config.service'; type NotifyLevel = 'info' | 'warn' | 'error'; interface NotifyChannel { send(title: string, content: string, level: NotifyLevel): Promise; } // ---- Feishu Webhook Channel ---- class FeishuChannel implements NotifyChannel { private webhookUrl: string; constructor(webhookUrl: string) { this.webhookUrl = webhookUrl; } async send(title: string, content: string, _level: NotifyLevel): Promise { try { const body = JSON.stringify({ msg_type: 'interactive', card: { header: { title: { tag: 'plain_text', content: title }, template: _level === 'error' ? 'red' : _level === 'warn' ? 'orange' : 'blue', }, elements: [ { tag: 'div', text: { tag: 'lark_md', content } }, { tag: 'note', elements: [ { tag: 'plain_text', content: `CloudSearch · ${new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })}` }, ], }, ], }, }); const resp = await fetch(this.webhookUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body, }); if (!resp.ok) { console.error(`[Notify] Feishu send failed: ${resp.status}`); } } catch (err: any) { console.error('[Notify] Feishu send error:', err.message); } } } // ---- Notification Manager ---- let _channel: NotifyChannel | null = null; function getChannel(): NotifyChannel | null { const feishuUrl = process.env.FEISHU_WEBHOOK || getSystemConfig('feishu_webhook_url'); if (!feishuUrl) return null; if (!_channel) { _channel = new FeishuChannel(feishuUrl); console.log('[Notify] Feishu webhook configured'); } return _channel; } /** * Send a notification through configured channels. * Returns immediately — failures are logged silently. */ export function notify(title: string, content: string, level: NotifyLevel = 'info'): void { const ch = getChannel(); if (!ch) return; // Fire-and-forget — don't block the caller ch.send(title, content, level).catch(() => {}); } /** * Notify on critical events: * - Cookie expired / login failed * - Save/transfer failed repeatedly * - Storage below threshold */ export function notifyError(title: string, detail: string): void { notify(`⚠️ ${title}`, detail, 'error'); } export function notifyWarn(title: string, detail: string): void { notify(`🔔 ${title}`, detail, 'warn'); } export function notifyInfo(title: string, detail: string): void { notify(`ℹ️ ${title}`, detail, 'info'); }