@zaplier/sdk 1.6.1 → 1.6.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.
- package/dist/index.cjs +324 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.esm.js +324 -3
- package/dist/index.esm.js.map +1 -1
- package/dist/sdk.js +324 -3
- package/dist/sdk.js.map +1 -1
- package/dist/sdk.min.js +1 -1
- package/dist/src/modules/fingerprint/hashing.d.ts +1 -0
- package/dist/src/modules/fingerprint/hashing.d.ts.map +1 -1
- package/dist/src/modules/visitor-persistence.d.ts +21 -88
- package/dist/src/modules/visitor-persistence.d.ts.map +1 -1
- package/dist/src/sdk.d.ts +2 -1
- package/dist/src/sdk.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -748,6 +748,7 @@ declare class ZaplierSDK implements ZaplierSDK$1 {
|
|
|
748
748
|
private heatmapEngine?;
|
|
749
749
|
private antiAdblockManager?;
|
|
750
750
|
private autoTracker?;
|
|
751
|
+
private visitorIdentityManager?;
|
|
751
752
|
constructor(userConfig: SDKConfig);
|
|
752
753
|
/**
|
|
753
754
|
* Initialize SDK
|
|
@@ -776,7 +777,7 @@ declare class ZaplierSDK implements ZaplierSDK$1 {
|
|
|
776
777
|
private initializeAntiAdblock;
|
|
777
778
|
/**
|
|
778
779
|
* Collect fingerprint and generate visitor ID (IMPROVED - 2024)
|
|
779
|
-
* Enhanced with better incognito detection
|
|
780
|
+
* Enhanced with better incognito detection and localStorage persistence
|
|
780
781
|
*/
|
|
781
782
|
private collectFingerprint;
|
|
782
783
|
/**
|
|
@@ -1355,6 +1356,7 @@ declare function hash32(input: string): string;
|
|
|
1355
1356
|
declare function hashFingerprint(components: Record<string, any>, debug?: boolean): string;
|
|
1356
1357
|
/**
|
|
1357
1358
|
* Generate a visitor ID from fingerprint hash
|
|
1359
|
+
* Returns a proper UUID v4 format for database compatibility
|
|
1358
1360
|
*/
|
|
1359
1361
|
declare function generateVisitorId(fingerprintHash: string): string;
|
|
1360
1362
|
|
package/dist/index.esm.js
CHANGED
|
@@ -199,10 +199,19 @@ function hashFingerprint(components, debug = false) {
|
|
|
199
199
|
}
|
|
200
200
|
/**
|
|
201
201
|
* Generate a visitor ID from fingerprint hash
|
|
202
|
+
* Returns a proper UUID v4 format for database compatibility
|
|
202
203
|
*/
|
|
203
204
|
function generateVisitorId(fingerprintHash) {
|
|
204
|
-
//
|
|
205
|
-
|
|
205
|
+
// Generate UUID v4 format from fingerprint hash
|
|
206
|
+
const hash = fingerprintHash.length >= 32 ? fingerprintHash : (fingerprintHash + fingerprintHash + fingerprintHash + fingerprintHash).substring(0, 32);
|
|
207
|
+
// Extract bytes for UUID construction
|
|
208
|
+
const hex = hash.substring(0, 32);
|
|
209
|
+
// Set version 4 and variant bits according to RFC 4122
|
|
210
|
+
const chars = hex.split('');
|
|
211
|
+
chars[12] = '4'; // Version 4
|
|
212
|
+
chars[16] = (parseInt(chars[16] || '0', 16) & 0x3 | 0x8).toString(16); // Variant 10
|
|
213
|
+
// Format as UUID: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
|
|
214
|
+
return `${chars.slice(0, 8).join('')}-${chars.slice(8, 12).join('')}-${chars.slice(12, 16).join('')}-${chars.slice(16, 20).join('')}-${chars.slice(20, 32).join('')}`;
|
|
206
215
|
}
|
|
207
216
|
/**
|
|
208
217
|
* Check if a key represents an unstable component that should be excluded from hashing
|
|
@@ -19608,6 +19617,292 @@ class AutoTracker {
|
|
|
19608
19617
|
}
|
|
19609
19618
|
}
|
|
19610
19619
|
|
|
19620
|
+
/**
|
|
19621
|
+
* Visitor Persistence Manager for SDK
|
|
19622
|
+
* Implements client-side visitor identification with localStorage camouflage
|
|
19623
|
+
*/
|
|
19624
|
+
// Camuflaged storage keys to avoid detection/blocking
|
|
19625
|
+
const STORAGE_KEYS = {
|
|
19626
|
+
session: "__zp_s", // Session identifier
|
|
19627
|
+
visitor: "__zp_v", // Visitor identifier (camuflado)
|
|
19628
|
+
device: "__zp_d", // Device fingerprint cache
|
|
19629
|
+
prefs: "__zp_p", // User preferences (decoy storage)
|
|
19630
|
+
analytics: "__zp_a", // Analytics preferences (additional decoy)
|
|
19631
|
+
};
|
|
19632
|
+
/**
|
|
19633
|
+
* Multi-layer persistence manager with fallbacks
|
|
19634
|
+
*/
|
|
19635
|
+
class PersistenceManager {
|
|
19636
|
+
// 1. LocalStorage (primary) - Most persistent
|
|
19637
|
+
static setLocal(key, value) {
|
|
19638
|
+
try {
|
|
19639
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
19640
|
+
localStorage.setItem(key, value);
|
|
19641
|
+
return true;
|
|
19642
|
+
}
|
|
19643
|
+
}
|
|
19644
|
+
catch (e) {
|
|
19645
|
+
// Storage disabled/private mode
|
|
19646
|
+
}
|
|
19647
|
+
return false;
|
|
19648
|
+
}
|
|
19649
|
+
static getLocal(key) {
|
|
19650
|
+
try {
|
|
19651
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
19652
|
+
return localStorage.getItem(key);
|
|
19653
|
+
}
|
|
19654
|
+
}
|
|
19655
|
+
catch (e) {
|
|
19656
|
+
// Storage disabled/private mode
|
|
19657
|
+
}
|
|
19658
|
+
return null;
|
|
19659
|
+
}
|
|
19660
|
+
// 2. SessionStorage (secondary) - Session-only
|
|
19661
|
+
static setSession(key, value) {
|
|
19662
|
+
try {
|
|
19663
|
+
if (typeof window !== "undefined" && window.sessionStorage) {
|
|
19664
|
+
sessionStorage.setItem(key, value);
|
|
19665
|
+
return true;
|
|
19666
|
+
}
|
|
19667
|
+
}
|
|
19668
|
+
catch (e) {
|
|
19669
|
+
// Storage disabled/private mode
|
|
19670
|
+
}
|
|
19671
|
+
return false;
|
|
19672
|
+
}
|
|
19673
|
+
static getSession(key) {
|
|
19674
|
+
try {
|
|
19675
|
+
if (typeof window !== "undefined" && window.sessionStorage) {
|
|
19676
|
+
return sessionStorage.getItem(key);
|
|
19677
|
+
}
|
|
19678
|
+
}
|
|
19679
|
+
catch (e) {
|
|
19680
|
+
// Storage disabled/private mode
|
|
19681
|
+
}
|
|
19682
|
+
return null;
|
|
19683
|
+
}
|
|
19684
|
+
// 3. Cookie (tertiary) - Cross-session with expiration
|
|
19685
|
+
static setCookie(key, value, days = 365) {
|
|
19686
|
+
try {
|
|
19687
|
+
if (typeof document !== "undefined") {
|
|
19688
|
+
const expires = new Date(Date.now() + days * 24 * 60 * 60 * 1000).toUTCString();
|
|
19689
|
+
document.cookie = `${key}=${value}; expires=${expires}; path=/; SameSite=Lax`;
|
|
19690
|
+
return true;
|
|
19691
|
+
}
|
|
19692
|
+
}
|
|
19693
|
+
catch (e) {
|
|
19694
|
+
// Cookies disabled
|
|
19695
|
+
}
|
|
19696
|
+
return false;
|
|
19697
|
+
}
|
|
19698
|
+
static getCookie(key) {
|
|
19699
|
+
try {
|
|
19700
|
+
if (typeof document !== "undefined") {
|
|
19701
|
+
const name = key + "=";
|
|
19702
|
+
const decodedCookie = decodeURIComponent(document.cookie);
|
|
19703
|
+
const ca = decodedCookie.split(";");
|
|
19704
|
+
for (let i = 0; i < ca.length; i++) {
|
|
19705
|
+
let c = ca[i];
|
|
19706
|
+
if (c) {
|
|
19707
|
+
while (c.charAt(0) === " ") {
|
|
19708
|
+
c = c.substring(1);
|
|
19709
|
+
}
|
|
19710
|
+
if (c.indexOf(name) === 0) {
|
|
19711
|
+
return c.substring(name.length, c.length);
|
|
19712
|
+
}
|
|
19713
|
+
}
|
|
19714
|
+
}
|
|
19715
|
+
}
|
|
19716
|
+
}
|
|
19717
|
+
catch (e) {
|
|
19718
|
+
// Cookies disabled
|
|
19719
|
+
}
|
|
19720
|
+
return null;
|
|
19721
|
+
}
|
|
19722
|
+
// 4. Memory (fallback) - Current session only
|
|
19723
|
+
static setMemory(key, value) {
|
|
19724
|
+
this.memoryStore.set(key, value);
|
|
19725
|
+
return true;
|
|
19726
|
+
}
|
|
19727
|
+
static getMemory(key) {
|
|
19728
|
+
return this.memoryStore.get(key) || null;
|
|
19729
|
+
}
|
|
19730
|
+
// Multi-layer get with fallbacks
|
|
19731
|
+
static get(key) {
|
|
19732
|
+
// Try localStorage first (most persistent)
|
|
19733
|
+
let value = this.getLocal(key);
|
|
19734
|
+
if (value)
|
|
19735
|
+
return { value, method: "localStorage" };
|
|
19736
|
+
// Try sessionStorage (session-only)
|
|
19737
|
+
value = this.getSession(key);
|
|
19738
|
+
if (value)
|
|
19739
|
+
return { value, method: "sessionStorage" };
|
|
19740
|
+
// Try cookies (cross-session)
|
|
19741
|
+
value = this.getCookie(key);
|
|
19742
|
+
if (value)
|
|
19743
|
+
return { value, method: "cookie" };
|
|
19744
|
+
// Try memory (current session)
|
|
19745
|
+
value = this.getMemory(key);
|
|
19746
|
+
if (value)
|
|
19747
|
+
return { value, method: "memory" };
|
|
19748
|
+
return { value: null, method: "none" };
|
|
19749
|
+
}
|
|
19750
|
+
// Multi-layer set with fallbacks
|
|
19751
|
+
static set(key, value) {
|
|
19752
|
+
// Try localStorage first (most persistent)
|
|
19753
|
+
if (this.setLocal(key, value)) {
|
|
19754
|
+
return { success: true, method: "localStorage" };
|
|
19755
|
+
}
|
|
19756
|
+
// Try sessionStorage (session-only)
|
|
19757
|
+
if (this.setSession(key, value)) {
|
|
19758
|
+
return { success: true, method: "sessionStorage" };
|
|
19759
|
+
}
|
|
19760
|
+
// Try cookies (cross-session)
|
|
19761
|
+
if (this.setCookie(key, value)) {
|
|
19762
|
+
return { success: true, method: "cookie" };
|
|
19763
|
+
}
|
|
19764
|
+
// Fallback to memory (current session)
|
|
19765
|
+
this.setMemory(key, value);
|
|
19766
|
+
return { success: true, method: "memory" };
|
|
19767
|
+
}
|
|
19768
|
+
}
|
|
19769
|
+
PersistenceManager.memoryStore = new Map();
|
|
19770
|
+
/**
|
|
19771
|
+
* Advanced Visitor Identity Manager with Camouflaged Storage
|
|
19772
|
+
*/
|
|
19773
|
+
class VisitorIdentityManager {
|
|
19774
|
+
generateVisitorId() {
|
|
19775
|
+
// Generate UUID v4 format instead of vis_ prefix
|
|
19776
|
+
const bytes = crypto.getRandomValues(new Uint8Array(16));
|
|
19777
|
+
// Set version 4
|
|
19778
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
19779
|
+
// Set variant
|
|
19780
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
19781
|
+
const hex = Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
19782
|
+
return `${hex.substr(0, 8)}-${hex.substr(8, 4)}-${hex.substr(12, 4)}-${hex.substr(16, 4)}-${hex.substr(20, 12)}`;
|
|
19783
|
+
}
|
|
19784
|
+
generateVisitorIdFromHash(hash) {
|
|
19785
|
+
// Generate deterministic UUID v4 format from fingerprint hash
|
|
19786
|
+
// This ensures same fingerprint = same visitor ID
|
|
19787
|
+
const hashExtended = hash.length >= 32 ? hash : (hash + hash + hash + hash).substring(0, 32);
|
|
19788
|
+
// Extract hex characters for UUID construction
|
|
19789
|
+
const hex = hashExtended.substring(0, 32);
|
|
19790
|
+
const chars = hex.split('');
|
|
19791
|
+
// Set version 4 and variant bits according to RFC 4122
|
|
19792
|
+
chars[12] = '4'; // Version 4
|
|
19793
|
+
chars[16] = (parseInt(chars[16] || '0', 16) & 0x3 | 0x8).toString(16); // Variant 10
|
|
19794
|
+
// Format as UUID: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
|
|
19795
|
+
return `${chars.slice(0, 8).join('')}-${chars.slice(8, 12).join('')}-${chars.slice(12, 16).join('')}-${chars.slice(16, 20).join('')}-${chars.slice(20, 32).join('')}`;
|
|
19796
|
+
}
|
|
19797
|
+
generateSessionId() {
|
|
19798
|
+
return "ses_" + Array.from(crypto.getRandomValues(new Uint8Array(8)))
|
|
19799
|
+
.map(b => b.toString(16).padStart(2, '0'))
|
|
19800
|
+
.join('') + "_" + Date.now().toString(36);
|
|
19801
|
+
}
|
|
19802
|
+
createCamouflageData(visitorId, sessionId, stableCoreHash) {
|
|
19803
|
+
return {
|
|
19804
|
+
theme: "auto",
|
|
19805
|
+
lang: (navigator.language || "en-US").substring(0, 2),
|
|
19806
|
+
tz: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
19807
|
+
analytics: true,
|
|
19808
|
+
cookies: true,
|
|
19809
|
+
_v: visitorId, // Hidden visitor ID
|
|
19810
|
+
_s: sessionId, // Hidden session ID
|
|
19811
|
+
_sc: stableCoreHash, // Hidden stable core
|
|
19812
|
+
ts: Date.now(),
|
|
19813
|
+
};
|
|
19814
|
+
}
|
|
19815
|
+
extractFromCamouflage(data) {
|
|
19816
|
+
try {
|
|
19817
|
+
const parsed = JSON.parse(data);
|
|
19818
|
+
if (parsed._v && parsed._s && parsed._sc) {
|
|
19819
|
+
return {
|
|
19820
|
+
visitorId: parsed._v,
|
|
19821
|
+
sessionId: parsed._s,
|
|
19822
|
+
stableCoreHash: parsed._sc,
|
|
19823
|
+
persistenceMethod: "localStorage",
|
|
19824
|
+
confidence: 0.95,
|
|
19825
|
+
createdAt: parsed.ts || Date.now(),
|
|
19826
|
+
lastSeen: Date.now(),
|
|
19827
|
+
reused: true,
|
|
19828
|
+
};
|
|
19829
|
+
}
|
|
19830
|
+
}
|
|
19831
|
+
catch (e) {
|
|
19832
|
+
// Invalid data
|
|
19833
|
+
}
|
|
19834
|
+
return null;
|
|
19835
|
+
}
|
|
19836
|
+
async getOrCreateVisitorIdentity(params) {
|
|
19837
|
+
const { stableCoreHash } = params;
|
|
19838
|
+
// Try to recover existing identity from camouflaged storage
|
|
19839
|
+
const { value: storedData, method } = PersistenceManager.get(STORAGE_KEYS.prefs);
|
|
19840
|
+
if (storedData) {
|
|
19841
|
+
const existingIdentity = this.extractFromCamouflage(storedData);
|
|
19842
|
+
if (existingIdentity && existingIdentity.stableCoreHash === stableCoreHash) {
|
|
19843
|
+
// Update last seen time
|
|
19844
|
+
const updatedCamouflage = this.createCamouflageData(existingIdentity.visitorId, existingIdentity.sessionId, stableCoreHash);
|
|
19845
|
+
PersistenceManager.set(STORAGE_KEYS.prefs, JSON.stringify(updatedCamouflage));
|
|
19846
|
+
return {
|
|
19847
|
+
...existingIdentity,
|
|
19848
|
+
persistenceMethod: method,
|
|
19849
|
+
lastSeen: Date.now(),
|
|
19850
|
+
reused: true,
|
|
19851
|
+
};
|
|
19852
|
+
}
|
|
19853
|
+
}
|
|
19854
|
+
// Create new visitor identity (deterministic from fingerprint)
|
|
19855
|
+
// Use stableCoreHash for deterministic visitor ID generation
|
|
19856
|
+
// This ensures same fingerprint = same visitor ID across devices and sessions
|
|
19857
|
+
const deterministicVisitorId = this.generateVisitorIdFromHash(params.stableCoreHash);
|
|
19858
|
+
const newSessionId = params.sessionId || this.generateSessionId();
|
|
19859
|
+
const newIdentity = {
|
|
19860
|
+
visitorId: deterministicVisitorId,
|
|
19861
|
+
sessionId: newSessionId,
|
|
19862
|
+
stableCoreHash,
|
|
19863
|
+
deviceFingerprint: params.deviceFingerprint,
|
|
19864
|
+
persistenceMethod: "localStorage",
|
|
19865
|
+
confidence: 0.90,
|
|
19866
|
+
createdAt: Date.now(),
|
|
19867
|
+
lastSeen: Date.now(),
|
|
19868
|
+
reused: false,
|
|
19869
|
+
};
|
|
19870
|
+
// Store in camouflaged format
|
|
19871
|
+
const camouflageData = this.createCamouflageData(deterministicVisitorId, newSessionId, stableCoreHash);
|
|
19872
|
+
const { method: storageMethod } = PersistenceManager.set(STORAGE_KEYS.prefs, JSON.stringify(camouflageData));
|
|
19873
|
+
newIdentity.persistenceMethod = storageMethod;
|
|
19874
|
+
// Also store device fingerprint cache for faster lookups
|
|
19875
|
+
PersistenceManager.set(STORAGE_KEYS.device, params.deviceFingerprint);
|
|
19876
|
+
return newIdentity;
|
|
19877
|
+
}
|
|
19878
|
+
// Get current visitor ID without creating new one
|
|
19879
|
+
getCurrentVisitorId() {
|
|
19880
|
+
const { value: storedData } = PersistenceManager.get(STORAGE_KEYS.prefs);
|
|
19881
|
+
if (storedData) {
|
|
19882
|
+
const identity = this.extractFromCamouflage(storedData);
|
|
19883
|
+
return identity?.visitorId || null;
|
|
19884
|
+
}
|
|
19885
|
+
return null;
|
|
19886
|
+
}
|
|
19887
|
+
// Clear all stored identity data
|
|
19888
|
+
clearIdentity() {
|
|
19889
|
+
// Remove from all storage layers
|
|
19890
|
+
try {
|
|
19891
|
+
PersistenceManager.setLocal(STORAGE_KEYS.prefs, "");
|
|
19892
|
+
PersistenceManager.setLocal(STORAGE_KEYS.device, "");
|
|
19893
|
+
PersistenceManager.setSession(STORAGE_KEYS.prefs, "");
|
|
19894
|
+
PersistenceManager.setSession(STORAGE_KEYS.device, "");
|
|
19895
|
+
PersistenceManager.setCookie(STORAGE_KEYS.prefs, "", -1); // Expire immediately
|
|
19896
|
+
PersistenceManager.setCookie(STORAGE_KEYS.device, "", -1);
|
|
19897
|
+
PersistenceManager.setMemory(STORAGE_KEYS.prefs, "");
|
|
19898
|
+
PersistenceManager.setMemory(STORAGE_KEYS.device, "");
|
|
19899
|
+
}
|
|
19900
|
+
catch (e) {
|
|
19901
|
+
// Silent fail
|
|
19902
|
+
}
|
|
19903
|
+
}
|
|
19904
|
+
}
|
|
19905
|
+
|
|
19611
19906
|
/**
|
|
19612
19907
|
* Zaplier SDK v1.0.0
|
|
19613
19908
|
* 100% Cookieless Analytics Tracking
|
|
@@ -20043,10 +20338,12 @@ class ZaplierSDK {
|
|
|
20043
20338
|
}
|
|
20044
20339
|
/**
|
|
20045
20340
|
* Collect fingerprint and generate visitor ID (IMPROVED - 2024)
|
|
20046
|
-
* Enhanced with better incognito detection
|
|
20341
|
+
* Enhanced with better incognito detection and localStorage persistence
|
|
20047
20342
|
*/
|
|
20048
20343
|
async collectFingerprint() {
|
|
20049
20344
|
try {
|
|
20345
|
+
// Initialize visitor identity manager
|
|
20346
|
+
this.visitorIdentityManager = new VisitorIdentityManager();
|
|
20050
20347
|
// Use appropriate fingerprinting based on GDPR mode
|
|
20051
20348
|
const result = this.config.gdprMode
|
|
20052
20349
|
? await getLightweightFingerprint()
|
|
@@ -20064,6 +20361,26 @@ class ZaplierSDK {
|
|
|
20064
20361
|
sdkVersion: this.version,
|
|
20065
20362
|
};
|
|
20066
20363
|
}
|
|
20364
|
+
// Generate or retrieve visitor identity using persistent storage
|
|
20365
|
+
const visitorIdentity = await this.visitorIdentityManager.getOrCreateVisitorIdentity({
|
|
20366
|
+
fingerprintHash: result.data.hash,
|
|
20367
|
+
stableCoreHash: result.data.stableCoreHash,
|
|
20368
|
+
deviceFingerprint: result.data.hash,
|
|
20369
|
+
sessionId: this.sessionId,
|
|
20370
|
+
userAgent: navigator.userAgent,
|
|
20371
|
+
ipAddress: undefined, // Will be determined server-side
|
|
20372
|
+
});
|
|
20373
|
+
// Set the persistent visitor ID
|
|
20374
|
+
this.visitorId = visitorIdentity.visitorId;
|
|
20375
|
+
if (this.config.debug) {
|
|
20376
|
+
console.log("[Zaplier] Visitor identity resolved:", {
|
|
20377
|
+
visitorId: this.visitorId,
|
|
20378
|
+
sessionId: this.sessionId,
|
|
20379
|
+
persistenceMethod: visitorIdentity.persistenceMethod,
|
|
20380
|
+
confidence: visitorIdentity.confidence,
|
|
20381
|
+
isNewVisitor: !visitorIdentity.reused,
|
|
20382
|
+
});
|
|
20383
|
+
}
|
|
20067
20384
|
if (this.config.debug) {
|
|
20068
20385
|
console.log("[Zaplier] Fingerprint collected:", {
|
|
20069
20386
|
components: result.collectedComponents,
|
|
@@ -20170,6 +20487,10 @@ class ZaplierSDK {
|
|
|
20170
20487
|
try {
|
|
20171
20488
|
const payload = {
|
|
20172
20489
|
// workspaceId moved to query parameter
|
|
20490
|
+
// Visitor ID (persistido via localStorage camuflado)
|
|
20491
|
+
visitorId: this.visitorId,
|
|
20492
|
+
// Session ID (gerado por sessão)
|
|
20493
|
+
sessionId: this.sessionId,
|
|
20173
20494
|
fingerprintHash: this.fingerprint?.hash,
|
|
20174
20495
|
stableCoreHash: this.fingerprint?.stableCoreHash,
|
|
20175
20496
|
stableCoreVector: this.fingerprint?.stableCoreVector,
|