@singularity-payments/core 0.1.0-alpha.4 → 0.1.0-alpha.5
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.d.mts +45 -16
- package/dist/index.d.ts +45 -16
- package/dist/index.js +166 -32
- package/dist/index.mjs +166 -32
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -262,17 +262,6 @@ interface DynamicQRResponse {
|
|
|
262
262
|
ResponseDescription: string;
|
|
263
263
|
QRCode: string;
|
|
264
264
|
}
|
|
265
|
-
interface C2BSimulateRequest {
|
|
266
|
-
amount: number;
|
|
267
|
-
msisdn: string;
|
|
268
|
-
billRefNumber: string;
|
|
269
|
-
commandID?: "CustomerPayBillOnline" | "CustomerBuyGoodsOnline";
|
|
270
|
-
}
|
|
271
|
-
interface C2BSimulateResponse {
|
|
272
|
-
ConversationID: string;
|
|
273
|
-
OriginatorCoversationID: string;
|
|
274
|
-
ResponseDescription: string;
|
|
275
|
-
}
|
|
276
265
|
|
|
277
266
|
interface ParsedCallbackData {
|
|
278
267
|
merchantRequestId: string;
|
|
@@ -305,6 +294,11 @@ interface CallbackHandlerOptions {
|
|
|
305
294
|
onCallback?: (data: ParsedCallbackData) => void | Promise<void>;
|
|
306
295
|
onC2BConfirmation?: (data: ParsedC2BCallback) => void | Promise<void>;
|
|
307
296
|
onC2BValidation?: (data: ParsedC2BCallback) => Promise<boolean>;
|
|
297
|
+
onB2CResult?: (data: any) => void | Promise<void>;
|
|
298
|
+
onB2BResult?: (data: any) => void | Promise<void>;
|
|
299
|
+
onAccountBalanceResult?: (data: any) => void | Promise<void>;
|
|
300
|
+
onTransactionStatusResult?: (data: any) => void | Promise<void>;
|
|
301
|
+
onReversalResult?: (data: any) => void | Promise<void>;
|
|
308
302
|
validateIp?: boolean;
|
|
309
303
|
allowedIps?: string[];
|
|
310
304
|
isDuplicate?: (CheckoutRequestID: string) => boolean | Promise<boolean>;
|
|
@@ -350,6 +344,26 @@ declare class MpesaCallbackHandler {
|
|
|
350
344
|
* Get a readable error message based on the code
|
|
351
345
|
*/
|
|
352
346
|
getErrorMessage(resultCode: number): string;
|
|
347
|
+
/**
|
|
348
|
+
* Handle B2C result callback
|
|
349
|
+
*/
|
|
350
|
+
handleB2CResult(callback: B2BCallback, ipAddress?: string): Promise<void>;
|
|
351
|
+
/**
|
|
352
|
+
* Handle B2B result callback
|
|
353
|
+
*/
|
|
354
|
+
handleB2BResult(callback: B2BCallback, ipAddress?: string): Promise<void>;
|
|
355
|
+
/**
|
|
356
|
+
* Handle Account Balance result callback
|
|
357
|
+
*/
|
|
358
|
+
handleAccountBalanceResult(callback: AccountBalanceCallback, ipAddress?: string): Promise<void>;
|
|
359
|
+
/**
|
|
360
|
+
* Handle Transaction Status result callback
|
|
361
|
+
*/
|
|
362
|
+
handleTransactionStatusResult(callback: TransactionStatusCallback, ipAddress?: string): Promise<void>;
|
|
363
|
+
/**
|
|
364
|
+
* Handle Reversal result callback
|
|
365
|
+
*/
|
|
366
|
+
handleReversalResult(callback: ReversalCallback, ipAddress?: string): Promise<void>;
|
|
353
367
|
/**
|
|
354
368
|
* Handle STK Push callback and invoke appropriate handlers
|
|
355
369
|
*/
|
|
@@ -548,11 +562,6 @@ declare class MpesaClient {
|
|
|
548
562
|
* Handle C2B validation request
|
|
549
563
|
*/
|
|
550
564
|
handleC2BValidation(callback: C2BCallback): Promise<object>;
|
|
551
|
-
/**
|
|
552
|
-
* Simulate C2B transaction (Sandbox only)
|
|
553
|
-
* Used for testing C2B payments in sandbox environment
|
|
554
|
-
*/
|
|
555
|
-
simulateC2B(request: C2BSimulateRequest): Promise<C2BSimulateResponse>;
|
|
556
565
|
/**
|
|
557
566
|
* B2C - Send money from business to customer
|
|
558
567
|
*/
|
|
@@ -593,6 +602,26 @@ declare class MpesaClient {
|
|
|
593
602
|
* Get configuration (for plugins)
|
|
594
603
|
*/
|
|
595
604
|
getConfig(): MpesaConfig;
|
|
605
|
+
/**
|
|
606
|
+
* Handle B2C result callback
|
|
607
|
+
*/
|
|
608
|
+
handleB2CResult(callback: B2BCallback, ipAddress?: string): Promise<object>;
|
|
609
|
+
/**
|
|
610
|
+
* Handle B2B result callback
|
|
611
|
+
*/
|
|
612
|
+
handleB2BResult(callback: B2BCallback, ipAddress?: string): Promise<object>;
|
|
613
|
+
/**
|
|
614
|
+
* Handle Account Balance result callback
|
|
615
|
+
*/
|
|
616
|
+
handleAccountBalanceResult(callback: AccountBalanceCallback, ipAddress?: string): Promise<object>;
|
|
617
|
+
/**
|
|
618
|
+
* Handle Transaction Status result callback
|
|
619
|
+
*/
|
|
620
|
+
handleTransactionStatusResult(callback: TransactionStatusCallback, ipAddress?: string): Promise<object>;
|
|
621
|
+
/**
|
|
622
|
+
* Handle Reversal result callback
|
|
623
|
+
*/
|
|
624
|
+
handleReversalResult(callback: ReversalCallback, ipAddress?: string): Promise<object>;
|
|
596
625
|
/**
|
|
597
626
|
* Get rate limiter usage for a key
|
|
598
627
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -262,17 +262,6 @@ interface DynamicQRResponse {
|
|
|
262
262
|
ResponseDescription: string;
|
|
263
263
|
QRCode: string;
|
|
264
264
|
}
|
|
265
|
-
interface C2BSimulateRequest {
|
|
266
|
-
amount: number;
|
|
267
|
-
msisdn: string;
|
|
268
|
-
billRefNumber: string;
|
|
269
|
-
commandID?: "CustomerPayBillOnline" | "CustomerBuyGoodsOnline";
|
|
270
|
-
}
|
|
271
|
-
interface C2BSimulateResponse {
|
|
272
|
-
ConversationID: string;
|
|
273
|
-
OriginatorCoversationID: string;
|
|
274
|
-
ResponseDescription: string;
|
|
275
|
-
}
|
|
276
265
|
|
|
277
266
|
interface ParsedCallbackData {
|
|
278
267
|
merchantRequestId: string;
|
|
@@ -305,6 +294,11 @@ interface CallbackHandlerOptions {
|
|
|
305
294
|
onCallback?: (data: ParsedCallbackData) => void | Promise<void>;
|
|
306
295
|
onC2BConfirmation?: (data: ParsedC2BCallback) => void | Promise<void>;
|
|
307
296
|
onC2BValidation?: (data: ParsedC2BCallback) => Promise<boolean>;
|
|
297
|
+
onB2CResult?: (data: any) => void | Promise<void>;
|
|
298
|
+
onB2BResult?: (data: any) => void | Promise<void>;
|
|
299
|
+
onAccountBalanceResult?: (data: any) => void | Promise<void>;
|
|
300
|
+
onTransactionStatusResult?: (data: any) => void | Promise<void>;
|
|
301
|
+
onReversalResult?: (data: any) => void | Promise<void>;
|
|
308
302
|
validateIp?: boolean;
|
|
309
303
|
allowedIps?: string[];
|
|
310
304
|
isDuplicate?: (CheckoutRequestID: string) => boolean | Promise<boolean>;
|
|
@@ -350,6 +344,26 @@ declare class MpesaCallbackHandler {
|
|
|
350
344
|
* Get a readable error message based on the code
|
|
351
345
|
*/
|
|
352
346
|
getErrorMessage(resultCode: number): string;
|
|
347
|
+
/**
|
|
348
|
+
* Handle B2C result callback
|
|
349
|
+
*/
|
|
350
|
+
handleB2CResult(callback: B2BCallback, ipAddress?: string): Promise<void>;
|
|
351
|
+
/**
|
|
352
|
+
* Handle B2B result callback
|
|
353
|
+
*/
|
|
354
|
+
handleB2BResult(callback: B2BCallback, ipAddress?: string): Promise<void>;
|
|
355
|
+
/**
|
|
356
|
+
* Handle Account Balance result callback
|
|
357
|
+
*/
|
|
358
|
+
handleAccountBalanceResult(callback: AccountBalanceCallback, ipAddress?: string): Promise<void>;
|
|
359
|
+
/**
|
|
360
|
+
* Handle Transaction Status result callback
|
|
361
|
+
*/
|
|
362
|
+
handleTransactionStatusResult(callback: TransactionStatusCallback, ipAddress?: string): Promise<void>;
|
|
363
|
+
/**
|
|
364
|
+
* Handle Reversal result callback
|
|
365
|
+
*/
|
|
366
|
+
handleReversalResult(callback: ReversalCallback, ipAddress?: string): Promise<void>;
|
|
353
367
|
/**
|
|
354
368
|
* Handle STK Push callback and invoke appropriate handlers
|
|
355
369
|
*/
|
|
@@ -548,11 +562,6 @@ declare class MpesaClient {
|
|
|
548
562
|
* Handle C2B validation request
|
|
549
563
|
*/
|
|
550
564
|
handleC2BValidation(callback: C2BCallback): Promise<object>;
|
|
551
|
-
/**
|
|
552
|
-
* Simulate C2B transaction (Sandbox only)
|
|
553
|
-
* Used for testing C2B payments in sandbox environment
|
|
554
|
-
*/
|
|
555
|
-
simulateC2B(request: C2BSimulateRequest): Promise<C2BSimulateResponse>;
|
|
556
565
|
/**
|
|
557
566
|
* B2C - Send money from business to customer
|
|
558
567
|
*/
|
|
@@ -593,6 +602,26 @@ declare class MpesaClient {
|
|
|
593
602
|
* Get configuration (for plugins)
|
|
594
603
|
*/
|
|
595
604
|
getConfig(): MpesaConfig;
|
|
605
|
+
/**
|
|
606
|
+
* Handle B2C result callback
|
|
607
|
+
*/
|
|
608
|
+
handleB2CResult(callback: B2BCallback, ipAddress?: string): Promise<object>;
|
|
609
|
+
/**
|
|
610
|
+
* Handle B2B result callback
|
|
611
|
+
*/
|
|
612
|
+
handleB2BResult(callback: B2BCallback, ipAddress?: string): Promise<object>;
|
|
613
|
+
/**
|
|
614
|
+
* Handle Account Balance result callback
|
|
615
|
+
*/
|
|
616
|
+
handleAccountBalanceResult(callback: AccountBalanceCallback, ipAddress?: string): Promise<object>;
|
|
617
|
+
/**
|
|
618
|
+
* Handle Transaction Status result callback
|
|
619
|
+
*/
|
|
620
|
+
handleTransactionStatusResult(callback: TransactionStatusCallback, ipAddress?: string): Promise<object>;
|
|
621
|
+
/**
|
|
622
|
+
* Handle Reversal result callback
|
|
623
|
+
*/
|
|
624
|
+
handleReversalResult(callback: ReversalCallback, ipAddress?: string): Promise<object>;
|
|
596
625
|
/**
|
|
597
626
|
* Get rate limiter usage for a key
|
|
598
627
|
*/
|
package/dist/index.js
CHANGED
|
@@ -419,6 +419,91 @@ var MpesaCallbackHandler = class {
|
|
|
419
419
|
};
|
|
420
420
|
return errorMessages[resultCode] || `Transaction failed with code: ${resultCode}`;
|
|
421
421
|
}
|
|
422
|
+
/**
|
|
423
|
+
* Handle B2C result callback
|
|
424
|
+
*/
|
|
425
|
+
async handleB2CResult(callback, ipAddress) {
|
|
426
|
+
if (ipAddress && !this.validateCallbackIp(ipAddress)) {
|
|
427
|
+
this.log("warn", `Invalid callback IP: ${ipAddress}`);
|
|
428
|
+
throw new Error(`Invalid callback IP: ${ipAddress}`);
|
|
429
|
+
}
|
|
430
|
+
const parsed = this.parseB2CCallback(callback);
|
|
431
|
+
this.log("info", "Processing B2C result", {
|
|
432
|
+
transactionId: parsed.transactionId,
|
|
433
|
+
isSuccess: parsed.isSuccess
|
|
434
|
+
});
|
|
435
|
+
if (this.options.onB2CResult) {
|
|
436
|
+
await this.options.onB2CResult(parsed);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Handle B2B result callback
|
|
441
|
+
*/
|
|
442
|
+
async handleB2BResult(callback, ipAddress) {
|
|
443
|
+
if (ipAddress && !this.validateCallbackIp(ipAddress)) {
|
|
444
|
+
this.log("warn", `Invalid callback IP: ${ipAddress}`);
|
|
445
|
+
throw new Error(`Invalid callback IP: ${ipAddress}`);
|
|
446
|
+
}
|
|
447
|
+
const parsed = this.parseB2BCallback(callback);
|
|
448
|
+
this.log("info", "Processing B2B result", {
|
|
449
|
+
transactionId: parsed.transactionId,
|
|
450
|
+
isSuccess: parsed.isSuccess
|
|
451
|
+
});
|
|
452
|
+
if (this.options.onB2BResult) {
|
|
453
|
+
await this.options.onB2BResult(parsed);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Handle Account Balance result callback
|
|
458
|
+
*/
|
|
459
|
+
async handleAccountBalanceResult(callback, ipAddress) {
|
|
460
|
+
if (ipAddress && !this.validateCallbackIp(ipAddress)) {
|
|
461
|
+
this.log("warn", `Invalid callback IP: ${ipAddress}`);
|
|
462
|
+
throw new Error(`Invalid callback IP: ${ipAddress}`);
|
|
463
|
+
}
|
|
464
|
+
const parsed = this.parseAccountBalanceCallback(callback);
|
|
465
|
+
this.log("info", "Processing Account Balance result", {
|
|
466
|
+
isSuccess: parsed.isSuccess,
|
|
467
|
+
availableBalance: parsed.availableBalance
|
|
468
|
+
});
|
|
469
|
+
if (this.options.onAccountBalanceResult) {
|
|
470
|
+
await this.options.onAccountBalanceResult(parsed);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Handle Transaction Status result callback
|
|
475
|
+
*/
|
|
476
|
+
async handleTransactionStatusResult(callback, ipAddress) {
|
|
477
|
+
if (ipAddress && !this.validateCallbackIp(ipAddress)) {
|
|
478
|
+
this.log("warn", `Invalid callback IP: ${ipAddress}`);
|
|
479
|
+
throw new Error(`Invalid callback IP: ${ipAddress}`);
|
|
480
|
+
}
|
|
481
|
+
const parsed = this.parseTransactionStatusCallback(callback);
|
|
482
|
+
this.log("info", "Processing Transaction Status result", {
|
|
483
|
+
isSuccess: parsed.isSuccess,
|
|
484
|
+
receiptNo: parsed.receiptNo
|
|
485
|
+
});
|
|
486
|
+
if (this.options.onTransactionStatusResult) {
|
|
487
|
+
await this.options.onTransactionStatusResult(parsed);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Handle Reversal result callback
|
|
492
|
+
*/
|
|
493
|
+
async handleReversalResult(callback, ipAddress) {
|
|
494
|
+
if (ipAddress && !this.validateCallbackIp(ipAddress)) {
|
|
495
|
+
this.log("warn", `Invalid callback IP: ${ipAddress}`);
|
|
496
|
+
throw new Error(`Invalid callback IP: ${ipAddress}`);
|
|
497
|
+
}
|
|
498
|
+
const parsed = this.parseReversalCallback(callback);
|
|
499
|
+
this.log("info", "Processing Reversal result", {
|
|
500
|
+
isSuccess: parsed.isSuccess,
|
|
501
|
+
transactionId: parsed.transactionId
|
|
502
|
+
});
|
|
503
|
+
if (this.options.onReversalResult) {
|
|
504
|
+
await this.options.onReversalResult(parsed);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
422
507
|
/**
|
|
423
508
|
* Handle STK Push callback and invoke appropriate handlers
|
|
424
509
|
*/
|
|
@@ -956,38 +1041,6 @@ var MpesaClient = class {
|
|
|
956
1041
|
);
|
|
957
1042
|
}
|
|
958
1043
|
}
|
|
959
|
-
/**
|
|
960
|
-
* Simulate C2B transaction (Sandbox only)
|
|
961
|
-
* Used for testing C2B payments in sandbox environment
|
|
962
|
-
*/
|
|
963
|
-
async simulateC2B(request) {
|
|
964
|
-
if (this.config.environment !== "sandbox") {
|
|
965
|
-
throw new MpesaValidationError(
|
|
966
|
-
"C2B simulation is only available in sandbox environment"
|
|
967
|
-
);
|
|
968
|
-
}
|
|
969
|
-
if (request.amount < 1) {
|
|
970
|
-
throw new MpesaValidationError("Amount must be at least 1 KES");
|
|
971
|
-
}
|
|
972
|
-
if (!request.billRefNumber || request.billRefNumber.length > 20) {
|
|
973
|
-
throw new MpesaValidationError(
|
|
974
|
-
"Bill reference is required and must be 20 characters or less"
|
|
975
|
-
);
|
|
976
|
-
}
|
|
977
|
-
const phone = this.validateAndFormatPhone(request.msisdn);
|
|
978
|
-
const payload = {
|
|
979
|
-
ShortCode: this.config.shortcode,
|
|
980
|
-
CommandID: request.commandID || "CustomerPayBillOnline",
|
|
981
|
-
Amount: Math.floor(request.amount),
|
|
982
|
-
Msisdn: phone,
|
|
983
|
-
BillRefNumber: request.billRefNumber
|
|
984
|
-
};
|
|
985
|
-
return this.makeRequest(
|
|
986
|
-
"/mpesa/c2b/v2/simulate",
|
|
987
|
-
payload,
|
|
988
|
-
`c2b:simulate:${phone}`
|
|
989
|
-
);
|
|
990
|
-
}
|
|
991
1044
|
/**
|
|
992
1045
|
* B2C - Send money from business to customer
|
|
993
1046
|
*/
|
|
@@ -1194,6 +1247,87 @@ var MpesaClient = class {
|
|
|
1194
1247
|
getConfig() {
|
|
1195
1248
|
return this.config;
|
|
1196
1249
|
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Handle B2C result callback
|
|
1252
|
+
*/
|
|
1253
|
+
async handleB2CResult(callback, ipAddress) {
|
|
1254
|
+
try {
|
|
1255
|
+
await this.callbackHandler.handleB2CResult(callback, ipAddress);
|
|
1256
|
+
return this.callbackHandler.createCallbackResponse(true);
|
|
1257
|
+
} catch (error) {
|
|
1258
|
+
console.error("B2C result handling error:", error);
|
|
1259
|
+
return this.callbackHandler.createCallbackResponse(
|
|
1260
|
+
false,
|
|
1261
|
+
"Processing failed"
|
|
1262
|
+
);
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
/**
|
|
1266
|
+
* Handle B2B result callback
|
|
1267
|
+
*/
|
|
1268
|
+
async handleB2BResult(callback, ipAddress) {
|
|
1269
|
+
try {
|
|
1270
|
+
await this.callbackHandler.handleB2BResult(callback, ipAddress);
|
|
1271
|
+
return this.callbackHandler.createCallbackResponse(true);
|
|
1272
|
+
} catch (error) {
|
|
1273
|
+
console.error("B2B result handling error:", error);
|
|
1274
|
+
return this.callbackHandler.createCallbackResponse(
|
|
1275
|
+
false,
|
|
1276
|
+
"Processing failed"
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Handle Account Balance result callback
|
|
1282
|
+
*/
|
|
1283
|
+
async handleAccountBalanceResult(callback, ipAddress) {
|
|
1284
|
+
try {
|
|
1285
|
+
await this.callbackHandler.handleAccountBalanceResult(
|
|
1286
|
+
callback,
|
|
1287
|
+
ipAddress
|
|
1288
|
+
);
|
|
1289
|
+
return this.callbackHandler.createCallbackResponse(true);
|
|
1290
|
+
} catch (error) {
|
|
1291
|
+
console.error("Account Balance result handling error:", error);
|
|
1292
|
+
return this.callbackHandler.createCallbackResponse(
|
|
1293
|
+
false,
|
|
1294
|
+
"Processing failed"
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
/**
|
|
1299
|
+
* Handle Transaction Status result callback
|
|
1300
|
+
*/
|
|
1301
|
+
async handleTransactionStatusResult(callback, ipAddress) {
|
|
1302
|
+
try {
|
|
1303
|
+
await this.callbackHandler.handleTransactionStatusResult(
|
|
1304
|
+
callback,
|
|
1305
|
+
ipAddress
|
|
1306
|
+
);
|
|
1307
|
+
return this.callbackHandler.createCallbackResponse(true);
|
|
1308
|
+
} catch (error) {
|
|
1309
|
+
console.error("Transaction Status result handling error:", error);
|
|
1310
|
+
return this.callbackHandler.createCallbackResponse(
|
|
1311
|
+
false,
|
|
1312
|
+
"Processing failed"
|
|
1313
|
+
);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Handle Reversal result callback
|
|
1318
|
+
*/
|
|
1319
|
+
async handleReversalResult(callback, ipAddress) {
|
|
1320
|
+
try {
|
|
1321
|
+
await this.callbackHandler.handleReversalResult(callback, ipAddress);
|
|
1322
|
+
return this.callbackHandler.createCallbackResponse(true);
|
|
1323
|
+
} catch (error) {
|
|
1324
|
+
console.error("Reversal result handling error:", error);
|
|
1325
|
+
return this.callbackHandler.createCallbackResponse(
|
|
1326
|
+
false,
|
|
1327
|
+
"Processing failed"
|
|
1328
|
+
);
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1197
1331
|
/**
|
|
1198
1332
|
* Get rate limiter usage for a key
|
|
1199
1333
|
*/
|
package/dist/index.mjs
CHANGED
|
@@ -370,6 +370,91 @@ var MpesaCallbackHandler = class {
|
|
|
370
370
|
};
|
|
371
371
|
return errorMessages[resultCode] || `Transaction failed with code: ${resultCode}`;
|
|
372
372
|
}
|
|
373
|
+
/**
|
|
374
|
+
* Handle B2C result callback
|
|
375
|
+
*/
|
|
376
|
+
async handleB2CResult(callback, ipAddress) {
|
|
377
|
+
if (ipAddress && !this.validateCallbackIp(ipAddress)) {
|
|
378
|
+
this.log("warn", `Invalid callback IP: ${ipAddress}`);
|
|
379
|
+
throw new Error(`Invalid callback IP: ${ipAddress}`);
|
|
380
|
+
}
|
|
381
|
+
const parsed = this.parseB2CCallback(callback);
|
|
382
|
+
this.log("info", "Processing B2C result", {
|
|
383
|
+
transactionId: parsed.transactionId,
|
|
384
|
+
isSuccess: parsed.isSuccess
|
|
385
|
+
});
|
|
386
|
+
if (this.options.onB2CResult) {
|
|
387
|
+
await this.options.onB2CResult(parsed);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Handle B2B result callback
|
|
392
|
+
*/
|
|
393
|
+
async handleB2BResult(callback, ipAddress) {
|
|
394
|
+
if (ipAddress && !this.validateCallbackIp(ipAddress)) {
|
|
395
|
+
this.log("warn", `Invalid callback IP: ${ipAddress}`);
|
|
396
|
+
throw new Error(`Invalid callback IP: ${ipAddress}`);
|
|
397
|
+
}
|
|
398
|
+
const parsed = this.parseB2BCallback(callback);
|
|
399
|
+
this.log("info", "Processing B2B result", {
|
|
400
|
+
transactionId: parsed.transactionId,
|
|
401
|
+
isSuccess: parsed.isSuccess
|
|
402
|
+
});
|
|
403
|
+
if (this.options.onB2BResult) {
|
|
404
|
+
await this.options.onB2BResult(parsed);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Handle Account Balance result callback
|
|
409
|
+
*/
|
|
410
|
+
async handleAccountBalanceResult(callback, ipAddress) {
|
|
411
|
+
if (ipAddress && !this.validateCallbackIp(ipAddress)) {
|
|
412
|
+
this.log("warn", `Invalid callback IP: ${ipAddress}`);
|
|
413
|
+
throw new Error(`Invalid callback IP: ${ipAddress}`);
|
|
414
|
+
}
|
|
415
|
+
const parsed = this.parseAccountBalanceCallback(callback);
|
|
416
|
+
this.log("info", "Processing Account Balance result", {
|
|
417
|
+
isSuccess: parsed.isSuccess,
|
|
418
|
+
availableBalance: parsed.availableBalance
|
|
419
|
+
});
|
|
420
|
+
if (this.options.onAccountBalanceResult) {
|
|
421
|
+
await this.options.onAccountBalanceResult(parsed);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Handle Transaction Status result callback
|
|
426
|
+
*/
|
|
427
|
+
async handleTransactionStatusResult(callback, ipAddress) {
|
|
428
|
+
if (ipAddress && !this.validateCallbackIp(ipAddress)) {
|
|
429
|
+
this.log("warn", `Invalid callback IP: ${ipAddress}`);
|
|
430
|
+
throw new Error(`Invalid callback IP: ${ipAddress}`);
|
|
431
|
+
}
|
|
432
|
+
const parsed = this.parseTransactionStatusCallback(callback);
|
|
433
|
+
this.log("info", "Processing Transaction Status result", {
|
|
434
|
+
isSuccess: parsed.isSuccess,
|
|
435
|
+
receiptNo: parsed.receiptNo
|
|
436
|
+
});
|
|
437
|
+
if (this.options.onTransactionStatusResult) {
|
|
438
|
+
await this.options.onTransactionStatusResult(parsed);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Handle Reversal result callback
|
|
443
|
+
*/
|
|
444
|
+
async handleReversalResult(callback, ipAddress) {
|
|
445
|
+
if (ipAddress && !this.validateCallbackIp(ipAddress)) {
|
|
446
|
+
this.log("warn", `Invalid callback IP: ${ipAddress}`);
|
|
447
|
+
throw new Error(`Invalid callback IP: ${ipAddress}`);
|
|
448
|
+
}
|
|
449
|
+
const parsed = this.parseReversalCallback(callback);
|
|
450
|
+
this.log("info", "Processing Reversal result", {
|
|
451
|
+
isSuccess: parsed.isSuccess,
|
|
452
|
+
transactionId: parsed.transactionId
|
|
453
|
+
});
|
|
454
|
+
if (this.options.onReversalResult) {
|
|
455
|
+
await this.options.onReversalResult(parsed);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
373
458
|
/**
|
|
374
459
|
* Handle STK Push callback and invoke appropriate handlers
|
|
375
460
|
*/
|
|
@@ -907,38 +992,6 @@ var MpesaClient = class {
|
|
|
907
992
|
);
|
|
908
993
|
}
|
|
909
994
|
}
|
|
910
|
-
/**
|
|
911
|
-
* Simulate C2B transaction (Sandbox only)
|
|
912
|
-
* Used for testing C2B payments in sandbox environment
|
|
913
|
-
*/
|
|
914
|
-
async simulateC2B(request) {
|
|
915
|
-
if (this.config.environment !== "sandbox") {
|
|
916
|
-
throw new MpesaValidationError(
|
|
917
|
-
"C2B simulation is only available in sandbox environment"
|
|
918
|
-
);
|
|
919
|
-
}
|
|
920
|
-
if (request.amount < 1) {
|
|
921
|
-
throw new MpesaValidationError("Amount must be at least 1 KES");
|
|
922
|
-
}
|
|
923
|
-
if (!request.billRefNumber || request.billRefNumber.length > 20) {
|
|
924
|
-
throw new MpesaValidationError(
|
|
925
|
-
"Bill reference is required and must be 20 characters or less"
|
|
926
|
-
);
|
|
927
|
-
}
|
|
928
|
-
const phone = this.validateAndFormatPhone(request.msisdn);
|
|
929
|
-
const payload = {
|
|
930
|
-
ShortCode: this.config.shortcode,
|
|
931
|
-
CommandID: request.commandID || "CustomerPayBillOnline",
|
|
932
|
-
Amount: Math.floor(request.amount),
|
|
933
|
-
Msisdn: phone,
|
|
934
|
-
BillRefNumber: request.billRefNumber
|
|
935
|
-
};
|
|
936
|
-
return this.makeRequest(
|
|
937
|
-
"/mpesa/c2b/v2/simulate",
|
|
938
|
-
payload,
|
|
939
|
-
`c2b:simulate:${phone}`
|
|
940
|
-
);
|
|
941
|
-
}
|
|
942
995
|
/**
|
|
943
996
|
* B2C - Send money from business to customer
|
|
944
997
|
*/
|
|
@@ -1145,6 +1198,87 @@ var MpesaClient = class {
|
|
|
1145
1198
|
getConfig() {
|
|
1146
1199
|
return this.config;
|
|
1147
1200
|
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Handle B2C result callback
|
|
1203
|
+
*/
|
|
1204
|
+
async handleB2CResult(callback, ipAddress) {
|
|
1205
|
+
try {
|
|
1206
|
+
await this.callbackHandler.handleB2CResult(callback, ipAddress);
|
|
1207
|
+
return this.callbackHandler.createCallbackResponse(true);
|
|
1208
|
+
} catch (error) {
|
|
1209
|
+
console.error("B2C result handling error:", error);
|
|
1210
|
+
return this.callbackHandler.createCallbackResponse(
|
|
1211
|
+
false,
|
|
1212
|
+
"Processing failed"
|
|
1213
|
+
);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
/**
|
|
1217
|
+
* Handle B2B result callback
|
|
1218
|
+
*/
|
|
1219
|
+
async handleB2BResult(callback, ipAddress) {
|
|
1220
|
+
try {
|
|
1221
|
+
await this.callbackHandler.handleB2BResult(callback, ipAddress);
|
|
1222
|
+
return this.callbackHandler.createCallbackResponse(true);
|
|
1223
|
+
} catch (error) {
|
|
1224
|
+
console.error("B2B result handling error:", error);
|
|
1225
|
+
return this.callbackHandler.createCallbackResponse(
|
|
1226
|
+
false,
|
|
1227
|
+
"Processing failed"
|
|
1228
|
+
);
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
/**
|
|
1232
|
+
* Handle Account Balance result callback
|
|
1233
|
+
*/
|
|
1234
|
+
async handleAccountBalanceResult(callback, ipAddress) {
|
|
1235
|
+
try {
|
|
1236
|
+
await this.callbackHandler.handleAccountBalanceResult(
|
|
1237
|
+
callback,
|
|
1238
|
+
ipAddress
|
|
1239
|
+
);
|
|
1240
|
+
return this.callbackHandler.createCallbackResponse(true);
|
|
1241
|
+
} catch (error) {
|
|
1242
|
+
console.error("Account Balance result handling error:", error);
|
|
1243
|
+
return this.callbackHandler.createCallbackResponse(
|
|
1244
|
+
false,
|
|
1245
|
+
"Processing failed"
|
|
1246
|
+
);
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
/**
|
|
1250
|
+
* Handle Transaction Status result callback
|
|
1251
|
+
*/
|
|
1252
|
+
async handleTransactionStatusResult(callback, ipAddress) {
|
|
1253
|
+
try {
|
|
1254
|
+
await this.callbackHandler.handleTransactionStatusResult(
|
|
1255
|
+
callback,
|
|
1256
|
+
ipAddress
|
|
1257
|
+
);
|
|
1258
|
+
return this.callbackHandler.createCallbackResponse(true);
|
|
1259
|
+
} catch (error) {
|
|
1260
|
+
console.error("Transaction Status result handling error:", error);
|
|
1261
|
+
return this.callbackHandler.createCallbackResponse(
|
|
1262
|
+
false,
|
|
1263
|
+
"Processing failed"
|
|
1264
|
+
);
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
/**
|
|
1268
|
+
* Handle Reversal result callback
|
|
1269
|
+
*/
|
|
1270
|
+
async handleReversalResult(callback, ipAddress) {
|
|
1271
|
+
try {
|
|
1272
|
+
await this.callbackHandler.handleReversalResult(callback, ipAddress);
|
|
1273
|
+
return this.callbackHandler.createCallbackResponse(true);
|
|
1274
|
+
} catch (error) {
|
|
1275
|
+
console.error("Reversal result handling error:", error);
|
|
1276
|
+
return this.callbackHandler.createCallbackResponse(
|
|
1277
|
+
false,
|
|
1278
|
+
"Processing failed"
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1148
1282
|
/**
|
|
1149
1283
|
* Get rate limiter usage for a key
|
|
1150
1284
|
*/
|