@tapsilat/tapsilat-js 1.0.3 → 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,7 +545,14 @@ 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
558
  const baseURL = customBaseURL ||
@@ -373,7 +580,14 @@ class HttpClient {
373
580
  return fullUrl;
374
581
  }
375
582
  /**
376
- * 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
377
591
  */
378
592
  async buildRequestOptions(method, body, config) {
379
593
  const headers = new Headers({
@@ -408,7 +622,12 @@ class HttpClient {
408
622
  return options;
409
623
  }
410
624
  /**
411
- * 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
412
631
  */
413
632
  shouldNotRetry(error) {
414
633
  // Don't retry authentication, validation, or client errors
@@ -417,7 +636,12 @@ class HttpClient {
417
636
  (error instanceof TapsilatError && error.code === "NOT_FOUND"));
418
637
  }
419
638
  /**
420
- * 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
421
645
  */
422
646
  calculateRetryDelay(attempt) {
423
647
  const baseDelay = 1000; // 1 second
@@ -427,14 +651,21 @@ class HttpClient {
427
651
  return delay + Math.random() * 1000;
428
652
  }
429
653
  /**
430
- * 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
431
660
  */
432
661
  delay(ms) {
433
662
  return new Promise((resolve) => setTimeout(resolve, ms));
434
663
  }
435
664
  // Interceptor management methods
436
665
  /**
437
- * 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
438
669
  *
439
670
  * @returns InterceptorManager instance
440
671
  */
@@ -442,7 +673,9 @@ class HttpClient {
442
673
  return this.interceptors;
443
674
  }
444
675
  /**
445
- * 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
446
679
  *
447
680
  * @param interceptor - Request interceptor function
448
681
  * @returns Interceptor ID for removal
@@ -451,7 +684,9 @@ class HttpClient {
451
684
  return this.interceptors.addRequestInterceptor(interceptor);
452
685
  }
453
686
  /**
454
- * 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
455
690
  *
456
691
  * @param interceptor - Response interceptor function
457
692
  * @returns Interceptor ID for removal
@@ -460,7 +695,9 @@ class HttpClient {
460
695
  return this.interceptors.addResponseInterceptor(interceptor);
461
696
  }
462
697
  /**
463
- * 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
464
701
  *
465
702
  * @param interceptor - Error interceptor function
466
703
  * @returns Interceptor ID for removal
@@ -470,43 +707,108 @@ class HttpClient {
470
707
  }
471
708
  }
472
709
 
473
- // 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
474
713
  /**
475
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
476
721
  */
477
722
  function isPaymentMethod(value) {
478
723
  return (typeof value === "string" &&
479
724
  ["credit_card", "debit_card", "bank_transfer", "digital_wallet"].includes(value));
480
725
  }
726
+ // CURRENCY VALIDATION
727
+ // Summary: Type guard for currency validation
728
+ // Description: Checks if a value matches the allowed currency types
481
729
  /**
482
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
483
737
  */
484
738
  function isCurrency(value) {
485
739
  return (typeof value === "string" && ["TRY", "USD", "EUR", "GBP"].includes(value));
486
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
487
744
  /**
488
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
489
752
  */
490
753
  function isNonEmptyString(value) {
491
754
  return typeof value === "string" && value.trim().length > 0;
492
755
  }
756
+ // NUMBER VALIDATION
757
+ // Summary: Type guard for positive number validation
758
+ // Description: Checks if a value is a number greater than zero
493
759
  /**
494
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
495
767
  */
496
768
  function isPositiveNumber(value) {
497
769
  return (typeof value === "number" && value > 0 && !isNaN(value) && isFinite(value));
498
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
499
789
  /**
500
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
501
797
  */
502
798
  function hasValidDecimalPlaces(amount) {
503
799
  const decimalPlaces = (amount.toString().split(".")[1] || "").length;
504
800
  return decimalPlaces <= 2;
505
801
  }
506
- // 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
507
806
  /**
508
807
  * Validates Bearer token format and strength
509
808
  *
809
+ * @summary Validates authentication token format and security
810
+ * @description Checks token for required length, character set, and format constraints
811
+ *
510
812
  * @param bearerToken - Bearer token to validate
511
813
  * @throws {TapsilatValidationError} When Bearer token is invalid
512
814
  */
@@ -517,14 +819,19 @@ function validateBearerToken(bearerToken) {
517
819
  if (bearerToken.length < 10) {
518
820
  throw new TapsilatValidationError("Bearer token must be at least 10 characters long");
519
821
  }
520
- // Karakter kontrolü (opsiyonel, isterseniz ek kurallar koyabilirsiniz)
521
822
  if (!/^[a-zA-Z0-9._-]+$/.test(bearerToken)) {
522
823
  throw new TapsilatValidationError("Bearer token contains invalid characters");
523
824
  }
524
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
525
829
  /**
526
830
  * Validates payment request data comprehensively
527
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
+ *
528
835
  * @param request - Payment request to validate
529
836
  * @throws {TapsilatValidationError} When any field is invalid
530
837
  */
@@ -568,9 +875,15 @@ function validatePaymentRequest(request) {
568
875
  throw new TapsilatValidationError("Metadata must be an object when provided");
569
876
  }
570
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
571
881
  /**
572
882
  * Validates email format using robust regex
573
883
  *
884
+ * @summary Validates email address format with comprehensive regex
885
+ * @description Ensures email addresses conform to RFC standards with thorough pattern matching
886
+ *
574
887
  * @param email - Email address to validate
575
888
  * @returns True if email format is valid
576
889
  */
@@ -582,21 +895,45 @@ function validateEmail(email) {
582
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])?)*$/;
583
896
  return emailRegex.test(email);
584
897
  }
898
+ // DEPRECATED CURRENCY VALIDATION
899
+ // Summary: Legacy currency validation function
900
+ // Description: Maintained for backwards compatibility, redirects to the new type guard
585
901
  /**
586
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
587
909
  */
588
910
  function isValidCurrency(currency) {
589
911
  return isCurrency(currency);
590
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
591
916
  /**
592
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
593
924
  */
594
925
  function isValidPaymentMethod(paymentMethod) {
595
926
  return isPaymentMethod(paymentMethod);
596
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
597
931
  /**
598
932
  * Validates URL format and protocol
599
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
+ *
600
937
  * @param url - URL to validate
601
938
  * @returns True if URL is valid HTTP/HTTPS
602
939
  */
@@ -612,9 +949,15 @@ function isValidUrl(url) {
612
949
  return false;
613
950
  }
614
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
615
955
  /**
616
956
  * Sanitizes metadata by removing sensitive keys and cleaning values
617
957
  *
958
+ * @summary Removes sensitive data from metadata before processing
959
+ * @description Filters out security-sensitive keys and normalizes values for safe transmission
960
+ *
618
961
  * @param metadata - Raw metadata object
619
962
  * @returns Sanitized metadata object
620
963
  */
@@ -659,13 +1002,122 @@ function sanitizeMetadata(metadata) {
659
1002
  return sanitized;
660
1003
  }
661
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
+ */
662
1108
  const isValidEmail = (email) => {
663
1109
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
664
1110
  return emailRegex.test(email);
665
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
666
1115
  /**
667
1116
  * Generic response handler - consistent way to handle API responses
668
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
+ *
669
1121
  * @param response - The API response to process
670
1122
  * @param errorContext - Descriptive context for error messages
671
1123
  * @returns The data from a successful response
@@ -681,9 +1133,15 @@ const handleResponse = (response, errorContext) => {
681
1133
  }
682
1134
  return response.data;
683
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
684
1139
  /**
685
1140
  * Generic error handler - consistent way to handle errors
686
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
+ *
687
1145
  * @param error - The caught error to process
688
1146
  * @param errorContext - Descriptive context for error messages
689
1147
  * @throws {TapsilatError} Always throws an appropriate error type
@@ -698,6 +1156,27 @@ const handleError = (error, errorContext) => {
698
1156
  ? error.message
699
1157
  : `Unknown error during ${errorContext}`, "NETWORK_ERROR");
700
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
+ };
701
1180
 
702
1181
  /**
703
1182
  * Main SDK class for Tapsilat payment operations
@@ -718,7 +1197,10 @@ const handleError = (error, errorContext) => {
718
1197
  */
719
1198
  class TapsilatSDK {
720
1199
  httpClient;
721
- 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
722
1204
  /**
723
1205
  * Creates a new TapsilatSDK instance
724
1206
  *
@@ -745,8 +1227,8 @@ class TapsilatSDK {
745
1227
  */
746
1228
  constructor(config) {
747
1229
  validateBearerToken(config.bearerToken);
748
- this.config = config;
749
- this.httpClient = new HttpClient(config);
1230
+ this.configManager = new ConfigManager(config);
1231
+ this.httpClient = new HttpClient(this.configManager.getInternalConfig());
750
1232
  }
751
1233
  // ORDER CREATION
752
1234
  // Summary: Create new payment order and get checkout URL
@@ -847,9 +1329,9 @@ class TapsilatSDK {
847
1329
  }
848
1330
  try {
849
1331
  // Make the API request
850
- const response = await this.httpClient.post("/order/create", orderRequest);
1332
+ const createOrderResponse = await this.httpClient.post("/order/create", orderRequest);
851
1333
  // Use our generic response handler
852
- return handleResponse(response, "Order creation");
1334
+ return handleResponse(createOrderResponse, "Order creation");
853
1335
  }
854
1336
  catch (error) {
855
1337
  // Use our generic error handler
@@ -878,9 +1360,9 @@ class TapsilatSDK {
878
1360
  }
879
1361
  try {
880
1362
  // Make the API request
881
- const response = await this.httpClient.get(`/order/${referenceId}`);
1363
+ const getOrderResponse = await this.httpClient.get(`/order/${referenceId}`);
882
1364
  // Use our generic response handler
883
- return handleResponse(response, "Order retrieval");
1365
+ return handleResponse(getOrderResponse, "Order retrieval");
884
1366
  }
885
1367
  catch (error) {
886
1368
  // Use our generic error handler
@@ -904,18 +1386,34 @@ class TapsilatSDK {
904
1386
  async getOrders(params = {}) {
905
1387
  try {
906
1388
  // Validate pagination parameters if provided
907
- if (params.page !== undefined &&
908
- (!Number.isInteger(params.page) || params.page < 1)) {
909
- 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
+ }
910
1401
  }
911
- if (params.per_page !== undefined &&
912
- (!Number.isInteger(params.per_page) || params.per_page < 1)) {
913
- 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
+ }
914
1412
  }
915
1413
  // Make the API request
916
- const response = await this.httpClient.get("/order/list", { params: params });
1414
+ const getOrdersResponse = await this.httpClient.get("/order/list", { params: params });
917
1415
  // Use our generic response handler
918
- return handleResponse(response, "Order listing");
1416
+ return handleResponse(getOrdersResponse, "Order listing");
919
1417
  }
920
1418
  catch (error) {
921
1419
  // Use our generic error handler
@@ -930,19 +1428,34 @@ class TapsilatSDK {
930
1428
  *
931
1429
  * @summary Cancel a pending order before payment completion
932
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
933
1436
  */
934
1437
  async cancelOrder(referenceId) {
935
- if (!referenceId) {
936
- 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 });
937
1441
  }
938
- const response = await this.httpClient.post("/order/cancel", {
1442
+ const cancelOrderResponse = await this.httpClient.post("/order/cancel", {
939
1443
  reference_id: referenceId,
940
1444
  });
941
- if (!response.success || !response.data) {
942
- 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");
943
1453
  }
944
- return response.data;
1454
+ return cancelOrderResponse.data;
945
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
946
1459
  /**
947
1460
  * Gets the current status of an order by reference ID
948
1461
  *
@@ -986,9 +1499,9 @@ class TapsilatSDK {
986
1499
  }
987
1500
  try {
988
1501
  // Make the API request
989
- const response = await this.httpClient.get(`/order/${referenceId}/status`);
1502
+ const getOrderStatusResponse = await this.httpClient.get(`/order/${referenceId}/status`);
990
1503
  // Use our generic response handler
991
- return handleResponse(response, "Order status retrieval");
1504
+ return handleResponse(getOrderStatusResponse, "Order status retrieval");
992
1505
  }
993
1506
  catch (error) {
994
1507
  // Use our generic error handler
@@ -1007,14 +1520,19 @@ class TapsilatSDK {
1007
1520
  *
1008
1521
  * @param refundData - The refund details, including referenceId and amount.
1009
1522
  * @returns Promise resolving to the refund transaction details.
1523
+ * @throws {TapsilatError} When API returns an error response or refund fails
1010
1524
  */
1011
1525
  async refundOrder(refundData) {
1012
- const response = await this.httpClient.post("/order/refund", refundData);
1013
- if (!response.success || !response.data) {
1014
- 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");
1015
1529
  }
1016
- 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;
1017
1534
  }
1535
+ // ORDER FULL REFUND OPERATIONS
1018
1536
  // Summary: Process full refund for a completed order
1019
1537
  // Description: Refunds entire order amount and returns transaction details
1020
1538
  /**
@@ -1026,13 +1544,19 @@ class TapsilatSDK {
1026
1544
  *
1027
1545
  * @param referenceId - The unique identifier of the order to fully refund.
1028
1546
  * @returns Promise resolving to the refund transaction details.
1547
+ * @throws {TapsilatError} When API returns an error response or full refund fails
1029
1548
  */
1030
1549
  async refundAllOrder(referenceId) {
1031
- const response = await this.httpClient.post("/order/refund-all", { reference_id: referenceId });
1032
- if (!response.success || !response.data) {
1033
- 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");
1034
1555
  }
1035
- return response.data;
1556
+ if (!refundAllOrderResponse.data) {
1557
+ throw new TapsilatError("Full order refund response data is missing", "FULL_REFUND_DATA_MISSING");
1558
+ }
1559
+ return refundAllOrderResponse.data;
1036
1560
  }
1037
1561
  // ORDER PAYMENT DETAILS
1038
1562
  // Summary: Retrieve detailed payment transaction information for an order
@@ -1047,24 +1571,24 @@ class TapsilatSDK {
1047
1571
  * @param referenceId - The unique identifier of the order.
1048
1572
  * @param conversationId - Optional conversation ID for more specific querying.
1049
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
1050
1576
  */
1051
1577
  async getOrderPaymentDetails(referenceId, conversationId) {
1052
- if (conversationId) {
1053
- // If conversation_id is provided, use POST to /order/payment-details
1054
- const response = await this.httpClient.post("/order/payment-details", { conversation_id: conversationId, reference_id: referenceId });
1055
- if (!response.success || !response.data) {
1056
- throw new Error(response.error?.message || "Failed to get payment details");
1057
- }
1058
- return response.data;
1059
- }
1060
- else {
1061
- // If no conversation_id, use GET to /order/{reference_id}/payment-details
1062
- const response = await this.httpClient.get(`/order/${referenceId}/payment-details`);
1063
- if (!response.success || !response.data) {
1064
- throw new Error(response.error?.message || "Failed to get payment details");
1065
- }
1066
- return response.data;
1067
- }
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;
1068
1592
  }
1069
1593
  // ORDER LOOKUP BY CONVERSATION ID
1070
1594
  // Summary: Find order using conversation ID instead of reference ID
@@ -1075,65 +1599,104 @@ class TapsilatSDK {
1075
1599
  *
1076
1600
  * @summary Find order using conversation ID instead of reference ID
1077
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
1078
1607
  */
1079
1608
  async getOrderByConversationId(conversationId) {
1080
- if (!conversationId) {
1081
- throw new Error("Order conversationId is required");
1609
+ // Validate conversationId
1610
+ if (!isNonEmptyString(conversationId)) {
1611
+ throw new TapsilatValidationError("Order conversationId is required and must be a non-empty string", { provided: conversationId });
1082
1612
  }
1083
- const response = await this.httpClient.get(`/order/conversation/${conversationId}`);
1084
- if (!response.success || !response.data) {
1085
- throw new Error(response.error?.message || "Order retrieval by conversation ID failed");
1086
- }
1087
- return response.data;
1088
- }
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
1089
1624
  /**
1090
1625
  * Gets order transactions by reference_id.
1091
1626
  * Based on `get_order_transactions` from the Python SDK.
1092
1627
  *
1093
1628
  * @summary Retrieve transaction history for an order
1094
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
1095
1635
  */
1096
1636
  async getOrderTransactions(referenceId) {
1097
- if (!referenceId) {
1098
- throw new Error("Order referenceId is required");
1099
- }
1100
- const response = await this.httpClient.get(`/order/${referenceId}/transactions`);
1101
- if (!response.success || !response.data) {
1102
- 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 });
1103
1640
  }
1104
- return response.data;
1105
- }
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
1106
1653
  /**
1107
1654
  * Gets order submerchants with pagination.
1108
1655
  * Based on `get_order_submerchants` from the Python SDK.
1109
1656
  *
1110
1657
  * @summary Retrieve paginated list of submerchants for orders
1111
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
1112
1663
  */
1113
1664
  async getOrderSubmerchants(params = {}) {
1114
- const response = await this.httpClient.get("/order/submerchants", {
1665
+ const getOrderSubmerchantsResponse = await this.httpClient.get("/order/submerchants", {
1115
1666
  params: params,
1116
1667
  });
1117
- if (!response.success || !response.data) {
1118
- throw new Error(response.error?.message || "Order submerchants retrieval failed");
1119
- }
1120
- return response.data;
1121
- }
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
1122
1679
  /**
1123
1680
  * Gets checkout URL for an order.
1124
1681
  * Based on `get_checkout_url` from the Python SDK.
1125
1682
  *
1126
1683
  * @summary Retrieve checkout URL for existing order
1127
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
1128
1689
  */
1129
1690
  async getCheckoutUrl(referenceId) {
1130
1691
  const order = await this.getOrder(referenceId);
1131
1692
  if (order && order.checkout_url) {
1132
1693
  return order.checkout_url;
1133
1694
  }
1134
- 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");
1135
1696
  }
1136
- // 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
1137
1700
  /**
1138
1701
  * Verifies webhook signature for security
1139
1702
  *
@@ -1144,64 +1707,66 @@ class TapsilatSDK {
1144
1707
  * @param signature - Webhook signature from headers
1145
1708
  * @param secret - Your webhook secret key
1146
1709
  * @returns Promise resolving to true if signature is valid
1710
+ * @throws {TapsilatValidationError} When input validation fails for payload, signature or secret
1147
1711
  */
1148
1712
  async verifyWebhook(payload, signature, secret) {
1149
- // Implementation would depend on your webhook signature verification method
1150
- // This is a placeholder implementation
1151
- const crypto = await import('crypto');
1152
- const expectedSignature = crypto
1153
- .createHmac("sha256", secret)
1154
- .update(payload)
1155
- .digest("hex");
1156
- return `sha256=${expectedSignature}` === signature;
1157
- }
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
1158
1724
  /**
1159
1725
  * Checks API service health and availability
1160
1726
  *
1161
1727
  * @summary Check API service health and availability
1162
1728
  * @description Verifies that the Tapsilat API service is operational and accessible.
1163
1729
  *
1164
- * @returns Promise resolving to service status
1730
+ * @returns Promise resolving to service status with status string and timestamp
1731
+ * @throws {TapsilatError} When API health check fails or returns invalid data
1165
1732
  */
1166
1733
  async healthCheck() {
1167
- const response = await this.httpClient.get("/health");
1168
- if (!response.success || !response.data) {
1169
- throw new Error(response.error?.message || "Health check failed");
1170
- }
1171
- return response.data;
1172
- }
1173
- // 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
1174
1744
  /**
1175
- * Gets current SDK configuration (without sensitive data)
1745
+ * Gets the configuration manager instance
1176
1746
  *
1177
- * @summary Get current SDK configuration without sensitive information
1178
- * @description Returns a copy of the current configuration with sensitive data (like bearer token) excluded.
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.
1179
1751
  *
1180
- * @returns Copy of current configuration
1181
- */
1182
- getConfig() {
1183
- const { bearerToken, ...safeConfig } = this.config;
1184
- return {
1185
- ...safeConfig,
1186
- hasBearerToken: Boolean(bearerToken),
1187
- };
1188
- }
1189
- /**
1190
- * Updates SDK configuration
1752
+ * @example
1753
+ * ```typescript
1754
+ * const sdk = new TapsilatSDK(config);
1755
+ * const configManager = sdk.getConfigManager();
1191
1756
  *
1192
- * @summary Update SDK configuration with new values
1193
- * @description Updates the SDK configuration with provided values, validating bearer token if changed.
1757
+ * // Get config (without sensitive data)
1758
+ * console.log(configManager.getConfig());
1194
1759
  *
1195
- * @param newConfig - Partial configuration to update
1196
- * @throws {TapsilatValidationError} When Bearer token is invalid
1760
+ * // Update config
1761
+ * configManager.updateConfig({ timeout: 60000 });
1762
+ * ```
1763
+ *
1764
+ * @returns ConfigManager instance for configuration operations
1197
1765
  */
1198
- updateConfig(newConfig) {
1199
- if (newConfig.bearerToken) {
1200
- validateBearerToken(newConfig.bearerToken);
1201
- }
1202
- Object.assign(this.config, newConfig);
1766
+ getConfigManager() {
1767
+ return this.configManager;
1203
1768
  }
1204
1769
  }
1205
1770
 
1206
- 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 };
1207
1772
  //# sourceMappingURL=index.esm.js.map