-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: upgrade ua-parser-js to track correct device models #3406
base: dev
Are you sure you want to change the base?
Changes from all commits
e4c2d7e
86a0300
476a700
3bbd775
678f712
e3ce39c
e788661
d9c8614
40ef50f
eff955c
b03a92c
8afc1ef
781c858
e9c6fea
7154a4f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,7 +15,7 @@ export interface HMSSessionFeedback { | |
|
||
export interface HMSSessionInfo { | ||
peer: HMSSessionPeerInfo; | ||
agent: string; | ||
agent?: string; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. most likely should not be optional |
||
device_id: string; | ||
cluster: HMSSessionCluster; | ||
timestamp: number; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
import type UAParser from 'ua-parser-js'; | ||
import { ENV, isNode, parsedUserAgent } from './support'; | ||
import { isPresent } from './validations'; | ||
import { DomainCategory } from '../analytics/AnalyticsEventDomains'; | ||
|
@@ -20,7 +21,12 @@ type UserAgent = { | |
framework_sdk_version?: HMSFrameworkInfo['sdkVersion']; | ||
}; | ||
|
||
export function createUserAgent(sdkEnv: ENV = ENV.PROD, frameworkInfo?: HMSFrameworkInfo): string { | ||
/** | ||
* Create UserAgent string | ||
* @param sdkEnv - SDK environment | ||
* @param frameworkInfo - Framework information | ||
*/ | ||
export async function createUserAgent(sdkEnv: ENV = ENV.PROD, frameworkInfo?: HMSFrameworkInfo) { | ||
const sdk = 'web'; | ||
const env = domainCategory !== DomainCategory.LOCAL && sdkEnv === ENV.PROD ? 'prod' : 'debug'; | ||
|
||
|
@@ -39,21 +45,25 @@ export function createUserAgent(sdkEnv: ENV = ENV.PROD, frameworkInfo?: HMSFrame | |
}); | ||
} | ||
|
||
const parsedOs = parsedUserAgent.getOS(); | ||
const parsedDevice = parsedUserAgent.getDevice(); | ||
const parsedBrowser = parsedUserAgent.getBrowser(); | ||
console.error( | ||
'client hints', | ||
await parsedUserAgent.getOS().withClientHints(), | ||
await parsedUserAgent.getDevice().withClientHints(), | ||
await parsedUserAgent.getBrowser().withClientHints(), | ||
); | ||
|
||
const os = replaceSpaces(`web_${parsedOs.name}`); | ||
const os_version = parsedOs.version || ''; | ||
console.error( | ||
'feature check: ', | ||
await parsedUserAgent.getOS().withFeatureCheck(), | ||
await parsedUserAgent.getDevice().withFeatureCheck(), | ||
await parsedUserAgent.getBrowser().withFeatureCheck(), | ||
); | ||
|
||
const browser = replaceSpaces(`${parsedBrowser.name}_${parsedBrowser.version}`); | ||
let device_model = browser; | ||
if (parsedDevice.type) { | ||
const deviceVendor = replaceSpaces(`${parsedDevice.vendor}_${parsedDevice.type}`); | ||
device_model = `${deviceVendor}/${browser}`; | ||
} | ||
const { os, version: os_version } = await getOS(); | ||
|
||
const device_model = await getDevice(); | ||
|
||
return convertObjectToString({ | ||
const ua = convertObjectToString({ | ||
os, | ||
os_version, | ||
sdk, | ||
|
@@ -66,6 +76,135 @@ export function createUserAgent(sdkEnv: ENV = ENV.PROD, frameworkInfo?: HMSFrame | |
framework_version: frameworkInfo?.version, | ||
framework_sdk_version: frameworkInfo?.sdkVersion, | ||
}); | ||
console.error('UserAgent:', ua); | ||
return ua; | ||
} | ||
|
||
/** | ||
* Get OS name and version | ||
* @internal | ||
* @returns {Promise<{ os: string; version: string }>} OS name and version | ||
*/ | ||
async function getOS(): Promise<{ os: string; version: string }> { | ||
const { name, version } = await getOSFromUserAgent(); | ||
return getFormattedOS({ name, version }); | ||
} | ||
|
||
/** | ||
* Get OS name and version initially from UserAgent with ClientHints and then with FeatureCheck | ||
* @internal | ||
* @returns {Promise<UAParser.IOS>} OS name and version | ||
*/ | ||
async function getOSFromUserAgent(): Promise<UAParser.IOS> { | ||
const os = await parsedUserAgent.getOS().withClientHints(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it might fail in older devices/browsers no? should we add a try catch and do feature check there as well? |
||
if (!os.name || os.name.length === 0 || !os.version || os.version.length === 0) { | ||
return parsedUserAgent.getOS().withFeatureCheck(); | ||
} | ||
return os; | ||
} | ||
|
||
/** | ||
* Get formatted OS name and version | ||
* @internal | ||
* @param { name, version } - OS name and version | ||
* @returns { { os: string; version: string } } Formatted OS name and version | ||
*/ | ||
function getFormattedOS({ name, version }: { name?: string; version?: string }): { os: string; version: string } { | ||
return { | ||
os: replaceSpaces(`web_${name}`), | ||
version: version || '', | ||
}; | ||
} | ||
|
||
/** | ||
* Get Browser name and version | ||
* @internal | ||
* @returns {Promise<string | undefined>} Browser name and version string | ||
*/ | ||
async function getBrowser(): Promise<string | undefined> { | ||
const { name, version } = await getBrowserFromUserAgent(); | ||
return getFormattedBrowser({ name, version }); | ||
} | ||
|
||
/** | ||
* Get Browser name and version initially from UserAgent with ClientHints and then with FeatureCheck | ||
* @internal | ||
* @returns {Promise<UAParser.IBrowser>} Browser name and version | ||
*/ | ||
async function getBrowserFromUserAgent(): Promise<UAParser.IBrowser> { | ||
const browser = await parsedUserAgent.getBrowser().withClientHints(); | ||
if (!browser.name || browser.name.length === 0 || !browser.version || browser.version.length === 0) { | ||
return parsedUserAgent.getBrowser().withFeatureCheck(); | ||
} | ||
return browser; | ||
} | ||
|
||
/** | ||
* Get formatted Browser name and version | ||
* @param {name, version} - Browser name and version | ||
* @returns {string | undefined} Formatted Browser name and version string | ||
*/ | ||
function getFormattedBrowser({ name, version }: { name?: string; version?: string }): string | undefined { | ||
return name ? `${replaceSpaces(name)}_${version}` : version; | ||
} | ||
|
||
/** | ||
* Get Device name string | ||
* @internal | ||
* @returns {Promise<string | undefined>} Device name string | ||
*/ | ||
async function getDevice(): Promise<string | undefined> { | ||
const device = getFormattedDevice(await getDeviceFromUserAgent()); | ||
const browser = await getBrowser(); | ||
return device ? `${device}/${browser}` : browser; | ||
} | ||
|
||
/** | ||
* Get Device name string initially from UserAgent with FeatureCheck and then with ClientHints | ||
* @internal | ||
* @returns {Promise<UAParser.IDevice>} Device name string | ||
*/ | ||
async function getDeviceFromUserAgent(): Promise<UAParser.IDevice> { | ||
const device = await parsedUserAgent.getDevice().withFeatureCheck(); | ||
if (!device.vendor || device.vendor.length === 0 || !device.type || device.type.length === 0) { | ||
return parsedUserAgent.getDevice().withClientHints(); | ||
} | ||
return device; | ||
} | ||
|
||
/** | ||
* Get formatted Device name string | ||
* @param {vendor, type, model} - Device vendor, type and model | ||
* @returns {string | undefined} Formatted Device name string | ||
*/ | ||
function getFormattedDevice({ | ||
vendor, | ||
type, | ||
model, | ||
}: { | ||
vendor?: string; | ||
type?: string; | ||
model?: string; | ||
}): string | undefined { | ||
let device = undefined; | ||
if (vendor) { | ||
device = vendor; | ||
} | ||
if (type) { | ||
device = getDeviceType(device, type); | ||
} | ||
if (model) { | ||
device = getDeviceModel(device, model); | ||
} | ||
return device ? replaceSpaces(device) : undefined; | ||
} | ||
|
||
function getDeviceType(device?: string, type?: string) { | ||
return device && device.length > 0 ? `${device}_${type}` : type; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. length check probably not needed |
||
} | ||
|
||
function getDeviceModel(device?: string, model?: string) { | ||
return device && device.length > 0 ? `${device}_${model}` : model; | ||
} | ||
|
||
function replaceSpaces(s: string) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this optional?