@nile-squad/nylonpay-ts 1.0.0 → 1.0.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 +3 -4
- package/dist/index.cjs +223 -223
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +223 -223
- package/dist/index.js.map +1 -1
- package/package.json +1 -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");
|