@keverdjs/fraud-sdk 1.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Keverd
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,154 @@
1
+ # @keverdjs/fraud-sdk
2
+
3
+ Vanilla JavaScript SDK for Keverd fraud detection and device fingerprinting. Works in any JavaScript environment (browser, Node.js, etc.).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @keverdjs/fraud-sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```javascript
14
+ import { Keverd } from '@keverdjs/fraud-sdk';
15
+
16
+ // Initialize with API key
17
+ Keverd.init('your-api-key');
18
+
19
+ // Get visitor data and risk assessment
20
+ const result = await Keverd.getVisitorData();
21
+
22
+ console.log('Risk Score:', result.risk_score);
23
+ console.log('Action:', result.action);
24
+ console.log('Session ID:', result.session_id);
25
+ ```
26
+
27
+ ### With Configuration Object
28
+
29
+ ```javascript
30
+ import { Keverd } from '@keverdjs/fraud-sdk';
31
+
32
+ // Initialize with configuration
33
+ Keverd.init({
34
+ apiKey: 'your-api-key',
35
+ endpoint: 'https://app.keverd.com', // Optional
36
+ debug: true, // Optional: enable debug logging
37
+ });
38
+
39
+ // Get visitor data
40
+ const result = await Keverd.getVisitorData();
41
+ ```
42
+
43
+ ## API Reference
44
+
45
+ ### `Keverd.init(config)`
46
+
47
+ Initialize the SDK with your API key.
48
+
49
+ **Parameters:**
50
+ - `config` (string | SDKConfig): API key string or configuration object
51
+
52
+ **Example:**
53
+ ```javascript
54
+ // Simple initialization
55
+ Keverd.init('your-api-key');
56
+
57
+ // With options
58
+ Keverd.init({
59
+ apiKey: 'your-api-key',
60
+ endpoint: 'https://app.keverd.com',
61
+ userId: 'optional-user-id',
62
+ debug: false
63
+ });
64
+ ```
65
+
66
+ ### `Keverd.getVisitorData()`
67
+
68
+ Get visitor data and risk assessment. This is the main method for fraud detection.
69
+
70
+ **Returns:** Promise<FingerprintResponse>
71
+
72
+ **Example:**
73
+ ```javascript
74
+ const result = await Keverd.getVisitorData();
75
+
76
+ // Result structure:
77
+ // {
78
+ // risk_score: 25, // 0-100
79
+ // score: 0.25, // 0.0-1.0
80
+ // action: 'allow', // 'allow' | 'soft_challenge' | 'hard_challenge' | 'block'
81
+ // reason: ['new_user'], // Array of risk reasons
82
+ // session_id: 'uuid', // Session identifier
83
+ // requestId: 'uuid', // Request identifier
84
+ // sim_swap_engine: {...} // SIM swap detection results (null for web)
85
+ // }
86
+ ```
87
+
88
+ ### `Keverd.createTransactionID(metadata?)`
89
+
90
+ Legacy method for backward compatibility. Returns the session ID from `getVisitorData()`.
91
+
92
+ **Parameters:**
93
+ - `metadata` (TransactionMetadata, optional): Transaction metadata
94
+
95
+ **Returns:** Promise<string> - Session ID
96
+
97
+ **Example:**
98
+ ```javascript
99
+ const transactionId = await Keverd.createTransactionID({
100
+ amount: 1000,
101
+ currency: 'KES',
102
+ recipient: '254712345678'
103
+ });
104
+ ```
105
+
106
+ ### `Keverd.destroy()`
107
+
108
+ Destroy the SDK instance and stop all data collection.
109
+
110
+ **Example:**
111
+ ```javascript
112
+ Keverd.destroy();
113
+ ```
114
+
115
+ ## Response Structure
116
+
117
+ ```typescript
118
+ interface FingerprintResponse {
119
+ risk_score: number; // 0-100 risk score
120
+ score: number; // 0.0-1.0 normalized score
121
+ action: 'allow' | 'soft_challenge' | 'hard_challenge' | 'block';
122
+ reason: string[]; // Array of risk reasons
123
+ session_id: string; // UUID session identifier
124
+ requestId: string; // UUID request identifier
125
+ sim_swap_engine?: { // SIM swap detection (null for web SDKs)
126
+ userId?: string;
127
+ risk: number;
128
+ flags: {
129
+ sim_changed?: boolean;
130
+ device_changed?: boolean;
131
+ behavior_anomaly?: boolean;
132
+ time_anomaly?: boolean;
133
+ velocity_anomaly?: boolean;
134
+ };
135
+ updatedProfile?: Record<string, unknown>;
136
+ };
137
+ }
138
+ ```
139
+
140
+ ## Browser Support
141
+
142
+ - Chrome (latest)
143
+ - Firefox (latest)
144
+ - Safari (latest)
145
+ - Edge (latest)
146
+
147
+ ## License
148
+
149
+ MIT
150
+
151
+ ## Support
152
+
153
+ For issues, questions, or contributions, please visit the [GitHub repository](https://github.com/keverd/keverd-fraud-sdk-web).
154
+
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Behavioral Data Collector
3
+ * Collects typing patterns, mouse movements, swipe gestures, and calculates session entropy
4
+ * Matches React SDK implementation for consistency
5
+ */
6
+ import { BehavioralData } from '../types';
7
+ export declare class BehavioralCollector {
8
+ private keystrokes;
9
+ private mouseMovements;
10
+ private lastKeyDownTime;
11
+ private lastKeyUpTime;
12
+ private isActive;
13
+ private sessionStartTime;
14
+ private typingDwellTimes;
15
+ private typingFlightTimes;
16
+ private swipeVelocities;
17
+ private sessionEvents;
18
+ private touchStartPositions;
19
+ private keyDownHandler;
20
+ private keyUpHandler;
21
+ private mouseMoveHandler;
22
+ private touchStartHandler;
23
+ private touchEndHandler;
24
+ /**
25
+ * Start collecting behavioral data
26
+ * Uses passive listeners for efficiency (non-blocking)
27
+ */
28
+ start(): void;
29
+ /**
30
+ * Stop collecting behavioral data
31
+ */
32
+ stop(): void;
33
+ /**
34
+ * Get collected behavioral data
35
+ * Returns data in format expected by backend
36
+ */
37
+ getData(): BehavioralData;
38
+ /**
39
+ * Reset collected data
40
+ */
41
+ reset(): void;
42
+ /**
43
+ * Handle keydown event
44
+ */
45
+ private handleKeyDown;
46
+ /**
47
+ * Handle keyup event
48
+ */
49
+ private handleKeyUp;
50
+ /**
51
+ * Handle mouse move event
52
+ */
53
+ private handleMouseMove;
54
+ /**
55
+ * Handle touch start (for swipe detection)
56
+ */
57
+ private handleTouchStart;
58
+ /**
59
+ * Handle touch end (calculate swipe velocity)
60
+ */
61
+ private handleTouchEnd;
62
+ /**
63
+ * Calculate session entropy based on event diversity
64
+ * Uses Shannon entropy formula as expected by backend
65
+ */
66
+ private calculateSessionEntropy;
67
+ /**
68
+ * Check if key should be ignored
69
+ */
70
+ private shouldIgnoreKey;
71
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Device Fingerprint Collector
3
+ * Collects device information and generates SHA-256 fingerprint
4
+ * Matches React SDK implementation for consistency
5
+ */
6
+ import { DeviceInfo } from '../types';
7
+ export declare class DeviceCollector {
8
+ private cachedDeviceInfo;
9
+ /**
10
+ * Collect all device information and generate fingerprint
11
+ */
12
+ collect(): DeviceInfo;
13
+ /**
14
+ * Generate a stable device fingerprint using multiple browser characteristics
15
+ * Returns SHA-256 hash (64 hex characters) as required by backend
16
+ */
17
+ private generateDeviceFingerprint;
18
+ /**
19
+ * Generate canvas fingerprint
20
+ */
21
+ private getCanvasFingerprint;
22
+ /**
23
+ * Generate WebGL fingerprint
24
+ */
25
+ private getWebGLFingerprint;
26
+ /**
27
+ * Generate a stable device ID from fingerprint
28
+ */
29
+ private generateDeviceId;
30
+ /**
31
+ * Get manufacturer from user agent
32
+ */
33
+ private getManufacturer;
34
+ /**
35
+ * Get model from user agent
36
+ */
37
+ private getModel;
38
+ /**
39
+ * Get brand from user agent
40
+ */
41
+ private getBrand;
42
+ /**
43
+ * Get device type
44
+ */
45
+ private getDevice;
46
+ /**
47
+ * Get product name
48
+ */
49
+ private getProduct;
50
+ /**
51
+ * Get hardware info
52
+ */
53
+ private getHardware;
54
+ /**
55
+ * Get OS version
56
+ */
57
+ private getOSVersion;
58
+ /**
59
+ * Get screen density
60
+ */
61
+ private getScreenDensity;
62
+ /**
63
+ * Hash a string using SHA-256-like algorithm (64 hex characters)
64
+ * Backend expects SHA-256 format (64 hex chars)
65
+ */
66
+ private hashString;
67
+ /**
68
+ * SHA-256-like hash function (synchronous, deterministic)
69
+ * Produces 64-character hex string matching SHA-256 format
70
+ */
71
+ private sha256LikeHash;
72
+ /**
73
+ * Clear cached device info (useful for testing)
74
+ */
75
+ clearCache(): void;
76
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Keverd Fraud SDK Core (Vanilla JS)
3
+ * Main SDK class for fingerprinting and risk assessment
4
+ * Matches backend FingerprintSDKRequest format exactly
5
+ */
6
+ import { SDKConfig, FingerprintResponse, TransactionMetadata } from '../types';
7
+ export declare class KeverdSDK {
8
+ private config;
9
+ private deviceCollector;
10
+ private behavioralCollector;
11
+ private isInitialized;
12
+ private sessionId;
13
+ constructor();
14
+ /**
15
+ * Initialize the SDK with configuration
16
+ */
17
+ init(config: SDKConfig | string): void;
18
+ /**
19
+ * Get visitor data (fingerprint and risk assessment)
20
+ * This is the main method for getting risk scores
21
+ */
22
+ getVisitorData(): Promise<FingerprintResponse>;
23
+ /**
24
+ * Create transaction ID with risk assessment (legacy method)
25
+ * For new implementations, use getVisitorData() instead
26
+ */
27
+ createTransactionID(metadata?: TransactionMetadata): Promise<string>;
28
+ /**
29
+ * Send fingerprint request to backend
30
+ */
31
+ private sendFingerprintRequest;
32
+ /**
33
+ * Generate a unique session ID
34
+ */
35
+ private generateSessionId;
36
+ /**
37
+ * Destroy the SDK instance
38
+ */
39
+ destroy(): void;
40
+ }
41
+ export declare const Keverd: KeverdSDK;
@@ -0,0 +1 @@
1
+ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.FintechRisk=e():t.FintechRisk=e()}(this,()=>(()=>{"use strict";var t={d:(e,i)=>{for(var s in i)t.o(i,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:i[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"t",{value:!0})}},e={};t.r(e),t.d(e,{BehavioralCollector:()=>s,DeviceCollector:()=>i,Keverd:()=>r,KeverdSDK:()=>n});class i{constructor(){this.cachedDeviceInfo=null}collect(){if(this.cachedDeviceInfo)return this.cachedDeviceInfo;const t=this.generateDeviceFingerprint(),e=this.generateDeviceId(t);return this.cachedDeviceInfo={deviceId:e,fingerprint:t,manufacturer:this.getManufacturer(),model:this.getModel(),brand:this.getBrand(),device:this.getDevice(),product:this.getProduct(),hardware:this.getHardware(),sdkVersion:"1.0.0",osVersion:this.getOSVersion(),screenWidth:String(screen.width),screenHeight:String(screen.height),screenDensity:this.getScreenDensity(),locale:navigator.language||navigator.languages?.[0]||"en",timezone:Intl.DateTimeFormat().resolvedOptions().timeZone},this.cachedDeviceInfo}generateDeviceFingerprint(){const t=[],e=this.getCanvasFingerprint();e&&t.push(e);const i=this.getWebGLFingerprint();if(i&&t.push(i),t.push(navigator.userAgent),t.push(navigator.language||navigator.languages?.[0]||""),t.push(`${screen.width}x${screen.height}x${screen.colorDepth}`),t.push(String((new Date).getTimezoneOffset())),t.push(navigator.platform),t.push(String(navigator.hardwareConcurrency||0)),"deviceMemory"in navigator&&t.push(String(navigator.deviceMemory)),"maxTouchPoints"in navigator&&t.push(String(navigator.maxTouchPoints)),navigator.plugins&&navigator.plugins.length>0){const e=Array.from(navigator.plugins).slice(0,3).map(t=>t.name).join(",");t.push(e)}const s=t.join("|");return this.hashString(s)}getCanvasFingerprint(){try{const t=document.createElement("canvas"),e=t.getContext("2d");return e?(t.width=200,t.height=50,e.textBaseline="top",e.font="14px Arial",e.fillStyle="#f60",e.fillRect(125,1,62,20),e.fillStyle="#069",e.fillText("KeverdFingerprint",2,15),e.fillStyle="rgba(102, 204, 0, 0.7)",e.fillText("KeverdFingerprint",4,17),this.hashString(t.toDataURL())):""}catch(t){return""}}getWebGLFingerprint(){try{const t=document.createElement("canvas"),e=t.getContext("webgl")||t.getContext("experimental-webgl");if(!e)return"";const i=e.getExtension("WEBGL_debug_renderer_info");if(i){const t=e.getParameter(i.UNMASKED_VENDOR_WEBGL),s=e.getParameter(i.UNMASKED_RENDERER_WEBGL);return this.hashString(`${t}|${s}`)}const s=e.getParameter(e.VERSION),n=e.getParameter(e.VENDOR);return this.hashString(`${s}|${n}`)}catch(t){return""}}generateDeviceId(t){return t.substring(0,32)}getManufacturer(){const t=navigator.userAgent.toLowerCase();if(t.includes("iphone")||t.includes("ipad"))return"Apple";if(t.includes("android")){const e=t.match(/(?:^|\s)([a-z]+)(?:\s|$)/);return e?e[1].charAt(0).toUpperCase()+e[1].slice(1):void 0}}getModel(){const t=navigator.userAgent.match(/(iPhone|iPad|Android)[\s\/]+([\w]+)/i);return t?t[2]:void 0}getBrand(){return this.getManufacturer()}getDevice(){const t=navigator.userAgent.toLowerCase();return t.includes("mobile")?"mobile":t.includes("tablet")?"tablet":"desktop"}getProduct(){const t=navigator.userAgent.match(/(iPhone|iPad|Android|Windows|Mac|Linux)/i);return t?t[1]:void 0}getHardware(){const t=navigator.userAgent.match(/\(([^)]+)\)/);return t?t[1]:void 0}getOSVersion(){const t=navigator.userAgent,e=[/OS\s+([\d_]+)/i,/Android\s+([\d.]+)/i,/Windows\s+([\d.]+)/i,/Mac\s+OS\s+X\s+([\d_]+)/i,/Linux/i];for(const i of e){const e=t.match(i);if(e)return e[1]?.replace(/_/g,".")||e[0]}}getScreenDensity(){if(window.devicePixelRatio)return String(window.devicePixelRatio)}hashString(t){return this.sha256LikeHash(t)}sha256LikeHash(t){const e=[];let i=5381;for(let e=0;e<t.length;e++)i=(i<<5)+i+t.charCodeAt(e),i&=4294967295;e.push(i);let s=0;for(let e=t.length-1;e>=0;e--)s=(s<<7)-s+t.charCodeAt(e),s&=4294967295;e.push(s);let n=0;for(let e=0;e<t.length;e++)n^=t.charCodeAt(e)<<e%4*8,n&=4294967295;e.push(n);let r=0;for(let e=0;e<t.length;e++)r=31*r+t.charCodeAt(e)&4294967295;e.push(r);let o=0;for(let e=0;e<t.length;e++){o=o+(4294967295&(t.charCodeAt(e)<<e%16|t.charCodeAt(e)>>>32-e%16))&4294967295}e.push(o);let h=2166136261;for(let e=0;e<t.length;e++)h=16777619*(h^t.charCodeAt(e)),h&=4294967295;e.push(h);let a=0;for(let e=0;e<t.length;e++)a=a+t.charCodeAt(e)*(e+1)&4294967295;e.push(a);let c=0;for(let e=0;e<t.length;e+=2){c=(c<<3)-c+(t.charCodeAt(e)+256*(t.charCodeAt(e+1)||0)),c&=4294967295}e.push(c);return e.map(t=>Math.abs(t).toString(16).padStart(8,"0")).join("").substring(0,64).padEnd(64,"0")}clearCache(){this.cachedDeviceInfo=null}}class s{constructor(){this.keystrokes=[],this.mouseMovements=[],this.lastKeyDownTime=new Map,this.lastKeyUpTime=null,this.isActive=!1,this.sessionStartTime=Date.now(),this.typingDwellTimes=[],this.typingFlightTimes=[],this.swipeVelocities=[],this.sessionEvents=[],this.touchStartPositions=new Map,this.keyDownHandler=t=>this.handleKeyDown(t),this.keyUpHandler=t=>this.handleKeyUp(t),this.mouseMoveHandler=t=>this.handleMouseMove(t),this.touchStartHandler=t=>this.handleTouchStart(t),this.touchEndHandler=t=>this.handleTouchEnd(t)}start(){this.isActive||("undefined"!=typeof document&&(document.addEventListener("keydown",this.keyDownHandler,{passive:!0}),document.addEventListener("keyup",this.keyUpHandler,{passive:!0}),document.addEventListener("mousemove",this.mouseMoveHandler,{passive:!0}),document.addEventListener("touchstart",this.touchStartHandler,{passive:!0}),document.addEventListener("touchend",this.touchEndHandler,{passive:!0})),this.isActive=!0,this.sessionStartTime=Date.now())}stop(){this.isActive&&("undefined"!=typeof document&&(document.removeEventListener("keydown",this.keyDownHandler),document.removeEventListener("keyup",this.keyUpHandler),document.removeEventListener("mousemove",this.mouseMoveHandler),document.removeEventListener("touchstart",this.touchStartHandler),document.removeEventListener("touchend",this.touchEndHandler)),this.isActive=!1)}getData(){const t=this.typingDwellTimes.slice(-20),e=this.typingFlightTimes.slice(-20),i=this.swipeVelocities.length>0?this.swipeVelocities.reduce((t,e)=>t+e,0)/this.swipeVelocities.length:0,s=this.calculateSessionEntropy();return{typing_dwell_ms:t.length>0?t:[],typing_flight_ms:e.length>0?e:[],swipe_velocity:i>0?i:0,session_entropy:s>=0?s:0}}reset(){this.keystrokes=[],this.mouseMovements=[],this.lastKeyDownTime.clear(),this.lastKeyUpTime=null,this.typingDwellTimes=[],this.typingFlightTimes=[],this.swipeVelocities=[],this.sessionEvents=[],this.touchStartPositions.clear(),this.sessionStartTime=Date.now()}handleKeyDown(t){if(this.shouldIgnoreKey(t))return;const e=performance.now();this.lastKeyDownTime.set(t.key,e);const i={key:t.key,timestamp:e,type:"keydown"};this.keystrokes.push(i),this.sessionEvents.push({type:"keydown",timestamp:e})}handleKeyUp(t){if(this.shouldIgnoreKey(t))return;const e=performance.now(),i=this.lastKeyDownTime.get(t.key);if(void 0!==i){const s=e-i;this.typingDwellTimes.push(s),this.lastKeyDownTime.delete(t.key)}if(null!==this.lastKeyUpTime){const t=e-this.lastKeyUpTime;this.typingFlightTimes.push(t)}this.lastKeyUpTime=e;const s={key:t.key,timestamp:e,type:"keyup"};this.keystrokes.push(s),this.sessionEvents.push({type:"keyup",timestamp:e})}handleMouseMove(t){const e={x:t.clientX,y:t.clientY,timestamp:performance.now(),type:"move"};if(this.mouseMovements.length>0){const t=this.mouseMovements[this.mouseMovements.length-1],i=e.timestamp-t.timestamp;if(i>0){const s=Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2));e.velocity=s/i}}this.mouseMovements.push(e),this.sessionEvents.push({type:"mousemove",timestamp:e.timestamp})}handleTouchStart(t){const e=performance.now();for(let i=0;i<t.touches.length;i++){const s=t.touches[i];this.touchStartPositions.set(s.identifier,{x:s.clientX,y:s.clientY,timestamp:e})}this.sessionEvents.push({type:"touchstart",timestamp:e})}handleTouchEnd(t){const e=performance.now();for(let i=0;i<t.changedTouches.length;i++){const s=t.changedTouches[i],n=this.touchStartPositions.get(s.identifier);if(n){const t=e-n.timestamp;if(t>0&&t<1e3){const e=Math.sqrt(Math.pow(s.clientX-n.x,2)+Math.pow(s.clientY-n.y,2));if(e>10){const i=e/t;this.swipeVelocities.push(i)}}this.touchStartPositions.delete(s.identifier)}}this.sessionEvents.push({type:"touchend",timestamp:e})}calculateSessionEntropy(){if(0===this.sessionEvents.length)return 0;const t={};for(const e of this.sessionEvents)t[e.type]=(t[e.type]||0)+1;const e=this.sessionEvents.length;let i=0;for(const s of Object.values(t)){const t=s/e;t>0&&(i-=t*Math.log2(t))}return i}shouldIgnoreKey(t){return["Shift","Control","Alt","Meta","CapsLock","Tab","Escape","Enter","ArrowLeft","ArrowRight","ArrowUp","ArrowDown","Home","End","PageUp","PageDown","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12"].includes(t.key)}}class n{constructor(){this.config=null,this.isInitialized=!1,this.sessionId=null,this.deviceCollector=new i,this.behavioralCollector=new s}init(t){this.isInitialized?this.config:(this.config="string"==typeof t?{apiKey:t,endpoint:"https://app.keverd.com",debug:!1}:{endpoint:"https://app.keverd.com",debug:!1,...t},this.behavioralCollector.start(),this.sessionId=this.generateSessionId(),this.isInitialized=!0,this.config.debug)}async getVisitorData(){if(!this.isInitialized||!this.config)throw new Error("Keverd SDK not initialized. Call init() first.");try{const t=this.deviceCollector.collect(),e=this.behavioralCollector.getData(),i={sessionId:this.sessionId||void 0,timestamp:(new Date).toISOString()},s={userId:this.config.userId,device:t,session:i,behavioral:e};return await this.sendFingerprintRequest(s)}catch(t){const e=t instanceof Error?t.message:"Unknown error";throw this.config.debug,new Error(`Failed to get visitor data: ${e}`)}}async createTransactionID(t){return(await this.getVisitorData()).session_id}async sendFingerprintRequest(t){if(!this.config)throw new Error("SDK not initialized");const e=`${this.config.endpoint||"https://app.keverd.com"}/fingerprint/score`,i={"Content-Type":"application/json","X-SDK-Source":"javascript"},s=this.config.apiKey;s&&(i["x-keverd-key"]=s,i["X-API-KEY"]=s,i.Authorization=`Bearer ${s}`);const n=await fetch(e,{method:"POST",headers:i,body:JSON.stringify(t)});if(!n.ok){const t=await n.text().catch(()=>"Unknown error");throw new Error(`HTTP ${n.status}: ${t}`)}return await n.json()}generateSessionId(){return`${Date.now()}_${Math.random().toString(36).substr(2,9)}`}destroy(){this.behavioralCollector.stop(),this.isInitialized=!1,this.config,this.config=null,this.sessionId=null}}const r=new n;return e})());
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Keverd Fraud SDK (Vanilla JS)
3
+ * Main entry point
4
+ */
5
+ export { KeverdSDK, Keverd } from './core/sdk';
6
+ export { DeviceCollector } from './collectors/device';
7
+ export { BehavioralCollector } from './collectors/behavioral';
8
+ export type { SDKConfig, DeviceInfo, SessionInfo, BehavioralData, FingerprintRequest, FingerprintResponse, TransactionMetadata, } from './types';
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Type definitions for Keverd Fraud SDK (Vanilla JS)
3
+ * Matches backend FingerprintSDKRequest schema exactly
4
+ */
5
+ export interface DeviceInfo {
6
+ deviceId: string;
7
+ fingerprint: string;
8
+ manufacturer?: string;
9
+ model?: string;
10
+ brand?: string;
11
+ device?: string;
12
+ product?: string;
13
+ hardware?: string;
14
+ sdkVersion?: string;
15
+ osVersion?: string;
16
+ screenWidth?: string;
17
+ screenHeight?: string;
18
+ screenDensity?: string;
19
+ locale?: string;
20
+ timezone: string;
21
+ }
22
+ export interface SessionInfo {
23
+ sessionId?: string;
24
+ installId?: string;
25
+ sessionCount?: string;
26
+ firstSession?: string;
27
+ timestamp?: string;
28
+ }
29
+ export interface BehavioralData {
30
+ typing_dwell_ms?: number[];
31
+ typing_flight_ms?: number[];
32
+ swipe_velocity?: number;
33
+ session_entropy?: number;
34
+ }
35
+ export interface FingerprintRequest {
36
+ userId?: string;
37
+ device: DeviceInfo;
38
+ session?: SessionInfo;
39
+ behavioral?: BehavioralData;
40
+ }
41
+ export interface FingerprintResponse {
42
+ risk_score: number;
43
+ score: number;
44
+ action: 'allow' | 'soft_challenge' | 'hard_challenge' | 'block';
45
+ reason: string[];
46
+ session_id: string;
47
+ requestId: string;
48
+ sim_swap_engine?: {
49
+ userId?: string;
50
+ risk: number;
51
+ flags: {
52
+ sim_changed?: boolean;
53
+ device_changed?: boolean;
54
+ behavior_anomaly?: boolean;
55
+ time_anomaly?: boolean;
56
+ velocity_anomaly?: boolean;
57
+ };
58
+ updatedProfile?: Record<string, unknown>;
59
+ };
60
+ }
61
+ export interface SDKConfig {
62
+ apiKey: string;
63
+ endpoint?: string;
64
+ userId?: string;
65
+ debug?: boolean;
66
+ }
67
+ export interface TransactionMetadata {
68
+ amount?: number;
69
+ currency?: string;
70
+ recipient?: string;
71
+ transactionType?: string;
72
+ customData?: Record<string, unknown>;
73
+ }
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@keverdjs/fraud-sdk",
3
+ "version": "1.0.0",
4
+ "description": "Vanilla JavaScript SDK for Keverd fraud detection and device fingerprinting",
5
+ "main": "dist/fintechrisk.js",
6
+ "types": "dist/index.d.ts",
7
+ "module": "dist/fintechrisk.esm.js",
8
+ "files": [
9
+ "dist",
10
+ "README.md",
11
+ "LICENSE"
12
+ ],
13
+ "scripts": {
14
+ "build": "webpack --mode=production",
15
+ "dev": "webpack --mode=development --watch",
16
+ "lint": "eslint src/**/*.ts",
17
+ "typecheck": "tsc --noEmit",
18
+ "test": "jest",
19
+ "clean": "rm -rf dist",
20
+ "prepublishOnly": "npm run clean && npm run build"
21
+ },
22
+ "keywords": [
23
+ "keverd",
24
+ "fraud-detection",
25
+ "device-fingerprinting",
26
+ "behavioral-biometrics",
27
+ "vanilla-js",
28
+ "javascript",
29
+ "risk-assessment"
30
+ ],
31
+ "author": "Keverd",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/keverd/keverd-fraud-sdk-web.git",
36
+ "directory": "packages/@keverd/fraud-sdk"
37
+ },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "devDependencies": {
42
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
43
+ "@typescript-eslint/parser": "^6.0.0",
44
+ "eslint": "^8.45.0",
45
+ "jest": "^29.6.0",
46
+ "ts-jest": "^29.1.0",
47
+ "typescript": "^5.1.6",
48
+ "webpack": "^5.88.0",
49
+ "webpack-cli": "^5.1.0",
50
+ "terser-webpack-plugin": "^5.3.9",
51
+ "ts-loader": "^9.4.0"
52
+ }
53
+ }
54
+