@carlgo11/simpleimfparser 0.0.1-a → 0.0.2

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.
Files changed (44) hide show
  1. package/LICENSE +21 -674
  2. package/dist/index.d.ts +14 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/{src/parsers/parseEnvelope.ts → dist/parsers/parseEnvelope.d.ts} +2 -5
  5. package/dist/parsers/parseEnvelope.d.ts.map +1 -0
  6. package/dist/parsers/parseHeaders.d.ts +10 -0
  7. package/dist/parsers/parseHeaders.d.ts.map +1 -0
  8. package/dist/parsers/parseMessage.d.ts +11 -0
  9. package/dist/parsers/parseMessage.d.ts.map +1 -0
  10. package/dist/types/Attachment.d.ts +56 -0
  11. package/dist/types/Attachment.d.ts.map +1 -0
  12. package/dist/types/Email.d.ts +114 -0
  13. package/dist/types/Email.d.ts.map +1 -0
  14. package/dist/types/Envelope.d.ts +45 -0
  15. package/dist/types/Envelope.d.ts.map +1 -0
  16. package/dist/types/Sender.d.ts +75 -0
  17. package/dist/types/Sender.d.ts.map +1 -0
  18. package/dist/utils/streamToString.d.ts +8 -0
  19. package/dist/utils/streamToString.d.ts.map +1 -0
  20. package/package.json +12 -4
  21. package/.github/workflows/publish.yaml +0 -51
  22. package/.github/workflows/test.yaml +0 -14
  23. package/.gitignore +0 -6
  24. package/dist/index.js +0 -8
  25. package/dist/parsers/parseEnvelope.js +0 -9
  26. package/dist/parsers/parseHeaders.js +0 -65
  27. package/dist/parsers/parseMessage.js +0 -30
  28. package/dist/types/Attachment.js +0 -1
  29. package/dist/types/Email.js +0 -55
  30. package/dist/types/Envelope.js +0 -1
  31. package/dist/types/Sender.js +0 -1
  32. package/dist/utils/streamToString.js +0 -13
  33. package/src/index.ts +0 -14
  34. package/src/parsers/parseHeaders.ts +0 -65
  35. package/src/parsers/parseMessage.ts +0 -32
  36. package/src/types/Attachment.ts +0 -6
  37. package/src/types/Email.ts +0 -77
  38. package/src/types/Envelope.ts +0 -9
  39. package/src/types/Sender.ts +0 -10
  40. package/src/utils/streamToString.ts +0 -15
  41. package/test/index.test.ts +0 -40
  42. package/test/parsers/parseHeaders.test.ts +0 -32
  43. package/test/parsers/parseMessage.test.ts +0 -34
  44. package/tsconfig.json +0 -15
@@ -0,0 +1,14 @@
1
+ import { Readable } from 'node:stream';
2
+ import Email from './types/Email.js';
3
+ import type Envelope from './types/Envelope.js';
4
+ /**
5
+ * Parses an email message from raw data and an envelope object.
6
+ *
7
+ * @param {string | Readable} rawData - The raw email message content.
8
+ * @param {object} envelope - The envelope containing sender/recipient metadata.
9
+ * @returns {Promise<Email>} A parsed email object.
10
+ * @since 0.0.1
11
+ */
12
+ export default function parseEmail(rawData: string | Readable, envelope: object): Promise<Email>;
13
+ export { Email, Envelope };
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,MAAM,kBAAkB,CAAC;AAGrC,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAEhD;;;;;;;GAOG;AACH,wBAA8B,UAAU,CACtC,OAAO,EAAE,MAAM,GAAG,QAAQ,EAC1B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,KAAK,CAAC,CAKhB;AAED,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC"}
@@ -1,11 +1,8 @@
1
1
  import Envelope from '../types/Envelope.js';
2
-
3
2
  /**
4
3
  * Parses envelope metadata from the SMTP transaction.
5
4
  * @param envelope - Envelope data object
6
5
  * @returns Parsed Envelope object
7
6
  */
8
- export default async function parseEnvelope(envelope: Object): Promise<Envelope> {
9
- // TODO: Implement envelope parsing logic
10
- return envelope as Envelope;
11
- }
7
+ export default function parseEnvelope(envelope: Object): Promise<Envelope>;
8
+ //# sourceMappingURL=parseEnvelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseEnvelope.d.ts","sourceRoot":"","sources":["../../src/parsers/parseEnvelope.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,sBAAsB,CAAC;AAG5C;;;;GAIG;AACH,wBAA8B,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAyB/E"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Parses headers from a raw IMF header string.
3
+ * @param {string} rawHeaders - The raw headers as a string
4
+ * @param {'strict'|'relaxed'} mode - Strict mode rejects emails with invalid headers. Relaxed simply deletes invalid headers.
5
+ * @returns {Promise<Record<string, string | string[]>>} - A dictionary of headers (handling duplicates)
6
+ * @throws {Error} - If any header fails validation.
7
+ * @since 0.0.1
8
+ */
9
+ export default function parseHeaders(rawHeaders: string, mode?: 'strict' | 'relaxed'): Promise<Record<string, string | string[]>>;
10
+ //# sourceMappingURL=parseHeaders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseHeaders.d.ts","sourceRoot":"","sources":["../../src/parsers/parseHeaders.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,wBAA8B,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,QAAQ,GAAG,SAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,CAIjJ"}
@@ -0,0 +1,11 @@
1
+ import { Readable } from 'node:stream';
2
+ /**
3
+ * Parses the raw email message (headers + body).
4
+ * @param rawData - Raw IMF email (string or stream)
5
+ * @returns Parsed email components
6
+ */
7
+ export default function parseMessage(rawData: string | Readable): Promise<{
8
+ headers: Record<string, string | string[]>;
9
+ body: string;
10
+ }>;
11
+ //# sourceMappingURL=parseMessage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseMessage.d.ts","sourceRoot":"","sources":["../../src/parsers/parseMessage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAIvC;;;;GAIG;AACH,wBAA8B,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAoB5I"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Represents an email attachment.
3
+ *
4
+ * This interface defines the structure of an attachment, including
5
+ * its filename, MIME type, size, and content.
6
+ *
7
+ * @interface Attachment
8
+ * @since 0.0.1
9
+ */
10
+ export default interface Attachment {
11
+ /**
12
+ * The name of the attachment file.
13
+ *
14
+ * This is the filename as provided in the email message.
15
+ *
16
+ * @type {string}
17
+ * @example "invoice.pdf"
18
+ * @example "image.png"
19
+ * @since 0.0.1
20
+ */
21
+ filename: string;
22
+ /**
23
+ * The MIME type of the attachment.
24
+ *
25
+ * This indicates the media type of the file, as specified in the `Content-Type` header.
26
+ *
27
+ * @type {string}
28
+ * @example "application/pdf"
29
+ * @example "image/jpeg"
30
+ * @example "text/plain"
31
+ * @since 0.0.1
32
+ */
33
+ contentType: string;
34
+ /**
35
+ * The size of the attachment in bytes.
36
+ *
37
+ * Represents the total number of bytes in the attachment content.
38
+ *
39
+ * @type {number}
40
+ * @example 102400 // 100 KB
41
+ * @example 512 // 512 bytes
42
+ * @since 0.0.1
43
+ */
44
+ size: number;
45
+ /**
46
+ * The content of the attachment.
47
+ *
48
+ * This contains the actual file data as written in the email message.
49
+ *
50
+ * @type {string}
51
+ * @example /9j/4AAQSkZJRgABAQEAEQARAAD/2wB //JPEG example
52
+ * @since 0.0.1
53
+ */
54
+ content: string;
55
+ }
56
+ //# sourceMappingURL=Attachment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Attachment.d.ts","sourceRoot":"","sources":["../../src/types/Attachment.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,CAAC,OAAO,WAAW,UAAU;IACjC;;;;;;;;;OASG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;;;;;;;OAUG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;;;;;;OASG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;;;;;;OAQG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB"}
@@ -0,0 +1,114 @@
1
+ import Envelope from './Envelope.js';
2
+ import Attachment from './Attachment.js';
3
+ /**
4
+ * Represents an email message with an envelope, headers, body, and optional attachments.
5
+ *
6
+ * @class Email
7
+ * @module Email
8
+ * @since 0.0.1
9
+ */
10
+ export default class Email {
11
+ /**
12
+ * The envelope containing sender and recipient details.
13
+ *
14
+ * @type {Envelope}
15
+ * @since 0.0.1
16
+ */
17
+ envelope: Envelope;
18
+ /**
19
+ * The headers of the email, stored as key-value pairs.
20
+ * Header names are case-insensitive.
21
+ *
22
+ * @type {Record<string, string | string[]>}
23
+ * @since 0.0.1
24
+ */
25
+ headers: Record<string, string | string[]>;
26
+ /**
27
+ * The plain text body of the email.
28
+ *
29
+ * @type {string}
30
+ * @since 0.0.1
31
+ */
32
+ body: string;
33
+ /**
34
+ * The attachments associated with the email.
35
+ * Defaults to an empty array if not provided.
36
+ *
37
+ * @type {Attachment[]}
38
+ * @since 0.0.1
39
+ */
40
+ attachments?: Attachment[];
41
+ /**
42
+ * Creates a new email instance.
43
+ *
44
+ * @param {Envelope} envelope - The envelope containing sender and recipient details.
45
+ * @param {Record<string, string | string[]>} headers - The headers of the email.
46
+ * @param {string} body - The plain text body of the email.
47
+ * @param {Attachment[]} [attachments=[]] - Optional attachments for the email.
48
+ * @since 0.0.1
49
+ */
50
+ constructor(envelope: Envelope, headers: Record<string, string | string[]>, body: string, attachments?: Attachment[]);
51
+ /**
52
+ * Retrieves a header value by name (case-insensitive).
53
+ *
54
+ * @param {string} name - The name of the header to retrieve.
55
+ * @returns {string | string[] | undefined} The header value, or `undefined` if not found.
56
+ * @example
57
+ * const email = new Email(envelope, { 'subject': 'Subject String' });
58
+ * console.log(email.getHeader('Subject')); // Output: 'Subject String'
59
+ * @since 0.0.1
60
+ */
61
+ getHeader(name: string): string | string[] | undefined;
62
+ /**
63
+ * Adds a new header or appends to an existing header.
64
+ * If the header already exists, it is converted to an array.
65
+ *
66
+ * @param {string} name - The name of the header.
67
+ * @param {string} value - The value to add to the header.
68
+ * @example
69
+ * const email = new Email(envelope, {}, 'Hello');
70
+ * email.addHeader('X-Custom-Header', 'Value1');
71
+ * email.addHeader('X-Custom-Header', 'Value2');
72
+ * console.log(email.getHeader('X-Custom-Header')); // Output: ['Value1', 'Value2']
73
+ * @since 0.0.1
74
+ */
75
+ addHeader(name: string, value: string): void;
76
+ /**
77
+ * Removes a header by name (case-insensitive).
78
+ *
79
+ * @param {string} name - The name of the header to remove.
80
+ * @example
81
+ * const email = new Email(envelope, { 'X-Test': 'value' }, 'Hello');
82
+ * email.removeHeader('X-Test');
83
+ * console.log(email.getHeader('X-Test')); // Output: undefined
84
+ * @since 0.0.1
85
+ */
86
+ removeHeader(name: string): void;
87
+ /**
88
+ * Retrieves the body of the email.
89
+ * If the email contains both plain text and HTML, plain text is preferred.
90
+ *
91
+ * @returns {string} The email body.
92
+ * @example
93
+ * const email = new Email(envelope, {}, 'Hello, world!');
94
+ * console.log(email.getBody()); // Output: 'Hello, world!'
95
+ * @since 0.0.1
96
+ */
97
+ getBody(): string;
98
+ /**
99
+ * Returns the email as a string in the IMF format.
100
+ *
101
+ * @returns {string} The formatted email as a string.
102
+ * @see https://datatracker.ietf.org/doc/html/rfc5322
103
+ * @example
104
+ * const email = new Email(envelope, { subject: 'Test' }, 'Hello');
105
+ * console.log(email.toString());
106
+ * // Output:
107
+ * // Subject: Test
108
+ * //
109
+ * // Hello
110
+ * @since 0.0.1
111
+ */
112
+ toString(): string;
113
+ }
114
+ //# sourceMappingURL=Email.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Email.d.ts","sourceRoot":"","sources":["../../src/types/Email.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,eAAe,CAAC;AACrC,OAAO,UAAU,MAAM,iBAAiB,CAAC;AAEzC;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,OAAO,KAAK;IACxB;;;;;OAKG;IACH,QAAQ,EAAE,QAAQ,CAAC;IAEnB;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAE3C;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAE3B;;;;;;;;OAQG;gBAED,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAC1C,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,UAAU,EAAE;IAQ5B;;;;;;;;;OASG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS;IAItD;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAa5C;;;;;;;;;OASG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIhC;;;;;;;;;OASG;IACH,OAAO,IAAI,MAAM;IAIjB;;;;;;;;;;;;;OAaG;IACH,QAAQ,IAAI,MAAM;CAGnB"}
@@ -0,0 +1,45 @@
1
+ import Sender from './Sender.js';
2
+ /**
3
+ * Represents an email envelope, containing metadata about the sender, recipients, and delivery.
4
+ *
5
+ * The envelope is part of the message delivery process and includes information
6
+ * such as the sender, recipient list, and timestamps.
7
+ *
8
+ * @interface Envelope
9
+ * @since 0.0.1
10
+ */
11
+ export default interface Envelope {
12
+ /**
13
+ * A unique identifier for the email.
14
+ * This can be set either by the sender using Message-ID, or by the recipient server.
15
+ *
16
+ * @type {string}
17
+ * @since 0.0.1
18
+ */
19
+ id: string;
20
+ /**
21
+ * The sender's "MAIL FROM" email address.
22
+ *
23
+ * Note: This address may differ from the address used in the "From"-header inside the email message.
24
+ *
25
+ * @type {string}
26
+ * @since 0.0.1
27
+ */
28
+ from: string;
29
+ /**
30
+ * The list of recipient email addresses.
31
+ *
32
+ * @type {string[]}
33
+ * @since 0.0.1
34
+ */
35
+ to: string[];
36
+ /**
37
+ * The sender details, including additional metadata about the sender.
38
+ *
39
+ * @type {Sender}
40
+ * @see Sender
41
+ * @since 0.0.1
42
+ */
43
+ sender: Sender;
44
+ }
45
+ //# sourceMappingURL=Envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Envelope.d.ts","sourceRoot":"","sources":["../../src/types/Envelope.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC;;;;;;;;GAQG;AACH,MAAM,CAAC,OAAO,WAAW,QAAQ;IAC/B;;;;;;OAMG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;;;;;;OAOG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;;;OAKG;IACH,EAAE,EAAE,MAAM,EAAE,CAAC;IAEb;;;;;;OAMG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Represents details about the sender of an email during the SMTP transaction.
3
+ *
4
+ * This interface includes metadata about the sender's connection, such as
5
+ * the originating IP address, reverse DNS, HELO/EHLO value, TLS status,
6
+ * and authentication details (if applicable).
7
+ *
8
+ * @interface Sender
9
+ * @since 0.0.1
10
+ */
11
+ export default interface Sender {
12
+ /**
13
+ * The IP address of the sender.
14
+ *
15
+ * This is the IP address of the SMTP client that initiated the connection.
16
+ *
17
+ * @type {string}
18
+ * @example "192.168.1.100"
19
+ * @example "2001:db8::1"
20
+ * @since 0.0.1
21
+ */
22
+ ip: string;
23
+ /**
24
+ * The reverse DNS (rDNS) hostname of the sender.
25
+ *
26
+ * If available, this represents the resolved hostname of the sender's IP.
27
+ * This value may be `undefined` if no rDNS record exists.
28
+ *
29
+ * @type {string | undefined}
30
+ * @example "mail.example.com"
31
+ * @since 0.0.1
32
+ */
33
+ rDNS?: string;
34
+ /**
35
+ * The HELO/EHLO value provided by the SMTP client.
36
+ *
37
+ * This is the argument sent by the client in the EHLO or HELO command.
38
+ * It is typically a hostname but may also be an IP address.
39
+ * If the value is an IP address, it is enclosed in square brackets.
40
+ *
41
+ * @type {string | undefined}
42
+ * @example "mail.example.com"
43
+ * @example "[192.168.1.100]"
44
+ * @example "[IPv6:2001:db8::1]"
45
+ * @since 0.0.1
46
+ */
47
+ helo?: string;
48
+ /**
49
+ * Indicates whether the connection was secured using TLS (STARTTLS).
50
+ *
51
+ * A `true` value means that the SMTP session was encrypted using TLS (STARTTLS).
52
+ *
53
+ * @type {boolean}
54
+ * @example true
55
+ * @example false
56
+ * @since 0.0.1
57
+ */
58
+ tls: boolean;
59
+ /**
60
+ * Authentication details if the sender authenticated.
61
+ *
62
+ * This property exists only if the sender used SMTP authentication.
63
+ *
64
+ * @type {Object | undefined}
65
+ * @property {string} method - The authentication method used (e.g., "PLAIN", "LOGIN", "CRAM-MD5").
66
+ * @property {string | undefined} username - The authenticated username, if available.
67
+ * @example { method: "PLAIN", username: "user@example.com" }
68
+ * @since 0.0.1
69
+ */
70
+ authenticated?: {
71
+ method: string;
72
+ username?: string;
73
+ };
74
+ }
75
+ //# sourceMappingURL=Sender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sender.d.ts","sourceRoot":"","sources":["../../src/types/Sender.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,OAAO,WAAW,MAAM;IAC7B;;;;;;;;;OASG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;;;;;;;;OASG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;;;;;;;OASG;IACH,GAAG,EAAE,OAAO,CAAC;IAEb;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE;QACd,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH"}
@@ -0,0 +1,8 @@
1
+ import { Readable } from 'node:stream';
2
+ /**
3
+ * Converts a Readable Stream to a string.
4
+ * @param stream - Input stream
5
+ * @returns Promise resolving to the string content
6
+ */
7
+ export default function streamToString(stream: Readable): Promise<string>;
8
+ //# sourceMappingURL=streamToString.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamToString.d.ts","sourceRoot":"","sources":["../../src/utils/streamToString.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC;;;;GAIG;AACH,wBAA8B,cAAc,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAO9E"}
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "type": "module",
3
3
  "main": "dist/index.js",
4
+ "types": "dist/index.d.ts",
4
5
  "name": "@carlgo11/simpleimfparser",
5
6
  "description": "Simple IMF parser",
6
- "version": "0.0.1a",
7
- "license": "GPL-3.0",
7
+ "version": "0.0.2",
8
+ "license": "MIT",
8
9
  "author": "Carlgo11",
9
10
  "repository": {
10
11
  "type": "git",
@@ -17,16 +18,23 @@
17
18
  "scripts": {
18
19
  "start": "node src/index.ts",
19
20
  "test": "node --import tsx --test test/*.test.ts test/**/*.test.ts",
20
- "build": "npx tsc"
21
+ "build": "npx tsc",
22
+ "docs": "npx typedoc"
21
23
  },
22
24
  "private": false,
23
25
  "dependencies": {
24
- "@types/node": "^22.10.7"
26
+ "@types/node": "^22.10.7",
27
+ "validator": "^13.12.0"
25
28
  },
26
29
  "devDependencies": {
27
30
  "@faker-js/faker": "^9.4.0",
31
+ "@types/validator": "^13.12.2",
32
+ "esbuild": "^0.24.2",
33
+ "jsdoc": "^4.0.4",
28
34
  "ts-node": "^10.9.2",
29
35
  "tsx": "^4.19.2",
36
+ "typedoc": "^0.27.6",
37
+ "typedoc-plugin-merge-modules": "^6.1.0",
30
38
  "typescript": "^5.7.3"
31
39
  },
32
40
  "engines": {
@@ -1,51 +0,0 @@
1
- name: Publish package
2
- on:
3
- release:
4
- types:
5
- - published
6
- jobs:
7
- test:
8
- name: Test code
9
- runs-on: ubuntu-latest
10
- steps:
11
- - uses: actions/checkout@v4
12
- - uses: actions/setup-node@v4
13
- with:
14
- node-version: 20
15
- - run: npm install
16
- - run: npm test
17
-
18
- publish:
19
- name: Publish package
20
- needs: test
21
- runs-on: ubuntu-latest
22
- permissions:
23
- contents: read
24
- packages: write
25
- strategy:
26
- matrix:
27
- registry:
28
- - gpr
29
- - npm
30
- steps:
31
- - uses: actions/checkout@v4
32
- - uses: actions/setup-node@v4
33
- - uses: actions/setup-node@v4
34
- with:
35
- node-version: 22
36
- registry-url: ${{ matrix.registry == 'gpr' && 'https://npm.pkg.github.com/' || 'https://registry.npmjs.org/' }}
37
- - name: Extract version from tag
38
- id: extract_version
39
- run: |
40
- VERSION=${GITHUB_REF#refs/tags/v}
41
- echo "VERSION=$VERSION" >> $GITHUB_ENV
42
- - name: Update package.json version
43
- run: |
44
- jq ".version = \"$VERSION\"" package.json > package.tmp.json
45
- mv package.tmp.json package.json
46
- - run: npm install
47
- - run: npm run build
48
- - name: Publish package
49
- run: npm publish
50
- env:
51
- NODE_AUTH_TOKEN: ${{ matrix.registry == 'gpr' && secrets.GITHUB_TOKEN || secrets.npm_token }}
@@ -1,14 +0,0 @@
1
- name: Test package
2
- on: push
3
- jobs:
4
- test:
5
- name: Test package
6
- runs-on: ubuntu-latest
7
- steps:
8
- - uses: actions/checkout@v4
9
- - uses: actions/setup-node@v4
10
- with:
11
- node-version: 20
12
- - run: npm install
13
- - run: npm test
14
- - run: npm run build
package/.gitignore DELETED
@@ -1,6 +0,0 @@
1
- node_modules
2
- dist
3
- package-lock.json
4
- .*
5
- !.gitignore
6
- !.github
package/dist/index.js DELETED
@@ -1,8 +0,0 @@
1
- import { Email } from './types/Email.js';
2
- import parseEnvelope from './parsers/parseEnvelope.js';
3
- import parseMessage from './parsers/parseMessage.js';
4
- export default async function parseEmail(rawData, envelope) {
5
- const parsedEnvelope = await parseEnvelope(envelope);
6
- const { headers, body } = await parseMessage(rawData);
7
- return new Email(parsedEnvelope, headers, body);
8
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Parses envelope metadata from the SMTP transaction.
3
- * @param envelope - Envelope data object
4
- * @returns Parsed Envelope object
5
- */
6
- export default async function parseEnvelope(envelope) {
7
- // TODO: Implement envelope parsing logic
8
- return envelope;
9
- }
@@ -1,65 +0,0 @@
1
- /**
2
- * Parses headers from a raw IMF header string.
3
- * @param rawHeaders - The raw headers as a string
4
- * @returns A dictionary of headers (handling duplicates)
5
- */
6
- export default function parseHeaders(rawHeaders) {
7
- const headers = {};
8
- const lines = rawHeaders.split(/\r\n|\n/);
9
- let currentKey = null;
10
- let currentValue = '';
11
- for (const line of lines) {
12
- if (line.startsWith(' ') || line.startsWith('\t')) {
13
- // Handle folded headers (continuation lines)
14
- if (currentKey) {
15
- if (Array.isArray(headers[currentKey])) {
16
- headers[currentKey][headers[currentKey].length - 1] += ' ' + line.trim();
17
- }
18
- else {
19
- headers[currentKey] += ' ' + line.trim();
20
- }
21
- }
22
- else {
23
- throw new Error('Header folding found without a preceding header field.');
24
- }
25
- }
26
- else {
27
- // Store previous header before starting a new one
28
- if (currentKey) {
29
- if (headers[currentKey]) {
30
- if (Array.isArray(headers[currentKey])) {
31
- headers[currentKey].push(currentValue);
32
- }
33
- else {
34
- headers[currentKey] = [headers[currentKey], currentValue];
35
- }
36
- }
37
- else {
38
- headers[currentKey] = currentValue;
39
- }
40
- }
41
- // Extract new header key-value pair
42
- const match = line.match(/^([!#$%&'*+\-.0-9A-Z^_`a-z|~]+):\s*(.*)$/);
43
- if (!match) {
44
- throw new Error(`Invalid header format: "${line}"`);
45
- }
46
- currentKey = match[1].toLowerCase(); // Convert key to lowercase
47
- currentValue = match[2];
48
- }
49
- }
50
- // Store the last header
51
- if (currentKey) {
52
- if (headers[currentKey]) {
53
- if (Array.isArray(headers[currentKey])) {
54
- headers[currentKey].push(currentValue);
55
- }
56
- else {
57
- headers[currentKey] = [headers[currentKey], currentValue];
58
- }
59
- }
60
- else {
61
- headers[currentKey] = currentValue;
62
- }
63
- }
64
- return headers;
65
- }
@@ -1,30 +0,0 @@
1
- import { Readable } from 'node:stream';
2
- import parseHeaders from './parseHeaders.js';
3
- import streamToString from '../utils/streamToString.js';
4
- /**
5
- * Parses the raw email message (headers + body).
6
- * @param rawData - Raw IMF email (string or stream)
7
- * @returns Parsed email components
8
- */
9
- export default async function parseMessage(rawData) {
10
- let rawEmail;
11
- if (typeof rawData === 'string') {
12
- rawEmail = rawData;
13
- }
14
- else if (rawData instanceof Readable) {
15
- rawEmail = await streamToString(rawData);
16
- }
17
- else {
18
- throw new TypeError('Invalid rawData type. Expected a string or a Readable stream.');
19
- }
20
- const headerBoundary = rawEmail.indexOf('\r\n\r\n');
21
- const rawHeaders = rawEmail.slice(0, headerBoundary);
22
- const body = rawEmail.slice(headerBoundary + 4);
23
- if (body.length === 0) {
24
- throw new Error('Header and Body must be separated by \\r\\n\\r\\n');
25
- }
26
- return {
27
- headers: parseHeaders(rawHeaders),
28
- body,
29
- };
30
- }
@@ -1 +0,0 @@
1
- export {};