@mirad-work/sms-core
Version:
A framework-agnostic TypeScript SMS service core with provider abstraction for Iranian SMS providers
159 lines • 5.65 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseSmsDriver = void 0;
const sms_exceptions_1 = require("../exceptions/sms-exceptions");
/**
* Abstract base class for all SMS drivers
* Provides common functionality and enforces interface implementation
*/
class BaseSmsDriver {
constructor(config, httpClient) {
this.validateConfig(config);
this.config = config;
this.httpClient = httpClient;
}
/**
* Build default headers for HTTP requests
*/
buildHeaders(additionalHeaders = {}) {
return {
"Content-Type": "application/json",
Accept: "application/json",
"User-Agent": "@mirad-work/sms-core",
...additionalHeaders,
};
}
/**
* Build URL by combining base URL with endpoint
*/
buildUrl(endpoint) {
if (!this.config.url) {
throw new sms_exceptions_1.SmsDriverException("Driver URL is not configured");
}
const baseUrl = this.config.url.replace(/\/$/, "");
const cleanEndpoint = endpoint.replace(/^\//, "");
return `${baseUrl}/${cleanEndpoint}`;
}
/**
* Validate SMS message before sending
*/
validateMessage(message) {
if (!message) {
throw new sms_exceptions_1.MessageValidationException("Message is required");
}
if (!message.to) {
throw new sms_exceptions_1.MessageValidationException("Recipient phone number is required");
}
if (!message.content && !message.template) {
throw new sms_exceptions_1.MessageValidationException("Either content or template must be provided");
}
if (message.template && !message.tokens) {
throw new sms_exceptions_1.MessageValidationException("Tokens are required when using templates");
}
// Basic phone number validation (should start with + or digits)
if (!/^[+\d][\d\s-()]*$/.test(message.to)) {
throw new sms_exceptions_1.MessageValidationException("Invalid phone number format");
}
}
/**
* Validate driver configuration
*/
validateConfig(config) {
if (!config) {
throw new sms_exceptions_1.SmsDriverException("Driver configuration is required");
}
if (!config.url) {
throw new sms_exceptions_1.SmsDriverException("Driver URL is required");
}
try {
new URL(config.url);
}
catch {
throw new sms_exceptions_1.SmsDriverException("Invalid driver URL format");
}
}
/**
* Handle HTTP errors and convert to appropriate exceptions
*/
async handleHttpRequest(requestFn) {
try {
const response = await requestFn();
// Check for HTTP error status codes
if (response.status >= 400) {
throw new sms_exceptions_1.HttpException(`HTTP ${response.status}: ${response.statusText}`, response.status, response.data);
}
return response;
}
catch (error) {
if (error instanceof sms_exceptions_1.HttpException) {
throw error;
}
throw new sms_exceptions_1.SmsDriverException(`HTTP request failed: ${error.message}`, error, "HTTP_REQUEST_FAILED");
}
}
/**
* Handle and standardize driver errors
*/
handleError(error, context = "Driver operation") {
if (error instanceof sms_exceptions_1.SmsDriverException ||
error instanceof sms_exceptions_1.MessageValidationException) {
throw error;
}
const errorMessage = error instanceof Error ? error.message : String(error);
throw new sms_exceptions_1.SmsDriverException(`${context} failed: ${errorMessage}`, error, "DRIVER_ERROR");
}
/**
* Create a standardized success response
*/
createSuccessResponse(data, messageId) {
return {
success: true,
messageId,
data,
};
}
/**
* Create a standardized error response
*/
createErrorResponse(error, errorCode, data) {
return {
success: false,
error,
errorCode,
data,
};
}
/**
* Extract message ID from provider response
* This method can be overridden by concrete drivers if needed
*/
extractMessageId(response) {
if (!response || typeof response !== "object") {
return undefined;
}
const responseObj = response;
// Common patterns for message ID extraction
const messageId = responseObj.messageId ||
responseObj.id ||
responseObj.message_id ||
(responseObj.data &&
typeof responseObj.data === "object" &&
responseObj.data.messageId) ||
(responseObj.data &&
typeof responseObj.data === "object" &&
responseObj.data.id);
return typeof messageId === "string" ? messageId : undefined;
}
/**
* Log request/response for debugging (can be overridden)
*/
log(level, message, data) {
// Simple console logging - can be replaced with proper logging library
const timestamp = new Date().toISOString();
const logData = data ? JSON.stringify(data, null, 2) : "";
// eslint-disable-next-line no-console
console[level](`[${timestamp}] [SMS-Driver] ${message}`, logData);
}
}
exports.BaseSmsDriver = BaseSmsDriver;
//# sourceMappingURL=base-driver.js.map