@nile-squad/nylonpay-ts 1.1.0 → 1.2.1
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/README.md +7 -10
- package/dist/index.cjs +150 -114
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -4
- package/dist/index.d.ts +15 -4
- package/dist/index.js +150 -114
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ Use your test keys to work in sandbox, or your production keys to go live. There
|
|
|
41
41
|
|---|---|---|---|
|
|
42
42
|
| `apiKey` | Yes | | Must start with `npk_` |
|
|
43
43
|
| `apiSecret` | Yes | | Must start with `nps_` |
|
|
44
|
-
| `baseUrl` | No | Default is used | Override
|
|
44
|
+
| `baseUrl` | No | Default is used | Override for a custom endpoint |
|
|
45
45
|
| `timeoutMs` | No | `30000` | Request timeout in milliseconds |
|
|
46
46
|
| `maxRetries` | No | `3` | Retry count for failed requests |
|
|
47
47
|
| `maxPollIntervalMs` | No | `2000` | Polling interval for async payments |
|
|
@@ -231,16 +231,13 @@ if (!result.isOk) {
|
|
|
231
231
|
|
|
232
232
|
`USD`, `EUR`, `GBP`, `KES`, `UGX`, `TZS`, `RWF`
|
|
233
233
|
|
|
234
|
-
##
|
|
234
|
+
## Links
|
|
235
235
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
pnpm typecheck # tsc --noEmit
|
|
242
|
-
pnpm build # tsup
|
|
243
|
-
```
|
|
236
|
+
- [Documentation](https://docs.nylonpay.nilesquad.com/docs)
|
|
237
|
+
- [SDK Spec](https://github.com/nile-squad/specs/blob/main/nylonpay-sdk-spec/spec.md)
|
|
238
|
+
- [GitHub Repository](https://github.com/nile-squad/nylonpay-ts)
|
|
239
|
+
- [Python SDK](https://github.com/nile-squad/nylonpay-py)
|
|
240
|
+
- [Nylon Pay](https://nylonpay.nilesquad.com)
|
|
244
241
|
|
|
245
242
|
## License
|
|
246
243
|
|
package/dist/index.cjs
CHANGED
|
@@ -76,6 +76,7 @@ var SDK_ACTIONS = {
|
|
|
76
76
|
createInvoice: "sdk-create-invoice"
|
|
77
77
|
};
|
|
78
78
|
var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
|
|
79
|
+
var MAX_RESPONSE_BYTES = 10 * 1024 * 1024;
|
|
79
80
|
function generateFingerprint() {
|
|
80
81
|
const components = [
|
|
81
82
|
`type:${os.type()}`,
|
|
@@ -255,13 +256,13 @@ function createTransport({
|
|
|
255
256
|
async function send(request) {
|
|
256
257
|
const envelope = buildEnvelope(request);
|
|
257
258
|
const signedPayload = envelope.payload;
|
|
258
|
-
const headers = buildAuthHeaders({
|
|
259
|
-
apiKey,
|
|
260
|
-
apiSecret,
|
|
261
|
-
payload: signedPayload
|
|
262
|
-
});
|
|
263
259
|
const bodyString = JSON.stringify(envelope);
|
|
264
260
|
async function attempt(currentAttempt) {
|
|
261
|
+
const headers = buildAuthHeaders({
|
|
262
|
+
apiKey,
|
|
263
|
+
apiSecret,
|
|
264
|
+
payload: signedPayload
|
|
265
|
+
});
|
|
265
266
|
const { controller, cleanup } = withTimeout(timeoutMs);
|
|
266
267
|
try {
|
|
267
268
|
const response = await fetchImpl(baseUrl, {
|
|
@@ -270,6 +271,17 @@ function createTransport({
|
|
|
270
271
|
body: bodyString,
|
|
271
272
|
signal: controller.signal
|
|
272
273
|
});
|
|
274
|
+
const contentLength = response.headers?.get("content-length");
|
|
275
|
+
if (contentLength && Number(contentLength) > MAX_RESPONSE_BYTES) {
|
|
276
|
+
cleanup();
|
|
277
|
+
return slangTs.Err(
|
|
278
|
+
JSON.stringify({
|
|
279
|
+
category: "internal",
|
|
280
|
+
message: "Received an invalid response from the server",
|
|
281
|
+
retryable: false
|
|
282
|
+
})
|
|
283
|
+
);
|
|
284
|
+
}
|
|
273
285
|
if (!response.ok) {
|
|
274
286
|
const statusCode = response.status;
|
|
275
287
|
const retryable = RETRYABLE_STATUS_CODES.has(statusCode);
|
|
@@ -300,7 +312,7 @@ function createTransport({
|
|
|
300
312
|
return slangTs.Err(
|
|
301
313
|
JSON.stringify({
|
|
302
314
|
category: "internal",
|
|
303
|
-
message: "
|
|
315
|
+
message: "Received an invalid response from the server",
|
|
304
316
|
retryable: false
|
|
305
317
|
})
|
|
306
318
|
);
|
|
@@ -313,7 +325,7 @@ function createTransport({
|
|
|
313
325
|
return slangTs.Err(
|
|
314
326
|
JSON.stringify({
|
|
315
327
|
category: "internal",
|
|
316
|
-
message: "
|
|
328
|
+
message: "Could not verify the server response",
|
|
317
329
|
retryable: false
|
|
318
330
|
})
|
|
319
331
|
);
|
|
@@ -328,7 +340,7 @@ function createTransport({
|
|
|
328
340
|
return slangTs.Err(
|
|
329
341
|
JSON.stringify({
|
|
330
342
|
category: "internal",
|
|
331
|
-
message: "
|
|
343
|
+
message: "Could not verify the server response",
|
|
332
344
|
retryable: false
|
|
333
345
|
})
|
|
334
346
|
);
|
|
@@ -344,7 +356,7 @@ function createTransport({
|
|
|
344
356
|
const isAbort = error instanceof DOMException && error.name === "AbortError";
|
|
345
357
|
const sdkError = {
|
|
346
358
|
category: isAbort ? "timeout" : "network",
|
|
347
|
-
message: isAbort ?
|
|
359
|
+
message: isAbort ? "The request timed out" : "Could not reach the server, check your network connection and try again",
|
|
348
360
|
retryable: true
|
|
349
361
|
};
|
|
350
362
|
if (currentAttempt < maxRetries) {
|
|
@@ -410,10 +422,16 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
410
422
|
maxPollDuration: deps.maxPollDuration ?? 3e5,
|
|
411
423
|
maxPollAttempts: deps.maxPollAttempts ?? 150
|
|
412
424
|
};
|
|
413
|
-
function resolveWithError(error) {
|
|
425
|
+
function resolveWithError(error, category, retryable) {
|
|
414
426
|
state.resolved = true;
|
|
415
427
|
stopUpdates();
|
|
416
|
-
|
|
428
|
+
const parsed = parseError(error);
|
|
429
|
+
emitEvent(
|
|
430
|
+
"error",
|
|
431
|
+
parsed.message,
|
|
432
|
+
category ?? parsed.category,
|
|
433
|
+
parsed.retryable
|
|
434
|
+
);
|
|
417
435
|
}
|
|
418
436
|
function emitEvent(event, error, category, retryable) {
|
|
419
437
|
const data = {
|
|
@@ -450,7 +468,8 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
450
468
|
}
|
|
451
469
|
if (response.reference !== state.reference) {
|
|
452
470
|
resolveWithError(
|
|
453
|
-
|
|
471
|
+
"Received a status update for a different transaction",
|
|
472
|
+
"internal"
|
|
454
473
|
);
|
|
455
474
|
return;
|
|
456
475
|
}
|
|
@@ -472,7 +491,7 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
472
491
|
if (parsed.category === "not_found") {
|
|
473
492
|
return;
|
|
474
493
|
}
|
|
475
|
-
emitEvent("error", parsed.message);
|
|
494
|
+
emitEvent("error", parsed.message, parsed.category, parsed.retryable);
|
|
476
495
|
state.resolved = true;
|
|
477
496
|
stopUpdates();
|
|
478
497
|
}
|
|
@@ -492,11 +511,17 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
492
511
|
return;
|
|
493
512
|
}
|
|
494
513
|
if (state.pollAttempts >= state.maxPollAttempts) {
|
|
495
|
-
resolveWithError(
|
|
514
|
+
resolveWithError(
|
|
515
|
+
"Timed out waiting for the transaction status to update",
|
|
516
|
+
"timeout"
|
|
517
|
+
);
|
|
496
518
|
return;
|
|
497
519
|
}
|
|
498
520
|
if (Date.now() - state.pollStartTime >= state.maxPollDuration) {
|
|
499
|
-
resolveWithError(
|
|
521
|
+
resolveWithError(
|
|
522
|
+
"Timed out waiting for the transaction status to update",
|
|
523
|
+
"timeout"
|
|
524
|
+
);
|
|
500
525
|
return;
|
|
501
526
|
}
|
|
502
527
|
state.pollAttempts += 1;
|
|
@@ -616,6 +641,9 @@ function normalizePhone(phone) {
|
|
|
616
641
|
}
|
|
617
642
|
return normalized;
|
|
618
643
|
}
|
|
644
|
+
function isValidPhoneFormat(normalizedPhone) {
|
|
645
|
+
return /^\d{9,15}$/.test(normalizedPhone);
|
|
646
|
+
}
|
|
619
647
|
var DEFAULT_TOLERANCE_SECONDS = 300;
|
|
620
648
|
function decodePayload(payload) {
|
|
621
649
|
return typeof payload === "string" ? payload : Buffer.from(payload).toString("utf8");
|
|
@@ -641,27 +669,34 @@ function extractSignedTimestampMs(payloadString) {
|
|
|
641
669
|
return null;
|
|
642
670
|
}
|
|
643
671
|
function verifyWebhookSignature(input) {
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
672
|
+
try {
|
|
673
|
+
const payloadString = decodePayload(input.payload);
|
|
674
|
+
const payloadBytes = Buffer.from(payloadString, "utf8");
|
|
675
|
+
const expectedSignature = crypto.createHmac("sha256", input.secret).update(payloadBytes).digest("hex");
|
|
676
|
+
const providedBuffer = Buffer.from(input.signature, "hex");
|
|
677
|
+
const expectedBuffer = Buffer.from(expectedSignature, "hex");
|
|
678
|
+
if (providedBuffer.length !== expectedBuffer.length) {
|
|
679
|
+
return false;
|
|
680
|
+
}
|
|
681
|
+
if (!crypto.timingSafeEqual(providedBuffer, expectedBuffer)) {
|
|
682
|
+
return false;
|
|
683
|
+
}
|
|
684
|
+
const toleranceSeconds = input.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;
|
|
685
|
+
if (toleranceSeconds === 0) {
|
|
686
|
+
return true;
|
|
687
|
+
}
|
|
688
|
+
if (toleranceSeconds < 0) {
|
|
689
|
+
return false;
|
|
690
|
+
}
|
|
691
|
+
const timestampMs = extractSignedTimestampMs(payloadString);
|
|
692
|
+
if (timestampMs === null) {
|
|
693
|
+
return false;
|
|
694
|
+
}
|
|
695
|
+
const ageMs = Math.abs(Date.now() - timestampMs);
|
|
696
|
+
return ageMs <= toleranceSeconds * 1e3;
|
|
697
|
+
} catch {
|
|
661
698
|
return false;
|
|
662
699
|
}
|
|
663
|
-
const ageMs = Math.abs(Date.now() - timestampMs);
|
|
664
|
-
return ageMs <= toleranceSeconds * 1e3;
|
|
665
700
|
}
|
|
666
701
|
|
|
667
702
|
// src/sdk.ts
|
|
@@ -712,6 +747,56 @@ function validateNonEmpty(value, fieldName) {
|
|
|
712
747
|
throwValidation(`${fieldName} is required`);
|
|
713
748
|
}
|
|
714
749
|
}
|
|
750
|
+
function validatePhoneFormat(normalizedPhone, fieldName) {
|
|
751
|
+
if (!isValidPhoneFormat(normalizedPhone)) {
|
|
752
|
+
throwValidation(`${fieldName} must be a valid phone number`);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
function prepareCollectPayload(input) {
|
|
756
|
+
const reference = resolveReference(input.reference);
|
|
757
|
+
validateCollectionAmount(input.amount);
|
|
758
|
+
validateNonEmpty(input.customer.name, "customer.name");
|
|
759
|
+
validateNonEmpty(input.customer.phoneNumber, "customer.phoneNumber");
|
|
760
|
+
const normalizedPhone = normalizePhone(input.customer.phoneNumber);
|
|
761
|
+
validatePhoneFormat(normalizedPhone, "customer.phoneNumber");
|
|
762
|
+
validateNonEmpty(input.description, "description");
|
|
763
|
+
if (input.method === "bank" && !input.bank) {
|
|
764
|
+
throwValidation('bank details are required when method is "bank"');
|
|
765
|
+
}
|
|
766
|
+
return {
|
|
767
|
+
...input,
|
|
768
|
+
reference,
|
|
769
|
+
customer: { ...input.customer, phoneNumber: normalizedPhone }
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
function preparePayoutPayload(input) {
|
|
773
|
+
const reference = resolveReference(input.reference);
|
|
774
|
+
validatePayoutAmount(input.amount);
|
|
775
|
+
validateNonEmpty(input.customer.name, "customer.name");
|
|
776
|
+
validateNonEmpty(input.customer.phoneNumber, "customer.phoneNumber");
|
|
777
|
+
const normalizedPhone = normalizePhone(input.customer.phoneNumber);
|
|
778
|
+
validatePhoneFormat(normalizedPhone, "customer.phoneNumber");
|
|
779
|
+
validateNonEmpty(input.description, "description");
|
|
780
|
+
validateNonEmpty(
|
|
781
|
+
input.destination.accountHolderName,
|
|
782
|
+
"destination.accountHolderName"
|
|
783
|
+
);
|
|
784
|
+
validateNonEmpty(
|
|
785
|
+
input.destination.accountNumber,
|
|
786
|
+
"destination.accountNumber"
|
|
787
|
+
);
|
|
788
|
+
return {
|
|
789
|
+
...input,
|
|
790
|
+
reference,
|
|
791
|
+
customer: { ...input.customer, phoneNumber: normalizedPhone }
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
function applyBeforeHookMutation(mutated, current, prepare) {
|
|
795
|
+
return prepare({
|
|
796
|
+
...mutated,
|
|
797
|
+
reference: mutated.reference ?? current.reference
|
|
798
|
+
});
|
|
799
|
+
}
|
|
715
800
|
function createSdkInstance(config) {
|
|
716
801
|
const transport = createTransport({
|
|
717
802
|
apiKey: config.apiKey,
|
|
@@ -735,23 +820,15 @@ function createSdkInstance(config) {
|
|
|
735
820
|
maxPollAttempts: config.maxPollAttempts
|
|
736
821
|
};
|
|
737
822
|
async function collectPayment(input) {
|
|
738
|
-
|
|
739
|
-
validateCollectionAmount(input.amount);
|
|
740
|
-
validateNonEmpty(input.customer.name, "customer.name");
|
|
741
|
-
validateNonEmpty(input.customer.phoneNumber, "customer.phoneNumber");
|
|
742
|
-
const normalizedPhone = normalizePhone(input.customer.phoneNumber);
|
|
743
|
-
validateNonEmpty(input.description, "description");
|
|
744
|
-
if (input.method === "bank" && !input.bank) {
|
|
745
|
-
throwValidation('bank details are required when method is "bank"');
|
|
746
|
-
}
|
|
747
|
-
let payload = {
|
|
748
|
-
...input,
|
|
749
|
-
reference,
|
|
750
|
-
customer: { ...input.customer, phoneNumber: normalizedPhone }
|
|
751
|
-
};
|
|
823
|
+
let payload = prepareCollectPayload(input);
|
|
752
824
|
const mutated = await runHook(config.hooks?.beforeCollect, payload);
|
|
753
|
-
if (mutated != null)
|
|
754
|
-
payload =
|
|
825
|
+
if (mutated != null) {
|
|
826
|
+
payload = applyBeforeHookMutation(
|
|
827
|
+
mutated,
|
|
828
|
+
payload,
|
|
829
|
+
prepareCollectPayload
|
|
830
|
+
);
|
|
831
|
+
}
|
|
755
832
|
const result = await transport.send({
|
|
756
833
|
action: SDK_ACTIONS.collectPayment,
|
|
757
834
|
payload
|
|
@@ -759,35 +836,27 @@ function createSdkInstance(config) {
|
|
|
759
836
|
await runHook(
|
|
760
837
|
config.hooks?.afterCollect,
|
|
761
838
|
result.isOk ? slangTs.Ok({ reference: result.value.reference, status: result.value.status }) : slangTs.Err(result.error),
|
|
762
|
-
payload
|
|
839
|
+
{ ...payload, raw: input }
|
|
763
840
|
);
|
|
764
841
|
if (result.isErr) {
|
|
765
842
|
const sdkErr = parseError(result.error);
|
|
766
843
|
return createPaymentInstance(
|
|
767
|
-
{ reference, status: "pending" },
|
|
844
|
+
{ reference: payload.reference, status: "pending" },
|
|
768
845
|
{ ...commonDeps, initialError: sdkErr }
|
|
769
846
|
);
|
|
770
847
|
}
|
|
771
848
|
return createPaymentInstance(result.value, commonDeps);
|
|
772
849
|
}
|
|
773
850
|
async function collectPaymentAndResolve(input) {
|
|
774
|
-
|
|
775
|
-
validateCollectionAmount(input.amount);
|
|
776
|
-
validateNonEmpty(input.customer.name, "customer.name");
|
|
777
|
-
validateNonEmpty(input.customer.phoneNumber, "customer.phoneNumber");
|
|
778
|
-
const normalizedPhone = normalizePhone(input.customer.phoneNumber);
|
|
779
|
-
validateNonEmpty(input.description, "description");
|
|
780
|
-
if (input.method === "bank" && !input.bank) {
|
|
781
|
-
throwValidation('bank details are required when method is "bank"');
|
|
782
|
-
}
|
|
783
|
-
let payload = {
|
|
784
|
-
...input,
|
|
785
|
-
reference,
|
|
786
|
-
customer: { ...input.customer, phoneNumber: normalizedPhone }
|
|
787
|
-
};
|
|
851
|
+
let payload = prepareCollectPayload(input);
|
|
788
852
|
const mutated = await runHook(config.hooks?.beforeCollect, payload);
|
|
789
|
-
if (mutated != null)
|
|
790
|
-
payload =
|
|
853
|
+
if (mutated != null) {
|
|
854
|
+
payload = applyBeforeHookMutation(
|
|
855
|
+
mutated,
|
|
856
|
+
payload,
|
|
857
|
+
prepareCollectPayload
|
|
858
|
+
);
|
|
859
|
+
}
|
|
791
860
|
const result = await transport.send({
|
|
792
861
|
action: SDK_ACTIONS.collectPaymentAndResolve,
|
|
793
862
|
payload
|
|
@@ -795,7 +864,7 @@ function createSdkInstance(config) {
|
|
|
795
864
|
await runHook(
|
|
796
865
|
config.hooks?.afterCollect,
|
|
797
866
|
result.isOk ? slangTs.Ok({ reference: result.value.reference, status: result.value.status }) : slangTs.Err(result.error),
|
|
798
|
-
payload
|
|
867
|
+
{ ...payload, raw: input }
|
|
799
868
|
);
|
|
800
869
|
if (result.isOk) {
|
|
801
870
|
return slangTs.Ok(result.value);
|
|
@@ -803,28 +872,11 @@ function createSdkInstance(config) {
|
|
|
803
872
|
return slangTs.Err(result.error);
|
|
804
873
|
}
|
|
805
874
|
async function makePayout(input) {
|
|
806
|
-
|
|
807
|
-
validatePayoutAmount(input.amount);
|
|
808
|
-
validateNonEmpty(input.customer.name, "customer.name");
|
|
809
|
-
validateNonEmpty(input.customer.phoneNumber, "customer.phoneNumber");
|
|
810
|
-
const normalizedPhone = normalizePhone(input.customer.phoneNumber);
|
|
811
|
-
validateNonEmpty(input.description, "description");
|
|
812
|
-
validateNonEmpty(
|
|
813
|
-
input.destination.accountHolderName,
|
|
814
|
-
"destination.accountHolderName"
|
|
815
|
-
);
|
|
816
|
-
validateNonEmpty(
|
|
817
|
-
input.destination.accountNumber,
|
|
818
|
-
"destination.accountNumber"
|
|
819
|
-
);
|
|
820
|
-
let payload = {
|
|
821
|
-
...input,
|
|
822
|
-
reference,
|
|
823
|
-
customer: { ...input.customer, phoneNumber: normalizedPhone }
|
|
824
|
-
};
|
|
875
|
+
let payload = preparePayoutPayload(input);
|
|
825
876
|
const mutated = await runHook(config.hooks?.beforePayout, payload);
|
|
826
|
-
if (mutated != null)
|
|
827
|
-
payload =
|
|
877
|
+
if (mutated != null) {
|
|
878
|
+
payload = applyBeforeHookMutation(mutated, payload, preparePayoutPayload);
|
|
879
|
+
}
|
|
828
880
|
const result = await transport.send({
|
|
829
881
|
action: SDK_ACTIONS.makePayout,
|
|
830
882
|
payload
|
|
@@ -832,40 +884,23 @@ function createSdkInstance(config) {
|
|
|
832
884
|
await runHook(
|
|
833
885
|
config.hooks?.afterPayout,
|
|
834
886
|
result.isOk ? slangTs.Ok({ reference: result.value.reference, status: result.value.status }) : slangTs.Err(result.error),
|
|
835
|
-
payload
|
|
887
|
+
{ ...payload, raw: input }
|
|
836
888
|
);
|
|
837
889
|
if (result.isErr) {
|
|
838
890
|
const sdkErr = parseError(result.error);
|
|
839
891
|
return createPaymentInstance(
|
|
840
|
-
{ reference, status: "pending" },
|
|
892
|
+
{ reference: payload.reference, status: "pending" },
|
|
841
893
|
{ ...commonDeps, initialError: sdkErr }
|
|
842
894
|
);
|
|
843
895
|
}
|
|
844
896
|
return createPaymentInstance(result.value, commonDeps);
|
|
845
897
|
}
|
|
846
898
|
async function makePayoutAndResolve(input) {
|
|
847
|
-
|
|
848
|
-
validatePayoutAmount(input.amount);
|
|
849
|
-
validateNonEmpty(input.customer.name, "customer.name");
|
|
850
|
-
validateNonEmpty(input.customer.phoneNumber, "customer.phoneNumber");
|
|
851
|
-
const normalizedPhone = normalizePhone(input.customer.phoneNumber);
|
|
852
|
-
validateNonEmpty(input.description, "description");
|
|
853
|
-
validateNonEmpty(
|
|
854
|
-
input.destination.accountHolderName,
|
|
855
|
-
"destination.accountHolderName"
|
|
856
|
-
);
|
|
857
|
-
validateNonEmpty(
|
|
858
|
-
input.destination.accountNumber,
|
|
859
|
-
"destination.accountNumber"
|
|
860
|
-
);
|
|
861
|
-
let payload = {
|
|
862
|
-
...input,
|
|
863
|
-
reference,
|
|
864
|
-
customer: { ...input.customer, phoneNumber: normalizedPhone }
|
|
865
|
-
};
|
|
899
|
+
let payload = preparePayoutPayload(input);
|
|
866
900
|
const mutated = await runHook(config.hooks?.beforePayout, payload);
|
|
867
|
-
if (mutated != null)
|
|
868
|
-
payload =
|
|
901
|
+
if (mutated != null) {
|
|
902
|
+
payload = applyBeforeHookMutation(mutated, payload, preparePayoutPayload);
|
|
903
|
+
}
|
|
869
904
|
const result = await transport.send({
|
|
870
905
|
action: SDK_ACTIONS.makePayoutAndResolve,
|
|
871
906
|
payload
|
|
@@ -873,7 +908,7 @@ function createSdkInstance(config) {
|
|
|
873
908
|
await runHook(
|
|
874
909
|
config.hooks?.afterPayout,
|
|
875
910
|
result.isOk ? slangTs.Ok({ reference: result.value.reference, status: result.value.status }) : slangTs.Err(result.error),
|
|
876
|
-
payload
|
|
911
|
+
{ ...payload, raw: input }
|
|
877
912
|
);
|
|
878
913
|
if (result.isOk) {
|
|
879
914
|
return slangTs.Ok(result.value);
|
|
@@ -907,6 +942,7 @@ function createSdkInstance(config) {
|
|
|
907
942
|
async function verifyPhone(input) {
|
|
908
943
|
validateNonEmpty(input.phoneNumber, "phoneNumber");
|
|
909
944
|
const normalizedPhone = normalizePhone(input.phoneNumber);
|
|
945
|
+
validatePhoneFormat(normalizedPhone, "phoneNumber");
|
|
910
946
|
const result = await transport.send({
|
|
911
947
|
action: SDK_ACTIONS.verifyPhone,
|
|
912
948
|
payload: { ...input, phoneNumber: normalizedPhone }
|