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,784 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ // src/geolocation/client.ts
6
+ var GeolocationClient = class {
7
+ constructor(config) {
8
+ this.config = {
9
+ baseURL: config.baseURL,
10
+ tenantId: config.tenantId,
11
+ apiKey: config.apiKey || "",
12
+ headers: config.headers || {},
13
+ timeout: config.timeout || 1e4,
14
+ debug: config.debug || false
15
+ };
16
+ }
17
+ // ============================================================================
18
+ // Private Helper Methods
19
+ // ============================================================================
20
+ async request(endpoint, options = {}) {
21
+ const url = `${this.config.baseURL}${endpoint}`;
22
+ const headers = {
23
+ "Content-Type": "application/json",
24
+ "X-Tenant-ID": this.config.tenantId,
25
+ ...this.config.headers,
26
+ ...options.headers || {}
27
+ };
28
+ if (this.config.apiKey) {
29
+ headers["Authorization"] = `Bearer ${this.config.apiKey}`;
30
+ }
31
+ const controller = new AbortController();
32
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
33
+ try {
34
+ if (this.config.debug) {
35
+ console.log(`[GeolocationSDK] ${options.method || "GET"} ${url}`, {
36
+ headers,
37
+ body: options.body
38
+ });
39
+ }
40
+ const response = await fetch(url, {
41
+ ...options,
42
+ headers,
43
+ signal: controller.signal
44
+ });
45
+ clearTimeout(timeoutId);
46
+ const data = await response.json();
47
+ if (!response.ok) {
48
+ throw new Error(data.error || data.message || `HTTP ${response.status}`);
49
+ }
50
+ if (this.config.debug) {
51
+ console.log(`[GeolocationSDK] Response:`, data);
52
+ }
53
+ return data;
54
+ } catch (error) {
55
+ clearTimeout(timeoutId);
56
+ if (error instanceof Error) {
57
+ if (error.name === "AbortError") {
58
+ throw new Error(`Request timeout after ${this.config.timeout}ms`);
59
+ }
60
+ throw error;
61
+ }
62
+ throw new Error("Unknown error occurred");
63
+ }
64
+ }
65
+ buildQueryString(params) {
66
+ const query = new URLSearchParams();
67
+ Object.entries(params).forEach(([key, value]) => {
68
+ if (value !== void 0 && value !== null) {
69
+ query.append(key, String(value));
70
+ }
71
+ });
72
+ const queryString = query.toString();
73
+ return queryString ? `?${queryString}` : "";
74
+ }
75
+ // ============================================================================
76
+ // IP Verification & Compliance
77
+ // ============================================================================
78
+ /**
79
+ * Verify an IP address and check compliance
80
+ *
81
+ * @param request - Verification request with IP, user ID, event type, and optional device fingerprint
82
+ * @returns Location verification result with risk assessment
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * const result = await client.verifyIP({
87
+ * ip_address: "8.8.8.8",
88
+ * user_id: "user_123",
89
+ * event_type: "login",
90
+ * device_fingerprint: {
91
+ * device_id: "device_abc",
92
+ * user_agent: navigator.userAgent,
93
+ * platform: "web"
94
+ * }
95
+ * });
96
+ *
97
+ * if (result.is_blocked) {
98
+ * console.log("Access blocked:", result.risk_reasons);
99
+ * }
100
+ * ```
101
+ */
102
+ async verifyIP(request) {
103
+ return this.request("/api/v1/geo/verify", {
104
+ method: "POST",
105
+ body: JSON.stringify(request)
106
+ });
107
+ }
108
+ /**
109
+ * Check compliance for a specific country
110
+ *
111
+ * @param countryISO - ISO 3166-1 alpha-2 country code (e.g., "US", "GB")
112
+ * @returns Jurisdiction configuration and compliance status
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * const compliance = await client.checkCompliance("KP"); // North Korea
117
+ * if (!compliance.is_compliant) {
118
+ * console.log("Country is not allowed:", compliance.jurisdiction?.status);
119
+ * }
120
+ * ```
121
+ */
122
+ async checkCompliance(countryISO) {
123
+ return this.request(
124
+ `/api/v1/geo/compliance?country_iso=${countryISO}`
125
+ );
126
+ }
127
+ /**
128
+ * Get location history for a user
129
+ *
130
+ * @param userId - User ID to retrieve history for
131
+ * @param limit - Maximum number of records to return (default: 100)
132
+ * @returns Array of geolocation records
133
+ */
134
+ async getUserLocationHistory(userId, limit = 100) {
135
+ return this.request(
136
+ `/api/v1/geo/history?user_id=${userId}&limit=${limit}`
137
+ );
138
+ }
139
+ // ============================================================================
140
+ // Alert Management
141
+ // ============================================================================
142
+ /**
143
+ * Get a specific alert by ID
144
+ *
145
+ * @param alertId - Alert ID
146
+ * @returns Alert details
147
+ */
148
+ async getAlert(alertId) {
149
+ return this.request(`/api/v1/alerts/${alertId}`);
150
+ }
151
+ /**
152
+ * List alerts with filters and pagination
153
+ *
154
+ * @param filters - Optional filters (status, severity, type, user, dates)
155
+ * @param pagination - Optional pagination (page, page_size)
156
+ * @returns Paginated list of alerts
157
+ *
158
+ * @example
159
+ * ```typescript
160
+ * const alerts = await client.listAlerts(
161
+ * { status: "active", severity: "critical" },
162
+ * { page: 1, page_size: 20 }
163
+ * );
164
+ * console.log(`Found ${alerts.total} critical alerts`);
165
+ * ```
166
+ */
167
+ async listAlerts(filters, pagination) {
168
+ const params = {
169
+ ...filters,
170
+ ...pagination
171
+ };
172
+ return this.request(`/api/v1/alerts${this.buildQueryString(params)}`);
173
+ }
174
+ /**
175
+ * Update alert status
176
+ *
177
+ * @param alertId - Alert ID
178
+ * @param status - New status
179
+ */
180
+ async updateAlertStatus(alertId, status) {
181
+ await this.request(`/api/v1/alerts/${alertId}/status`, {
182
+ method: "PUT",
183
+ body: JSON.stringify({ status })
184
+ });
185
+ }
186
+ /**
187
+ * Assign an alert to an analyst
188
+ *
189
+ * @param alertId - Alert ID
190
+ * @param assignedTo - User ID to assign to
191
+ */
192
+ async assignAlert(alertId, assignedTo) {
193
+ await this.request(`/api/v1/alerts/${alertId}/assign`, {
194
+ method: "POST",
195
+ body: JSON.stringify({ assigned_to: assignedTo })
196
+ });
197
+ }
198
+ /**
199
+ * Resolve an alert
200
+ *
201
+ * @param alertId - Alert ID
202
+ * @param resolution - Resolution type
203
+ * @param notes - Optional notes
204
+ */
205
+ async resolveAlert(alertId, resolution, notes) {
206
+ await this.request(`/api/v1/alerts/${alertId}/resolve`, {
207
+ method: "POST",
208
+ body: JSON.stringify({ resolution, notes })
209
+ });
210
+ }
211
+ /**
212
+ * Dismiss an alert as false positive
213
+ *
214
+ * @param alertId - Alert ID
215
+ * @param notes - Optional notes explaining why it's a false positive
216
+ */
217
+ async dismissAlert(alertId, notes) {
218
+ await this.request(`/api/v1/alerts/${alertId}/dismiss`, {
219
+ method: "POST",
220
+ body: JSON.stringify({ notes })
221
+ });
222
+ }
223
+ /**
224
+ * Escalate an alert to higher severity or different assignee
225
+ *
226
+ * @param alertId - Alert ID
227
+ * @param assignedTo - New assignee user ID
228
+ * @param severity - New severity level
229
+ * @param notes - Escalation notes
230
+ */
231
+ async escalateAlert(alertId, assignedTo, severity, notes) {
232
+ await this.request(`/api/v1/alerts/${alertId}/escalate`, {
233
+ method: "POST",
234
+ body: JSON.stringify({ assigned_to: assignedTo, severity, notes })
235
+ });
236
+ }
237
+ /**
238
+ * Block an alert (mark as blocked)
239
+ *
240
+ * @param alertId - Alert ID
241
+ * @param notes - Optional notes
242
+ */
243
+ async blockAlert(alertId, notes) {
244
+ await this.request(`/api/v1/alerts/${alertId}/block`, {
245
+ method: "POST",
246
+ body: JSON.stringify({ notes })
247
+ });
248
+ }
249
+ /**
250
+ * Get dashboard metrics
251
+ *
252
+ * @param timeRangeHours - Time range in hours (default: 24)
253
+ * @returns Dashboard metrics and statistics
254
+ *
255
+ * @example
256
+ * ```typescript
257
+ * const metrics = await client.getDashboardMetrics(168); // Last 7 days
258
+ * console.log(`${metrics.critical_alerts} critical alerts in last week`);
259
+ * ```
260
+ */
261
+ async getDashboardMetrics(timeRangeHours = 24) {
262
+ return this.request(
263
+ `/api/v1/alerts/metrics?time_range_hours=${timeRangeHours}`
264
+ );
265
+ }
266
+ // ============================================================================
267
+ // Jurisdiction Configuration
268
+ // ============================================================================
269
+ /**
270
+ * List all jurisdiction configurations
271
+ *
272
+ * @returns Array of jurisdiction configurations
273
+ */
274
+ async listJurisdictions() {
275
+ return this.request("/api/v1/jurisdictions");
276
+ }
277
+ /**
278
+ * Get a jurisdiction configuration by ID
279
+ *
280
+ * @param jurisdictionId - Jurisdiction ID
281
+ * @returns Jurisdiction configuration
282
+ */
283
+ async getJurisdiction(jurisdictionId) {
284
+ return this.request(`/api/v1/jurisdictions/${jurisdictionId}`);
285
+ }
286
+ /**
287
+ * Create a new jurisdiction configuration
288
+ *
289
+ * @param request - Jurisdiction configuration data
290
+ * @returns Created jurisdiction
291
+ *
292
+ * @example
293
+ * ```typescript
294
+ * const jurisdiction = await client.createJurisdiction({
295
+ * country_iso: "US",
296
+ * country_name: "United States",
297
+ * status: "allowed",
298
+ * risk_level: "low",
299
+ * allow_login: true,
300
+ * allow_registration: true,
301
+ * allow_transactions: true,
302
+ * require_kyc: false,
303
+ * require_enhanced_verification: false
304
+ * });
305
+ * ```
306
+ */
307
+ async createJurisdiction(request) {
308
+ return this.request("/api/v1/jurisdictions", {
309
+ method: "POST",
310
+ body: JSON.stringify(request)
311
+ });
312
+ }
313
+ /**
314
+ * Update a jurisdiction configuration
315
+ *
316
+ * @param jurisdictionId - Jurisdiction ID
317
+ * @param request - Updated fields
318
+ * @returns Updated jurisdiction
319
+ */
320
+ async updateJurisdiction(jurisdictionId, request) {
321
+ return this.request(`/api/v1/jurisdictions/${jurisdictionId}`, {
322
+ method: "PUT",
323
+ body: JSON.stringify(request)
324
+ });
325
+ }
326
+ /**
327
+ * Delete a jurisdiction configuration
328
+ *
329
+ * @param jurisdictionId - Jurisdiction ID
330
+ */
331
+ async deleteJurisdiction(jurisdictionId) {
332
+ await this.request(`/api/v1/jurisdictions/${jurisdictionId}`, {
333
+ method: "DELETE"
334
+ });
335
+ }
336
+ // ============================================================================
337
+ // Geofence Rules
338
+ // ============================================================================
339
+ /**
340
+ * List all geofence rules
341
+ *
342
+ * @returns Array of geofence rules
343
+ */
344
+ async listGeofenceRules() {
345
+ return this.request("/api/v1/geofence-rules");
346
+ }
347
+ /**
348
+ * Get a geofence rule by ID
349
+ *
350
+ * @param ruleId - Geofence rule ID
351
+ * @returns Geofence rule
352
+ */
353
+ async getGeofenceRule(ruleId) {
354
+ return this.request(`/api/v1/geofence-rules/${ruleId}`);
355
+ }
356
+ /**
357
+ * Create a new geofence rule
358
+ *
359
+ * @param request - Geofence rule data
360
+ * @returns Created geofence rule
361
+ *
362
+ * @example
363
+ * ```typescript
364
+ * const rule = await client.createGeofenceRule({
365
+ * name: "Block High Risk Countries",
366
+ * rule_type: "block_list",
367
+ * action: "block",
368
+ * countries: ["KP", "IR", "SY"],
369
+ * event_types: ["login", "transaction"],
370
+ * priority: 100
371
+ * });
372
+ * ```
373
+ */
374
+ async createGeofenceRule(request) {
375
+ return this.request("/api/v1/geofence-rules", {
376
+ method: "POST",
377
+ body: JSON.stringify(request)
378
+ });
379
+ }
380
+ /**
381
+ * Update a geofence rule
382
+ *
383
+ * @param ruleId - Geofence rule ID
384
+ * @param request - Updated fields
385
+ * @returns Updated geofence rule
386
+ */
387
+ async updateGeofenceRule(ruleId, request) {
388
+ return this.request(`/api/v1/geofence-rules/${ruleId}`, {
389
+ method: "PUT",
390
+ body: JSON.stringify(request)
391
+ });
392
+ }
393
+ /**
394
+ * Delete a geofence rule
395
+ *
396
+ * @param ruleId - Geofence rule ID
397
+ */
398
+ async deleteGeofenceRule(ruleId) {
399
+ await this.request(`/api/v1/geofence-rules/${ruleId}`, {
400
+ method: "DELETE"
401
+ });
402
+ }
403
+ // ============================================================================
404
+ // Device Fingerprinting
405
+ // ============================================================================
406
+ /**
407
+ * Get all devices for a user
408
+ *
409
+ * @param userId - User ID
410
+ * @returns Array of device fingerprints
411
+ */
412
+ async getUserDevices(userId) {
413
+ return this.request(`/api/v1/devices/user/?user_id=${userId}`);
414
+ }
415
+ /**
416
+ * Get a specific device by device ID
417
+ *
418
+ * @param deviceId - Device ID
419
+ * @returns Device fingerprint
420
+ */
421
+ async getDevice(deviceId) {
422
+ return this.request(`/api/v1/devices/?device_id=${deviceId}`);
423
+ }
424
+ /**
425
+ * Update device trust status
426
+ *
427
+ * @param deviceId - Device ID
428
+ * @param action - "trust" or "untrust"
429
+ *
430
+ * @example
431
+ * ```typescript
432
+ * // Mark a device as trusted
433
+ * await client.updateDeviceTrust("device_abc", "trust");
434
+ *
435
+ * // Mark a device as untrusted
436
+ * await client.updateDeviceTrust("device_xyz", "untrust");
437
+ * ```
438
+ */
439
+ async updateDeviceTrust(deviceId, action) {
440
+ await this.request(`/api/v1/devices/?device_id=${deviceId}&action=${action}`, {
441
+ method: "POST"
442
+ });
443
+ }
444
+ // ============================================================================
445
+ // Utility Methods
446
+ // ============================================================================
447
+ /**
448
+ * Check service health
449
+ *
450
+ * @returns Health status object
451
+ */
452
+ async healthCheck() {
453
+ return this.request("/api/v1/health");
454
+ }
455
+ /**
456
+ * Update client configuration
457
+ *
458
+ * @param config - Partial configuration to update
459
+ */
460
+ updateConfig(config) {
461
+ this.config = {
462
+ ...this.config,
463
+ ...config,
464
+ headers: {
465
+ ...this.config.headers,
466
+ ...config.headers || {}
467
+ }
468
+ };
469
+ }
470
+ /**
471
+ * Get current configuration (readonly)
472
+ */
473
+ getConfig() {
474
+ return { ...this.config };
475
+ }
476
+ };
477
+ function useGeolocation(client, options = {}) {
478
+ const [verification, setVerification] = react.useState(null);
479
+ const [loading, setLoading] = react.useState(false);
480
+ const [error, setError] = react.useState(null);
481
+ const verifyIP = react.useCallback(
482
+ async (request) => {
483
+ setLoading(true);
484
+ setError(null);
485
+ try {
486
+ const result = await client.verifyIP(request);
487
+ setVerification(result);
488
+ return result;
489
+ } catch (err) {
490
+ const error2 = err instanceof Error ? err : new Error("Verification failed");
491
+ setError(error2);
492
+ throw error2;
493
+ } finally {
494
+ setLoading(false);
495
+ }
496
+ },
497
+ [client]
498
+ );
499
+ const checkCompliance = react.useCallback(
500
+ async (countryISO) => {
501
+ setLoading(true);
502
+ setError(null);
503
+ try {
504
+ const result = await client.checkCompliance(countryISO);
505
+ return result;
506
+ } catch (err) {
507
+ const error2 = err instanceof Error ? err : new Error("Compliance check failed");
508
+ setError(error2);
509
+ throw error2;
510
+ } finally {
511
+ setLoading(false);
512
+ }
513
+ },
514
+ [client]
515
+ );
516
+ const refresh = react.useCallback(async () => {
517
+ if (verification) {
518
+ await verifyIP({
519
+ ip_address: verification.ip_address,
520
+ user_id: "",
521
+ // Will need to be provided
522
+ event_type: options.eventType || "api_access"
523
+ });
524
+ }
525
+ }, [verification, verifyIP, options.eventType]);
526
+ react.useEffect(() => {
527
+ if (options.autoVerify) {
528
+ const detectAndVerify = async () => {
529
+ try {
530
+ const ipResponse = await fetch("https://api.ipify.org?format=json");
531
+ const { ip } = await ipResponse.json();
532
+ let deviceFingerprint;
533
+ if (options.includeDeviceFingerprint && typeof window !== "undefined") {
534
+ deviceFingerprint = {
535
+ device_id: localStorage.getItem("device_id") || generateDeviceId(),
536
+ user_agent: navigator.userAgent,
537
+ platform: navigator.platform,
538
+ language: navigator.language,
539
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
540
+ screen_resolution: `${window.screen.width}x${window.screen.height}`
541
+ };
542
+ if (!localStorage.getItem("device_id")) {
543
+ localStorage.setItem("device_id", deviceFingerprint.device_id);
544
+ }
545
+ }
546
+ await verifyIP({
547
+ ip_address: ip,
548
+ user_id: "",
549
+ // Should be provided by auth context
550
+ event_type: options.eventType || "page_view",
551
+ device_fingerprint: deviceFingerprint
552
+ });
553
+ } catch (err) {
554
+ console.error("Auto-verification failed:", err);
555
+ }
556
+ };
557
+ detectAndVerify();
558
+ }
559
+ }, [options.autoVerify, options.includeDeviceFingerprint, options.eventType, verifyIP]);
560
+ return {
561
+ verification,
562
+ loading,
563
+ error,
564
+ verifyIP,
565
+ checkCompliance,
566
+ refresh
567
+ };
568
+ }
569
+ function useAlerts(client, options = {}) {
570
+ const [alerts, setAlerts] = react.useState([]);
571
+ const [total, setTotal] = react.useState(0);
572
+ const [loading, setLoading] = react.useState(false);
573
+ const [error, setError] = react.useState(null);
574
+ const pollIntervalRef = react.useRef();
575
+ const fetchAlerts = react.useCallback(
576
+ async (filters, pagination) => {
577
+ setLoading(true);
578
+ setError(null);
579
+ try {
580
+ const result = await client.listAlerts(
581
+ filters || options.filters,
582
+ pagination || options.pagination
583
+ );
584
+ setAlerts(result.alerts);
585
+ setTotal(result.total);
586
+ } catch (err) {
587
+ const error2 = err instanceof Error ? err : new Error("Failed to fetch alerts");
588
+ setError(error2);
589
+ throw error2;
590
+ } finally {
591
+ setLoading(false);
592
+ }
593
+ },
594
+ [client, options.filters, options.pagination]
595
+ );
596
+ const updateStatus = react.useCallback(
597
+ async (alertId, status) => {
598
+ try {
599
+ await client.updateAlertStatus(alertId, status);
600
+ setAlerts(
601
+ (prev) => prev.map(
602
+ (alert) => alert.id === alertId ? { ...alert, status } : alert
603
+ )
604
+ );
605
+ } catch (err) {
606
+ const error2 = err instanceof Error ? err : new Error("Failed to update status");
607
+ setError(error2);
608
+ throw error2;
609
+ }
610
+ },
611
+ [client]
612
+ );
613
+ const assignAlert = react.useCallback(
614
+ async (alertId, assignedTo) => {
615
+ try {
616
+ await client.assignAlert(alertId, assignedTo);
617
+ setAlerts(
618
+ (prev) => prev.map(
619
+ (alert) => alert.id === alertId ? { ...alert, assigned_to: assignedTo, status: "under_review" } : alert
620
+ )
621
+ );
622
+ } catch (err) {
623
+ const error2 = err instanceof Error ? err : new Error("Failed to assign alert");
624
+ setError(error2);
625
+ throw error2;
626
+ }
627
+ },
628
+ [client]
629
+ );
630
+ const resolveAlert = react.useCallback(
631
+ async (alertId, resolution, notes) => {
632
+ try {
633
+ await client.resolveAlert(alertId, resolution, notes);
634
+ setAlerts(
635
+ (prev) => prev.map(
636
+ (alert) => alert.id === alertId ? { ...alert, status: "resolved", resolution, notes } : alert
637
+ )
638
+ );
639
+ } catch (err) {
640
+ const error2 = err instanceof Error ? err : new Error("Failed to resolve alert");
641
+ setError(error2);
642
+ throw error2;
643
+ }
644
+ },
645
+ [client]
646
+ );
647
+ const dismissAlert = react.useCallback(
648
+ async (alertId, notes) => {
649
+ try {
650
+ await client.dismissAlert(alertId, notes);
651
+ setAlerts(
652
+ (prev) => prev.map(
653
+ (alert) => alert.id === alertId ? { ...alert, status: "false_positive", resolution: "false_positive", notes } : alert
654
+ )
655
+ );
656
+ } catch (err) {
657
+ const error2 = err instanceof Error ? err : new Error("Failed to dismiss alert");
658
+ setError(error2);
659
+ throw error2;
660
+ }
661
+ },
662
+ [client]
663
+ );
664
+ const refresh = react.useCallback(async () => {
665
+ await fetchAlerts();
666
+ }, [fetchAlerts]);
667
+ react.useEffect(() => {
668
+ if (options.autoFetch) {
669
+ fetchAlerts();
670
+ }
671
+ }, [options.autoFetch, fetchAlerts]);
672
+ react.useEffect(() => {
673
+ if (options.pollInterval && options.pollInterval > 0) {
674
+ pollIntervalRef.current = setInterval(() => {
675
+ fetchAlerts();
676
+ }, options.pollInterval);
677
+ return () => {
678
+ if (pollIntervalRef.current) {
679
+ clearInterval(pollIntervalRef.current);
680
+ }
681
+ };
682
+ }
683
+ }, [options.pollInterval, fetchAlerts]);
684
+ return {
685
+ alerts,
686
+ total,
687
+ loading,
688
+ error,
689
+ fetchAlerts,
690
+ updateStatus,
691
+ assignAlert,
692
+ resolveAlert,
693
+ dismissAlert,
694
+ refresh
695
+ };
696
+ }
697
+ function useDashboardMetrics(client, timeRangeHours = 24, autoFetch = true) {
698
+ const [metrics, setMetrics] = react.useState(null);
699
+ const [loading, setLoading] = react.useState(false);
700
+ const [error, setError] = react.useState(null);
701
+ const fetchMetrics = react.useCallback(async () => {
702
+ setLoading(true);
703
+ setError(null);
704
+ try {
705
+ const result = await client.getDashboardMetrics(timeRangeHours);
706
+ setMetrics(result);
707
+ } catch (err) {
708
+ const error2 = err instanceof Error ? err : new Error("Failed to fetch metrics");
709
+ setError(error2);
710
+ throw error2;
711
+ } finally {
712
+ setLoading(false);
713
+ }
714
+ }, [client, timeRangeHours]);
715
+ react.useEffect(() => {
716
+ if (autoFetch) {
717
+ fetchMetrics();
718
+ }
719
+ }, [autoFetch, fetchMetrics]);
720
+ return {
721
+ metrics,
722
+ loading,
723
+ error,
724
+ refresh: fetchMetrics
725
+ };
726
+ }
727
+ function generateDeviceId() {
728
+ return `device_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
729
+ }
730
+ function getBrowserInfo() {
731
+ if (typeof window === "undefined") return {};
732
+ const userAgent = navigator.userAgent;
733
+ let browser;
734
+ let browserVersion;
735
+ let os;
736
+ if (userAgent.indexOf("Firefox") > -1) {
737
+ browser = "Firefox";
738
+ browserVersion = userAgent.match(/Firefox\/([0-9.]+)/)?.[1];
739
+ } else if (userAgent.indexOf("Chrome") > -1) {
740
+ browser = "Chrome";
741
+ browserVersion = userAgent.match(/Chrome\/([0-9.]+)/)?.[1];
742
+ } else if (userAgent.indexOf("Safari") > -1) {
743
+ browser = "Safari";
744
+ browserVersion = userAgent.match(/Version\/([0-9.]+)/)?.[1];
745
+ } else if (userAgent.indexOf("Edge") > -1) {
746
+ browser = "Edge";
747
+ browserVersion = userAgent.match(/Edge\/([0-9.]+)/)?.[1];
748
+ }
749
+ if (userAgent.indexOf("Win") > -1) os = "Windows";
750
+ else if (userAgent.indexOf("Mac") > -1) os = "macOS";
751
+ else if (userAgent.indexOf("Linux") > -1) os = "Linux";
752
+ else if (userAgent.indexOf("Android") > -1) os = "Android";
753
+ else if (userAgent.indexOf("iOS") > -1) os = "iOS";
754
+ return {
755
+ browser,
756
+ browser_version: browserVersion,
757
+ os
758
+ };
759
+ }
760
+ function createDeviceFingerprint() {
761
+ const browserInfo = getBrowserInfo();
762
+ const deviceId = localStorage.getItem("device_id") || generateDeviceId();
763
+ if (!localStorage.getItem("device_id")) {
764
+ localStorage.setItem("device_id", deviceId);
765
+ }
766
+ return {
767
+ device_id: deviceId,
768
+ user_agent: navigator.userAgent,
769
+ platform: navigator.platform,
770
+ language: navigator.language,
771
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
772
+ screen_resolution: `${window.screen.width}x${window.screen.height}`,
773
+ ...browserInfo
774
+ };
775
+ }
776
+
777
+ exports.GeolocationClient = GeolocationClient;
778
+ exports.createDeviceFingerprint = createDeviceFingerprint;
779
+ exports.getBrowserInfo = getBrowserInfo;
780
+ exports.useAlerts = useAlerts;
781
+ exports.useDashboardMetrics = useDashboardMetrics;
782
+ exports.useGeolocation = useGeolocation;
783
+ //# sourceMappingURL=index.js.map
784
+ //# sourceMappingURL=index.js.map