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