@nile-squad/nylonpay-ts 1.0.9 → 1.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.js CHANGED
@@ -147,6 +147,7 @@ var KNOWN_CATEGORIES = /* @__PURE__ */ new Set([
147
147
  "rate_limit",
148
148
  "account",
149
149
  "provider",
150
+ "duplicate",
150
151
  "not_found",
151
152
  "internal",
152
153
  "network",
@@ -372,6 +373,7 @@ function parseError(error) {
372
373
 
373
374
  // src/payment.ts
374
375
  var STATUS_TO_EVENT = {
376
+ pending: "processing",
375
377
  successful: "success",
376
378
  failed: "failed",
377
379
  processing: "processing",
@@ -395,6 +397,7 @@ function createPaymentInstance(initialResponse, deps) {
395
397
  status: normalizeStatus(initialResponse.status),
396
398
  transaction: null,
397
399
  pollingTimer: null,
400
+ lastStatusEvent: null,
398
401
  resolved: false,
399
402
  pollAttempts: 0,
400
403
  pollStartTime: Date.now(),
@@ -413,6 +416,7 @@ function createPaymentInstance(initialResponse, deps) {
413
416
  function emitEvent(event, error, category, retryable) {
414
417
  const data = {
415
418
  event,
419
+ reference: state.reference,
416
420
  transaction: state.transaction ?? void 0,
417
421
  error,
418
422
  category,
@@ -449,18 +453,17 @@ function createPaymentInstance(initialResponse, deps) {
449
453
  return;
450
454
  }
451
455
  const newStatus = normalizeStatus(response.status);
452
- const oldStatus = state.status;
453
456
  state.status = newStatus;
454
- if (newStatus !== oldStatus) {
455
- const event = statusToEvent(newStatus);
456
- if (event) {
457
- if (TERMINAL_STATES.has(newStatus)) {
458
- await handleTerminalState(newStatus);
459
- return;
460
- }
461
- emitEvent(event);
462
- }
457
+ const event = statusToEvent(newStatus);
458
+ if (!event || event === state.lastStatusEvent) {
459
+ return;
460
+ }
461
+ state.lastStatusEvent = event;
462
+ if (TERMINAL_STATES.has(newStatus)) {
463
+ await handleTerminalState(newStatus);
464
+ return;
463
465
  }
466
+ emitEvent(event);
464
467
  }
465
468
  function handlePollError(error) {
466
469
  const parsed = parseError(error);
@@ -514,6 +517,15 @@ function createPaymentInstance(initialResponse, deps) {
514
517
  }, 0);
515
518
  return;
516
519
  }
520
+ const initialEvent = statusToEvent(state.status);
521
+ if (initialEvent) {
522
+ state.lastStatusEvent = initialEvent;
523
+ setTimeout(() => {
524
+ if (!state.resolved) {
525
+ emitEvent(initialEvent);
526
+ }
527
+ }, 0);
528
+ }
517
529
  scheduleNextPoll();
518
530
  }
519
531
  function stopUpdates() {
@@ -593,6 +605,15 @@ function createPaymentInstance(initialResponse, deps) {
593
605
  }
594
606
  return paymentInstance;
595
607
  }
608
+
609
+ // src/phone.ts
610
+ function normalizePhone(phone) {
611
+ let normalized = phone.replace(/\s+/g, "").replace(/^\+/, "");
612
+ if (normalized.startsWith("0") && normalized.length === 10) {
613
+ normalized = `256${normalized.slice(1)}`;
614
+ }
615
+ return normalized;
616
+ }
596
617
  var DEFAULT_TOLERANCE_SECONDS = 300;
597
618
  function decodePayload(payload) {
598
619
  return typeof payload === "string" ? payload : Buffer.from(payload).toString("utf8");
@@ -668,10 +689,21 @@ async function runHook(hook, ...args) {
668
689
  function throwValidation(message) {
669
690
  throw createSdkError({ category: "validation", message });
670
691
  }
671
- function validateAmount(amount) {
692
+ function validateCollectionAmount(amount) {
693
+ if (!Number.isInteger(amount) || amount <= 0) {
694
+ throwValidation("amount must be a positive integer");
695
+ }
696
+ if (amount < 500) {
697
+ throwValidation("Collection amount must be at least 500 UGX");
698
+ }
699
+ }
700
+ function validatePayoutAmount(amount) {
672
701
  if (!Number.isInteger(amount) || amount <= 0) {
673
702
  throwValidation("amount must be a positive integer");
674
703
  }
704
+ if (amount < 5e3) {
705
+ throwValidation("Payout amount must be at least 5000 UGX");
706
+ }
675
707
  }
676
708
  function validateNonEmpty(value, fieldName) {
677
709
  if (!value || value.trim() === "") {
@@ -702,14 +734,19 @@ function createSdkInstance(config) {
702
734
  };
703
735
  async function collectPayment(input) {
704
736
  const reference = resolveReference(input.reference);
705
- validateAmount(input.amount);
737
+ validateCollectionAmount(input.amount);
706
738
  validateNonEmpty(input.customer.name, "customer.name");
707
739
  validateNonEmpty(input.customer.phoneNumber, "customer.phoneNumber");
740
+ const normalizedPhone = normalizePhone(input.customer.phoneNumber);
708
741
  validateNonEmpty(input.description, "description");
709
742
  if (input.method === "bank" && !input.bank) {
710
743
  throwValidation('bank details are required when method is "bank"');
711
744
  }
712
- let payload = { ...input, reference };
745
+ let payload = {
746
+ ...input,
747
+ reference,
748
+ customer: { ...input.customer, phoneNumber: normalizedPhone }
749
+ };
713
750
  const mutated = await runHook(config.hooks?.beforeCollect, payload);
714
751
  if (mutated != null)
715
752
  payload = { ...mutated, reference: mutated.reference ?? reference };
@@ -733,14 +770,19 @@ function createSdkInstance(config) {
733
770
  }
734
771
  async function collectPaymentAndResolve(input) {
735
772
  const reference = resolveReference(input.reference);
736
- validateAmount(input.amount);
773
+ validateCollectionAmount(input.amount);
737
774
  validateNonEmpty(input.customer.name, "customer.name");
738
775
  validateNonEmpty(input.customer.phoneNumber, "customer.phoneNumber");
776
+ const normalizedPhone = normalizePhone(input.customer.phoneNumber);
739
777
  validateNonEmpty(input.description, "description");
740
778
  if (input.method === "bank" && !input.bank) {
741
779
  throwValidation('bank details are required when method is "bank"');
742
780
  }
743
- let payload = { ...input, reference };
781
+ let payload = {
782
+ ...input,
783
+ reference,
784
+ customer: { ...input.customer, phoneNumber: normalizedPhone }
785
+ };
744
786
  const mutated = await runHook(config.hooks?.beforeCollect, payload);
745
787
  if (mutated != null)
746
788
  payload = { ...mutated, reference: mutated.reference ?? reference };
@@ -760,9 +802,10 @@ function createSdkInstance(config) {
760
802
  }
761
803
  async function makePayout(input) {
762
804
  const reference = resolveReference(input.reference);
763
- validateAmount(input.amount);
805
+ validatePayoutAmount(input.amount);
764
806
  validateNonEmpty(input.customer.name, "customer.name");
765
807
  validateNonEmpty(input.customer.phoneNumber, "customer.phoneNumber");
808
+ const normalizedPhone = normalizePhone(input.customer.phoneNumber);
766
809
  validateNonEmpty(input.description, "description");
767
810
  validateNonEmpty(
768
811
  input.destination.accountHolderName,
@@ -772,7 +815,11 @@ function createSdkInstance(config) {
772
815
  input.destination.accountNumber,
773
816
  "destination.accountNumber"
774
817
  );
775
- let payload = { ...input, reference };
818
+ let payload = {
819
+ ...input,
820
+ reference,
821
+ customer: { ...input.customer, phoneNumber: normalizedPhone }
822
+ };
776
823
  const mutated = await runHook(config.hooks?.beforePayout, payload);
777
824
  if (mutated != null)
778
825
  payload = { ...mutated, reference: mutated.reference ?? reference };
@@ -796,9 +843,10 @@ function createSdkInstance(config) {
796
843
  }
797
844
  async function makePayoutAndResolve(input) {
798
845
  const reference = resolveReference(input.reference);
799
- validateAmount(input.amount);
846
+ validatePayoutAmount(input.amount);
800
847
  validateNonEmpty(input.customer.name, "customer.name");
801
848
  validateNonEmpty(input.customer.phoneNumber, "customer.phoneNumber");
849
+ const normalizedPhone = normalizePhone(input.customer.phoneNumber);
802
850
  validateNonEmpty(input.description, "description");
803
851
  validateNonEmpty(
804
852
  input.destination.accountHolderName,
@@ -808,7 +856,11 @@ function createSdkInstance(config) {
808
856
  input.destination.accountNumber,
809
857
  "destination.accountNumber"
810
858
  );
811
- let payload = { ...input, reference };
859
+ let payload = {
860
+ ...input,
861
+ reference,
862
+ customer: { ...input.customer, phoneNumber: normalizedPhone }
863
+ };
812
864
  const mutated = await runHook(config.hooks?.beforePayout, payload);
813
865
  if (mutated != null)
814
866
  payload = { ...mutated, reference: mutated.reference ?? reference };
@@ -852,9 +904,10 @@ function createSdkInstance(config) {
852
904
  }
853
905
  async function verifyPhone(input) {
854
906
  validateNonEmpty(input.phoneNumber, "phoneNumber");
907
+ const normalizedPhone = normalizePhone(input.phoneNumber);
855
908
  const result = await transport.send({
856
909
  action: SDK_ACTIONS.verifyPhone,
857
- payload: input
910
+ payload: { ...input, phoneNumber: normalizedPhone }
858
911
  });
859
912
  if (result.isOk) {
860
913
  return Ok(result.value);
@@ -863,7 +916,7 @@ function createSdkInstance(config) {
863
916
  }
864
917
  async function createInvoice(input) {
865
918
  const reference = resolveReference(input.reference);
866
- validateAmount(input.amount);
919
+ validateCollectionAmount(input.amount);
867
920
  validateNonEmpty(input.description, "description");
868
921
  if (input.items) {
869
922
  if (input.items.length > 50) {