@singularity-payments/core 0.1.0-alpha.7 → 0.1.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.d.mts CHANGED
@@ -262,18 +262,6 @@ interface DynamicQRResponse {
262
262
  ResponseDescription: string;
263
263
  QRCode: string;
264
264
  }
265
- interface C2BSimulateRequest {
266
- shortCode?: string;
267
- amount: number;
268
- msisdn: string;
269
- billRefNumber: string;
270
- commandID?: "CustomerPayBillOnline" | "CustomerBuyGoodsOnline";
271
- }
272
- interface C2BSimulateResponse {
273
- ConversationID: string;
274
- OriginatorCoversationID: string;
275
- ResponseDescription: string;
276
- }
277
265
 
278
266
  interface ParsedCallbackData {
279
267
  merchantRequestId: string;
@@ -306,6 +294,11 @@ interface CallbackHandlerOptions {
306
294
  onCallback?: (data: ParsedCallbackData) => void | Promise<void>;
307
295
  onC2BConfirmation?: (data: ParsedC2BCallback) => void | Promise<void>;
308
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>;
309
302
  validateIp?: boolean;
310
303
  allowedIps?: string[];
311
304
  isDuplicate?: (CheckoutRequestID: string) => boolean | Promise<boolean>;
@@ -351,6 +344,26 @@ declare class MpesaCallbackHandler {
351
344
  * Get a readable error message based on the code
352
345
  */
353
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>;
354
367
  /**
355
368
  * Handle STK Push callback and invoke appropriate handlers
356
369
  */
@@ -549,11 +562,6 @@ declare class MpesaClient {
549
562
  * Handle C2B validation request
550
563
  */
551
564
  handleC2BValidation(callback: C2BCallback): Promise<object>;
552
- /**
553
- * Simulate C2B transaction (Sandbox only)
554
- * Used for testing C2B payments in sandbox environment
555
- */
556
- simulateC2B(request: C2BSimulateRequest): Promise<C2BSimulateResponse>;
557
565
  /**
558
566
  * B2C - Send money from business to customer
559
567
  */
@@ -594,6 +602,26 @@ declare class MpesaClient {
594
602
  * Get configuration (for plugins)
595
603
  */
596
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>;
597
625
  /**
598
626
  * Get rate limiter usage for a key
599
627
  */
@@ -647,4 +675,4 @@ declare function encryptInitiatorPassword(initiatorPassword: string, certificate
647
675
  */
648
676
  declare function validateSecurityCredential(credential: string): boolean;
649
677
 
650
- export { type AccountBalanceCallback, type AccountBalanceRequest, type AccountBalanceResponse, type B2BCallback, type B2BCommandID, type B2BRequest, type B2BResponse, type B2CCallback, type B2CCommandID, type B2CRequest, type B2CResponse, type BalanceIdentifierType, type C2BCallback, type C2BRegisterRequest, type C2BRegisterResponse, type C2BSimulateRequest, type C2BSimulateResponse, type CallbackHandlerOptions, type DynamicQRRequest, type DynamicQRResponse, type Environment, type GeneralTransactionStatusRequest, type GeneralTransactionStatusResponse, MpesaApiError, MpesaAuthError, MpesaCallbackHandler, MpesaClient, type MpesaClientOptions, type MpesaConfig, MpesaError, MpesaNetworkError, type MpesaPlugin, MpesaRateLimitError, MpesaTimeoutError, MpesaValidationError, type ParsedC2BCallback, type ParsedCallbackData, RateLimiter, type RateLimiterOptions, type RedisLike, RedisRateLimiter, type RetryOptions, type ReversalCallback, type ReversalRequest, type ReversalResponse, type STKCallback, type STKPushRequest, type STKPushResponse, type TransactionStatusCallback, type TransactionStatusRequest, type TransactionStatusResponse, encryptInitiatorPassword, retryWithBackoff, validateSecurityCredential };
678
+ export { type AccountBalanceCallback, type AccountBalanceRequest, type AccountBalanceResponse, type B2BCallback, type B2BCommandID, type B2BRequest, type B2BResponse, type B2CCallback, type B2CCommandID, type B2CRequest, type B2CResponse, type BalanceIdentifierType, type C2BCallback, type C2BRegisterRequest, type C2BRegisterResponse, type CallbackHandlerOptions, type DynamicQRRequest, type DynamicQRResponse, type Environment, type GeneralTransactionStatusRequest, type GeneralTransactionStatusResponse, MpesaApiError, MpesaAuthError, MpesaCallbackHandler, MpesaClient, type MpesaClientOptions, type MpesaConfig, MpesaError, MpesaNetworkError, type MpesaPlugin, MpesaRateLimitError, MpesaTimeoutError, MpesaValidationError, type ParsedC2BCallback, type ParsedCallbackData, RateLimiter, type RateLimiterOptions, type RedisLike, RedisRateLimiter, type RetryOptions, type ReversalCallback, type ReversalRequest, type ReversalResponse, type STKCallback, type STKPushRequest, type STKPushResponse, type TransactionStatusCallback, type TransactionStatusRequest, type TransactionStatusResponse, encryptInitiatorPassword, retryWithBackoff, validateSecurityCredential };
package/dist/index.d.ts CHANGED
@@ -262,18 +262,6 @@ interface DynamicQRResponse {
262
262
  ResponseDescription: string;
263
263
  QRCode: string;
264
264
  }
265
- interface C2BSimulateRequest {
266
- shortCode?: string;
267
- amount: number;
268
- msisdn: string;
269
- billRefNumber: string;
270
- commandID?: "CustomerPayBillOnline" | "CustomerBuyGoodsOnline";
271
- }
272
- interface C2BSimulateResponse {
273
- ConversationID: string;
274
- OriginatorCoversationID: string;
275
- ResponseDescription: string;
276
- }
277
265
 
278
266
  interface ParsedCallbackData {
279
267
  merchantRequestId: string;
@@ -306,6 +294,11 @@ interface CallbackHandlerOptions {
306
294
  onCallback?: (data: ParsedCallbackData) => void | Promise<void>;
307
295
  onC2BConfirmation?: (data: ParsedC2BCallback) => void | Promise<void>;
308
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>;
309
302
  validateIp?: boolean;
310
303
  allowedIps?: string[];
311
304
  isDuplicate?: (CheckoutRequestID: string) => boolean | Promise<boolean>;
@@ -351,6 +344,26 @@ declare class MpesaCallbackHandler {
351
344
  * Get a readable error message based on the code
352
345
  */
353
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>;
354
367
  /**
355
368
  * Handle STK Push callback and invoke appropriate handlers
356
369
  */
@@ -549,11 +562,6 @@ declare class MpesaClient {
549
562
  * Handle C2B validation request
550
563
  */
551
564
  handleC2BValidation(callback: C2BCallback): Promise<object>;
552
- /**
553
- * Simulate C2B transaction (Sandbox only)
554
- * Used for testing C2B payments in sandbox environment
555
- */
556
- simulateC2B(request: C2BSimulateRequest): Promise<C2BSimulateResponse>;
557
565
  /**
558
566
  * B2C - Send money from business to customer
559
567
  */
@@ -594,6 +602,26 @@ declare class MpesaClient {
594
602
  * Get configuration (for plugins)
595
603
  */
596
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>;
597
625
  /**
598
626
  * Get rate limiter usage for a key
599
627
  */
@@ -647,4 +675,4 @@ declare function encryptInitiatorPassword(initiatorPassword: string, certificate
647
675
  */
648
676
  declare function validateSecurityCredential(credential: string): boolean;
649
677
 
650
- export { type AccountBalanceCallback, type AccountBalanceRequest, type AccountBalanceResponse, type B2BCallback, type B2BCommandID, type B2BRequest, type B2BResponse, type B2CCallback, type B2CCommandID, type B2CRequest, type B2CResponse, type BalanceIdentifierType, type C2BCallback, type C2BRegisterRequest, type C2BRegisterResponse, type C2BSimulateRequest, type C2BSimulateResponse, type CallbackHandlerOptions, type DynamicQRRequest, type DynamicQRResponse, type Environment, type GeneralTransactionStatusRequest, type GeneralTransactionStatusResponse, MpesaApiError, MpesaAuthError, MpesaCallbackHandler, MpesaClient, type MpesaClientOptions, type MpesaConfig, MpesaError, MpesaNetworkError, type MpesaPlugin, MpesaRateLimitError, MpesaTimeoutError, MpesaValidationError, type ParsedC2BCallback, type ParsedCallbackData, RateLimiter, type RateLimiterOptions, type RedisLike, RedisRateLimiter, type RetryOptions, type ReversalCallback, type ReversalRequest, type ReversalResponse, type STKCallback, type STKPushRequest, type STKPushResponse, type TransactionStatusCallback, type TransactionStatusRequest, type TransactionStatusResponse, encryptInitiatorPassword, retryWithBackoff, validateSecurityCredential };
678
+ export { type AccountBalanceCallback, type AccountBalanceRequest, type AccountBalanceResponse, type B2BCallback, type B2BCommandID, type B2BRequest, type B2BResponse, type B2CCallback, type B2CCommandID, type B2CRequest, type B2CResponse, type BalanceIdentifierType, type C2BCallback, type C2BRegisterRequest, type C2BRegisterResponse, type CallbackHandlerOptions, type DynamicQRRequest, type DynamicQRResponse, type Environment, type GeneralTransactionStatusRequest, type GeneralTransactionStatusResponse, MpesaApiError, MpesaAuthError, MpesaCallbackHandler, MpesaClient, type MpesaClientOptions, type MpesaConfig, MpesaError, MpesaNetworkError, type MpesaPlugin, MpesaRateLimitError, MpesaTimeoutError, MpesaValidationError, type ParsedC2BCallback, type ParsedCallbackData, RateLimiter, type RateLimiterOptions, type RedisLike, RedisRateLimiter, type RetryOptions, type ReversalCallback, type ReversalRequest, type ReversalResponse, type STKCallback, type STKPushRequest, type STKPushResponse, type TransactionStatusCallback, type TransactionStatusRequest, type TransactionStatusResponse, encryptInitiatorPassword, retryWithBackoff, validateSecurityCredential };
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: request.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: request.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
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@singularity-payments/core",
3
- "version": "0.1.0-alpha.7",
3
+ "version": "0.1.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },