chore(repo): initialize planarchy workspace

This commit is contained in:
2026-03-14 14:31:09 +01:00
commit dd55d0e78b
769 changed files with 166461 additions and 0 deletions
+81
View File
@@ -0,0 +1,81 @@
/**
* Email sending utility using nodemailer.
* Non-blocking — errors are logged, not thrown.
*/
import nodemailer from "nodemailer";
import { prisma as db } from "@planarchy/db";
interface EmailPayload {
to: string | string[];
subject: string;
text: string;
html?: string;
}
async function getSmtpConfig() {
const settings = await db.systemSettings.findUnique({ where: { id: "singleton" } });
if (!settings?.smtpHost) return null;
return {
host: settings.smtpHost,
port: settings.smtpPort ?? 587,
secure: settings.smtpTls === false ? false : true,
auth:
settings.smtpUser && settings.smtpPassword
? { user: settings.smtpUser, pass: settings.smtpPassword }
: undefined,
from: settings.smtpFrom ?? settings.smtpUser ?? "noreply@planarchy.app",
};
}
/**
* Send an email. Swallows errors so calling code is never blocked.
* Returns true if sent successfully.
*/
export async function sendEmail(payload: EmailPayload): Promise<boolean> {
try {
const config = await getSmtpConfig();
if (!config) return false;
const transporter = nodemailer.createTransport({
host: config.host,
port: config.port,
secure: config.secure,
auth: config.auth,
});
await transporter.sendMail({
from: config.from,
to: Array.isArray(payload.to) ? payload.to.join(", ") : payload.to,
subject: payload.subject,
text: payload.text,
html: payload.html,
});
return true;
} catch (err) {
console.error("[email] Failed to send email:", err);
return false;
}
}
/**
* Test SMTP connection. Returns { ok: boolean; error?: string }.
*/
export async function testSmtpConnection(): Promise<{ ok: boolean; error?: string }> {
try {
const config = await getSmtpConfig();
if (!config) return { ok: false, error: "SMTP not configured" };
const transporter = nodemailer.createTransport({
host: config.host,
port: config.port,
secure: config.secure,
auth: config.auth,
});
await transporter.verify();
return { ok: true };
} catch (err) {
return { ok: false, error: err instanceof Error ? err.message : String(err) };
}
}