budgetsms-client 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nick Leeman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,440 @@
1
+ # budgetsms-client
2
+
3
+ Modern, type-safe TypeScript/JavaScript client for the [BudgetSMS.net](https://www.budgetsms.net) HTTP API.
4
+
5
+ > **Note:** This is an **unofficial** client library and is not affiliated with or endorsed by BudgetSMS.net. It is a community-maintained open-source project.
6
+
7
+ [![npm version](https://img.shields.io/npm/v/budgetsms-client.svg)](https://www.npmjs.com/package/budgetsms-client)
8
+ [![CI](https://github.com/Frozenverse/budgetsms-client/workflows/CI/badge.svg)](https://github.com/Frozenverse/budgetsms-client/actions/workflows/ci.yml)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
10
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue.svg)](https://www.typescriptlang.org/)
11
+ [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-green.svg)](https://nodejs.org/)
12
+ [![npm downloads](https://img.shields.io/npm/dm/budgetsms-client.svg)](https://www.npmjs.com/package/budgetsms-client)
13
+
14
+ ## Features
15
+
16
+ - ðŸŽŊ **Works with JavaScript & TypeScript** - No TypeScript required!
17
+ - ðŸ“Ķ **Dual module support** - ESM and CommonJS
18
+ - 🔒 **Type-safe error handling** - Error code enums with helper methods
19
+ - ðŸŽĻ **Response parsing** - Clean, typed response objects
20
+ - ðŸŠķ **Zero dependencies** - Lightweight (22KB) and fast
21
+ - ✅ **Fully tested** - 42 tests, 100% coverage
22
+ - 📚 **Complete API coverage** - All 7 BudgetSMS endpoints
23
+ - ðŸ’Ą **IntelliSense support** - Autocomplete in VS Code, even in JavaScript
24
+ - 🚀 **Node.js 18+** - Uses native fetch (no extra dependencies)
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ npm install budgetsms-client
30
+ ```
31
+
32
+ ```bash
33
+ yarn add budgetsms-client
34
+ ```
35
+
36
+ ```bash
37
+ pnpm add budgetsms-client
38
+ ```
39
+
40
+ ## Quick Start
41
+
42
+ ### TypeScript / ESM
43
+
44
+ ```typescript
45
+ import { BudgetSMS } from 'budgetsms-client';
46
+
47
+ // Initialize the client
48
+ const client = new BudgetSMS({
49
+ username: 'your-username',
50
+ userid: 'your-userid',
51
+ handle: 'your-api-handle'
52
+ });
53
+
54
+ // Send an SMS
55
+ const result = await client.sendSMS({
56
+ msg: 'Hello World!',
57
+ from: 'YourApp',
58
+ to: '31612345678'
59
+ });
60
+
61
+ console.log(`SMS sent with ID: ${result.smsId}`);
62
+ ```
63
+
64
+ ### JavaScript / CommonJS
65
+
66
+ ```javascript
67
+ const { BudgetSMS } = require('budgetsms-client');
68
+
69
+ // Initialize the client
70
+ const client = new BudgetSMS({
71
+ username: 'your-username',
72
+ userid: 'your-userid',
73
+ handle: 'your-api-handle'
74
+ });
75
+
76
+ // Send an SMS (using .then() or async/await)
77
+ client.sendSMS({
78
+ msg: 'Hello World!',
79
+ from: 'YourApp',
80
+ to: '31612345678'
81
+ }).then(result => {
82
+ console.log(`SMS sent with ID: ${result.smsId}`);
83
+ }).catch(error => {
84
+ console.error('Error:', error.message);
85
+ });
86
+ ```
87
+
88
+ ### JavaScript / ESM (Node.js with "type": "module")
89
+
90
+ ```javascript
91
+ import { BudgetSMS } from 'budgetsms-client';
92
+
93
+ const client = new BudgetSMS({
94
+ username: 'your-username',
95
+ userid: 'your-userid',
96
+ handle: 'your-api-handle'
97
+ });
98
+
99
+ const result = await client.sendSMS({
100
+ msg: 'Hello World!',
101
+ from: 'YourApp',
102
+ to: '31612345678'
103
+ });
104
+
105
+ console.log(`SMS sent with ID: ${result.smsId}`);
106
+ ```
107
+
108
+ ## API Reference
109
+
110
+ ### Initialize Client
111
+
112
+ ```typescript
113
+ import { BudgetSMS } from 'budgetsms-client';
114
+
115
+ const client = new BudgetSMS({
116
+ username: 'your-username', // Your BudgetSMS username
117
+ userid: 'your-userid', // Your BudgetSMS user ID
118
+ handle: 'your-api-handle', // Your API handle
119
+
120
+ // Optional configuration
121
+ baseUrl: 'https://api.budgetsms.net', // Custom API base URL
122
+ timeout: 30000 // Request timeout in ms (default: 30000)
123
+ });
124
+ ```
125
+
126
+ ### Send SMS
127
+
128
+ Send an SMS message to a recipient.
129
+
130
+ ```typescript
131
+ const result = await client.sendSMS({
132
+ msg: 'Your message text',
133
+ from: 'YourApp', // Sender ID (max 11 alphanumeric or 16 numeric)
134
+ to: '31612345678', // Recipient phone number (international format, no +)
135
+
136
+ // Optional parameters
137
+ customid: 'unique-id-123', // Custom message ID (max 50 chars, must be unique)
138
+ price: true, // Include price information in response
139
+ mccmnc: true, // Include operator network information
140
+ credit: true // Include remaining credit in response
141
+ });
142
+
143
+ console.log(`SMS ID: ${result.smsId}`);
144
+
145
+ // If price was requested
146
+ if (result.price) {
147
+ console.log(`Cost: ₮${result.price} for ${result.parts} part(s)`);
148
+ }
149
+
150
+ // If mccmnc was requested
151
+ if (result.mccMnc) {
152
+ console.log(`Network: ${result.mccMnc}`);
153
+ }
154
+ ```
155
+
156
+ ### Test SMS
157
+
158
+ Test your SMS implementation without actually sending or consuming credits.
159
+
160
+ ```typescript
161
+ const result = await client.testSMS({
162
+ msg: 'Test message',
163
+ from: 'TestApp',
164
+ to: '31612345678'
165
+ });
166
+
167
+ console.log(`Test successful, would get SMS ID: ${result.smsId}`);
168
+ ```
169
+
170
+ ### Check Credit
171
+
172
+ Get your remaining account balance.
173
+
174
+ ```typescript
175
+ const result = await client.checkCredit();
176
+ console.log(`Remaining credit: ₮${result.credit}`);
177
+ ```
178
+
179
+ ### Check Operator
180
+
181
+ Check the operator for a phone number based on its prefix.
182
+
183
+ > **Note:** This checks the original operator. If a number has been ported to another operator, use `hlr()` instead.
184
+
185
+ ```typescript
186
+ const result = await client.checkOperator('31612345678');
187
+ console.log(`Operator: ${result.operatorName}`);
188
+ console.log(`Network: ${result.mccMnc}`);
189
+ console.log(`Cost per SMS: ₮${result.messageCost}`);
190
+ ```
191
+
192
+ ### HLR Lookup
193
+
194
+ Perform an HLR (Home Location Register) lookup to determine the actual current operator, even if the number has been ported.
195
+
196
+ ```typescript
197
+ const result = await client.hlr('31612345678');
198
+ console.log(`Current operator: ${result.operatorName}`);
199
+ console.log(`Network: ${result.mccMnc}`);
200
+ ```
201
+
202
+ ### Check SMS Status
203
+
204
+ Check the delivery status of a sent message (Pull DLR).
205
+
206
+ ```typescript
207
+ const result = await client.checkSMS('12345678'); // SMS ID from sendSMS()
208
+ console.log(`Status: ${result.status}`);
209
+
210
+ // Use DLRStatus enum for type-safe status checking
211
+ import { DLRStatus, DLR_STATUS_MESSAGES } from 'budgetsms-client';
212
+
213
+ if (result.status === DLRStatus.DELIVERED) {
214
+ console.log('Message was delivered!');
215
+ } else {
216
+ console.log(`Status: ${DLR_STATUS_MESSAGES[result.status]}`);
217
+ }
218
+ ```
219
+
220
+ ### Get Pricing
221
+
222
+ Retrieve pricing information for all operators in your account.
223
+
224
+ ```typescript
225
+ const pricing = await client.getPricing();
226
+
227
+ for (const entry of pricing) {
228
+ console.log(`${entry.countryname} - ${entry.operatorname}: ₮${entry.price}`);
229
+ console.log(` MCC/MNC: ${entry.mcc}/${entry.mnc}`);
230
+ console.log(` Last modified: ${entry.last_modified}`);
231
+ }
232
+ ```
233
+
234
+ ## Error Handling
235
+
236
+ The client uses typed error handling with the `BudgetSMSError` class.
237
+
238
+ ```typescript
239
+ import { BudgetSMSError, BudgetSMSErrorCode } from 'budgetsms-client';
240
+
241
+ try {
242
+ await client.sendSMS({
243
+ msg: 'Test',
244
+ from: 'App',
245
+ to: '31612345678'
246
+ });
247
+ } catch (error) {
248
+ if (error instanceof BudgetSMSError) {
249
+ console.error(`BudgetSMS Error: ${error.message}`);
250
+ console.error(`Error Code: ${error.code}`);
251
+
252
+ // Check specific error conditions
253
+ if (error.isInsufficientCredits()) {
254
+ console.error('Please top up your account!');
255
+ }
256
+
257
+ if (error.isAuthenticationError()) {
258
+ console.error('Check your credentials!');
259
+ }
260
+
261
+ if (error.isRetryable()) {
262
+ console.error('Temporary error, you can retry');
263
+ }
264
+ } else {
265
+ console.error('Unexpected error:', error);
266
+ }
267
+ }
268
+ ```
269
+
270
+ ### Error Codes
271
+
272
+ All BudgetSMS API error codes are available as an enum:
273
+
274
+ ```typescript
275
+ import { BudgetSMSErrorCode, ERROR_MESSAGES } from 'budgetsms-client';
276
+
277
+ // Access error codes
278
+ BudgetSMSErrorCode.NOT_ENOUGH_CREDITS // 1001
279
+ BudgetSMSErrorCode.INVALID_CREDENTIALS // 1002
280
+ BudgetSMSErrorCode.ACCOUNT_NOT_ACTIVE // 1003
281
+ // ... and many more
282
+
283
+ // Get error message for a code
284
+ console.log(ERROR_MESSAGES[BudgetSMSErrorCode.NOT_ENOUGH_CREDITS]);
285
+ // "Not enough credits to send messages"
286
+ ```
287
+
288
+ ## DLR Status Codes
289
+
290
+ Delivery report statuses are available as an enum:
291
+
292
+ ```typescript
293
+ import { DLRStatus, DLR_STATUS_MESSAGES } from 'budgetsms-client';
294
+
295
+ // DLR status values
296
+ DLRStatus.DELIVERED // 1 - Message is delivered
297
+ DLRStatus.DELIVERY_FAILED // 3 - Message delivery failed
298
+ DLRStatus.EXPIRED // 5 - Message expired
299
+ DLRStatus.SENT_NO_STATUS // 0 - Message is sent, no status yet
300
+ // ... and more
301
+
302
+ // Get human-readable status message
303
+ console.log(DLR_STATUS_MESSAGES[DLRStatus.DELIVERED]);
304
+ // "Message is delivered"
305
+ ```
306
+
307
+ ## Validation Utilities
308
+
309
+ The package includes validation utilities for common use cases:
310
+
311
+ ```typescript
312
+ import { validatePhoneNumber, validateSender, validateMessage } from 'budgetsms-client';
313
+
314
+ // Validate phone number (8-16 digits)
315
+ if (!validatePhoneNumber('31612345678')) {
316
+ console.error('Invalid phone number format');
317
+ }
318
+
319
+ // Validate sender ID
320
+ // - Alphanumeric: max 11 characters [a-zA-Z0-9]
321
+ // - Numeric: max 16 digits
322
+ if (!validateSender('MyApp')) {
323
+ console.error('Invalid sender format');
324
+ }
325
+
326
+ // Validate message text (not empty, max 612 chars for 4 SMS parts)
327
+ if (!validateMessage('Hello World')) {
328
+ console.error('Invalid message');
329
+ }
330
+ ```
331
+
332
+ ## TypeScript Support
333
+
334
+ This package is written in TypeScript and provides full type definitions.
335
+
336
+ ```typescript
337
+ import type {
338
+ BudgetSMSConfig,
339
+ SendSMSParams,
340
+ SendSMSResponse,
341
+ OperatorResponse,
342
+ PricingEntry,
343
+ // ... and more
344
+ } from 'budgetsms-client';
345
+ ```
346
+
347
+ ## Requirements
348
+
349
+ - Node.js >= 18.0.0 (for native `fetch` support)
350
+ - Works with **both JavaScript and TypeScript** projects
351
+ - No build step required for JavaScript users
352
+
353
+ ## JavaScript & TypeScript Support
354
+
355
+ This package is **fully compatible with JavaScript** projects:
356
+
357
+ - ✅ **JavaScript (CommonJS)**: `require('budgetsms-client')`
358
+ - ✅ **JavaScript (ESM)**: `import { BudgetSMS } from 'budgetsms-client'`
359
+ - ✅ **TypeScript**: Full type definitions included
360
+ - ✅ **No TypeScript required**: The package ships as compiled JavaScript
361
+ - ✅ **IntelliSense support**: Get autocomplete even in JavaScript projects (VS Code, etc.)
362
+
363
+ ### For JavaScript Users
364
+
365
+ You don't need TypeScript installed to use this package. It's written in TypeScript but **compiled to JavaScript** before publishing. The TypeScript definitions are optional and only provide better editor autocomplete.
366
+
367
+ ```javascript
368
+ // Plain JavaScript - works perfectly!
369
+ const { BudgetSMS } = require('budgetsms-client');
370
+
371
+ const client = new BudgetSMS({
372
+ username: 'test',
373
+ userid: '123',
374
+ handle: 'abc'
375
+ });
376
+
377
+ // Your editor will still show autocomplete thanks to included .d.ts files
378
+ client.sendSMS({ /* autocomplete works here! */ });
379
+ ```
380
+
381
+ ### For TypeScript Users
382
+
383
+ Full type safety out of the box:
384
+
385
+ ```typescript
386
+ import { BudgetSMS, SendSMSResponse, BudgetSMSError } from 'budgetsms-client';
387
+
388
+ const client = new BudgetSMS({ ... });
389
+ const result: SendSMSResponse = await client.sendSMS({ ... });
390
+ ```
391
+
392
+ ## Module Format Support
393
+
394
+ This package supports both ESM and CommonJS:
395
+
396
+ ```typescript
397
+ // ESM (TypeScript or JavaScript with "type": "module")
398
+ import { BudgetSMS } from 'budgetsms-client';
399
+
400
+ // CommonJS (Traditional Node.js)
401
+ const { BudgetSMS } = require('budgetsms-client');
402
+ ```
403
+
404
+ ## Examples
405
+
406
+ Check out the [examples](./examples) directory for complete working examples:
407
+
408
+ - **[javascript-example.js](./examples/javascript-example.js)** - CommonJS (traditional Node.js)
409
+ - **[javascript-esm-example.mjs](./examples/javascript-esm-example.mjs)** - ES Modules
410
+ - **[typescript-example.ts](./examples/typescript-example.ts)** - TypeScript with full types
411
+
412
+ Each example includes:
413
+ - Client initialization
414
+ - Sending SMS
415
+ - Error handling
416
+ - Credit checking
417
+ - Operator lookup
418
+ - Status tracking
419
+
420
+ ## API Documentation
421
+
422
+ For complete BudgetSMS API documentation, visit:
423
+ - [Official BudgetSMS API Documentation](https://www.budgetsms.net/sms-http-api/)
424
+
425
+ ## License
426
+
427
+ MIT ÂĐ [Nick Leeman](https://github.com/Frozenverse)
428
+
429
+ ## Contributing
430
+
431
+ Contributions are welcome! Please feel free to submit a Pull Request.
432
+
433
+ ## Support
434
+
435
+ - 📧 For BudgetSMS API issues: [contact BudgetSMS support](https://www.budgetsms.net/contact/)
436
+ - 🐛 For package issues: [GitHub Issues](https://github.com/Frozenverse/budgetsms-client/issues)
437
+
438
+ ## Changelog
439
+
440
+ See [Releases](https://github.com/Frozenverse/budgetsms-client/releases) for version history.