UNPKG

@bdcode/sms

Version:

Unified (BD) SMS Providers client package for all TS/JS applications

222 lines (216 loc) 7.29 kB
"use strict"; 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 });