@nile-squad/nylonpay-ts 1.0.7 → 1.0.8
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 +123 -258
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +54 -23
- package/dist/index.d.ts +54 -23
- package/dist/index.js +123 -258
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -4,7 +4,7 @@ var crypto = require('crypto');
|
|
|
4
4
|
var slangTs = require('slang-ts');
|
|
5
5
|
var os = require('os');
|
|
6
6
|
|
|
7
|
-
// src/
|
|
7
|
+
// src/create-nylon-pay.ts
|
|
8
8
|
|
|
9
9
|
// src/pubsub.ts
|
|
10
10
|
function createEmitter() {
|
|
@@ -63,9 +63,7 @@ var DEFAULT_MAX_RETRIES = 3;
|
|
|
63
63
|
var DEFAULT_MAX_POLL_INTERVAL_MS = 2e3;
|
|
64
64
|
var DEFAULT_MAX_POLL_DURATION_MS = 3e5;
|
|
65
65
|
var DEFAULT_MAX_POLL_ATTEMPTS = 150;
|
|
66
|
-
var
|
|
67
|
-
var STREAM_PATH = "/sse/transaction";
|
|
68
|
-
var MAX_STREAM_RECONNECTS = 2;
|
|
66
|
+
var POLL_JITTER_MS = 250;
|
|
69
67
|
var SDK_SERVICE = "sdk";
|
|
70
68
|
var SDK_ACTIONS = {
|
|
71
69
|
collectPayment: "sdk-collect-payment",
|
|
@@ -93,13 +91,22 @@ function generateFingerprint() {
|
|
|
93
91
|
function generateNonce(length = 16) {
|
|
94
92
|
return crypto.randomBytes(length).toString("hex");
|
|
95
93
|
}
|
|
94
|
+
function compareByCodePoint(first, second) {
|
|
95
|
+
if (first < second) {
|
|
96
|
+
return -1;
|
|
97
|
+
}
|
|
98
|
+
if (first > second) {
|
|
99
|
+
return 1;
|
|
100
|
+
}
|
|
101
|
+
return 0;
|
|
102
|
+
}
|
|
96
103
|
function sortValue(value) {
|
|
97
104
|
if (Array.isArray(value)) {
|
|
98
105
|
return value.map((entry) => sortValue(entry));
|
|
99
106
|
}
|
|
100
107
|
if (value && typeof value === "object") {
|
|
101
108
|
const sortedEntries = Object.entries(value).sort(
|
|
102
|
-
([firstKey], [secondKey]) => firstKey
|
|
109
|
+
([firstKey], [secondKey]) => compareByCodePoint(firstKey, secondKey)
|
|
103
110
|
);
|
|
104
111
|
return Object.fromEntries(
|
|
105
112
|
sortedEntries.map(([entryKey, entryValue]) => [
|
|
@@ -123,42 +130,6 @@ function createSignature(input) {
|
|
|
123
130
|
function createTimestamp() {
|
|
124
131
|
return Date.now().toString();
|
|
125
132
|
}
|
|
126
|
-
|
|
127
|
-
// src/sse-parse.ts
|
|
128
|
-
function parseBlock(block) {
|
|
129
|
-
let event = "message";
|
|
130
|
-
const dataLines = [];
|
|
131
|
-
for (const rawLine of block.split("\n")) {
|
|
132
|
-
const line = rawLine.replace(/\r$/, "");
|
|
133
|
-
if (line.startsWith(":")) {
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
if (line.startsWith("event:")) {
|
|
137
|
-
event = line.slice("event:".length).trim();
|
|
138
|
-
} else if (line.startsWith("data:")) {
|
|
139
|
-
dataLines.push(line.slice("data:".length).trim());
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
if (dataLines.length === 0) {
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
return { event, data: dataLines.join("\n") };
|
|
146
|
-
}
|
|
147
|
-
function parseSseBuffer(buffer) {
|
|
148
|
-
const messages = [];
|
|
149
|
-
let rest = buffer;
|
|
150
|
-
let separator = rest.indexOf("\n\n");
|
|
151
|
-
while (separator !== -1) {
|
|
152
|
-
const block = rest.slice(0, separator);
|
|
153
|
-
rest = rest.slice(separator + 2);
|
|
154
|
-
const message = parseBlock(block);
|
|
155
|
-
if (message) {
|
|
156
|
-
messages.push(message);
|
|
157
|
-
}
|
|
158
|
-
separator = rest.indexOf("\n\n");
|
|
159
|
-
}
|
|
160
|
-
return { messages, rest };
|
|
161
|
-
}
|
|
162
133
|
function verifyResponseSignature(data, signature, secret) {
|
|
163
134
|
const expectedSignature = crypto.createHmac("sha256", secret).update(createCanonicalPayload(data)).digest("hex");
|
|
164
135
|
const providedBuffer = Buffer.from(signature, "hex");
|
|
@@ -171,13 +142,6 @@ function verifyResponseSignature(data, signature, secret) {
|
|
|
171
142
|
|
|
172
143
|
// src/transport.ts
|
|
173
144
|
var CACHED_FINGERPRINT = generateFingerprint();
|
|
174
|
-
function streamUrl(baseUrl) {
|
|
175
|
-
try {
|
|
176
|
-
return new URL(baseUrl).origin + STREAM_PATH;
|
|
177
|
-
} catch {
|
|
178
|
-
return baseUrl.replace(/\/api\/services\/?$/u, "") + STREAM_PATH;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
145
|
var KNOWN_CATEGORIES = /* @__PURE__ */ new Set([
|
|
182
146
|
"auth",
|
|
183
147
|
"validation",
|
|
@@ -343,22 +307,30 @@ function createTransport({
|
|
|
343
307
|
const { status, message, data } = responseBody;
|
|
344
308
|
if (status === true) {
|
|
345
309
|
const { data: strippedData, responseSignature } = stripResponseSignature(data);
|
|
346
|
-
if (responseSignature) {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
310
|
+
if (!responseSignature) {
|
|
311
|
+
cleanup();
|
|
312
|
+
return slangTs.Err(
|
|
313
|
+
JSON.stringify({
|
|
314
|
+
category: "internal",
|
|
315
|
+
message: "Response signature missing",
|
|
316
|
+
retryable: false
|
|
317
|
+
})
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
const isValid = verifyResponseSignature(
|
|
321
|
+
strippedData,
|
|
322
|
+
responseSignature,
|
|
323
|
+
apiSecret
|
|
324
|
+
);
|
|
325
|
+
if (!isValid) {
|
|
326
|
+
cleanup();
|
|
327
|
+
return slangTs.Err(
|
|
328
|
+
JSON.stringify({
|
|
329
|
+
category: "internal",
|
|
330
|
+
message: "Response signature verification failed",
|
|
331
|
+
retryable: false
|
|
332
|
+
})
|
|
351
333
|
);
|
|
352
|
-
if (!isValid) {
|
|
353
|
-
cleanup();
|
|
354
|
-
return slangTs.Err(
|
|
355
|
-
JSON.stringify({
|
|
356
|
-
category: "internal",
|
|
357
|
-
message: "Response signature verification failed",
|
|
358
|
-
retryable: false
|
|
359
|
-
})
|
|
360
|
-
);
|
|
361
|
-
}
|
|
362
334
|
}
|
|
363
335
|
cleanup();
|
|
364
336
|
return slangTs.Ok(strippedData);
|
|
@@ -383,91 +355,7 @@ function createTransport({
|
|
|
383
355
|
}
|
|
384
356
|
return attempt(0);
|
|
385
357
|
}
|
|
386
|
-
|
|
387
|
-
const controller = new AbortController();
|
|
388
|
-
let closed = false;
|
|
389
|
-
const close = () => {
|
|
390
|
-
if (closed) {
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
closed = true;
|
|
394
|
-
controller.abort();
|
|
395
|
-
};
|
|
396
|
-
const payload = {
|
|
397
|
-
reference: input.reference,
|
|
398
|
-
_fingerprint: CACHED_FINGERPRINT
|
|
399
|
-
};
|
|
400
|
-
const headers = buildAuthHeaders({ apiKey, apiSecret, payload });
|
|
401
|
-
const url = streamUrl(baseUrl);
|
|
402
|
-
const run = async () => {
|
|
403
|
-
const fetchResult = await slangTs.safeTry(
|
|
404
|
-
() => fetchImpl(url, {
|
|
405
|
-
method: "POST",
|
|
406
|
-
headers,
|
|
407
|
-
body: JSON.stringify(payload),
|
|
408
|
-
signal: controller.signal
|
|
409
|
-
})
|
|
410
|
-
);
|
|
411
|
-
if (fetchResult.isErr) {
|
|
412
|
-
if (!closed) {
|
|
413
|
-
input.onError(fetchResult.error);
|
|
414
|
-
}
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
417
|
-
const response = fetchResult.value;
|
|
418
|
-
if (!response.ok || !response.body) {
|
|
419
|
-
const textResult = await slangTs.safeTry(() => response.text());
|
|
420
|
-
const message = textResult.isOk ? textResult.value : `HTTP ${response.status}`;
|
|
421
|
-
if (!closed) {
|
|
422
|
-
input.onError(message || `HTTP ${response.status}`);
|
|
423
|
-
}
|
|
424
|
-
return;
|
|
425
|
-
}
|
|
426
|
-
const reader = response.body.getReader();
|
|
427
|
-
const decoder = new TextDecoder();
|
|
428
|
-
let buffer = "";
|
|
429
|
-
while (!closed) {
|
|
430
|
-
const chunkResult = await slangTs.safeTry(() => reader.read());
|
|
431
|
-
if (chunkResult.isErr) {
|
|
432
|
-
if (!closed) {
|
|
433
|
-
input.onError(chunkResult.error);
|
|
434
|
-
}
|
|
435
|
-
return;
|
|
436
|
-
}
|
|
437
|
-
const chunk = chunkResult.value;
|
|
438
|
-
if (chunk.done) {
|
|
439
|
-
break;
|
|
440
|
-
}
|
|
441
|
-
buffer += decoder.decode(chunk.value, { stream: true });
|
|
442
|
-
const { messages, rest } = parseSseBuffer(buffer);
|
|
443
|
-
buffer = rest;
|
|
444
|
-
for (const message of messages) {
|
|
445
|
-
if (message.event === "status") {
|
|
446
|
-
const statusResult = await slangTs.safeTry(
|
|
447
|
-
() => JSON.parse(message.data)
|
|
448
|
-
);
|
|
449
|
-
if (statusResult.isOk) {
|
|
450
|
-
input.onStatus(statusResult.value);
|
|
451
|
-
}
|
|
452
|
-
} else if (message.event === "error") {
|
|
453
|
-
const errDataResult = await slangTs.safeTry(
|
|
454
|
-
() => JSON.parse(message.data)
|
|
455
|
-
);
|
|
456
|
-
const text = errDataResult.isOk ? errDataResult.value.message ?? message.data : message.data;
|
|
457
|
-
close();
|
|
458
|
-
input.onError(text);
|
|
459
|
-
return;
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
if (!closed) {
|
|
464
|
-
input.onClose();
|
|
465
|
-
}
|
|
466
|
-
};
|
|
467
|
-
void run();
|
|
468
|
-
return { close };
|
|
469
|
-
}
|
|
470
|
-
return { send, openStream, parseError };
|
|
358
|
+
return { send, parseError };
|
|
471
359
|
}
|
|
472
360
|
function parseError(error) {
|
|
473
361
|
try {
|
|
@@ -517,11 +405,7 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
517
405
|
fetchTransaction: deps.fetchTransaction,
|
|
518
406
|
pollIntervalMs: deps.pollIntervalMs ?? 2e3,
|
|
519
407
|
maxPollDuration: deps.maxPollDuration ?? 3e5,
|
|
520
|
-
maxPollAttempts: deps.maxPollAttempts ?? 150
|
|
521
|
-
streaming: deps.streaming ?? false,
|
|
522
|
-
openStream: deps.openStream,
|
|
523
|
-
streamHandle: null,
|
|
524
|
-
streamReconnects: 0
|
|
408
|
+
maxPollAttempts: deps.maxPollAttempts ?? 150
|
|
525
409
|
};
|
|
526
410
|
function resolveWithError(error) {
|
|
527
411
|
state.resolved = true;
|
|
@@ -557,6 +441,9 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
557
441
|
stopUpdates();
|
|
558
442
|
}
|
|
559
443
|
async function handleStatusUpdate(response) {
|
|
444
|
+
if (state.resolved) {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
560
447
|
if (response.reference !== state.reference) {
|
|
561
448
|
resolveWithError(
|
|
562
449
|
`Reference mismatch: expected ${state.reference} but got ${response.reference}`
|
|
@@ -590,10 +477,11 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
590
477
|
if (state.resolved || state.pollingTimer) {
|
|
591
478
|
return;
|
|
592
479
|
}
|
|
480
|
+
const delay2 = state.pollIntervalMs + Math.random() * POLL_JITTER_MS;
|
|
593
481
|
state.pollingTimer = setTimeout(() => {
|
|
594
482
|
state.pollingTimer = null;
|
|
595
483
|
void pollStatus();
|
|
596
|
-
},
|
|
484
|
+
}, delay2);
|
|
597
485
|
}
|
|
598
486
|
async function pollStatus() {
|
|
599
487
|
if (state.resolved) {
|
|
@@ -621,42 +509,6 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
621
509
|
}
|
|
622
510
|
scheduleNextPoll();
|
|
623
511
|
}
|
|
624
|
-
function closeStream() {
|
|
625
|
-
if (state.streamHandle) {
|
|
626
|
-
state.streamHandle.close();
|
|
627
|
-
state.streamHandle = null;
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
function startStream() {
|
|
631
|
-
if (state.resolved || !state.openStream) {
|
|
632
|
-
return;
|
|
633
|
-
}
|
|
634
|
-
state.streamHandle = state.openStream({
|
|
635
|
-
reference: state.reference,
|
|
636
|
-
onStatus: (status) => {
|
|
637
|
-
void handleStatusUpdate(status);
|
|
638
|
-
},
|
|
639
|
-
onError: () => handleStreamFailure(),
|
|
640
|
-
onClose: () => handleStreamFailure()
|
|
641
|
-
});
|
|
642
|
-
}
|
|
643
|
-
function handleStreamFailure() {
|
|
644
|
-
closeStream();
|
|
645
|
-
if (state.resolved) {
|
|
646
|
-
return;
|
|
647
|
-
}
|
|
648
|
-
if (state.streamReconnects < MAX_STREAM_RECONNECTS) {
|
|
649
|
-
state.streamReconnects += 1;
|
|
650
|
-
const backoff = 500 * 2 ** (state.streamReconnects - 1) + Math.random() * 250;
|
|
651
|
-
setTimeout(() => {
|
|
652
|
-
if (!state.resolved) {
|
|
653
|
-
startStream();
|
|
654
|
-
}
|
|
655
|
-
}, backoff);
|
|
656
|
-
return;
|
|
657
|
-
}
|
|
658
|
-
scheduleNextPoll();
|
|
659
|
-
}
|
|
660
512
|
function startUpdates() {
|
|
661
513
|
if (TERMINAL_STATES.has(state.status)) {
|
|
662
514
|
setTimeout(() => {
|
|
@@ -664,10 +516,6 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
664
516
|
}, 0);
|
|
665
517
|
return;
|
|
666
518
|
}
|
|
667
|
-
if (state.streaming && state.openStream) {
|
|
668
|
-
startStream();
|
|
669
|
-
return;
|
|
670
|
-
}
|
|
671
519
|
scheduleNextPoll();
|
|
672
520
|
}
|
|
673
521
|
function stopUpdates() {
|
|
@@ -675,7 +523,6 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
675
523
|
clearTimeout(state.pollingTimer);
|
|
676
524
|
state.pollingTimer = null;
|
|
677
525
|
}
|
|
678
|
-
closeStream();
|
|
679
526
|
}
|
|
680
527
|
function on(event, handler) {
|
|
681
528
|
state.emitter.on(event, handler);
|
|
@@ -748,21 +595,65 @@ function createPaymentInstance(initialResponse, deps) {
|
|
|
748
595
|
}
|
|
749
596
|
return paymentInstance;
|
|
750
597
|
}
|
|
598
|
+
var DEFAULT_TOLERANCE_SECONDS = 300;
|
|
599
|
+
function decodePayload(payload) {
|
|
600
|
+
return typeof payload === "string" ? payload : Buffer.from(payload).toString("utf8");
|
|
601
|
+
}
|
|
602
|
+
function extractSignedTimestampMs(payloadString) {
|
|
603
|
+
let parsed;
|
|
604
|
+
try {
|
|
605
|
+
parsed = JSON.parse(payloadString);
|
|
606
|
+
} catch {
|
|
607
|
+
return null;
|
|
608
|
+
}
|
|
609
|
+
if (!parsed || typeof parsed !== "object") {
|
|
610
|
+
return null;
|
|
611
|
+
}
|
|
612
|
+
const raw = parsed.timestamp;
|
|
613
|
+
if (typeof raw === "number" && Number.isFinite(raw)) {
|
|
614
|
+
return raw < 1e12 ? raw * 1e3 : raw;
|
|
615
|
+
}
|
|
616
|
+
if (typeof raw === "string") {
|
|
617
|
+
const ms = Date.parse(raw);
|
|
618
|
+
return Number.isNaN(ms) ? null : ms;
|
|
619
|
+
}
|
|
620
|
+
return null;
|
|
621
|
+
}
|
|
751
622
|
function verifyWebhookSignature(input) {
|
|
752
|
-
const
|
|
623
|
+
const payloadString = decodePayload(input.payload);
|
|
624
|
+
const payloadBytes = Buffer.from(payloadString, "utf8");
|
|
753
625
|
const expectedSignature = crypto.createHmac("sha256", input.secret).update(payloadBytes).digest("hex");
|
|
754
626
|
const providedBuffer = Buffer.from(input.signature, "hex");
|
|
755
627
|
const expectedBuffer = Buffer.from(expectedSignature, "hex");
|
|
756
628
|
if (providedBuffer.length !== expectedBuffer.length) {
|
|
757
629
|
return false;
|
|
758
630
|
}
|
|
759
|
-
|
|
631
|
+
if (!crypto.timingSafeEqual(providedBuffer, expectedBuffer)) {
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
const toleranceSeconds = input.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;
|
|
635
|
+
if (toleranceSeconds <= 0) {
|
|
636
|
+
return true;
|
|
637
|
+
}
|
|
638
|
+
const timestampMs = extractSignedTimestampMs(payloadString);
|
|
639
|
+
if (timestampMs === null) {
|
|
640
|
+
return false;
|
|
641
|
+
}
|
|
642
|
+
const ageMs = Math.abs(Date.now() - timestampMs);
|
|
643
|
+
return ageMs <= toleranceSeconds * 1e3;
|
|
760
644
|
}
|
|
761
645
|
|
|
762
646
|
// src/sdk.ts
|
|
763
647
|
function generateReference() {
|
|
764
648
|
return crypto.randomBytes(16).toString("hex").slice(0, 15);
|
|
765
649
|
}
|
|
650
|
+
async function runHook(hook, ...args) {
|
|
651
|
+
if (!hook || hook.enabled === false) return void 0;
|
|
652
|
+
const result = await slangTs.safeTry(async () => hook.fn(...args));
|
|
653
|
+
if (result.isOk) return result.value;
|
|
654
|
+
await slangTs.safeTry(async () => hook.onError(result.error));
|
|
655
|
+
return void 0;
|
|
656
|
+
}
|
|
766
657
|
function throwValidation(message) {
|
|
767
658
|
throw createSdkError({ category: "validation", message });
|
|
768
659
|
}
|
|
@@ -796,9 +687,7 @@ function createSdkInstance(config) {
|
|
|
796
687
|
}),
|
|
797
688
|
pollIntervalMs: config.maxPollIntervalMs,
|
|
798
689
|
maxPollDuration: config.maxPollDurationMs,
|
|
799
|
-
maxPollAttempts: config.maxPollAttempts
|
|
800
|
-
streaming: config.streaming,
|
|
801
|
-
openStream: config.streaming ? transport.openStream : void 0
|
|
690
|
+
maxPollAttempts: config.maxPollAttempts
|
|
802
691
|
};
|
|
803
692
|
async function collectPayment(input) {
|
|
804
693
|
const reference = input.reference ?? generateReference();
|
|
@@ -810,24 +699,18 @@ function createSdkInstance(config) {
|
|
|
810
699
|
throwValidation('bank details are required when method is "bank"');
|
|
811
700
|
}
|
|
812
701
|
let payload = { ...input, reference };
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
payload = { ...mutated, reference: mutated.reference ?? reference };
|
|
817
|
-
}
|
|
702
|
+
const mutated = await runHook(config.hooks?.beforeCollect, payload);
|
|
703
|
+
if (mutated != null)
|
|
704
|
+
payload = { ...mutated, reference: mutated.reference ?? reference };
|
|
818
705
|
const result = await transport.send({
|
|
819
706
|
action: SDK_ACTIONS.collectPayment,
|
|
820
707
|
payload
|
|
821
708
|
});
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
}) : slangTs.Err(result.error),
|
|
828
|
-
payload
|
|
829
|
-
);
|
|
830
|
-
}
|
|
709
|
+
await runHook(
|
|
710
|
+
config.hooks?.afterCollect,
|
|
711
|
+
result.isOk ? slangTs.Ok({ reference: result.value.reference, status: result.value.status }) : slangTs.Err(result.error),
|
|
712
|
+
payload
|
|
713
|
+
);
|
|
831
714
|
if (result.isErr) {
|
|
832
715
|
const sdkErr = parseError(result.error);
|
|
833
716
|
return createPaymentInstance(
|
|
@@ -847,24 +730,18 @@ function createSdkInstance(config) {
|
|
|
847
730
|
throwValidation('bank details are required when method is "bank"');
|
|
848
731
|
}
|
|
849
732
|
let payload = { ...input, reference };
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
payload = { ...mutated, reference: mutated.reference ?? reference };
|
|
854
|
-
}
|
|
733
|
+
const mutated = await runHook(config.hooks?.beforeCollect, payload);
|
|
734
|
+
if (mutated != null)
|
|
735
|
+
payload = { ...mutated, reference: mutated.reference ?? reference };
|
|
855
736
|
const result = await transport.send({
|
|
856
737
|
action: SDK_ACTIONS.collectPaymentAndResolve,
|
|
857
738
|
payload
|
|
858
739
|
});
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
}) : slangTs.Err(result.error),
|
|
865
|
-
payload
|
|
866
|
-
);
|
|
867
|
-
}
|
|
740
|
+
await runHook(
|
|
741
|
+
config.hooks?.afterCollect,
|
|
742
|
+
result.isOk ? slangTs.Ok({ reference: result.value.reference, status: result.value.status }) : slangTs.Err(result.error),
|
|
743
|
+
payload
|
|
744
|
+
);
|
|
868
745
|
if (result.isOk) {
|
|
869
746
|
return slangTs.Ok(result.value);
|
|
870
747
|
}
|
|
@@ -885,24 +762,18 @@ function createSdkInstance(config) {
|
|
|
885
762
|
"destination.accountNumber"
|
|
886
763
|
);
|
|
887
764
|
let payload = { ...input, reference };
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
payload = { ...mutated, reference: mutated.reference ?? reference };
|
|
892
|
-
}
|
|
765
|
+
const mutated = await runHook(config.hooks?.beforePayout, payload);
|
|
766
|
+
if (mutated != null)
|
|
767
|
+
payload = { ...mutated, reference: mutated.reference ?? reference };
|
|
893
768
|
const result = await transport.send({
|
|
894
769
|
action: SDK_ACTIONS.makePayout,
|
|
895
770
|
payload
|
|
896
771
|
});
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
}) : slangTs.Err(result.error),
|
|
903
|
-
payload
|
|
904
|
-
);
|
|
905
|
-
}
|
|
772
|
+
await runHook(
|
|
773
|
+
config.hooks?.afterPayout,
|
|
774
|
+
result.isOk ? slangTs.Ok({ reference: result.value.reference, status: result.value.status }) : slangTs.Err(result.error),
|
|
775
|
+
payload
|
|
776
|
+
);
|
|
906
777
|
if (result.isErr) {
|
|
907
778
|
const sdkErr = parseError(result.error);
|
|
908
779
|
return createPaymentInstance(
|
|
@@ -927,24 +798,18 @@ function createSdkInstance(config) {
|
|
|
927
798
|
"destination.accountNumber"
|
|
928
799
|
);
|
|
929
800
|
let payload = { ...input, reference };
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
payload = { ...mutated, reference: mutated.reference ?? reference };
|
|
934
|
-
}
|
|
801
|
+
const mutated = await runHook(config.hooks?.beforePayout, payload);
|
|
802
|
+
if (mutated != null)
|
|
803
|
+
payload = { ...mutated, reference: mutated.reference ?? reference };
|
|
935
804
|
const result = await transport.send({
|
|
936
805
|
action: SDK_ACTIONS.makePayoutAndResolve,
|
|
937
806
|
payload
|
|
938
807
|
});
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
}) : slangTs.Err(result.error),
|
|
945
|
-
payload
|
|
946
|
-
);
|
|
947
|
-
}
|
|
808
|
+
await runHook(
|
|
809
|
+
config.hooks?.afterPayout,
|
|
810
|
+
result.isOk ? slangTs.Ok({ reference: result.value.reference, status: result.value.status }) : slangTs.Err(result.error),
|
|
811
|
+
payload
|
|
812
|
+
);
|
|
948
813
|
if (result.isOk) {
|
|
949
814
|
return slangTs.Ok(result.value);
|
|
950
815
|
}
|
|
@@ -1044,7 +909,8 @@ function createNylonPay(config) {
|
|
|
1044
909
|
throw new Error('apiSecret must start with "nps_"');
|
|
1045
910
|
}
|
|
1046
911
|
const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
|
|
1047
|
-
const
|
|
912
|
+
const secretHash = crypto.createHash("sha256").update(config.apiSecret).digest("hex").slice(0, 16);
|
|
913
|
+
const instanceKey = `${config.apiKey}:${baseUrl}:${secretHash}`;
|
|
1048
914
|
if (!config.force) {
|
|
1049
915
|
const existing = instances.get(instanceKey);
|
|
1050
916
|
if (existing) return existing;
|
|
@@ -1058,7 +924,6 @@ function createNylonPay(config) {
|
|
|
1058
924
|
maxPollIntervalMs: config.maxPollIntervalMs ?? DEFAULT_MAX_POLL_INTERVAL_MS,
|
|
1059
925
|
maxPollDurationMs: config.maxPollDurationMs ?? DEFAULT_MAX_POLL_DURATION_MS,
|
|
1060
926
|
maxPollAttempts: config.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS,
|
|
1061
|
-
streaming: config.streaming ?? DEFAULT_STREAMING,
|
|
1062
927
|
fetch: config.fetch ?? globalThis.fetch.bind(globalThis),
|
|
1063
928
|
hooks: config.hooks
|
|
1064
929
|
};
|