UNPKG

@withstudiocms/effect

Version:

Effect-TS Utilities for Astro

121 lines (120 loc) 4.29 kB
import _nodemailer from "nodemailer"; import socks from "socks"; import { Brand, Context, Effect, Layer } from "./effect.js"; const TransportConfig = Brand.nominal(); const convertTransporterConfig = Effect.fn( (config) => Effect.try({ try: () => { const { transport, defaults } = config; let transportOptions; let proxyConfig; if (transport) { const { proxy, ...rest } = transport; transportOptions = rest; proxyConfig = proxy; } return { proxy: proxyConfig, transport: transportOptions, defaults: defaults || void 0 }; }, catch: (cause) => new Error( `Failed to convert TransportConfig: ${cause instanceof Error ? cause.message : String(cause)}` ) }) ); class SMTPTransportConfig extends Context.Tag("SMTPTransportConfig")() { static makeLive(config) { return Layer.succeed(SMTPTransportConfig, SMTPTransportConfig.of(TransportConfig(config))); } } class SMTPService extends Effect.Service()("SMTPService", { effect: Effect.gen(function* () { const nodemailer = Effect.fn( (fn) => Effect.try({ try: () => fn(_nodemailer), // If an error occurs, we throw a new Error with a custom message. // This is useful for debugging and understanding where the error originated. // The cause is checked to see if it's an instance of Error, and if so, // we use its message; otherwise, we convert it to a string. catch: (cause) => new Error( `Failed to run nodemailer function: ${cause instanceof Error ? cause.message : String(cause)}` ) }) ); const createTransport = Effect.fn(function* (rawMailerConfig2) { const { transport, defaults, proxy } = yield* convertTransporterConfig(rawMailerConfig2); const transportInstance = yield* nodemailer( (mailer) => mailer.createTransport(transport, defaults) ); if (proxy?.startsWith("socks")) { transportInstance.set("proxy_socks_module", socks); transportInstance.setupProxy(proxy); } return transportInstance; }); const rawMailerConfig = yield* SMTPTransportConfig; const _mailer = yield* createTransport(rawMailerConfig); const Mailer = Effect.fn(function* (fn) { return yield* Effect.tryPromise({ try: () => Promise.resolve().then(() => fn(_mailer)), catch: (cause) => new Error( `Failed to run Mailer function: ${cause instanceof Error ? cause.message : String(cause)}` ) }); }); const verifyTransport = Effect.fn(function* () { return yield* Effect.tryPromise({ try: () => _mailer.verify(), // If an error occurs during verification, we throw a new Error with a custom message. // This helps in debugging SMTP configuration issues. catch: (cause) => new Error( `Failed to verify SMTP transport: ${cause instanceof Error ? cause.message : String(cause)}` ) }); }); const sendMail = (mailOptions) => Effect.tryPromise({ try: () => _mailer.sendMail(mailOptions), catch: (cause) => new Error( `Failed to send mail: ${cause instanceof Error ? cause.message : String(cause)}` ) }); const isIdle = Effect.fn(function* () { return yield* Effect.try({ try: () => _mailer.isIdle(), catch: (cause) => new Error( `Failed to check if SMTP transport is idle: ${cause instanceof Error ? cause.message : String(cause)}` ) }); }); const getVersionString = Effect.fn(function* () { return yield* Effect.try({ try: () => _mailer.getVersionString(), catch: (cause) => new Error( `Failed to get SMTP transport version string: ${cause instanceof Error ? cause.message : String(cause)}` ) }); }); const close = () => Effect.try({ try: () => _mailer.close(), catch: (cause) => new Error( `Failed to close SMTP transport: ${cause instanceof Error ? cause.message : String(cause)}` ) }); return { Mailer, verifyTransport, sendMail, isIdle, getVersionString, close }; }) }) { } export { SMTPService, SMTPTransportConfig, TransportConfig };