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/dist/index.cjs ADDED
@@ -0,0 +1,569 @@
1
+ 'use strict';
2
+
3
+ // src/constants.ts
4
+ var API_BASE = "https://api.budgetsms.net";
5
+ var ENDPOINTS = {
6
+ SEND_SMS: "/sendsms/",
7
+ TEST_SMS: "/testsms/",
8
+ CHECK_CREDIT: "/checkcredit/",
9
+ CHECK_OPERATOR: "/checkoperator/",
10
+ HLR: "/hlr/",
11
+ CHECK_SMS: "/checksms/",
12
+ GET_PRICING: "/getpricing/"
13
+ };
14
+ var BudgetSMSErrorCode = /* @__PURE__ */ ((BudgetSMSErrorCode2) => {
15
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["NOT_ENOUGH_CREDITS"] = 1001] = "NOT_ENOUGH_CREDITS";
16
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["INVALID_CREDENTIALS"] = 1002] = "INVALID_CREDENTIALS";
17
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["ACCOUNT_NOT_ACTIVE"] = 1003] = "ACCOUNT_NOT_ACTIVE";
18
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["IP_NOT_ALLOWED"] = 1004] = "IP_NOT_ALLOWED";
19
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["NO_HANDLE_PROVIDED"] = 1005] = "NO_HANDLE_PROVIDED";
20
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["NO_USERID_PROVIDED"] = 1006] = "NO_USERID_PROVIDED";
21
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["NO_USERNAME_PROVIDED"] = 1007] = "NO_USERNAME_PROVIDED";
22
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["SMS_TEXT_EMPTY"] = 2001] = "SMS_TEXT_EMPTY";
23
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["SMS_NUMERIC_SENDER_TOO_LONG"] = 2002] = "SMS_NUMERIC_SENDER_TOO_LONG";
24
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["SMS_ALPHANUMERIC_SENDER_TOO_LONG"] = 2003] = "SMS_ALPHANUMERIC_SENDER_TOO_LONG";
25
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["SMS_SENDER_EMPTY_OR_INVALID"] = 2004] = "SMS_SENDER_EMPTY_OR_INVALID";
26
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["DESTINATION_TOO_SHORT"] = 2005] = "DESTINATION_TOO_SHORT";
27
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["DESTINATION_NOT_NUMERIC"] = 2006] = "DESTINATION_NOT_NUMERIC";
28
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["DESTINATION_EMPTY"] = 2007] = "DESTINATION_EMPTY";
29
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["SMS_TEXT_NOT_OK"] = 2008] = "SMS_TEXT_NOT_OK";
30
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["PARAMETER_ISSUE"] = 2009] = "PARAMETER_ISSUE";
31
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["DESTINATION_INVALIDLY_FORMATTED"] = 2010] = "DESTINATION_INVALIDLY_FORMATTED";
32
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["DESTINATION_INVALID"] = 2011] = "DESTINATION_INVALID";
33
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["SMS_TEXT_TOO_LONG"] = 2012] = "SMS_TEXT_TOO_LONG";
34
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["SMS_MESSAGE_INVALID"] = 2013] = "SMS_MESSAGE_INVALID";
35
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["CUSTOM_ID_ALREADY_USED"] = 2014] = "CUSTOM_ID_ALREADY_USED";
36
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["CHARSET_PROBLEM"] = 2015] = "CHARSET_PROBLEM";
37
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["INVALID_UTF8_ENCODING"] = 2016] = "INVALID_UTF8_ENCODING";
38
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["INVALID_SMS_ID"] = 2017] = "INVALID_SMS_ID";
39
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["NO_ROUTE_TO_DESTINATION"] = 3001] = "NO_ROUTE_TO_DESTINATION";
40
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["NO_ROUTES_SETUP"] = 3002] = "NO_ROUTES_SETUP";
41
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["INVALID_DESTINATION"] = 3003] = "INVALID_DESTINATION";
42
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["SYSTEM_ERROR_CUSTOM_ID"] = 4001] = "SYSTEM_ERROR_CUSTOM_ID";
43
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["SYSTEM_ERROR_TEMPORARY"] = 4002] = "SYSTEM_ERROR_TEMPORARY";
44
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["SYSTEM_ERROR_TEMPORARY_2"] = 4003] = "SYSTEM_ERROR_TEMPORARY_2";
45
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["SYSTEM_ERROR_CONTACT_SUPPORT"] = 4004] = "SYSTEM_ERROR_CONTACT_SUPPORT";
46
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["SYSTEM_ERROR_PERMANENT"] = 4005] = "SYSTEM_ERROR_PERMANENT";
47
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["GATEWAY_NOT_REACHABLE"] = 4006] = "GATEWAY_NOT_REACHABLE";
48
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["SYSTEM_ERROR_CONTACT_SUPPORT_2"] = 4007] = "SYSTEM_ERROR_CONTACT_SUPPORT_2";
49
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["SEND_ERROR"] = 5001] = "SEND_ERROR";
50
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["WRONG_SMS_TYPE"] = 5002] = "WRONG_SMS_TYPE";
51
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["WRONG_OPERATOR"] = 5003] = "WRONG_OPERATOR";
52
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["UNKNOWN_ERROR"] = 6001] = "UNKNOWN_ERROR";
53
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["NO_HLR_PROVIDER"] = 7001] = "NO_HLR_PROVIDER";
54
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["UNEXPECTED_HLR_RESULTS"] = 7002] = "UNEXPECTED_HLR_RESULTS";
55
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["BAD_NUMBER_FORMAT"] = 7003] = "BAD_NUMBER_FORMAT";
56
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["HLR_UNEXPECTED_ERROR"] = 7901] = "HLR_UNEXPECTED_ERROR";
57
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["HLR_PROVIDER_ERROR"] = 7902] = "HLR_PROVIDER_ERROR";
58
+ BudgetSMSErrorCode2[BudgetSMSErrorCode2["HLR_PROVIDER_ERROR_2"] = 7903] = "HLR_PROVIDER_ERROR_2";
59
+ return BudgetSMSErrorCode2;
60
+ })(BudgetSMSErrorCode || {});
61
+ var ERROR_MESSAGES = {
62
+ [1001 /* NOT_ENOUGH_CREDITS */]: "Not enough credits to send messages",
63
+ [1002 /* INVALID_CREDENTIALS */]: "Identification failed. Wrong credentials",
64
+ [1003 /* ACCOUNT_NOT_ACTIVE */]: "Account not active, contact BudgetSMS",
65
+ [1004 /* IP_NOT_ALLOWED */]: "This IP address is not added to this account. No access to the API",
66
+ [1005 /* NO_HANDLE_PROVIDED */]: "No handle provided",
67
+ [1006 /* NO_USERID_PROVIDED */]: "No UserID provided",
68
+ [1007 /* NO_USERNAME_PROVIDED */]: "No Username provided",
69
+ [2001 /* SMS_TEXT_EMPTY */]: "SMS message text is empty",
70
+ [2002 /* SMS_NUMERIC_SENDER_TOO_LONG */]: "SMS numeric senderid can be max. 16 numbers",
71
+ [2003 /* SMS_ALPHANUMERIC_SENDER_TOO_LONG */]: "SMS alphanumeric sender can be max. 11 characters",
72
+ [2004 /* SMS_SENDER_EMPTY_OR_INVALID */]: "SMS senderid is empty or invalid",
73
+ [2005 /* DESTINATION_TOO_SHORT */]: "Destination number is too short",
74
+ [2006 /* DESTINATION_NOT_NUMERIC */]: "Destination is not numeric",
75
+ [2007 /* DESTINATION_EMPTY */]: "Destination is empty",
76
+ [2008 /* SMS_TEXT_NOT_OK */]: "SMS text is not OK (check encoding?)",
77
+ [2009 /* PARAMETER_ISSUE */]: "Parameter issue (check all mandatory parameters, encoding, etc.)",
78
+ [2010 /* DESTINATION_INVALIDLY_FORMATTED */]: "Destination number is invalidly formatted",
79
+ [2011 /* DESTINATION_INVALID */]: "Destination is invalid",
80
+ [2012 /* SMS_TEXT_TOO_LONG */]: "SMS message text is too long",
81
+ [2013 /* SMS_MESSAGE_INVALID */]: "SMS message is invalid",
82
+ [2014 /* CUSTOM_ID_ALREADY_USED */]: "SMS CustomID is used before",
83
+ [2015 /* CHARSET_PROBLEM */]: "Charset problem",
84
+ [2016 /* INVALID_UTF8_ENCODING */]: "Invalid UTF-8 encoding",
85
+ [2017 /* INVALID_SMS_ID */]: "Invalid SMSid",
86
+ [3001 /* NO_ROUTE_TO_DESTINATION */]: "No route to destination. Contact BudgetSMS for possible solutions",
87
+ [3002 /* NO_ROUTES_SETUP */]: "No routes are setup. Contact BudgetSMS for a route setup",
88
+ [3003 /* INVALID_DESTINATION */]: "Invalid destination. Check international mobile number formatting",
89
+ [4001 /* SYSTEM_ERROR_CUSTOM_ID */]: "System error, related to customID",
90
+ [4002 /* SYSTEM_ERROR_TEMPORARY */]: "System error, temporary issue. Try resubmitting in 2 to 3 minutes",
91
+ [4003 /* SYSTEM_ERROR_TEMPORARY_2 */]: "System error, temporary issue",
92
+ [4004 /* SYSTEM_ERROR_CONTACT_SUPPORT */]: "System error, temporary issue. Contact BudgetSMS",
93
+ [4005 /* SYSTEM_ERROR_PERMANENT */]: "System error, permanent",
94
+ [4006 /* GATEWAY_NOT_REACHABLE */]: "Gateway not reachable",
95
+ [4007 /* SYSTEM_ERROR_CONTACT_SUPPORT_2 */]: "System error, contact BudgetSMS",
96
+ [5001 /* SEND_ERROR */]: "Send error, Contact BudgetSMS with the send details",
97
+ [5002 /* WRONG_SMS_TYPE */]: "Wrong SMS type",
98
+ [5003 /* WRONG_OPERATOR */]: "Wrong operator",
99
+ [6001 /* UNKNOWN_ERROR */]: "Unknown error",
100
+ [7001 /* NO_HLR_PROVIDER */]: "No HLR provider present, Contact BudgetSMS",
101
+ [7002 /* UNEXPECTED_HLR_RESULTS */]: "Unexpected results from HLR provider",
102
+ [7003 /* BAD_NUMBER_FORMAT */]: "Bad number format",
103
+ [7901 /* HLR_UNEXPECTED_ERROR */]: "Unexpected error. Contact BudgetSMS",
104
+ [7902 /* HLR_PROVIDER_ERROR */]: "HLR provider error. Contact BudgetSMS",
105
+ [7903 /* HLR_PROVIDER_ERROR_2 */]: "HLR provider error. Contact BudgetSMS"
106
+ };
107
+ var DLRStatus = /* @__PURE__ */ ((DLRStatus2) => {
108
+ DLRStatus2[DLRStatus2["SENT_NO_STATUS"] = 0] = "SENT_NO_STATUS";
109
+ DLRStatus2[DLRStatus2["DELIVERED"] = 1] = "DELIVERED";
110
+ DLRStatus2[DLRStatus2["NOT_SENT"] = 2] = "NOT_SENT";
111
+ DLRStatus2[DLRStatus2["DELIVERY_FAILED"] = 3] = "DELIVERY_FAILED";
112
+ DLRStatus2[DLRStatus2["SENT"] = 4] = "SENT";
113
+ DLRStatus2[DLRStatus2["EXPIRED"] = 5] = "EXPIRED";
114
+ DLRStatus2[DLRStatus2["INVALID_DESTINATION"] = 6] = "INVALID_DESTINATION";
115
+ DLRStatus2[DLRStatus2["SMSC_ERROR"] = 7] = "SMSC_ERROR";
116
+ DLRStatus2[DLRStatus2["NOT_ALLOWED"] = 8] = "NOT_ALLOWED";
117
+ DLRStatus2[DLRStatus2["STATUS_UNKNOWN_24H"] = 11] = "STATUS_UNKNOWN_24H";
118
+ DLRStatus2[DLRStatus2["STATUS_UNKNOWN_CODE"] = 12] = "STATUS_UNKNOWN_CODE";
119
+ DLRStatus2[DLRStatus2["STATUS_UNKNOWN_72H"] = 13] = "STATUS_UNKNOWN_72H";
120
+ return DLRStatus2;
121
+ })(DLRStatus || {});
122
+ var DLR_STATUS_MESSAGES = {
123
+ [0 /* SENT_NO_STATUS */]: "Message is sent, no status yet",
124
+ [1 /* DELIVERED */]: "Message is delivered",
125
+ [2 /* NOT_SENT */]: "Message is not sent",
126
+ [3 /* DELIVERY_FAILED */]: "Message delivery failed",
127
+ [4 /* SENT */]: "Message is sent",
128
+ [5 /* EXPIRED */]: "Message expired",
129
+ [6 /* INVALID_DESTINATION */]: "Message has invalid destination address",
130
+ [7 /* SMSC_ERROR */]: "SMSC error, message could not be processed",
131
+ [8 /* NOT_ALLOWED */]: "Message is not allowed",
132
+ [11 /* STATUS_UNKNOWN_24H */]: "Message status unknown, usually after 24 hours without status update from SMSC",
133
+ [12 /* STATUS_UNKNOWN_CODE */]: "Message status unknown, SMSC received unknown status code",
134
+ [13 /* STATUS_UNKNOWN_72H */]: "Message status unknown, no status update received from SMSC after 72 hours"
135
+ };
136
+
137
+ // src/errors.ts
138
+ var BudgetSMSError = class _BudgetSMSError extends Error {
139
+ /**
140
+ * Creates a new BudgetSMSError
141
+ * @param code - The BudgetSMS error code
142
+ * @param message - Optional custom error message (defaults to standard message for the code)
143
+ */
144
+ constructor(code, message) {
145
+ super(message || ERROR_MESSAGES[code] || `BudgetSMS API error: ${code}`);
146
+ this.code = code;
147
+ this.name = "BudgetSMSError";
148
+ if (Error.captureStackTrace) {
149
+ Error.captureStackTrace(this, _BudgetSMSError);
150
+ }
151
+ }
152
+ /**
153
+ * Returns true if the error code indicates a temporary/retryable error
154
+ */
155
+ isRetryable() {
156
+ return [
157
+ 4002 /* SYSTEM_ERROR_TEMPORARY */,
158
+ 4003 /* SYSTEM_ERROR_TEMPORARY_2 */,
159
+ 4006 /* GATEWAY_NOT_REACHABLE */
160
+ ].includes(this.code);
161
+ }
162
+ /**
163
+ * Returns true if the error code indicates an authentication/credentials issue
164
+ */
165
+ isAuthenticationError() {
166
+ return [
167
+ 1002 /* INVALID_CREDENTIALS */,
168
+ 1003 /* ACCOUNT_NOT_ACTIVE */,
169
+ 1004 /* IP_NOT_ALLOWED */,
170
+ 1005 /* NO_HANDLE_PROVIDED */,
171
+ 1006 /* NO_USERID_PROVIDED */,
172
+ 1007 /* NO_USERNAME_PROVIDED */
173
+ ].includes(this.code);
174
+ }
175
+ /**
176
+ * Returns true if the error code indicates insufficient credits
177
+ */
178
+ isInsufficientCredits() {
179
+ return this.code === 1001 /* NOT_ENOUGH_CREDITS */;
180
+ }
181
+ /**
182
+ * Convert error to JSON for logging/serialization
183
+ */
184
+ toJSON() {
185
+ return {
186
+ name: this.name,
187
+ code: this.code,
188
+ message: this.message,
189
+ stack: this.stack
190
+ };
191
+ }
192
+ };
193
+
194
+ // src/utils.ts
195
+ function buildQueryString(params) {
196
+ const pairs = [];
197
+ for (const [key, value] of Object.entries(params)) {
198
+ if (value !== void 0 && value !== null) {
199
+ const stringValue = typeof value === "boolean" ? value ? "1" : "0" : String(value);
200
+ pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(stringValue)}`);
201
+ }
202
+ }
203
+ return pairs.join("&");
204
+ }
205
+ function parseResponse(response) {
206
+ const trimmed = response.trim();
207
+ if (trimmed.startsWith("ERR ")) {
208
+ const errorCode = parseInt(trimmed.substring(4), 10);
209
+ if (isNaN(errorCode)) {
210
+ throw new Error(`Invalid error response format: ${trimmed}`);
211
+ }
212
+ throw new BudgetSMSError(errorCode);
213
+ }
214
+ if (trimmed.startsWith("OK ")) {
215
+ return trimmed.substring(3).trim();
216
+ }
217
+ if (trimmed === "OK") {
218
+ return "";
219
+ }
220
+ throw new Error(`Unexpected API response format: ${trimmed}`);
221
+ }
222
+ function parseSendSMSResponse(response, includePrice, includeMccMnc, includeCredit) {
223
+ const data = parseResponse(response);
224
+ const parts = data.split(/\s+/);
225
+ if (parts.length === 0) {
226
+ throw new Error("Invalid send SMS response: no SMS ID found");
227
+ }
228
+ const result = {
229
+ success: true,
230
+ smsId: parts[0]
231
+ };
232
+ let index = 1;
233
+ if (includePrice && parts.length > index + 1) {
234
+ result.price = parseFloat(parts[index]);
235
+ result.parts = parseInt(parts[index + 1], 10);
236
+ index += 2;
237
+ }
238
+ if (includeMccMnc && parts.length > index) {
239
+ result.mccMnc = parts[index];
240
+ index += 1;
241
+ }
242
+ if (includeCredit && parts.length > index) {
243
+ result.credit = parseFloat(parts[index]);
244
+ }
245
+ return result;
246
+ }
247
+ function parseCheckCreditResponse(response) {
248
+ const data = parseResponse(response);
249
+ const credit = parseFloat(data);
250
+ if (isNaN(credit)) {
251
+ throw new Error(`Invalid credit response: ${data}`);
252
+ }
253
+ return {
254
+ success: true,
255
+ credit
256
+ };
257
+ }
258
+ function parseOperatorResponse(response) {
259
+ const data = parseResponse(response);
260
+ const parts = data.split(":");
261
+ if (parts.length < 3) {
262
+ throw new Error(`Invalid operator response format: ${data}`);
263
+ }
264
+ return {
265
+ success: true,
266
+ mccMnc: parts[0],
267
+ operatorName: parts[1],
268
+ messageCost: parseFloat(parts[2])
269
+ };
270
+ }
271
+ function parseSMSStatusResponse(response, smsId) {
272
+ const data = parseResponse(response);
273
+ const status = parseInt(data, 10);
274
+ if (isNaN(status)) {
275
+ throw new Error(`Invalid status response: ${data}`);
276
+ }
277
+ return {
278
+ success: true,
279
+ smsId,
280
+ status
281
+ };
282
+ }
283
+ function parsePricingResponse(response) {
284
+ if (response.trim().startsWith("ERR ")) {
285
+ parseResponse(response);
286
+ }
287
+ try {
288
+ const pricing = JSON.parse(response);
289
+ if (!Array.isArray(pricing)) {
290
+ throw new Error("Pricing response is not an array");
291
+ }
292
+ return pricing;
293
+ } catch (error) {
294
+ if (error instanceof BudgetSMSError) {
295
+ throw error;
296
+ }
297
+ throw new Error(`Failed to parse pricing response: ${error instanceof Error ? error.message : "Unknown error"}`);
298
+ }
299
+ }
300
+ function validatePhoneNumber(phoneNumber) {
301
+ return /^\d{8,16}$/.test(phoneNumber);
302
+ }
303
+ function validateSender(sender) {
304
+ if (/^[a-zA-Z0-9]{1,11}$/.test(sender)) {
305
+ return true;
306
+ }
307
+ if (/^\d{1,16}$/.test(sender)) {
308
+ return true;
309
+ }
310
+ return false;
311
+ }
312
+ function validateMessage(message) {
313
+ return message.length > 0 && message.length <= 612;
314
+ }
315
+
316
+ // src/client.ts
317
+ var BudgetSMS = class {
318
+ username;
319
+ userid;
320
+ handle;
321
+ baseUrl;
322
+ timeout;
323
+ /**
324
+ * Create a new BudgetSMS client
325
+ * @param config - Configuration object with credentials and optional settings
326
+ */
327
+ constructor(config) {
328
+ this.username = config.username;
329
+ this.userid = config.userid;
330
+ this.handle = config.handle;
331
+ this.baseUrl = config.baseUrl || API_BASE;
332
+ this.timeout = config.timeout || 3e4;
333
+ }
334
+ /**
335
+ * Make an HTTP GET request to the API
336
+ * @param endpoint - API endpoint path
337
+ * @param params - Query parameters
338
+ * @returns Response text
339
+ */
340
+ async request(endpoint, params = {}) {
341
+ const queryString = buildQueryString(params);
342
+ const url = `${this.baseUrl}${endpoint}?${queryString}`;
343
+ const controller = new AbortController();
344
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
345
+ try {
346
+ const response = await fetch(url, {
347
+ method: "GET",
348
+ signal: controller.signal
349
+ });
350
+ if (!response.ok) {
351
+ throw new Error(`HTTP error! status: ${response.status}`);
352
+ }
353
+ return await response.text();
354
+ } catch (error) {
355
+ if (error instanceof Error && error.name === "AbortError") {
356
+ throw new Error(`Request timeout after ${this.timeout}ms`);
357
+ }
358
+ throw error;
359
+ } finally {
360
+ clearTimeout(timeoutId);
361
+ }
362
+ }
363
+ /**
364
+ * Get base authentication parameters
365
+ */
366
+ getAuthParams() {
367
+ return {
368
+ username: this.username,
369
+ userid: this.userid,
370
+ handle: this.handle
371
+ };
372
+ }
373
+ /**
374
+ * Send an SMS message
375
+ *
376
+ * @param params - SMS parameters
377
+ * @returns Promise resolving to SendSMSResponse
378
+ * @throws {BudgetSMSError} If the API returns an error
379
+ *
380
+ * @example
381
+ * ```typescript
382
+ * const result = await client.sendSMS({
383
+ * msg: 'Hello World!',
384
+ * from: 'YourApp',
385
+ * to: '31612345678',
386
+ * price: true, // Get price info in response
387
+ * mccmnc: true // Get operator info in response
388
+ * });
389
+ *
390
+ * console.log(`SMS sent with ID: ${result.smsId}`);
391
+ * if (result.price) {
392
+ * console.log(`Cost: €${result.price} for ${result.parts} part(s)`);
393
+ * }
394
+ * ```
395
+ */
396
+ async sendSMS(params) {
397
+ const requestParams = {
398
+ ...this.getAuthParams(),
399
+ msg: params.msg,
400
+ from: params.from,
401
+ to: params.to,
402
+ customid: params.customid,
403
+ price: params.price,
404
+ mccmnc: params.mccmnc,
405
+ credit: params.credit
406
+ };
407
+ const response = await this.request(ENDPOINTS.SEND_SMS, requestParams);
408
+ return parseSendSMSResponse(response, params.price, params.mccmnc, params.credit);
409
+ }
410
+ /**
411
+ * Test SMS sending without actually sending or reducing credit
412
+ *
413
+ * Useful for testing your implementation without consuming credits.
414
+ *
415
+ * @param params - SMS parameters (same as sendSMS)
416
+ * @returns Promise resolving to TestSMSResponse
417
+ * @throws {BudgetSMSError} If the API returns an error
418
+ *
419
+ * @example
420
+ * ```typescript
421
+ * const result = await client.testSMS({
422
+ * msg: 'Test message',
423
+ * from: 'TestApp',
424
+ * to: '31612345678'
425
+ * });
426
+ *
427
+ * console.log(`Test successful, would get SMS ID: ${result.smsId}`);
428
+ * ```
429
+ */
430
+ async testSMS(params) {
431
+ const requestParams = {
432
+ ...this.getAuthParams(),
433
+ msg: params.msg,
434
+ from: params.from,
435
+ to: params.to,
436
+ customid: params.customid,
437
+ price: params.price,
438
+ mccmnc: params.mccmnc,
439
+ credit: params.credit
440
+ };
441
+ const response = await this.request(ENDPOINTS.TEST_SMS, requestParams);
442
+ return parseSendSMSResponse(response, params.price, params.mccmnc, params.credit);
443
+ }
444
+ /**
445
+ * Check remaining account credit
446
+ *
447
+ * @returns Promise resolving to CheckCreditResponse
448
+ * @throws {BudgetSMSError} If the API returns an error
449
+ *
450
+ * @example
451
+ * ```typescript
452
+ * const result = await client.checkCredit();
453
+ * console.log(`Remaining credit: €${result.credit}`);
454
+ * ```
455
+ */
456
+ async checkCredit() {
457
+ const response = await this.request(ENDPOINTS.CHECK_CREDIT, this.getAuthParams());
458
+ return parseCheckCreditResponse(response);
459
+ }
460
+ /**
461
+ * Check operator based on phone number prefix
462
+ *
463
+ * Note: This checks the original operator based on prefix.
464
+ * If a number has been ported, use hlr() instead.
465
+ *
466
+ * @param phoneNumber - Phone number to check (international format, no +)
467
+ * @returns Promise resolving to OperatorResponse
468
+ * @throws {BudgetSMSError} If the API returns an error
469
+ *
470
+ * @example
471
+ * ```typescript
472
+ * const result = await client.checkOperator('31612345678');
473
+ * console.log(`Operator: ${result.operatorName} (${result.mccMnc})`);
474
+ * console.log(`Cost: €${result.messageCost}`);
475
+ * ```
476
+ */
477
+ async checkOperator(phoneNumber) {
478
+ const requestParams = {
479
+ ...this.getAuthParams(),
480
+ check: phoneNumber
481
+ };
482
+ const response = await this.request(ENDPOINTS.CHECK_OPERATOR, requestParams);
483
+ return parseOperatorResponse(response);
484
+ }
485
+ /**
486
+ * Perform HLR (Home Location Register) lookup
487
+ *
488
+ * Returns the actual current operator, even if the number has been ported.
489
+ * More accurate than checkOperator() but may cost credits.
490
+ *
491
+ * @param phoneNumber - Phone number to lookup (international format, no +)
492
+ * @returns Promise resolving to HLRResponse
493
+ * @throws {BudgetSMSError} If the API returns an error
494
+ *
495
+ * @example
496
+ * ```typescript
497
+ * const result = await client.hlr('31612345678');
498
+ * console.log(`Current operator: ${result.operatorName}`);
499
+ * console.log(`Network: ${result.mccMnc}`);
500
+ * ```
501
+ */
502
+ async hlr(phoneNumber) {
503
+ const requestParams = {
504
+ ...this.getAuthParams(),
505
+ to: phoneNumber
506
+ };
507
+ const response = await this.request(ENDPOINTS.HLR, requestParams);
508
+ return parseOperatorResponse(response);
509
+ }
510
+ /**
511
+ * Check SMS delivery status (Pull DLR)
512
+ *
513
+ * Retrieve the current delivery status of a sent message.
514
+ * For automatic updates, consider using Push DLR instead.
515
+ *
516
+ * @param smsId - The SMS ID returned from sendSMS()
517
+ * @returns Promise resolving to SMSStatusResponse
518
+ * @throws {BudgetSMSError} If the API returns an error
519
+ *
520
+ * @example
521
+ * ```typescript
522
+ * const result = await client.checkSMS('12345678');
523
+ * console.log(`Status: ${result.status}`); // DLRStatus enum value
524
+ * ```
525
+ */
526
+ async checkSMS(smsId) {
527
+ const requestParams = {
528
+ ...this.getAuthParams(),
529
+ smsid: smsId
530
+ };
531
+ const response = await this.request(ENDPOINTS.CHECK_SMS, requestParams);
532
+ return parseSMSStatusResponse(response, smsId);
533
+ }
534
+ /**
535
+ * Get account pricing for all operators
536
+ *
537
+ * Returns a comprehensive list of pricing for all available operators.
538
+ * Each entry includes country, operator, MCC/MNC codes, and pricing info.
539
+ *
540
+ * @returns Promise resolving to GetPricingResponse (array of pricing entries)
541
+ * @throws {BudgetSMSError} If the API returns an error
542
+ *
543
+ * @example
544
+ * ```typescript
545
+ * const pricing = await client.getPricing();
546
+ * for (const entry of pricing) {
547
+ * console.log(`${entry.countryname} - ${entry.operatorname}: €${entry.price}`);
548
+ * }
549
+ * ```
550
+ */
551
+ async getPricing() {
552
+ const response = await this.request(ENDPOINTS.GET_PRICING, this.getAuthParams());
553
+ return parsePricingResponse(response);
554
+ }
555
+ };
556
+
557
+ exports.API_BASE = API_BASE;
558
+ exports.BudgetSMS = BudgetSMS;
559
+ exports.BudgetSMSError = BudgetSMSError;
560
+ exports.BudgetSMSErrorCode = BudgetSMSErrorCode;
561
+ exports.DLRStatus = DLRStatus;
562
+ exports.DLR_STATUS_MESSAGES = DLR_STATUS_MESSAGES;
563
+ exports.ENDPOINTS = ENDPOINTS;
564
+ exports.ERROR_MESSAGES = ERROR_MESSAGES;
565
+ exports.validateMessage = validateMessage;
566
+ exports.validatePhoneNumber = validatePhoneNumber;
567
+ exports.validateSender = validateSender;
568
+ //# sourceMappingURL=index.cjs.map
569
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/constants.ts","../src/errors.ts","../src/utils.ts","../src/client.ts"],"names":["BudgetSMSErrorCode","DLRStatus"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * BudgetSMS API Base URL and Endpoints\n */\nexport const API_BASE = 'https://api.budgetsms.net';\n\nexport const ENDPOINTS = {\n SEND_SMS: '/sendsms/',\n TEST_SMS: '/testsms/',\n CHECK_CREDIT: '/checkcredit/',\n CHECK_OPERATOR: '/checkoperator/',\n HLR: '/hlr/',\n CHECK_SMS: '/checksms/',\n GET_PRICING: '/getpricing/',\n} as const;\n\n/**\n * BudgetSMS API Error Codes\n * Source: HTTP API Specification V2.7, Chapter 11\n */\nexport enum BudgetSMSErrorCode {\n // Authentication & Account Errors (1xxx)\n NOT_ENOUGH_CREDITS = 1001,\n INVALID_CREDENTIALS = 1002,\n ACCOUNT_NOT_ACTIVE = 1003,\n IP_NOT_ALLOWED = 1004,\n NO_HANDLE_PROVIDED = 1005,\n NO_USERID_PROVIDED = 1006,\n NO_USERNAME_PROVIDED = 1007,\n\n // SMS Message Errors (2xxx)\n SMS_TEXT_EMPTY = 2001,\n SMS_NUMERIC_SENDER_TOO_LONG = 2002,\n SMS_ALPHANUMERIC_SENDER_TOO_LONG = 2003,\n SMS_SENDER_EMPTY_OR_INVALID = 2004,\n DESTINATION_TOO_SHORT = 2005,\n DESTINATION_NOT_NUMERIC = 2006,\n DESTINATION_EMPTY = 2007,\n SMS_TEXT_NOT_OK = 2008,\n PARAMETER_ISSUE = 2009,\n DESTINATION_INVALIDLY_FORMATTED = 2010,\n DESTINATION_INVALID = 2011,\n SMS_TEXT_TOO_LONG = 2012,\n SMS_MESSAGE_INVALID = 2013,\n CUSTOM_ID_ALREADY_USED = 2014,\n CHARSET_PROBLEM = 2015,\n INVALID_UTF8_ENCODING = 2016,\n INVALID_SMS_ID = 2017,\n\n // Routing Errors (3xxx)\n NO_ROUTE_TO_DESTINATION = 3001,\n NO_ROUTES_SETUP = 3002,\n INVALID_DESTINATION = 3003,\n\n // System Errors (4xxx)\n SYSTEM_ERROR_CUSTOM_ID = 4001,\n SYSTEM_ERROR_TEMPORARY = 4002,\n SYSTEM_ERROR_TEMPORARY_2 = 4003,\n SYSTEM_ERROR_CONTACT_SUPPORT = 4004,\n SYSTEM_ERROR_PERMANENT = 4005,\n GATEWAY_NOT_REACHABLE = 4006,\n SYSTEM_ERROR_CONTACT_SUPPORT_2 = 4007,\n\n // Send Errors (5xxx)\n SEND_ERROR = 5001,\n WRONG_SMS_TYPE = 5002,\n WRONG_OPERATOR = 5003,\n\n // Unknown Error (6xxx)\n UNKNOWN_ERROR = 6001,\n\n // HLR Errors (7xxx)\n NO_HLR_PROVIDER = 7001,\n UNEXPECTED_HLR_RESULTS = 7002,\n BAD_NUMBER_FORMAT = 7003,\n HLR_UNEXPECTED_ERROR = 7901,\n HLR_PROVIDER_ERROR = 7902,\n HLR_PROVIDER_ERROR_2 = 7903,\n}\n\n/**\n * Error code descriptions for better error messages\n */\nexport const ERROR_MESSAGES: Record<BudgetSMSErrorCode, string> = {\n [BudgetSMSErrorCode.NOT_ENOUGH_CREDITS]: 'Not enough credits to send messages',\n [BudgetSMSErrorCode.INVALID_CREDENTIALS]: 'Identification failed. Wrong credentials',\n [BudgetSMSErrorCode.ACCOUNT_NOT_ACTIVE]: 'Account not active, contact BudgetSMS',\n [BudgetSMSErrorCode.IP_NOT_ALLOWED]: 'This IP address is not added to this account. No access to the API',\n [BudgetSMSErrorCode.NO_HANDLE_PROVIDED]: 'No handle provided',\n [BudgetSMSErrorCode.NO_USERID_PROVIDED]: 'No UserID provided',\n [BudgetSMSErrorCode.NO_USERNAME_PROVIDED]: 'No Username provided',\n\n [BudgetSMSErrorCode.SMS_TEXT_EMPTY]: 'SMS message text is empty',\n [BudgetSMSErrorCode.SMS_NUMERIC_SENDER_TOO_LONG]: 'SMS numeric senderid can be max. 16 numbers',\n [BudgetSMSErrorCode.SMS_ALPHANUMERIC_SENDER_TOO_LONG]: 'SMS alphanumeric sender can be max. 11 characters',\n [BudgetSMSErrorCode.SMS_SENDER_EMPTY_OR_INVALID]: 'SMS senderid is empty or invalid',\n [BudgetSMSErrorCode.DESTINATION_TOO_SHORT]: 'Destination number is too short',\n [BudgetSMSErrorCode.DESTINATION_NOT_NUMERIC]: 'Destination is not numeric',\n [BudgetSMSErrorCode.DESTINATION_EMPTY]: 'Destination is empty',\n [BudgetSMSErrorCode.SMS_TEXT_NOT_OK]: 'SMS text is not OK (check encoding?)',\n [BudgetSMSErrorCode.PARAMETER_ISSUE]: 'Parameter issue (check all mandatory parameters, encoding, etc.)',\n [BudgetSMSErrorCode.DESTINATION_INVALIDLY_FORMATTED]: 'Destination number is invalidly formatted',\n [BudgetSMSErrorCode.DESTINATION_INVALID]: 'Destination is invalid',\n [BudgetSMSErrorCode.SMS_TEXT_TOO_LONG]: 'SMS message text is too long',\n [BudgetSMSErrorCode.SMS_MESSAGE_INVALID]: 'SMS message is invalid',\n [BudgetSMSErrorCode.CUSTOM_ID_ALREADY_USED]: 'SMS CustomID is used before',\n [BudgetSMSErrorCode.CHARSET_PROBLEM]: 'Charset problem',\n [BudgetSMSErrorCode.INVALID_UTF8_ENCODING]: 'Invalid UTF-8 encoding',\n [BudgetSMSErrorCode.INVALID_SMS_ID]: 'Invalid SMSid',\n\n [BudgetSMSErrorCode.NO_ROUTE_TO_DESTINATION]: 'No route to destination. Contact BudgetSMS for possible solutions',\n [BudgetSMSErrorCode.NO_ROUTES_SETUP]: 'No routes are setup. Contact BudgetSMS for a route setup',\n [BudgetSMSErrorCode.INVALID_DESTINATION]: 'Invalid destination. Check international mobile number formatting',\n\n [BudgetSMSErrorCode.SYSTEM_ERROR_CUSTOM_ID]: 'System error, related to customID',\n [BudgetSMSErrorCode.SYSTEM_ERROR_TEMPORARY]: 'System error, temporary issue. Try resubmitting in 2 to 3 minutes',\n [BudgetSMSErrorCode.SYSTEM_ERROR_TEMPORARY_2]: 'System error, temporary issue',\n [BudgetSMSErrorCode.SYSTEM_ERROR_CONTACT_SUPPORT]: 'System error, temporary issue. Contact BudgetSMS',\n [BudgetSMSErrorCode.SYSTEM_ERROR_PERMANENT]: 'System error, permanent',\n [BudgetSMSErrorCode.GATEWAY_NOT_REACHABLE]: 'Gateway not reachable',\n [BudgetSMSErrorCode.SYSTEM_ERROR_CONTACT_SUPPORT_2]: 'System error, contact BudgetSMS',\n\n [BudgetSMSErrorCode.SEND_ERROR]: 'Send error, Contact BudgetSMS with the send details',\n [BudgetSMSErrorCode.WRONG_SMS_TYPE]: 'Wrong SMS type',\n [BudgetSMSErrorCode.WRONG_OPERATOR]: 'Wrong operator',\n\n [BudgetSMSErrorCode.UNKNOWN_ERROR]: 'Unknown error',\n\n [BudgetSMSErrorCode.NO_HLR_PROVIDER]: 'No HLR provider present, Contact BudgetSMS',\n [BudgetSMSErrorCode.UNEXPECTED_HLR_RESULTS]: 'Unexpected results from HLR provider',\n [BudgetSMSErrorCode.BAD_NUMBER_FORMAT]: 'Bad number format',\n [BudgetSMSErrorCode.HLR_UNEXPECTED_ERROR]: 'Unexpected error. Contact BudgetSMS',\n [BudgetSMSErrorCode.HLR_PROVIDER_ERROR]: 'HLR provider error. Contact BudgetSMS',\n [BudgetSMSErrorCode.HLR_PROVIDER_ERROR_2]: 'HLR provider error. Contact BudgetSMS',\n};\n\n/**\n * DLR (Delivery Report) Status Codes\n * Source: HTTP API Specification V2.7, Chapter 12\n */\nexport enum DLRStatus {\n /** Message is sent, no status yet (default) */\n SENT_NO_STATUS = 0,\n /** Message is delivered */\n DELIVERED = 1,\n /** Message is not sent */\n NOT_SENT = 2,\n /** Message delivery failed */\n DELIVERY_FAILED = 3,\n /** Message is sent */\n SENT = 4,\n /** Message expired */\n EXPIRED = 5,\n /** Message has a invalid destination address */\n INVALID_DESTINATION = 6,\n /** SMSC error, message could not be processed */\n SMSC_ERROR = 7,\n /** Message is not allowed */\n NOT_ALLOWED = 8,\n /** Message status unknown, usually after 24 hours without status update SMSC */\n STATUS_UNKNOWN_24H = 11,\n /** Message status unknown, SMSC received unknown status code */\n STATUS_UNKNOWN_CODE = 12,\n /** Message status unknown, no status update received from SMSC after 72 hours after submit */\n STATUS_UNKNOWN_72H = 13,\n}\n\n/**\n * DLR status descriptions for better understanding\n */\nexport const DLR_STATUS_MESSAGES: Record<DLRStatus, string> = {\n [DLRStatus.SENT_NO_STATUS]: 'Message is sent, no status yet',\n [DLRStatus.DELIVERED]: 'Message is delivered',\n [DLRStatus.NOT_SENT]: 'Message is not sent',\n [DLRStatus.DELIVERY_FAILED]: 'Message delivery failed',\n [DLRStatus.SENT]: 'Message is sent',\n [DLRStatus.EXPIRED]: 'Message expired',\n [DLRStatus.INVALID_DESTINATION]: 'Message has invalid destination address',\n [DLRStatus.SMSC_ERROR]: 'SMSC error, message could not be processed',\n [DLRStatus.NOT_ALLOWED]: 'Message is not allowed',\n [DLRStatus.STATUS_UNKNOWN_24H]: 'Message status unknown, usually after 24 hours without status update from SMSC',\n [DLRStatus.STATUS_UNKNOWN_CODE]: 'Message status unknown, SMSC received unknown status code',\n [DLRStatus.STATUS_UNKNOWN_72H]: 'Message status unknown, no status update received from SMSC after 72 hours',\n};\n","import { BudgetSMSErrorCode, ERROR_MESSAGES } from './constants';\n\n/**\n * Custom error class for BudgetSMS API errors\n */\nexport class BudgetSMSError extends Error {\n /**\n * Creates a new BudgetSMSError\n * @param code - The BudgetSMS error code\n * @param message - Optional custom error message (defaults to standard message for the code)\n */\n constructor(\n public readonly code: BudgetSMSErrorCode,\n message?: string\n ) {\n super(message || ERROR_MESSAGES[code] || `BudgetSMS API error: ${code}`);\n this.name = 'BudgetSMSError';\n\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, BudgetSMSError);\n }\n }\n\n /**\n * Returns true if the error code indicates a temporary/retryable error\n */\n isRetryable(): boolean {\n return [\n BudgetSMSErrorCode.SYSTEM_ERROR_TEMPORARY,\n BudgetSMSErrorCode.SYSTEM_ERROR_TEMPORARY_2,\n BudgetSMSErrorCode.GATEWAY_NOT_REACHABLE,\n ].includes(this.code);\n }\n\n /**\n * Returns true if the error code indicates an authentication/credentials issue\n */\n isAuthenticationError(): boolean {\n return [\n BudgetSMSErrorCode.INVALID_CREDENTIALS,\n BudgetSMSErrorCode.ACCOUNT_NOT_ACTIVE,\n BudgetSMSErrorCode.IP_NOT_ALLOWED,\n BudgetSMSErrorCode.NO_HANDLE_PROVIDED,\n BudgetSMSErrorCode.NO_USERID_PROVIDED,\n BudgetSMSErrorCode.NO_USERNAME_PROVIDED,\n ].includes(this.code);\n }\n\n /**\n * Returns true if the error code indicates insufficient credits\n */\n isInsufficientCredits(): boolean {\n return this.code === BudgetSMSErrorCode.NOT_ENOUGH_CREDITS;\n }\n\n /**\n * Convert error to JSON for logging/serialization\n */\n toJSON() {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n stack: this.stack,\n };\n }\n}\n","import { BudgetSMSError } from './errors';\nimport { BudgetSMSErrorCode, DLRStatus } from './constants';\nimport type {\n APIRequestParams,\n SendSMSResponse,\n CheckCreditResponse,\n OperatorResponse,\n SMSStatusResponse,\n GetPricingResponse,\n} from './types';\n\n/**\n * Build a query string from parameters with proper UTF-8 URL encoding\n * @param params - Object containing query parameters\n * @returns URL-encoded query string\n */\nexport function buildQueryString(params: APIRequestParams): string {\n const pairs: string[] = [];\n\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n // Convert booleans to 1/0 as expected by the API\n const stringValue = typeof value === 'boolean' ? (value ? '1' : '0') : String(value);\n pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(stringValue)}`);\n }\n }\n\n return pairs.join('&');\n}\n\n/**\n * Parse a basic API response (OK/ERR format)\n * @param response - Raw response text from API\n * @returns Parsed response data or throws BudgetSMSError\n */\nexport function parseResponse(response: string): string {\n const trimmed = response.trim();\n\n // Check for error response\n if (trimmed.startsWith('ERR ')) {\n const errorCode = parseInt(trimmed.substring(4), 10);\n if (isNaN(errorCode)) {\n throw new Error(`Invalid error response format: ${trimmed}`);\n }\n throw new BudgetSMSError(errorCode as BudgetSMSErrorCode);\n }\n\n // Check for success response\n if (trimmed.startsWith('OK ')) {\n return trimmed.substring(3).trim();\n }\n\n if (trimmed === 'OK') {\n return '';\n }\n\n throw new Error(`Unexpected API response format: ${trimmed}`);\n}\n\n/**\n * Parse Send SMS response with optional price and mccmnc data\n * Format: \"OK smsId [price parts] [mccMnc]\"\n * @param response - Raw response text from API\n * @param includePrice - Whether price info was requested\n * @param includeMccMnc - Whether mccmnc info was requested\n * @param includeCredit - Whether credit info was requested\n * @returns Parsed SendSMSResponse object\n */\nexport function parseSendSMSResponse(\n response: string,\n includePrice?: boolean,\n includeMccMnc?: boolean,\n includeCredit?: boolean\n): SendSMSResponse {\n const data = parseResponse(response);\n const parts = data.split(/\\s+/);\n\n if (parts.length === 0) {\n throw new Error('Invalid send SMS response: no SMS ID found');\n }\n\n const result: SendSMSResponse = {\n success: true,\n smsId: parts[0],\n };\n\n let index = 1;\n\n // Parse price and parts if requested\n if (includePrice && parts.length > index + 1) {\n result.price = parseFloat(parts[index]);\n result.parts = parseInt(parts[index + 1], 10);\n index += 2;\n }\n\n // Parse mccMnc if requested\n if (includeMccMnc && parts.length > index) {\n result.mccMnc = parts[index];\n index += 1;\n }\n\n // Parse credit if requested\n if (includeCredit && parts.length > index) {\n result.credit = parseFloat(parts[index]);\n }\n\n return result;\n}\n\n/**\n * Parse check credit response\n * Format: \"OK credit\"\n * @param response - Raw response text from API\n * @returns Parsed CheckCreditResponse object\n */\nexport function parseCheckCreditResponse(response: string): CheckCreditResponse {\n const data = parseResponse(response);\n const credit = parseFloat(data);\n\n if (isNaN(credit)) {\n throw new Error(`Invalid credit response: ${data}`);\n }\n\n return {\n success: true,\n credit,\n };\n}\n\n/**\n * Parse operator or HLR response\n * Format: \"OK:mccMnc:operatorName:messageCost\"\n * @param response - Raw response text from API\n * @returns Parsed OperatorResponse object\n */\nexport function parseOperatorResponse(response: string): OperatorResponse {\n const data = parseResponse(response);\n const parts = data.split(':');\n\n if (parts.length < 3) {\n throw new Error(`Invalid operator response format: ${data}`);\n }\n\n return {\n success: true,\n mccMnc: parts[0],\n operatorName: parts[1],\n messageCost: parseFloat(parts[2]),\n };\n}\n\n/**\n * Parse SMS status check response\n * Format: \"OK status\"\n * @param response - Raw response text from API\n * @param smsId - The SMS ID that was checked\n * @returns Parsed SMSStatusResponse object\n */\nexport function parseSMSStatusResponse(response: string, smsId: string): SMSStatusResponse {\n const data = parseResponse(response);\n const status = parseInt(data, 10);\n\n if (isNaN(status)) {\n throw new Error(`Invalid status response: ${data}`);\n }\n\n return {\n success: true,\n smsId,\n status: status as DLRStatus,\n };\n}\n\n/**\n * Parse pricing response (JSON format)\n * @param response - Raw JSON response from API\n * @returns Parsed GetPricingResponse array\n */\nexport function parsePricingResponse(response: string): GetPricingResponse {\n // Check for error response first\n if (response.trim().startsWith('ERR ')) {\n parseResponse(response); // This will throw the appropriate error\n }\n\n try {\n const pricing = JSON.parse(response);\n if (!Array.isArray(pricing)) {\n throw new Error('Pricing response is not an array');\n }\n return pricing;\n } catch (error) {\n if (error instanceof BudgetSMSError) {\n throw error;\n }\n throw new Error(`Failed to parse pricing response: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n}\n\n/**\n * Validate phone number format (basic MSISDN validation)\n * @param phoneNumber - Phone number to validate\n * @returns true if valid, false otherwise\n */\nexport function validatePhoneNumber(phoneNumber: string): boolean {\n // Must be numeric and between 8-16 digits\n return /^\\d{8,16}$/.test(phoneNumber);\n}\n\n/**\n * Validate sender ID format\n * @param sender - Sender ID to validate\n * @returns true if valid, false otherwise\n */\nexport function validateSender(sender: string): boolean {\n // Alphanumeric: max 11 characters [a-zA-Z0-9]\n if (/^[a-zA-Z0-9]{1,11}$/.test(sender)) {\n return true;\n }\n\n // Numeric: max 16 digits\n if (/^\\d{1,16}$/.test(sender)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Validate message text\n * @param message - Message text to validate\n * @returns true if valid, false otherwise\n */\nexport function validateMessage(message: string): boolean {\n // Must not be empty and should be reasonable length (max 612 chars for 4 SMS parts)\n return message.length > 0 && message.length <= 612;\n}\n","import { API_BASE, ENDPOINTS } from './constants';\nimport type {\n BudgetSMSConfig,\n SendSMSParams,\n TestSMSParams,\n SendSMSResponse,\n TestSMSResponse,\n CheckCreditResponse,\n OperatorResponse,\n HLRResponse,\n SMSStatusResponse,\n GetPricingResponse,\n APIRequestParams,\n} from './types';\nimport {\n buildQueryString,\n parseSendSMSResponse,\n parseCheckCreditResponse,\n parseOperatorResponse,\n parseSMSStatusResponse,\n parsePricingResponse,\n} from './utils';\n\n/**\n * BudgetSMS API Client\n *\n * A modern, type-safe client for the BudgetSMS.net HTTP API.\n * Supports all API endpoints with proper error handling and response parsing.\n *\n * @example\n * ```typescript\n * const client = new BudgetSMS({\n * username: 'your-username',\n * userid: 'your-userid',\n * handle: 'your-api-handle'\n * });\n *\n * // Send an SMS\n * const result = await client.sendSMS({\n * msg: 'Hello World!',\n * from: 'YourApp',\n * to: '31612345678'\n * });\n * ```\n */\nexport class BudgetSMS {\n private readonly username: string;\n private readonly userid: string;\n private readonly handle: string;\n private readonly baseUrl: string;\n private readonly timeout: number;\n\n /**\n * Create a new BudgetSMS client\n * @param config - Configuration object with credentials and optional settings\n */\n constructor(config: BudgetSMSConfig) {\n this.username = config.username;\n this.userid = config.userid;\n this.handle = config.handle;\n this.baseUrl = config.baseUrl || API_BASE;\n this.timeout = config.timeout || 30000;\n }\n\n /**\n * Make an HTTP GET request to the API\n * @param endpoint - API endpoint path\n * @param params - Query parameters\n * @returns Response text\n */\n private async request(endpoint: string, params: APIRequestParams = {}): Promise<string> {\n const queryString = buildQueryString(params);\n const url = `${this.baseUrl}${endpoint}?${queryString}`;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n return await response.text();\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`Request timeout after ${this.timeout}ms`);\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Get base authentication parameters\n */\n private getAuthParams(): APIRequestParams {\n return {\n username: this.username,\n userid: this.userid,\n handle: this.handle,\n };\n }\n\n /**\n * Send an SMS message\n *\n * @param params - SMS parameters\n * @returns Promise resolving to SendSMSResponse\n * @throws {BudgetSMSError} If the API returns an error\n *\n * @example\n * ```typescript\n * const result = await client.sendSMS({\n * msg: 'Hello World!',\n * from: 'YourApp',\n * to: '31612345678',\n * price: true, // Get price info in response\n * mccmnc: true // Get operator info in response\n * });\n *\n * console.log(`SMS sent with ID: ${result.smsId}`);\n * if (result.price) {\n * console.log(`Cost: €${result.price} for ${result.parts} part(s)`);\n * }\n * ```\n */\n async sendSMS(params: SendSMSParams): Promise<SendSMSResponse> {\n const requestParams: APIRequestParams = {\n ...this.getAuthParams(),\n msg: params.msg,\n from: params.from,\n to: params.to,\n customid: params.customid,\n price: params.price,\n mccmnc: params.mccmnc,\n credit: params.credit,\n };\n\n const response = await this.request(ENDPOINTS.SEND_SMS, requestParams);\n return parseSendSMSResponse(response, params.price, params.mccmnc, params.credit);\n }\n\n /**\n * Test SMS sending without actually sending or reducing credit\n *\n * Useful for testing your implementation without consuming credits.\n *\n * @param params - SMS parameters (same as sendSMS)\n * @returns Promise resolving to TestSMSResponse\n * @throws {BudgetSMSError} If the API returns an error\n *\n * @example\n * ```typescript\n * const result = await client.testSMS({\n * msg: 'Test message',\n * from: 'TestApp',\n * to: '31612345678'\n * });\n *\n * console.log(`Test successful, would get SMS ID: ${result.smsId}`);\n * ```\n */\n async testSMS(params: TestSMSParams): Promise<TestSMSResponse> {\n const requestParams: APIRequestParams = {\n ...this.getAuthParams(),\n msg: params.msg,\n from: params.from,\n to: params.to,\n customid: params.customid,\n price: params.price,\n mccmnc: params.mccmnc,\n credit: params.credit,\n };\n\n const response = await this.request(ENDPOINTS.TEST_SMS, requestParams);\n return parseSendSMSResponse(response, params.price, params.mccmnc, params.credit);\n }\n\n /**\n * Check remaining account credit\n *\n * @returns Promise resolving to CheckCreditResponse\n * @throws {BudgetSMSError} If the API returns an error\n *\n * @example\n * ```typescript\n * const result = await client.checkCredit();\n * console.log(`Remaining credit: €${result.credit}`);\n * ```\n */\n async checkCredit(): Promise<CheckCreditResponse> {\n const response = await this.request(ENDPOINTS.CHECK_CREDIT, this.getAuthParams());\n return parseCheckCreditResponse(response);\n }\n\n /**\n * Check operator based on phone number prefix\n *\n * Note: This checks the original operator based on prefix.\n * If a number has been ported, use hlr() instead.\n *\n * @param phoneNumber - Phone number to check (international format, no +)\n * @returns Promise resolving to OperatorResponse\n * @throws {BudgetSMSError} If the API returns an error\n *\n * @example\n * ```typescript\n * const result = await client.checkOperator('31612345678');\n * console.log(`Operator: ${result.operatorName} (${result.mccMnc})`);\n * console.log(`Cost: €${result.messageCost}`);\n * ```\n */\n async checkOperator(phoneNumber: string): Promise<OperatorResponse> {\n const requestParams: APIRequestParams = {\n ...this.getAuthParams(),\n check: phoneNumber,\n };\n\n const response = await this.request(ENDPOINTS.CHECK_OPERATOR, requestParams);\n return parseOperatorResponse(response);\n }\n\n /**\n * Perform HLR (Home Location Register) lookup\n *\n * Returns the actual current operator, even if the number has been ported.\n * More accurate than checkOperator() but may cost credits.\n *\n * @param phoneNumber - Phone number to lookup (international format, no +)\n * @returns Promise resolving to HLRResponse\n * @throws {BudgetSMSError} If the API returns an error\n *\n * @example\n * ```typescript\n * const result = await client.hlr('31612345678');\n * console.log(`Current operator: ${result.operatorName}`);\n * console.log(`Network: ${result.mccMnc}`);\n * ```\n */\n async hlr(phoneNumber: string): Promise<HLRResponse> {\n const requestParams: APIRequestParams = {\n ...this.getAuthParams(),\n to: phoneNumber,\n };\n\n const response = await this.request(ENDPOINTS.HLR, requestParams);\n return parseOperatorResponse(response);\n }\n\n /**\n * Check SMS delivery status (Pull DLR)\n *\n * Retrieve the current delivery status of a sent message.\n * For automatic updates, consider using Push DLR instead.\n *\n * @param smsId - The SMS ID returned from sendSMS()\n * @returns Promise resolving to SMSStatusResponse\n * @throws {BudgetSMSError} If the API returns an error\n *\n * @example\n * ```typescript\n * const result = await client.checkSMS('12345678');\n * console.log(`Status: ${result.status}`); // DLRStatus enum value\n * ```\n */\n async checkSMS(smsId: string): Promise<SMSStatusResponse> {\n const requestParams: APIRequestParams = {\n ...this.getAuthParams(),\n smsid: smsId,\n };\n\n const response = await this.request(ENDPOINTS.CHECK_SMS, requestParams);\n return parseSMSStatusResponse(response, smsId);\n }\n\n /**\n * Get account pricing for all operators\n *\n * Returns a comprehensive list of pricing for all available operators.\n * Each entry includes country, operator, MCC/MNC codes, and pricing info.\n *\n * @returns Promise resolving to GetPricingResponse (array of pricing entries)\n * @throws {BudgetSMSError} If the API returns an error\n *\n * @example\n * ```typescript\n * const pricing = await client.getPricing();\n * for (const entry of pricing) {\n * console.log(`${entry.countryname} - ${entry.operatorname}: €${entry.price}`);\n * }\n * ```\n */\n async getPricing(): Promise<GetPricingResponse> {\n const response = await this.request(ENDPOINTS.GET_PRICING, this.getAuthParams());\n return parsePricingResponse(response);\n }\n}\n"]}