@bernierllc/sender-identity-verification 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.
Files changed (51) hide show
  1. package/.env.test +8 -0
  2. package/.eslintrc.js +30 -0
  3. package/README.md +376 -0
  4. package/__tests__/SenderIdentityVerification.test.ts +461 -0
  5. package/__tests__/__mocks__/fetch-mock.ts +156 -0
  6. package/__tests__/additional-coverage.test.ts +129 -0
  7. package/__tests__/additional-error-coverage.test.ts +483 -0
  8. package/__tests__/branch-coverage.test.ts +509 -0
  9. package/__tests__/config.test.ts +119 -0
  10. package/__tests__/error-handling.test.ts +321 -0
  11. package/__tests__/final-branch-coverage.test.ts +372 -0
  12. package/__tests__/integration.real-api.test.ts +295 -0
  13. package/__tests__/providers.test.ts +331 -0
  14. package/__tests__/service-coverage.test.ts +412 -0
  15. package/dist/SenderIdentityVerification.d.ts +72 -0
  16. package/dist/SenderIdentityVerification.js +643 -0
  17. package/dist/config.d.ts +31 -0
  18. package/dist/config.js +38 -0
  19. package/dist/errors.d.ts +27 -0
  20. package/dist/errors.js +61 -0
  21. package/dist/index.d.ts +4 -0
  22. package/dist/index.js +21 -0
  23. package/dist/providers/MailgunProvider.d.ts +13 -0
  24. package/dist/providers/MailgunProvider.js +35 -0
  25. package/dist/providers/SESProvider.d.ts +12 -0
  26. package/dist/providers/SESProvider.js +47 -0
  27. package/dist/providers/SMTPProvider.d.ts +12 -0
  28. package/dist/providers/SMTPProvider.js +30 -0
  29. package/dist/providers/SendGridProvider.d.ts +19 -0
  30. package/dist/providers/SendGridProvider.js +98 -0
  31. package/dist/templates/verification-email.d.ts +9 -0
  32. package/dist/templates/verification-email.js +67 -0
  33. package/dist/types.d.ts +139 -0
  34. package/dist/types.js +33 -0
  35. package/dist/utils/domain-extractor.d.ts +4 -0
  36. package/dist/utils/domain-extractor.js +20 -0
  37. package/jest.config.cjs +33 -0
  38. package/package.json +60 -0
  39. package/src/SenderIdentityVerification.ts +796 -0
  40. package/src/config.ts +81 -0
  41. package/src/errors.ts +64 -0
  42. package/src/global.d.ts +24 -0
  43. package/src/index.ts +24 -0
  44. package/src/providers/MailgunProvider.ts +35 -0
  45. package/src/providers/SESProvider.ts +51 -0
  46. package/src/providers/SMTPProvider.ts +29 -0
  47. package/src/providers/SendGridProvider.ts +108 -0
  48. package/src/templates/verification-email.ts +67 -0
  49. package/src/types.ts +163 -0
  50. package/src/utils/domain-extractor.ts +18 -0
  51. package/tsconfig.json +22 -0
package/.env.test ADDED
@@ -0,0 +1,8 @@
1
+
2
+ NAMECOM_TESTING_API_KEY=b5944374cc5398daea865ba0780906bca8bf4b14
3
+ NAMECOM_TESTING_USERNAME=mkbernier-test
4
+ NAMECOM_API_KEY=43bb0dbe1e762ce1900a459e8ebd4076e006418f
5
+ NAMECOM_KEY_NAME=domain_testing_key
6
+ SENDGRID_API_KEY=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
7
+
8
+ TESTING_DOMAIN=bernierllc.com
package/.eslintrc.js ADDED
@@ -0,0 +1,30 @@
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
+ parser: '@typescript-eslint/parser',
11
+ extends: [
12
+ 'eslint:recommended',
13
+ 'plugin:@typescript-eslint/recommended'
14
+ ],
15
+ parserOptions: {
16
+ ecmaVersion: 2020,
17
+ sourceType: 'module',
18
+ project: './tsconfig.json'
19
+ },
20
+ rules: {
21
+ '@typescript-eslint/no-explicit-any': 'error',
22
+ '@typescript-eslint/explicit-function-return-type': 'warn',
23
+ '@typescript-eslint/no-unused-vars': ['error', { 'argsIgnorePattern': '^_' }],
24
+ 'no-console': 'off'
25
+ },
26
+ env: {
27
+ node: true,
28
+ jest: true
29
+ }
30
+ };
package/README.md ADDED
@@ -0,0 +1,376 @@
1
+ # @bernierllc/sender-identity-verification
2
+
3
+ Individual sender email address verification service for email production compliance. Manages sender identity creation, email address verification workflows, provider compliance validation, and administrative interfaces.
4
+
5
+ ## 📋 Overview
6
+
7
+ This package enables production email sending by verifying individual sender identities and ensuring provider compliance for email addresses. Works in conjunction with `@bernierllc/email-domain-verification` to ensure complete email sending compliance.
8
+
9
+ **Version**: 1.0.0
10
+ **Category**: service
11
+ **Priority**: critical
12
+
13
+ ## 🚀 Installation
14
+
15
+ ```bash
16
+ npm install @bernierllc/sender-identity-verification
17
+ ```
18
+
19
+ ## 📦 Dependencies
20
+
21
+ This package requires the following dependencies:
22
+
23
+ - `@bernierllc/email-sender` - For sending verification emails
24
+ - `@bernierllc/logger` - For audit logging
25
+ - `@bernierllc/neverhub-adapter` - For service mesh integration
26
+ - `@bernierllc/crypto-utils` - For secure token generation
27
+ - `@bernierllc/retry-policy` - For retry logic
28
+ - `@bernierllc/validators-email` - For email validation
29
+
30
+ **Note**: `@bernierllc/email-domain-verification` is required but not yet published. Domain verification features will be available when this dependency is released.
31
+
32
+ ## 🎯 Quick Start
33
+
34
+ ```typescript
35
+ import { SenderIdentityVerification, EmailProvider } from '@bernierllc/sender-identity-verification';
36
+
37
+ // Initialize the service
38
+ const service = new SenderIdentityVerification({
39
+ verificationBaseUrl: 'https://app.example.com',
40
+ verificationFromEmail: 'noreply@example.com',
41
+ verificationFromName: 'Example Verification',
42
+ sendgridApiKey: process.env.SENDGRID_API_KEY,
43
+ emailSenderConfig: {},
44
+ domainVerificationConfig: {}
45
+ });
46
+
47
+ await service.initialize();
48
+
49
+ // Create a sender
50
+ const result = await service.createSender({
51
+ email: 'hello@example.com',
52
+ name: 'Hello Team',
53
+ replyToEmail: 'support@example.com',
54
+ provider: EmailProvider.SENDGRID,
55
+ isDefault: true
56
+ });
57
+
58
+ console.log('Sender created:', result.data);
59
+ // Verification email automatically sent to hello@example.com
60
+ ```
61
+
62
+ ## 📚 API Reference
63
+
64
+ ### SenderIdentityVerification
65
+
66
+ Main service class for managing sender identities.
67
+
68
+ #### Constructor
69
+
70
+ ```typescript
71
+ new SenderIdentityVerification(config: SenderIdentityConfig)
72
+ ```
73
+
74
+ **Configuration Options**:
75
+
76
+ ```typescript
77
+ interface SenderIdentityConfig {
78
+ // Verification settings
79
+ verificationBaseUrl: string; // Base URL for verification links
80
+ verificationFromEmail: string; // From email for verification emails
81
+ verificationFromName: string; // From name for verification emails
82
+
83
+ // Provider API keys
84
+ sendgridApiKey?: string; // SendGrid API key
85
+ mailgunApiKey?: string; // Mailgun API key
86
+ sesAccessKey?: string; // AWS SES access key
87
+ sesSecretKey?: string; // AWS SES secret key
88
+ sesRegion?: string; // AWS SES region (default: 'us-east-1')
89
+
90
+ // Email sender configuration
91
+ emailSenderConfig: object;
92
+
93
+ // Domain verification configuration
94
+ domainVerificationConfig: object;
95
+
96
+ // Retry configuration
97
+ retryConfig?: object;
98
+
99
+ // Database configuration
100
+ databaseUrl?: string;
101
+ }
102
+ ```
103
+
104
+ #### Methods
105
+
106
+ ##### `createSender(input: CreateSenderInput): Promise<SenderIdentityResult<SenderIdentity>>`
107
+
108
+ Create a new sender identity.
109
+
110
+ ```typescript
111
+ const result = await service.createSender({
112
+ email: 'hello@example.com',
113
+ name: 'Hello Team',
114
+ replyToEmail: 'support@example.com',
115
+ replyToName: 'Support Team',
116
+ provider: EmailProvider.SENDGRID,
117
+ isDefault: true,
118
+ skipVerification: false // Set to true for testing
119
+ });
120
+ ```
121
+
122
+ ##### `verifySender(token: string): Promise<VerificationResult>`
123
+
124
+ Verify a sender using the verification token from the email.
125
+
126
+ ```typescript
127
+ const result = await service.verifySender('abc123token');
128
+
129
+ if (result.success) {
130
+ console.log('Sender verified:', result.senderId);
131
+ }
132
+ ```
133
+
134
+ ##### `getSender(senderId: string): Promise<SenderIdentityResult<SenderIdentity>>`
135
+
136
+ Get sender by ID.
137
+
138
+ ```typescript
139
+ const result = await service.getSender('sender-id-123');
140
+ console.log('Sender:', result.data);
141
+ ```
142
+
143
+ ##### `listSenders(options?: ListSendersOptions): Promise<SenderIdentityResult<SenderIdentity[]>>`
144
+
145
+ List senders with optional filtering.
146
+
147
+ ```typescript
148
+ const result = await service.listSenders({
149
+ provider: EmailProvider.SENDGRID,
150
+ status: SenderStatus.VERIFIED,
151
+ isActive: true,
152
+ limit: 50,
153
+ offset: 0
154
+ });
155
+ ```
156
+
157
+ ##### `updateSender(senderId: string, input: UpdateSenderInput): Promise<SenderIdentityResult<SenderIdentity>>`
158
+
159
+ Update sender details.
160
+
161
+ ```typescript
162
+ const result = await service.updateSender('sender-id-123', {
163
+ name: 'Updated Name',
164
+ replyToEmail: 'new-support@example.com',
165
+ isDefault: true
166
+ });
167
+ ```
168
+
169
+ ##### `deleteSender(senderId: string): Promise<SenderIdentityResult<void>>`
170
+
171
+ Soft delete a sender.
172
+
173
+ ```typescript
174
+ const result = await service.deleteSender('sender-id-123');
175
+ ```
176
+
177
+ ##### `checkCompliance(senderId: string): Promise<SenderIdentityResult<ComplianceCheckResult>>`
178
+
179
+ Check provider compliance for a sender.
180
+
181
+ ```typescript
182
+ const result = await service.checkCompliance('sender-id-123');
183
+
184
+ if (result.success) {
185
+ console.log('Compliance status:', result.data?.isCompliant);
186
+ console.log('Domain verified:', result.data?.checks.domainVerified);
187
+ console.log('SPF valid:', result.data?.checks.spfValid);
188
+ console.log('DKIM valid:', result.data?.checks.dkimValid);
189
+ }
190
+ ```
191
+
192
+ ##### `getDefaultSender(provider: EmailProvider): Promise<SenderIdentityResult<SenderIdentity>>`
193
+
194
+ Get the default sender for a provider.
195
+
196
+ ```typescript
197
+ const result = await service.getDefaultSender(EmailProvider.SENDGRID);
198
+ console.log('Default sender:', result.data?.email);
199
+ ```
200
+
201
+ ##### `resendVerification(senderId: string): Promise<SenderIdentityResult<void>>`
202
+
203
+ Resend verification email.
204
+
205
+ ```typescript
206
+ const result = await service.resendVerification('sender-id-123');
207
+ ```
208
+
209
+ ## 🔌 Integration Status
210
+
211
+ - **Logger**: integrated - Critical for audit trail of sender verification events
212
+ - **Docs-Suite**: ready - Complete API documentation with TypeScript interfaces
213
+ - **NeverHub**: required - Service mesh integration for event publishing
214
+
215
+ ## 🔒 Security Considerations
216
+
217
+ ### Verification Token Security
218
+ - Tokens are cryptographically secure (32 bytes, URL-safe)
219
+ - Single-use tokens (cleared after successful verification)
220
+ - Time-limited (24 hour expiration)
221
+ - Stored securely in database
222
+
223
+ ### Rate Limiting
224
+ - Max 3 verification emails per hour per sender
225
+ - Prevents abuse and spam
226
+ - Locks sender after too many failed attempts
227
+
228
+ ### Provider API Key Storage
229
+ - API keys stored in environment variables (never in code)
230
+ - API keys never logged or exposed in responses
231
+ - Encrypted at rest in database (if persisting config)
232
+
233
+ ## 📊 Monitoring & Observability
234
+
235
+ ### Key Metrics to Track
236
+
237
+ - `sender.created` - Senders created
238
+ - `sender.verified` - Senders verified
239
+ - `sender.failed` - Verification failures
240
+ - `sender.locked` - Senders locked
241
+ - `verification.email_sent` - Verification emails sent
242
+ - `verification.token_validated` - Token validations
243
+ - `compliance.checked` - Compliance checks
244
+ - `compliance.passed` - Compliance passes
245
+
246
+ ### Critical Events to Log
247
+
248
+ ```typescript
249
+ logger.info('sender.created', { senderId, email, provider });
250
+ logger.info('sender.verified', { senderId, email, verifiedAt });
251
+ logger.warn('sender.verification_failed', { senderId, reason });
252
+ logger.error('sender.locked', { senderId, attempts });
253
+ logger.audit('sender.deleted', { senderId, email, deletedBy });
254
+ ```
255
+
256
+ ## 🔗 Related Packages
257
+
258
+ ### Dependencies
259
+ - [@bernierllc/email-sender](../email-sender) - Email sending functionality
260
+ - [@bernierllc/logger](../logger) - Logging infrastructure
261
+ - [@bernierllc/neverhub-adapter](../neverhub-adapter) - Service mesh integration
262
+ - [@bernierllc/crypto-utils](../crypto-utils) - Cryptographic utilities
263
+ - [@bernierllc/retry-policy](../retry-policy) - Retry logic
264
+ - [@bernierllc/validators-email](../validators-email) - Email validation
265
+
266
+ ### Dependent Packages
267
+ - [@bernierllc/email-manager](../email-manager) - Email management suite
268
+ - [@bernierllc/email-admin-ui](../email-admin-ui) - Email administration UI
269
+ - [@bernierllc/email-webhook-events](../email-webhook-events) - Email event tracking
270
+
271
+ ## 📝 Examples
272
+
273
+ ### Basic Sender Creation
274
+
275
+ ```typescript
276
+ import { SenderIdentityVerification, EmailProvider } from '@bernierllc/sender-identity-verification';
277
+
278
+ const service = new SenderIdentityVerification({
279
+ verificationBaseUrl: 'https://app.example.com',
280
+ verificationFromEmail: 'noreply@example.com',
281
+ verificationFromName: 'Example Verification',
282
+ sendgridApiKey: process.env.SENDGRID_API_KEY,
283
+ emailSenderConfig: {},
284
+ domainVerificationConfig: {}
285
+ });
286
+
287
+ await service.initialize();
288
+
289
+ // Create sender
290
+ const result = await service.createSender({
291
+ email: 'hello@example.com',
292
+ name: 'Hello Team',
293
+ replyToEmail: 'support@example.com',
294
+ provider: EmailProvider.SENDGRID,
295
+ isDefault: true
296
+ });
297
+
298
+ console.log('Sender created:', result.data);
299
+ ```
300
+
301
+ ### Verify Sender Email
302
+
303
+ ```typescript
304
+ // User clicks verification link in email
305
+ // Link contains token: https://app.example.com/verify-sender?token=abc123
306
+
307
+ const verifyResult = await service.verifySender('abc123');
308
+
309
+ if (verifyResult.success) {
310
+ console.log('Sender verified:', verifyResult.senderId);
311
+ console.log('Verified at:', verifyResult.verifiedAt);
312
+ } else {
313
+ console.error('Verification failed:', verifyResult.message);
314
+ }
315
+ ```
316
+
317
+ ### List Verified Senders
318
+
319
+ ```typescript
320
+ // List all verified senders for SendGrid
321
+ const sendersResult = await service.listSenders({
322
+ provider: EmailProvider.SENDGRID,
323
+ status: SenderStatus.VERIFIED,
324
+ isActive: true
325
+ });
326
+
327
+ console.log('Verified SendGrid senders:', sendersResult.data);
328
+ ```
329
+
330
+ ### Check Compliance
331
+
332
+ ```typescript
333
+ // Check compliance for a sender
334
+ const complianceResult = await service.checkCompliance('sender-id-123');
335
+
336
+ if (complianceResult.success) {
337
+ const compliance = complianceResult.data!;
338
+
339
+ console.log('Compliance Status:', compliance.isCompliant ? 'PASS' : 'FAIL');
340
+ console.log('Domain Verified:', compliance.checks.domainVerified);
341
+ console.log('SPF Valid:', compliance.checks.spfValid);
342
+ console.log('DKIM Valid:', compliance.checks.dkimValid);
343
+
344
+ if (!compliance.isCompliant) {
345
+ console.log('Errors:', compliance.errors);
346
+ }
347
+ }
348
+ ```
349
+
350
+ ## 🐛 Troubleshooting
351
+
352
+ ### Common Issues
353
+
354
+ **Issue**: Domain not verified error
355
+ **Solution**: Ensure the domain is verified using `@bernierllc/email-domain-verification` before creating senders
356
+
357
+ **Issue**: Sender already exists
358
+ **Solution**: Check for existing senders with `listSenders()` before creating new ones
359
+
360
+ **Issue**: Verification token expired
361
+ **Solution**: Use `resendVerification()` to send a new verification email
362
+
363
+ **Issue**: Too many verification emails
364
+ **Solution**: Rate limiting prevents more than 3 emails per hour - wait before retrying
365
+
366
+ ## 📜 License
367
+
368
+ Copyright (c) 2025 Bernier LLC
369
+
370
+ This file is licensed to the client under a limited-use license.
371
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
372
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
373
+
374
+ ## 🤝 Support
375
+
376
+ For issues, questions, or contributions, please contact Bernier LLC.