@bernierllc/email-tracking 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/.eslintrc.cjs +24 -0
- package/README.md +478 -0
- package/__mocks__/neverhub-adapter.ts +29 -0
- package/__tests__/EmailTracking.test.ts +334 -0
- package/__tests__/campaign-stats.test.ts +224 -0
- package/__tests__/config.test.ts +108 -0
- package/__tests__/integration.test.ts +244 -0
- package/__tests__/recipient-history.test.ts +210 -0
- package/__tests__/status-calculator.test.ts +141 -0
- package/coverage/clover.xml +187 -0
- package/coverage/coverage-final.json +6 -0
- package/coverage/lcov-report/EmailTracking.ts.html +973 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/config.ts.html +163 -0
- package/coverage/lcov-report/database.ts.html +622 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +176 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov-report/status-calculator.ts.html +214 -0
- package/coverage/lcov-report/types.ts.html +430 -0
- package/coverage/lcov.info +356 -0
- package/dist/EmailTracking.d.ts +22 -0
- package/dist/EmailTracking.d.ts.map +1 -0
- package/dist/EmailTracking.js +253 -0
- package/dist/EmailTracking.js.map +1 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +27 -0
- package/dist/config.js.map +1 -0
- package/dist/database.d.ts +22 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +156 -0
- package/dist/database.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/status-calculator.d.ts +4 -0
- package/dist/status-calculator.d.ts.map +1 -0
- package/dist/status-calculator.js +40 -0
- package/dist/status-calculator.js.map +1 -0
- package/dist/types.d.ts +98 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +22 -0
- package/dist/types.js.map +1 -0
- package/jest.config.cjs +32 -0
- package/package.json +54 -0
- package/src/EmailTracking.ts +296 -0
- package/src/config.ts +26 -0
- package/src/database.ts +179 -0
- package/src/index.ts +12 -0
- package/src/status-calculator.ts +43 -0
- package/src/types.ts +115 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { EmailSendRecord, EmailEvent, RecipientHistory, EmailDeliveryStatus, CampaignStatistics } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* In-memory database implementation for email tracking.
|
|
4
|
+
* In production, this would be replaced with a real database (PostgreSQL, etc.)
|
|
5
|
+
*/
|
|
6
|
+
export declare class Database {
|
|
7
|
+
private sendRecords;
|
|
8
|
+
private messageIdIndex;
|
|
9
|
+
private events;
|
|
10
|
+
private recipientHistory;
|
|
11
|
+
storeSendRecord(record: EmailSendRecord): Promise<void>;
|
|
12
|
+
getSendRecord(trackingId: string): Promise<EmailSendRecord | null>;
|
|
13
|
+
findSendRecordByMessageId(messageId: string): Promise<EmailSendRecord | null>;
|
|
14
|
+
updateSendRecordStatus(trackingId: string, status: EmailDeliveryStatus): Promise<void>;
|
|
15
|
+
createEvent(event: EmailEvent): Promise<void>;
|
|
16
|
+
getEventsBySendRecord(sendRecordId: string): Promise<EmailEvent[]>;
|
|
17
|
+
updateRecipientHistory(recipients: string[], eventType: EmailDeliveryStatus): Promise<void>;
|
|
18
|
+
fetchRecipientHistory(emailAddress: string): Promise<RecipientHistory>;
|
|
19
|
+
aggregateCampaignStats(campaignId: string): Promise<CampaignStatistics>;
|
|
20
|
+
clear(): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=database.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,eAAe,EACf,UAAU,EACV,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,WAAW,CAA2C;IAC9D,OAAO,CAAC,cAAc,CAAkC;IACxD,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,gBAAgB,CAA4C;IAE9D,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvD,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAIlE,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAM7E,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAStF,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAM7C,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAIlE,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAwD3F,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAoBtE,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAoCvE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAM7B"}
|
package/dist/database.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Copyright (c) 2025 Bernier LLC
|
|
4
|
+
|
|
5
|
+
This file is licensed to the client under a limited-use license.
|
|
6
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
7
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.Database = void 0;
|
|
11
|
+
const types_js_1 = require("./types.js");
|
|
12
|
+
/**
|
|
13
|
+
* In-memory database implementation for email tracking.
|
|
14
|
+
* In production, this would be replaced with a real database (PostgreSQL, etc.)
|
|
15
|
+
*/
|
|
16
|
+
class Database {
|
|
17
|
+
constructor() {
|
|
18
|
+
this.sendRecords = new Map();
|
|
19
|
+
this.messageIdIndex = new Map(); // messageId -> trackingId
|
|
20
|
+
this.events = new Map(); // sendRecordId -> events[]
|
|
21
|
+
this.recipientHistory = new Map();
|
|
22
|
+
}
|
|
23
|
+
async storeSendRecord(record) {
|
|
24
|
+
this.sendRecords.set(record.id, record);
|
|
25
|
+
this.messageIdIndex.set(record.messageId, record.id);
|
|
26
|
+
}
|
|
27
|
+
async getSendRecord(trackingId) {
|
|
28
|
+
return this.sendRecords.get(trackingId) || null;
|
|
29
|
+
}
|
|
30
|
+
async findSendRecordByMessageId(messageId) {
|
|
31
|
+
const trackingId = this.messageIdIndex.get(messageId);
|
|
32
|
+
if (!trackingId)
|
|
33
|
+
return null;
|
|
34
|
+
return this.getSendRecord(trackingId);
|
|
35
|
+
}
|
|
36
|
+
async updateSendRecordStatus(trackingId, status) {
|
|
37
|
+
const record = this.sendRecords.get(trackingId);
|
|
38
|
+
if (record) {
|
|
39
|
+
record.currentStatus = status;
|
|
40
|
+
record.updatedAt = new Date();
|
|
41
|
+
this.sendRecords.set(trackingId, record);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async createEvent(event) {
|
|
45
|
+
const existingEvents = this.events.get(event.sendRecordId) || [];
|
|
46
|
+
existingEvents.push(event);
|
|
47
|
+
this.events.set(event.sendRecordId, existingEvents);
|
|
48
|
+
}
|
|
49
|
+
async getEventsBySendRecord(sendRecordId) {
|
|
50
|
+
return this.events.get(sendRecordId) || [];
|
|
51
|
+
}
|
|
52
|
+
async updateRecipientHistory(recipients, eventType) {
|
|
53
|
+
for (const recipient of recipients) {
|
|
54
|
+
let history = this.recipientHistory.get(recipient);
|
|
55
|
+
if (!history) {
|
|
56
|
+
history = {
|
|
57
|
+
emailAddress: recipient,
|
|
58
|
+
totalSent: 0,
|
|
59
|
+
totalDelivered: 0,
|
|
60
|
+
totalBounced: 0,
|
|
61
|
+
totalOpened: 0,
|
|
62
|
+
totalClicked: 0,
|
|
63
|
+
totalComplained: 0,
|
|
64
|
+
totalUnsubscribed: 0,
|
|
65
|
+
reputationScore: 100
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const now = new Date();
|
|
69
|
+
switch (eventType) {
|
|
70
|
+
case types_js_1.EmailDeliveryStatus.SENT:
|
|
71
|
+
history.totalSent++;
|
|
72
|
+
history.lastSentAt = now;
|
|
73
|
+
break;
|
|
74
|
+
case types_js_1.EmailDeliveryStatus.DELIVERED:
|
|
75
|
+
history.totalDelivered++;
|
|
76
|
+
history.lastDeliveredAt = now;
|
|
77
|
+
break;
|
|
78
|
+
case types_js_1.EmailDeliveryStatus.BOUNCED:
|
|
79
|
+
history.totalBounced++;
|
|
80
|
+
history.lastBouncedAt = now;
|
|
81
|
+
history.reputationScore = Math.max(0, history.reputationScore - 10);
|
|
82
|
+
break;
|
|
83
|
+
case types_js_1.EmailDeliveryStatus.OPENED:
|
|
84
|
+
history.totalOpened++;
|
|
85
|
+
history.lastOpenedAt = now;
|
|
86
|
+
break;
|
|
87
|
+
case types_js_1.EmailDeliveryStatus.CLICKED:
|
|
88
|
+
history.totalClicked++;
|
|
89
|
+
history.lastClickedAt = now;
|
|
90
|
+
break;
|
|
91
|
+
case types_js_1.EmailDeliveryStatus.COMPLAINED:
|
|
92
|
+
history.totalComplained++;
|
|
93
|
+
history.reputationScore = Math.max(0, history.reputationScore - 25);
|
|
94
|
+
break;
|
|
95
|
+
case types_js_1.EmailDeliveryStatus.UNSUBSCRIBED:
|
|
96
|
+
history.totalUnsubscribed++;
|
|
97
|
+
history.reputationScore = Math.max(0, history.reputationScore - 5);
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
this.recipientHistory.set(recipient, history);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async fetchRecipientHistory(emailAddress) {
|
|
104
|
+
const history = this.recipientHistory.get(emailAddress);
|
|
105
|
+
if (!history) {
|
|
106
|
+
return {
|
|
107
|
+
emailAddress,
|
|
108
|
+
totalSent: 0,
|
|
109
|
+
totalDelivered: 0,
|
|
110
|
+
totalBounced: 0,
|
|
111
|
+
totalOpened: 0,
|
|
112
|
+
totalClicked: 0,
|
|
113
|
+
totalComplained: 0,
|
|
114
|
+
totalUnsubscribed: 0,
|
|
115
|
+
reputationScore: 100
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return history;
|
|
119
|
+
}
|
|
120
|
+
async aggregateCampaignStats(campaignId) {
|
|
121
|
+
const campaignRecords = Array.from(this.sendRecords.values())
|
|
122
|
+
.filter(record => record.campaignId === campaignId);
|
|
123
|
+
const totalSent = campaignRecords.length;
|
|
124
|
+
const totalDelivered = campaignRecords.filter(r => [types_js_1.EmailDeliveryStatus.DELIVERED, types_js_1.EmailDeliveryStatus.OPENED, types_js_1.EmailDeliveryStatus.CLICKED]
|
|
125
|
+
.includes(r.currentStatus)).length;
|
|
126
|
+
const totalBounced = campaignRecords.filter(r => r.currentStatus === types_js_1.EmailDeliveryStatus.BOUNCED).length;
|
|
127
|
+
const totalOpened = campaignRecords.filter(r => [types_js_1.EmailDeliveryStatus.OPENED, types_js_1.EmailDeliveryStatus.CLICKED].includes(r.currentStatus)).length;
|
|
128
|
+
const totalClicked = campaignRecords.filter(r => r.currentStatus === types_js_1.EmailDeliveryStatus.CLICKED).length;
|
|
129
|
+
const totalComplained = campaignRecords.filter(r => r.currentStatus === types_js_1.EmailDeliveryStatus.COMPLAINED).length;
|
|
130
|
+
const totalUnsubscribed = campaignRecords.filter(r => r.currentStatus === types_js_1.EmailDeliveryStatus.UNSUBSCRIBED).length;
|
|
131
|
+
const deliveryRate = totalSent > 0 ? (totalDelivered / totalSent) * 100 : 0;
|
|
132
|
+
const openRate = totalDelivered > 0 ? (totalOpened / totalDelivered) * 100 : 0;
|
|
133
|
+
const clickRate = totalOpened > 0 ? (totalClicked / totalOpened) * 100 : 0;
|
|
134
|
+
return {
|
|
135
|
+
campaignId,
|
|
136
|
+
totalSent,
|
|
137
|
+
totalDelivered,
|
|
138
|
+
totalBounced,
|
|
139
|
+
totalOpened,
|
|
140
|
+
totalClicked,
|
|
141
|
+
totalComplained,
|
|
142
|
+
totalUnsubscribed,
|
|
143
|
+
deliveryRate: Math.round(deliveryRate * 100) / 100,
|
|
144
|
+
openRate: Math.round(openRate * 100) / 100,
|
|
145
|
+
clickRate: Math.round(clickRate * 100) / 100
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
async clear() {
|
|
149
|
+
this.sendRecords.clear();
|
|
150
|
+
this.messageIdIndex.clear();
|
|
151
|
+
this.events.clear();
|
|
152
|
+
this.recipientHistory.clear();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
exports.Database = Database;
|
|
156
|
+
//# sourceMappingURL=database.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Copyright (c) 2025 Bernier LLC
|
|
4
|
+
|
|
5
|
+
This file is licensed to the client under a limited-use license.
|
|
6
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
7
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
21
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
22
|
+
};
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.loadConfig = exports.mapWebhookEventType = exports.calculateNewStatus = exports.EmailTracking = void 0;
|
|
25
|
+
var EmailTracking_js_1 = require("./EmailTracking.js");
|
|
26
|
+
Object.defineProperty(exports, "EmailTracking", { enumerable: true, get: function () { return EmailTracking_js_1.EmailTracking; } });
|
|
27
|
+
__exportStar(require("./types.js"), exports);
|
|
28
|
+
var status_calculator_js_1 = require("./status-calculator.js");
|
|
29
|
+
Object.defineProperty(exports, "calculateNewStatus", { enumerable: true, get: function () { return status_calculator_js_1.calculateNewStatus; } });
|
|
30
|
+
Object.defineProperty(exports, "mapWebhookEventType", { enumerable: true, get: function () { return status_calculator_js_1.mapWebhookEventType; } });
|
|
31
|
+
var config_js_1 = require("./config.js");
|
|
32
|
+
Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return config_js_1.loadConfig; } });
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;EAME;;;;;;;;;;;;;;;;;AAEF,uDAAmD;AAA1C,iHAAA,aAAa,OAAA;AACtB,6CAA2B;AAC3B,+DAAiF;AAAxE,0HAAA,kBAAkB,OAAA;AAAE,2HAAA,mBAAmB,OAAA;AAChD,yCAAyC;AAAhC,uGAAA,UAAU,OAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { EmailDeliveryStatus } from './types.js';
|
|
2
|
+
export declare function calculateNewStatus(currentStatus: EmailDeliveryStatus, eventType: EmailDeliveryStatus): EmailDeliveryStatus;
|
|
3
|
+
export declare function mapWebhookEventType(webhookEventType: string): EmailDeliveryStatus;
|
|
4
|
+
//# sourceMappingURL=status-calculator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-calculator.d.ts","sourceRoot":"","sources":["../src/status-calculator.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAajD,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,mBAAmB,EAClC,SAAS,EAAE,mBAAmB,GAC7B,mBAAmB,CAIrB;AAED,wBAAgB,mBAAmB,CAAC,gBAAgB,EAAE,MAAM,GAAG,mBAAmB,CAYjF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Copyright (c) 2025 Bernier LLC
|
|
4
|
+
|
|
5
|
+
This file is licensed to the client under a limited-use license.
|
|
6
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
7
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.calculateNewStatus = calculateNewStatus;
|
|
11
|
+
exports.mapWebhookEventType = mapWebhookEventType;
|
|
12
|
+
const types_js_1 = require("./types.js");
|
|
13
|
+
const STATUS_PRIORITY = {
|
|
14
|
+
[types_js_1.EmailDeliveryStatus.COMPLAINED]: 7,
|
|
15
|
+
[types_js_1.EmailDeliveryStatus.UNSUBSCRIBED]: 6,
|
|
16
|
+
[types_js_1.EmailDeliveryStatus.BOUNCED]: 5,
|
|
17
|
+
[types_js_1.EmailDeliveryStatus.FAILED]: 4,
|
|
18
|
+
[types_js_1.EmailDeliveryStatus.CLICKED]: 3,
|
|
19
|
+
[types_js_1.EmailDeliveryStatus.OPENED]: 2,
|
|
20
|
+
[types_js_1.EmailDeliveryStatus.DELIVERED]: 1,
|
|
21
|
+
[types_js_1.EmailDeliveryStatus.SENT]: 0
|
|
22
|
+
};
|
|
23
|
+
function calculateNewStatus(currentStatus, eventType) {
|
|
24
|
+
return STATUS_PRIORITY[eventType] > STATUS_PRIORITY[currentStatus]
|
|
25
|
+
? eventType
|
|
26
|
+
: currentStatus;
|
|
27
|
+
}
|
|
28
|
+
function mapWebhookEventType(webhookEventType) {
|
|
29
|
+
const mapping = {
|
|
30
|
+
delivered: types_js_1.EmailDeliveryStatus.DELIVERED,
|
|
31
|
+
bounce: types_js_1.EmailDeliveryStatus.BOUNCED,
|
|
32
|
+
open: types_js_1.EmailDeliveryStatus.OPENED,
|
|
33
|
+
click: types_js_1.EmailDeliveryStatus.CLICKED,
|
|
34
|
+
spamreport: types_js_1.EmailDeliveryStatus.COMPLAINED,
|
|
35
|
+
unsubscribe: types_js_1.EmailDeliveryStatus.UNSUBSCRIBED,
|
|
36
|
+
failed: types_js_1.EmailDeliveryStatus.FAILED
|
|
37
|
+
};
|
|
38
|
+
return mapping[webhookEventType.toLowerCase()] || types_js_1.EmailDeliveryStatus.SENT;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=status-calculator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-calculator.js","sourceRoot":"","sources":["../src/status-calculator.ts"],"names":[],"mappings":";AAAA;;;;;;EAME;;AAeF,gDAOC;AAED,kDAYC;AAlCD,yCAAiD;AAEjD,MAAM,eAAe,GAAwC;IAC3D,CAAC,8BAAmB,CAAC,UAAU,CAAC,EAAE,CAAC;IACnC,CAAC,8BAAmB,CAAC,YAAY,CAAC,EAAE,CAAC;IACrC,CAAC,8BAAmB,CAAC,OAAO,CAAC,EAAE,CAAC;IAChC,CAAC,8BAAmB,CAAC,MAAM,CAAC,EAAE,CAAC;IAC/B,CAAC,8BAAmB,CAAC,OAAO,CAAC,EAAE,CAAC;IAChC,CAAC,8BAAmB,CAAC,MAAM,CAAC,EAAE,CAAC;IAC/B,CAAC,8BAAmB,CAAC,SAAS,CAAC,EAAE,CAAC;IAClC,CAAC,8BAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;CAC9B,CAAC;AAEF,SAAgB,kBAAkB,CAChC,aAAkC,EAClC,SAA8B;IAE9B,OAAO,eAAe,CAAC,SAAS,CAAC,GAAG,eAAe,CAAC,aAAa,CAAC;QAChE,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,aAAa,CAAC;AACpB,CAAC;AAED,SAAgB,mBAAmB,CAAC,gBAAwB;IAC1D,MAAM,OAAO,GAAwC;QACnD,SAAS,EAAE,8BAAmB,CAAC,SAAS;QACxC,MAAM,EAAE,8BAAmB,CAAC,OAAO;QACnC,IAAI,EAAE,8BAAmB,CAAC,MAAM;QAChC,KAAK,EAAE,8BAAmB,CAAC,OAAO;QAClC,UAAU,EAAE,8BAAmB,CAAC,UAAU;QAC1C,WAAW,EAAE,8BAAmB,CAAC,YAAY;QAC7C,MAAM,EAAE,8BAAmB,CAAC,MAAM;KACnC,CAAC;IAEF,OAAO,OAAO,CAAC,gBAAgB,CAAC,WAAW,EAAE,CAAC,IAAI,8BAAmB,CAAC,IAAI,CAAC;AAC7E,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
export declare enum EmailDeliveryStatus {
|
|
2
|
+
SENT = "sent",
|
|
3
|
+
DELIVERED = "delivered",
|
|
4
|
+
BOUNCED = "bounced",
|
|
5
|
+
OPENED = "opened",
|
|
6
|
+
CLICKED = "clicked",
|
|
7
|
+
COMPLAINED = "complained",
|
|
8
|
+
UNSUBSCRIBED = "unsubscribed",
|
|
9
|
+
FAILED = "failed"
|
|
10
|
+
}
|
|
11
|
+
export type EmailProvider = 'sendgrid' | 'mailgun' | 'ses' | 'postmark';
|
|
12
|
+
export interface EmailSendRecord {
|
|
13
|
+
id: string;
|
|
14
|
+
messageId: string;
|
|
15
|
+
provider: EmailProvider;
|
|
16
|
+
from: string;
|
|
17
|
+
to: string[];
|
|
18
|
+
cc?: string[];
|
|
19
|
+
bcc?: string[];
|
|
20
|
+
subject: string;
|
|
21
|
+
campaignId?: string;
|
|
22
|
+
metadata?: Record<string, unknown>;
|
|
23
|
+
sentAt: Date;
|
|
24
|
+
currentStatus: EmailDeliveryStatus;
|
|
25
|
+
updatedAt: Date;
|
|
26
|
+
}
|
|
27
|
+
export interface EmailEvent {
|
|
28
|
+
id: string;
|
|
29
|
+
sendRecordId: string;
|
|
30
|
+
eventType: EmailDeliveryStatus;
|
|
31
|
+
timestamp: Date;
|
|
32
|
+
metadata?: Record<string, unknown>;
|
|
33
|
+
sourceEvent?: unknown;
|
|
34
|
+
}
|
|
35
|
+
export interface EmailTimeline {
|
|
36
|
+
sendRecord: EmailSendRecord;
|
|
37
|
+
events: EmailEvent[];
|
|
38
|
+
currentStatus: EmailDeliveryStatus;
|
|
39
|
+
lastEventAt: Date;
|
|
40
|
+
}
|
|
41
|
+
export interface RecipientHistory {
|
|
42
|
+
emailAddress: string;
|
|
43
|
+
totalSent: number;
|
|
44
|
+
totalDelivered: number;
|
|
45
|
+
totalBounced: number;
|
|
46
|
+
totalOpened: number;
|
|
47
|
+
totalClicked: number;
|
|
48
|
+
totalComplained: number;
|
|
49
|
+
totalUnsubscribed: number;
|
|
50
|
+
lastSentAt?: Date;
|
|
51
|
+
lastDeliveredAt?: Date;
|
|
52
|
+
lastBouncedAt?: Date;
|
|
53
|
+
lastOpenedAt?: Date;
|
|
54
|
+
lastClickedAt?: Date;
|
|
55
|
+
reputationScore: number;
|
|
56
|
+
}
|
|
57
|
+
export interface TrackingConfig {
|
|
58
|
+
enableOpenTracking?: boolean;
|
|
59
|
+
enableClickTracking?: boolean;
|
|
60
|
+
eventRetentionDays?: number;
|
|
61
|
+
aggregateStats?: boolean;
|
|
62
|
+
}
|
|
63
|
+
export interface EmailTrackingResult<T = unknown> {
|
|
64
|
+
success: boolean;
|
|
65
|
+
data?: T;
|
|
66
|
+
error?: string;
|
|
67
|
+
}
|
|
68
|
+
export interface RecordEmailSentData {
|
|
69
|
+
messageId: string;
|
|
70
|
+
provider: string;
|
|
71
|
+
from: string;
|
|
72
|
+
to: string[];
|
|
73
|
+
cc?: string[];
|
|
74
|
+
bcc?: string[];
|
|
75
|
+
subject: string;
|
|
76
|
+
campaignId?: string;
|
|
77
|
+
metadata?: Record<string, unknown>;
|
|
78
|
+
}
|
|
79
|
+
export interface WebhookEventData {
|
|
80
|
+
messageId: string;
|
|
81
|
+
eventType: string;
|
|
82
|
+
timestamp: string | Date;
|
|
83
|
+
metadata?: Record<string, unknown>;
|
|
84
|
+
}
|
|
85
|
+
export interface CampaignStatistics {
|
|
86
|
+
campaignId: string;
|
|
87
|
+
totalSent: number;
|
|
88
|
+
totalDelivered: number;
|
|
89
|
+
totalBounced: number;
|
|
90
|
+
totalOpened: number;
|
|
91
|
+
totalClicked: number;
|
|
92
|
+
totalComplained: number;
|
|
93
|
+
totalUnsubscribed: number;
|
|
94
|
+
deliveryRate: number;
|
|
95
|
+
openRate: number;
|
|
96
|
+
clickRate: number;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Copyright (c) 2025 Bernier LLC
|
|
4
|
+
|
|
5
|
+
This file is licensed to the client under a limited-use license.
|
|
6
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
7
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.EmailDeliveryStatus = void 0;
|
|
11
|
+
var EmailDeliveryStatus;
|
|
12
|
+
(function (EmailDeliveryStatus) {
|
|
13
|
+
EmailDeliveryStatus["SENT"] = "sent";
|
|
14
|
+
EmailDeliveryStatus["DELIVERED"] = "delivered";
|
|
15
|
+
EmailDeliveryStatus["BOUNCED"] = "bounced";
|
|
16
|
+
EmailDeliveryStatus["OPENED"] = "opened";
|
|
17
|
+
EmailDeliveryStatus["CLICKED"] = "clicked";
|
|
18
|
+
EmailDeliveryStatus["COMPLAINED"] = "complained";
|
|
19
|
+
EmailDeliveryStatus["UNSUBSCRIBED"] = "unsubscribed";
|
|
20
|
+
EmailDeliveryStatus["FAILED"] = "failed";
|
|
21
|
+
})(EmailDeliveryStatus || (exports.EmailDeliveryStatus = EmailDeliveryStatus = {}));
|
|
22
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;;;;;EAME;;;AAEF,IAAY,mBASX;AATD,WAAY,mBAAmB;IAC7B,oCAAa,CAAA;IACb,8CAAuB,CAAA;IACvB,0CAAmB,CAAA;IACnB,wCAAiB,CAAA;IACjB,0CAAmB,CAAA;IACnB,gDAAyB,CAAA;IACzB,oDAA6B,CAAA;IAC7B,wCAAiB,CAAA;AACnB,CAAC,EATW,mBAAmB,mCAAnB,mBAAmB,QAS9B"}
|
package/jest.config.cjs
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2025 Bernier LLC
|
|
3
|
+
|
|
4
|
+
This file is licensed to the client under a limited-use license.
|
|
5
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
preset: 'ts-jest',
|
|
11
|
+
testEnvironment: '<rootDir>/../../../jest-environment-node-fixed.cjs',
|
|
12
|
+
collectCoverageFrom: [
|
|
13
|
+
'src/**/*.{ts,tsx}',
|
|
14
|
+
'!src/**/*.d.ts',
|
|
15
|
+
'!src/index.ts'
|
|
16
|
+
],
|
|
17
|
+
coverageThreshold: {
|
|
18
|
+
global: {
|
|
19
|
+
branches: 74,
|
|
20
|
+
functions: 85,
|
|
21
|
+
lines: 85,
|
|
22
|
+
statements: 85
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
testMatch: [
|
|
26
|
+
'**/__tests__/**/*.test.ts'
|
|
27
|
+
],
|
|
28
|
+
moduleNameMapper: {
|
|
29
|
+
'^(\\.{1,2}/.*)\\.js$': '$1',
|
|
30
|
+
'@bernierllc/neverhub-adapter': '<rootDir>/__mocks__/neverhub-adapter.ts'
|
|
31
|
+
}
|
|
32
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bernierllc/email-tracking",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Email delivery tracking service that monitors email lifecycle from send to delivery/bounce/open/click",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"email",
|
|
9
|
+
"tracking",
|
|
10
|
+
"delivery",
|
|
11
|
+
"analytics",
|
|
12
|
+
"events",
|
|
13
|
+
"webhooks",
|
|
14
|
+
"sendgrid",
|
|
15
|
+
"mailgun",
|
|
16
|
+
"ses",
|
|
17
|
+
"postmark"
|
|
18
|
+
],
|
|
19
|
+
"author": "Bernier LLC",
|
|
20
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@bernierllc/email-webhook-events": "^1.0.0",
|
|
23
|
+
"@bernierllc/logger": "^1.2.0",
|
|
24
|
+
"@bernierllc/neverhub-adapter": "^1.0.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/jest": "^29.0.0",
|
|
28
|
+
"@types/node": "^20.0.0",
|
|
29
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
30
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
31
|
+
"eslint": "^8.0.0",
|
|
32
|
+
"jest": "^29.0.0",
|
|
33
|
+
"ts-jest": "^29.0.0",
|
|
34
|
+
"typescript": "^5.0.0"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"bernierllc": {
|
|
40
|
+
"integration": {
|
|
41
|
+
"neverhub": "required",
|
|
42
|
+
"neveradmin": "not-applicable",
|
|
43
|
+
"logger": "integrated"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsc",
|
|
48
|
+
"test": "jest --watch",
|
|
49
|
+
"test:run": "jest",
|
|
50
|
+
"test:coverage": "jest --coverage",
|
|
51
|
+
"lint": "eslint src --ext .ts",
|
|
52
|
+
"clean": "rm -rf dist"
|
|
53
|
+
}
|
|
54
|
+
}
|