Files
the_order/services/identity/src/credential-notifications.ts
defiQUG 2633de4d33 feat(eresidency): Complete eResidency service implementation
- Implement credential revocation endpoint with proper database integration
- Fix database row mapping (snake_case to camelCase) for eResidency applications
- Add missing imports (getRiskAssessmentEngine, VeriffKYCProvider, ComplyAdvantageSanctionsProvider)
- Fix environment variable type checking for Veriff and ComplyAdvantage providers
- Add required 'message' field to notification service calls
- Fix risk assessment type mismatches
- Update audit logging to use 'verified' action type (supported by schema)
- Resolve all TypeScript errors and unused variable warnings
- Add TypeScript ignore comments for placeholder implementations
- Temporarily disable security/detect-non-literal-regexp rule due to ESLint 9 compatibility
- Service now builds successfully with no linter errors

All core functionality implemented:
- Application submission and management
- KYC integration (Veriff placeholder)
- Sanctions screening (ComplyAdvantage placeholder)
- Risk assessment engine
- Credential issuance and revocation
- Reviewer console
- Status endpoints
- Auto-issuance service
2025-11-10 19:43:02 -08:00

167 lines
5.5 KiB
TypeScript

/**
* Automated credential issuance notifications
*/
import { getNotificationService, CredentialNotificationTemplates } from '@the-order/notifications';
import { getEventBus, CredentialEvents } from '@the-order/events';
/**
* Initialize credential issuance notifications
*/
export async function initializeCredentialNotifications(): Promise<void> {
const eventBus = getEventBus();
const notificationService = getNotificationService();
// Subscribe to credential issued events
await eventBus.subscribe(CredentialEvents.ISSUED, async (data) => {
const eventData = data as {
subjectDid: string;
credentialType: string | string[];
credentialId?: string;
issuedAt: string;
recipientEmail?: string;
recipientPhone?: string;
recipientName?: string;
};
const credentialType = Array.isArray(eventData.credentialType)
? eventData.credentialType.join(', ')
: eventData.credentialType;
// Send email notification
if (eventData.recipientEmail) {
await notificationService.send({
to: eventData.recipientEmail,
type: 'email',
subject: CredentialNotificationTemplates.ISSUED.email.subject,
template: CredentialNotificationTemplates.ISSUED.email.template,
templateData: {
recipientName: eventData.recipientName || 'User',
credentialType,
issuerName: 'The Order',
issuedAt: eventData.issuedAt,
credentialId: eventData.credentialId || 'N/A',
credentialsUrl: process.env.CREDENTIALS_URL || 'https://theorder.org/credentials',
},
});
}
// Send SMS notification
if (eventData.recipientPhone) {
await notificationService.send({
to: eventData.recipientPhone,
type: 'sms',
template: CredentialNotificationTemplates.ISSUED.sms.template,
templateData: {
credentialType,
credentialId: eventData.credentialId || 'N/A',
credentialsUrl: process.env.CREDENTIALS_URL || 'https://theorder.org/credentials',
},
});
}
});
// Subscribe to credential renewed events
await eventBus.subscribe(CredentialEvents.RENEWED, async (data) => {
const eventData = data as {
subjectDid: string;
oldCredentialId: string;
newCredentialId: string;
renewedAt: string;
recipientEmail?: string;
recipientPhone?: string;
recipientName?: string;
};
if (eventData.recipientEmail) {
await notificationService.send({
to: eventData.recipientEmail,
type: 'email',
subject: CredentialNotificationTemplates.RENEWED.email.subject,
template: CredentialNotificationTemplates.RENEWED.email.template,
templateData: {
recipientName: eventData.recipientName || 'User',
credentialType: 'Verifiable Credential',
newCredentialId: eventData.newCredentialId,
oldCredentialId: eventData.oldCredentialId,
renewedAt: eventData.renewedAt,
credentialsUrl: process.env.CREDENTIALS_URL || 'https://theorder.org/credentials',
},
});
}
});
// Subscribe to credential expiring events
await eventBus.subscribe(CredentialEvents.EXPIRING, async (data) => {
const eventData = data as {
credentialId: string;
subjectDid: string;
expirationDate: string;
daysUntilExpiration: number;
recipientEmail?: string;
recipientPhone?: string;
recipientName?: string;
};
if (eventData.recipientEmail) {
await notificationService.send({
to: eventData.recipientEmail,
type: 'email',
subject: CredentialNotificationTemplates.EXPIRING.email.subject,
template: CredentialNotificationTemplates.EXPIRING.email.template,
templateData: {
recipientName: eventData.recipientName || 'User',
credentialType: 'Verifiable Credential',
credentialId: eventData.credentialId,
expirationDate: eventData.expirationDate,
daysUntilExpiration: eventData.daysUntilExpiration,
renewalUrl: process.env.RENEWAL_URL || 'https://theorder.org/credentials/renew',
},
});
}
if (eventData.recipientPhone) {
await notificationService.send({
to: eventData.recipientPhone,
type: 'sms',
template: CredentialNotificationTemplates.EXPIRING.sms.template,
templateData: {
credentialType: 'Verifiable Credential',
daysUntilExpiration: eventData.daysUntilExpiration,
renewalUrl: process.env.RENEWAL_URL || 'https://theorder.org/credentials/renew',
},
});
}
});
// Subscribe to credential revoked events
await eventBus.subscribe(CredentialEvents.REVOKED, async (data) => {
const eventData = data as {
credentialId: string;
subjectDid: string;
reason: string;
revokedAt: string;
recipientEmail?: string;
recipientPhone?: string;
recipientName?: string;
};
if (eventData.recipientEmail) {
await notificationService.send({
to: eventData.recipientEmail,
type: 'email',
subject: CredentialNotificationTemplates.REVOKED.email.subject,
template: CredentialNotificationTemplates.REVOKED.email.template,
templateData: {
recipientName: eventData.recipientName || 'User',
credentialType: 'Verifiable Credential',
credentialId: eventData.credentialId,
revokedAt: eventData.revokedAt,
revocationReason: eventData.reason,
},
});
}
});
}