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