unismsgateway 1.3.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,13 +1,8 @@
1
- # Unified Sms Gateway
1
+ # Unified SMS Gateway
2
2
 
3
- Most of the time a single project relies on multiple sms Gateway so it can switched if one goes off.
4
- However, each sms api specification is different from the other, hence the need to create separate implementation
5
- for each sms gateway.
6
-
7
- Unified sms gateway is library that brings most common sms gateways under a Unified api.
8
- which means you only does one implementation in it works for all supported sms gateway.
9
- you just have select or switch your sms platform and your code still works fine like nothing has changed
3
+ Most projects rely on more than one SMS provider so they can switch if a gateway is unavailable. Each provider’s API differs, so separate integrations are usually required.
10
4
 
5
+ **unismsgateway** exposes a single API for multiple SMS gateways. You implement once, then select or switch the platform; your send flow stays the same.
11
6
 
12
7
  ## Installation
13
8
 
@@ -15,170 +10,372 @@ you just have select or switch your sms platform and your code still works fine
15
10
  npm install unismsgateway
16
11
  ```
17
12
 
18
- ## Supported Gateways
19
-
20
- | Platform ID | Provider | Required Params |
21
- |-------------|----------|-----------------|
22
- | `route` | routeMobile | username, password, host |
23
- | `hubtel` | Hubtel SMS (Ghana) | clientId, clientSecret |
24
- | `nest` | SMSOnlineGH / smsonlinegh | apiKey |
13
+ **Requirements:** Node.js `>= 12.0.0` (see `package.json` `engines`).
25
14
 
26
- ## Usage/Examples
15
+ ## Module import
27
16
 
28
- ### Initialize with Platform
17
+ **CommonJS**
29
18
 
30
19
  ```javascript
31
- const unisms = require('unismsgateway')
32
-
33
- // For routeMobile
34
- const routeGateway = unisms.init({
35
- platformId: 'route',
36
- param: {
37
- username: 'your-username',
38
- password: 'your-password',
39
- host: 'rslr.connectbind.com',
40
- protocol: 'http',
41
- port: 8080
42
- }
43
- })
44
-
45
- // For Hubtel
46
- const hubtelGateway = unisms.init({
47
- platformId: 'hubtel',
48
- param: {
49
- clientId: 'your-client-id',
50
- clientSecret: 'your-client-secret'
51
- }
52
- })
53
-
54
- // For SMSOnlineGH (nest)
55
- const nestGateway = unisms.init({
56
- platformId: 'nest',
57
- param: {
58
- apiKey: 'your-api-key',
59
- // Optional: host, protocol (defaults to api.smsonlinegh.com, https)
60
- }
61
- })
20
+ const unisms = require('unismsgateway');
21
+ ```
22
+
23
+ **ESM / TypeScript**
24
+
25
+ ```typescript
26
+ import * as unisms from 'unismsgateway';
27
+ // or named:
28
+ import { init, getSmsPlatform, reset, smsPlatform } from 'unismsgateway';
62
29
  ```
63
30
 
64
- ### Send SMS Message
31
+ ---
32
+
33
+ ## Configuration overview
34
+
35
+ ### `IgatewaySettings`
36
+
37
+ | Field | Type | Description |
38
+ |-------|------|-------------|
39
+ | `platformId` | `'route' \| 'hubtel' \| 'nest'` | Which gateway to use. |
40
+ | `param` | `IgatewayParam` | Provider-specific options (see below). |
41
+
42
+ ### `IgatewayParam` (all fields optional except what your `platformId` requires)
43
+
44
+ | Field | Type | Used by | Description |
45
+ |-------|------|---------|-------------|
46
+ | `username` | `string` | `route` | Route Mobile account username. **Required** for `route`. |
47
+ | `password` | `string` | `route` | Route Mobile account password. **Required** for `route`. |
48
+ | `host` | `string` | `route`, `nest` | API host. See per-gateway defaults below. |
49
+ | `port` | `number` | `route` | TCP port for Route Mobile. Default: `8080`. |
50
+ | `protocol` | `'http' \| 'https'` | `route`, `nest` | URL scheme. See defaults per gateway. |
51
+ | `clientId` | `string` | `hubtel` | Hubtel client ID. **Required** for `hubtel`. |
52
+ | `clientSecret` | `string` | `hubtel` | Hubtel client secret. **Required** for `hubtel`. |
53
+ | `apiKey` | `string` | `nest` | SMSOnlineGH API key (`Authorization: key …`). **Required** for `nest`. |
54
+
55
+ Validation runs in `smsPlatform` when the instance is constructed: missing required fields for the chosen `platformId` throw `Error` with a clear message.
56
+
57
+ ---
58
+
59
+ ## Environment variables
60
+
61
+ **This library does not read `process.env` or any configuration files.** You pass all credentials and endpoints explicitly in `init({ platformId, param })`.
62
+
63
+ In your own application it is common to map environment variables into `param`. Suggested names (you define these in `.env` or your host’s secret store):
64
+
65
+ | Suggested env name | Maps to `param` | Gateways |
66
+ |--------------------|-----------------|----------|
67
+ | `SMS_PLATFORM_ID` | `platformId` | all |
68
+ | `ROUTE_SMS_USERNAME` | `username` | `route` |
69
+ | `ROUTE_SMS_PASSWORD` | `password` | `route` |
70
+ | `ROUTE_SMS_HOST` | `host` | `route` (optional; has default) |
71
+ | `ROUTE_SMS_PORT` | `port` | `route` (optional) |
72
+ | `ROUTE_SMS_PROTOCOL` | `protocol` | `route` (optional) |
73
+ | `HUBTEL_CLIENT_ID` | `clientId` | `hubtel` |
74
+ | `HUBTEL_CLIENT_SECRET` | `clientSecret` | `hubtel` |
75
+ | `SMSONLINEGH_API_KEY` or `NEST_API_KEY` | `apiKey` | `nest` |
76
+ | `SMSONLINEGH_HOST` or `NEST_HOST` | `host` | `nest` (optional) |
77
+ | `SMSONLINEGH_PROTOCOL` or `NEST_PROTOCOL` | `protocol` | `nest` (optional) |
78
+
79
+ Example wiring (conceptual): branch on `platformId` and build `param` so you do not mix unrelated fields.
65
80
 
66
81
  ```javascript
67
- const unisms = require('unismsgateway')
82
+ const unisms = require('unismsgateway');
83
+
84
+ const platformId = process.env.SMS_PLATFORM_ID;
85
+
86
+ const paramByPlatform = {
87
+ route: {
88
+ username: process.env.ROUTE_SMS_USERNAME,
89
+ password: process.env.ROUTE_SMS_PASSWORD,
90
+ host: process.env.ROUTE_SMS_HOST,
91
+ port: process.env.ROUTE_SMS_PORT ? Number(process.env.ROUTE_SMS_PORT) : undefined,
92
+ protocol: process.env.ROUTE_SMS_PROTOCOL
93
+ },
94
+ hubtel: {
95
+ clientId: process.env.HUBTEL_CLIENT_ID,
96
+ clientSecret: process.env.HUBTEL_CLIENT_SECRET
97
+ },
98
+ nest: {
99
+ apiKey: process.env.SMSONLINEGH_API_KEY,
100
+ host: process.env.SMSONLINEGH_HOST,
101
+ protocol: process.env.SMSONLINEGH_PROTOCOL
102
+ }
103
+ };
68
104
 
69
- // Initialize gateway
70
105
  const gateway = unisms.init({
71
- platformId: 'nest',
72
- param: {
73
- apiKey: 'your-api-key'
74
- }
75
- })
106
+ platformId,
107
+ param: paramByPlatform[platformId]
108
+ });
109
+ ```
76
110
 
77
- // Send message
78
- async function sendSms() {
79
- try {
80
- const result = await gateway.quickSend({
81
- From: 'SenderName',
82
- To: '233XXXXXXXXX', // recipient number
83
- Content: 'Hello from unismsgateway!',
84
- Type: 0 // optional, defaults to 0
85
- })
86
-
87
- if (result.success) {
88
- console.log('Message sent successfully:', result.messageId)
89
- } else {
90
- console.error('Failed to send:', result.error)
91
- }
92
- } catch (err) {
93
- console.error('Error:', err)
94
- }
95
- }
111
+ ---
96
112
 
97
- sendSms()
98
- ```
113
+ ## How initialization works
114
+
115
+ 1. **`init(settings: IgatewaySettings): smsPlatform`** (in `src/lib/lib.ts`):
116
+ - Validates and constructs a new `smsPlatform` with your `settings`.
117
+ - Stores it as the **module singleton** (`smsPlatformInstance`).
118
+ - Calls `smsPlatform.init()` on that instance (returns the same facade for chaining).
119
+ - Returns the `smsPlatform` instance.
120
+
121
+ 2. **`smsPlatform` constructor** (in `src/lib/platform.ts`):
122
+ - Runs `validateSettings()` (platform id + required `param` fields for that id).
123
+ - Calls `createGateway()` to instantiate the underlying provider (`routeSms`, `HubtelSms`, or `NestSmsGateway`).
124
+
125
+ 3. **`getSmsPlatform(): smsPlatform | null`**: Returns the current singleton, or `null` if `reset()` was called and no new `init()` has run.
99
126
 
100
- ### With Callback
127
+ There is **no async bootstrap**; after `init()` returns, `quickSend` is ready.
128
+
129
+ ---
130
+
131
+ ## Re-initializing and reset
132
+
133
+ - **Switch platform or credentials:** Call **`init(newSettings)`** again. Each call **replaces** the stored singleton with a new `smsPlatform`. You do not have to call `reset()` first.
134
+ - **Clear the singleton:** **`reset()`** sets the internal reference to `null`. `getSmsPlatform()` then returns `null` until the next `init()`. Use this when you want to guarantee nothing holds a gateway instance (e.g. tests or explicit teardown).
101
135
 
102
136
  ```javascript
103
- gateway.quickSend({
104
- From: 'SenderName',
105
- To: '233XXXXXXXXX',
106
- Content: 'Test message'
107
- }, (response) => {
108
- console.log('Response:', response)
109
- })
137
+ const unisms = require('unismsgateway');
138
+
139
+ const a = unisms.init({ platformId: 'nest', param: { apiKey: 'key-1' } });
140
+ // Later: new config
141
+ const b = unisms.init({ platformId: 'hubtel', param: { clientId: 'x', clientSecret: 'y' } });
142
+ // b replaces a; unisms.getSmsPlatform() === b
143
+
144
+ unisms.reset();
145
+ // unisms.getSmsPlatform() === null
146
+
147
+ const c = unisms.init({ platformId: 'nest', param: { apiKey: 'key-2' } });
110
148
  ```
111
149
 
112
- ### Check Balance (SMSOnlineGH/nest only)
150
+ ---
151
+
152
+ ## Supported gateways
153
+
154
+ | `platformId` | Provider | Package / implementation |
155
+ |----------------|----------|---------------------------|
156
+ | `route` | Route Mobile | `routemobilesms` |
157
+ | `hubtel` | Hubtel SMS (Ghana) | `hubtel-sms-extended` |
158
+ | `nest` | SMSOnlineGH | Built-in REST client (`NestSmsGateway`) |
159
+
160
+ ### `route` (Route Mobile)
161
+
162
+ **Required `param`:** `username`, `password`.
163
+
164
+ **Optional `param` (defaults in this library):**
165
+
166
+ | Field | Default if omitted |
167
+ |-------|-------------------|
168
+ | `host` | `rslr.connectbind.com` |
169
+ | `protocol` | `'http'` |
170
+ | `port` | `8080` |
171
+
172
+ These are passed into `routeSms` from `routemobilesms`.
113
173
 
114
174
  ```javascript
115
175
  const gateway = unisms.init({
116
- platformId: 'nest',
117
- param: { apiKey: 'your-api-key' }
118
- })
119
-
120
- // Only available for nest platform
121
- if (gateway.getGateway) {
122
- const nestGateway = gateway.getGateway()
123
- const balance = await nestGateway.getBalance()
124
- console.log('Balance:', balance)
125
- }
176
+ platformId: 'route',
177
+ param: {
178
+ username: 'your-username',
179
+ password: 'your-password',
180
+ host: 'rslr.connectbind.com',
181
+ protocol: 'http',
182
+ port: 8080
183
+ }
184
+ });
126
185
  ```
127
186
 
128
- ### Reset Gateway Instance
187
+ ### `hubtel` (Hubtel)
188
+
189
+ **Required `param`:** `clientId`, `clientSecret`.
190
+
191
+ No `host` / `protocol` in `IgatewayParam` for Hubtel in this library; configuration follows `hubtel-sms-extended`.
129
192
 
130
193
  ```javascript
131
- // Clear the current gateway instance
132
- unisms.reset()
133
-
134
- // Initialize with new platform
135
- const newGateway = unisms.init({
136
- platformId: 'hubtel',
137
- param: {
138
- clientId: 'new-client-id',
139
- clientSecret: 'new-secret'
140
- }
141
- })
194
+ const gateway = unisms.init({
195
+ platformId: 'hubtel',
196
+ param: {
197
+ clientId: 'your-client-id',
198
+ clientSecret: 'your-client-secret'
199
+ }
200
+ });
142
201
  ```
143
202
 
144
- ## API Reference
203
+ ### `nest` (SMSOnlineGH)
145
204
 
146
- ### `init(settings: IgatewaySettings): smsPlatform`
205
+ **Required `param`:** `apiKey`.
147
206
 
148
- Initialize the SMS gateway with your platform configuration.
207
+ **Optional `param`:**
149
208
 
150
- **Parameters:**
151
- - `platformId`: `'route'` | `'hubtel'` | `'nest'`
152
- - `param`: Platform-specific configuration object
209
+ | Field | Default if omitted |
210
+ |-------|-------------------|
211
+ | `host` | `api.smsonlinegh.com` |
212
+ | `protocol` | `'https'` |
153
213
 
154
- ### `getSmsPlatform(): smsPlatform | null`
214
+ Requests use `POST` to path **`/v5/<endpoint>`** (e.g. send: `message/sms/send`, balance: `account/balance`). Authorization header: `Authorization: key <apiKey>`.
155
215
 
156
- Get the current gateway instance. Returns `null` if not initialized.
216
+ ```javascript
217
+ const gateway = unisms.init({
218
+ platformId: 'nest',
219
+ param: {
220
+ apiKey: 'your-api-key'
221
+ // optional: host, protocol
222
+ }
223
+ });
224
+ ```
225
+
226
+ **Balance (nest only):** The underlying `NestSmsGateway` implements `getBalance()`. Access it via the facade’s `getGateway()`:
227
+
228
+ ```javascript
229
+ const gateway = unisms.init({
230
+ platformId: 'nest',
231
+ param: { apiKey: 'your-api-key' }
232
+ });
233
+
234
+ const nest = gateway.getGateway();
235
+ const balance = await nest.getBalance();
236
+ console.log(balance.balance, balance.model);
237
+ ```
157
238
 
158
- ### `reset(): void`
239
+ ---
159
240
 
160
- Clear the current gateway instance.
241
+ ## Sending messages
161
242
 
162
- ### `quickSend(params: QuickSendParams, callback?: Function): Promise<SendResult>`
243
+ ### `QuickSendParams`
163
244
 
164
- Send an SMS message.
245
+ | Field | Type | Required | Description |
246
+ |-------|------|----------|-------------|
247
+ | `From` | `string` | yes | Sender ID or label. |
248
+ | `To` | `string \| number` | yes | Recipient number (format as required by the provider). |
249
+ | `Content` | `string` | yes | Message body. |
250
+ | `Type` | `number` | no | Message type; **nest** maps this to request body `type` (default `0`). |
165
251
 
166
- **Parameters:**
167
- - `From`: Sender ID/name
168
- - `To`: Recipient phone number (string or number)
169
- - `Content`: Message content
170
- - `Type`: Optional message type (defaults to 0)
252
+ ### `quickSend(params, callback?)`
253
+
254
+ Returns `Promise<SendResult>`. Optional `callback` is invoked with the same result when the promise completes.
255
+
256
+ **`SendResult`:**
171
257
 
172
- **Returns:**
173
258
  ```typescript
174
259
  {
175
- success: boolean;
176
- messageId?: string;
177
- data?: any;
178
- error?: string;
260
+ success: boolean;
261
+ messageId?: string;
262
+ data?: any;
263
+ error?: string;
264
+ }
265
+ ```
266
+
267
+ **Example**
268
+
269
+ ```javascript
270
+ const unisms = require('unismsgateway');
271
+
272
+ const gateway = unisms.init({
273
+ platformId: 'nest',
274
+ param: { apiKey: 'your-api-key' }
275
+ });
276
+
277
+ async function sendSms() {
278
+ try {
279
+ const result = await gateway.quickSend({
280
+ From: 'SenderName',
281
+ To: '233XXXXXXXXX',
282
+ Content: 'Hello from unismsgateway!',
283
+ Type: 0
284
+ });
285
+
286
+ if (result.success) {
287
+ console.log('Sent:', result.messageId);
288
+ } else {
289
+ console.error('Failed:', result.error);
290
+ }
291
+ } catch (err) {
292
+ console.error(err);
293
+ }
179
294
  }
180
295
  ```
181
296
 
297
+ **With callback**
298
+
299
+ ```javascript
300
+ gateway.quickSend(
301
+ { From: 'SenderName', To: '233XXXXXXXXX', Content: 'Test' },
302
+ (response) => {
303
+ console.log(response);
304
+ }
305
+ );
306
+ ```
307
+
308
+ ---
309
+
310
+ ## Testing (live integration)
311
+
312
+ There is no unit test suite in this package. For **manual integration checks** against real gateways, use the script in `scripts/test-live.ts`.
313
+
314
+ **Setup**
315
+
316
+ 1. Clone the repo and install dependencies: `npm install`
317
+ 2. Copy `.env.example` to `.env` and fill in credentials for the platform you want to exercise
318
+ 3. Run:
319
+
320
+ ```bash
321
+ npm test
322
+ # same as:
323
+ npm run test:live
324
+ ```
325
+
326
+ **Selecting a platform**
327
+
328
+ | Env variable | Description |
329
+ |--------------|-------------|
330
+ | `GATEWAY_PLATFORM` | One of `nest`, `hubtel`, or `route`. Required unless you use `TEST_ALL`. |
331
+ | `TEST_ALL` | If set to `true`, runs tests for `nest`, `hubtel`, and `route` in sequence (each needs its env vars set). |
332
+
333
+ **What runs**
334
+
335
+ 1. **Init** — Builds `param` from your `.env`, calls `init()`, and checks configuration validation.
336
+ 2. **Balance** — For `nest` and `hubtel` only, calls `getBalance()` when the adapter supports it. `route` skips this step.
337
+ 3. **Send** — **Opt-in.** By default no SMS is sent. Set `TEST_SEND=true` to call `quickSend()` with `TEST_FROM`, `TEST_TO`, and optional `TEST_CONTENT`.
338
+
339
+ **Environment variables (live script)**
340
+
341
+ Variables below match `.env.example` and `scripts/test-live.ts`.
342
+
343
+ | Variable | Required when | Purpose |
344
+ |----------|----------------|---------|
345
+ | `GATEWAY_PLATFORM` | Unless `TEST_ALL=true` | `nest` \| `hubtel` \| `route` |
346
+ | `TEST_ALL` | Optional | `true` to test all three platforms |
347
+ | `NEST_API_KEY` | `nest` | SMSOnlineGH API key |
348
+ | `NEST_HOST`, `NEST_PROTOCOL` | `nest` | Optional overrides |
349
+ | `HUBTEL_CLIENT_ID`, `HUBTEL_CLIENT_SECRET` | `hubtel` | Hubtel credentials |
350
+ | `ROUTE_USERNAME`, `ROUTE_PASSWORD` | `route` | Route Mobile credentials |
351
+ | `ROUTE_HOST`, `ROUTE_PORT`, `ROUTE_PROTOCOL` | `route` | Optional overrides |
352
+ | `TEST_SEND` | To send SMS | Set to `true` to enable live send |
353
+ | `TEST_FROM`, `TEST_TO` | When `TEST_SEND=true` | Sender and recipient |
354
+ | `TEST_CONTENT` | When `TEST_SEND=true` | Message body (script has a default if omitted) |
355
+
356
+ The script loads `.env` via `dotenv` (dev dependency). Exit code is `0` when all checks pass, non-zero if a step fails or no platform is selected.
357
+
358
+ ---
359
+
360
+ ## API reference
361
+
362
+ | Export | Description |
363
+ |--------|-------------|
364
+ | `init(settings)` | Create and register the singleton `smsPlatform`, return it. |
365
+ | `getSmsPlatform()` | Current `smsPlatform` or `null` after `reset()` and before `init()`. |
366
+ | `reset()` | Clear the singleton. |
367
+ | `smsPlatform` | Class type for typing/advanced use. |
368
+
369
+ **`smsPlatform` instance methods**
370
+
371
+ | Method | Returns | Description |
372
+ |--------|---------|-------------|
373
+ | `init()` | `ISmsGateway` | Returns `this` (facade). |
374
+ | `quickSend(params, callback?)` | `Promise<SendResult>` | Delegates to the active gateway. |
375
+ | `getGateway()` | `ISmsGateway` | Underlying adapter (for nest: `getBalance()`). |
376
+
377
+ ---
378
+
182
379
  ## License
183
380
 
184
- [MIT](https://choosealicense.com/licenses/mit/)
381
+ [MIT](https://choosealicense.com/licenses/mit/)
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Live integration test script for unismsgateway.
3
+ *
4
+ * Usage:
5
+ * 1. Copy .env.example to .env and fill in your credentials.
6
+ * 2. npm run test:live
7
+ *
8
+ * Set TEST_SEND=true in .env (or inline) to actually send an SMS.
9
+ * Without it, only init and balance checks run.
10
+ */
11
+ export {};
@@ -0,0 +1,188 @@
1
+ "use strict";
2
+ /**
3
+ * Live integration test script for unismsgateway.
4
+ *
5
+ * Usage:
6
+ * 1. Copy .env.example to .env and fill in your credentials.
7
+ * 2. npm run test:live
8
+ *
9
+ * Set TEST_SEND=true in .env (or inline) to actually send an SMS.
10
+ * Without it, only init and balance checks run.
11
+ */
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || function (mod) {
25
+ if (mod && mod.__esModule) return mod;
26
+ var result = {};
27
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
28
+ __setModuleDefault(result, mod);
29
+ return result;
30
+ };
31
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
32
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
33
+ return new (P || (P = Promise))(function (resolve, reject) {
34
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
35
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
36
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
37
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
38
+ });
39
+ };
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ const dotenv = __importStar(require("dotenv"));
42
+ dotenv.config();
43
+ const lib_1 = require("../src/lib/lib");
44
+ // ─── Colour helpers ──────────────────────────────────────────────────────────
45
+ const GREEN = '\x1b[32m';
46
+ const RED = '\x1b[31m';
47
+ const YELLOW = '\x1b[33m';
48
+ const CYAN = '\x1b[36m';
49
+ const BOLD = '\x1b[1m';
50
+ const RESET = '\x1b[0m';
51
+ const pass = (msg) => console.log(` ${GREEN}✔${RESET} ${msg}`);
52
+ const fail = (msg) => console.log(` ${RED}✖${RESET} ${msg}`);
53
+ const info = (msg) => console.log(` ${CYAN}ℹ${RESET} ${msg}`);
54
+ const warn = (msg) => console.log(` ${YELLOW}⚠${RESET} ${msg}`);
55
+ const title = (msg) => console.log(`\n${BOLD}${msg}${RESET}`);
56
+ // ─── Env helpers ─────────────────────────────────────────────────────────────
57
+ function env(key) {
58
+ return process.env[key] || undefined;
59
+ }
60
+ function requireEnv(key) {
61
+ const val = process.env[key];
62
+ if (!val)
63
+ throw new Error(`Missing required env var: ${key}`);
64
+ return val;
65
+ }
66
+ // ─── Test counters ───────────────────────────────────────────────────────────
67
+ let passed = 0;
68
+ let failed = 0;
69
+ function runTest(label, fn) {
70
+ return __awaiter(this, void 0, void 0, function* () {
71
+ try {
72
+ yield fn();
73
+ passed++;
74
+ }
75
+ catch (err) {
76
+ failed++;
77
+ fail(`${label}: ${err instanceof Error ? err.message : String(err)}`);
78
+ }
79
+ });
80
+ }
81
+ // ─── Per-platform tests ───────────────────────────────────────────────────────
82
+ function testPlatform(platformId) {
83
+ return __awaiter(this, void 0, void 0, function* () {
84
+ title(`Platform: ${platformId.toUpperCase()}`);
85
+ let platform;
86
+ // 1. Initialisation
87
+ yield runTest('Init / config validation', () => __awaiter(this, void 0, void 0, function* () {
88
+ const param = {};
89
+ switch (platformId) {
90
+ case 'nest':
91
+ param.apiKey = requireEnv('NEST_API_KEY');
92
+ if (env('NEST_HOST'))
93
+ param.host = env('NEST_HOST');
94
+ if (env('NEST_PROTOCOL'))
95
+ param.protocol = env('NEST_PROTOCOL');
96
+ break;
97
+ case 'hubtel':
98
+ param.clientId = requireEnv('HUBTEL_CLIENT_ID');
99
+ param.clientSecret = requireEnv('HUBTEL_CLIENT_SECRET');
100
+ break;
101
+ case 'route':
102
+ param.username = requireEnv('ROUTE_USERNAME');
103
+ param.password = requireEnv('ROUTE_PASSWORD');
104
+ if (env('ROUTE_HOST'))
105
+ param.host = env('ROUTE_HOST');
106
+ if (env('ROUTE_PORT'))
107
+ param.port = Number(env('ROUTE_PORT'));
108
+ if (env('ROUTE_PROTOCOL'))
109
+ param.protocol = env('ROUTE_PROTOCOL');
110
+ break;
111
+ }
112
+ platform = (0, lib_1.init)({ platformId, param: param });
113
+ pass(`Initialized ${platformId} platform`);
114
+ }));
115
+ // 2. Balance check (only nest and hubtel expose getBalance)
116
+ if (platformId === 'nest' || platformId === 'hubtel') {
117
+ yield runTest('getBalance()', () => __awaiter(this, void 0, void 0, function* () {
118
+ const gateway = platform.getGateway();
119
+ if (!gateway.getBalance) {
120
+ warn('getBalance not implemented — skipped');
121
+ return;
122
+ }
123
+ const balance = yield gateway.getBalance();
124
+ pass(`Balance retrieved: ${JSON.stringify(balance)}`);
125
+ }));
126
+ }
127
+ else {
128
+ warn(`getBalance not supported by '${platformId}' — skipped`);
129
+ }
130
+ // 3. Send SMS (opt-in via TEST_SEND=true)
131
+ const shouldSend = env('TEST_SEND') === 'true';
132
+ if (!shouldSend) {
133
+ warn('TEST_SEND is not set to true — skipping live send');
134
+ return;
135
+ }
136
+ yield runTest('quickSend()', () => __awaiter(this, void 0, void 0, function* () {
137
+ const sendParams = {
138
+ From: requireEnv('TEST_FROM'),
139
+ To: requireEnv('TEST_TO'),
140
+ Content: env('TEST_CONTENT') || 'unismsgateway live test — please ignore.'
141
+ };
142
+ info(`Sending from "${sendParams.From}" to "${sendParams.To}"...`);
143
+ const result = yield platform.quickSend(sendParams);
144
+ if (!result.success) {
145
+ throw new Error(result.error || `Send failed: ${JSON.stringify(result)}`);
146
+ }
147
+ pass(`Message sent. Result: ${JSON.stringify(result)}`);
148
+ }));
149
+ });
150
+ }
151
+ // ─── Entry point ─────────────────────────────────────────────────────────────
152
+ function main() {
153
+ return __awaiter(this, void 0, void 0, function* () {
154
+ console.log(`\n${BOLD}═══════════════════════════════════════${RESET}`);
155
+ console.log(`${BOLD} unismsgateway — live test runner ${RESET}`);
156
+ console.log(`${BOLD}═══════════════════════════════════════${RESET}`);
157
+ const platformArg = env('GATEWAY_PLATFORM');
158
+ const platforms = platformArg
159
+ ? [platformArg]
160
+ : (env('TEST_ALL') === 'true' ? ['nest', 'hubtel', 'route'] : []);
161
+ if (platforms.length === 0) {
162
+ console.log(`\n${YELLOW}No platform selected.${RESET}`);
163
+ console.log('Set GATEWAY_PLATFORM=nest|hubtel|route in your .env file,');
164
+ console.log('or set TEST_ALL=true to test all configured platforms.\n');
165
+ process.exit(1);
166
+ }
167
+ for (const p of platforms) {
168
+ try {
169
+ yield testPlatform(p);
170
+ }
171
+ catch (_a) {
172
+ // individual test errors already captured above
173
+ }
174
+ }
175
+ // ─── Summary ────────────────────────────────────────────────────────────
176
+ title('Summary');
177
+ if (passed > 0)
178
+ pass(`${passed} check(s) passed`);
179
+ if (failed > 0)
180
+ fail(`${failed} check(s) failed`);
181
+ console.log();
182
+ process.exit(failed > 0 ? 1 : 0);
183
+ });
184
+ }
185
+ main().catch((err) => {
186
+ console.error(`\n${RED}Unexpected error:${RESET}`, err);
187
+ process.exit(1);
188
+ });
@@ -0,0 +1 @@
1
+ export * from './lib/lib';
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ __exportStar(require("./lib/lib"), exports);
@@ -0,0 +1,13 @@
1
+ import { ISmsGatewayDelegate, QuickSendParams, SendResult } from './types';
2
+ export interface HubtelSmsGatewayConfig {
3
+ clientId: string;
4
+ clientSecret: string;
5
+ }
6
+ /**
7
+ * Wraps hubtel-sms-extended and maps API responses to {@link SendResult}.
8
+ */
9
+ export declare class HubtelSmsGateway implements ISmsGatewayDelegate {
10
+ private _client;
11
+ constructor(config: HubtelSmsGatewayConfig);
12
+ quickSend(params: QuickSendParams, callback?: Function): Promise<SendResult>;
13
+ }
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.HubtelSmsGateway = void 0;
13
+ const hubtel_sms_extended_1 = require("hubtel-sms-extended");
14
+ /**
15
+ * Wraps hubtel-sms-extended and maps API responses to {@link SendResult}.
16
+ */
17
+ class HubtelSmsGateway {
18
+ constructor(config) {
19
+ this._client = new hubtel_sms_extended_1.HubtelSms({
20
+ clientId: config.clientId,
21
+ clientSecret: config.clientSecret
22
+ });
23
+ }
24
+ quickSend(params, callback) {
25
+ return __awaiter(this, void 0, void 0, function* () {
26
+ try {
27
+ const raw = yield this._client.quickSend({
28
+ From: params.From,
29
+ To: String(params.To),
30
+ Content: params.Content
31
+ });
32
+ const ok = Number(raw.Status) === 0;
33
+ const result = {
34
+ success: ok,
35
+ messageId: String(raw.MessageId),
36
+ data: raw,
37
+ error: ok ? undefined : `Hubtel Status=${raw.Status}`
38
+ };
39
+ if (callback) {
40
+ callback(result);
41
+ }
42
+ return result;
43
+ }
44
+ catch (error) {
45
+ const result = {
46
+ success: false,
47
+ error: error instanceof Error ? error.message : String(error)
48
+ };
49
+ if (callback) {
50
+ callback(result);
51
+ }
52
+ return result;
53
+ }
54
+ });
55
+ }
56
+ }
57
+ exports.HubtelSmsGateway = HubtelSmsGateway;
@@ -0,0 +1,5 @@
1
+ import { smsPlatform, IgatewaySettings, IgatewayParam, PlatformId, QuickSendParams, SendResult, ISmsGateway } from './platform';
2
+ export declare function init(settings: IgatewaySettings): smsPlatform;
3
+ export declare function getSmsPlatform(): smsPlatform | null;
4
+ export declare function reset(): void;
5
+ export { smsPlatform, IgatewaySettings, IgatewayParam, PlatformId, QuickSendParams, SendResult, ISmsGateway };
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.smsPlatform = exports.reset = exports.getSmsPlatform = exports.init = void 0;
4
+ const platform_1 = require("./platform");
5
+ Object.defineProperty(exports, "smsPlatform", { enumerable: true, get: function () { return platform_1.smsPlatform; } });
6
+ let smsPlatformInstance = null;
7
+ function init(settings) {
8
+ smsPlatformInstance = new platform_1.smsPlatform(settings);
9
+ smsPlatformInstance.init();
10
+ return smsPlatformInstance;
11
+ }
12
+ exports.init = init;
13
+ function getSmsPlatform() {
14
+ return smsPlatformInstance;
15
+ }
16
+ exports.getSmsPlatform = getSmsPlatform;
17
+ function reset() {
18
+ smsPlatformInstance = null;
19
+ }
20
+ exports.reset = reset;
@@ -0,0 +1,12 @@
1
+ import { ISmsGateway, QuickSendParams, SendResult, NestSmsConfig } from './types';
2
+ export declare class NestSmsGateway implements ISmsGateway {
3
+ private config;
4
+ constructor(config: NestSmsConfig);
5
+ init(): ISmsGateway;
6
+ private makeRequest;
7
+ quickSend(params: QuickSendParams, callback?: Function): Promise<SendResult>;
8
+ getBalance(): Promise<{
9
+ balance: number;
10
+ model: string;
11
+ }>;
12
+ }
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
21
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
22
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
23
+ return new (P || (P = Promise))(function (resolve, reject) {
24
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
25
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
26
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
27
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
28
+ });
29
+ };
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.NestSmsGateway = void 0;
32
+ const https = __importStar(require("https"));
33
+ const http = __importStar(require("http"));
34
+ const DEFAULT_HOST = 'api.smsonlinegh.com';
35
+ const DEFAULT_PROTOCOL = 'https';
36
+ class NestSmsGateway {
37
+ constructor(config) {
38
+ this.config = {
39
+ host: config.host || DEFAULT_HOST,
40
+ protocol: config.protocol || DEFAULT_PROTOCOL,
41
+ apiKey: config.apiKey
42
+ };
43
+ }
44
+ init() {
45
+ return this;
46
+ }
47
+ makeRequest(endpoint, data) {
48
+ return __awaiter(this, void 0, void 0, function* () {
49
+ return new Promise((resolve, reject) => {
50
+ var _a;
51
+ const postData = data ? JSON.stringify(data) : '';
52
+ const protocol = this.config.protocol || DEFAULT_PROTOCOL;
53
+ const httpModule = protocol === 'https' ? https : http;
54
+ const defaultPort = protocol === 'https' ? 443 : 80;
55
+ const options = {
56
+ hostname: this.config.host || DEFAULT_HOST,
57
+ port: ((_a = this.config.host) === null || _a === void 0 ? void 0 : _a.includes(':'))
58
+ ? parseInt(this.config.host.split(':')[1])
59
+ : defaultPort,
60
+ path: `/v5/${endpoint}`,
61
+ method: 'POST',
62
+ headers: {
63
+ 'Host': this.config.host || DEFAULT_HOST,
64
+ 'Content-Type': 'application/json',
65
+ 'Accept': 'application/json',
66
+ 'Authorization': `key ${this.config.apiKey}`,
67
+ 'Content-Length': Buffer.byteLength(postData)
68
+ }
69
+ };
70
+ const req = httpModule.request(options, (res) => {
71
+ let responseBody = '';
72
+ res.on('data', (chunk) => {
73
+ responseBody += chunk;
74
+ });
75
+ res.on('end', () => {
76
+ try {
77
+ if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
78
+ const parsed = JSON.parse(responseBody);
79
+ resolve(parsed);
80
+ }
81
+ else {
82
+ reject(new Error(`HTTP ${res.statusCode}: ${responseBody}`));
83
+ }
84
+ }
85
+ catch (error) {
86
+ reject(new Error(`Failed to parse response: ${responseBody}`));
87
+ }
88
+ });
89
+ });
90
+ req.on('error', (error) => {
91
+ reject(error);
92
+ });
93
+ req.write(postData);
94
+ req.end();
95
+ });
96
+ });
97
+ }
98
+ quickSend(params, callback) {
99
+ var _a, _b, _c, _d, _e;
100
+ return __awaiter(this, void 0, void 0, function* () {
101
+ const endpoint = 'message/sms/send';
102
+ // SMSOnlineGH v5 expects: text, sender, destinations[] (see API docs — not from/to/content).
103
+ const requestBody = {
104
+ text: params.Content,
105
+ type: params.Type || 0,
106
+ sender: params.From,
107
+ destinations: [String(params.To)]
108
+ };
109
+ try {
110
+ const response = yield this.makeRequest(endpoint, requestBody);
111
+ const handshakeOk = Number((_a = response.handshake) === null || _a === void 0 ? void 0 : _a.id) === 0;
112
+ const data = (_b = response.data) !== null && _b !== void 0 ? _b : null;
113
+ const batchId = data && typeof data === 'object' ? data.batch : undefined;
114
+ const firstDest = data && typeof data === 'object'
115
+ ? (_c = data.destinations) === null || _c === void 0 ? void 0 : _c[0]
116
+ : undefined;
117
+ const result = {
118
+ success: handshakeOk,
119
+ data,
120
+ messageId: batchId || (firstDest === null || firstDest === void 0 ? void 0 : firstDest.id),
121
+ error: handshakeOk
122
+ ? undefined
123
+ : (((_d = response.handshake) === null || _d === void 0 ? void 0 : _d.label)
124
+ || `handshake id ${String((_e = response.handshake) === null || _e === void 0 ? void 0 : _e.id)}`)
125
+ };
126
+ if (callback) {
127
+ callback(result);
128
+ }
129
+ return result;
130
+ }
131
+ catch (error) {
132
+ const errorMessage = error instanceof Error ? error.message : String(error);
133
+ const result = {
134
+ success: false,
135
+ error: errorMessage
136
+ };
137
+ if (callback) {
138
+ callback(result);
139
+ }
140
+ return result;
141
+ }
142
+ });
143
+ }
144
+ getBalance() {
145
+ var _a, _b;
146
+ return __awaiter(this, void 0, void 0, function* () {
147
+ const endpoint = 'account/balance';
148
+ const response = yield this.makeRequest(endpoint);
149
+ return {
150
+ balance: ((_a = response.data) === null || _a === void 0 ? void 0 : _a.balance) || 0,
151
+ model: ((_b = response.data) === null || _b === void 0 ? void 0 : _b.model) || 'quantity'
152
+ };
153
+ });
154
+ }
155
+ }
156
+ exports.NestSmsGateway = NestSmsGateway;
@@ -0,0 +1,13 @@
1
+ import { IgatewaySettings, IgatewayParam, ISmsGateway, ISmsGatewayDelegate, QuickSendParams, SendResult } from './types';
2
+ export * from './types';
3
+ export declare class smsPlatform implements ISmsGateway {
4
+ private _settings;
5
+ private _gateway;
6
+ constructor(settings: IgatewaySettings);
7
+ private validateSettings;
8
+ private createGateway;
9
+ init(): ISmsGateway;
10
+ quickSend(param: QuickSendParams, callback?: Function): Promise<SendResult>;
11
+ getGateway(): ISmsGatewayDelegate;
12
+ }
13
+ export { IgatewaySettings, IgatewayParam };
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.smsPlatform = void 0;
14
+ const nest_gateway_1 = require("./nest-gateway");
15
+ const hubtel_gateway_1 = require("./hubtel-gateway");
16
+ const route_gateway_1 = require("./route-gateway");
17
+ __exportStar(require("./types"), exports);
18
+ const GATEWAY_CONFIGS = {
19
+ route: { requiresUsernamePassword: true },
20
+ hubtel: { requiresClientCredentials: true },
21
+ nest: { requiresApiKey: true }
22
+ };
23
+ class smsPlatform {
24
+ constructor(settings) {
25
+ this.validateSettings(settings);
26
+ this._settings = settings;
27
+ this._gateway = this.createGateway();
28
+ }
29
+ validateSettings(settings) {
30
+ const validPlatforms = ['route', 'hubtel', 'nest'];
31
+ if (!validPlatforms.includes(settings.platformId)) {
32
+ throw new Error(`Invalid platform ID. Supported platforms: ${validPlatforms.join(', ')}`);
33
+ }
34
+ const config = GATEWAY_CONFIGS[settings.platformId];
35
+ const param = settings.param;
36
+ if (config.requiresApiKey && !param.apiKey) {
37
+ throw new Error(`Platform '${settings.platformId}' requires 'apiKey' in param`);
38
+ }
39
+ if (config.requiresClientCredentials && (!param.clientId || !param.clientSecret)) {
40
+ throw new Error(`Platform '${settings.platformId}' requires 'clientId' and 'clientSecret' in param`);
41
+ }
42
+ if (config.requiresUsernamePassword && (!param.username || !param.password)) {
43
+ throw new Error(`Platform '${settings.platformId}' requires 'username' and 'password' in param`);
44
+ }
45
+ }
46
+ createGateway() {
47
+ const { platformId, param } = this._settings;
48
+ switch (platformId) {
49
+ case 'route':
50
+ return new route_gateway_1.RouteSmsGateway({
51
+ host: param.host || 'rslr.connectbind.com',
52
+ username: param.username,
53
+ password: param.password,
54
+ protocol: param.protocol || 'http',
55
+ port: param.port || 8080
56
+ });
57
+ case 'hubtel':
58
+ return new hubtel_gateway_1.HubtelSmsGateway({
59
+ clientId: param.clientId,
60
+ clientSecret: param.clientSecret
61
+ });
62
+ case 'nest':
63
+ return new nest_gateway_1.NestSmsGateway({
64
+ apiKey: param.apiKey,
65
+ host: param.host,
66
+ protocol: param.protocol
67
+ });
68
+ default:
69
+ throw new Error(`Unsupported platform: ${platformId}`);
70
+ }
71
+ }
72
+ init() {
73
+ return this;
74
+ }
75
+ quickSend(param, callback) {
76
+ if (!this._gateway) {
77
+ throw new Error('Gateway not initialized. Call init() first.');
78
+ }
79
+ return this._gateway.quickSend(param, callback);
80
+ }
81
+ getGateway() {
82
+ return this._gateway;
83
+ }
84
+ }
85
+ exports.smsPlatform = smsPlatform;
@@ -0,0 +1,12 @@
1
+ import { ISmsGatewayDelegate, QuickSendParams, SendResult } from './types';
2
+ export interface RouteSmsGatewayConfig {
3
+ host: string;
4
+ username: string;
5
+ password: string;
6
+ protocol: 'http' | 'https';
7
+ port: number;
8
+ }
9
+ export declare class RouteSmsGateway implements ISmsGatewayDelegate {
10
+ constructor(config: RouteSmsGatewayConfig);
11
+ quickSend(params: QuickSendParams, callback?: Function): Promise<SendResult>;
12
+ }
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.RouteSmsGateway = void 0;
13
+ const routemobilesms_1 = require("routemobilesms");
14
+ /**
15
+ * Adapts routemobilesms static `sendAsync` API to {@link ISmsGatewayDelegate}.
16
+ */
17
+ function toRouteDestination(to) {
18
+ if (typeof to === 'number') {
19
+ return to;
20
+ }
21
+ const digits = String(to).replace(/\D/g, '');
22
+ const n = Number(digits);
23
+ return Number.isNaN(n) ? 0 : n;
24
+ }
25
+ class RouteSmsGateway {
26
+ constructor(config) {
27
+ new routemobilesms_1.routeSms({
28
+ host: config.host,
29
+ username: config.username,
30
+ password: config.password,
31
+ protocol: config.protocol,
32
+ port: config.port
33
+ });
34
+ }
35
+ quickSend(params, callback) {
36
+ return __awaiter(this, void 0, void 0, function* () {
37
+ const sendParams = {
38
+ From: params.From,
39
+ To: toRouteDestination(params.To),
40
+ Content: params.Content
41
+ };
42
+ if (params.Type !== undefined) {
43
+ sendParams.config = { type: params.Type, dlr: 0 };
44
+ }
45
+ const raw = yield routemobilesms_1.routeSms.sendAsync(sendParams);
46
+ let result;
47
+ if (raw === undefined || raw === null) {
48
+ result = { success: false, error: 'No response from route SMS gateway' };
49
+ }
50
+ else if (Array.isArray(raw) && raw.length > 0) {
51
+ const first = raw[0];
52
+ const ok = first.status === 'successful';
53
+ result = {
54
+ success: ok,
55
+ messageId: first.id,
56
+ data: raw,
57
+ error: ok ? undefined : (first.message || first.code || 'Send failed')
58
+ };
59
+ }
60
+ else {
61
+ result = { success: false, error: 'Unexpected response from route SMS gateway', data: raw };
62
+ }
63
+ if (callback) {
64
+ callback(result);
65
+ }
66
+ return result;
67
+ });
68
+ }
69
+ }
70
+ exports.RouteSmsGateway = RouteSmsGateway;
@@ -0,0 +1,47 @@
1
+ export declare type PlatformId = 'route' | 'hubtel' | 'nest';
2
+ export interface QuickSendParams {
3
+ From: string;
4
+ To: string | number;
5
+ Content: string;
6
+ Type?: number;
7
+ }
8
+ export interface SendResult {
9
+ success: boolean;
10
+ messageId?: string;
11
+ data?: any;
12
+ error?: string;
13
+ }
14
+ export interface IgatewayParam {
15
+ host?: string;
16
+ port?: number;
17
+ username?: string;
18
+ password?: string;
19
+ clientId?: string;
20
+ clientSecret?: string;
21
+ apiKey?: string;
22
+ protocol?: 'http' | 'https';
23
+ }
24
+ export interface IgatewaySettings {
25
+ platformId: PlatformId;
26
+ param: IgatewayParam;
27
+ }
28
+ /** Send surface used by the facade; third-party SDKs may omit `init()`. */
29
+ export interface ISmsGatewayDelegate {
30
+ quickSend(params: QuickSendParams, callback?: Function): Promise<SendResult>;
31
+ getBalance?(): Promise<any>;
32
+ }
33
+ export interface ISmsGateway extends ISmsGatewayDelegate {
34
+ init(): ISmsGateway;
35
+ }
36
+ export interface NestSmsConfig {
37
+ apiKey: string;
38
+ host?: string;
39
+ protocol?: 'http' | 'https';
40
+ }
41
+ export interface NestSendResponse {
42
+ handshake: {
43
+ id: number;
44
+ label: string;
45
+ };
46
+ data?: any;
47
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "unismsgateway",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "A unified SMS gateway library that brings access to multiple SMS gateways under a single API",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
7
7
  "scripts": {
8
- "test": "echo \"Error: no test specified\" && exit 1",
8
+ "test": "npm run test:live",
9
+ "test:live": "ts-node scripts/test-live.ts",
9
10
  "build": "tsc",
10
11
  "prepublish": "npm run build"
11
12
  },
@@ -38,7 +39,10 @@
38
39
  "node": ">=12.0.0"
39
40
  },
40
41
  "devDependencies": {
42
+ "@types/dotenv": "^6.1.1",
41
43
  "@types/node": "^17.0.4",
44
+ "dotenv": "^17.4.0",
45
+ "ts-node": "^10.9.2",
42
46
  "typescript": "^4.5.4"
43
47
  },
44
48
  "dependencies": {
File without changes