@bernierllc/email-sendgrid-plugin 1.8.1 → 1.8.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.
- package/package.json +2 -2
- package/dist/api/errors.d.ts +0 -20
- package/dist/api/errors.js +0 -55
- package/dist/api/rate-limiter.d.ts +0 -17
- package/dist/api/rate-limiter.js +0 -60
- package/dist/api/sendgrid-client.d.ts +0 -21
- package/dist/api/sendgrid-client.js +0 -70
- package/dist/converters/sender-converter.d.ts +0 -30
- package/dist/converters/sender-converter.js +0 -114
- package/dist/converters/template-converter.d.ts +0 -11
- package/dist/converters/template-converter.js +0 -77
- package/dist/errors.d.ts +0 -11
- package/dist/errors.js +0 -24
- package/dist/index.d.ts +0 -15
- package/dist/index.js +0 -45
- package/dist/plugin/sender-manager.d.ts +0 -20
- package/dist/plugin/sender-manager.js +0 -129
- package/dist/plugin/sendgrid-plugin.d.ts +0 -60
- package/dist/plugin/sendgrid-plugin.js +0 -215
- package/dist/plugin/sync-manager.d.ts +0 -19
- package/dist/plugin/sync-manager.js +0 -98
- package/dist/plugin/template-manager.d.ts +0 -25
- package/dist/plugin/template-manager.js +0 -157
- package/dist/safety/ownership-validator.d.ts +0 -15
- package/dist/safety/ownership-validator.js +0 -44
- package/dist/safety/prefix-enforcer.d.ts +0 -8
- package/dist/safety/prefix-enforcer.js +0 -35
- package/dist/types/config-types.d.ts +0 -24
- package/dist/types/config-types.js +0 -9
- package/dist/types/plugin-types.d.ts +0 -79
- package/dist/types/plugin-types.js +0 -9
- package/dist/types/sendgrid-types.d.ts +0 -82
- package/dist/types/sendgrid-types.js +0 -9
|
@@ -1,129 +0,0 @@
|
|
|
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.SenderManager = void 0;
|
|
11
|
-
const errors_1 = require("../api/errors");
|
|
12
|
-
class SenderManager {
|
|
13
|
-
client;
|
|
14
|
-
converter;
|
|
15
|
-
logger;
|
|
16
|
-
sendersCache;
|
|
17
|
-
cacheTimestamp;
|
|
18
|
-
cacheTTL = 300000; // 5 minutes
|
|
19
|
-
constructor(client, converter, logger) {
|
|
20
|
-
this.client = client;
|
|
21
|
-
this.converter = converter;
|
|
22
|
-
this.logger = logger;
|
|
23
|
-
}
|
|
24
|
-
async getVerifiedSenders(useCache = true) {
|
|
25
|
-
// Return cached data if valid
|
|
26
|
-
if (useCache &&
|
|
27
|
-
this.sendersCache &&
|
|
28
|
-
this.cacheTimestamp &&
|
|
29
|
-
Date.now() - this.cacheTimestamp < this.cacheTTL) {
|
|
30
|
-
this.logger?.debug('Returning cached verified senders');
|
|
31
|
-
return this.sendersCache;
|
|
32
|
-
}
|
|
33
|
-
const response = await this.client.request('/verified_senders', {
|
|
34
|
-
method: 'GET'
|
|
35
|
-
});
|
|
36
|
-
if (!this.client.isSuccessResponse(response)) {
|
|
37
|
-
throw new errors_1.SendGridApiError('Failed to fetch verified senders', response.statusCode, response.body);
|
|
38
|
-
}
|
|
39
|
-
const data = this.client.parseResponseBody(response);
|
|
40
|
-
const senders = data.results.map(sender => this.converter.convertToVerifiedSender(sender));
|
|
41
|
-
// Update cache
|
|
42
|
-
this.sendersCache = senders;
|
|
43
|
-
this.cacheTimestamp = Date.now();
|
|
44
|
-
this.logger?.info(`Fetched ${senders.length} verified senders from SendGrid`);
|
|
45
|
-
return senders;
|
|
46
|
-
}
|
|
47
|
-
async validateSender(email) {
|
|
48
|
-
const verifiedSenders = await this.getVerifiedSenders();
|
|
49
|
-
const emailDomain = this.converter.extractDomain(email);
|
|
50
|
-
// Check for exact match
|
|
51
|
-
const exactMatch = verifiedSenders.find(sender => sender.email.toLowerCase() === email.toLowerCase() && sender.isVerified);
|
|
52
|
-
if (exactMatch) {
|
|
53
|
-
return {
|
|
54
|
-
isValid: true,
|
|
55
|
-
verifiedSender: exactMatch,
|
|
56
|
-
domain: emailDomain,
|
|
57
|
-
domainMatches: [exactMatch],
|
|
58
|
-
errors: [],
|
|
59
|
-
suggestions: []
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
// Check for domain matches
|
|
63
|
-
const domainMatches = verifiedSenders.filter(sender => {
|
|
64
|
-
const senderDomain = this.converter.extractDomain(sender.email);
|
|
65
|
-
return this.converter.isDomainMatch(emailDomain, senderDomain) && sender.isVerified;
|
|
66
|
-
});
|
|
67
|
-
if (domainMatches.length > 0) {
|
|
68
|
-
return {
|
|
69
|
-
isValid: true,
|
|
70
|
-
domain: emailDomain,
|
|
71
|
-
domainMatches,
|
|
72
|
-
errors: [],
|
|
73
|
-
suggestions: domainMatches.map(sender => sender.email)
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
// No matches found
|
|
77
|
-
return {
|
|
78
|
-
isValid: false,
|
|
79
|
-
domain: emailDomain,
|
|
80
|
-
domainMatches: [],
|
|
81
|
-
errors: [`No verified sender found for email ${email} or domain ${emailDomain}`],
|
|
82
|
-
suggestions: this.getSenderSuggestions(email, verifiedSenders)
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
async selectBestSender(fromEmail) {
|
|
86
|
-
const validation = await this.validateSender(fromEmail);
|
|
87
|
-
if (!validation.isValid || validation.domainMatches.length === 0) {
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
// Prefer exact match
|
|
91
|
-
if (validation.verifiedSender) {
|
|
92
|
-
return validation.verifiedSender;
|
|
93
|
-
}
|
|
94
|
-
// Fall back to best domain match
|
|
95
|
-
// Priority: most recently verified, then alphabetical
|
|
96
|
-
return validation.domainMatches.sort((a, b) => {
|
|
97
|
-
if (a.lastVerifiedAt && b.lastVerifiedAt) {
|
|
98
|
-
return b.lastVerifiedAt.getTime() - a.lastVerifiedAt.getTime();
|
|
99
|
-
}
|
|
100
|
-
if (a.lastVerifiedAt && !b.lastVerifiedAt)
|
|
101
|
-
return -1;
|
|
102
|
-
if (!a.lastVerifiedAt && b.lastVerifiedAt)
|
|
103
|
-
return 1;
|
|
104
|
-
return a.email.localeCompare(b.email);
|
|
105
|
-
})[0];
|
|
106
|
-
}
|
|
107
|
-
clearCache() {
|
|
108
|
-
this.sendersCache = undefined;
|
|
109
|
-
this.cacheTimestamp = undefined;
|
|
110
|
-
this.logger?.debug('Cleared verified senders cache');
|
|
111
|
-
}
|
|
112
|
-
getSenderSuggestions(email, senders) {
|
|
113
|
-
const emailDomain = this.converter.extractDomain(email);
|
|
114
|
-
// Find senders with similar domains
|
|
115
|
-
const suggestions = [];
|
|
116
|
-
for (const sender of senders) {
|
|
117
|
-
if (!sender.isVerified)
|
|
118
|
-
continue;
|
|
119
|
-
const senderDomain = this.converter.extractDomain(sender.email);
|
|
120
|
-
// Check for partial domain matches
|
|
121
|
-
if (emailDomain.includes(senderDomain) ||
|
|
122
|
-
senderDomain.includes(emailDomain)) {
|
|
123
|
-
suggestions.push(sender.email);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return suggestions.slice(0, 5); // Limit to 5 suggestions
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
exports.SenderManager = SenderManager;
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { SendGridPluginConfig } from '../types/config-types';
|
|
2
|
-
import { PluginConfig, ProviderCapability, Template, ProviderTemplate, TemplateVersion, SyncResult, ValidationResult, DateRange, TemplateAnalytics, FeatureConfig } from '../types/plugin-types';
|
|
3
|
-
import { VerifiedSender, SenderValidationResult } from '../types/sendgrid-types';
|
|
4
|
-
export interface TemplateProviderPlugin {
|
|
5
|
-
readonly name: string;
|
|
6
|
-
readonly version: string;
|
|
7
|
-
readonly providerId: string;
|
|
8
|
-
initialize(config: PluginConfig): Promise<void>;
|
|
9
|
-
destroy(): Promise<void>;
|
|
10
|
-
createTemplate(template: Template): Promise<string>;
|
|
11
|
-
updateTemplate(providerTemplateId: string, template: Template): Promise<void>;
|
|
12
|
-
deleteTemplate(providerTemplateId: string): Promise<void>;
|
|
13
|
-
getTemplate(providerTemplateId: string): Promise<ProviderTemplate>;
|
|
14
|
-
listTemplates(): Promise<ProviderTemplate[]>;
|
|
15
|
-
syncToProvider(template: Template): Promise<SyncResult>;
|
|
16
|
-
syncFromProvider(providerTemplateId: string): Promise<Template>;
|
|
17
|
-
getCapabilities(): ProviderCapability[];
|
|
18
|
-
supportsFeature(feature: string): boolean;
|
|
19
|
-
getFeatureConfig(feature: string): FeatureConfig | null;
|
|
20
|
-
}
|
|
21
|
-
export declare class SendGridTemplatePlugin implements TemplateProviderPlugin {
|
|
22
|
-
readonly name = "sendgrid-templates";
|
|
23
|
-
readonly version = "1.0.0";
|
|
24
|
-
readonly providerId = "sendgrid";
|
|
25
|
-
private client;
|
|
26
|
-
private rateLimiter?;
|
|
27
|
-
private ownershipValidator;
|
|
28
|
-
private prefixEnforcer;
|
|
29
|
-
private templateConverter;
|
|
30
|
-
private senderConverter;
|
|
31
|
-
private templateManager;
|
|
32
|
-
private senderManager;
|
|
33
|
-
private syncManager;
|
|
34
|
-
private readonly config;
|
|
35
|
-
private readonly logger?;
|
|
36
|
-
private initialized;
|
|
37
|
-
constructor(config: SendGridPluginConfig);
|
|
38
|
-
initialize(__pluginConfig: PluginConfig): Promise<void>;
|
|
39
|
-
destroy(): Promise<void>;
|
|
40
|
-
createTemplate(template: Template): Promise<string>;
|
|
41
|
-
updateTemplate(providerTemplateId: string, template: Template): Promise<void>;
|
|
42
|
-
deleteTemplate(providerTemplateId: string): Promise<void>;
|
|
43
|
-
getTemplate(providerTemplateId: string): Promise<ProviderTemplate>;
|
|
44
|
-
listTemplates(): Promise<ProviderTemplate[]>;
|
|
45
|
-
syncToProvider(template: Template): Promise<SyncResult>;
|
|
46
|
-
syncFromProvider(providerTemplateId: string): Promise<Template>;
|
|
47
|
-
getVerifiedSenders(): Promise<VerifiedSender[]>;
|
|
48
|
-
validateSender(email: string): Promise<SenderValidationResult>;
|
|
49
|
-
selectBestSender(email: string): Promise<VerifiedSender | null>;
|
|
50
|
-
createTemplateVersion(templateId: string, version: TemplateVersion): Promise<string>;
|
|
51
|
-
activateTemplateVersion(templateId: string, versionId: string): Promise<void>;
|
|
52
|
-
getTemplateAnalytics(__templateId: string, __dateRange: DateRange): Promise<TemplateAnalytics>;
|
|
53
|
-
batchSyncTemplates(templates: Template[]): Promise<SyncResult[]>;
|
|
54
|
-
getCapabilities(): ProviderCapability[];
|
|
55
|
-
supportsFeature(feature: string): boolean;
|
|
56
|
-
getFeatureConfig(feature: string): FeatureConfig | null;
|
|
57
|
-
validateRoute(__route: unknown): ValidationResult;
|
|
58
|
-
private loadExistingTemplates;
|
|
59
|
-
private ensureInitialized;
|
|
60
|
-
}
|
|
@@ -1,215 +0,0 @@
|
|
|
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.SendGridTemplatePlugin = void 0;
|
|
11
|
-
const sendgrid_client_1 = require("../api/sendgrid-client");
|
|
12
|
-
const rate_limiter_1 = require("../api/rate-limiter");
|
|
13
|
-
const ownership_validator_1 = require("../safety/ownership-validator");
|
|
14
|
-
const prefix_enforcer_1 = require("../safety/prefix-enforcer");
|
|
15
|
-
const template_converter_1 = require("../converters/template-converter");
|
|
16
|
-
const sender_converter_1 = require("../converters/sender-converter");
|
|
17
|
-
const template_manager_1 = require("./template-manager");
|
|
18
|
-
const sender_manager_1 = require("./sender-manager");
|
|
19
|
-
const sync_manager_1 = require("./sync-manager");
|
|
20
|
-
class SendGridTemplatePlugin {
|
|
21
|
-
name = 'sendgrid-templates';
|
|
22
|
-
version = '1.0.0';
|
|
23
|
-
providerId = 'sendgrid';
|
|
24
|
-
client;
|
|
25
|
-
rateLimiter;
|
|
26
|
-
ownershipValidator;
|
|
27
|
-
prefixEnforcer;
|
|
28
|
-
templateConverter;
|
|
29
|
-
senderConverter;
|
|
30
|
-
templateManager;
|
|
31
|
-
senderManager;
|
|
32
|
-
syncManager;
|
|
33
|
-
config;
|
|
34
|
-
logger;
|
|
35
|
-
initialized = false;
|
|
36
|
-
constructor(config) {
|
|
37
|
-
this.config = config;
|
|
38
|
-
}
|
|
39
|
-
async initialize(__pluginConfig) {
|
|
40
|
-
if (this.initialized) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
// Initialize rate limiter if configured
|
|
44
|
-
if (this.config.rateLimits) {
|
|
45
|
-
this.rateLimiter = new rate_limiter_1.SimpleRateLimiter({
|
|
46
|
-
maxRequestsPerSecond: this.config.rateLimits.apiCallsPerSecond,
|
|
47
|
-
maxRequestsPerMinute: this.config.rateLimits.templatesPerMinute
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
// Initialize SendGrid client
|
|
51
|
-
this.client = new sendgrid_client_1.SendGridClient({
|
|
52
|
-
apiKey: this.config.apiKey,
|
|
53
|
-
rateLimiter: this.rateLimiter,
|
|
54
|
-
logger: this.logger
|
|
55
|
-
});
|
|
56
|
-
// Initialize safety components
|
|
57
|
-
this.ownershipValidator = new ownership_validator_1.OwnershipValidator(this.config.safetyMode, this.logger);
|
|
58
|
-
this.prefixEnforcer = new prefix_enforcer_1.PrefixEnforcer(this.config.templatePrefix);
|
|
59
|
-
// Initialize converters
|
|
60
|
-
this.templateConverter = new template_converter_1.TemplateConverter(this.prefixEnforcer);
|
|
61
|
-
this.senderConverter = new sender_converter_1.SenderConverter();
|
|
62
|
-
// Initialize managers
|
|
63
|
-
this.templateManager = new template_manager_1.TemplateManager(this.client, this.ownershipValidator, this.prefixEnforcer, this.templateConverter, this.logger);
|
|
64
|
-
this.senderManager = new sender_manager_1.SenderManager(this.client, this.senderConverter, this.logger);
|
|
65
|
-
this.syncManager = new sync_manager_1.SyncManager(this.templateManager, this.templateConverter, this.client, this.logger);
|
|
66
|
-
// Load existing templates
|
|
67
|
-
await this.loadExistingTemplates();
|
|
68
|
-
this.initialized = true;
|
|
69
|
-
this.logger?.info('SendGrid plugin initialized successfully');
|
|
70
|
-
}
|
|
71
|
-
async destroy() {
|
|
72
|
-
if (!this.initialized) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
this.ownershipValidator.clearRegistrations();
|
|
76
|
-
this.senderManager.clearCache();
|
|
77
|
-
this.initialized = false;
|
|
78
|
-
this.logger?.info('SendGrid plugin destroyed');
|
|
79
|
-
}
|
|
80
|
-
// Template operations
|
|
81
|
-
async createTemplate(template) {
|
|
82
|
-
this.ensureInitialized();
|
|
83
|
-
return this.templateManager.createTemplate(template);
|
|
84
|
-
}
|
|
85
|
-
async updateTemplate(providerTemplateId, template) {
|
|
86
|
-
this.ensureInitialized();
|
|
87
|
-
return this.templateManager.updateTemplate(providerTemplateId, template);
|
|
88
|
-
}
|
|
89
|
-
async deleteTemplate(providerTemplateId) {
|
|
90
|
-
this.ensureInitialized();
|
|
91
|
-
return this.templateManager.deleteTemplate(providerTemplateId);
|
|
92
|
-
}
|
|
93
|
-
async getTemplate(providerTemplateId) {
|
|
94
|
-
this.ensureInitialized();
|
|
95
|
-
return this.templateManager.getTemplate(providerTemplateId);
|
|
96
|
-
}
|
|
97
|
-
async listTemplates() {
|
|
98
|
-
this.ensureInitialized();
|
|
99
|
-
return this.templateManager.listTemplates();
|
|
100
|
-
}
|
|
101
|
-
// Synchronization
|
|
102
|
-
async syncToProvider(template) {
|
|
103
|
-
this.ensureInitialized();
|
|
104
|
-
return this.syncManager.syncToProvider(template);
|
|
105
|
-
}
|
|
106
|
-
async syncFromProvider(providerTemplateId) {
|
|
107
|
-
this.ensureInitialized();
|
|
108
|
-
return this.syncManager.syncFromProvider(providerTemplateId);
|
|
109
|
-
}
|
|
110
|
-
// SendGrid-specific features
|
|
111
|
-
async getVerifiedSenders() {
|
|
112
|
-
this.ensureInitialized();
|
|
113
|
-
return this.senderManager.getVerifiedSenders();
|
|
114
|
-
}
|
|
115
|
-
async validateSender(email) {
|
|
116
|
-
this.ensureInitialized();
|
|
117
|
-
return this.senderManager.validateSender(email);
|
|
118
|
-
}
|
|
119
|
-
async selectBestSender(email) {
|
|
120
|
-
this.ensureInitialized();
|
|
121
|
-
return this.senderManager.selectBestSender(email);
|
|
122
|
-
}
|
|
123
|
-
async createTemplateVersion(templateId, version) {
|
|
124
|
-
this.ensureInitialized();
|
|
125
|
-
return this.templateManager.createTemplateVersion(templateId, version);
|
|
126
|
-
}
|
|
127
|
-
async activateTemplateVersion(templateId, versionId) {
|
|
128
|
-
this.ensureInitialized();
|
|
129
|
-
return this.templateManager.activateTemplateVersion(templateId, versionId);
|
|
130
|
-
}
|
|
131
|
-
async getTemplateAnalytics(__templateId, __dateRange) {
|
|
132
|
-
this.ensureInitialized();
|
|
133
|
-
// TODO: Implement analytics fetching from SendGrid
|
|
134
|
-
throw new Error('Template analytics not yet implemented');
|
|
135
|
-
}
|
|
136
|
-
async batchSyncTemplates(templates) {
|
|
137
|
-
this.ensureInitialized();
|
|
138
|
-
return this.syncManager.batchSync(templates);
|
|
139
|
-
}
|
|
140
|
-
// Capabilities
|
|
141
|
-
getCapabilities() {
|
|
142
|
-
return [
|
|
143
|
-
{
|
|
144
|
-
feature: 'template-management',
|
|
145
|
-
description: 'Full CRUD operations for SendGrid templates',
|
|
146
|
-
methods: ['createTemplate', 'updateTemplate', 'deleteTemplate', 'getTemplate', 'listTemplates'],
|
|
147
|
-
config: {
|
|
148
|
-
supportsVersioning: true,
|
|
149
|
-
supportsActivation: true,
|
|
150
|
-
maxNameLength: 100,
|
|
151
|
-
templatePrefix: this.config.templatePrefix
|
|
152
|
-
}
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
feature: 'sender-verification',
|
|
156
|
-
description: 'SendGrid verified sender management',
|
|
157
|
-
methods: ['getVerifiedSenders', 'validateSender', 'selectBestSender'],
|
|
158
|
-
config: {
|
|
159
|
-
supportsDomainMatching: true,
|
|
160
|
-
supportsAutoSelection: true
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
{
|
|
164
|
-
feature: 'template-analytics',
|
|
165
|
-
description: 'SendGrid template usage and performance analytics',
|
|
166
|
-
methods: ['getTemplateAnalytics'],
|
|
167
|
-
config: {
|
|
168
|
-
supportsRealTime: false,
|
|
169
|
-
historicalDataDays: 30,
|
|
170
|
-
metricsAvailable: ['opens', 'clicks', 'bounces', 'deliveries']
|
|
171
|
-
}
|
|
172
|
-
},
|
|
173
|
-
{
|
|
174
|
-
feature: 'batch-operations',
|
|
175
|
-
description: 'Efficient bulk template operations',
|
|
176
|
-
methods: ['batchSyncTemplates'],
|
|
177
|
-
config: {
|
|
178
|
-
maxBatchSize: 50,
|
|
179
|
-
supportsTransactions: false
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
];
|
|
183
|
-
}
|
|
184
|
-
supportsFeature(feature) {
|
|
185
|
-
return this.getCapabilities().some(cap => cap.feature === feature);
|
|
186
|
-
}
|
|
187
|
-
getFeatureConfig(feature) {
|
|
188
|
-
const capability = this.getCapabilities().find(cap => cap.feature === feature);
|
|
189
|
-
return capability?.config || null;
|
|
190
|
-
}
|
|
191
|
-
validateRoute(__route) {
|
|
192
|
-
// Placeholder validation
|
|
193
|
-
return {
|
|
194
|
-
isValid: true,
|
|
195
|
-
errors: []
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
// Private methods
|
|
199
|
-
async loadExistingTemplates() {
|
|
200
|
-
try {
|
|
201
|
-
const templates = await this.templateManager.listTemplates();
|
|
202
|
-
this.logger?.info(`Loaded ${templates.length} existing SendGrid templates`);
|
|
203
|
-
}
|
|
204
|
-
catch (error) {
|
|
205
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
206
|
-
this.logger?.error(`Failed to load existing templates: ${errorMessage}`);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
ensureInitialized() {
|
|
210
|
-
if (!this.initialized) {
|
|
211
|
-
throw new Error('SendGrid plugin not initialized. Call initialize() first.');
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
exports.SendGridTemplatePlugin = SendGridTemplatePlugin;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { TemplateManager } from './template-manager';
|
|
2
|
-
import { TemplateConverter } from '../converters/template-converter';
|
|
3
|
-
import { SendGridClient } from '../api/sendgrid-client';
|
|
4
|
-
import { Template, SyncResult } from '../types/plugin-types';
|
|
5
|
-
export declare class SyncManager {
|
|
6
|
-
private readonly templateManager;
|
|
7
|
-
private readonly converter;
|
|
8
|
-
private readonly client;
|
|
9
|
-
private readonly logger?;
|
|
10
|
-
constructor(templateManager: TemplateManager, converter: TemplateConverter, client: SendGridClient, logger?: {
|
|
11
|
-
info: (message: string) => void;
|
|
12
|
-
error: (message: string) => void;
|
|
13
|
-
} | undefined);
|
|
14
|
-
syncToProvider(template: Template): Promise<SyncResult>;
|
|
15
|
-
syncFromProvider(providerTemplateId: string): Promise<Template>;
|
|
16
|
-
batchSync(templates: Template[]): Promise<SyncResult[]>;
|
|
17
|
-
private generateLocalId;
|
|
18
|
-
private sleep;
|
|
19
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
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.SyncManager = void 0;
|
|
11
|
-
class SyncManager {
|
|
12
|
-
templateManager;
|
|
13
|
-
converter;
|
|
14
|
-
client;
|
|
15
|
-
logger;
|
|
16
|
-
constructor(templateManager, converter, client, logger) {
|
|
17
|
-
this.templateManager = templateManager;
|
|
18
|
-
this.converter = converter;
|
|
19
|
-
this.client = client;
|
|
20
|
-
this.logger = logger;
|
|
21
|
-
}
|
|
22
|
-
async syncToProvider(template) {
|
|
23
|
-
try {
|
|
24
|
-
const existingProviderId = template.providerTemplateIds?.sendgrid;
|
|
25
|
-
if (existingProviderId) {
|
|
26
|
-
// Update existing template
|
|
27
|
-
await this.templateManager.updateTemplate(existingProviderId, template);
|
|
28
|
-
return {
|
|
29
|
-
success: true,
|
|
30
|
-
action: 'updated',
|
|
31
|
-
providerTemplateId: existingProviderId,
|
|
32
|
-
localTemplateId: template.id,
|
|
33
|
-
metadata: {
|
|
34
|
-
newVersion: template.version
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
// Create new template
|
|
40
|
-
const newProviderId = await this.templateManager.createTemplate(template);
|
|
41
|
-
return {
|
|
42
|
-
success: true,
|
|
43
|
-
action: 'created',
|
|
44
|
-
providerTemplateId: newProviderId,
|
|
45
|
-
localTemplateId: template.id,
|
|
46
|
-
metadata: {
|
|
47
|
-
version: template.version
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
catch (error) {
|
|
53
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
54
|
-
this.logger?.error(`Template sync failed: ${errorMessage}`);
|
|
55
|
-
return {
|
|
56
|
-
success: false,
|
|
57
|
-
action: 'failed',
|
|
58
|
-
localTemplateId: template.id,
|
|
59
|
-
error: errorMessage,
|
|
60
|
-
metadata: {
|
|
61
|
-
errorType: error instanceof Error ? error.constructor.name : 'UnknownError',
|
|
62
|
-
timestamp: new Date()
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
async syncFromProvider(providerTemplateId) {
|
|
68
|
-
const response = await this.client.request(`/templates/${providerTemplateId}`, {
|
|
69
|
-
method: 'GET'
|
|
70
|
-
});
|
|
71
|
-
if (!this.client.isSuccessResponse(response)) {
|
|
72
|
-
throw new Error(`Failed to fetch template from SendGrid: ${response.statusCode}`);
|
|
73
|
-
}
|
|
74
|
-
const templateData = this.client.parseResponseBody(response);
|
|
75
|
-
const localId = this.generateLocalId();
|
|
76
|
-
return this.converter.convertToLocalTemplate(templateData, localId);
|
|
77
|
-
}
|
|
78
|
-
async batchSync(templates) {
|
|
79
|
-
this.logger?.info(`Starting batch sync of ${templates.length} templates`);
|
|
80
|
-
const results = [];
|
|
81
|
-
for (const template of templates) {
|
|
82
|
-
const result = await this.syncToProvider(template);
|
|
83
|
-
results.push(result);
|
|
84
|
-
// Add delay to respect rate limits
|
|
85
|
-
await this.sleep(100);
|
|
86
|
-
}
|
|
87
|
-
const successful = results.filter(r => r.success).length;
|
|
88
|
-
this.logger?.info(`Batch sync completed: ${successful}/${templates.length} successful`);
|
|
89
|
-
return results;
|
|
90
|
-
}
|
|
91
|
-
generateLocalId() {
|
|
92
|
-
return `local_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
93
|
-
}
|
|
94
|
-
sleep(ms) {
|
|
95
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
exports.SyncManager = SyncManager;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { SendGridClient } from '../api/sendgrid-client';
|
|
2
|
-
import { OwnershipValidator } from '../safety/ownership-validator';
|
|
3
|
-
import { PrefixEnforcer } from '../safety/prefix-enforcer';
|
|
4
|
-
import { TemplateConverter } from '../converters/template-converter';
|
|
5
|
-
import { Template, ProviderTemplate, TemplateVersion } from '../types/plugin-types';
|
|
6
|
-
export declare class TemplateManager {
|
|
7
|
-
private readonly client;
|
|
8
|
-
private readonly ownershipValidator;
|
|
9
|
-
private readonly prefixEnforcer;
|
|
10
|
-
private readonly converter;
|
|
11
|
-
private readonly logger?;
|
|
12
|
-
constructor(client: SendGridClient, ownershipValidator: OwnershipValidator, prefixEnforcer: PrefixEnforcer, converter: TemplateConverter, logger?: {
|
|
13
|
-
info: (message: string) => void;
|
|
14
|
-
error: (message: string) => void;
|
|
15
|
-
} | undefined);
|
|
16
|
-
createTemplate(template: Template): Promise<string>;
|
|
17
|
-
updateTemplate(providerTemplateId: string, template: Template): Promise<void>;
|
|
18
|
-
deleteTemplate(providerTemplateId: string): Promise<void>;
|
|
19
|
-
getTemplate(providerTemplateId: string): Promise<ProviderTemplate>;
|
|
20
|
-
listTemplates(): Promise<ProviderTemplate[]>;
|
|
21
|
-
createTemplateVersion(templateId: string, version: TemplateVersion): Promise<string>;
|
|
22
|
-
activateTemplateVersion(templateId: string, versionId: string): Promise<void>;
|
|
23
|
-
private hasConflicts;
|
|
24
|
-
private detectConflicts;
|
|
25
|
-
}
|