1
0

types.ts 15 KB

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