@mirad-work/sms-core
Version:
A framework-agnostic TypeScript SMS service core with provider abstraction for Iranian SMS providers
289 lines (284 loc) • 10.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SmsConfigManager = void 0;
const driver_types_1 = require("../types/driver-types");
const sms_exceptions_1 = require("../exceptions/sms-exceptions");
/**
* Configuration manager for SMS service
* Supports environment variables, config objects, and default values
*/
class SmsConfigManager {
/**
* Parse a numeric environment variable, falling back to a default when the
* value is absent or not a usable number.
*
* Without this, a malformed value (e.g. SMS_TIMEOUT=fast) yields NaN, which
* silently aborts every request because setTimeout(fn, NaN) fires immediately.
*/
static parseNumber(value, fallback, { allowZero = false } = {}) {
if (value === undefined || value.trim() === "") {
return fallback;
}
const parsed = Number(value);
if (!Number.isFinite(parsed) || parsed < 0) {
return fallback;
}
if (parsed === 0 && !allowZero) {
return fallback;
}
return parsed;
}
/**
* Create configuration from environment variables
*/
static fromEnvironment() {
const defaultDriver = process.env.SMS_DEFAULT_DRIVER || driver_types_1.DriverType.KAVENEGAR;
const timeout = this.parseNumber(process.env.SMS_TIMEOUT, 10000);
const config = {
defaultDriver,
timeout,
drivers: {},
};
// Kavenegar configuration
if (process.env.SMS_KAVENEGAR_URL || process.env.SMS_KAVENEGAR_API_KEY) {
config.drivers.kavenegar = {
url: process.env.SMS_KAVENEGAR_URL || "https://api.kavenegar.com/v1/",
apiKey: process.env.SMS_KAVENEGAR_API_KEY || "",
lineNumber: process.env.SMS_KAVENEGAR_LINE_NUMBER || "",
};
}
// SMS.ir configuration
if (process.env.SMS_SMSIR_URL || process.env.SMS_SMSIR_API_KEY) {
config.drivers.smsir = {
url: process.env.SMS_SMSIR_URL || "https://api.sms.ir/v1/",
apiKey: process.env.SMS_SMSIR_API_KEY || "",
lineNumber: process.env.SMS_SMSIR_LINE_NUMBER || "",
};
}
// Melipayamak configuration
if (process.env.SMS_MELIPAYAMAK_URL ||
process.env.SMS_MELIPAYAMAK_USERNAME ||
process.env.SMS_MELIPAYAMAK_PASSWORD ||
process.env.SMS_MELIPAYAMAK_API_KEY) {
config.drivers.melipayamak = {
url: process.env.SMS_MELIPAYAMAK_URL ||
"https://rest.payamak-panel.com/api/SendSMS/",
username: process.env.SMS_MELIPAYAMAK_USERNAME || "",
password: process.env.SMS_MELIPAYAMAK_PASSWORD ||
process.env.SMS_MELIPAYAMAK_API_KEY ||
"",
};
}
// IPPanel configuration
if (process.env.SMS_IPPANEL_URL || process.env.SMS_IPPANEL_API_KEY) {
config.drivers.ippanel = {
url: process.env.SMS_IPPANEL_URL || "https://api2.ippanel.com/",
apiKey: process.env.SMS_IPPANEL_API_KEY || "",
lineNumber: process.env.SMS_IPPANEL_LINE_NUMBER || "",
};
}
// Mock driver configuration (for testing)
if (process.env.NODE_ENV === "test" ||
process.env.SMS_USE_MOCK === "true") {
config.drivers.mock = {
shouldFail: process.env.SMS_MOCK_SHOULD_FAIL === "true",
delay: this.parseNumber(process.env.SMS_MOCK_DELAY, 0, {
allowZero: true,
}),
};
}
return config;
}
/**
* Create configuration with validation
*/
static create(config) {
const fullConfig = {
defaultDriver: config.defaultDriver || driver_types_1.DriverType.KAVENEGAR,
timeout: config.timeout || 10000,
drivers: config.drivers || {},
};
this.validateConfig(fullConfig);
return fullConfig;
}
/**
* Create a simple configuration for testing with mock driver
*/
static createForTesting(options = {}) {
return {
defaultDriver: driver_types_1.DriverType.MOCK,
timeout: 5000,
drivers: {
mock: {
shouldFail: options.shouldFail || false,
delay: options.delay || 0,
},
},
};
}
/**
* Create configuration for Kavenegar
*/
static createKavenegarConfig(options) {
return {
defaultDriver: driver_types_1.DriverType.KAVENEGAR,
timeout: 10000,
drivers: {
kavenegar: {
url: options.url || "https://api.kavenegar.com/v1/",
apiKey: options.apiKey,
lineNumber: options.lineNumber,
},
},
};
}
/**
* Create configuration for SMS.ir
*/
static createSmsIrConfig(options) {
return {
defaultDriver: driver_types_1.DriverType.SMSIR,
timeout: 10000,
drivers: {
smsir: {
url: options.url || "https://api.sms.ir/v1/",
apiKey: options.apiKey,
lineNumber: options.lineNumber,
},
},
};
}
/**
* Create configuration for Melipayamak
*/
static createMelipayamakConfig(options) {
return {
defaultDriver: driver_types_1.DriverType.MELIPAYAMAK,
timeout: 10000,
drivers: {
melipayamak: {
url: options.url || "https://rest.payamak-panel.com/api/SendSMS/",
username: options.username,
password: options.password,
},
},
};
}
/**
* Create configuration for IPPanel
*/
static createIppanelConfig(options) {
return {
defaultDriver: driver_types_1.DriverType.IPPANEL,
timeout: 10000,
drivers: {
ippanel: {
url: options.url || "https://api2.ippanel.com/",
apiKey: options.apiKey,
lineNumber: options.lineNumber,
},
},
};
}
/**
* Merge multiple configurations
*/
static merge(...configs) {
const mergedConfig = {
defaultDriver: driver_types_1.DriverType.KAVENEGAR,
timeout: 10000,
drivers: {},
};
for (const config of configs) {
if (config.defaultDriver) {
mergedConfig.defaultDriver = config.defaultDriver;
}
if (config.timeout) {
mergedConfig.timeout = config.timeout;
}
if (config.drivers) {
Object.assign(mergedConfig.drivers, config.drivers);
}
}
this.validateConfig(mergedConfig);
return mergedConfig;
}
/**
* Validate configuration
*/
static validateConfig(config) {
if (!config.defaultDriver) {
throw new sms_exceptions_1.MissingConfigException("defaultDriver");
}
if (!config.drivers || Object.keys(config.drivers).length === 0) {
throw new sms_exceptions_1.ConfigurationException("At least one driver must be configured");
}
// Validate that default driver is configured
if (!config.drivers[config.defaultDriver]) {
throw new sms_exceptions_1.ConfigurationException(`Default driver '${config.defaultDriver}' is not configured`);
}
// Validate individual driver configurations
Object.entries(config.drivers).forEach(([driverType, driverConfig]) => {
if (!driverConfig)
return;
switch (driverType) {
case driver_types_1.DriverType.KAVENEGAR:
case driver_types_1.DriverType.SMSIR:
case driver_types_1.DriverType.IPPANEL: {
const basicDriverConfig = driverConfig;
const config = basicDriverConfig;
if (!config.url || !config.apiKey || !config.lineNumber) {
throw new sms_exceptions_1.ConfigurationException(`Driver '${driverType}' requires url, apiKey, and lineNumber`);
}
break;
}
case driver_types_1.DriverType.MELIPAYAMAK: {
const melipayamakConfig = driverConfig;
if (!melipayamakConfig.url ||
!melipayamakConfig.username ||
!melipayamakConfig.password) {
throw new sms_exceptions_1.ConfigurationException("Driver 'melipayamak' requires url, username, and password");
}
break;
}
case driver_types_1.DriverType.MOCK:
// Mock driver doesn't require specific validation
break;
default:
throw new sms_exceptions_1.ConfigurationException(`Unknown driver type: ${driverType}`);
}
});
}
/**
* Get sample environment variables
*/
static getSampleEnvVars() {
return `
# SMS Service Configuration
SMS_DEFAULT_DRIVER=kavenegar
SMS_TIMEOUT=10000
# Kavenegar Configuration
SMS_KAVENEGAR_URL=https://api.kavenegar.com/v1/
SMS_KAVENEGAR_API_KEY=your-kavenegar-api-key
SMS_KAVENEGAR_LINE_NUMBER=your-line-number
# SMS.ir Configuration
SMS_SMSIR_URL=https://api.sms.ir/v1/
SMS_SMSIR_API_KEY=your-smsir-api-key
SMS_SMSIR_LINE_NUMBER=your-line-number
# Melipayamak Configuration
SMS_MELIPAYAMAK_URL=https://rest.payamak-panel.com/api/SendSMS/
SMS_MELIPAYAMAK_USERNAME=your-melipayamak-username
SMS_MELIPAYAMAK_PASSWORD=your-melipayamak-password-or-api-key
# IPPanel Configuration
SMS_IPPANEL_URL=https://api2.ippanel.com/
SMS_IPPANEL_API_KEY=your-ippanel-api-key
SMS_IPPANEL_LINE_NUMBER=your-line-number
# Mock Driver Configuration (for testing)
SMS_USE_MOCK=false
SMS_MOCK_SHOULD_FAIL=false
SMS_MOCK_DELAY=0
`.trim();
}
}
exports.SmsConfigManager = SmsConfigManager;
//# sourceMappingURL=sms-config.js.map