tracker: start tracker sdk
This commit is contained in:
parent
4c967d4bc1
commit
2a1c28cc49
3 changed files with 308 additions and 0 deletions
7
tracker/tracker/src/main/app/analytics/events.ts
Normal file
7
tracker/tracker/src/main/app/analytics/events.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import SharedProperties from './sharedProperties.js'
|
||||
|
||||
export default class Events {
|
||||
constructor(private readonly sharedProperties: SharedProperties, private readonly token: string) {}
|
||||
|
||||
sendEvent(eventName: string) {}
|
||||
}
|
||||
71
tracker/tracker/src/main/app/analytics/sharedProperties.ts
Normal file
71
tracker/tracker/src/main/app/analytics/sharedProperties.ts
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
import App from '../index.js'
|
||||
import { uaParse } from './utils.js'
|
||||
|
||||
const refKey = '$__initial_ref__$'
|
||||
const distinctIdKey = '$__distinct_device_id__$'
|
||||
|
||||
export default class SharedProperties {
|
||||
os: string
|
||||
browser: string
|
||||
device: string
|
||||
screenHeight: number
|
||||
screenWidth: number
|
||||
initialReferrer: string
|
||||
utmSource: string | null
|
||||
utmMedium: string | null
|
||||
utmCampaign: string | null
|
||||
deviceId: string
|
||||
|
||||
constructor(private readonly app: App) {
|
||||
const { width, height, browser, browserVersion, browserMajorVersion, os, osVersion, mobile } =
|
||||
uaParse(window)
|
||||
this.os = `${os} ${osVersion}`
|
||||
this.browser = `${browser} ${browserVersion} (${browserMajorVersion})`
|
||||
this.device = mobile ? 'Mobile' : 'Desktop'
|
||||
this.screenHeight = height
|
||||
this.screenWidth = width
|
||||
this.initialReferrer = this.getReferrer()
|
||||
const searchParams = new URLSearchParams(window.location.search)
|
||||
this.utmSource = searchParams.get('utm_source') || null
|
||||
this.utmMedium = searchParams.get('utm_medium') || null
|
||||
this.utmCampaign = searchParams.get('utm_campaign') || null
|
||||
this.deviceId = this.getDistinctDeviceId()
|
||||
}
|
||||
|
||||
get all() {
|
||||
return {
|
||||
os: this.os,
|
||||
browser: this.browser,
|
||||
device: this.device,
|
||||
screenHeight: this.screenHeight,
|
||||
screenWidth: this.screenWidth,
|
||||
initialReferrer: this.initialReferrer,
|
||||
utmSource: this.utmSource,
|
||||
utmMedium: this.utmMedium,
|
||||
utmCampaign: this.utmCampaign,
|
||||
deviceId: this.deviceId,
|
||||
}
|
||||
}
|
||||
|
||||
private getDistinctDeviceId() {
|
||||
const potentialStored = this.app.localStorage.getItem(distinctIdKey)
|
||||
if (potentialStored) {
|
||||
return potentialStored
|
||||
} else {
|
||||
const distinctId = `${Math.random().toString(36).slice(2)}-${Math.random().toString(36).slice(2)}-${Math.random().toString(36).slice(2)}`
|
||||
this.app.localStorage.setItem(distinctIdKey, distinctId)
|
||||
return distinctId
|
||||
}
|
||||
}
|
||||
|
||||
private getReferrer() {
|
||||
const potentialStored = this.app.sessionStorage.getItem(refKey)
|
||||
if (potentialStored) {
|
||||
return potentialStored
|
||||
} else {
|
||||
const ref = document.referrer
|
||||
this.app.sessionStorage.setItem(refKey, ref)
|
||||
return ref
|
||||
}
|
||||
}
|
||||
}
|
||||
230
tracker/tracker/src/main/app/analytics/utils.ts
Normal file
230
tracker/tracker/src/main/app/analytics/utils.ts
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
interface ClientData {
|
||||
screen: string
|
||||
width: number
|
||||
height: number
|
||||
browser: string
|
||||
browserVersion: string
|
||||
browserMajorVersion: number
|
||||
mobile: boolean
|
||||
os: string
|
||||
osVersion: string
|
||||
cookies: boolean
|
||||
}
|
||||
|
||||
interface ClientOS {
|
||||
s: string
|
||||
r: RegExp
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects client browser, OS, and device information
|
||||
*/
|
||||
export function uaParse(window: Window & typeof globalThis): ClientData {
|
||||
const unknown = '-'
|
||||
|
||||
// Screen detection
|
||||
let width: number = 0
|
||||
let height: number = 0
|
||||
let screenSize = ''
|
||||
|
||||
if (screen.width) {
|
||||
width = screen.width
|
||||
height = screen.height
|
||||
screenSize = `${width} x ${height}`
|
||||
}
|
||||
|
||||
// Browser detection
|
||||
const nVer: string = navigator.appVersion
|
||||
const nAgt: string = navigator.userAgent
|
||||
let browser: string = navigator.appName
|
||||
let version: string = String(parseFloat(nVer))
|
||||
let nameOffset: number
|
||||
let verOffset: number
|
||||
let ix: number
|
||||
|
||||
// Browser detection logic
|
||||
if ((verOffset = nAgt.indexOf('YaBrowser')) !== -1) {
|
||||
browser = 'Yandex'
|
||||
version = nAgt.substring(verOffset + 10)
|
||||
} else if ((verOffset = nAgt.indexOf('SamsungBrowser')) !== -1) {
|
||||
browser = 'Samsung'
|
||||
version = nAgt.substring(verOffset + 15)
|
||||
} else if ((verOffset = nAgt.indexOf('UCBrowser')) !== -1) {
|
||||
browser = 'UC Browser'
|
||||
version = nAgt.substring(verOffset + 10)
|
||||
} else if ((verOffset = nAgt.indexOf('OPR')) !== -1) {
|
||||
browser = 'Opera'
|
||||
version = nAgt.substring(verOffset + 4)
|
||||
} else if ((verOffset = nAgt.indexOf('Opera')) !== -1) {
|
||||
browser = 'Opera'
|
||||
version = nAgt.substring(verOffset + 6)
|
||||
if ((verOffset = nAgt.indexOf('Version')) !== -1) {
|
||||
version = nAgt.substring(verOffset + 8)
|
||||
}
|
||||
} else if ((verOffset = nAgt.indexOf('Edge')) !== -1) {
|
||||
browser = 'Microsoft Legacy Edge'
|
||||
version = nAgt.substring(verOffset + 5)
|
||||
} else if ((verOffset = nAgt.indexOf('Edg')) !== -1) {
|
||||
browser = 'Microsoft Edge'
|
||||
version = nAgt.substring(verOffset + 4)
|
||||
} else if ((verOffset = nAgt.indexOf('MSIE')) !== -1) {
|
||||
browser = 'Microsoft Internet Explorer'
|
||||
version = nAgt.substring(verOffset + 5)
|
||||
} else if ((verOffset = nAgt.indexOf('Chrome')) !== -1) {
|
||||
browser = 'Chrome'
|
||||
version = nAgt.substring(verOffset + 7)
|
||||
} else if ((verOffset = nAgt.indexOf('Safari')) !== -1) {
|
||||
browser = 'Safari'
|
||||
version = nAgt.substring(verOffset + 7)
|
||||
if ((verOffset = nAgt.indexOf('Version')) !== -1) {
|
||||
version = nAgt.substring(verOffset + 8)
|
||||
}
|
||||
} else if ((verOffset = nAgt.indexOf('Firefox')) !== -1) {
|
||||
browser = 'Firefox'
|
||||
version = nAgt.substring(verOffset + 8)
|
||||
} else if (nAgt.indexOf('Trident/') !== -1) {
|
||||
browser = 'Microsoft Internet Explorer'
|
||||
version = nAgt.substring(nAgt.indexOf('rv:') + 3)
|
||||
} else if ((nameOffset = nAgt.lastIndexOf(' ') + 1) < (verOffset = nAgt.lastIndexOf('/'))) {
|
||||
browser = nAgt.substring(nameOffset, verOffset)
|
||||
version = nAgt.substring(verOffset + 1)
|
||||
if (browser.toLowerCase() === browser.toUpperCase()) {
|
||||
browser = navigator.appName
|
||||
}
|
||||
}
|
||||
|
||||
// Trim the version string
|
||||
if ((ix = version.indexOf(';')) !== -1) {
|
||||
version = version.substring(0, ix)
|
||||
}
|
||||
if ((ix = version.indexOf(' ')) !== -1) {
|
||||
version = version.substring(0, ix)
|
||||
}
|
||||
if ((ix = version.indexOf(')')) !== -1) {
|
||||
version = version.substring(0, ix)
|
||||
}
|
||||
|
||||
let majorVersion: number = parseInt(version, 10)
|
||||
if (isNaN(majorVersion)) {
|
||||
version = String(parseFloat(nVer))
|
||||
majorVersion = parseInt(nVer, 10)
|
||||
}
|
||||
|
||||
// Mobile detection
|
||||
const mobile: boolean = /Mobile|mini|Fennec|Android|iP(ad|od|hone)/.test(nVer)
|
||||
|
||||
// Cookie detection
|
||||
let cookieEnabled: boolean = navigator.cookieEnabled || false
|
||||
|
||||
if (typeof navigator.cookieEnabled === 'undefined' && !cookieEnabled) {
|
||||
document.cookie = 'testcookie'
|
||||
cookieEnabled = document.cookie.indexOf('testcookie') !== -1
|
||||
}
|
||||
|
||||
// OS detection
|
||||
let os: string = unknown
|
||||
const clientStrings: ClientOS[] = [
|
||||
{ s: 'Windows 10', r: /(Windows 10.0|Windows NT 10.0)/ },
|
||||
{ s: 'Windows 8.1', r: /(Windows 8.1|Windows NT 6.3)/ },
|
||||
{ s: 'Windows 8', r: /(Windows 8|Windows NT 6.2)/ },
|
||||
{ s: 'Windows 7', r: /(Windows 7|Windows NT 6.1)/ },
|
||||
{ s: 'Windows Vista', r: /Windows NT 6.0/ },
|
||||
{ s: 'Windows Server 2003', r: /Windows NT 5.2/ },
|
||||
{ s: 'Windows XP', r: /(Windows NT 5.1|Windows XP)/ },
|
||||
{ s: 'Windows 2000', r: /(Windows NT 5.0|Windows 2000)/ },
|
||||
{ s: 'Windows ME', r: /(Win 9x 4.90|Windows ME)/ },
|
||||
{ s: 'Windows 98', r: /(Windows 98|Win98)/ },
|
||||
{ s: 'Windows 95', r: /(Windows 95|Win95|Windows_95)/ },
|
||||
{ s: 'Windows NT 4.0', r: /(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/ },
|
||||
{ s: 'Windows CE', r: /Windows CE/ },
|
||||
{ s: 'Windows 3.11', r: /Win16/ },
|
||||
{ s: 'Android', r: /Android/ },
|
||||
{ s: 'Open BSD', r: /OpenBSD/ },
|
||||
{ s: 'Sun OS', r: /SunOS/ },
|
||||
{ s: 'Chrome OS', r: /CrOS/ },
|
||||
{ s: 'Linux', r: /(Linux|X11(?!.*CrOS))/ },
|
||||
{ s: 'iOS', r: /(iPhone|iPad|iPod)/ },
|
||||
{ s: 'Mac OS X', r: /Mac OS X/ },
|
||||
{ s: 'Mac OS', r: /(Mac OS|MacPPC|MacIntel|Mac_PowerPC|Macintosh)/ },
|
||||
{ s: 'QNX', r: /QNX/ },
|
||||
{ s: 'UNIX', r: /UNIX/ },
|
||||
{ s: 'BeOS', r: /BeOS/ },
|
||||
{ s: 'OS/2', r: /OS\/2/ },
|
||||
{
|
||||
s: 'Search Bot',
|
||||
r: /(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/,
|
||||
},
|
||||
]
|
||||
|
||||
// Find matching OS
|
||||
for (const client of clientStrings) {
|
||||
if (client.r.test(nAgt)) {
|
||||
os = client.s
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// OS Version detection
|
||||
let osVersion: string = unknown
|
||||
|
||||
if (/Windows/.test(os)) {
|
||||
const matches = /Windows (.*)/.exec(os)
|
||||
if (matches && matches[1]) {
|
||||
osVersion = matches[1]
|
||||
// Handle Windows 10/11 detection with newer API if available
|
||||
if (osVersion === '10' && 'userAgentData' in navigator) {
|
||||
const nav = navigator as Navigator & {
|
||||
userAgentData?: {
|
||||
getHighEntropyValues(values: string[]): Promise<{ platformVersion: string }>
|
||||
}
|
||||
}
|
||||
|
||||
if (nav.userAgentData) {
|
||||
nav.userAgentData
|
||||
.getHighEntropyValues(['platformVersion'])
|
||||
.then((ua) => {
|
||||
const version = parseInt(ua.platformVersion.split('.')[0], 10)
|
||||
;(window as any).jscd.osVersion = version < 13 ? '10' : '11'
|
||||
})
|
||||
.catch(() => {
|
||||
// Fallback if high entropy values not available
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
os = 'Windows'
|
||||
}
|
||||
|
||||
// OS version detection for Mac/Android/iOS
|
||||
switch (os) {
|
||||
case 'Mac OS':
|
||||
case 'Mac OS X':
|
||||
case 'Android': {
|
||||
const matches =
|
||||
/(?:Android|Mac OS|Mac OS X|MacPPC|MacIntel|Mac_PowerPC|Macintosh) ([\.\_\d]+)/.exec(nAgt)
|
||||
osVersion = matches && matches[1] ? matches[1] : unknown
|
||||
break
|
||||
}
|
||||
case 'iOS': {
|
||||
const matches = /OS (\d+)_(\d+)_?(\d+)?/.exec(nVer)
|
||||
if (matches && matches[1]) {
|
||||
osVersion = `${matches[1]}.${matches[2]}.${parseInt(matches[3] || '0', 10)}`
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Return client data
|
||||
return {
|
||||
screen: screenSize,
|
||||
width,
|
||||
height,
|
||||
browser,
|
||||
browserVersion: version,
|
||||
browserMajorVersion: majorVersion,
|
||||
mobile,
|
||||
os,
|
||||
osVersion,
|
||||
cookies: cookieEnabled,
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue