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