/* ===================================================================== lib/supporter-mail.js — Transaktions-E-Mails für den Supporter-Bereich (E-Mail-Bestätigung, Login-Codes, Zahlungs-/Prämien-Benachrichtigungen). WICHTIG — offener Punkt, siehe auch README.md "Supporter-Abo Setup": Es existiert aktuell KEIN E-Mail-Versand-Anbieter (kein Resend/ MailChannels o.ä. eingerichtet) und KEINE eigene Domain (die Seite läuft noch auf *.workers.dev) — beides wird für zuverlässigen E-Mail-Versand gebraucht (Absender-Domain muss per SPF/DKIM verifiziert sein, sonst landet alles im Spam oder wird abgelehnt). Diese Datei ist deshalb bewusst als AUSTAUSCHBARER Adapter gebaut: Sobald RESEND_API_KEY (+ RESEND_FROM) als Secret gesetzt ist, wird über die Resend-API (https://resend.com, kostenloser Tier reicht für den Start) verschickt. Fehlt der Key, wird NICHTS verschickt und ein sprechender Fehler zurückgegeben — bewusst "fail closed" statt den Code irgendwo im Klartext zu loggen (Sicherheitsprinzip wie beim Rest des Zugangssystems, siehe audit.js). ===================================================================== */ export class EmailNotConfiguredError extends Error { constructor() { super("E-Mail-Versand ist noch nicht eingerichtet (RESEND_API_KEY fehlt)."); this.name = "EmailNotConfiguredError"; this.code = "EMAIL_NOT_CONFIGURED"; } } async function send(env, { to, subject, html }) { if (!env.RESEND_API_KEY || !env.RESEND_FROM) throw new EmailNotConfiguredError(); const res = await fetch("https://api.resend.com/emails", { method: "POST", headers: { Authorization: `Bearer ${env.RESEND_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ from: env.RESEND_FROM, to: [to], subject, html }), }); if (!res.ok) { const text = await res.text().catch(() => ""); throw new Error(`E-Mail-Versand fehlgeschlagen (${res.status}): ${text.slice(0, 300)}`); } return true; } const WRAP = (title, bodyHtml) => `

${title}

${bodyHtml}

DogiCrew 🩵

`; export async function sendVerifyEmailCode(env, { to, name, code }) { return send(env, { to, subject: "Bestätige deine E-Mail-Adresse — DogiCrew 🩵", html: WRAP( `Willkommen, ${name}! 🩵`, `

Bestätige deine E-Mail-Adresse mit diesem Code:

${code}

Der Code ist 15 Minuten gültig.

` ), }); } export async function sendLoginCode(env, { to, name, code }) { return send(env, { to, subject: "Dein Login-Code — Dogfather Supporter-Bereich", html: WRAP( `Hallo ${name} 👋`, `

Dein Login-Code für den Supporter-Bereich:

${code}

Der Code ist 15 Minuten gültig. Hast du das nicht angefordert, ignoriere diese E-Mail.

` ), }); } export async function sendMilestoneUnlocked(env, { to, name, premiumLabel }) { return send(env, { to, subject: `Neuer Meilenstein freigeschaltet — ${premiumLabel} 🎉`, html: WRAP( `Glückwunsch, ${name}! 🩵`, `

Du hast einen neuen Meilenstein erreicht und kannst jetzt deine Prämie einlösen:

${premiumLabel}

Logge dich in deinen Supporter-Bereich ein, um die Prämie einzulösen.

` ), }); }