@tracetail/js 2.3.3 → 2.3.5
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/README.md +247 -156
- package/dist/index.d.ts +7 -26
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +21 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Enterprise browser fingerprinting with **over 99.5% accuracy**. Zero dependencies, TypeScript support, and rock-solid stability.
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/@tracetail/js)
|
|
6
6
|
[](https://www.npmjs.com/package/@tracetail/js)
|
|
7
7
|
[](https://www.typescriptlang.org/)
|
|
8
8
|
[](https://bundlephobia.com/package/@tracetail/js)
|
|
@@ -14,243 +14,334 @@ npm install @tracetail/js
|
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
```javascript
|
|
17
|
-
import
|
|
17
|
+
import TraceTail from '@tracetail/js';
|
|
18
18
|
|
|
19
|
-
// Initialize
|
|
19
|
+
// Initialize with API key
|
|
20
20
|
const tracetail = new TraceTail({
|
|
21
|
-
apiKey: 'your-api-key'
|
|
21
|
+
apiKey: 'your-api-key',
|
|
22
|
+
debug: false
|
|
22
23
|
});
|
|
23
24
|
|
|
24
25
|
// Generate fingerprint
|
|
25
|
-
const
|
|
26
|
-
console.log(
|
|
26
|
+
const result = await tracetail.generateFingerprint();
|
|
27
|
+
console.log('Visitor ID:', result.visitorId);
|
|
28
|
+
console.log('Confidence:', (result.confidence * 100).toFixed(1) + '%');
|
|
27
29
|
```
|
|
28
30
|
|
|
29
31
|
## ✨ Features
|
|
30
32
|
|
|
31
33
|
- **🎯 Over 99.5% accuracy** - Industry-leading device identification
|
|
32
|
-
- **⚡ Zero dependencies** - Lightweight and fast (
|
|
34
|
+
- **⚡ Zero dependencies** - Lightweight and fast (27KB bundle)
|
|
33
35
|
- **🔒 Enterprise security** - Bank-grade fraud detection
|
|
34
36
|
- **📱 Cross-platform** - Works on all browsers and devices
|
|
35
37
|
- **🔧 TypeScript** - Full type safety and IntelliSense
|
|
36
38
|
- **🌐 Incognito consistent** - Same ID across normal and private browsing
|
|
37
|
-
- **🚀 Performance optimized** - <
|
|
39
|
+
- **🚀 Performance optimized** - <25ms fingerprint generation
|
|
38
40
|
|
|
39
|
-
## 📖
|
|
41
|
+
## 📖 API Reference
|
|
40
42
|
|
|
41
|
-
###
|
|
43
|
+
### new TraceTail(options)
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
import { TraceTail } from '@tracetail/js';
|
|
45
|
+
Create a new TraceTail instance.
|
|
45
46
|
|
|
47
|
+
```javascript
|
|
46
48
|
const tracetail = new TraceTail({
|
|
47
|
-
apiKey: '
|
|
48
|
-
endpoint: 'https://
|
|
49
|
+
apiKey: 'tt_live_abc123xyz789', // Required: Your API key
|
|
50
|
+
endpoint: 'https://tracetail.io/api', // Optional: Custom endpoint
|
|
51
|
+
debug: true // Optional: Enable debug logging
|
|
49
52
|
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Parameters:**
|
|
56
|
+
- `apiKey` (string): Your TraceTail API key (required)
|
|
57
|
+
- `endpoint` (string): Custom API endpoint (optional)
|
|
58
|
+
- `debug` (boolean): Enable debug logging (optional)
|
|
59
|
+
|
|
60
|
+
### tracetail.generateFingerprint(options?)
|
|
61
|
+
|
|
62
|
+
Generate a browser fingerprint with visitor identification.
|
|
50
63
|
|
|
51
|
-
|
|
64
|
+
```javascript
|
|
65
|
+
// Basic usage
|
|
52
66
|
const result = await tracetail.generateFingerprint();
|
|
53
67
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
components: result.components // Raw fingerprint components
|
|
68
|
+
// With detailed components
|
|
69
|
+
const detailedResult = await tracetail.generateFingerprint({
|
|
70
|
+
verbose: true // Include raw component data
|
|
58
71
|
});
|
|
59
72
|
```
|
|
60
73
|
|
|
61
|
-
|
|
74
|
+
**Parameters:**
|
|
75
|
+
- `options.verbose` (boolean): Include detailed component data
|
|
76
|
+
|
|
77
|
+
**Returns:** `Promise<FingerprintResult>`
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
interface FingerprintResult {
|
|
81
|
+
visitorId: string; // Unique visitor identifier
|
|
82
|
+
confidence: number; // Accuracy confidence (0-1)
|
|
83
|
+
processingTime: number; // Generation time in milliseconds
|
|
84
|
+
timestamp: string; // ISO timestamp
|
|
85
|
+
version: string; // SDK version (2.3.3)
|
|
86
|
+
signalCount: number; // Number of signals collected
|
|
87
|
+
components?: ComponentData; // Raw signal data (verbose mode)
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### TraceTail.version
|
|
92
|
+
|
|
93
|
+
Get the SDK version (static property).
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
console.log('SDK Version:', TraceTail.version); // "2.3.3"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## 🎯 Usage Examples
|
|
100
|
+
|
|
101
|
+
### Basic Visitor Identification
|
|
62
102
|
|
|
63
103
|
```javascript
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
104
|
+
import TraceTail from '@tracetail/js';
|
|
105
|
+
|
|
106
|
+
// Initialize once
|
|
107
|
+
const tracetail = new TraceTail({
|
|
108
|
+
apiKey: process.env.TRACETAIL_API_KEY
|
|
69
109
|
});
|
|
70
110
|
|
|
111
|
+
// Use throughout your app
|
|
112
|
+
async function identifyVisitor() {
|
|
113
|
+
try {
|
|
114
|
+
const result = await tracetail.generateFingerprint();
|
|
115
|
+
|
|
116
|
+
console.log({
|
|
117
|
+
visitorId: result.visitorId, // "fp_abc123def456"
|
|
118
|
+
confidence: result.confidence, // 0.995 (99.5% accurate)
|
|
119
|
+
processingTime: result.processingTime, // 18ms
|
|
120
|
+
signalCount: result.signalCount // 45 signals collected
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
return result.visitorId;
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error('Fingerprinting failed:', error);
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Advanced Usage with Components
|
|
132
|
+
|
|
133
|
+
```javascript
|
|
134
|
+
// Get detailed fingerprint data
|
|
135
|
+
const detailed = await tracetail.generateFingerprint({ verbose: true });
|
|
136
|
+
|
|
71
137
|
console.log({
|
|
72
|
-
visitorId:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
138
|
+
visitorId: detailed.visitorId,
|
|
139
|
+
confidence: detailed.confidence,
|
|
140
|
+
components: {
|
|
141
|
+
canvas: detailed.components.canvas, // Canvas fingerprint
|
|
142
|
+
webgl: detailed.components.webgl, // WebGL parameters
|
|
143
|
+
audio: detailed.components.audio, // Audio context
|
|
144
|
+
fonts: detailed.components.fonts, // Font detection
|
|
145
|
+
hardware: detailed.components.hardware // Hardware info
|
|
146
|
+
}
|
|
77
147
|
});
|
|
78
148
|
```
|
|
79
149
|
|
|
80
|
-
###
|
|
150
|
+
### Error Handling
|
|
81
151
|
|
|
82
152
|
```javascript
|
|
83
|
-
|
|
84
|
-
|
|
153
|
+
async function safeFingerprinting() {
|
|
154
|
+
try {
|
|
155
|
+
const result = await tracetail.generateFingerprint();
|
|
156
|
+
|
|
157
|
+
if (result.confidence > 0.9) {
|
|
158
|
+
// High confidence - reliable identification
|
|
159
|
+
return result.visitorId;
|
|
160
|
+
} else {
|
|
161
|
+
// Lower confidence - may want to retry or use fallback
|
|
162
|
+
console.warn('Lower confidence fingerprint');
|
|
163
|
+
return result.visitorId;
|
|
164
|
+
}
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.error('Fingerprinting error:', error);
|
|
167
|
+
|
|
168
|
+
// Implement fallback identification
|
|
169
|
+
return generateFallbackId();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Caching Results
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
const CACHE_KEY = 'tracetail_visitor_id';
|
|
178
|
+
const CACHE_TTL = 3600000; // 1 hour
|
|
179
|
+
|
|
180
|
+
async function getCachedFingerprint() {
|
|
181
|
+
// Check cache first
|
|
182
|
+
const cached = localStorage.getItem(CACHE_KEY);
|
|
183
|
+
if (cached) {
|
|
184
|
+
const data = JSON.parse(cached);
|
|
185
|
+
if (Date.now() - data.timestamp < CACHE_TTL) {
|
|
186
|
+
return data.visitorId;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
85
189
|
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
timeout: 10000,
|
|
89
|
-
debug: false,
|
|
90
|
-
caching: true,
|
|
190
|
+
// Generate new fingerprint
|
|
191
|
+
const result = await tracetail.generateFingerprint();
|
|
91
192
|
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
193
|
+
// Cache result
|
|
194
|
+
localStorage.setItem(CACHE_KEY, JSON.stringify({
|
|
195
|
+
visitorId: result.visitorId,
|
|
196
|
+
timestamp: Date.now()
|
|
197
|
+
}));
|
|
96
198
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
batchRequests: true, // Batch multiple calls
|
|
100
|
-
fallbackMode: 'basic' // Fallback when enhanced fails
|
|
101
|
-
});
|
|
199
|
+
return result.visitorId;
|
|
200
|
+
}
|
|
102
201
|
```
|
|
103
202
|
|
|
104
|
-
##
|
|
203
|
+
## 🌐 CDN Usage
|
|
105
204
|
|
|
106
|
-
|
|
205
|
+
For quick integration without NPM:
|
|
107
206
|
|
|
108
|
-
|
|
207
|
+
```html
|
|
208
|
+
<script src="https://tracetail.io/sdk.js"
|
|
209
|
+
data-api-key="your-api-key"></script>
|
|
210
|
+
<script>
|
|
211
|
+
TraceTail.generateFingerprint().then(result => {
|
|
212
|
+
console.log('Visitor ID:', result.visitorId);
|
|
213
|
+
console.log('Confidence:', (result.confidence * 100).toFixed(1) + '%');
|
|
214
|
+
});
|
|
215
|
+
</script>
|
|
216
|
+
```
|
|
109
217
|
|
|
110
|
-
|
|
218
|
+
## 🔧 TypeScript Support
|
|
111
219
|
|
|
112
|
-
|
|
113
|
-
- `options.apiKey` (string, required) - Your TraceTail API key
|
|
114
|
-
- `options.endpoint` (string, optional) - Custom API endpoint
|
|
115
|
-
- `options.timeout` (number, optional) - Request timeout in milliseconds
|
|
116
|
-
- `options.debug` (boolean, optional) - Enable debug logging
|
|
220
|
+
Full TypeScript support with comprehensive type definitions:
|
|
117
221
|
|
|
118
|
-
|
|
222
|
+
```typescript
|
|
223
|
+
import TraceTail, { FingerprintResult, ComponentData } from '@tracetail/js';
|
|
119
224
|
|
|
120
|
-
|
|
225
|
+
// Initialize with types
|
|
226
|
+
const tracetail = new TraceTail({
|
|
227
|
+
apiKey: process.env.TRACETAIL_API_KEY!,
|
|
228
|
+
debug: process.env.NODE_ENV !== 'production'
|
|
229
|
+
});
|
|
121
230
|
|
|
122
|
-
|
|
231
|
+
// Typed results
|
|
232
|
+
const result: FingerprintResult = await tracetail.generateFingerprint();
|
|
123
233
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
processingTime: number;
|
|
129
|
-
components?: Record<string, any>;
|
|
234
|
+
// Type-safe component access
|
|
235
|
+
if (result.components) {
|
|
236
|
+
const canvas: ComponentData = result.components.canvas;
|
|
237
|
+
const webgl: ComponentData = result.components.webgl;
|
|
130
238
|
}
|
|
131
239
|
```
|
|
132
240
|
|
|
133
|
-
|
|
241
|
+
## 🎭 Framework Integrations
|
|
134
242
|
|
|
135
|
-
|
|
243
|
+
### React
|
|
136
244
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
```typescript
|
|
140
|
-
interface EnhancedFingerprintResult extends FingerprintResult {
|
|
141
|
-
riskScore: number;
|
|
142
|
-
threatLevel: 'low' | 'medium' | 'high';
|
|
143
|
-
geolocation?: GeolocationData;
|
|
144
|
-
botProbability: number;
|
|
145
|
-
fraudSignals: string[];
|
|
146
|
-
}
|
|
245
|
+
```bash
|
|
246
|
+
npm install @tracetail/react
|
|
147
247
|
```
|
|
148
248
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
### Fraud Detection
|
|
249
|
+
```tsx
|
|
250
|
+
import { useTraceTail } from '@tracetail/react';
|
|
152
251
|
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
} else if (result.riskScore > 0.3) {
|
|
160
|
-
// Medium risk - monitor closely
|
|
161
|
-
enableExtendedMonitoring();
|
|
252
|
+
function App() {
|
|
253
|
+
const { fingerprint, loading } = useTraceTail({
|
|
254
|
+
apiKey: 'your-api-key'
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
return <div>Visitor: {fingerprint?.visitorId}</div>;
|
|
162
258
|
}
|
|
163
259
|
```
|
|
164
260
|
|
|
165
|
-
###
|
|
261
|
+
### Vue 3
|
|
166
262
|
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
// Track unique visitors without cookies
|
|
171
|
-
analytics.track('page_view', {
|
|
172
|
-
visitorId: fingerprint.visitorId,
|
|
173
|
-
page: window.location.pathname
|
|
174
|
-
});
|
|
263
|
+
```bash
|
|
264
|
+
npm install @tracetail/vue
|
|
175
265
|
```
|
|
176
266
|
|
|
177
|
-
|
|
267
|
+
```vue
|
|
268
|
+
<script setup>
|
|
269
|
+
import { useFingerprint } from '@tracetail/vue';
|
|
178
270
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const currentFingerprint = await tracetail.generateFingerprint();
|
|
182
|
-
const storedFingerprint = localStorage.getItem('userFingerprint');
|
|
271
|
+
const { visitorId, loading } = useFingerprint();
|
|
272
|
+
</script>
|
|
183
273
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
274
|
+
<template>
|
|
275
|
+
<div>Visitor: {{ visitorId }}</div>
|
|
276
|
+
</template>
|
|
188
277
|
```
|
|
189
278
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
TraceTail is designed with privacy in mind:
|
|
279
|
+
### Angular
|
|
193
280
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
- **Secure** - All data encrypted in transit and at rest
|
|
281
|
+
```bash
|
|
282
|
+
npm install @tracetail/angular
|
|
283
|
+
```
|
|
198
284
|
|
|
199
|
-
|
|
285
|
+
```typescript
|
|
286
|
+
import { TraceTailService } from '@tracetail/angular';
|
|
200
287
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
288
|
+
@Component({
|
|
289
|
+
template: `<div>Visitor: {{ fingerprint$ | async | json }}</div>`
|
|
290
|
+
})
|
|
291
|
+
export class MyComponent {
|
|
292
|
+
fingerprint$ = this.traceTail.fingerprint$;
|
|
293
|
+
|
|
294
|
+
constructor(private traceTail: TraceTailService) {}
|
|
295
|
+
}
|
|
296
|
+
```
|
|
206
297
|
|
|
207
|
-
##
|
|
298
|
+
## 🛠️ Development
|
|
208
299
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
- Edge 80+
|
|
213
|
-
- Mobile browsers (iOS Safari 13+, Chrome Mobile 80+)
|
|
300
|
+
```bash
|
|
301
|
+
# Clone repository
|
|
302
|
+
git clone https://github.com/tracetail/tracetail.git
|
|
214
303
|
|
|
215
|
-
|
|
304
|
+
# Install dependencies
|
|
305
|
+
npm install
|
|
216
306
|
|
|
217
|
-
|
|
307
|
+
# Run tests
|
|
308
|
+
npm test
|
|
218
309
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
import FingerprintJS from '@fingerprintjs/fingerprintjs';
|
|
222
|
-
const fp = await FingerprintJS.load();
|
|
223
|
-
const result = await fp.get();
|
|
224
|
-
|
|
225
|
-
// After (TraceTail)
|
|
226
|
-
import { TraceTail } from '@tracetail/js';
|
|
227
|
-
const tracetail = new TraceTail({ apiKey: 'your-key' });
|
|
228
|
-
const result = await tracetail.generateFingerprint();
|
|
310
|
+
# Build package
|
|
311
|
+
npm run build
|
|
229
312
|
```
|
|
230
313
|
|
|
231
|
-
|
|
314
|
+
## 📊 Performance
|
|
232
315
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
316
|
+
- **Bundle Size**: 27KB minified + gzipped
|
|
317
|
+
- **Generation Time**: <25ms average
|
|
318
|
+
- **Accuracy**: >99.5% unique identification
|
|
319
|
+
- **Browser Support**: All modern browsers + IE11
|
|
320
|
+
- **Caching**: Automatic 1-hour local caching
|
|
237
321
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
322
|
+
## 🔒 Privacy & Security
|
|
323
|
+
|
|
324
|
+
- **GDPR Compliant**: No PII collected by default
|
|
325
|
+
- **Secure**: Client-side processing with optional server enhancement
|
|
326
|
+
- **Transparent**: Open source and auditable
|
|
327
|
+
- **Configurable**: Respect user privacy preferences
|
|
241
328
|
|
|
242
|
-
##
|
|
329
|
+
## 📈 Use Cases
|
|
243
330
|
|
|
244
|
-
- **
|
|
245
|
-
- **
|
|
246
|
-
- **
|
|
247
|
-
- **
|
|
248
|
-
- **
|
|
331
|
+
- **Fraud Prevention**: Detect suspicious users and prevent account takeovers
|
|
332
|
+
- **Analytics**: Track unique visitors without cookies
|
|
333
|
+
- **Personalization**: Provide consistent experience across sessions
|
|
334
|
+
- **Security**: Implement device-based authentication
|
|
335
|
+
- **A/B Testing**: Ensure consistent test groups
|
|
249
336
|
|
|
250
|
-
##
|
|
337
|
+
## 🆘 Support
|
|
251
338
|
|
|
252
|
-
|
|
339
|
+
- **Documentation**: [docs.tracetail.io](https://docs.tracetail.io)
|
|
340
|
+
- **API Reference**: [tracetail.io/api/docs](https://tracetail.io/api/docs)
|
|
341
|
+
- **GitHub Issues**: [github.com/tracetail/tracetail/issues](https://github.com/tracetail/tracetail/issues)
|
|
342
|
+
- **Email**: support@tracetail.com
|
|
343
|
+
- **Discord**: [discord.gg/tracetail](https://discord.gg/tracetail)
|
|
253
344
|
|
|
254
|
-
|
|
345
|
+
## 📄 License
|
|
255
346
|
|
|
256
|
-
|
|
347
|
+
MIT - see [LICENSE](LICENSE) for details.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @tracetail/js - Enterprise Browser Fingerprinting SDK
|
|
3
|
-
* Version: 2.3.
|
|
3
|
+
* Version: 2.3.4
|
|
4
4
|
*
|
|
5
|
-
* Over 99.5% accuracy browser fingerprinting with
|
|
5
|
+
* Over 99.5% accuracy browser fingerprinting with server-side processing.
|
|
6
6
|
* Perfect for fraud detection, user analytics, and security applications.
|
|
7
7
|
*/
|
|
8
8
|
export interface FingerprintOptions {
|
|
@@ -24,18 +24,6 @@ export interface FingerprintResult {
|
|
|
24
24
|
processingTime: number;
|
|
25
25
|
components?: ComponentData;
|
|
26
26
|
}
|
|
27
|
-
export interface EnhancedFingerprintResult extends FingerprintResult {
|
|
28
|
-
riskScore: number;
|
|
29
|
-
threatLevel: 'low' | 'medium' | 'high';
|
|
30
|
-
geolocation?: {
|
|
31
|
-
country?: string;
|
|
32
|
-
region?: string;
|
|
33
|
-
city?: string;
|
|
34
|
-
timezone?: string;
|
|
35
|
-
};
|
|
36
|
-
botProbability: number;
|
|
37
|
-
fraudSignals: string[];
|
|
38
|
-
}
|
|
39
27
|
export interface ComponentData {
|
|
40
28
|
canvas?: string;
|
|
41
29
|
webgl?: string;
|
|
@@ -74,26 +62,20 @@ export declare class TraceTail {
|
|
|
74
62
|
private cache;
|
|
75
63
|
constructor(options: FingerprintOptions);
|
|
76
64
|
/**
|
|
77
|
-
* Generate a
|
|
65
|
+
* Generate a browser fingerprint with server-side processing
|
|
78
66
|
*
|
|
79
67
|
* @param options Optional generation parameters
|
|
80
68
|
* @returns Promise resolving to fingerprint result
|
|
81
69
|
*/
|
|
82
70
|
generateFingerprint(options?: {
|
|
83
71
|
timeout?: number;
|
|
84
|
-
|
|
72
|
+
verbose?: boolean;
|
|
85
73
|
}): Promise<FingerprintResult>;
|
|
86
74
|
/**
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* @param options Optional generation parameters
|
|
90
|
-
* @returns Promise resolving to enhanced fingerprint result
|
|
75
|
+
* Send fingerprint components to server for enhanced processing
|
|
76
|
+
* @private
|
|
91
77
|
*/
|
|
92
|
-
|
|
93
|
-
timeout?: number;
|
|
94
|
-
includeComponents?: boolean;
|
|
95
|
-
fraudDetection?: boolean;
|
|
96
|
-
}): Promise<EnhancedFingerprintResult>;
|
|
78
|
+
private sendToServer;
|
|
97
79
|
/**
|
|
98
80
|
* Get the current SDK version
|
|
99
81
|
*/
|
|
@@ -105,7 +87,6 @@ export declare class TraceTail {
|
|
|
105
87
|
private collectComponents;
|
|
106
88
|
private generateVisitorId;
|
|
107
89
|
private calculateConfidence;
|
|
108
|
-
private performServerAnalysis;
|
|
109
90
|
private generateCanvasFingerprint;
|
|
110
91
|
private generateWebGLFingerprint;
|
|
111
92
|
private generateAudioFingerprint;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});class e{constructor(e){if(this.cache=new Map,!e.apiKey)throw new Error("TraceTail: API key is required. Get yours at https://tracetail.io");this.options={apiKey:e.apiKey,endpoint:e.endpoint||"https://
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});class e{constructor(e){if(this.cache=new Map,!e.apiKey)throw new Error("TraceTail: API key is required. Get yours at https://tracetail.io");this.options={apiKey:e.apiKey,endpoint:e.endpoint||"https://tracetail.io/api",timeout:e.timeout||1e4,debug:e.debug||!1,caching:!1!==e.caching,respectDNT:e.respectDNT||!1,includeIP:!1!==e.includeIP,storeFingerprints:!1!==e.storeFingerprints,enableWorkers:!1!==e.enableWorkers,batchRequests:!1!==e.batchRequests,fallbackMode:e.fallbackMode||"basic"},this.log("TraceTail SDK initialized",{version:"2.3.4",options:this.options})}async generateFingerprint(e){const t=performance.now();try{if(this.options.respectDNT&&this.isDNTEnabled())throw new Error("TraceTail: Do Not Track is enabled");const n="basic_fingerprint";if(this.options.caching&&this.cache.has(n)){const e=this.cache.get(n);if(e)return this.log("Using cached fingerprint",e),e}const r=await this.collectComponents(),i=Math.round(performance.now()-t);if(this.options.apiKey&&this.options.endpoint)try{const i=await this.sendToServer(r,null==e?void 0:e.verbose);if(i){const e={...i,processingTime:Math.round(performance.now()-t)};return this.options.caching&&this.cache.set(n,e),this.log("Server-enhanced fingerprint generated",e),e}}catch(e){this.log("Server processing failed, falling back to client-side",e)}const o=await this.generateVisitorId(r),a={visitorId:o,confidence:this.calculateConfidence(r),processingTime:i,...(null==e?void 0:e.verbose)&&{components:r}};return this.options.caching&&this.cache.set(n,a),this.log("Client-side fingerprint generated",a),a}catch(e){throw this.log("Fingerprint generation failed",e),e}}async sendToServer(e,t){try{const n=new AbortController,r=setTimeout(()=>n.abort(),this.options.timeout),i=await fetch(`${this.options.endpoint}/id`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKey}`,"X-TraceTail-SDK":"js/2.3.4"},body:JSON.stringify({components:e,clientCapabilities:{timestamp:Date.now(),sdkVersion:"2.3.4"}}),signal:n.signal});if(clearTimeout(r),!i.ok){if(401===i.status)throw new Error("Invalid API key");throw new Error(`Server returned ${i.status}`)}const o=await i.json();return{visitorId:o.visitorId,confidence:o.confidence,processingTime:o.processingTime||0,...t&&o.components&&{components:o.components}}}catch(e){return this.options.debug&&console.error("[TraceTail] Server error:",e),null}}static getVersion(){return"2.3.4"}static validateApiKey(e){return/^tt_(test|prod)_[a-zA-Z0-9]{32,}$/.test(e)}async collectComponents(){const e={};try{e.screen={width:screen.width,height:screen.height,colorDepth:screen.colorDepth,pixelRatio:window.devicePixelRatio||1},e.timezone=Intl.DateTimeFormat().resolvedOptions().timeZone,e.language=navigator.language,e.platform=navigator.platform,e.userAgent=navigator.userAgent,e.cookiesEnabled=navigator.cookieEnabled,e.localStorage=this.testStorage("localStorage"),e.sessionStorage=this.testStorage("sessionStorage"),e.indexedDB="indexedDB"in window,e.canvas=await this.generateCanvasFingerprint(),e.webgl=this.generateWebGLFingerprint(),e.audio=await this.generateAudioFingerprint(),e.fonts=this.detectFonts(),e.webRTC=await this.generateWebRTCFingerprint()}catch(e){this.log("Component collection error",e)}return e}async generateVisitorId(e){const t=JSON.stringify(e,Object.keys(e).sort()),n=(new TextEncoder).encode(t),r=await crypto.subtle.digest("SHA-256",n);return`fp_${Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,"0")).join("").substring(0,32)}`}calculateConfidence(e){let t=0,n=0;const r={canvas:.25,webgl:.2,audio:.15,fonts:.15,screen:.1,webRTC:.15};for(const[i,o]of Object.entries(r))n+=o,e[i]&&(t+=o);return Math.min(.995,Math.max(.7,t/n))}async generateCanvasFingerprint(){try{const e=document.createElement("canvas"),t=e.getContext("2d");return t?(e.width=200,e.height=50,t.textBaseline="top",t.font="14px Arial",t.fillStyle="#f60",t.fillRect(125,1,62,20),t.fillStyle="#069",t.fillText("TraceTail 🔒",2,15),t.fillStyle="rgba(102, 204, 0, 0.2)",t.fillText("TraceTail 🔒",4,17),e.toDataURL().substring(0,100)):"unsupported"}catch(e){return"error"}}generateWebGLFingerprint(){try{const e=document.createElement("canvas"),t=e.getContext("webgl")||e.getContext("experimental-webgl");if(!t)return"unsupported";const n=t.getParameter(t.RENDERER);return`${t.getParameter(t.VENDOR)}-${n}`.substring(0,100)}catch(e){return"error"}}async generateAudioFingerprint(){try{const e=window.AudioContext||window.webkitAudioContext;if(!e)return"unsupported";const t=new e,n=t.createOscillator(),r=t.createAnalyser();n.connect(r),r.connect(t.destination);const i=new Float32Array(r.frequencyBinCount);return r.getFloatFrequencyData(i),await t.close(),Array.from(i.slice(0,10)).join(",")}catch(e){return"error"}}detectFonts(){const e=["Arial","Helvetica","Times","Courier","Verdana","Georgia","Palatino","Garamond","Bookman","Comic Sans MS","Trebuchet MS","Arial Black","Impact"],t=[],n=document.createElement("div");n.style.position="absolute",n.style.left="-9999px",document.body.appendChild(n);try{for(const r of e){const e=document.createElement("span");e.style.fontSize="72px",e.style.fontFamily=r,e.textContent="mmmmmmmmmmlli",n.appendChild(e),e.offsetWidth>0&&t.push(r)}}finally{document.body.removeChild(n)}return t}async generateWebRTCFingerprint(){var e;try{if(!window.RTCPeerConnection)return"unsupported";const t=new RTCPeerConnection({iceServers:[{urls:"stun:stun.l.google.com:19302"}]});t.createDataChannel("test");await t.createOffer();const n=t.localDescription;return t.close(),(null===(e=null==n?void 0:n.sdp)||void 0===e?void 0:e.substring(0,100))||"error"}catch(e){return"error"}}testStorage(e){try{const t=window[e],n="__tt_test__";return t.setItem(n,"test"),t.removeItem(n),!0}catch(e){return!1}}isDNTEnabled(){return"1"===navigator.doNotTrack||"1"===window.doNotTrack||"1"===navigator.msDoNotTrack}log(e,t){this.options.debug&&console.log(`[TraceTail] ${e}`,t)}}exports.TraceTail=e,exports.default=e;
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
class e{constructor(e){if(this.cache=new Map,!e.apiKey)throw new Error("TraceTail: API key is required. Get yours at https://tracetail.io");this.options={apiKey:e.apiKey,endpoint:e.endpoint||"https://
|
|
1
|
+
class e{constructor(e){if(this.cache=new Map,!e.apiKey)throw new Error("TraceTail: API key is required. Get yours at https://tracetail.io");this.options={apiKey:e.apiKey,endpoint:e.endpoint||"https://tracetail.io/api",timeout:e.timeout||1e4,debug:e.debug||!1,caching:!1!==e.caching,respectDNT:e.respectDNT||!1,includeIP:!1!==e.includeIP,storeFingerprints:!1!==e.storeFingerprints,enableWorkers:!1!==e.enableWorkers,batchRequests:!1!==e.batchRequests,fallbackMode:e.fallbackMode||"basic"},this.log("TraceTail SDK initialized",{version:"2.3.4",options:this.options})}async generateFingerprint(e){const t=performance.now();try{if(this.options.respectDNT&&this.isDNTEnabled())throw new Error("TraceTail: Do Not Track is enabled");const n="basic_fingerprint";if(this.options.caching&&this.cache.has(n)){const e=this.cache.get(n);if(e)return this.log("Using cached fingerprint",e),e}const r=await this.collectComponents(),i=Math.round(performance.now()-t);if(this.options.apiKey&&this.options.endpoint)try{const i=await this.sendToServer(r,null==e?void 0:e.verbose);if(i){const e={...i,processingTime:Math.round(performance.now()-t)};return this.options.caching&&this.cache.set(n,e),this.log("Server-enhanced fingerprint generated",e),e}}catch(e){this.log("Server processing failed, falling back to client-side",e)}const o=await this.generateVisitorId(r),a={visitorId:o,confidence:this.calculateConfidence(r),processingTime:i,...(null==e?void 0:e.verbose)&&{components:r}};return this.options.caching&&this.cache.set(n,a),this.log("Client-side fingerprint generated",a),a}catch(e){throw this.log("Fingerprint generation failed",e),e}}async sendToServer(e,t){try{const n=new AbortController,r=setTimeout(()=>n.abort(),this.options.timeout),i=await fetch(`${this.options.endpoint}/id`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKey}`,"X-TraceTail-SDK":"js/2.3.4"},body:JSON.stringify({components:e,clientCapabilities:{timestamp:Date.now(),sdkVersion:"2.3.4"}}),signal:n.signal});if(clearTimeout(r),!i.ok){if(401===i.status)throw new Error("Invalid API key");throw new Error(`Server returned ${i.status}`)}const o=await i.json();return{visitorId:o.visitorId,confidence:o.confidence,processingTime:o.processingTime||0,...t&&o.components&&{components:o.components}}}catch(e){return this.options.debug&&console.error("[TraceTail] Server error:",e),null}}static getVersion(){return"2.3.4"}static validateApiKey(e){return/^tt_(test|prod)_[a-zA-Z0-9]{32,}$/.test(e)}async collectComponents(){const e={};try{e.screen={width:screen.width,height:screen.height,colorDepth:screen.colorDepth,pixelRatio:window.devicePixelRatio||1},e.timezone=Intl.DateTimeFormat().resolvedOptions().timeZone,e.language=navigator.language,e.platform=navigator.platform,e.userAgent=navigator.userAgent,e.cookiesEnabled=navigator.cookieEnabled,e.localStorage=this.testStorage("localStorage"),e.sessionStorage=this.testStorage("sessionStorage"),e.indexedDB="indexedDB"in window,e.canvas=await this.generateCanvasFingerprint(),e.webgl=this.generateWebGLFingerprint(),e.audio=await this.generateAudioFingerprint(),e.fonts=this.detectFonts(),e.webRTC=await this.generateWebRTCFingerprint()}catch(e){this.log("Component collection error",e)}return e}async generateVisitorId(e){const t=JSON.stringify(e,Object.keys(e).sort()),n=(new TextEncoder).encode(t),r=await crypto.subtle.digest("SHA-256",n);return`fp_${Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,"0")).join("").substring(0,32)}`}calculateConfidence(e){let t=0,n=0;const r={canvas:.25,webgl:.2,audio:.15,fonts:.15,screen:.1,webRTC:.15};for(const[i,o]of Object.entries(r))n+=o,e[i]&&(t+=o);return Math.min(.995,Math.max(.7,t/n))}async generateCanvasFingerprint(){try{const e=document.createElement("canvas"),t=e.getContext("2d");return t?(e.width=200,e.height=50,t.textBaseline="top",t.font="14px Arial",t.fillStyle="#f60",t.fillRect(125,1,62,20),t.fillStyle="#069",t.fillText("TraceTail 🔒",2,15),t.fillStyle="rgba(102, 204, 0, 0.2)",t.fillText("TraceTail 🔒",4,17),e.toDataURL().substring(0,100)):"unsupported"}catch(e){return"error"}}generateWebGLFingerprint(){try{const e=document.createElement("canvas"),t=e.getContext("webgl")||e.getContext("experimental-webgl");if(!t)return"unsupported";const n=t.getParameter(t.RENDERER);return`${t.getParameter(t.VENDOR)}-${n}`.substring(0,100)}catch(e){return"error"}}async generateAudioFingerprint(){try{const e=window.AudioContext||window.webkitAudioContext;if(!e)return"unsupported";const t=new e,n=t.createOscillator(),r=t.createAnalyser();n.connect(r),r.connect(t.destination);const i=new Float32Array(r.frequencyBinCount);return r.getFloatFrequencyData(i),await t.close(),Array.from(i.slice(0,10)).join(",")}catch(e){return"error"}}detectFonts(){const e=["Arial","Helvetica","Times","Courier","Verdana","Georgia","Palatino","Garamond","Bookman","Comic Sans MS","Trebuchet MS","Arial Black","Impact"],t=[],n=document.createElement("div");n.style.position="absolute",n.style.left="-9999px",document.body.appendChild(n);try{for(const r of e){const e=document.createElement("span");e.style.fontSize="72px",e.style.fontFamily=r,e.textContent="mmmmmmmmmmlli",n.appendChild(e),e.offsetWidth>0&&t.push(r)}}finally{document.body.removeChild(n)}return t}async generateWebRTCFingerprint(){var e;try{if(!window.RTCPeerConnection)return"unsupported";const t=new RTCPeerConnection({iceServers:[{urls:"stun:stun.l.google.com:19302"}]});t.createDataChannel("test");await t.createOffer();const n=t.localDescription;return t.close(),(null===(e=null==n?void 0:n.sdp)||void 0===e?void 0:e.substring(0,100))||"error"}catch(e){return"error"}}testStorage(e){try{const t=window[e],n="__tt_test__";return t.setItem(n,"test"),t.removeItem(n),!0}catch(e){return!1}}isDNTEnabled(){return"1"===navigator.doNotTrack||"1"===window.doNotTrack||"1"===navigator.msDoNotTrack}log(e,t){this.options.debug&&console.log(`[TraceTail] ${e}`,t)}}export{e as TraceTail,e as default};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tracetail/js",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.5",
|
|
4
4
|
"description": "TraceTail JavaScript SDK for browser fingerprinting",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -13,7 +13,25 @@
|
|
|
13
13
|
"build": "rollup -c",
|
|
14
14
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
15
15
|
},
|
|
16
|
-
"homepage": "https://tracetail.io",
|
|
16
|
+
"homepage": "https://demo-js.tracetail.io",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/tracetail/tracetail-js.git",
|
|
20
|
+
"directory": "packages/js"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/tracetail/tracetail-js/issues"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"browser-fingerprinting",
|
|
27
|
+
"fraud-detection",
|
|
28
|
+
"device-identification",
|
|
29
|
+
"tracetail",
|
|
30
|
+
"javascript",
|
|
31
|
+
"fingerprinting",
|
|
32
|
+
"security",
|
|
33
|
+
"live-demo"
|
|
34
|
+
],
|
|
17
35
|
"author": "TraceTail",
|
|
18
36
|
"license": "MIT",
|
|
19
37
|
"devDependencies": {
|
|
@@ -22,4 +40,4 @@
|
|
|
22
40
|
"@rollup/plugin-terser": "^0.4.4",
|
|
23
41
|
"typescript": "^5.3.3"
|
|
24
42
|
}
|
|
25
|
-
}
|
|
43
|
+
}
|