@keverdjs/fraud-sdk-angular 1.1.0 → 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.
package/dist/index.mjs CHANGED
@@ -2801,11 +2801,19 @@ var PageInteractionCollector = class {
2801
2801
  };
2802
2802
 
2803
2803
  // ../fraud-sdk/src/core/sdk.ts
2804
+ var DEFAULT_ENDPOINT = "https://api.keverd.com";
2804
2805
  var KeverdSDK = class {
2806
+ // Maximum 10 minutes of collection
2805
2807
  constructor() {
2806
2808
  this.config = null;
2807
2809
  this.isInitialized = false;
2808
2810
  this.sessionId = null;
2811
+ this.ghostInterval = null;
2812
+ this.ghostStartTime = null;
2813
+ this.ghostSignalCount = 0;
2814
+ this.MIN_GHOST_SIGNALS = 10;
2815
+ // Collect at least 10 signals (5 minutes of data)
2816
+ this.MAX_GHOST_COLLECTION_TIME = 10 * 60 * 1e3;
2809
2817
  this.deviceCollector = new DeviceCollector();
2810
2818
  this.behavioralCollector = new BehavioralCollector();
2811
2819
  this.fingerprintManager = new FingerprintManager();
@@ -2828,12 +2836,10 @@ var KeverdSDK = class {
2828
2836
  if (typeof config === "string") {
2829
2837
  this.config = {
2830
2838
  apiKey: config,
2831
- endpoint: "https://api.keverd.com",
2832
2839
  debug: false
2833
2840
  };
2834
2841
  } else {
2835
2842
  this.config = {
2836
- endpoint: "https://api.keverd.com",
2837
2843
  debug: false,
2838
2844
  ...config
2839
2845
  };
@@ -2844,10 +2850,115 @@ var KeverdSDK = class {
2844
2850
  this.sessionId = this.generateSessionId();
2845
2851
  this.isInitialized = true;
2846
2852
  if (this.config.debug) {
2847
- console.log("[Keverd SDK] Initialized successfully", {
2848
- endpoint: this.config.endpoint
2853
+ console.log("[Keverd SDK] Initialized successfully");
2854
+ }
2855
+ this.startSession().catch(() => {
2856
+ });
2857
+ this.startGhostSignalCollection();
2858
+ }
2859
+ startGhostSignalCollection() {
2860
+ if (this.ghostInterval) return;
2861
+ if (!this.config) return;
2862
+ this.ghostStartTime = Date.now();
2863
+ this.ghostSignalCount = 0;
2864
+ const intervalMs = 3e4;
2865
+ const sendGhostSignal = () => {
2866
+ const now = Date.now();
2867
+ const totalCollectionTime = this.ghostStartTime ? now - this.ghostStartTime : 0;
2868
+ const hasEnoughSignals = this.ghostSignalCount >= this.MIN_GHOST_SIGNALS;
2869
+ const exceededMaxTime = totalCollectionTime >= this.MAX_GHOST_COLLECTION_TIME;
2870
+ if (hasEnoughSignals || exceededMaxTime) {
2871
+ if (this.config?.debug) {
2872
+ console.log(`[Keverd SDK] Ghost collection complete: ${this.ghostSignalCount} signals, ${Math.round(totalCollectionTime / 1e3)}s elapsed`);
2873
+ }
2874
+ this.stopGhostSignalCollection();
2875
+ return;
2876
+ }
2877
+ const durationMs = this.ghostStartTime ? now - this.ghostStartTime : intervalMs;
2878
+ this.sendGhostSignals(durationMs).catch((err) => {
2879
+ if (this.config?.debug) {
2880
+ console.debug("[Keverd SDK] Ghost signals upload failed:", err);
2881
+ }
2849
2882
  });
2883
+ this.ghostSignalCount++;
2884
+ this.ghostStartTime = now;
2885
+ };
2886
+ setTimeout(() => {
2887
+ sendGhostSignal();
2888
+ this.ghostInterval = setInterval(() => {
2889
+ sendGhostSignal();
2890
+ }, intervalMs);
2891
+ }, intervalMs);
2892
+ }
2893
+ stopGhostSignalCollection() {
2894
+ if (this.ghostInterval) {
2895
+ clearInterval(this.ghostInterval);
2896
+ this.ghostInterval = null;
2897
+ this.ghostStartTime = null;
2898
+ }
2899
+ }
2900
+ async sendGhostSignals(durationMs) {
2901
+ if (!this.isInitialized || !this.config) return;
2902
+ const deviceInfo = this.deviceCollector.collect();
2903
+ const behavioralData = this.behavioralCollector.getData();
2904
+ const fingerprintData = await this.fingerprintManager.collect();
2905
+ const fingerprintjsData = {
2906
+ visitorId: fingerprintData.visitorId,
2907
+ confidence: fingerprintData.confidence,
2908
+ components: fingerprintData.components
2909
+ };
2910
+ const privacySignals = this.privacySignalCollector.collect();
2911
+ const browserCapabilities = this.browserCapabilityCollector.collect();
2912
+ const hardwareSignals = this.hardwareSignalCollector.collect();
2913
+ const formInteractions = this.formInteractionCollector.getData();
2914
+ const mouseSignals = this.behavioralCollector.getMouseSignals();
2915
+ const keyboardSignals = this.behavioralCollector.getKeyboardSignals();
2916
+ const pageInteractions = this.pageInteractionCollector.getData();
2917
+ const networkSignals = {
2918
+ connectionType: hardwareSignals.connectionType || void 0,
2919
+ effectiveType: hardwareSignals.effectiveType || void 0,
2920
+ downlink: hardwareSignals.downlink || void 0,
2921
+ rtt: hardwareSignals.rtt || void 0,
2922
+ saveData: hardwareSignals.saveData || void 0
2923
+ };
2924
+ const sessionInfo = {
2925
+ sessionId: this.sessionId || void 0,
2926
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2927
+ };
2928
+ const request = {
2929
+ userId: this.config.userId,
2930
+ device: deviceInfo,
2931
+ session: sessionInfo,
2932
+ behavioral: behavioralData,
2933
+ duration_ms: durationMs,
2934
+ fingerprintjs: fingerprintjsData || void 0,
2935
+ privacySignals,
2936
+ browserCapabilities,
2937
+ hardwareSignals,
2938
+ formInteractions,
2939
+ mouseSignals,
2940
+ keyboardSignals,
2941
+ pageInteractions,
2942
+ networkSignals,
2943
+ useCase: "ghost"
2944
+ };
2945
+ const url = `${DEFAULT_ENDPOINT}/fingerprint/ghost`;
2946
+ const headers = {
2947
+ "Content-Type": "application/json",
2948
+ "X-SDK-Source": "javascript"
2949
+ };
2950
+ const apiKey = this.config.apiKey;
2951
+ if (apiKey) {
2952
+ headers["x-keverd-key"] = apiKey;
2953
+ headers["X-API-KEY"] = apiKey;
2954
+ headers["Authorization"] = `Bearer ${apiKey}`;
2850
2955
  }
2956
+ await fetch(url, {
2957
+ method: "POST",
2958
+ headers,
2959
+ body: JSON.stringify(request)
2960
+ }).catch(() => {
2961
+ });
2851
2962
  }
2852
2963
  /**
2853
2964
  * Get visitor data (fingerprint and risk assessment)
@@ -3033,8 +3144,7 @@ var KeverdSDK = class {
3033
3144
  if (options.changeType) {
3034
3145
  request.changeType = options.changeType;
3035
3146
  }
3036
- const endpoint = this.config.endpoint || "https://api.keverd.com";
3037
- const url = `${endpoint}/fingerprint/verify/${useCase}`;
3147
+ const url = `${DEFAULT_ENDPOINT}/fingerprint/verify/${useCase}`;
3038
3148
  const headers = {
3039
3149
  "Content-Type": "application/json",
3040
3150
  "X-SDK-Source": "javascript"
@@ -3064,8 +3174,7 @@ var KeverdSDK = class {
3064
3174
  if (!this.config) {
3065
3175
  throw new Error("SDK not initialized");
3066
3176
  }
3067
- const endpoint = this.config.endpoint || "https://api.keverd.com";
3068
- const url = `${endpoint}/fingerprint/score`;
3177
+ const url = `${DEFAULT_ENDPOINT}/fingerprint/score`;
3069
3178
  const headers = {
3070
3179
  "Content-Type": "application/json",
3071
3180
  "X-SDK-Source": "javascript"
@@ -3095,15 +3204,215 @@ var KeverdSDK = class {
3095
3204
  generateSessionId() {
3096
3205
  return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
3097
3206
  }
3207
+ /**
3208
+ * Detect browser name from user agent
3209
+ */
3210
+ _detectBrowser() {
3211
+ const ua = navigator.userAgent;
3212
+ if (ua.includes("Chrome")) return "Chrome";
3213
+ if (ua.includes("Firefox")) return "Firefox";
3214
+ if (ua.includes("Safari") && !ua.includes("Chrome")) return "Safari";
3215
+ if (ua.includes("Edge")) return "Edge";
3216
+ if (ua.includes("Opera")) return "Opera";
3217
+ return void 0;
3218
+ }
3219
+ /**
3220
+ * Detect OS from user agent
3221
+ */
3222
+ _detectOS() {
3223
+ const ua = navigator.userAgent;
3224
+ if (ua.includes("Windows")) return "Windows";
3225
+ if (ua.includes("Mac OS")) return "macOS";
3226
+ if (ua.includes("Linux")) return "Linux";
3227
+ if (ua.includes("Android")) return "Android";
3228
+ if (ua.includes("iOS") || ua.includes("iPhone") || ua.includes("iPad")) return "iOS";
3229
+ return void 0;
3230
+ }
3231
+ /**
3232
+ * Start a new session (called automatically on init, but can be called manually)
3233
+ */
3234
+ async startSession(userId, deviceHash, metadata) {
3235
+ if (!this.isInitialized || !this.config) {
3236
+ throw new Error("Keverd SDK not initialized. Call init() first.");
3237
+ }
3238
+ if (!this.sessionId) {
3239
+ this.sessionId = this.generateSessionId();
3240
+ }
3241
+ try {
3242
+ const url = `${DEFAULT_ENDPOINT}/dashboard/sessions/start`;
3243
+ const headers = {
3244
+ "Content-Type": "application/json"
3245
+ };
3246
+ const apiKey = this.config.apiKey;
3247
+ if (apiKey) {
3248
+ headers["x-keverd-key"] = apiKey;
3249
+ headers["X-API-KEY"] = apiKey;
3250
+ headers["Authorization"] = `Bearer ${apiKey}`;
3251
+ }
3252
+ const deviceInfo = this.deviceCollector.collect();
3253
+ await fetch(url, {
3254
+ method: "POST",
3255
+ headers,
3256
+ body: JSON.stringify({
3257
+ session_id: this.sessionId,
3258
+ user_id: userId || this.config.userId,
3259
+ device_hash: deviceHash || deviceInfo.fingerprint,
3260
+ metadata: metadata || {},
3261
+ user_agent: navigator.userAgent,
3262
+ browser: this._detectBrowser(),
3263
+ os: this._detectOS(),
3264
+ platform: "web",
3265
+ sdk_type: "web",
3266
+ sdk_source: "javascript"
3267
+ })
3268
+ });
3269
+ if (this.config.debug) {
3270
+ console.log(`[Keverd SDK] Session started: ${this.sessionId}`);
3271
+ }
3272
+ } catch (error) {
3273
+ if (this.config.debug) {
3274
+ console.warn("[Keverd SDK] Failed to start session on server:", error);
3275
+ }
3276
+ }
3277
+ }
3278
+ /**
3279
+ * End the current session
3280
+ */
3281
+ async endSession() {
3282
+ if (!this.isInitialized || !this.config || !this.sessionId) {
3283
+ return;
3284
+ }
3285
+ try {
3286
+ const url = `${DEFAULT_ENDPOINT}/dashboard/sessions/${this.sessionId}/end`;
3287
+ const headers = {
3288
+ "Content-Type": "application/json"
3289
+ };
3290
+ const apiKey = this.config.apiKey;
3291
+ if (apiKey) {
3292
+ headers["x-keverd-key"] = apiKey;
3293
+ headers["X-API-KEY"] = apiKey;
3294
+ headers["Authorization"] = `Bearer ${apiKey}`;
3295
+ }
3296
+ await fetch(url, {
3297
+ method: "POST",
3298
+ headers
3299
+ });
3300
+ if (this.config.debug) {
3301
+ console.log(`[Keverd SDK] Session ended: ${this.sessionId}`);
3302
+ }
3303
+ } catch (error) {
3304
+ if (this.config.debug) {
3305
+ console.warn("[Keverd SDK] Failed to end session on server:", error);
3306
+ }
3307
+ }
3308
+ }
3309
+ /**
3310
+ * Pause the current session (e.g., when app goes to background)
3311
+ */
3312
+ async pauseSession() {
3313
+ if (!this.isInitialized || !this.config || !this.sessionId) {
3314
+ return;
3315
+ }
3316
+ try {
3317
+ const url = `${DEFAULT_ENDPOINT}/dashboard/sessions/${this.sessionId}/pause`;
3318
+ const headers = {
3319
+ "Content-Type": "application/json"
3320
+ };
3321
+ const apiKey = this.config.apiKey;
3322
+ if (apiKey) {
3323
+ headers["x-keverd-key"] = apiKey;
3324
+ headers["X-API-KEY"] = apiKey;
3325
+ headers["Authorization"] = `Bearer ${apiKey}`;
3326
+ }
3327
+ await fetch(url, {
3328
+ method: "POST",
3329
+ headers
3330
+ });
3331
+ if (this.config.debug) {
3332
+ console.log(`[Keverd SDK] Session paused: ${this.sessionId}`);
3333
+ }
3334
+ } catch (error) {
3335
+ if (this.config.debug) {
3336
+ console.warn("[Keverd SDK] Failed to pause session on server:", error);
3337
+ }
3338
+ }
3339
+ }
3340
+ /**
3341
+ * Resume a paused session (e.g., when app comes to foreground)
3342
+ */
3343
+ async resumeSession() {
3344
+ if (!this.isInitialized || !this.config || !this.sessionId) {
3345
+ return;
3346
+ }
3347
+ try {
3348
+ const url = `${DEFAULT_ENDPOINT}/dashboard/sessions/${this.sessionId}/resume`;
3349
+ const headers = {
3350
+ "Content-Type": "application/json"
3351
+ };
3352
+ const apiKey = this.config.apiKey;
3353
+ if (apiKey) {
3354
+ headers["x-keverd-key"] = apiKey;
3355
+ headers["X-API-KEY"] = apiKey;
3356
+ headers["Authorization"] = `Bearer ${apiKey}`;
3357
+ }
3358
+ await fetch(url, {
3359
+ method: "POST",
3360
+ headers
3361
+ });
3362
+ if (this.config.debug) {
3363
+ console.log(`[Keverd SDK] Session resumed: ${this.sessionId}`);
3364
+ }
3365
+ } catch (error) {
3366
+ if (this.config.debug) {
3367
+ console.warn("[Keverd SDK] Failed to resume session on server:", error);
3368
+ }
3369
+ }
3370
+ }
3371
+ /**
3372
+ * Get current session status
3373
+ */
3374
+ async getSessionStatus() {
3375
+ if (!this.isInitialized || !this.config || !this.sessionId) {
3376
+ return null;
3377
+ }
3378
+ try {
3379
+ const url = `${DEFAULT_ENDPOINT}/dashboard/sessions/${this.sessionId}/status`;
3380
+ const headers = {};
3381
+ const apiKey = this.config.apiKey;
3382
+ if (apiKey) {
3383
+ headers["x-keverd-key"] = apiKey;
3384
+ headers["X-API-KEY"] = apiKey;
3385
+ headers["Authorization"] = `Bearer ${apiKey}`;
3386
+ }
3387
+ const response = await fetch(url, {
3388
+ method: "GET",
3389
+ headers
3390
+ });
3391
+ if (!response.ok) {
3392
+ return null;
3393
+ }
3394
+ return await response.json();
3395
+ } catch (error) {
3396
+ if (this.config.debug) {
3397
+ console.warn("[Keverd SDK] Failed to get session status:", error);
3398
+ }
3399
+ return null;
3400
+ }
3401
+ }
3098
3402
  /**
3099
3403
  * Destroy the SDK instance
3100
3404
  */
3101
- destroy() {
3405
+ async destroy() {
3406
+ if (this.sessionId) {
3407
+ await this.endSession();
3408
+ }
3102
3409
  this.behavioralCollector.stop();
3103
3410
  this.formInteractionCollector.stop();
3104
3411
  this.pageInteractionCollector.stop();
3105
3412
  this.fingerprintManager.clearCache();
3106
3413
  this.isInitialized = false;
3414
+ this.stopGhostSignalCollection();
3415
+ this.ghostSignalCount = 0;
3107
3416
  if (this.config?.debug) {
3108
3417
  console.log("[Keverd SDK] Destroyed");
3109
3418
  }
@@ -3143,22 +3452,20 @@ var KeverdService = class {
3143
3452
  throw new Error("Keverd SDK: apiKey is required");
3144
3453
  }
3145
3454
  this.config = {
3146
- endpoint: config.endpoint || this.getDefaultEndpoint(),
3147
3455
  debug: false,
3148
3456
  ...config
3149
3457
  };
3150
3458
  Keverd.init({
3151
3459
  apiKey: this.config.apiKey,
3152
- endpoint: this.config.endpoint,
3153
3460
  userId: this.config.userId,
3154
3461
  debug: this.config.debug || false
3155
3462
  });
3156
3463
  this.isInitialized = true;
3157
3464
  if (this.config.debug) {
3158
- console.log("[Keverd SDK] Initialized successfully", {
3159
- endpoint: this.config.endpoint
3160
- });
3465
+ console.log("[Keverd SDK] Initialized successfully");
3161
3466
  }
3467
+ Keverd.startSession().catch(() => {
3468
+ });
3162
3469
  }
3163
3470
  /**
3164
3471
  * Get visitor data (fingerprint and risk assessment)
@@ -3223,22 +3530,115 @@ var KeverdService = class {
3223
3530
  recommendedAction: response.recommended_action
3224
3531
  };
3225
3532
  }
3226
- /**
3227
- * Get default endpoint
3228
- */
3229
- getDefaultEndpoint() {
3230
- return "https://api.keverd.com";
3231
- }
3232
3533
  /**
3233
3534
  * Generate a session ID
3234
3535
  */
3235
3536
  generateSessionId() {
3236
3537
  return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
3237
3538
  }
3539
+ /**
3540
+ * Start a new session (called automatically on init, but can be called manually)
3541
+ */
3542
+ startSession(userId, deviceHash, metadata) {
3543
+ if (!this.isInitialized || !this.config) {
3544
+ return throwError(() => ({
3545
+ message: "Keverd SDK not initialized. Call init() first.",
3546
+ code: "SDK_NOT_INITIALIZED"
3547
+ }));
3548
+ }
3549
+ return from(Keverd.startSession(userId, deviceHash, metadata)).pipe(
3550
+ catchError((error) => {
3551
+ if (this.config?.debug) {
3552
+ console.warn("[Keverd SDK] Failed to start session:", error);
3553
+ }
3554
+ return throwError(() => error);
3555
+ })
3556
+ );
3557
+ }
3558
+ /**
3559
+ * End the current session
3560
+ */
3561
+ endSession() {
3562
+ if (!this.isInitialized || !this.config) {
3563
+ return throwError(() => ({
3564
+ message: "Keverd SDK not initialized. Call init() first.",
3565
+ code: "SDK_NOT_INITIALIZED"
3566
+ }));
3567
+ }
3568
+ return from(Keverd.endSession()).pipe(
3569
+ catchError((error) => {
3570
+ if (this.config?.debug) {
3571
+ console.warn("[Keverd SDK] Failed to end session:", error);
3572
+ }
3573
+ return throwError(() => error);
3574
+ })
3575
+ );
3576
+ }
3577
+ /**
3578
+ * Pause the current session (e.g., when app goes to background)
3579
+ */
3580
+ pauseSession() {
3581
+ if (!this.isInitialized || !this.config) {
3582
+ return throwError(() => ({
3583
+ message: "Keverd SDK not initialized. Call init() first.",
3584
+ code: "SDK_NOT_INITIALIZED"
3585
+ }));
3586
+ }
3587
+ return from(Keverd.pauseSession()).pipe(
3588
+ catchError((error) => {
3589
+ if (this.config?.debug) {
3590
+ console.warn("[Keverd SDK] Failed to pause session:", error);
3591
+ }
3592
+ return throwError(() => error);
3593
+ })
3594
+ );
3595
+ }
3596
+ /**
3597
+ * Resume a paused session (e.g., when app comes to foreground)
3598
+ */
3599
+ resumeSession() {
3600
+ if (!this.isInitialized || !this.config) {
3601
+ return throwError(() => ({
3602
+ message: "Keverd SDK not initialized. Call init() first.",
3603
+ code: "SDK_NOT_INITIALIZED"
3604
+ }));
3605
+ }
3606
+ return from(Keverd.resumeSession()).pipe(
3607
+ catchError((error) => {
3608
+ if (this.config?.debug) {
3609
+ console.warn("[Keverd SDK] Failed to resume session:", error);
3610
+ }
3611
+ return throwError(() => error);
3612
+ })
3613
+ );
3614
+ }
3615
+ /**
3616
+ * Get current session status
3617
+ */
3618
+ getSessionStatus() {
3619
+ if (!this.isInitialized || !this.config) {
3620
+ return throwError(() => ({
3621
+ message: "Keverd SDK not initialized. Call init() first.",
3622
+ code: "SDK_NOT_INITIALIZED"
3623
+ }));
3624
+ }
3625
+ return from(Keverd.getSessionStatus()).pipe(
3626
+ catchError((error) => {
3627
+ if (this.config?.debug) {
3628
+ console.warn("[Keverd SDK] Failed to get session status:", error);
3629
+ }
3630
+ return throwError(() => error);
3631
+ })
3632
+ );
3633
+ }
3238
3634
  /**
3239
3635
  * Destroy the SDK instance
3240
3636
  */
3241
3637
  destroy() {
3638
+ if (this.isInitialized) {
3639
+ Keverd.endSession().catch(() => {
3640
+ });
3641
+ }
3242
3642
  Keverd.destroy();
3243
3643
  this.isInitialized = false;
3244
3644
  this.config = null;
@@ -3274,7 +3674,6 @@ var KeverdModule = class {
3274
3674
  * imports: [
3275
3675
  * KeverdModule.forRoot({
3276
3676
  * apiKey: 'your-api-key',
3277
- * endpoint: 'https://api.keverd.com'
3278
3677
  * })
3279
3678
  * ]
3280
3679
  * })