mailchannels-sdk 1.6.0 → 1.7.0

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/README.md CHANGED
@@ -18,7 +18,10 @@ This library provides a simple way to interact with the [MailChannels Email API]
18
18
  <!-- #endregion overview -->
19
19
 
20
20
  - [✨ Release Notes](https://bitbucket.org/mailchannels/mailchannels-email-api-sdk-js/src/HEAD/CHANGELOG.md)
21
- - [📖 Documentation](https://mailchannels.yizack.com)
21
+ - [📖 Official quickstart](https://docs.mailchannels.com/email-api/javascript/quickstart)
22
+ - [📦 npm package](https://www.npmjs.com/package/mailchannels-sdk)
23
+ - [📚 SDK reference](https://mailchannels.yizack.com)
24
+ - [Nuxt community module](https://nuxt.com/modules/mailchannels) — maintained separately from this SDK.
22
25
 
23
26
  ## Contents
24
27
 
@@ -3,7 +3,7 @@ import { subtle } from "node:crypto";
3
3
  import { Buffer } from "node:buffer";
4
4
  import mime from "mime";
5
5
  var name = "mailchannels-sdk";
6
- var version = "1.6.0";
6
+ var version = "1.7.0";
7
7
  var MailChannelsClient = class MailChannelsClient {
8
8
  static DEFAULT_BASE_URL = "https://api.mailchannels.net";
9
9
  static DEFAULT_TIMEOUT = 12e4;
@@ -1563,7 +1563,7 @@ var SubAccountsLimits = class {
1563
1563
  error
1564
1564
  };
1565
1565
  }
1566
- if (options.sends < 0) {
1566
+ if (!Number.isInteger(options.sends) || options.sends < 0) {
1567
1567
  error = createValidationError("The sends value must be at least 0.");
1568
1568
  return {
1569
1569
  success: false,
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { Attachment, Emails, MailChannelsClient, name, version } from "../_chunks/mailchannels.mjs";
2
+ import { Attachment, Emails, MailChannelsClient, Suppressions, Webhooks, name, version } from "../_chunks/mailchannels.mjs";
3
3
  import { createSimulator } from "../_chunks/simulator.mjs";
4
4
  import { defineCommand, runMain } from "citty";
5
5
  var simulate_default = defineCommand({
@@ -39,16 +39,42 @@ var simulate_default = defineCommand({
39
39
  process.on("SIGTERM", shutdown);
40
40
  }
41
41
  });
42
+ const getApiKey = (apiKey) => {
43
+ const { MAILCHANNELS_API_KEY } = process.env;
44
+ const key = apiKey || MAILCHANNELS_API_KEY;
45
+ if (!key) {
46
+ console.error("Missing API key. Provide it using the '--api-key' flag or set the 'MAILCHANNELS_API_KEY' environment variable.");
47
+ process.exit(1);
48
+ }
49
+ return key;
50
+ };
51
+ const sharedArgs = { "api-key": {
52
+ type: "string",
53
+ alias: "k",
54
+ valueHint: "key"
55
+ } };
42
56
  const emailArgs = {
43
- "api-key": {
57
+ ...sharedArgs,
58
+ "campaign-id": {
59
+ type: "string",
60
+ valueHint: "id"
61
+ },
62
+ "dkim-domain": {
63
+ type: "string",
64
+ valueHint: "domain"
65
+ },
66
+ "dkim-selector": {
67
+ type: "string",
68
+ valueHint: "selector"
69
+ },
70
+ "dkim-private-key": {
71
+ type: "string",
72
+ valueHint: "key"
73
+ },
74
+ "envelope-from": {
44
75
  type: "string",
45
- alias: "k"
76
+ valueHint: "address"
46
77
  },
47
- "campaign-id": { type: "string" },
48
- "dkim-domain": { type: "string" },
49
- "dkim-selector": { type: "string" },
50
- "dkim-private-key": { type: "string" },
51
- "envelope-from": { type: "string" },
52
78
  "tracking-click": {
53
79
  type: "boolean",
54
80
  default: false
@@ -67,16 +93,17 @@ const emailArgs = {
67
93
  },
68
94
  "from": {
69
95
  type: "string",
70
- required: true
96
+ required: true,
97
+ valueHint: "address"
71
98
  },
72
99
  "headers": {
73
100
  type: "string",
74
- alias: "h",
75
- valueHint: "JSON"
101
+ valueHint: "json"
76
102
  },
77
103
  "to": {
78
104
  type: "string",
79
- required: true
105
+ required: true,
106
+ valueHint: "addresses"
80
107
  },
81
108
  "subject": {
82
109
  type: "string",
@@ -90,9 +117,18 @@ const emailArgs = {
90
117
  type: "string",
91
118
  default: ""
92
119
  },
93
- "cc": { type: "string" },
94
- "bcc": { type: "string" },
95
- "reply-to": { type: "string" },
120
+ "cc": {
121
+ type: "string",
122
+ valueHint: "addresses"
123
+ },
124
+ "bcc": {
125
+ type: "string",
126
+ valueHint: "addresses"
127
+ },
128
+ "reply-to": {
129
+ type: "string",
130
+ valueHint: "address"
131
+ },
96
132
  "attachments": {
97
133
  type: "boolean",
98
134
  alias: "a",
@@ -107,15 +143,6 @@ const emailArgs = {
107
143
  valueHint: "name"
108
144
  }
109
145
  };
110
- const getApiKey = (apiKey) => {
111
- const { MAILCHANNELS_API_KEY } = process.env;
112
- const key = MAILCHANNELS_API_KEY || apiKey;
113
- if (!key) {
114
- console.error("[Emails] Missing API key. Provide it using the '--api-key' flag or set the 'MAILCHANNELS_API_KEY' environment variable.");
115
- process.exit(1);
116
- }
117
- return key;
118
- };
119
146
  const parseAttachments = async (rawAttachments) => {
120
147
  if (!rawAttachments) return;
121
148
  if (process.stdin.isTTY) {
@@ -196,7 +223,7 @@ const parseOptions = async (args) => {
196
223
  var send_default = defineCommand({
197
224
  meta: {
198
225
  name: "send",
199
- description: "Send an email using the MailChannels Email API"
226
+ description: "Send an email"
200
227
  },
201
228
  args: {
202
229
  ...emailArgs,
@@ -221,7 +248,7 @@ var send_default = defineCommand({
221
248
  var queue_default = defineCommand({
222
249
  meta: {
223
250
  name: "queue",
224
- description: "Queue an email to be sent using the MailChannels Email API"
251
+ description: "Queue an email to be sent"
225
252
  },
226
253
  args: emailArgs,
227
254
  async run({ args }) {
@@ -240,7 +267,7 @@ var queue_default = defineCommand({
240
267
  var emails_default = defineCommand({
241
268
  meta: {
242
269
  name: "emails",
243
- description: "Commands for sending emails using the MailChannels Email API"
270
+ description: "Commands for sending emails"
244
271
  },
245
272
  args: {},
246
273
  subCommands: {
@@ -248,6 +275,431 @@ var emails_default = defineCommand({
248
275
  queue: queue_default
249
276
  }
250
277
  });
278
+ const isValidEntry = (value) => {
279
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
280
+ const entry = value;
281
+ return typeof entry.recipient === "string" && (entry.types === void 0 || Array.isArray(entry.types));
282
+ };
283
+ const parseEntries = async (rawEntries, recipient, types, notes) => {
284
+ if (rawEntries) {
285
+ if (recipient) console.warn("[Suppressions] Warning: both '--entries' and '--recipient' are provided. Using '--entries'.");
286
+ if (types || notes) console.warn("[Suppressions] Warning: '--entries' ignores '--types' and '--notes'.");
287
+ if (process.stdin.isTTY) {
288
+ console.error("[Suppressions] '--entries' requires JSON input piped to stdin.");
289
+ process.exit(1);
290
+ }
291
+ let input = "";
292
+ for await (const chunk of process.stdin) input += chunk;
293
+ let parsed;
294
+ try {
295
+ parsed = JSON.parse(input);
296
+ } catch {
297
+ console.error("[Suppressions] JSON input for '--entries' is not valid.");
298
+ process.exit(1);
299
+ }
300
+ if (!Array.isArray(parsed) || !parsed.every(isValidEntry)) {
301
+ console.error("[Suppressions] '--entries' must be a JSON array of suppression entries.");
302
+ process.exit(1);
303
+ }
304
+ return parsed;
305
+ }
306
+ if (!recipient) {
307
+ console.error("[Suppressions] Either '--entries' or '--recipient' is required.");
308
+ process.exit(1);
309
+ }
310
+ const entry = { recipient };
311
+ const parsedTypes = types?.split(",").map((type) => type.trim());
312
+ if (parsedTypes?.length) entry.types = parsedTypes;
313
+ if (notes) entry.notes = notes;
314
+ return [entry];
315
+ };
316
+ var create_default$1 = defineCommand({
317
+ meta: {
318
+ name: "create",
319
+ description: "Create suppression entries"
320
+ },
321
+ args: {
322
+ ...sharedArgs,
323
+ "recipient": {
324
+ type: "string",
325
+ valueHint: "address"
326
+ },
327
+ "types": {
328
+ type: "string",
329
+ valueHint: "types"
330
+ },
331
+ "notes": { type: "string" },
332
+ "entries": {
333
+ type: "boolean",
334
+ default: false
335
+ },
336
+ "add-to-sub-accounts": {
337
+ type: "boolean",
338
+ default: false
339
+ }
340
+ },
341
+ async run({ args }) {
342
+ const apiKey = getApiKey(args["api-key"]);
343
+ const client = new MailChannelsClient(apiKey);
344
+ const suppressions = new Suppressions(client);
345
+ const entries = await parseEntries(args["entries"], args["recipient"], args["types"], args["notes"]);
346
+ const { error } = await suppressions.create(entries, { addToSubAccounts: args["add-to-sub-accounts"] });
347
+ if (error) {
348
+ console.error(`[Suppressions] ${error.message}`);
349
+ process.exit(1);
350
+ }
351
+ console.info("[Suppressions] Suppression entries created successfully.");
352
+ }
353
+ });
354
+ var delete_default = defineCommand({
355
+ meta: {
356
+ name: "delete",
357
+ description: "Delete a suppression entry"
358
+ },
359
+ args: {
360
+ ...sharedArgs,
361
+ recipient: {
362
+ type: "string",
363
+ required: true,
364
+ valueHint: "address"
365
+ },
366
+ source: {
367
+ type: "string",
368
+ valueHint: "source"
369
+ }
370
+ },
371
+ async run({ args }) {
372
+ const apiKey = getApiKey(args["api-key"]);
373
+ const client = new MailChannelsClient(apiKey);
374
+ const { error } = await new Suppressions(client).delete(args["recipient"], args["source"]);
375
+ if (error) {
376
+ console.error(`[Suppressions] ${error.message}`);
377
+ process.exit(1);
378
+ }
379
+ console.info("[Suppressions] Suppression entry deleted successfully.");
380
+ }
381
+ });
382
+ const parsePagination = (limit, offset) => {
383
+ return {
384
+ limit: limit ? Number(limit) : void 0,
385
+ offset: offset ? Number(offset) : void 0
386
+ };
387
+ };
388
+ const escape = "\x1B";
389
+ const createStyle = (code, reset = 39) => (text) => {
390
+ return `${escape}[${code}m${text}${escape}[${reset}m`;
391
+ };
392
+ const styles = {
393
+ green: createStyle(32),
394
+ yellow: createStyle(33),
395
+ blue: createStyle(34),
396
+ underline: createStyle(4, 24)
397
+ };
398
+ const styleText = (format, text) => {
399
+ if (Array.isArray(format)) return format.reduceRight((styledText, currentFormat) => styles[currentFormat](styledText), text);
400
+ return styles[format](text);
401
+ };
402
+ const styleValue = (value) => {
403
+ if (Array.isArray(value)) return `[ ${value.map(styleValue).join(", ")} ]`;
404
+ if (value !== null && typeof value === "object") return `{ ${Object.entries(value).map(([key, nestedValue]) => `${key}: ${styleValue(nestedValue)}`).join(", ")} }`;
405
+ const text = String(value);
406
+ switch (typeof value) {
407
+ case "number":
408
+ case "boolean": return styleText("yellow", text);
409
+ case "string": return styleText("green", `'${text}'`);
410
+ default: return text;
411
+ }
412
+ };
413
+ const camelCaseToWords = (text) => {
414
+ return text.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase());
415
+ };
416
+ const toWordsKeys = (record) => {
417
+ if (Array.isArray(record)) return record.map((item) => typeof item === "object" && item !== null ? toWordsKeys(item) : item);
418
+ return Object.fromEntries(Object.entries(record).map(([key, value]) => [camelCaseToWords(key), typeof value === "object" && value !== null ? toWordsKeys(value) : value]));
419
+ };
420
+ const separatorChar = "─";
421
+ const separatorLength = 64;
422
+ const markerStart = 2;
423
+ const separator = separatorChar.repeat(separatorLength);
424
+ const separatorWithIndex = (index) => {
425
+ const marker = ` [${index}] `;
426
+ return separator.slice(0, markerStart) + marker + separator.slice(markerStart + marker.length);
427
+ };
428
+ const tabulate = (record) => {
429
+ const entries = Object.entries(toWordsKeys(record));
430
+ const labelWidth = Math.max(...entries.map(([label]) => label.length));
431
+ return entries.map(([label, value]) => ` ${label.padEnd(labelWidth + 2)}${styleValue(value)}`).join("\n");
432
+ };
433
+ const tabulatedSections = (records) => {
434
+ const isArray = Array.isArray(records);
435
+ const arr = isArray ? records : [records];
436
+ return arr.map((record, i) => {
437
+ const content = tabulate(record);
438
+ return `\n${isArray ? separatorWithIndex(i) : separator}\n${content}${i < arr.length - 1 ? "" : "\n" + separator}`;
439
+ }).join("");
440
+ };
441
+ var list_default$1 = defineCommand({
442
+ meta: {
443
+ name: "list",
444
+ description: "List suppression entries"
445
+ },
446
+ args: {
447
+ ...sharedArgs,
448
+ "recipient": {
449
+ type: "string",
450
+ valueHint: "address"
451
+ },
452
+ "source": {
453
+ type: "string",
454
+ valueHint: "source"
455
+ },
456
+ "created-after": {
457
+ type: "string",
458
+ valueHint: "datetime"
459
+ },
460
+ "created-before": {
461
+ type: "string",
462
+ valueHint: "datetime"
463
+ },
464
+ "limit": {
465
+ type: "string",
466
+ alias: "l",
467
+ valueHint: "number"
468
+ },
469
+ "offset": {
470
+ type: "string",
471
+ alias: "o",
472
+ valueHint: "number"
473
+ }
474
+ },
475
+ async run({ args }) {
476
+ const apiKey = getApiKey(args["api-key"]);
477
+ const client = new MailChannelsClient(apiKey);
478
+ const { data, error } = await new Suppressions(client).list({
479
+ recipient: args["recipient"],
480
+ source: args["source"],
481
+ createdAfter: args["created-after"],
482
+ createdBefore: args["created-before"],
483
+ ...parsePagination(args["limit"], args["offset"])
484
+ });
485
+ if (error) {
486
+ console.error(`[Suppressions] ${error.message}`);
487
+ process.exit(1);
488
+ }
489
+ if (!data.length) {
490
+ console.info("[Suppressions] No suppression entries found.");
491
+ return;
492
+ }
493
+ console.info("[Suppressions] Retrieved suppression entries:" + tabulatedSections(data));
494
+ console.info("[Suppressions] Total suppression entries retrieved:", data.length, `(with limit: ${styleText("yellow", args["limit"] ?? "1000")}, offset: ${styleText("yellow", args["offset"] ?? "0")})`);
495
+ }
496
+ });
497
+ var suppressions_default = defineCommand({
498
+ meta: {
499
+ name: "suppressions",
500
+ description: "Commands for managing suppression entries"
501
+ },
502
+ args: {},
503
+ subCommands: {
504
+ create: create_default$1,
505
+ delete: delete_default,
506
+ list: list_default$1
507
+ }
508
+ });
509
+ var create_default = defineCommand({
510
+ meta: {
511
+ name: "create",
512
+ description: "Enroll a new webhook endpoint"
513
+ },
514
+ args: {
515
+ ...sharedArgs,
516
+ endpoint: {
517
+ type: "string",
518
+ alias: "e",
519
+ required: true,
520
+ valueHint: "url"
521
+ }
522
+ },
523
+ async run({ args }) {
524
+ const apiKey = getApiKey(args["api-key"]);
525
+ const client = new MailChannelsClient(apiKey);
526
+ const { error } = await new Webhooks(client).create(args["endpoint"]);
527
+ if (error) {
528
+ console.error(`[Webhooks] ${error.message}`);
529
+ process.exit(1);
530
+ }
531
+ console.info("[Webhooks] Webhook created successfully.");
532
+ }
533
+ });
534
+ var delete_all_default = defineCommand({
535
+ meta: {
536
+ name: "delete-all",
537
+ description: "Delete all webhook endpoints"
538
+ },
539
+ args: { ...sharedArgs },
540
+ async run({ args }) {
541
+ const apiKey = getApiKey(args["api-key"]);
542
+ const client = new MailChannelsClient(apiKey);
543
+ const { error } = await new Webhooks(client).deleteAll();
544
+ if (error) {
545
+ console.error(`[Webhooks] ${error.message}`);
546
+ process.exit(1);
547
+ }
548
+ console.info("[Webhooks] All webhooks deleted successfully.");
549
+ }
550
+ });
551
+ var list_default = defineCommand({
552
+ meta: {
553
+ name: "list",
554
+ description: "List all webhook endpoints"
555
+ },
556
+ args: { ...sharedArgs },
557
+ async run({ args }) {
558
+ const apiKey = getApiKey(args["api-key"]);
559
+ const client = new MailChannelsClient(apiKey);
560
+ const { data, error } = await new Webhooks(client).list();
561
+ if (error) {
562
+ console.error(`[Webhooks] ${error.message}`);
563
+ process.exit(1);
564
+ }
565
+ if (!data.length) {
566
+ console.info("[Webhooks] No registered webhooks found.");
567
+ return;
568
+ }
569
+ console.info("[Webhooks] Registered webhook endpoints:");
570
+ console.table(toWordsKeys(data));
571
+ }
572
+ });
573
+ var batches_default = defineCommand({
574
+ meta: {
575
+ name: "batches",
576
+ description: "Retrieve paged webhook batches"
577
+ },
578
+ args: {
579
+ ...sharedArgs,
580
+ "created-after": {
581
+ type: "string",
582
+ valueHint: "datetime"
583
+ },
584
+ "created-before": {
585
+ type: "string",
586
+ valueHint: "datetime"
587
+ },
588
+ "statuses": {
589
+ type: "string",
590
+ alias: "s"
591
+ },
592
+ "webhook": {
593
+ type: "string",
594
+ alias: ["e", "endpoint"],
595
+ valueHint: "url"
596
+ },
597
+ "limit": {
598
+ type: "string",
599
+ alias: "l",
600
+ valueHint: "number"
601
+ },
602
+ "offset": {
603
+ type: "string",
604
+ alias: "o",
605
+ valueHint: "number"
606
+ }
607
+ },
608
+ async run({ args }) {
609
+ const apiKey = getApiKey(args["api-key"]);
610
+ const client = new MailChannelsClient(apiKey);
611
+ const { data, error } = await new Webhooks(client).batches({
612
+ createdAfter: args["created-after"],
613
+ createdBefore: args["created-before"],
614
+ statuses: args["statuses"]?.split(",").map((s) => s.trim()),
615
+ webhook: args["webhook"],
616
+ ...parsePagination(args["limit"], args["offset"])
617
+ });
618
+ if (error) {
619
+ console.error(`[Webhooks] ${error.message}`);
620
+ process.exit(1);
621
+ }
622
+ if (!data.length) {
623
+ console.info("[Webhooks] No webhook batches found.");
624
+ return;
625
+ }
626
+ console.info("[Webhooks] Retrieved webhook batches:" + tabulatedSections(data.map((batch) => ({
627
+ ...batch,
628
+ duration: batch.duration ? `${batch.duration.value} ${batch.duration.unit}` : ""
629
+ }))));
630
+ console.info("[Webhooks] Total batches retrieved:", data.length, `(with limit: ${styleText("yellow", args["limit"] ?? "500")}, offset: ${styleText("yellow", args["offset"] ?? "0")})`);
631
+ }
632
+ });
633
+ var resend_batch_default = defineCommand({
634
+ meta: {
635
+ name: "resend-batch",
636
+ description: "Resend a webhook batch"
637
+ },
638
+ args: {
639
+ ...sharedArgs,
640
+ "batch-id": {
641
+ type: "string",
642
+ alias: "b",
643
+ required: true,
644
+ valueHint: "id"
645
+ }
646
+ },
647
+ async run({ args }) {
648
+ const apiKey = getApiKey(args["api-key"]);
649
+ const client = new MailChannelsClient(apiKey);
650
+ const { data, error } = await new Webhooks(client).resendBatch(Number(args["batch-id"]));
651
+ if (error) {
652
+ console.error(`[Webhooks] ${error.message}`);
653
+ process.exit(1);
654
+ }
655
+ console.info("[Webhooks] Webhook batch resent:" + tabulatedSections(data));
656
+ }
657
+ });
658
+ var validate_default = defineCommand({
659
+ meta: {
660
+ name: "validate",
661
+ description: "Validate enrolled webhooks"
662
+ },
663
+ args: {
664
+ ...sharedArgs,
665
+ "request-id": {
666
+ type: "string",
667
+ alias: "r",
668
+ valueHint: "id"
669
+ }
670
+ },
671
+ async run({ args }) {
672
+ const apiKey = getApiKey(args["api-key"]);
673
+ const client = new MailChannelsClient(apiKey);
674
+ const { data, error } = await new Webhooks(client).validate(args["request-id"]);
675
+ if (error) {
676
+ console.error(`[Webhooks] ${error.message}`);
677
+ process.exit(1);
678
+ }
679
+ console.info("[Webhooks] Webhook validation result:");
680
+ console.table(toWordsKeys(data.results.map(({ result, webhook, response }) => ({
681
+ result,
682
+ webhook,
683
+ status: response?.status
684
+ }))));
685
+ console.info("[Webhooks] Total webhooks validated:", data.results.length, "all passed?:", data.allPassed);
686
+ }
687
+ });
688
+ var webhooks_default = defineCommand({
689
+ meta: {
690
+ name: "webhooks",
691
+ description: "Commands for managing webhooks"
692
+ },
693
+ args: {},
694
+ subCommands: {
695
+ create: create_default,
696
+ "delete-all": delete_all_default,
697
+ list: list_default,
698
+ batches: batches_default,
699
+ "resend-batch": resend_batch_default,
700
+ validate: validate_default
701
+ }
702
+ });
251
703
  const main = defineCommand({
252
704
  meta: {
253
705
  name,
@@ -256,11 +708,14 @@ const main = defineCommand({
256
708
  },
257
709
  subCommands: {
258
710
  simulate: simulate_default,
259
- emails: emails_default
711
+ emails: emails_default,
712
+ suppressions: suppressions_default,
713
+ webhooks: webhooks_default
260
714
  },
261
715
  setup() {
262
716
  const LOGGER_NAME = "[MailChannels-CLI]";
263
717
  console.info = console.info.bind(console, LOGGER_NAME);
718
+ console.warn = console.warn.bind(console, LOGGER_NAME);
264
719
  console.error = console.error.bind(console, LOGGER_NAME);
265
720
  }
266
721
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mailchannels-sdk",
3
- "version": "1.6.0",
4
- "description": "Node.js SDK to integrate MailChannels Email API into your JavaScript or TypeScript server-side applications.",
3
+ "version": "1.7.0",
4
+ "description": "Official MailChannels Email API SDK for sending transactional email from server-side JavaScript and TypeScript applications.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -9,13 +9,16 @@
9
9
  "typescript",
10
10
  "email",
11
11
  "transactional-email",
12
- "sdk"
12
+ "sdk",
13
+ "email-api",
14
+ "javascript",
15
+ "nodejs"
13
16
  ],
14
17
  "repository": {
15
18
  "type": "git",
16
19
  "url": "git+https://bitbucket.org/mailchannels/mailchannels-email-api-sdk-js.git"
17
20
  },
18
- "homepage": "https://mailchannels.yizack.com",
21
+ "homepage": "https://docs.mailchannels.com/email-api/javascript/quickstart",
19
22
  "author": {
20
23
  "name": "MailChannels",
21
24
  "email": "dev@mailchannels.com"
@@ -52,18 +55,18 @@
52
55
  "devDependencies": {
53
56
  "@stylistic/eslint-plugin": "^5.10.0",
54
57
  "@types/markdown-it": "^14.2.0",
55
- "@types/node": "^26.5.0",
56
- "@vitest/coverage-v8": "^5.0.0",
58
+ "@types/node": "^26.6.3",
59
+ "@vitest/coverage-v8": "^5.0.3",
57
60
  "changelogen": "^0.6.2",
58
- "nodemailer": "^10.0.1",
59
- "obuild": "^0.4.39",
60
- "oxlint": "^1.82.0",
61
+ "nodemailer": "^10.0.13",
62
+ "obuild": "^0.4.43",
63
+ "oxlint": "^1.86.0",
61
64
  "scule": "^1.3.0",
62
65
  "typescript": "^6.0.3",
63
66
  "vitepress": "^2.0.0-alpha.20",
64
67
  "vitepress-plugin-group-icons": "^1.7.6",
65
- "vitepress-plugin-llms": "^1.13.5",
66
- "vitest": "^5.0.0"
68
+ "vitepress-plugin-llms": "^1.14.0",
69
+ "vitest": "^5.0.3"
67
70
  },
68
71
  "engines": {
69
72
  "node": ">=20"