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