email-origin-chain 1.0.0 → 1.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/dist/inline-layer.js +24 -5
- package/dist/mime-layer.js +6 -1
- package/dist/types.d.ts +1 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +40 -0
- package/package.json +2 -2
package/dist/inline-layer.js
CHANGED
|
@@ -27,14 +27,22 @@ async function processInline(text, depth, baseHistory = [], customDetectors = []
|
|
|
27
27
|
flags: ['level:root', 'trust:medium_inline']
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
|
-
// Detection loop
|
|
31
|
-
// with custom local detectors (OutlookFRDetector, etc.)
|
|
30
|
+
// Detection loop
|
|
32
31
|
while (currentDepth < maxRecursiveDepth) {
|
|
33
32
|
const result = registry.detect(currentText);
|
|
34
33
|
if (!result.found || !result.email) {
|
|
35
34
|
// No more forwards detected
|
|
36
35
|
const lastIdx = history.length - 1;
|
|
37
36
|
history[lastIdx].text = (0, utils_1.cleanText)(currentText);
|
|
37
|
+
// Enrich with inline attachments if not already present
|
|
38
|
+
const inlineAtts = (0, utils_1.extractInlineAttachments)(history[lastIdx].text);
|
|
39
|
+
if (inlineAtts.length > 0) {
|
|
40
|
+
const existing = history[lastIdx].attachments || [];
|
|
41
|
+
const toAdd = inlineAtts.filter(a => !existing.find(e => e.filename === a.filename));
|
|
42
|
+
if (toAdd.length > 0) {
|
|
43
|
+
history[lastIdx].attachments = [...existing, ...toAdd];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
38
46
|
break;
|
|
39
47
|
}
|
|
40
48
|
const email = result.email;
|
|
@@ -44,6 +52,15 @@ async function processInline(text, depth, baseHistory = [], customDetectors = []
|
|
|
44
52
|
if (!history[previousIdx].text && !history[previousIdx].flags.includes('content:silent_forward')) {
|
|
45
53
|
history[previousIdx].flags.push('content:silent_forward');
|
|
46
54
|
}
|
|
55
|
+
// Enrich previous level with inline attachments
|
|
56
|
+
const prevInlineAtts = (0, utils_1.extractInlineAttachments)(history[previousIdx].text);
|
|
57
|
+
if (prevInlineAtts.length > 0) {
|
|
58
|
+
const existing = history[previousIdx].attachments || [];
|
|
59
|
+
const toAdd = prevInlineAtts.filter(a => !existing.find(e => e.filename === a.filename));
|
|
60
|
+
if (toAdd.length > 0) {
|
|
61
|
+
history[previousIdx].attachments = [...existing, ...toAdd];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
47
64
|
// Build flags
|
|
48
65
|
const flags = [`method:${result.detector || 'unknown'}`, 'trust:medium_inline'];
|
|
49
66
|
if (!email.body || email.body.trim() === '') {
|
|
@@ -55,20 +72,22 @@ async function processInline(text, depth, baseHistory = [], customDetectors = []
|
|
|
55
72
|
warnings.push(`Could not normalize date: "${email.date}"`);
|
|
56
73
|
flags.push('date:unparseable');
|
|
57
74
|
}
|
|
58
|
-
// Normalize from address
|
|
75
|
+
// Normalize from address
|
|
59
76
|
let fromNormalized = typeof email.from === 'object'
|
|
60
77
|
? { name: email.from.name, address: email.from.address }
|
|
61
78
|
: (email.from ? { address: email.from } : null);
|
|
62
79
|
fromNormalized = (0, utils_1.normalizeFrom)(fromNormalized);
|
|
63
80
|
// Add this forward level to history
|
|
81
|
+
const cleanedBody = (0, utils_1.cleanText)(email.body || '');
|
|
64
82
|
history.push({
|
|
65
83
|
from: fromNormalized,
|
|
66
84
|
subject: email.subject || null,
|
|
67
85
|
date_raw: email.date || null,
|
|
68
86
|
date_iso: dateIso,
|
|
69
|
-
text:
|
|
87
|
+
text: cleanedBody,
|
|
70
88
|
depth: currentDepth + 1,
|
|
71
|
-
flags: flags
|
|
89
|
+
flags: flags,
|
|
90
|
+
attachments: (0, utils_1.extractInlineAttachments)(cleanedBody)
|
|
72
91
|
});
|
|
73
92
|
// Continue with the body for next iteration
|
|
74
93
|
currentText = (email.body || '').trim();
|
package/dist/mime-layer.js
CHANGED
|
@@ -28,7 +28,12 @@ async function processMime(raw, options) {
|
|
|
28
28
|
date_iso: parsed.date ? parsed.date.toISOString() : null,
|
|
29
29
|
text: parsed.text || null, // Will be "exclusive" text once we know if there’s a forward inside
|
|
30
30
|
depth,
|
|
31
|
-
flags: ['trust:high_mime']
|
|
31
|
+
flags: ['trust:high_mime'],
|
|
32
|
+
attachments: parsed.attachments.map(att => ({
|
|
33
|
+
filename: att.filename,
|
|
34
|
+
contentType: att.contentType || 'application/octet-stream',
|
|
35
|
+
size: att.size || 0
|
|
36
|
+
}))
|
|
32
37
|
});
|
|
33
38
|
// Check for attached messages
|
|
34
39
|
const rfcParts = parsed.attachments.filter(a => a.contentType === 'message/rfc822');
|
package/dist/types.d.ts
CHANGED
package/dist/utils.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ResultObject, EmailAddress } from './types';
|
|
2
2
|
export declare function normalizeDateToISO(dateRaw: string | Date | null | undefined): string | null;
|
|
3
3
|
export declare function cleanText(text: string | null | undefined): string | null;
|
|
4
|
+
export declare function extractInlineAttachments(text: string | null | undefined): import('./types').Attachment[];
|
|
4
5
|
/**
|
|
5
6
|
* Normalizes EmailAddress to fix edge cases like "email [email]" pattern
|
|
6
7
|
*
|
package/dist/utils.js
CHANGED
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.normalizeDateToISO = normalizeDateToISO;
|
|
37
37
|
exports.cleanText = cleanText;
|
|
38
|
+
exports.extractInlineAttachments = extractInlineAttachments;
|
|
38
39
|
exports.normalizeFrom = normalizeFrom;
|
|
39
40
|
exports.normalizeParserResult = normalizeParserResult;
|
|
40
41
|
const anyDateParser = __importStar(require("any-date-parser"));
|
|
@@ -109,6 +110,45 @@ function cleanText(text) {
|
|
|
109
110
|
.replace(/[ \t]+$/gm, '') // trim end of lines
|
|
110
111
|
.trim();
|
|
111
112
|
}
|
|
113
|
+
function extractInlineAttachments(text) {
|
|
114
|
+
if (typeof text !== 'string')
|
|
115
|
+
return [];
|
|
116
|
+
const attachments = [];
|
|
117
|
+
const attachmentRegex = /<([-a-zA-Z0-9._ ]+\.([a-zA-Z0-9]+))>/g;
|
|
118
|
+
let match;
|
|
119
|
+
const extensionMap = {
|
|
120
|
+
'pdf': 'application/pdf',
|
|
121
|
+
'jpg': 'image/jpeg',
|
|
122
|
+
'jpeg': 'image/jpeg',
|
|
123
|
+
'png': 'image/png',
|
|
124
|
+
'gif': 'image/gif',
|
|
125
|
+
'zip': 'application/zip',
|
|
126
|
+
'rar': 'application/x-rar-compressed',
|
|
127
|
+
'7z': 'application/x-7z-compressed',
|
|
128
|
+
'doc': 'application/msword',
|
|
129
|
+
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
130
|
+
'xls': 'application/vnd.ms-excel',
|
|
131
|
+
'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
132
|
+
'txt': 'text/plain',
|
|
133
|
+
'csv': 'text/csv',
|
|
134
|
+
'html': 'text/html',
|
|
135
|
+
'xml': 'application/xml',
|
|
136
|
+
'json': 'application/json'
|
|
137
|
+
};
|
|
138
|
+
while ((match = attachmentRegex.exec(text)) !== null) {
|
|
139
|
+
const filename = match[1];
|
|
140
|
+
const ext = match[2]?.toLowerCase();
|
|
141
|
+
// Prevent duplicate filenames in the same node
|
|
142
|
+
if (!attachments.find(a => a.filename === filename)) {
|
|
143
|
+
attachments.push({
|
|
144
|
+
filename: filename,
|
|
145
|
+
contentType: extensionMap[ext] || 'application/octet-stream',
|
|
146
|
+
size: 0
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return attachments;
|
|
151
|
+
}
|
|
112
152
|
/**
|
|
113
153
|
* Normalizes EmailAddress to fix edge cases like "email [email]" pattern
|
|
114
154
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "email-origin-chain",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Uncover the full audit trail of your email threads. Recursively reconstructs the entire conversation history with instant access to the original sender and true source message.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -45,4 +45,4 @@
|
|
|
45
45
|
"email-forward-parser": "^1.7.2",
|
|
46
46
|
"mailparser": "^3.9.1"
|
|
47
47
|
}
|
|
48
|
-
}
|
|
48
|
+
}
|