@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/src/config.ts ADDED
@@ -0,0 +1,81 @@
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
+ import { IEmailDomainVerification } from './types.js';
10
+
11
+ /**
12
+ * Configuration for sender identity verification service
13
+ */
14
+ export interface SenderIdentityConfig {
15
+ // Email sender configuration (for sending verification emails)
16
+ emailSenderConfig: {
17
+ provider?: string;
18
+ apiKey?: string;
19
+ };
20
+
21
+ // Domain verification configuration
22
+ domainVerificationConfig: {
23
+ instance?: IEmailDomainVerification;
24
+ };
25
+
26
+ // Retry configuration
27
+ retryConfig?: {
28
+ maxRetries?: number;
29
+ initialDelayMs?: number;
30
+ maxDelayMs?: number;
31
+ };
32
+
33
+ // Verification settings
34
+ verificationBaseUrl: string;
35
+ verificationFromEmail: string;
36
+ verificationFromName: string;
37
+
38
+ // Provider API keys
39
+ sendgridApiKey?: string;
40
+ mailgunApiKey?: string;
41
+ sesAccessKey?: string;
42
+ sesSecretKey?: string;
43
+ sesRegion?: string;
44
+
45
+ // Database configuration
46
+ databaseUrl?: string;
47
+ }
48
+
49
+ /**
50
+ * Load configuration from environment variables
51
+ */
52
+ export function loadConfigFromEnv(overrides: Partial<SenderIdentityConfig> = {}): SenderIdentityConfig {
53
+ const config: SenderIdentityConfig = {
54
+ verificationBaseUrl: process.env.SENDER_VERIFICATION_BASE_URL || overrides.verificationBaseUrl || '',
55
+ verificationFromEmail: process.env.SENDER_VERIFICATION_FROM_EMAIL || overrides.verificationFromEmail || 'noreply@example.com',
56
+ verificationFromName: process.env.SENDER_VERIFICATION_FROM_NAME || overrides.verificationFromName || 'Email Verification',
57
+
58
+ sendgridApiKey: process.env.SENDGRID_API_KEY || overrides.sendgridApiKey,
59
+ mailgunApiKey: process.env.MAILGUN_API_KEY || overrides.mailgunApiKey,
60
+ sesAccessKey: process.env.AWS_SES_ACCESS_KEY || overrides.sesAccessKey,
61
+ sesSecretKey: process.env.AWS_SES_SECRET_KEY || overrides.sesSecretKey,
62
+ sesRegion: process.env.AWS_SES_REGION || overrides.sesRegion || 'us-east-1',
63
+
64
+ databaseUrl: process.env.DATABASE_URL || overrides.databaseUrl,
65
+
66
+ emailSenderConfig: overrides.emailSenderConfig || {},
67
+ domainVerificationConfig: overrides.domainVerificationConfig || {},
68
+ retryConfig: overrides.retryConfig
69
+ };
70
+
71
+ // Log configuration (without sensitive data)
72
+ console.log('⚙️ Sender Identity Verification Configuration:');
73
+ console.log(` └── Verification Base URL: ${config.verificationBaseUrl || '(not set)'}`);
74
+ console.log(` └── From Email: ${config.verificationFromEmail}`);
75
+ console.log(` └── SendGrid: ${config.sendgridApiKey ? '***configured***' : '(not set)'}`);
76
+ console.log(` └── Mailgun: ${config.mailgunApiKey ? '***configured***' : '(not set)'}`);
77
+ console.log(` └── SES: ${config.sesAccessKey ? '***configured***' : '(not set)'}`);
78
+ console.log(` └── Database: ${config.databaseUrl ? '***configured***' : '(not set)'}`);
79
+
80
+ return config;
81
+ }
package/src/errors.ts ADDED
@@ -0,0 +1,64 @@
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
+ import { SenderIdentityResult } from './types.js';
10
+
11
+ /**
12
+ * Sender error codes
13
+ */
14
+ export enum SenderErrorCode {
15
+ SENDER_NOT_FOUND = 'SENDER_NOT_FOUND',
16
+ SENDER_ALREADY_EXISTS = 'SENDER_ALREADY_EXISTS',
17
+ SENDER_LOCKED = 'SENDER_LOCKED',
18
+ VERIFICATION_EXPIRED = 'VERIFICATION_EXPIRED',
19
+ VERIFICATION_FAILED = 'VERIFICATION_FAILED',
20
+ DOMAIN_NOT_VERIFIED = 'DOMAIN_NOT_VERIFIED',
21
+ PROVIDER_ERROR = 'PROVIDER_ERROR',
22
+ INVALID_EMAIL = 'INVALID_EMAIL',
23
+ RATE_LIMIT_EXCEEDED = 'RATE_LIMIT_EXCEEDED',
24
+ }
25
+
26
+ /**
27
+ * Custom error class for sender verification errors
28
+ */
29
+ export class SenderVerificationError extends Error {
30
+ constructor(
31
+ message: string,
32
+ public code: SenderErrorCode,
33
+ public details?: unknown
34
+ ) {
35
+ super(message);
36
+ this.name = 'SenderVerificationError';
37
+ Object.setPrototypeOf(this, SenderVerificationError.prototype);
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Error handling wrapper
43
+ */
44
+ export function handleSenderError(error: unknown): SenderIdentityResult<never> {
45
+ if (error instanceof SenderVerificationError) {
46
+ return {
47
+ success: false,
48
+ error: error.message,
49
+ errors: [error.code]
50
+ };
51
+ }
52
+
53
+ if (error instanceof Error) {
54
+ return {
55
+ success: false,
56
+ error: error.message
57
+ };
58
+ }
59
+
60
+ return {
61
+ success: false,
62
+ error: 'Unknown error occurred'
63
+ };
64
+ }
@@ -0,0 +1,24 @@
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
+ // Node.js global types
10
+ declare const process: {
11
+ env: {
12
+ [key: string]: string | undefined;
13
+ };
14
+ };
15
+
16
+ // Fetch API types (minimal declaration)
17
+ declare function fetch(url: string, init?: {
18
+ method?: string;
19
+ headers?: Record<string, string>;
20
+ body?: string;
21
+ }): Promise<{
22
+ ok: boolean;
23
+ json(): Promise<unknown>;
24
+ }>;
package/src/index.ts ADDED
@@ -0,0 +1,24 @@
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
+ export { SenderIdentityVerification } from './SenderIdentityVerification.js';
10
+ export { SenderIdentityConfig, loadConfigFromEnv } from './config.js';
11
+ export { SenderVerificationError, SenderErrorCode, handleSenderError } from './errors.js';
12
+ export {
13
+ SenderIdentity,
14
+ SenderStatus,
15
+ EmailProvider,
16
+ CreateSenderInput,
17
+ UpdateSenderInput,
18
+ VerificationResult,
19
+ ComplianceCheckResult,
20
+ ListSendersOptions,
21
+ SenderIdentityResult,
22
+ DomainVerificationStatus,
23
+ IEmailDomainVerification
24
+ } from './types.js';
@@ -0,0 +1,35 @@
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
+ import { SenderIdentity, SenderIdentityResult } from '../types.js';
10
+
11
+ /**
12
+ * Mailgun provider for sender verification
13
+ * Note: Mailgun doesn't have sender-level verification, only domain verification
14
+ */
15
+ export class MailgunProvider {
16
+ constructor(_apiKey: string) {
17
+ // apiKey parameter reserved for future Mailgun API integration
18
+ void _apiKey;
19
+ }
20
+
21
+ /**
22
+ * Verify sender with Mailgun
23
+ * Mailgun only verifies domains, not individual senders
24
+ */
25
+ async verifySender(_sender: SenderIdentity): Promise<SenderIdentityResult<Record<string, unknown>>> {
26
+ // Mailgun doesn't require individual sender verification
27
+ // Domain verification is handled by @bernierllc/email-domain-verification
28
+ return {
29
+ success: true,
30
+ data: {
31
+ note: 'Mailgun does not require individual sender verification'
32
+ }
33
+ };
34
+ }
35
+ }
@@ -0,0 +1,51 @@
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
+ import { SenderIdentity, SenderIdentityResult } from '../types.js';
10
+
11
+ /**
12
+ * AWS SES provider for sender verification
13
+ */
14
+ export class SESProvider {
15
+ constructor(
16
+ _accessKey: string,
17
+ _secretKey: string,
18
+ _region: string
19
+ ) {
20
+ // Parameters reserved for future AWS SDK integration
21
+ void _accessKey;
22
+ void _secretKey;
23
+ void _region;
24
+ }
25
+
26
+ /**
27
+ * Verify sender with AWS SES
28
+ * TODO: Implement AWS SDK integration for SES VerifyEmailIdentity
29
+ */
30
+ async verifySender(_sender: SenderIdentity): Promise<SenderIdentityResult<Record<string, unknown>>> {
31
+ try {
32
+ // TODO: Call SES VerifyEmailIdentity API
33
+ // For now, return success (stub implementation)
34
+ // Real implementation would use AWS SDK:
35
+ // const ses = new SES({ region: this.region, credentials: {...} });
36
+ // await ses.verifyEmailIdentity({ EmailAddress: sender.email });
37
+
38
+ return {
39
+ success: true,
40
+ data: {
41
+ note: 'SES verification stubbed - AWS SDK integration pending'
42
+ }
43
+ };
44
+ } catch (error) {
45
+ return {
46
+ success: false,
47
+ error: error instanceof Error ? error.message : 'SES verification failed'
48
+ };
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,29 @@
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
+ import { SenderIdentity, SenderIdentityResult } from '../types.js';
10
+
11
+ /**
12
+ * SMTP provider for sender verification
13
+ * Note: SMTP doesn't require provider-level verification
14
+ */
15
+ export class SMTPProvider {
16
+ /**
17
+ * Verify sender with SMTP
18
+ * SMTP doesn't require provider verification - just email validation
19
+ */
20
+ async verifySender(_sender: SenderIdentity): Promise<SenderIdentityResult<Record<string, unknown>>> {
21
+ // SMTP doesn't require provider-level verification
22
+ return {
23
+ success: true,
24
+ data: {
25
+ note: 'SMTP does not require provider-level verification'
26
+ }
27
+ };
28
+ }
29
+ }
@@ -0,0 +1,108 @@
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
+ import { SenderIdentity, SenderIdentityResult } from '../types.js';
10
+
11
+ /**
12
+ * SendGrid provider for sender verification
13
+ */
14
+ export class SendGridProvider {
15
+ constructor(private apiKey: string) {}
16
+
17
+ /**
18
+ * Verify sender with SendGrid
19
+ */
20
+ async verifySender(sender: SenderIdentity): Promise<SenderIdentityResult<{
21
+ providerId: string;
22
+ metadata: Record<string, unknown>;
23
+ }>> {
24
+ try {
25
+ if (!this.apiKey) {
26
+ return {
27
+ success: false,
28
+ error: 'SendGrid API key not configured'
29
+ };
30
+ }
31
+
32
+ // Create verified sender in SendGrid
33
+ const response = await this.sendGridRequest('POST', '/verified_senders', {
34
+ nickname: sender.name,
35
+ from_email: sender.email,
36
+ from_name: sender.name,
37
+ reply_to: sender.replyToEmail,
38
+ reply_to_name: sender.replyToName,
39
+ address: '123 Main St',
40
+ city: 'Anytown',
41
+ state: 'CA', // Must be 2-character state code per SendGrid API requirements
42
+ zip: '12345',
43
+ country: 'US'
44
+ });
45
+
46
+ if (!response.success) {
47
+ return {
48
+ success: false,
49
+ error: 'SendGrid verification failed',
50
+ errors: [response.error || 'Unknown SendGrid error']
51
+ };
52
+ }
53
+
54
+ return {
55
+ success: true,
56
+ data: {
57
+ providerId: response.data?.id as string || '',
58
+ metadata: response.data || {}
59
+ }
60
+ };
61
+ } catch (error) {
62
+ return {
63
+ success: false,
64
+ error: error instanceof Error ? error.message : 'SendGrid verification failed'
65
+ };
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Make SendGrid API request
71
+ */
72
+ private async sendGridRequest(
73
+ method: string,
74
+ path: string,
75
+ body?: Record<string, unknown>
76
+ ): Promise<SenderIdentityResult<Record<string, unknown>>> {
77
+ try {
78
+ const response = await fetch(`https://api.sendgrid.com/v3${path}`, {
79
+ method,
80
+ headers: {
81
+ 'Authorization': `Bearer ${this.apiKey}`,
82
+ 'Content-Type': 'application/json'
83
+ },
84
+ body: body ? JSON.stringify(body) : undefined
85
+ });
86
+
87
+ const data = await response.json() as { errors?: Array<{ message: string }>; id?: string };
88
+
89
+ if (!response.ok) {
90
+ return {
91
+ success: false,
92
+ error: data.errors?.[0]?.message || 'SendGrid API error',
93
+ errors: data.errors?.map((e) => e.message)
94
+ };
95
+ }
96
+
97
+ return {
98
+ success: true,
99
+ data: data as Record<string, unknown>
100
+ };
101
+ } catch (error) {
102
+ return {
103
+ success: false,
104
+ error: error instanceof Error ? error.message : 'SendGrid request failed'
105
+ };
106
+ }
107
+ }
108
+ }
@@ -0,0 +1,67 @@
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
+ import { SenderIdentity } from '../types.js';
10
+
11
+ /**
12
+ * Build HTML verification email
13
+ */
14
+ export function buildVerificationEmailHtml(sender: SenderIdentity, verificationUrl: string): string {
15
+ return `
16
+ <!DOCTYPE html>
17
+ <html>
18
+ <head>
19
+ <style>
20
+ body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
21
+ .container { max-width: 600px; margin: 0 auto; padding: 20px; }
22
+ .button { background-color: #007bff; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block; margin: 20px 0; }
23
+ .footer { margin-top: 40px; padding-top: 20px; border-top: 1px solid #ddd; font-size: 12px; color: #666; }
24
+ </style>
25
+ </head>
26
+ <body>
27
+ <div class="container">
28
+ <h1>Verify Your Sender Email Address</h1>
29
+ <p>Hello ${sender.name},</p>
30
+ <p>You've added <strong>${sender.email}</strong> as a sender email address for ${sender.provider}.</p>
31
+ <p>To complete the verification process, please click the button below:</p>
32
+ <a href="${verificationUrl}" class="button">Verify Email Address</a>
33
+ <p>Or copy and paste this URL into your browser:</p>
34
+ <p>${verificationUrl}</p>
35
+ <p><strong>This link will expire in 24 hours.</strong></p>
36
+ <div class="footer">
37
+ <p>If you didn't request this verification, please ignore this email.</p>
38
+ <p>Sender ID: ${sender.id}</p>
39
+ </div>
40
+ </div>
41
+ </body>
42
+ </html>
43
+ `;
44
+ }
45
+
46
+ /**
47
+ * Build plain text verification email
48
+ */
49
+ export function buildVerificationEmailText(sender: SenderIdentity, verificationUrl: string): string {
50
+ return `
51
+ Verify Your Sender Email Address
52
+
53
+ Hello ${sender.name},
54
+
55
+ You've added ${sender.email} as a sender email address for ${sender.provider}.
56
+
57
+ To complete the verification process, please visit:
58
+
59
+ ${verificationUrl}
60
+
61
+ This link will expire in 24 hours.
62
+
63
+ If you didn't request this verification, please ignore this email.
64
+
65
+ Sender ID: ${sender.id}
66
+ `.trim();
67
+ }
package/src/types.ts ADDED
@@ -0,0 +1,163 @@
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
+ /**
10
+ * Sender identity record
11
+ */
12
+ export interface SenderIdentity {
13
+ id: string;
14
+ email: string;
15
+ name: string;
16
+ replyToEmail?: string;
17
+ replyToName?: string;
18
+ domain: string;
19
+ provider: EmailProvider;
20
+
21
+ // Status tracking
22
+ status: SenderStatus;
23
+ isDefault: boolean;
24
+ isActive: boolean;
25
+
26
+ // Verification
27
+ verifiedAt?: Date;
28
+ verificationToken?: string;
29
+ verificationSentAt?: Date;
30
+ verificationExpiresAt?: Date;
31
+ verificationAttempts: number;
32
+
33
+ // Provider-specific data
34
+ providerSenderId?: string; // SendGrid verified sender ID
35
+ providerMetadata?: Record<string, unknown>;
36
+
37
+ // Validation
38
+ lastValidated?: Date;
39
+ validationErrors?: string[];
40
+
41
+ // Timestamps
42
+ createdAt: Date;
43
+ updatedAt: Date;
44
+ deletedAt?: Date;
45
+ }
46
+
47
+ /**
48
+ * Sender status enum
49
+ */
50
+ export enum SenderStatus {
51
+ PENDING = 'pending', // Created, awaiting verification
52
+ VERIFICATION_SENT = 'verification_sent', // Verification email sent
53
+ VERIFIED = 'verified', // Email verified, ready to use
54
+ FAILED = 'failed', // Verification failed
55
+ EXPIRED = 'expired', // Verification token expired
56
+ LOCKED = 'locked', // Too many failed attempts
57
+ INACTIVE = 'inactive', // Deactivated by admin
58
+ }
59
+
60
+ /**
61
+ * Email provider enum
62
+ */
63
+ export enum EmailProvider {
64
+ SENDGRID = 'sendgrid',
65
+ MAILGUN = 'mailgun',
66
+ SES = 'ses',
67
+ SMTP = 'smtp',
68
+ }
69
+
70
+ /**
71
+ * Sender creation input
72
+ */
73
+ export interface CreateSenderInput {
74
+ email: string;
75
+ name: string;
76
+ replyToEmail?: string;
77
+ replyToName?: string;
78
+ provider: EmailProvider;
79
+ isDefault?: boolean;
80
+ skipVerification?: boolean; // For testing/dev
81
+ }
82
+
83
+ /**
84
+ * Sender update input
85
+ */
86
+ export interface UpdateSenderInput {
87
+ name?: string;
88
+ replyToEmail?: string;
89
+ replyToName?: string;
90
+ isDefault?: boolean;
91
+ isActive?: boolean;
92
+ }
93
+
94
+ /**
95
+ * Verification result
96
+ */
97
+ export interface VerificationResult {
98
+ success: boolean;
99
+ senderId: string;
100
+ status: SenderStatus;
101
+ message: string;
102
+ verifiedAt?: Date;
103
+ errors?: string[];
104
+ }
105
+
106
+ /**
107
+ * Provider compliance check result
108
+ */
109
+ export interface ComplianceCheckResult {
110
+ isCompliant: boolean;
111
+ checks: {
112
+ domainVerified: boolean;
113
+ spfValid: boolean;
114
+ dkimValid: boolean;
115
+ emailFormat: boolean;
116
+ };
117
+ errors: string[];
118
+ warnings: string[];
119
+ }
120
+
121
+ /**
122
+ * Sender list options
123
+ */
124
+ export interface ListSendersOptions {
125
+ provider?: EmailProvider;
126
+ status?: SenderStatus;
127
+ isActive?: boolean;
128
+ domain?: string;
129
+ limit?: number;
130
+ offset?: number;
131
+ }
132
+
133
+ /**
134
+ * Package result wrapper
135
+ */
136
+ export interface SenderIdentityResult<T = unknown> {
137
+ success: boolean;
138
+ data?: T;
139
+ error?: string;
140
+ errors?: string[];
141
+ }
142
+
143
+ /**
144
+ * Domain verification status (interface for missing @bernierllc/email-domain-verification)
145
+ * TODO: Replace with actual import when email-domain-verification package is available
146
+ */
147
+ export interface DomainVerificationStatus {
148
+ isVerified: boolean;
149
+ domain: string;
150
+ verificationUrl?: string;
151
+ dnsRecords?: {
152
+ spf?: { isValid: boolean };
153
+ dkim?: { isValid: boolean };
154
+ };
155
+ }
156
+
157
+ /**
158
+ * Email domain verification interface (stub for missing dependency)
159
+ * TODO: Replace with actual @bernierllc/email-domain-verification when available
160
+ */
161
+ export interface IEmailDomainVerification {
162
+ getDomainStatus(domain: string): Promise<DomainVerificationStatus>;
163
+ }
@@ -0,0 +1,18 @@
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
+ /**
10
+ * Extract domain from email address
11
+ */
12
+ export function extractDomain(email: string): string {
13
+ const parts = email.split('@');
14
+ if (parts.length !== 2) {
15
+ throw new Error(`Invalid email format: ${email}`);
16
+ }
17
+ return parts[1].toLowerCase();
18
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "lib": ["ES2020", "DOM"],
6
+ "declaration": true,
7
+ "outDir": "./dist",
8
+ "rootDir": "./src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "moduleResolution": "node",
14
+ "resolveJsonModule": true,
15
+ "noUnusedLocals": true,
16
+ "noUnusedParameters": true,
17
+ "noImplicitReturns": true,
18
+ "noFallthroughCasesInSwitch": true
19
+ },
20
+ "include": ["src/**/*"],
21
+ "exclude": ["node_modules", "dist", "__tests__"]
22
+ }