alepha
Version:
Easy-to-use modern TypeScript framework for building many kind of applications.
92 lines (78 loc) • 2.75 kB
text/typescript
import {
AlephaError,
createPrimitive,
type InstantiableClass,
KIND,
Primitive,
} from "alepha";
import type { EmailSendOptions } from "../providers/EmailProvider.ts";
import { EmailProvider } from "../providers/EmailProvider.ts";
import { MemoryEmailProvider } from "../providers/MemoryEmailProvider.ts";
// ---------------------------------------------------------------------------------------------------------------------
export const $email = (options: EmailPrimitiveOptions = {}) =>
createPrimitive(EmailPrimitive, options);
// ---------------------------------------------------------------------------------------------------------------------
export interface EmailPrimitiveOptions {
name?: string;
provider?: InstantiableClass<EmailProvider> | "memory";
}
// ---------------------------------------------------------------------------------------------------------------------
/**
* Email primitive for sending emails through various providers.
*
* The primitive's `name` identifies the channel in the `email:sending` /
* `email:sent` hooks; it does not select a template — `send()` expects an
* already-rendered `subject` and `body`.
*
* Usage:
* ```typescript
* class MyService {
* protected readonly welcomeEmail = $email({ name: "welcome" });
*
* async sendWelcome(userEmail: string, userName: string) {
* await this.welcomeEmail.send({
* to: userEmail,
* subject: "Welcome!",
* body: `<p>Hello ${userName}!</p>`
* });
* }
* }
* ```
*/
export class EmailPrimitive extends Primitive<EmailPrimitiveOptions> {
protected readonly provider = this.$provider();
public get name() {
return this.options.name ?? `${this.config.propertyKey}`;
}
/**
* Send an email using the configured provider.
*/
public async send(options: EmailSendOptions): Promise<void> {
await this.alepha.events.emit("email:sending", {
to: options.to,
template: this.name,
variables: {},
provider: this.provider,
abort: () => {
throw new AlephaError("Email sending aborted by hook");
},
});
await this.provider.send(options);
await this.alepha.events.emit("email:sent", {
to: options.to,
template: this.name,
provider: this.provider,
});
}
protected $provider(): EmailProvider {
if (!this.options.provider) {
return this.alepha.inject(EmailProvider);
}
if (this.options.provider === "memory") {
return this.alepha.inject(MemoryEmailProvider);
}
return this.alepha.inject(this.options.provider);
}
}
// ---------------------------------------------------------------------------------------------------------------------
$email[KIND] = EmailPrimitive;