@easydev_org/notification-sdk
v1.0.3
Published
TypeScript SDK client for the Unified Email and SMS Notification Service
Maintainers
Readme
@easydev_org/notification-sdk
An elegant, fully-typed TypeScript SDK client for interacting with the Unified Email and SMS Notification Service.
Features
- Typed Interfaces: Comprehensive TypeScript interfaces for all Email, SMS, and OTP payloads and response formats.
- Sync & Async Methods: Supporting both async queueing (BullMQ) and synchronous dispatching (waiting for SMTP/SMS provider feedback).
- Auto-Config: Instantiates automatically using standard environment variables.
- Idempotency Out of the Box: Auto-generates unique idempotency keys for email requests unless explicitly overridden.
- Error Mapping: Detailed custom error classes (
NotificationHttpError,NotificationValidationError,NotificationTimeoutError) to inspect HTTP statuses and response details. - Custom Logging: Connects easily to your favorite logger (Pino, Winston, etc.) or uses the built-in prefix-aware Console Logger.
Installation
Install using your preferred package manager:
# Using pnpm
pnpm add @easydev_org/notification-sdk
# Using npm
npm install @easydev_org/notification-sdk
# Using yarn
yarn add @easydev_org/notification-sdkGetting Started
1. Configure the Client
You can explicitly configure the client or let it fall back to environment variables.
Option A: Zero-Config (Default Production Setup)
You can initialize the client without any arguments. It will automatically connect to the production URL (https://notifications.easydev.in) using the default API key and tenant ID configurations:
import { NotificationClient } from '@easydev_org/notification-sdk';
const notificationClient = new NotificationClient();Option B: Environment Variable Overrides
If you define the following environment variables, the SDK will automatically read and apply them:
EASYDEV_NOTIFICATION_URL(e.g.https://notifications.staging.url)EASYDEV_NOTIFICATION_API_KEY(your custom secret API key)EASYDEV_NOTIFICATION_TENANT_ID(your custom tenant identifier)
// Uses environment variables automatically
const notificationClient = new NotificationClient();Option C: Custom Constructor Configuration
You can pass overrides explicitly inside the constructor:
const notificationClient = new NotificationClient({
baseUrl: 'https://notifications.easydev.in',
apiKey: 'your-production-secret-api-key',
tenantId: 'your-tenant-id',
logger: true, // Enables default ConsoleLogger
timeout: 10000, // 10 seconds timeout
});Usage Examples
1. Sending Emails
The SDK client handles branding attributes (like from, fromName, appUrl, and ctaPath) by maps-converting them into the specific request headers expected by the backend service.
Asynchronous Send (Queued via BullMQ)
Dispatches the email to the background queue immediately and resolves.
try {
const result = await notificationClient.sendEmail({
to: '[email protected]',
template: 'welcomeEmailTemplate',
data: {
username: 'John Doe',
},
// Optional overrides:
fromName: 'EasyDev Support',
appUrl: 'https://easydev.in',
ctaPath: '/dashboard',
});
console.log(`Email accepted! Request ID: ${result.requestId}`);
} catch (error) {
console.error('Failed to send email:', error);
}Synchronous Send (Waits for SMTP delivery)
Waits for the SMTP transmission to complete before resolving. Recommended for critical transactional flows where you must confirm delivery status (e.g. OTPs).
const result = await notificationClient.sendEmailSync({
to: '[email protected]',
template: 'otpEmailTemplate',
data: {
name: 'John Doe',
otp: '847291',
purpose: 'login verification',
expiryMinutes: 10,
},
// Set explicit idempotency key to prevent double-send in case of retry
idempotencyKey: 'otp-john-doe-1719889200',
});
console.log(`Email sent successfully! SMTP Message ID: ${result.messageId}`);2. SMS and OTPs
Sending a Single SMS
const response = await notificationClient.sendSms({
to: '+919876543210',
message: 'Your order #ORD-2026-001 has been packed and is ready to ship!',
messageType: 'TRANSACTIONAL',
});Generating & Sending an OTP via SMS
Sends a secure OTP generated by the notification service backend.
const response = await notificationClient.sendOtp({
to: '+919876543210',
templateCode: 'otp_verification',
otpLength: 6,
expiresInMinutes: 5,
});
console.log(`OTP sent. Expires at: ${response.data.expiresAt}`);Verifying an OTP
const verification = await notificationClient.verifyOtp({
to: '+919876543210',
otp: '123456',
});
if (verification.data.valid) {
console.log('OTP verification successful!');
} else {
console.warn('Invalid OTP:', verification.data.reason);
}Bulk SMS Campaigns
const response = await notificationClient.sendBulkSms({
recipients: [
{ to: '+919876543210', variables: { name: 'John' } },
{ to: '+919876543211', variables: { name: 'Jane' } },
],
templateCode: 'holiday_greetings',
messageType: 'PROMOTIONAL',
});3. Log Retrieval and Health Checking
Querying Email Logs
const logsResponse = await notificationClient.getEmailLogs({
status: 'failed',
limit: 20,
sort: { createdAt: -1 },
});
console.log(`Found ${logsResponse.total} failed emails.`);Checking SMTP connection health
const health = await notificationClient.getEmailHealth();
if (health.success) {
console.log('SMTP connections are healthy!');
}Error Handling
The SDK exposes three main categories of errors inheriting from the base NotificationError.
import {
NotificationError,
NotificationValidationError,
NotificationHttpError,
NotificationTimeoutError
} from '@easydev_org/notification-sdk';
try {
await notificationClient.sendEmail({
to: 'invalid-email',
template: 'welcomeEmailTemplate',
});
} catch (error) {
if (error instanceof NotificationValidationError) {
// Thrown BEFORE network request (e.g. missing required properties)
console.error('Validation error:', error.message);
} else if (error instanceof NotificationHttpError) {
// Non-2xx response from the server (e.g. 401 Unauthorized, 400 Bad Request, 500 Server Error)
console.error(`API Error (HTTP ${error.statusCode}):`, error.responseData);
console.error(`Error Code:`, error.errorCode); // e.g. 'BadRequestException'
} else if (error instanceof NotificationTimeoutError) {
// Request timed out
console.error(`Request timed out after ${error.timeoutMs}ms`);
} else if (error instanceof NotificationError) {
// General network or system error
console.error('General error:', error.message);
}
}Logger Integration
You can easily supply your own logger (e.g. Winston or Pino) by passing an object conforming to the Logger interface.
import { Logger } from '@easydev_org/notification-sdk';
import winston from 'winston';
const myWinstonLogger = winston.createLogger({
level: 'info',
transports: [new winston.transports.Console()],
});
// Adapter conforming to the Logger interface
const sdkLoggerAdapter: Logger = {
info: (msg, ...meta) => myWinstonLogger.info(msg, ...meta),
warn: (msg, ...meta) => myWinstonLogger.warn(msg, ...meta),
error: (msg, ...meta) => myWinstonLogger.error(msg, ...meta),
debug: (msg, ...meta) => myWinstonLogger.debug(msg, ...meta),
};
const client = new NotificationClient({
apiKey: 'secret',
logger: sdkLoggerAdapter,
});Development, Building & Packaging
1. Build the SDK
Compiles the TypeScript source code into ESM and CommonJS formats:
pnpm install
pnpm run buildThis cleans the dist/ folder and outputs the compiled bundles containing index.js, index.mjs, and .d.ts typescript mapping files.
2. Pack the SDK (Offline Distribution)
To create a redistributable, compressed package (.tgz file) for use in other projects:
pnpm packThis generates a file named easydev-notification-sdk-1.0.0.tgz at the package root.
3. Installing in Other Services
Option A: Direct File Installation (in external repositories)
In your other microservices or frontend repositories, install the package directly using the path to the compressed tarball:
# Using pnpm
pnpm add C:/Users/kisho/WorkSpace/Backend/notification-service/packages/notification-sdk/easydev_org-notification-sdk-1.0.0.tgz
# Using npm
npm install C:/Users/kisho/WorkSpace/Backend/notification-service/packages/notification-sdk/easydev_org-notification-sdk-1.0.0.tgzOption B: Linking Locally (within this Monorepo workspace)
If the target service resides in the same repository workspace, add it as a workspace dependency inside the target's package.json:
"dependencies": {
"@easydev/notification-sdk": "workspace:*"
}Then run pnpm install in the root workspace to link the package.
