types.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  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. cc?: string;
  250. bcc?: string;
  251. replyTo?: string;
  252. }
  253. /**
  254. * @description
  255. * Forwards the raw GeneratedEmailContext object to a provided callback, for use in testing.
  256. *
  257. * @docsCategory EmailPlugin
  258. * @docsPage Transport Options
  259. */
  260. export interface TestingTransportOptions {
  261. type: 'testing';
  262. /**
  263. * @description
  264. * Callback to be invoked when an email would be sent.
  265. */
  266. onSend: (details: EmailDetails) => void;
  267. }
  268. /**
  269. * @description
  270. * An EmailSender is responsible for sending the email, e.g. via an SMTP connection
  271. * or using some other mail-sending API. By default, the EmailPlugin uses the
  272. * {@link NodemailerEmailSender}, but it is also possible to supply a custom implementation:
  273. *
  274. * @example
  275. * ```TypeScript
  276. * const sgMail = require('\@sendgrid/mail');
  277. *
  278. * sgMail.setApiKey(process.env.SENDGRID_API_KEY);
  279. *
  280. * class SendgridEmailSender implements EmailSender {
  281. * async send(email: EmailDetails) {
  282. * await sgMail.send({
  283. * to: email.recipient,
  284. * from: email.from,
  285. * subject: email.subject,
  286. * html: email.body,
  287. * });
  288. * }
  289. * }
  290. *
  291. * const config: VendureConfig = {
  292. * logger: new DefaultLogger({ level: LogLevel.Debug })
  293. * // ...
  294. * plugins: [
  295. * EmailPlugin.init({
  296. * // ... template, handlers config omitted
  297. * transport: { type: 'none' },
  298. * emailSender: new SendgridEmailSender(),
  299. * }),
  300. * ],
  301. * };
  302. * ```
  303. *
  304. * @docsCategory EmailPlugin
  305. * @docsPage EmailSender
  306. * @docsWeight 0
  307. */
  308. export interface EmailSender {
  309. send: (email: EmailDetails, options: EmailTransportOptions) => void | Promise<void>;
  310. }
  311. /**
  312. * @description
  313. * An EmailGenerator generates the subject and body details of an email.
  314. *
  315. * @docsCategory EmailPlugin
  316. * @docsPage EmailGenerator
  317. * @docsWeight 0
  318. */
  319. export interface EmailGenerator<T extends string = any, E extends VendureEvent = any> {
  320. /**
  321. * @description
  322. * Any necessary setup can be performed here.
  323. */
  324. onInit?(options: EmailPluginOptions): void | Promise<void>;
  325. /**
  326. * @description
  327. * Given a subject and body from an email template, this method generates the final
  328. * interpolated email text.
  329. */
  330. generate(
  331. from: string,
  332. subject: string,
  333. body: string,
  334. templateVars: { [key: string]: any },
  335. ): Pick<EmailDetails, 'from' | 'subject' | 'body'>;
  336. }
  337. /**
  338. * @description
  339. * A function used to load async data for use by an {@link EmailEventHandler}.
  340. *
  341. * @docsCategory EmailPlugin
  342. * @docsPage Email Plugin Types
  343. */
  344. export type LoadDataFn<Event extends EventWithContext, R> = (context: {
  345. event: Event;
  346. injector: Injector;
  347. }) => Promise<R>;
  348. export type OptionalToNullable<O> = {
  349. [K in keyof O]-?: undefined extends O[K] ? NonNullable<O[K]> | null : O[K];
  350. };
  351. /**
  352. * @description
  353. * An object defining a file attachment for an email. Based on the object described
  354. * [here in the Nodemailer docs](https://nodemailer.com/message/attachments/), but
  355. * only uses the `path` property to define a filesystem path or a URL pointing to
  356. * the attachment file.
  357. *
  358. * @docsCategory EmailPlugin
  359. * @docsPage Email Plugin Types
  360. */
  361. export type EmailAttachment = Omit<Attachment, 'raw'> & { path?: string };
  362. export type SerializedAttachment = OptionalToNullable<
  363. Omit<EmailAttachment, 'content'> & { content: string | null }
  364. >;
  365. export type IntermediateEmailDetails = {
  366. type: string;
  367. from: string;
  368. recipient: string;
  369. templateVars: any;
  370. subject: string;
  371. templateFile: string;
  372. attachments: SerializedAttachment[];
  373. cc?: string;
  374. bcc?: string;
  375. replyTo?: string;
  376. };
  377. /**
  378. * @description
  379. * Configures the {@link EmailEventHandler} to handle a particular channel & languageCode
  380. * combination.
  381. *
  382. * @docsCategory EmailPlugin
  383. * @docsPage Email Plugin Types
  384. */
  385. export interface EmailTemplateConfig {
  386. /**
  387. * @description
  388. * Specifies the channel to which this configuration will apply. If set to `'default'`, it will be applied to all
  389. * channels.
  390. */
  391. channelCode: string | 'default';
  392. /**
  393. * @description
  394. * Specifies the languageCode to which this configuration will apply. If set to `'default'`, it will be applied to all
  395. * languages.
  396. */
  397. languageCode: LanguageCode | 'default';
  398. /**
  399. * @description
  400. * Defines the file name of the Handlebars template file to be used to when generating this email.
  401. */
  402. templateFile: string;
  403. /**
  404. * @description
  405. * A string defining the email subject line. Handlebars variables defined in the `templateVars` object may
  406. * be used inside the subject.
  407. */
  408. subject: string;
  409. }
  410. /**
  411. * @description
  412. * A function used to define template variables available to email templates.
  413. * See {@link EmailEventHandler}.setTemplateVars().
  414. *
  415. * @docsCategory EmailPlugin
  416. * @docsPage Email Plugin Types
  417. */
  418. export type SetTemplateVarsFn<Event> = (
  419. event: Event,
  420. globals: { [key: string]: any },
  421. ) => { [key: string]: any };
  422. /**
  423. * @description
  424. * A function used to define attachments to be sent with the email.
  425. * See https://nodemailer.com/message/attachments/ for more information about
  426. * how attachments work in Nodemailer.
  427. *
  428. * @docsCategory EmailPlugin
  429. * @docsPage Email Plugin Types
  430. */
  431. export type SetAttachmentsFn<Event> = (event: Event) => EmailAttachment[] | Promise<EmailAttachment[]>;
  432. /**
  433. * @description
  434. * Optional address-related fields for sending the email.
  435. *
  436. * @since 1.1.0
  437. * @docsCategory EmailPlugin
  438. * @docsPage Email Plugin Types
  439. */
  440. export interface OptionalAddressFields {
  441. /**
  442. * @description
  443. * Comma separated list of recipients email addresses that will appear on the _Cc:_ field
  444. */
  445. cc?: string;
  446. /**
  447. * @description
  448. * Comma separated list of recipients email addresses that will appear on the _Bcc:_ field
  449. */
  450. bcc?: string;
  451. /**
  452. * @description
  453. * An email address that will appear on the _Reply-To:_ field
  454. */
  455. replyTo?: string;
  456. }
  457. /**
  458. * @description
  459. * A function used to set the {@link OptionalAddressFields}.
  460. *
  461. * @since 1.1.0
  462. * @docsCategory EmailPlugin
  463. * @docsPage Email Plugin Types
  464. */
  465. export type SetOptionalAddressFieldsFn<Event> = (
  466. event: Event,
  467. ) => OptionalAddressFields | Promise<OptionalAddressFields>;