@bdcode/sms
Version:
Unified (BD) SMS Providers client package for all TS/JS applications
222 lines (216 loc) • 7.29 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// lib/mod.ts
var mod_exports = {};
__export(mod_exports, {
SmsGateway: () => SmsGateway,
smsAdapters: () => smsAdapters
});
module.exports = __toCommonJS(mod_exports);
// lib/adapters/smsnetbd.ts
var import_zod = require("zod");
// lib/common.ts
var import_axios = __toESM(require("axios"), 1);
var composeHeaders = (headers) => {
const composedHeaders = {};
for (const [key, value] of Object.entries(headers)) {
if (value !== void 0) {
composedHeaders[key] = String(value);
}
}
return composedHeaders;
};
var safeComposeRequestBodyData = (body, target = "json") => {
if (typeof body === "object" && body !== null) {
if (target === "form") {
const formData = new URLSearchParams();
for (const [key, value] of Object.entries(body)) {
if (value !== void 0) {
formData.append(key, String(value));
}
}
return formData;
}
return JSON.stringify(body);
}
return body;
};
var axApiCall = async (method, endpoint, headers = {}, body = void 0, target = "json") => {
try {
const isWriteMethod = ["post", "put", "patch", "delete"].includes(
method.toLowerCase()
);
const formattedBody = body ? safeComposeRequestBodyData(body, target) : void 0;
if (formattedBody) {
headers["Content-Type"] = target === "form" ? "application/x-www-form-urlencoded" : "application/json";
}
const axiosConfig = {
headers
};
const response = isWriteMethod ? await import_axios.default[method](endpoint, formattedBody, axiosConfig) : await import_axios.default[method](endpoint, axiosConfig);
if (!response || !response.data) {
throw new Error("No response data received from the API.");
}
return response.data;
} catch (err) {
if (import_axios.default.isAxiosError(err)) {
throw new Error(`API Error: ${err.response?.data?.msg || err.message}`);
}
throw new Error(
`Unexpected Error: ${err instanceof Error ? err.message : "Unknown error"}`
);
}
};
// lib/adapters/smsnetbd.ts
var SmsNetBdEndpoints = {
SEND_SMS: "/sendsms",
GET_BALANCE: "/user/balance/",
GET_REPORT: "/report/request/{id}/"
// {id} is a placeholder for request_id
// ... add more if newly added in their API_DOCS
};
var validatePayloadWithReqID = import_zod.z.object({
request_id: import_zod.z.union([import_zod.z.string(), import_zod.z.number()]).transform((val) => String(val))
});
var validateSendSmsPayload = import_zod.z.object({
msg: import_zod.z.string().min(1, "Message content is required"),
to: import_zod.z.string().min(1, "Recipient number(s) are required").refine(
(val) => val.split(",").map((num) => num.trim()).every((num) => /^(\+?8801\d{9}|01\d{9})$/.test(num)),
{
message: "Each recipient number must start with country code (880) or Standard 01X and be valid."
}
),
schedule: import_zod.z.string().optional().refine(
(val) => !val || /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(val),
{
message: "Schedule must be formatted as Y-m-d H:i:s (e.g. 2021-10-13 16:00:52)"
}
),
sender_id: import_zod.z.string().optional(),
content_id: import_zod.z.string().optional()
});
var SmsNetBd = class {
constructor(config) {
this.config = config;
this.base = config.base ?? "https://api.sms.net.bd";
this.api_key = config.api_key;
}
base;
api_key;
// SEND: SMS
async sendSms(payload) {
const parsed = validateSendSmsPayload.safeParse(payload);
if (!parsed.success) {
throw new Error(
`Validation Error: ${parsed.error.issues.map((issue) => issue.message).join(", ")}`
);
}
const res = await axApiCall(
"post",
`${this.base}${SmsNetBdEndpoints.SEND_SMS}`,
composeHeaders({
"Content-Type": "application/x-www-form-urlencoded"
}),
{ ...parsed.data, api_key: this.api_key },
// Include api_key from config
"form"
// Use form-urlencoded for sending SMS
);
if (res.error !== 0) {
throw new Error(`${res.error}: ${res.msg}`);
}
return res;
}
// GET: SMS Account Balance
async getBalance() {
const res = await axApiCall(
"post",
`${this.base}${SmsNetBdEndpoints.GET_BALANCE}`,
composeHeaders({
"Content-Type": "application/x-www-form-urlencoded"
}),
{ api_key: this.api_key },
"form"
// Use form-urlencoded for getting balance
);
if (res.error !== 0) {
throw new Error(`${res.error}: ${res.msg}`);
}
return res;
}
// GET: SMS Delivery Report \\ {id} is a placeholder for request_id
async getReport(request_id) {
const data = validatePayloadWithReqID.parse({ request_id });
const url = `${this.base}${SmsNetBdEndpoints.GET_REPORT}`.replace(
"{id}",
String(data.request_id)
);
const res = await axApiCall(
"post",
url,
composeHeaders({
"Content-Type": "application/x-www-form-urlencoded"
}),
{ api_key: this.api_key },
"form"
// Use form-urlencoded for getting report
);
if (res.error !== 0) {
throw new Error(`${res.error}: ${res.msg}`);
}
return res;
}
};
// lib/gateways.ts
var smsAdapters = ["sms-net-bd", "bulk-sms-dhaka"];
var SmsGateway = class {
constructor(_adapter, config) {
this._adapter = _adapter;
this.config = config;
this.client = this.loadAdapter(this._adapter, this.config);
}
client;
loadAdapter(adapter, config) {
switch (adapter) {
case "sms-net-bd":
return new SmsNetBd(
config
);
case "bulk-sms-dhaka":
throw new Error("Adapter not available yet.");
default:
throw new Error(`Adapter "${adapter}" is invalid or not supported.`);
}
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
SmsGateway,
smsAdapters
});