wisetrack 2.0.0
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/LICENSE +5 -0
- package/README.md +128 -0
- package/dist/cdn/constants/constants.d.ts +20 -0
- package/dist/cdn/constants/endpoints.d.ts +11 -0
- package/dist/cdn/constants/environments.d.ts +25 -0
- package/dist/cdn/core/caching/queue-data.d.ts +25 -0
- package/dist/cdn/core/caching/request-queue-manager.d.ts +54 -0
- package/dist/cdn/core/fields/event-fields-builder.d.ts +8 -0
- package/dist/cdn/core/fields/fields-builder.d.ts +9 -0
- package/dist/cdn/core/network/api-client.d.ts +9 -0
- package/dist/cdn/core/network/network-error.d.ts +17 -0
- package/dist/cdn/core/network/network-manager.d.ts +22 -0
- package/dist/cdn/core/network/retry-policy.d.ts +8 -0
- package/dist/cdn/core/storage/storage-manager.d.ts +52 -0
- package/dist/cdn/core/wisetrack.d.ts +125 -0
- package/dist/cdn/core/wt-tracker.d.ts +25 -0
- package/dist/cdn/index.d.ts +4 -0
- package/dist/cdn/sdk.bundle.js +3604 -0
- package/dist/cdn/sdk.bundle.js.map +1 -0
- package/dist/cdn/sdk.bundle.min.js +1 -0
- package/dist/cdn/types/config/initial-config.d.ts +43 -0
- package/dist/cdn/types/config/wt-app-settings.d.ts +15 -0
- package/dist/cdn/types/config/wt-config.d.ts +18 -0
- package/dist/cdn/types/event/revenue-currency.d.ts +39 -0
- package/dist/cdn/types/event/wt-event.d.ts +94 -0
- package/dist/cdn/utils/activity-ticker.d.ts +12 -0
- package/dist/cdn/utils/country-finder.d.ts +9 -0
- package/dist/cdn/utils/crypto-helper.d.ts +4 -0
- package/dist/cdn/utils/device-detector.d.ts +41 -0
- package/dist/cdn/utils/logger.d.ts +36 -0
- package/dist/cdn/utils/storage-support.d.ts +16 -0
- package/dist/cdn/utils/utils.d.ts +5 -0
- package/dist/cdn/utils/webgl-fingerprint.d.ts +7 -0
- package/dist/cjs/constants/constants.d.ts +20 -0
- package/dist/cjs/constants/endpoints.d.ts +11 -0
- package/dist/cjs/constants/environments.d.ts +25 -0
- package/dist/cjs/core/caching/queue-data.d.ts +25 -0
- package/dist/cjs/core/caching/request-queue-manager.d.ts +54 -0
- package/dist/cjs/core/fields/event-fields-builder.d.ts +8 -0
- package/dist/cjs/core/fields/fields-builder.d.ts +9 -0
- package/dist/cjs/core/network/api-client.d.ts +9 -0
- package/dist/cjs/core/network/network-error.d.ts +17 -0
- package/dist/cjs/core/network/network-manager.d.ts +22 -0
- package/dist/cjs/core/network/retry-policy.d.ts +8 -0
- package/dist/cjs/core/storage/storage-manager.d.ts +52 -0
- package/dist/cjs/core/wisetrack.d.ts +125 -0
- package/dist/cjs/core/wt-tracker.d.ts +25 -0
- package/dist/cjs/index.d.ts +4 -0
- package/dist/cjs/index.js +3599 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/types/config/initial-config.d.ts +43 -0
- package/dist/cjs/types/config/wt-app-settings.d.ts +15 -0
- package/dist/cjs/types/config/wt-config.d.ts +18 -0
- package/dist/cjs/types/event/revenue-currency.d.ts +39 -0
- package/dist/cjs/types/event/wt-event.d.ts +94 -0
- package/dist/cjs/utils/activity-ticker.d.ts +12 -0
- package/dist/cjs/utils/country-finder.d.ts +9 -0
- package/dist/cjs/utils/crypto-helper.d.ts +4 -0
- package/dist/cjs/utils/device-detector.d.ts +41 -0
- package/dist/cjs/utils/logger.d.ts +36 -0
- package/dist/cjs/utils/storage-support.d.ts +16 -0
- package/dist/cjs/utils/utils.d.ts +5 -0
- package/dist/cjs/utils/webgl-fingerprint.d.ts +7 -0
- package/dist/constants/constants.d.ts +20 -0
- package/dist/constants/constants.js +19 -0
- package/dist/constants/constants.js.map +1 -0
- package/dist/constants/endpoints.d.ts +11 -0
- package/dist/constants/endpoints.js +10 -0
- package/dist/constants/endpoints.js.map +1 -0
- package/dist/constants/environments.d.ts +25 -0
- package/dist/constants/environments.js +37 -0
- package/dist/constants/environments.js.map +1 -0
- package/dist/core/caching/queue-data.d.ts +25 -0
- package/dist/core/caching/queue-data.js +50 -0
- package/dist/core/caching/queue-data.js.map +1 -0
- package/dist/core/caching/request-queue-manager.d.ts +54 -0
- package/dist/core/caching/request-queue-manager.js +333 -0
- package/dist/core/caching/request-queue-manager.js.map +1 -0
- package/dist/core/fields/event-fields-builder.d.ts +8 -0
- package/dist/core/fields/event-fields-builder.js +29 -0
- package/dist/core/fields/event-fields-builder.js.map +1 -0
- package/dist/core/fields/fields-builder.d.ts +9 -0
- package/dist/core/fields/fields-builder.js +120 -0
- package/dist/core/fields/fields-builder.js.map +1 -0
- package/dist/core/network/api-client.d.ts +9 -0
- package/dist/core/network/api-client.js +88 -0
- package/dist/core/network/api-client.js.map +1 -0
- package/dist/core/network/network-error.d.ts +17 -0
- package/dist/core/network/network-error.js +35 -0
- package/dist/core/network/network-error.js.map +1 -0
- package/dist/core/network/network-manager.d.ts +22 -0
- package/dist/core/network/network-manager.js +72 -0
- package/dist/core/network/network-manager.js.map +1 -0
- package/dist/core/network/retry-policy.d.ts +8 -0
- package/dist/core/network/retry-policy.js +26 -0
- package/dist/core/network/retry-policy.js.map +1 -0
- package/dist/core/storage/storage-manager.d.ts +52 -0
- package/dist/core/storage/storage-manager.js +221 -0
- package/dist/core/storage/storage-manager.js.map +1 -0
- package/dist/core/wisetrack.d.ts +125 -0
- package/dist/core/wisetrack.js +277 -0
- package/dist/core/wisetrack.js.map +1 -0
- package/dist/core/wt-tracker.d.ts +25 -0
- package/dist/core/wt-tracker.js +239 -0
- package/dist/core/wt-tracker.js.map +1 -0
- package/dist/esm/constants/constants.d.ts +20 -0
- package/dist/esm/constants/endpoints.d.ts +11 -0
- package/dist/esm/constants/environments.d.ts +25 -0
- package/dist/esm/core/caching/queue-data.d.ts +25 -0
- package/dist/esm/core/caching/request-queue-manager.d.ts +54 -0
- package/dist/esm/core/fields/event-fields-builder.d.ts +8 -0
- package/dist/esm/core/fields/fields-builder.d.ts +9 -0
- package/dist/esm/core/network/api-client.d.ts +9 -0
- package/dist/esm/core/network/network-error.d.ts +17 -0
- package/dist/esm/core/network/network-manager.d.ts +22 -0
- package/dist/esm/core/network/retry-policy.d.ts +8 -0
- package/dist/esm/core/storage/storage-manager.d.ts +52 -0
- package/dist/esm/core/wisetrack.d.ts +125 -0
- package/dist/esm/core/wt-tracker.d.ts +25 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +3594 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/types/config/initial-config.d.ts +43 -0
- package/dist/esm/types/config/wt-app-settings.d.ts +15 -0
- package/dist/esm/types/config/wt-config.d.ts +18 -0
- package/dist/esm/types/event/revenue-currency.d.ts +39 -0
- package/dist/esm/types/event/wt-event.d.ts +94 -0
- package/dist/esm/utils/activity-ticker.d.ts +12 -0
- package/dist/esm/utils/country-finder.d.ts +9 -0
- package/dist/esm/utils/crypto-helper.d.ts +4 -0
- package/dist/esm/utils/device-detector.d.ts +41 -0
- package/dist/esm/utils/logger.d.ts +36 -0
- package/dist/esm/utils/storage-support.d.ts +16 -0
- package/dist/esm/utils/utils.d.ts +5 -0
- package/dist/esm/utils/webgl-fingerprint.d.ts +7 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/types/config/initial-config.d.ts +43 -0
- package/dist/types/config/initial-config.js +2 -0
- package/dist/types/config/initial-config.js.map +1 -0
- package/dist/types/config/wt-app-settings.d.ts +15 -0
- package/dist/types/config/wt-app-settings.js +25 -0
- package/dist/types/config/wt-app-settings.js.map +1 -0
- package/dist/types/config/wt-config.d.ts +18 -0
- package/dist/types/config/wt-config.js +28 -0
- package/dist/types/config/wt-config.js.map +1 -0
- package/dist/types/event/revenue-currency.d.ts +39 -0
- package/dist/types/event/revenue-currency.js +39 -0
- package/dist/types/event/revenue-currency.js.map +1 -0
- package/dist/types/event/wt-event.d.ts +94 -0
- package/dist/types/event/wt-event.js +93 -0
- package/dist/types/event/wt-event.js.map +1 -0
- package/dist/utils/activity-ticker.d.ts +12 -0
- package/dist/utils/activity-ticker.js +37 -0
- package/dist/utils/activity-ticker.js.map +1 -0
- package/dist/utils/country-finder.d.ts +9 -0
- package/dist/utils/country-finder.js +71 -0
- package/dist/utils/country-finder.js.map +1 -0
- package/dist/utils/crypto-helper.d.ts +4 -0
- package/dist/utils/crypto-helper.js +7 -0
- package/dist/utils/crypto-helper.js.map +1 -0
- package/dist/utils/device-detector.d.ts +41 -0
- package/dist/utils/device-detector.js +101 -0
- package/dist/utils/device-detector.js.map +1 -0
- package/dist/utils/logger.d.ts +36 -0
- package/dist/utils/logger.js +84 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/storage-support.d.ts +16 -0
- package/dist/utils/storage-support.js +86 -0
- package/dist/utils/storage-support.js.map +1 -0
- package/dist/utils/utils.d.ts +5 -0
- package/dist/utils/utils.js +95 -0
- package/dist/utils/utils.js.map +1 -0
- package/dist/utils/webgl-fingerprint.d.ts +7 -0
- package/dist/utils/webgl-fingerprint.js +100 -0
- package/dist/utils/webgl-fingerprint.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,3599 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/******************************************************************************
|
|
4
|
+
Copyright (c) Microsoft Corporation.
|
|
5
|
+
|
|
6
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
7
|
+
purpose with or without fee is hereby granted.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
16
|
+
***************************************************************************** */
|
|
17
|
+
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
21
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
22
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
23
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
24
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
25
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
26
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
31
|
+
var e = new Error(message);
|
|
32
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/** @internal */
|
|
36
|
+
const WTConstants = {
|
|
37
|
+
SDK: {
|
|
38
|
+
HASH: "997bfbb583c1245a426a53dc1899ec779ff354f9",
|
|
39
|
+
PLATFORM: "web",
|
|
40
|
+
VERSION: "2.0.0",
|
|
41
|
+
},
|
|
42
|
+
CONFIG: {
|
|
43
|
+
BASE_URL: "https://config.wisetrack.io",
|
|
44
|
+
DEFAULT_ENVIRONMENT: "debug",
|
|
45
|
+
},
|
|
46
|
+
DEFAULTS: {
|
|
47
|
+
LOG_LEVEL: "debug",
|
|
48
|
+
SESSION_INTERVAL: '1800000', // 30 minutes
|
|
49
|
+
SUBSESSION_INTERVAL: '300000'},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/** @internal */
|
|
53
|
+
const WTSDKEnvironment = {
|
|
54
|
+
DEBUG: "debug",
|
|
55
|
+
STAGE: "stage",
|
|
56
|
+
PRODUCTION: "production",
|
|
57
|
+
};
|
|
58
|
+
/** @internal */
|
|
59
|
+
const EnvironmentUtils = {
|
|
60
|
+
sdkEnvironment: WTConstants.CONFIG.DEFAULT_ENVIRONMENT,
|
|
61
|
+
needAppSettings() {
|
|
62
|
+
return this.sdkEnvironment !== WTSDKEnvironment.PRODUCTION;
|
|
63
|
+
},
|
|
64
|
+
baseUrl() {
|
|
65
|
+
switch (this.sdkEnvironment) {
|
|
66
|
+
case WTSDKEnvironment.DEBUG:
|
|
67
|
+
return "https://core.debug.wisetrackdev.ir";
|
|
68
|
+
case WTSDKEnvironment.STAGE:
|
|
69
|
+
return "https://core.stage.wisetrackdev.ir";
|
|
70
|
+
case WTSDKEnvironment.PRODUCTION:
|
|
71
|
+
return "https://core.wisetrack.io";
|
|
72
|
+
default:
|
|
73
|
+
throw new Error(`Unknown environment: ${this.sdkEnvironment}`);
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/** @internal */
|
|
79
|
+
const WTEndpoints = {
|
|
80
|
+
EVENTS: "/api/v1/events",
|
|
81
|
+
SESSIONS: "/api/v1/sessions",
|
|
82
|
+
SDK_CLICKS: "/api/v1/sdk_clicks",
|
|
83
|
+
SDK_INFOS: "/api/v1/sdk_infos",
|
|
84
|
+
ATTRIBUTIONS: "/api/v1/attributions",
|
|
85
|
+
APP_SETTINGS: "/api/v1/app_settings",
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/** @internal */
|
|
89
|
+
class WTAppSettings {
|
|
90
|
+
constructor(events, sessions, sdkClicks, sdkInfos, attributions, sessionInterval = WTConstants.DEFAULTS.SESSION_INTERVAL, subsessionInterval = WTConstants.DEFAULTS.SUBSESSION_INTERVAL) {
|
|
91
|
+
this.events = events;
|
|
92
|
+
this.sessions = sessions;
|
|
93
|
+
this.sdkClicks = sdkClicks;
|
|
94
|
+
this.sdkInfos = sdkInfos;
|
|
95
|
+
this.attributions = attributions;
|
|
96
|
+
this.sessionInterval = sessionInterval;
|
|
97
|
+
this.subsessionInterval = subsessionInterval;
|
|
98
|
+
}
|
|
99
|
+
static fromConfig(config) {
|
|
100
|
+
return new WTAppSettings(config.events, config.sessions, config.sdkClicks, config.sdkInfos, config.attributions, config.sessionInterval, config.subsessionInterval);
|
|
101
|
+
}
|
|
102
|
+
static fromJson(json) {
|
|
103
|
+
var _a, _b;
|
|
104
|
+
return new WTAppSettings(json.events, json.sessions, json.sdk_clicks, json.sdk_infos, json.attributions, (_a = json.session_interval) !== null && _a !== void 0 ? _a : WTConstants.DEFAULTS.SESSION_INTERVAL, (_b = json.subsession_interval) !== null && _b !== void 0 ? _b : WTConstants.DEFAULTS.SUBSESSION_INTERVAL);
|
|
105
|
+
}
|
|
106
|
+
static get defaultValue() {
|
|
107
|
+
return new WTAppSettings(WTEndpoints.EVENTS, WTEndpoints.SESSIONS, WTEndpoints.SDK_CLICKS, WTEndpoints.SDK_INFOS, WTEndpoints.ATTRIBUTIONS, WTConstants.DEFAULTS.SESSION_INTERVAL, WTConstants.DEFAULTS.SUBSESSION_INTERVAL);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** @internal */
|
|
112
|
+
class WTConfig {
|
|
113
|
+
constructor(baseUrl, events, sessions, sdkClicks, sdkInfos, attributions, appSettings, sdkEnabled = true, forceUpdate = false, sdkUpdate = false, sessionInterval = WTConstants.DEFAULTS.SESSION_INTERVAL, subsessionInterval = WTConstants.DEFAULTS.SUBSESSION_INTERVAL) {
|
|
114
|
+
this.baseUrl = baseUrl;
|
|
115
|
+
this.events = events;
|
|
116
|
+
this.sessions = sessions;
|
|
117
|
+
this.sdkClicks = sdkClicks;
|
|
118
|
+
this.sdkInfos = sdkInfos;
|
|
119
|
+
this.attributions = attributions;
|
|
120
|
+
this.appSettings = appSettings;
|
|
121
|
+
this.sdkEnabled = sdkEnabled;
|
|
122
|
+
this.forceUpdate = forceUpdate;
|
|
123
|
+
this.sdkUpdate = sdkUpdate;
|
|
124
|
+
this.sessionInterval = sessionInterval;
|
|
125
|
+
this.subsessionInterval = subsessionInterval;
|
|
126
|
+
}
|
|
127
|
+
static fromJson(json) {
|
|
128
|
+
var _a, _b, _c, _d, _e;
|
|
129
|
+
return new WTConfig(json.base_url, json.events, json.sessions, json.sdk_clicks, json.sdk_infos, json.attributions, json.app_settings, (_a = json.sdk_enabled) !== null && _a !== void 0 ? _a : true, (_b = json.force_update) !== null && _b !== void 0 ? _b : false, (_c = json.sdk_update) !== null && _c !== void 0 ? _c : false, (_d = json.session_interval) !== null && _d !== void 0 ? _d : WTConstants.DEFAULTS.SESSION_INTERVAL, (_e = json.subsession_interval) !== null && _e !== void 0 ? _e : WTConstants.DEFAULTS.SUBSESSION_INTERVAL);
|
|
130
|
+
}
|
|
131
|
+
static get defaultValue() {
|
|
132
|
+
return new WTConfig(EnvironmentUtils.baseUrl(), WTEndpoints.EVENTS, WTEndpoints.SESSIONS, WTEndpoints.SDK_CLICKS, WTEndpoints.SDK_INFOS, WTEndpoints.ATTRIBUTIONS, WTEndpoints.APP_SETTINGS);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** @internal */
|
|
137
|
+
class WTLogEngine {
|
|
138
|
+
}
|
|
139
|
+
/** @internal */
|
|
140
|
+
class ConsoleLogEngine extends WTLogEngine {
|
|
141
|
+
log(level, prefix, ...args) {
|
|
142
|
+
switch (level) {
|
|
143
|
+
case "debug":
|
|
144
|
+
console.debug(prefix, ...args);
|
|
145
|
+
break;
|
|
146
|
+
case "info":
|
|
147
|
+
console.info(prefix, ...args);
|
|
148
|
+
break;
|
|
149
|
+
case "warn":
|
|
150
|
+
console.warn(prefix, ...args);
|
|
151
|
+
break;
|
|
152
|
+
case "error":
|
|
153
|
+
console.error(prefix, ...args);
|
|
154
|
+
break;
|
|
155
|
+
default:
|
|
156
|
+
console.log(prefix, ...args);
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Defines the available log levels for the SDK.
|
|
163
|
+
*
|
|
164
|
+
* - `DEBUG`: Logs everything, including debug info.
|
|
165
|
+
* - `INFO`: Logs general information.
|
|
166
|
+
* - `WARN`: Logs warnings.
|
|
167
|
+
* - `ERROR`: Logs errors only.
|
|
168
|
+
* - `NONE`: Disables logging.
|
|
169
|
+
*/
|
|
170
|
+
const WTLogLevel = {
|
|
171
|
+
DEBUG: "debug",
|
|
172
|
+
INFO: "info",
|
|
173
|
+
WARN: "warn",
|
|
174
|
+
ERROR: "error",
|
|
175
|
+
NONE: "none",
|
|
176
|
+
};
|
|
177
|
+
/** @internal */
|
|
178
|
+
class WTLogger {
|
|
179
|
+
static setLevel(level) {
|
|
180
|
+
this.level = level;
|
|
181
|
+
}
|
|
182
|
+
static setPrefix(prefix) {
|
|
183
|
+
this.prefix = prefix;
|
|
184
|
+
}
|
|
185
|
+
static addOutputEngine(engine) {
|
|
186
|
+
this.outputEngines.push(engine);
|
|
187
|
+
}
|
|
188
|
+
static shouldLog(type) {
|
|
189
|
+
const levels = ["debug", "info", "warn", "error"];
|
|
190
|
+
const currentIndex = levels.indexOf(this.level);
|
|
191
|
+
const typeIndex = levels.indexOf(type);
|
|
192
|
+
return typeIndex >= currentIndex;
|
|
193
|
+
}
|
|
194
|
+
static log(level, ...args) {
|
|
195
|
+
if (!this.shouldLog(level))
|
|
196
|
+
return;
|
|
197
|
+
const prefix = `[${this.prefix}-${level.toUpperCase()}]`;
|
|
198
|
+
for (const output of this.outputEngines) {
|
|
199
|
+
output.log(level, prefix, ...args);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
static debug(...args) {
|
|
203
|
+
this.log("debug", ...args);
|
|
204
|
+
}
|
|
205
|
+
static info(...args) {
|
|
206
|
+
this.log("info", ...args);
|
|
207
|
+
}
|
|
208
|
+
static warn(...args) {
|
|
209
|
+
this.log("warn", ...args);
|
|
210
|
+
}
|
|
211
|
+
static error(...args) {
|
|
212
|
+
this.log("error", ...args);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
WTLogger.level = WTConstants.DEFAULTS.LOG_LEVEL;
|
|
216
|
+
WTLogger.prefix = "WT";
|
|
217
|
+
WTLogger.outputEngines = [new ConsoleLogEngine()];
|
|
218
|
+
|
|
219
|
+
const WTStorageKeys = {
|
|
220
|
+
DEVICE_ID: "WT.DeviceId",
|
|
221
|
+
INITIAL_DATE: "WT.InitialDate",
|
|
222
|
+
INITIAL_CONFIG: "WT.InitialConfigs",
|
|
223
|
+
CONFIG: "WT.Configs",
|
|
224
|
+
APP_SETTINGS: "WT.AppSettings",
|
|
225
|
+
SDK_CLICK_SUBMIT: "WT.SdkClickSubmit",
|
|
226
|
+
FIRST_SESSION_SUBMIT: "WT.FirstSessionSubmit",
|
|
227
|
+
SDK_ENABLED: "WT.SdkEnabled",
|
|
228
|
+
FCM_TOKEN: "WT.FcmToken", // used for calling push token request
|
|
229
|
+
PUSH_TOKEN: "WT.PushToken", // used in request param fields as "push_token"
|
|
230
|
+
EVENT_COUNT: "WT.EventCount",
|
|
231
|
+
SESSION_COUNT: "WT.SessionCount",
|
|
232
|
+
SESSION_LENGTH: "WT.SessionLenght", // ACTIVE_DURATION
|
|
233
|
+
SUBSESSION_COUNT: "WT.SubSessionCount",
|
|
234
|
+
ACTIVE_TIME: "WT.ActiveTime",
|
|
235
|
+
INACTIVE_TIME: "WT.InactiveTime",
|
|
236
|
+
INACTIVE_DURATION: "WT.InactiveDuration",
|
|
237
|
+
REQUEST_QUEUE: "WT.RequestQueue",
|
|
238
|
+
PENDING_REQUEST_QUEUE: "WT.PendingRequestQueue",
|
|
239
|
+
};
|
|
240
|
+
class StorageManager {
|
|
241
|
+
clear() {
|
|
242
|
+
localStorage.clear();
|
|
243
|
+
}
|
|
244
|
+
setJson(key, obj) {
|
|
245
|
+
if (!obj) {
|
|
246
|
+
localStorage.removeItem(key);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
const encoded = JSON.stringify(obj);
|
|
251
|
+
localStorage.setItem(key, encoded);
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
WTLogger.error(`Error in encoding object for key '${key}'`, error);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
getJson(key) {
|
|
258
|
+
const data = localStorage.getItem(key);
|
|
259
|
+
if (!data) {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
try {
|
|
263
|
+
const decoded = JSON.parse(data);
|
|
264
|
+
return decoded;
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
WTLogger.error(`Error in JSON decoding for key '${key}': ${error}`, error);
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
optionalNumber(key) {
|
|
272
|
+
const value = localStorage.getItem(key);
|
|
273
|
+
if (value === null) {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
const num = Number(value);
|
|
277
|
+
return isNaN(num) ? null : num;
|
|
278
|
+
}
|
|
279
|
+
optionalBool(key) {
|
|
280
|
+
const value = localStorage.getItem(key);
|
|
281
|
+
if (value === null) {
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
return value === "true" ? true : value === "false" ? false : null;
|
|
285
|
+
}
|
|
286
|
+
get deviceId() {
|
|
287
|
+
return localStorage.getItem(WTStorageKeys.DEVICE_ID);
|
|
288
|
+
}
|
|
289
|
+
set deviceId(value) {
|
|
290
|
+
if (value) {
|
|
291
|
+
localStorage.setItem(WTStorageKeys.DEVICE_ID, value);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
localStorage.removeItem(WTStorageKeys.DEVICE_ID);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
get initialDate() {
|
|
298
|
+
return this.getJson(WTStorageKeys.INITIAL_DATE);
|
|
299
|
+
}
|
|
300
|
+
set initialDate(value) {
|
|
301
|
+
this.setJson(WTStorageKeys.INITIAL_DATE, value);
|
|
302
|
+
}
|
|
303
|
+
get initialConfig() {
|
|
304
|
+
return this.getJson(WTStorageKeys.INITIAL_CONFIG);
|
|
305
|
+
}
|
|
306
|
+
set initialConfig(value) {
|
|
307
|
+
this.setJson(WTStorageKeys.INITIAL_CONFIG, value);
|
|
308
|
+
}
|
|
309
|
+
get config() {
|
|
310
|
+
return this.getJson(WTStorageKeys.CONFIG);
|
|
311
|
+
}
|
|
312
|
+
set config(value) {
|
|
313
|
+
this.setJson(WTStorageKeys.CONFIG, value);
|
|
314
|
+
}
|
|
315
|
+
get appSettings() {
|
|
316
|
+
return this.getJson(WTStorageKeys.APP_SETTINGS);
|
|
317
|
+
}
|
|
318
|
+
set appSettings(value) {
|
|
319
|
+
this.setJson(WTStorageKeys.APP_SETTINGS, value);
|
|
320
|
+
}
|
|
321
|
+
get sdkEnabled() {
|
|
322
|
+
var _a;
|
|
323
|
+
return (_a = this.optionalBool(WTStorageKeys.SDK_ENABLED)) !== null && _a !== void 0 ? _a : false;
|
|
324
|
+
}
|
|
325
|
+
set sdkEnabled(value) {
|
|
326
|
+
localStorage.setItem(WTStorageKeys.SDK_ENABLED, value.toString());
|
|
327
|
+
}
|
|
328
|
+
get sdkClickSubmit() {
|
|
329
|
+
var _a;
|
|
330
|
+
return (_a = this.optionalBool(WTStorageKeys.SDK_CLICK_SUBMIT)) !== null && _a !== void 0 ? _a : false;
|
|
331
|
+
}
|
|
332
|
+
set sdkClickSubmit(value) {
|
|
333
|
+
localStorage.setItem(WTStorageKeys.SDK_CLICK_SUBMIT, value.toString());
|
|
334
|
+
}
|
|
335
|
+
get firstSessionSubmit() {
|
|
336
|
+
var _a;
|
|
337
|
+
return (_a = this.optionalBool(WTStorageKeys.FIRST_SESSION_SUBMIT)) !== null && _a !== void 0 ? _a : false;
|
|
338
|
+
}
|
|
339
|
+
set firstSessionSubmit(value) {
|
|
340
|
+
localStorage.setItem(WTStorageKeys.FIRST_SESSION_SUBMIT, value.toString());
|
|
341
|
+
}
|
|
342
|
+
get fcmToken() {
|
|
343
|
+
return localStorage.getItem(WTStorageKeys.FCM_TOKEN);
|
|
344
|
+
}
|
|
345
|
+
set fcmToken(value) {
|
|
346
|
+
if (value) {
|
|
347
|
+
localStorage.setItem(WTStorageKeys.FCM_TOKEN, value);
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
localStorage.removeItem(WTStorageKeys.FCM_TOKEN);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
get pushToken() {
|
|
354
|
+
return localStorage.getItem(WTStorageKeys.PUSH_TOKEN);
|
|
355
|
+
}
|
|
356
|
+
set pushToken(value) {
|
|
357
|
+
if (value) {
|
|
358
|
+
localStorage.setItem(WTStorageKeys.PUSH_TOKEN, value);
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
localStorage.removeItem(WTStorageKeys.PUSH_TOKEN);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
get sessionCount() {
|
|
365
|
+
var _a;
|
|
366
|
+
return (_a = this.optionalNumber(WTStorageKeys.SESSION_COUNT)) !== null && _a !== void 0 ? _a : 1;
|
|
367
|
+
}
|
|
368
|
+
set sessionCount(value) {
|
|
369
|
+
localStorage.setItem(WTStorageKeys.SESSION_COUNT, value.toString());
|
|
370
|
+
}
|
|
371
|
+
get subSessionCount() {
|
|
372
|
+
var _a;
|
|
373
|
+
return (_a = this.optionalNumber(WTStorageKeys.SUBSESSION_COUNT)) !== null && _a !== void 0 ? _a : 1;
|
|
374
|
+
}
|
|
375
|
+
set subSessionCount(value) {
|
|
376
|
+
localStorage.setItem(WTStorageKeys.SUBSESSION_COUNT, value.toString());
|
|
377
|
+
}
|
|
378
|
+
get activeDuration() {
|
|
379
|
+
var _a;
|
|
380
|
+
return (_a = this.optionalNumber(WTStorageKeys.SESSION_LENGTH)) !== null && _a !== void 0 ? _a : 0;
|
|
381
|
+
}
|
|
382
|
+
set activeDuration(value) {
|
|
383
|
+
localStorage.setItem(WTStorageKeys.SESSION_LENGTH, value.toString());
|
|
384
|
+
}
|
|
385
|
+
get inactiveDuration() {
|
|
386
|
+
var _a;
|
|
387
|
+
return (_a = this.optionalNumber(WTStorageKeys.INACTIVE_DURATION)) !== null && _a !== void 0 ? _a : 0;
|
|
388
|
+
}
|
|
389
|
+
set inactiveDuration(value) {
|
|
390
|
+
localStorage.setItem(WTStorageKeys.INACTIVE_DURATION, value.toString());
|
|
391
|
+
}
|
|
392
|
+
get inactiveTime() {
|
|
393
|
+
return this.optionalNumber(WTStorageKeys.ACTIVE_TIME);
|
|
394
|
+
}
|
|
395
|
+
set inactiveTime(value) {
|
|
396
|
+
if (value !== null) {
|
|
397
|
+
localStorage.setItem(WTStorageKeys.ACTIVE_TIME, value.toString());
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
localStorage.removeItem(WTStorageKeys.ACTIVE_TIME);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
get activeTime() {
|
|
404
|
+
return this.optionalNumber(WTStorageKeys.INACTIVE_TIME);
|
|
405
|
+
}
|
|
406
|
+
set activeTime(value) {
|
|
407
|
+
if (value !== null) {
|
|
408
|
+
localStorage.setItem(WTStorageKeys.INACTIVE_TIME, value.toString());
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
localStorage.removeItem(WTStorageKeys.INACTIVE_TIME);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
get requestRecords() {
|
|
415
|
+
var _a;
|
|
416
|
+
return (_a = this.getJson(WTStorageKeys.REQUEST_QUEUE)) !== null && _a !== void 0 ? _a : [];
|
|
417
|
+
}
|
|
418
|
+
set requestRecords(value) {
|
|
419
|
+
this.setJson(WTStorageKeys.REQUEST_QUEUE, value);
|
|
420
|
+
}
|
|
421
|
+
get pendingRequestRecords() {
|
|
422
|
+
var _a;
|
|
423
|
+
return (_a = this.getJson(WTStorageKeys.PENDING_REQUEST_QUEUE)) !== null && _a !== void 0 ? _a : [];
|
|
424
|
+
}
|
|
425
|
+
set pendingRequestRecords(value) {
|
|
426
|
+
this.setJson(WTStorageKeys.PENDING_REQUEST_QUEUE, value);
|
|
427
|
+
}
|
|
428
|
+
get eventCount() {
|
|
429
|
+
var _a;
|
|
430
|
+
return (_a = this.optionalNumber(WTStorageKeys.EVENT_COUNT)) !== null && _a !== void 0 ? _a : 0;
|
|
431
|
+
}
|
|
432
|
+
set eventCount(value) {
|
|
433
|
+
localStorage.setItem(WTStorageKeys.EVENT_COUNT, value.toString());
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
/** @internal */
|
|
437
|
+
const storageManager = new StorageManager();
|
|
438
|
+
|
|
439
|
+
/** @internal */
|
|
440
|
+
var ApiError;
|
|
441
|
+
(function (ApiError) {
|
|
442
|
+
class InvalidUrl extends Error {
|
|
443
|
+
constructor(url) {
|
|
444
|
+
super(`Invalid URL: ${url}`);
|
|
445
|
+
this.name = "InvalidUrl";
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
ApiError.InvalidUrl = InvalidUrl;
|
|
449
|
+
class ServerError extends Error {
|
|
450
|
+
constructor(statusCode, message) {
|
|
451
|
+
super(`ServerError ${statusCode}: ${message}`);
|
|
452
|
+
this.statusCode = statusCode;
|
|
453
|
+
this.message = message;
|
|
454
|
+
this.name = "ServerError";
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
ApiError.ServerError = ServerError;
|
|
458
|
+
class NetworkError extends Error {
|
|
459
|
+
constructor(message) {
|
|
460
|
+
super(`NetworkError: ${message}`);
|
|
461
|
+
this.name = "NetworkFailure";
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
ApiError.NetworkError = NetworkError;
|
|
465
|
+
class DecodingError extends Error {
|
|
466
|
+
constructor(message) {
|
|
467
|
+
super(`DecodingError: ${message}`);
|
|
468
|
+
this.name = "DecodingError";
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
ApiError.DecodingError = DecodingError;
|
|
472
|
+
})(ApiError || (ApiError = {}));
|
|
473
|
+
|
|
474
|
+
/** @internal */
|
|
475
|
+
class RetryPolicy {
|
|
476
|
+
constructor(maxRetries = 3, retryInterval = 2000 // milliseconds
|
|
477
|
+
) {
|
|
478
|
+
this.maxRetries = maxRetries;
|
|
479
|
+
this.retryInterval = retryInterval;
|
|
480
|
+
}
|
|
481
|
+
canRetry(attempt) {
|
|
482
|
+
return attempt < this.maxRetries;
|
|
483
|
+
}
|
|
484
|
+
waitBeforeRetry() {
|
|
485
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
486
|
+
return new Promise((res) => setTimeout(res, this.retryInterval));
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/** @internal */
|
|
492
|
+
const networkManager = {
|
|
493
|
+
retryPolicy() {
|
|
494
|
+
return new RetryPolicy();
|
|
495
|
+
},
|
|
496
|
+
sendRequest(endpoint_1) {
|
|
497
|
+
return __awaiter(this, arguments, void 0, function* (endpoint, options = {}) {
|
|
498
|
+
const retryAttempt = options.retryAttempt || 1;
|
|
499
|
+
WTLogger.debug(`🚀 REQUEST (${retryAttempt}) => ${options.method} ${endpoint}`);
|
|
500
|
+
WTLogger.debug("-- PARAMETERS =>", options.params || options.formData || {});
|
|
501
|
+
let body;
|
|
502
|
+
const requestHeaders = Object.assign({ Accept: "application/json" }, options.headers);
|
|
503
|
+
if (options.formData) {
|
|
504
|
+
const form = new FormData();
|
|
505
|
+
for (const key in options.formData) {
|
|
506
|
+
form.append(key, options.formData[key]);
|
|
507
|
+
}
|
|
508
|
+
body = form;
|
|
509
|
+
}
|
|
510
|
+
else if (options.params) {
|
|
511
|
+
requestHeaders["Content-Type"] = "application/json";
|
|
512
|
+
body = JSON.stringify(options.params);
|
|
513
|
+
}
|
|
514
|
+
try {
|
|
515
|
+
const response = yield fetch(endpoint, {
|
|
516
|
+
method: options.method,
|
|
517
|
+
headers: requestHeaders,
|
|
518
|
+
body,
|
|
519
|
+
});
|
|
520
|
+
if (!response.ok) {
|
|
521
|
+
let json = yield response.json();
|
|
522
|
+
let errorText = json.message || (yield response.text());
|
|
523
|
+
WTLogger.warn(`❌ API ERROR (${response.status}) =>`, errorText);
|
|
524
|
+
throw new ApiError.ServerError(response.status, json.message || "Server error");
|
|
525
|
+
}
|
|
526
|
+
try {
|
|
527
|
+
const result = yield response.json();
|
|
528
|
+
WTLogger.debug(`✅ API SUCCESS (${response.status}) =>`, result.message || "Request successful");
|
|
529
|
+
return result;
|
|
530
|
+
}
|
|
531
|
+
catch (error) {
|
|
532
|
+
throw new ApiError.DecodingError(error.message || String(error));
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
catch (err) {
|
|
536
|
+
if (err instanceof ApiError.ServerError ||
|
|
537
|
+
err instanceof ApiError.DecodingError) {
|
|
538
|
+
throw err;
|
|
539
|
+
}
|
|
540
|
+
WTLogger.error("Error executing request", err);
|
|
541
|
+
if (this.retryPolicy().canRetry(retryAttempt)) {
|
|
542
|
+
yield this.retryPolicy().waitBeforeRetry();
|
|
543
|
+
return this.sendRequest(endpoint, Object.assign(Object.assign({}, options), { retryAttempt: retryAttempt + 1 }));
|
|
544
|
+
}
|
|
545
|
+
throw new ApiError.NetworkError(err.message || "Unknown error");
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
},
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
/** @internal */
|
|
552
|
+
const apiClient = {
|
|
553
|
+
doGetConfig() {
|
|
554
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
555
|
+
const initialConfig = storageManager.initialConfig;
|
|
556
|
+
if (!initialConfig) {
|
|
557
|
+
throw "Initial Config is not set";
|
|
558
|
+
}
|
|
559
|
+
const params = {
|
|
560
|
+
app_token: initialConfig.appToken,
|
|
561
|
+
app_version: initialConfig.appVersion,
|
|
562
|
+
framework: initialConfig.appFrameWork,
|
|
563
|
+
env: EnvironmentUtils.sdkEnvironment,
|
|
564
|
+
sdk_hash: WTConstants.SDK.HASH,
|
|
565
|
+
package_name: window.location.hostname,
|
|
566
|
+
platform: WTConstants.SDK.PLATFORM,
|
|
567
|
+
store_name: "other",
|
|
568
|
+
};
|
|
569
|
+
const response = yield networkManager.sendRequest(WTConstants.CONFIG.BASE_URL, {
|
|
570
|
+
method: "POST",
|
|
571
|
+
formData: params,
|
|
572
|
+
});
|
|
573
|
+
return WTConfig.fromJson(response.result);
|
|
574
|
+
});
|
|
575
|
+
},
|
|
576
|
+
doGetAppSettings() {
|
|
577
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
578
|
+
const initialConfig = storageManager.initialConfig;
|
|
579
|
+
const wtConfig = storageManager.config;
|
|
580
|
+
if (!initialConfig)
|
|
581
|
+
throw "Initial Config is not set";
|
|
582
|
+
if (!wtConfig)
|
|
583
|
+
throw "SDK Config is not set";
|
|
584
|
+
if (!wtConfig.appSettings)
|
|
585
|
+
throw "AppSettings Url is not set";
|
|
586
|
+
const params = {
|
|
587
|
+
app_token: initialConfig.appToken,
|
|
588
|
+
app_version: initialConfig.appVersion,
|
|
589
|
+
framework: initialConfig.appFrameWork,
|
|
590
|
+
env: EnvironmentUtils.sdkEnvironment,
|
|
591
|
+
sdk_hash: WTConstants.SDK.HASH,
|
|
592
|
+
package_name: window.location.hostname,
|
|
593
|
+
platform: WTConstants.SDK.PLATFORM,
|
|
594
|
+
store_name: "other",
|
|
595
|
+
};
|
|
596
|
+
const response = yield networkManager.sendRequest(wtConfig.baseUrl + wtConfig.appSettings, {
|
|
597
|
+
method: "POST",
|
|
598
|
+
formData: params,
|
|
599
|
+
});
|
|
600
|
+
return WTAppSettings.fromJson(response.result);
|
|
601
|
+
});
|
|
602
|
+
},
|
|
603
|
+
doCallRequest(endpoint, params) {
|
|
604
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
605
|
+
const initialConfig = storageManager.initialConfig;
|
|
606
|
+
const wtConfig = storageManager.config;
|
|
607
|
+
if (!initialConfig)
|
|
608
|
+
throw "Initial Config is not set";
|
|
609
|
+
if (!wtConfig)
|
|
610
|
+
throw "SDK Config is not set";
|
|
611
|
+
params.updated_at = new Date().toISOString();
|
|
612
|
+
const response = yield networkManager.sendRequest(wtConfig.baseUrl + endpoint, {
|
|
613
|
+
method: "POST",
|
|
614
|
+
params: {
|
|
615
|
+
needs_response_details: EnvironmentUtils.sdkEnvironment != WTSDKEnvironment.PRODUCTION,
|
|
616
|
+
parameters: params,
|
|
617
|
+
},
|
|
618
|
+
});
|
|
619
|
+
return response.success;
|
|
620
|
+
});
|
|
621
|
+
},
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
// import { WTLogger } from "./logger";
|
|
625
|
+
class ActivityTicker {
|
|
626
|
+
constructor() {
|
|
627
|
+
this.tickerDelay = 1000;
|
|
628
|
+
this.isPaused = false;
|
|
629
|
+
}
|
|
630
|
+
start() {
|
|
631
|
+
if (this.tickerJob) {
|
|
632
|
+
clearInterval(this.tickerJob);
|
|
633
|
+
}
|
|
634
|
+
this.tickerJob = setInterval(() => {
|
|
635
|
+
if (this.isPaused)
|
|
636
|
+
return;
|
|
637
|
+
if (document.hidden)
|
|
638
|
+
return;
|
|
639
|
+
if (!document.hasFocus())
|
|
640
|
+
return;
|
|
641
|
+
console.log(`ActivityTicker: active duration= ${storageManager.activeDuration / 1000}s, inactive duration= ${storageManager.inactiveDuration / 1000}s`);
|
|
642
|
+
storageManager.activeTime = Date.now();
|
|
643
|
+
storageManager.activeDuration += this.tickerDelay;
|
|
644
|
+
}, this.tickerDelay);
|
|
645
|
+
}
|
|
646
|
+
stop() {
|
|
647
|
+
clearInterval(this.tickerJob);
|
|
648
|
+
this.tickerJob = undefined;
|
|
649
|
+
}
|
|
650
|
+
pause() {
|
|
651
|
+
this.isPaused = true;
|
|
652
|
+
}
|
|
653
|
+
resume() {
|
|
654
|
+
this.isPaused = false;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
/** @internal */
|
|
658
|
+
const activityTicker = new ActivityTicker();
|
|
659
|
+
|
|
660
|
+
/** @internal */
|
|
661
|
+
class CountryFinder {
|
|
662
|
+
constructor() {
|
|
663
|
+
this._country = null;
|
|
664
|
+
}
|
|
665
|
+
getCountryCode() {
|
|
666
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
667
|
+
if (!this._country) {
|
|
668
|
+
this._country = yield this.tryAllEndpoints();
|
|
669
|
+
}
|
|
670
|
+
return this._country;
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
tryAllEndpoints() {
|
|
674
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
675
|
+
const endpoints = [
|
|
676
|
+
() => __awaiter(this, void 0, void 0, function* () {
|
|
677
|
+
const res = yield this.fetchWithTimeout("https://api.country.is");
|
|
678
|
+
if (!res.ok)
|
|
679
|
+
throw new Error("country.is failed");
|
|
680
|
+
const json = yield res.json();
|
|
681
|
+
return json.country || null;
|
|
682
|
+
}),
|
|
683
|
+
() => __awaiter(this, void 0, void 0, function* () {
|
|
684
|
+
const res = yield this.fetchWithTimeout("https://free.freeipapi.com/api/json");
|
|
685
|
+
if (!res.ok)
|
|
686
|
+
throw new Error("country.is failed");
|
|
687
|
+
const json = yield res.json();
|
|
688
|
+
return json.countryCode || null;
|
|
689
|
+
}),
|
|
690
|
+
() => __awaiter(this, void 0, void 0, function* () {
|
|
691
|
+
const res = yield this.fetchWithTimeout("https://ipwho.is/");
|
|
692
|
+
if (!res.ok)
|
|
693
|
+
throw new Error("ipwho.is failed");
|
|
694
|
+
const json = yield res.json();
|
|
695
|
+
return json.country_code || null;
|
|
696
|
+
}),
|
|
697
|
+
];
|
|
698
|
+
for (const tryFetch of endpoints) {
|
|
699
|
+
try {
|
|
700
|
+
const countryCode = yield tryFetch();
|
|
701
|
+
if (countryCode)
|
|
702
|
+
return countryCode;
|
|
703
|
+
}
|
|
704
|
+
catch (_) {
|
|
705
|
+
// Try next API
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
return null;
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
fetchWithTimeout(url_1) {
|
|
712
|
+
return __awaiter(this, arguments, void 0, function* (url, timeout = 2000) {
|
|
713
|
+
const controller = new AbortController();
|
|
714
|
+
const id = setTimeout(() => controller.abort(), timeout);
|
|
715
|
+
return fetch(url, { signal: controller.signal }).finally(() => clearTimeout(id));
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
/** @internal */
|
|
720
|
+
const countryFinder = new CountryFinder();
|
|
721
|
+
|
|
722
|
+
/** @internal */
|
|
723
|
+
const cryptoHelper = {
|
|
724
|
+
generateDeviceUUID() {
|
|
725
|
+
return crypto.randomUUID();
|
|
726
|
+
}
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
/** @internal */
|
|
730
|
+
class RequestRecord {
|
|
731
|
+
constructor(endpoint, parameters) {
|
|
732
|
+
this.retryCount = 0;
|
|
733
|
+
this.maxRetries = 3;
|
|
734
|
+
this.id = crypto.randomUUID();
|
|
735
|
+
this.endpoint = endpoint;
|
|
736
|
+
this.parameters = parameters;
|
|
737
|
+
this.createdAt = Date.now();
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
/** @internal */
|
|
741
|
+
class Mutex {
|
|
742
|
+
constructor() {
|
|
743
|
+
this.locked = false;
|
|
744
|
+
this.waitingQueue = [];
|
|
745
|
+
}
|
|
746
|
+
acquire() {
|
|
747
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
748
|
+
return new Promise((resolve) => {
|
|
749
|
+
if (!this.locked) {
|
|
750
|
+
this.locked = true;
|
|
751
|
+
resolve();
|
|
752
|
+
}
|
|
753
|
+
else {
|
|
754
|
+
this.waitingQueue.push(resolve);
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
release() {
|
|
760
|
+
if (this.waitingQueue.length > 0) {
|
|
761
|
+
const next = this.waitingQueue.shift();
|
|
762
|
+
next();
|
|
763
|
+
}
|
|
764
|
+
else {
|
|
765
|
+
this.locked = false;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/** @internal */
|
|
771
|
+
class RequestsQueueManager {
|
|
772
|
+
constructor() {
|
|
773
|
+
this.isInitialized = false;
|
|
774
|
+
this.isProcessing = false;
|
|
775
|
+
this.isCurrentlyProcessing = false;
|
|
776
|
+
this.mutex = new Mutex();
|
|
777
|
+
this.processingInterval = null;
|
|
778
|
+
this.PROCESSING_INTERVAL_MS = 100; // Check queue every 100ms
|
|
779
|
+
// Backoff strategy properties
|
|
780
|
+
this.failedRequestDelay = 0;
|
|
781
|
+
this.MAX_DELAY_MS = 30000; // 30 seconds max delay
|
|
782
|
+
this.BACKOFF_MULTIPLIER = 2;
|
|
783
|
+
this.BASE_DELAY_MS = 1000; // Start with 1 second
|
|
784
|
+
}
|
|
785
|
+
initialize() {
|
|
786
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
787
|
+
// Initialize the queue manager if needed
|
|
788
|
+
this.isInitialized = true;
|
|
789
|
+
if (!this.isProcessing) {
|
|
790
|
+
yield this.startProcessing();
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
shutdown() {
|
|
795
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
796
|
+
if (!this.isInitialized) {
|
|
797
|
+
return; // Nothing to shutdown
|
|
798
|
+
}
|
|
799
|
+
yield this.stopProcessing();
|
|
800
|
+
this.isInitialized = false;
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
startProcessing() {
|
|
804
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
805
|
+
if (!this.isInitialized) {
|
|
806
|
+
WTLogger.warn("Queue Manager is not initialized. Call initialize() first.");
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
yield this.mutex.acquire();
|
|
810
|
+
try {
|
|
811
|
+
if (this.isProcessing) {
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
this.isProcessing = true;
|
|
815
|
+
// Start the processing loop
|
|
816
|
+
this.processingInterval = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
817
|
+
try {
|
|
818
|
+
yield this.processQueues();
|
|
819
|
+
}
|
|
820
|
+
catch (error) {
|
|
821
|
+
WTLogger.error("Error in processing loop:", error);
|
|
822
|
+
}
|
|
823
|
+
}), this.PROCESSING_INTERVAL_MS);
|
|
824
|
+
}
|
|
825
|
+
finally {
|
|
826
|
+
this.mutex.release();
|
|
827
|
+
}
|
|
828
|
+
// Process immediately after releasing the mutex
|
|
829
|
+
yield this.processQueues();
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
stopProcessing() {
|
|
833
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
834
|
+
yield this.mutex.acquire();
|
|
835
|
+
try {
|
|
836
|
+
this.isProcessing = false;
|
|
837
|
+
if (this.processingInterval) {
|
|
838
|
+
clearInterval(this.processingInterval);
|
|
839
|
+
this.processingInterval = null;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
finally {
|
|
843
|
+
this.mutex.release();
|
|
844
|
+
}
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
addRequest(request) {
|
|
848
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
849
|
+
yield this.mutex.acquire();
|
|
850
|
+
try {
|
|
851
|
+
const mainQueue = this.getMainQueue();
|
|
852
|
+
mainQueue.push(request);
|
|
853
|
+
this.saveMainQueue(mainQueue);
|
|
854
|
+
// Reset delay when new request is added (optional - gives fresh chance)
|
|
855
|
+
this.failedRequestDelay = 0;
|
|
856
|
+
// Start processing if not already started
|
|
857
|
+
if (!this.isProcessing) {
|
|
858
|
+
// Release mutex before starting processing
|
|
859
|
+
this.mutex.release();
|
|
860
|
+
yield this.startProcessing();
|
|
861
|
+
return; // Exit early since mutex was already released
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
finally {
|
|
865
|
+
// Only release if we haven't already released above
|
|
866
|
+
if (this.isProcessing) {
|
|
867
|
+
this.mutex.release();
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
addPendingRequest(request) {
|
|
873
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
874
|
+
yield this.mutex.acquire();
|
|
875
|
+
try {
|
|
876
|
+
const mainRequestsSent = this.getMainRequestsSentFlag();
|
|
877
|
+
if (mainRequestsSent) {
|
|
878
|
+
// Main requests have been sent, add to main queue directly
|
|
879
|
+
const mainQueue = this.getMainQueue();
|
|
880
|
+
mainQueue.push(request);
|
|
881
|
+
this.saveMainQueue(mainQueue);
|
|
882
|
+
}
|
|
883
|
+
else {
|
|
884
|
+
// Main requests not sent yet, add to pending queue
|
|
885
|
+
const pendingQueue = this.getPendingQueue();
|
|
886
|
+
pendingQueue.push(request);
|
|
887
|
+
this.savePendingQueue(pendingQueue);
|
|
888
|
+
}
|
|
889
|
+
// Reset delay when new request is added
|
|
890
|
+
this.failedRequestDelay = 0;
|
|
891
|
+
// Start processing if not already started
|
|
892
|
+
if (!this.isProcessing) {
|
|
893
|
+
// Release mutex before starting processing
|
|
894
|
+
this.mutex.release();
|
|
895
|
+
yield this.startProcessing();
|
|
896
|
+
return; // Exit early since mutex was already released
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
finally {
|
|
900
|
+
// Only release if we haven't already released above
|
|
901
|
+
if (this.isProcessing) {
|
|
902
|
+
this.mutex.release();
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
processQueues() {
|
|
908
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
909
|
+
if (!this.isProcessing || this.isCurrentlyProcessing) {
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
// Check if we're in delay period
|
|
913
|
+
if (this.failedRequestDelay > 0) {
|
|
914
|
+
if (Date.now() < this.failedRequestDelay) {
|
|
915
|
+
return; // Still in delay period
|
|
916
|
+
}
|
|
917
|
+
// Delay period ended
|
|
918
|
+
this.failedRequestDelay = 0;
|
|
919
|
+
WTLogger.debug("⏰ Backoff delay ended, resuming queue processing");
|
|
920
|
+
}
|
|
921
|
+
this.isCurrentlyProcessing = true;
|
|
922
|
+
yield this.mutex.acquire();
|
|
923
|
+
try {
|
|
924
|
+
yield this.processMainQueue();
|
|
925
|
+
yield this.processPendingQueue();
|
|
926
|
+
}
|
|
927
|
+
finally {
|
|
928
|
+
this.mutex.release();
|
|
929
|
+
this.isCurrentlyProcessing = false;
|
|
930
|
+
}
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
processMainQueue() {
|
|
934
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
935
|
+
const mainQueue = this.getMainQueue();
|
|
936
|
+
if (mainQueue.length === 0) {
|
|
937
|
+
return;
|
|
938
|
+
}
|
|
939
|
+
// Take the first request
|
|
940
|
+
const request = mainQueue[0];
|
|
941
|
+
try {
|
|
942
|
+
const success = yield this.sendRequest(request);
|
|
943
|
+
if (success) {
|
|
944
|
+
// Remove the processed request from queue
|
|
945
|
+
mainQueue.shift();
|
|
946
|
+
this.saveMainQueue(mainQueue);
|
|
947
|
+
// Set flag that main requests have been sent
|
|
948
|
+
this.postRequestCheck(request);
|
|
949
|
+
WTLogger.debug(`✅ Request ${request.id} processed successfully`);
|
|
950
|
+
}
|
|
951
|
+
else {
|
|
952
|
+
// Update retry count in the queue (not just in memory)
|
|
953
|
+
mainQueue[0].retryCount++;
|
|
954
|
+
if (mainQueue[0].retryCount >= mainQueue[0].maxRetries) {
|
|
955
|
+
// Calculate backoff delay
|
|
956
|
+
const delayMs = this.calculateBackoffDelay(mainQueue[0].retryCount);
|
|
957
|
+
this.failedRequestDelay = Date.now() + delayMs;
|
|
958
|
+
WTLogger.warn(`⏳ Request ${request.id} failed after ${request.maxRetries} attempts. ` +
|
|
959
|
+
`Applying backoff delay of ${delayMs}ms`);
|
|
960
|
+
}
|
|
961
|
+
else {
|
|
962
|
+
WTLogger.warn(`⚠️ Request ${request.id} failed. Retry ${mainQueue[0].retryCount}/${mainQueue[0].maxRetries}`);
|
|
963
|
+
}
|
|
964
|
+
// Save the updated queue with new retry count
|
|
965
|
+
this.saveMainQueue(mainQueue);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
catch (error) {
|
|
969
|
+
WTLogger.error(`Error sending request ${request.endpoint}:`, error);
|
|
970
|
+
// Update retry count in storage
|
|
971
|
+
mainQueue[0].retryCount++;
|
|
972
|
+
if (mainQueue[0].retryCount >= mainQueue[0].maxRetries) {
|
|
973
|
+
// Apply backoff delay instead of removing
|
|
974
|
+
const delayMs = this.calculateBackoffDelay(mainQueue[0].retryCount);
|
|
975
|
+
this.failedRequestDelay = Date.now() + delayMs;
|
|
976
|
+
WTLogger.warn(`⏳ Request ${request.id} failed with error after ${mainQueue[0].maxRetries} attempts. ` +
|
|
977
|
+
`Applying backoff delay of ${delayMs}ms`);
|
|
978
|
+
}
|
|
979
|
+
// Save the updated queue
|
|
980
|
+
this.saveMainQueue(mainQueue);
|
|
981
|
+
}
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
calculateBackoffDelay(retryCount) {
|
|
985
|
+
// Exponential backoff: baseDelay * (multiplier ^ (retryCount - 1))
|
|
986
|
+
const delay = this.BASE_DELAY_MS * Math.pow(this.BACKOFF_MULTIPLIER, retryCount - 1);
|
|
987
|
+
return Math.min(delay, this.MAX_DELAY_MS);
|
|
988
|
+
}
|
|
989
|
+
processPendingQueue() {
|
|
990
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
991
|
+
const mainRequestsSent = this.getMainRequestsSentFlag();
|
|
992
|
+
if (!mainRequestsSent) {
|
|
993
|
+
return; // Main requests haven't been sent yet
|
|
994
|
+
}
|
|
995
|
+
const pendingQueue = this.getPendingQueue();
|
|
996
|
+
if (pendingQueue.length === 0) {
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
// Move all pending requests to main queue
|
|
1000
|
+
const mainQueue = this.getMainQueue();
|
|
1001
|
+
mainQueue.push(...pendingQueue);
|
|
1002
|
+
// Clear pending queue
|
|
1003
|
+
this.saveMainQueue(mainQueue);
|
|
1004
|
+
this.savePendingQueue([]);
|
|
1005
|
+
console.log(`📦 Moved ${pendingQueue.length} pending requests to main queue`);
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
sendRequest(request_1) {
|
|
1009
|
+
return __awaiter(this, arguments, void 0, function* (request, attempt = 1) {
|
|
1010
|
+
WTLogger.debug(`💥 Sending request (${request.endpoint}): id=${request.id}`);
|
|
1011
|
+
let result = false;
|
|
1012
|
+
try {
|
|
1013
|
+
result = yield apiClient.doCallRequest(request.endpoint, request.parameters);
|
|
1014
|
+
}
|
|
1015
|
+
catch (error) {
|
|
1016
|
+
WTLogger.error(`❌ Request ${request.endpoint} failed`, error);
|
|
1017
|
+
}
|
|
1018
|
+
return result;
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
getMainQueue() {
|
|
1022
|
+
return storageManager.requestRecords;
|
|
1023
|
+
}
|
|
1024
|
+
saveMainQueue(queue) {
|
|
1025
|
+
storageManager.requestRecords = queue;
|
|
1026
|
+
}
|
|
1027
|
+
getPendingQueue() {
|
|
1028
|
+
return storageManager.pendingRequestRecords;
|
|
1029
|
+
}
|
|
1030
|
+
savePendingQueue(queue) {
|
|
1031
|
+
storageManager.pendingRequestRecords = queue;
|
|
1032
|
+
}
|
|
1033
|
+
getMainRequestsSentFlag() {
|
|
1034
|
+
return storageManager.sdkClickSubmit;
|
|
1035
|
+
}
|
|
1036
|
+
postRequestCheck(request) {
|
|
1037
|
+
switch (request.endpoint) {
|
|
1038
|
+
case WTEndpoints.SDK_CLICKS:
|
|
1039
|
+
storageManager.sdkClickSubmit = true;
|
|
1040
|
+
break;
|
|
1041
|
+
case WTEndpoints.SESSIONS:
|
|
1042
|
+
if (storageManager.firstSessionSubmit) {
|
|
1043
|
+
storageManager.activeDuration = 0;
|
|
1044
|
+
storageManager.inactiveDuration = 0;
|
|
1045
|
+
storageManager.subSessionCount = 1;
|
|
1046
|
+
}
|
|
1047
|
+
else {
|
|
1048
|
+
storageManager.firstSessionSubmit = true;
|
|
1049
|
+
}
|
|
1050
|
+
break;
|
|
1051
|
+
case WTEndpoints.SDK_INFOS:
|
|
1052
|
+
storageManager.fcmToken = request.parameters.push_token;
|
|
1053
|
+
break;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
getQueueStatus() {
|
|
1057
|
+
return {
|
|
1058
|
+
mainQueueLength: this.getMainQueue().length,
|
|
1059
|
+
pendingQueueLength: this.getPendingQueue().length,
|
|
1060
|
+
isProcessing: this.isProcessing,
|
|
1061
|
+
mainRequestsSent: this.getMainRequestsSentFlag(),
|
|
1062
|
+
isInBackoffDelay: this.failedRequestDelay > 0 && Date.now() < this.failedRequestDelay,
|
|
1063
|
+
backoffEndsAt: this.failedRequestDelay > 0 ? this.failedRequestDelay : null,
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
1067
|
+
* Manually reset backoff delay (useful for testing or manual recovery)
|
|
1068
|
+
*/
|
|
1069
|
+
resetBackoffDelay() {
|
|
1070
|
+
this.failedRequestDelay = 0;
|
|
1071
|
+
WTLogger.debug("🔄 Backoff delay manually reset");
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Get current backoff delay configuration
|
|
1075
|
+
*/
|
|
1076
|
+
getBackoffConfig() {
|
|
1077
|
+
return {
|
|
1078
|
+
baseDelayMs: this.BASE_DELAY_MS,
|
|
1079
|
+
multiplier: this.BACKOFF_MULTIPLIER,
|
|
1080
|
+
maxDelayMs: this.MAX_DELAY_MS,
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
/** @internal */
|
|
1085
|
+
const queueManager = new RequestsQueueManager();
|
|
1086
|
+
|
|
1087
|
+
// Generated ESM version of ua-parser-js
|
|
1088
|
+
// DO NOT EDIT THIS FILE!
|
|
1089
|
+
// Source: /src/main/ua-parser.js
|
|
1090
|
+
|
|
1091
|
+
/////////////////////////////////////////////////////////////////////////////////
|
|
1092
|
+
/* UAParser.js v2.0.4
|
|
1093
|
+
Copyright © 2012-2025 Faisal Salman <f@faisalman.com>
|
|
1094
|
+
AGPLv3 License *//*
|
|
1095
|
+
Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
|
|
1096
|
+
Supports browser & node.js environment.
|
|
1097
|
+
Demo : https://uaparser.dev
|
|
1098
|
+
Source : https://github.com/faisalman/ua-parser-js */
|
|
1099
|
+
/////////////////////////////////////////////////////////////////////////////////
|
|
1100
|
+
|
|
1101
|
+
/* jshint esversion: 6 */
|
|
1102
|
+
/* globals window */
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
|
|
1106
|
+
//////////////
|
|
1107
|
+
// Constants
|
|
1108
|
+
/////////////
|
|
1109
|
+
|
|
1110
|
+
var LIBVERSION = '2.0.4',
|
|
1111
|
+
UA_MAX_LENGTH = 500,
|
|
1112
|
+
USER_AGENT = 'user-agent',
|
|
1113
|
+
EMPTY = '',
|
|
1114
|
+
UNKNOWN = '?',
|
|
1115
|
+
|
|
1116
|
+
// typeof
|
|
1117
|
+
FUNC_TYPE = 'function',
|
|
1118
|
+
UNDEF_TYPE = 'undefined',
|
|
1119
|
+
OBJ_TYPE = 'object',
|
|
1120
|
+
STR_TYPE = 'string',
|
|
1121
|
+
|
|
1122
|
+
// properties
|
|
1123
|
+
UA_BROWSER = 'browser',
|
|
1124
|
+
UA_CPU = 'cpu',
|
|
1125
|
+
UA_DEVICE = 'device',
|
|
1126
|
+
UA_ENGINE = 'engine',
|
|
1127
|
+
UA_OS = 'os',
|
|
1128
|
+
UA_RESULT = 'result',
|
|
1129
|
+
|
|
1130
|
+
NAME = 'name',
|
|
1131
|
+
TYPE = 'type',
|
|
1132
|
+
VENDOR = 'vendor',
|
|
1133
|
+
VERSION = 'version',
|
|
1134
|
+
ARCHITECTURE= 'architecture',
|
|
1135
|
+
MAJOR = 'major',
|
|
1136
|
+
MODEL = 'model',
|
|
1137
|
+
|
|
1138
|
+
// device types
|
|
1139
|
+
CONSOLE = 'console',
|
|
1140
|
+
MOBILE = 'mobile',
|
|
1141
|
+
TABLET = 'tablet',
|
|
1142
|
+
SMARTTV = 'smarttv',
|
|
1143
|
+
WEARABLE = 'wearable',
|
|
1144
|
+
XR = 'xr',
|
|
1145
|
+
EMBEDDED = 'embedded',
|
|
1146
|
+
|
|
1147
|
+
// browser types
|
|
1148
|
+
INAPP = 'inapp',
|
|
1149
|
+
|
|
1150
|
+
// client hints
|
|
1151
|
+
BRANDS = 'brands',
|
|
1152
|
+
FORMFACTORS = 'formFactors',
|
|
1153
|
+
FULLVERLIST = 'fullVersionList',
|
|
1154
|
+
PLATFORM = 'platform',
|
|
1155
|
+
PLATFORMVER = 'platformVersion',
|
|
1156
|
+
BITNESS = 'bitness',
|
|
1157
|
+
CH_HEADER = 'sec-ch-ua',
|
|
1158
|
+
CH_HEADER_FULL_VER_LIST = CH_HEADER + '-full-version-list',
|
|
1159
|
+
CH_HEADER_ARCH = CH_HEADER + '-arch',
|
|
1160
|
+
CH_HEADER_BITNESS = CH_HEADER + '-' + BITNESS,
|
|
1161
|
+
CH_HEADER_FORM_FACTORS = CH_HEADER + '-form-factors',
|
|
1162
|
+
CH_HEADER_MOBILE = CH_HEADER + '-' + MOBILE,
|
|
1163
|
+
CH_HEADER_MODEL = CH_HEADER + '-' + MODEL,
|
|
1164
|
+
CH_HEADER_PLATFORM = CH_HEADER + '-' + PLATFORM,
|
|
1165
|
+
CH_HEADER_PLATFORM_VER = CH_HEADER_PLATFORM + '-version',
|
|
1166
|
+
CH_ALL_VALUES = [BRANDS, FULLVERLIST, MOBILE, MODEL, PLATFORM, PLATFORMVER, ARCHITECTURE, FORMFACTORS, BITNESS],
|
|
1167
|
+
|
|
1168
|
+
// device vendors
|
|
1169
|
+
AMAZON = 'Amazon',
|
|
1170
|
+
APPLE = 'Apple',
|
|
1171
|
+
ASUS = 'ASUS',
|
|
1172
|
+
BLACKBERRY = 'BlackBerry',
|
|
1173
|
+
GOOGLE = 'Google',
|
|
1174
|
+
HUAWEI = 'Huawei',
|
|
1175
|
+
LENOVO = 'Lenovo',
|
|
1176
|
+
HONOR = 'Honor',
|
|
1177
|
+
LG = 'LG',
|
|
1178
|
+
MICROSOFT = 'Microsoft',
|
|
1179
|
+
MOTOROLA = 'Motorola',
|
|
1180
|
+
NVIDIA = 'Nvidia',
|
|
1181
|
+
ONEPLUS = 'OnePlus',
|
|
1182
|
+
OPPO = 'OPPO',
|
|
1183
|
+
SAMSUNG = 'Samsung',
|
|
1184
|
+
SHARP = 'Sharp',
|
|
1185
|
+
SONY = 'Sony',
|
|
1186
|
+
XIAOMI = 'Xiaomi',
|
|
1187
|
+
ZEBRA = 'Zebra',
|
|
1188
|
+
|
|
1189
|
+
// browsers
|
|
1190
|
+
CHROME = 'Chrome',
|
|
1191
|
+
CHROMIUM = 'Chromium',
|
|
1192
|
+
CHROMECAST = 'Chromecast',
|
|
1193
|
+
EDGE = 'Edge',
|
|
1194
|
+
FIREFOX = 'Firefox',
|
|
1195
|
+
OPERA = 'Opera',
|
|
1196
|
+
FACEBOOK = 'Facebook',
|
|
1197
|
+
SOGOU = 'Sogou',
|
|
1198
|
+
|
|
1199
|
+
PREFIX_MOBILE = 'Mobile ',
|
|
1200
|
+
SUFFIX_BROWSER = ' Browser',
|
|
1201
|
+
|
|
1202
|
+
// os
|
|
1203
|
+
WINDOWS = 'Windows';
|
|
1204
|
+
|
|
1205
|
+
var isWindow = typeof window !== UNDEF_TYPE,
|
|
1206
|
+
NAVIGATOR = (isWindow && window.navigator) ?
|
|
1207
|
+
window.navigator :
|
|
1208
|
+
undefined,
|
|
1209
|
+
NAVIGATOR_UADATA = (NAVIGATOR && NAVIGATOR.userAgentData) ?
|
|
1210
|
+
NAVIGATOR.userAgentData :
|
|
1211
|
+
undefined;
|
|
1212
|
+
|
|
1213
|
+
///////////
|
|
1214
|
+
// Helper
|
|
1215
|
+
//////////
|
|
1216
|
+
|
|
1217
|
+
var extend = function (defaultRgx, extensions) {
|
|
1218
|
+
var mergedRgx = {};
|
|
1219
|
+
var extraRgx = extensions;
|
|
1220
|
+
if (!isExtensions(extensions)) {
|
|
1221
|
+
extraRgx = {};
|
|
1222
|
+
for (var i in extensions) {
|
|
1223
|
+
for (var j in extensions[i]) {
|
|
1224
|
+
extraRgx[j] = extensions[i][j].concat(extraRgx[j] ? extraRgx[j] : []);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
for (var k in defaultRgx) {
|
|
1229
|
+
mergedRgx[k] = extraRgx[k] && extraRgx[k].length % 2 === 0 ? extraRgx[k].concat(defaultRgx[k]) : defaultRgx[k];
|
|
1230
|
+
}
|
|
1231
|
+
return mergedRgx;
|
|
1232
|
+
},
|
|
1233
|
+
enumerize = function (arr) {
|
|
1234
|
+
var enums = {};
|
|
1235
|
+
for (var i=0; i<arr.length; i++) {
|
|
1236
|
+
enums[arr[i].toUpperCase()] = arr[i];
|
|
1237
|
+
}
|
|
1238
|
+
return enums;
|
|
1239
|
+
},
|
|
1240
|
+
has = function (str1, str2) {
|
|
1241
|
+
if (typeof str1 === OBJ_TYPE && str1.length > 0) {
|
|
1242
|
+
for (var i in str1) {
|
|
1243
|
+
if (lowerize(str2) == lowerize(str1[i])) return true;
|
|
1244
|
+
}
|
|
1245
|
+
return false;
|
|
1246
|
+
}
|
|
1247
|
+
return isString(str1) ? lowerize(str2) == lowerize(str1) : false;
|
|
1248
|
+
},
|
|
1249
|
+
isExtensions = function (obj, deep) {
|
|
1250
|
+
for (var prop in obj) {
|
|
1251
|
+
return /^(browser|cpu|device|engine|os)$/.test(prop) || (deep ? isExtensions(obj[prop]) : false);
|
|
1252
|
+
}
|
|
1253
|
+
},
|
|
1254
|
+
isString = function (val) {
|
|
1255
|
+
return typeof val === STR_TYPE;
|
|
1256
|
+
},
|
|
1257
|
+
itemListToArray = function (header) {
|
|
1258
|
+
if (!header) return undefined;
|
|
1259
|
+
var arr = [];
|
|
1260
|
+
var tokens = strip(/\\?\"/g, header).split(',');
|
|
1261
|
+
for (var i = 0; i < tokens.length; i++) {
|
|
1262
|
+
if (tokens[i].indexOf(';') > -1) {
|
|
1263
|
+
var token = trim(tokens[i]).split(';v=');
|
|
1264
|
+
arr[i] = { brand : token[0], version : token[1] };
|
|
1265
|
+
} else {
|
|
1266
|
+
arr[i] = trim(tokens[i]);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
return arr;
|
|
1270
|
+
},
|
|
1271
|
+
lowerize = function (str) {
|
|
1272
|
+
return isString(str) ? str.toLowerCase() : str;
|
|
1273
|
+
},
|
|
1274
|
+
majorize = function (version) {
|
|
1275
|
+
return isString(version) ? strip(/[^\d\.]/g, version).split('.')[0] : undefined;
|
|
1276
|
+
},
|
|
1277
|
+
setProps = function (arr) {
|
|
1278
|
+
for (var i in arr) {
|
|
1279
|
+
var propName = arr[i];
|
|
1280
|
+
if (typeof propName == OBJ_TYPE && propName.length == 2) {
|
|
1281
|
+
this[propName[0]] = propName[1];
|
|
1282
|
+
} else {
|
|
1283
|
+
this[propName] = undefined;
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
return this;
|
|
1287
|
+
},
|
|
1288
|
+
strip = function (pattern, str) {
|
|
1289
|
+
return isString(str) ? str.replace(pattern, EMPTY) : str;
|
|
1290
|
+
},
|
|
1291
|
+
stripQuotes = function (str) {
|
|
1292
|
+
return strip(/\\?\"/g, str);
|
|
1293
|
+
},
|
|
1294
|
+
trim = function (str, len) {
|
|
1295
|
+
if (isString(str)) {
|
|
1296
|
+
str = strip(/^\s\s*/, str);
|
|
1297
|
+
return typeof len === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH);
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
|
|
1301
|
+
///////////////
|
|
1302
|
+
// Map helper
|
|
1303
|
+
//////////////
|
|
1304
|
+
|
|
1305
|
+
var rgxMapper = function (ua, arrays) {
|
|
1306
|
+
|
|
1307
|
+
if(!ua || !arrays) return;
|
|
1308
|
+
|
|
1309
|
+
var i = 0, j, k, p, q, matches, match;
|
|
1310
|
+
|
|
1311
|
+
// loop through all regexes maps
|
|
1312
|
+
while (i < arrays.length && !matches) {
|
|
1313
|
+
|
|
1314
|
+
var regex = arrays[i], // even sequence (0,2,4,..)
|
|
1315
|
+
props = arrays[i + 1]; // odd sequence (1,3,5,..)
|
|
1316
|
+
j = k = 0;
|
|
1317
|
+
|
|
1318
|
+
// try matching uastring with regexes
|
|
1319
|
+
while (j < regex.length && !matches) {
|
|
1320
|
+
|
|
1321
|
+
if (!regex[j]) { break; }
|
|
1322
|
+
matches = regex[j++].exec(ua);
|
|
1323
|
+
|
|
1324
|
+
if (!!matches) {
|
|
1325
|
+
for (p = 0; p < props.length; p++) {
|
|
1326
|
+
match = matches[++k];
|
|
1327
|
+
q = props[p];
|
|
1328
|
+
// check if given property is actually array
|
|
1329
|
+
if (typeof q === OBJ_TYPE && q.length > 0) {
|
|
1330
|
+
if (q.length === 2) {
|
|
1331
|
+
if (typeof q[1] == FUNC_TYPE) {
|
|
1332
|
+
// assign modified match
|
|
1333
|
+
this[q[0]] = q[1].call(this, match);
|
|
1334
|
+
} else {
|
|
1335
|
+
// assign given value, ignore regex match
|
|
1336
|
+
this[q[0]] = q[1];
|
|
1337
|
+
}
|
|
1338
|
+
} else if (q.length >= 3) {
|
|
1339
|
+
// Check whether q[1] FUNCTION or REGEX
|
|
1340
|
+
if (typeof q[1] === FUNC_TYPE && !(q[1].exec && q[1].test)) {
|
|
1341
|
+
if (q.length > 3) {
|
|
1342
|
+
this[q[0]] = match ? q[1].apply(this, q.slice(2)) : undefined;
|
|
1343
|
+
} else {
|
|
1344
|
+
// call function (usually string mapper)
|
|
1345
|
+
this[q[0]] = match ? q[1].call(this, match, q[2]) : undefined;
|
|
1346
|
+
}
|
|
1347
|
+
} else {
|
|
1348
|
+
if (q.length == 3) {
|
|
1349
|
+
// sanitize match using given regex
|
|
1350
|
+
this[q[0]] = match ? match.replace(q[1], q[2]) : undefined;
|
|
1351
|
+
} else if (q.length == 4) {
|
|
1352
|
+
this[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined;
|
|
1353
|
+
} else if (q.length > 4) {
|
|
1354
|
+
this[q[0]] = match ? q[3].apply(this, [match.replace(q[1], q[2])].concat(q.slice(4))) : undefined;
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
} else {
|
|
1359
|
+
this[q] = match ? match : undefined;
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
i += 2;
|
|
1365
|
+
}
|
|
1366
|
+
},
|
|
1367
|
+
|
|
1368
|
+
strMapper = function (str, map) {
|
|
1369
|
+
|
|
1370
|
+
for (var i in map) {
|
|
1371
|
+
// check if current value is array
|
|
1372
|
+
if (typeof map[i] === OBJ_TYPE && map[i].length > 0) {
|
|
1373
|
+
for (var j = 0; j < map[i].length; j++) {
|
|
1374
|
+
if (has(map[i][j], str)) {
|
|
1375
|
+
return (i === UNKNOWN) ? undefined : i;
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
} else if (has(map[i], str)) {
|
|
1379
|
+
return (i === UNKNOWN) ? undefined : i;
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
return map.hasOwnProperty('*') ? map['*'] : str;
|
|
1383
|
+
};
|
|
1384
|
+
|
|
1385
|
+
///////////////
|
|
1386
|
+
// String map
|
|
1387
|
+
//////////////
|
|
1388
|
+
|
|
1389
|
+
var windowsVersionMap = {
|
|
1390
|
+
'ME' : '4.90',
|
|
1391
|
+
'NT 3.51': '3.51',
|
|
1392
|
+
'NT 4.0': '4.0',
|
|
1393
|
+
'2000' : ['5.0', '5.01'],
|
|
1394
|
+
'XP' : ['5.1', '5.2'],
|
|
1395
|
+
'Vista' : '6.0',
|
|
1396
|
+
'7' : '6.1',
|
|
1397
|
+
'8' : '6.2',
|
|
1398
|
+
'8.1' : '6.3',
|
|
1399
|
+
'10' : ['6.4', '10.0'],
|
|
1400
|
+
'NT' : ''
|
|
1401
|
+
},
|
|
1402
|
+
|
|
1403
|
+
formFactorsMap = {
|
|
1404
|
+
'embedded' : 'Automotive',
|
|
1405
|
+
'mobile' : 'Mobile',
|
|
1406
|
+
'tablet' : ['Tablet', 'EInk'],
|
|
1407
|
+
'smarttv' : 'TV',
|
|
1408
|
+
'wearable' : 'Watch',
|
|
1409
|
+
'xr' : ['VR', 'XR'],
|
|
1410
|
+
'?' : ['Desktop', 'Unknown'],
|
|
1411
|
+
'*' : undefined
|
|
1412
|
+
},
|
|
1413
|
+
|
|
1414
|
+
browserHintsMap = {
|
|
1415
|
+
'Chrome' : 'Google Chrome',
|
|
1416
|
+
'Edge' : 'Microsoft Edge',
|
|
1417
|
+
'Edge WebView2' : 'Microsoft Edge WebView2',
|
|
1418
|
+
'Chrome WebView': 'Android WebView',
|
|
1419
|
+
'Chrome Headless':'HeadlessChrome',
|
|
1420
|
+
'Huawei Browser': 'HuaweiBrowser',
|
|
1421
|
+
'MIUI Browser' : 'Miui Browser',
|
|
1422
|
+
'Opera Mobi' : 'OperaMobile',
|
|
1423
|
+
'Yandex' : 'YaBrowser'
|
|
1424
|
+
};
|
|
1425
|
+
|
|
1426
|
+
//////////////
|
|
1427
|
+
// Regex map
|
|
1428
|
+
/////////////
|
|
1429
|
+
|
|
1430
|
+
var defaultRegexes = {
|
|
1431
|
+
|
|
1432
|
+
browser : [[
|
|
1433
|
+
|
|
1434
|
+
// Most common regardless engine
|
|
1435
|
+
/\b(?:crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS
|
|
1436
|
+
], [VERSION, [NAME, PREFIX_MOBILE + 'Chrome']], [
|
|
1437
|
+
/webview.+edge\/([\w\.]+)/i // Microsoft Edge
|
|
1438
|
+
], [VERSION, [NAME, EDGE+' WebView']], [
|
|
1439
|
+
/edg(?:e|ios|a)?\/([\w\.]+)/i
|
|
1440
|
+
], [VERSION, [NAME, 'Edge']], [
|
|
1441
|
+
|
|
1442
|
+
// Presto based
|
|
1443
|
+
/(opera mini)\/([-\w\.]+)/i, // Opera Mini
|
|
1444
|
+
/(opera [mobiletab]{3,6})\b.+version\/([-\w\.]+)/i, // Opera Mobi/Tablet
|
|
1445
|
+
/(opera)(?:.+version\/|[\/ ]+)([\w\.]+)/i // Opera
|
|
1446
|
+
], [NAME, VERSION], [
|
|
1447
|
+
/opios[\/ ]+([\w\.]+)/i // Opera mini on iphone >= 8.0
|
|
1448
|
+
], [VERSION, [NAME, OPERA+' Mini']], [
|
|
1449
|
+
/\bop(?:rg)?x\/([\w\.]+)/i // Opera GX
|
|
1450
|
+
], [VERSION, [NAME, OPERA+' GX']], [
|
|
1451
|
+
/\bopr\/([\w\.]+)/i // Opera Webkit
|
|
1452
|
+
], [VERSION, [NAME, OPERA]], [
|
|
1453
|
+
|
|
1454
|
+
// Mixed
|
|
1455
|
+
/\bb[ai]*d(?:uhd|[ub]*[aekoprswx]{5,6})[\/ ]?([\w\.]+)/i // Baidu
|
|
1456
|
+
], [VERSION, [NAME, 'Baidu']], [
|
|
1457
|
+
/\b(?:mxbrowser|mxios|myie2)\/?([-\w\.]*)\b/i // Maxthon
|
|
1458
|
+
], [VERSION, [NAME, 'Maxthon']], [
|
|
1459
|
+
/(kindle)\/([\w\.]+)/i, // Kindle
|
|
1460
|
+
/(lunascape|maxthon|netfront|jasmine|blazer|sleipnir)[\/ ]?([\w\.]*)/i,
|
|
1461
|
+
// Lunascape/Maxthon/Netfront/Jasmine/Blazer/Sleipnir
|
|
1462
|
+
// Trident based
|
|
1463
|
+
/(avant|iemobile|slim(?:browser|boat|jet))[\/ ]?([\d\.]*)/i, // Avant/IEMobile/SlimBrowser/SlimBoat/Slimjet
|
|
1464
|
+
/(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer
|
|
1465
|
+
|
|
1466
|
+
// Blink/Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon/LG Browser/Otter/qutebrowser/Dooble
|
|
1467
|
+
/(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar|helio|(?=comodo_)?dragon|otter|dooble|(?:lg |qute)browser)\/([-\w\.]+)/i,
|
|
1468
|
+
// Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar/Helio/Dragon
|
|
1469
|
+
/(heytap|ovi|115|surf)browser\/([\d\.]+)/i, // HeyTap/Ovi/115/Surf
|
|
1470
|
+
/(ecosia|weibo)(?:__| \w+@)([\d\.]+)/i // Ecosia/Weibo
|
|
1471
|
+
], [NAME, VERSION], [
|
|
1472
|
+
/quark(?:pc)?\/([-\w\.]+)/i // Quark
|
|
1473
|
+
], [VERSION, [NAME, 'Quark']], [
|
|
1474
|
+
/\bddg\/([\w\.]+)/i // DuckDuckGo
|
|
1475
|
+
], [VERSION, [NAME, 'DuckDuckGo']], [
|
|
1476
|
+
/(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser
|
|
1477
|
+
], [VERSION, [NAME, 'UCBrowser']], [
|
|
1478
|
+
/microm.+\bqbcore\/([\w\.]+)/i, // WeChat Desktop for Windows Built-in Browser
|
|
1479
|
+
/\bqbcore\/([\w\.]+).+microm/i,
|
|
1480
|
+
/micromessenger\/([\w\.]+)/i // WeChat
|
|
1481
|
+
], [VERSION, [NAME, 'WeChat']], [
|
|
1482
|
+
/konqueror\/([\w\.]+)/i // Konqueror
|
|
1483
|
+
], [VERSION, [NAME, 'Konqueror']], [
|
|
1484
|
+
/trident.+rv[: ]([\w\.]{1,9})\b.+like gecko/i // IE11
|
|
1485
|
+
], [VERSION, [NAME, 'IE']], [
|
|
1486
|
+
/ya(?:search)?browser\/([\w\.]+)/i // Yandex
|
|
1487
|
+
], [VERSION, [NAME, 'Yandex']], [
|
|
1488
|
+
/slbrowser\/([\w\.]+)/i // Smart Lenovo Browser
|
|
1489
|
+
], [VERSION, [NAME, 'Smart ' + LENOVO + SUFFIX_BROWSER]], [
|
|
1490
|
+
/(avast|avg)\/([\w\.]+)/i // Avast/AVG Secure Browser
|
|
1491
|
+
], [[NAME, /(.+)/, '$1 Secure' + SUFFIX_BROWSER], VERSION], [
|
|
1492
|
+
/\bfocus\/([\w\.]+)/i // Firefox Focus
|
|
1493
|
+
], [VERSION, [NAME, FIREFOX+' Focus']], [
|
|
1494
|
+
/\bopt\/([\w\.]+)/i // Opera Touch
|
|
1495
|
+
], [VERSION, [NAME, OPERA+' Touch']], [
|
|
1496
|
+
/coc_coc\w+\/([\w\.]+)/i // Coc Coc Browser
|
|
1497
|
+
], [VERSION, [NAME, 'Coc Coc']], [
|
|
1498
|
+
/dolfin\/([\w\.]+)/i // Dolphin
|
|
1499
|
+
], [VERSION, [NAME, 'Dolphin']], [
|
|
1500
|
+
/coast\/([\w\.]+)/i // Opera Coast
|
|
1501
|
+
], [VERSION, [NAME, OPERA+' Coast']], [
|
|
1502
|
+
/miuibrowser\/([\w\.]+)/i // MIUI Browser
|
|
1503
|
+
], [VERSION, [NAME, 'MIUI' + SUFFIX_BROWSER]], [
|
|
1504
|
+
/fxios\/([\w\.-]+)/i // Firefox for iOS
|
|
1505
|
+
], [VERSION, [NAME, PREFIX_MOBILE + FIREFOX]], [
|
|
1506
|
+
/\bqihoobrowser\/?([\w\.]*)/i // 360
|
|
1507
|
+
], [VERSION, [NAME, '360']], [
|
|
1508
|
+
/\b(qq)\/([\w\.]+)/i // QQ
|
|
1509
|
+
], [[NAME, /(.+)/, '$1Browser'], VERSION], [
|
|
1510
|
+
/(oculus|sailfish|huawei|vivo|pico)browser\/([\w\.]+)/i
|
|
1511
|
+
], [[NAME, /(.+)/, '$1' + SUFFIX_BROWSER], VERSION], [ // Oculus/Sailfish/HuaweiBrowser/VivoBrowser/PicoBrowser
|
|
1512
|
+
/samsungbrowser\/([\w\.]+)/i // Samsung Internet
|
|
1513
|
+
], [VERSION, [NAME, SAMSUNG + ' Internet']], [
|
|
1514
|
+
/metasr[\/ ]?([\d\.]+)/i // Sogou Explorer
|
|
1515
|
+
], [VERSION, [NAME, SOGOU + ' Explorer']], [
|
|
1516
|
+
/(sogou)mo\w+\/([\d\.]+)/i // Sogou Mobile
|
|
1517
|
+
], [[NAME, SOGOU + ' Mobile'], VERSION], [
|
|
1518
|
+
/(electron)\/([\w\.]+) safari/i, // Electron-based App
|
|
1519
|
+
/(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, // Tesla
|
|
1520
|
+
/m?(qqbrowser|2345(?=browser|chrome|explorer))\w*[\/ ]?v?([\w\.]+)/i // QQ/2345
|
|
1521
|
+
], [NAME, VERSION], [
|
|
1522
|
+
/(lbbrowser|rekonq)/i // LieBao Browser/Rekonq
|
|
1523
|
+
], [NAME], [
|
|
1524
|
+
/ome\/([\w\.]+) \w* ?(iron) saf/i, // Iron
|
|
1525
|
+
/ome\/([\w\.]+).+qihu (360)[es]e/i // 360
|
|
1526
|
+
], [VERSION, NAME], [
|
|
1527
|
+
|
|
1528
|
+
// WebView
|
|
1529
|
+
/((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i // Facebook App for iOS & Android
|
|
1530
|
+
], [[NAME, FACEBOOK], VERSION, [TYPE, INAPP]], [
|
|
1531
|
+
/(kakao(?:talk|story))[\/ ]([\w\.]+)/i, // Kakao App
|
|
1532
|
+
/(naver)\(.*?(\d+\.[\w\.]+).*\)/i, // Naver InApp
|
|
1533
|
+
/(daum)apps[\/ ]([\w\.]+)/i, // Daum App
|
|
1534
|
+
/safari (line)\/([\w\.]+)/i, // Line App for iOS
|
|
1535
|
+
/\b(line)\/([\w\.]+)\/iab/i, // Line App for Android
|
|
1536
|
+
/(alipay)client\/([\w\.]+)/i, // Alipay
|
|
1537
|
+
/(twitter)(?:and| f.+e\/([\w\.]+))/i, // Twitter
|
|
1538
|
+
/(instagram|snapchat|klarna)[\/ ]([-\w\.]+)/i // Instagram/Snapchat/Klarna
|
|
1539
|
+
], [NAME, VERSION, [TYPE, INAPP]], [
|
|
1540
|
+
/\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
|
|
1541
|
+
], [VERSION, [NAME, 'GSA'], [TYPE, INAPP]], [
|
|
1542
|
+
/musical_ly(?:.+app_?version\/|_)([\w\.]+)/i // TikTok
|
|
1543
|
+
], [VERSION, [NAME, 'TikTok'], [TYPE, INAPP]], [
|
|
1544
|
+
/\[(linkedin)app\]/i // LinkedIn App for iOS & Android
|
|
1545
|
+
], [NAME, [TYPE, INAPP]], [
|
|
1546
|
+
|
|
1547
|
+
/(chromium)[\/ ]([-\w\.]+)/i // Chromium
|
|
1548
|
+
], [NAME, VERSION], [
|
|
1549
|
+
|
|
1550
|
+
/headlesschrome(?:\/([\w\.]+)| )/i // Chrome Headless
|
|
1551
|
+
], [VERSION, [NAME, CHROME+' Headless']], [
|
|
1552
|
+
|
|
1553
|
+
/wv\).+chrome\/([\w\.]+).+edgw\//i // Edge WebView2
|
|
1554
|
+
], [VERSION, [NAME, EDGE+' WebView2']], [
|
|
1555
|
+
|
|
1556
|
+
/ wv\).+(chrome)\/([\w\.]+)/i // Chrome WebView
|
|
1557
|
+
], [[NAME, CHROME+' WebView'], VERSION], [
|
|
1558
|
+
|
|
1559
|
+
/droid.+ version\/([\w\.]+)\b.+(?:mobile safari|safari)/i // Android Browser
|
|
1560
|
+
], [VERSION, [NAME, 'Android' + SUFFIX_BROWSER]], [
|
|
1561
|
+
|
|
1562
|
+
/chrome\/([\w\.]+) mobile/i // Chrome Mobile
|
|
1563
|
+
], [VERSION, [NAME, PREFIX_MOBILE + 'Chrome']], [
|
|
1564
|
+
|
|
1565
|
+
/(chrome|omniweb|arora|[tizenoka]{5} ?browser)\/v?([\w\.]+)/i // Chrome/OmniWeb/Arora/Tizen/Nokia
|
|
1566
|
+
], [NAME, VERSION], [
|
|
1567
|
+
|
|
1568
|
+
/version\/([\w\.\,]+) .*mobile(?:\/\w+ | ?)safari/i // Safari Mobile
|
|
1569
|
+
], [VERSION, [NAME, PREFIX_MOBILE + 'Safari']], [
|
|
1570
|
+
/iphone .*mobile(?:\/\w+ | ?)safari/i
|
|
1571
|
+
], [[NAME, PREFIX_MOBILE + 'Safari']], [
|
|
1572
|
+
/version\/([\w\.\,]+) .*(safari)/i // Safari
|
|
1573
|
+
], [VERSION, NAME], [
|
|
1574
|
+
/webkit.+?(mobile ?safari|safari)(\/[\w\.]+)/i // Safari < 3.0
|
|
1575
|
+
], [NAME, [VERSION, '1']], [
|
|
1576
|
+
|
|
1577
|
+
/(webkit|khtml)\/([\w\.]+)/i
|
|
1578
|
+
], [NAME, VERSION], [
|
|
1579
|
+
|
|
1580
|
+
// Gecko based
|
|
1581
|
+
/(?:mobile|tablet);.*(firefox)\/([\w\.-]+)/i // Firefox Mobile
|
|
1582
|
+
], [[NAME, PREFIX_MOBILE + FIREFOX], VERSION], [
|
|
1583
|
+
/(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape
|
|
1584
|
+
], [[NAME, 'Netscape'], VERSION], [
|
|
1585
|
+
/(wolvic|librewolf)\/([\w\.]+)/i // Wolvic/LibreWolf
|
|
1586
|
+
], [NAME, VERSION], [
|
|
1587
|
+
/mobile vr; rv:([\w\.]+)\).+firefox/i // Firefox Reality
|
|
1588
|
+
], [VERSION, [NAME, FIREFOX+' Reality']], [
|
|
1589
|
+
/ekiohf.+(flow)\/([\w\.]+)/i, // Flow
|
|
1590
|
+
/(swiftfox)/i, // Swiftfox
|
|
1591
|
+
/(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror)[\/ ]?([\w\.\+]+)/i,
|
|
1592
|
+
// IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
|
|
1593
|
+
/(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i,
|
|
1594
|
+
// Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
|
|
1595
|
+
/(firefox)\/([\w\.]+)/i, // Other Firefox-based
|
|
1596
|
+
/(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, // Mozilla
|
|
1597
|
+
|
|
1598
|
+
// Other
|
|
1599
|
+
/(amaya|dillo|doris|icab|ladybird|lynx|mosaic|netsurf|obigo|polaris|w3m|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,
|
|
1600
|
+
// Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Obigo/Mosaic/Go/ICE/UP.Browser/Ladybird
|
|
1601
|
+
/\b(links) \(([\w\.]+)/i // Links
|
|
1602
|
+
], [NAME, [VERSION, /_/g, '.']], [
|
|
1603
|
+
|
|
1604
|
+
/(cobalt)\/([\w\.]+)/i // Cobalt
|
|
1605
|
+
], [NAME, [VERSION, /[^\d\.]+./, EMPTY]]
|
|
1606
|
+
],
|
|
1607
|
+
|
|
1608
|
+
cpu : [[
|
|
1609
|
+
|
|
1610
|
+
/\b((amd|x|x86[-_]?|wow|win)64)\b/i // AMD64 (x64)
|
|
1611
|
+
], [[ARCHITECTURE, 'amd64']], [
|
|
1612
|
+
|
|
1613
|
+
/(ia32(?=;))/i, // IA32 (quicktime)
|
|
1614
|
+
/\b((i[346]|x)86)(pc)?\b/i // IA32 (x86)
|
|
1615
|
+
], [[ARCHITECTURE, 'ia32']], [
|
|
1616
|
+
|
|
1617
|
+
/\b(aarch64|arm(v?[89]e?l?|_?64))\b/i // ARM64
|
|
1618
|
+
], [[ARCHITECTURE, 'arm64']], [
|
|
1619
|
+
|
|
1620
|
+
/\b(arm(v[67])?ht?n?[fl]p?)\b/i // ARMHF
|
|
1621
|
+
], [[ARCHITECTURE, 'armhf']], [
|
|
1622
|
+
|
|
1623
|
+
// PocketPC mistakenly identified as PowerPC
|
|
1624
|
+
/( (ce|mobile); ppc;|\/[\w\.]+arm\b)/i
|
|
1625
|
+
], [[ARCHITECTURE, 'arm']], [
|
|
1626
|
+
|
|
1627
|
+
/((ppc|powerpc)(64)?)( mac|;|\))/i // PowerPC
|
|
1628
|
+
], [[ARCHITECTURE, /ower/, EMPTY, lowerize]], [
|
|
1629
|
+
|
|
1630
|
+
/ sun4\w[;\)]/i // SPARC
|
|
1631
|
+
], [[ARCHITECTURE, 'sparc']], [
|
|
1632
|
+
|
|
1633
|
+
/\b(avr32|ia64(?=;)|68k(?=\))|\barm(?=v([1-7]|[5-7]1)l?|;|eabi)|(irix|mips|sparc)(64)?\b|pa-risc)/i
|
|
1634
|
+
// IA64, 68K, ARM/64, AVR/32, IRIX/64, MIPS/64, SPARC/64, PA-RISC
|
|
1635
|
+
], [[ARCHITECTURE, lowerize]]
|
|
1636
|
+
],
|
|
1637
|
+
|
|
1638
|
+
device : [[
|
|
1639
|
+
|
|
1640
|
+
//////////////////////////
|
|
1641
|
+
// MOBILES & TABLETS
|
|
1642
|
+
/////////////////////////
|
|
1643
|
+
|
|
1644
|
+
// Samsung
|
|
1645
|
+
/\b(sch-i[89]0\d|shw-m380s|sm-[ptx]\w{2,4}|gt-[pn]\d{2,4}|sgh-t8[56]9|nexus 10)/i
|
|
1646
|
+
], [MODEL, [VENDOR, SAMSUNG], [TYPE, TABLET]], [
|
|
1647
|
+
/\b((?:s[cgp]h|gt|sm)-(?![lr])\w+|sc[g-]?[\d]+a?|galaxy nexus)/i,
|
|
1648
|
+
/samsung[- ]((?!sm-[lr]|browser)[-\w]+)/i,
|
|
1649
|
+
/sec-(sgh\w+)/i
|
|
1650
|
+
], [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], [
|
|
1651
|
+
|
|
1652
|
+
// Apple
|
|
1653
|
+
/(?:\/|\()(ip(?:hone|od)[\w, ]*)(?:\/|;)/i // iPod/iPhone
|
|
1654
|
+
], [MODEL, [VENDOR, APPLE], [TYPE, MOBILE]], [
|
|
1655
|
+
/\((ipad);[-\w\),; ]+apple/i, // iPad
|
|
1656
|
+
/applecoremedia\/[\w\.]+ \((ipad)/i,
|
|
1657
|
+
/\b(ipad)\d\d?,\d\d?[;\]].+ios/i
|
|
1658
|
+
], [MODEL, [VENDOR, APPLE], [TYPE, TABLET]], [
|
|
1659
|
+
/(macintosh);/i
|
|
1660
|
+
], [MODEL, [VENDOR, APPLE]], [
|
|
1661
|
+
|
|
1662
|
+
// Sharp
|
|
1663
|
+
/\b(sh-?[altvz]?\d\d[a-ekm]?)/i
|
|
1664
|
+
], [MODEL, [VENDOR, SHARP], [TYPE, MOBILE]], [
|
|
1665
|
+
|
|
1666
|
+
// Honor
|
|
1667
|
+
/\b((?:brt|eln|hey2?|gdi|jdn)-a?[lnw]09|(?:ag[rm]3?|jdn2|kob2)-a?[lw]0[09]hn)(?: bui|\)|;)/i
|
|
1668
|
+
], [MODEL, [VENDOR, HONOR], [TYPE, TABLET]], [
|
|
1669
|
+
/honor([-\w ]+)[;\)]/i
|
|
1670
|
+
], [MODEL, [VENDOR, HONOR], [TYPE, MOBILE]], [
|
|
1671
|
+
|
|
1672
|
+
// Huawei
|
|
1673
|
+
/\b((?:ag[rs][2356]?k?|bah[234]?|bg[2o]|bt[kv]|cmr|cpn|db[ry]2?|jdn2|got|kob2?k?|mon|pce|scm|sht?|[tw]gr|vrd)-[ad]?[lw][0125][09]b?|605hw|bg2-u03|(?:gem|fdr|m2|ple|t1)-[7a]0[1-4][lu]|t1-a2[13][lw]|mediapad[\w\. ]*(?= bui|\)))\b(?!.+d\/s)/i
|
|
1674
|
+
], [MODEL, [VENDOR, HUAWEI], [TYPE, TABLET]], [
|
|
1675
|
+
/(?:huawei)([-\w ]+)[;\)]/i,
|
|
1676
|
+
/\b(nexus 6p|\w{2,4}e?-[atu]?[ln][\dx][012359c][adn]?)\b(?!.+d\/s)/i
|
|
1677
|
+
], [MODEL, [VENDOR, HUAWEI], [TYPE, MOBILE]], [
|
|
1678
|
+
|
|
1679
|
+
// Xiaomi
|
|
1680
|
+
/oid[^\)]+; (2[\dbc]{4}(182|283|rp\w{2})[cgl]|m2105k81a?c)(?: bui|\))/i,
|
|
1681
|
+
/\b((?:red)?mi[-_ ]?pad[\w- ]*)(?: bui|\))/i // Mi Pad tablets
|
|
1682
|
+
],[[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, TABLET]], [
|
|
1683
|
+
|
|
1684
|
+
/\b(poco[\w ]+|m2\d{3}j\d\d[a-z]{2})(?: bui|\))/i, // Xiaomi POCO
|
|
1685
|
+
/\b; (\w+) build\/hm\1/i, // Xiaomi Hongmi 'numeric' models
|
|
1686
|
+
/\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i, // Xiaomi Hongmi
|
|
1687
|
+
/\b(redmi[\-_ ]?(?:note|k)?[\w_ ]+)(?: bui|\))/i, // Xiaomi Redmi
|
|
1688
|
+
/oid[^\)]+; (m?[12][0-389][01]\w{3,6}[c-y])( bui|; wv|\))/i, // Xiaomi Redmi 'numeric' models
|
|
1689
|
+
/\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note lte|max|cc)?[_ ]?(?:\d?\w?)[_ ]?(?:plus|se|lite|pro)?)(?: bui|\))/i, // Xiaomi Mi
|
|
1690
|
+
/ ([\w ]+) miui\/v?\d/i
|
|
1691
|
+
], [[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, MOBILE]], [
|
|
1692
|
+
|
|
1693
|
+
// OnePlus
|
|
1694
|
+
/droid.+; (cph2[3-6]\d[13579]|((gm|hd)19|(ac|be|in|kb)20|(d[en]|eb|le|mt)21|ne22)[0-2]\d|p[g-k]\w[1m]10)\b/i,
|
|
1695
|
+
/(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i
|
|
1696
|
+
], [MODEL, [VENDOR, ONEPLUS], [TYPE, MOBILE]], [
|
|
1697
|
+
|
|
1698
|
+
// OPPO
|
|
1699
|
+
/; (\w+) bui.+ oppo/i,
|
|
1700
|
+
/\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/i
|
|
1701
|
+
], [MODEL, [VENDOR, OPPO], [TYPE, MOBILE]], [
|
|
1702
|
+
/\b(opd2(\d{3}a?))(?: bui|\))/i
|
|
1703
|
+
], [MODEL, [VENDOR, strMapper, { 'OnePlus' : ['203', '304', '403', '404', '413', '415'], '*' : OPPO }], [TYPE, TABLET]], [
|
|
1704
|
+
|
|
1705
|
+
// BLU
|
|
1706
|
+
/(vivo (5r?|6|8l?|go|one|s|x[il]?[2-4]?)[\w\+ ]*)(?: bui|\))/i // Vivo series
|
|
1707
|
+
], [MODEL, [VENDOR, 'BLU'], [TYPE, MOBILE]], [
|
|
1708
|
+
|
|
1709
|
+
// Vivo
|
|
1710
|
+
/; vivo (\w+)(?: bui|\))/i,
|
|
1711
|
+
/\b(v[12]\d{3}\w?[at])(?: bui|;)/i
|
|
1712
|
+
], [MODEL, [VENDOR, 'Vivo'], [TYPE, MOBILE]], [
|
|
1713
|
+
|
|
1714
|
+
// Realme
|
|
1715
|
+
/\b(rmx[1-3]\d{3})(?: bui|;|\))/i
|
|
1716
|
+
], [MODEL, [VENDOR, 'Realme'], [TYPE, MOBILE]], [
|
|
1717
|
+
|
|
1718
|
+
// Lenovo
|
|
1719
|
+
/(ideatab[-\w ]+|602lv|d-42a|a101lv|a2109a|a3500-hv|s[56]000|pb-6505[my]|tb-?x?\d{3,4}(?:f[cu]|xu|[av])|yt\d?-[jx]?\d+[lfmx])( bui|;|\)|\/)/i,
|
|
1720
|
+
/lenovo ?(b[68]0[08]0-?[hf]?|tab(?:[\w- ]+?)|tb[\w-]{6,7})( bui|;|\)|\/)/i
|
|
1721
|
+
], [MODEL, [VENDOR, LENOVO], [TYPE, TABLET]], [
|
|
1722
|
+
/lenovo[-_ ]?([-\w ]+?)(?: bui|\)|\/)/i
|
|
1723
|
+
], [MODEL, [VENDOR, LENOVO], [TYPE, MOBILE]], [
|
|
1724
|
+
|
|
1725
|
+
// Motorola
|
|
1726
|
+
/\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\b[\w ]+build\//i,
|
|
1727
|
+
/\bmot(?:orola)?[- ]([\w\s]+)(\)| bui)/i,
|
|
1728
|
+
/((?:moto(?! 360)[-\w\(\) ]+|xt\d{3,4}[cgkosw\+]?[-\d]*|nexus 6)(?= bui|\)))/i
|
|
1729
|
+
], [MODEL, [VENDOR, MOTOROLA], [TYPE, MOBILE]], [
|
|
1730
|
+
/\b(mz60\d|xoom[2 ]{0,2}) build\//i
|
|
1731
|
+
], [MODEL, [VENDOR, MOTOROLA], [TYPE, TABLET]], [
|
|
1732
|
+
|
|
1733
|
+
// LG
|
|
1734
|
+
/((?=lg)?[vl]k\-?\d{3}) bui| 3\.[-\w; ]{10}lg?-([06cv9]{3,4})/i
|
|
1735
|
+
], [MODEL, [VENDOR, LG], [TYPE, TABLET]], [
|
|
1736
|
+
/(lm(?:-?f100[nv]?|-[\w\.]+)(?= bui|\))|nexus [45])/i,
|
|
1737
|
+
/\blg[-e;\/ ]+(?!.*(?:browser|netcast|android tv|watch|webos))(\w+)/i,
|
|
1738
|
+
/\blg-?([\d\w]+) bui/i
|
|
1739
|
+
], [MODEL, [VENDOR, LG], [TYPE, MOBILE]], [
|
|
1740
|
+
|
|
1741
|
+
// Nokia
|
|
1742
|
+
/(nokia) (t[12][01])/i
|
|
1743
|
+
], [VENDOR, MODEL, [TYPE, TABLET]], [
|
|
1744
|
+
/(?:maemo|nokia).*(n900|lumia \d+|rm-\d+)/i,
|
|
1745
|
+
/nokia[-_ ]?(([-\w\. ]*))/i
|
|
1746
|
+
], [[MODEL, /_/g, ' '], [TYPE, MOBILE], [VENDOR, 'Nokia']], [
|
|
1747
|
+
|
|
1748
|
+
// Google
|
|
1749
|
+
/(pixel (c|tablet))\b/i // Google Pixel C/Tablet
|
|
1750
|
+
], [MODEL, [VENDOR, GOOGLE], [TYPE, TABLET]], [
|
|
1751
|
+
// Google Pixel
|
|
1752
|
+
/droid.+;(?: google)? (g(01[13]a|020[aem]|025[jn]|1b60|1f8f|2ybb|4s1m|576d|5nz6|8hhn|8vou|a02099|c15s|d1yq|e2ae|ec77|gh2x|kv4x|p4bc|pj41|r83y|tt9q|ur25|wvk6)|pixel[\d ]*a?( pro)?( xl)?( fold)?( \(5g\))?)( bui|\))/i
|
|
1753
|
+
], [MODEL, [VENDOR, GOOGLE], [TYPE, MOBILE]], [
|
|
1754
|
+
/(google) (pixelbook( go)?)/i
|
|
1755
|
+
], [VENDOR, MODEL], [
|
|
1756
|
+
|
|
1757
|
+
// Sony
|
|
1758
|
+
/droid.+; (a?\d[0-2]{2}so|[c-g]\d{4}|so[-gl]\w+|xq-\w\w\d\d)(?= bui|\).+chrome\/(?![1-6]{0,1}\d\.))/i
|
|
1759
|
+
], [MODEL, [VENDOR, SONY], [TYPE, MOBILE]], [
|
|
1760
|
+
/sony tablet [ps]/i,
|
|
1761
|
+
/\b(?:sony)?sgp\w+(?: bui|\))/i
|
|
1762
|
+
], [[MODEL, 'Xperia Tablet'], [VENDOR, SONY], [TYPE, TABLET]], [
|
|
1763
|
+
|
|
1764
|
+
// Amazon
|
|
1765
|
+
/(alexa)webm/i,
|
|
1766
|
+
/(kf[a-z]{2}wi|aeo(?!bc)\w\w)( bui|\))/i, // Kindle Fire without Silk / Echo Show
|
|
1767
|
+
/(kf[a-z]+)( bui|\)).+silk\//i // Kindle Fire HD
|
|
1768
|
+
], [MODEL, [VENDOR, AMAZON], [TYPE, TABLET]], [
|
|
1769
|
+
/((?:sd|kf)[0349hijorstuw]+)( bui|\)).+silk\//i // Fire Phone
|
|
1770
|
+
], [[MODEL, /(.+)/g, 'Fire Phone $1'], [VENDOR, AMAZON], [TYPE, MOBILE]], [
|
|
1771
|
+
|
|
1772
|
+
// BlackBerry
|
|
1773
|
+
/(playbook);[-\w\),; ]+(rim)/i // BlackBerry PlayBook
|
|
1774
|
+
], [MODEL, VENDOR, [TYPE, TABLET]], [
|
|
1775
|
+
/\b((?:bb[a-f]|st[hv])100-\d)/i,
|
|
1776
|
+
/\(bb10; (\w+)/i // BlackBerry 10
|
|
1777
|
+
], [MODEL, [VENDOR, BLACKBERRY], [TYPE, MOBILE]], [
|
|
1778
|
+
|
|
1779
|
+
// Asus
|
|
1780
|
+
/(?:\b|asus_)(transfo[prime ]{4,10} \w+|eeepc|slider \w+|nexus 7|padfone|p00[cj])/i
|
|
1781
|
+
], [MODEL, [VENDOR, ASUS], [TYPE, TABLET]], [
|
|
1782
|
+
/ (z[bes]6[027][012][km][ls]|zenfone \d\w?)\b/i
|
|
1783
|
+
], [MODEL, [VENDOR, ASUS], [TYPE, MOBILE]], [
|
|
1784
|
+
|
|
1785
|
+
// HTC
|
|
1786
|
+
/(nexus 9)/i // HTC Nexus 9
|
|
1787
|
+
], [MODEL, [VENDOR, 'HTC'], [TYPE, TABLET]], [
|
|
1788
|
+
/(htc)[-;_ ]{1,2}([\w ]+(?=\)| bui)|\w+)/i, // HTC
|
|
1789
|
+
|
|
1790
|
+
// ZTE
|
|
1791
|
+
/(zte)[- ]([\w ]+?)(?: bui|\/|\))/i,
|
|
1792
|
+
/(alcatel|geeksphone|nexian|panasonic(?!(?:;|\.))|sony(?!-bra))[-_ ]?([-\w]*)/i // Alcatel/GeeksPhone/Nexian/Panasonic/Sony
|
|
1793
|
+
], [VENDOR, [MODEL, /_/g, ' '], [TYPE, MOBILE]], [
|
|
1794
|
+
|
|
1795
|
+
// TCL
|
|
1796
|
+
/tcl (xess p17aa)/i,
|
|
1797
|
+
/droid [\w\.]+; ((?:8[14]9[16]|9(?:0(?:48|60|8[01])|1(?:3[27]|66)|2(?:6[69]|9[56])|466))[gqswx])(_\w(\w|\w\w))?(\)| bui)/i
|
|
1798
|
+
], [MODEL, [VENDOR, 'TCL'], [TYPE, TABLET]], [
|
|
1799
|
+
/droid [\w\.]+; (418(?:7d|8v)|5087z|5102l|61(?:02[dh]|25[adfh]|27[ai]|56[dh]|59k|65[ah])|a509dl|t(?:43(?:0w|1[adepqu])|50(?:6d|7[adju])|6(?:09dl|10k|12b|71[efho]|76[hjk])|7(?:66[ahju]|67[hw]|7[045][bh]|71[hk]|73o|76[ho]|79w|81[hks]?|82h|90[bhsy]|99b)|810[hs]))(_\w(\w|\w\w))?(\)| bui)/i
|
|
1800
|
+
], [MODEL, [VENDOR, 'TCL'], [TYPE, MOBILE]], [
|
|
1801
|
+
|
|
1802
|
+
// itel
|
|
1803
|
+
/(itel) ((\w+))/i
|
|
1804
|
+
], [[VENDOR, lowerize], MODEL, [TYPE, strMapper, { 'tablet' : ['p10001l', 'w7001'], '*' : 'mobile' }]], [
|
|
1805
|
+
|
|
1806
|
+
// Acer
|
|
1807
|
+
/droid.+; ([ab][1-7]-?[0178a]\d\d?)/i
|
|
1808
|
+
], [MODEL, [VENDOR, 'Acer'], [TYPE, TABLET]], [
|
|
1809
|
+
|
|
1810
|
+
// Meizu
|
|
1811
|
+
/droid.+; (m[1-5] note) bui/i,
|
|
1812
|
+
/\bmz-([-\w]{2,})/i
|
|
1813
|
+
], [MODEL, [VENDOR, 'Meizu'], [TYPE, MOBILE]], [
|
|
1814
|
+
|
|
1815
|
+
// Ulefone
|
|
1816
|
+
/; ((?:power )?armor(?:[\w ]{0,8}))(?: bui|\))/i
|
|
1817
|
+
], [MODEL, [VENDOR, 'Ulefone'], [TYPE, MOBILE]], [
|
|
1818
|
+
|
|
1819
|
+
// Energizer
|
|
1820
|
+
/; (energy ?\w+)(?: bui|\))/i,
|
|
1821
|
+
/; energizer ([\w ]+)(?: bui|\))/i
|
|
1822
|
+
], [MODEL, [VENDOR, 'Energizer'], [TYPE, MOBILE]], [
|
|
1823
|
+
|
|
1824
|
+
// Cat
|
|
1825
|
+
/; cat (b35);/i,
|
|
1826
|
+
/; (b15q?|s22 flip|s48c|s62 pro)(?: bui|\))/i
|
|
1827
|
+
], [MODEL, [VENDOR, 'Cat'], [TYPE, MOBILE]], [
|
|
1828
|
+
|
|
1829
|
+
// Smartfren
|
|
1830
|
+
/((?:new )?andromax[\w- ]+)(?: bui|\))/i
|
|
1831
|
+
], [MODEL, [VENDOR, 'Smartfren'], [TYPE, MOBILE]], [
|
|
1832
|
+
|
|
1833
|
+
// Nothing
|
|
1834
|
+
/droid.+; (a(in)?(0(15|59|6[35])|142)p?)/i
|
|
1835
|
+
], [MODEL, [VENDOR, 'Nothing'], [TYPE, MOBILE]], [
|
|
1836
|
+
|
|
1837
|
+
// Archos
|
|
1838
|
+
/; (x67 5g|tikeasy \w+|ac[1789]\d\w+)( b|\))/i,
|
|
1839
|
+
/archos ?(5|gamepad2?|([\w ]*[t1789]|hello) ?\d+[\w ]*)( b|\))/i
|
|
1840
|
+
], [MODEL, [VENDOR, 'Archos'], [TYPE, TABLET]], [
|
|
1841
|
+
/archos ([\w ]+)( b|\))/i,
|
|
1842
|
+
/; (ac[3-6]\d\w{2,8})( b|\))/i
|
|
1843
|
+
], [MODEL, [VENDOR, 'Archos'], [TYPE, MOBILE]], [
|
|
1844
|
+
|
|
1845
|
+
// HMD
|
|
1846
|
+
/; (n159v)/i
|
|
1847
|
+
], [MODEL, [VENDOR, 'HMD'], [TYPE, MOBILE]], [
|
|
1848
|
+
|
|
1849
|
+
// MIXED
|
|
1850
|
+
/(imo) (tab \w+)/i, // IMO
|
|
1851
|
+
/(infinix|tecno) (x1101b?|p904|dp(7c|8d|10a)( pro)?|p70[1-3]a?|p904|t1101)/i // Infinix XPad / Tecno
|
|
1852
|
+
], [VENDOR, MODEL, [TYPE, TABLET]], [
|
|
1853
|
+
|
|
1854
|
+
/(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus(?! zenw)|dell|jolla|meizu|motorola|polytron|tecno|micromax|advan)[-_ ]?([-\w]*)/i,
|
|
1855
|
+
// BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron/Tecno/Micromax/Advan
|
|
1856
|
+
/; (blu|hmd|imo|infinix|lava|oneplus|tcl)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i, // BLU/HMD/IMO/Infinix/Lava/OnePlus/TCL
|
|
1857
|
+
/(hp) ([\w ]+\w)/i, // HP iPAQ
|
|
1858
|
+
/(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia
|
|
1859
|
+
/(oppo) ?([\w ]+) bui/i // OPPO
|
|
1860
|
+
], [VENDOR, MODEL, [TYPE, MOBILE]], [
|
|
1861
|
+
|
|
1862
|
+
/(kobo)\s(ereader|touch)/i, // Kobo
|
|
1863
|
+
/(hp).+(touchpad(?!.+tablet)|tablet)/i, // HP TouchPad
|
|
1864
|
+
/(kindle)\/([\w\.]+)/i // Kindle
|
|
1865
|
+
], [VENDOR, MODEL, [TYPE, TABLET]], [
|
|
1866
|
+
|
|
1867
|
+
/(surface duo)/i // Surface Duo
|
|
1868
|
+
], [MODEL, [VENDOR, MICROSOFT], [TYPE, TABLET]], [
|
|
1869
|
+
/droid [\d\.]+; (fp\du?)(?: b|\))/i // Fairphone
|
|
1870
|
+
], [MODEL, [VENDOR, 'Fairphone'], [TYPE, MOBILE]], [
|
|
1871
|
+
/((?:tegranote|shield t(?!.+d tv))[\w- ]*?)(?: b|\))/i // Nvidia Tablets
|
|
1872
|
+
], [MODEL, [VENDOR, NVIDIA], [TYPE, TABLET]], [
|
|
1873
|
+
/(sprint) (\w+)/i // Sprint Phones
|
|
1874
|
+
], [VENDOR, MODEL, [TYPE, MOBILE]], [
|
|
1875
|
+
/(kin\.[onetw]{3})/i // Microsoft Kin
|
|
1876
|
+
], [[MODEL, /\./g, ' '], [VENDOR, MICROSOFT], [TYPE, MOBILE]], [
|
|
1877
|
+
/droid.+; ([c6]+|et5[16]|mc[239][23]x?|vc8[03]x?)\)/i // Zebra
|
|
1878
|
+
], [MODEL, [VENDOR, ZEBRA], [TYPE, TABLET]], [
|
|
1879
|
+
/droid.+; (ec30|ps20|tc[2-8]\d[kx])\)/i
|
|
1880
|
+
], [MODEL, [VENDOR, ZEBRA], [TYPE, MOBILE]], [
|
|
1881
|
+
|
|
1882
|
+
///////////////////
|
|
1883
|
+
// SMARTTVS
|
|
1884
|
+
///////////////////
|
|
1885
|
+
|
|
1886
|
+
/smart-tv.+(samsung)/i // Samsung
|
|
1887
|
+
], [VENDOR, [TYPE, SMARTTV]], [
|
|
1888
|
+
/hbbtv.+maple;(\d+)/i
|
|
1889
|
+
], [[MODEL, /^/, 'SmartTV'], [VENDOR, SAMSUNG], [TYPE, SMARTTV]], [
|
|
1890
|
+
/(vizio)(?: |.+model\/)(\w+-\w+)/i, // Vizio
|
|
1891
|
+
/tcast.+(lg)e?. ([-\w]+)/i // LG SmartTV
|
|
1892
|
+
], [VENDOR, MODEL, [TYPE, SMARTTV]], [
|
|
1893
|
+
/(nux; netcast.+smarttv|lg (netcast\.tv-201\d|android tv))/i
|
|
1894
|
+
], [[VENDOR, LG], [TYPE, SMARTTV]], [
|
|
1895
|
+
/(apple) ?tv/i // Apple TV
|
|
1896
|
+
], [VENDOR, [MODEL, APPLE+' TV'], [TYPE, SMARTTV]], [
|
|
1897
|
+
/crkey.*devicetype\/chromecast/i // Google Chromecast Third Generation
|
|
1898
|
+
], [[MODEL, CHROMECAST+' Third Generation'], [VENDOR, GOOGLE], [TYPE, SMARTTV]], [
|
|
1899
|
+
/crkey.*devicetype\/([^/]*)/i // Google Chromecast with specific device type
|
|
1900
|
+
], [[MODEL, /^/, 'Chromecast '], [VENDOR, GOOGLE], [TYPE, SMARTTV]], [
|
|
1901
|
+
/fuchsia.*crkey/i // Google Chromecast Nest Hub
|
|
1902
|
+
], [[MODEL, CHROMECAST+' Nest Hub'], [VENDOR, GOOGLE], [TYPE, SMARTTV]], [
|
|
1903
|
+
/crkey/i // Google Chromecast, Linux-based or unknown
|
|
1904
|
+
], [[MODEL, CHROMECAST], [VENDOR, GOOGLE], [TYPE, SMARTTV]], [
|
|
1905
|
+
/(portaltv)/i // Facebook Portal TV
|
|
1906
|
+
], [MODEL, [VENDOR, FACEBOOK], [TYPE, SMARTTV]], [
|
|
1907
|
+
/droid.+aft(\w+)( bui|\))/i // Fire TV
|
|
1908
|
+
], [MODEL, [VENDOR, AMAZON], [TYPE, SMARTTV]], [
|
|
1909
|
+
/(shield \w+ tv)/i // Nvidia Shield TV
|
|
1910
|
+
], [MODEL, [VENDOR, NVIDIA], [TYPE, SMARTTV]], [
|
|
1911
|
+
/\(dtv[\);].+(aquos)/i,
|
|
1912
|
+
/(aquos-tv[\w ]+)\)/i // Sharp
|
|
1913
|
+
], [MODEL, [VENDOR, SHARP], [TYPE, SMARTTV]],[
|
|
1914
|
+
/(bravia[\w ]+)( bui|\))/i // Sony
|
|
1915
|
+
], [MODEL, [VENDOR, SONY], [TYPE, SMARTTV]], [
|
|
1916
|
+
/(mi(tv|box)-?\w+) bui/i // Xiaomi
|
|
1917
|
+
], [MODEL, [VENDOR, XIAOMI], [TYPE, SMARTTV]], [
|
|
1918
|
+
/Hbbtv.*(technisat) (.*);/i // TechniSAT
|
|
1919
|
+
], [VENDOR, MODEL, [TYPE, SMARTTV]], [
|
|
1920
|
+
/\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku
|
|
1921
|
+
/hbbtv\/\d+\.\d+\.\d+ +\([\w\+ ]*; *([\w\d][^;]*);([^;]*)/i // HbbTV devices
|
|
1922
|
+
], [[VENDOR, /.+\/(\w+)/, '$1', strMapper, {'LG':'lge'}], [MODEL, trim], [TYPE, SMARTTV]], [
|
|
1923
|
+
// SmartTV from Unidentified Vendors
|
|
1924
|
+
/droid.+; ([\w- ]+) (?:android tv|smart[- ]?tv)/i
|
|
1925
|
+
], [MODEL, [TYPE, SMARTTV]], [
|
|
1926
|
+
/\b(android tv|smart[- ]?tv|opera tv|tv; rv:|large screen[\w ]+safari)\b/i
|
|
1927
|
+
], [[TYPE, SMARTTV]], [
|
|
1928
|
+
|
|
1929
|
+
///////////////////
|
|
1930
|
+
// CONSOLES
|
|
1931
|
+
///////////////////
|
|
1932
|
+
|
|
1933
|
+
/(playstation \w+)/i // Playstation
|
|
1934
|
+
], [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], [
|
|
1935
|
+
/\b(xbox(?: one)?(?!; xbox))[\); ]/i // Microsoft Xbox
|
|
1936
|
+
], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [
|
|
1937
|
+
/(ouya)/i, // Ouya
|
|
1938
|
+
/(nintendo) (\w+)/i, // Nintendo
|
|
1939
|
+
/(retroid) (pocket ([^\)]+))/i // Retroid Pocket
|
|
1940
|
+
], [VENDOR, MODEL, [TYPE, CONSOLE]], [
|
|
1941
|
+
/droid.+; (shield)( bui|\))/i // Nvidia Portable
|
|
1942
|
+
], [MODEL, [VENDOR, NVIDIA], [TYPE, CONSOLE]], [
|
|
1943
|
+
|
|
1944
|
+
///////////////////
|
|
1945
|
+
// WEARABLES
|
|
1946
|
+
///////////////////
|
|
1947
|
+
|
|
1948
|
+
/\b(sm-[lr]\d\d[0156][fnuw]?s?|gear live)\b/i // Samsung Galaxy Watch
|
|
1949
|
+
], [MODEL, [VENDOR, SAMSUNG], [TYPE, WEARABLE]], [
|
|
1950
|
+
/((pebble))app/i, // Pebble
|
|
1951
|
+
/(asus|google|lg|oppo) ((pixel |zen)?watch[\w ]*)( bui|\))/i // Asus ZenWatch / LG Watch / Pixel Watch
|
|
1952
|
+
], [VENDOR, MODEL, [TYPE, WEARABLE]], [
|
|
1953
|
+
/(ow(?:19|20)?we?[1-3]{1,3})/i // Oppo Watch
|
|
1954
|
+
], [MODEL, [VENDOR, OPPO], [TYPE, WEARABLE]], [
|
|
1955
|
+
/(watch)(?: ?os[,\/]|\d,\d\/)[\d\.]+/i // Apple Watch
|
|
1956
|
+
], [MODEL, [VENDOR, APPLE], [TYPE, WEARABLE]], [
|
|
1957
|
+
/(opwwe\d{3})/i // OnePlus Watch
|
|
1958
|
+
], [MODEL, [VENDOR, ONEPLUS], [TYPE, WEARABLE]], [
|
|
1959
|
+
/(moto 360)/i // Motorola 360
|
|
1960
|
+
], [MODEL, [VENDOR, MOTOROLA], [TYPE, WEARABLE]], [
|
|
1961
|
+
/(smartwatch 3)/i // Sony SmartWatch
|
|
1962
|
+
], [MODEL, [VENDOR, SONY], [TYPE, WEARABLE]], [
|
|
1963
|
+
/(g watch r)/i // LG G Watch R
|
|
1964
|
+
], [MODEL, [VENDOR, LG], [TYPE, WEARABLE]], [
|
|
1965
|
+
/droid.+; (wt63?0{2,3})\)/i
|
|
1966
|
+
], [MODEL, [VENDOR, ZEBRA], [TYPE, WEARABLE]], [
|
|
1967
|
+
|
|
1968
|
+
///////////////////
|
|
1969
|
+
// XR
|
|
1970
|
+
///////////////////
|
|
1971
|
+
|
|
1972
|
+
/droid.+; (glass) \d/i // Google Glass
|
|
1973
|
+
], [MODEL, [VENDOR, GOOGLE], [TYPE, XR]], [
|
|
1974
|
+
/(pico) (4|neo3(?: link|pro)?)/i // Pico
|
|
1975
|
+
], [VENDOR, MODEL, [TYPE, XR]], [
|
|
1976
|
+
/(quest( \d| pro)?s?).+vr/i // Meta Quest
|
|
1977
|
+
], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [
|
|
1978
|
+
/mobile vr; rv.+firefox/i // Unidentifiable VR device using Firefox Reality / Wolvic
|
|
1979
|
+
], [[TYPE, XR]], [
|
|
1980
|
+
|
|
1981
|
+
///////////////////
|
|
1982
|
+
// EMBEDDED
|
|
1983
|
+
///////////////////
|
|
1984
|
+
|
|
1985
|
+
/(tesla)(?: qtcarbrowser|\/[-\w\.]+)/i // Tesla
|
|
1986
|
+
], [VENDOR, [TYPE, EMBEDDED]], [
|
|
1987
|
+
/(aeobc)\b/i // Echo Dot
|
|
1988
|
+
], [MODEL, [VENDOR, AMAZON], [TYPE, EMBEDDED]], [
|
|
1989
|
+
/(homepod).+mac os/i // Apple HomePod
|
|
1990
|
+
], [MODEL, [VENDOR, APPLE], [TYPE, EMBEDDED]], [
|
|
1991
|
+
/windows iot/i // Unidentifiable embedded device using Windows IoT
|
|
1992
|
+
], [[TYPE, EMBEDDED]], [
|
|
1993
|
+
|
|
1994
|
+
////////////////////
|
|
1995
|
+
// MIXED (GENERIC)
|
|
1996
|
+
///////////////////
|
|
1997
|
+
|
|
1998
|
+
/droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew).+?(mobile|vr|\d) safari/i
|
|
1999
|
+
], [MODEL, [TYPE, strMapper, { 'mobile' : 'Mobile', 'xr' : 'VR', '*' : TABLET }]], [
|
|
2000
|
+
/\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i // Unidentifiable Tablet
|
|
2001
|
+
], [[TYPE, TABLET]], [
|
|
2002
|
+
/(phone|mobile(?:[;\/]| [ \w\/\.]*safari)|pda(?=.+windows ce))/i // Unidentifiable Mobile
|
|
2003
|
+
], [[TYPE, MOBILE]], [
|
|
2004
|
+
/droid .+?; ([\w\. -]+)( bui|\))/i // Generic Android Device
|
|
2005
|
+
], [MODEL, [VENDOR, 'Generic']]
|
|
2006
|
+
],
|
|
2007
|
+
|
|
2008
|
+
engine : [[
|
|
2009
|
+
|
|
2010
|
+
/windows.+ edge\/([\w\.]+)/i // EdgeHTML
|
|
2011
|
+
], [VERSION, [NAME, EDGE+'HTML']], [
|
|
2012
|
+
|
|
2013
|
+
/(arkweb)\/([\w\.]+)/i // ArkWeb
|
|
2014
|
+
], [NAME, VERSION], [
|
|
2015
|
+
|
|
2016
|
+
/webkit\/537\.36.+chrome\/(?!27)([\w\.]+)/i // Blink
|
|
2017
|
+
], [VERSION, [NAME, 'Blink']], [
|
|
2018
|
+
|
|
2019
|
+
/(presto)\/([\w\.]+)/i, // Presto
|
|
2020
|
+
/(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna|servo)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m/Goanna/Servo
|
|
2021
|
+
/ekioh(flow)\/([\w\.]+)/i, // Flow
|
|
2022
|
+
/(khtml|tasman|links)[\/ ]\(?([\w\.]+)/i, // KHTML/Tasman/Links
|
|
2023
|
+
/(icab)[\/ ]([23]\.[\d\.]+)/i, // iCab
|
|
2024
|
+
|
|
2025
|
+
/\b(libweb)/i // LibWeb
|
|
2026
|
+
], [NAME, VERSION], [
|
|
2027
|
+
/ladybird\//i
|
|
2028
|
+
], [[NAME, 'LibWeb']], [
|
|
2029
|
+
|
|
2030
|
+
/rv\:([\w\.]{1,9})\b.+(gecko)/i // Gecko
|
|
2031
|
+
], [VERSION, NAME]
|
|
2032
|
+
],
|
|
2033
|
+
|
|
2034
|
+
os : [[
|
|
2035
|
+
|
|
2036
|
+
// Windows
|
|
2037
|
+
/(windows nt) (6\.[23]); arm/i // Windows RT
|
|
2038
|
+
], [[NAME, /N/, 'R'], [VERSION, strMapper, windowsVersionMap]], [
|
|
2039
|
+
/(windows (?:phone|mobile|iot))(?: os)?[\/ ]?([\d\.]*( se)?)/i, // Windows IoT/Mobile/Phone
|
|
2040
|
+
// Windows NT/3.1/95/98/ME/2000/XP/Vista/7/8/8.1/10/11
|
|
2041
|
+
/(windows)[\/ ](1[01]|2000|3\.1|7|8(\.1)?|9[58]|me|server 20\d\d( r2)?|vista|xp)/i
|
|
2042
|
+
], [NAME, VERSION], [
|
|
2043
|
+
/windows nt ?([\d\.\)]*)(?!.+xbox)/i,
|
|
2044
|
+
/\bwin(?=3| ?9|n)(?:nt| 9x )?([\d\.;]*)/i
|
|
2045
|
+
], [[VERSION, /(;|\))/g, '', strMapper, windowsVersionMap], [NAME, WINDOWS]], [
|
|
2046
|
+
/(windows ce)\/?([\d\.]*)/i // Windows CE
|
|
2047
|
+
], [NAME, VERSION], [
|
|
2048
|
+
|
|
2049
|
+
// iOS/macOS
|
|
2050
|
+
/[adehimnop]{4,7}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS
|
|
2051
|
+
/(?:ios;fbsv\/|iphone.+ios[\/ ])([\d\.]+)/i,
|
|
2052
|
+
/cfnetwork\/.+darwin/i
|
|
2053
|
+
], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [
|
|
2054
|
+
/(mac os x) ?([\w\. ]*)/i,
|
|
2055
|
+
/(macintosh|mac_powerpc\b)(?!.+(haiku|morphos))/i // Mac OS
|
|
2056
|
+
], [[NAME, 'macOS'], [VERSION, /_/g, '.']], [
|
|
2057
|
+
|
|
2058
|
+
// Google Chromecast
|
|
2059
|
+
/android ([\d\.]+).*crkey/i // Google Chromecast, Android-based
|
|
2060
|
+
], [VERSION, [NAME, CHROMECAST + ' Android']], [
|
|
2061
|
+
/fuchsia.*crkey\/([\d\.]+)/i // Google Chromecast, Fuchsia-based
|
|
2062
|
+
], [VERSION, [NAME, CHROMECAST + ' Fuchsia']], [
|
|
2063
|
+
/crkey\/([\d\.]+).*devicetype\/smartspeaker/i // Google Chromecast, Linux-based Smart Speaker
|
|
2064
|
+
], [VERSION, [NAME, CHROMECAST + ' SmartSpeaker']], [
|
|
2065
|
+
/linux.*crkey\/([\d\.]+)/i // Google Chromecast, Legacy Linux-based
|
|
2066
|
+
], [VERSION, [NAME, CHROMECAST + ' Linux']], [
|
|
2067
|
+
/crkey\/([\d\.]+)/i // Google Chromecast, unknown
|
|
2068
|
+
], [VERSION, [NAME, CHROMECAST]], [
|
|
2069
|
+
|
|
2070
|
+
// Mobile OSes
|
|
2071
|
+
/droid ([\w\.]+)\b.+(android[- ]x86)/i // Android-x86
|
|
2072
|
+
], [VERSION, NAME], [
|
|
2073
|
+
/(ubuntu) ([\w\.]+) like android/i // Ubuntu Touch
|
|
2074
|
+
], [[NAME, /(.+)/, '$1 Touch'], VERSION], [
|
|
2075
|
+
/(harmonyos)[\/ ]?([\d\.]*)/i, // HarmonyOS
|
|
2076
|
+
// Android/Blackberry/WebOS/QNX/Bada/RIM/KaiOS/Maemo/MeeGo/S40/Sailfish OS/OpenHarmony/Tizen
|
|
2077
|
+
/(android|bada|blackberry|kaios|maemo|meego|openharmony|qnx|rim tablet os|sailfish|series40|symbian|tizen)\w*[-\/\.; ]?([\d\.]*)/i
|
|
2078
|
+
], [NAME, VERSION], [
|
|
2079
|
+
/\(bb(10);/i // BlackBerry 10
|
|
2080
|
+
], [VERSION, [NAME, BLACKBERRY]], [
|
|
2081
|
+
/(?:symbian ?os|symbos|s60(?=;)|series ?60)[-\/ ]?([\w\.]*)/i // Symbian
|
|
2082
|
+
], [VERSION, [NAME, 'Symbian']], [
|
|
2083
|
+
/mozilla\/[\d\.]+ \((?:mobile|tablet|tv|mobile; [\w ]+); rv:.+ gecko\/([\w\.]+)/i // Firefox OS
|
|
2084
|
+
], [VERSION, [NAME, FIREFOX+' OS']], [
|
|
2085
|
+
/\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i, // WebOS
|
|
2086
|
+
/webos(?:[ \/]?|\.tv-20(?=2[2-9]))(\d[\d\.]*)/i
|
|
2087
|
+
], [VERSION, [NAME, 'webOS']], [
|
|
2088
|
+
/web0s;.+?(?:chr[o0]me|safari)\/(\d+)/i
|
|
2089
|
+
// https://webostv.developer.lge.com/develop/specifications/web-api-and-web-engine
|
|
2090
|
+
], [[VERSION, strMapper, {'25':'120','24':'108','23':'94','22':'87','6':'79','5':'68','4':'53','3':'38','2':'538','1':'537','*':'TV'}], [NAME, 'webOS']], [
|
|
2091
|
+
/watch(?: ?os[,\/]|\d,\d\/)([\d\.]+)/i // watchOS
|
|
2092
|
+
], [VERSION, [NAME, 'watchOS']], [
|
|
2093
|
+
|
|
2094
|
+
// Google ChromeOS
|
|
2095
|
+
/(cros) [\w]+(?:\)| ([\w\.]+)\b)/i // Chromium OS
|
|
2096
|
+
], [[NAME, "Chrome OS"], VERSION],[
|
|
2097
|
+
|
|
2098
|
+
// Smart TVs
|
|
2099
|
+
/panasonic;(viera)/i, // Panasonic Viera
|
|
2100
|
+
/(netrange)mmh/i, // Netrange
|
|
2101
|
+
/(nettv)\/(\d+\.[\w\.]+)/i, // NetTV
|
|
2102
|
+
|
|
2103
|
+
// Console
|
|
2104
|
+
/(nintendo|playstation) (\w+)/i, // Nintendo/Playstation
|
|
2105
|
+
/(xbox); +xbox ([^\);]+)/i, // Microsoft Xbox (360, One, X, S, Series X, Series S)
|
|
2106
|
+
/(pico) .+os([\w\.]+)/i, // Pico
|
|
2107
|
+
|
|
2108
|
+
// Other
|
|
2109
|
+
/\b(joli|palm)\b ?(?:os)?\/?([\w\.]*)/i, // Joli/Palm
|
|
2110
|
+
/linux.+(mint)[\/\(\) ]?([\w\.]*)/i, // Mint
|
|
2111
|
+
/(mageia|vectorlinux|fuchsia|arcaos|arch(?= ?linux))[;l ]([\d\.]*)/i, // Mageia/VectorLinux/Fuchsia/ArcaOS/Arch
|
|
2112
|
+
/([kxln]?ubuntu|debian|suse|opensuse|gentoo|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire|knoppix)(?: gnu[\/ ]linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\/ ]?(?!chrom|package)([-\w\.]*)/i,
|
|
2113
|
+
// Ubuntu/Debian/SUSE/Gentoo/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus/Raspbian/Plan9/Minix/RISCOS/Contiki/Deepin/Manjaro/elementary/Sabayon/Linspire/Knoppix
|
|
2114
|
+
/((?:open)?solaris)[-\/ ]?([\w\.]*)/i, // Solaris
|
|
2115
|
+
/\b(aix)[; ]([1-9\.]{0,4})/i, // AIX
|
|
2116
|
+
/(hurd|linux|morphos)(?: (?:arm|x86|ppc)\w*| ?)([\w\.]*)/i, // Hurd/Linux/MorphOS
|
|
2117
|
+
/(gnu) ?([\w\.]*)/i, // GNU
|
|
2118
|
+
/\b([-frentopcghs]{0,5}bsd|dragonfly)[\/ ]?(?!amd|[ix346]{1,2}86)([\w\.]*)/i, // FreeBSD/NetBSD/OpenBSD/PC-BSD/GhostBSD/DragonFly
|
|
2119
|
+
/(haiku) ?(r\d)?/i // Haiku
|
|
2120
|
+
], [NAME, VERSION], [
|
|
2121
|
+
/(sunos) ?([\d\.]*)/i // Solaris
|
|
2122
|
+
], [[NAME, 'Solaris'], VERSION], [
|
|
2123
|
+
/\b(beos|os\/2|amigaos|openvms|hp-ux|serenityos)/i, // BeOS/OS2/AmigaOS/OpenVMS/HP-UX/SerenityOS
|
|
2124
|
+
/(unix) ?([\w\.]*)/i // UNIX
|
|
2125
|
+
], [NAME, VERSION]
|
|
2126
|
+
]
|
|
2127
|
+
};
|
|
2128
|
+
|
|
2129
|
+
/////////////////
|
|
2130
|
+
// Factories
|
|
2131
|
+
////////////////
|
|
2132
|
+
|
|
2133
|
+
var defaultProps = (function () {
|
|
2134
|
+
var props = { init : {}, isIgnore : {}, isIgnoreRgx : {}, toString : {}};
|
|
2135
|
+
setProps.call(props.init, [
|
|
2136
|
+
[UA_BROWSER, [NAME, VERSION, MAJOR, TYPE]],
|
|
2137
|
+
[UA_CPU, [ARCHITECTURE]],
|
|
2138
|
+
[UA_DEVICE, [TYPE, MODEL, VENDOR]],
|
|
2139
|
+
[UA_ENGINE, [NAME, VERSION]],
|
|
2140
|
+
[UA_OS, [NAME, VERSION]]
|
|
2141
|
+
]);
|
|
2142
|
+
setProps.call(props.isIgnore, [
|
|
2143
|
+
[UA_BROWSER, [VERSION, MAJOR]],
|
|
2144
|
+
[UA_ENGINE, [VERSION]],
|
|
2145
|
+
[UA_OS, [VERSION]]
|
|
2146
|
+
]);
|
|
2147
|
+
setProps.call(props.isIgnoreRgx, [
|
|
2148
|
+
[UA_BROWSER, / ?browser$/i],
|
|
2149
|
+
[UA_OS, / ?os$/i]
|
|
2150
|
+
]);
|
|
2151
|
+
setProps.call(props.toString, [
|
|
2152
|
+
[UA_BROWSER, [NAME, VERSION]],
|
|
2153
|
+
[UA_CPU, [ARCHITECTURE]],
|
|
2154
|
+
[UA_DEVICE, [VENDOR, MODEL]],
|
|
2155
|
+
[UA_ENGINE, [NAME, VERSION]],
|
|
2156
|
+
[UA_OS, [NAME, VERSION]]
|
|
2157
|
+
]);
|
|
2158
|
+
return props;
|
|
2159
|
+
})();
|
|
2160
|
+
|
|
2161
|
+
var createIData = function (item, itemType) {
|
|
2162
|
+
|
|
2163
|
+
var init_props = defaultProps.init[itemType],
|
|
2164
|
+
is_ignoreProps = defaultProps.isIgnore[itemType] || 0,
|
|
2165
|
+
is_ignoreRgx = defaultProps.isIgnoreRgx[itemType] || 0,
|
|
2166
|
+
toString_props = defaultProps.toString[itemType] || 0;
|
|
2167
|
+
|
|
2168
|
+
function IData () {
|
|
2169
|
+
setProps.call(this, init_props);
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
IData.prototype.getItem = function () {
|
|
2173
|
+
return item;
|
|
2174
|
+
};
|
|
2175
|
+
|
|
2176
|
+
IData.prototype.withClientHints = function () {
|
|
2177
|
+
|
|
2178
|
+
// nodejs / non-client-hints browsers
|
|
2179
|
+
if (!NAVIGATOR_UADATA) {
|
|
2180
|
+
return item
|
|
2181
|
+
.parseCH()
|
|
2182
|
+
.get();
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
// browsers based on chromium 85+
|
|
2186
|
+
return NAVIGATOR_UADATA
|
|
2187
|
+
.getHighEntropyValues(CH_ALL_VALUES)
|
|
2188
|
+
.then(function (res) {
|
|
2189
|
+
return item
|
|
2190
|
+
.setCH(new UACHData(res, false))
|
|
2191
|
+
.parseCH()
|
|
2192
|
+
.get();
|
|
2193
|
+
});
|
|
2194
|
+
};
|
|
2195
|
+
|
|
2196
|
+
IData.prototype.withFeatureCheck = function () {
|
|
2197
|
+
return item.detectFeature().get();
|
|
2198
|
+
};
|
|
2199
|
+
|
|
2200
|
+
if (itemType != UA_RESULT) {
|
|
2201
|
+
IData.prototype.is = function (strToCheck) {
|
|
2202
|
+
var is = false;
|
|
2203
|
+
for (var i in this) {
|
|
2204
|
+
if (this.hasOwnProperty(i) && !has(is_ignoreProps, i) && lowerize(is_ignoreRgx ? strip(is_ignoreRgx, this[i]) : this[i]) == lowerize(is_ignoreRgx ? strip(is_ignoreRgx, strToCheck) : strToCheck)) {
|
|
2205
|
+
is = true;
|
|
2206
|
+
if (strToCheck != UNDEF_TYPE) break;
|
|
2207
|
+
} else if (strToCheck == UNDEF_TYPE && is) {
|
|
2208
|
+
is = !is;
|
|
2209
|
+
break;
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
return is;
|
|
2213
|
+
};
|
|
2214
|
+
IData.prototype.toString = function () {
|
|
2215
|
+
var str = EMPTY;
|
|
2216
|
+
for (var i in toString_props) {
|
|
2217
|
+
if (typeof(this[toString_props[i]]) !== UNDEF_TYPE) {
|
|
2218
|
+
str += (str ? ' ' : EMPTY) + this[toString_props[i]];
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
return str || UNDEF_TYPE;
|
|
2222
|
+
};
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
if (!NAVIGATOR_UADATA) {
|
|
2226
|
+
IData.prototype.then = function (cb) {
|
|
2227
|
+
var that = this;
|
|
2228
|
+
var IDataResolve = function () {
|
|
2229
|
+
for (var prop in that) {
|
|
2230
|
+
if (that.hasOwnProperty(prop)) {
|
|
2231
|
+
this[prop] = that[prop];
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
};
|
|
2235
|
+
IDataResolve.prototype = {
|
|
2236
|
+
is : IData.prototype.is,
|
|
2237
|
+
toString : IData.prototype.toString
|
|
2238
|
+
};
|
|
2239
|
+
var resolveData = new IDataResolve();
|
|
2240
|
+
cb(resolveData);
|
|
2241
|
+
return resolveData;
|
|
2242
|
+
};
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
return new IData();
|
|
2246
|
+
};
|
|
2247
|
+
|
|
2248
|
+
/////////////////
|
|
2249
|
+
// Constructor
|
|
2250
|
+
////////////////
|
|
2251
|
+
|
|
2252
|
+
function UACHData (uach, isHttpUACH) {
|
|
2253
|
+
uach = uach || {};
|
|
2254
|
+
setProps.call(this, CH_ALL_VALUES);
|
|
2255
|
+
if (isHttpUACH) {
|
|
2256
|
+
setProps.call(this, [
|
|
2257
|
+
[BRANDS, itemListToArray(uach[CH_HEADER])],
|
|
2258
|
+
[FULLVERLIST, itemListToArray(uach[CH_HEADER_FULL_VER_LIST])],
|
|
2259
|
+
[MOBILE, /\?1/.test(uach[CH_HEADER_MOBILE])],
|
|
2260
|
+
[MODEL, stripQuotes(uach[CH_HEADER_MODEL])],
|
|
2261
|
+
[PLATFORM, stripQuotes(uach[CH_HEADER_PLATFORM])],
|
|
2262
|
+
[PLATFORMVER, stripQuotes(uach[CH_HEADER_PLATFORM_VER])],
|
|
2263
|
+
[ARCHITECTURE, stripQuotes(uach[CH_HEADER_ARCH])],
|
|
2264
|
+
[FORMFACTORS, itemListToArray(uach[CH_HEADER_FORM_FACTORS])],
|
|
2265
|
+
[BITNESS, stripQuotes(uach[CH_HEADER_BITNESS])]
|
|
2266
|
+
]);
|
|
2267
|
+
} else {
|
|
2268
|
+
for (var prop in uach) {
|
|
2269
|
+
if(this.hasOwnProperty(prop) && typeof uach[prop] !== UNDEF_TYPE) this[prop] = uach[prop];
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
function UAItem (itemType, ua, rgxMap, uaCH) {
|
|
2275
|
+
|
|
2276
|
+
this.get = function (prop) {
|
|
2277
|
+
if (!prop) return this.data;
|
|
2278
|
+
return this.data.hasOwnProperty(prop) ? this.data[prop] : undefined;
|
|
2279
|
+
};
|
|
2280
|
+
|
|
2281
|
+
this.set = function (prop, val) {
|
|
2282
|
+
this.data[prop] = val;
|
|
2283
|
+
return this;
|
|
2284
|
+
};
|
|
2285
|
+
|
|
2286
|
+
this.setCH = function (ch) {
|
|
2287
|
+
this.uaCH = ch;
|
|
2288
|
+
return this;
|
|
2289
|
+
};
|
|
2290
|
+
|
|
2291
|
+
this.detectFeature = function () {
|
|
2292
|
+
if (NAVIGATOR && NAVIGATOR.userAgent == this.ua) {
|
|
2293
|
+
switch (this.itemType) {
|
|
2294
|
+
case UA_BROWSER:
|
|
2295
|
+
// Brave-specific detection
|
|
2296
|
+
if (NAVIGATOR.brave && typeof NAVIGATOR.brave.isBrave == FUNC_TYPE) {
|
|
2297
|
+
this.set(NAME, 'Brave');
|
|
2298
|
+
}
|
|
2299
|
+
break;
|
|
2300
|
+
case UA_DEVICE:
|
|
2301
|
+
// Chrome-specific detection: check for 'mobile' value of navigator.userAgentData
|
|
2302
|
+
if (!this.get(TYPE) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[MOBILE]) {
|
|
2303
|
+
this.set(TYPE, MOBILE);
|
|
2304
|
+
}
|
|
2305
|
+
// iPadOS-specific detection: identified as Mac, but has some iOS-only properties
|
|
2306
|
+
if (this.get(MODEL) == 'Macintosh' && NAVIGATOR && typeof NAVIGATOR.standalone !== UNDEF_TYPE && NAVIGATOR.maxTouchPoints && NAVIGATOR.maxTouchPoints > 2) {
|
|
2307
|
+
this.set(MODEL, 'iPad')
|
|
2308
|
+
.set(TYPE, TABLET);
|
|
2309
|
+
}
|
|
2310
|
+
break;
|
|
2311
|
+
case UA_OS:
|
|
2312
|
+
// Chrome-specific detection: check for 'platform' value of navigator.userAgentData
|
|
2313
|
+
if (!this.get(NAME) && NAVIGATOR_UADATA && NAVIGATOR_UADATA[PLATFORM]) {
|
|
2314
|
+
this.set(NAME, NAVIGATOR_UADATA[PLATFORM]);
|
|
2315
|
+
}
|
|
2316
|
+
break;
|
|
2317
|
+
case UA_RESULT:
|
|
2318
|
+
var data = this.data;
|
|
2319
|
+
var detect = function (itemType) {
|
|
2320
|
+
return data[itemType]
|
|
2321
|
+
.getItem()
|
|
2322
|
+
.detectFeature()
|
|
2323
|
+
.get();
|
|
2324
|
+
};
|
|
2325
|
+
this.set(UA_BROWSER, detect(UA_BROWSER))
|
|
2326
|
+
.set(UA_CPU, detect(UA_CPU))
|
|
2327
|
+
.set(UA_DEVICE, detect(UA_DEVICE))
|
|
2328
|
+
.set(UA_ENGINE, detect(UA_ENGINE))
|
|
2329
|
+
.set(UA_OS, detect(UA_OS));
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
return this;
|
|
2333
|
+
};
|
|
2334
|
+
|
|
2335
|
+
this.parseUA = function () {
|
|
2336
|
+
if (this.itemType != UA_RESULT) {
|
|
2337
|
+
rgxMapper.call(this.data, this.ua, this.rgxMap);
|
|
2338
|
+
}
|
|
2339
|
+
if (this.itemType == UA_BROWSER) {
|
|
2340
|
+
this.set(MAJOR, majorize(this.get(VERSION)));
|
|
2341
|
+
}
|
|
2342
|
+
return this;
|
|
2343
|
+
};
|
|
2344
|
+
|
|
2345
|
+
this.parseCH = function () {
|
|
2346
|
+
var uaCH = this.uaCH,
|
|
2347
|
+
rgxMap = this.rgxMap;
|
|
2348
|
+
|
|
2349
|
+
switch (this.itemType) {
|
|
2350
|
+
case UA_BROWSER:
|
|
2351
|
+
case UA_ENGINE:
|
|
2352
|
+
var brands = uaCH[FULLVERLIST] || uaCH[BRANDS], prevName;
|
|
2353
|
+
if (brands) {
|
|
2354
|
+
for (var i in brands) {
|
|
2355
|
+
var brandName = brands[i].brand || brands[i],
|
|
2356
|
+
brandVersion = brands[i].version;
|
|
2357
|
+
if (this.itemType == UA_BROWSER &&
|
|
2358
|
+
!/not.a.brand/i.test(brandName) &&
|
|
2359
|
+
(!prevName ||
|
|
2360
|
+
(/Chrom/.test(prevName) && brandName != CHROMIUM) ||
|
|
2361
|
+
(prevName == EDGE && /WebView2/.test(brandName))
|
|
2362
|
+
)) {
|
|
2363
|
+
brandName = strMapper(brandName, browserHintsMap);
|
|
2364
|
+
prevName = this.get(NAME);
|
|
2365
|
+
if (!(prevName && !/Chrom/.test(prevName) && /Chrom/.test(brandName))) {
|
|
2366
|
+
this.set(NAME, brandName)
|
|
2367
|
+
.set(VERSION, brandVersion)
|
|
2368
|
+
.set(MAJOR, majorize(brandVersion));
|
|
2369
|
+
}
|
|
2370
|
+
prevName = brandName;
|
|
2371
|
+
}
|
|
2372
|
+
if (this.itemType == UA_ENGINE && brandName == CHROMIUM) {
|
|
2373
|
+
this.set(VERSION, brandVersion);
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
break;
|
|
2378
|
+
case UA_CPU:
|
|
2379
|
+
var archName = uaCH[ARCHITECTURE];
|
|
2380
|
+
if (archName) {
|
|
2381
|
+
if (archName && uaCH[BITNESS] == '64') archName += '64';
|
|
2382
|
+
rgxMapper.call(this.data, archName + ';', rgxMap);
|
|
2383
|
+
}
|
|
2384
|
+
break;
|
|
2385
|
+
case UA_DEVICE:
|
|
2386
|
+
if (uaCH[MOBILE]) {
|
|
2387
|
+
this.set(TYPE, MOBILE);
|
|
2388
|
+
}
|
|
2389
|
+
if (uaCH[MODEL]) {
|
|
2390
|
+
this.set(MODEL, uaCH[MODEL]);
|
|
2391
|
+
if (!this.get(TYPE) || !this.get(VENDOR)) {
|
|
2392
|
+
var reParse = {};
|
|
2393
|
+
rgxMapper.call(reParse, 'droid 9; ' + uaCH[MODEL] + ')', rgxMap);
|
|
2394
|
+
if (!this.get(TYPE) && !!reParse.type) {
|
|
2395
|
+
this.set(TYPE, reParse.type);
|
|
2396
|
+
}
|
|
2397
|
+
if (!this.get(VENDOR) && !!reParse.vendor) {
|
|
2398
|
+
this.set(VENDOR, reParse.vendor);
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
if (uaCH[FORMFACTORS]) {
|
|
2403
|
+
var ff;
|
|
2404
|
+
if (typeof uaCH[FORMFACTORS] !== 'string') {
|
|
2405
|
+
var idx = 0;
|
|
2406
|
+
while (!ff && idx < uaCH[FORMFACTORS].length) {
|
|
2407
|
+
ff = strMapper(uaCH[FORMFACTORS][idx++], formFactorsMap);
|
|
2408
|
+
}
|
|
2409
|
+
} else {
|
|
2410
|
+
ff = strMapper(uaCH[FORMFACTORS], formFactorsMap);
|
|
2411
|
+
}
|
|
2412
|
+
this.set(TYPE, ff);
|
|
2413
|
+
}
|
|
2414
|
+
break;
|
|
2415
|
+
case UA_OS:
|
|
2416
|
+
var osName = uaCH[PLATFORM];
|
|
2417
|
+
if(osName) {
|
|
2418
|
+
var osVersion = uaCH[PLATFORMVER];
|
|
2419
|
+
if (osName == WINDOWS) osVersion = (parseInt(majorize(osVersion), 10) >= 13 ? '11' : '10');
|
|
2420
|
+
this.set(NAME, osName)
|
|
2421
|
+
.set(VERSION, osVersion);
|
|
2422
|
+
}
|
|
2423
|
+
// Xbox-Specific Detection
|
|
2424
|
+
if (this.get(NAME) == WINDOWS && uaCH[MODEL] == 'Xbox') {
|
|
2425
|
+
this.set(NAME, 'Xbox')
|
|
2426
|
+
.set(VERSION, undefined);
|
|
2427
|
+
}
|
|
2428
|
+
break;
|
|
2429
|
+
case UA_RESULT:
|
|
2430
|
+
var data = this.data;
|
|
2431
|
+
var parse = function (itemType) {
|
|
2432
|
+
return data[itemType]
|
|
2433
|
+
.getItem()
|
|
2434
|
+
.setCH(uaCH)
|
|
2435
|
+
.parseCH()
|
|
2436
|
+
.get();
|
|
2437
|
+
};
|
|
2438
|
+
this.set(UA_BROWSER, parse(UA_BROWSER))
|
|
2439
|
+
.set(UA_CPU, parse(UA_CPU))
|
|
2440
|
+
.set(UA_DEVICE, parse(UA_DEVICE))
|
|
2441
|
+
.set(UA_ENGINE, parse(UA_ENGINE))
|
|
2442
|
+
.set(UA_OS, parse(UA_OS));
|
|
2443
|
+
}
|
|
2444
|
+
return this;
|
|
2445
|
+
};
|
|
2446
|
+
|
|
2447
|
+
setProps.call(this, [
|
|
2448
|
+
['itemType', itemType],
|
|
2449
|
+
['ua', ua],
|
|
2450
|
+
['uaCH', uaCH],
|
|
2451
|
+
['rgxMap', rgxMap],
|
|
2452
|
+
['data', createIData(this, itemType)]
|
|
2453
|
+
]);
|
|
2454
|
+
|
|
2455
|
+
return this;
|
|
2456
|
+
}
|
|
2457
|
+
|
|
2458
|
+
function UAParser (ua, extensions, headers) {
|
|
2459
|
+
|
|
2460
|
+
if (typeof ua === OBJ_TYPE) {
|
|
2461
|
+
if (isExtensions(ua, true)) {
|
|
2462
|
+
if (typeof extensions === OBJ_TYPE) {
|
|
2463
|
+
headers = extensions; // case UAParser(extensions, headers)
|
|
2464
|
+
}
|
|
2465
|
+
extensions = ua; // case UAParser(extensions)
|
|
2466
|
+
} else {
|
|
2467
|
+
headers = ua; // case UAParser(headers)
|
|
2468
|
+
extensions = undefined;
|
|
2469
|
+
}
|
|
2470
|
+
ua = undefined;
|
|
2471
|
+
} else if (typeof ua === STR_TYPE && !isExtensions(extensions, true)) {
|
|
2472
|
+
headers = extensions; // case UAParser(ua, headers)
|
|
2473
|
+
extensions = undefined;
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
// Convert Headers object into a plain object
|
|
2477
|
+
if (headers && typeof headers.append === FUNC_TYPE) {
|
|
2478
|
+
var kv = {};
|
|
2479
|
+
headers.forEach(function (v, k) { kv[k] = v; });
|
|
2480
|
+
headers = kv;
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
if (!(this instanceof UAParser)) {
|
|
2484
|
+
return new UAParser(ua, extensions, headers).getResult();
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
var userAgent = typeof ua === STR_TYPE ? ua : // Passed user-agent string
|
|
2488
|
+
(headers && headers[USER_AGENT] ? headers[USER_AGENT] : // User-Agent from passed headers
|
|
2489
|
+
((NAVIGATOR && NAVIGATOR.userAgent) ? NAVIGATOR.userAgent : // navigator.userAgent
|
|
2490
|
+
EMPTY)), // empty string
|
|
2491
|
+
|
|
2492
|
+
httpUACH = new UACHData(headers, true),
|
|
2493
|
+
regexMap = extensions ?
|
|
2494
|
+
extend(defaultRegexes, extensions) :
|
|
2495
|
+
defaultRegexes,
|
|
2496
|
+
|
|
2497
|
+
createItemFunc = function (itemType) {
|
|
2498
|
+
if (itemType == UA_RESULT) {
|
|
2499
|
+
return function () {
|
|
2500
|
+
return new UAItem(itemType, userAgent, regexMap, httpUACH)
|
|
2501
|
+
.set('ua', userAgent)
|
|
2502
|
+
.set(UA_BROWSER, this.getBrowser())
|
|
2503
|
+
.set(UA_CPU, this.getCPU())
|
|
2504
|
+
.set(UA_DEVICE, this.getDevice())
|
|
2505
|
+
.set(UA_ENGINE, this.getEngine())
|
|
2506
|
+
.set(UA_OS, this.getOS())
|
|
2507
|
+
.get();
|
|
2508
|
+
};
|
|
2509
|
+
} else {
|
|
2510
|
+
return function () {
|
|
2511
|
+
return new UAItem(itemType, userAgent, regexMap[itemType], httpUACH)
|
|
2512
|
+
.parseUA()
|
|
2513
|
+
.get();
|
|
2514
|
+
};
|
|
2515
|
+
}
|
|
2516
|
+
};
|
|
2517
|
+
|
|
2518
|
+
// public methods
|
|
2519
|
+
setProps.call(this, [
|
|
2520
|
+
['getBrowser', createItemFunc(UA_BROWSER)],
|
|
2521
|
+
['getCPU', createItemFunc(UA_CPU)],
|
|
2522
|
+
['getDevice', createItemFunc(UA_DEVICE)],
|
|
2523
|
+
['getEngine', createItemFunc(UA_ENGINE)],
|
|
2524
|
+
['getOS', createItemFunc(UA_OS)],
|
|
2525
|
+
['getResult', createItemFunc(UA_RESULT)],
|
|
2526
|
+
['getUA', function () { return userAgent; }],
|
|
2527
|
+
['setUA', function (ua) {
|
|
2528
|
+
if (isString(ua))
|
|
2529
|
+
userAgent = ua.length > UA_MAX_LENGTH ? trim(ua, UA_MAX_LENGTH) : ua;
|
|
2530
|
+
return this;
|
|
2531
|
+
}]
|
|
2532
|
+
])
|
|
2533
|
+
.setUA(userAgent);
|
|
2534
|
+
|
|
2535
|
+
return this;
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
UAParser.VERSION = LIBVERSION;
|
|
2539
|
+
UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR, TYPE]);
|
|
2540
|
+
UAParser.CPU = enumerize([ARCHITECTURE]);
|
|
2541
|
+
UAParser.DEVICE = enumerize([MODEL, VENDOR, TYPE, CONSOLE, MOBILE, SMARTTV, TABLET, WEARABLE, EMBEDDED]);
|
|
2542
|
+
UAParser.ENGINE = UAParser.OS = enumerize([NAME, VERSION]);
|
|
2543
|
+
|
|
2544
|
+
class DeviceDetector {
|
|
2545
|
+
getDeviceInfo() {
|
|
2546
|
+
const parser = new UAParser();
|
|
2547
|
+
const result = parser.getResult();
|
|
2548
|
+
return {
|
|
2549
|
+
browser: result.browser,
|
|
2550
|
+
os: result.os,
|
|
2551
|
+
device: result.device,
|
|
2552
|
+
engine: result.engine,
|
|
2553
|
+
cpu: result.cpu,
|
|
2554
|
+
ua: result.ua,
|
|
2555
|
+
};
|
|
2556
|
+
}
|
|
2557
|
+
get screenDensity() {
|
|
2558
|
+
if (window.devicePixelRatio >= 3)
|
|
2559
|
+
return "high";
|
|
2560
|
+
if (window.devicePixelRatio >= 2)
|
|
2561
|
+
return "medium";
|
|
2562
|
+
return "low";
|
|
2563
|
+
}
|
|
2564
|
+
get screenFormat() {
|
|
2565
|
+
return window.innerHeight > window.innerWidth ? "long" : "normal";
|
|
2566
|
+
}
|
|
2567
|
+
get screenSize() {
|
|
2568
|
+
const width = window.innerWidth;
|
|
2569
|
+
if (width < 480)
|
|
2570
|
+
return "small";
|
|
2571
|
+
else if (width < 768)
|
|
2572
|
+
return "normal";
|
|
2573
|
+
else if (width < 1440)
|
|
2574
|
+
return "large";
|
|
2575
|
+
else
|
|
2576
|
+
return "xlarge";
|
|
2577
|
+
}
|
|
2578
|
+
get uiMode() {
|
|
2579
|
+
var _a, _b, _c;
|
|
2580
|
+
const deviceInfo = this.getDeviceInfo();
|
|
2581
|
+
const deviceType = ((_a = deviceInfo.device) === null || _a === void 0 ? void 0 : _a.type) || ""; // 'mobile', 'tablet', 'smarttv', 'console', 'wearable', 'embedded'
|
|
2582
|
+
const model = ((_c = (_b = deviceInfo.device) === null || _b === void 0 ? void 0 : _b.model) === null || _c === void 0 ? void 0 : _c.toLowerCase()) || "";
|
|
2583
|
+
const ua = deviceInfo.ua.toLowerCase();
|
|
2584
|
+
if (deviceType === "wearable" || model.includes("watch")) {
|
|
2585
|
+
return 6; // UI_MODE_TYPE_WATCH
|
|
2586
|
+
}
|
|
2587
|
+
if (deviceType === "smarttv" ||
|
|
2588
|
+
ua.includes("smart-tv") ||
|
|
2589
|
+
ua.includes("hbbtv") ||
|
|
2590
|
+
ua.includes("netcast") ||
|
|
2591
|
+
ua.includes("googletv") ||
|
|
2592
|
+
ua.includes("appletv")) {
|
|
2593
|
+
return 4; // UI_MODE_TYPE_TELEVISION
|
|
2594
|
+
}
|
|
2595
|
+
if (deviceType === "console" ||
|
|
2596
|
+
ua.includes("playstation") ||
|
|
2597
|
+
ua.includes("xbox") ||
|
|
2598
|
+
ua.includes("nintendo")) {
|
|
2599
|
+
return 5; // UI_MODE_TYPE_APPLIANCE
|
|
2600
|
+
}
|
|
2601
|
+
if (ua.includes("car") ||
|
|
2602
|
+
ua.includes("android auto") ||
|
|
2603
|
+
ua.includes("carplay")) {
|
|
2604
|
+
return 3; // UI_MODE_TYPE_CAR
|
|
2605
|
+
}
|
|
2606
|
+
if (ua.includes("oculus") ||
|
|
2607
|
+
ua.includes("vive") ||
|
|
2608
|
+
ua.includes("vr") ||
|
|
2609
|
+
deviceType === "embedded") {
|
|
2610
|
+
return 7; // UI_MODE_TYPE_VR_HEADSET
|
|
2611
|
+
}
|
|
2612
|
+
if (deviceType === "mobile" || deviceType === "tablet") {
|
|
2613
|
+
return 1; // UI_MODE_TYPE_NORMAL
|
|
2614
|
+
}
|
|
2615
|
+
if (deviceType === "" || deviceType === "desktop") {
|
|
2616
|
+
return 2; // UI_MODE_TYPE_DESK
|
|
2617
|
+
}
|
|
2618
|
+
return 0; // UI_MODE_TYPE_UNDEFINED
|
|
2619
|
+
}
|
|
2620
|
+
get uiStyle() {
|
|
2621
|
+
const isDarkMode = window.matchMedia &&
|
|
2622
|
+
window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
2623
|
+
return isDarkMode ? "1" : "0";
|
|
2624
|
+
}
|
|
2625
|
+
get displaySize() {
|
|
2626
|
+
const dpr = window.devicePixelRatio || 1;
|
|
2627
|
+
const pixelWidth = screen.width * dpr;
|
|
2628
|
+
const pixelHeight = screen.height * dpr;
|
|
2629
|
+
const assumedDPI = 160;
|
|
2630
|
+
const widthInInches = pixelWidth / assumedDPI;
|
|
2631
|
+
const heightInInches = pixelHeight / assumedDPI;
|
|
2632
|
+
const diagonal = Math.sqrt(Math.pow(widthInInches, 2) + Math.pow(heightInInches, 2));
|
|
2633
|
+
return diagonal.toFixed(2);
|
|
2634
|
+
}
|
|
2635
|
+
get screenType() {
|
|
2636
|
+
return "ontouchstart" in window || navigator.maxTouchPoints > 0
|
|
2637
|
+
? "touch"
|
|
2638
|
+
: "pointer";
|
|
2639
|
+
}
|
|
2640
|
+
}
|
|
2641
|
+
/** @internal */
|
|
2642
|
+
const deviceDetector = new DeviceDetector();
|
|
2643
|
+
|
|
2644
|
+
class StorageSupport {
|
|
2645
|
+
constructor() {
|
|
2646
|
+
this.supportResults = null;
|
|
2647
|
+
}
|
|
2648
|
+
getSupportResult() {
|
|
2649
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2650
|
+
if (this.supportResults)
|
|
2651
|
+
return this.supportResults;
|
|
2652
|
+
const localStorageSupported = this.isLocalStorageSupported();
|
|
2653
|
+
const sessionStorageSupported = this.isSessionStorageSupported();
|
|
2654
|
+
const indexedDBSupported = yield this.isIndexedDBSupported();
|
|
2655
|
+
this.supportResults = {
|
|
2656
|
+
localStorage: localStorageSupported,
|
|
2657
|
+
sessionStorage: sessionStorageSupported,
|
|
2658
|
+
indexedDB: indexedDBSupported,
|
|
2659
|
+
};
|
|
2660
|
+
return this.supportResults;
|
|
2661
|
+
});
|
|
2662
|
+
}
|
|
2663
|
+
getStorageSizeBytes(storage) {
|
|
2664
|
+
let total = 0;
|
|
2665
|
+
for (let i = 0; i < storage.length; i++) {
|
|
2666
|
+
const key = storage.key(i);
|
|
2667
|
+
if (!key)
|
|
2668
|
+
continue;
|
|
2669
|
+
const value = storage.getItem(key);
|
|
2670
|
+
if (value == null)
|
|
2671
|
+
continue;
|
|
2672
|
+
total += key.length * 2;
|
|
2673
|
+
total += value.length * 2;
|
|
2674
|
+
}
|
|
2675
|
+
return total;
|
|
2676
|
+
}
|
|
2677
|
+
isLocalStorageSupported() {
|
|
2678
|
+
try {
|
|
2679
|
+
const testKey = "__test__";
|
|
2680
|
+
localStorage.setItem(testKey, "1");
|
|
2681
|
+
localStorage.removeItem(testKey);
|
|
2682
|
+
return true;
|
|
2683
|
+
}
|
|
2684
|
+
catch (e) {
|
|
2685
|
+
return false;
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2688
|
+
isSessionStorageSupported() {
|
|
2689
|
+
try {
|
|
2690
|
+
const testKey = "__test__";
|
|
2691
|
+
sessionStorage.setItem(testKey, "1");
|
|
2692
|
+
sessionStorage.removeItem(testKey);
|
|
2693
|
+
return true;
|
|
2694
|
+
}
|
|
2695
|
+
catch (e) {
|
|
2696
|
+
return false;
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
isIndexedDBSupported() {
|
|
2700
|
+
if (!("indexedDB" in window))
|
|
2701
|
+
return Promise.resolve(false);
|
|
2702
|
+
return new Promise((resolve) => {
|
|
2703
|
+
try {
|
|
2704
|
+
const request = indexedDB.open("__test__check__");
|
|
2705
|
+
request.onerror = () => resolve(false);
|
|
2706
|
+
request.onsuccess = () => {
|
|
2707
|
+
request.result.close();
|
|
2708
|
+
indexedDB.deleteDatabase("__test__check__");
|
|
2709
|
+
resolve(true);
|
|
2710
|
+
};
|
|
2711
|
+
}
|
|
2712
|
+
catch (_a) {
|
|
2713
|
+
resolve(false);
|
|
2714
|
+
}
|
|
2715
|
+
});
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
/** @internal */
|
|
2719
|
+
const storageSupport = new StorageSupport();
|
|
2720
|
+
|
|
2721
|
+
/** @internal */
|
|
2722
|
+
class Utils {
|
|
2723
|
+
static getUTMParamsString() {
|
|
2724
|
+
const params = new URLSearchParams(window.location.search);
|
|
2725
|
+
const utmParams = {};
|
|
2726
|
+
for (const [key, value] of params.entries()) {
|
|
2727
|
+
if (key.startsWith("utm_") && value) {
|
|
2728
|
+
utmParams[key] = value;
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
if (!utmParams["utm_source"]) {
|
|
2732
|
+
const referrer = document.referrer;
|
|
2733
|
+
utmParams["utm_source"] = referrer ? new URL(referrer).hostname : "other";
|
|
2734
|
+
}
|
|
2735
|
+
if (!utmParams["utm_medium"]) {
|
|
2736
|
+
utmParams["utm_medium"] = "organic";
|
|
2737
|
+
}
|
|
2738
|
+
return Object.entries(utmParams)
|
|
2739
|
+
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
|
|
2740
|
+
.join("&");
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
Utils.detectWebFramework = () => {
|
|
2744
|
+
// Next.js (React)
|
|
2745
|
+
if (!!document.querySelector("script[id=__NEXT_DATA__]") ||
|
|
2746
|
+
[...document.scripts].some((s) => s.src.includes("/_next/")))
|
|
2747
|
+
return "Next.js";
|
|
2748
|
+
// React (if next.js dosn't exists)
|
|
2749
|
+
if (!!window.React ||
|
|
2750
|
+
!!document.querySelector("[data-reactroot], [data-reactid]") ||
|
|
2751
|
+
Array.from(document.querySelectorAll("*")).some((e) => e._reactRootContainer !== undefined ||
|
|
2752
|
+
Object.keys(e).some((k) => k.startsWith("__reactContainer"))) ||
|
|
2753
|
+
window.__REACT_DEVTOOLS_GLOBAL_HOOK__)
|
|
2754
|
+
return "React";
|
|
2755
|
+
// Vue / Nuxt.js
|
|
2756
|
+
if ([...document.scripts].some((s) => s.src.includes("/_nuxt/")))
|
|
2757
|
+
return "Nuxt.js";
|
|
2758
|
+
if (window.__VUE__ ||
|
|
2759
|
+
window.Vue ||
|
|
2760
|
+
document.querySelector("[data-v-app], [data-v-]"))
|
|
2761
|
+
return "Vue.js";
|
|
2762
|
+
// Gatsby.js
|
|
2763
|
+
if (!!document.querySelector("[id=___gatsby]"))
|
|
2764
|
+
return "Gatsby.js";
|
|
2765
|
+
// Angular
|
|
2766
|
+
if (!!window ||
|
|
2767
|
+
!!document.querySelector(".ng-binding, [ng-app], [data-ng-app], [ng-controller], [data-ng-controller], [ng-repeat], [data-ng-repeat]") ||
|
|
2768
|
+
!!document.querySelector('script[src*="angular.js"], script[src*="angular.min.js"]') ||
|
|
2769
|
+
window.ng ||
|
|
2770
|
+
document.querySelector("[ng-version]"))
|
|
2771
|
+
return "Angular";
|
|
2772
|
+
// Svelte
|
|
2773
|
+
if ([...document.scripts].some((s) => { var _a; return s.src.includes("svelte") || ((_a = s.textContent) === null || _a === void 0 ? void 0 : _a.includes("svelte")); }))
|
|
2774
|
+
return "Svelte";
|
|
2775
|
+
// Alpine.js
|
|
2776
|
+
if (document.querySelector("[x-data], [x-init], [x-bind]"))
|
|
2777
|
+
return "Alpine.js";
|
|
2778
|
+
// jQuery
|
|
2779
|
+
if (window.jQuery)
|
|
2780
|
+
return "jQuery";
|
|
2781
|
+
// Backbone
|
|
2782
|
+
if (!!window.Backbone)
|
|
2783
|
+
return "Backbone.js";
|
|
2784
|
+
// Meteor
|
|
2785
|
+
if (!!window.Meteor)
|
|
2786
|
+
return "Meteor.js";
|
|
2787
|
+
// Zepto
|
|
2788
|
+
if (!!window.Zepto)
|
|
2789
|
+
return "Zepto.js";
|
|
2790
|
+
// WordPress (CMS)
|
|
2791
|
+
if (document.querySelector('meta[name="generator"][content*="WordPress"]') ||
|
|
2792
|
+
[...document.scripts].some((s) => s.src.includes("wp-content") || s.src.includes("wp-includes")))
|
|
2793
|
+
return "WordPress";
|
|
2794
|
+
// Laravel
|
|
2795
|
+
if ([...document.scripts].some((s) => s.src.includes("/js/app.js") || s.src.includes("mix-manifest.json")))
|
|
2796
|
+
return "Laravel";
|
|
2797
|
+
// Drupal (CMS)
|
|
2798
|
+
if (document.querySelector('meta[name="generator"][content*="Drupal"]') ||
|
|
2799
|
+
document.documentElement.innerHTML.includes("drupal-settings-json"))
|
|
2800
|
+
return "Drupal";
|
|
2801
|
+
// Shopify
|
|
2802
|
+
if (document.documentElement.innerHTML.includes("cdn.shopify.com"))
|
|
2803
|
+
return "Shopify";
|
|
2804
|
+
// Squarespace
|
|
2805
|
+
if ([...document.scripts].some((s) => s.src.includes("static.squarespace.com")))
|
|
2806
|
+
return "Squarespace";
|
|
2807
|
+
// Wix
|
|
2808
|
+
if ([...document.scripts].some((s) => s.src.includes("wix.com")))
|
|
2809
|
+
return "Wix";
|
|
2810
|
+
// Ghost CMS
|
|
2811
|
+
if (document.querySelector('meta[name="generator"][content*="Ghost"]'))
|
|
2812
|
+
return "Ghost CMS";
|
|
2813
|
+
return undefined;
|
|
2814
|
+
};
|
|
2815
|
+
|
|
2816
|
+
/** @internal */
|
|
2817
|
+
class DeviceFingerprint {
|
|
2818
|
+
static isWebGLSupported() {
|
|
2819
|
+
try {
|
|
2820
|
+
const canvas = document.createElement("canvas");
|
|
2821
|
+
return !!(canvas.getContext("webgl") || canvas.getContext("experimental-webgl"));
|
|
2822
|
+
}
|
|
2823
|
+
catch (e) {
|
|
2824
|
+
return false;
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
static getWebGLFingerprint() {
|
|
2828
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2829
|
+
const canvas = document.createElement("canvas");
|
|
2830
|
+
const gl = (canvas.getContext("webgl") ||
|
|
2831
|
+
canvas.getContext("experimental-webgl"));
|
|
2832
|
+
if (!gl)
|
|
2833
|
+
return undefined;
|
|
2834
|
+
const info = {
|
|
2835
|
+
version: gl.getParameter(gl.VERSION),
|
|
2836
|
+
shadingLangVersion: gl.getParameter(gl.SHADING_LANGUAGE_VERSION),
|
|
2837
|
+
maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE),
|
|
2838
|
+
maxRenderBufferSize: gl.getParameter(gl.MAX_RENDERBUFFER_SIZE),
|
|
2839
|
+
supportedExtensions: gl.getSupportedExtensions(),
|
|
2840
|
+
};
|
|
2841
|
+
try {
|
|
2842
|
+
const debugInfo = gl.getExtension("WEBGL_debug_renderer_info");
|
|
2843
|
+
info.vendor = debugInfo
|
|
2844
|
+
? gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL)
|
|
2845
|
+
: gl.getParameter(gl.VENDOR);
|
|
2846
|
+
}
|
|
2847
|
+
catch (_) {
|
|
2848
|
+
info.vendor = gl.getParameter(gl.VENDOR);
|
|
2849
|
+
}
|
|
2850
|
+
try {
|
|
2851
|
+
const debugInfo = gl.getExtension("WEBGL_debug_renderer_info");
|
|
2852
|
+
info.renderer = debugInfo
|
|
2853
|
+
? gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL)
|
|
2854
|
+
: gl.getParameter(gl.RENDERER);
|
|
2855
|
+
}
|
|
2856
|
+
catch (_) {
|
|
2857
|
+
info.renderer = gl.getParameter(gl.RENDERER);
|
|
2858
|
+
}
|
|
2859
|
+
return yield this.hashData(JSON.stringify(info));
|
|
2860
|
+
});
|
|
2861
|
+
}
|
|
2862
|
+
static getCanvasFingerprint() {
|
|
2863
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2864
|
+
const canvas = document.createElement("canvas");
|
|
2865
|
+
canvas.width = 200;
|
|
2866
|
+
canvas.height = 50;
|
|
2867
|
+
const ctx = canvas.getContext("2d");
|
|
2868
|
+
if (!ctx)
|
|
2869
|
+
return undefined;
|
|
2870
|
+
ctx.textBaseline = "top";
|
|
2871
|
+
ctx.font = "14px 'Arial'";
|
|
2872
|
+
ctx.fillStyle = "#f60";
|
|
2873
|
+
ctx.fillRect(0, 0, 200, 50);
|
|
2874
|
+
ctx.fillStyle = "#069";
|
|
2875
|
+
ctx.fillText("WiseTrack WebGL Fingerprint!", 2, 2);
|
|
2876
|
+
return yield this.hashData(canvas.toDataURL());
|
|
2877
|
+
});
|
|
2878
|
+
}
|
|
2879
|
+
// static async generateFingerprint(): Promise<string> {
|
|
2880
|
+
// const webglData = this.getWebGLFingerprint();
|
|
2881
|
+
// const canvasData = this.getCanvasFingerprint();
|
|
2882
|
+
// const combined = webglData + "|" + canvasData;
|
|
2883
|
+
// const encoder = new TextEncoder();
|
|
2884
|
+
// const data = encoder.encode(combined);
|
|
2885
|
+
// const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
2886
|
+
// const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
2887
|
+
// const hashHex = hashArray
|
|
2888
|
+
// .map((b) => b.toString(16).padStart(2, "0"))
|
|
2889
|
+
// .join("");
|
|
2890
|
+
// return hashHex;
|
|
2891
|
+
// }
|
|
2892
|
+
static hashData(input) {
|
|
2893
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2894
|
+
const str = typeof input === "string" ? input : JSON.stringify(input);
|
|
2895
|
+
const encoder = new TextEncoder();
|
|
2896
|
+
const data = encoder.encode(str);
|
|
2897
|
+
const hashBuffer = yield crypto.subtle.digest("SHA-256", data);
|
|
2898
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
2899
|
+
const hashHex = hashArray
|
|
2900
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
2901
|
+
.join("");
|
|
2902
|
+
return hashHex;
|
|
2903
|
+
});
|
|
2904
|
+
}
|
|
2905
|
+
}
|
|
2906
|
+
|
|
2907
|
+
/** @internal */
|
|
2908
|
+
class FieldsBuilder {
|
|
2909
|
+
build() {
|
|
2910
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2911
|
+
const startTime = window.performance.now();
|
|
2912
|
+
let fields = {};
|
|
2913
|
+
fields.created_at = new Date().toISOString();
|
|
2914
|
+
Object.assign(fields, this.getLocalFields());
|
|
2915
|
+
Object.assign(fields, yield this.getApplicationFields());
|
|
2916
|
+
Object.assign(fields, this.getDeviceFields());
|
|
2917
|
+
fields.time_spent = (window.performance.now() - startTime).toFixed(1);
|
|
2918
|
+
{
|
|
2919
|
+
fields = Object.fromEntries(Object.entries(fields).filter(([_, value]) => value !== null && value !== undefined));
|
|
2920
|
+
}
|
|
2921
|
+
return fields;
|
|
2922
|
+
});
|
|
2923
|
+
}
|
|
2924
|
+
getApplicationFields() {
|
|
2925
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2926
|
+
const storageSupportResult = yield storageSupport.getSupportResult();
|
|
2927
|
+
return {
|
|
2928
|
+
connectivity_type: navigator.onLine ? "1" : "-1",
|
|
2929
|
+
country: yield countryFinder.getCountryCode(),
|
|
2930
|
+
package_name: window.location.hostname,
|
|
2931
|
+
session_storage_enabled: storageSupportResult.sessionStorage,
|
|
2932
|
+
indexed_db_enabled: storageSupportResult.indexedDB,
|
|
2933
|
+
local_storage_enabled: storageSupportResult.localStorage,
|
|
2934
|
+
session_storage: storageSupport
|
|
2935
|
+
.getStorageSizeBytes(sessionStorage)
|
|
2936
|
+
.toFixed(0),
|
|
2937
|
+
local_storage: storageSupport
|
|
2938
|
+
.getStorageSizeBytes(localStorage)
|
|
2939
|
+
.toFixed(0),
|
|
2940
|
+
web_gl_support: DeviceFingerprint.isWebGLSupported(),
|
|
2941
|
+
web_gl_fingerprint: yield DeviceFingerprint.getWebGLFingerprint(),
|
|
2942
|
+
web_gl_canvas_fingerprint: yield DeviceFingerprint.getCanvasFingerprint(),
|
|
2943
|
+
};
|
|
2944
|
+
});
|
|
2945
|
+
}
|
|
2946
|
+
getLocalFields() {
|
|
2947
|
+
const initialConfig = storageManager.initialConfig;
|
|
2948
|
+
if (!initialConfig)
|
|
2949
|
+
return {};
|
|
2950
|
+
return {
|
|
2951
|
+
uuid: storageManager.deviceId,
|
|
2952
|
+
app_token: initialConfig.appToken,
|
|
2953
|
+
environment: initialConfig.userEnvironment,
|
|
2954
|
+
store_name: "other",
|
|
2955
|
+
app_version: initialConfig.appVersion,
|
|
2956
|
+
push_token: storageManager.pushToken,
|
|
2957
|
+
custom_device_id: initialConfig.customDeviceId,
|
|
2958
|
+
default_tracker: initialConfig.defaultTracker,
|
|
2959
|
+
platform: WTConstants.SDK.PLATFORM,
|
|
2960
|
+
framework: initialConfig.appFrameWork.toLowerCase(),
|
|
2961
|
+
initiated_by: `${WTConstants.SDK.PLATFORM}_${initialConfig.appFrameWork.toLowerCase()}`,
|
|
2962
|
+
initiated_version: WTConstants.SDK.VERSION,
|
|
2963
|
+
referrer: Utils.getUTMParamsString(),
|
|
2964
|
+
installed_at: storageManager.initialDate,
|
|
2965
|
+
session_count: storageManager.sessionCount.toString(),
|
|
2966
|
+
session_length: parseInt((storageManager.activeDuration / 1000).toString()).toString(),
|
|
2967
|
+
subsession_count: parseInt((storageManager.subSessionCount / 1000).toString()).toString(),
|
|
2968
|
+
last_interval: parseInt((storageManager.inactiveDuration / 1000).toString()).toString(),
|
|
2969
|
+
};
|
|
2970
|
+
}
|
|
2971
|
+
getDeviceFields() {
|
|
2972
|
+
const deviceInfo = deviceDetector.getDeviceInfo();
|
|
2973
|
+
return {
|
|
2974
|
+
browser_version: deviceInfo.browser.version,
|
|
2975
|
+
device_manufacturer: deviceInfo.device.vendor,
|
|
2976
|
+
device_name: deviceInfo.device.model,
|
|
2977
|
+
device_type: deviceInfo.device.type,
|
|
2978
|
+
os_name: deviceInfo.os.name,
|
|
2979
|
+
os_version: deviceInfo.os.version,
|
|
2980
|
+
cpu_type: deviceInfo.cpu.architecture,
|
|
2981
|
+
web_user_agent: deviceInfo.ua,
|
|
2982
|
+
display_height: window.innerHeight.toFixed(0),
|
|
2983
|
+
display_width: window.innerWidth.toFixed(0),
|
|
2984
|
+
language: navigator.language.split("-")[0],
|
|
2985
|
+
screen_density: deviceDetector.screenDensity,
|
|
2986
|
+
screen_format: deviceDetector.screenFormat,
|
|
2987
|
+
screen_size: deviceDetector.screenSize,
|
|
2988
|
+
ui_mode: deviceDetector.uiMode.toString(),
|
|
2989
|
+
cpu_lpc: navigator.hardwareConcurrency.toString(),
|
|
2990
|
+
ui_style: deviceDetector.uiStyle,
|
|
2991
|
+
wout_width: window.outerWidth.toString(),
|
|
2992
|
+
wout_height: window.outerHeight.toString(),
|
|
2993
|
+
web_engine: deviceInfo.engine.name,
|
|
2994
|
+
web_engine_version: deviceInfo.engine.version,
|
|
2995
|
+
display_size: deviceDetector.displaySize,
|
|
2996
|
+
screen_type: deviceDetector.screenType,
|
|
2997
|
+
};
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
/** @internal */
|
|
3001
|
+
const fieldsBuilder = new FieldsBuilder();
|
|
3002
|
+
|
|
3003
|
+
/** @internal */
|
|
3004
|
+
class EventFieldsBuilder extends FieldsBuilder {
|
|
3005
|
+
constructor(event) {
|
|
3006
|
+
super();
|
|
3007
|
+
this.event = event;
|
|
3008
|
+
}
|
|
3009
|
+
build() {
|
|
3010
|
+
const _super = Object.create(null, {
|
|
3011
|
+
build: { get: () => super.build }
|
|
3012
|
+
});
|
|
3013
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3014
|
+
const fields = yield _super.build.call(this);
|
|
3015
|
+
return new Promise((resolve) => {
|
|
3016
|
+
resolve(Object.assign(Object.assign({}, fields), this.event.toJSON()));
|
|
3017
|
+
});
|
|
3018
|
+
});
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
|
|
3022
|
+
/** @internal */
|
|
3023
|
+
class WTTracker {
|
|
3024
|
+
constructor() {
|
|
3025
|
+
this.isRunning = false;
|
|
3026
|
+
this.initialized = false;
|
|
3027
|
+
}
|
|
3028
|
+
get isEnabled() {
|
|
3029
|
+
return storageManager.sdkEnabled;
|
|
3030
|
+
}
|
|
3031
|
+
initialize() {
|
|
3032
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3033
|
+
this.getCountryCode();
|
|
3034
|
+
yield this.setActivityTimes();
|
|
3035
|
+
this.createDeviceID();
|
|
3036
|
+
this.addObservers();
|
|
3037
|
+
this.initialized = true;
|
|
3038
|
+
});
|
|
3039
|
+
}
|
|
3040
|
+
startTracking() {
|
|
3041
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3042
|
+
if (!this.isEnabled) {
|
|
3043
|
+
WTLogger.warn("SDK is not enabled to start tracking!");
|
|
3044
|
+
return;
|
|
3045
|
+
}
|
|
3046
|
+
WTLogger.debug("WT Tracker started");
|
|
3047
|
+
yield queueManager.initialize();
|
|
3048
|
+
yield this.checkSdkClicks();
|
|
3049
|
+
yield this.checkFirstSession();
|
|
3050
|
+
yield this.createAttribution();
|
|
3051
|
+
this.isRunning = true;
|
|
3052
|
+
});
|
|
3053
|
+
}
|
|
3054
|
+
stopTracking() {
|
|
3055
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3056
|
+
this.isRunning = false;
|
|
3057
|
+
activityTicker.stop();
|
|
3058
|
+
yield queueManager.shutdown();
|
|
3059
|
+
WTLogger.debug("WT Tracker stopped");
|
|
3060
|
+
});
|
|
3061
|
+
}
|
|
3062
|
+
checkPushToken(token) {
|
|
3063
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3064
|
+
storageManager.pushToken = token;
|
|
3065
|
+
if (!this.isEnabled) {
|
|
3066
|
+
WTLogger.warn("CheckPushToken: SDK is not enabled");
|
|
3067
|
+
return;
|
|
3068
|
+
}
|
|
3069
|
+
if (storageManager.fcmToken === token) {
|
|
3070
|
+
WTLogger.info("This Notification token has sent to server previously");
|
|
3071
|
+
return;
|
|
3072
|
+
}
|
|
3073
|
+
yield this.createRequest({
|
|
3074
|
+
endpoint: WTEndpoints.SDK_INFOS,
|
|
3075
|
+
queueType: "pending",
|
|
3076
|
+
});
|
|
3077
|
+
});
|
|
3078
|
+
}
|
|
3079
|
+
trackEvent(event) {
|
|
3080
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3081
|
+
if (!this.isEnabled) {
|
|
3082
|
+
WTLogger.warn("trackEvent: SDK is not enabled");
|
|
3083
|
+
return;
|
|
3084
|
+
}
|
|
3085
|
+
if (!this.initialized) {
|
|
3086
|
+
WTLogger.warn("trackEvent: SDK is not initialized yet");
|
|
3087
|
+
return;
|
|
3088
|
+
}
|
|
3089
|
+
storageManager.eventCount += 1;
|
|
3090
|
+
yield this.createRequest({
|
|
3091
|
+
endpoint: WTEndpoints.EVENTS,
|
|
3092
|
+
fBuilder: new EventFieldsBuilder(event),
|
|
3093
|
+
queueType: "pending",
|
|
3094
|
+
});
|
|
3095
|
+
});
|
|
3096
|
+
}
|
|
3097
|
+
// =======================================================================
|
|
3098
|
+
getCountryCode() {
|
|
3099
|
+
countryFinder.getCountryCode();
|
|
3100
|
+
}
|
|
3101
|
+
createAttribution() {
|
|
3102
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3103
|
+
if (!this.isEnabled) {
|
|
3104
|
+
WTLogger.warn("Creating Attribution: SDK is not enabled!");
|
|
3105
|
+
return;
|
|
3106
|
+
}
|
|
3107
|
+
yield this.createRequest({
|
|
3108
|
+
endpoint: WTEndpoints.ATTRIBUTIONS,
|
|
3109
|
+
queueType: "pending",
|
|
3110
|
+
});
|
|
3111
|
+
});
|
|
3112
|
+
}
|
|
3113
|
+
checkFirstSession() {
|
|
3114
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3115
|
+
if (!this.isEnabled) {
|
|
3116
|
+
WTLogger.warn("Creating First Session: SDK is not enabled!");
|
|
3117
|
+
return;
|
|
3118
|
+
}
|
|
3119
|
+
if (storageManager.firstSessionSubmit) {
|
|
3120
|
+
WTLogger.debug("Creating Session: First-Session has already submitted");
|
|
3121
|
+
return;
|
|
3122
|
+
}
|
|
3123
|
+
yield this.createRequest({
|
|
3124
|
+
endpoint: WTEndpoints.SESSIONS,
|
|
3125
|
+
queueType: storageManager.sdkClickSubmit ? "main" : "pending",
|
|
3126
|
+
});
|
|
3127
|
+
});
|
|
3128
|
+
}
|
|
3129
|
+
checkSdkClicks() {
|
|
3130
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3131
|
+
if (!this.isEnabled) {
|
|
3132
|
+
WTLogger.warn("Creating Install: SDK is not enabled!");
|
|
3133
|
+
return;
|
|
3134
|
+
}
|
|
3135
|
+
if (storageManager.sdkClickSubmit) {
|
|
3136
|
+
WTLogger.debug("Creating Install: SDK-Clicks has already submitted");
|
|
3137
|
+
return;
|
|
3138
|
+
}
|
|
3139
|
+
yield this.createRequest({
|
|
3140
|
+
endpoint: WTEndpoints.SDK_CLICKS,
|
|
3141
|
+
});
|
|
3142
|
+
});
|
|
3143
|
+
}
|
|
3144
|
+
createRequest(_a) {
|
|
3145
|
+
return __awaiter(this, arguments, void 0, function* ({ endpoint, fBuilder = fieldsBuilder, queueType = "main", }) {
|
|
3146
|
+
const fields = yield fBuilder.build();
|
|
3147
|
+
const request = new RequestRecord(endpoint, fields);
|
|
3148
|
+
if (queueType === "pending") {
|
|
3149
|
+
WTLogger.info(`Add ${endpoint} request to pending queue`);
|
|
3150
|
+
yield queueManager.addPendingRequest(request);
|
|
3151
|
+
}
|
|
3152
|
+
else {
|
|
3153
|
+
WTLogger.info(`Add ${endpoint} request to main queue`);
|
|
3154
|
+
yield queueManager.addRequest(request);
|
|
3155
|
+
}
|
|
3156
|
+
const queueStatus = queueManager.getQueueStatus();
|
|
3157
|
+
console.log(JSON.stringify(queueStatus));
|
|
3158
|
+
});
|
|
3159
|
+
}
|
|
3160
|
+
createDeviceID() {
|
|
3161
|
+
if (!storageManager.deviceId) {
|
|
3162
|
+
storageManager.deviceId = cryptoHelper.generateDeviceUUID();
|
|
3163
|
+
}
|
|
3164
|
+
if (!storageManager.initialDate) {
|
|
3165
|
+
storageManager.initialDate = new Date().toISOString();
|
|
3166
|
+
}
|
|
3167
|
+
}
|
|
3168
|
+
setActivityTimes() {
|
|
3169
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3170
|
+
// Update inactive time to last stored active time
|
|
3171
|
+
if (storageManager.activeTime) {
|
|
3172
|
+
storageManager.inactiveTime = storageManager.activeTime;
|
|
3173
|
+
const inteval = Date.now() - storageManager.inactiveTime;
|
|
3174
|
+
storageManager.inactiveDuration += inteval;
|
|
3175
|
+
console.log(`User was inactived for ${inteval / 1000}s | (${storageManager.inactiveDuration / 1000}s Totaly)`);
|
|
3176
|
+
yield this.checkSessionIntervals();
|
|
3177
|
+
}
|
|
3178
|
+
// update active time to now and start ticker for update active time/duration per 1s
|
|
3179
|
+
storageManager.activeTime = Date.now();
|
|
3180
|
+
activityTicker.start();
|
|
3181
|
+
});
|
|
3182
|
+
}
|
|
3183
|
+
checkSessionIntervals() {
|
|
3184
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3185
|
+
var _a, _b;
|
|
3186
|
+
const inactiveTime = storageManager.inactiveTime;
|
|
3187
|
+
const sessionInterval = (_a = storageManager.appSettings) === null || _a === void 0 ? void 0 : _a.sessionInterval;
|
|
3188
|
+
const subsessionInterval = (_b = storageManager.appSettings) === null || _b === void 0 ? void 0 : _b.subsessionInterval;
|
|
3189
|
+
if (!this.isEnabled) {
|
|
3190
|
+
WTLogger.warn("Creating Session: SDK is not enabled!");
|
|
3191
|
+
return;
|
|
3192
|
+
}
|
|
3193
|
+
if (!inactiveTime || !sessionInterval || !subsessionInterval) {
|
|
3194
|
+
return;
|
|
3195
|
+
}
|
|
3196
|
+
const interval = Date.now() - inactiveTime;
|
|
3197
|
+
if (interval > parseInt(sessionInterval)) {
|
|
3198
|
+
storageManager.sessionCount += 1;
|
|
3199
|
+
yield this.createRequest({
|
|
3200
|
+
endpoint: WTEndpoints.SESSIONS,
|
|
3201
|
+
queueType: storageManager.sdkClickSubmit ? "main" : "pending",
|
|
3202
|
+
});
|
|
3203
|
+
}
|
|
3204
|
+
else if (interval > parseInt(subsessionInterval)) {
|
|
3205
|
+
storageManager.subSessionCount += 1;
|
|
3206
|
+
}
|
|
3207
|
+
});
|
|
3208
|
+
}
|
|
3209
|
+
isVisibleFocused() {
|
|
3210
|
+
return document.visibilityState === "visible" && document.hasFocus();
|
|
3211
|
+
}
|
|
3212
|
+
addObservers() {
|
|
3213
|
+
// document.addEventListener("load", () => {
|
|
3214
|
+
// this.setActivityTimes();
|
|
3215
|
+
// });
|
|
3216
|
+
window.addEventListener("beforeunload", () => {
|
|
3217
|
+
activityTicker.stop();
|
|
3218
|
+
});
|
|
3219
|
+
document.addEventListener("visibilitychange", () => {
|
|
3220
|
+
if (this.isVisibleFocused()) {
|
|
3221
|
+
this.createAttribution();
|
|
3222
|
+
this.setActivityTimes();
|
|
3223
|
+
}
|
|
3224
|
+
else {
|
|
3225
|
+
activityTicker.stop();
|
|
3226
|
+
}
|
|
3227
|
+
});
|
|
3228
|
+
window.addEventListener("focus", () => {
|
|
3229
|
+
if (this.isVisibleFocused()) {
|
|
3230
|
+
this.createAttribution();
|
|
3231
|
+
this.setActivityTimes();
|
|
3232
|
+
}
|
|
3233
|
+
});
|
|
3234
|
+
window.addEventListener("blur", () => {
|
|
3235
|
+
activityTicker.stop();
|
|
3236
|
+
});
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3239
|
+
/** @internal */
|
|
3240
|
+
const tracker = new WTTracker();
|
|
3241
|
+
|
|
3242
|
+
/**
|
|
3243
|
+
* The main entry point for the WiseTrack Web SDK.
|
|
3244
|
+
*
|
|
3245
|
+
* Use this singleton to initialize the SDK, configure its behavior, and track events.
|
|
3246
|
+
*
|
|
3247
|
+
* @example
|
|
3248
|
+
* ```ts
|
|
3249
|
+
* const initialConfig: WTInitialConfig = {
|
|
3250
|
+
* appToken: appToken ?? "rMN5ZCwpOzY7",
|
|
3251
|
+
* appFrameWork: "native",
|
|
3252
|
+
* appVersion: "1.0.0",
|
|
3253
|
+
* };
|
|
3254
|
+
* await WiseTrack.instance.init(initialConfig);
|
|
3255
|
+
* ```
|
|
3256
|
+
*/
|
|
3257
|
+
class WiseTrack {
|
|
3258
|
+
/**
|
|
3259
|
+
* Returns the singleton instance of the WiseTrack SDK.
|
|
3260
|
+
*/
|
|
3261
|
+
static get instance() {
|
|
3262
|
+
if (!WiseTrack._instance) {
|
|
3263
|
+
WiseTrack._instance = new WiseTrack();
|
|
3264
|
+
}
|
|
3265
|
+
return WiseTrack._instance;
|
|
3266
|
+
}
|
|
3267
|
+
constructor() {
|
|
3268
|
+
this.sdkInitialized = false;
|
|
3269
|
+
}
|
|
3270
|
+
/**
|
|
3271
|
+
* Initializes the WiseTrack SDK with the given configuration.
|
|
3272
|
+
*
|
|
3273
|
+
* This method must be called before using any tracking features.
|
|
3274
|
+
*
|
|
3275
|
+
* @param initConfig - The initial configuration object.
|
|
3276
|
+
*
|
|
3277
|
+
* @example
|
|
3278
|
+
* ```ts
|
|
3279
|
+
* const initialConfig: WTInitialConfig = {
|
|
3280
|
+
* appToken: appToken ?? "rMN5ZCwpOzY7",
|
|
3281
|
+
* appFrameWork: "native", // your current web app framework (native, reactjs, nextjs, ...)
|
|
3282
|
+
* appVersion: "1.0.0", // your current web app version
|
|
3283
|
+
* };
|
|
3284
|
+
*
|
|
3285
|
+
* ```
|
|
3286
|
+
*/
|
|
3287
|
+
init(initConfig) {
|
|
3288
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3289
|
+
var _a, _b;
|
|
3290
|
+
const config = yield this.getConfig(initConfig);
|
|
3291
|
+
this.checkSdkEnabled(config);
|
|
3292
|
+
this.checkSdkUpdate(config);
|
|
3293
|
+
this.setEnabled(true);
|
|
3294
|
+
yield this.updateAppSettings(config);
|
|
3295
|
+
this.sdkInitialized = true;
|
|
3296
|
+
yield tracker.initialize();
|
|
3297
|
+
const autoStart = (_a = initConfig.startTrackerAutomatically) !== null && _a !== void 0 ? _a : true;
|
|
3298
|
+
if (autoStart) {
|
|
3299
|
+
setTimeout(() => this.startTracking(), ((_b = initConfig.trackingWaitingTime) !== null && _b !== void 0 ? _b : 0) * 1000);
|
|
3300
|
+
}
|
|
3301
|
+
});
|
|
3302
|
+
}
|
|
3303
|
+
/**
|
|
3304
|
+
* Sets the log level for internal SDK logging.
|
|
3305
|
+
*
|
|
3306
|
+
* @param level - The desired log level.
|
|
3307
|
+
*
|
|
3308
|
+
* @example
|
|
3309
|
+
* ```ts
|
|
3310
|
+
* WiseTrack.instance.setLogLevel(WTLogLevel.WARN)
|
|
3311
|
+
* // or
|
|
3312
|
+
* WiseTrack.instance.setLogLevel("warn")
|
|
3313
|
+
*
|
|
3314
|
+
* ```
|
|
3315
|
+
*/
|
|
3316
|
+
setLogLevel(level) {
|
|
3317
|
+
WTLogger.setLevel(level);
|
|
3318
|
+
}
|
|
3319
|
+
/**
|
|
3320
|
+
* Clears all stored data and stops the tracker.
|
|
3321
|
+
*/
|
|
3322
|
+
flush() {
|
|
3323
|
+
WTLogger.info("Clearing Data and stop tracker!");
|
|
3324
|
+
storageManager.clear();
|
|
3325
|
+
this.stopTracking();
|
|
3326
|
+
}
|
|
3327
|
+
/**
|
|
3328
|
+
* Returns whether the SDK is currently enabled.
|
|
3329
|
+
*/
|
|
3330
|
+
isEnabled() {
|
|
3331
|
+
return storageManager.sdkEnabled;
|
|
3332
|
+
}
|
|
3333
|
+
/**
|
|
3334
|
+
* Enables or disables the SDK.
|
|
3335
|
+
*
|
|
3336
|
+
* Throws an error if the SDK is disabled by the server or needs an update.
|
|
3337
|
+
*
|
|
3338
|
+
* @param enabled - Whether to enable the SDK.
|
|
3339
|
+
* @throws If the server has disabled the SDK or a forced update is required.
|
|
3340
|
+
*/
|
|
3341
|
+
setEnabled(enabled) {
|
|
3342
|
+
const config = storageManager.config;
|
|
3343
|
+
if (!config) {
|
|
3344
|
+
throw new Error("Config is not set!");
|
|
3345
|
+
}
|
|
3346
|
+
if (!config.sdkEnabled) {
|
|
3347
|
+
throw new Error("SDK is disabled form server, contact your adminstrator!");
|
|
3348
|
+
}
|
|
3349
|
+
if (config.forceUpdate) {
|
|
3350
|
+
throw new Error("The version you are currently using has expired and is no longer supported. Please update to the latest version to continue using the SDK");
|
|
3351
|
+
}
|
|
3352
|
+
storageManager.sdkEnabled = enabled;
|
|
3353
|
+
}
|
|
3354
|
+
/**
|
|
3355
|
+
* Starts the tracking process.
|
|
3356
|
+
*
|
|
3357
|
+
* @remarks
|
|
3358
|
+
* The SDK must be initialized and enabled before calling this method.
|
|
3359
|
+
*
|
|
3360
|
+
* NOTE: call this method just if you set startTrackerAutomatically=false in WTInitialConfig
|
|
3361
|
+
*/
|
|
3362
|
+
startTracking() {
|
|
3363
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3364
|
+
if (!this.sdkInitialized) {
|
|
3365
|
+
WTLogger.warn("‼️ Start Tracking: SDK is not initialized yet");
|
|
3366
|
+
return;
|
|
3367
|
+
}
|
|
3368
|
+
if (!this.isEnabled()) {
|
|
3369
|
+
WTLogger.warn("Start Tracking: SDK is not enabled!");
|
|
3370
|
+
return;
|
|
3371
|
+
}
|
|
3372
|
+
yield tracker.startTracking();
|
|
3373
|
+
});
|
|
3374
|
+
}
|
|
3375
|
+
/**
|
|
3376
|
+
* Stops the tracking process.
|
|
3377
|
+
*/
|
|
3378
|
+
stopTracking() {
|
|
3379
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3380
|
+
yield tracker.stopTracking();
|
|
3381
|
+
});
|
|
3382
|
+
}
|
|
3383
|
+
/**
|
|
3384
|
+
* Sets the Firebase Cloud Messaging (FCM) push token for server.
|
|
3385
|
+
*
|
|
3386
|
+
* @param token - The FCM token.
|
|
3387
|
+
*/
|
|
3388
|
+
setFCMToken(token) {
|
|
3389
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3390
|
+
if (!this.sdkInitialized) {
|
|
3391
|
+
WTLogger.warn("‼️ Set Fcm Token: SDK is not initialized yet");
|
|
3392
|
+
return;
|
|
3393
|
+
}
|
|
3394
|
+
if (!this.isEnabled()) {
|
|
3395
|
+
WTLogger.warn("Set Fcm Token: SDK is not enabled!");
|
|
3396
|
+
return;
|
|
3397
|
+
}
|
|
3398
|
+
yield tracker.checkPushToken(token);
|
|
3399
|
+
});
|
|
3400
|
+
}
|
|
3401
|
+
/**
|
|
3402
|
+
* Tracks a custom event or revenue event.
|
|
3403
|
+
*
|
|
3404
|
+
* @param event - The event object to be tracked.
|
|
3405
|
+
*
|
|
3406
|
+
* @example
|
|
3407
|
+
* ```ts
|
|
3408
|
+
* // Create a Default Event
|
|
3409
|
+
* const defaultEvent = new WTEvent.Default("default-event");
|
|
3410
|
+
* defaultEvent.addParam("key1", "value1");
|
|
3411
|
+
* defaultEvent.addParam("key2", 123);
|
|
3412
|
+
* defaultEvent.addParam("key3", true);
|
|
3413
|
+
* await WiseTrack.instance.trackEvent(defaultEvent);
|
|
3414
|
+
*
|
|
3415
|
+
* // Create a Revenue Event
|
|
3416
|
+
* const revenueEvent = new WTEvent.Revenue("revenue-event", 100, "USD");
|
|
3417
|
+
* revenueEvent.addParam("item_id", "item123");
|
|
3418
|
+
* revenueEvent.addParam("quantity", 2);
|
|
3419
|
+
* await WiseTrack.instance.trackEvent(revenueEvent);
|
|
3420
|
+
* ```
|
|
3421
|
+
*/
|
|
3422
|
+
trackEvent(event) {
|
|
3423
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3424
|
+
if (!this.sdkInitialized) {
|
|
3425
|
+
WTLogger.warn("‼️ Track Event: SDK is not initialized yet");
|
|
3426
|
+
return;
|
|
3427
|
+
}
|
|
3428
|
+
if (!this.isEnabled()) {
|
|
3429
|
+
WTLogger.warn("Track Event: SDK is not enabled!");
|
|
3430
|
+
return;
|
|
3431
|
+
}
|
|
3432
|
+
yield tracker.trackEvent(event);
|
|
3433
|
+
});
|
|
3434
|
+
}
|
|
3435
|
+
// ===========================================================================
|
|
3436
|
+
/** @internal */
|
|
3437
|
+
getConfig(initConfig) {
|
|
3438
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3439
|
+
storageManager.initialConfig = initConfig;
|
|
3440
|
+
let config;
|
|
3441
|
+
try {
|
|
3442
|
+
config = yield apiClient.doGetConfig();
|
|
3443
|
+
}
|
|
3444
|
+
catch (error) {
|
|
3445
|
+
if (!(error instanceof ApiError.NetworkError)) {
|
|
3446
|
+
WTLogger.info("‼️ SDK Config NOT set!, check errors.");
|
|
3447
|
+
throw error;
|
|
3448
|
+
}
|
|
3449
|
+
config = storageManager.config || WTConfig.defaultValue;
|
|
3450
|
+
}
|
|
3451
|
+
storageManager.config = config;
|
|
3452
|
+
WTLogger.info("SDK Config set");
|
|
3453
|
+
return config;
|
|
3454
|
+
});
|
|
3455
|
+
}
|
|
3456
|
+
/** @internal */
|
|
3457
|
+
updateAppSettings(config) {
|
|
3458
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
3459
|
+
let appSettings;
|
|
3460
|
+
if (!EnvironmentUtils.needAppSettings()) {
|
|
3461
|
+
appSettings = WTAppSettings.fromConfig(config);
|
|
3462
|
+
}
|
|
3463
|
+
else {
|
|
3464
|
+
WTLogger.debug(`Need to get app-settings for ${EnvironmentUtils.sdkEnvironment} environment`);
|
|
3465
|
+
try {
|
|
3466
|
+
appSettings = yield apiClient.doGetAppSettings();
|
|
3467
|
+
}
|
|
3468
|
+
catch (error) {
|
|
3469
|
+
if (!(error instanceof ApiError.NetworkError)) {
|
|
3470
|
+
WTLogger.info("‼️ App Settings NOT set!, check errors.");
|
|
3471
|
+
throw error;
|
|
3472
|
+
}
|
|
3473
|
+
appSettings = WTAppSettings.defaultValue;
|
|
3474
|
+
}
|
|
3475
|
+
}
|
|
3476
|
+
storageManager.appSettings = appSettings;
|
|
3477
|
+
WTLogger.info("App Settings set");
|
|
3478
|
+
return appSettings;
|
|
3479
|
+
});
|
|
3480
|
+
}
|
|
3481
|
+
/** @internal */
|
|
3482
|
+
checkSdkEnabled(config) {
|
|
3483
|
+
if (!config.sdkEnabled) {
|
|
3484
|
+
const message = "SDK is disabled form server, contact your adminstrator!";
|
|
3485
|
+
WTLogger.error(message);
|
|
3486
|
+
throw new Error(message);
|
|
3487
|
+
}
|
|
3488
|
+
}
|
|
3489
|
+
/** @internal */
|
|
3490
|
+
checkSdkUpdate(config) {
|
|
3491
|
+
if (config.forceUpdate) {
|
|
3492
|
+
const message = "The version you are currently using has expired and is no longer supported. Please update to the latest version to continue using the SDK";
|
|
3493
|
+
WTLogger.error(message);
|
|
3494
|
+
throw new Error(message);
|
|
3495
|
+
}
|
|
3496
|
+
if (config.sdkUpdate) {
|
|
3497
|
+
WTLogger.warn("A new version of the SDK is available. It is recommended to update to the latest version to enjoy improved features and better performance.");
|
|
3498
|
+
}
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3501
|
+
|
|
3502
|
+
exports.WTEvent = void 0;
|
|
3503
|
+
(function (WTEvent) {
|
|
3504
|
+
/**
|
|
3505
|
+
* Represents a generic custom event.
|
|
3506
|
+
*
|
|
3507
|
+
* Use this class to log custom actions performed by the user.
|
|
3508
|
+
*
|
|
3509
|
+
* @example
|
|
3510
|
+
* ```ts
|
|
3511
|
+
* const event = new WTEvent.Default("signup");
|
|
3512
|
+
* event.addParam("method", "Google");
|
|
3513
|
+
* WiseTrack.instance.trackEvent(event);
|
|
3514
|
+
* ```
|
|
3515
|
+
*/
|
|
3516
|
+
class Default {
|
|
3517
|
+
/**
|
|
3518
|
+
* Creates a new custom event.
|
|
3519
|
+
* @param name - The name of the event.
|
|
3520
|
+
*/
|
|
3521
|
+
constructor(name) {
|
|
3522
|
+
/**
|
|
3523
|
+
* The type of event.
|
|
3524
|
+
* @internal
|
|
3525
|
+
*/
|
|
3526
|
+
this.type = "default";
|
|
3527
|
+
this.name = name;
|
|
3528
|
+
}
|
|
3529
|
+
/**
|
|
3530
|
+
* Adds a parameter to the event.
|
|
3531
|
+
*
|
|
3532
|
+
* @param key - The parameter key.
|
|
3533
|
+
* @param value - The parameter value.
|
|
3534
|
+
*/
|
|
3535
|
+
addParam(key, value) {
|
|
3536
|
+
var _a;
|
|
3537
|
+
let _params = (_a = this.params) !== null && _a !== void 0 ? _a : {};
|
|
3538
|
+
_params[key] = value;
|
|
3539
|
+
this.params = _params;
|
|
3540
|
+
}
|
|
3541
|
+
/** @internal */
|
|
3542
|
+
toJSON() {
|
|
3543
|
+
return {
|
|
3544
|
+
event_type: this.type,
|
|
3545
|
+
event_name: this.name,
|
|
3546
|
+
partner_params: this.params,
|
|
3547
|
+
};
|
|
3548
|
+
}
|
|
3549
|
+
}
|
|
3550
|
+
WTEvent.Default = Default;
|
|
3551
|
+
/**
|
|
3552
|
+
* Represents a revenue event with an amount and currency.
|
|
3553
|
+
*
|
|
3554
|
+
* Use this class to log purchases or monetary transactions.
|
|
3555
|
+
*
|
|
3556
|
+
* @example
|
|
3557
|
+
* ```ts
|
|
3558
|
+
* const purchase = new WTEvent.Revenue("order_complete", 49.99, RevenueCurrency.USD);
|
|
3559
|
+
* purchase.addParam("item_count", "3");
|
|
3560
|
+
* WiseTrack.instance.trackEvent(purchase);
|
|
3561
|
+
* ```
|
|
3562
|
+
*/
|
|
3563
|
+
class Revenue extends Default {
|
|
3564
|
+
/**
|
|
3565
|
+
* Creates a new revenue event.
|
|
3566
|
+
*
|
|
3567
|
+
* @param name - The name of the revenue event.
|
|
3568
|
+
* @param amount - The amount of revenue.
|
|
3569
|
+
* @param currency - The currency of the revenue.
|
|
3570
|
+
*/
|
|
3571
|
+
constructor(name, amount, currency) {
|
|
3572
|
+
super(name);
|
|
3573
|
+
/**
|
|
3574
|
+
* The type of event.
|
|
3575
|
+
* @internal
|
|
3576
|
+
*/
|
|
3577
|
+
this.type = "revenue";
|
|
3578
|
+
this.amount = amount;
|
|
3579
|
+
this.currency = currency;
|
|
3580
|
+
}
|
|
3581
|
+
/** @internal */
|
|
3582
|
+
toJSON() {
|
|
3583
|
+
return {
|
|
3584
|
+
event_type: this.type,
|
|
3585
|
+
event_name: this.name,
|
|
3586
|
+
revenue: this.amount,
|
|
3587
|
+
currency: this.currency,
|
|
3588
|
+
partner_params: this.params,
|
|
3589
|
+
};
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3592
|
+
WTEvent.Revenue = Revenue;
|
|
3593
|
+
})(exports.WTEvent || (exports.WTEvent = {}));
|
|
3594
|
+
|
|
3595
|
+
exports.WTLogEngine = WTLogEngine;
|
|
3596
|
+
exports.WTLogLevel = WTLogLevel;
|
|
3597
|
+
exports.WTLogger = WTLogger;
|
|
3598
|
+
exports.WiseTrack = WiseTrack;
|
|
3599
|
+
//# sourceMappingURL=index.js.map
|