cgs-compliance-sdk 2.0.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.
@@ -0,0 +1,1475 @@
1
+ // src/geolocation/client.ts
2
+ var GeolocationClient = class {
3
+ constructor(config) {
4
+ this.config = {
5
+ baseURL: config.baseURL,
6
+ tenantId: config.tenantId,
7
+ apiKey: config.apiKey || "",
8
+ headers: config.headers || {},
9
+ timeout: config.timeout || 1e4,
10
+ debug: config.debug || false
11
+ };
12
+ }
13
+ // ============================================================================
14
+ // Private Helper Methods
15
+ // ============================================================================
16
+ async request(endpoint, options = {}) {
17
+ const url = `${this.config.baseURL}${endpoint}`;
18
+ const headers = {
19
+ "Content-Type": "application/json",
20
+ "X-Tenant-ID": this.config.tenantId,
21
+ ...this.config.headers,
22
+ ...options.headers || {}
23
+ };
24
+ if (this.config.apiKey) {
25
+ headers["Authorization"] = `Bearer ${this.config.apiKey}`;
26
+ }
27
+ const controller = new AbortController();
28
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
29
+ try {
30
+ if (this.config.debug) {
31
+ console.log(`[GeolocationSDK] ${options.method || "GET"} ${url}`, {
32
+ headers,
33
+ body: options.body
34
+ });
35
+ }
36
+ const response = await fetch(url, {
37
+ ...options,
38
+ headers,
39
+ signal: controller.signal
40
+ });
41
+ clearTimeout(timeoutId);
42
+ const data = await response.json();
43
+ if (!response.ok) {
44
+ throw new Error(data.error || data.message || `HTTP ${response.status}`);
45
+ }
46
+ if (this.config.debug) {
47
+ console.log(`[GeolocationSDK] Response:`, data);
48
+ }
49
+ return data;
50
+ } catch (error) {
51
+ clearTimeout(timeoutId);
52
+ if (error instanceof Error) {
53
+ if (error.name === "AbortError") {
54
+ throw new Error(`Request timeout after ${this.config.timeout}ms`);
55
+ }
56
+ throw error;
57
+ }
58
+ throw new Error("Unknown error occurred");
59
+ }
60
+ }
61
+ buildQueryString(params) {
62
+ const query = new URLSearchParams();
63
+ Object.entries(params).forEach(([key, value]) => {
64
+ if (value !== void 0 && value !== null) {
65
+ query.append(key, String(value));
66
+ }
67
+ });
68
+ const queryString = query.toString();
69
+ return queryString ? `?${queryString}` : "";
70
+ }
71
+ // ============================================================================
72
+ // IP Verification & Compliance
73
+ // ============================================================================
74
+ /**
75
+ * Verify an IP address and check compliance
76
+ *
77
+ * @param request - Verification request with IP, user ID, event type, and optional device fingerprint
78
+ * @returns Location verification result with risk assessment
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * const result = await client.verifyIP({
83
+ * ip_address: "8.8.8.8",
84
+ * user_id: "user_123",
85
+ * event_type: "login",
86
+ * device_fingerprint: {
87
+ * device_id: "device_abc",
88
+ * user_agent: navigator.userAgent,
89
+ * platform: "web"
90
+ * }
91
+ * });
92
+ *
93
+ * if (result.is_blocked) {
94
+ * console.log("Access blocked:", result.risk_reasons);
95
+ * }
96
+ * ```
97
+ */
98
+ async verifyIP(request) {
99
+ return this.request("/api/v1/geo/verify", {
100
+ method: "POST",
101
+ body: JSON.stringify(request)
102
+ });
103
+ }
104
+ /**
105
+ * Check compliance for a specific country
106
+ *
107
+ * @param countryISO - ISO 3166-1 alpha-2 country code (e.g., "US", "GB")
108
+ * @returns Jurisdiction configuration and compliance status
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * const compliance = await client.checkCompliance("KP"); // North Korea
113
+ * if (!compliance.is_compliant) {
114
+ * console.log("Country is not allowed:", compliance.jurisdiction?.status);
115
+ * }
116
+ * ```
117
+ */
118
+ async checkCompliance(countryISO) {
119
+ return this.request(
120
+ `/api/v1/geo/compliance?country_iso=${countryISO}`
121
+ );
122
+ }
123
+ /**
124
+ * Get location history for a user
125
+ *
126
+ * @param userId - User ID to retrieve history for
127
+ * @param limit - Maximum number of records to return (default: 100)
128
+ * @returns Array of geolocation records
129
+ */
130
+ async getUserLocationHistory(userId, limit = 100) {
131
+ return this.request(
132
+ `/api/v1/geo/history?user_id=${userId}&limit=${limit}`
133
+ );
134
+ }
135
+ // ============================================================================
136
+ // Alert Management
137
+ // ============================================================================
138
+ /**
139
+ * Get a specific alert by ID
140
+ *
141
+ * @param alertId - Alert ID
142
+ * @returns Alert details
143
+ */
144
+ async getAlert(alertId) {
145
+ return this.request(`/api/v1/alerts/${alertId}`);
146
+ }
147
+ /**
148
+ * List alerts with filters and pagination
149
+ *
150
+ * @param filters - Optional filters (status, severity, type, user, dates)
151
+ * @param pagination - Optional pagination (page, page_size)
152
+ * @returns Paginated list of alerts
153
+ *
154
+ * @example
155
+ * ```typescript
156
+ * const alerts = await client.listAlerts(
157
+ * { status: "active", severity: "critical" },
158
+ * { page: 1, page_size: 20 }
159
+ * );
160
+ * console.log(`Found ${alerts.total} critical alerts`);
161
+ * ```
162
+ */
163
+ async listAlerts(filters, pagination) {
164
+ const params = {
165
+ ...filters,
166
+ ...pagination
167
+ };
168
+ return this.request(`/api/v1/alerts${this.buildQueryString(params)}`);
169
+ }
170
+ /**
171
+ * Update alert status
172
+ *
173
+ * @param alertId - Alert ID
174
+ * @param status - New status
175
+ */
176
+ async updateAlertStatus(alertId, status) {
177
+ await this.request(`/api/v1/alerts/${alertId}/status`, {
178
+ method: "PUT",
179
+ body: JSON.stringify({ status })
180
+ });
181
+ }
182
+ /**
183
+ * Assign an alert to an analyst
184
+ *
185
+ * @param alertId - Alert ID
186
+ * @param assignedTo - User ID to assign to
187
+ */
188
+ async assignAlert(alertId, assignedTo) {
189
+ await this.request(`/api/v1/alerts/${alertId}/assign`, {
190
+ method: "POST",
191
+ body: JSON.stringify({ assigned_to: assignedTo })
192
+ });
193
+ }
194
+ /**
195
+ * Resolve an alert
196
+ *
197
+ * @param alertId - Alert ID
198
+ * @param resolution - Resolution type
199
+ * @param notes - Optional notes
200
+ */
201
+ async resolveAlert(alertId, resolution, notes) {
202
+ await this.request(`/api/v1/alerts/${alertId}/resolve`, {
203
+ method: "POST",
204
+ body: JSON.stringify({ resolution, notes })
205
+ });
206
+ }
207
+ /**
208
+ * Dismiss an alert as false positive
209
+ *
210
+ * @param alertId - Alert ID
211
+ * @param notes - Optional notes explaining why it's a false positive
212
+ */
213
+ async dismissAlert(alertId, notes) {
214
+ await this.request(`/api/v1/alerts/${alertId}/dismiss`, {
215
+ method: "POST",
216
+ body: JSON.stringify({ notes })
217
+ });
218
+ }
219
+ /**
220
+ * Escalate an alert to higher severity or different assignee
221
+ *
222
+ * @param alertId - Alert ID
223
+ * @param assignedTo - New assignee user ID
224
+ * @param severity - New severity level
225
+ * @param notes - Escalation notes
226
+ */
227
+ async escalateAlert(alertId, assignedTo, severity, notes) {
228
+ await this.request(`/api/v1/alerts/${alertId}/escalate`, {
229
+ method: "POST",
230
+ body: JSON.stringify({ assigned_to: assignedTo, severity, notes })
231
+ });
232
+ }
233
+ /**
234
+ * Block an alert (mark as blocked)
235
+ *
236
+ * @param alertId - Alert ID
237
+ * @param notes - Optional notes
238
+ */
239
+ async blockAlert(alertId, notes) {
240
+ await this.request(`/api/v1/alerts/${alertId}/block`, {
241
+ method: "POST",
242
+ body: JSON.stringify({ notes })
243
+ });
244
+ }
245
+ /**
246
+ * Get dashboard metrics
247
+ *
248
+ * @param timeRangeHours - Time range in hours (default: 24)
249
+ * @returns Dashboard metrics and statistics
250
+ *
251
+ * @example
252
+ * ```typescript
253
+ * const metrics = await client.getDashboardMetrics(168); // Last 7 days
254
+ * console.log(`${metrics.critical_alerts} critical alerts in last week`);
255
+ * ```
256
+ */
257
+ async getDashboardMetrics(timeRangeHours = 24) {
258
+ return this.request(
259
+ `/api/v1/alerts/metrics?time_range_hours=${timeRangeHours}`
260
+ );
261
+ }
262
+ // ============================================================================
263
+ // Jurisdiction Configuration
264
+ // ============================================================================
265
+ /**
266
+ * List all jurisdiction configurations
267
+ *
268
+ * @returns Array of jurisdiction configurations
269
+ */
270
+ async listJurisdictions() {
271
+ return this.request("/api/v1/jurisdictions");
272
+ }
273
+ /**
274
+ * Get a jurisdiction configuration by ID
275
+ *
276
+ * @param jurisdictionId - Jurisdiction ID
277
+ * @returns Jurisdiction configuration
278
+ */
279
+ async getJurisdiction(jurisdictionId) {
280
+ return this.request(`/api/v1/jurisdictions/${jurisdictionId}`);
281
+ }
282
+ /**
283
+ * Create a new jurisdiction configuration
284
+ *
285
+ * @param request - Jurisdiction configuration data
286
+ * @returns Created jurisdiction
287
+ *
288
+ * @example
289
+ * ```typescript
290
+ * const jurisdiction = await client.createJurisdiction({
291
+ * country_iso: "US",
292
+ * country_name: "United States",
293
+ * status: "allowed",
294
+ * risk_level: "low",
295
+ * allow_login: true,
296
+ * allow_registration: true,
297
+ * allow_transactions: true,
298
+ * require_kyc: false,
299
+ * require_enhanced_verification: false
300
+ * });
301
+ * ```
302
+ */
303
+ async createJurisdiction(request) {
304
+ return this.request("/api/v1/jurisdictions", {
305
+ method: "POST",
306
+ body: JSON.stringify(request)
307
+ });
308
+ }
309
+ /**
310
+ * Update a jurisdiction configuration
311
+ *
312
+ * @param jurisdictionId - Jurisdiction ID
313
+ * @param request - Updated fields
314
+ * @returns Updated jurisdiction
315
+ */
316
+ async updateJurisdiction(jurisdictionId, request) {
317
+ return this.request(`/api/v1/jurisdictions/${jurisdictionId}`, {
318
+ method: "PUT",
319
+ body: JSON.stringify(request)
320
+ });
321
+ }
322
+ /**
323
+ * Delete a jurisdiction configuration
324
+ *
325
+ * @param jurisdictionId - Jurisdiction ID
326
+ */
327
+ async deleteJurisdiction(jurisdictionId) {
328
+ await this.request(`/api/v1/jurisdictions/${jurisdictionId}`, {
329
+ method: "DELETE"
330
+ });
331
+ }
332
+ // ============================================================================
333
+ // Geofence Rules
334
+ // ============================================================================
335
+ /**
336
+ * List all geofence rules
337
+ *
338
+ * @returns Array of geofence rules
339
+ */
340
+ async listGeofenceRules() {
341
+ return this.request("/api/v1/geofence-rules");
342
+ }
343
+ /**
344
+ * Get a geofence rule by ID
345
+ *
346
+ * @param ruleId - Geofence rule ID
347
+ * @returns Geofence rule
348
+ */
349
+ async getGeofenceRule(ruleId) {
350
+ return this.request(`/api/v1/geofence-rules/${ruleId}`);
351
+ }
352
+ /**
353
+ * Create a new geofence rule
354
+ *
355
+ * @param request - Geofence rule data
356
+ * @returns Created geofence rule
357
+ *
358
+ * @example
359
+ * ```typescript
360
+ * const rule = await client.createGeofenceRule({
361
+ * name: "Block High Risk Countries",
362
+ * rule_type: "block_list",
363
+ * action: "block",
364
+ * countries: ["KP", "IR", "SY"],
365
+ * event_types: ["login", "transaction"],
366
+ * priority: 100
367
+ * });
368
+ * ```
369
+ */
370
+ async createGeofenceRule(request) {
371
+ return this.request("/api/v1/geofence-rules", {
372
+ method: "POST",
373
+ body: JSON.stringify(request)
374
+ });
375
+ }
376
+ /**
377
+ * Update a geofence rule
378
+ *
379
+ * @param ruleId - Geofence rule ID
380
+ * @param request - Updated fields
381
+ * @returns Updated geofence rule
382
+ */
383
+ async updateGeofenceRule(ruleId, request) {
384
+ return this.request(`/api/v1/geofence-rules/${ruleId}`, {
385
+ method: "PUT",
386
+ body: JSON.stringify(request)
387
+ });
388
+ }
389
+ /**
390
+ * Delete a geofence rule
391
+ *
392
+ * @param ruleId - Geofence rule ID
393
+ */
394
+ async deleteGeofenceRule(ruleId) {
395
+ await this.request(`/api/v1/geofence-rules/${ruleId}`, {
396
+ method: "DELETE"
397
+ });
398
+ }
399
+ // ============================================================================
400
+ // Device Fingerprinting
401
+ // ============================================================================
402
+ /**
403
+ * Get all devices for a user
404
+ *
405
+ * @param userId - User ID
406
+ * @returns Array of device fingerprints
407
+ */
408
+ async getUserDevices(userId) {
409
+ return this.request(`/api/v1/devices/user/?user_id=${userId}`);
410
+ }
411
+ /**
412
+ * Get a specific device by device ID
413
+ *
414
+ * @param deviceId - Device ID
415
+ * @returns Device fingerprint
416
+ */
417
+ async getDevice(deviceId) {
418
+ return this.request(`/api/v1/devices/?device_id=${deviceId}`);
419
+ }
420
+ /**
421
+ * Update device trust status
422
+ *
423
+ * @param deviceId - Device ID
424
+ * @param action - "trust" or "untrust"
425
+ *
426
+ * @example
427
+ * ```typescript
428
+ * // Mark a device as trusted
429
+ * await client.updateDeviceTrust("device_abc", "trust");
430
+ *
431
+ * // Mark a device as untrusted
432
+ * await client.updateDeviceTrust("device_xyz", "untrust");
433
+ * ```
434
+ */
435
+ async updateDeviceTrust(deviceId, action) {
436
+ await this.request(`/api/v1/devices/?device_id=${deviceId}&action=${action}`, {
437
+ method: "POST"
438
+ });
439
+ }
440
+ // ============================================================================
441
+ // Utility Methods
442
+ // ============================================================================
443
+ /**
444
+ * Check service health
445
+ *
446
+ * @returns Health status object
447
+ */
448
+ async healthCheck() {
449
+ return this.request("/api/v1/health");
450
+ }
451
+ /**
452
+ * Update client configuration
453
+ *
454
+ * @param config - Partial configuration to update
455
+ */
456
+ updateConfig(config) {
457
+ this.config = {
458
+ ...this.config,
459
+ ...config,
460
+ headers: {
461
+ ...this.config.headers,
462
+ ...config.headers || {}
463
+ }
464
+ };
465
+ }
466
+ /**
467
+ * Get current configuration (readonly)
468
+ */
469
+ getConfig() {
470
+ return { ...this.config };
471
+ }
472
+ };
473
+
474
+ // src/core/errors.ts
475
+ var CGSError = class _CGSError extends Error {
476
+ constructor(message, code, statusCode, details) {
477
+ super(message);
478
+ this.code = code;
479
+ this.statusCode = statusCode;
480
+ this.details = details;
481
+ this.name = "CGSError";
482
+ Object.setPrototypeOf(this, _CGSError.prototype);
483
+ }
484
+ };
485
+ var NetworkError = class _NetworkError extends CGSError {
486
+ constructor(message, originalError) {
487
+ super(message, "NETWORK_ERROR", void 0, { originalError });
488
+ this.originalError = originalError;
489
+ this.name = "NetworkError";
490
+ Object.setPrototypeOf(this, _NetworkError.prototype);
491
+ }
492
+ };
493
+ var ServiceUnavailableError = class _ServiceUnavailableError extends CGSError {
494
+ constructor(service) {
495
+ super(`${service} is unavailable`, "SERVICE_UNAVAILABLE", 503, { service });
496
+ this.name = "ServiceUnavailableError";
497
+ Object.setPrototypeOf(this, _ServiceUnavailableError.prototype);
498
+ }
499
+ };
500
+ var AuthenticationError = class _AuthenticationError extends CGSError {
501
+ constructor(message = "Authentication failed") {
502
+ super(message, "AUTHENTICATION_ERROR", 401);
503
+ this.name = "AuthenticationError";
504
+ Object.setPrototypeOf(this, _AuthenticationError.prototype);
505
+ }
506
+ };
507
+ var RateLimitError = class _RateLimitError extends CGSError {
508
+ constructor(retryAfter) {
509
+ super("Rate limit exceeded", "RATE_LIMIT_EXCEEDED", 429, { retryAfter });
510
+ this.retryAfter = retryAfter;
511
+ this.name = "RateLimitError";
512
+ Object.setPrototypeOf(this, _RateLimitError.prototype);
513
+ }
514
+ };
515
+ var TimeoutError = class _TimeoutError extends CGSError {
516
+ constructor(timeout) {
517
+ super(`Request timeout after ${timeout}ms`, "TIMEOUT", 408, { timeout });
518
+ this.timeout = timeout;
519
+ this.name = "TimeoutError";
520
+ Object.setPrototypeOf(this, _TimeoutError.prototype);
521
+ }
522
+ };
523
+ var ComplianceError = class _ComplianceError extends CGSError {
524
+ constructor(message, originalError, code = "COMPLIANCE_ERROR") {
525
+ super(message, code, void 0, { originalError });
526
+ this.originalError = originalError;
527
+ this.name = "ComplianceError";
528
+ Object.setPrototypeOf(this, _ComplianceError.prototype);
529
+ }
530
+ };
531
+
532
+ // src/core/client.ts
533
+ var BaseClient = class {
534
+ constructor(config) {
535
+ this.config = {
536
+ baseURL: config.baseURL,
537
+ tenantId: config.tenantId,
538
+ apiKey: config.apiKey || "",
539
+ headers: config.headers || {},
540
+ timeout: config.timeout || 1e4,
541
+ retries: config.retries || 3,
542
+ debug: config.debug || false
543
+ };
544
+ }
545
+ /**
546
+ * Make an HTTP request with timeout and error handling
547
+ */
548
+ async request(endpoint, options = {}, serviceURL) {
549
+ const url = `${serviceURL || this.config.baseURL}${endpoint}`;
550
+ const headers = {
551
+ "Content-Type": "application/json",
552
+ "X-Tenant-ID": this.config.tenantId,
553
+ ...this.config.headers,
554
+ ...options.headers || {}
555
+ };
556
+ if (this.config.apiKey) {
557
+ headers["Authorization"] = `Bearer ${this.config.apiKey}`;
558
+ }
559
+ const controller = new AbortController();
560
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
561
+ try {
562
+ if (this.config.debug) {
563
+ console.log(`[CGS SDK] ${options.method || "GET"} ${url}`, {
564
+ headers,
565
+ body: options.body
566
+ });
567
+ }
568
+ const response = await fetch(url, {
569
+ ...options,
570
+ headers,
571
+ signal: controller.signal
572
+ });
573
+ clearTimeout(timeoutId);
574
+ const data = await response.json();
575
+ if (!response.ok) {
576
+ this.handleErrorResponse(response.status, data);
577
+ }
578
+ if (this.config.debug) {
579
+ console.log(`[CGS SDK] Response:`, data);
580
+ }
581
+ return data;
582
+ } catch (error) {
583
+ clearTimeout(timeoutId);
584
+ if (error instanceof Error) {
585
+ if (error.name === "AbortError") {
586
+ throw new TimeoutError(this.config.timeout);
587
+ }
588
+ if (error instanceof CGSError) {
589
+ throw error;
590
+ }
591
+ }
592
+ throw new NetworkError("Network request failed", error);
593
+ }
594
+ }
595
+ /**
596
+ * Make an HTTP request with retry logic
597
+ */
598
+ async requestWithRetry(endpoint, options = {}, serviceURL, retries = this.config.retries) {
599
+ let lastError;
600
+ for (let attempt = 0; attempt <= retries; attempt++) {
601
+ try {
602
+ return await this.request(endpoint, options, serviceURL);
603
+ } catch (error) {
604
+ lastError = error instanceof Error ? error : new Error("Unknown error");
605
+ if (lastError instanceof CGSError && lastError.statusCode && lastError.statusCode >= 400 && lastError.statusCode < 500) {
606
+ throw lastError;
607
+ }
608
+ if (attempt === retries) {
609
+ break;
610
+ }
611
+ const delay = Math.min(1e3 * Math.pow(2, attempt) + Math.random() * 1e3, 1e4);
612
+ await new Promise((resolve) => setTimeout(resolve, delay));
613
+ if (this.config.debug) {
614
+ console.log(`[CGS SDK] Retry attempt ${attempt + 1}/${retries} after ${delay.toFixed(0)}ms`);
615
+ }
616
+ }
617
+ }
618
+ throw new NetworkError(`Request failed after ${retries} retries`, lastError);
619
+ }
620
+ /**
621
+ * Handle error responses from API
622
+ */
623
+ handleErrorResponse(status, data) {
624
+ const message = data.error || data.message || `HTTP ${status}`;
625
+ switch (status) {
626
+ case 400:
627
+ throw new CGSError(message, "BAD_REQUEST", 400, data);
628
+ case 401:
629
+ throw new AuthenticationError(message);
630
+ case 403:
631
+ throw new CGSError(message, "FORBIDDEN", 403, data);
632
+ case 404:
633
+ throw new CGSError(message, "NOT_FOUND", 404, data);
634
+ case 429:
635
+ const retryAfter = data.retry_after || data.retryAfter;
636
+ throw new RateLimitError(retryAfter);
637
+ case 500:
638
+ case 502:
639
+ case 503:
640
+ case 504:
641
+ throw new ServiceUnavailableError(message);
642
+ default:
643
+ throw new CGSError(message, "UNKNOWN_ERROR", status, data);
644
+ }
645
+ }
646
+ /**
647
+ * Build query string from parameters
648
+ */
649
+ buildQueryString(params) {
650
+ const query = new URLSearchParams();
651
+ Object.entries(params).forEach(([key, value]) => {
652
+ if (value !== void 0 && value !== null) {
653
+ if (Array.isArray(value)) {
654
+ value.forEach((item) => query.append(key, String(item)));
655
+ } else {
656
+ query.append(key, String(value));
657
+ }
658
+ }
659
+ });
660
+ const queryString = query.toString();
661
+ return queryString ? `?${queryString}` : "";
662
+ }
663
+ /**
664
+ * Update client configuration
665
+ */
666
+ updateConfig(config) {
667
+ this.config = {
668
+ ...this.config,
669
+ ...config,
670
+ headers: {
671
+ ...this.config.headers,
672
+ ...config.headers || {}
673
+ }
674
+ };
675
+ }
676
+ /**
677
+ * Get current configuration (readonly)
678
+ */
679
+ getConfig() {
680
+ return { ...this.config };
681
+ }
682
+ /**
683
+ * Health check endpoint
684
+ */
685
+ async healthCheck() {
686
+ return this.request("/api/v1/health");
687
+ }
688
+ };
689
+
690
+ // src/risk-profile/client.ts
691
+ var RiskProfileClient = class extends BaseClient {
692
+ constructor(config) {
693
+ super(config);
694
+ }
695
+ // ============================================================================
696
+ // Profile Management
697
+ // ============================================================================
698
+ /**
699
+ * Create a new customer risk profile
700
+ *
701
+ * @param request - Profile creation data
702
+ * @returns Created customer profile
703
+ *
704
+ * @example
705
+ * ```typescript
706
+ * const profile = await client.createProfile({
707
+ * customer_id: 'CUST-12345',
708
+ * entity_type: 'individual',
709
+ * customer_status: 'active',
710
+ * full_name: 'John Doe',
711
+ * email_address: 'john@example.com',
712
+ * date_of_birth: '1990-01-15',
713
+ * country_of_residence: 'US'
714
+ * });
715
+ * ```
716
+ */
717
+ async createProfile(request) {
718
+ return this.request("/api/v1/profiles", {
719
+ method: "POST",
720
+ body: JSON.stringify(request)
721
+ });
722
+ }
723
+ /**
724
+ * Get customer profile by customer ID
725
+ *
726
+ * Note: This searches for the profile using the customer_id field.
727
+ * Returns the first matching profile for the tenant.
728
+ *
729
+ * @param customerId - Customer ID to search for
730
+ * @returns Customer profile
731
+ *
732
+ * @example
733
+ * ```typescript
734
+ * const profile = await client.getProfile('CUST-12345');
735
+ * console.log('Risk score:', profile.risk_score);
736
+ * ```
737
+ */
738
+ async getProfile(customerId) {
739
+ const response = await this.queryProfiles({
740
+ search: customerId,
741
+ page: 1,
742
+ page_size: 1
743
+ });
744
+ if (response.data.length === 0) {
745
+ throw new Error(`Profile not found for customer ID: ${customerId}`);
746
+ }
747
+ return response.data[0];
748
+ }
749
+ /**
750
+ * Get profile by UUID
751
+ *
752
+ * @param profileId - Profile UUID
753
+ * @returns Customer profile
754
+ */
755
+ async getProfileById(profileId) {
756
+ const details = await this.getProfileDetails(profileId);
757
+ return details.profile;
758
+ }
759
+ /**
760
+ * Get detailed profile information including risk factors and history
761
+ *
762
+ * @param profileId - Profile UUID
763
+ * @returns Detailed profile response with risk factors and history
764
+ *
765
+ * @example
766
+ * ```typescript
767
+ * const details = await client.getProfileDetails(profileId);
768
+ * console.log('Risk factors:', details.risk_factors);
769
+ * console.log('Risk history:', details.risk_history);
770
+ * console.log('Alert counts:', {
771
+ * watchlist: details.watchlist_alert_count,
772
+ * fraud: details.fraud_alert_count,
773
+ * geo: details.geolocation_alert_count
774
+ * });
775
+ * ```
776
+ */
777
+ async getProfileDetails(profileId) {
778
+ return this.request(
779
+ `/api/v1/risk-dashboard/profiles/${profileId}`
780
+ );
781
+ }
782
+ /**
783
+ * Update customer profile
784
+ *
785
+ * @param profileId - Profile UUID
786
+ * @param updates - Fields to update
787
+ * @returns Updated customer profile
788
+ *
789
+ * @example
790
+ * ```typescript
791
+ * const updated = await client.updateProfile(profileId, {
792
+ * location: 'New York, USA',
793
+ * location_compliance: 'compliant',
794
+ * last_recorded_activity: new Date().toISOString()
795
+ * });
796
+ * ```
797
+ */
798
+ async updateProfile(profileId, updates) {
799
+ return this.request(`/api/v1/profiles/${profileId}`, {
800
+ method: "PUT",
801
+ body: JSON.stringify(updates)
802
+ });
803
+ }
804
+ /**
805
+ * Manually recalculate risk score for a profile
806
+ *
807
+ * Triggers immediate risk score recalculation based on current risk factors.
808
+ *
809
+ * @param profileId - Profile UUID
810
+ * @param reason - Optional reason for recalculation
811
+ *
812
+ * @example
813
+ * ```typescript
814
+ * await client.recalculateRiskScore(profileId, 'Manual review completed');
815
+ * ```
816
+ */
817
+ async recalculateRiskScore(profileId, reason) {
818
+ const body = reason ? JSON.stringify({ reason }) : void 0;
819
+ await this.request(`/api/v1/profiles/recalculate/${profileId}`, {
820
+ method: "POST",
821
+ body
822
+ });
823
+ }
824
+ // ============================================================================
825
+ // Query & Search
826
+ // ============================================================================
827
+ /**
828
+ * Query profiles with advanced filters
829
+ *
830
+ * @param filters - Filter criteria and pagination
831
+ * @returns Paginated list of profiles
832
+ *
833
+ * @example
834
+ * ```typescript
835
+ * const results = await client.queryProfiles({
836
+ * risk_category: ['high', 'critical'],
837
+ * kyc_status: ['pending'],
838
+ * is_pep: true,
839
+ * page: 1,
840
+ * page_size: 20,
841
+ * sort_by: 'risk_score',
842
+ * sort_order: 'desc'
843
+ * });
844
+ *
845
+ * console.log(`Found ${results.total} high-risk profiles`);
846
+ * results.data.forEach(profile => {
847
+ * console.log(`${profile.full_name}: ${profile.risk_score}`);
848
+ * });
849
+ * ```
850
+ */
851
+ async queryProfiles(filters = {}) {
852
+ const queryString = this.buildQueryString(filters);
853
+ return this.request(
854
+ `/api/v1/risk-dashboard/profiles${queryString}`
855
+ );
856
+ }
857
+ /**
858
+ * Search profiles by text (searches name, email, customer_id, account_number)
859
+ *
860
+ * @param searchText - Text to search for
861
+ * @param limit - Maximum results to return (default: 10)
862
+ * @returns Array of matching profiles
863
+ */
864
+ async searchProfiles(searchText, limit = 10) {
865
+ const response = await this.queryProfiles({
866
+ search: searchText,
867
+ page: 1,
868
+ page_size: limit
869
+ });
870
+ return response.data;
871
+ }
872
+ /**
873
+ * Get all high-risk profiles (high + critical)
874
+ *
875
+ * @param limit - Maximum results to return (default: 50)
876
+ * @returns Array of high-risk profiles
877
+ */
878
+ async getHighRiskProfiles(limit = 50) {
879
+ const response = await this.queryProfiles({
880
+ risk_category: ["high", "critical"],
881
+ page: 1,
882
+ page_size: limit,
883
+ sort_by: "risk_score",
884
+ sort_order: "desc"
885
+ });
886
+ return response.data;
887
+ }
888
+ /**
889
+ * Get profiles requiring PEP review
890
+ *
891
+ * @param limit - Maximum results to return (default: 50)
892
+ * @returns Array of PEP profiles
893
+ */
894
+ async getPEPProfiles(limit = 50) {
895
+ const response = await this.queryProfiles({
896
+ is_pep: true,
897
+ page: 1,
898
+ page_size: limit
899
+ });
900
+ return response.data;
901
+ }
902
+ /**
903
+ * Get profiles with sanctions matches
904
+ *
905
+ * @param limit - Maximum results to return (default: 50)
906
+ * @returns Array of sanctioned profiles
907
+ */
908
+ async getSanctionedProfiles(limit = 50) {
909
+ const response = await this.queryProfiles({
910
+ has_sanctions: true,
911
+ page: 1,
912
+ page_size: limit
913
+ });
914
+ return response.data;
915
+ }
916
+ // ============================================================================
917
+ // Dashboard & Metrics
918
+ // ============================================================================
919
+ /**
920
+ * Get risk dashboard metrics and statistics
921
+ *
922
+ * @param startDate - Optional start date for metrics (ISO format)
923
+ * @param endDate - Optional end date for metrics (ISO format)
924
+ * @returns Dashboard metrics
925
+ *
926
+ * @example
927
+ * ```typescript
928
+ * const metrics = await client.getDashboardMetrics();
929
+ * console.log('Total risky profiles:', metrics.total_risky_profiles);
930
+ * console.log('Critical profiles:', metrics.total_critical_profiles);
931
+ * console.log('Average risk score:', metrics.average_risk_score);
932
+ *
933
+ * metrics.risk_distribution.forEach(item => {
934
+ * console.log(`${item.category}: ${item.count} (${item.percentage}%)`);
935
+ * });
936
+ * ```
937
+ */
938
+ async getDashboardMetrics(startDate, endDate) {
939
+ const params = {};
940
+ if (startDate) params.start_date = startDate;
941
+ if (endDate) params.end_date = endDate;
942
+ const queryString = this.buildQueryString(params);
943
+ return this.request(
944
+ `/api/v1/risk-dashboard/metrics${queryString}`
945
+ );
946
+ }
947
+ // ============================================================================
948
+ // Bulk Operations
949
+ // ============================================================================
950
+ /**
951
+ * Get or create profile (idempotent operation)
952
+ *
953
+ * Attempts to get existing profile by customer_id, creates if not found.
954
+ *
955
+ * @param customerId - Customer ID
956
+ * @param createRequest - Profile data to use if creating new profile
957
+ * @returns Existing or newly created profile
958
+ *
959
+ * @example
960
+ * ```typescript
961
+ * const profile = await client.getOrCreateProfile('CUST-123', {
962
+ * customer_id: 'CUST-123',
963
+ * entity_type: 'individual',
964
+ * full_name: 'John Doe',
965
+ * email_address: 'john@example.com'
966
+ * });
967
+ * ```
968
+ */
969
+ async getOrCreateProfile(customerId, createRequest) {
970
+ try {
971
+ return await this.getProfile(customerId);
972
+ } catch (error) {
973
+ return await this.createProfile(createRequest);
974
+ }
975
+ }
976
+ /**
977
+ * Batch get profiles by customer IDs
978
+ *
979
+ * @param customerIds - Array of customer IDs
980
+ * @returns Array of profiles (may be less than input if some not found)
981
+ */
982
+ async batchGetProfiles(customerIds) {
983
+ const profiles = [];
984
+ for (const customerId of customerIds) {
985
+ try {
986
+ const profile = await this.getProfile(customerId);
987
+ profiles.push(profile);
988
+ } catch (error) {
989
+ if (this.config.debug) {
990
+ console.warn(`[RiskProfileClient] Profile not found for: ${customerId}`);
991
+ }
992
+ }
993
+ }
994
+ return profiles;
995
+ }
996
+ // ============================================================================
997
+ // Configuration
998
+ // ============================================================================
999
+ /**
1000
+ * Get risk configuration for tenant
1001
+ *
1002
+ * Returns the risk scoring weights and thresholds configured for the tenant.
1003
+ *
1004
+ * @returns Risk configuration
1005
+ */
1006
+ async getRiskConfiguration() {
1007
+ return this.request("/api/v1/risk-config");
1008
+ }
1009
+ /**
1010
+ * Update risk configuration for tenant
1011
+ *
1012
+ * Updates risk scoring weights and/or thresholds.
1013
+ *
1014
+ * @param config - Configuration updates
1015
+ * @returns Updated risk configuration
1016
+ */
1017
+ async updateRiskConfiguration(config) {
1018
+ return this.request("/api/v1/risk-config", {
1019
+ method: "PUT",
1020
+ body: JSON.stringify(config)
1021
+ });
1022
+ }
1023
+ };
1024
+
1025
+ // src/compliance/client.ts
1026
+ var ComplianceClient = class {
1027
+ constructor(config) {
1028
+ this.config = {
1029
+ apiGatewayURL: config.apiGatewayURL,
1030
+ tenantId: config.tenantId,
1031
+ apiKey: config.apiKey || "",
1032
+ headers: config.headers || {},
1033
+ timeout: config.timeout || 1e4,
1034
+ retries: config.retries || 3,
1035
+ debug: config.debug || false,
1036
+ autoCreateProfiles: config.autoCreateProfiles !== false,
1037
+ // default true
1038
+ syncMode: config.syncMode || "sync"
1039
+ };
1040
+ this.geoClient = new GeolocationClient({
1041
+ baseURL: this.config.apiGatewayURL,
1042
+ tenantId: this.config.tenantId,
1043
+ apiKey: this.config.apiKey,
1044
+ headers: this.config.headers,
1045
+ timeout: this.config.timeout,
1046
+ retries: this.config.retries,
1047
+ debug: this.config.debug
1048
+ });
1049
+ this.riskClient = new RiskProfileClient({
1050
+ baseURL: this.config.apiGatewayURL,
1051
+ tenantId: this.config.tenantId,
1052
+ apiKey: this.config.apiKey,
1053
+ headers: this.config.headers,
1054
+ timeout: this.config.timeout,
1055
+ retries: this.config.retries,
1056
+ debug: this.config.debug
1057
+ });
1058
+ this.currencyRates = DEFAULT_CURRENCY_RATES;
1059
+ }
1060
+ // ============================================================================
1061
+ // Main Verification Methods
1062
+ // ============================================================================
1063
+ /**
1064
+ * Verify customer registration with automatic profile creation
1065
+ *
1066
+ * This is the primary integration point for new customer sign-ups.
1067
+ * Combines geolocation verification with customer risk profile creation.
1068
+ *
1069
+ * @param request - Registration verification request
1070
+ * @returns Verification response with profile and compliance status
1071
+ *
1072
+ * @example
1073
+ * ```typescript
1074
+ * const result = await sdk.verifyAtRegistration({
1075
+ * customerId: 'CUST-12345',
1076
+ * fullName: 'John Doe',
1077
+ * emailAddress: 'john@example.com',
1078
+ * ipAddress: req.ip,
1079
+ * deviceFingerprint: getDeviceFingerprint()
1080
+ * });
1081
+ *
1082
+ * if (result.allowed) {
1083
+ * // Create account
1084
+ * console.log('Profile created:', result.profile);
1085
+ * if (result.requiresKYC) {
1086
+ * // Redirect to KYC flow
1087
+ * }
1088
+ * } else {
1089
+ * // Block registration
1090
+ * console.log('Blocked:', result.blockReasons);
1091
+ * }
1092
+ * ```
1093
+ */
1094
+ async verifyAtRegistration(request) {
1095
+ const startTime = Date.now();
1096
+ try {
1097
+ if (this.config.debug) {
1098
+ console.log("[ComplianceSDK] Starting registration verification for:", request.customerId);
1099
+ }
1100
+ const geoVerification = await this.geoClient.verifyIP({
1101
+ ip_address: request.ipAddress,
1102
+ user_id: request.customerId,
1103
+ event_type: "registration",
1104
+ device_fingerprint: request.deviceFingerprint
1105
+ });
1106
+ const profile = await this.riskClient.createProfile({
1107
+ customer_id: request.customerId,
1108
+ entity_type: request.entityType || "individual",
1109
+ customer_status: "active",
1110
+ full_name: request.fullName,
1111
+ email_address: request.emailAddress,
1112
+ primary_phone_number: request.phoneNumber,
1113
+ date_of_birth: request.dateOfBirth,
1114
+ residential_address: request.address,
1115
+ country_of_residence: geoVerification.location.country_iso,
1116
+ // Geolocation data
1117
+ location: `${geoVerification.location.city}, ${geoVerification.location.country}`,
1118
+ location_compliance: geoVerification.is_compliant ? "compliant" : "non-compliant",
1119
+ // Initial KYC status
1120
+ kyc_status: "pending"
1121
+ });
1122
+ const isAllowed = geoVerification.is_compliant && !geoVerification.is_blocked;
1123
+ const requiresKYC = geoVerification.jurisdiction?.require_kyc || false;
1124
+ const requiresEDD = geoVerification.jurisdiction?.require_enhanced_verification || false;
1125
+ if (this.config.debug) {
1126
+ console.log("[ComplianceSDK] Registration verification complete:", {
1127
+ allowed: isAllowed,
1128
+ riskScore: geoVerification.risk_score,
1129
+ profileId: profile.id
1130
+ });
1131
+ }
1132
+ return {
1133
+ allowed: isAllowed,
1134
+ geolocation: geoVerification,
1135
+ profile,
1136
+ requiresKYC,
1137
+ requiresEDD,
1138
+ blockReasons: !isAllowed ? geoVerification.risk_reasons : [],
1139
+ processingTime: Date.now() - startTime
1140
+ };
1141
+ } catch (error) {
1142
+ if (this.config.debug) {
1143
+ console.error("[ComplianceSDK] Registration verification failed:", error);
1144
+ }
1145
+ throw new ComplianceError("Registration verification failed", error);
1146
+ }
1147
+ }
1148
+ /**
1149
+ * Verify customer login with profile activity update
1150
+ *
1151
+ * Verifies geolocation and updates customer profile with latest activity.
1152
+ *
1153
+ * @param request - Login verification request
1154
+ * @returns Verification response with compliance status
1155
+ *
1156
+ * @example
1157
+ * ```typescript
1158
+ * const result = await sdk.verifyAtLogin({
1159
+ * customerId: 'CUST-12345',
1160
+ * ipAddress: req.ip,
1161
+ * deviceFingerprint: getDeviceFingerprint()
1162
+ * });
1163
+ *
1164
+ * if (result.allowed) {
1165
+ * // Allow login
1166
+ * if (result.requiresStepUp) {
1167
+ * // Trigger MFA or additional verification
1168
+ * }
1169
+ * } else {
1170
+ * // Block login
1171
+ * console.log('Blocked:', result.blockReasons);
1172
+ * }
1173
+ * ```
1174
+ */
1175
+ async verifyAtLogin(request) {
1176
+ const startTime = Date.now();
1177
+ try {
1178
+ if (this.config.debug) {
1179
+ console.log("[ComplianceSDK] Starting login verification for:", request.customerId);
1180
+ }
1181
+ const geoVerification = await this.geoClient.verifyIP({
1182
+ ip_address: request.ipAddress,
1183
+ user_id: request.customerId,
1184
+ event_type: "login",
1185
+ device_fingerprint: request.deviceFingerprint
1186
+ });
1187
+ let profile;
1188
+ try {
1189
+ profile = await this.riskClient.getProfile(request.customerId);
1190
+ if (this.shouldUpdateProfile(profile, geoVerification.location.city)) {
1191
+ await this.riskClient.updateProfile(profile.id, {
1192
+ last_recorded_activity: (/* @__PURE__ */ new Date()).toISOString(),
1193
+ location: `${geoVerification.location.city}, ${geoVerification.location.country}`,
1194
+ location_compliance: geoVerification.is_compliant ? "compliant" : "non-compliant"
1195
+ });
1196
+ profile = await this.riskClient.getProfile(request.customerId);
1197
+ }
1198
+ } catch (error) {
1199
+ if (this.config.autoCreateProfiles && this.config.debug) {
1200
+ console.warn("[ComplianceSDK] Profile not found for login, creating...");
1201
+ }
1202
+ profile = await this.createProfileFromGeo(request.customerId, geoVerification);
1203
+ }
1204
+ const isAllowed = geoVerification.is_compliant && !geoVerification.is_blocked && profile.customer_status !== "suspended";
1205
+ const requiresStepUp = geoVerification.risk_level === "high" || geoVerification.risk_level === "critical";
1206
+ return {
1207
+ allowed: isAllowed,
1208
+ geolocation: geoVerification,
1209
+ profile,
1210
+ requiresStepUp,
1211
+ blockReasons: this.getBlockReasons(geoVerification, profile),
1212
+ processingTime: Date.now() - startTime
1213
+ };
1214
+ } catch (error) {
1215
+ throw new ComplianceError("Login verification failed", error);
1216
+ }
1217
+ }
1218
+ /**
1219
+ * Verify transaction with amount-based risk assessment
1220
+ *
1221
+ * Combines geolocation verification with transaction amount analysis
1222
+ * and customer risk profile for comprehensive transaction screening.
1223
+ *
1224
+ * @param request - Transaction verification request
1225
+ * @returns Verification response with transaction risk assessment
1226
+ *
1227
+ * @example
1228
+ * ```typescript
1229
+ * const result = await sdk.verifyAtTransaction({
1230
+ * customerId: 'CUST-12345',
1231
+ * ipAddress: req.ip,
1232
+ * amount: 5000,
1233
+ * currency: 'USD',
1234
+ * transactionType: 'withdrawal',
1235
+ * deviceFingerprint: getDeviceFingerprint()
1236
+ * });
1237
+ *
1238
+ * if (result.allowed) {
1239
+ * // Process transaction
1240
+ * } else if (result.requiresApproval) {
1241
+ * // Queue for manual review
1242
+ * } else {
1243
+ * // Block transaction
1244
+ * console.log('Blocked:', result.blockReasons);
1245
+ * }
1246
+ * ```
1247
+ */
1248
+ async verifyAtTransaction(request) {
1249
+ const startTime = Date.now();
1250
+ try {
1251
+ if (this.config.debug) {
1252
+ console.log("[ComplianceSDK] Starting transaction verification:", {
1253
+ customerId: request.customerId,
1254
+ amount: request.amount,
1255
+ currency: request.currency
1256
+ });
1257
+ }
1258
+ const geoVerification = await this.geoClient.verifyIP({
1259
+ ip_address: request.ipAddress,
1260
+ user_id: request.customerId,
1261
+ event_type: "transaction",
1262
+ device_fingerprint: request.deviceFingerprint
1263
+ });
1264
+ const profile = await this.riskClient.getProfile(request.customerId);
1265
+ const transactionRisk = this.calculateTransactionRisk(
1266
+ request.amount,
1267
+ request.currency,
1268
+ geoVerification,
1269
+ profile
1270
+ );
1271
+ const jurisdictionAllowed = this.checkJurisdictionLimits(
1272
+ request.amount,
1273
+ request.currency,
1274
+ geoVerification.jurisdiction
1275
+ );
1276
+ const isAllowed = geoVerification.is_compliant && !geoVerification.is_blocked && jurisdictionAllowed && transactionRisk.allowed;
1277
+ return {
1278
+ allowed: isAllowed,
1279
+ geolocation: geoVerification,
1280
+ profile,
1281
+ transactionRisk,
1282
+ requiresApproval: transactionRisk.requiresManualReview,
1283
+ blockReasons: this.getTransactionBlockReasons(
1284
+ geoVerification,
1285
+ transactionRisk,
1286
+ jurisdictionAllowed
1287
+ ),
1288
+ processingTime: Date.now() - startTime
1289
+ };
1290
+ } catch (error) {
1291
+ throw new ComplianceError("Transaction verification failed", error);
1292
+ }
1293
+ }
1294
+ /**
1295
+ * Generic event verification (for other touchpoints)
1296
+ *
1297
+ * @param request - Event verification request
1298
+ * @returns Verification response
1299
+ */
1300
+ async verifyEvent(request) {
1301
+ const startTime = Date.now();
1302
+ const geoVerification = await this.geoClient.verifyIP({
1303
+ ip_address: request.ipAddress,
1304
+ user_id: request.customerId,
1305
+ event_type: request.eventType,
1306
+ device_fingerprint: request.deviceFingerprint
1307
+ });
1308
+ if (this.config.autoCreateProfiles) {
1309
+ try {
1310
+ const profile = await this.riskClient.getProfile(request.customerId);
1311
+ await this.riskClient.updateProfile(profile.id, {
1312
+ last_recorded_activity: (/* @__PURE__ */ new Date()).toISOString()
1313
+ });
1314
+ } catch (error) {
1315
+ if (this.config.debug) {
1316
+ console.warn("[ComplianceSDK] Profile not found for event");
1317
+ }
1318
+ }
1319
+ }
1320
+ return {
1321
+ allowed: geoVerification.is_compliant && !geoVerification.is_blocked,
1322
+ geolocation: geoVerification,
1323
+ blockReasons: geoVerification.risk_reasons,
1324
+ processingTime: Date.now() - startTime
1325
+ };
1326
+ }
1327
+ // ============================================================================
1328
+ // Helper Methods
1329
+ // ============================================================================
1330
+ shouldUpdateProfile(profile, newCity) {
1331
+ return !profile.location || !profile.location.includes(newCity);
1332
+ }
1333
+ async createProfileFromGeo(customerId, geoVerification) {
1334
+ return this.riskClient.createProfile({
1335
+ customer_id: customerId,
1336
+ entity_type: "individual",
1337
+ customer_status: "active",
1338
+ email_address: `${customerId}@placeholder.local`,
1339
+ // Temporary email
1340
+ location: `${geoVerification.location.city}, ${geoVerification.location.country}`,
1341
+ location_compliance: geoVerification.is_compliant ? "compliant" : "non-compliant",
1342
+ country_of_residence: geoVerification.location.country_iso,
1343
+ kyc_status: "pending"
1344
+ });
1345
+ }
1346
+ calculateTransactionRisk(amount, currency, geoVerification, profile) {
1347
+ let riskScore = 0;
1348
+ const factors = [];
1349
+ const normalizedAmount = this.normalizeToUSD(amount, currency);
1350
+ if (normalizedAmount > 1e4) {
1351
+ riskScore += 30;
1352
+ factors.push("high_transaction_amount");
1353
+ } else if (normalizedAmount > 5e3) {
1354
+ riskScore += 15;
1355
+ factors.push("elevated_transaction_amount");
1356
+ }
1357
+ riskScore += geoVerification.risk_score * 0.4;
1358
+ if (geoVerification.risk_level === "high" || geoVerification.risk_level === "critical") {
1359
+ factors.push("high_risk_location");
1360
+ }
1361
+ riskScore += profile.risk_score * 0.3;
1362
+ if (profile.risk_category === "high" || profile.risk_category === "critical") {
1363
+ factors.push("high_risk_customer");
1364
+ }
1365
+ if (geoVerification.location.is_vpn || geoVerification.location.is_proxy) {
1366
+ riskScore += 20;
1367
+ factors.push("anonymization_detected");
1368
+ }
1369
+ if (profile.customer_status === "suspended") {
1370
+ riskScore += 50;
1371
+ factors.push("account_suspended");
1372
+ }
1373
+ return {
1374
+ score: Math.min(riskScore, 100),
1375
+ level: this.getRiskLevel(riskScore),
1376
+ factors,
1377
+ allowed: riskScore < 70,
1378
+ requiresManualReview: riskScore >= 60 && riskScore < 70
1379
+ };
1380
+ }
1381
+ checkJurisdictionLimits(amount, currency, jurisdiction) {
1382
+ if (!jurisdiction || !jurisdiction.max_transaction_amount) {
1383
+ return true;
1384
+ }
1385
+ const normalizedAmount = this.normalizeToUSD(amount, currency);
1386
+ return normalizedAmount <= jurisdiction.max_transaction_amount;
1387
+ }
1388
+ normalizeToUSD(amount, currency) {
1389
+ const rate = this.currencyRates[currency.toUpperCase()] || 1;
1390
+ return amount * rate;
1391
+ }
1392
+ getRiskLevel(score) {
1393
+ if (score >= 80) return "critical";
1394
+ if (score >= 60) return "high";
1395
+ if (score >= 40) return "medium";
1396
+ return "low";
1397
+ }
1398
+ getBlockReasons(geoVerification, profile) {
1399
+ const reasons = [];
1400
+ if (geoVerification.is_blocked) {
1401
+ reasons.push(...geoVerification.risk_reasons);
1402
+ }
1403
+ if (profile.customer_status === "suspended") {
1404
+ reasons.push("account_suspended");
1405
+ }
1406
+ if (profile.has_sanctions) {
1407
+ reasons.push("sanctions_match");
1408
+ }
1409
+ return reasons;
1410
+ }
1411
+ getTransactionBlockReasons(geoVerification, transactionRisk, jurisdictionAllowed) {
1412
+ const reasons = [];
1413
+ if (!geoVerification.is_compliant) {
1414
+ reasons.push("non_compliant_jurisdiction");
1415
+ }
1416
+ if (!jurisdictionAllowed) {
1417
+ reasons.push("exceeds_jurisdiction_limit");
1418
+ }
1419
+ if (!transactionRisk.allowed) {
1420
+ reasons.push(...transactionRisk.factors);
1421
+ }
1422
+ return reasons;
1423
+ }
1424
+ // ============================================================================
1425
+ // Configuration
1426
+ // ============================================================================
1427
+ /**
1428
+ * Update currency exchange rates
1429
+ *
1430
+ * @param rates - Currency to USD exchange rates
1431
+ */
1432
+ updateCurrencyRates(rates) {
1433
+ this.currencyRates = { ...this.currencyRates, ...rates };
1434
+ }
1435
+ /**
1436
+ * Get underlying geolocation client
1437
+ */
1438
+ getGeolocationClient() {
1439
+ return this.geoClient;
1440
+ }
1441
+ /**
1442
+ * Get underlying risk profile client
1443
+ */
1444
+ getRiskProfileClient() {
1445
+ return this.riskClient;
1446
+ }
1447
+ /**
1448
+ * Update configuration
1449
+ */
1450
+ updateConfig(config) {
1451
+ this.config = { ...this.config, ...config };
1452
+ this.geoClient.updateConfig(config);
1453
+ this.riskClient.updateConfig(config);
1454
+ }
1455
+ };
1456
+
1457
+ // src/compliance/types.ts
1458
+ var DEFAULT_CURRENCY_RATES2 = {
1459
+ USD: 1,
1460
+ EUR: 1.1,
1461
+ GBP: 1.27,
1462
+ CAD: 0.74,
1463
+ AUD: 0.66,
1464
+ JPY: 67e-4,
1465
+ CHF: 1.13,
1466
+ CNY: 0.14,
1467
+ INR: 0.012,
1468
+ BRL: 0.2,
1469
+ MXN: 0.058,
1470
+ ZAR: 0.055
1471
+ };
1472
+
1473
+ export { ComplianceClient, DEFAULT_CURRENCY_RATES2 as DEFAULT_CURRENCY_RATES };
1474
+ //# sourceMappingURL=index.mjs.map
1475
+ //# sourceMappingURL=index.mjs.map