@bernierllc/email-sendgrid-plugin 1.3.0 → 1.4.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/CHANGELOG.md +16 -0
- package/__tests__/converters/attachment-header-mapping.test.ts +337 -0
- package/coverage/clover.xml +395 -0
- package/coverage/coverage-final.json +12 -0
- package/coverage/lcov-report/api/errors.ts.html +232 -0
- package/coverage/lcov-report/api/index.html +146 -0
- package/coverage/lcov-report/api/rate-limiter.ts.html +322 -0
- package/coverage/lcov-report/api/sendgrid-client.ts.html +343 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/converters/index.html +131 -0
- package/coverage/lcov-report/converters/sender-converter.ts.html +208 -0
- package/coverage/lcov-report/converters/template-converter.ts.html +376 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +161 -0
- package/coverage/lcov-report/plugin/index.html +161 -0
- package/coverage/lcov-report/plugin/sender-manager.ts.html +583 -0
- package/coverage/lcov-report/plugin/sendgrid-plugin.ts.html +1033 -0
- package/coverage/lcov-report/plugin/sync-manager.ts.html +430 -0
- package/coverage/lcov-report/plugin/template-manager.ts.html +805 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/safety/index.html +131 -0
- package/coverage/lcov-report/safety/ownership-validator.ts.html +250 -0
- package/coverage/lcov-report/safety/prefix-enforcer.ts.html +196 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov.info +734 -0
- package/dist/converters/sender-converter.d.ts +25 -1
- package/dist/converters/sender-converter.js +74 -0
- package/dist/index.d.ts +1 -1
- package/dist/types/sendgrid-types.d.ts +26 -0
- package/package.json +15 -17
- package/src/converters/sender-converter.ts +98 -1
- package/src/index.ts +4 -1
- package/src/types/sendgrid-types.ts +29 -0
|
@@ -1,6 +1,30 @@
|
|
|
1
|
-
import { VerifiedSender, SendGridVerifiedSenderData } from '../types/sendgrid-types';
|
|
1
|
+
import { VerifiedSender, SendGridVerifiedSenderData, EmailAttachment, SendGridAttachment, SendGridMailPayload } from '../types/sendgrid-types';
|
|
2
2
|
export declare class SenderConverter {
|
|
3
3
|
convertToVerifiedSender(sendgridData: SendGridVerifiedSenderData): VerifiedSender;
|
|
4
|
+
/**
|
|
5
|
+
* Convert a single EmailAttachment to SendGrid's attachment format.
|
|
6
|
+
*/
|
|
7
|
+
convertAttachment(attachment: EmailAttachment): SendGridAttachment;
|
|
8
|
+
/**
|
|
9
|
+
* Convert an array of EmailAttachment objects to SendGrid format.
|
|
10
|
+
* Returns undefined if the array is empty or undefined (so the field
|
|
11
|
+
* can be omitted from the payload).
|
|
12
|
+
*/
|
|
13
|
+
convertAttachments(attachments?: EmailAttachment[]): SendGridAttachment[] | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Convert custom headers to the format expected by SendGrid's v3 mail send API.
|
|
16
|
+
* Filters out reserved SendGrid headers that must not be overridden.
|
|
17
|
+
* Returns undefined if no valid headers remain.
|
|
18
|
+
*/
|
|
19
|
+
convertHeaders(headers?: Record<string, string>): Record<string, string> | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Build the attachment and header portion of a SendGrid mail payload
|
|
22
|
+
* from canonical email data.
|
|
23
|
+
*/
|
|
24
|
+
buildMailPayload(options: {
|
|
25
|
+
attachments?: EmailAttachment[];
|
|
26
|
+
headers?: Record<string, string>;
|
|
27
|
+
}): SendGridMailPayload;
|
|
4
28
|
extractDomain(email: string): string;
|
|
5
29
|
isDomainMatch(domain1: string, domain2: string): boolean;
|
|
6
30
|
}
|
|
@@ -22,6 +22,80 @@ class SenderConverter {
|
|
|
22
22
|
lastVerifiedAt: sendgridData.verified ? new Date() : undefined
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Convert a single EmailAttachment to SendGrid's attachment format.
|
|
27
|
+
*/
|
|
28
|
+
convertAttachment(attachment) {
|
|
29
|
+
const sgAttachment = {
|
|
30
|
+
content: attachment.content,
|
|
31
|
+
filename: attachment.filename,
|
|
32
|
+
};
|
|
33
|
+
if (attachment.contentType) {
|
|
34
|
+
sgAttachment.type = attachment.contentType;
|
|
35
|
+
}
|
|
36
|
+
if (attachment.disposition) {
|
|
37
|
+
sgAttachment.disposition = attachment.disposition;
|
|
38
|
+
}
|
|
39
|
+
return sgAttachment;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Convert an array of EmailAttachment objects to SendGrid format.
|
|
43
|
+
* Returns undefined if the array is empty or undefined (so the field
|
|
44
|
+
* can be omitted from the payload).
|
|
45
|
+
*/
|
|
46
|
+
convertAttachments(attachments) {
|
|
47
|
+
if (!attachments || attachments.length === 0) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
return attachments.map(a => this.convertAttachment(a));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Convert custom headers to the format expected by SendGrid's v3 mail send API.
|
|
54
|
+
* Filters out reserved SendGrid headers that must not be overridden.
|
|
55
|
+
* Returns undefined if no valid headers remain.
|
|
56
|
+
*/
|
|
57
|
+
convertHeaders(headers) {
|
|
58
|
+
if (!headers || Object.keys(headers).length === 0) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
const RESERVED_HEADERS = new Set([
|
|
62
|
+
'x-sg-id',
|
|
63
|
+
'x-sg-eid',
|
|
64
|
+
'received',
|
|
65
|
+
'dkim-signature',
|
|
66
|
+
'content-type',
|
|
67
|
+
'content-transfer-encoding',
|
|
68
|
+
'to',
|
|
69
|
+
'from',
|
|
70
|
+
'subject',
|
|
71
|
+
'reply-to',
|
|
72
|
+
'cc',
|
|
73
|
+
'bcc',
|
|
74
|
+
]);
|
|
75
|
+
const filtered = {};
|
|
76
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
77
|
+
if (!RESERVED_HEADERS.has(key.toLowerCase())) {
|
|
78
|
+
filtered[key] = value;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return Object.keys(filtered).length > 0 ? filtered : undefined;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Build the attachment and header portion of a SendGrid mail payload
|
|
85
|
+
* from canonical email data.
|
|
86
|
+
*/
|
|
87
|
+
buildMailPayload(options) {
|
|
88
|
+
const payload = {};
|
|
89
|
+
const attachments = this.convertAttachments(options.attachments);
|
|
90
|
+
if (attachments) {
|
|
91
|
+
payload.attachments = attachments;
|
|
92
|
+
}
|
|
93
|
+
const headers = this.convertHeaders(options.headers);
|
|
94
|
+
if (headers) {
|
|
95
|
+
payload.headers = headers;
|
|
96
|
+
}
|
|
97
|
+
return payload;
|
|
98
|
+
}
|
|
25
99
|
extractDomain(email) {
|
|
26
100
|
return email.split('@')[1]?.toLowerCase() || '';
|
|
27
101
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,4 +11,4 @@ export { SenderConverter } from './converters/sender-converter';
|
|
|
11
11
|
export { SendGridApiError, TemplateNotFoundError, UnauthorizedTemplateAccessError, TemplateConflictError, RateLimitError } from './api/errors';
|
|
12
12
|
export type { SendGridPluginConfig, ApiRequestOptions, ApiResponse } from './types/config-types';
|
|
13
13
|
export type { PluginConfig, ProviderCapability, Template, ProviderTemplate, TemplateVersion, SyncResult, ValidationResult, DateRange, TemplateAnalytics, FeatureConfig } from './types/plugin-types';
|
|
14
|
-
export type { VerifiedSender, SenderValidationResult, SendGridTemplateData, SendGridTemplateVersion, SendGridVerifiedSenderData } from './types/sendgrid-types';
|
|
14
|
+
export type { VerifiedSender, SenderValidationResult, SendGridTemplateData, SendGridTemplateVersion, SendGridVerifiedSenderData, EmailAttachment, SendGridAttachment, SendGridMailPayload } from './types/sendgrid-types';
|
|
@@ -54,3 +54,29 @@ export interface SendGridApiError extends Error {
|
|
|
54
54
|
statusCode?: number;
|
|
55
55
|
response?: unknown;
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Email attachment in the canonical format (matches @bernierllc/email-sender EmailAttachment).
|
|
59
|
+
*/
|
|
60
|
+
export interface EmailAttachment {
|
|
61
|
+
filename: string;
|
|
62
|
+
content: string;
|
|
63
|
+
contentType?: string;
|
|
64
|
+
disposition?: 'attachment' | 'inline';
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* SendGrid's attachment format for the v3 mail send API.
|
|
68
|
+
*/
|
|
69
|
+
export interface SendGridAttachment {
|
|
70
|
+
content: string;
|
|
71
|
+
filename: string;
|
|
72
|
+
type?: string;
|
|
73
|
+
disposition?: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* SendGrid mail personalization/message payload fields related to
|
|
77
|
+
* attachments and custom headers.
|
|
78
|
+
*/
|
|
79
|
+
export interface SendGridMailPayload {
|
|
80
|
+
attachments?: SendGridAttachment[];
|
|
81
|
+
headers?: Record<string, string>;
|
|
82
|
+
}
|
package/package.json
CHANGED
|
@@ -1,20 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bernierllc/email-sendgrid-plugin",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"deprecated": "This package is deprecated. SendGrid functionality has been merged into @bernierllc/email-sender@3.0.0+. See https://github.com/BernierLLC/tools/blob/main/packages/core/email-sender/MIGRATION.md for migration guide.",
|
|
5
5
|
"description": "SendGrid-specific template management, sender verification, and advanced features plugin for email template service",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
-
"scripts": {
|
|
9
|
-
"build": "tsc",
|
|
10
|
-
"clean": "rm -rf dist",
|
|
11
|
-
"test": "jest",
|
|
12
|
-
"test:run": "jest --watchAll=false",
|
|
13
|
-
"test:watch": "jest --watch",
|
|
14
|
-
"test:coverage": "jest --coverage",
|
|
15
|
-
"lint": "eslint src --ext .ts",
|
|
16
|
-
"prepublishOnly": "npm run clean && npm run build"
|
|
17
|
-
},
|
|
18
8
|
"keywords": [
|
|
19
9
|
"sendgrid",
|
|
20
10
|
"email",
|
|
@@ -26,10 +16,10 @@
|
|
|
26
16
|
"author": "Bernier LLC",
|
|
27
17
|
"license": "SEE LICENSE IN LICENSE",
|
|
28
18
|
"dependencies": {
|
|
29
|
-
"@
|
|
30
|
-
"@bernierllc/rate-limiter": "0.2.
|
|
31
|
-
"@bernierllc/
|
|
32
|
-
"@
|
|
19
|
+
"@sendgrid/mail": "^8.1.3",
|
|
20
|
+
"@bernierllc/rate-limiter": "0.2.2",
|
|
21
|
+
"@bernierllc/logger": "1.3.1",
|
|
22
|
+
"@bernierllc/retry-policy": "0.3.1"
|
|
33
23
|
},
|
|
34
24
|
"devDependencies": {
|
|
35
25
|
"@types/jest": "^29.5.12",
|
|
@@ -45,5 +35,13 @@
|
|
|
45
35
|
"access": "public",
|
|
46
36
|
"registry": "https://registry.npmjs.org/"
|
|
47
37
|
},
|
|
48
|
-
"
|
|
49
|
-
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsc",
|
|
40
|
+
"clean": "rm -rf dist",
|
|
41
|
+
"test": "jest",
|
|
42
|
+
"test:run": "jest --watchAll=false",
|
|
43
|
+
"test:watch": "jest --watch",
|
|
44
|
+
"test:coverage": "jest --coverage",
|
|
45
|
+
"lint": "eslint src --ext .ts"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -6,7 +6,13 @@ The client may use and modify this code *only within the scope of the project it
|
|
|
6
6
|
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
VerifiedSender,
|
|
11
|
+
SendGridVerifiedSenderData,
|
|
12
|
+
EmailAttachment,
|
|
13
|
+
SendGridAttachment,
|
|
14
|
+
SendGridMailPayload
|
|
15
|
+
} from '../types/sendgrid-types';
|
|
10
16
|
|
|
11
17
|
export class SenderConverter {
|
|
12
18
|
convertToVerifiedSender(sendgridData: SendGridVerifiedSenderData): VerifiedSender {
|
|
@@ -24,6 +30,97 @@ export class SenderConverter {
|
|
|
24
30
|
};
|
|
25
31
|
}
|
|
26
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Convert a single EmailAttachment to SendGrid's attachment format.
|
|
35
|
+
*/
|
|
36
|
+
convertAttachment(attachment: EmailAttachment): SendGridAttachment {
|
|
37
|
+
const sgAttachment: SendGridAttachment = {
|
|
38
|
+
content: attachment.content,
|
|
39
|
+
filename: attachment.filename,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
if (attachment.contentType) {
|
|
43
|
+
sgAttachment.type = attachment.contentType;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (attachment.disposition) {
|
|
47
|
+
sgAttachment.disposition = attachment.disposition;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return sgAttachment;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Convert an array of EmailAttachment objects to SendGrid format.
|
|
55
|
+
* Returns undefined if the array is empty or undefined (so the field
|
|
56
|
+
* can be omitted from the payload).
|
|
57
|
+
*/
|
|
58
|
+
convertAttachments(attachments?: EmailAttachment[]): SendGridAttachment[] | undefined {
|
|
59
|
+
if (!attachments || attachments.length === 0) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return attachments.map(a => this.convertAttachment(a));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Convert custom headers to the format expected by SendGrid's v3 mail send API.
|
|
68
|
+
* Filters out reserved SendGrid headers that must not be overridden.
|
|
69
|
+
* Returns undefined if no valid headers remain.
|
|
70
|
+
*/
|
|
71
|
+
convertHeaders(headers?: Record<string, string>): Record<string, string> | undefined {
|
|
72
|
+
if (!headers || Object.keys(headers).length === 0) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const RESERVED_HEADERS = new Set([
|
|
77
|
+
'x-sg-id',
|
|
78
|
+
'x-sg-eid',
|
|
79
|
+
'received',
|
|
80
|
+
'dkim-signature',
|
|
81
|
+
'content-type',
|
|
82
|
+
'content-transfer-encoding',
|
|
83
|
+
'to',
|
|
84
|
+
'from',
|
|
85
|
+
'subject',
|
|
86
|
+
'reply-to',
|
|
87
|
+
'cc',
|
|
88
|
+
'bcc',
|
|
89
|
+
]);
|
|
90
|
+
|
|
91
|
+
const filtered: Record<string, string> = {};
|
|
92
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
93
|
+
if (!RESERVED_HEADERS.has(key.toLowerCase())) {
|
|
94
|
+
filtered[key] = value;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return Object.keys(filtered).length > 0 ? filtered : undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Build the attachment and header portion of a SendGrid mail payload
|
|
103
|
+
* from canonical email data.
|
|
104
|
+
*/
|
|
105
|
+
buildMailPayload(options: {
|
|
106
|
+
attachments?: EmailAttachment[];
|
|
107
|
+
headers?: Record<string, string>;
|
|
108
|
+
}): SendGridMailPayload {
|
|
109
|
+
const payload: SendGridMailPayload = {};
|
|
110
|
+
|
|
111
|
+
const attachments = this.convertAttachments(options.attachments);
|
|
112
|
+
if (attachments) {
|
|
113
|
+
payload.attachments = attachments;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const headers = this.convertHeaders(options.headers);
|
|
117
|
+
if (headers) {
|
|
118
|
+
payload.headers = headers;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return payload;
|
|
122
|
+
}
|
|
123
|
+
|
|
27
124
|
extractDomain(email: string): string {
|
|
28
125
|
return email.split('@')[1]?.toLowerCase() || '';
|
|
29
126
|
}
|
package/src/index.ts
CHANGED
|
@@ -67,3 +67,32 @@ export interface SendGridApiError extends Error {
|
|
|
67
67
|
statusCode?: number;
|
|
68
68
|
response?: unknown;
|
|
69
69
|
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Email attachment in the canonical format (matches @bernierllc/email-sender EmailAttachment).
|
|
73
|
+
*/
|
|
74
|
+
export interface EmailAttachment {
|
|
75
|
+
filename: string;
|
|
76
|
+
content: string; // Base64 encoded
|
|
77
|
+
contentType?: string;
|
|
78
|
+
disposition?: 'attachment' | 'inline';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* SendGrid's attachment format for the v3 mail send API.
|
|
83
|
+
*/
|
|
84
|
+
export interface SendGridAttachment {
|
|
85
|
+
content: string;
|
|
86
|
+
filename: string;
|
|
87
|
+
type?: string;
|
|
88
|
+
disposition?: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* SendGrid mail personalization/message payload fields related to
|
|
93
|
+
* attachments and custom headers.
|
|
94
|
+
*/
|
|
95
|
+
export interface SendGridMailPayload {
|
|
96
|
+
attachments?: SendGridAttachment[];
|
|
97
|
+
headers?: Record<string, string>;
|
|
98
|
+
}
|