types.ts 11 KB

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