@withstudiocms/effect
Version:
Effect-TS Utilities for Astro
121 lines (120 loc) • 4.29 kB
JavaScript
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
};