types.ts 12 KB

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