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.
- package/dist/{client-BWp5FI3x.d.ts → client-B6fUFAUM.d.mts} +2 -1
- package/dist/{client-BIfLMfuC.d.mts → client-DoczGA6L.d.ts} +2 -1
- package/dist/client-DzElM7u-.d.mts +238 -0
- package/dist/client-DzElM7u-.d.ts +238 -0
- package/dist/compliance/index.d.mts +5 -4
- package/dist/compliance/index.d.ts +5 -4
- package/dist/compliance/index.js +306 -98
- package/dist/compliance/index.js.map +1 -1
- package/dist/compliance/index.mjs +306 -98
- package/dist/compliance/index.mjs.map +1 -1
- package/dist/decisions/index.d.mts +100 -0
- package/dist/decisions/index.d.ts +100 -0
- package/dist/decisions/index.js +607 -0
- package/dist/decisions/index.js.map +1 -0
- package/dist/decisions/index.mjs +605 -0
- package/dist/decisions/index.mjs.map +1 -0
- package/dist/geolocation/index.d.mts +4 -3
- package/dist/geolocation/index.d.ts +4 -3
- package/dist/geolocation/index.js +306 -98
- package/dist/geolocation/index.js.map +1 -1
- package/dist/geolocation/index.mjs +306 -98
- package/dist/geolocation/index.mjs.map +1 -1
- package/dist/index.d.mts +15 -7
- package/dist/index.d.ts +15 -7
- package/dist/index.js +676 -90
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +667 -91
- package/dist/index.mjs.map +1 -1
- package/dist/kyc/core.d.mts +4 -3
- package/dist/kyc/core.d.ts +4 -3
- package/dist/kyc/core.js +284 -29
- package/dist/kyc/core.js.map +1 -1
- package/dist/kyc/core.mjs +284 -29
- package/dist/kyc/core.mjs.map +1 -1
- package/dist/kyc/index.d.mts +46 -3
- package/dist/kyc/index.d.ts +46 -3
- package/dist/kyc/index.js +284 -29
- package/dist/kyc/index.js.map +1 -1
- package/dist/kyc/index.mjs +284 -29
- package/dist/kyc/index.mjs.map +1 -1
- package/dist/react.d.mts +9 -5
- package/dist/react.d.ts +9 -5
- package/dist/react.js +422 -99
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +322 -4
- package/dist/react.mjs.map +1 -1
- package/dist/risk-profile/index.d.mts +4 -4
- package/dist/risk-profile/index.d.ts +4 -4
- package/dist/risk-profile/index.js +249 -29
- package/dist/risk-profile/index.js.map +1 -1
- package/dist/risk-profile/index.mjs +249 -29
- package/dist/risk-profile/index.mjs.map +1 -1
- package/dist/scores/index.d.mts +96 -0
- package/dist/scores/index.d.ts +96 -0
- package/dist/scores/index.js +594 -0
- package/dist/scores/index.js.map +1 -0
- package/dist/scores/index.mjs +591 -0
- package/dist/scores/index.mjs.map +1 -0
- package/dist/{types-DfHLp_tz.d.ts → types-DLC7Sfy5.d.ts} +1 -1
- package/dist/types-DZHongaK.d.mts +61 -0
- package/dist/types-DZHongaK.d.ts +61 -0
- package/dist/{types-DKCQN4C5.d.mts → types-jaLuzruy.d.mts} +1 -1
- package/dist/webhooks/index.d.mts +176 -0
- package/dist/webhooks/index.d.ts +176 -0
- package/dist/webhooks/index.js +193 -0
- package/dist/webhooks/index.js.map +1 -0
- package/dist/webhooks/index.mjs +188 -0
- package/dist/webhooks/index.mjs.map +1 -0
- package/package.json +25 -2
- package/dist/types-BpKxSXGF.d.mts +0 -177
- package/dist/types-BpKxSXGF.d.ts +0 -177
package/dist/index.js
CHANGED
|
@@ -71,6 +71,146 @@ var ComplianceError = class _ComplianceError extends CGSError {
|
|
|
71
71
|
Object.setPrototypeOf(this, _ComplianceError.prototype);
|
|
72
72
|
}
|
|
73
73
|
};
|
|
74
|
+
var CircuitBreakerOpenError = class _CircuitBreakerOpenError extends CGSError {
|
|
75
|
+
constructor() {
|
|
76
|
+
super("Circuit breaker is open \u2014 requests are temporarily blocked", "CIRCUIT_BREAKER_OPEN", 503);
|
|
77
|
+
this.name = "CircuitBreakerOpenError";
|
|
78
|
+
Object.setPrototypeOf(this, _CircuitBreakerOpenError.prototype);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// src/core/circuit-breaker.ts
|
|
83
|
+
var CircuitBreaker = class {
|
|
84
|
+
constructor(config = {}) {
|
|
85
|
+
this.state = "closed";
|
|
86
|
+
this.failures = 0;
|
|
87
|
+
this.successes = 0;
|
|
88
|
+
this.lastFailureTime = null;
|
|
89
|
+
this.failureThreshold = config.failureThreshold ?? 5;
|
|
90
|
+
this.resetTimeout = config.resetTimeout ?? 3e4;
|
|
91
|
+
this.successThreshold = config.successThreshold ?? 1;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Check if a request can proceed through the circuit breaker.
|
|
95
|
+
*/
|
|
96
|
+
canExecute() {
|
|
97
|
+
if (this.state === "closed") {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
if (this.state === "open") {
|
|
101
|
+
const now = Date.now();
|
|
102
|
+
if (this.lastFailureTime && now - this.lastFailureTime >= this.resetTimeout) {
|
|
103
|
+
this.state = "half-open";
|
|
104
|
+
this.successes = 0;
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Record a successful request.
|
|
113
|
+
*/
|
|
114
|
+
onSuccess() {
|
|
115
|
+
if (this.state === "half-open") {
|
|
116
|
+
this.successes++;
|
|
117
|
+
if (this.successes >= this.successThreshold) {
|
|
118
|
+
this.state = "closed";
|
|
119
|
+
this.failures = 0;
|
|
120
|
+
this.successes = 0;
|
|
121
|
+
this.lastFailureTime = null;
|
|
122
|
+
}
|
|
123
|
+
} else if (this.state === "closed") {
|
|
124
|
+
this.failures = 0;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Record a failed request.
|
|
129
|
+
*/
|
|
130
|
+
onFailure() {
|
|
131
|
+
this.failures++;
|
|
132
|
+
this.lastFailureTime = Date.now();
|
|
133
|
+
if (this.state === "half-open") {
|
|
134
|
+
this.state = "open";
|
|
135
|
+
this.successes = 0;
|
|
136
|
+
} else if (this.state === "closed" && this.failures >= this.failureThreshold) {
|
|
137
|
+
this.state = "open";
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get current circuit breaker status.
|
|
142
|
+
*/
|
|
143
|
+
getStatus() {
|
|
144
|
+
return {
|
|
145
|
+
state: this.state,
|
|
146
|
+
failures: this.failures,
|
|
147
|
+
successes: this.successes,
|
|
148
|
+
lastFailureTime: this.lastFailureTime,
|
|
149
|
+
nextRetryTime: this.state === "open" && this.lastFailureTime ? this.lastFailureTime + this.resetTimeout : null
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Reset the circuit breaker to its initial closed state.
|
|
154
|
+
*/
|
|
155
|
+
reset() {
|
|
156
|
+
this.state = "closed";
|
|
157
|
+
this.failures = 0;
|
|
158
|
+
this.successes = 0;
|
|
159
|
+
this.lastFailureTime = null;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// src/core/rate-limiter.ts
|
|
164
|
+
var RateLimitTracker = class {
|
|
165
|
+
constructor() {
|
|
166
|
+
this.limit = null;
|
|
167
|
+
this.remaining = null;
|
|
168
|
+
this.reset = null;
|
|
169
|
+
this.retryAfter = null;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Extract rate limit information from response headers.
|
|
173
|
+
*/
|
|
174
|
+
updateFromHeaders(headers) {
|
|
175
|
+
const limit = headers.get("x-ratelimit-limit");
|
|
176
|
+
const remaining = headers.get("x-ratelimit-remaining");
|
|
177
|
+
const reset = headers.get("x-ratelimit-reset");
|
|
178
|
+
const retryAfter = headers.get("retry-after");
|
|
179
|
+
if (limit !== null) this.limit = parseInt(limit, 10);
|
|
180
|
+
if (remaining !== null) this.remaining = parseInt(remaining, 10);
|
|
181
|
+
if (reset !== null) this.reset = parseInt(reset, 10);
|
|
182
|
+
if (retryAfter !== null) this.retryAfter = parseInt(retryAfter, 10);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Check if the rate limit has been exceeded based on tracked headers.
|
|
186
|
+
*/
|
|
187
|
+
isLimitExceeded() {
|
|
188
|
+
if (this.remaining !== null && this.remaining <= 0) {
|
|
189
|
+
if (this.reset !== null) {
|
|
190
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
191
|
+
if (now >= this.reset) {
|
|
192
|
+
this.remaining = null;
|
|
193
|
+
this.reset = null;
|
|
194
|
+
this.retryAfter = null;
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Get current rate limit status.
|
|
204
|
+
*/
|
|
205
|
+
getStatus() {
|
|
206
|
+
return {
|
|
207
|
+
limit: this.limit,
|
|
208
|
+
remaining: this.remaining,
|
|
209
|
+
reset: this.reset,
|
|
210
|
+
retryAfter: this.retryAfter
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
};
|
|
74
214
|
|
|
75
215
|
// src/core/logger.ts
|
|
76
216
|
function createConsoleLogger() {
|
|
@@ -101,11 +241,82 @@ var noopLogger = {
|
|
|
101
241
|
};
|
|
102
242
|
|
|
103
243
|
// src/core/version.ts
|
|
104
|
-
var SDK_VERSION = "1.
|
|
244
|
+
var SDK_VERSION = "1.3.0";
|
|
245
|
+
|
|
246
|
+
// src/shared/browser-utils.ts
|
|
247
|
+
function generateUUID() {
|
|
248
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
249
|
+
return crypto.randomUUID();
|
|
250
|
+
}
|
|
251
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
252
|
+
const r = Math.random() * 16 | 0;
|
|
253
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
254
|
+
return v.toString(16);
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
function generateDeviceId() {
|
|
258
|
+
if (typeof window === "undefined" || typeof localStorage === "undefined") {
|
|
259
|
+
return generateUUID();
|
|
260
|
+
}
|
|
261
|
+
const storageKey = "cgs_device_id";
|
|
262
|
+
let deviceId = localStorage.getItem(storageKey);
|
|
263
|
+
if (!deviceId) {
|
|
264
|
+
deviceId = generateUUID();
|
|
265
|
+
localStorage.setItem(storageKey, deviceId);
|
|
266
|
+
}
|
|
267
|
+
return deviceId;
|
|
268
|
+
}
|
|
269
|
+
function getBrowserInfo() {
|
|
270
|
+
if (typeof navigator === "undefined") {
|
|
271
|
+
return { browser: "unknown", browser_version: "", os: "unknown", os_version: "" };
|
|
272
|
+
}
|
|
273
|
+
const ua = navigator.userAgent;
|
|
274
|
+
let browser = "unknown";
|
|
275
|
+
let browserVersion = "";
|
|
276
|
+
let os = "unknown";
|
|
277
|
+
let osVersion = "";
|
|
278
|
+
if (ua.includes("Firefox/")) {
|
|
279
|
+
browser = "Firefox";
|
|
280
|
+
browserVersion = ua.match(/Firefox\/([\d.]+)/)?.[1] || "";
|
|
281
|
+
} else if (ua.includes("Edg/")) {
|
|
282
|
+
browser = "Edge";
|
|
283
|
+
browserVersion = ua.match(/Edg\/([\d.]+)/)?.[1] || "";
|
|
284
|
+
} else if (ua.includes("Chrome/")) {
|
|
285
|
+
browser = "Chrome";
|
|
286
|
+
browserVersion = ua.match(/Chrome\/([\d.]+)/)?.[1] || "";
|
|
287
|
+
} else if (ua.includes("Safari/") && !ua.includes("Chrome")) {
|
|
288
|
+
browser = "Safari";
|
|
289
|
+
browserVersion = ua.match(/Version\/([\d.]+)/)?.[1] || "";
|
|
290
|
+
} else if (ua.includes("Opera") || ua.includes("OPR/")) {
|
|
291
|
+
browser = "Opera";
|
|
292
|
+
browserVersion = ua.match(/(?:Opera|OPR)\/([\d.]+)/)?.[1] || "";
|
|
293
|
+
}
|
|
294
|
+
if (ua.includes("Windows")) {
|
|
295
|
+
os = "Windows";
|
|
296
|
+
if (ua.includes("Windows NT 10.0")) osVersion = "10";
|
|
297
|
+
else if (ua.includes("Windows NT 6.3")) osVersion = "8.1";
|
|
298
|
+
else if (ua.includes("Windows NT 6.2")) osVersion = "8";
|
|
299
|
+
else if (ua.includes("Windows NT 6.1")) osVersion = "7";
|
|
300
|
+
} else if (ua.includes("Mac OS X")) {
|
|
301
|
+
os = "macOS";
|
|
302
|
+
osVersion = ua.match(/Mac OS X ([\d_]+)/)?.[1]?.replace(/_/g, ".") || "";
|
|
303
|
+
} else if (ua.includes("Linux")) {
|
|
304
|
+
os = "Linux";
|
|
305
|
+
} else if (ua.includes("Android")) {
|
|
306
|
+
os = "Android";
|
|
307
|
+
osVersion = ua.match(/Android ([\d.]+)/)?.[1] || "";
|
|
308
|
+
} else if (ua.includes("iOS") || ua.includes("iPhone") || ua.includes("iPad")) {
|
|
309
|
+
os = "iOS";
|
|
310
|
+
osVersion = ua.match(/OS ([\d_]+)/)?.[1]?.replace(/_/g, ".") || "";
|
|
311
|
+
}
|
|
312
|
+
return { browser, browser_version: browserVersion, os, os_version: osVersion };
|
|
313
|
+
}
|
|
105
314
|
|
|
106
315
|
// src/core/client.ts
|
|
107
316
|
var BaseClient = class {
|
|
108
317
|
constructor(config) {
|
|
318
|
+
this.circuitBreaker = null;
|
|
319
|
+
this.rateLimitTracker = null;
|
|
109
320
|
if (!config.baseURL?.trim()) {
|
|
110
321
|
throw new ValidationError("baseURL is required and must be a non-empty string", ["baseURL"]);
|
|
111
322
|
}
|
|
@@ -115,8 +326,7 @@ var BaseClient = class {
|
|
|
115
326
|
this.interceptors = config.interceptors || [];
|
|
116
327
|
this.logger = config.logger || createConsoleLogger();
|
|
117
328
|
this.config = {
|
|
118
|
-
|
|
119
|
-
tenantId: config.tenantId,
|
|
329
|
+
...config,
|
|
120
330
|
apiKey: config.apiKey || "",
|
|
121
331
|
headers: config.headers || {},
|
|
122
332
|
timeout: config.timeout || 1e4,
|
|
@@ -125,22 +335,49 @@ var BaseClient = class {
|
|
|
125
335
|
interceptors: this.interceptors,
|
|
126
336
|
logger: this.logger
|
|
127
337
|
};
|
|
338
|
+
if (config.circuitBreaker) {
|
|
339
|
+
this.circuitBreaker = new CircuitBreaker(config.circuitBreaker);
|
|
340
|
+
}
|
|
341
|
+
if (config.enableRateLimitTracking) {
|
|
342
|
+
this.rateLimitTracker = new RateLimitTracker();
|
|
343
|
+
}
|
|
128
344
|
}
|
|
129
345
|
/**
|
|
130
346
|
* Make an HTTP request with timeout and error handling
|
|
131
347
|
*/
|
|
132
348
|
async request(endpoint, options = {}, serviceURL, requestOptions) {
|
|
133
|
-
const
|
|
349
|
+
const requestId = generateUUID();
|
|
350
|
+
if (this.circuitBreaker && !this.circuitBreaker.canExecute()) {
|
|
351
|
+
const error = new CircuitBreakerOpenError();
|
|
352
|
+
error.requestId = requestId;
|
|
353
|
+
throw error;
|
|
354
|
+
}
|
|
355
|
+
if (this.rateLimitTracker && this.rateLimitTracker.isLimitExceeded()) {
|
|
356
|
+
const status = this.rateLimitTracker.getStatus();
|
|
357
|
+
const error = new RateLimitError(status.retryAfter ?? void 0);
|
|
358
|
+
error.requestId = requestId;
|
|
359
|
+
throw error;
|
|
360
|
+
}
|
|
361
|
+
const baseURL = this.config.environment === "sandbox" && this.config.sandboxBaseURL ? this.config.sandboxBaseURL : serviceURL || this.config.baseURL;
|
|
362
|
+
const url = `${serviceURL || baseURL}${endpoint}`;
|
|
134
363
|
const headers = {
|
|
135
364
|
"Content-Type": "application/json",
|
|
136
365
|
"X-Tenant-ID": this.config.tenantId,
|
|
137
366
|
"X-SDK-Version": `vesant-sdk-ts/${SDK_VERSION}`,
|
|
367
|
+
"X-Request-ID": requestId,
|
|
138
368
|
...this.config.headers,
|
|
139
369
|
...options.headers || {}
|
|
140
370
|
};
|
|
141
371
|
if (this.config.apiKey) {
|
|
142
372
|
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
143
373
|
}
|
|
374
|
+
if (this.config.environment === "sandbox") {
|
|
375
|
+
headers["X-Sandbox"] = "true";
|
|
376
|
+
}
|
|
377
|
+
const method = (options.method || "GET").toUpperCase();
|
|
378
|
+
if (["POST", "PUT", "PATCH"].includes(method)) {
|
|
379
|
+
headers["Idempotency-Key"] = requestOptions?.idempotencyKey || generateUUID();
|
|
380
|
+
}
|
|
144
381
|
const controller = new AbortController();
|
|
145
382
|
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
146
383
|
if (requestOptions?.signal) {
|
|
@@ -168,6 +405,9 @@ var BaseClient = class {
|
|
|
168
405
|
signal: controller.signal
|
|
169
406
|
});
|
|
170
407
|
clearTimeout(timeoutId);
|
|
408
|
+
if (this.rateLimitTracker) {
|
|
409
|
+
this.rateLimitTracker.updateFromHeaders(response.headers);
|
|
410
|
+
}
|
|
171
411
|
let data;
|
|
172
412
|
try {
|
|
173
413
|
data = await response.json();
|
|
@@ -176,13 +416,15 @@ var BaseClient = class {
|
|
|
176
416
|
this.handleErrorResponse(response.status, {
|
|
177
417
|
error: `HTTP ${response.status}`,
|
|
178
418
|
message: response.statusText
|
|
179
|
-
});
|
|
419
|
+
}, requestId);
|
|
180
420
|
}
|
|
421
|
+
this.circuitBreaker?.onSuccess();
|
|
181
422
|
return void 0;
|
|
182
423
|
}
|
|
183
424
|
if (!response.ok) {
|
|
184
|
-
this.handleErrorResponse(response.status, data || {});
|
|
425
|
+
this.handleErrorResponse(response.status, data || {}, requestId);
|
|
185
426
|
}
|
|
427
|
+
this.circuitBreaker?.onSuccess();
|
|
186
428
|
let result = data;
|
|
187
429
|
for (const interceptor of this.interceptors) {
|
|
188
430
|
if (interceptor.onResponse) {
|
|
@@ -195,6 +437,14 @@ var BaseClient = class {
|
|
|
195
437
|
return result;
|
|
196
438
|
} catch (error) {
|
|
197
439
|
clearTimeout(timeoutId);
|
|
440
|
+
if (error instanceof CGSError && error.statusCode && error.statusCode >= 500) {
|
|
441
|
+
this.circuitBreaker?.onFailure();
|
|
442
|
+
} else if (error instanceof NetworkError || error instanceof TimeoutError) {
|
|
443
|
+
this.circuitBreaker?.onFailure();
|
|
444
|
+
}
|
|
445
|
+
if (error instanceof CGSError && !error.requestId) {
|
|
446
|
+
error.requestId = requestId;
|
|
447
|
+
}
|
|
198
448
|
if (error instanceof Error) {
|
|
199
449
|
for (const interceptor of this.interceptors) {
|
|
200
450
|
if (interceptor.onError) {
|
|
@@ -205,15 +455,23 @@ var BaseClient = class {
|
|
|
205
455
|
if (error instanceof Error) {
|
|
206
456
|
if (error.name === "AbortError") {
|
|
207
457
|
if (requestOptions?.signal?.aborted) {
|
|
208
|
-
|
|
458
|
+
const abortError = new CGSError("Request aborted", "REQUEST_ABORTED");
|
|
459
|
+
abortError.requestId = requestId;
|
|
460
|
+
throw abortError;
|
|
209
461
|
}
|
|
210
|
-
|
|
462
|
+
this.circuitBreaker?.onFailure();
|
|
463
|
+
const timeoutError = new TimeoutError(this.config.timeout);
|
|
464
|
+
timeoutError.requestId = requestId;
|
|
465
|
+
throw timeoutError;
|
|
211
466
|
}
|
|
212
467
|
if (error instanceof CGSError) {
|
|
213
468
|
throw error;
|
|
214
469
|
}
|
|
215
470
|
}
|
|
216
|
-
|
|
471
|
+
const networkError = new NetworkError("Network request failed", error);
|
|
472
|
+
networkError.requestId = requestId;
|
|
473
|
+
this.circuitBreaker?.onFailure();
|
|
474
|
+
throw networkError;
|
|
217
475
|
}
|
|
218
476
|
}
|
|
219
477
|
/**
|
|
@@ -252,29 +510,36 @@ var BaseClient = class {
|
|
|
252
510
|
/**
|
|
253
511
|
* Handle error responses from API
|
|
254
512
|
*/
|
|
255
|
-
handleErrorResponse(status, data) {
|
|
513
|
+
handleErrorResponse(status, data, requestId) {
|
|
256
514
|
const message = data.error || data.message || `HTTP ${status}`;
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
515
|
+
const createError = () => {
|
|
516
|
+
switch (status) {
|
|
517
|
+
case 400:
|
|
518
|
+
return new CGSError(message, "BAD_REQUEST", 400, data);
|
|
519
|
+
case 401:
|
|
520
|
+
return new AuthenticationError(message);
|
|
521
|
+
case 403:
|
|
522
|
+
return new CGSError(message, "FORBIDDEN", 403, data);
|
|
523
|
+
case 404:
|
|
524
|
+
return new CGSError(message, "NOT_FOUND", 404, data);
|
|
525
|
+
case 429: {
|
|
526
|
+
const retryAfter = data.retry_after || data.retryAfter;
|
|
527
|
+
return new RateLimitError(retryAfter);
|
|
528
|
+
}
|
|
529
|
+
case 500:
|
|
530
|
+
case 502:
|
|
531
|
+
case 503:
|
|
532
|
+
case 504:
|
|
533
|
+
return new ServiceUnavailableError(message);
|
|
534
|
+
default:
|
|
535
|
+
return new CGSError(message, "UNKNOWN_ERROR", status, data);
|
|
269
536
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
throw new ServiceUnavailableError(message);
|
|
275
|
-
default:
|
|
276
|
-
throw new CGSError(message, "UNKNOWN_ERROR", status, data);
|
|
537
|
+
};
|
|
538
|
+
const error = createError();
|
|
539
|
+
if (requestId) {
|
|
540
|
+
error.requestId = requestId;
|
|
277
541
|
}
|
|
542
|
+
throw error;
|
|
278
543
|
}
|
|
279
544
|
/**
|
|
280
545
|
* Build query string from parameters
|
|
@@ -318,6 +583,18 @@ var BaseClient = class {
|
|
|
318
583
|
getConfig() {
|
|
319
584
|
return { ...this.config };
|
|
320
585
|
}
|
|
586
|
+
/**
|
|
587
|
+
* Get rate limit status from tracked response headers.
|
|
588
|
+
*/
|
|
589
|
+
getRateLimitStatus() {
|
|
590
|
+
return this.rateLimitTracker?.getStatus() ?? null;
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Get circuit breaker status.
|
|
594
|
+
*/
|
|
595
|
+
getCircuitBreakerStatus() {
|
|
596
|
+
return this.circuitBreaker?.getStatus() ?? null;
|
|
597
|
+
}
|
|
321
598
|
/**
|
|
322
599
|
* Health check endpoint
|
|
323
600
|
*/
|
|
@@ -326,73 +603,46 @@ var BaseClient = class {
|
|
|
326
603
|
}
|
|
327
604
|
};
|
|
328
605
|
|
|
329
|
-
// src/
|
|
330
|
-
function
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
return v.toString(16);
|
|
338
|
-
});
|
|
606
|
+
// src/core/webhook-utils.ts
|
|
607
|
+
async function verifyWebhookSignature(payload, signature, secret) {
|
|
608
|
+
const hexDigest = await computeHmacSha256(payload, secret);
|
|
609
|
+
const expectedPrefixed = `sha256=${hexDigest}`;
|
|
610
|
+
if (signature.startsWith("sha256=")) {
|
|
611
|
+
return constantTimeEqual(signature, expectedPrefixed);
|
|
612
|
+
}
|
|
613
|
+
return constantTimeEqual(signature, hexDigest);
|
|
339
614
|
}
|
|
340
|
-
function
|
|
341
|
-
if (typeof
|
|
342
|
-
|
|
615
|
+
async function computeHmacSha256(message, secret) {
|
|
616
|
+
if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.subtle) {
|
|
617
|
+
const encoder = new TextEncoder();
|
|
618
|
+
const key = await globalThis.crypto.subtle.importKey(
|
|
619
|
+
"raw",
|
|
620
|
+
encoder.encode(secret),
|
|
621
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
622
|
+
false,
|
|
623
|
+
["sign"]
|
|
624
|
+
);
|
|
625
|
+
const sig = await globalThis.crypto.subtle.sign("HMAC", key, encoder.encode(message));
|
|
626
|
+
return Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
343
627
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
628
|
+
try {
|
|
629
|
+
const { createHmac } = await import('crypto');
|
|
630
|
+
return createHmac("sha256", secret).update(message).digest("hex");
|
|
631
|
+
} catch {
|
|
632
|
+
throw new Error(
|
|
633
|
+
"No crypto implementation available. Requires Web Crypto API or Node.js crypto module."
|
|
634
|
+
);
|
|
349
635
|
}
|
|
350
|
-
return deviceId;
|
|
351
636
|
}
|
|
352
|
-
function
|
|
353
|
-
if (
|
|
354
|
-
return
|
|
637
|
+
function constantTimeEqual(a, b) {
|
|
638
|
+
if (a.length !== b.length) {
|
|
639
|
+
return false;
|
|
355
640
|
}
|
|
356
|
-
|
|
357
|
-
let
|
|
358
|
-
|
|
359
|
-
let os = "unknown";
|
|
360
|
-
let osVersion = "";
|
|
361
|
-
if (ua.includes("Firefox/")) {
|
|
362
|
-
browser = "Firefox";
|
|
363
|
-
browserVersion = ua.match(/Firefox\/([\d.]+)/)?.[1] || "";
|
|
364
|
-
} else if (ua.includes("Edg/")) {
|
|
365
|
-
browser = "Edge";
|
|
366
|
-
browserVersion = ua.match(/Edg\/([\d.]+)/)?.[1] || "";
|
|
367
|
-
} else if (ua.includes("Chrome/")) {
|
|
368
|
-
browser = "Chrome";
|
|
369
|
-
browserVersion = ua.match(/Chrome\/([\d.]+)/)?.[1] || "";
|
|
370
|
-
} else if (ua.includes("Safari/") && !ua.includes("Chrome")) {
|
|
371
|
-
browser = "Safari";
|
|
372
|
-
browserVersion = ua.match(/Version\/([\d.]+)/)?.[1] || "";
|
|
373
|
-
} else if (ua.includes("Opera") || ua.includes("OPR/")) {
|
|
374
|
-
browser = "Opera";
|
|
375
|
-
browserVersion = ua.match(/(?:Opera|OPR)\/([\d.]+)/)?.[1] || "";
|
|
376
|
-
}
|
|
377
|
-
if (ua.includes("Windows")) {
|
|
378
|
-
os = "Windows";
|
|
379
|
-
if (ua.includes("Windows NT 10.0")) osVersion = "10";
|
|
380
|
-
else if (ua.includes("Windows NT 6.3")) osVersion = "8.1";
|
|
381
|
-
else if (ua.includes("Windows NT 6.2")) osVersion = "8";
|
|
382
|
-
else if (ua.includes("Windows NT 6.1")) osVersion = "7";
|
|
383
|
-
} else if (ua.includes("Mac OS X")) {
|
|
384
|
-
os = "macOS";
|
|
385
|
-
osVersion = ua.match(/Mac OS X ([\d_]+)/)?.[1]?.replace(/_/g, ".") || "";
|
|
386
|
-
} else if (ua.includes("Linux")) {
|
|
387
|
-
os = "Linux";
|
|
388
|
-
} else if (ua.includes("Android")) {
|
|
389
|
-
os = "Android";
|
|
390
|
-
osVersion = ua.match(/Android ([\d.]+)/)?.[1] || "";
|
|
391
|
-
} else if (ua.includes("iOS") || ua.includes("iPhone") || ua.includes("iPad")) {
|
|
392
|
-
os = "iOS";
|
|
393
|
-
osVersion = ua.match(/OS ([\d_]+)/)?.[1]?.replace(/_/g, ".") || "";
|
|
641
|
+
let result = 0;
|
|
642
|
+
for (let i = 0; i < a.length; i++) {
|
|
643
|
+
result |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
394
644
|
}
|
|
395
|
-
return
|
|
645
|
+
return result === 0;
|
|
396
646
|
}
|
|
397
647
|
|
|
398
648
|
// src/geolocation/ciphertext.ts
|
|
@@ -2045,6 +2295,41 @@ var KycClient = class extends BaseClient {
|
|
|
2045
2295
|
headers: this.getUserHeaders()
|
|
2046
2296
|
});
|
|
2047
2297
|
}
|
|
2298
|
+
/**
|
|
2299
|
+
* Create a reuse KYC session for validate a user with existing KYC verification
|
|
2300
|
+
*
|
|
2301
|
+
* @param request - Request containing the reference, customer_id, optional redirect URL, and callback URL (receives POST requests)
|
|
2302
|
+
*/
|
|
2303
|
+
async createReuseKycSession(request) {
|
|
2304
|
+
return this.requestWithRetry("/api/v1/kyc/face/session", {
|
|
2305
|
+
method: "POST",
|
|
2306
|
+
body: JSON.stringify(request),
|
|
2307
|
+
headers: this.getUserHeaders()
|
|
2308
|
+
});
|
|
2309
|
+
}
|
|
2310
|
+
/**
|
|
2311
|
+
* Submit a reuse KYC session for validate a user with existing KYC verification
|
|
2312
|
+
*
|
|
2313
|
+
* @param request - Request containing the reference, token and proof (receives POST requests)
|
|
2314
|
+
*/
|
|
2315
|
+
async submitReuseKycSession(request) {
|
|
2316
|
+
return this.requestWithRetry("/api/v1/kyc/face/submit", {
|
|
2317
|
+
method: "POST",
|
|
2318
|
+
body: JSON.stringify(request),
|
|
2319
|
+
headers: this.getUserHeaders()
|
|
2320
|
+
});
|
|
2321
|
+
}
|
|
2322
|
+
/**
|
|
2323
|
+
* Check reuse KYC session status for a reference
|
|
2324
|
+
* @param reference - The unique reference used for the reuse KYC session (e.g., customer ID or transaction ID)
|
|
2325
|
+
* @returns Response with kyc_status and message (reason)
|
|
2326
|
+
* **/
|
|
2327
|
+
async getReuseKycSessionStatus(reference) {
|
|
2328
|
+
return this.requestWithRetry(`/api/v1/kyc/face/verify/${encodeURIComponent(reference)}`, {
|
|
2329
|
+
method: "GET",
|
|
2330
|
+
headers: this.getUserHeaders()
|
|
2331
|
+
});
|
|
2332
|
+
}
|
|
2048
2333
|
/**
|
|
2049
2334
|
* Check KYC status for a user
|
|
2050
2335
|
*
|
|
@@ -2516,26 +2801,327 @@ var KycClient = class extends BaseClient {
|
|
|
2516
2801
|
// ============================================================================
|
|
2517
2802
|
};
|
|
2518
2803
|
|
|
2804
|
+
// src/decisions/client.ts
|
|
2805
|
+
var DecisionsClient = class extends BaseClient {
|
|
2806
|
+
/**
|
|
2807
|
+
* Record a new decision for a customer.
|
|
2808
|
+
*/
|
|
2809
|
+
async recordDecision(request, requestOptions) {
|
|
2810
|
+
return this.requestWithRetry(
|
|
2811
|
+
"/api/v1/decisions",
|
|
2812
|
+
{ method: "POST", body: JSON.stringify(request) },
|
|
2813
|
+
void 0,
|
|
2814
|
+
void 0,
|
|
2815
|
+
requestOptions
|
|
2816
|
+
);
|
|
2817
|
+
}
|
|
2818
|
+
/**
|
|
2819
|
+
* Get decisions for a customer.
|
|
2820
|
+
*/
|
|
2821
|
+
async getDecisions(customerId, filters, requestOptions) {
|
|
2822
|
+
const queryString = this.buildQueryString({
|
|
2823
|
+
customer_id: customerId,
|
|
2824
|
+
...filters
|
|
2825
|
+
});
|
|
2826
|
+
return this.requestWithRetry(
|
|
2827
|
+
`/api/v1/decisions${queryString}`,
|
|
2828
|
+
{ method: "GET" },
|
|
2829
|
+
void 0,
|
|
2830
|
+
void 0,
|
|
2831
|
+
requestOptions
|
|
2832
|
+
);
|
|
2833
|
+
}
|
|
2834
|
+
/**
|
|
2835
|
+
* Get a specific decision by ID.
|
|
2836
|
+
*/
|
|
2837
|
+
async getDecision(decisionId, requestOptions) {
|
|
2838
|
+
return this.requestWithRetry(
|
|
2839
|
+
`/api/v1/decisions/${encodeURIComponent(decisionId)}`,
|
|
2840
|
+
{ method: "GET" },
|
|
2841
|
+
void 0,
|
|
2842
|
+
void 0,
|
|
2843
|
+
requestOptions
|
|
2844
|
+
);
|
|
2845
|
+
}
|
|
2846
|
+
/**
|
|
2847
|
+
* Apply a label to a customer.
|
|
2848
|
+
*/
|
|
2849
|
+
async applyLabel(request, requestOptions) {
|
|
2850
|
+
return this.requestWithRetry(
|
|
2851
|
+
"/api/v1/labels",
|
|
2852
|
+
{ method: "POST", body: JSON.stringify(request) },
|
|
2853
|
+
void 0,
|
|
2854
|
+
void 0,
|
|
2855
|
+
requestOptions
|
|
2856
|
+
);
|
|
2857
|
+
}
|
|
2858
|
+
/**
|
|
2859
|
+
* Remove a label from a customer.
|
|
2860
|
+
*/
|
|
2861
|
+
async removeLabel(customerId, requestOptions) {
|
|
2862
|
+
return this.requestWithRetry(
|
|
2863
|
+
`/api/v1/labels/${encodeURIComponent(customerId)}`,
|
|
2864
|
+
{ method: "DELETE" },
|
|
2865
|
+
void 0,
|
|
2866
|
+
void 0,
|
|
2867
|
+
requestOptions
|
|
2868
|
+
);
|
|
2869
|
+
}
|
|
2870
|
+
/**
|
|
2871
|
+
* Get labels for a customer.
|
|
2872
|
+
*/
|
|
2873
|
+
async getLabels(customerId, requestOptions) {
|
|
2874
|
+
const queryString = this.buildQueryString({ customer_id: customerId });
|
|
2875
|
+
return this.requestWithRetry(
|
|
2876
|
+
`/api/v1/labels${queryString}`,
|
|
2877
|
+
{ method: "GET" },
|
|
2878
|
+
void 0,
|
|
2879
|
+
void 0,
|
|
2880
|
+
requestOptions
|
|
2881
|
+
);
|
|
2882
|
+
}
|
|
2883
|
+
};
|
|
2884
|
+
|
|
2885
|
+
// src/scores/client.ts
|
|
2886
|
+
var ScoresClient = class extends BaseClient {
|
|
2887
|
+
/**
|
|
2888
|
+
* Get the current risk score for a customer.
|
|
2889
|
+
*/
|
|
2890
|
+
async getScore(customerId, requestOptions) {
|
|
2891
|
+
return this.requestWithRetry(
|
|
2892
|
+
`/api/v1/scores/${encodeURIComponent(customerId)}`,
|
|
2893
|
+
{ method: "GET" },
|
|
2894
|
+
void 0,
|
|
2895
|
+
void 0,
|
|
2896
|
+
requestOptions
|
|
2897
|
+
);
|
|
2898
|
+
}
|
|
2899
|
+
/**
|
|
2900
|
+
* Get a detailed score breakdown for a customer.
|
|
2901
|
+
*/
|
|
2902
|
+
async getScoreBreakdown(customerId, requestOptions) {
|
|
2903
|
+
return this.requestWithRetry(
|
|
2904
|
+
`/api/v1/scores/${encodeURIComponent(customerId)}/breakdown`,
|
|
2905
|
+
{ method: "GET" },
|
|
2906
|
+
void 0,
|
|
2907
|
+
void 0,
|
|
2908
|
+
requestOptions
|
|
2909
|
+
);
|
|
2910
|
+
}
|
|
2911
|
+
};
|
|
2912
|
+
var WorkflowClient = class extends BaseClient {
|
|
2913
|
+
/**
|
|
2914
|
+
* Get the current workflow status for a customer.
|
|
2915
|
+
*/
|
|
2916
|
+
async getWorkflowStatus(customerId, requestOptions) {
|
|
2917
|
+
return this.requestWithRetry(
|
|
2918
|
+
`/api/v1/workflows/${encodeURIComponent(customerId)}/status`,
|
|
2919
|
+
{ method: "GET" },
|
|
2920
|
+
void 0,
|
|
2921
|
+
void 0,
|
|
2922
|
+
requestOptions
|
|
2923
|
+
);
|
|
2924
|
+
}
|
|
2925
|
+
/**
|
|
2926
|
+
* List workflows with optional filters.
|
|
2927
|
+
*/
|
|
2928
|
+
async listWorkflows(filters, requestOptions) {
|
|
2929
|
+
const queryString = this.buildQueryString(filters || {});
|
|
2930
|
+
return this.requestWithRetry(
|
|
2931
|
+
`/api/v1/workflows${queryString}`,
|
|
2932
|
+
{ method: "GET" },
|
|
2933
|
+
void 0,
|
|
2934
|
+
void 0,
|
|
2935
|
+
requestOptions
|
|
2936
|
+
);
|
|
2937
|
+
}
|
|
2938
|
+
/**
|
|
2939
|
+
* Get a specific workflow by ID.
|
|
2940
|
+
*/
|
|
2941
|
+
async getWorkflow(workflowId, requestOptions) {
|
|
2942
|
+
return this.requestWithRetry(
|
|
2943
|
+
`/api/v1/workflows/${encodeURIComponent(workflowId)}`,
|
|
2944
|
+
{ method: "GET" },
|
|
2945
|
+
void 0,
|
|
2946
|
+
void 0,
|
|
2947
|
+
requestOptions
|
|
2948
|
+
);
|
|
2949
|
+
}
|
|
2950
|
+
};
|
|
2951
|
+
|
|
2952
|
+
// src/webhooks/handler.ts
|
|
2953
|
+
var WebhookHandler = class {
|
|
2954
|
+
constructor(config) {
|
|
2955
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
2956
|
+
this.anyHandlers = [];
|
|
2957
|
+
this.secret = config.secret;
|
|
2958
|
+
this.tolerance = config.tolerance ?? 3e5;
|
|
2959
|
+
}
|
|
2960
|
+
/**
|
|
2961
|
+
* Register a handler for a specific event type.
|
|
2962
|
+
*/
|
|
2963
|
+
on(eventType, handler) {
|
|
2964
|
+
const existing = this.handlers.get(eventType) || [];
|
|
2965
|
+
existing.push(handler);
|
|
2966
|
+
this.handlers.set(eventType, existing);
|
|
2967
|
+
return this;
|
|
2968
|
+
}
|
|
2969
|
+
/**
|
|
2970
|
+
* Register a catch-all handler for all event types.
|
|
2971
|
+
*/
|
|
2972
|
+
onAny(handler) {
|
|
2973
|
+
this.anyHandlers.push(handler);
|
|
2974
|
+
return this;
|
|
2975
|
+
}
|
|
2976
|
+
/**
|
|
2977
|
+
* Verify signature and parse the webhook body.
|
|
2978
|
+
*/
|
|
2979
|
+
async verifyAndParse(body, signature) {
|
|
2980
|
+
const isValid = await verifyWebhookSignature(body, signature, this.secret);
|
|
2981
|
+
if (!isValid) {
|
|
2982
|
+
throw new Error("Invalid webhook signature");
|
|
2983
|
+
}
|
|
2984
|
+
return this.parseAndValidate(body);
|
|
2985
|
+
}
|
|
2986
|
+
/**
|
|
2987
|
+
* Verify signature, parse, and dispatch to registered handlers.
|
|
2988
|
+
*/
|
|
2989
|
+
async handle(body, signature) {
|
|
2990
|
+
const event = await this.verifyAndParse(body, signature);
|
|
2991
|
+
await this.dispatch(event);
|
|
2992
|
+
}
|
|
2993
|
+
/**
|
|
2994
|
+
* Parse an event without signature verification (for testing).
|
|
2995
|
+
*/
|
|
2996
|
+
parseEvent(body) {
|
|
2997
|
+
return this.parseAndValidate(body);
|
|
2998
|
+
}
|
|
2999
|
+
parseAndValidate(body) {
|
|
3000
|
+
const event = JSON.parse(body);
|
|
3001
|
+
if (!event.type || !event.id || !event.timestamp) {
|
|
3002
|
+
throw new Error("Invalid webhook event: missing required fields (type, id, timestamp)");
|
|
3003
|
+
}
|
|
3004
|
+
if (this.tolerance > 0) {
|
|
3005
|
+
const eventTime = new Date(event.timestamp).getTime();
|
|
3006
|
+
const now = Date.now();
|
|
3007
|
+
if (Math.abs(now - eventTime) > this.tolerance) {
|
|
3008
|
+
throw new Error(
|
|
3009
|
+
`Webhook event timestamp is outside tolerance window (${this.tolerance}ms)`
|
|
3010
|
+
);
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
return event;
|
|
3014
|
+
}
|
|
3015
|
+
async dispatch(event) {
|
|
3016
|
+
const typeHandlers = this.handlers.get(event.type) || [];
|
|
3017
|
+
const allHandlers = [...typeHandlers, ...this.anyHandlers];
|
|
3018
|
+
for (const handler of allHandlers) {
|
|
3019
|
+
await handler(event);
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3022
|
+
};
|
|
3023
|
+
|
|
3024
|
+
// src/webhooks/middleware.ts
|
|
3025
|
+
function createWebhookMiddleware(options) {
|
|
3026
|
+
const handler = buildHandler(options);
|
|
3027
|
+
const signatureHeader = options.signatureHeader || "x-webhook-signature";
|
|
3028
|
+
return async (req, res, next) => {
|
|
3029
|
+
try {
|
|
3030
|
+
const body = typeof req.body === "string" ? req.body : req.body.toString("utf-8");
|
|
3031
|
+
const signature = req.headers[signatureHeader];
|
|
3032
|
+
if (!signature || typeof signature !== "string") {
|
|
3033
|
+
res.status(401).json({ error: "Missing webhook signature" });
|
|
3034
|
+
return;
|
|
3035
|
+
}
|
|
3036
|
+
await handler.handle(body, signature);
|
|
3037
|
+
res.status(200).json({ received: true });
|
|
3038
|
+
} catch (error) {
|
|
3039
|
+
const message = error instanceof Error ? error.message : "Webhook processing failed";
|
|
3040
|
+
if (message.includes("signature")) {
|
|
3041
|
+
res.status(401).json({ error: message });
|
|
3042
|
+
} else if (message.includes("tolerance") || message.includes("timestamp")) {
|
|
3043
|
+
res.status(400).json({ error: message });
|
|
3044
|
+
} else if (next) {
|
|
3045
|
+
next(error);
|
|
3046
|
+
} else {
|
|
3047
|
+
res.status(500).json({ error: message });
|
|
3048
|
+
}
|
|
3049
|
+
}
|
|
3050
|
+
};
|
|
3051
|
+
}
|
|
3052
|
+
function createNextWebhookHandler(options) {
|
|
3053
|
+
const handler = buildHandler(options);
|
|
3054
|
+
const signatureHeader = options.signatureHeader || "x-webhook-signature";
|
|
3055
|
+
return async (request) => {
|
|
3056
|
+
try {
|
|
3057
|
+
const body = await request.text();
|
|
3058
|
+
const signature = request.headers.get(signatureHeader);
|
|
3059
|
+
if (!signature) {
|
|
3060
|
+
return new Response(JSON.stringify({ error: "Missing webhook signature" }), {
|
|
3061
|
+
status: 401,
|
|
3062
|
+
headers: { "Content-Type": "application/json" }
|
|
3063
|
+
});
|
|
3064
|
+
}
|
|
3065
|
+
await handler.handle(body, signature);
|
|
3066
|
+
return new Response(JSON.stringify({ received: true }), {
|
|
3067
|
+
status: 200,
|
|
3068
|
+
headers: { "Content-Type": "application/json" }
|
|
3069
|
+
});
|
|
3070
|
+
} catch (error) {
|
|
3071
|
+
const message = error instanceof Error ? error.message : "Webhook processing failed";
|
|
3072
|
+
const status = message.includes("signature") ? 401 : message.includes("tolerance") || message.includes("timestamp") ? 400 : 500;
|
|
3073
|
+
return new Response(JSON.stringify({ error: message }), {
|
|
3074
|
+
status,
|
|
3075
|
+
headers: { "Content-Type": "application/json" }
|
|
3076
|
+
});
|
|
3077
|
+
}
|
|
3078
|
+
};
|
|
3079
|
+
}
|
|
3080
|
+
function buildHandler(options) {
|
|
3081
|
+
const handler = new WebhookHandler(options);
|
|
3082
|
+
if (options.handlers) {
|
|
3083
|
+
for (const [eventType, eventHandler] of Object.entries(options.handlers)) {
|
|
3084
|
+
if (eventHandler) {
|
|
3085
|
+
handler.on(eventType, eventHandler);
|
|
3086
|
+
}
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
if (options.onAny) {
|
|
3090
|
+
handler.onAny(options.onAny);
|
|
3091
|
+
}
|
|
3092
|
+
return handler;
|
|
3093
|
+
}
|
|
3094
|
+
|
|
2519
3095
|
exports.AuthenticationError = AuthenticationError;
|
|
2520
3096
|
exports.BaseClient = BaseClient;
|
|
2521
3097
|
exports.CGSError = CGSError;
|
|
3098
|
+
exports.CircuitBreaker = CircuitBreaker;
|
|
3099
|
+
exports.CircuitBreakerOpenError = CircuitBreakerOpenError;
|
|
2522
3100
|
exports.ComplianceBlockedError = ComplianceBlockedError;
|
|
2523
3101
|
exports.ComplianceClient = ComplianceClient;
|
|
2524
3102
|
exports.ComplianceError = ComplianceError;
|
|
2525
3103
|
exports.DEFAULT_CURRENCY_RATES = DEFAULT_CURRENCY_RATES;
|
|
3104
|
+
exports.DecisionsClient = DecisionsClient;
|
|
2526
3105
|
exports.GeolocationClient = GeolocationClient;
|
|
2527
3106
|
exports.KycClient = KycClient;
|
|
2528
3107
|
exports.NetworkError = NetworkError;
|
|
2529
3108
|
exports.RateLimitError = RateLimitError;
|
|
3109
|
+
exports.RateLimitTracker = RateLimitTracker;
|
|
2530
3110
|
exports.RiskProfileClient = RiskProfileClient;
|
|
2531
3111
|
exports.SDK_VERSION = SDK_VERSION;
|
|
3112
|
+
exports.ScoresClient = ScoresClient;
|
|
2532
3113
|
exports.ServiceUnavailableError = ServiceUnavailableError;
|
|
2533
3114
|
exports.TimeoutError = TimeoutError;
|
|
2534
3115
|
exports.ValidationError = ValidationError;
|
|
3116
|
+
exports.WebhookHandler = WebhookHandler;
|
|
3117
|
+
exports.WorkflowClient = WorkflowClient;
|
|
2535
3118
|
exports.createConsoleLogger = createConsoleLogger;
|
|
3119
|
+
exports.createNextWebhookHandler = createNextWebhookHandler;
|
|
3120
|
+
exports.createWebhookMiddleware = createWebhookMiddleware;
|
|
2536
3121
|
exports.decodeCipherText = decodeCipherText;
|
|
2537
3122
|
exports.generateCipherText = generateCipherText;
|
|
2538
3123
|
exports.isCipherTextExpired = isCipherTextExpired;
|
|
2539
3124
|
exports.noopLogger = noopLogger;
|
|
3125
|
+
exports.verifyWebhookSignature = verifyWebhookSignature;
|
|
2540
3126
|
//# sourceMappingURL=index.js.map
|
|
2541
3127
|
//# sourceMappingURL=index.js.map
|