vesant-sdk 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/{client-BWp5FI3x.d.ts → client-B6fUFAUM.d.mts} +2 -1
  2. package/dist/{client-BIfLMfuC.d.mts → client-DoczGA6L.d.ts} +2 -1
  3. package/dist/client-DzElM7u-.d.mts +238 -0
  4. package/dist/client-DzElM7u-.d.ts +238 -0
  5. package/dist/compliance/index.d.mts +5 -4
  6. package/dist/compliance/index.d.ts +5 -4
  7. package/dist/compliance/index.js +306 -98
  8. package/dist/compliance/index.js.map +1 -1
  9. package/dist/compliance/index.mjs +306 -98
  10. package/dist/compliance/index.mjs.map +1 -1
  11. package/dist/decisions/index.d.mts +100 -0
  12. package/dist/decisions/index.d.ts +100 -0
  13. package/dist/decisions/index.js +607 -0
  14. package/dist/decisions/index.js.map +1 -0
  15. package/dist/decisions/index.mjs +605 -0
  16. package/dist/decisions/index.mjs.map +1 -0
  17. package/dist/geolocation/index.d.mts +4 -3
  18. package/dist/geolocation/index.d.ts +4 -3
  19. package/dist/geolocation/index.js +306 -98
  20. package/dist/geolocation/index.js.map +1 -1
  21. package/dist/geolocation/index.mjs +306 -98
  22. package/dist/geolocation/index.mjs.map +1 -1
  23. package/dist/index.d.mts +15 -7
  24. package/dist/index.d.ts +15 -7
  25. package/dist/index.js +676 -90
  26. package/dist/index.js.map +1 -1
  27. package/dist/index.mjs +667 -91
  28. package/dist/index.mjs.map +1 -1
  29. package/dist/kyc/core.d.mts +4 -3
  30. package/dist/kyc/core.d.ts +4 -3
  31. package/dist/kyc/core.js +284 -29
  32. package/dist/kyc/core.js.map +1 -1
  33. package/dist/kyc/core.mjs +284 -29
  34. package/dist/kyc/core.mjs.map +1 -1
  35. package/dist/kyc/index.d.mts +46 -3
  36. package/dist/kyc/index.d.ts +46 -3
  37. package/dist/kyc/index.js +284 -29
  38. package/dist/kyc/index.js.map +1 -1
  39. package/dist/kyc/index.mjs +284 -29
  40. package/dist/kyc/index.mjs.map +1 -1
  41. package/dist/react.d.mts +9 -5
  42. package/dist/react.d.ts +9 -5
  43. package/dist/react.js +422 -99
  44. package/dist/react.js.map +1 -1
  45. package/dist/react.mjs +322 -4
  46. package/dist/react.mjs.map +1 -1
  47. package/dist/risk-profile/index.d.mts +4 -4
  48. package/dist/risk-profile/index.d.ts +4 -4
  49. package/dist/risk-profile/index.js +249 -29
  50. package/dist/risk-profile/index.js.map +1 -1
  51. package/dist/risk-profile/index.mjs +249 -29
  52. package/dist/risk-profile/index.mjs.map +1 -1
  53. package/dist/scores/index.d.mts +96 -0
  54. package/dist/scores/index.d.ts +96 -0
  55. package/dist/scores/index.js +594 -0
  56. package/dist/scores/index.js.map +1 -0
  57. package/dist/scores/index.mjs +591 -0
  58. package/dist/scores/index.mjs.map +1 -0
  59. package/dist/{types-DfHLp_tz.d.ts → types-DLC7Sfy5.d.ts} +1 -1
  60. package/dist/types-DZHongaK.d.mts +61 -0
  61. package/dist/types-DZHongaK.d.ts +61 -0
  62. package/dist/{types-DKCQN4C5.d.mts → types-jaLuzruy.d.mts} +1 -1
  63. package/dist/webhooks/index.d.mts +176 -0
  64. package/dist/webhooks/index.d.ts +176 -0
  65. package/dist/webhooks/index.js +193 -0
  66. package/dist/webhooks/index.js.map +1 -0
  67. package/dist/webhooks/index.mjs +188 -0
  68. package/dist/webhooks/index.mjs.map +1 -0
  69. package/package.json +25 -2
  70. package/dist/types-BpKxSXGF.d.mts +0 -177
  71. package/dist/types-BpKxSXGF.d.ts +0 -177
package/dist/kyc/index.js CHANGED
@@ -56,6 +56,146 @@ var TimeoutError = class _TimeoutError extends CGSError {
56
56
  Object.setPrototypeOf(this, _TimeoutError.prototype);
57
57
  }
58
58
  };
59
+ var CircuitBreakerOpenError = class _CircuitBreakerOpenError extends CGSError {
60
+ constructor() {
61
+ super("Circuit breaker is open \u2014 requests are temporarily blocked", "CIRCUIT_BREAKER_OPEN", 503);
62
+ this.name = "CircuitBreakerOpenError";
63
+ Object.setPrototypeOf(this, _CircuitBreakerOpenError.prototype);
64
+ }
65
+ };
66
+
67
+ // src/core/circuit-breaker.ts
68
+ var CircuitBreaker = class {
69
+ constructor(config = {}) {
70
+ this.state = "closed";
71
+ this.failures = 0;
72
+ this.successes = 0;
73
+ this.lastFailureTime = null;
74
+ this.failureThreshold = config.failureThreshold ?? 5;
75
+ this.resetTimeout = config.resetTimeout ?? 3e4;
76
+ this.successThreshold = config.successThreshold ?? 1;
77
+ }
78
+ /**
79
+ * Check if a request can proceed through the circuit breaker.
80
+ */
81
+ canExecute() {
82
+ if (this.state === "closed") {
83
+ return true;
84
+ }
85
+ if (this.state === "open") {
86
+ const now = Date.now();
87
+ if (this.lastFailureTime && now - this.lastFailureTime >= this.resetTimeout) {
88
+ this.state = "half-open";
89
+ this.successes = 0;
90
+ return true;
91
+ }
92
+ return false;
93
+ }
94
+ return true;
95
+ }
96
+ /**
97
+ * Record a successful request.
98
+ */
99
+ onSuccess() {
100
+ if (this.state === "half-open") {
101
+ this.successes++;
102
+ if (this.successes >= this.successThreshold) {
103
+ this.state = "closed";
104
+ this.failures = 0;
105
+ this.successes = 0;
106
+ this.lastFailureTime = null;
107
+ }
108
+ } else if (this.state === "closed") {
109
+ this.failures = 0;
110
+ }
111
+ }
112
+ /**
113
+ * Record a failed request.
114
+ */
115
+ onFailure() {
116
+ this.failures++;
117
+ this.lastFailureTime = Date.now();
118
+ if (this.state === "half-open") {
119
+ this.state = "open";
120
+ this.successes = 0;
121
+ } else if (this.state === "closed" && this.failures >= this.failureThreshold) {
122
+ this.state = "open";
123
+ }
124
+ }
125
+ /**
126
+ * Get current circuit breaker status.
127
+ */
128
+ getStatus() {
129
+ return {
130
+ state: this.state,
131
+ failures: this.failures,
132
+ successes: this.successes,
133
+ lastFailureTime: this.lastFailureTime,
134
+ nextRetryTime: this.state === "open" && this.lastFailureTime ? this.lastFailureTime + this.resetTimeout : null
135
+ };
136
+ }
137
+ /**
138
+ * Reset the circuit breaker to its initial closed state.
139
+ */
140
+ reset() {
141
+ this.state = "closed";
142
+ this.failures = 0;
143
+ this.successes = 0;
144
+ this.lastFailureTime = null;
145
+ }
146
+ };
147
+
148
+ // src/core/rate-limiter.ts
149
+ var RateLimitTracker = class {
150
+ constructor() {
151
+ this.limit = null;
152
+ this.remaining = null;
153
+ this.reset = null;
154
+ this.retryAfter = null;
155
+ }
156
+ /**
157
+ * Extract rate limit information from response headers.
158
+ */
159
+ updateFromHeaders(headers) {
160
+ const limit = headers.get("x-ratelimit-limit");
161
+ const remaining = headers.get("x-ratelimit-remaining");
162
+ const reset = headers.get("x-ratelimit-reset");
163
+ const retryAfter = headers.get("retry-after");
164
+ if (limit !== null) this.limit = parseInt(limit, 10);
165
+ if (remaining !== null) this.remaining = parseInt(remaining, 10);
166
+ if (reset !== null) this.reset = parseInt(reset, 10);
167
+ if (retryAfter !== null) this.retryAfter = parseInt(retryAfter, 10);
168
+ }
169
+ /**
170
+ * Check if the rate limit has been exceeded based on tracked headers.
171
+ */
172
+ isLimitExceeded() {
173
+ if (this.remaining !== null && this.remaining <= 0) {
174
+ if (this.reset !== null) {
175
+ const now = Math.floor(Date.now() / 1e3);
176
+ if (now >= this.reset) {
177
+ this.remaining = null;
178
+ this.reset = null;
179
+ this.retryAfter = null;
180
+ return false;
181
+ }
182
+ }
183
+ return true;
184
+ }
185
+ return false;
186
+ }
187
+ /**
188
+ * Get current rate limit status.
189
+ */
190
+ getStatus() {
191
+ return {
192
+ limit: this.limit,
193
+ remaining: this.remaining,
194
+ reset: this.reset,
195
+ retryAfter: this.retryAfter
196
+ };
197
+ }
198
+ };
59
199
 
60
200
  // src/core/logger.ts
61
201
  function createConsoleLogger() {
@@ -76,11 +216,25 @@ function createConsoleLogger() {
76
216
  }
77
217
 
78
218
  // src/core/version.ts
79
- var SDK_VERSION = "1.2.0";
219
+ var SDK_VERSION = "1.3.0";
220
+
221
+ // src/shared/browser-utils.ts
222
+ function generateUUID() {
223
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
224
+ return crypto.randomUUID();
225
+ }
226
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
227
+ const r = Math.random() * 16 | 0;
228
+ const v = c === "x" ? r : r & 3 | 8;
229
+ return v.toString(16);
230
+ });
231
+ }
80
232
 
81
233
  // src/core/client.ts
82
234
  var BaseClient = class {
83
235
  constructor(config) {
236
+ this.circuitBreaker = null;
237
+ this.rateLimitTracker = null;
84
238
  if (!config.baseURL?.trim()) {
85
239
  throw new ValidationError("baseURL is required and must be a non-empty string", ["baseURL"]);
86
240
  }
@@ -90,8 +244,7 @@ var BaseClient = class {
90
244
  this.interceptors = config.interceptors || [];
91
245
  this.logger = config.logger || createConsoleLogger();
92
246
  this.config = {
93
- baseURL: config.baseURL,
94
- tenantId: config.tenantId,
247
+ ...config,
95
248
  apiKey: config.apiKey || "",
96
249
  headers: config.headers || {},
97
250
  timeout: config.timeout || 1e4,
@@ -100,22 +253,49 @@ var BaseClient = class {
100
253
  interceptors: this.interceptors,
101
254
  logger: this.logger
102
255
  };
256
+ if (config.circuitBreaker) {
257
+ this.circuitBreaker = new CircuitBreaker(config.circuitBreaker);
258
+ }
259
+ if (config.enableRateLimitTracking) {
260
+ this.rateLimitTracker = new RateLimitTracker();
261
+ }
103
262
  }
104
263
  /**
105
264
  * Make an HTTP request with timeout and error handling
106
265
  */
107
266
  async request(endpoint, options = {}, serviceURL, requestOptions) {
108
- const url = `${serviceURL || this.config.baseURL}${endpoint}`;
267
+ const requestId = generateUUID();
268
+ if (this.circuitBreaker && !this.circuitBreaker.canExecute()) {
269
+ const error = new CircuitBreakerOpenError();
270
+ error.requestId = requestId;
271
+ throw error;
272
+ }
273
+ if (this.rateLimitTracker && this.rateLimitTracker.isLimitExceeded()) {
274
+ const status = this.rateLimitTracker.getStatus();
275
+ const error = new RateLimitError(status.retryAfter ?? void 0);
276
+ error.requestId = requestId;
277
+ throw error;
278
+ }
279
+ const baseURL = this.config.environment === "sandbox" && this.config.sandboxBaseURL ? this.config.sandboxBaseURL : serviceURL || this.config.baseURL;
280
+ const url = `${serviceURL || baseURL}${endpoint}`;
109
281
  const headers = {
110
282
  "Content-Type": "application/json",
111
283
  "X-Tenant-ID": this.config.tenantId,
112
284
  "X-SDK-Version": `vesant-sdk-ts/${SDK_VERSION}`,
285
+ "X-Request-ID": requestId,
113
286
  ...this.config.headers,
114
287
  ...options.headers || {}
115
288
  };
116
289
  if (this.config.apiKey) {
117
290
  headers["Authorization"] = `Bearer ${this.config.apiKey}`;
118
291
  }
292
+ if (this.config.environment === "sandbox") {
293
+ headers["X-Sandbox"] = "true";
294
+ }
295
+ const method = (options.method || "GET").toUpperCase();
296
+ if (["POST", "PUT", "PATCH"].includes(method)) {
297
+ headers["Idempotency-Key"] = requestOptions?.idempotencyKey || generateUUID();
298
+ }
119
299
  const controller = new AbortController();
120
300
  const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
121
301
  if (requestOptions?.signal) {
@@ -143,6 +323,9 @@ var BaseClient = class {
143
323
  signal: controller.signal
144
324
  });
145
325
  clearTimeout(timeoutId);
326
+ if (this.rateLimitTracker) {
327
+ this.rateLimitTracker.updateFromHeaders(response.headers);
328
+ }
146
329
  let data;
147
330
  try {
148
331
  data = await response.json();
@@ -151,13 +334,15 @@ var BaseClient = class {
151
334
  this.handleErrorResponse(response.status, {
152
335
  error: `HTTP ${response.status}`,
153
336
  message: response.statusText
154
- });
337
+ }, requestId);
155
338
  }
339
+ this.circuitBreaker?.onSuccess();
156
340
  return void 0;
157
341
  }
158
342
  if (!response.ok) {
159
- this.handleErrorResponse(response.status, data || {});
343
+ this.handleErrorResponse(response.status, data || {}, requestId);
160
344
  }
345
+ this.circuitBreaker?.onSuccess();
161
346
  let result = data;
162
347
  for (const interceptor of this.interceptors) {
163
348
  if (interceptor.onResponse) {
@@ -170,6 +355,14 @@ var BaseClient = class {
170
355
  return result;
171
356
  } catch (error) {
172
357
  clearTimeout(timeoutId);
358
+ if (error instanceof CGSError && error.statusCode && error.statusCode >= 500) {
359
+ this.circuitBreaker?.onFailure();
360
+ } else if (error instanceof NetworkError || error instanceof TimeoutError) {
361
+ this.circuitBreaker?.onFailure();
362
+ }
363
+ if (error instanceof CGSError && !error.requestId) {
364
+ error.requestId = requestId;
365
+ }
173
366
  if (error instanceof Error) {
174
367
  for (const interceptor of this.interceptors) {
175
368
  if (interceptor.onError) {
@@ -180,15 +373,23 @@ var BaseClient = class {
180
373
  if (error instanceof Error) {
181
374
  if (error.name === "AbortError") {
182
375
  if (requestOptions?.signal?.aborted) {
183
- throw new CGSError("Request aborted", "REQUEST_ABORTED");
376
+ const abortError = new CGSError("Request aborted", "REQUEST_ABORTED");
377
+ abortError.requestId = requestId;
378
+ throw abortError;
184
379
  }
185
- throw new TimeoutError(this.config.timeout);
380
+ this.circuitBreaker?.onFailure();
381
+ const timeoutError = new TimeoutError(this.config.timeout);
382
+ timeoutError.requestId = requestId;
383
+ throw timeoutError;
186
384
  }
187
385
  if (error instanceof CGSError) {
188
386
  throw error;
189
387
  }
190
388
  }
191
- throw new NetworkError("Network request failed", error);
389
+ const networkError = new NetworkError("Network request failed", error);
390
+ networkError.requestId = requestId;
391
+ this.circuitBreaker?.onFailure();
392
+ throw networkError;
192
393
  }
193
394
  }
194
395
  /**
@@ -227,29 +428,36 @@ var BaseClient = class {
227
428
  /**
228
429
  * Handle error responses from API
229
430
  */
230
- handleErrorResponse(status, data) {
431
+ handleErrorResponse(status, data, requestId) {
231
432
  const message = data.error || data.message || `HTTP ${status}`;
232
- switch (status) {
233
- case 400:
234
- throw new CGSError(message, "BAD_REQUEST", 400, data);
235
- case 401:
236
- throw new AuthenticationError(message);
237
- case 403:
238
- throw new CGSError(message, "FORBIDDEN", 403, data);
239
- case 404:
240
- throw new CGSError(message, "NOT_FOUND", 404, data);
241
- case 429: {
242
- const retryAfter = data.retry_after || data.retryAfter;
243
- throw new RateLimitError(retryAfter);
433
+ const createError = () => {
434
+ switch (status) {
435
+ case 400:
436
+ return new CGSError(message, "BAD_REQUEST", 400, data);
437
+ case 401:
438
+ return new AuthenticationError(message);
439
+ case 403:
440
+ return new CGSError(message, "FORBIDDEN", 403, data);
441
+ case 404:
442
+ return new CGSError(message, "NOT_FOUND", 404, data);
443
+ case 429: {
444
+ const retryAfter = data.retry_after || data.retryAfter;
445
+ return new RateLimitError(retryAfter);
446
+ }
447
+ case 500:
448
+ case 502:
449
+ case 503:
450
+ case 504:
451
+ return new ServiceUnavailableError(message);
452
+ default:
453
+ return new CGSError(message, "UNKNOWN_ERROR", status, data);
244
454
  }
245
- case 500:
246
- case 502:
247
- case 503:
248
- case 504:
249
- throw new ServiceUnavailableError(message);
250
- default:
251
- throw new CGSError(message, "UNKNOWN_ERROR", status, data);
455
+ };
456
+ const error = createError();
457
+ if (requestId) {
458
+ error.requestId = requestId;
252
459
  }
460
+ throw error;
253
461
  }
254
462
  /**
255
463
  * Build query string from parameters
@@ -293,6 +501,18 @@ var BaseClient = class {
293
501
  getConfig() {
294
502
  return { ...this.config };
295
503
  }
504
+ /**
505
+ * Get rate limit status from tracked response headers.
506
+ */
507
+ getRateLimitStatus() {
508
+ return this.rateLimitTracker?.getStatus() ?? null;
509
+ }
510
+ /**
511
+ * Get circuit breaker status.
512
+ */
513
+ getCircuitBreakerStatus() {
514
+ return this.circuitBreaker?.getStatus() ?? null;
515
+ }
296
516
  /**
297
517
  * Health check endpoint
298
518
  */
@@ -382,6 +602,41 @@ var KycClient = class extends BaseClient {
382
602
  headers: this.getUserHeaders()
383
603
  });
384
604
  }
605
+ /**
606
+ * Create a reuse KYC session for validate a user with existing KYC verification
607
+ *
608
+ * @param request - Request containing the reference, customer_id, optional redirect URL, and callback URL (receives POST requests)
609
+ */
610
+ async createReuseKycSession(request) {
611
+ return this.requestWithRetry("/api/v1/kyc/face/session", {
612
+ method: "POST",
613
+ body: JSON.stringify(request),
614
+ headers: this.getUserHeaders()
615
+ });
616
+ }
617
+ /**
618
+ * Submit a reuse KYC session for validate a user with existing KYC verification
619
+ *
620
+ * @param request - Request containing the reference, token and proof (receives POST requests)
621
+ */
622
+ async submitReuseKycSession(request) {
623
+ return this.requestWithRetry("/api/v1/kyc/face/submit", {
624
+ method: "POST",
625
+ body: JSON.stringify(request),
626
+ headers: this.getUserHeaders()
627
+ });
628
+ }
629
+ /**
630
+ * Check reuse KYC session status for a reference
631
+ * @param reference - The unique reference used for the reuse KYC session (e.g., customer ID or transaction ID)
632
+ * @returns Response with kyc_status and message (reason)
633
+ * **/
634
+ async getReuseKycSessionStatus(reference) {
635
+ return this.requestWithRetry(`/api/v1/kyc/face/verify/${encodeURIComponent(reference)}`, {
636
+ method: "GET",
637
+ headers: this.getUserHeaders()
638
+ });
639
+ }
385
640
  /**
386
641
  * Check KYC status for a user
387
642
  *