types.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. import { LanguageCode } from '@vendure/common/lib/generated-types';
  2. import { Omit } from '@vendure/common/lib/omit';
  3. import { Injector, RequestContext, VendureEvent } from '@vendure/core';
  4. import { Attachment } from 'nodemailer/lib/mailer';
  5. import { EmailEventHandler } from './event-handler';
  6. /**
  7. * @description
  8. * A VendureEvent which also includes a `ctx` property containing the current
  9. * {@link RequestContext}, which is used to determine the channel and language
  10. * to use when generating the email.
  11. *
  12. * @docsCategory EmailPlugin
  13. * @docsPage Email Plugin Types
  14. */
  15. export type EventWithContext = VendureEvent & { ctx: RequestContext };
  16. /**
  17. * @description
  18. * A VendureEvent with a {@link RequestContext} and a `data` property which contains the
  19. * value resolved from the {@link EmailEventHandler}`.loadData()` callback.
  20. *
  21. * @docsCategory EmailPlugin
  22. * @docsPage Email Plugin Types
  23. */
  24. export type EventWithAsyncData<Event extends EventWithContext, R> = Event & { data: R };
  25. /**
  26. * @description
  27. * Configuration for the EmailPlugin.
  28. *
  29. * @docsCategory EmailPlugin
  30. * @docsPage EmailPluginOptions
  31. * */
  32. export interface EmailPluginOptions {
  33. /**
  34. * @description
  35. * The path to the location of the email templates. In a default Vendure installation,
  36. * the templates are installed to `<project root>/vendure/email/templates`.
  37. */
  38. templatePath: string;
  39. /**
  40. * @description
  41. * Configures how the emails are sent.
  42. */
  43. transport: EmailTransportOptions;
  44. /**
  45. * @description
  46. * An array of {@link EmailEventHandler}s which define which Vendure events will trigger
  47. * emails, and how those emails are generated.
  48. */
  49. handlers: EmailEventHandler[];
  50. /**
  51. * @description
  52. * An object containing variables which are made available to all templates. For example,
  53. * the storefront URL could be defined here and then used in the "email address verification"
  54. * email.
  55. */
  56. globalTemplateVars?: { [key: string]: any };
  57. /**
  58. * @description
  59. * An optional allowed EmailSender, used to allow custom implementations of the send functionality
  60. * while still utilizing the existing emailPlugin functionality.
  61. *
  62. * @default NodemailerEmailSender
  63. */
  64. emailSender?: EmailSender;
  65. /**
  66. * @description
  67. * An optional allowed EmailGenerator, used to allow custom email generation functionality to
  68. * better match with custom email sending functionality.
  69. *
  70. * @default HandlebarsMjmlGenerator
  71. */
  72. emailGenerator?: EmailGenerator;
  73. }
  74. /**
  75. * @description
  76. * Configuration for running the EmailPlugin in development mode.
  77. *
  78. * @docsCategory EmailPlugin
  79. * @docsPage EmailPluginOptions
  80. */
  81. export interface EmailPluginDevModeOptions extends Omit<EmailPluginOptions, 'transport'> {
  82. devMode: true;
  83. /**
  84. * @description
  85. * The path to which html email files will be saved rather than being sent.
  86. */
  87. outputPath: string;
  88. /**
  89. * @description
  90. * The route to the dev mailbox server.
  91. */
  92. route: string;
  93. }
  94. /**
  95. * @description
  96. * The credentials used for sending email via SMTP
  97. *
  98. * @docsCategory EmailPlugin
  99. * @docsPage Email Plugin Types
  100. */
  101. export interface SMTPCredentials {
  102. /** @description The username */
  103. user: string;
  104. /** @description The password */
  105. pass: string;
  106. }
  107. /**
  108. * @description
  109. * A union of all the possible transport options for sending emails.
  110. *
  111. * @docsCategory EmailPlugin
  112. * @docsPage Transport Options
  113. */
  114. export type EmailTransportOptions =
  115. | SMTPTransportOptions
  116. | SendmailTransportOptions
  117. | FileTransportOptions
  118. | NoopTransportOptions
  119. | TestingTransportOptions;
  120. /**
  121. * @description
  122. * A subset of the SMTP transport options of [Nodemailer](https://nodemailer.com/smtp/)
  123. *
  124. * @docsCategory EmailPlugin
  125. * @docsPage Transport Options
  126. */
  127. export interface SMTPTransportOptions {
  128. type: 'smtp';
  129. /**
  130. * @description
  131. * the hostname or IP address to connect to (defaults to ‘localhost’)
  132. */
  133. host: string;
  134. /**
  135. * @description
  136. * The port to connect to (defaults to 25 or 465)
  137. */
  138. port: number;
  139. /**
  140. * @description
  141. * Defines authentication data
  142. */
  143. auth: SMTPCredentials;
  144. /**
  145. * @description
  146. * Defines if the connection should use SSL (if true) or not (if false)
  147. */
  148. secure?: boolean;
  149. /**
  150. * @description
  151. * Turns off STARTTLS support if true
  152. */
  153. ignoreTLS?: boolean;
  154. /**
  155. * @description
  156. * Forces the client to use STARTTLS. Returns an error if upgrading the connection is not possible or fails.
  157. */
  158. requireTLS?: boolean;
  159. /**
  160. * @description
  161. * Optional hostname of the client, used for identifying to the server
  162. */
  163. name?: string;
  164. /**
  165. * @description
  166. * The local interface to bind to for network connections
  167. */
  168. localAddress?: string;
  169. /**
  170. * @description
  171. * Defines preferred authentication method, e.g. ‘PLAIN’
  172. */
  173. authMethod?: string;
  174. /**
  175. * @description
  176. * If true, uses the configured {@link VendureLogger} to log messages from Nodemailer as it interacts with
  177. * the SMTP server.
  178. *
  179. * @default false
  180. */
  181. logging?: boolean;
  182. /**
  183. * @description
  184. * If set to true, then logs SMTP traffic without message content.
  185. *
  186. * @default false
  187. */
  188. transactionLog?: boolean;
  189. /**
  190. * @description
  191. * If set to true, then logs SMTP traffic and message content, otherwise logs only transaction events.
  192. *
  193. * @default false
  194. */
  195. debug?: boolean;
  196. }
  197. /**
  198. * @description
  199. * Uses the local Sendmail program to send the email.
  200. *
  201. * @docsCategory EmailPlugin
  202. * @docsPage Transport Options
  203. */
  204. export interface SendmailTransportOptions {
  205. type: 'sendmail';
  206. /** path to the sendmail command (defaults to ‘sendmail’) */
  207. path?: string;
  208. /** either ‘windows’ or ‘unix’ (default). Forces all newlines in the output to either use Windows syntax <CR><LF> or Unix syntax <LF> */
  209. newline?: string;
  210. }
  211. /**
  212. * @description
  213. * Outputs the email as an HTML file for development purposes.
  214. *
  215. * @docsCategory EmailPlugin
  216. * @docsPage Transport Options
  217. */
  218. export interface FileTransportOptions {
  219. type: 'file';
  220. /** The directory in which the emails will be saved */
  221. outputPath: string;
  222. /** When set to true, a raw text file will be output rather than an HTML file */
  223. raw?: boolean;
  224. }
  225. /**
  226. * @description
  227. * Does nothing with the generated email. Intended for use in testing where we don't care about the email transport,
  228. * or when using a custom {@link EmailSender} which does not require transport options.
  229. *
  230. * @docsCategory EmailPlugin
  231. * @docsPage Transport Options
  232. */
  233. export interface NoopTransportOptions {
  234. type: 'none';
  235. }
  236. /**
  237. * @description
  238. * The final, generated email details to be sent.
  239. *
  240. * @docsCategory EmailPlugin
  241. * @docsPage Email Plugin Types
  242. */
  243. export interface EmailDetails<Type extends 'serialized' | 'unserialized' = 'unserialized'> {
  244. from: string;
  245. recipient: string;
  246. subject: string;
  247. body: string;
  248. attachments: Array<Type extends 'serialized' ? SerializedAttachment : Attachment>;
  249. }
  250. /**
  251. * @description
  252. * Forwards the raw GeneratedEmailContext object to a provided callback, for use in testing.
  253. *
  254. * @docsCategory EmailPlugin
  255. * @docsPage Transport Options
  256. */
  257. export interface TestingTransportOptions {
  258. type: 'testing';
  259. /**
  260. * @description
  261. * Callback to be invoked when an email would be sent.
  262. */
  263. onSend: (details: EmailDetails) => void;
  264. }
  265. /**
  266. * @description
  267. * An EmailSender is responsible for sending the email, e.g. via an SMTP connection
  268. * or using some other mail-sending API. By default, the EmailPlugin uses the
  269. * {@link NodemailerEmailSender}, but it is also possible to supply a custom implementation:
  270. *
  271. * @example
  272. * ```TypeScript
  273. * const sgMail = require('\@sendgrid/mail');
  274. *
  275. * sgMail.setApiKey(process.env.SENDGRID_API_KEY);
  276. *
  277. * class SendgridEmailSender implements EmailSender {
  278. * async send(email: EmailDetails) {
  279. * await sgMail.send({
  280. * to: email.recipient,
  281. * from: email.from,
  282. * subject: email.subject,
  283. * html: email.body,
  284. * });
  285. * }
  286. * }
  287. *
  288. * const config: VendureConfig = {
  289. * logger: new DefaultLogger({ level: LogLevel.Debug })
  290. * // ...
  291. * plugins: [
  292. * EmailPlugin.init({
  293. * // ... template, handlers config omitted
  294. * transport: { type: 'none' },
  295. * emailSender: new SendgridEmailSender(),
  296. * }),
  297. * ],
  298. * };
  299. * ```
  300. *
  301. * @docsCategory EmailPlugin
  302. * @docsPage EmailSender
  303. * @docsWeight 0
  304. */
  305. export interface EmailSender {
  306. send: (email: EmailDetails, options: EmailTransportOptions) => void | Promise<void>;
  307. }
  308. /**
  309. * @description
  310. * An EmailGenerator generates the subject and body details of an email.
  311. *
  312. * @docsCategory EmailPlugin
  313. * @docsPage EmailGenerator
  314. * @docsWeight 0
  315. */
  316. export interface EmailGenerator<T extends string = any, E extends VendureEvent = any> {
  317. /**
  318. * @description
  319. * Any necessary setup can be performed here.
  320. */
  321. onInit?(options: EmailPluginOptions): void | Promise<void>;
  322. /**
  323. * @description
  324. * Given a subject and body from an email template, this method generates the final
  325. * interpolated email text.
  326. */
  327. generate(
  328. from: string,
  329. subject: string,
  330. body: string,
  331. templateVars: { [key: string]: any },
  332. ): Omit<EmailDetails, 'recipient' | 'attachments'>;
  333. }
  334. /**
  335. * @description
  336. * A function used to load async data for use by an {@link EmailEventHandler}.
  337. *
  338. * @docsCategory EmailPlugin
  339. * @docsPage Email Plugin Types
  340. */
  341. export type LoadDataFn<Event extends EventWithContext, R> = (context: {
  342. event: Event;
  343. injector: Injector;
  344. }) => Promise<R>;
  345. export type OptionalTuNullable<O> = {
  346. [K in keyof O]-?: undefined extends O[K] ? NonNullable<O[K]> | null : O[K];
  347. };
  348. /**
  349. * @description
  350. * An object defining a file attachment for an email. Based on the object described
  351. * [here in the Nodemailer docs](https://nodemailer.com/message/attachments/), but
  352. * only uses the `path` property to define a filesystem path or a URL pointing to
  353. * the attachment file.
  354. *
  355. * @docsCategory EmailPlugin
  356. * @docsPage Email Plugin Types
  357. */
  358. export type EmailAttachment = Omit<Attachment, 'content' | 'raw'> & { path: string };
  359. export type SerializedAttachment = OptionalTuNullable<EmailAttachment>;
  360. export type IntermediateEmailDetails = {
  361. type: string;
  362. from: string;
  363. recipient: string;
  364. templateVars: any;
  365. subject: string;
  366. templateFile: string;
  367. attachments: SerializedAttachment[];
  368. };
  369. /**
  370. * @description
  371. * Configures the {@link EmailEventHandler} to handle a particular channel & languageCode
  372. * combination.
  373. *
  374. * @docsCategory EmailPlugin
  375. * @docsPage Email Plugin Types
  376. */
  377. export interface EmailTemplateConfig {
  378. /**
  379. * @description
  380. * Specifies the channel to which this configuration will apply. If set to `'default'`, it will be applied to all
  381. * channels.
  382. */
  383. channelCode: string | 'default';
  384. /**
  385. * @description
  386. * Specifies the languageCode to which this configuration will apply. If set to `'default'`, it will be applied to all
  387. * languages.
  388. */
  389. languageCode: LanguageCode | 'default';
  390. /**
  391. * @description
  392. * Defines the file name of the Handlebars template file to be used to when generating this email.
  393. */
  394. templateFile: string;
  395. /**
  396. * @description
  397. * A string defining the email subject line. Handlebars variables defined in the `templateVars` object may
  398. * be used inside the subject.
  399. */
  400. subject: string;
  401. }
  402. /**
  403. * @description
  404. * A function used to define template variables available to email templates.
  405. * See {@link EmailEventHandler}.setTemplateVars().
  406. *
  407. * @docsCategory EmailPlugin
  408. * @docsPage Email Plugin Types
  409. */
  410. export type SetTemplateVarsFn<Event> = (
  411. event: Event,
  412. globals: { [key: string]: any },
  413. ) => { [key: string]: any };
  414. /**
  415. * @description
  416. * A function used to define attachments to be sent with the email.
  417. * See https://nodemailer.com/message/attachments/ for more information about
  418. * how attachments work in Nodemailer.
  419. *
  420. * @docsCategory EmailPlugin
  421. * @docsPage Email Plugin Types
  422. */
  423. export type SetAttachmentsFn<Event> = (event: Event) => EmailAttachment[] | Promise<EmailAttachment[]>;