@igniter-js/mail 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -4,7 +4,7 @@ import nodemailer from 'nodemailer';
4
4
  import React from 'react';
5
5
  import { render } from '@react-email/components';
6
6
 
7
- // src/errors/igniter-mail.error.ts
7
+ // src/errors/mail.error.ts
8
8
  var IgniterMailError = class _IgniterMailError extends IgniterError {
9
9
  constructor(payload) {
10
10
  super({
@@ -27,560 +27,375 @@ var IgniterMailError = class _IgniterMailError extends IgniterError {
27
27
  };
28
28
 
29
29
  // src/adapters/postmark.adapter.ts
30
- var PostmarkMailAdapterBuilder = class _PostmarkMailAdapterBuilder {
31
- /** Creates a new builder instance. */
32
- static create() {
33
- return new _PostmarkMailAdapterBuilder();
34
- }
35
- /** Sets the Postmark Server Token. */
36
- withSecret(secret) {
37
- this.secret = secret;
38
- return this;
30
+ var PostmarkMailAdapter = class _PostmarkMailAdapter {
31
+ /**
32
+ * Creates a new adapter instance.
33
+ *
34
+ * @param credentials - Provider credentials (secret/from).
35
+ * @throws {IgniterMailError} Does not throw on creation; errors surface on send.
36
+ */
37
+ constructor(credentials = {}) {
38
+ this.credentials = credentials;
39
39
  }
40
- /** Sets the default FROM address used when sending emails via Postmark. */
41
- withFrom(from) {
42
- this.from = from;
43
- return this;
40
+ /**
41
+ * Creates a new adapter instance.
42
+ *
43
+ * @param credentials - Provider credentials (secret/from).
44
+ * @returns A Postmark adapter instance.
45
+ * @throws {IgniterMailError} Does not throw on creation; errors surface on send.
46
+ * @example
47
+ * ```ts
48
+ * const adapter = PostmarkMailAdapter.create({ secret: 'token', from: 'no-reply@acme.com' })
49
+ * ```
50
+ */
51
+ static create(credentials) {
52
+ return new _PostmarkMailAdapter(credentials);
44
53
  }
45
- /** Builds the adapter instance. */
46
- build() {
47
- if (!this.secret) {
54
+ /**
55
+ * Sends an email using Postmark (HTTP API).
56
+ *
57
+ * @param params - Normalized email parameters.
58
+ * @returns A promise that resolves when the email is accepted.
59
+ * @throws {IgniterMailError} When configuration is invalid or Postmark rejects the request.
60
+ * @example
61
+ * ```ts
62
+ * await adapter.send({ to: 'user@example.com', subject: 'Hello', html: '<p>Hi</p>', text: 'Hi' })
63
+ * ```
64
+ */
65
+ async send(params) {
66
+ if (!this.credentials.secret) {
48
67
  throw new IgniterMailError({
49
68
  code: "MAIL_ADAPTER_CONFIGURATION_INVALID",
50
69
  message: "Postmark adapter secret is required"
51
70
  });
52
71
  }
53
- if (!this.from) {
72
+ if (!this.credentials.from) {
54
73
  throw new IgniterMailError({
55
74
  code: "MAIL_ADAPTER_CONFIGURATION_INVALID",
56
75
  message: "Postmark adapter from is required"
57
76
  });
58
77
  }
59
- const token = this.secret;
60
- const from = this.from;
61
- return {
62
- /** Sends an email using Postmark (HTTP API). */
63
- send: async ({ to, subject, html, text }) => {
64
- const response = await fetch("https://api.postmarkapp.com/email", {
65
- method: "POST",
66
- headers: {
67
- Accept: "application/json",
68
- "Content-Type": "application/json",
69
- "X-Postmark-Server-Token": token
70
- },
71
- body: JSON.stringify({
72
- From: from,
73
- To: to,
74
- Subject: subject,
75
- HtmlBody: html,
76
- TextBody: text
77
- })
78
- });
79
- if (!response.ok) {
80
- const body = await response.text().catch(() => "");
81
- throw new IgniterMailError({
82
- code: "MAIL_PROVIDER_SEND_FAILED",
83
- message: "Postmark send failed",
84
- metadata: {
85
- status: response.status,
86
- body
87
- }
88
- });
78
+ const token = this.credentials.secret;
79
+ const from = this.credentials.from;
80
+ const response = await fetch("https://api.postmarkapp.com/email", {
81
+ method: "POST",
82
+ headers: {
83
+ Accept: "application/json",
84
+ "Content-Type": "application/json",
85
+ "X-Postmark-Server-Token": token
86
+ },
87
+ body: JSON.stringify({
88
+ From: from,
89
+ To: params.to,
90
+ Subject: params.subject,
91
+ HtmlBody: params.html,
92
+ TextBody: params.text
93
+ })
94
+ });
95
+ if (!response.ok) {
96
+ const body = await response.text().catch(() => "");
97
+ throw new IgniterMailError({
98
+ code: "MAIL_PROVIDER_SEND_FAILED",
99
+ message: "Postmark send failed",
100
+ metadata: {
101
+ status: response.status,
102
+ body
89
103
  }
90
- }
91
- };
104
+ });
105
+ }
92
106
  }
93
107
  };
94
- var postmarkAdapter = (options) => PostmarkMailAdapterBuilder.create().withSecret(options.secret).withFrom(options.from).build();
95
- var ResendMailAdapterBuilder = class _ResendMailAdapterBuilder {
96
- /** Creates a new builder instance. */
97
- static create() {
98
- return new _ResendMailAdapterBuilder();
99
- }
100
- /** Sets the Resend API key. */
101
- withSecret(secret) {
102
- this.secret = secret;
103
- return this;
108
+ var ResendMailAdapter = class _ResendMailAdapter {
109
+ /**
110
+ * Creates an adapter with credentials.
111
+ *
112
+ * @param credentials - Adapter credentials including API secret and default from.
113
+ * @throws {IgniterMailError} Does not throw on creation; errors surface on send.
114
+ */
115
+ constructor(credentials = {}) {
116
+ this.credentials = credentials;
104
117
  }
105
- /** Sets the default FROM address used when sending emails via Resend. */
106
- withFrom(from) {
107
- this.from = from;
108
- return this;
118
+ /**
119
+ * Creates a new adapter instance.
120
+ *
121
+ * @param credentials - Adapter credentials including API secret and default from.
122
+ * @returns A configured Resend adapter.
123
+ * @throws {IgniterMailError} Does not throw on creation; errors surface on send.
124
+ * @example
125
+ * ```ts
126
+ * const adapter = ResendMailAdapter.create({ secret: 'token', from: 'no-reply@acme.com' })
127
+ * ```
128
+ */
129
+ static create(credentials) {
130
+ return new _ResendMailAdapter(credentials);
109
131
  }
110
- /** Builds the adapter instance. */
111
- build() {
112
- if (!this.secret) {
132
+ /**
133
+ * Sends an email using Resend.
134
+ *
135
+ * @param params - Email payload to send.
136
+ * @returns Resolves when the email is accepted by Resend.
137
+ * @throws {IgniterMailError} When credentials are missing or Resend rejects the request.
138
+ *
139
+ * @example
140
+ * ```ts
141
+ * await adapter.send({ to: 'user@example.com', subject: 'Welcome', html: '<p>Hi</p>', text: 'Hi' })
142
+ * ```
143
+ */
144
+ async send(params) {
145
+ if (!this.credentials.secret) {
113
146
  throw new IgniterMailError({
114
147
  code: "MAIL_ADAPTER_CONFIGURATION_INVALID",
115
148
  message: "Resend adapter secret is required"
116
149
  });
117
150
  }
118
- if (!this.from) {
151
+ if (!this.credentials.from) {
119
152
  throw new IgniterMailError({
120
153
  code: "MAIL_ADAPTER_CONFIGURATION_INVALID",
121
154
  message: "Resend adapter from is required"
122
155
  });
123
156
  }
124
- const resend = new Resend(this.secret);
125
- const from = this.from;
126
- return {
127
- /**
128
- * Sends an email using Resend.
129
- *
130
- * Note: Resend accepts `scheduledAt` as an ISO string.
131
- */
132
- send: async ({ to, subject, html, text, scheduledAt }) => {
133
- await resend.emails.create({
134
- to,
135
- from,
136
- subject,
137
- html,
138
- text,
139
- scheduledAt: scheduledAt?.toISOString()
140
- });
141
- }
142
- };
157
+ const resend = new Resend(this.credentials.secret);
158
+ const from = this.credentials.from;
159
+ await resend.emails.create({
160
+ to: params.to,
161
+ from,
162
+ subject: params.subject,
163
+ html: params.html,
164
+ text: params.text,
165
+ scheduledAt: params.scheduledAt?.toISOString()
166
+ });
143
167
  }
144
168
  };
145
- var resendAdapter = (options) => ResendMailAdapterBuilder.create().withSecret(options.secret).withFrom(options.from).build();
146
169
 
147
170
  // src/adapters/sendgrid.adapter.ts
148
- var SendGridMailAdapterBuilder = class _SendGridMailAdapterBuilder {
149
- /** Creates a new builder instance. */
150
- static create() {
151
- return new _SendGridMailAdapterBuilder();
152
- }
153
- /** Sets the SendGrid API key. */
154
- withSecret(secret) {
155
- this.secret = secret;
156
- return this;
171
+ var SendGridMailAdapter = class _SendGridMailAdapter {
172
+ /**
173
+ * Creates an adapter with credentials.
174
+ *
175
+ * @param credentials - Adapter credentials including API secret and default from.
176
+ * @throws {IgniterMailError} Does not throw on creation; errors surface on send.
177
+ */
178
+ constructor(credentials = {}) {
179
+ this.credentials = credentials;
157
180
  }
158
- /** Sets the default FROM address used when sending emails via SendGrid. */
159
- withFrom(from) {
160
- this.from = from;
161
- return this;
181
+ /**
182
+ * Creates a new adapter instance.
183
+ *
184
+ * @param credentials - Adapter credentials including API secret and default from.
185
+ * @returns A configured SendGrid adapter.
186
+ * @throws {IgniterMailError} Does not throw on creation; errors surface on send.
187
+ * @example
188
+ * ```ts
189
+ * const adapter = SendGridMailAdapter.create({ secret: 'token', from: 'no-reply@acme.com' })
190
+ * ```
191
+ */
192
+ static create(credentials) {
193
+ return new _SendGridMailAdapter(credentials);
162
194
  }
163
- /** Builds the adapter instance. */
164
- build() {
165
- if (!this.secret) {
195
+ /**
196
+ * Sends an email using SendGrid (HTTP API).
197
+ *
198
+ * @param params - Email payload to send.
199
+ * @returns Resolves when the email is accepted by SendGrid.
200
+ * @throws {IgniterMailError} When credentials are missing or the API fails.
201
+ *
202
+ * @example
203
+ * ```ts
204
+ * await adapter.send({ to: 'user@example.com', subject: 'Hi', html: '<p>Hi</p>', text: 'Hi' })
205
+ * ```
206
+ */
207
+ async send(params) {
208
+ if (!this.credentials.secret) {
166
209
  throw new IgniterMailError({
167
210
  code: "MAIL_ADAPTER_CONFIGURATION_INVALID",
168
211
  message: "SendGrid adapter secret is required"
169
212
  });
170
213
  }
171
- if (!this.from) {
214
+ if (!this.credentials.from) {
172
215
  throw new IgniterMailError({
173
216
  code: "MAIL_ADAPTER_CONFIGURATION_INVALID",
174
217
  message: "SendGrid adapter from is required"
175
218
  });
176
219
  }
177
- const apiKey = this.secret;
178
- const from = this.from;
179
- return {
180
- /** Sends an email using SendGrid (HTTP API). */
181
- send: async ({ to, subject, html, text }) => {
182
- const response = await fetch("https://api.sendgrid.com/v3/mail/send", {
183
- method: "POST",
184
- headers: {
185
- Authorization: `Bearer ${apiKey}`,
186
- "Content-Type": "application/json"
187
- },
188
- body: JSON.stringify({
189
- personalizations: [{
190
- to: [{ email: to }]
191
- }],
192
- from: { email: from },
193
- subject,
194
- content: [
195
- { type: "text/plain", value: text },
196
- { type: "text/html", value: html }
197
- ]
198
- })
199
- });
200
- if (!response.ok) {
201
- const body = await response.text().catch(() => "");
202
- throw new IgniterMailError({
203
- code: "MAIL_PROVIDER_SEND_FAILED",
204
- message: "SendGrid send failed",
205
- metadata: {
206
- status: response.status,
207
- body
208
- }
209
- });
220
+ const apiKey = this.credentials.secret;
221
+ const from = this.credentials.from;
222
+ const response = await fetch("https://api.sendgrid.com/v3/mail/send", {
223
+ method: "POST",
224
+ headers: {
225
+ Authorization: `Bearer ${apiKey}`,
226
+ "Content-Type": "application/json"
227
+ },
228
+ body: JSON.stringify({
229
+ personalizations: [
230
+ {
231
+ to: [{ email: params.to }]
232
+ }
233
+ ],
234
+ from: { email: from },
235
+ subject: params.subject,
236
+ content: [
237
+ { type: "text/plain", value: params.text },
238
+ { type: "text/html", value: params.html }
239
+ ]
240
+ })
241
+ });
242
+ if (!response.ok) {
243
+ const body = await response.text().catch(() => "");
244
+ throw new IgniterMailError({
245
+ code: "MAIL_PROVIDER_SEND_FAILED",
246
+ message: "SendGrid send failed",
247
+ metadata: {
248
+ status: response.status,
249
+ body
210
250
  }
211
- }
212
- };
251
+ });
252
+ }
213
253
  }
214
254
  };
215
- var sendgridAdapter = (options) => SendGridMailAdapterBuilder.create().withSecret(options.secret).withFrom(options.from).build();
216
- var SmtpMailAdapterBuilder = class _SmtpMailAdapterBuilder {
217
- /** Creates a new builder instance. */
218
- static create() {
219
- return new _SmtpMailAdapterBuilder();
220
- }
221
- /** Sets the SMTP connection URL (e.g. `smtps://user:pass@host:port`). */
222
- withSecret(secret) {
223
- this.secret = secret;
224
- return this;
255
+ var SmtpMailAdapter = class _SmtpMailAdapter {
256
+ /**
257
+ * Creates an adapter with credentials.
258
+ *
259
+ * @param credentials - Adapter credentials including SMTP URL and default from.
260
+ * @throws {IgniterMailError} Does not throw on creation; errors surface on send.
261
+ */
262
+ constructor(credentials = {}) {
263
+ this.credentials = credentials;
225
264
  }
226
- /** Sets the default FROM address used when sending emails via SMTP. */
227
- withFrom(from) {
228
- this.from = from;
229
- return this;
265
+ /**
266
+ * Creates a new adapter instance.
267
+ *
268
+ * @param credentials - Adapter credentials including SMTP URL and default from.
269
+ * @returns A configured SMTP adapter.
270
+ * @throws {IgniterMailError} Does not throw on creation; errors surface on send.
271
+ * @example
272
+ * ```ts
273
+ * const adapter = SmtpMailAdapter.create({ secret: 'smtps://user:pass@host:465', from: 'no-reply@acme.com' })
274
+ * ```
275
+ */
276
+ static create(credentials) {
277
+ return new _SmtpMailAdapter(credentials);
230
278
  }
231
- /** Builds the adapter instance. */
232
- build() {
233
- if (!this.secret) {
279
+ /**
280
+ * Sends an email using Nodemailer over SMTP.
281
+ *
282
+ * @param params - Email payload to send.
283
+ * @returns Resolves when the email is sent.
284
+ * @throws {IgniterMailError} When credentials are missing or the SMTP send fails.
285
+ *
286
+ * @example
287
+ * ```ts
288
+ * await adapter.send({ to: 'user@example.com', subject: 'Hi', html: '<p>Hi</p>', text: 'Hi' })
289
+ * ```
290
+ */
291
+ async send(params) {
292
+ if (!this.credentials.secret) {
234
293
  throw new IgniterMailError({
235
294
  code: "MAIL_ADAPTER_CONFIGURATION_INVALID",
236
295
  message: "SMTP adapter secret is required"
237
296
  });
238
297
  }
239
- if (!this.from) {
298
+ if (!this.credentials.from) {
240
299
  throw new IgniterMailError({
241
300
  code: "MAIL_ADAPTER_CONFIGURATION_INVALID",
242
301
  message: "SMTP adapter from is required"
243
302
  });
244
303
  }
245
- const smtpUrl = this.secret;
246
- const from = this.from;
247
- const createTransporter = () => {
248
- return nodemailer.createTransport(smtpUrl, {
249
- tls: {
250
- rejectUnauthorized: false
251
- },
252
- connectionTimeout: 1e4,
253
- greetingTimeout: 5e3,
254
- socketTimeout: 1e4
255
- });
256
- };
257
- return {
258
- /** Sends an email using Nodemailer over SMTP. */
259
- send: async ({ to, subject, html, text }) => {
260
- const transport = createTransporter();
261
- const mailOptions = {
262
- from,
263
- to,
264
- subject,
265
- html,
266
- text
267
- };
268
- try {
269
- await transport.sendMail(mailOptions);
270
- transport.close();
271
- } catch (error) {
272
- transport.close();
273
- throw error;
274
- }
304
+ const smtpUrl = this.credentials.secret;
305
+ const from = this.credentials.from;
306
+ const transport = nodemailer.createTransport(smtpUrl, {
307
+ connectionTimeout: 1e4,
308
+ greetingTimeout: 5e3,
309
+ socketTimeout: 1e4,
310
+ tls: {
311
+ rejectUnauthorized: false
275
312
  }
276
- };
277
- }
278
- };
279
- var smtpAdapter = (options) => SmtpMailAdapterBuilder.create().withSecret(options.secret).withFrom(options.from).build();
280
-
281
- // src/adapters/test.adapter.ts
282
- function createTestMailAdapter(options = {}) {
283
- const sent = [];
284
- const logger = options.logger ?? console;
285
- const silent = options.silent ?? false;
286
- return {
287
- sent,
288
- reset: () => {
289
- sent.length = 0;
290
- },
291
- last: () => sent.at(-1),
292
- send: async (params) => {
293
- sent.push({ ...params, at: /* @__PURE__ */ new Date() });
294
- if (!silent) {
295
- logger.info(
296
- `[TestMailAdapter] to=${params.to} subject=${params.subject} html=${params.html.length}B text=${params.text.length}B`
297
- );
298
- }
299
- }
300
- };
301
- }
302
-
303
- // src/adapters/webhook.adapter.ts
304
- var WebhookMailAdapterBuilder = class _WebhookMailAdapterBuilder {
305
- /** Creates a new builder instance. */
306
- static create() {
307
- return new _WebhookMailAdapterBuilder();
308
- }
309
- /**
310
- * Sets the webhook URL.
311
- *
312
- * Note: when using `IgniterMailBuilder.withAdapter('webhook', secret)`, the `secret`
313
- * is treated as the webhook URL.
314
- */
315
- withUrl(url) {
316
- this.url = url;
317
- return this;
318
- }
319
- /** Sets the default FROM address. */
320
- withFrom(from) {
321
- this.from = from;
322
- return this;
323
- }
324
- /** Builds the adapter instance. */
325
- build() {
326
- if (!this.url) {
327
- throw new IgniterMailError({
328
- code: "MAIL_ADAPTER_CONFIGURATION_INVALID",
329
- message: "Webhook adapter url is required"
313
+ });
314
+ try {
315
+ await transport.sendMail({
316
+ from,
317
+ to: params.to,
318
+ subject: params.subject,
319
+ html: params.html,
320
+ text: params.text
330
321
  });
331
- }
332
- if (!this.from) {
322
+ } catch (error) {
333
323
  throw new IgniterMailError({
334
- code: "MAIL_ADAPTER_CONFIGURATION_INVALID",
335
- message: "Webhook adapter from is required"
324
+ code: "MAIL_PROVIDER_SEND_FAILED",
325
+ message: "SMTP send failed",
326
+ metadata: {
327
+ originalError: error
328
+ }
336
329
  });
330
+ } finally {
331
+ transport.close();
337
332
  }
338
- const url = this.url;
339
- const from = this.from;
340
- return {
341
- /** Sends an email by POST-ing to the configured webhook URL. */
342
- send: async ({ to, subject, html, text, scheduledAt }) => {
343
- const response = await fetch(url, {
344
- method: "POST",
345
- headers: {
346
- "Content-Type": "application/json"
347
- },
348
- body: JSON.stringify({
349
- to,
350
- from,
351
- subject,
352
- html,
353
- text,
354
- scheduledAt: scheduledAt?.toISOString()
355
- })
356
- });
357
- if (!response.ok) {
358
- const body = await response.text().catch(() => "");
359
- throw new IgniterMailError({
360
- code: "MAIL_PROVIDER_SEND_FAILED",
361
- message: "Webhook send failed",
362
- metadata: {
363
- status: response.status,
364
- body
365
- }
366
- });
367
- }
368
- }
369
- };
370
333
  }
371
334
  };
372
- var webhookAdapter = (options) => WebhookMailAdapterBuilder.create().withUrl(options.secret).withFrom(options.from).build();
373
335
 
374
- // src/builders/igniter-mail.builder.ts
375
- var IgniterMailBuilder = class _IgniterMailBuilder {
376
- constructor(factory) {
377
- this.templates = {};
378
- this.factory = factory;
379
- }
380
- /**
381
- * Creates a new builder.
382
- */
383
- static create(factory) {
384
- return new _IgniterMailBuilder(factory);
385
- }
386
- /** Sets the default FROM address. */
387
- withFrom(from) {
388
- this.from = from;
389
- return this;
390
- }
391
- /** Attaches a logger instance. */
392
- withLogger(logger) {
393
- this.logger = logger;
394
- return this;
395
- }
336
+ // src/types/telemetry.ts
337
+ var IGNITER_MAIL_TELEMETRY_EVENTS = {
338
+ /** Emitted when mail send operation starts */
339
+ SEND_STARTED: "igniter.mail.send.started",
340
+ /** Emitted when mail send operation succeeds */
341
+ SEND_SUCCESS: "igniter.mail.send.success",
342
+ /** Emitted when mail send operation fails */
343
+ SEND_ERROR: "igniter.mail.send.error",
344
+ /** Emitted when mail schedule operation starts */
345
+ SCHEDULE_STARTED: "igniter.mail.schedule.started",
346
+ /** Emitted when mail schedule operation succeeds */
347
+ SCHEDULE_SUCCESS: "igniter.mail.schedule.success",
348
+ /** Emitted when mail schedule operation fails */
349
+ SCHEDULE_ERROR: "igniter.mail.schedule.error"
350
+ };
351
+
352
+ // src/utils/schema.ts
353
+ var IgniterMailSchema = class {
396
354
  /**
397
- * Enables queue delivery.
355
+ * Validates an unknown input using `StandardSchemaV1` when the schema provides `~standard.validate`.
398
356
  *
399
- * If configured, `IgniterMail.schedule()` will enqueue jobs instead of using `setTimeout`.
400
- */
401
- withQueue(adapter, options) {
402
- this.queue = { adapter, options };
403
- return this;
404
- }
405
- withAdapter(adapterOrProvider, secret) {
406
- if (typeof adapterOrProvider === "string") {
407
- if (!secret) {
408
- throw new IgniterMailError({
409
- code: "MAIL_PROVIDER_ADAPTER_SECRET_REQUIRED",
410
- message: "MAIL_PROVIDER_ADAPTER_SECRET_REQUIRED",
411
- logger: this.logger
412
- });
413
- }
414
- this.adapter = {
415
- kind: "provider",
416
- provider: adapterOrProvider,
417
- secret
418
- };
419
- return this;
420
- }
421
- this.adapter = {
422
- kind: "adapter",
423
- adapter: adapterOrProvider
424
- };
425
- return this;
426
- }
427
- /**
428
- * Registers a template.
429
- */
430
- addTemplate(key, template) {
431
- this.templates[key] = template;
432
- return this;
433
- }
434
- /** Hook invoked before sending. */
435
- withOnSendStarted(onSendStarted) {
436
- this.onSendStarted = onSendStarted;
437
- return this;
438
- }
439
- /** Hook invoked on error. */
440
- withOnSendError(onSendError) {
441
- this.onSendError = onSendError;
442
- return this;
443
- }
444
- /** Hook invoked on success. */
445
- withOnSendSuccess(onSendSuccess) {
446
- this.onSendSuccess = onSendSuccess;
447
- return this;
448
- }
449
- /**
450
- * Builds the {@link IgniterMail} instance.
357
+ * If the schema does not provide a validator, this method returns the input as-is.
451
358
  */
452
- build() {
453
- if (!this.from) {
454
- throw new IgniterMailError({
455
- code: "MAIL_PROVIDER_FROM_REQUIRED",
456
- message: "MAIL_PROVIDER_FROM_REQUIRED",
457
- logger: this.logger
458
- });
359
+ static async validateInput(schema, input) {
360
+ const standard = schema?.["~standard"];
361
+ if (!standard?.validate) {
362
+ return input;
459
363
  }
460
- if (!this.adapter) {
364
+ const result = await standard.validate(input);
365
+ if (result?.issues?.length) {
461
366
  throw new IgniterMailError({
462
- code: "MAIL_PROVIDER_ADAPTER_REQUIRED",
463
- message: "MAIL_PROVIDER_ADAPTER_REQUIRED",
464
- logger: this.logger
367
+ code: "MAIL_PROVIDER_TEMPLATE_DATA_INVALID",
368
+ message: "Invalid mail template payload",
369
+ statusCode: 400,
370
+ details: result.issues
465
371
  });
466
372
  }
467
- const resolvedAdapter = this.adapter.kind === "adapter" ? this.adapter.adapter : (() => {
468
- switch (this.adapter.provider) {
469
- case "resend":
470
- return ResendMailAdapterBuilder.create().withSecret(this.adapter.secret).withFrom(this.from).build();
471
- case "smtp":
472
- return SmtpMailAdapterBuilder.create().withSecret(this.adapter.secret).withFrom(this.from).build();
473
- case "postmark":
474
- return PostmarkMailAdapterBuilder.create().withSecret(this.adapter.secret).withFrom(this.from).build();
475
- case "sendgrid":
476
- return SendGridMailAdapterBuilder.create().withSecret(this.adapter.secret).withFrom(this.from).build();
477
- case "webhook":
478
- return WebhookMailAdapterBuilder.create().withUrl(this.adapter.secret).withFrom(this.from).build();
479
- default:
480
- throw new IgniterMailError({
481
- code: "MAIL_PROVIDER_ADAPTER_NOT_FOUND",
482
- message: `MAIL_PROVIDER_ADAPTER_NOT_FOUND: ${this.adapter.provider}`,
483
- logger: this.logger,
484
- metadata: {
485
- provider: this.adapter.provider
486
- }
487
- });
488
- }
489
- })();
490
- return this.factory({
491
- from: this.from,
492
- adapter: resolvedAdapter,
493
- templates: this.templates,
494
- onSendStarted: this.onSendStarted,
495
- onSendError: this.onSendError,
496
- onSendSuccess: this.onSendSuccess,
497
- logger: this.logger,
498
- queue: this.queue ? {
499
- adapter: this.queue.adapter,
500
- id: `${this.queue.options?.namespace ?? "mail"}.${this.queue.options?.task ?? "send"}`,
501
- options: this.queue.options
502
- } : void 0
503
- });
373
+ return result?.value ?? input;
504
374
  }
505
- };
506
-
507
- // src/builders/mail-template.builder.ts
508
- var MailTemplateBuilder = class _MailTemplateBuilder {
509
- /** Creates a new builder instance. */
510
- static create() {
511
- return new _MailTemplateBuilder();
512
- }
513
- /** Sets the default subject for the template. */
514
- withSubject(subject) {
515
- this.subject = subject;
516
- return this;
517
- }
518
- /** Attaches the schema used to validate and infer payload types. */
519
- withSchema(schema) {
520
- this.schema = schema;
521
- return this;
522
- }
523
- /** Sets the React Email render function for the template. */
524
- withRender(render2) {
525
- this.render = render2;
526
- return this;
527
- }
528
- /** Builds the template definition. */
529
- build() {
530
- if (!this.subject) {
531
- throw new IgniterMailError({
532
- code: "MAIL_TEMPLATE_CONFIGURATION_INVALID",
533
- message: "Mail template subject is required"
534
- });
535
- }
536
- if (!this.schema) {
537
- throw new IgniterMailError({
538
- code: "MAIL_TEMPLATE_CONFIGURATION_INVALID",
539
- message: "Mail template schema is required"
540
- });
541
- }
542
- if (!this.render) {
543
- throw new IgniterMailError({
544
- code: "MAIL_TEMPLATE_CONFIGURATION_INVALID",
545
- message: "Mail template render is required"
546
- });
547
- }
375
+ /**
376
+ * Creates a passthrough StandardSchema validator.
377
+ */
378
+ static createPassthroughSchema() {
548
379
  return {
549
- subject: this.subject,
550
- schema: this.schema,
551
- render: this.render
380
+ "~standard": {
381
+ vendor: "@igniter-js/mail",
382
+ version: 1,
383
+ validate: async (value) => ({ value })
384
+ }
552
385
  };
553
386
  }
554
387
  };
555
388
 
556
- // src/utils/validate-standard-schema-input.ts
557
- async function validateStandardSchemaInput(schema, input) {
558
- const standard = schema?.["~standard"];
559
- if (!standard?.validate) {
560
- return input;
561
- }
562
- const result = await standard.validate(input);
563
- if (result?.issues?.length) {
564
- throw new IgniterMailError({
565
- code: "MAIL_PROVIDER_TEMPLATE_DATA_INVALID",
566
- message: "Invalid mail template payload",
567
- statusCode: 400,
568
- details: result.issues
569
- });
570
- }
571
- return result?.value ?? input;
572
- }
573
-
574
- // src/core/igniter-mail.tsx
575
- var _IgniterMail = class _IgniterMail {
389
+ // src/core/manager.tsx
390
+ var IgniterMailManagerCore = class {
576
391
  constructor(options) {
577
392
  this.queueJobRegistered = false;
578
393
  /**
579
394
  * Type inference helper.
580
395
  * Access via `typeof mail.$Infer` (type-level only).
581
396
  */
582
- this.$Infer = void 0;
583
- const { adapter, templates, logger, queue, ...rest } = options;
397
+ this.$Infer = {};
398
+ const { adapter, templates, logger, telemetry, queue, ...rest } = options;
584
399
  if (!adapter) {
585
400
  throw new IgniterMailError({
586
401
  code: "MAIL_PROVIDER_ADAPTER_REQUIRED",
@@ -598,6 +413,7 @@ var _IgniterMail = class _IgniterMail {
598
413
  this.adapter = adapter;
599
414
  this.templates = templates;
600
415
  this.logger = logger;
416
+ this.telemetry = telemetry;
601
417
  this.queue = queue;
602
418
  this.options = rest;
603
419
  }
@@ -611,30 +427,20 @@ var _IgniterMail = class _IgniterMail {
611
427
  }
612
428
  this.queueJobRegistering = (async () => {
613
429
  const queueOptions = queue.options;
614
- const name = queueOptions?.name ?? "send";
615
- const passthroughSchema = {
616
- "~standard": {
617
- vendor: "@igniter-js/mail",
618
- version: 1,
619
- validate: async (value) => ({ value })
620
- }
621
- };
622
- const definition = queue.adapter.register({
623
- name,
430
+ const passthroughSchema = IgniterMailSchema.createPassthroughSchema();
431
+ queue.adapter.register({
432
+ name: queueOptions?.job ?? "send",
624
433
  input: passthroughSchema,
625
- handler: async ({ input }) => {
626
- await this.send(input);
627
- },
628
- queue: queueOptions?.queue,
629
434
  attempts: queueOptions?.attempts,
630
435
  priority: queueOptions?.priority,
631
436
  removeOnComplete: queueOptions?.removeOnComplete,
632
437
  removeOnFail: queueOptions?.removeOnFail,
633
438
  metadata: queueOptions?.metadata,
634
- limiter: queueOptions?.limiter
635
- });
636
- await queue.adapter.bulkRegister({
637
- [queue.id]: definition
439
+ limiter: queueOptions?.limiter,
440
+ queue: { name: queueOptions?.queue ?? "mail" },
441
+ handler: async ({ input }) => {
442
+ await this.send(input);
443
+ }
638
444
  });
639
445
  this.queueJobRegistered = true;
640
446
  })();
@@ -646,7 +452,7 @@ var _IgniterMail = class _IgniterMail {
646
452
  }
647
453
  async validateTemplateData(template, data) {
648
454
  try {
649
- return await validateStandardSchemaInput(
455
+ return await IgniterMailSchema.validateInput(
650
456
  template.schema,
651
457
  data
652
458
  );
@@ -665,11 +471,20 @@ var _IgniterMail = class _IgniterMail {
665
471
  * Sends an email immediately.
666
472
  */
667
473
  async send(params) {
474
+ const startTime = Date.now();
668
475
  try {
669
476
  this.logger?.debug("IgniterMail.send started", {
670
477
  to: params.to,
671
478
  template: String(params.template)
672
479
  });
480
+ this.telemetry?.emit(IGNITER_MAIL_TELEMETRY_EVENTS.SEND_STARTED, {
481
+ level: "debug",
482
+ attributes: {
483
+ "mail.to": params.to,
484
+ "mail.template": String(params.template),
485
+ "mail.subject": params.subject
486
+ }
487
+ });
673
488
  await this.onSendStarted(params);
674
489
  const template = this.templates[params.template];
675
490
  if (!template) {
@@ -698,9 +513,20 @@ var _IgniterMail = class _IgniterMail {
698
513
  text
699
514
  });
700
515
  await this.onSendSuccess(params);
516
+ const durationMs = Date.now() - startTime;
517
+ this.telemetry?.emit(IGNITER_MAIL_TELEMETRY_EVENTS.SEND_SUCCESS, {
518
+ level: "info",
519
+ attributes: {
520
+ "mail.to": params.to,
521
+ "mail.template": String(params.template),
522
+ "mail.subject": params.subject || template.subject,
523
+ "mail.duration_ms": durationMs
524
+ }
525
+ });
701
526
  this.logger?.info("IgniterMail.send success", {
702
527
  to: params.to,
703
- template: String(params.template)
528
+ template: String(params.template),
529
+ durationMs
704
530
  });
705
531
  } catch (error) {
706
532
  const normalizedError = IgniterMailError.is(error) ? error : new IgniterMailError({
@@ -713,6 +539,18 @@ var _IgniterMail = class _IgniterMail {
713
539
  template: String(params.template)
714
540
  }
715
541
  });
542
+ const durationMs = Date.now() - startTime;
543
+ this.telemetry?.emit(IGNITER_MAIL_TELEMETRY_EVENTS.SEND_ERROR, {
544
+ level: "error",
545
+ attributes: {
546
+ "mail.to": params.to,
547
+ "mail.template": String(params.template),
548
+ "mail.subject": params.subject,
549
+ "mail.error.code": normalizedError.code,
550
+ "mail.error.message": normalizedError.message,
551
+ "mail.duration_ms": durationMs
552
+ }
553
+ });
716
554
  this.logger?.error("IgniterMail.send failed", normalizedError);
717
555
  await this.onSendError(params, normalizedError);
718
556
  throw normalizedError;
@@ -721,10 +559,10 @@ var _IgniterMail = class _IgniterMail {
721
559
  /**
722
560
  * Schedules an email for a future date.
723
561
  *
724
- * If a queue is configured, this method enqueues a job.
725
- * Otherwise, it uses a best-effort `setTimeout`.
562
+ * Requires a queue adapter; otherwise it throws.
726
563
  */
727
564
  async schedule(params, date) {
565
+ const startTime = Date.now();
728
566
  if (date.getTime() <= Date.now()) {
729
567
  throw new IgniterMailError({
730
568
  code: "MAIL_PROVIDER_SCHEDULE_DATE_INVALID",
@@ -732,24 +570,60 @@ var _IgniterMail = class _IgniterMail {
732
570
  logger: this.logger
733
571
  });
734
572
  }
735
- if (this.queue) {
736
- try {
737
- await this.ensureQueueJobRegistered();
738
- const delay = Math.max(0, date.getTime() - Date.now());
739
- this.logger?.info("IgniterMail.schedule enqueued", {
740
- id: this.queue.id,
741
- to: params.to,
742
- template: String(params.template),
743
- delay
744
- });
745
- await this.queue.adapter.invoke({
746
- id: this.queue.id,
747
- input: params,
748
- delay
749
- });
750
- return;
751
- } catch (error) {
752
- const normalizedError = IgniterMailError.is(error) ? error : new IgniterMailError({
573
+ const delay = Math.max(0, date.getTime() - Date.now());
574
+ this.logger?.debug("IgniterMail.schedule started", {
575
+ to: params.to,
576
+ template: String(params.template),
577
+ scheduledAt: date.toISOString(),
578
+ delayMs: delay
579
+ });
580
+ this.telemetry?.emit(IGNITER_MAIL_TELEMETRY_EVENTS.SCHEDULE_STARTED, {
581
+ level: "debug",
582
+ attributes: {
583
+ "mail.to": params.to,
584
+ "mail.template": String(params.template),
585
+ "mail.scheduled_at": date.toISOString(),
586
+ "mail.delay_ms": delay
587
+ }
588
+ });
589
+ if (!this.queue) {
590
+ throw new IgniterMailError({
591
+ code: "MAIL_PROVIDER_SCHEDULE_QUEUE_NOT_CONFIGURED",
592
+ message: "MAIL_PROVIDER_SCHEDULE_QUEUE_NOT_CONFIGURED",
593
+ logger: this.logger
594
+ });
595
+ }
596
+ try {
597
+ await this.ensureQueueJobRegistered();
598
+ const queue = this.queue.options?.queue ?? "mail";
599
+ const job = this.queue.options?.job ?? "send";
600
+ const id = `${queue}.${job}`;
601
+ this.logger?.info("IgniterMail.schedule enqueued", {
602
+ to: params.to,
603
+ template: String(params.template),
604
+ delay,
605
+ durationMs: Date.now() - startTime
606
+ });
607
+ await this.queue.adapter.invoke({
608
+ id,
609
+ input: params,
610
+ delay
611
+ });
612
+ this.telemetry?.emit(IGNITER_MAIL_TELEMETRY_EVENTS.SCHEDULE_SUCCESS, {
613
+ level: "info",
614
+ attributes: {
615
+ "mail.to": params.to,
616
+ "mail.template": String(params.template),
617
+ "mail.scheduled_at": date.toISOString(),
618
+ "mail.delay_ms": delay,
619
+ "mail.queue_id": this.queue.options?.queue ?? "mail"
620
+ }
621
+ });
622
+ return;
623
+ } catch (error) {
624
+ let normalizedError = error;
625
+ if (!IgniterMailError.is(error)) {
626
+ normalizedError = new IgniterMailError({
753
627
  code: "MAIL_PROVIDER_SCHEDULE_FAILED",
754
628
  message: "MAIL_PROVIDER_SCHEDULE_FAILED",
755
629
  cause: error,
@@ -757,19 +631,23 @@ var _IgniterMail = class _IgniterMail {
757
631
  metadata: {
758
632
  to: params.to,
759
633
  template: String(params.template),
760
- date: date.toISOString()
634
+ scheduledAt: date.toISOString()
761
635
  }
762
636
  });
763
- this.logger?.error("IgniterMail.schedule failed", normalizedError);
764
- throw normalizedError;
765
637
  }
766
- }
767
- const timeout = date.getTime() - Date.now();
768
- setTimeout(() => {
769
- this.send(params).catch((error) => {
770
- console.error("Failed to send scheduled email:", error);
638
+ this.telemetry?.emit(IGNITER_MAIL_TELEMETRY_EVENTS.SCHEDULE_ERROR, {
639
+ level: "error",
640
+ attributes: {
641
+ "mail.to": params.to,
642
+ "mail.template": String(params.template),
643
+ "mail.scheduled_at": date.toISOString(),
644
+ "mail.error.code": normalizedError.code,
645
+ "mail.error.message": normalizedError.message
646
+ }
771
647
  });
772
- }, timeout);
648
+ this.logger?.error("IgniterMail.schedule failed", normalizedError);
649
+ throw normalizedError;
650
+ }
773
651
  }
774
652
  async onSendStarted(params) {
775
653
  await this.options.onSendStarted?.(params);
@@ -781,76 +659,227 @@ var _IgniterMail = class _IgniterMail {
781
659
  await this.options.onSendSuccess?.(params);
782
660
  }
783
661
  };
784
- /** Helper to declare adapter factories. */
785
- _IgniterMail.adapter = (adapter) => adapter;
786
- /** Helper to declare templates with inferred payload types. */
787
- _IgniterMail.template = (template) => template;
788
- /**
789
- * Creates a new builder instance.
790
- */
791
- _IgniterMail.create = () => IgniterMailBuilder.create((options) => new _IgniterMail(options));
792
- /**
793
- * Initializes (singleton) instance.
794
- *
795
- * Prefer using {@link IgniterMail.create} for new code.
796
- */
797
- _IgniterMail.initialize = (options) => {
798
- if (_IgniterMail.instance) {
799
- return _IgniterMail.instance;
800
- }
801
- const adapter = options.adapter;
802
- if (typeof adapter === "function") {
803
- const legacyOptions = options;
804
- _IgniterMail.instance = new _IgniterMail({
805
- from: legacyOptions.from,
806
- templates: legacyOptions.templates,
807
- adapter: legacyOptions.adapter(legacyOptions),
808
- onSendStarted: legacyOptions.onSendStarted,
809
- onSendError: legacyOptions.onSendError,
810
- onSendSuccess: legacyOptions.onSendSuccess
662
+
663
+ // src/builders/main.builder.ts
664
+ var IgniterMailBuilder = class _IgniterMailBuilder {
665
+ constructor(options) {
666
+ this.templates = {};
667
+ this.from = options.from;
668
+ this.adapter = options.adapter;
669
+ this.templates = options.templates;
670
+ this.logger = options.logger;
671
+ this.telemetry = options.telemetry;
672
+ this.onSendStartedHandler = options.onSendStarted;
673
+ this.onSendErrorHandler = options.onSendError;
674
+ this.onSendSuccessHandler = options.onSendSuccess;
675
+ if (options.queue) {
676
+ this.queue = {
677
+ adapter: options.queue.adapter,
678
+ options: options.queue.options
679
+ };
680
+ }
681
+ }
682
+ /**
683
+ * Creates a new builder.
684
+ */
685
+ static create() {
686
+ return new _IgniterMailBuilder({ from: "", adapter: {}, templates: {} });
687
+ }
688
+ /** Sets the default FROM address. */
689
+ withFrom(from) {
690
+ this.from = from;
691
+ return this;
692
+ }
693
+ /** Attaches a logger instance. */
694
+ withLogger(logger) {
695
+ this.logger = logger;
696
+ return this;
697
+ }
698
+ /** Attaches a telemetry instance for observability. */
699
+ withTelemetry(telemetry) {
700
+ this.telemetry = telemetry;
701
+ return this;
702
+ }
703
+ /**
704
+ * Enables queue delivery.
705
+ *
706
+ * When configured, `IgniterMail.schedule()` will enqueue jobs using the queue adapter.
707
+ */
708
+ withQueue(adapter, options) {
709
+ this.queue = { adapter, options };
710
+ return this;
711
+ }
712
+ withAdapter(adapterOrProvider, secret) {
713
+ if (typeof adapterOrProvider === "string") {
714
+ if (!secret) {
715
+ throw new IgniterMailError({
716
+ code: "MAIL_PROVIDER_ADAPTER_SECRET_REQUIRED",
717
+ message: "MAIL_PROVIDER_ADAPTER_SECRET_REQUIRED",
718
+ logger: this.logger
719
+ });
720
+ }
721
+ switch (adapterOrProvider) {
722
+ case "resend":
723
+ this.adapter = ResendMailAdapter.create({
724
+ secret,
725
+ from: this.from
726
+ });
727
+ return this;
728
+ case "smtp":
729
+ this.adapter = SmtpMailAdapter.create({
730
+ secret,
731
+ from: this.from
732
+ });
733
+ return this;
734
+ case "postmark":
735
+ this.adapter = PostmarkMailAdapter.create({
736
+ secret,
737
+ from: this.from
738
+ });
739
+ return this;
740
+ case "sendgrid":
741
+ this.adapter = SendGridMailAdapter.create({
742
+ secret,
743
+ from: this.from
744
+ });
745
+ return this;
746
+ default:
747
+ throw new IgniterMailError({
748
+ code: "MAIL_PROVIDER_ADAPTER_NOT_FOUND",
749
+ message: `MAIL_PROVIDER_ADAPTER_NOT_FOUND: ${adapterOrProvider}`,
750
+ logger: this.logger,
751
+ metadata: {
752
+ provider: adapterOrProvider
753
+ }
754
+ });
755
+ }
756
+ }
757
+ this.adapter = adapterOrProvider;
758
+ return this;
759
+ }
760
+ /**
761
+ * Registers a template.
762
+ */
763
+ addTemplate(key, template) {
764
+ return new _IgniterMailBuilder({
765
+ from: this.from,
766
+ adapter: this.adapter,
767
+ templates: {
768
+ ...this.templates,
769
+ [key]: template
770
+ },
771
+ logger: this.logger,
772
+ telemetry: this.telemetry,
773
+ onSendStarted: this.onSendStartedHandler,
774
+ onSendError: this.onSendErrorHandler,
775
+ onSendSuccess: this.onSendSuccessHandler,
776
+ queue: this.queue ? {
777
+ adapter: this.queue.adapter,
778
+ options: this.queue.options
779
+ } : void 0
780
+ });
781
+ }
782
+ /** Hook invoked before sending. */
783
+ onSendStarted(handler) {
784
+ this.onSendStartedHandler = handler;
785
+ return this;
786
+ }
787
+ /** Hook invoked on error. */
788
+ onSendError(handler) {
789
+ this.onSendErrorHandler = handler;
790
+ return this;
791
+ }
792
+ /** Hook invoked on success. */
793
+ onSendSuccess(handler) {
794
+ this.onSendSuccessHandler = handler;
795
+ return this;
796
+ }
797
+ /**
798
+ * Builds the {@link IgniterMail} instance.
799
+ */
800
+ build() {
801
+ if (!this.from) {
802
+ throw new IgniterMailError({
803
+ code: "MAIL_PROVIDER_FROM_REQUIRED",
804
+ message: "MAIL_PROVIDER_FROM_REQUIRED",
805
+ logger: this.logger
806
+ });
807
+ }
808
+ if (!this.adapter) {
809
+ throw new IgniterMailError({
810
+ code: "MAIL_PROVIDER_ADAPTER_REQUIRED",
811
+ message: "MAIL_PROVIDER_ADAPTER_REQUIRED",
812
+ logger: this.logger
813
+ });
814
+ }
815
+ return new IgniterMailManagerCore({
816
+ from: this.from,
817
+ adapter: this.adapter,
818
+ templates: this.templates,
819
+ onSendStarted: this.onSendStartedHandler,
820
+ onSendError: this.onSendErrorHandler,
821
+ onSendSuccess: this.onSendSuccessHandler,
822
+ telemetry: this.telemetry,
823
+ logger: this.logger,
824
+ queue: this.queue ? {
825
+ adapter: this.queue.adapter,
826
+ options: this.queue.options
827
+ } : void 0
811
828
  });
812
- return _IgniterMail.instance;
813
829
  }
814
- _IgniterMail.instance = new _IgniterMail(
815
- options
816
- );
817
- return _IgniterMail.instance;
818
830
  };
819
- var IgniterMail = _IgniterMail;
831
+ var IgniterMail = IgniterMailBuilder;
820
832
 
821
- // src/types/provider.ts
822
- function createPassthroughSchema() {
823
- return {
824
- "~standard": {
825
- vendor: "@igniter-js/mail",
826
- version: 1,
827
- validate: async (value) => ({ value })
833
+ // src/builders/template.builder.ts
834
+ var IgniterMailTemplateBuilder = class _IgniterMailTemplateBuilder {
835
+ /** Creates a new builder instance. */
836
+ static create() {
837
+ return new _IgniterMailTemplateBuilder();
838
+ }
839
+ /** Sets the default subject for the template. */
840
+ withSubject(subject) {
841
+ this.subject = subject;
842
+ return this;
843
+ }
844
+ /** Attaches the schema used to validate and infer payload types. */
845
+ withSchema(schema) {
846
+ this.schema = schema;
847
+ return this;
848
+ }
849
+ /** Sets the React Email render function for the template. */
850
+ withRender(render2) {
851
+ this.render = render2;
852
+ return this;
853
+ }
854
+ /** Builds the template definition. */
855
+ build() {
856
+ if (!this.subject) {
857
+ throw new IgniterMailError({
858
+ code: "MAIL_TEMPLATE_CONFIGURATION_INVALID",
859
+ message: "Mail template subject is required"
860
+ });
828
861
  }
829
- };
830
- }
831
-
832
- // src/utils/get-adapter.ts
833
- var getAdapter = (adapter) => {
834
- switch (adapter) {
835
- case "resend":
836
- return resendAdapter;
837
- case "smtp":
838
- return smtpAdapter;
839
- case "postmark":
840
- return postmarkAdapter;
841
- case "sendgrid":
842
- return sendgridAdapter;
843
- case "webhook":
844
- return webhookAdapter;
845
- default:
862
+ if (!this.schema) {
846
863
  throw new IgniterMailError({
847
- code: "MAIL_PROVIDER_ADAPTER_NOT_FOUND",
848
- message: `MAIL_PROVIDER_ADAPTER_NOT_FOUND: ${adapter}`,
849
- metadata: { adapter }
864
+ code: "MAIL_TEMPLATE_CONFIGURATION_INVALID",
865
+ message: "Mail template schema is required"
850
866
  });
867
+ }
868
+ if (!this.render) {
869
+ throw new IgniterMailError({
870
+ code: "MAIL_TEMPLATE_CONFIGURATION_INVALID",
871
+ message: "Mail template render is required"
872
+ });
873
+ }
874
+ return {
875
+ subject: this.subject,
876
+ schema: this.schema,
877
+ render: this.render
878
+ };
851
879
  }
852
880
  };
881
+ var IgniterMailTemplate = IgniterMailTemplateBuilder;
853
882
 
854
- export { IgniterMail, IgniterMailBuilder, IgniterMailError, MailTemplateBuilder, PostmarkMailAdapterBuilder, ResendMailAdapterBuilder, SendGridMailAdapterBuilder, SmtpMailAdapterBuilder, WebhookMailAdapterBuilder, createPassthroughSchema, createTestMailAdapter, getAdapter, postmarkAdapter, resendAdapter, sendgridAdapter, smtpAdapter, validateStandardSchemaInput, webhookAdapter };
883
+ export { IgniterMail, IgniterMailBuilder, IgniterMailError, IgniterMailManagerCore, IgniterMailSchema, IgniterMailTemplate, IgniterMailTemplateBuilder };
855
884
  //# sourceMappingURL=index.mjs.map
856
885
  //# sourceMappingURL=index.mjs.map