types.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. import { LanguageCode } from '@vendure/common/lib/generated-types';
  2. import { Omit } from '@vendure/common/lib/omit';
  3. import { Injector, RequestContext, SerializedRequestContext, VendureEvent } from '@vendure/core';
  4. import { Attachment } from 'nodemailer/lib/mailer';
  5. import SESTransport from 'nodemailer/lib/ses-transport';
  6. import SMTPTransport from 'nodemailer/lib/smtp-transport';
  7. import { EmailGenerator } from './email-generator';
  8. import { EmailSender } from './email-sender';
  9. import { EmailEventHandler } from './event-handler';
  10. /**
  11. * @description
  12. * A VendureEvent which also includes a `ctx` property containing the current
  13. * {@link RequestContext}, which is used to determine the channel and language
  14. * to use when generating the email.
  15. *
  16. * @docsCategory core plugins/EmailPlugin
  17. * @docsPage Email Plugin Types
  18. */
  19. export type EventWithContext = VendureEvent & { ctx: RequestContext };
  20. /**
  21. * @description
  22. * A VendureEvent with a {@link RequestContext} and a `data` property which contains the
  23. * value resolved from the {@link EmailEventHandler}`.loadData()` callback.
  24. *
  25. * @docsCategory core plugins/EmailPlugin
  26. * @docsPage Email Plugin Types
  27. */
  28. export type EventWithAsyncData<Event extends EventWithContext, R> = Event & { data: R };
  29. /**
  30. * @description
  31. * Configuration for the EmailPlugin.
  32. *
  33. * @docsCategory core plugins/EmailPlugin
  34. * @docsPage EmailPluginOptions
  35. * */
  36. export interface EmailPluginOptions {
  37. /**
  38. * @description
  39. * The path to the location of the email templates. In a default Vendure installation,
  40. * the templates are installed to `<project root>/vendure/email/templates`.
  41. *
  42. * @deprecated Use `templateLoader` to define a template path: `templateLoader: new FileBasedTemplateLoader('../your-path/templates')`
  43. */
  44. templatePath?: string;
  45. /**
  46. * @description
  47. * An optional TemplateLoader which can be used to load templates from a custom location or async service.
  48. * The default uses the FileBasedTemplateLoader which loads templates from `<project root>/vendure/email/templates`
  49. *
  50. * @since 2.0.0
  51. */
  52. templateLoader?: TemplateLoader;
  53. /**
  54. * @description
  55. * Configures how the emails are sent.
  56. */
  57. transport:
  58. | EmailTransportOptions
  59. | ((
  60. injector?: Injector,
  61. ctx?: RequestContext,
  62. ) => EmailTransportOptions | Promise<EmailTransportOptions>);
  63. /**
  64. * @description
  65. * An array of {@link EmailEventHandler}s which define which Vendure events will trigger
  66. * emails, and how those emails are generated.
  67. */
  68. handlers: Array<EmailEventHandler<string, any>>;
  69. /**
  70. * @description
  71. * An object containing variables which are made available to all templates. For example,
  72. * the storefront URL could be defined here and then used in the "email address verification"
  73. * email.
  74. */
  75. globalTemplateVars?: { [key: string]: any };
  76. /**
  77. * @description
  78. * An optional allowed EmailSender, used to allow custom implementations of the send functionality
  79. * while still utilizing the existing emailPlugin functionality.
  80. *
  81. * @default NodemailerEmailSender
  82. */
  83. emailSender?: EmailSender;
  84. /**
  85. * @description
  86. * An optional allowed EmailGenerator, used to allow custom email generation functionality to
  87. * better match with custom email sending functionality.
  88. *
  89. * @default HandlebarsMjmlGenerator
  90. */
  91. emailGenerator?: EmailGenerator;
  92. }
  93. /**
  94. * EmailPLuginOptions type after initialization, where templateLoader is no longer optional
  95. */
  96. export type InitializedEmailPluginOptions = EmailPluginOptions & { templateLoader: TemplateLoader };
  97. /**
  98. * @description
  99. * Configuration for running the EmailPlugin in development mode.
  100. *
  101. * @docsCategory core plugins/EmailPlugin
  102. * @docsPage EmailPluginOptions
  103. */
  104. export interface EmailPluginDevModeOptions extends Omit<EmailPluginOptions, 'transport'> {
  105. devMode: true;
  106. /**
  107. * @description
  108. * The path to which html email files will be saved rather than being sent.
  109. */
  110. outputPath: string;
  111. /**
  112. * @description
  113. * The route to the dev mailbox server.
  114. */
  115. route: string;
  116. }
  117. /**
  118. * @description
  119. * A union of all the possible transport options for sending emails.
  120. *
  121. * @docsCategory core plugins/EmailPlugin
  122. * @docsPage Transport Options
  123. */
  124. export type EmailTransportOptions =
  125. | SMTPTransportOptions
  126. | SendmailTransportOptions
  127. | FileTransportOptions
  128. | NoopTransportOptions
  129. | SESTransportOptions
  130. | TestingTransportOptions;
  131. /**
  132. * @description
  133. * The SMTP transport options of [Nodemailer](https://nodemailer.com/smtp/)
  134. *
  135. * @docsCategory core plugins/EmailPlugin
  136. * @docsPage Transport Options
  137. */
  138. export interface SMTPTransportOptions extends SMTPTransport.Options {
  139. type: 'smtp';
  140. /**
  141. * @description
  142. * If true, uses the configured {@link VendureLogger} to log messages from Nodemailer as it interacts with
  143. * the SMTP server.
  144. *
  145. * @default false
  146. */
  147. logging?: boolean;
  148. }
  149. /**
  150. * @description
  151. * The SES transport options of [Nodemailer](https://nodemailer.com/transports/ses//)
  152. *
  153. * See [Nodemailers's SES docs](https://nodemailer.com/transports/ses/) for more details
  154. *
  155. * @example
  156. * ```TypeScript
  157. * import { SES, SendRawEmailCommand } from '\@aws-sdk/client-ses'
  158. *
  159. * const ses = new SES({
  160. * apiVersion: '2010-12-01',
  161. * region: 'eu-central-1',
  162. * credentials: {
  163. * accessKeyId: process.env.SES_ACCESS_KEY || '',
  164. * secretAccessKey: process.env.SES_SECRET_KEY || '',
  165. * },
  166. * })
  167. *
  168. * const config: VendureConfig = {
  169. * // Add an instance of the plugin to the plugins array
  170. * plugins: [
  171. * EmailPlugin.init({
  172. * handlers: defaultEmailHandlers,
  173. * templatePath: path.join(__dirname, 'static/email/templates'),
  174. * transport: {
  175. * type: 'ses',
  176. * SES: { ses, aws: { SendRawEmailCommand } },
  177. * sendingRate: 10, // optional messages per second sending rate
  178. * },
  179. * }),
  180. * ],
  181. * };
  182. * ```
  183. * @docsCategory core plugins/EmailPlugin
  184. * @docsPage Transport Options
  185. */
  186. export interface SESTransportOptions extends SESTransport.Options {
  187. type: 'ses';
  188. }
  189. /**
  190. * @description
  191. * Uses the local Sendmail program to send the email.
  192. *
  193. * @docsCategory core plugins/EmailPlugin
  194. * @docsPage Transport Options
  195. */
  196. export interface SendmailTransportOptions {
  197. type: 'sendmail';
  198. /** path to the sendmail command (defaults to ‘sendmail’) */
  199. path?: string;
  200. /** either ‘windows’ or ‘unix’ (default). Forces all newlines in the output to either use Windows syntax <CR><LF> or Unix syntax <LF> */
  201. newline?: string;
  202. }
  203. /**
  204. * @description
  205. * Outputs the email as an HTML file for development purposes.
  206. *
  207. * @docsCategory core plugins/EmailPlugin
  208. * @docsPage Transport Options
  209. */
  210. export interface FileTransportOptions {
  211. type: 'file';
  212. /** The directory in which the emails will be saved */
  213. outputPath: string;
  214. /** When set to true, a raw text file will be output rather than an HTML file */
  215. raw?: boolean;
  216. }
  217. /**
  218. * @description
  219. * Does nothing with the generated email. Intended for use in testing where we don't care about the email transport,
  220. * or when using a custom {@link EmailSender} which does not require transport options.
  221. *
  222. * @docsCategory core plugins/EmailPlugin
  223. * @docsPage Transport Options
  224. */
  225. export interface NoopTransportOptions {
  226. type: 'none';
  227. }
  228. /**
  229. * @description
  230. * The final, generated email details to be sent.
  231. *
  232. * @docsCategory core plugins/EmailPlugin
  233. * @docsPage Email Plugin Types
  234. */
  235. export interface EmailDetails<Type extends 'serialized' | 'unserialized' = 'unserialized'> {
  236. from: string;
  237. recipient: string;
  238. subject: string;
  239. body: string;
  240. attachments: Array<Type extends 'serialized' ? SerializedAttachment : Attachment>;
  241. cc?: string;
  242. bcc?: string;
  243. replyTo?: string;
  244. }
  245. /**
  246. * @description
  247. * Forwards the raw GeneratedEmailContext object to a provided callback, for use in testing.
  248. *
  249. * @docsCategory core plugins/EmailPlugin
  250. * @docsPage Transport Options
  251. */
  252. export interface TestingTransportOptions {
  253. type: 'testing';
  254. /**
  255. * @description
  256. * Callback to be invoked when an email would be sent.
  257. */
  258. onSend: (details: EmailDetails) => void;
  259. }
  260. /**
  261. * @description
  262. * A function used to load async data for use by an {@link EmailEventHandler}.
  263. *
  264. * @docsCategory core plugins/EmailPlugin
  265. * @docsPage Email Plugin Types
  266. */
  267. export type LoadDataFn<Event extends EventWithContext, R> = (context: {
  268. event: Event;
  269. injector: Injector;
  270. }) => Promise<R>;
  271. export type OptionalToNullable<O> = {
  272. [K in keyof O]-?: undefined extends O[K] ? NonNullable<O[K]> | null : O[K];
  273. };
  274. /**
  275. * @description
  276. * An object defining a file attachment for an email. Based on the object described
  277. * [here in the Nodemailer docs](https://nodemailer.com/message/attachments/), but
  278. * only uses the `path` property to define a filesystem path or a URL pointing to
  279. * the attachment file.
  280. *
  281. * @docsCategory core plugins/EmailPlugin
  282. * @docsPage Email Plugin Types
  283. */
  284. export type EmailAttachment = Omit<Attachment, 'raw'> & { path?: string };
  285. export type SerializedAttachment = OptionalToNullable<
  286. Omit<EmailAttachment, 'content'> & { content: string | null }
  287. >;
  288. export type IntermediateEmailDetails = {
  289. ctx: SerializedRequestContext;
  290. type: string;
  291. from: string;
  292. recipient: string;
  293. templateVars: any;
  294. subject: string;
  295. templateFile: string;
  296. attachments: SerializedAttachment[];
  297. cc?: string;
  298. bcc?: string;
  299. replyTo?: string;
  300. };
  301. /**
  302. * @description
  303. * Configures the {@link EmailEventHandler} to handle a particular channel & languageCode
  304. * combination.
  305. *
  306. * @deprecated Use a custom {@link TemplateLoader} instead.
  307. */
  308. export interface EmailTemplateConfig {
  309. /**
  310. * @description
  311. * Specifies the channel to which this configuration will apply. If set to `'default'`, it will be applied to all
  312. * channels.
  313. */
  314. channelCode: string | 'default';
  315. /**
  316. * @description
  317. * Specifies the languageCode to which this configuration will apply. If set to `'default'`, it will be applied to all
  318. * languages.
  319. */
  320. languageCode: LanguageCode | 'default';
  321. /**
  322. * @description
  323. * Defines the file name of the Handlebars template file to be used to when generating this email.
  324. */
  325. templateFile: string;
  326. /**
  327. * @description
  328. * A string defining the email subject line. Handlebars variables defined in the `templateVars` object may
  329. * be used inside the subject.
  330. */
  331. subject: string;
  332. }
  333. export interface LoadTemplateInput {
  334. type: string;
  335. templateName: string;
  336. }
  337. export interface Partial {
  338. name: string;
  339. content: string;
  340. }
  341. /**
  342. * @description
  343. * Load an email template based on the given request context, type and template name
  344. * and return the template as a string.
  345. *
  346. * @example
  347. * ```TypeScript
  348. * import { EmailPlugin, TemplateLoader } from '@vendure/email-plugin';
  349. *
  350. * class MyTemplateLoader implements TemplateLoader {
  351. * loadTemplate(injector, ctx, { type, templateName }){
  352. * return myCustomTemplateFunction(ctx);
  353. * }
  354. * }
  355. *
  356. * // In vendure-config.ts:
  357. * ...
  358. * EmailPlugin.init({
  359. * templateLoader: new MyTemplateLoader()
  360. * ...
  361. * })
  362. * ```
  363. *
  364. * @docsCategory core plugins/EmailPlugin
  365. * @docsPage Custom Template Loader
  366. */
  367. export interface TemplateLoader {
  368. /**
  369. * Load template and return it's content as a string
  370. */
  371. loadTemplate(injector: Injector, ctx: RequestContext, input: LoadTemplateInput): Promise<string>;
  372. /**
  373. * Load partials and return their contents.
  374. * This method is only called during initalization, i.e. during server startup.
  375. */
  376. loadPartials?(): Promise<Partial[]>;
  377. }
  378. /**
  379. * @description
  380. * A function used to define template variables available to email templates.
  381. * See {@link EmailEventHandler}.setTemplateVars().
  382. *
  383. * @docsCategory core plugins/EmailPlugin
  384. * @docsPage Email Plugin Types
  385. */
  386. export type SetTemplateVarsFn<Event> = (
  387. event: Event,
  388. globals: { [key: string]: any },
  389. ) => { [key: string]: any };
  390. /**
  391. * @description
  392. * A function used to define attachments to be sent with the email.
  393. * See https://nodemailer.com/message/attachments/ for more information about
  394. * how attachments work in Nodemailer.
  395. *
  396. * @docsCategory core plugins/EmailPlugin
  397. * @docsPage Email Plugin Types
  398. */
  399. export type SetAttachmentsFn<Event> = (event: Event) => EmailAttachment[] | Promise<EmailAttachment[]>;
  400. /**
  401. * @description
  402. * Optional address-related fields for sending the email.
  403. *
  404. * @since 1.1.0
  405. * @docsCategory core plugins/EmailPlugin
  406. * @docsPage Email Plugin Types
  407. */
  408. export interface OptionalAddressFields {
  409. /**
  410. * @description
  411. * Comma separated list of recipients email addresses that will appear on the _Cc:_ field
  412. */
  413. cc?: string;
  414. /**
  415. * @description
  416. * Comma separated list of recipients email addresses that will appear on the _Bcc:_ field
  417. */
  418. bcc?: string;
  419. /**
  420. * @description
  421. * An email address that will appear on the _Reply-To:_ field
  422. */
  423. replyTo?: string;
  424. }
  425. /**
  426. * @description
  427. * A function used to set the {@link OptionalAddressFields}.
  428. *
  429. * @since 1.1.0
  430. * @docsCategory core plugins/EmailPlugin
  431. * @docsPage Email Plugin Types
  432. */
  433. export type SetOptionalAddressFieldsFn<Event> = (
  434. event: Event,
  435. ) => OptionalAddressFields | Promise<OptionalAddressFields>;