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