vesant-sdk 1.2.0 → 1.3.0
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 +14 -6
- package/dist/index.d.ts +14 -6
- package/dist/index.js +641 -90
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +632 -91
- package/dist/index.mjs.map +1 -1
- package/dist/kyc/core.d.mts +3 -2
- package/dist/kyc/core.d.ts +3 -2
- package/dist/kyc/core.js +249 -29
- package/dist/kyc/core.js.map +1 -1
- package/dist/kyc/core.mjs +249 -29
- package/dist/kyc/core.mjs.map +1 -1
- package/dist/kyc/index.d.mts +3 -2
- package/dist/kyc/index.d.ts +3 -2
- package/dist/kyc/index.js +249 -29
- package/dist/kyc/index.js.map +1 -1
- package/dist/kyc/index.mjs +249 -29
- package/dist/kyc/index.mjs.map +1 -1
- package/dist/react.d.mts +4 -3
- package/dist/react.d.ts +4 -3
- package/dist/react.js +1 -1
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +1 -1
- 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 +16 -1
- package/dist/types-BpKxSXGF.d.mts +0 -177
- package/dist/types-BpKxSXGF.d.ts +0 -177
|
@@ -54,6 +54,146 @@ var TimeoutError = class _TimeoutError extends CGSError {
|
|
|
54
54
|
Object.setPrototypeOf(this, _TimeoutError.prototype);
|
|
55
55
|
}
|
|
56
56
|
};
|
|
57
|
+
var CircuitBreakerOpenError = class _CircuitBreakerOpenError extends CGSError {
|
|
58
|
+
constructor() {
|
|
59
|
+
super("Circuit breaker is open \u2014 requests are temporarily blocked", "CIRCUIT_BREAKER_OPEN", 503);
|
|
60
|
+
this.name = "CircuitBreakerOpenError";
|
|
61
|
+
Object.setPrototypeOf(this, _CircuitBreakerOpenError.prototype);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// src/core/circuit-breaker.ts
|
|
66
|
+
var CircuitBreaker = class {
|
|
67
|
+
constructor(config = {}) {
|
|
68
|
+
this.state = "closed";
|
|
69
|
+
this.failures = 0;
|
|
70
|
+
this.successes = 0;
|
|
71
|
+
this.lastFailureTime = null;
|
|
72
|
+
this.failureThreshold = config.failureThreshold ?? 5;
|
|
73
|
+
this.resetTimeout = config.resetTimeout ?? 3e4;
|
|
74
|
+
this.successThreshold = config.successThreshold ?? 1;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Check if a request can proceed through the circuit breaker.
|
|
78
|
+
*/
|
|
79
|
+
canExecute() {
|
|
80
|
+
if (this.state === "closed") {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
if (this.state === "open") {
|
|
84
|
+
const now = Date.now();
|
|
85
|
+
if (this.lastFailureTime && now - this.lastFailureTime >= this.resetTimeout) {
|
|
86
|
+
this.state = "half-open";
|
|
87
|
+
this.successes = 0;
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Record a successful request.
|
|
96
|
+
*/
|
|
97
|
+
onSuccess() {
|
|
98
|
+
if (this.state === "half-open") {
|
|
99
|
+
this.successes++;
|
|
100
|
+
if (this.successes >= this.successThreshold) {
|
|
101
|
+
this.state = "closed";
|
|
102
|
+
this.failures = 0;
|
|
103
|
+
this.successes = 0;
|
|
104
|
+
this.lastFailureTime = null;
|
|
105
|
+
}
|
|
106
|
+
} else if (this.state === "closed") {
|
|
107
|
+
this.failures = 0;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Record a failed request.
|
|
112
|
+
*/
|
|
113
|
+
onFailure() {
|
|
114
|
+
this.failures++;
|
|
115
|
+
this.lastFailureTime = Date.now();
|
|
116
|
+
if (this.state === "half-open") {
|
|
117
|
+
this.state = "open";
|
|
118
|
+
this.successes = 0;
|
|
119
|
+
} else if (this.state === "closed" && this.failures >= this.failureThreshold) {
|
|
120
|
+
this.state = "open";
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get current circuit breaker status.
|
|
125
|
+
*/
|
|
126
|
+
getStatus() {
|
|
127
|
+
return {
|
|
128
|
+
state: this.state,
|
|
129
|
+
failures: this.failures,
|
|
130
|
+
successes: this.successes,
|
|
131
|
+
lastFailureTime: this.lastFailureTime,
|
|
132
|
+
nextRetryTime: this.state === "open" && this.lastFailureTime ? this.lastFailureTime + this.resetTimeout : null
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Reset the circuit breaker to its initial closed state.
|
|
137
|
+
*/
|
|
138
|
+
reset() {
|
|
139
|
+
this.state = "closed";
|
|
140
|
+
this.failures = 0;
|
|
141
|
+
this.successes = 0;
|
|
142
|
+
this.lastFailureTime = null;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// src/core/rate-limiter.ts
|
|
147
|
+
var RateLimitTracker = class {
|
|
148
|
+
constructor() {
|
|
149
|
+
this.limit = null;
|
|
150
|
+
this.remaining = null;
|
|
151
|
+
this.reset = null;
|
|
152
|
+
this.retryAfter = null;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Extract rate limit information from response headers.
|
|
156
|
+
*/
|
|
157
|
+
updateFromHeaders(headers) {
|
|
158
|
+
const limit = headers.get("x-ratelimit-limit");
|
|
159
|
+
const remaining = headers.get("x-ratelimit-remaining");
|
|
160
|
+
const reset = headers.get("x-ratelimit-reset");
|
|
161
|
+
const retryAfter = headers.get("retry-after");
|
|
162
|
+
if (limit !== null) this.limit = parseInt(limit, 10);
|
|
163
|
+
if (remaining !== null) this.remaining = parseInt(remaining, 10);
|
|
164
|
+
if (reset !== null) this.reset = parseInt(reset, 10);
|
|
165
|
+
if (retryAfter !== null) this.retryAfter = parseInt(retryAfter, 10);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Check if the rate limit has been exceeded based on tracked headers.
|
|
169
|
+
*/
|
|
170
|
+
isLimitExceeded() {
|
|
171
|
+
if (this.remaining !== null && this.remaining <= 0) {
|
|
172
|
+
if (this.reset !== null) {
|
|
173
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
174
|
+
if (now >= this.reset) {
|
|
175
|
+
this.remaining = null;
|
|
176
|
+
this.reset = null;
|
|
177
|
+
this.retryAfter = null;
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Get current rate limit status.
|
|
187
|
+
*/
|
|
188
|
+
getStatus() {
|
|
189
|
+
return {
|
|
190
|
+
limit: this.limit,
|
|
191
|
+
remaining: this.remaining,
|
|
192
|
+
reset: this.reset,
|
|
193
|
+
retryAfter: this.retryAfter
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
};
|
|
57
197
|
|
|
58
198
|
// src/core/logger.ts
|
|
59
199
|
function createConsoleLogger() {
|
|
@@ -74,11 +214,82 @@ function createConsoleLogger() {
|
|
|
74
214
|
}
|
|
75
215
|
|
|
76
216
|
// src/core/version.ts
|
|
77
|
-
var SDK_VERSION = "1.
|
|
217
|
+
var SDK_VERSION = "1.3.0";
|
|
218
|
+
|
|
219
|
+
// src/shared/browser-utils.ts
|
|
220
|
+
function generateUUID() {
|
|
221
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
222
|
+
return crypto.randomUUID();
|
|
223
|
+
}
|
|
224
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
225
|
+
const r = Math.random() * 16 | 0;
|
|
226
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
227
|
+
return v.toString(16);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
function generateDeviceId() {
|
|
231
|
+
if (typeof window === "undefined" || typeof localStorage === "undefined") {
|
|
232
|
+
return generateUUID();
|
|
233
|
+
}
|
|
234
|
+
const storageKey = "cgs_device_id";
|
|
235
|
+
let deviceId = localStorage.getItem(storageKey);
|
|
236
|
+
if (!deviceId) {
|
|
237
|
+
deviceId = generateUUID();
|
|
238
|
+
localStorage.setItem(storageKey, deviceId);
|
|
239
|
+
}
|
|
240
|
+
return deviceId;
|
|
241
|
+
}
|
|
242
|
+
function getBrowserInfo() {
|
|
243
|
+
if (typeof navigator === "undefined") {
|
|
244
|
+
return { browser: "unknown", browser_version: "", os: "unknown", os_version: "" };
|
|
245
|
+
}
|
|
246
|
+
const ua = navigator.userAgent;
|
|
247
|
+
let browser = "unknown";
|
|
248
|
+
let browserVersion = "";
|
|
249
|
+
let os = "unknown";
|
|
250
|
+
let osVersion = "";
|
|
251
|
+
if (ua.includes("Firefox/")) {
|
|
252
|
+
browser = "Firefox";
|
|
253
|
+
browserVersion = ua.match(/Firefox\/([\d.]+)/)?.[1] || "";
|
|
254
|
+
} else if (ua.includes("Edg/")) {
|
|
255
|
+
browser = "Edge";
|
|
256
|
+
browserVersion = ua.match(/Edg\/([\d.]+)/)?.[1] || "";
|
|
257
|
+
} else if (ua.includes("Chrome/")) {
|
|
258
|
+
browser = "Chrome";
|
|
259
|
+
browserVersion = ua.match(/Chrome\/([\d.]+)/)?.[1] || "";
|
|
260
|
+
} else if (ua.includes("Safari/") && !ua.includes("Chrome")) {
|
|
261
|
+
browser = "Safari";
|
|
262
|
+
browserVersion = ua.match(/Version\/([\d.]+)/)?.[1] || "";
|
|
263
|
+
} else if (ua.includes("Opera") || ua.includes("OPR/")) {
|
|
264
|
+
browser = "Opera";
|
|
265
|
+
browserVersion = ua.match(/(?:Opera|OPR)\/([\d.]+)/)?.[1] || "";
|
|
266
|
+
}
|
|
267
|
+
if (ua.includes("Windows")) {
|
|
268
|
+
os = "Windows";
|
|
269
|
+
if (ua.includes("Windows NT 10.0")) osVersion = "10";
|
|
270
|
+
else if (ua.includes("Windows NT 6.3")) osVersion = "8.1";
|
|
271
|
+
else if (ua.includes("Windows NT 6.2")) osVersion = "8";
|
|
272
|
+
else if (ua.includes("Windows NT 6.1")) osVersion = "7";
|
|
273
|
+
} else if (ua.includes("Mac OS X")) {
|
|
274
|
+
os = "macOS";
|
|
275
|
+
osVersion = ua.match(/Mac OS X ([\d_]+)/)?.[1]?.replace(/_/g, ".") || "";
|
|
276
|
+
} else if (ua.includes("Linux")) {
|
|
277
|
+
os = "Linux";
|
|
278
|
+
} else if (ua.includes("Android")) {
|
|
279
|
+
os = "Android";
|
|
280
|
+
osVersion = ua.match(/Android ([\d.]+)/)?.[1] || "";
|
|
281
|
+
} else if (ua.includes("iOS") || ua.includes("iPhone") || ua.includes("iPad")) {
|
|
282
|
+
os = "iOS";
|
|
283
|
+
osVersion = ua.match(/OS ([\d_]+)/)?.[1]?.replace(/_/g, ".") || "";
|
|
284
|
+
}
|
|
285
|
+
return { browser, browser_version: browserVersion, os, os_version: osVersion };
|
|
286
|
+
}
|
|
78
287
|
|
|
79
288
|
// src/core/client.ts
|
|
80
289
|
var BaseClient = class {
|
|
81
290
|
constructor(config) {
|
|
291
|
+
this.circuitBreaker = null;
|
|
292
|
+
this.rateLimitTracker = null;
|
|
82
293
|
if (!config.baseURL?.trim()) {
|
|
83
294
|
throw new ValidationError("baseURL is required and must be a non-empty string", ["baseURL"]);
|
|
84
295
|
}
|
|
@@ -88,8 +299,7 @@ var BaseClient = class {
|
|
|
88
299
|
this.interceptors = config.interceptors || [];
|
|
89
300
|
this.logger = config.logger || createConsoleLogger();
|
|
90
301
|
this.config = {
|
|
91
|
-
|
|
92
|
-
tenantId: config.tenantId,
|
|
302
|
+
...config,
|
|
93
303
|
apiKey: config.apiKey || "",
|
|
94
304
|
headers: config.headers || {},
|
|
95
305
|
timeout: config.timeout || 1e4,
|
|
@@ -98,22 +308,49 @@ var BaseClient = class {
|
|
|
98
308
|
interceptors: this.interceptors,
|
|
99
309
|
logger: this.logger
|
|
100
310
|
};
|
|
311
|
+
if (config.circuitBreaker) {
|
|
312
|
+
this.circuitBreaker = new CircuitBreaker(config.circuitBreaker);
|
|
313
|
+
}
|
|
314
|
+
if (config.enableRateLimitTracking) {
|
|
315
|
+
this.rateLimitTracker = new RateLimitTracker();
|
|
316
|
+
}
|
|
101
317
|
}
|
|
102
318
|
/**
|
|
103
319
|
* Make an HTTP request with timeout and error handling
|
|
104
320
|
*/
|
|
105
321
|
async request(endpoint, options = {}, serviceURL, requestOptions) {
|
|
106
|
-
const
|
|
322
|
+
const requestId = generateUUID();
|
|
323
|
+
if (this.circuitBreaker && !this.circuitBreaker.canExecute()) {
|
|
324
|
+
const error = new CircuitBreakerOpenError();
|
|
325
|
+
error.requestId = requestId;
|
|
326
|
+
throw error;
|
|
327
|
+
}
|
|
328
|
+
if (this.rateLimitTracker && this.rateLimitTracker.isLimitExceeded()) {
|
|
329
|
+
const status = this.rateLimitTracker.getStatus();
|
|
330
|
+
const error = new RateLimitError(status.retryAfter ?? void 0);
|
|
331
|
+
error.requestId = requestId;
|
|
332
|
+
throw error;
|
|
333
|
+
}
|
|
334
|
+
const baseURL = this.config.environment === "sandbox" && this.config.sandboxBaseURL ? this.config.sandboxBaseURL : serviceURL || this.config.baseURL;
|
|
335
|
+
const url = `${serviceURL || baseURL}${endpoint}`;
|
|
107
336
|
const headers = {
|
|
108
337
|
"Content-Type": "application/json",
|
|
109
338
|
"X-Tenant-ID": this.config.tenantId,
|
|
110
339
|
"X-SDK-Version": `vesant-sdk-ts/${SDK_VERSION}`,
|
|
340
|
+
"X-Request-ID": requestId,
|
|
111
341
|
...this.config.headers,
|
|
112
342
|
...options.headers || {}
|
|
113
343
|
};
|
|
114
344
|
if (this.config.apiKey) {
|
|
115
345
|
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
116
346
|
}
|
|
347
|
+
if (this.config.environment === "sandbox") {
|
|
348
|
+
headers["X-Sandbox"] = "true";
|
|
349
|
+
}
|
|
350
|
+
const method = (options.method || "GET").toUpperCase();
|
|
351
|
+
if (["POST", "PUT", "PATCH"].includes(method)) {
|
|
352
|
+
headers["Idempotency-Key"] = requestOptions?.idempotencyKey || generateUUID();
|
|
353
|
+
}
|
|
117
354
|
const controller = new AbortController();
|
|
118
355
|
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
119
356
|
if (requestOptions?.signal) {
|
|
@@ -141,6 +378,9 @@ var BaseClient = class {
|
|
|
141
378
|
signal: controller.signal
|
|
142
379
|
});
|
|
143
380
|
clearTimeout(timeoutId);
|
|
381
|
+
if (this.rateLimitTracker) {
|
|
382
|
+
this.rateLimitTracker.updateFromHeaders(response.headers);
|
|
383
|
+
}
|
|
144
384
|
let data;
|
|
145
385
|
try {
|
|
146
386
|
data = await response.json();
|
|
@@ -149,13 +389,15 @@ var BaseClient = class {
|
|
|
149
389
|
this.handleErrorResponse(response.status, {
|
|
150
390
|
error: `HTTP ${response.status}`,
|
|
151
391
|
message: response.statusText
|
|
152
|
-
});
|
|
392
|
+
}, requestId);
|
|
153
393
|
}
|
|
394
|
+
this.circuitBreaker?.onSuccess();
|
|
154
395
|
return void 0;
|
|
155
396
|
}
|
|
156
397
|
if (!response.ok) {
|
|
157
|
-
this.handleErrorResponse(response.status, data || {});
|
|
398
|
+
this.handleErrorResponse(response.status, data || {}, requestId);
|
|
158
399
|
}
|
|
400
|
+
this.circuitBreaker?.onSuccess();
|
|
159
401
|
let result = data;
|
|
160
402
|
for (const interceptor of this.interceptors) {
|
|
161
403
|
if (interceptor.onResponse) {
|
|
@@ -168,6 +410,14 @@ var BaseClient = class {
|
|
|
168
410
|
return result;
|
|
169
411
|
} catch (error) {
|
|
170
412
|
clearTimeout(timeoutId);
|
|
413
|
+
if (error instanceof CGSError && error.statusCode && error.statusCode >= 500) {
|
|
414
|
+
this.circuitBreaker?.onFailure();
|
|
415
|
+
} else if (error instanceof NetworkError || error instanceof TimeoutError) {
|
|
416
|
+
this.circuitBreaker?.onFailure();
|
|
417
|
+
}
|
|
418
|
+
if (error instanceof CGSError && !error.requestId) {
|
|
419
|
+
error.requestId = requestId;
|
|
420
|
+
}
|
|
171
421
|
if (error instanceof Error) {
|
|
172
422
|
for (const interceptor of this.interceptors) {
|
|
173
423
|
if (interceptor.onError) {
|
|
@@ -178,15 +428,23 @@ var BaseClient = class {
|
|
|
178
428
|
if (error instanceof Error) {
|
|
179
429
|
if (error.name === "AbortError") {
|
|
180
430
|
if (requestOptions?.signal?.aborted) {
|
|
181
|
-
|
|
431
|
+
const abortError = new CGSError("Request aborted", "REQUEST_ABORTED");
|
|
432
|
+
abortError.requestId = requestId;
|
|
433
|
+
throw abortError;
|
|
182
434
|
}
|
|
183
|
-
|
|
435
|
+
this.circuitBreaker?.onFailure();
|
|
436
|
+
const timeoutError = new TimeoutError(this.config.timeout);
|
|
437
|
+
timeoutError.requestId = requestId;
|
|
438
|
+
throw timeoutError;
|
|
184
439
|
}
|
|
185
440
|
if (error instanceof CGSError) {
|
|
186
441
|
throw error;
|
|
187
442
|
}
|
|
188
443
|
}
|
|
189
|
-
|
|
444
|
+
const networkError = new NetworkError("Network request failed", error);
|
|
445
|
+
networkError.requestId = requestId;
|
|
446
|
+
this.circuitBreaker?.onFailure();
|
|
447
|
+
throw networkError;
|
|
190
448
|
}
|
|
191
449
|
}
|
|
192
450
|
/**
|
|
@@ -225,29 +483,36 @@ var BaseClient = class {
|
|
|
225
483
|
/**
|
|
226
484
|
* Handle error responses from API
|
|
227
485
|
*/
|
|
228
|
-
handleErrorResponse(status, data) {
|
|
486
|
+
handleErrorResponse(status, data, requestId) {
|
|
229
487
|
const message = data.error || data.message || `HTTP ${status}`;
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
488
|
+
const createError = () => {
|
|
489
|
+
switch (status) {
|
|
490
|
+
case 400:
|
|
491
|
+
return new CGSError(message, "BAD_REQUEST", 400, data);
|
|
492
|
+
case 401:
|
|
493
|
+
return new AuthenticationError(message);
|
|
494
|
+
case 403:
|
|
495
|
+
return new CGSError(message, "FORBIDDEN", 403, data);
|
|
496
|
+
case 404:
|
|
497
|
+
return new CGSError(message, "NOT_FOUND", 404, data);
|
|
498
|
+
case 429: {
|
|
499
|
+
const retryAfter = data.retry_after || data.retryAfter;
|
|
500
|
+
return new RateLimitError(retryAfter);
|
|
501
|
+
}
|
|
502
|
+
case 500:
|
|
503
|
+
case 502:
|
|
504
|
+
case 503:
|
|
505
|
+
case 504:
|
|
506
|
+
return new ServiceUnavailableError(message);
|
|
507
|
+
default:
|
|
508
|
+
return new CGSError(message, "UNKNOWN_ERROR", status, data);
|
|
242
509
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
throw new ServiceUnavailableError(message);
|
|
248
|
-
default:
|
|
249
|
-
throw new CGSError(message, "UNKNOWN_ERROR", status, data);
|
|
510
|
+
};
|
|
511
|
+
const error = createError();
|
|
512
|
+
if (requestId) {
|
|
513
|
+
error.requestId = requestId;
|
|
250
514
|
}
|
|
515
|
+
throw error;
|
|
251
516
|
}
|
|
252
517
|
/**
|
|
253
518
|
* Build query string from parameters
|
|
@@ -291,6 +556,18 @@ var BaseClient = class {
|
|
|
291
556
|
getConfig() {
|
|
292
557
|
return { ...this.config };
|
|
293
558
|
}
|
|
559
|
+
/**
|
|
560
|
+
* Get rate limit status from tracked response headers.
|
|
561
|
+
*/
|
|
562
|
+
getRateLimitStatus() {
|
|
563
|
+
return this.rateLimitTracker?.getStatus() ?? null;
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Get circuit breaker status.
|
|
567
|
+
*/
|
|
568
|
+
getCircuitBreakerStatus() {
|
|
569
|
+
return this.circuitBreaker?.getStatus() ?? null;
|
|
570
|
+
}
|
|
294
571
|
/**
|
|
295
572
|
* Health check endpoint
|
|
296
573
|
*/
|
|
@@ -299,75 +576,6 @@ var BaseClient = class {
|
|
|
299
576
|
}
|
|
300
577
|
};
|
|
301
578
|
|
|
302
|
-
// src/shared/browser-utils.ts
|
|
303
|
-
function generateUUID() {
|
|
304
|
-
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
305
|
-
return crypto.randomUUID();
|
|
306
|
-
}
|
|
307
|
-
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
308
|
-
const r = Math.random() * 16 | 0;
|
|
309
|
-
const v = c === "x" ? r : r & 3 | 8;
|
|
310
|
-
return v.toString(16);
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
function generateDeviceId() {
|
|
314
|
-
if (typeof window === "undefined" || typeof localStorage === "undefined") {
|
|
315
|
-
return generateUUID();
|
|
316
|
-
}
|
|
317
|
-
const storageKey = "cgs_device_id";
|
|
318
|
-
let deviceId = localStorage.getItem(storageKey);
|
|
319
|
-
if (!deviceId) {
|
|
320
|
-
deviceId = generateUUID();
|
|
321
|
-
localStorage.setItem(storageKey, deviceId);
|
|
322
|
-
}
|
|
323
|
-
return deviceId;
|
|
324
|
-
}
|
|
325
|
-
function getBrowserInfo() {
|
|
326
|
-
if (typeof navigator === "undefined") {
|
|
327
|
-
return { browser: "unknown", browser_version: "", os: "unknown", os_version: "" };
|
|
328
|
-
}
|
|
329
|
-
const ua = navigator.userAgent;
|
|
330
|
-
let browser = "unknown";
|
|
331
|
-
let browserVersion = "";
|
|
332
|
-
let os = "unknown";
|
|
333
|
-
let osVersion = "";
|
|
334
|
-
if (ua.includes("Firefox/")) {
|
|
335
|
-
browser = "Firefox";
|
|
336
|
-
browserVersion = ua.match(/Firefox\/([\d.]+)/)?.[1] || "";
|
|
337
|
-
} else if (ua.includes("Edg/")) {
|
|
338
|
-
browser = "Edge";
|
|
339
|
-
browserVersion = ua.match(/Edg\/([\d.]+)/)?.[1] || "";
|
|
340
|
-
} else if (ua.includes("Chrome/")) {
|
|
341
|
-
browser = "Chrome";
|
|
342
|
-
browserVersion = ua.match(/Chrome\/([\d.]+)/)?.[1] || "";
|
|
343
|
-
} else if (ua.includes("Safari/") && !ua.includes("Chrome")) {
|
|
344
|
-
browser = "Safari";
|
|
345
|
-
browserVersion = ua.match(/Version\/([\d.]+)/)?.[1] || "";
|
|
346
|
-
} else if (ua.includes("Opera") || ua.includes("OPR/")) {
|
|
347
|
-
browser = "Opera";
|
|
348
|
-
browserVersion = ua.match(/(?:Opera|OPR)\/([\d.]+)/)?.[1] || "";
|
|
349
|
-
}
|
|
350
|
-
if (ua.includes("Windows")) {
|
|
351
|
-
os = "Windows";
|
|
352
|
-
if (ua.includes("Windows NT 10.0")) osVersion = "10";
|
|
353
|
-
else if (ua.includes("Windows NT 6.3")) osVersion = "8.1";
|
|
354
|
-
else if (ua.includes("Windows NT 6.2")) osVersion = "8";
|
|
355
|
-
else if (ua.includes("Windows NT 6.1")) osVersion = "7";
|
|
356
|
-
} else if (ua.includes("Mac OS X")) {
|
|
357
|
-
os = "macOS";
|
|
358
|
-
osVersion = ua.match(/Mac OS X ([\d_]+)/)?.[1]?.replace(/_/g, ".") || "";
|
|
359
|
-
} else if (ua.includes("Linux")) {
|
|
360
|
-
os = "Linux";
|
|
361
|
-
} else if (ua.includes("Android")) {
|
|
362
|
-
os = "Android";
|
|
363
|
-
osVersion = ua.match(/Android ([\d.]+)/)?.[1] || "";
|
|
364
|
-
} else if (ua.includes("iOS") || ua.includes("iPhone") || ua.includes("iPad")) {
|
|
365
|
-
os = "iOS";
|
|
366
|
-
osVersion = ua.match(/OS ([\d_]+)/)?.[1]?.replace(/_/g, ".") || "";
|
|
367
|
-
}
|
|
368
|
-
return { browser, browser_version: browserVersion, os, os_version: osVersion };
|
|
369
|
-
}
|
|
370
|
-
|
|
371
579
|
// src/geolocation/ciphertext.ts
|
|
372
580
|
var CIPHER_TEXT_EXPIRY_MINUTES = 5;
|
|
373
581
|
async function computeHMAC(key, message) {
|