@huloglobal/vendure-plugin-email-tracking 0.1.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/LICENSE +34 -0
  3. package/README.md +129 -0
  4. package/dist/email-log.entity.d.ts +57 -0
  5. package/dist/email-log.entity.d.ts.map +1 -0
  6. package/dist/email-log.entity.js +147 -0
  7. package/dist/email-log.entity.js.map +1 -0
  8. package/dist/email-tracking.controller.d.ts +51 -0
  9. package/dist/email-tracking.controller.d.ts.map +1 -0
  10. package/dist/email-tracking.controller.js +260 -0
  11. package/dist/email-tracking.controller.js.map +1 -0
  12. package/dist/email-tracking.service.d.ts +48 -0
  13. package/dist/email-tracking.service.d.ts.map +1 -0
  14. package/dist/email-tracking.service.js +196 -0
  15. package/dist/email-tracking.service.js.map +1 -0
  16. package/dist/index.d.ts +16 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +22 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/options.d.ts +43 -0
  21. package/dist/options.d.ts.map +1 -0
  22. package/dist/options.js +52 -0
  23. package/dist/options.js.map +1 -0
  24. package/dist/plugin.d.ts +53 -0
  25. package/dist/plugin.d.ts.map +1 -0
  26. package/dist/plugin.js +118 -0
  27. package/dist/plugin.js.map +1 -0
  28. package/dist/proxy-headers.d.ts +37 -0
  29. package/dist/proxy-headers.d.ts.map +1 -0
  30. package/dist/proxy-headers.js +81 -0
  31. package/dist/proxy-headers.js.map +1 -0
  32. package/dist/tracking-email-sender.d.ts +22 -0
  33. package/dist/tracking-email-sender.d.ts.map +1 -0
  34. package/dist/tracking-email-sender.js +117 -0
  35. package/dist/tracking-email-sender.js.map +1 -0
  36. package/package.json +53 -0
  37. package/ui/components/email-log.component.ts +372 -0
  38. package/ui/email-log-nav.module.ts +24 -0
  39. package/ui/email-log.module.ts +17 -0
@@ -0,0 +1,260 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.EmailTrackingController = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const core_1 = require("@vendure/core");
18
+ const email_log_entity_1 = require("./email-log.entity");
19
+ const email_tracking_service_1 = require("./email-tracking.service");
20
+ const loggerCtx = 'EmailTrackingController';
21
+ // 1×1 transparent GIF (43 bytes) returned by the open-tracking endpoint.
22
+ const ONE_PX_GIF = Buffer.from('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', 'base64');
23
+ const proxy_headers_1 = require("./proxy-headers");
24
+ function realIp(req) { return (0, proxy_headers_1.getRealIp)(req); }
25
+ function requireAdmin(ctx, res, write = false) {
26
+ if (!(ctx === null || ctx === void 0 ? void 0 : ctx.activeUserId)) {
27
+ res.status(401).json({ error: 'Authentication required' });
28
+ return false;
29
+ }
30
+ const needed = write ? [core_1.Permission.UpdateCustomer] : [core_1.Permission.ReadCustomer];
31
+ if (!ctx.userHasPermissions(needed)) {
32
+ res.status(403).json({ error: 'Insufficient permissions' });
33
+ return false;
34
+ }
35
+ return true;
36
+ }
37
+ let EmailTrackingController = class EmailTrackingController {
38
+ constructor(connection, tracking) {
39
+ this.connection = connection;
40
+ this.tracking = tracking;
41
+ }
42
+ /**
43
+ * Open-tracking pixel. Returns a 1×1 transparent GIF and logs the
44
+ * open against the event. No-cache so privacy-protecting prefetchers
45
+ * still get caught per fetch (and we count opens accurately).
46
+ *
47
+ * GET /email-track/open/:id.gif
48
+ */
49
+ async open(idParam, req, res) {
50
+ const id = parseInt(idParam, 10);
51
+ if (!isNaN(id) && id > 0) {
52
+ this.tracking.recordOpen(id, realIp(req), req.headers['user-agent'] || null)
53
+ .catch((e) => core_1.Logger.warn(`open log fail #${id}: ${e === null || e === void 0 ? void 0 : e.message}`, loggerCtx));
54
+ }
55
+ res.setHeader('Content-Type', 'image/gif');
56
+ res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0');
57
+ res.setHeader('Pragma', 'no-cache');
58
+ res.setHeader('Expires', '0');
59
+ return res.end(ONE_PX_GIF);
60
+ }
61
+ /**
62
+ * Click redirect. Logs the click then 302-redirects to the original
63
+ * URL. Returns 400 if the URL is missing or malformed (we never
64
+ * redirect to an empty / javascript: target).
65
+ *
66
+ * GET /email-track/click/:id?u=<encoded>
67
+ */
68
+ async click(idParam, u, req, res) {
69
+ const id = parseInt(idParam, 10);
70
+ const url = (u || '').trim();
71
+ if (!url || !/^https?:\/\//i.test(url)) {
72
+ return res.status(400).send('Invalid redirect target');
73
+ }
74
+ if (!isNaN(id) && id > 0) {
75
+ await this.tracking.recordClick(id, url, realIp(req), req.headers['user-agent'] || null)
76
+ .catch((e) => core_1.Logger.warn(`click log fail #${id}: ${e === null || e === void 0 ? void 0 : e.message}`, loggerCtx));
77
+ }
78
+ res.setHeader('Cache-Control', 'no-store');
79
+ return res.redirect(302, url);
80
+ }
81
+ /**
82
+ * Bounce webhook. Wire up a postmaster / mail-server hook (or have a
83
+ * scheduled DSN-parser POST here) to mark messages as bounced or
84
+ * complained. Both fields are required; the messageId is the
85
+ * `<...@domain>` value Gmail returned at submit time.
86
+ *
87
+ * POST /email-track/bounce
88
+ * Body: { messageId, status: 'bounced'|'complained', reason? }
89
+ *
90
+ * Currently unauthenticated to keep the integration simple — gate
91
+ * behind a shared secret header if you expose the endpoint to the
92
+ * public internet (it's fine on a private network).
93
+ */
94
+ async bounce(body, res) {
95
+ const messageId = String((body === null || body === void 0 ? void 0 : body.messageId) || '').trim();
96
+ const status = (body === null || body === void 0 ? void 0 : body.status) === 'complained' ? 'complained' : 'bounced';
97
+ if (!messageId)
98
+ return res.status(400).json({ error: 'messageId required' });
99
+ const ok = await this.tracking.recordBounce(messageId, status, body === null || body === void 0 ? void 0 : body.reason);
100
+ return res.json({ ok, matched: ok });
101
+ }
102
+ /**
103
+ * Admin: list email events, with filtering for the "Email Log" page
104
+ * and the per-customer Emails tab. Filterable by customerId, orderId,
105
+ * orderCode, status, type, recipient, and a date range.
106
+ *
107
+ * GET /email-track/log?customerId=&orderId=&status=&take=
108
+ */
109
+ async listLog(ctx, req, res) {
110
+ if (!requireAdmin(ctx, res, false))
111
+ return;
112
+ const q = req.query;
113
+ const take = Math.min(parseInt(q.take, 10) || 100, 500);
114
+ const skip = parseInt(q.skip, 10) || 0;
115
+ const where = [];
116
+ const params = [];
117
+ if (q.customerId) {
118
+ where.push('customerId = ?');
119
+ params.push(parseInt(q.customerId, 10));
120
+ }
121
+ if (q.orderId) {
122
+ where.push('orderId = ?');
123
+ params.push(parseInt(q.orderId, 10));
124
+ }
125
+ if (q.orderCode) {
126
+ where.push('orderCode = ?');
127
+ params.push(String(q.orderCode));
128
+ }
129
+ if (q.invoiceId) {
130
+ where.push('invoiceId = ?');
131
+ params.push(parseInt(q.invoiceId, 10));
132
+ }
133
+ if (q.status) {
134
+ where.push('status = ?');
135
+ params.push(String(q.status));
136
+ }
137
+ if (q.type) {
138
+ where.push('type = ?');
139
+ params.push(String(q.type));
140
+ }
141
+ if (q.recipient) {
142
+ where.push('recipient LIKE ?');
143
+ params.push(`%${String(q.recipient)}%`);
144
+ }
145
+ if (q.from) {
146
+ where.push('createdAt >= ?');
147
+ params.push(new Date(String(q.from)));
148
+ }
149
+ if (q.to) {
150
+ where.push('createdAt <= ?');
151
+ params.push(new Date(String(q.to)));
152
+ }
153
+ const whereClause = where.length ? ` WHERE ${where.join(' AND ')}` : '';
154
+ const rows = await this.connection.rawConnection.query(`SELECT id, createdAt, type, recipient, subject, status,
155
+ customerId, orderId, orderCode, invoiceId, applicationId,
156
+ channelId, openCount, firstOpenedAt, lastOpenedAt,
157
+ clickCount, firstClickedAt, smtpResponse, errorMessage
158
+ FROM email_log
159
+ ${whereClause}
160
+ ORDER BY createdAt DESC
161
+ LIMIT ? OFFSET ?`, [...params, take, skip]);
162
+ const [{ total }] = await this.connection.rawConnection.query(`SELECT COUNT(*) AS total FROM email_log${whereClause}`, params);
163
+ return res.json({ items: rows, total: Number(total) || 0, take, skip });
164
+ }
165
+ /** Admin: aggregate counts by status for a quick dashboard tile. */
166
+ async logSummary(ctx, req, res) {
167
+ if (!requireAdmin(ctx, res, false))
168
+ return;
169
+ const fromDays = parseInt(req.query.fromDays, 10) || 30;
170
+ const rows = await this.connection.rawConnection.query(`SELECT status, COUNT(*) AS n, SUM(openCount) AS opens, SUM(clickCount) AS clicks
171
+ FROM email_log
172
+ WHERE createdAt >= DATE_SUB(NOW(), INTERVAL ? DAY)
173
+ GROUP BY status`, [fromDays]);
174
+ const summary = { sent: 0, failed: 0, deferred: 0, bounced: 0, complained: 0, opens: 0, clicks: 0, fromDays };
175
+ for (const r of rows) {
176
+ summary[r.status] = Number(r.n);
177
+ summary.opens += Number(r.opens) || 0;
178
+ summary.clicks += Number(r.clicks) || 0;
179
+ }
180
+ return res.json(summary);
181
+ }
182
+ /** Admin: full detail for one event including the clicks JSON. */
183
+ async logDetail(ctx, idParam, res) {
184
+ if (!requireAdmin(ctx, res, false))
185
+ return;
186
+ const id = parseInt(idParam, 10);
187
+ if (!id)
188
+ return res.status(400).json({ error: 'Invalid id' });
189
+ const row = await this.connection.rawConnection.getRepository(email_log_entity_1.EmailLog).findOne({ where: { id } });
190
+ if (!row)
191
+ return res.status(404).json({ error: 'Not found' });
192
+ let clicks = [];
193
+ try {
194
+ clicks = JSON.parse(row.clicksJson || '[]');
195
+ }
196
+ catch { }
197
+ return res.json({ ...row, clicks, clicksJson: undefined });
198
+ }
199
+ };
200
+ exports.EmailTrackingController = EmailTrackingController;
201
+ __decorate([
202
+ (0, common_1.Get)('open/:id.gif'),
203
+ __param(0, (0, common_1.Param)('id')),
204
+ __param(1, (0, common_1.Req)()),
205
+ __param(2, (0, common_1.Res)()),
206
+ __metadata("design:type", Function),
207
+ __metadata("design:paramtypes", [String, Object, Object]),
208
+ __metadata("design:returntype", Promise)
209
+ ], EmailTrackingController.prototype, "open", null);
210
+ __decorate([
211
+ (0, common_1.Get)('click/:id'),
212
+ __param(0, (0, common_1.Param)('id')),
213
+ __param(1, (0, common_1.Query)('u')),
214
+ __param(2, (0, common_1.Req)()),
215
+ __param(3, (0, common_1.Res)()),
216
+ __metadata("design:type", Function),
217
+ __metadata("design:paramtypes", [String, String, Object, Object]),
218
+ __metadata("design:returntype", Promise)
219
+ ], EmailTrackingController.prototype, "click", null);
220
+ __decorate([
221
+ (0, common_1.Post)('bounce'),
222
+ __param(0, (0, common_1.Body)()),
223
+ __param(1, (0, common_1.Res)()),
224
+ __metadata("design:type", Function),
225
+ __metadata("design:paramtypes", [Object, Object]),
226
+ __metadata("design:returntype", Promise)
227
+ ], EmailTrackingController.prototype, "bounce", null);
228
+ __decorate([
229
+ (0, common_1.Get)('log'),
230
+ __param(0, (0, core_1.Ctx)()),
231
+ __param(1, (0, common_1.Req)()),
232
+ __param(2, (0, common_1.Res)()),
233
+ __metadata("design:type", Function),
234
+ __metadata("design:paramtypes", [core_1.RequestContext, Object, Object]),
235
+ __metadata("design:returntype", Promise)
236
+ ], EmailTrackingController.prototype, "listLog", null);
237
+ __decorate([
238
+ (0, common_1.Get)('log/summary'),
239
+ __param(0, (0, core_1.Ctx)()),
240
+ __param(1, (0, common_1.Req)()),
241
+ __param(2, (0, common_1.Res)()),
242
+ __metadata("design:type", Function),
243
+ __metadata("design:paramtypes", [core_1.RequestContext, Object, Object]),
244
+ __metadata("design:returntype", Promise)
245
+ ], EmailTrackingController.prototype, "logSummary", null);
246
+ __decorate([
247
+ (0, common_1.Get)('log/:id'),
248
+ __param(0, (0, core_1.Ctx)()),
249
+ __param(1, (0, common_1.Param)('id')),
250
+ __param(2, (0, common_1.Res)()),
251
+ __metadata("design:type", Function),
252
+ __metadata("design:paramtypes", [core_1.RequestContext, String, Object]),
253
+ __metadata("design:returntype", Promise)
254
+ ], EmailTrackingController.prototype, "logDetail", null);
255
+ exports.EmailTrackingController = EmailTrackingController = __decorate([
256
+ (0, common_1.Controller)('email-track'),
257
+ __metadata("design:paramtypes", [core_1.TransactionalConnection,
258
+ email_tracking_service_1.EmailTrackingService])
259
+ ], EmailTrackingController);
260
+ //# sourceMappingURL=email-tracking.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-tracking.controller.js","sourceRoot":"","sources":["../src/email-tracking.controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import { TransactionalConnection } from '@vendure/core';
2
+ import * as nodemailer from 'nodemailer';
3
+ import { EmailLog } from './email-log.entity';
4
+ interface SendTrackedMeta {
5
+ /** Logical email type — e.g. 'welcome', 'order-confirmation', 'invoice'. */
6
+ type: string;
7
+ /** Optional context string, e.g. chase stage 'T-7' / 'due' / 'T+14'. */
8
+ context?: string;
9
+ /** Channel id (1 = elite, 2 = LD). Defaults to 1. */
10
+ channelId?: number;
11
+ customerId?: number;
12
+ orderId?: number;
13
+ orderCode?: string;
14
+ invoiceId?: number;
15
+ applicationId?: number;
16
+ }
17
+ export declare class EmailTrackingService {
18
+ private connection;
19
+ constructor(connection: TransactionalConnection);
20
+ /**
21
+ * Send an email through nodemailer with full tracking: creates an
22
+ * EmailLog row, injects a 1×1 open-tracking pixel, rewrites every
23
+ * `href` in the html to go through our click-tracker, records the
24
+ * SMTP response on success / failure.
25
+ *
26
+ * Returns the created EmailLog row (with id). Throws only if the
27
+ * transport configuration itself is invalid; SMTP delivery failures
28
+ * are caught and recorded as status='failed' / 'deferred'.
29
+ */
30
+ sendTracked(transporter: nodemailer.Transporter, mail: nodemailer.SendMailOptions, meta: SendTrackedMeta): Promise<EmailLog>;
31
+ /** Wrap an HTML body for tracking: rewrite links + append open pixel. */
32
+ wrapHtml(html: string, eventId: number): string;
33
+ /** Rewrite every <a href> in the html to go through the click tracker.
34
+ * Skips mailto:, tel:, #anchors, our own tracking endpoints, and the
35
+ * unsubscribe link (always passthrough). */
36
+ private rewriteLinks;
37
+ /** Record a pixel-hit open. Idempotent re-counting; firstOpenedAt only
38
+ * set the first time. */
39
+ recordOpen(id: number, ip: string | null, ua: string | null): Promise<void>;
40
+ /** Record a click + return the original URL so the controller can 302. */
41
+ recordClick(id: number, url: string, ip: string | null, ua: string | null): Promise<string | null>;
42
+ /** SMTP DSN (bounce / complaint) hook — wire up if you point Postmaster
43
+ * Tools / a bounce-processor at /email-track/bounce. */
44
+ recordBounce(messageId: string, status: 'bounced' | 'complained', reason?: string): Promise<boolean>;
45
+ private firstAddress;
46
+ }
47
+ export {};
48
+ //# sourceMappingURL=email-tracking.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-tracking.service.d.ts","sourceRoot":"","sources":["../src/email-tracking.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAU,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,KAAK,UAAU,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAkB,MAAM,oBAAoB,CAAC;AAK9D,UAAU,eAAe;IACrB,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,qBACa,oBAAoB;IACjB,OAAO,CAAC,UAAU;gBAAV,UAAU,EAAE,uBAAuB;IAEvD;;;;;;;;;OASG;IACG,WAAW,CACb,WAAW,EAAE,UAAU,CAAC,WAAW,EACnC,IAAI,EAAE,UAAU,CAAC,eAAe,EAChC,IAAI,EAAE,eAAe,GACtB,OAAO,CAAC,QAAQ,CAAC;IAwDpB,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAW/C;;iDAE6C;IAC7C,OAAO,CAAC,YAAY;IAepB;8BAC0B;IACpB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAejE,0EAA0E;IACpE,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAuBxG;6DACyD;IACnD,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,YAAY,EAAE,MAAM,CAAC,EAAE,MAAM;IAUvF,OAAO,CAAC,YAAY;CAOvB"}
@@ -0,0 +1,196 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.EmailTrackingService = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const core_1 = require("@vendure/core");
15
+ const email_log_entity_1 = require("./email-log.entity");
16
+ const options_1 = require("./options");
17
+ const loggerCtx = 'EmailTrackingService';
18
+ let EmailTrackingService = class EmailTrackingService {
19
+ constructor(connection) {
20
+ this.connection = connection;
21
+ }
22
+ /**
23
+ * Send an email through nodemailer with full tracking: creates an
24
+ * EmailLog row, injects a 1×1 open-tracking pixel, rewrites every
25
+ * `href` in the html to go through our click-tracker, records the
26
+ * SMTP response on success / failure.
27
+ *
28
+ * Returns the created EmailLog row (with id). Throws only if the
29
+ * transport configuration itself is invalid; SMTP delivery failures
30
+ * are caught and recorded as status='failed' / 'deferred'.
31
+ */
32
+ async sendTracked(transporter, mail, meta) {
33
+ const repo = this.connection.rawConnection.getRepository(email_log_entity_1.EmailLog);
34
+ // Create the row up-front so the pixel/click URLs have an id to
35
+ // reference. status starts as 'sent' optimistically; we update
36
+ // it if the SMTP submit throws or returns 4xx/5xx.
37
+ const row = repo.create({
38
+ type: meta.type,
39
+ recipient: this.firstAddress(mail.to),
40
+ subject: String(mail.subject || ''),
41
+ fromAddress: this.firstAddress(mail.from),
42
+ bcc: this.firstAddress(mail.bcc),
43
+ replyTo: this.firstAddress(mail.replyTo),
44
+ context: meta.context,
45
+ channelId: meta.channelId || 1,
46
+ customerId: meta.customerId,
47
+ orderId: meta.orderId,
48
+ orderCode: meta.orderCode,
49
+ invoiceId: meta.invoiceId,
50
+ applicationId: meta.applicationId,
51
+ status: 'sent',
52
+ tracked: true,
53
+ });
54
+ const saved = await repo.save(row);
55
+ // Wrap the HTML — clicks first (so the pixel itself isn't rewritten),
56
+ // then the pixel append. Plain-text-only emails are unaffected.
57
+ const html = mail.html ? String(mail.html) : '';
58
+ if (html) {
59
+ const wrapped = this.wrapHtml(html, Number(saved.id));
60
+ mail = { ...mail, html: wrapped };
61
+ }
62
+ // Send.
63
+ try {
64
+ const info = await transporter.sendMail(mail);
65
+ saved.smtpResponse = String(info.response || '').slice(0, 500);
66
+ saved.smtpMessageId = String(info.messageId || '').slice(0, 500);
67
+ // Gmail's "250 2.0.0 OK" → sent. 4xx → deferred. 5xx → failed.
68
+ const code = parseInt((info.response || '').split(' ')[0], 10);
69
+ if (code >= 500)
70
+ saved.status = 'failed';
71
+ else if (code >= 400)
72
+ saved.status = 'deferred';
73
+ else
74
+ saved.status = 'sent';
75
+ await repo.save(saved);
76
+ }
77
+ catch (e) {
78
+ saved.status = 'failed';
79
+ saved.errorMessage = String((e === null || e === void 0 ? void 0 : e.message) || e).slice(0, 2000);
80
+ saved.smtpResponse = (e === null || e === void 0 ? void 0 : e.response) ? String(e.response).slice(0, 500) : '';
81
+ await repo.save(saved);
82
+ core_1.Logger.error(`Tracked send FAILED [${meta.type}] to ${saved.recipient}: ${e === null || e === void 0 ? void 0 : e.message}`, loggerCtx);
83
+ throw e;
84
+ }
85
+ core_1.Logger.info(`Tracked send OK [${meta.type}] to ${saved.recipient} (id=${saved.id})`, loggerCtx);
86
+ return saved;
87
+ }
88
+ /** Wrap an HTML body for tracking: rewrite links + append open pixel. */
89
+ wrapHtml(html, eventId) {
90
+ const base = (0, options_1.trackingBaseUrl)();
91
+ const trackedHtml = this.rewriteLinks(html, eventId, base);
92
+ const pixel = `<img src="${base}/email-track/open/${eventId}.gif" width="1" height="1" alt="" border="0" style="display:none;border:0;max-height:1px;max-width:1px;outline:none;overflow:hidden;visibility:hidden">`;
93
+ // Insert the pixel just before </body> if possible, otherwise append.
94
+ if (/<\/body>/i.test(trackedHtml)) {
95
+ return trackedHtml.replace(/<\/body>/i, `${pixel}</body>`);
96
+ }
97
+ return trackedHtml + pixel;
98
+ }
99
+ /** Rewrite every <a href> in the html to go through the click tracker.
100
+ * Skips mailto:, tel:, #anchors, our own tracking endpoints, and the
101
+ * unsubscribe link (always passthrough). */
102
+ rewriteLinks(html, eventId, base) {
103
+ const ownPrefixes = (0, options_1.ownTrackingPrefixes)();
104
+ return html.replace(/<a\b([^>]*?)\bhref\s*=\s*(["'])(.*?)\2/gi, (match, attrs, quote, url) => {
105
+ const trimmed = String(url).trim();
106
+ if (!trimmed)
107
+ return match;
108
+ if (/^(mailto:|tel:|#)/i.test(trimmed))
109
+ return match;
110
+ if (ownPrefixes.some(p => trimmed.startsWith(p)))
111
+ return match;
112
+ // unsubscribe / list-unsubscribe links — never rewrite (ESP rules
113
+ // and recipient privacy expectations).
114
+ if (/unsubscribe/i.test(trimmed) || /\bopt[-_]?out\b/i.test(trimmed))
115
+ return match;
116
+ const encoded = encodeURIComponent(trimmed);
117
+ return `<a${attrs}href=${quote}${base}/email-track/click/${eventId}?u=${encoded}${quote}`;
118
+ });
119
+ }
120
+ /** Record a pixel-hit open. Idempotent re-counting; firstOpenedAt only
121
+ * set the first time. */
122
+ async recordOpen(id, ip, ua) {
123
+ const repo = this.connection.rawConnection.getRepository(email_log_entity_1.EmailLog);
124
+ const row = await repo.findOne({ where: { id } });
125
+ if (!row)
126
+ return;
127
+ const now = new Date();
128
+ row.lastOpenedAt = now;
129
+ row.openCount = (row.openCount || 0) + 1;
130
+ if (!row.firstOpenedAt) {
131
+ row.firstOpenedAt = now;
132
+ row.firstOpenIp = ip || undefined;
133
+ row.firstOpenUserAgent = ua ? ua.slice(0, 1000) : undefined;
134
+ }
135
+ await repo.save(row);
136
+ }
137
+ /** Record a click + return the original URL so the controller can 302. */
138
+ async recordClick(id, url, ip, ua) {
139
+ const repo = this.connection.rawConnection.getRepository(email_log_entity_1.EmailLog);
140
+ const row = await repo.findOne({ where: { id } });
141
+ if (!row)
142
+ return null;
143
+ const now = new Date();
144
+ if (!row.firstClickedAt)
145
+ row.firstClickedAt = now;
146
+ row.clickCount = (row.clickCount || 0) + 1;
147
+ let clicks = [];
148
+ try {
149
+ clicks = JSON.parse(row.clicksJson || '[]');
150
+ }
151
+ catch { }
152
+ clicks.push({
153
+ url: url.slice(0, 1000),
154
+ ts: now.toISOString(),
155
+ ip,
156
+ ua: ua ? ua.slice(0, 300) : null,
157
+ });
158
+ // Cap the JSON at the most recent 50 events; older ones live as
159
+ // a per-row clickCount only.
160
+ if (clicks.length > 50)
161
+ clicks = clicks.slice(-50);
162
+ row.clicksJson = JSON.stringify(clicks);
163
+ await repo.save(row);
164
+ return url;
165
+ }
166
+ /** SMTP DSN (bounce / complaint) hook — wire up if you point Postmaster
167
+ * Tools / a bounce-processor at /email-track/bounce. */
168
+ async recordBounce(messageId, status, reason) {
169
+ const repo = this.connection.rawConnection.getRepository(email_log_entity_1.EmailLog);
170
+ const row = await repo.findOne({ where: { smtpMessageId: messageId } });
171
+ if (!row)
172
+ return false;
173
+ row.status = status;
174
+ if (reason)
175
+ row.errorMessage = reason.slice(0, 2000);
176
+ await repo.save(row);
177
+ return true;
178
+ }
179
+ firstAddress(addr) {
180
+ if (!addr)
181
+ return undefined;
182
+ if (typeof addr === 'string')
183
+ return addr.slice(0, 500);
184
+ if (Array.isArray(addr))
185
+ return addr.map(a => typeof a === 'string' ? a : a === null || a === void 0 ? void 0 : a.address).filter(Boolean).join(', ').slice(0, 500);
186
+ if (addr.address)
187
+ return String(addr.address).slice(0, 500);
188
+ return String(addr).slice(0, 500);
189
+ }
190
+ };
191
+ exports.EmailTrackingService = EmailTrackingService;
192
+ exports.EmailTrackingService = EmailTrackingService = __decorate([
193
+ (0, common_1.Injectable)(),
194
+ __metadata("design:paramtypes", [core_1.TransactionalConnection])
195
+ ], EmailTrackingService);
196
+ //# sourceMappingURL=email-tracking.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-tracking.service.js","sourceRoot":"","sources":["../src/email-tracking.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `@huloglobal/vendure-plugin-email-tracking` — public exports.
3
+ *
4
+ * Consumers wire the plugin into Vendure via `EmailTrackingPlugin.init()`,
5
+ * pass `new TrackingEmailSender()` to the `@vendure/email-plugin`'s
6
+ * `emailSender` option, and (optionally) inject `EmailTrackingService`
7
+ * into their own custom controllers to send tracked emails outside the
8
+ * email-plugin pipeline (e.g. ad-hoc transactional sends from plugin
9
+ * code).
10
+ */
11
+ export { EmailTrackingPlugin } from './plugin';
12
+ export { TrackingEmailSender } from './tracking-email-sender';
13
+ export { EmailTrackingService } from './email-tracking.service';
14
+ export { EmailLog, EmailLogStatus } from './email-log.entity';
15
+ export { EmailTrackingPluginOptions } from './options';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ /**
3
+ * `@huloglobal/vendure-plugin-email-tracking` — public exports.
4
+ *
5
+ * Consumers wire the plugin into Vendure via `EmailTrackingPlugin.init()`,
6
+ * pass `new TrackingEmailSender()` to the `@vendure/email-plugin`'s
7
+ * `emailSender` option, and (optionally) inject `EmailTrackingService`
8
+ * into their own custom controllers to send tracked emails outside the
9
+ * email-plugin pipeline (e.g. ad-hoc transactional sends from plugin
10
+ * code).
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.EmailLog = exports.EmailTrackingService = exports.TrackingEmailSender = exports.EmailTrackingPlugin = void 0;
14
+ var plugin_1 = require("./plugin");
15
+ Object.defineProperty(exports, "EmailTrackingPlugin", { enumerable: true, get: function () { return plugin_1.EmailTrackingPlugin; } });
16
+ var tracking_email_sender_1 = require("./tracking-email-sender");
17
+ Object.defineProperty(exports, "TrackingEmailSender", { enumerable: true, get: function () { return tracking_email_sender_1.TrackingEmailSender; } });
18
+ var email_tracking_service_1 = require("./email-tracking.service");
19
+ Object.defineProperty(exports, "EmailTrackingService", { enumerable: true, get: function () { return email_tracking_service_1.EmailTrackingService; } });
20
+ var email_log_entity_1 = require("./email-log.entity");
21
+ Object.defineProperty(exports, "EmailLog", { enumerable: true, get: function () { return email_log_entity_1.EmailLog; } });
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AAEH,mCAA+C;AAAtC,6GAAA,mBAAmB,OAAA;AAC5B,iEAA8D;AAArD,4HAAA,mBAAmB,OAAA;AAC5B,mEAAgE;AAAvD,8HAAA,oBAAoB,OAAA;AAC7B,uDAA8D;AAArD,4GAAA,QAAQ,OAAA"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Module-scoped plugin options. Populated by `EmailTrackingPlugin.init()`
3
+ * at boot and read by the service / sender / controller via the
4
+ * exported helpers below. Keeping options in module scope rather than
5
+ * threading them through every constructor avoids a refactor of the
6
+ * Nest providers — Nest creates services lazily and we want options
7
+ * available before that happens.
8
+ */
9
+ import { LicenceStatus } from '@huloglobal/vendure-licence-sdk';
10
+ export interface EmailTrackingPluginOptions {
11
+ /**
12
+ * Public base URL where the tracking endpoints are reachable. Must
13
+ * be the externally-resolvable hostname of your Vendure server —
14
+ * the pixel + click URLs we embed in outgoing email point to this
15
+ * host. Example: `https://shop.example.com`.
16
+ */
17
+ publicBaseUrl: string;
18
+ /**
19
+ * Required licence JWT for production use. Without a valid key the
20
+ * plugin still registers and writes basic delivery rows to the
21
+ * EmailLog table, but the open/click tracking endpoints respond
22
+ * with 410 Gone and the admin UI shows an "Unlicensed" banner.
23
+ */
24
+ licenceKey?: string;
25
+ /**
26
+ * Hostnames considered "self" — used by the click rewriter to
27
+ * detect that a link points to our tracking endpoint and shouldn't
28
+ * be rewritten a second time. Defaults to `[publicBaseUrl]` if
29
+ * omitted.
30
+ */
31
+ trackedHosts?: string[];
32
+ }
33
+ export declare function setOptions(opts: EmailTrackingPluginOptions): void;
34
+ export declare function getOptions(): EmailTrackingPluginOptions;
35
+ export declare function setLicenceStatus(status: LicenceStatus): void;
36
+ export declare function getLicenceStatus(): LicenceStatus | null;
37
+ /** Public tracking base URL — used by both the click-rewriter and the
38
+ * open-pixel injector. Always returns a value without a trailing slash. */
39
+ export declare function trackingBaseUrl(): string;
40
+ /** Hostname prefixes the click-rewriter should treat as already-ours
41
+ * and skip rewriting. */
42
+ export declare function ownTrackingPrefixes(): string[];
43
+ //# sourceMappingURL=options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAEhE,MAAM,WAAW,0BAA0B;IACvC;;;;;OAKG;IACH,aAAa,EAAE,MAAM,CAAC;IAEtB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AASD,wBAAgB,UAAU,CAAC,IAAI,EAAE,0BAA0B,GAAG,IAAI,CAMjE;AAED,wBAAgB,UAAU,IAAI,0BAA0B,CAEvD;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAE5D;AAED,wBAAgB,gBAAgB,IAAI,aAAa,GAAG,IAAI,CAEvD;AAED;4EAC4E;AAC5E,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;0BAC0B;AAC1B,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAK9C"}