mikromail 0.0.7 → 1.0.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
@@ -89,6 +89,49 @@ const emailOptions = {
89
89
  await new MikroMail({ config }).send(emailOptions);
90
90
  ```
91
91
 
92
+ ## Provider-specific configurations
93
+
94
+ ### Proton Mail
95
+
96
+ Proton Mail works reliably with port 465 and implicit TLS:
97
+
98
+ ```typescript
99
+ const config = {
100
+ user: 'your-email@proton.me',
101
+ password: 'YOUR_APP_PASSWORD',
102
+ host: 'smtp.protonmail.ch',
103
+ port: 465,
104
+ secure: true
105
+ };
106
+ ```
107
+
108
+ Note: Port 587 with STARTTLS (`secure: false`) may have connectivity issues with some Proton Mail configurations. Use port 465 for the most reliable connection.
109
+
110
+ ### Test providers (Mailtrap, etc.)
111
+
112
+ Some test SMTP providers use long random IDs instead of email addresses. To support these providers, use the `skipEmailValidation` and `skipMXRecordCheck` options:
113
+
114
+ ```typescript
115
+ const config = {
116
+ user: 'your-mailtrap-username',
117
+ password: 'your-mailtrap-password',
118
+ host: 'smtp.mailtrap.io',
119
+ port: 587,
120
+ secure: false,
121
+ skipEmailValidation: true,
122
+ skipMXRecordCheck: true
123
+ };
124
+
125
+ const emailOptions = {
126
+ from: 'sender@example.com',
127
+ subject: 'Test Email',
128
+ text: 'Hello!',
129
+ to: 'a1b2c3d4e5f6g7' // Long random ID used by test providers
130
+ };
131
+
132
+ await new MikroMail({ config }).send(emailOptions);
133
+ ```
134
+
92
135
  ## Testing
93
136
 
94
137
  Some of the tests require faking an SMTP server. Here we use [Mailpit](https://github.com/axllent/mailpit), which will run a server on `http://localhost:8025`.
@@ -67,7 +67,9 @@ var Configuration = class {
67
67
  port: 465,
68
68
  secure: true,
69
69
  debug: false,
70
- maxRetries: 2
70
+ maxRetries: 2,
71
+ skipEmailValidation: false,
72
+ skipMXRecordCheck: false
71
73
  };
72
74
  let fileConfig = {};
73
75
  if ((0, import_node_fs.existsSync)(configFilePath)) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Configuration
3
- } from "./chunk-YVXB6HCK.mjs";
3
+ } from "./chunk-ULVDQIAT.mjs";
4
4
  import "./chunk-47VXJTWV.mjs";
5
5
  export {
6
6
  Configuration
@@ -20,6 +20,7 @@ import { ConfigurationOptions, EmailOptions } from './interfaces/index.mjs';
20
20
  */
21
21
  declare class MikroMail {
22
22
  private readonly smtpClient;
23
+ private readonly config;
23
24
  constructor(options?: ConfigurationOptions);
24
25
  /**
25
26
  * Sends an email to valid domains.
@@ -20,6 +20,7 @@ import { ConfigurationOptions, EmailOptions } from './interfaces/index.js';
20
20
  */
21
21
  declare class MikroMail {
22
22
  private readonly smtpClient;
23
+ private readonly config;
23
24
  constructor(options?: ConfigurationOptions);
24
25
  /**
25
26
  * Sends an email to valid domains.
package/lib/MikroMail.js CHANGED
@@ -79,7 +79,9 @@ var Configuration = class {
79
79
  port: 465,
80
80
  secure: true,
81
81
  debug: false,
82
- maxRetries: 2
82
+ maxRetries: 2,
83
+ skipEmailValidation: false,
84
+ skipMXRecordCheck: false
83
85
  };
84
86
  let fileConfig = {};
85
87
  if ((0, import_node_fs.existsSync)(configFilePath)) {
@@ -189,7 +191,7 @@ function validateEmail(email) {
189
191
  return false;
190
192
  for (const part of domainParts) {
191
193
  if (!part || part.length > 63) return false;
192
- if (!/^[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?$/.test(part)) return false;
194
+ if (!/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/.test(part)) return false;
193
195
  }
194
196
  return true;
195
197
  } catch (_error) {
@@ -237,7 +239,9 @@ var SMTPClient = class {
237
239
  clientName: config.clientName ?? import_node_os.default.hostname(),
238
240
  maxRetries: config.maxRetries ?? 3,
239
241
  retryDelay: config.retryDelay ?? 1e3,
240
- skipAuthentication: config.skipAuthentication || false
242
+ skipAuthentication: config.skipAuthentication || false,
243
+ skipEmailValidation: config.skipEmailValidation || false,
244
+ skipMXRecordCheck: config.skipMXRecordCheck || false
241
245
  };
242
246
  this.socket = null;
243
247
  this.connected = false;
@@ -642,20 +646,24 @@ ${text || ""}`;
642
646
  error: "Missing required email parameters (from, to, subject, and either text or html)"
643
647
  };
644
648
  }
645
- if (!validateEmail(from)) {
646
- return {
647
- success: false,
648
- error: "Invalid email address format"
649
- };
650
- }
651
649
  const recipients = Array.isArray(options.to) ? options.to : [options.to];
652
- for (const recipient of recipients) {
653
- if (!validateEmail(recipient)) {
650
+ if (!this.config.skipEmailValidation) {
651
+ if (!validateEmail(from)) {
654
652
  return {
655
653
  success: false,
656
- error: `Invalid recipient email address format: ${recipient}`
654
+ error: "Invalid email address format"
657
655
  };
658
656
  }
657
+ for (const recipient of recipients) {
658
+ if (!validateEmail(recipient)) {
659
+ return {
660
+ success: false,
661
+ error: `Invalid recipient email address format: ${recipient}`
662
+ };
663
+ }
664
+ }
665
+ } else {
666
+ this.log("Email validation skipped (testing mode)");
659
667
  }
660
668
  for (this.retryCount = 0; this.retryCount <= this.config.maxRetries; this.retryCount++) {
661
669
  try {
@@ -754,10 +762,12 @@ ${text || ""}`;
754
762
  // src/MikroMail.ts
755
763
  var MikroMail = class {
756
764
  smtpClient;
765
+ config;
757
766
  constructor(options) {
758
767
  const config = new Configuration(options).get();
759
768
  const smtpClient = new SMTPClient(config);
760
769
  this.smtpClient = smtpClient;
770
+ this.config = config;
761
771
  }
762
772
  /**
763
773
  * Sends an email to valid domains.
@@ -765,12 +775,14 @@ var MikroMail = class {
765
775
  async send(emailOptions) {
766
776
  try {
767
777
  const recipients = Array.isArray(emailOptions.to) ? emailOptions.to : [emailOptions.to];
768
- for (const recipient of recipients) {
769
- const hasMXRecords = await verifyEmailDomain(recipient);
770
- if (!hasMXRecords)
771
- console.error(
772
- `Warning: No MX records found for recipient domain: ${recipient}`
773
- );
778
+ if (!this.config.skipMXRecordCheck) {
779
+ for (const recipient of recipients) {
780
+ const hasMXRecords = await verifyEmailDomain(recipient);
781
+ if (!hasMXRecords)
782
+ console.error(
783
+ `Warning: No MX records found for recipient domain: ${recipient}`
784
+ );
785
+ }
774
786
  }
775
787
  const result = await this.smtpClient.sendEmail(emailOptions);
776
788
  if (result.success) console.log(`Message ID: ${result.messageId}`);
package/lib/MikroMail.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  MikroMail
3
- } from "./chunk-422R3NOG.mjs";
4
- import "./chunk-YVXB6HCK.mjs";
5
- import "./chunk-NGT3KX7A.mjs";
3
+ } from "./chunk-IYCQK5YZ.mjs";
4
+ import "./chunk-ULVDQIAT.mjs";
5
+ import "./chunk-QCFOUQRH.mjs";
6
6
  import "./chunk-47VXJTWV.mjs";
7
- import "./chunk-UDLJWUFN.mjs";
7
+ import "./chunk-5BK3VY6I.mjs";
8
8
  export {
9
9
  MikroMail
10
10
  };
package/lib/SMTPClient.js CHANGED
@@ -62,7 +62,7 @@ function validateEmail(email) {
62
62
  return false;
63
63
  for (const part of domainParts) {
64
64
  if (!part || part.length > 63) return false;
65
- if (!/^[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?$/.test(part)) return false;
65
+ if (!/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/.test(part)) return false;
66
66
  }
67
67
  return true;
68
68
  } catch (_error) {
@@ -93,7 +93,9 @@ var SMTPClient = class {
93
93
  clientName: config.clientName ?? import_node_os.default.hostname(),
94
94
  maxRetries: config.maxRetries ?? 3,
95
95
  retryDelay: config.retryDelay ?? 1e3,
96
- skipAuthentication: config.skipAuthentication || false
96
+ skipAuthentication: config.skipAuthentication || false,
97
+ skipEmailValidation: config.skipEmailValidation || false,
98
+ skipMXRecordCheck: config.skipMXRecordCheck || false
97
99
  };
98
100
  this.socket = null;
99
101
  this.connected = false;
@@ -498,20 +500,24 @@ ${text || ""}`;
498
500
  error: "Missing required email parameters (from, to, subject, and either text or html)"
499
501
  };
500
502
  }
501
- if (!validateEmail(from)) {
502
- return {
503
- success: false,
504
- error: "Invalid email address format"
505
- };
506
- }
507
503
  const recipients = Array.isArray(options.to) ? options.to : [options.to];
508
- for (const recipient of recipients) {
509
- if (!validateEmail(recipient)) {
504
+ if (!this.config.skipEmailValidation) {
505
+ if (!validateEmail(from)) {
510
506
  return {
511
507
  success: false,
512
- error: `Invalid recipient email address format: ${recipient}`
508
+ error: "Invalid email address format"
513
509
  };
514
510
  }
511
+ for (const recipient of recipients) {
512
+ if (!validateEmail(recipient)) {
513
+ return {
514
+ success: false,
515
+ error: `Invalid recipient email address format: ${recipient}`
516
+ };
517
+ }
518
+ }
519
+ } else {
520
+ this.log("Email validation skipped (testing mode)");
515
521
  }
516
522
  for (this.retryCount = 0; this.retryCount <= this.config.maxRetries; this.retryCount++) {
517
523
  try {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SMTPClient
3
- } from "./chunk-NGT3KX7A.mjs";
4
- import "./chunk-UDLJWUFN.mjs";
3
+ } from "./chunk-QCFOUQRH.mjs";
4
+ import "./chunk-5BK3VY6I.mjs";
5
5
  export {
6
6
  SMTPClient
7
7
  };
@@ -1,5 +1,5 @@
1
1
  // src/utils/index.ts
2
- import { promises as dnsPromises } from "node:dns";
2
+ import { promises as dnsPromises } from "dns";
3
3
  function encodeQuotedPrintable(text) {
4
4
  let result = text.replace(/\r?\n/g, "\r\n");
5
5
  result = result.replace(/=/g, "=3D");
@@ -50,7 +50,7 @@ function validateEmail(email) {
50
50
  return false;
51
51
  for (const part of domainParts) {
52
52
  if (!part || part.length > 63) return false;
53
- if (!/^[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?$/.test(part)) return false;
53
+ if (!/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/.test(part)) return false;
54
54
  }
55
55
  return true;
56
56
  } catch (_error) {
@@ -1,20 +1,22 @@
1
1
  import {
2
2
  Configuration
3
- } from "./chunk-YVXB6HCK.mjs";
3
+ } from "./chunk-ULVDQIAT.mjs";
4
4
  import {
5
5
  SMTPClient
6
- } from "./chunk-NGT3KX7A.mjs";
6
+ } from "./chunk-QCFOUQRH.mjs";
7
7
  import {
8
8
  verifyEmailDomain
9
- } from "./chunk-UDLJWUFN.mjs";
9
+ } from "./chunk-5BK3VY6I.mjs";
10
10
 
11
11
  // src/MikroMail.ts
12
12
  var MikroMail = class {
13
13
  smtpClient;
14
+ config;
14
15
  constructor(options) {
15
16
  const config = new Configuration(options).get();
16
17
  const smtpClient = new SMTPClient(config);
17
18
  this.smtpClient = smtpClient;
19
+ this.config = config;
18
20
  }
19
21
  /**
20
22
  * Sends an email to valid domains.
@@ -22,12 +24,14 @@ var MikroMail = class {
22
24
  async send(emailOptions) {
23
25
  try {
24
26
  const recipients = Array.isArray(emailOptions.to) ? emailOptions.to : [emailOptions.to];
25
- for (const recipient of recipients) {
26
- const hasMXRecords = await verifyEmailDomain(recipient);
27
- if (!hasMXRecords)
28
- console.error(
29
- `Warning: No MX records found for recipient domain: ${recipient}`
30
- );
27
+ if (!this.config.skipMXRecordCheck) {
28
+ for (const recipient of recipients) {
29
+ const hasMXRecords = await verifyEmailDomain(recipient);
30
+ if (!hasMXRecords)
31
+ console.error(
32
+ `Warning: No MX records found for recipient domain: ${recipient}`
33
+ );
34
+ }
31
35
  }
32
36
  const result = await this.smtpClient.sendEmail(emailOptions);
33
37
  if (result.success) console.log(`Message ID: ${result.messageId}`);
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  validateEmail
3
- } from "./chunk-UDLJWUFN.mjs";
3
+ } from "./chunk-5BK3VY6I.mjs";
4
4
 
5
5
  // src/SMTPClient.ts
6
- import { Buffer } from "node:buffer";
7
- import crypto from "node:crypto";
8
- import net from "node:net";
9
- import os from "node:os";
10
- import tls from "node:tls";
6
+ import { Buffer } from "buffer";
7
+ import crypto from "crypto";
8
+ import net from "net";
9
+ import os from "os";
10
+ import tls from "tls";
11
11
  var SMTPClient = class {
12
12
  config;
13
13
  socket;
@@ -30,7 +30,9 @@ var SMTPClient = class {
30
30
  clientName: config.clientName ?? os.hostname(),
31
31
  maxRetries: config.maxRetries ?? 3,
32
32
  retryDelay: config.retryDelay ?? 1e3,
33
- skipAuthentication: config.skipAuthentication || false
33
+ skipAuthentication: config.skipAuthentication || false,
34
+ skipEmailValidation: config.skipEmailValidation || false,
35
+ skipMXRecordCheck: config.skipMXRecordCheck || false
34
36
  };
35
37
  this.socket = null;
36
38
  this.connected = false;
@@ -435,20 +437,24 @@ ${text || ""}`;
435
437
  error: "Missing required email parameters (from, to, subject, and either text or html)"
436
438
  };
437
439
  }
438
- if (!validateEmail(from)) {
439
- return {
440
- success: false,
441
- error: "Invalid email address format"
442
- };
443
- }
444
440
  const recipients = Array.isArray(options.to) ? options.to : [options.to];
445
- for (const recipient of recipients) {
446
- if (!validateEmail(recipient)) {
441
+ if (!this.config.skipEmailValidation) {
442
+ if (!validateEmail(from)) {
447
443
  return {
448
444
  success: false,
449
- error: `Invalid recipient email address format: ${recipient}`
445
+ error: "Invalid email address format"
450
446
  };
451
447
  }
448
+ for (const recipient of recipients) {
449
+ if (!validateEmail(recipient)) {
450
+ return {
451
+ success: false,
452
+ error: `Invalid recipient email address format: ${recipient}`
453
+ };
454
+ }
455
+ }
456
+ } else {
457
+ this.log("Email validation skipped (testing mode)");
452
458
  }
453
459
  for (this.retryCount = 0; this.retryCount <= this.config.maxRetries; this.retryCount++) {
454
460
  try {
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-47VXJTWV.mjs";
4
4
 
5
5
  // src/Configuration.ts
6
- import { existsSync, readFileSync } from "node:fs";
6
+ import { existsSync, readFileSync } from "fs";
7
7
  var Configuration = class {
8
8
  config;
9
9
  defaults = {
@@ -35,7 +35,9 @@ var Configuration = class {
35
35
  port: 465,
36
36
  secure: true,
37
37
  debug: false,
38
- maxRetries: 2
38
+ maxRetries: 2,
39
+ skipEmailValidation: false,
40
+ skipMXRecordCheck: false
39
41
  };
40
42
  let fileConfig = {};
41
43
  if (existsSync(configFilePath)) {
package/lib/index.js CHANGED
@@ -79,7 +79,9 @@ var Configuration = class {
79
79
  port: 465,
80
80
  secure: true,
81
81
  debug: false,
82
- maxRetries: 2
82
+ maxRetries: 2,
83
+ skipEmailValidation: false,
84
+ skipMXRecordCheck: false
83
85
  };
84
86
  let fileConfig = {};
85
87
  if ((0, import_node_fs.existsSync)(configFilePath)) {
@@ -189,7 +191,7 @@ function validateEmail(email) {
189
191
  return false;
190
192
  for (const part of domainParts) {
191
193
  if (!part || part.length > 63) return false;
192
- if (!/^[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?$/.test(part)) return false;
194
+ if (!/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/.test(part)) return false;
193
195
  }
194
196
  return true;
195
197
  } catch (_error) {
@@ -237,7 +239,9 @@ var SMTPClient = class {
237
239
  clientName: config.clientName ?? import_node_os.default.hostname(),
238
240
  maxRetries: config.maxRetries ?? 3,
239
241
  retryDelay: config.retryDelay ?? 1e3,
240
- skipAuthentication: config.skipAuthentication || false
242
+ skipAuthentication: config.skipAuthentication || false,
243
+ skipEmailValidation: config.skipEmailValidation || false,
244
+ skipMXRecordCheck: config.skipMXRecordCheck || false
241
245
  };
242
246
  this.socket = null;
243
247
  this.connected = false;
@@ -642,20 +646,24 @@ ${text || ""}`;
642
646
  error: "Missing required email parameters (from, to, subject, and either text or html)"
643
647
  };
644
648
  }
645
- if (!validateEmail(from)) {
646
- return {
647
- success: false,
648
- error: "Invalid email address format"
649
- };
650
- }
651
649
  const recipients = Array.isArray(options.to) ? options.to : [options.to];
652
- for (const recipient of recipients) {
653
- if (!validateEmail(recipient)) {
650
+ if (!this.config.skipEmailValidation) {
651
+ if (!validateEmail(from)) {
654
652
  return {
655
653
  success: false,
656
- error: `Invalid recipient email address format: ${recipient}`
654
+ error: "Invalid email address format"
657
655
  };
658
656
  }
657
+ for (const recipient of recipients) {
658
+ if (!validateEmail(recipient)) {
659
+ return {
660
+ success: false,
661
+ error: `Invalid recipient email address format: ${recipient}`
662
+ };
663
+ }
664
+ }
665
+ } else {
666
+ this.log("Email validation skipped (testing mode)");
659
667
  }
660
668
  for (this.retryCount = 0; this.retryCount <= this.config.maxRetries; this.retryCount++) {
661
669
  try {
@@ -754,10 +762,12 @@ ${text || ""}`;
754
762
  // src/MikroMail.ts
755
763
  var MikroMail = class {
756
764
  smtpClient;
765
+ config;
757
766
  constructor(options) {
758
767
  const config = new Configuration(options).get();
759
768
  const smtpClient = new SMTPClient(config);
760
769
  this.smtpClient = smtpClient;
770
+ this.config = config;
761
771
  }
762
772
  /**
763
773
  * Sends an email to valid domains.
@@ -765,12 +775,14 @@ var MikroMail = class {
765
775
  async send(emailOptions) {
766
776
  try {
767
777
  const recipients = Array.isArray(emailOptions.to) ? emailOptions.to : [emailOptions.to];
768
- for (const recipient of recipients) {
769
- const hasMXRecords = await verifyEmailDomain(recipient);
770
- if (!hasMXRecords)
771
- console.error(
772
- `Warning: No MX records found for recipient domain: ${recipient}`
773
- );
778
+ if (!this.config.skipMXRecordCheck) {
779
+ for (const recipient of recipients) {
780
+ const hasMXRecords = await verifyEmailDomain(recipient);
781
+ if (!hasMXRecords)
782
+ console.error(
783
+ `Warning: No MX records found for recipient domain: ${recipient}`
784
+ );
785
+ }
774
786
  }
775
787
  const result = await this.smtpClient.sendEmail(emailOptions);
776
788
  if (result.success) console.log(`Message ID: ${result.messageId}`);
package/lib/index.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  MikroMail
3
- } from "./chunk-422R3NOG.mjs";
4
- import "./chunk-YVXB6HCK.mjs";
5
- import "./chunk-NGT3KX7A.mjs";
3
+ } from "./chunk-IYCQK5YZ.mjs";
4
+ import "./chunk-ULVDQIAT.mjs";
5
+ import "./chunk-QCFOUQRH.mjs";
6
6
  import "./chunk-47VXJTWV.mjs";
7
- import "./chunk-UDLJWUFN.mjs";
7
+ import "./chunk-5BK3VY6I.mjs";
8
8
  export {
9
9
  MikroMail
10
10
  };
@@ -13,6 +13,8 @@ interface SMTPConfiguration {
13
13
  maxRetries?: number;
14
14
  retryDelay?: number;
15
15
  skipAuthentication?: boolean;
16
+ skipEmailValidation?: boolean;
17
+ skipMXRecordCheck?: boolean;
16
18
  }
17
19
  /**
18
20
  * Email sending options.
@@ -13,6 +13,8 @@ interface SMTPConfiguration {
13
13
  maxRetries?: number;
14
14
  retryDelay?: number;
15
15
  skipAuthentication?: boolean;
16
+ skipEmailValidation?: boolean;
17
+ skipMXRecordCheck?: boolean;
16
18
  }
17
19
  /**
18
20
  * Email sending options.
@@ -77,7 +77,7 @@ function validateEmail(email) {
77
77
  return false;
78
78
  for (const part of domainParts) {
79
79
  if (!part || part.length > 63) return false;
80
- if (!/^[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?$/.test(part)) return false;
80
+ if (!/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/.test(part)) return false;
81
81
  }
82
82
  return true;
83
83
  } catch (_error) {
@@ -3,7 +3,7 @@ import {
3
3
  validateEmail,
4
4
  verifyEmailDomain,
5
5
  verifyMXRecords
6
- } from "../chunk-UDLJWUFN.mjs";
6
+ } from "../chunk-5BK3VY6I.mjs";
7
7
  export {
8
8
  encodeQuotedPrintable,
9
9
  validateEmail,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mikromail",
3
3
  "description": "Lightweight replacement for Nodemailer, supporting HTML, international symbols, and more.",
4
- "version": "0.0.7",
4
+ "version": "1.0.0",
5
5
  "author": "Mikael Vesavuori",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -31,7 +31,6 @@
31
31
  ],
32
32
  "scripts": {
33
33
  "test": "npm run test:licenses && npm run test:types && npm run lint && npm run test:unit",
34
- "test:data": "rm -rf test-db && npx tsx random-data.ts",
35
34
  "test:types": "npx type-coverage --at-least 95 --strict --ignore-files \"tests/**/*.ts\" --ignore-files \"*.ts\" --ignore-files \"src/errors/*.ts\" --ignore-files \"testdata/*.ts\"",
36
35
  "test:licenses": "npx license-compliance --direct --allow 'MIT;ISC;0BSD;BSD-2-Clause;BSD-3-Clause;Apache-2.0;Unlicense;CC0-1.0'",
37
36
  "test:unit": "npx vitest run --coverage",
@@ -45,9 +44,9 @@
45
44
  "prepare": "husky"
46
45
  },
47
46
  "devDependencies": {
48
- "@biomejs/biome": "1",
47
+ "@biomejs/biome": "2",
49
48
  "@types/node": "latest",
50
- "@vitest/coverage-v8": "2",
49
+ "@vitest/coverage-v8": "4",
51
50
  "husky": "9",
52
51
  "license-compliance": "latest",
53
52
  "tslib": "latest",
@@ -55,6 +54,6 @@
55
54
  "tsx": "latest",
56
55
  "type-coverage": "2",
57
56
  "typescript": "5",
58
- "vitest": "2"
57
+ "vitest": "4"
59
58
  }
60
59
  }