@tapsilat/tapsilat-js 1.0.2 → 1.0.4

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.esm.js CHANGED
@@ -1,6 +1,23 @@
1
+ import crypto from 'crypto';
2
+
3
+ /**
4
+ * @category Errors
5
+ * @summary Base error class for Tapsilat SDK
6
+ * @description Foundation error class for all Tapsilat-specific errors with error code and details support
7
+ * @class TapsilatError
8
+ * @extends Error
9
+ */
1
10
  class TapsilatError extends Error {
2
11
  code;
3
12
  details;
13
+ /**
14
+ * @summary Creates a new TapsilatError instance
15
+ * @description Initializes base error with message, code and optional details
16
+ *
17
+ * @param message - Human-readable error message
18
+ * @param code - Error code for programmatic identification
19
+ * @param details - Optional additional error context
20
+ */
4
21
  constructor(message, code, details) {
5
22
  super(message);
6
23
  this.name = 'TapsilatError';
@@ -11,32 +28,96 @@ class TapsilatError extends Error {
11
28
  Error.captureStackTrace(this, TapsilatError);
12
29
  }
13
30
  }
31
+ /**
32
+ * @summary Creates a TapsilatError from an API error response
33
+ * @description Factory method to convert API error format to a TapsilatError instance
34
+ *
35
+ * @param apiError - API error object from response
36
+ * @returns New TapsilatError instance with properties from API error
37
+ */
14
38
  static fromAPIError(apiError) {
15
39
  return new TapsilatError(apiError.message, apiError.code, apiError.details);
16
40
  }
17
41
  }
42
+ /**
43
+ * @category Errors
44
+ * @summary Network-related error class for HTTP issues
45
+ * @description Error class for network and HTTP-specific problems including status codes
46
+ * @class TapsilatNetworkError
47
+ * @extends TapsilatError
48
+ */
18
49
  class TapsilatNetworkError extends TapsilatError {
19
50
  statusCode;
51
+ /**
52
+ * @summary Creates a new network error instance
53
+ * @description Initializes network error with message, code, status code and optional details
54
+ *
55
+ * @param message - Human-readable error message
56
+ * @param code - Error code for programmatic identification
57
+ * @param statusCode - HTTP status code if applicable
58
+ * @param details - Optional additional error context
59
+ */
20
60
  constructor(message, code, statusCode, details) {
21
61
  super(message, code, details);
22
62
  this.name = 'TapsilatNetworkError';
23
63
  this.statusCode = statusCode;
24
64
  }
25
65
  }
66
+ /**
67
+ * @category Errors
68
+ * @summary Error class for validation failures
69
+ * @description Error class for data validation issues with field-specific error details
70
+ * @class TapsilatValidationError
71
+ * @extends TapsilatError
72
+ */
26
73
  class TapsilatValidationError extends TapsilatError {
74
+ /**
75
+ * @summary Creates a new validation error instance
76
+ * @description Initializes validation error with message and optional field-specific details
77
+ *
78
+ * @param message - Human-readable error message
79
+ * @param details - Optional field-specific validation errors
80
+ */
27
81
  constructor(message, details) {
28
82
  super(message, 'VALIDATION_ERROR', details);
29
83
  this.name = 'TapsilatValidationError';
30
84
  }
31
85
  }
86
+ /**
87
+ * @category Errors
88
+ * @summary Error class for authentication issues
89
+ * @description Error class for problems related to API keys, authentication tokens, or permissions
90
+ * @class TapsilatAuthenticationError
91
+ * @extends TapsilatError
92
+ */
32
93
  class TapsilatAuthenticationError extends TapsilatError {
94
+ /**
95
+ * @summary Creates a new authentication error instance
96
+ * @description Initializes authentication error with an optional custom message
97
+ *
98
+ * @param message - Human-readable error message (defaults to 'Authentication failed')
99
+ */
33
100
  constructor(message = 'Authentication failed') {
34
101
  super(message, 'AUTHENTICATION_ERROR');
35
102
  this.name = 'TapsilatAuthenticationError';
36
103
  }
37
104
  }
105
+ /**
106
+ * @category Errors
107
+ * @summary Error class for rate limit exceeded issues
108
+ * @description Error class for API rate limiting with information about when to retry
109
+ * @class TapsilatRateLimitError
110
+ * @extends TapsilatError
111
+ */
38
112
  class TapsilatRateLimitError extends TapsilatError {
39
113
  retryAfter;
114
+ /**
115
+ * @summary Creates a new rate limit error instance
116
+ * @description Initializes rate limit error with message and optional retry-after seconds
117
+ *
118
+ * @param message - Human-readable error message (defaults to 'Rate limit exceeded')
119
+ * @param retryAfter - Optional seconds to wait before retrying
120
+ */
40
121
  constructor(message = 'Rate limit exceeded', retryAfter) {
41
122
  super(message, 'RATE_LIMIT_ERROR');
42
123
  this.name = 'TapsilatRateLimitError';
@@ -44,20 +125,52 @@ class TapsilatRateLimitError extends TapsilatError {
44
125
  }
45
126
  }
46
127
 
128
+ /**
129
+ * @category HTTP
130
+ * @summary Central registry and execution engine for all HTTP interceptors
131
+ * @description Maintains lists of request, response and error interceptors and provides methods to execute them in sequence
132
+ * @class InterceptorManager
133
+ */
47
134
  class InterceptorManager {
48
135
  requestInterceptors = [];
49
136
  responseInterceptors = [];
50
137
  errorInterceptors = [];
51
- // Request interceptors
138
+ /**
139
+ * Adds a request interceptor to the chain
140
+ *
141
+ * @summary Register a new request interceptor function
142
+ * @description Adds a new interceptor to process requests before they are sent
143
+ *
144
+ * @param interceptor - The request interceptor function to add
145
+ * @returns The index of the added interceptor (can be used to remove it later)
146
+ */
52
147
  addRequestInterceptor(interceptor) {
53
148
  this.requestInterceptors.push(interceptor);
54
149
  return this.requestInterceptors.length - 1;
55
150
  }
151
+ /**
152
+ * Removes a previously added request interceptor
153
+ *
154
+ * @summary Unregister a request interceptor by its ID
155
+ * @description Removes the request interceptor at the specified position
156
+ *
157
+ * @param id - The index of the interceptor to remove
158
+ */
56
159
  removeRequestInterceptor(id) {
57
160
  if (this.requestInterceptors[id]) {
58
161
  delete this.requestInterceptors[id];
59
162
  }
60
163
  }
164
+ /**
165
+ * Runs all registered request interceptors in sequence
166
+ *
167
+ * @summary Process a request through all interceptors
168
+ * @description Executes each registered request interceptor in order, passing modified url and options to each
169
+ *
170
+ * @param url - The initial request URL
171
+ * @param options - The initial request options
172
+ * @returns Modified URL and options after all interceptors have processed them
173
+ */
61
174
  async executeRequestInterceptors(url, options) {
62
175
  let currentUrl = url;
63
176
  let currentOptions = options;
@@ -70,16 +183,36 @@ class InterceptorManager {
70
183
  }
71
184
  return { url: currentUrl, options: currentOptions };
72
185
  }
73
- // Response interceptors
186
+ /**
187
+ * @summary Register a new response interceptor function
188
+ * @description Adds a new interceptor to process responses before they are returned to the caller
189
+ *
190
+ * @param interceptor - The response interceptor function to add
191
+ * @returns The index of the added interceptor (can be used to remove it later)
192
+ */
74
193
  addResponseInterceptor(interceptor) {
75
194
  this.responseInterceptors.push(interceptor);
76
195
  return this.responseInterceptors.length - 1;
77
196
  }
197
+ /**
198
+ * @summary Unregister a response interceptor by its ID
199
+ * @description Removes the response interceptor at the specified position
200
+ *
201
+ * @param id - The index of the interceptor to remove
202
+ */
78
203
  removeResponseInterceptor(id) {
79
204
  if (this.responseInterceptors[id]) {
80
205
  delete this.responseInterceptors[id];
81
206
  }
82
207
  }
208
+ /**
209
+ * @summary Process a response through all interceptors
210
+ * @description Executes each registered response interceptor in order
211
+ *
212
+ * @param response - The API response to process
213
+ * @param request - The original request information
214
+ * @returns Modified response after all interceptors have processed it
215
+ */
83
216
  async executeResponseInterceptors(response, request) {
84
217
  let currentResponse = response;
85
218
  for (const interceptor of this.responseInterceptors) {
@@ -89,16 +222,36 @@ class InterceptorManager {
89
222
  }
90
223
  return currentResponse;
91
224
  }
92
- // Error interceptors
225
+ /**
226
+ * @summary Register a new error interceptor function
227
+ * @description Adds a new interceptor to process errors before they are thrown
228
+ *
229
+ * @param interceptor - The error interceptor function to add
230
+ * @returns The index of the added interceptor (can be used to remove it later)
231
+ */
93
232
  addErrorInterceptor(interceptor) {
94
233
  this.errorInterceptors.push(interceptor);
95
234
  return this.errorInterceptors.length - 1;
96
235
  }
236
+ /**
237
+ * @summary Unregister an error interceptor by its ID
238
+ * @description Removes the error interceptor at the specified position
239
+ *
240
+ * @param id - The index of the interceptor to remove
241
+ */
97
242
  removeErrorInterceptor(id) {
98
243
  if (this.errorInterceptors[id]) {
99
244
  delete this.errorInterceptors[id];
100
245
  }
101
246
  }
247
+ /**
248
+ * @summary Process an error through all interceptors
249
+ * @description Executes each registered error interceptor in order until one handles the error
250
+ *
251
+ * @param error - The error that occurred during the request
252
+ * @param request - The original request information
253
+ * @returns Either a recovery response or throws the error if no interceptors handle it
254
+ */
102
255
  async executeErrorInterceptors(error, request) {
103
256
  for (const interceptor of this.errorInterceptors) {
104
257
  if (interceptor) {
@@ -114,7 +267,10 @@ class InterceptorManager {
114
267
  // If no interceptor handled the error, re-throw
115
268
  throw error;
116
269
  }
117
- // Clear all interceptors
270
+ /**
271
+ * @summary Remove all registered interceptors
272
+ * @description Clears all request, response, and error interceptors at once
273
+ */
118
274
  clear() {
119
275
  this.requestInterceptors = [];
120
276
  this.responseInterceptors = [];
@@ -123,8 +279,10 @@ class InterceptorManager {
123
279
  }
124
280
 
125
281
  /**
126
- * HTTP Client for making API requests with comprehensive error handling,
127
- * retry logic, and request/response interceptors
282
+ * @category HTTP
283
+ * @summary HTTP Client for making API requests to Tapsilat services
284
+ * @description Provides a robust client with comprehensive error handling,
285
+ * retry logic, and request/response interceptors for interacting with the Tapsilat API
128
286
  *
129
287
  * @example
130
288
  * ```typescript
@@ -135,10 +293,17 @@ class InterceptorManager {
135
293
  *
136
294
  * const data = await client.get<UserResponse>('/users/123');
137
295
  * ```
296
+ * @class HttpClient
138
297
  */
139
298
  class HttpClient {
140
299
  config;
141
300
  interceptors = new InterceptorManager();
301
+ /**
302
+ * @summary Creates a new HTTP client instance
303
+ * @description Initializes the HTTP client with the provided configuration
304
+ *
305
+ * @param config - The configuration for the Tapsilat API client
306
+ */
142
307
  constructor(config) {
143
308
  this.config = config;
144
309
  }
@@ -158,7 +323,9 @@ class HttpClient {
158
323
  return this.request("DELETE", url, undefined, config);
159
324
  }
160
325
  /**
161
- * Core request method with comprehensive error handling and retry logic
326
+ * @category HTTP Client
327
+ * @summary Core request method with comprehensive error handling and retry logic
328
+ * @description Handles all HTTP requests with error handling, retries, and interceptors
162
329
  *
163
330
  * @param method - HTTP method to use
164
331
  * @param url - Request URL (relative to baseURL)
@@ -209,7 +376,14 @@ class HttpClient {
209
376
  }
210
377
  }
211
378
  /**
212
- * Makes the actual HTTP request with timeout handling
379
+ * @category HTTP Client Internals
380
+ * @summary Makes the actual HTTP request with timeout handling
381
+ * @description Performs the fetch request with timeout handling and abort controller
382
+ *
383
+ * @param url - Full URL to request
384
+ * @param options - Fetch request options
385
+ * @param timeout - Optional timeout in milliseconds
386
+ * @returns Promise resolving to API response
213
387
  */
214
388
  async makeRequest(url, options, timeout) {
215
389
  const controller = new AbortController();
@@ -241,7 +415,12 @@ class HttpClient {
241
415
  }
242
416
  }
243
417
  /**
244
- * Processes the fetch response and converts to APIResponse format
418
+ * @category HTTP Client Internals
419
+ * @summary Processes the fetch response and converts to APIResponse format
420
+ * @description Parses the response and formats it according to the APIResponse interface
421
+ *
422
+ * @param response - The raw fetch Response object
423
+ * @returns Processed API response
245
424
  */
246
425
  async processResponse(response) {
247
426
  const contentType = response.headers.get("content-type");
@@ -277,7 +456,13 @@ class HttpClient {
277
456
  };
278
457
  }
279
458
  /**
280
- * Creates appropriate error based on response status and data
459
+ * @category HTTP Client Internals
460
+ * @summary Creates appropriate error based on response status and data
461
+ * @description Maps HTTP status codes to specific Tapsilat error types
462
+ *
463
+ * @param response - The raw fetch Response object
464
+ * @param data - The parsed response data
465
+ * @returns Appropriate TapsilatError subclass instance
281
466
  */
282
467
  createErrorFromResponse(response, data) {
283
468
  const status = response.status;
@@ -309,7 +494,12 @@ class HttpClient {
309
494
  }
310
495
  }
311
496
  /**
312
- * Extracts error message from response data
497
+ * @category HTTP Client Internals
498
+ * @summary Extracts error message from response data
499
+ * @description Attempts to find an error message in various locations within the response
500
+ *
501
+ * @param data - The parsed response data
502
+ * @returns Error message if found
313
503
  */
314
504
  extractErrorMessage(data) {
315
505
  if (typeof data === "string") {
@@ -322,7 +512,12 @@ class HttpClient {
322
512
  return undefined;
323
513
  }
324
514
  /**
325
- * Extracts validation details from error response
515
+ * @category HTTP Client Internals
516
+ * @summary Extracts validation details from error response
517
+ * @description Parses field-specific validation errors from the API response
518
+ *
519
+ * @param data - The parsed response data
520
+ * @returns Object mapping field names to error messages
326
521
  */
327
522
  extractValidationDetails(data) {
328
523
  if (data && typeof data === "object") {
@@ -332,7 +527,12 @@ class HttpClient {
332
527
  return undefined;
333
528
  }
334
529
  /**
335
- * Extracts rate limit information from response headers
530
+ * @category HTTP Client Internals
531
+ * @summary Extracts rate limit information from response headers
532
+ * @description Reads and parses rate limiting headers from the API response
533
+ *
534
+ * @param response - The raw fetch Response object
535
+ * @returns Rate limit information including limits and reset time
336
536
  */
337
537
  extractRateLimitInfo(response) {
338
538
  const limit = response.headers.get("x-ratelimit-limit");
@@ -345,10 +545,19 @@ class HttpClient {
345
545
  };
346
546
  }
347
547
  /**
348
- * Builds the complete URL for the request
548
+ * @category HTTP Client Internals
549
+ * @summary Builds the complete URL for the request
550
+ * @description Constructs the full URL with base URL and query parameters
551
+ *
552
+ * @param url - The endpoint path or full URL
553
+ * @param customBaseURL - Optional override for the base URL
554
+ * @param params - Optional query parameters
555
+ * @returns Complete request URL
349
556
  */
350
557
  buildUrl(url, customBaseURL, params) {
351
- const baseURL = customBaseURL || this.config.baseURL || "https://api.tapsilat.com/v1";
558
+ const baseURL = customBaseURL ||
559
+ this.config.baseURL ||
560
+ "https://acquiring.tapsilat.dev/api/v1";
352
561
  if (url.startsWith("http://") || url.startsWith("https://")) {
353
562
  return url;
354
563
  }
@@ -371,7 +580,14 @@ class HttpClient {
371
580
  return fullUrl;
372
581
  }
373
582
  /**
374
- * Builds RequestInit options for the fetch request
583
+ * @category HTTP Client Internals
584
+ * @summary Builds RequestInit options for the fetch request
585
+ * @description Prepares headers and request configuration for fetch API
586
+ *
587
+ * @param method - The HTTP method to use
588
+ * @param body - Optional request body
589
+ * @param config - Additional request configuration
590
+ * @returns Configured RequestInit object for fetch
375
591
  */
376
592
  async buildRequestOptions(method, body, config) {
377
593
  const headers = new Headers({
@@ -406,7 +622,12 @@ class HttpClient {
406
622
  return options;
407
623
  }
408
624
  /**
409
- * Determines if an error should prevent retrying
625
+ * @category HTTP Client Internals
626
+ * @summary Determines if an error should prevent retrying
627
+ * @description Checks error types to decide if retry attempts should be aborted
628
+ *
629
+ * @param error - The error that occurred
630
+ * @returns Whether retry should be prevented for this error
410
631
  */
411
632
  shouldNotRetry(error) {
412
633
  // Don't retry authentication, validation, or client errors
@@ -415,7 +636,12 @@ class HttpClient {
415
636
  (error instanceof TapsilatError && error.code === "NOT_FOUND"));
416
637
  }
417
638
  /**
418
- * Calculates retry delay with exponential backoff
639
+ * @category HTTP Client Internals
640
+ * @summary Calculates retry delay with exponential backoff
641
+ * @description Implements exponential backoff with jitter for retry attempts
642
+ *
643
+ * @param attempt - The current retry attempt number (0-indexed)
644
+ * @returns Delay in milliseconds before next retry
419
645
  */
420
646
  calculateRetryDelay(attempt) {
421
647
  const baseDelay = 1000; // 1 second
@@ -425,14 +651,21 @@ class HttpClient {
425
651
  return delay + Math.random() * 1000;
426
652
  }
427
653
  /**
428
- * Utility method to create delay
654
+ * @category HTTP Client Internals
655
+ * @summary Utility method to create delay
656
+ * @description Creates a promise that resolves after the specified time
657
+ *
658
+ * @param ms - Delay time in milliseconds
659
+ * @returns Promise that resolves after the delay
429
660
  */
430
661
  delay(ms) {
431
662
  return new Promise((resolve) => setTimeout(resolve, ms));
432
663
  }
433
664
  // Interceptor management methods
434
665
  /**
435
- * Gets the interceptor manager for advanced request/response handling
666
+ * @category Interceptors
667
+ * @summary Gets the interceptor manager for advanced request/response handling
668
+ * @description Provides access to the internal interceptor manager for custom handling
436
669
  *
437
670
  * @returns InterceptorManager instance
438
671
  */
@@ -440,7 +673,9 @@ class HttpClient {
440
673
  return this.interceptors;
441
674
  }
442
675
  /**
443
- * Adds a request interceptor
676
+ * @category Interceptors
677
+ * @summary Adds a request interceptor
678
+ * @description Registers a function to intercept and modify requests before they are sent
444
679
  *
445
680
  * @param interceptor - Request interceptor function
446
681
  * @returns Interceptor ID for removal
@@ -449,7 +684,9 @@ class HttpClient {
449
684
  return this.interceptors.addRequestInterceptor(interceptor);
450
685
  }
451
686
  /**
452
- * Adds a response interceptor
687
+ * @category Interceptors
688
+ * @summary Adds a response interceptor
689
+ * @description Registers a function to intercept and modify responses before they are returned
453
690
  *
454
691
  * @param interceptor - Response interceptor function
455
692
  * @returns Interceptor ID for removal
@@ -458,7 +695,9 @@ class HttpClient {
458
695
  return this.interceptors.addResponseInterceptor(interceptor);
459
696
  }
460
697
  /**
461
- * Adds an error interceptor
698
+ * @category Interceptors
699
+ * @summary Adds an error interceptor
700
+ * @description Registers a function to intercept and potentially recover from errors
462
701
  *
463
702
  * @param interceptor - Error interceptor function
464
703
  * @returns Interceptor ID for removal
@@ -468,43 +707,108 @@ class HttpClient {
468
707
  }
469
708
  }
470
709
 
471
- // Type Guards
710
+ // TYPE GUARDS
711
+ // Summary: Type guards for payment method validation
712
+ // Description: Checks if a value matches the allowed payment method types
472
713
  /**
473
714
  * Type guard to check if a value is a valid PaymentMethod
715
+ *
716
+ * @summary Validates a value against supported payment methods
717
+ * @description Checks if provided value is a string and matches one of the supported payment methods
718
+ *
719
+ * @param value - The value to check
720
+ * @returns True if the value is a valid PaymentMethod, narrowing the type
474
721
  */
475
722
  function isPaymentMethod(value) {
476
723
  return (typeof value === "string" &&
477
724
  ["credit_card", "debit_card", "bank_transfer", "digital_wallet"].includes(value));
478
725
  }
726
+ // CURRENCY VALIDATION
727
+ // Summary: Type guard for currency validation
728
+ // Description: Checks if a value matches the allowed currency types
479
729
  /**
480
730
  * Type guard to check if a value is a valid Currency
731
+ *
732
+ * @summary Validates a value against supported currencies
733
+ * @description Checks if provided value is a string and matches one of the supported currencies (TRY, USD, EUR, GBP)
734
+ *
735
+ * @param value - The value to check
736
+ * @returns True if the value is a valid Currency, narrowing the type
481
737
  */
482
738
  function isCurrency(value) {
483
739
  return (typeof value === "string" && ["TRY", "USD", "EUR", "GBP"].includes(value));
484
740
  }
741
+ // STRING VALIDATION
742
+ // Summary: Type guard for non-empty string validation
743
+ // Description: Checks if a value is a string and contains non-whitespace characters
485
744
  /**
486
745
  * Type guard to check if a value is a non-empty string
746
+ *
747
+ * @summary Validates a value is a non-empty string
748
+ * @description Checks if provided value is of string type and contains at least one non-whitespace character
749
+ *
750
+ * @param value - The value to check
751
+ * @returns True if the value is a non-empty string, narrowing the type
487
752
  */
488
753
  function isNonEmptyString(value) {
489
754
  return typeof value === "string" && value.trim().length > 0;
490
755
  }
756
+ // NUMBER VALIDATION
757
+ // Summary: Type guard for positive number validation
758
+ // Description: Checks if a value is a number greater than zero
491
759
  /**
492
760
  * Type guard to check if a value is a positive number
761
+ *
762
+ * @summary Validates a value is a positive number
763
+ * @description Checks if provided value is of number type, is greater than zero, and is not NaN or infinity
764
+ *
765
+ * @param value - The value to check
766
+ * @returns True if the value is a positive number, narrowing the type
493
767
  */
494
768
  function isPositiveNumber(value) {
495
769
  return (typeof value === "number" && value > 0 && !isNaN(value) && isFinite(value));
496
770
  }
771
+ // INTEGER VALIDATION
772
+ // Summary: Type guard for integer validation
773
+ // Description: Checks if a value is an integer number
774
+ /**
775
+ * Type guard to check if a value is an integer
776
+ *
777
+ * @summary Validates a value is an integer
778
+ * @description Checks if provided value is of number type and is an integer (no decimal places)
779
+ *
780
+ * @param value - The value to check
781
+ * @returns True if the value is an integer, narrowing the type
782
+ */
783
+ function isInteger(value) {
784
+ return typeof value === "number" && Number.isInteger(value);
785
+ }
786
+ // DECIMAL PLACES VALIDATION
787
+ // Summary: Validates that a number has maximum 2 decimal places
788
+ // Description: Ensures monetary values have appropriate precision for currency operations
497
789
  /**
498
790
  * Type guard to check if amount has max 2 decimal places
791
+ *
792
+ * @summary Validates that a number has maximum 2 decimal places
793
+ * @description Ensures monetary values have appropriate precision for currency operations
794
+ *
795
+ * @param amount - The numeric amount to validate
796
+ * @returns True if the amount has 2 or fewer decimal places
499
797
  */
500
798
  function hasValidDecimalPlaces(amount) {
501
799
  const decimalPlaces = (amount.toString().split(".")[1] || "").length;
502
800
  return decimalPlaces <= 2;
503
801
  }
504
- // Validation Functions
802
+ // VALIDATION FUNCTIONS
803
+ // BEARER TOKEN VALIDATION
804
+ // Summary: Validates authentication token format and security
805
+ // Description: Checks token for required length, character set, and format constraints
505
806
  /**
506
807
  * Validates Bearer token format and strength
507
808
  *
809
+ * @summary Validates authentication token format and security
810
+ * @description Checks token for required length, character set, and format constraints
811
+ *
508
812
  * @param bearerToken - Bearer token to validate
509
813
  * @throws {TapsilatValidationError} When Bearer token is invalid
510
814
  */
@@ -515,14 +819,19 @@ function validateBearerToken(bearerToken) {
515
819
  if (bearerToken.length < 10) {
516
820
  throw new TapsilatValidationError("Bearer token must be at least 10 characters long");
517
821
  }
518
- // Karakter kontrolü (opsiyonel, isterseniz ek kurallar koyabilirsiniz)
519
822
  if (!/^[a-zA-Z0-9._-]+$/.test(bearerToken)) {
520
823
  throw new TapsilatValidationError("Bearer token contains invalid characters");
521
824
  }
522
825
  }
826
+ // PAYMENT REQUEST VALIDATION
827
+ // Summary: Comprehensive validation of payment request data
828
+ // Description: Validates all required and optional fields in a payment request for integrity and correctness
523
829
  /**
524
830
  * Validates payment request data comprehensively
525
831
  *
832
+ * @summary Comprehensive validation of payment request data
833
+ * @description Validates all required and optional fields in a payment request for integrity and correctness
834
+ *
526
835
  * @param request - Payment request to validate
527
836
  * @throws {TapsilatValidationError} When any field is invalid
528
837
  */
@@ -566,9 +875,15 @@ function validatePaymentRequest(request) {
566
875
  throw new TapsilatValidationError("Metadata must be an object when provided");
567
876
  }
568
877
  }
878
+ // EMAIL FORMAT VALIDATION
879
+ // Summary: Validates email address format with comprehensive regex
880
+ // Description: Ensures email addresses conform to RFC standards with thorough pattern matching
569
881
  /**
570
882
  * Validates email format using robust regex
571
883
  *
884
+ * @summary Validates email address format with comprehensive regex
885
+ * @description Ensures email addresses conform to RFC standards with thorough pattern matching
886
+ *
572
887
  * @param email - Email address to validate
573
888
  * @returns True if email format is valid
574
889
  */
@@ -580,21 +895,45 @@ function validateEmail(email) {
580
895
  const emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
581
896
  return emailRegex.test(email);
582
897
  }
898
+ // DEPRECATED CURRENCY VALIDATION
899
+ // Summary: Legacy currency validation function
900
+ // Description: Maintained for backwards compatibility, redirects to the new type guard
583
901
  /**
584
902
  * @deprecated Use isCurrency type guard instead
903
+ *
904
+ * @summary Legacy currency validation function
905
+ * @description Maintained for backwards compatibility, redirects to the new type guard
906
+ *
907
+ * @param currency - Currency code to validate
908
+ * @returns True if currency is supported
585
909
  */
586
910
  function isValidCurrency(currency) {
587
911
  return isCurrency(currency);
588
912
  }
913
+ // DEPRECATED PAYMENT METHOD VALIDATION
914
+ // Summary: Legacy payment method validation function
915
+ // Description: Maintained for backwards compatibility, redirects to the new type guard
589
916
  /**
590
917
  * @deprecated Use isPaymentMethod type guard instead
918
+ *
919
+ * @summary Legacy payment method validation function
920
+ * @description Maintained for backwards compatibility, redirects to the new type guard
921
+ *
922
+ * @param paymentMethod - Payment method to validate
923
+ * @returns True if payment method is supported
591
924
  */
592
925
  function isValidPaymentMethod(paymentMethod) {
593
926
  return isPaymentMethod(paymentMethod);
594
927
  }
928
+ // URL FORMAT VALIDATION
929
+ // Summary: Validates URL format and ensures proper protocol
930
+ // Description: Checks that URLs are well-formed and use HTTP or HTTPS protocols for security
595
931
  /**
596
932
  * Validates URL format and protocol
597
933
  *
934
+ * @summary Validates URL format and ensures proper protocol
935
+ * @description Checks that URLs are well-formed and use HTTP or HTTPS protocols for security
936
+ *
598
937
  * @param url - URL to validate
599
938
  * @returns True if URL is valid HTTP/HTTPS
600
939
  */
@@ -610,9 +949,15 @@ function isValidUrl(url) {
610
949
  return false;
611
950
  }
612
951
  }
952
+ // METADATA SANITIZATION
953
+ // Summary: Removes sensitive data from metadata before processing
954
+ // Description: Filters out security-sensitive keys and normalizes values for safe transmission
613
955
  /**
614
956
  * Sanitizes metadata by removing sensitive keys and cleaning values
615
957
  *
958
+ * @summary Removes sensitive data from metadata before processing
959
+ * @description Filters out security-sensitive keys and normalizes values for safe transmission
960
+ *
616
961
  * @param metadata - Raw metadata object
617
962
  * @returns Sanitized metadata object
618
963
  */
@@ -657,93 +1002,307 @@ function sanitizeMetadata(metadata) {
657
1002
  return sanitized;
658
1003
  }
659
1004
 
1005
+ /**
1006
+ * @category Configuration
1007
+ * @summary Configuration management for Tapsilat SDK
1008
+ * @description Handles SDK configuration updates, validation, and secure access to configuration data
1009
+ * @class ConfigManager
1010
+ */
1011
+ class ConfigManager {
1012
+ config;
1013
+ /**
1014
+ * @summary Creates a new configuration manager
1015
+ * @description Initializes the configuration manager with the provided configuration options
1016
+ *
1017
+ * @param config - Initial SDK configuration
1018
+ */
1019
+ constructor(config) {
1020
+ this.config = { ...config }; // Create a copy to avoid external mutations
1021
+ }
1022
+ /**
1023
+ * @category Configuration Access
1024
+ * @summary Get current SDK configuration without sensitive information
1025
+ * @description Returns a copy of the current configuration with sensitive data (like bearer token) excluded
1026
+ *
1027
+ * @returns Copy of current configuration without bearer token
1028
+ */
1029
+ getConfig() {
1030
+ const { bearerToken, ...safeConfig } = this.config;
1031
+ return {
1032
+ ...safeConfig,
1033
+ hasBearerToken: Boolean(bearerToken),
1034
+ };
1035
+ }
1036
+ /**
1037
+ * @category Configuration Management
1038
+ * @summary Update SDK configuration with new values
1039
+ * @description Updates the SDK configuration with provided values, validating bearer token if changed
1040
+ *
1041
+ * @param newConfig - Partial configuration to update
1042
+ * @throws {TapsilatValidationError} When Bearer token is invalid
1043
+ */
1044
+ updateConfig(newConfig) {
1045
+ if (newConfig.bearerToken) {
1046
+ validateBearerToken(newConfig.bearerToken);
1047
+ }
1048
+ Object.assign(this.config, newConfig);
1049
+ }
1050
+ /**
1051
+ * @category Internal
1052
+ * @summary Gets the internal configuration for SDK use
1053
+ * @description Returns a full copy of the configuration for internal SDK operations
1054
+ *
1055
+ * @internal
1056
+ * @returns Full configuration including sensitive data
1057
+ */
1058
+ getInternalConfig() {
1059
+ return { ...this.config }; // Return a copy to prevent external mutations
1060
+ }
1061
+ /**
1062
+ * @category Authentication
1063
+ * @summary Gets the bearer token for authentication
1064
+ * @description Retrieves the configured bearer token for API authentication
1065
+ *
1066
+ * @internal
1067
+ * @returns Bearer token
1068
+ */
1069
+ getBearerToken() {
1070
+ return this.config.bearerToken;
1071
+ }
1072
+ /**
1073
+ * @category Endpoints
1074
+ * @summary Gets the base URL for API requests
1075
+ * @description Retrieves the configured base URL for API endpoints
1076
+ *
1077
+ * @internal
1078
+ * @returns API base URL
1079
+ */
1080
+ getBaseUrl() {
1081
+ return this.config.baseURL;
1082
+ }
1083
+ /**
1084
+ * @category Networking
1085
+ * @summary Gets the request timeout value
1086
+ * @description Retrieves the configured timeout value for API requests
1087
+ *
1088
+ * @internal
1089
+ * @returns Request timeout in milliseconds
1090
+ */
1091
+ getTimeout() {
1092
+ return this.config.timeout;
1093
+ }
1094
+ }
1095
+
1096
+ // EMAIL VALIDATION
1097
+ // Summary: Validates email format using basic regex pattern
1098
+ // Description: Ensures email addresses conform to standard format with username, @ symbol, and domain
1099
+ /**
1100
+ * Validates email format using basic regex pattern
1101
+ *
1102
+ * @summary Validates email format using basic regex pattern
1103
+ * @description Ensures email addresses conform to standard format with username, @ symbol, and domain
1104
+ *
1105
+ * @param email - Email address to validate
1106
+ * @returns True if email matches required format, false otherwise
1107
+ */
1108
+ const isValidEmail = (email) => {
1109
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1110
+ return emailRegex.test(email);
1111
+ };
1112
+ // API RESPONSE HANDLING
1113
+ // Summary: Process API responses consistently across the SDK
1114
+ // Description: Validates response structure, extracts data or converts API errors to domain errors
1115
+ /**
1116
+ * Generic response handler - consistent way to handle API responses
1117
+ *
1118
+ * @summary Process API responses consistently across the SDK
1119
+ * @description Validates response structure, extracts data or converts API errors to domain errors
1120
+ *
1121
+ * @param response - The API response to process
1122
+ * @param errorContext - Descriptive context for error messages
1123
+ * @returns The data from a successful response
1124
+ * @throws {TapsilatError} On any response error
1125
+ */
1126
+ const handleResponse = (response, errorContext) => {
1127
+ if (!response.success || !response.data) {
1128
+ // Convert API errors to domain-specific errors
1129
+ if (response.error) {
1130
+ throw TapsilatError.fromAPIError(response.error);
1131
+ }
1132
+ throw new TapsilatError(`${errorContext} failed with no error details`, "UNKNOWN_ERROR");
1133
+ }
1134
+ return response.data;
1135
+ };
1136
+ // ERROR HANDLING
1137
+ // Summary: Centralized error handling for consistent error reporting
1138
+ // Description: Processes caught errors and ensures they are properly converted to TapsilatError types
1139
+ /**
1140
+ * Generic error handler - consistent way to handle errors
1141
+ *
1142
+ * @summary Centralized error handling for consistent error reporting
1143
+ * @description Processes caught errors and ensures they are properly converted to TapsilatError types
1144
+ *
1145
+ * @param error - The caught error to process
1146
+ * @param errorContext - Descriptive context for error messages
1147
+ * @throws {TapsilatError} Always throws an appropriate error type
1148
+ */
1149
+ const handleError = (error, errorContext) => {
1150
+ // Rethrow TapsilatErrors as-is
1151
+ if (error instanceof TapsilatError) {
1152
+ throw error;
1153
+ }
1154
+ // Convert generic errors to TapsilatNetworkError
1155
+ throw new TapsilatNetworkError(error instanceof Error
1156
+ ? error.message
1157
+ : `Unknown error during ${errorContext}`, "NETWORK_ERROR");
1158
+ };
1159
+ // WEBHOOK SIGNATURE VERIFICATION
1160
+ // Summary: Security verification of webhook payloads using HMAC-SHA256
1161
+ // Description: Computes expected signature from payload and secret, compares with provided signature
1162
+ /**
1163
+ * Verifies HMAC-SHA256 signature for webhook security
1164
+ *
1165
+ * @summary Security verification of webhook payloads using HMAC-SHA256
1166
+ * @description Computes expected signature from payload and secret, compares with provided signature
1167
+ *
1168
+ * @param payload - Raw webhook payload string
1169
+ * @param signature - Webhook signature from headers (should include "sha256=" prefix)
1170
+ * @param secret - Your webhook secret key
1171
+ * @returns true if signature is valid, false otherwise
1172
+ */
1173
+ const verifyHmacSignature = (payload, signature, secret) => {
1174
+ const expectedSignature = crypto
1175
+ .createHmac("sha256", secret)
1176
+ .update(payload)
1177
+ .digest("hex");
1178
+ return `sha256=${expectedSignature}` === signature;
1179
+ };
1180
+
660
1181
  /**
661
1182
  * Main SDK class for Tapsilat payment operations
662
1183
  *
663
- * @example
664
- * ```typescript
665
- * const tapsilat = new TapsilatSDK({
666
- * bearerToken: 'your-bearer-token',
667
- * baseURL: 'https://api.tapsilat.com/v1'
668
- * });
1184
+ * @summary Enterprise-grade TypeScript SDK for Tapsilat Payment Processing Platform
1185
+ * @description
1186
+ * The TapsilatSDK class provides a comprehensive interface for integrating with the Tapsilat payment platform.
1187
+ * It offers secure, efficient, and type-safe methods for managing orders, payments, refunds, and other
1188
+ * payment-related operations. The SDK includes built-in error handling, request validation, retry logic,
1189
+ * and comprehensive logging capabilities.
669
1190
  *
670
- * const payment = await tapsilat.createPayment({
671
- * amount: 100.50,
672
- * currency: 'TRY',
673
- * paymentMethod: 'credit_card'
674
- * });
675
- * ```
1191
+ * Key features:
1192
+ * - Type-safe API with TypeScript support
1193
+ * - Built-in error handling with custom error types
1194
+ * - Automatic request/response validation
1195
+ * - Configurable retry mechanism
1196
+ * - Full compliance with Tapsilat API specifications
676
1197
  */
677
1198
  class TapsilatSDK {
678
1199
  httpClient;
679
- config;
1200
+ configManager;
1201
+ // SDK INITIALIZATION
1202
+ // Summary: Initializes the Tapsilat SDK with configuration options
1203
+ // Description: Creates and configures a new instance of the TapsilatSDK with the provided configuration
680
1204
  /**
681
1205
  * Creates a new TapsilatSDK instance
682
1206
  *
683
- * @param config - SDK configuration options
684
- * @throws {TapsilatValidationError} When Bearer token is invalid
1207
+ * @summary Initializes the Tapsilat SDK with configuration options
1208
+ * @description
1209
+ * Creates and configures a new instance of the TapsilatSDK with the provided configuration.
1210
+ * The constructor validates the bearer token, sets up the HTTP client with proper headers,
1211
+ * configures retry mechanisms, and initializes internal state for API communication.
1212
+ *
1213
+ * The SDK instance is immutable after creation - configuration cannot be changed without
1214
+ * creating a new instance. This ensures thread safety and predictable behavior.
1215
+ *
1216
+ * @param {TapsilatConfig} config - SDK configuration options
1217
+ * @param {string} config.bearerToken - API authentication token (required)
1218
+ * @param {string} [config.baseURL='https://api.tapsilat.com/v1'] - API base URL
1219
+ * @param {number} [config.timeout=30000] - Request timeout in milliseconds
1220
+ * @param {number} [config.maxRetries=3] - Maximum number of retry attempts
1221
+ * @param {number} [config.retryDelay=1000] - Delay between retries in milliseconds
1222
+ * @param {string} [config.version='v1'] - API version to use
1223
+ * @param {boolean} [config.debug=false] - Enable debug logging
1224
+ *
1225
+ * @throws {TapsilatValidationError} When bearer token is invalid, missing, or malformed
1226
+ * @throws {TypeError} When config parameter is not an object or missing required fields
685
1227
  */
686
1228
  constructor(config) {
687
1229
  validateBearerToken(config.bearerToken);
688
- this.config = config;
689
- this.httpClient = new HttpClient(config);
1230
+ this.configManager = new ConfigManager(config);
1231
+ this.httpClient = new HttpClient(this.configManager.getInternalConfig());
690
1232
  }
691
- // Order Operations
1233
+ // ORDER CREATION
1234
+ // Summary: Create new payment order and get checkout URL
1235
+ // Description: Initiates payment process with buyer info and returns secure checkout URL
692
1236
  /**
693
- * Creates a new order and returns a checkout URL.
1237
+ * Creates a new order and returns a checkout URL
694
1238
  *
695
- * @param orderRequest - The order details including amount, currency, and buyer information
696
- * @returns Promise resolving to the created order response including reference ID and checkout URL
697
- * @throws {TapsilatValidationError} When order request data is invalid
698
- * @throws {TapsilatNetworkError} When API request fails due to network issues
699
- * @throws {TapsilatError} When API returns an error response
1239
+ * @summary Initiates a new payment order with buyer information and generates checkout URL
1240
+ * @description
1241
+ * Creates a new payment order in the Tapsilat system with the provided order details.
1242
+ * This method performs comprehensive validation of all input parameters, creates the order
1243
+ * on the payment platform, and returns a checkout URL that customers can use to complete
1244
+ * their payment. The method supports multiple currencies, locales, and comprehensive
1245
+ * buyer information for compliance and fraud prevention.
700
1246
  *
701
- * @example
702
- * ```typescript
703
- * try {
704
- * const orderResponse = await tapsilat.createOrder({
705
- * amount: 100.50,
706
- * currency: 'TRY',
707
- * locale: 'en',
708
- * buyer: {
709
- * name: 'John',
710
- * surname: 'Doe',
711
- * email: 'john.doe@example.com'
712
- * }
713
- * });
714
- * console.log(`Checkout URL: ${orderResponse.checkoutUrl}`);
715
- * } catch (error) {
716
- * console.error(`Order creation failed: ${error.message}`);
717
- * }
718
- * ```
1247
+ * The returned checkout URL is valid for a limited time (typically 24 hours) and should
1248
+ * be presented to the customer immediately. The order status can be tracked using the
1249
+ * returned reference ID through the getOrderStatus method.
1250
+ *
1251
+ * @param {OrderCreateRequest} orderRequest - Complete order information
1252
+ * @param {number} orderRequest.amount - Payment amount (must be positive, max 2 decimal places)
1253
+ * @param {Currency} orderRequest.currency - Payment currency ('TRY', 'USD', 'EUR', 'GBP')
1254
+ * @param {Locale} orderRequest.locale - Display language ('tr' for Turkish, 'en' for English)
1255
+ * @param {Buyer} orderRequest.buyer - Customer information for payment processing
1256
+ * @param {string} orderRequest.buyer.name - Customer's first name (required)
1257
+ * @param {string} orderRequest.buyer.surname - Customer's last name (required)
1258
+ * @param {string} orderRequest.buyer.email - Customer's email address (required, validated)
1259
+ * @param {string} [orderRequest.buyer.phone] - Customer's phone number
1260
+ * @param {string} [orderRequest.buyer.identityNumber] - National ID or tax number
1261
+ * @param {Address} [orderRequest.buyer.shippingAddress] - Shipping address for physical goods
1262
+ * @param {Address} [orderRequest.buyer.billingAddress] - Billing address for invoicing
1263
+ * @param {string} [orderRequest.description] - Order description for customer reference
1264
+ * @param {string} [orderRequest.callbackUrl] - URL to redirect after payment completion
1265
+ * @param {string} [orderRequest.conversationId] - Custom tracking ID for your system
1266
+ * @param {Record<string, unknown>} [orderRequest.metadata] - Additional custom data
1267
+ *
1268
+ * @returns {Promise<OrderCreateResponse>} Promise resolving to order creation response
1269
+ * @returns {string} OrderCreateResponse.referenceId - Unique order identifier for tracking
1270
+ * @returns {string} OrderCreateResponse.conversationId - Echo of provided conversation ID
1271
+ * @returns {string} OrderCreateResponse.checkoutUrl - Payment page URL for customer
1272
+ * @returns {string} OrderCreateResponse.status - Initial order status (typically 'CREATED')
1273
+ * @returns {string} [OrderCreateResponse.qrCodeUrl] - QR code URL for mobile payments
1274
+ *
1275
+ * @throws {TapsilatValidationError} When input validation fails:
1276
+ * - Amount is not positive or has more than 2 decimal places
1277
+ * - Currency is not supported
1278
+ * - Buyer information is incomplete or invalid
1279
+ * - Email format is invalid
1280
+ * - Required fields are missing
1281
+ * @throws {TapsilatNetworkError} When network request fails:
1282
+ * - Connection timeout
1283
+ * - DNS resolution failure
1284
+ * - Network connectivity issues
1285
+ * @throws {TapsilatError} When API returns business logic errors:
1286
+ * - Insufficient merchant balance
1287
+ * - Currency not enabled for merchant
1288
+ * - Buyer blocked due to fraud detection
1289
+ * - Rate limiting exceeded
719
1290
  */
720
1291
  async createOrder(orderRequest) {
721
- // Validate the order request
722
- this.validateOrderRequest(orderRequest);
723
- try {
724
- // Make the API request
725
- const response = await this.httpClient.post("/order/create", orderRequest);
726
- // Use our generic response handler
727
- return this.handleResponse(response, "Order creation");
728
- }
729
- catch (error) {
730
- // Use our generic error handler
731
- this.handleError(error, "order creation");
732
- }
733
- }
734
- /**
735
- * Validates an order request object
736
- * @private
737
- */
738
- validateOrderRequest(orderRequest) {
1292
+ // Validate the order request directly
739
1293
  // Check if request is null/undefined
740
1294
  if (!orderRequest) {
741
1295
  throw new TapsilatValidationError("Order request cannot be null or undefined");
742
1296
  }
743
- // Validate amount
744
- if (!isPositiveNumber(orderRequest.amount) ||
745
- !hasValidDecimalPlaces(orderRequest.amount)) {
746
- throw new TapsilatValidationError("Amount must be a positive number with maximum 2 decimal places", { provided: orderRequest.amount });
1297
+ // Validate amount - check if positive
1298
+ if (!isPositiveNumber(orderRequest.amount)) {
1299
+ throw new TapsilatValidationError("Amount must be a positive number", {
1300
+ provided: orderRequest.amount,
1301
+ });
1302
+ }
1303
+ // Validate amount - check decimal places
1304
+ if (!hasValidDecimalPlaces(orderRequest.amount)) {
1305
+ throw new TapsilatValidationError("Amount must have maximum 2 decimal places", { provided: orderRequest.amount });
747
1306
  }
748
1307
  // Validate currency
749
1308
  if (!isNonEmptyString(orderRequest.currency)) {
@@ -760,73 +1319,39 @@ class TapsilatSDK {
760
1319
  if (!isNonEmptyString(buyer.surname)) {
761
1320
  throw new TapsilatValidationError("Buyer surname is required and must be a non-empty string", { provided: buyer.surname });
762
1321
  }
763
- if (!isNonEmptyString(buyer.email) || !this.isValidEmail(buyer.email)) {
764
- throw new TapsilatValidationError("Buyer email is required and must be a valid email address", { provided: buyer.email });
1322
+ // Validate buyer email - check if provided
1323
+ if (!isNonEmptyString(buyer.email)) {
1324
+ throw new TapsilatValidationError("Buyer email is required and must be a non-empty string", { provided: buyer.email });
765
1325
  }
766
- }
767
- /**
768
- * Basic email validation
769
- * @private
770
- */
771
- isValidEmail(email) {
772
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
773
- return emailRegex.test(email);
774
- }
775
- /**
776
- * Generic response handler - consistent way to handle API responses across SDK methods
777
- * @private
778
- *
779
- * @param response - The API response to process
780
- * @param errorContext - Descriptive context for error messages
781
- * @returns The data from a successful response
782
- * @throws {TapsilatError} On any response error
783
- */
784
- handleResponse(response, errorContext) {
785
- if (!response.success || !response.data) {
786
- // Convert API errors to domain-specific errors
787
- if (response.error) {
788
- throw TapsilatError.fromAPIError(response.error);
789
- }
790
- throw new TapsilatError(`${errorContext} failed with no error details`, "UNKNOWN_ERROR");
1326
+ // Validate buyer email - check format
1327
+ if (!isValidEmail(buyer.email)) {
1328
+ throw new TapsilatValidationError("Buyer email must be a valid email address", { provided: buyer.email });
791
1329
  }
792
- return response.data;
793
- }
794
- /**
795
- * Generic error handler - consistent way to handle errors across SDK methods
796
- * @private
797
- *
798
- * @param error - The caught error to process
799
- * @param errorContext - Descriptive context for error messages
800
- * @throws {TapsilatError} Always throws an appropriate error type
801
- */
802
- handleError(error, errorContext) {
803
- // Rethrow TapsilatErrors as-is
804
- if (error instanceof TapsilatError) {
805
- throw error;
1330
+ try {
1331
+ // Make the API request
1332
+ const createOrderResponse = await this.httpClient.post("/order/create", orderRequest);
1333
+ // Use our generic response handler
1334
+ return handleResponse(createOrderResponse, "Order creation");
1335
+ }
1336
+ catch (error) {
1337
+ // Use our generic error handler
1338
+ return handleError(error, "order creation");
806
1339
  }
807
- // Convert generic errors to TapsilatNetworkError
808
- throw new TapsilatNetworkError(error instanceof Error
809
- ? error.message
810
- : `Unknown error during ${errorContext}`, "NETWORK_ERROR");
811
1340
  }
1341
+ // ORDER RETRIEVAL BY REFERENCE ID
1342
+ // Summary: Get complete order details and information
1343
+ // Description: Retrieves full order data including buyer info, amounts, and current status
812
1344
  /**
813
1345
  * Gets an order by reference ID.
814
1346
  *
1347
+ * @summary Retrieve complete order details and information
1348
+ * @description Gets complete order data including buyer info, amounts, and current status using the unique reference ID.
1349
+ *
815
1350
  * @param referenceId - The unique reference ID of the order
816
1351
  * @returns Promise resolving to the complete order details
817
1352
  * @throws {TapsilatValidationError} When referenceId is invalid
818
1353
  * @throws {TapsilatNetworkError} When API request fails due to network issues
819
1354
  * @throws {TapsilatError} When API returns an error response
820
- *
821
- * @example
822
- * ```typescript
823
- * try {
824
- * const order = await tapsilat.getOrder("ord_123456789");
825
- * console.log(`Order amount: ${order.amount} ${order.currency}`);
826
- * } catch (error) {
827
- * console.error(`Failed to get order: ${error.message}`);
828
- * }
829
- * ```
830
1355
  */
831
1356
  async getOrder(referenceId) {
832
1357
  // Validate input
@@ -835,95 +1360,137 @@ class TapsilatSDK {
835
1360
  }
836
1361
  try {
837
1362
  // Make the API request
838
- const response = await this.httpClient.get(`/order/${referenceId}`);
1363
+ const getOrderResponse = await this.httpClient.get(`/order/${referenceId}`);
839
1364
  // Use our generic response handler
840
- return this.handleResponse(response, "Order retrieval");
1365
+ return handleResponse(getOrderResponse, "Order retrieval");
841
1366
  }
842
1367
  catch (error) {
843
1368
  // Use our generic error handler
844
- this.handleError(error, "order retrieval");
1369
+ return handleError(error, "order retrieval");
845
1370
  }
846
1371
  }
1372
+ // ORDER LISTING WITH PAGINATION
1373
+ // Summary: Retrieve paginated list of merchant orders
1374
+ // Description: Gets orders with pagination support, filtering, and sorting options
847
1375
  /**
848
1376
  * Lists orders with pagination support.
849
1377
  *
1378
+ * @summary Retrieve paginated list of merchant orders
1379
+ * @description Gets orders with pagination support, filtering, and sorting options.
1380
+ *
850
1381
  * @param params - Optional pagination parameters (page number and items per page)
851
1382
  * @returns Promise resolving to paginated list of orders
852
1383
  * @throws {TapsilatNetworkError} When API request fails due to network issues
853
1384
  * @throws {TapsilatError} When API returns an error response
854
- *
855
- * @example
856
- * ```typescript
857
- * try {
858
- * // Get the second page with 20 items per page
859
- * const orderList = await tapsilat.getOrders({ page: 2, per_page: 20 });
860
- * console.log(`Total orders: ${orderList.total}`);
861
- * orderList.rows.forEach(order => {
862
- * console.log(`Order ${order.referenceId}: ${order.amount} ${order.currency}`);
863
- * });
864
- * } catch (error) {
865
- * console.error(`Failed to list orders: ${error.message}`);
866
- * }
867
- * ```
868
1385
  */
869
1386
  async getOrders(params = {}) {
870
1387
  try {
871
1388
  // Validate pagination parameters if provided
872
- if (params.page !== undefined &&
873
- (!Number.isInteger(params.page) || params.page < 1)) {
874
- throw new TapsilatValidationError("Page number must be a positive integer", { provided: params.page });
1389
+ // Check if page is defined
1390
+ if (params.page !== undefined) {
1391
+ // Check if page is integer
1392
+ if (!isInteger(params.page)) {
1393
+ throw new TapsilatValidationError("Page number must be an integer", {
1394
+ provided: params.page,
1395
+ });
1396
+ }
1397
+ // Check if page is positive
1398
+ if (params.page < 1) {
1399
+ throw new TapsilatValidationError("Page number must be greater than 0", { provided: params.page });
1400
+ }
875
1401
  }
876
- if (params.per_page !== undefined &&
877
- (!Number.isInteger(params.per_page) || params.per_page < 1)) {
878
- throw new TapsilatValidationError("Items per page must be a positive integer", { provided: params.per_page });
1402
+ // Check if per_page is defined
1403
+ if (params.per_page !== undefined) {
1404
+ // Check if per_page is integer
1405
+ if (!isInteger(params.per_page)) {
1406
+ throw new TapsilatValidationError("Items per page must be an integer", { provided: params.per_page });
1407
+ }
1408
+ // Check if per_page is positive
1409
+ if (params.per_page < 1) {
1410
+ throw new TapsilatValidationError("Items per page must be greater than 0", { provided: params.per_page });
1411
+ }
879
1412
  }
880
1413
  // Make the API request
881
- const response = await this.httpClient.get("/order/list", { params: params });
1414
+ const getOrdersResponse = await this.httpClient.get("/order/list", { params: params });
882
1415
  // Use our generic response handler
883
- return this.handleResponse(response, "Order listing");
1416
+ return handleResponse(getOrdersResponse, "Order listing");
884
1417
  }
885
1418
  catch (error) {
886
1419
  // Use our generic error handler
887
- this.handleError(error, "order listing");
1420
+ return handleError(error, "order listing");
888
1421
  }
889
1422
  }
1423
+ // ORDER CANCELLATION
1424
+ // Summary: Cancel a pending order before payment completion
1425
+ // Description: Cancels unpaid order and prevents further payment processing
890
1426
  /**
891
1427
  * Cancels an order by reference_id.
1428
+ *
1429
+ * @summary Cancel a pending order before payment completion
1430
+ * @description Cancels unpaid order and prevents further payment processing.
1431
+ *
1432
+ * @param referenceId - The unique reference ID of the order to cancel
1433
+ * @returns Promise resolving to the canceled order details
1434
+ * @throws {TapsilatValidationError} When referenceId is invalid
1435
+ * @throws {TapsilatError} When API returns an error response or order cannot be canceled
892
1436
  */
893
1437
  async cancelOrder(referenceId) {
894
- if (!referenceId) {
895
- throw new Error("Order referenceId is required for cancellation");
1438
+ // Validate referenceId
1439
+ if (!isNonEmptyString(referenceId)) {
1440
+ throw new TapsilatValidationError("Order referenceId is required and must be a non-empty string", { provided: referenceId });
896
1441
  }
897
- const response = await this.httpClient.post("/order/cancel", {
1442
+ const cancelOrderResponse = await this.httpClient.post("/order/cancel", {
898
1443
  reference_id: referenceId,
899
1444
  });
900
- if (!response.success || !response.data) {
901
- throw new Error(response.error?.message || "Order cancellation failed");
1445
+ // Check if API call was successful
1446
+ if (!cancelOrderResponse.success) {
1447
+ throw new TapsilatError(cancelOrderResponse.error?.message ||
1448
+ "Order cancellation API call failed", cancelOrderResponse.error?.code || "CANCELLATION_API_FAILED");
1449
+ }
1450
+ // Check if response data exists
1451
+ if (!cancelOrderResponse.data) {
1452
+ throw new TapsilatError("Order cancellation response data is missing", "CANCELLATION_DATA_MISSING");
902
1453
  }
903
- return response.data;
1454
+ return cancelOrderResponse.data;
904
1455
  }
1456
+ // ORDER STATUS RETRIEVAL
1457
+ // Summary: Retrieves real-time payment status and tracking information for a specific order
1458
+ // Description: Queries the payment platform to retrieve current status of an order using its reference ID
905
1459
  /**
906
- * Gets the status of an order by reference ID.
1460
+ * Gets the current status of an order by reference ID
907
1461
  *
908
- * @param referenceId - The unique reference ID of the order
909
- * @returns Promise resolving to the current order status, including status code and last update time
910
- * @throws {TapsilatValidationError} When referenceId is invalid
911
- * @throws {TapsilatNetworkError} When API request fails due to network issues
912
- * @throws {TapsilatError} When API returns an error response
1462
+ * @summary Retrieves real-time payment status and tracking information for a specific order
1463
+ * @description
1464
+ * Queries the Tapsilat payment platform to retrieve the current status of an order using its
1465
+ * unique reference ID. This method provides real-time information about payment progress,
1466
+ * completion status, and last update timestamp. It's essential for tracking payment flow
1467
+ * and implementing proper order state management in your application.
913
1468
  *
914
- * @example
915
- * ```typescript
916
- * try {
917
- * const orderStatus = await tapsilat.getOrderStatus("ord_123456789");
918
- * console.log(`Order status: ${orderStatus.status}`);
919
- * } catch (error) {
920
- * if (error instanceof TapsilatValidationError) {
921
- * console.error("Invalid reference ID format");
922
- * } else if (error instanceof TapsilatError) {
923
- * console.error(`API error: ${error.message}`);
924
- * }
925
- * }
926
- * ```
1469
+ * The status information includes payment state (CREATED, PENDING_PAYMENT, COMPLETED, CANCELLED),
1470
+ * last update timestamp, and any relevant status metadata. This method should be used to:
1471
+ * - Check if a payment has been completed after redirecting from checkout
1472
+ * - Monitor payment status for pending transactions
1473
+ * - Verify order state before fulfilling goods/services
1474
+ * - Implement webhook verification and status synchronization
1475
+ *
1476
+ * @param {string} referenceId - Unique order reference identifier from order creation
1477
+ *
1478
+ * @returns {Promise<OrderStatusResponse>} Promise resolving to current order status information
1479
+ * @returns {string} OrderStatusResponse.referenceId - Echo of the provided reference ID
1480
+ * @returns {string} OrderStatusResponse.status - Current payment status (CREATED, PENDING_PAYMENT, COMPLETED, CANCELLED, FAILED)
1481
+ * @returns {string} OrderStatusResponse.lastUpdatedAt - ISO 8601 timestamp of last status change
1482
+ *
1483
+ * @throws {TapsilatValidationError} When input validation fails:
1484
+ * - Reference ID is null, undefined, or empty string
1485
+ * - Reference ID format is invalid (should match order ID pattern)
1486
+ * @throws {TapsilatNetworkError} When network request fails:
1487
+ * - Connection timeout during status check
1488
+ * - DNS resolution failure
1489
+ * - Network connectivity issues
1490
+ * @throws {TapsilatError} When API returns business logic errors:
1491
+ * - ORDER_NOT_FOUND: Order with given reference ID doesn't exist
1492
+ * - ACCESS_DENIED: Order belongs to different merchant
1493
+ * - RATE_LIMIT_EXCEEDED: Too many status check requests
927
1494
  */
928
1495
  async getOrderStatus(referenceId) {
929
1496
  // Validate input using proper validation
@@ -932,187 +1499,274 @@ class TapsilatSDK {
932
1499
  }
933
1500
  try {
934
1501
  // Make the API request
935
- const response = await this.httpClient.get(`/order/${referenceId}/status`);
1502
+ const getOrderStatusResponse = await this.httpClient.get(`/order/${referenceId}/status`);
936
1503
  // Use our generic response handler
937
- return this.handleResponse(response, "Order status retrieval");
1504
+ return handleResponse(getOrderStatusResponse, "Order status retrieval");
938
1505
  }
939
1506
  catch (error) {
940
1507
  // Use our generic error handler
941
- this.handleError(error, "order status retrieval");
1508
+ return handleError(error, "order status retrieval");
942
1509
  }
943
1510
  }
1511
+ // ORDER REFUND OPERATIONS
1512
+ // Summary: Process partial refund for a completed order
1513
+ // Description: Refunds specified amount from a paid order and returns transaction details
944
1514
  /**
945
1515
  * Partially refunds an order.
946
1516
  * Based on `refund_order` from the Python SDK.
947
1517
  *
1518
+ * @summary Process partial refund for a completed order
1519
+ * @description Refunds specified amount from a paid order and returns transaction details.
1520
+ *
948
1521
  * @param refundData - The refund details, including referenceId and amount.
949
1522
  * @returns Promise resolving to the refund transaction details.
1523
+ * @throws {TapsilatError} When API returns an error response or refund fails
950
1524
  */
951
1525
  async refundOrder(refundData) {
952
- const response = await this.httpClient.post("/order/refund", refundData);
953
- if (!response.success || !response.data) {
954
- throw new Error(response.error?.message || "Order refund failed");
1526
+ const refundOrderResponse = await this.httpClient.post("/order/refund", refundData);
1527
+ if (!refundOrderResponse.success) {
1528
+ throw new TapsilatError(refundOrderResponse.error?.message || "Order refund failed", refundOrderResponse.error?.code || "REFUND_FAILED");
955
1529
  }
956
- return response.data;
1530
+ if (!refundOrderResponse.data) {
1531
+ throw new TapsilatError("Order refund response data is missing", "REFUND_DATA_MISSING");
1532
+ }
1533
+ return refundOrderResponse.data;
957
1534
  }
1535
+ // ORDER FULL REFUND OPERATIONS
1536
+ // Summary: Process full refund for a completed order
1537
+ // Description: Refunds entire order amount and returns transaction details
958
1538
  /**
959
1539
  * Fully refunds an order by its reference ID.
960
1540
  * Based on `refund_all_order` from the Python SDK.
961
1541
  *
1542
+ * @summary Process full refund for a completed order
1543
+ * @description Refunds entire order amount and returns transaction details.
1544
+ *
962
1545
  * @param referenceId - The unique identifier of the order to fully refund.
963
1546
  * @returns Promise resolving to the refund transaction details.
1547
+ * @throws {TapsilatError} When API returns an error response or full refund fails
964
1548
  */
965
1549
  async refundAllOrder(referenceId) {
966
- const response = await this.httpClient.post("/order/refund-all", { reference_id: referenceId });
967
- if (!response.success || !response.data) {
968
- throw new Error(response.error?.message || "Full order refund failed");
1550
+ const refundAllOrderResponse = await this.httpClient.post("/order/refund-all", {
1551
+ reference_id: referenceId,
1552
+ });
1553
+ if (!refundAllOrderResponse.success) {
1554
+ throw new TapsilatError(refundAllOrderResponse.error?.message || "Full order refund failed", refundAllOrderResponse.error?.code || "FULL_REFUND_FAILED");
1555
+ }
1556
+ if (!refundAllOrderResponse.data) {
1557
+ throw new TapsilatError("Full order refund response data is missing", "FULL_REFUND_DATA_MISSING");
969
1558
  }
970
- return response.data;
1559
+ return refundAllOrderResponse.data;
971
1560
  }
1561
+ // ORDER PAYMENT DETAILS
1562
+ // Summary: Retrieve detailed payment transaction information for an order
1563
+ // Description: Gets payment method, amount, status, and card info for order transactions
972
1564
  /**
973
1565
  * Retrieves the payment details for an order.
974
1566
  * Based on `get_order_payment_details` from the Python SDK.
975
1567
  *
1568
+ * @summary Retrieve detailed payment transaction information for an order
1569
+ * @description Gets payment method, amount, status, and card info for order transactions.
1570
+ *
976
1571
  * @param referenceId - The unique identifier of the order.
977
1572
  * @param conversationId - Optional conversation ID for more specific querying.
978
1573
  * @returns Promise resolving to a list of payment details.
1574
+ * @throws {TapsilatValidationError} When referenceId is invalid
1575
+ * @throws {TapsilatError} When API returns an error response or payment details are missing
979
1576
  */
980
1577
  async getOrderPaymentDetails(referenceId, conversationId) {
981
- if (conversationId) {
982
- // If conversation_id is provided, use POST to /order/payment-details
983
- const response = await this.httpClient.post("/order/payment-details", { conversation_id: conversationId, reference_id: referenceId });
984
- if (!response.success || !response.data) {
985
- throw new Error(response.error?.message || "Failed to get payment details");
986
- }
987
- return response.data;
988
- }
989
- else {
990
- // If no conversation_id, use GET to /order/{reference_id}/payment-details
991
- const response = await this.httpClient.get(`/order/${referenceId}/payment-details`);
992
- if (!response.success || !response.data) {
993
- throw new Error(response.error?.message || "Failed to get payment details");
994
- }
995
- return response.data;
996
- }
997
- }
1578
+ if (!isNonEmptyString(referenceId))
1579
+ throw new TapsilatValidationError("Reference ID is required and must be a non-empty string");
1580
+ const getOrderPaymentDetailsResponse = conversationId
1581
+ ? await this.httpClient.post("/order/payment-details", {
1582
+ conversation_id: conversationId,
1583
+ })
1584
+ : await this.httpClient.get(`/order/${referenceId}/payment-details`);
1585
+ if (!getOrderPaymentDetailsResponse.success)
1586
+ throw new TapsilatError(getOrderPaymentDetailsResponse.error?.message ||
1587
+ "Payment details API call failed", getOrderPaymentDetailsResponse.error?.code ||
1588
+ "PAYMENT_DETAILS_API_FAILED");
1589
+ if (!getOrderPaymentDetailsResponse.data)
1590
+ throw new TapsilatError("Payment details response data is missing", "PAYMENT_DETAILS_DATA_MISSING");
1591
+ return getOrderPaymentDetailsResponse.data;
1592
+ }
1593
+ // ORDER LOOKUP BY CONVERSATION ID
1594
+ // Summary: Find order using conversation ID instead of reference ID
1595
+ // Description: Alternative lookup method for orders using custom conversation identifier
998
1596
  /**
999
1597
  * Gets an order by conversation_id.
1000
1598
  * Based on `get_order_by_conversation_id` from the Python SDK.
1599
+ *
1600
+ * @summary Find order using conversation ID instead of reference ID
1601
+ * @description Alternative lookup method for orders using custom conversation identifier.
1602
+ *
1603
+ * @param conversationId - The custom conversation identifier used when creating the order
1604
+ * @returns Promise resolving to the complete order details
1605
+ * @throws {TapsilatValidationError} When conversationId is invalid
1606
+ * @throws {TapsilatError} When API returns an error response
1001
1607
  */
1002
1608
  async getOrderByConversationId(conversationId) {
1003
- if (!conversationId) {
1004
- throw new Error("Order conversationId is required");
1005
- }
1006
- const response = await this.httpClient.get(`/order/conversation/${conversationId}`);
1007
- if (!response.success || !response.data) {
1008
- throw new Error(response.error?.message || "Order retrieval by conversation ID failed");
1609
+ // Validate conversationId
1610
+ if (!isNonEmptyString(conversationId)) {
1611
+ throw new TapsilatValidationError("Order conversationId is required and must be a non-empty string", { provided: conversationId });
1009
1612
  }
1010
- return response.data;
1011
- }
1613
+ const getOrderByConversationIdResponse = await this.httpClient.get(`/order/conversation/${conversationId}`);
1614
+ if (!getOrderByConversationIdResponse.success)
1615
+ throw new TapsilatError(getOrderByConversationIdResponse.error?.message ||
1616
+ "Order retrieval by conversation ID failed", getOrderByConversationIdResponse.error?.code || "ORDER_RETRIEVAL_FAILED");
1617
+ if (!getOrderByConversationIdResponse.data)
1618
+ throw new TapsilatError("Order response data is missing", "ORDER_DATA_MISSING");
1619
+ return getOrderByConversationIdResponse.data;
1620
+ }
1621
+ // ORDER TRANSACTION HISTORY
1622
+ // Summary: Retrieve transaction history for an order
1623
+ // Description: Gets detailed transaction records and payment attempts for a specific order
1012
1624
  /**
1013
1625
  * Gets order transactions by reference_id.
1014
1626
  * Based on `get_order_transactions` from the Python SDK.
1627
+ *
1628
+ * @summary Retrieve transaction history for an order
1629
+ * @description Gets detailed transaction records and payment attempts for a specific order.
1630
+ *
1631
+ * @param referenceId - The unique reference ID of the order
1632
+ * @returns Promise resolving to array of transaction records
1633
+ * @throws {TapsilatValidationError} When referenceId is invalid
1634
+ * @throws {TapsilatError} When API returns an error response
1015
1635
  */
1016
1636
  async getOrderTransactions(referenceId) {
1017
- if (!referenceId) {
1018
- throw new Error("Order referenceId is required");
1019
- }
1020
- const response = await this.httpClient.get(`/order/${referenceId}/transactions`);
1021
- if (!response.success || !response.data) {
1022
- throw new Error(response.error?.message || "Order transactions retrieval failed");
1637
+ // Validate referenceId
1638
+ if (!isNonEmptyString(referenceId)) {
1639
+ throw new TapsilatValidationError("Order referenceId is required and must be a non-empty string", { provided: referenceId });
1023
1640
  }
1024
- return response.data;
1025
- }
1641
+ const getOrderTransactionsResponse = await this.httpClient.get(`/order/${referenceId}/transactions`);
1642
+ if (!getOrderTransactionsResponse.success)
1643
+ throw new TapsilatError(getOrderTransactionsResponse.error?.message ||
1644
+ "Order transactions retrieval failed", getOrderTransactionsResponse.error?.code ||
1645
+ "TRANSACTIONS_RETRIEVAL_FAILED");
1646
+ if (!getOrderTransactionsResponse.data)
1647
+ throw new TapsilatError("Order transactions response data is missing", "TRANSACTIONS_DATA_MISSING");
1648
+ return getOrderTransactionsResponse.data;
1649
+ }
1650
+ // ORDER SUBMERCHANT LISTING
1651
+ // Summary: Retrieve paginated list of submerchants for orders
1652
+ // Description: Gets submerchant information with pagination support for order management
1026
1653
  /**
1027
1654
  * Gets order submerchants with pagination.
1028
1655
  * Based on `get_order_submerchants` from the Python SDK.
1656
+ *
1657
+ * @summary Retrieve paginated list of submerchants for orders
1658
+ * @description Gets submerchant information with pagination support for order management.
1659
+ *
1660
+ * @param params - Optional pagination parameters (page number and items per page)
1661
+ * @returns Promise resolving to paginated list of submerchants
1662
+ * @throws {TapsilatError} When API returns an error response
1029
1663
  */
1030
1664
  async getOrderSubmerchants(params = {}) {
1031
- const response = await this.httpClient.get("/order/submerchants", {
1665
+ const getOrderSubmerchantsResponse = await this.httpClient.get("/order/submerchants", {
1032
1666
  params: params,
1033
1667
  });
1034
- if (!response.success || !response.data) {
1035
- throw new Error(response.error?.message || "Order submerchants retrieval failed");
1036
- }
1037
- return response.data;
1038
- }
1668
+ if (!getOrderSubmerchantsResponse.success)
1669
+ throw new TapsilatError(getOrderSubmerchantsResponse.error?.message ||
1670
+ "Order submerchants retrieval failed", getOrderSubmerchantsResponse.error?.code ||
1671
+ "SUBMERCHANTS_RETRIEVAL_FAILED");
1672
+ if (!getOrderSubmerchantsResponse.data)
1673
+ throw new TapsilatError("Order submerchants response data is missing", "SUBMERCHANTS_DATA_MISSING");
1674
+ return getOrderSubmerchantsResponse.data;
1675
+ }
1676
+ // ORDER CHECKOUT URL RETRIEVAL
1677
+ // Summary: Retrieve checkout URL for existing order
1678
+ // Description: Gets the payment checkout URL for an existing order using reference ID
1039
1679
  /**
1040
1680
  * Gets checkout URL for an order.
1041
1681
  * Based on `get_checkout_url` from the Python SDK.
1682
+ *
1683
+ * @summary Retrieve checkout URL for existing order
1684
+ * @description Gets the payment checkout URL for an existing order using reference ID.
1685
+ *
1686
+ * @param referenceId - The unique reference ID of the order
1687
+ * @returns Promise resolving to the checkout URL string
1688
+ * @throws {TapsilatError} When checkout URL is not found in order response
1042
1689
  */
1043
1690
  async getCheckoutUrl(referenceId) {
1044
1691
  const order = await this.getOrder(referenceId);
1045
1692
  if (order && order.checkout_url) {
1046
1693
  return order.checkout_url;
1047
1694
  }
1048
- throw new Error("Checkout URL not found in order response");
1695
+ throw new TapsilatError("Checkout URL not found in order response", "CHECKOUT_URL_NOT_FOUND");
1049
1696
  }
1050
- // Utility Methods
1697
+ // WEBHOOK SIGNATURE VERIFICATION
1698
+ // Summary: Validate webhook signature for security verification
1699
+ // Description: Verifies the authenticity of webhook payloads using HMAC signature validation
1051
1700
  /**
1052
1701
  * Verifies webhook signature for security
1053
1702
  *
1703
+ * @summary Validate webhook signature for security verification
1704
+ * @description Verifies the authenticity of webhook payloads using HMAC signature validation.
1705
+ *
1054
1706
  * @param payload - Raw webhook payload string
1055
1707
  * @param signature - Webhook signature from headers
1056
1708
  * @param secret - Your webhook secret key
1057
1709
  * @returns Promise resolving to true if signature is valid
1058
- *
1059
- * @example
1060
- * ```typescript
1061
- * const isValid = await sdk.verifyWebhook(
1062
- * JSON.stringify(req.body),
1063
- * req.headers['x-tapsilat-signature'],
1064
- * 'your-webhook-secret'
1065
- * );
1066
- * ```
1710
+ * @throws {TapsilatValidationError} When input validation fails for payload, signature or secret
1067
1711
  */
1068
1712
  async verifyWebhook(payload, signature, secret) {
1069
- // Implementation would depend on your webhook signature verification method
1070
- // This is a placeholder implementation
1071
- const crypto = await import('crypto');
1072
- const expectedSignature = crypto
1073
- .createHmac("sha256", secret)
1074
- .update(payload)
1075
- .digest("hex");
1076
- return `sha256=${expectedSignature}` === signature;
1077
- }
1713
+ if (!isNonEmptyString(payload))
1714
+ throw new TapsilatValidationError("Webhook payload is required and must be a non-empty string");
1715
+ if (!isNonEmptyString(signature))
1716
+ throw new TapsilatValidationError("Webhook signature is required and must be a non-empty string");
1717
+ if (!isNonEmptyString(secret))
1718
+ throw new TapsilatValidationError("Webhook secret is required and must be a non-empty string");
1719
+ return verifyHmacSignature(payload, signature, secret);
1720
+ }
1721
+ // API HEALTH STATUS CHECK
1722
+ // Summary: Check API service health and availability
1723
+ // Description: Verifies that the Tapsilat API service is operational and accessible
1078
1724
  /**
1079
1725
  * Checks API service health and availability
1080
1726
  *
1081
- * @returns Promise resolving to service status
1727
+ * @summary Check API service health and availability
1728
+ * @description Verifies that the Tapsilat API service is operational and accessible.
1729
+ *
1730
+ * @returns Promise resolving to service status with status string and timestamp
1731
+ * @throws {TapsilatError} When API health check fails or returns invalid data
1082
1732
  */
1083
1733
  async healthCheck() {
1084
- const response = await this.httpClient.get("/health");
1085
- if (!response.success || !response.data) {
1086
- throw new Error(response.error?.message || "Health check failed");
1087
- }
1088
- return response.data;
1089
- }
1090
- // Configuration methods
1734
+ const healthCheckResponse = await this.httpClient.get("/health");
1735
+ if (!healthCheckResponse.success)
1736
+ throw new TapsilatError(healthCheckResponse.error?.message || "Health check failed", healthCheckResponse.error?.code || "HEALTH_CHECK_FAILED");
1737
+ if (!healthCheckResponse.data)
1738
+ throw new TapsilatError("Health check response data is missing", "HEALTH_CHECK_DATA_MISSING");
1739
+ return healthCheckResponse.data;
1740
+ }
1741
+ // CONFIGURATION MANAGEMENT
1742
+ // Summary: Access to the configuration manager for advanced configuration management
1743
+ // Description: Provides direct access to the ConfigManager instance for configuration operations
1091
1744
  /**
1092
- * Gets current SDK configuration (without sensitive data)
1745
+ * Gets the configuration manager instance
1093
1746
  *
1094
- * @returns Copy of current configuration
1095
- */
1096
- getConfig() {
1097
- const { bearerToken, ...safeConfig } = this.config;
1098
- return {
1099
- ...safeConfig,
1100
- hasBearerToken: Boolean(bearerToken),
1101
- };
1102
- }
1103
- /**
1104
- * Updates SDK configuration
1747
+ * @summary Access to the configuration manager for advanced configuration management
1748
+ * @description
1749
+ * Provides direct access to the ConfigManager instance for configuration operations.
1750
+ * Use this to get, update, or manage SDK configuration settings.
1105
1751
  *
1106
- * @param newConfig - Partial configuration to update
1107
- * @throws {TapsilatValidationError} When Bearer token is invalid
1752
+ * @example
1753
+ * ```typescript
1754
+ * const sdk = new TapsilatSDK(config);
1755
+ * const configManager = sdk.getConfigManager();
1756
+ *
1757
+ * // Get config (without sensitive data)
1758
+ * console.log(configManager.getConfig());
1759
+ *
1760
+ * // Update config
1761
+ * configManager.updateConfig({ timeout: 60000 });
1762
+ * ```
1763
+ *
1764
+ * @returns ConfigManager instance for configuration operations
1108
1765
  */
1109
- updateConfig(newConfig) {
1110
- if (newConfig.bearerToken) {
1111
- validateBearerToken(newConfig.bearerToken);
1112
- }
1113
- Object.assign(this.config, newConfig);
1766
+ getConfigManager() {
1767
+ return this.configManager;
1114
1768
  }
1115
1769
  }
1116
1770
 
1117
- export { TapsilatAuthenticationError, TapsilatError, TapsilatNetworkError, TapsilatRateLimitError, TapsilatSDK, TapsilatValidationError, isValidCurrency, isValidPaymentMethod, isValidUrl, sanitizeMetadata, validateEmail, validatePaymentRequest };
1771
+ export { ConfigManager, TapsilatAuthenticationError, TapsilatError, TapsilatNetworkError, TapsilatRateLimitError, TapsilatSDK, TapsilatValidationError, isValidCurrency, isValidPaymentMethod, isValidUrl, sanitizeMetadata, validateEmail, validatePaymentRequest };
1118
1772
  //# sourceMappingURL=index.esm.js.map