@nile-squad/nylonpay-ts 1.0.0 → 1.0.2
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 +17 -5
- package/dist/index.cjs +296 -230
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +57 -3
- package/dist/index.d.ts +57 -3
- package/dist/index.js +296 -230
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ function createEmitter() {
|
|
|
13
13
|
if (!state.listeners.has(event)) {
|
|
14
14
|
state.listeners.set(event, /* @__PURE__ */ new Set());
|
|
15
15
|
}
|
|
16
|
-
state.listeners.get(event)
|
|
16
|
+
state.listeners.get(event)?.add(handler);
|
|
17
17
|
return () => off(event, handler);
|
|
18
18
|
}
|
|
19
19
|
function once(event, handler) {
|
|
@@ -53,217 +53,24 @@ function createEmitter() {
|
|
|
53
53
|
const emitter = { on, once, off, emit, clear, listenerCount };
|
|
54
54
|
return emitter;
|
|
55
55
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
56
|
+
function generateFingerprint() {
|
|
57
|
+
const components = [
|
|
58
|
+
`type:${type()}`,
|
|
59
|
+
`platform:${platform()}`,
|
|
60
|
+
`arch:${arch()}`,
|
|
61
|
+
`release:${release()}`,
|
|
62
|
+
`hostname:${hostname()}`,
|
|
63
|
+
`node:${process.versions.node}`,
|
|
64
|
+
`v8:${process.versions.v8}`
|
|
65
|
+
].join("|");
|
|
66
|
+
return createHash("sha256").update(components).digest("hex");
|
|
66
67
|
}
|
|
67
|
-
|
|
68
|
-
"
|
|
69
|
-
"failed",
|
|
70
|
-
"cancelled"
|
|
71
|
-
]);
|
|
72
|
-
function createPaymentInstance(initialResponse, deps) {
|
|
73
|
-
const state = {
|
|
74
|
-
reference: initialResponse.reference,
|
|
75
|
-
status: initialResponse.status,
|
|
76
|
-
transaction: null,
|
|
77
|
-
pollingTimer: null,
|
|
78
|
-
resolved: false,
|
|
79
|
-
pollAttempts: 0,
|
|
80
|
-
pollStartTime: Date.now(),
|
|
81
|
-
emitter: createEmitter(),
|
|
82
|
-
fetchStatus: deps.fetchStatus,
|
|
83
|
-
fetchTransaction: deps.fetchTransaction,
|
|
84
|
-
pollIntervalMs: deps.pollIntervalMs ?? 2e3,
|
|
85
|
-
maxPollDuration: deps.maxPollDuration ?? 3e5,
|
|
86
|
-
maxPollAttempts: deps.maxPollAttempts ?? 150
|
|
87
|
-
};
|
|
88
|
-
function resolveWithError(error) {
|
|
89
|
-
state.resolved = true;
|
|
90
|
-
stopPolling();
|
|
91
|
-
emitEvent("error", error);
|
|
92
|
-
}
|
|
93
|
-
function emitEvent(event, error) {
|
|
94
|
-
const data = {
|
|
95
|
-
event,
|
|
96
|
-
transaction: state.transaction ?? void 0,
|
|
97
|
-
error,
|
|
98
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
99
|
-
};
|
|
100
|
-
state.emitter.emit(event, data);
|
|
101
|
-
}
|
|
102
|
-
async function handleTerminalState(status) {
|
|
103
|
-
const txResult = await state.fetchTransaction({
|
|
104
|
-
reference: state.reference
|
|
105
|
-
});
|
|
106
|
-
if (txResult.isOk) {
|
|
107
|
-
state.transaction = txResult.value;
|
|
108
|
-
const event = statusToEvent(status);
|
|
109
|
-
if (event) {
|
|
110
|
-
emitEvent(event);
|
|
111
|
-
}
|
|
112
|
-
} else {
|
|
113
|
-
emitEvent("error", `Failed to fetch transaction: ${txResult.error}`);
|
|
114
|
-
}
|
|
115
|
-
state.resolved = true;
|
|
116
|
-
stopPolling();
|
|
117
|
-
}
|
|
118
|
-
async function handleStatusUpdate(response) {
|
|
119
|
-
if (response.reference !== state.reference) {
|
|
120
|
-
resolveWithError(
|
|
121
|
-
`Reference mismatch: expected ${state.reference} but got ${response.reference}`
|
|
122
|
-
);
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
const newStatus = response.status;
|
|
126
|
-
const oldStatus = state.status;
|
|
127
|
-
state.status = newStatus;
|
|
128
|
-
if (newStatus !== oldStatus) {
|
|
129
|
-
const event = statusToEvent(newStatus);
|
|
130
|
-
if (event) {
|
|
131
|
-
if (TERMINAL_STATES.has(newStatus)) {
|
|
132
|
-
await handleTerminalState(newStatus);
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
emitEvent(event);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
function handlePollError(error) {
|
|
140
|
-
const isNotFound = error.includes("not found") || error.includes("NOT_FOUND");
|
|
141
|
-
if (isNotFound) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
emitEvent("error", error);
|
|
145
|
-
state.resolved = true;
|
|
146
|
-
stopPolling();
|
|
147
|
-
}
|
|
148
|
-
function scheduleNextPoll() {
|
|
149
|
-
if (state.resolved || state.pollingTimer) {
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
state.pollingTimer = setTimeout(() => {
|
|
153
|
-
state.pollingTimer = null;
|
|
154
|
-
void pollStatus();
|
|
155
|
-
}, state.pollIntervalMs);
|
|
156
|
-
}
|
|
157
|
-
async function pollStatus() {
|
|
158
|
-
if (state.resolved) {
|
|
159
|
-
stopPolling();
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
if (state.pollAttempts >= state.maxPollAttempts) {
|
|
163
|
-
resolveWithError("Polling timeout: exceeded maximum attempts");
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
if (Date.now() - state.pollStartTime >= state.maxPollDuration) {
|
|
167
|
-
resolveWithError("Polling timeout: exceeded maximum duration");
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
state.pollAttempts += 1;
|
|
171
|
-
const result = await state.fetchStatus({ reference: state.reference });
|
|
172
|
-
if (result.isOk) {
|
|
173
|
-
await handleStatusUpdate(result.value);
|
|
174
|
-
} else {
|
|
175
|
-
handlePollError(result.error);
|
|
176
|
-
}
|
|
177
|
-
if (state.resolved) {
|
|
178
|
-
stopPolling();
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
scheduleNextPoll();
|
|
182
|
-
}
|
|
183
|
-
function startPolling() {
|
|
184
|
-
scheduleNextPoll();
|
|
185
|
-
}
|
|
186
|
-
function stopPolling() {
|
|
187
|
-
if (state.pollingTimer) {
|
|
188
|
-
clearTimeout(state.pollingTimer);
|
|
189
|
-
state.pollingTimer = null;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
function on(event, handler) {
|
|
193
|
-
state.emitter.on(event, handler);
|
|
194
|
-
return paymentInstance;
|
|
195
|
-
}
|
|
196
|
-
function off(event, handler) {
|
|
197
|
-
state.emitter.off(event, handler);
|
|
198
|
-
return paymentInstance;
|
|
199
|
-
}
|
|
200
|
-
function once(event, handler) {
|
|
201
|
-
state.emitter.once(event, handler);
|
|
202
|
-
return paymentInstance;
|
|
203
|
-
}
|
|
204
|
-
function wait() {
|
|
205
|
-
return new Promise((resolve, reject) => {
|
|
206
|
-
if (state.resolved) {
|
|
207
|
-
if (state.status === "successful" && state.transaction) {
|
|
208
|
-
resolve(state.transaction);
|
|
209
|
-
} else {
|
|
210
|
-
reject(new Error(`Payment ${state.status ?? "error"}`));
|
|
211
|
-
}
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
function onSuccess() {
|
|
215
|
-
cleanup();
|
|
216
|
-
if (state.transaction) {
|
|
217
|
-
resolve(state.transaction);
|
|
218
|
-
} else {
|
|
219
|
-
reject(
|
|
220
|
-
new Error("Payment successful but transaction data unavailable")
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
function onFailed() {
|
|
225
|
-
cleanup();
|
|
226
|
-
reject(new Error("Payment failed"));
|
|
227
|
-
}
|
|
228
|
-
function onCancelled() {
|
|
229
|
-
cleanup();
|
|
230
|
-
reject(new Error("Payment cancelled"));
|
|
231
|
-
}
|
|
232
|
-
function onError(data) {
|
|
233
|
-
cleanup();
|
|
234
|
-
const eventData = data;
|
|
235
|
-
reject(new Error(eventData.error ?? "Payment error"));
|
|
236
|
-
}
|
|
237
|
-
function cleanup() {
|
|
238
|
-
state.emitter.off("success", onSuccess);
|
|
239
|
-
state.emitter.off("failed", onFailed);
|
|
240
|
-
state.emitter.off("cancelled", onCancelled);
|
|
241
|
-
state.emitter.off("error", onError);
|
|
242
|
-
}
|
|
243
|
-
state.emitter.on("success", onSuccess);
|
|
244
|
-
state.emitter.on("failed", onFailed);
|
|
245
|
-
state.emitter.on("cancelled", onCancelled);
|
|
246
|
-
state.emitter.on("error", onError);
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
const paymentInstance = {
|
|
250
|
-
get reference() {
|
|
251
|
-
return state.reference;
|
|
252
|
-
},
|
|
253
|
-
get status() {
|
|
254
|
-
return state.status;
|
|
255
|
-
},
|
|
256
|
-
on,
|
|
257
|
-
once,
|
|
258
|
-
off,
|
|
259
|
-
wait
|
|
260
|
-
};
|
|
261
|
-
startPolling();
|
|
262
|
-
return paymentInstance;
|
|
68
|
+
function generateNonce(length = 16) {
|
|
69
|
+
return randomBytes(length).toString("hex");
|
|
263
70
|
}
|
|
264
71
|
|
|
265
72
|
// src/sdk.config.ts
|
|
266
|
-
var DEFAULT_BASE_URL = "https://api.nylonpay.
|
|
73
|
+
var DEFAULT_BASE_URL = "https://api.nylonpay.nilesquad.com/api/services";
|
|
267
74
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
268
75
|
var DEFAULT_MAX_RETRIES = 3;
|
|
269
76
|
var DEFAULT_MAX_POLL_INTERVAL_MS = 2e3;
|
|
@@ -281,21 +88,6 @@ var SDK_ACTIONS = {
|
|
|
281
88
|
createInvoice: "sdk-create-invoice"
|
|
282
89
|
};
|
|
283
90
|
var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
|
|
284
|
-
function generateFingerprint() {
|
|
285
|
-
const components = [
|
|
286
|
-
`type:${type()}`,
|
|
287
|
-
`platform:${platform()}`,
|
|
288
|
-
`arch:${arch()}`,
|
|
289
|
-
`release:${release()}`,
|
|
290
|
-
`hostname:${hostname()}`,
|
|
291
|
-
`node:${process.versions.node}`,
|
|
292
|
-
`v8:${process.versions.v8}`
|
|
293
|
-
].join("|");
|
|
294
|
-
return createHash("sha256").update(components).digest("hex");
|
|
295
|
-
}
|
|
296
|
-
function generateNonce(length = 16) {
|
|
297
|
-
return randomBytes(length).toString("hex");
|
|
298
|
-
}
|
|
299
91
|
function sortValue(value) {
|
|
300
92
|
if (Array.isArray(value)) {
|
|
301
93
|
return value.map((entry) => sortValue(entry));
|
|
@@ -515,6 +307,214 @@ function parseError(error) {
|
|
|
515
307
|
}
|
|
516
308
|
return { code: "UNKNOWN", message: error };
|
|
517
309
|
}
|
|
310
|
+
|
|
311
|
+
// src/payment.ts
|
|
312
|
+
var STATUS_TO_EVENT = {
|
|
313
|
+
successful: "success",
|
|
314
|
+
failed: "failed",
|
|
315
|
+
processing: "processing",
|
|
316
|
+
cancelled: "cancelled"
|
|
317
|
+
};
|
|
318
|
+
function statusToEvent(status) {
|
|
319
|
+
return STATUS_TO_EVENT[status] ?? null;
|
|
320
|
+
}
|
|
321
|
+
var TERMINAL_STATES = /* @__PURE__ */ new Set([
|
|
322
|
+
"successful",
|
|
323
|
+
"failed",
|
|
324
|
+
"cancelled"
|
|
325
|
+
]);
|
|
326
|
+
function createPaymentInstance(initialResponse, deps) {
|
|
327
|
+
const state = {
|
|
328
|
+
reference: initialResponse.reference,
|
|
329
|
+
status: initialResponse.status,
|
|
330
|
+
transaction: null,
|
|
331
|
+
pollingTimer: null,
|
|
332
|
+
resolved: false,
|
|
333
|
+
pollAttempts: 0,
|
|
334
|
+
pollStartTime: Date.now(),
|
|
335
|
+
emitter: createEmitter(),
|
|
336
|
+
fetchStatus: deps.fetchStatus,
|
|
337
|
+
fetchTransaction: deps.fetchTransaction,
|
|
338
|
+
pollIntervalMs: deps.pollIntervalMs ?? 2e3,
|
|
339
|
+
maxPollDuration: deps.maxPollDuration ?? 3e5,
|
|
340
|
+
maxPollAttempts: deps.maxPollAttempts ?? 150
|
|
341
|
+
};
|
|
342
|
+
function resolveWithError(error) {
|
|
343
|
+
state.resolved = true;
|
|
344
|
+
stopPolling();
|
|
345
|
+
emitEvent("error", parseError(error).message);
|
|
346
|
+
}
|
|
347
|
+
function emitEvent(event, error) {
|
|
348
|
+
const data = {
|
|
349
|
+
event,
|
|
350
|
+
transaction: state.transaction ?? void 0,
|
|
351
|
+
error,
|
|
352
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
353
|
+
};
|
|
354
|
+
state.emitter.emit(event, data);
|
|
355
|
+
}
|
|
356
|
+
async function handleTerminalState(status) {
|
|
357
|
+
const txResult = await state.fetchTransaction({
|
|
358
|
+
reference: state.reference
|
|
359
|
+
});
|
|
360
|
+
if (txResult.isOk) {
|
|
361
|
+
state.transaction = txResult.value;
|
|
362
|
+
const event = statusToEvent(status);
|
|
363
|
+
if (event) {
|
|
364
|
+
emitEvent(event);
|
|
365
|
+
}
|
|
366
|
+
} else {
|
|
367
|
+
emitEvent("error", `Failed to fetch transaction: ${txResult.error}`);
|
|
368
|
+
}
|
|
369
|
+
state.resolved = true;
|
|
370
|
+
stopPolling();
|
|
371
|
+
}
|
|
372
|
+
async function handleStatusUpdate(response) {
|
|
373
|
+
if (response.reference !== state.reference) {
|
|
374
|
+
resolveWithError(
|
|
375
|
+
`Reference mismatch: expected ${state.reference} but got ${response.reference}`
|
|
376
|
+
);
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
const newStatus = response.status;
|
|
380
|
+
const oldStatus = state.status;
|
|
381
|
+
state.status = newStatus;
|
|
382
|
+
if (newStatus !== oldStatus) {
|
|
383
|
+
const event = statusToEvent(newStatus);
|
|
384
|
+
if (event) {
|
|
385
|
+
if (TERMINAL_STATES.has(newStatus)) {
|
|
386
|
+
await handleTerminalState(newStatus);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
emitEvent(event);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function handlePollError(error) {
|
|
394
|
+
const isNotFound = error.includes("not found") || error.includes("NOT_FOUND");
|
|
395
|
+
if (isNotFound) {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
emitEvent("error", parseError(error).message);
|
|
399
|
+
state.resolved = true;
|
|
400
|
+
stopPolling();
|
|
401
|
+
}
|
|
402
|
+
function scheduleNextPoll() {
|
|
403
|
+
if (state.resolved || state.pollingTimer) {
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
state.pollingTimer = setTimeout(() => {
|
|
407
|
+
state.pollingTimer = null;
|
|
408
|
+
void pollStatus();
|
|
409
|
+
}, state.pollIntervalMs);
|
|
410
|
+
}
|
|
411
|
+
async function pollStatus() {
|
|
412
|
+
if (state.resolved) {
|
|
413
|
+
stopPolling();
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
if (state.pollAttempts >= state.maxPollAttempts) {
|
|
417
|
+
resolveWithError("Polling timeout: exceeded maximum attempts");
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
if (Date.now() - state.pollStartTime >= state.maxPollDuration) {
|
|
421
|
+
resolveWithError("Polling timeout: exceeded maximum duration");
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
state.pollAttempts += 1;
|
|
425
|
+
const result = await state.fetchStatus({ reference: state.reference });
|
|
426
|
+
if (result.isOk) {
|
|
427
|
+
await handleStatusUpdate(result.value);
|
|
428
|
+
} else {
|
|
429
|
+
handlePollError(result.error);
|
|
430
|
+
}
|
|
431
|
+
if (state.resolved) {
|
|
432
|
+
stopPolling();
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
scheduleNextPoll();
|
|
436
|
+
}
|
|
437
|
+
function startPolling() {
|
|
438
|
+
scheduleNextPoll();
|
|
439
|
+
}
|
|
440
|
+
function stopPolling() {
|
|
441
|
+
if (state.pollingTimer) {
|
|
442
|
+
clearTimeout(state.pollingTimer);
|
|
443
|
+
state.pollingTimer = null;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
function on(event, handler) {
|
|
447
|
+
state.emitter.on(event, handler);
|
|
448
|
+
return paymentInstance;
|
|
449
|
+
}
|
|
450
|
+
function off(event, handler) {
|
|
451
|
+
state.emitter.off(event, handler);
|
|
452
|
+
return paymentInstance;
|
|
453
|
+
}
|
|
454
|
+
function once(event, handler) {
|
|
455
|
+
state.emitter.once(event, handler);
|
|
456
|
+
return paymentInstance;
|
|
457
|
+
}
|
|
458
|
+
function wait() {
|
|
459
|
+
return new Promise((resolve, reject) => {
|
|
460
|
+
if (state.resolved) {
|
|
461
|
+
if (state.status === "successful" && state.transaction) {
|
|
462
|
+
resolve(state.transaction);
|
|
463
|
+
} else {
|
|
464
|
+
reject(new Error(`Payment ${state.status ?? "error"}`));
|
|
465
|
+
}
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
function onSuccess() {
|
|
469
|
+
cleanup();
|
|
470
|
+
if (state.transaction) {
|
|
471
|
+
resolve(state.transaction);
|
|
472
|
+
} else {
|
|
473
|
+
reject(
|
|
474
|
+
new Error("Payment successful but transaction data unavailable")
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
function onFailed() {
|
|
479
|
+
cleanup();
|
|
480
|
+
reject(new Error("Payment failed"));
|
|
481
|
+
}
|
|
482
|
+
function onCancelled() {
|
|
483
|
+
cleanup();
|
|
484
|
+
reject(new Error("Payment cancelled"));
|
|
485
|
+
}
|
|
486
|
+
function onError(data) {
|
|
487
|
+
cleanup();
|
|
488
|
+
const eventData = data;
|
|
489
|
+
reject(new Error(eventData.error ?? "Payment error"));
|
|
490
|
+
}
|
|
491
|
+
function cleanup() {
|
|
492
|
+
state.emitter.off("success", onSuccess);
|
|
493
|
+
state.emitter.off("failed", onFailed);
|
|
494
|
+
state.emitter.off("cancelled", onCancelled);
|
|
495
|
+
state.emitter.off("error", onError);
|
|
496
|
+
}
|
|
497
|
+
state.emitter.on("success", onSuccess);
|
|
498
|
+
state.emitter.on("failed", onFailed);
|
|
499
|
+
state.emitter.on("cancelled", onCancelled);
|
|
500
|
+
state.emitter.on("error", onError);
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
const paymentInstance = {
|
|
504
|
+
get reference() {
|
|
505
|
+
return state.reference;
|
|
506
|
+
},
|
|
507
|
+
get status() {
|
|
508
|
+
return state.status;
|
|
509
|
+
},
|
|
510
|
+
on,
|
|
511
|
+
once,
|
|
512
|
+
off,
|
|
513
|
+
wait
|
|
514
|
+
};
|
|
515
|
+
startPolling();
|
|
516
|
+
return paymentInstance;
|
|
517
|
+
}
|
|
518
518
|
function verifyWebhookSignature(input) {
|
|
519
519
|
const payloadBytes = typeof input.payload === "string" ? Buffer.from(input.payload, "utf8") : Buffer.from(input.payload);
|
|
520
520
|
const expectedSignature = createHmac("sha256", input.secret).update(payloadBytes).digest("hex");
|
|
@@ -571,11 +571,25 @@ function createSdkInstance(config) {
|
|
|
571
571
|
if (input.method === "bank" && !input.bank) {
|
|
572
572
|
throw new Error('bank details are required when method is "bank"');
|
|
573
573
|
}
|
|
574
|
-
|
|
574
|
+
let payload = { ...input, reference };
|
|
575
|
+
if (config.hooks?.beforeCollect) {
|
|
576
|
+
const mutated = await config.hooks.beforeCollect(payload);
|
|
577
|
+
if (mutated != null)
|
|
578
|
+
payload = { ...mutated, reference: mutated.reference ?? reference };
|
|
579
|
+
}
|
|
575
580
|
const result = await transport.send({
|
|
576
581
|
action: SDK_ACTIONS.collectPayment,
|
|
577
582
|
payload
|
|
578
583
|
});
|
|
584
|
+
if (config.hooks?.afterCollect) {
|
|
585
|
+
await config.hooks.afterCollect(
|
|
586
|
+
result.isOk ? Ok({
|
|
587
|
+
reference: result.value.reference,
|
|
588
|
+
status: result.value.status
|
|
589
|
+
}) : Err(result.error),
|
|
590
|
+
payload
|
|
591
|
+
);
|
|
592
|
+
}
|
|
579
593
|
if (result.isOk) {
|
|
580
594
|
return createPaymentInstance(result.value, commonDeps);
|
|
581
595
|
}
|
|
@@ -599,11 +613,25 @@ function createSdkInstance(config) {
|
|
|
599
613
|
if (input.method === "bank" && !input.bank) {
|
|
600
614
|
throw new Error('bank details are required when method is "bank"');
|
|
601
615
|
}
|
|
602
|
-
|
|
616
|
+
let payload = { ...input, reference };
|
|
617
|
+
if (config.hooks?.beforeCollect) {
|
|
618
|
+
const mutated = await config.hooks.beforeCollect(payload);
|
|
619
|
+
if (mutated != null)
|
|
620
|
+
payload = { ...mutated, reference: mutated.reference ?? reference };
|
|
621
|
+
}
|
|
603
622
|
const result = await transport.send({
|
|
604
623
|
action: SDK_ACTIONS.collectPaymentAndResolve,
|
|
605
624
|
payload
|
|
606
625
|
});
|
|
626
|
+
if (config.hooks?.afterCollect) {
|
|
627
|
+
await config.hooks.afterCollect(
|
|
628
|
+
result.isOk ? Ok({
|
|
629
|
+
reference: result.value.reference,
|
|
630
|
+
status: result.value.status
|
|
631
|
+
}) : Err(result.error),
|
|
632
|
+
payload
|
|
633
|
+
);
|
|
634
|
+
}
|
|
607
635
|
if (result.isOk) {
|
|
608
636
|
return Ok(result.value);
|
|
609
637
|
}
|
|
@@ -623,11 +651,25 @@ function createSdkInstance(config) {
|
|
|
623
651
|
input.destination.accountNumber,
|
|
624
652
|
"destination.accountNumber"
|
|
625
653
|
);
|
|
626
|
-
|
|
654
|
+
let payload = { ...input, reference };
|
|
655
|
+
if (config.hooks?.beforePayout) {
|
|
656
|
+
const mutated = await config.hooks.beforePayout(payload);
|
|
657
|
+
if (mutated != null)
|
|
658
|
+
payload = { ...mutated, reference: mutated.reference ?? reference };
|
|
659
|
+
}
|
|
627
660
|
const result = await transport.send({
|
|
628
661
|
action: SDK_ACTIONS.makePayout,
|
|
629
662
|
payload
|
|
630
663
|
});
|
|
664
|
+
if (config.hooks?.afterPayout) {
|
|
665
|
+
await config.hooks.afterPayout(
|
|
666
|
+
result.isOk ? Ok({
|
|
667
|
+
reference: result.value.reference,
|
|
668
|
+
status: result.value.status
|
|
669
|
+
}) : Err(result.error),
|
|
670
|
+
payload
|
|
671
|
+
);
|
|
672
|
+
}
|
|
631
673
|
if (result.isOk) {
|
|
632
674
|
return createPaymentInstance(result.value, commonDeps);
|
|
633
675
|
}
|
|
@@ -656,11 +698,25 @@ function createSdkInstance(config) {
|
|
|
656
698
|
input.destination.accountNumber,
|
|
657
699
|
"destination.accountNumber"
|
|
658
700
|
);
|
|
659
|
-
|
|
701
|
+
let payload = { ...input, reference };
|
|
702
|
+
if (config.hooks?.beforePayout) {
|
|
703
|
+
const mutated = await config.hooks.beforePayout(payload);
|
|
704
|
+
if (mutated != null)
|
|
705
|
+
payload = { ...mutated, reference: mutated.reference ?? reference };
|
|
706
|
+
}
|
|
660
707
|
const result = await transport.send({
|
|
661
708
|
action: SDK_ACTIONS.makePayoutAndResolve,
|
|
662
709
|
payload
|
|
663
710
|
});
|
|
711
|
+
if (config.hooks?.afterPayout) {
|
|
712
|
+
await config.hooks.afterPayout(
|
|
713
|
+
result.isOk ? Ok({
|
|
714
|
+
reference: result.value.reference,
|
|
715
|
+
status: result.value.status
|
|
716
|
+
}) : Err(result.error),
|
|
717
|
+
payload
|
|
718
|
+
);
|
|
719
|
+
}
|
|
664
720
|
if (result.isOk) {
|
|
665
721
|
return Ok(result.value);
|
|
666
722
|
}
|
|
@@ -745,6 +801,7 @@ function createSdkInstance(config) {
|
|
|
745
801
|
}
|
|
746
802
|
|
|
747
803
|
// src/create-nylon-pay.ts
|
|
804
|
+
var instances = /* @__PURE__ */ new Map();
|
|
748
805
|
function createNylonPay(config) {
|
|
749
806
|
if (!config.apiKey) {
|
|
750
807
|
throw new Error("apiKey is required");
|
|
@@ -758,18 +815,27 @@ function createNylonPay(config) {
|
|
|
758
815
|
if (!config.apiSecret.startsWith("nps_")) {
|
|
759
816
|
throw new Error('apiSecret must start with "nps_"');
|
|
760
817
|
}
|
|
818
|
+
const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
|
|
819
|
+
const instanceKey = `${config.apiKey}:${baseUrl}`;
|
|
820
|
+
if (!config.force) {
|
|
821
|
+
const existing = instances.get(instanceKey);
|
|
822
|
+
if (existing) return existing;
|
|
823
|
+
}
|
|
761
824
|
const resolvedConfig = {
|
|
762
825
|
apiKey: config.apiKey,
|
|
763
826
|
apiSecret: config.apiSecret,
|
|
764
|
-
baseUrl
|
|
827
|
+
baseUrl,
|
|
765
828
|
timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
766
829
|
maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,
|
|
767
830
|
maxPollIntervalMs: config.maxPollIntervalMs ?? DEFAULT_MAX_POLL_INTERVAL_MS,
|
|
768
831
|
maxPollDurationMs: config.maxPollDurationMs ?? DEFAULT_MAX_POLL_DURATION_MS,
|
|
769
832
|
maxPollAttempts: config.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS,
|
|
770
|
-
fetch: config.fetch ?? globalThis.fetch.bind(globalThis)
|
|
833
|
+
fetch: config.fetch ?? globalThis.fetch.bind(globalThis),
|
|
834
|
+
hooks: config.hooks
|
|
771
835
|
};
|
|
772
|
-
|
|
836
|
+
const instance = createSdkInstance(resolvedConfig);
|
|
837
|
+
instances.set(instanceKey, instance);
|
|
838
|
+
return instance;
|
|
773
839
|
}
|
|
774
840
|
|
|
775
841
|
export { createNylonPay, parseError, verifyWebhookSignature };
|