@tracetail/angular 2.3.3

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,179 @@
1
+ import { Injectable, Inject } from '@angular/core';
2
+ import { BehaviorSubject } from 'rxjs';
3
+ import TraceTail from '@tracetail/js';
4
+ import { TRACETAIL_CONFIG } from './tracetail.config';
5
+ import * as i0 from "@angular/core";
6
+ export class TraceTailService {
7
+ config;
8
+ client;
9
+ fingerprintSubject = new BehaviorSubject(null);
10
+ loadingSubject = new BehaviorSubject(true);
11
+ errorSubject = new BehaviorSubject(null);
12
+ fingerprint$ = this.fingerprintSubject.asObservable();
13
+ loading$ = this.loadingSubject.asObservable();
14
+ error$ = this.errorSubject.asObservable();
15
+ constructor(config) {
16
+ this.config = config;
17
+ this.initializeClient();
18
+ }
19
+ initializeClient() {
20
+ try {
21
+ // Handle test mode
22
+ if (this.config.config?.testMode && this.config.config.mockData) {
23
+ this.fingerprintSubject.next({
24
+ visitorId: 'mock-visitor-123',
25
+ confidence: 0.99,
26
+ riskScore: 0.1,
27
+ fraudulent: false,
28
+ signals: {},
29
+ timestamp: new Date(),
30
+ ...this.config.config.mockData
31
+ });
32
+ this.loadingSubject.next(false);
33
+ return;
34
+ }
35
+ // Initialize real client
36
+ this.client = new TraceTail({
37
+ apiKey: this.config.apiKey,
38
+ timeout: this.config.config?.timeout,
39
+ debug: this.config.config?.debug || false
40
+ });
41
+ // Get initial fingerprint
42
+ this.loadFingerprint();
43
+ }
44
+ catch (error) {
45
+ this.handleError(error);
46
+ }
47
+ }
48
+ async loadFingerprint() {
49
+ try {
50
+ this.loadingSubject.next(true);
51
+ this.errorSubject.next(null);
52
+ const result = await this.client.generateFingerprint();
53
+ const fingerprint = {
54
+ visitorId: result.visitorId,
55
+ confidence: result.confidence,
56
+ riskScore: 0,
57
+ fraudulent: false,
58
+ signals: result.components || {},
59
+ timestamp: new Date()
60
+ };
61
+ this.fingerprintSubject.next(fingerprint);
62
+ this.loadingSubject.next(false);
63
+ }
64
+ catch (error) {
65
+ this.handleError(error);
66
+ }
67
+ }
68
+ handleError(error) {
69
+ console.error('TraceTail error:', error);
70
+ this.errorSubject.next(error);
71
+ this.loadingSubject.next(false);
72
+ }
73
+ /**
74
+ * Get current fingerprint as a promise
75
+ */
76
+ async getFingerprint() {
77
+ const current = this.fingerprintSubject.value;
78
+ if (current) {
79
+ return current;
80
+ }
81
+ // Wait for fingerprint to be loaded
82
+ return new Promise((resolve, reject) => {
83
+ const subscription = this.fingerprint$.subscribe({
84
+ next: (fingerprint) => {
85
+ if (fingerprint) {
86
+ subscription.unsubscribe();
87
+ resolve(fingerprint);
88
+ }
89
+ },
90
+ error: (error) => {
91
+ subscription.unsubscribe();
92
+ reject(error);
93
+ }
94
+ });
95
+ });
96
+ }
97
+ /**
98
+ * Track an event
99
+ */
100
+ async trackEvent(event, data) {
101
+ try {
102
+ // TraceTail doesn't have a track method - this is custom app functionality
103
+ // For now, just return mock data with a generated event ID
104
+ const eventId = `evt_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
105
+ return {
106
+ success: true,
107
+ fraudulent: false,
108
+ riskScore: 0,
109
+ eventId: eventId
110
+ };
111
+ }
112
+ catch (error) {
113
+ console.error('Track event error:', error);
114
+ throw error;
115
+ }
116
+ }
117
+ /**
118
+ * Check for fraud
119
+ */
120
+ async checkFraud(data) {
121
+ try {
122
+ const fingerprint = await this.getFingerprint();
123
+ // Simple fraud detection logic based on risk score
124
+ const block = fingerprint.riskScore > 0.8;
125
+ const challenge = fingerprint.riskScore > 0.5 && fingerprint.riskScore <= 0.8;
126
+ const allow = fingerprint.riskScore <= 0.5;
127
+ const reasons = [];
128
+ if (fingerprint.signals.vpn)
129
+ reasons.push('VPN detected');
130
+ if (fingerprint.signals.tor)
131
+ reasons.push('Tor browser detected');
132
+ if (fingerprint.signals.proxy)
133
+ reasons.push('Proxy detected');
134
+ if (fingerprint.riskScore > 0.7)
135
+ reasons.push('High risk score');
136
+ return {
137
+ block,
138
+ challenge,
139
+ allow,
140
+ riskScore: fingerprint.riskScore,
141
+ reasons
142
+ };
143
+ }
144
+ catch (error) {
145
+ console.error('Fraud check error:', error);
146
+ throw error;
147
+ }
148
+ }
149
+ /**
150
+ * Retry fingerprinting
151
+ */
152
+ retry() {
153
+ this.loadFingerprint();
154
+ }
155
+ /**
156
+ * Force refresh fingerprint
157
+ */
158
+ async refresh() {
159
+ await this.loadFingerprint();
160
+ }
161
+ /**
162
+ * Get raw TraceTail client instance
163
+ */
164
+ getClient() {
165
+ return this.client;
166
+ }
167
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TraceTailService, deps: [{ token: TRACETAIL_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable });
168
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TraceTailService, providedIn: 'root' });
169
+ }
170
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TraceTailService, decorators: [{
171
+ type: Injectable,
172
+ args: [{
173
+ providedIn: 'root'
174
+ }]
175
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
176
+ type: Inject,
177
+ args: [TRACETAIL_CONFIG]
178
+ }] }] });
179
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhY2V0YWlsLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3RyYWNldGFpbC5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFBRSxlQUFlLEVBQXdCLE1BQU0sTUFBTSxDQUFDO0FBRTdELE9BQU8sU0FBUyxNQUFNLGVBQWUsQ0FBQztBQUN0QyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQzs7QUFXdEQsTUFBTSxPQUFPLGdCQUFnQjtJQVVtQjtJQVR0QyxNQUFNLENBQVk7SUFDbEIsa0JBQWtCLEdBQUcsSUFBSSxlQUFlLENBQXFCLElBQUksQ0FBQyxDQUFDO0lBQ25FLGNBQWMsR0FBRyxJQUFJLGVBQWUsQ0FBVSxJQUFJLENBQUMsQ0FBQztJQUNwRCxZQUFZLEdBQUcsSUFBSSxlQUFlLENBQWUsSUFBSSxDQUFDLENBQUM7SUFFL0QsWUFBWSxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUN0RCxRQUFRLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUM5QyxNQUFNLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUUxQyxZQUE4QyxNQUF1QjtRQUF2QixXQUFNLEdBQU4sTUFBTSxDQUFpQjtRQUNuRSxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztJQUMxQixDQUFDO0lBRU8sZ0JBQWdCO1FBQ3RCLElBQUk7WUFDRixtQkFBbUI7WUFDbkIsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxRQUFRLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFO2dCQUMvRCxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDO29C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dGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBJbmplY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgT2JzZXJ2YWJsZSwgZnJvbSwgb2YgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGNhdGNoRXJyb3IsIHNoYXJlUmVwbGF5LCB0YXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgVHJhY2VUYWlsIGZyb20gJ0B0cmFjZXRhaWwvanMnO1xuaW1wb3J0IHsgVFJBQ0VUQUlMX0NPTkZJRyB9IGZyb20gJy4vdHJhY2V0YWlsLmNvbmZpZyc7XG5pbXBvcnQgeyBcbiAgVHJhY2VUYWlsQ29uZmlnLCBcbiAgRmluZ2VycHJpbnQsIFxuICBUcmFja2luZ1Jlc3VsdCwgXG4gIEZyYXVkUmVzdWx0IFxufSBmcm9tICcuL3RyYWNldGFpbC50eXBlcyc7XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIFRyYWNlVGFpbFNlcnZpY2Uge1xuICBwcml2YXRlIGNsaWVudDogVHJhY2VUYWlsO1xuICBwcml2YXRlIGZpbmdlcnByaW50U3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8RmluZ2VycHJpbnQgfCBudWxsPihudWxsKTtcbiAgcHJpdmF0ZSBsb2FkaW5nU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4odHJ1ZSk7XG4gIHByaXZhdGUgZXJyb3JTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxFcnJvciB8IG51bGw+KG51bGwpO1xuXG4gIGZpbmdlcnByaW50JCA9IHRoaXMuZmluZ2VycHJpbnRTdWJqZWN0LmFzT2JzZXJ2YWJsZSgpO1xuICBsb2FkaW5nJCA9IHRoaXMubG9hZGluZ1N1YmplY3QuYXNPYnNlcnZhYmxlKCk7XG4gIGVycm9yJCA9IHRoaXMuZXJyb3JTdWJqZWN0LmFzT2JzZXJ2YWJsZSgpO1xuXG4gIGNvbnN0cnVjdG9yKEBJbmplY3QoVFJBQ0VUQUlMX0NPTkZJRykgcHJpdmF0ZSBjb25maWc6IFRyYWNlVGFpbENvbmZpZykge1xuICAgIHRoaXMuaW5pdGlhbGl6ZUNsaWVudCgpO1xuICB9XG5cbiAgcHJpdmF0ZSBpbml0aWFsaXplQ2xpZW50KCk6IHZvaWQge1xuICAgIHRyeSB7XG4gICAgICAvLyBIYW5kbGUgdGVzdCBtb2RlXG4gICAgICBpZiAodGhpcy5jb25maWcuY29uZmlnPy50ZXN0TW9kZSAmJiB0aGlzLmNvbmZpZy5jb25maWcubW9ja0RhdGEpIHtcbiAgICAgICAgdGhpcy5maW5nZXJwcmludFN1YmplY3QubmV4dCh7XG4gICAgICAgICAgdmlzaXRvcklkOiAnbW9jay12aXNpdG9yLTEyMycsXG4gICAgICAgICAgY29uZmlkZW5jZTogMC45OSxcbiAgICAgICAgICByaXNrU2NvcmU6IDAuMSxcbiAgICAgICAgICBmcmF1ZHVsZW50OiBmYWxzZSxcbiAgICAgICAgICBzaWduYWxzOiB7fSBhcyBhbnksXG4gICAgICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLFxuICAgICAgICAgIC4uLnRoaXMuY29uZmlnLmNvbmZpZy5tb2NrRGF0YVxuICAgICAgICB9IGFzIEZpbmdlcnByaW50KTtcbiAgICAgICAgdGhpcy5sb2FkaW5nU3ViamVjdC5uZXh0KGZhbHNlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICAvLyBJbml0aWFsaXplIHJlYWwgY2xpZW50XG4gICAgICB0aGlzLmNsaWVudCA9IG5ldyBUcmFjZVRhaWwoe1xuICAgICAgICBhcGlLZXk6IHRoaXMuY29uZmlnLmFwaUtleSxcbiAgICAgICAgdGltZW91dDogdGhpcy5jb25maWcuY29uZmlnPy50aW1lb3V0LFxuICAgICAgICBkZWJ1ZzogdGhpcy5jb25maWcuY29uZmlnPy5kZWJ1ZyB8fCBmYWxzZVxuICAgICAgfSk7XG5cbiAgICAgIC8vIEdldCBpbml0aWFsIGZpbmdlcnByaW50XG4gICAgICB0aGlzLmxvYWRGaW5nZXJwcmludCgpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLmhhbmRsZUVycm9yKGVycm9yIGFzIEVycm9yKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGxvYWRGaW5nZXJwcmludCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgdGhpcy5sb2FkaW5nU3ViamVjdC5uZXh0KHRydWUpO1xuICAgICAgdGhpcy5lcnJvclN1YmplY3QubmV4dChudWxsKTtcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5jbGllbnQuZ2VuZXJhdGVGaW5nZXJwcmludCgpO1xuICAgICAgXG4gICAgICBjb25zdCBmaW5nZXJwcmludDogRmluZ2VycHJpbnQgPSB7XG4gICAgICAgIHZpc2l0b3JJZDogcmVzdWx0LnZpc2l0b3JJZCxcbiAgICAgICAgY29uZmlkZW5jZTogcmVzdWx0LmNvbmZpZGVuY2UsXG4gICAgICAgIHJpc2tTY29yZTogMCwgIC8vIERlZmF1bHQgdmFsdWUgLSBub3QgaW4gYmFzZSBTREtcbiAgICAgICAgZnJhdWR1bGVudDogZmFsc2UsICAvLyBEZWZhdWx0IHZhbHVlIC0gbm90IGluIGJhc2UgU0RLICBcbiAgICAgICAgc2lnbmFsczogcmVzdWx0LmNvbXBvbmVudHMgfHwge30gYXMgYW55LFxuICAgICAgICB0aW1lc3RhbXA6IG5ldyBEYXRlKClcbiAgICAgIH07XG5cbiAgICAgIHRoaXMuZmluZ2VycHJpbnRTdWJqZWN0Lm5leHQoZmluZ2VycHJpbnQpO1xuICAgICAgdGhpcy5sb2FkaW5nU3ViamVjdC5uZXh0KGZhbHNlKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5oYW5kbGVFcnJvcihlcnJvciBhcyBFcnJvcik7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVFcnJvcihlcnJvcjogRXJyb3IpOiB2b2lkIHtcbiAgICBjb25zb2xlLmVycm9yKCdUcmFjZVRhaWwgZXJyb3I6JywgZXJyb3IpO1xuICAgIHRoaXMuZXJyb3JTdWJqZWN0Lm5leHQoZXJyb3IpO1xuICAgIHRoaXMubG9hZGluZ1N1YmplY3QubmV4dChmYWxzZSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGN1cnJlbnQgZmluZ2VycHJpbnQgYXMgYSBwcm9taXNlXG4gICAqL1xuICBhc3luYyBnZXRGaW5nZXJwcmludCgpOiBQcm9taXNlPEZpbmdlcnByaW50PiB7XG4gICAgY29uc3QgY3VycmVudCA9IHRoaXMuZmluZ2VycHJpbnRTdWJqZWN0LnZhbHVlO1xuICAgIGlmIChjdXJyZW50KSB7XG4gICAgICByZXR1cm4gY3VycmVudDtcbiAgICB9XG5cbiAgICAvLyBXYWl0IGZvciBmaW5nZXJwcmludCB0byBiZSBsb2FkZWRcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3Qgc3Vic2NyaXB0aW9uID0gdGhpcy5maW5nZXJwcmludCQuc3Vic2NyaWJlKHtcbiAgICAgICAgbmV4dDogKGZpbmdlcnByaW50KSA9PiB7XG4gICAgICAgICAgaWYgKGZpbmdlcnByaW50KSB7XG4gICAgICAgICAgICBzdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICAgICAgICAgIHJlc29sdmUoZmluZ2VycHJpbnQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgZXJyb3I6IChlcnJvcikgPT4ge1xuICAgICAgICAgIHN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyYWNrIGFuIGV2ZW50XG4gICAqL1xuICBhc3luYyB0cmFja0V2ZW50KGV2ZW50OiBzdHJpbmcsIGRhdGE/OiBhbnkpOiBQcm9taXNlPFRyYWNraW5nUmVzdWx0PiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIFRyYWNlVGFpbCBkb2Vzbid0IGhhdmUgYSB0cmFjayBtZXRob2QgLSB0aGlzIGlzIGN1c3RvbSBhcHAgZnVuY3Rpb25hbGl0eVxuICAgICAgLy8gRm9yIG5vdywganVzdCByZXR1cm4gbW9jayBkYXRhIHdpdGggYSBnZW5lcmF0ZWQgZXZlbnQgSURcbiAgICAgIGNvbnN0IGV2ZW50SWQgPSBgZXZ0XyR7RGF0ZS5ub3coKX1fJHtNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDM2KS5zdWJzdHIoMiwgOSl9YDtcbiAgICAgIFxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgZnJhdWR1bGVudDogZmFsc2UsXG4gICAgICAgIHJpc2tTY29yZTogMCxcbiAgICAgICAgZXZlbnRJZDogZXZlbnRJZFxuICAgICAgfTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignVHJhY2sgZXZlbnQgZXJyb3I6JywgZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGZvciBmcmF1ZFxuICAgKi9cbiAgYXN5bmMgY2hlY2tGcmF1ZChkYXRhOiBhbnkpOiBQcm9taXNlPEZyYXVkUmVzdWx0PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGZpbmdlcnByaW50ID0gYXdhaXQgdGhpcy5nZXRGaW5nZXJwcmludCgpO1xuICAgICAgXG4gICAgICAvLyBTaW1wbGUgZnJhdWQgZGV0ZWN0aW9uIGxvZ2ljIGJhc2VkIG9uIHJpc2sgc2NvcmVcbiAgICAgIGNvbnN0IGJsb2NrID0gZmluZ2VycHJpbnQucmlza1Njb3JlID4gMC44O1xuICAgICAgY29uc3QgY2hhbGxlbmdlID0gZmluZ2VycHJpbnQucmlza1Njb3JlID4gMC41ICYmIGZpbmdlcnByaW50LnJpc2tTY29yZSA8PSAwLjg7XG4gICAgICBjb25zdCBhbGxvdyA9IGZpbmdlcnByaW50LnJpc2tTY29yZSA8PSAwLjU7XG4gICAgICBcbiAgICAgIGNvbnN0IHJlYXNvbnM6IHN0cmluZ1tdID0gW107XG4gICAgICBpZiAoZmluZ2VycHJpbnQuc2lnbmFscy52cG4pIHJlYXNvbnMucHVzaCgnVlBOIGRldGVjdGVkJyk7XG4gICAgICBpZiAoZmluZ2VycHJpbnQuc2lnbmFscy50b3IpIHJlYXNvbnMucHVzaCgnVG9yIGJyb3dzZXIgZGV0ZWN0ZWQnKTtcbiAgICAgIGlmIChmaW5nZXJwcmludC5zaWduYWxzLnByb3h5KSByZWFzb25zLnB1c2goJ1Byb3h5IGRldGVjdGVkJyk7XG4gICAgICBpZiAoZmluZ2VycHJpbnQucmlza1Njb3JlID4gMC43KSByZWFzb25zLnB1c2goJ0hpZ2ggcmlzayBzY29yZScpO1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBibG9jayxcbiAgICAgICAgY2hhbGxlbmdlLFxuICAgICAgICBhbGxvdyxcbiAgICAgICAgcmlza1Njb3JlOiBmaW5nZXJwcmludC5yaXNrU2NvcmUsXG4gICAgICAgIHJlYXNvbnNcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0ZyYXVkIGNoZWNrIGVycm9yOicsIGVycm9yKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyeSBmaW5nZXJwcmludGluZ1xuICAgKi9cbiAgcmV0cnkoKTogdm9pZCB7XG4gICAgdGhpcy5sb2FkRmluZ2VycHJpbnQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGb3JjZSByZWZyZXNoIGZpbmdlcnByaW50XG4gICAqL1xuICBhc3luYyByZWZyZXNoKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMubG9hZEZpbmdlcnByaW50KCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHJhdyBUcmFjZVRhaWwgY2xpZW50IGluc3RhbmNlXG4gICAqL1xuICBnZXRDbGllbnQoKTogVHJhY2VUYWlsIHtcbiAgICByZXR1cm4gdGhpcy5jbGllbnQ7XG4gIH1cbn0iXX0=
@@ -0,0 +1,5 @@
1
+ /**
2
+ * TraceTail types for Angular
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhY2V0YWlsLnR5cGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi90cmFjZXRhaWwudHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUciLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFRyYWNlVGFpbCB0eXBlcyBmb3IgQW5ndWxhclxuICovXG5cbmV4cG9ydCBpbnRlcmZhY2UgRmluZ2VycHJpbnQge1xuICB2aXNpdG9ySWQ6IHN0cmluZztcbiAgY29uZmlkZW5jZTogbnVtYmVyO1xuICByaXNrU2NvcmU6IG51bWJlcjtcbiAgZnJhdWR1bGVudDogYm9vbGVhbjtcbiAgc2lnbmFsczogU2lnbmFsRGF0YTtcbiAgdGltZXN0YW1wOiBEYXRlO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNpZ25hbERhdGEge1xuICBicm93c2VyOiBzdHJpbmc7XG4gIG9zOiBzdHJpbmc7XG4gIGRldmljZTogc3RyaW5nO1xuICBzY3JlZW46IHtcbiAgICB3aWR0aDogbnVtYmVyO1xuICAgIGhlaWdodDogbnVtYmVyO1xuICAgIGNvbG9yRGVwdGg6IG51bWJlcjtcbiAgfTtcbiAgdGltZXpvbmU6IHN0cmluZztcbiAgbGFuZ3VhZ2U6IHN0cmluZztcbiAgcGx1Z2luczogc3RyaW5nW107XG4gIGZvbnRzOiBzdHJpbmdbXTtcbiAgY2FudmFzOiBzdHJpbmc7XG4gIHdlYmdsOiBzdHJpbmc7XG4gIGF1ZGlvOiBzdHJpbmc7XG4gIHZwbjogYm9vbGVhbjtcbiAgdG9yOiBib29sZWFuO1xuICBwcm94eTogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUcmFja2luZ1Jlc3VsdCB7XG4gIHN1Y2Nlc3M6IGJvb2xlYW47XG4gIGZyYXVkdWxlbnQ6IGJvb2xlYW47XG4gIHJpc2tTY29yZTogbnVtYmVyO1xuICBldmVudElkOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRnJhdWRSZXN1bHQge1xuICBibG9jazogYm9vbGVhbjtcbiAgY2hhbGxlbmdlOiBib29sZWFuO1xuICBhbGxvdzogYm9vbGVhbjtcbiAgcmlza1Njb3JlOiBudW1iZXI7XG4gIHJlYXNvbnM6IHN0cmluZ1tdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRyYWNlVGFpbENvbmZpZyB7XG4gIGFwaUtleTogc3RyaW5nO1xuICBjb25maWc/OiB7XG4gICAgZW5oYW5jZWQ/OiBib29sZWFuO1xuICAgIHRpbWVvdXQ/OiBudW1iZXI7XG4gICAgZW5kcG9pbnQ/OiBzdHJpbmc7XG4gICAgZGVidWc/OiBib29sZWFuO1xuICAgIHRlc3RNb2RlPzogYm9vbGVhbjtcbiAgICBtb2NrRGF0YT86IFBhcnRpYWw8RmluZ2VycHJpbnQ+O1xuICB9O1xufSJdfQ==
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Public API Surface of @tracetail/angular
3
+ */
4
+ export * from './lib/tracetail.module';
5
+ export * from './lib/tracetail.service';
6
+ export * from './lib/tracetail.config';
7
+ export * from './lib/tracetail.types';
8
+ export * from './lib/directives/fraud-detection.directive';
9
+ export * from './lib/interceptors/tracetail.interceptor';
10
+ export * from './lib/guards/fraud-protection.guard';
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wdWJsaWMtYXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyx3QkFBd0IsQ0FBQztBQUN2QyxjQUFjLHlCQUF5QixDQUFDO0FBQ3hDLGNBQWMsd0JBQXdCLENBQUM7QUFDdkMsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLDRDQUE0QyxDQUFDO0FBQzNELGNBQWMsMENBQTBDLENBQUM7QUFDekQsY0FBYyxxQ0FBcUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUHVibGljIEFQSSBTdXJmYWNlIG9mIEB0cmFjZXRhaWwvYW5ndWxhclxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vbGliL3RyYWNldGFpbC5tb2R1bGUnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvdHJhY2V0YWlsLnNlcnZpY2UnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvdHJhY2V0YWlsLmNvbmZpZyc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi90cmFjZXRhaWwudHlwZXMnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvZGlyZWN0aXZlcy9mcmF1ZC1kZXRlY3Rpb24uZGlyZWN0aXZlJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL2ludGVyY2VwdG9ycy90cmFjZXRhaWwuaW50ZXJjZXB0b3InO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvZ3VhcmRzL2ZyYXVkLXByb3RlY3Rpb24uZ3VhcmQnOyJdfQ==
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ export * from './public-api';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhY2V0YWlsLWFuZ3VsYXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHJhY2V0YWlsLWFuZ3VsYXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLGNBQWMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9wdWJsaWMtYXBpJztcbiJdfQ==
@@ -0,0 +1,403 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, Inject, Injectable, Input, Directive, NgModule } from '@angular/core';
3
+ import { CommonModule } from '@angular/common';
4
+ import { HTTP_INTERCEPTORS } from '@angular/common/http';
5
+ import { BehaviorSubject } from 'rxjs';
6
+ import TraceTail from '@tracetail/js';
7
+ import { take, switchMap, map } from 'rxjs/operators';
8
+ import * as i2 from '@angular/router';
9
+
10
+ const TRACETAIL_CONFIG = new InjectionToken('TRACETAIL_CONFIG');
11
+ const DEFAULT_CONFIG = {
12
+ config: {
13
+ enhanced: true,
14
+ timeout: 5000,
15
+ endpoint: 'https://api.tracetail.com',
16
+ testMode: false
17
+ }
18
+ };
19
+
20
+ class TraceTailService {
21
+ config;
22
+ client;
23
+ fingerprintSubject = new BehaviorSubject(null);
24
+ loadingSubject = new BehaviorSubject(true);
25
+ errorSubject = new BehaviorSubject(null);
26
+ fingerprint$ = this.fingerprintSubject.asObservable();
27
+ loading$ = this.loadingSubject.asObservable();
28
+ error$ = this.errorSubject.asObservable();
29
+ constructor(config) {
30
+ this.config = config;
31
+ this.initializeClient();
32
+ }
33
+ initializeClient() {
34
+ try {
35
+ // Handle test mode
36
+ if (this.config.config?.testMode && this.config.config.mockData) {
37
+ this.fingerprintSubject.next({
38
+ visitorId: 'mock-visitor-123',
39
+ confidence: 0.99,
40
+ riskScore: 0.1,
41
+ fraudulent: false,
42
+ signals: {},
43
+ timestamp: new Date(),
44
+ ...this.config.config.mockData
45
+ });
46
+ this.loadingSubject.next(false);
47
+ return;
48
+ }
49
+ // Initialize real client
50
+ this.client = new TraceTail({
51
+ apiKey: this.config.apiKey,
52
+ timeout: this.config.config?.timeout,
53
+ debug: this.config.config?.debug || false
54
+ });
55
+ // Get initial fingerprint
56
+ this.loadFingerprint();
57
+ }
58
+ catch (error) {
59
+ this.handleError(error);
60
+ }
61
+ }
62
+ async loadFingerprint() {
63
+ try {
64
+ this.loadingSubject.next(true);
65
+ this.errorSubject.next(null);
66
+ const result = await this.client.generateFingerprint();
67
+ const fingerprint = {
68
+ visitorId: result.visitorId,
69
+ confidence: result.confidence,
70
+ riskScore: 0,
71
+ fraudulent: false,
72
+ signals: result.components || {},
73
+ timestamp: new Date()
74
+ };
75
+ this.fingerprintSubject.next(fingerprint);
76
+ this.loadingSubject.next(false);
77
+ }
78
+ catch (error) {
79
+ this.handleError(error);
80
+ }
81
+ }
82
+ handleError(error) {
83
+ console.error('TraceTail error:', error);
84
+ this.errorSubject.next(error);
85
+ this.loadingSubject.next(false);
86
+ }
87
+ /**
88
+ * Get current fingerprint as a promise
89
+ */
90
+ async getFingerprint() {
91
+ const current = this.fingerprintSubject.value;
92
+ if (current) {
93
+ return current;
94
+ }
95
+ // Wait for fingerprint to be loaded
96
+ return new Promise((resolve, reject) => {
97
+ const subscription = this.fingerprint$.subscribe({
98
+ next: (fingerprint) => {
99
+ if (fingerprint) {
100
+ subscription.unsubscribe();
101
+ resolve(fingerprint);
102
+ }
103
+ },
104
+ error: (error) => {
105
+ subscription.unsubscribe();
106
+ reject(error);
107
+ }
108
+ });
109
+ });
110
+ }
111
+ /**
112
+ * Track an event
113
+ */
114
+ async trackEvent(event, data) {
115
+ try {
116
+ // TraceTail doesn't have a track method - this is custom app functionality
117
+ // For now, just return mock data with a generated event ID
118
+ const eventId = `evt_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
119
+ return {
120
+ success: true,
121
+ fraudulent: false,
122
+ riskScore: 0,
123
+ eventId: eventId
124
+ };
125
+ }
126
+ catch (error) {
127
+ console.error('Track event error:', error);
128
+ throw error;
129
+ }
130
+ }
131
+ /**
132
+ * Check for fraud
133
+ */
134
+ async checkFraud(data) {
135
+ try {
136
+ const fingerprint = await this.getFingerprint();
137
+ // Simple fraud detection logic based on risk score
138
+ const block = fingerprint.riskScore > 0.8;
139
+ const challenge = fingerprint.riskScore > 0.5 && fingerprint.riskScore <= 0.8;
140
+ const allow = fingerprint.riskScore <= 0.5;
141
+ const reasons = [];
142
+ if (fingerprint.signals.vpn)
143
+ reasons.push('VPN detected');
144
+ if (fingerprint.signals.tor)
145
+ reasons.push('Tor browser detected');
146
+ if (fingerprint.signals.proxy)
147
+ reasons.push('Proxy detected');
148
+ if (fingerprint.riskScore > 0.7)
149
+ reasons.push('High risk score');
150
+ return {
151
+ block,
152
+ challenge,
153
+ allow,
154
+ riskScore: fingerprint.riskScore,
155
+ reasons
156
+ };
157
+ }
158
+ catch (error) {
159
+ console.error('Fraud check error:', error);
160
+ throw error;
161
+ }
162
+ }
163
+ /**
164
+ * Retry fingerprinting
165
+ */
166
+ retry() {
167
+ this.loadFingerprint();
168
+ }
169
+ /**
170
+ * Force refresh fingerprint
171
+ */
172
+ async refresh() {
173
+ await this.loadFingerprint();
174
+ }
175
+ /**
176
+ * Get raw TraceTail client instance
177
+ */
178
+ getClient() {
179
+ return this.client;
180
+ }
181
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TraceTailService, deps: [{ token: TRACETAIL_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable });
182
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TraceTailService, providedIn: 'root' });
183
+ }
184
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TraceTailService, decorators: [{
185
+ type: Injectable,
186
+ args: [{
187
+ providedIn: 'root'
188
+ }]
189
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
190
+ type: Inject,
191
+ args: [TRACETAIL_CONFIG]
192
+ }] }] });
193
+
194
+ class FraudDetectionDirective {
195
+ el;
196
+ traceTail;
197
+ appFraudDetection = 'medium';
198
+ disableOnRisk = true;
199
+ cssClass = 'high-risk';
200
+ subscription = null;
201
+ constructor(el, traceTail) {
202
+ this.el = el;
203
+ this.traceTail = traceTail;
204
+ }
205
+ ngOnInit() {
206
+ this.subscription = this.traceTail.fingerprint$.subscribe(fingerprint => {
207
+ if (!fingerprint)
208
+ return;
209
+ const thresholds = {
210
+ low: 0.3,
211
+ medium: 0.5,
212
+ high: 0.7
213
+ };
214
+ const threshold = thresholds[this.appFraudDetection];
215
+ const isHighRisk = fingerprint.riskScore > threshold;
216
+ // Apply or remove CSS class
217
+ if (isHighRisk) {
218
+ this.el.nativeElement.classList.add(this.cssClass);
219
+ // Optionally disable the element
220
+ if (this.disableOnRisk && this.isFormElement()) {
221
+ this.el.nativeElement.setAttribute('disabled', 'true');
222
+ this.el.nativeElement.setAttribute('title', 'High fraud risk detected');
223
+ }
224
+ }
225
+ else {
226
+ this.el.nativeElement.classList.remove(this.cssClass);
227
+ if (this.disableOnRisk && this.isFormElement()) {
228
+ this.el.nativeElement.removeAttribute('disabled');
229
+ this.el.nativeElement.removeAttribute('title');
230
+ }
231
+ }
232
+ // Emit custom event
233
+ this.el.nativeElement.dispatchEvent(new CustomEvent('fraudStatusChange', {
234
+ detail: {
235
+ isHighRisk,
236
+ riskScore: fingerprint.riskScore,
237
+ threshold
238
+ },
239
+ bubbles: true
240
+ }));
241
+ });
242
+ }
243
+ ngOnDestroy() {
244
+ if (this.subscription) {
245
+ this.subscription.unsubscribe();
246
+ }
247
+ }
248
+ isFormElement() {
249
+ const tagName = this.el.nativeElement.tagName.toLowerCase();
250
+ return ['input', 'button', 'select', 'textarea', 'form'].includes(tagName);
251
+ }
252
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FraudDetectionDirective, deps: [{ token: i0.ElementRef }, { token: TraceTailService }], target: i0.ɵɵFactoryTarget.Directive });
253
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: FraudDetectionDirective, selector: "[appFraudDetection]", inputs: { appFraudDetection: "appFraudDetection", disableOnRisk: "disableOnRisk", cssClass: "cssClass" }, ngImport: i0 });
254
+ }
255
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FraudDetectionDirective, decorators: [{
256
+ type: Directive,
257
+ args: [{
258
+ selector: '[appFraudDetection]'
259
+ }]
260
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: TraceTailService }], propDecorators: { appFraudDetection: [{
261
+ type: Input
262
+ }], disableOnRisk: [{
263
+ type: Input
264
+ }], cssClass: [{
265
+ type: Input
266
+ }] } });
267
+
268
+ class TraceTailInterceptor {
269
+ traceTail;
270
+ constructor(traceTail) {
271
+ this.traceTail = traceTail;
272
+ }
273
+ intercept(req, next) {
274
+ // Skip TraceTail API requests to prevent circular dependency
275
+ if (req.url.includes('api.tracetail.com')) {
276
+ return next.handle(req);
277
+ }
278
+ return this.traceTail.fingerprint$.pipe(take(1), switchMap(fingerprint => {
279
+ // Clone the request and add TraceTail headers
280
+ const modifiedReq = req.clone({
281
+ headers: req.headers
282
+ .set('X-TraceTail-Visitor-ID', fingerprint?.visitorId || 'unknown')
283
+ .set('X-TraceTail-Risk-Score', fingerprint?.riskScore?.toString() || '0')
284
+ .set('X-TraceTail-Confidence', fingerprint?.confidence?.toString() || '0')
285
+ });
286
+ return next.handle(modifiedReq);
287
+ }));
288
+ }
289
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TraceTailInterceptor, deps: [{ token: TraceTailService }], target: i0.ɵɵFactoryTarget.Injectable });
290
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TraceTailInterceptor });
291
+ }
292
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TraceTailInterceptor, decorators: [{
293
+ type: Injectable
294
+ }], ctorParameters: () => [{ type: TraceTailService }] });
295
+
296
+ class TraceTailModule {
297
+ static forRoot(config) {
298
+ return {
299
+ ngModule: TraceTailModule,
300
+ providers: [
301
+ {
302
+ provide: TRACETAIL_CONFIG,
303
+ useValue: { ...DEFAULT_CONFIG, ...config }
304
+ },
305
+ TraceTailService,
306
+ {
307
+ provide: HTTP_INTERCEPTORS,
308
+ useClass: TraceTailInterceptor,
309
+ multi: true
310
+ }
311
+ ]
312
+ };
313
+ }
314
+ static forFeature(config) {
315
+ return {
316
+ ngModule: TraceTailModule,
317
+ providers: config ? [
318
+ {
319
+ provide: TRACETAIL_CONFIG,
320
+ useValue: { ...DEFAULT_CONFIG, ...config }
321
+ }
322
+ ] : []
323
+ };
324
+ }
325
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TraceTailModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
326
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.12", ngImport: i0, type: TraceTailModule, declarations: [FraudDetectionDirective], imports: [CommonModule], exports: [FraudDetectionDirective] });
327
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TraceTailModule, imports: [CommonModule] });
328
+ }
329
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TraceTailModule, decorators: [{
330
+ type: NgModule,
331
+ args: [{
332
+ declarations: [
333
+ FraudDetectionDirective
334
+ ],
335
+ imports: [
336
+ CommonModule
337
+ ],
338
+ exports: [
339
+ FraudDetectionDirective
340
+ ]
341
+ }]
342
+ }] });
343
+
344
+ /**
345
+ * TraceTail types for Angular
346
+ */
347
+
348
+ class FraudProtectionGuard {
349
+ traceTail;
350
+ router;
351
+ constructor(traceTail, router) {
352
+ this.traceTail = traceTail;
353
+ this.router = router;
354
+ }
355
+ canActivate(route, state) {
356
+ // Get risk threshold from route data or use default
357
+ const maxRiskScore = route.data['maxRiskScore'] ?? 0.7;
358
+ const verificationUrl = route.data['verificationUrl'] ?? '/verify';
359
+ return this.traceTail.fingerprint$.pipe(take(1), map(fingerprint => {
360
+ if (!fingerprint) {
361
+ // No fingerprint yet, allow but monitor
362
+ console.warn('No fingerprint available for fraud check');
363
+ return true;
364
+ }
365
+ // Check if user is fraudulent or high risk
366
+ if (fingerprint.fraudulent || fingerprint.riskScore > maxRiskScore) {
367
+ console.warn('High risk user blocked:', {
368
+ visitorId: fingerprint.visitorId,
369
+ riskScore: fingerprint.riskScore,
370
+ fraudulent: fingerprint.fraudulent
371
+ });
372
+ // Redirect to verification page
373
+ return this.router.createUrlTree([verificationUrl], {
374
+ queryParams: {
375
+ reason: fingerprint.fraudulent ? 'fraud' : 'risk',
376
+ returnUrl: state.url
377
+ }
378
+ });
379
+ }
380
+ // User is safe, allow access
381
+ return true;
382
+ }));
383
+ }
384
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FraudProtectionGuard, deps: [{ token: TraceTailService }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Injectable });
385
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FraudProtectionGuard, providedIn: 'root' });
386
+ }
387
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FraudProtectionGuard, decorators: [{
388
+ type: Injectable,
389
+ args: [{
390
+ providedIn: 'root'
391
+ }]
392
+ }], ctorParameters: () => [{ type: TraceTailService }, { type: i2.Router }] });
393
+
394
+ /**
395
+ * Public API Surface of @tracetail/angular
396
+ */
397
+
398
+ /**
399
+ * Generated bundle index. Do not edit.
400
+ */
401
+
402
+ export { DEFAULT_CONFIG, FraudDetectionDirective, FraudProtectionGuard, TRACETAIL_CONFIG, TraceTailInterceptor, TraceTailModule, TraceTailService };
403
+ //# sourceMappingURL=tracetail-angular.mjs.map