@naiv/mta 0.0.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/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # NAIV Mail Transfer Agent
2
+
3
+ Mail Transfer Agent in pure NodeJS with no dependency.
4
+
5
+ ## Usage Example
6
+
7
+ ```ts
8
+ import { createAttachmentFromUri, EmailParams, sendEmail } from "./mta";
9
+ import fs from 'fs';
10
+
11
+ async function main() {
12
+ const privateKey = fs.readFileSync('./dkim_private.pem', 'utf8');
13
+ const param: EmailParams = {
14
+ from: "admin9@org.naiv.dev",
15
+ to: ["test-75vgkjs3e@srv1.mail-tester.com"],
16
+ subject: "Last Meeting Notes (5)",
17
+ text: "This is our last meeting notes, please read all our deals for tomorrow events, dont miss any details. Regards",
18
+ html: "<div><b>This</b> is our last <i>meeting notes</i>, please read all our deals for tomorrow events, dont miss any details. <u>Regards</u></div>",
19
+ attachments: [await createAttachmentFromUri('./meeting-notes.txt')],
20
+ dkimOptions: {
21
+ domain: "org.naiv.dev",
22
+ selector: "graf",
23
+ privateKey
24
+ }
25
+ };
26
+ return await sendEmail(param);
27
+ }
28
+
29
+ main().then(console.log).catch(console.error).finally(() => process.exit(0));
30
+ ```
@@ -0,0 +1,81 @@
1
+ /**
2
+ * IMPLEMENT THIS: This is your hook for greylisting/retry logic.
3
+ * In a real system, you would save this to a database (PostgreSQL/Redis)
4
+ * and trigger a background job to run again in 15-30 minutes.
5
+ */
6
+ export type HandleRetryFn = (params: EmailParams, smtpError: string, attemptCount: number) => Promise<void>;
7
+ /**
8
+ * Interface representing an email attachment.
9
+ * Based on RFC 2045 (MIME) and RFC 2183 (Content-Disposition).
10
+ */
11
+ export interface Attachment {
12
+ /**
13
+ * The name of the file as it will appear in the recipient's email client.
14
+ * RFC 2183: Will be encoded into the 'filename' parameter of Content-Disposition.
15
+ */
16
+ filename: string;
17
+ /**
18
+ * The actual binary data of the file.
19
+ * Security: This is converted to Base64 in DATA_START to ensure 7-bit SMTP safety.
20
+ */
21
+ content: Buffer;
22
+ /**
23
+ * The MIME type (e.g., 'application/pdf', 'image/png').
24
+ * RFC 2045: Defaults to 'application/octet-stream' if not provided.
25
+ */
26
+ contentType: string;
27
+ /**
28
+ * Optional: Content-ID for inline images.
29
+ * RFC 2392: Used to reference an attachment within HTML via <img src="cid:unique-id">.
30
+ */
31
+ cid?: string;
32
+ }
33
+ export interface DKIMOptions {
34
+ domain: string;
35
+ selector: string;
36
+ privateKey: string;
37
+ }
38
+ export interface EmailParams {
39
+ from: string;
40
+ to: string | string[];
41
+ subject: string;
42
+ text?: string;
43
+ html?: string;
44
+ attachments?: Attachment[];
45
+ dkimOptions: DKIMOptions;
46
+ customHeaders?: Record<string, string>;
47
+ attemptCount?: number;
48
+ requireTLS?: boolean;
49
+ }
50
+ export interface SendResult {
51
+ domain: string;
52
+ recipients: string[];
53
+ status: string;
54
+ error?: string;
55
+ }
56
+ export interface SendResultComplete {
57
+ result: SendResult[];
58
+ error?: string;
59
+ }
60
+ /**
61
+ * Helper to create an Attachment object from a URI (Local path or Remote URL).
62
+ * Handles binary safety and MIME type guessing.
63
+ */
64
+ export declare function createAttachmentFromUri(uri: string, customFilename?: string): Promise<Attachment>;
65
+ /** --- Utilities (Encoders) --- */
66
+ /**
67
+ * RFC 5321 Section 4.1.2: Email address validation.
68
+ * Validates both local-part and domain syntax to prevent crashes and injection attacks.
69
+ */
70
+ export declare function validateEmailAddress(email: string): boolean;
71
+ export declare function encodeHeaderValue(value: string): string;
72
+ export declare function encodeQuotedPrintable(body: string): string;
73
+ /** --- Main SMTP Function --- */
74
+ /**
75
+ * Helper: Groups recipients by domain to optimize SMTP connections.
76
+ * Returns a Map where Key = Domain, Value = Array of recipients.
77
+ */
78
+ export declare function groupRecipients(recipients: string[]): Map<string, string[]>;
79
+ /** --- Main Exported Function --- */
80
+ export declare function sendEmail(params: EmailParams, handleRetry?: HandleRetryFn): Promise<SendResultComplete>;
81
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE5G;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,UAAU,EAAE,CAAA;IAC1B,WAAW,EAAE,WAAW,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,UAAU,EAAE,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AA+BD;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAoEvG;AAsBD,mCAAmC;AAEnC;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAgB3D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA6BvD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA4C1D;AAED,iCAAiC;AAGjC;;;GAGG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAc3E;AAubD,qCAAqC;AAErC,wBAAsB,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA6C7G"}
package/dist/index.js ADDED
@@ -0,0 +1,694 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.createAttachmentFromUri = createAttachmentFromUri;
40
+ exports.validateEmailAddress = validateEmailAddress;
41
+ exports.encodeHeaderValue = encodeHeaderValue;
42
+ exports.encodeQuotedPrintable = encodeQuotedPrintable;
43
+ exports.groupRecipients = groupRecipients;
44
+ exports.sendEmail = sendEmail;
45
+ const dns = __importStar(require("dns"));
46
+ const net = __importStar(require("net"));
47
+ const crypto = __importStar(require("crypto"));
48
+ const tls = __importStar(require("tls"));
49
+ const promises_1 = __importDefault(require("node:fs/promises"));
50
+ const node_path_1 = __importDefault(require("node:path"));
51
+ /**
52
+ * RFC 5322 Section 2.2: Header fields can technically appear in any order.
53
+ * However, this static order serves two critical 2026 Deliverability functions:
54
+ */
55
+ const HEADER_ORDER = [
56
+ // RFC 6376 (DKIM): It is "Best Practice" to place the signature first or
57
+ // near the top to ensure the receiving MTA identifies the mail as signed
58
+ // before processing heavy MIME parts.
59
+ 'DKIM-Signature',
60
+ // RFC 5322 Section 3.6: Mandatory 'Originator' and 'Destination' fields.
61
+ 'From', 'To', 'Subject', 'Date', 'Message-ID',
62
+ // RFC 2045 (MIME): These define how the body should be interpreted.
63
+ // Grouping them prevents "Header Fragmentation" where a relay might
64
+ // inject its own headers in between yours.
65
+ 'MIME-Version', 'Content-Type', 'Content-Transfer-Encoding',
66
+ // RFC 2369 & RFC 8058: Deliverability requirements for 2026.
67
+ // Gmail and Yahoo require 'List-Unsubscribe' for "One-Click" compliance.
68
+ // Placing these consistently prevents them from being "buried" or
69
+ // stripped by intermediate security appliances.
70
+ 'List-Unsubscribe', 'List-Unsubscribe-Post',
71
+ // RFC 2076 / Common Practice: Identifies this as automated/bulk mail.
72
+ // This lowers the "Spam Score" by being honest about the mail type.
73
+ 'Precedence'
74
+ ];
75
+ /**
76
+ * Helper to create an Attachment object from a URI (Local path or Remote URL).
77
+ * Handles binary safety and MIME type guessing.
78
+ */
79
+ async function createAttachmentFromUri(uri, customFilename) {
80
+ let content;
81
+ let filename;
82
+ // Security: Maximum attachment size (25MB default, prevents resource exhaustion)
83
+ const MAX_ATTACHMENT_SIZE = 25 * 1024 * 1024;
84
+ if (uri.startsWith('http://') || uri.startsWith('https://')) {
85
+ // --- REMOTE URL ---
86
+ // Security: Validate URL to prevent SSRF (Server-Side Request Forgery) attacks
87
+ const url = new URL(uri);
88
+ // Security: Block private IP ranges and localhost to prevent internal network scanning
89
+ const hostname = url.hostname.toLowerCase();
90
+ if (hostname === 'localhost' ||
91
+ hostname === '127.0.0.1' ||
92
+ hostname.startsWith('192.168.') ||
93
+ hostname.startsWith('10.') ||
94
+ hostname.startsWith('172.16.') ||
95
+ hostname.startsWith('172.17.') ||
96
+ hostname.startsWith('172.18.') ||
97
+ hostname.startsWith('172.19.') ||
98
+ hostname.startsWith('172.2') ||
99
+ hostname.startsWith('172.30.') ||
100
+ hostname.startsWith('172.31.') ||
101
+ hostname === '::1' ||
102
+ hostname.startsWith('fe80:')) {
103
+ throw new Error(`SSRF_BLOCKED: Cannot fetch attachments from private IP ranges or localhost`);
104
+ }
105
+ const response = await fetch(uri);
106
+ if (!response.ok)
107
+ throw new Error(`Failed to fetch attachment: ${response.statusText}`);
108
+ const arrayBuffer = await response.arrayBuffer();
109
+ content = Buffer.from(arrayBuffer);
110
+ // Security: Validate file size to prevent resource exhaustion
111
+ if (content.length > MAX_ATTACHMENT_SIZE) {
112
+ throw new Error(`ATTACHMENT_TOO_LARGE: File size ${content.length} bytes exceeds limit of ${MAX_ATTACHMENT_SIZE} bytes`);
113
+ }
114
+ // Try to get filename from URL or header
115
+ filename = customFilename || node_path_1.default.basename(url.pathname) || 'attachment';
116
+ }
117
+ else {
118
+ // --- LOCAL PATH ---
119
+ // Security: Validate file exists and get size before reading
120
+ const stats = await promises_1.default.stat(uri);
121
+ if (stats.size > MAX_ATTACHMENT_SIZE) {
122
+ throw new Error(`ATTACHMENT_TOO_LARGE: File size ${stats.size} bytes exceeds limit of ${MAX_ATTACHMENT_SIZE} bytes`);
123
+ }
124
+ content = await promises_1.default.readFile(uri);
125
+ filename = customFilename || node_path_1.default.basename(uri);
126
+ }
127
+ // Map extension to MIME type (RFC 2045 requirement)
128
+ const ext = node_path_1.default.extname(filename).toLowerCase();
129
+ const contentType = getMimeType(ext);
130
+ return {
131
+ filename,
132
+ content,
133
+ contentType
134
+ };
135
+ }
136
+ /**
137
+ * Basic MIME mapper to satisfy RFC 2045 Content-Type requirements.
138
+ * In production, consider using the 'mime-types' npm package.
139
+ */
140
+ function getMimeType(ext) {
141
+ const map = {
142
+ '.pdf': 'application/pdf',
143
+ '.jpg': 'image/jpeg',
144
+ '.jpeg': 'image/jpeg',
145
+ '.png': 'image/png',
146
+ '.gif': 'image/gif',
147
+ '.txt': 'text/plain',
148
+ '.html': 'text/html',
149
+ '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
150
+ '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
151
+ '.zip': 'application/zip'
152
+ };
153
+ return map[ext] || 'application/octet-stream'; // RFC default for unknown binary
154
+ }
155
+ /** --- Utilities (Encoders) --- */
156
+ /**
157
+ * RFC 5321 Section 4.1.2: Email address validation.
158
+ * Validates both local-part and domain syntax to prevent crashes and injection attacks.
159
+ */
160
+ function validateEmailAddress(email) {
161
+ // RFC 5321: Maximum email length is 320 characters (64 local + 1 @ + 255 domain)
162
+ if (!email || email.length > 320)
163
+ return false;
164
+ // Basic RFC 5321 validation (simplified but safe)
165
+ const emailRegex = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
166
+ if (!emailRegex.test(email))
167
+ return false;
168
+ // Ensure there's exactly one @ symbol
169
+ const parts = email.split('@');
170
+ if (parts.length !== 2)
171
+ return false;
172
+ // RFC 5321: Local part max 64 chars, domain max 255 chars
173
+ const [localPart, domain] = parts;
174
+ return localPart.length <= 64 && domain.length <= 255;
175
+ }
176
+ function encodeHeaderValue(value) {
177
+ // Security Measure: SMTP Header Injection Prevention.
178
+ // RFC 5322 Section 2.2: Headers are defined as "Name: Body" ending in CRLF.
179
+ // If an attacker injects \r\n, they can start new headers (e.g., Bcc:).
180
+ // Stripping these prevents the protocol from being hijacked.
181
+ const sanitized = value
182
+ .replace(/[\r\n\0]/g, '') // Also strip null bytes
183
+ .replace(/[\x00-\x1F\x7F]/g, '') // Strip all control characters
184
+ .trim();
185
+ // RFC 5322 Section 2.1.1: Header lines MUST be no more than 998 characters
186
+ // (excluding CRLF). We enforce this limit to prevent buffer issues.
187
+ if (sanitized.length > 998) {
188
+ throw new Error(`HEADER_TOO_LONG: Header value exceeds 998 character limit (RFC 5322)`);
189
+ }
190
+ // RFC 5322 Section 2.1.1: Standard headers MUST be composed of
191
+ // 7-bit US-ASCII characters only (printable ASCII 32-126).
192
+ // If the string is already "safe" ASCII, we return it as-is.
193
+ if (/^[\x20-\x7E]*$/.test(sanitized))
194
+ return sanitized;
195
+ // RFC 2047: "MIME Part Three: Message Header Extensions for Non-ASCII Text".
196
+ // This provides the specific "Encoded-Word" syntax to safely transport
197
+ // UTF-8 characters using only the 7-bit ASCII characters allowed by SMTP.
198
+ // =?UTF-8 -> Charset (RFC 2279)
199
+ // ?B? -> Encoding: 'B' stands for Base64 (RFC 2045)
200
+ // ?= -> Required terminator for the Encoded-Word.
201
+ return `=?UTF-8?B?${Buffer.from(sanitized).toString('base64')}?=`;
202
+ }
203
+ function encodeQuotedPrintable(body) {
204
+ // Security/Integrity: Strips the UTF-8 Byte Order Mark (BOM).
205
+ // RFC 6376 (DKIM) is byte-sensitive; some MTAs strip BOMs automatically.
206
+ // Stripping it here ensures your signed 'bh' (body hash) matches the receiver's hash.
207
+ const cleanBody = body.replace(/^\uFEFF/, '');
208
+ // RFC 2045: QP is line-based. We split to process individual lines.
209
+ const lines = cleanBody.split(/\r?\n/);
210
+ return lines.map(line => {
211
+ let encoded = line
212
+ // RFC 2045 Section 6.7 (Rule #1 & #2):
213
+ // Safe characters are 33-60 and 62-126.
214
+ // All other characters (including '=' itself, 61) MUST be encoded as =XX.
215
+ .replace(/[^\x21-\x3C\x3E-\x7E\x20\x09]/g, (m) => '=' + m.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0'))
216
+ // RFC 2045 Section 6.7 (Rule #3):
217
+ // Trailing whitespace (space/tabs) at the end of a line MUST be encoded.
218
+ // This prevents "helpful" MTAs from trimming whitespace and breaking the DKIM hash.
219
+ .replace(/[ \t]+$/, (m) => m.split('').map(c => '=' + c.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0')).join(''));
220
+ const res = [];
221
+ // RFC 2045 Section 6.7 (Rule #5):
222
+ // Encoded lines MUST NOT exceed 76 characters.
223
+ while (encoded.length > 75) {
224
+ let len = 75;
225
+ // Integrity Logic: We cannot split in the middle of an =XX escape sequence.
226
+ // If the 75th char is '=', or if we are inside the XX, we shorten the line.
227
+ if (encoded.substring(0, len).endsWith('='))
228
+ len = 74;
229
+ else if (encoded.substring(0, len).match(/=[0-9A-F]$/))
230
+ len = 73;
231
+ // RFC 2045 Rule #5 (Soft Line Breaks):
232
+ // An '=' at the very end of a line indicates a "Soft Break" (ignored by the reader).
233
+ res.push(encoded.substring(0, len) + '=');
234
+ encoded = encoded.substring(len);
235
+ }
236
+ res.push(encoded);
237
+ // RFC 5321/5322: All SMTP body transfers MUST use CRLF (\r\n) as the line separator.
238
+ return res.join('\r\n');
239
+ }).join('\r\n');
240
+ }
241
+ /** --- Main SMTP Function --- */
242
+ /**
243
+ * Helper: Groups recipients by domain to optimize SMTP connections.
244
+ * Returns a Map where Key = Domain, Value = Array of recipients.
245
+ */
246
+ function groupRecipients(recipients) {
247
+ const groups = new Map();
248
+ for (const email of recipients) {
249
+ if (!validateEmailAddress(email)) {
250
+ console.warn(`[SKIP] Invalid email address: ${email}`);
251
+ continue;
252
+ }
253
+ const domain = email.split('@')[1].toLowerCase();
254
+ if (!groups.has(domain)) {
255
+ groups.set(domain, []);
256
+ }
257
+ groups.get(domain).push(email);
258
+ }
259
+ return groups;
260
+ }
261
+ /** --- Internal SMTP Session Handler (Single Domain) --- */
262
+ /**
263
+ * Helper: Attempts to connect and send email to a specific SMTP host.
264
+ * Returns 'Delivered' on success, or throws an error on failure.
265
+ */
266
+ async function connectAndSend(smtpHost, params, recipients) {
267
+ const { from, dkimOptions, customHeaders } = params;
268
+ return new Promise((resolve, reject) => {
269
+ // RFC 5321: SMTP standard port is 25. family: 4 enforces IPv4 to ensure
270
+ // consistency with SPF records, as IPv6 often requires separate DNS setup.
271
+ let socket = net.createConnection({ port: 25, host: smtpHost, family: 4 });
272
+ // Performance/Security: Disables Nagle's Algorithm. SMTP is a command-response
273
+ // "chatty" protocol; delaying small packets (EHLO, MAIL FROM) can cause
274
+ // session timeouts on strict MTAs.
275
+ socket.setNoDelay(true);
276
+ // Reliability Measure: Prevents "Zombie" connections. Some MTAs use "Tarpitting"
277
+ // (intentionally slow responses) to discourage spam bots. This ensures your
278
+ // process doesn't hang indefinitely.
279
+ socket.setTimeout(30000); // 30 seconds timeout per host
280
+ // SMTP State Machine: Tracks the conversation flow as required by RFC 5321.
281
+ let step = 'GREETING';
282
+ // Multi-Recipient Logic:
283
+ let recipientIndex = 0;
284
+ let validRecipientsCount = 0;
285
+ // RFC 1870: Captures the 'SIZE' extension from the EHLO response.
286
+ // Prevents "Blind Sending" of large files that the server would eventually reject.
287
+ let serverMaxPayload = Infinity;
288
+ // RFC 5322 Section 3.3: All messages MUST have a Date header in a specific
289
+ // fixed format (provided by .toUTCString()).
290
+ const date = new Date().toUTCString();
291
+ // RFC 5322 Section 3.6.4: Every message SHOULD have a globally unique
292
+ // Message-ID. Using crypto.randomBytes prevents "ID Collisions" and
293
+ // helps with thread tracking/logging.
294
+ const messageId = `<${crypto.randomBytes(16).toString('hex')}@${dkimOptions.domain}>`;
295
+ const finalizeFailure = async (errStr) => {
296
+ // Security: Hard-close the socket on error to prevent resource leaks
297
+ // or "command pipelining" by an attacker.
298
+ socket.destroy();
299
+ // Enhanced error logging with structured information for debugging and security auditing
300
+ const errorInfo = {
301
+ timestamp: new Date().toISOString(),
302
+ recipients,
303
+ smtpHost,
304
+ step,
305
+ error: errStr
306
+ };
307
+ console.error('[SMTP ERROR]', JSON.stringify(errorInfo));
308
+ // RFC 5321 Section 4.2.1: SMTP Reply Codes.
309
+ // 4xx codes = "Persistent Transient Failure" (e.g., Greylisting, mailbox full).
310
+ // 5xx codes = "Permanent Failure" (e.g., User does not exist, SPF fail).
311
+ if (errStr.includes('SMTP Error') && /^[4]/.test(errStr.split(': ')[1])) {
312
+ // Business Logic: Only temporary errors should be retried to avoid
313
+ // being flagged as a "Spammer" for repeatedly hitting a dead address.
314
+ // NOTE: In the context of MX retry loop, we might want to let the caller handle global retry.
315
+ // But here, we just reject with a specific error type so the loop knows to try next MX.
316
+ reject(new Error(`TEMPORARY_FAILURE: ${errStr}`));
317
+ }
318
+ else if (errStr.includes('SMTP Error') && /^[5]/.test(errStr.split(': ')[1])) {
319
+ // Permanent failure on this host.
320
+ // In some cases (like "User unknown"), retrying another MX won't help.
321
+ // We should throwing a PERMANENT_FAILURE to stop the loop.
322
+ reject(new Error(`PERMANENT_FAILURE: ${errStr}`));
323
+ }
324
+ else {
325
+ // Network errors, timeouts, etc. usually treated as temporary for that specific host.
326
+ reject(new Error(`CONNECTION_ERROR: ${errStr}`));
327
+ }
328
+ };
329
+ // RFC 5321 Section 2.3.8: SMTP commands and responses MUST be terminated
330
+ // by the ASCII sequence <CRLF> (Carriage Return followed by Line Feed).
331
+ // Using only '\n' (LF) is a common "bare-newline" violation that causes
332
+ // many strict MTAs (like Microsoft Outlook/Office365) to reject the connection.
333
+ const send = (cmd) => socket.write(cmd + '\r\n');
334
+ const handleData = (data) => {
335
+ // RFC 5321 Section 4.2.1: Reply Codes.
336
+ // This converts the raw binary buffer to a UTF-8 string to parse the status code.
337
+ const res = data.toString();
338
+ // RFC 5321 Section 4.2: Every SMTP response MUST begin with a 3-digit code.
339
+ // [4xx]: Persistent Transient Failure (The server is busy, try later).
340
+ // [5xx]: Permanent Failure (The address is wrong or you are blacklisted).
341
+ if (res.match(/^[45]\d{2}/)) {
342
+ // Security/Reliability: If the server returns a failure at any 'step'
343
+ // (e.g., during MAIL FROM or RCPT TO), we must stop immediately.
344
+ // Proceeding would result in an invalid state or a rejected DATA phase.
345
+ return finalizeFailure(`SMTP Error at ${step}: ${res.trim()}`);
346
+ }
347
+ switch (step) {
348
+ case 'GREETING':
349
+ // RFC 5321 Section 4.1.1.1: The EHLO (Extended HELLO) command.
350
+ // This identifies your server to the recipient. The argument MUST
351
+ // be a valid domain name (your sending domain).
352
+ send(`EHLO ${dkimOptions.domain}`);
353
+ // State Management: We update the step so the next server response
354
+ // is processed by the 'EHLO' logic (parsing extensions like SIZE or STARTTLS).
355
+ step = 'EHLO';
356
+ break;
357
+ case 'EHLO':
358
+ case 'EHLO_POST_TLS':
359
+ // RFC 1870: SMTP Service Extension for Message Size Declaration.
360
+ // The server advertises its maximum message size (in bytes).
361
+ // Capturing this prevents "Resource Exhaustion" errors later;
362
+ // sending a 50MB file to a 10MB-limit server is a waste of bandwidth.
363
+ const sizeMatch = res.match(/SIZE\s+(\d+)/i);
364
+ if (sizeMatch)
365
+ serverMaxPayload = parseInt(sizeMatch[1], 10);
366
+ // RFC 3207: SMTP Service Extension for Secure SMTP over TLS.
367
+ // We check for 'STARTTLS' in the capability list.
368
+ // If found and we haven't upgraded yet (step === 'EHLO'), we initiate encryption.
369
+ if (step === 'EHLO' && res.includes('STARTTLS')) {
370
+ send(`STARTTLS`);
371
+ step = 'STARTTLS';
372
+ }
373
+ else {
374
+ // Security: Check if TLS is required but not available
375
+ // RFC 3207: TLS should be required for sensitive communications
376
+ const tlsRequired = params.requireTLS !== false; // Default to true for security
377
+ if (tlsRequired && step === 'EHLO') {
378
+ // Server doesn't support STARTTLS but we require it
379
+ return finalizeFailure('TLS_REQUIRED: Server does not support STARTTLS and requireTLS is enabled');
380
+ }
381
+ // RFC 5321 Section 4.1.1.2: The "MAIL FROM" command.
382
+ // If the server doesn't support TLS, or we are already encrypted (EHLO_POST_TLS),
383
+ // we proceed to the 'Reverse-Path' declaration to start the actual mail transfer.
384
+ send(`MAIL FROM:<${from}>`);
385
+ step = 'MAIL';
386
+ }
387
+ break;
388
+ case 'STARTTLS':
389
+ // Security/Memory: We stop listening to the plaintext socket.
390
+ // If we don't remove this, the old listener might try to process
391
+ // encrypted binary data as text, causing a crash or "Buffer Poisoning."
392
+ socket.removeListener('data', handleData);
393
+ // RFC 3207: "SMTP Service Extension for Secure SMTP over TLS".
394
+ // This wraps the existing TCP 'socket' in a TLS layer.
395
+ const secureSocket = tls.connect({
396
+ socket: socket,
397
+ servername: smtpHost, // Security: SNI (Server Name Indication) for cert matching.
398
+ minVersion: 'TLSv1.2', // Security: Blocks obsolete, insecure protocols (SSLv3, TLS 1.0/1.1).
399
+ rejectUnauthorized: true // Security: MITM Protection. Validates the server's certificate.
400
+ }, () => {
401
+ // Logic: Once the handshake is complete, we re-attach our data listener
402
+ // to the new "Secure Socket."
403
+ socket = secureSocket;
404
+ socket.on('data', handleData);
405
+ // RFC 3207 Section 4.2: Upon successful TLS negotiation,
406
+ // the client MUST send EHLO again to reset the server state.
407
+ send(`EHLO ${dkimOptions.domain}`);
408
+ step = 'EHLO_POST_TLS';
409
+ });
410
+ // Reliability: Catching handshake failures (e.g., certificate mismatch).
411
+ secureSocket.on('error', (err) => reject(new Error(`TLS_ERR: ${err.message}`)));
412
+ break;
413
+ case 'MAIL':
414
+ // RFC 5321 Section 4.1.1.3: The "RCPT TO" (Recipient) command.
415
+ // This defines the "Envelope Recipient." The email address MUST be
416
+ // enclosed in brackets < >. This is the actual destination of the mail.
417
+ // We assume the server accepted MAIL FROM. Now we start the loops for recipients.
418
+ if (recipientIndex < recipients.length) {
419
+ send(`RCPT TO:<${recipients[recipientIndex]}>`);
420
+ step = 'RCPT';
421
+ }
422
+ else {
423
+ // Should not happen here usually, but safe guard
424
+ finalizeFailure('NO_RECIPIENTS');
425
+ }
426
+ break;
427
+ case 'RCPT':
428
+ // We just got a response for a RCPT TO command.
429
+ // RFC 5321: A 250/251 means accepted. 550 means rejected (e.g. user unknown).
430
+ // We should generally continue to the next recipient even if one fails,
431
+ // UNLESS the error is a connection error (handled elsewhere).
432
+ if (res.startsWith('250') || res.startsWith('251')) {
433
+ validRecipientsCount++;
434
+ }
435
+ else {
436
+ // Log the failure for this specific recipient but don't abort the session yet
437
+ console.warn(`[SMTP PARTIAL FAIL] RCPT Rejected: ${recipients[recipientIndex]} -> ${res.trim()}`);
438
+ }
439
+ // Move to next recipient
440
+ recipientIndex++;
441
+ if (recipientIndex < recipients.length) {
442
+ // Send next recipient
443
+ send(`RCPT TO:<${recipients[recipientIndex]}>`);
444
+ // Stay in RCPT step
445
+ }
446
+ else {
447
+ // All recipients processed.
448
+ if (validRecipientsCount === 0) {
449
+ // Optimization: If NO recipients were accepted, do not send DATA.
450
+ // We should quit and report failure.
451
+ return finalizeFailure('ALL_RECIPIENTS_REJECTED: Server rejected all RCPT TO commands');
452
+ }
453
+ // Proceed to DATA
454
+ send(`DATA`);
455
+ step = 'DATA_START';
456
+ }
457
+ break;
458
+ case 'DATA_START':
459
+ const hasText = !!params.text?.trim();
460
+ const hasHtml = !!params.html?.trim();
461
+ const attachments = params.attachments || [];
462
+ let fullBody = '';
463
+ let contentTypeHeader = '';
464
+ const mixedBoundary = `----=_Part_M_${crypto.randomBytes(4).toString('hex')}`;
465
+ const altBoundary = `----=_Part_A_${crypto.randomBytes(4).toString('hex')}`;
466
+ // RFC 2046: Content construction
467
+ if (attachments.length > 0) {
468
+ // OUTER LAYER: multipart/mixed (RFC 2046 Section 5.1.3)
469
+ contentTypeHeader = `multipart/mixed; boundary="${mixedBoundary}"`;
470
+ let bodyParts = [`--${mixedBoundary}`];
471
+ // INNER LAYER: Nested alternative part for Text/HTML
472
+ bodyParts.push(`Content-Type: multipart/alternative; boundary="${altBoundary}"`, ``);
473
+ if (hasText) {
474
+ bodyParts.push(`--${altBoundary}`, `Content-Type: text/plain; charset=utf-8`, `Content-Transfer-Encoding: quoted-printable`, ``, encodeQuotedPrintable(params.text));
475
+ }
476
+ if (hasHtml) {
477
+ bodyParts.push(`--${altBoundary}`, `Content-Type: text/html; charset=utf-8`, `Content-Transfer-Encoding: quoted-printable`, ``, encodeQuotedPrintable(params.html));
478
+ }
479
+ bodyParts.push(`--${altBoundary}--`);
480
+ // ATTACHMENT PARTS: (RFC 2183)
481
+ for (const att of attachments) {
482
+ bodyParts.push(`--${mixedBoundary}`);
483
+ // RFC 2183: Content-Disposition defines how the file is handled (attachment vs inline)
484
+ bodyParts.push(`Content-Type: ${att.contentType || 'application/octet-stream'}; name="${encodeHeaderValue(att.filename)}"`);
485
+ bodyParts.push(`Content-Transfer-Encoding: base64`);
486
+ bodyParts.push(`Content-Disposition: attachment; filename="${encodeHeaderValue(att.filename)}"`, ``);
487
+ // Security: Base64 encoding ensures binary data doesn't break SMTP 7-bit limits
488
+ bodyParts.push(att.content.toString('base64').match(/.{1,76}/g)?.join('\r\n') || '');
489
+ }
490
+ bodyParts.push(`--${mixedBoundary}--`);
491
+ fullBody = bodyParts.join('\r\n');
492
+ }
493
+ else if (hasText && hasHtml) {
494
+ // Standard multipart/alternative (No attachments)
495
+ contentTypeHeader = `multipart/alternative; boundary="${altBoundary}"`;
496
+ fullBody = [
497
+ `--${altBoundary}`,
498
+ `Content-Type: text/plain; charset=utf-8`,
499
+ `Content-Transfer-Encoding: quoted-printable`,
500
+ ``,
501
+ encodeQuotedPrintable(params.text),
502
+ `--${altBoundary}`,
503
+ `Content-Type: text/html; charset=utf-8`,
504
+ `Content-Transfer-Encoding: quoted-printable`,
505
+ ``,
506
+ encodeQuotedPrintable(params.html),
507
+ `--${altBoundary}--`
508
+ ].join('\r\n');
509
+ }
510
+ else {
511
+ // Simple Single Part
512
+ contentTypeHeader = hasHtml ? 'text/html; charset=utf-8' : 'text/plain; charset=utf-8';
513
+ fullBody = encodeQuotedPrintable(params.html || params.text || ' ');
514
+ }
515
+ // RFC 1870: Message size check (Critical for attachments!)
516
+ if (Buffer.byteLength(fullBody) > serverMaxPayload)
517
+ return finalizeFailure(`SIZE_EXCEEDED`);
518
+ const headerMap = {
519
+ 'from': encodeHeaderValue(from),
520
+ 'to': encodeHeaderValue(Array.isArray(params.to) ? params.to.join(', ') : params.to),
521
+ 'subject': encodeHeaderValue(params.subject),
522
+ 'date': date,
523
+ 'message-id': messageId,
524
+ 'mime-version': '1.0', // RFC 2045: Required to enable MIME features.
525
+ 'content-type': contentTypeHeader,
526
+ // RFC 8058: 2026 requirement for "One-Click Unsubscribe" in bulk mail.
527
+ // 'list-unsubscribe': `<https://${dkimOptions.domain}/unsubscribe>`,
528
+ // 'list-unsubscribe-post': 'List-Unsubscribe=One-Click',
529
+ // 'precedence': 'bulk'
530
+ };
531
+ if (customHeaders)
532
+ Object.entries(customHeaders).forEach(([k, v]) => headerMap[k.toLowerCase()] = encodeHeaderValue(v));
533
+ /** --- DKIM SIGNING (RFC 6376) --- **/
534
+ // RFC 6376 Section 3.4.4: Relaxed Body Canonicalization.
535
+ // Reduces spaces and trims end. Security: Prevents "Broken Signatures"
536
+ // caused by intermediate servers adding/stripping trailing whitespace.
537
+ const canonBody = fullBody.replace(/[ \t]+/g, ' ').replace(/[ \t]+\r\n/g, '\r\n').trimEnd() + '\r\n';
538
+ const bodyHash = crypto.createHash('sha256').update(canonBody).digest('base64');
539
+ const dkimKeys = Object.keys(headerMap);
540
+ // RFC 6376 Section 3.5: v=1, a=rsa-sha256, c=relaxed/relaxed.
541
+ // bh= is the body hash; b= is the cryptographic signature of headers + bh.
542
+ const dkimPrefix = `v=1; a=rsa-sha256; c=relaxed/relaxed; d=${dkimOptions.domain}; s=${dkimOptions.selector}; h=${dkimKeys.join(':')}; bh=${bodyHash}; b=`;
543
+ // RFC 6376 Section 3.4.2: Relaxed Header Canonicalization.
544
+ // Headers are lowercased and folded before signing to survive relaying.
545
+ const sig = crypto.sign('RSA-SHA256', Buffer.from(dkimKeys.map(k => `${k}:${headerMap[k].replace(/\s+/g, ' ').trim()}`).join('\r\n') + `\r\ndkim-signature:${dkimPrefix}`), dkimOptions.privateKey).toString('base64');
546
+ const wireHeaders = [`DKIM-Signature: ${dkimPrefix}${sig}`];
547
+ HEADER_ORDER.slice(1).forEach(k => { if (headerMap[k.toLowerCase()])
548
+ wireHeaders.push(`${k}: ${headerMap[k.toLowerCase()]}`); });
549
+ Object.keys(headerMap).forEach(k => { if (!HEADER_ORDER.map(ho => ho.toLowerCase()).includes(k))
550
+ wireHeaders.push(`${k}: ${headerMap[k]}`); });
551
+ // RFC 5321 Section 4.5.2: "Transparency" (Dot-Stuffing).
552
+ // Security: Prevents "SMTP Smuggling." We normalize line endings FIRST,
553
+ // then apply dot-stuffing to prevent mixed line ending attacks.
554
+ const normalizedBody = fullBody.replace(/\r?\n/g, '\r\n');
555
+ const wireBody = normalizedBody.split('\r\n').map(l => l.startsWith('.') ? '.' + l : l).join('\r\n');
556
+ // RFC 5321: The message MUST end with <CRLF>.<CRLF>.
557
+ socket.write(wireHeaders.join('\r\n') + '\r\n\r\n' + wireBody + '\r\n.\r\n');
558
+ step = 'DATA_CONFIRM';
559
+ break;
560
+ case 'DATA_CONFIRM':
561
+ // RFC 5321 Section 4.1.1.4: The "Post-Dot" Response.
562
+ // A '250 OK' here is the ONLY point where you can be certain the
563
+ // remote server has accepted the email into its delivery queue.
564
+ if (res.startsWith('250')) {
565
+ // RFC 5321 Section 4.1.1.10: The QUIT command.
566
+ // This tells the server you are finished. Closing the connection
567
+ // without sending QUIT is considered "rude" protocol behavior
568
+ // and can lead to temporary IP rate-limiting.
569
+ send(`QUIT`);
570
+ step = 'END';
571
+ }
572
+ else {
573
+ // Security/Reliability: If the server rejects the message AFTER
574
+ // the data transfer (e.g., "554 Message rejected due to spam content"),
575
+ // we must capture this as a permanent failure.
576
+ return finalizeFailure(`DATA_REJECT: ${res.trim()}`);
577
+ }
578
+ break;
579
+ case 'END':
580
+ // RFC 5321 Section 4.1.1.10: After the 'QUIT' command is sent,
581
+ // the client MUST close the connection.
582
+ // socket.end() sends a FIN packet, telling the server we are
583
+ // officially done with the TCP session.
584
+ socket.end();
585
+ resolve('Delivered');
586
+ break;
587
+ }
588
+ };
589
+ socket.on('data', handleData);
590
+ socket.on('error', (err) => finalizeFailure(`CONN_ERR: ${err.message}`));
591
+ socket.on('timeout', () => finalizeFailure('TIMEOUT'));
592
+ });
593
+ }
594
+ async function processDomainSession(params, recipients, handleRetry) {
595
+ // Logic: Destructuring parameters. 'to' in params is used for Headers only.
596
+ // 'recipients' argument is used for Envelope (RCPT TO).
597
+ const { from, dkimOptions, customHeaders, attemptCount = 1 } = params;
598
+ // RFC 5321 Section 4.1.2: Validate email addresses before processing
599
+ // Security: Prevents crashes and CRLF injection via malformed addresses
600
+ if (!validateEmailAddress(from)) {
601
+ throw new Error(`INVALID_SENDER: "${from}" is not a valid RFC 5321 email address`);
602
+ }
603
+ // Recipients are already validated and grouped by caller, but we pick the domain from the first one.
604
+ if (recipients.length === 0)
605
+ return 'No recipients';
606
+ const recipientDomain = recipients[0].split('@')[1];
607
+ // RFC 5321 Section 5.1: Locating the Message Delivery Agent.
608
+ // This performs a DNS MX (Mail Exchanger) lookup.
609
+ // Security Note: In production, this should ideally be validated via DNSSEC
610
+ // to prevent MX-spoofing (redirecting your mail to an attacker's server).
611
+ const mxRecords = await dns.promises.resolveMx(recipientDomain);
612
+ // RFC 5321 Section 5.1: "The list of MX bin records MUST be sorted".
613
+ // Priority (Preference) value: Lower numbers have HIGHER priority.
614
+ // Sorting ensures we try the "Primary" mail server first.
615
+ mxRecords.sort((a, b) => a.priority - b.priority);
616
+ // MX Retry Loop
617
+ if (mxRecords.length === 0) {
618
+ throw new Error(`NO_MX_RECORDS: No MX records found for domain ${recipientDomain}`);
619
+ }
620
+ let lastError = new Error('Unknown error');
621
+ let delivered = false;
622
+ for (const mx of mxRecords) {
623
+ const smtpHost = mx.exchange;
624
+ try {
625
+ console.log(`[MTA] Attempting delivery to MX: ${smtpHost} (Priority: ${mx.priority})`);
626
+ const result = await connectAndSend(smtpHost, params, recipients);
627
+ if (result === 'Delivered') {
628
+ delivered = true;
629
+ return 'Delivered';
630
+ }
631
+ }
632
+ catch (err) {
633
+ console.warn(`[MTA] Failed to deliver to MX ${smtpHost}: ${err.message}`);
634
+ lastError = err;
635
+ // Logic: Decisions based on error type
636
+ // 1. If PERMANENT_FAILURE (5xx), we stop immediately. Changing MX won't fix "User unknown".
637
+ // 2. If TEMPORARY_FAILURE (4xx) or CONNECTION_ERROR, we continue to the next MX loop.
638
+ if (err.message.includes('PERMANENT_FAILURE')) {
639
+ throw err;
640
+ }
641
+ // Implicit continue for other errors
642
+ }
643
+ }
644
+ if (!delivered) {
645
+ // If we exhausted all MX records and failed
646
+ // If it was a temporary failure on all of them, we might trigger the globale retry mechanism.
647
+ if (handleRetry && !lastError.message.includes('PERMANENT_FAILURE')) {
648
+ await handleRetry(params, lastError.message, attemptCount + 1);
649
+ throw new Error(`ALL_MX_FAILED_TEMPORARY: ${lastError.message}`); // Trigger retry logic in caller/queues
650
+ }
651
+ throw lastError;
652
+ }
653
+ return 'Delivered'; // Should not reach here if loop works correctly
654
+ }
655
+ /** --- Main Exported Function --- */
656
+ async function sendEmail(params, handleRetry) {
657
+ // 1. Normalize 'to' to array
658
+ const rawRecipients = Array.isArray(params.to) ? params.to : [params.to];
659
+ // 2. Validate From (Optimization: Do it once here)
660
+ if (!validateEmailAddress(params.from)) {
661
+ throw new Error(`INVALID_SENDER: "${params.from}" is not a valid RFC 5321 email address`);
662
+ }
663
+ // 3. Group by Domain
664
+ const domainGroups = groupRecipients(rawRecipients);
665
+ if (domainGroups.size === 0) {
666
+ throw new Error('NO_VALID_RECIPIENTS: No valid email addresses found in "to" field.');
667
+ }
668
+ // 4. Process each domain in a separate session
669
+ // Logic: We process them concurrently (Promise.allSettled) for speed,
670
+ // but could be sequential if resource constrained.
671
+ const results = await Promise.allSettled(Array.from(domainGroups.entries()).map(async ([domain, recipients]) => {
672
+ try {
673
+ console.log(`[MTA] Starting session for domain: ${domain} (${recipients.length} recipients)`);
674
+ await processDomainSession(params, recipients, handleRetry);
675
+ return { domain, recipients, status: 'Sent' };
676
+ }
677
+ catch (err) {
678
+ console.error(`[MTA] Failed session for domain: ${domain}`, err.message);
679
+ return { domain, recipients, status: 'Failed', error: err.message };
680
+ }
681
+ }));
682
+ // 5. Aggregate Results
683
+ const failures = results.filter(r => r.status === 'rejected');
684
+ const fulfilled = results.filter(r => r.status === 'fulfilled').map(r => r.value);
685
+ let error;
686
+ if (failures.length > 0) {
687
+ error = `Failed: ${failures.map(f => f.reason.message).join(', ')}`;
688
+ }
689
+ return {
690
+ result: fulfilled,
691
+ error
692
+ };
693
+ }
694
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@naiv/mta",
3
+ "version": "0.0.1",
4
+ "description": "Pure NodeJS Mail Transfer Agent",
5
+ "main": "dist/index.js",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "package.json"
12
+ ],
13
+ "scripts": {
14
+ "build": "rm -rf dist && tsc"
15
+ },
16
+ "keywords": [],
17
+ "author": "",
18
+ "license": "ISC",
19
+ "devDependencies": {
20
+ "@types/node": "^25.2.3",
21
+ "typescript": "^5.9.3"
22
+ }
23
+ }