@zoho_apptics/apptics-js-sdk 1.0.2 → 2.0.0-beta.1

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 (243) hide show
  1. package/CHANGELOG.md +193 -0
  2. package/LICENSE +13 -0
  3. package/README.md +846 -11
  4. package/dist/apptics.esm.min.js +3 -0
  5. package/dist/apptics.esm.min.js.map +1 -0
  6. package/dist/apptics.min.js +3 -0
  7. package/dist/apptics.min.js.map +1 -0
  8. package/dist/chunks/lifecycle-VYr43KcB.min.js +3 -0
  9. package/dist/chunks/lifecycle-VYr43KcB.min.js.map +1 -0
  10. package/dist/cjs/auto-init.d.ts +8 -0
  11. package/dist/cjs/auto-init.js +32 -0
  12. package/dist/cjs/core/attempts.d.ts +28 -0
  13. package/dist/cjs/core/attempts.js +113 -0
  14. package/dist/cjs/core/batch.d.ts +32 -0
  15. package/dist/cjs/core/batch.js +116 -0
  16. package/dist/cjs/core/callsite.d.ts +34 -0
  17. package/dist/cjs/core/callsite.js +115 -0
  18. package/dist/cjs/core/consent.d.ts +27 -0
  19. package/dist/cjs/core/consent.js +132 -0
  20. package/dist/cjs/core/constants.d.ts +237 -0
  21. package/dist/cjs/core/constants.js +315 -0
  22. package/dist/cjs/core/db.d.ts +48 -0
  23. package/dist/cjs/core/db.js +467 -0
  24. package/dist/cjs/core/debug.d.ts +22 -0
  25. package/dist/cjs/core/debug.js +88 -0
  26. package/dist/cjs/core/env.d.ts +28 -0
  27. package/dist/cjs/core/env.js +267 -0
  28. package/dist/cjs/core/framework-id.d.ts +1 -0
  29. package/dist/cjs/core/framework-id.js +9 -0
  30. package/dist/cjs/core/guard.d.ts +11 -0
  31. package/dist/cjs/core/guard.js +86 -0
  32. package/dist/cjs/core/hooks.d.ts +39 -0
  33. package/dist/cjs/core/hooks.js +22 -0
  34. package/dist/cjs/core/locks.d.ts +9 -0
  35. package/dist/cjs/core/locks.js +22 -0
  36. package/dist/cjs/core/logger.d.ts +15 -0
  37. package/dist/cjs/core/logger.js +50 -0
  38. package/dist/cjs/core/state.d.ts +70 -0
  39. package/dist/cjs/core/state.js +78 -0
  40. package/dist/cjs/core/storage.d.ts +61 -0
  41. package/dist/cjs/core/storage.js +327 -0
  42. package/dist/cjs/core/stylesheet.d.ts +8 -0
  43. package/dist/cjs/core/stylesheet.js +29 -0
  44. package/dist/cjs/core/transport.d.ts +85 -0
  45. package/dist/cjs/core/transport.js +456 -0
  46. package/dist/cjs/core/utils.d.ts +26 -0
  47. package/dist/cjs/core/utils.js +175 -0
  48. package/dist/cjs/core/validate.d.ts +18 -0
  49. package/dist/cjs/core/validate.js +233 -0
  50. package/dist/cjs/device/appversion.d.ts +15 -0
  51. package/dist/cjs/device/appversion.js +170 -0
  52. package/dist/cjs/device/index.d.ts +34 -0
  53. package/dist/cjs/device/index.js +472 -0
  54. package/dist/cjs/engagement/api-rules.d.ts +49 -0
  55. package/dist/cjs/engagement/api-rules.js +206 -0
  56. package/dist/cjs/engagement/auto-api.d.ts +7 -0
  57. package/dist/cjs/engagement/auto-api.js +200 -0
  58. package/dist/cjs/engagement/auto-screen.d.ts +18 -0
  59. package/dist/cjs/engagement/auto-screen.js +305 -0
  60. package/dist/cjs/engagement/defined-events.d.ts +23 -0
  61. package/dist/cjs/engagement/defined-events.js +58 -0
  62. package/dist/cjs/engagement/send.d.ts +6 -0
  63. package/dist/cjs/engagement/send.js +104 -0
  64. package/dist/cjs/engagement/session.d.ts +51 -0
  65. package/dist/cjs/engagement/session.js +463 -0
  66. package/dist/cjs/engagement/track.d.ts +56 -0
  67. package/dist/cjs/engagement/track.js +375 -0
  68. package/dist/cjs/errors/send.d.ts +6 -0
  69. package/dist/cjs/errors/send.js +73 -0
  70. package/dist/cjs/errors/track.d.ts +4 -0
  71. package/dist/cjs/errors/track.js +167 -0
  72. package/dist/cjs/feedback/controls.d.ts +37 -0
  73. package/dist/cjs/feedback/controls.js +316 -0
  74. package/dist/cjs/feedback/index.d.ts +9 -0
  75. package/dist/cjs/feedback/index.js +56 -0
  76. package/dist/cjs/feedback/logs.d.ts +45 -0
  77. package/dist/cjs/feedback/logs.js +241 -0
  78. package/dist/cjs/feedback/quartz.d.ts +18 -0
  79. package/dist/cjs/feedback/quartz.js +105 -0
  80. package/dist/cjs/feedback/send.d.ts +28 -0
  81. package/dist/cjs/feedback/send.js +203 -0
  82. package/dist/cjs/feedback/styles.d.ts +10 -0
  83. package/dist/cjs/feedback/styles.js +8 -0
  84. package/dist/cjs/feedback/template.d.ts +2 -0
  85. package/dist/cjs/feedback/template.js +162 -0
  86. package/dist/cjs/feedback/ui.d.ts +63 -0
  87. package/dist/cjs/feedback/ui.js +709 -0
  88. package/dist/cjs/heatmap/send.d.ts +13 -0
  89. package/dist/cjs/heatmap/send.js +82 -0
  90. package/dist/cjs/heatmap/track.d.ts +4 -0
  91. package/dist/cjs/heatmap/track.js +448 -0
  92. package/dist/cjs/index.d.ts +22 -0
  93. package/dist/cjs/index.js +162 -0
  94. package/dist/cjs/lifecycle.d.ts +21 -0
  95. package/dist/cjs/lifecycle.js +734 -0
  96. package/dist/cjs/package.json +3 -0
  97. package/dist/cjs/remoteconfig/country.d.ts +4 -0
  98. package/dist/cjs/remoteconfig/country.js +73 -0
  99. package/dist/cjs/remoteconfig/custom.d.ts +10 -0
  100. package/dist/cjs/remoteconfig/custom.js +58 -0
  101. package/dist/cjs/remoteconfig/evaluate.d.ts +24 -0
  102. package/dist/cjs/remoteconfig/evaluate.js +184 -0
  103. package/dist/cjs/remoteconfig/fetch.d.ts +24 -0
  104. package/dist/cjs/remoteconfig/fetch.js +200 -0
  105. package/dist/cjs/remoteconfig/index.d.ts +15 -0
  106. package/dist/cjs/remoteconfig/index.js +116 -0
  107. package/dist/cjs/remoteconfig/store.d.ts +18 -0
  108. package/dist/cjs/remoteconfig/store.js +98 -0
  109. package/dist/cjs/remoteconfig/tz-countries.d.ts +8 -0
  110. package/dist/cjs/remoteconfig/tz-countries.js +13 -0
  111. package/dist/cjs/remotelog/gate.d.ts +2 -0
  112. package/dist/cjs/remotelog/gate.js +28 -0
  113. package/dist/cjs/remotelog/index.d.ts +8 -0
  114. package/dist/cjs/remotelog/logger.d.ts +22 -0
  115. package/dist/cjs/remotelog/logger.js +111 -0
  116. package/dist/cjs/remotelog/send.d.ts +13 -0
  117. package/dist/cjs/remotelog/send.js +153 -0
  118. package/dist/cjs/remotelogger/index.d.ts +12 -0
  119. package/dist/cjs/remotelogger/index.js +18 -0
  120. package/dist/cjs/scheduler.d.ts +8 -0
  121. package/dist/cjs/scheduler.js +78 -0
  122. package/dist/cjs/types.d.ts +385 -0
  123. package/dist/cjs/user/index.d.ts +33 -0
  124. package/dist/cjs/user/index.js +183 -0
  125. package/dist/esm/auto-init.d.ts +8 -0
  126. package/dist/esm/auto-init.js +29 -0
  127. package/dist/esm/core/attempts.d.ts +28 -0
  128. package/dist/esm/core/attempts.js +106 -0
  129. package/dist/esm/core/batch.d.ts +32 -0
  130. package/dist/esm/core/batch.js +109 -0
  131. package/dist/esm/core/callsite.d.ts +34 -0
  132. package/dist/esm/core/callsite.js +110 -0
  133. package/dist/esm/core/consent.d.ts +27 -0
  134. package/dist/esm/core/consent.js +122 -0
  135. package/dist/esm/core/constants.d.ts +237 -0
  136. package/dist/esm/core/constants.js +292 -0
  137. package/dist/esm/core/db.d.ts +48 -0
  138. package/dist/esm/core/db.js +453 -0
  139. package/dist/esm/core/debug.d.ts +22 -0
  140. package/dist/esm/core/debug.js +81 -0
  141. package/dist/esm/core/env.d.ts +28 -0
  142. package/dist/esm/core/env.js +251 -0
  143. package/dist/esm/core/framework-id.d.ts +1 -0
  144. package/dist/esm/core/framework-id.js +7 -0
  145. package/dist/esm/core/guard.d.ts +11 -0
  146. package/dist/esm/core/guard.js +83 -0
  147. package/dist/esm/core/hooks.d.ts +39 -0
  148. package/dist/esm/core/hooks.js +20 -0
  149. package/dist/esm/core/locks.d.ts +9 -0
  150. package/dist/esm/core/locks.js +20 -0
  151. package/dist/esm/core/logger.d.ts +15 -0
  152. package/dist/esm/core/logger.js +46 -0
  153. package/dist/esm/core/state.d.ts +70 -0
  154. package/dist/esm/core/state.js +73 -0
  155. package/dist/esm/core/storage.d.ts +61 -0
  156. package/dist/esm/core/storage.js +314 -0
  157. package/dist/esm/core/stylesheet.d.ts +8 -0
  158. package/dist/esm/core/stylesheet.js +27 -0
  159. package/dist/esm/core/transport.d.ts +85 -0
  160. package/dist/esm/core/transport.js +439 -0
  161. package/dist/esm/core/utils.d.ts +26 -0
  162. package/dist/esm/core/utils.js +161 -0
  163. package/dist/esm/core/validate.d.ts +18 -0
  164. package/dist/esm/core/validate.js +226 -0
  165. package/dist/esm/device/appversion.d.ts +15 -0
  166. package/dist/esm/device/appversion.js +164 -0
  167. package/dist/esm/device/index.d.ts +34 -0
  168. package/dist/esm/device/index.js +461 -0
  169. package/dist/esm/engagement/api-rules.d.ts +49 -0
  170. package/dist/esm/engagement/api-rules.js +199 -0
  171. package/dist/esm/engagement/auto-api.d.ts +7 -0
  172. package/dist/esm/engagement/auto-api.js +198 -0
  173. package/dist/esm/engagement/auto-screen.d.ts +18 -0
  174. package/dist/esm/engagement/auto-screen.js +301 -0
  175. package/dist/esm/engagement/defined-events.d.ts +23 -0
  176. package/dist/esm/engagement/defined-events.js +55 -0
  177. package/dist/esm/engagement/send.d.ts +6 -0
  178. package/dist/esm/engagement/send.js +101 -0
  179. package/dist/esm/engagement/session.d.ts +51 -0
  180. package/dist/esm/engagement/session.js +448 -0
  181. package/dist/esm/engagement/track.d.ts +56 -0
  182. package/dist/esm/engagement/track.js +365 -0
  183. package/dist/esm/errors/send.d.ts +6 -0
  184. package/dist/esm/errors/send.js +70 -0
  185. package/dist/esm/errors/track.d.ts +4 -0
  186. package/dist/esm/errors/track.js +163 -0
  187. package/dist/esm/feedback/controls.d.ts +37 -0
  188. package/dist/esm/feedback/controls.js +309 -0
  189. package/dist/esm/feedback/index.d.ts +9 -0
  190. package/dist/esm/feedback/index.js +51 -0
  191. package/dist/esm/feedback/logs.d.ts +45 -0
  192. package/dist/esm/feedback/logs.js +227 -0
  193. package/dist/esm/feedback/quartz.d.ts +18 -0
  194. package/dist/esm/feedback/quartz.js +99 -0
  195. package/dist/esm/feedback/send.d.ts +28 -0
  196. package/dist/esm/feedback/send.js +198 -0
  197. package/dist/esm/feedback/styles.d.ts +10 -0
  198. package/dist/esm/feedback/styles.js +4 -0
  199. package/dist/esm/feedback/template.d.ts +2 -0
  200. package/dist/esm/feedback/template.js +159 -0
  201. package/dist/esm/feedback/ui.d.ts +63 -0
  202. package/dist/esm/feedback/ui.js +703 -0
  203. package/dist/esm/heatmap/send.d.ts +13 -0
  204. package/dist/esm/heatmap/send.js +79 -0
  205. package/dist/esm/heatmap/track.d.ts +4 -0
  206. package/dist/esm/heatmap/track.js +445 -0
  207. package/dist/esm/index.d.ts +22 -0
  208. package/dist/esm/index.js +150 -0
  209. package/dist/esm/lifecycle.d.ts +21 -0
  210. package/dist/esm/lifecycle.js +729 -0
  211. package/dist/esm/package.json +3 -0
  212. package/dist/esm/remoteconfig/country.d.ts +4 -0
  213. package/dist/esm/remoteconfig/country.js +70 -0
  214. package/dist/esm/remoteconfig/custom.d.ts +10 -0
  215. package/dist/esm/remoteconfig/custom.js +54 -0
  216. package/dist/esm/remoteconfig/evaluate.d.ts +24 -0
  217. package/dist/esm/remoteconfig/evaluate.js +179 -0
  218. package/dist/esm/remoteconfig/fetch.d.ts +24 -0
  219. package/dist/esm/remoteconfig/fetch.js +196 -0
  220. package/dist/esm/remoteconfig/index.d.ts +15 -0
  221. package/dist/esm/remoteconfig/index.js +111 -0
  222. package/dist/esm/remoteconfig/store.d.ts +18 -0
  223. package/dist/esm/remoteconfig/store.js +91 -0
  224. package/dist/esm/remoteconfig/tz-countries.d.ts +8 -0
  225. package/dist/esm/remoteconfig/tz-countries.js +11 -0
  226. package/dist/esm/remotelog/gate.d.ts +2 -0
  227. package/dist/esm/remotelog/gate.js +26 -0
  228. package/dist/esm/remotelog/index.d.ts +8 -0
  229. package/dist/esm/remotelog/logger.d.ts +22 -0
  230. package/dist/esm/remotelog/logger.js +108 -0
  231. package/dist/esm/remotelog/send.d.ts +13 -0
  232. package/dist/esm/remotelog/send.js +149 -0
  233. package/dist/esm/remotelogger/index.d.ts +12 -0
  234. package/dist/esm/remotelogger/index.js +13 -0
  235. package/dist/esm/scheduler.d.ts +8 -0
  236. package/dist/esm/scheduler.js +74 -0
  237. package/dist/esm/types.d.ts +385 -0
  238. package/dist/esm/user/index.d.ts +33 -0
  239. package/dist/esm/user/index.js +176 -0
  240. package/dist/feedback.esm.min.js +3 -0
  241. package/dist/feedback.esm.min.js.map +1 -0
  242. package/package.json +122 -7
  243. package/src/appticssdk.js +0 -1
@@ -0,0 +1,729 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ import { REQUIRED_CONFIG, CONFIG_KEYS, AP_CONFIG, RETIRED_CONFIG_NAMES, DEFAULT_INACTIVE_MINUTES } from './core/constants.js';
3
+ import { _ZAP } from './core/state.js';
4
+ import { Console, warnAlways } from './core/logger.js';
5
+ import { isEmpty, isSuccess } from './core/utils.js';
6
+ import { storageReady, user_defaults, engagement_transactions, error_transactions, tracking_preference } from './core/storage.js';
7
+ import { hooks } from './core/hooks.js';
8
+ import { applyDebugConfig } from './core/debug.js';
9
+ import { getConnectionType, getOrientation } from './core/env.js';
10
+ import { restoreServerSettings, prepareDevice, updateDeviceWithApptics, refreshServerSettings, needsDevice, deviceReady } from './device/index.js';
11
+ import { clearAppVersion, registerAppVersion, appVersionFailedForNetwork } from './device/appversion.js';
12
+ import { holdTabLock, checkAndUpdateSession, updateLastActiveTimeOfSession, updateScreenWithEndtime, endCurrentSession } from './engagement/session.js';
13
+ import { enableApiTracking } from './engagement/auto-api.js';
14
+ import { routePath, enableScreenTracking } from './engagement/auto-screen.js';
15
+ import { resumeScreen, trackEvent } from './engagement/track.js';
16
+ import { trackError } from './errors/track.js';
17
+ import { startTimers, flush, stopTimers } from './scheduler.js';
18
+ import { sendStoredLogs, forgetStoredLogs } from './remotelog/send.js';
19
+ import { getUserInfo } from './user/index.js';
20
+ import { clearAttempts } from './core/attempts.js';
21
+ import { FRAMEWORK_ID } from './core/framework-id.js';
22
+
23
+ let listenersAttached = false;
24
+ /** The config init() was last called with; reset() starts again from it. */
25
+ let lastConfig = null;
26
+ /** Bumped by every init(); a start() from an earlier init() that was reset in between does nothing. */
27
+ let generation = 0;
28
+ function isBrowser() {
29
+ if (typeof window === 'undefined' || typeof document === 'undefined' || typeof Promise === 'undefined') { // no i18n
30
+ return false;
31
+ }
32
+ try {
33
+ return typeof indexedDB !== 'undefined' || !!window.localStorage; // no i18n
34
+ }
35
+ catch (err) {
36
+ return false; // storage access can throw in sandboxed frames
37
+ }
38
+ }
39
+ /**
40
+ * The config as the SDK keeps it: base_url, auth_key and app_domain under their inside names
41
+ * (serviceUrl, zak, identifier; see CONFIG_KEYS), and appversion as text. An earlier name of a
42
+ * key is still read when the key itself is not given, with a warning naming the key to use.
43
+ * The base url loses any trailing slash, because request paths add their own.
44
+ */
45
+ function normaliseConfig(config) {
46
+ var settings = Object.assign({}, config);
47
+ Object.keys(CONFIG_KEYS).forEach(function (key) {
48
+ var inside = CONFIG_KEYS[key];
49
+ if (!isEmpty(config[key])) {
50
+ settings[inside] = config[key];
51
+ return;
52
+ }
53
+ delete settings[inside];
54
+ Object.keys(RETIRED_CONFIG_NAMES).forEach(function (old) {
55
+ if (RETIRED_CONFIG_NAMES[old] !== key || isEmpty(config[old])) {
56
+ return;
57
+ }
58
+ warnAlways('Apptics.init: ' + old + ' is now ' + key + '; rename it in your config'); // no i18n
59
+ if (isEmpty(settings[inside])) {
60
+ settings[inside] = config[old];
61
+ }
62
+ });
63
+ });
64
+ if (!isEmpty(settings.serviceUrl)) {
65
+ settings.serviceUrl = String(settings.serviceUrl).replace(/\/+$/, ''); // no i18n
66
+ }
67
+ settings.appversion = appVersionText(settings.appversion);
68
+ return settings;
69
+ }
70
+ /**
71
+ * The version as the text it is stored and sent as: a string trimmed, a finite number as its digits.
72
+ * Anything else — blank, NaN, an object — is '', which init() reports as missing.
73
+ */
74
+ function appVersionText(value) {
75
+ if (typeof value === 'number') { // no i18n
76
+ return isFinite(value) ? String(value) : ''; // no i18n
77
+ }
78
+ return typeof value === 'string' ? value.trim() : ''; // no i18n
79
+ }
80
+ /**
81
+ * The placeholders the console's snippets and the docs show for appversion. Starting with one
82
+ * would register a version that was never shipped, and every visit after it would report under it.
83
+ */
84
+ const APPVERSION_PLACEHOLDERS = ['YOUR_APP_VERSION', 'YOUR_BUILD_OR_APP_VERSION', 'YOUR_APPVERSION']; // no i18n
85
+ function isAppVersionPlaceholder(version) {
86
+ return APPVERSION_PLACEHOLDERS.indexOf(version.toUpperCase()) !== -1;
87
+ }
88
+ /**
89
+ * The framework id this SDK reports to serviceUrl. The id built into the package is the one
90
+ * sdk-apptics.zoho.com issued at publish time, and localzoho servers don't know it: any
91
+ * localzoho serviceUrl reports 5970 instead, the id apptics.localzoho.com issued for 2.0.0-beta
92
+ * (Browser), so the same package also runs there.
93
+ */
94
+ const LOCALZOHO_FRAMEWORK_ID = 5970;
95
+ function frameworkIdFor(serviceUrl) {
96
+ var host = serviceUrl;
97
+ try {
98
+ host = new URL(serviceUrl).hostname;
99
+ }
100
+ catch (err) {
101
+ // not a url: judge the text as it is
102
+ }
103
+ return host.indexOf('localzoho') !== -1 ? LOCALZOHO_FRAMEWORK_ID : FRAMEWORK_ID; // no i18n
104
+ }
105
+ /** Which app this browser's stored data belongs to, before app/addversion has named it. */
106
+ function appKey(settings) {
107
+ return settings.serviceUrl + '|' + settings.identifier; // no i18n
108
+ }
109
+ /**
110
+ * The app version stored data belongs to, read before app/addversion replaces it: what tells a
111
+ * new release of the app from a reload. '' on a first visit.
112
+ */
113
+ var previousAppVersion = ''; // no i18n
114
+ /**
115
+ * Data stored for another app on this origin is discarded before anything else reads it,
116
+ * including the stored app/addversion answer that would otherwise hand out that app's ids.
117
+ */
118
+ function discardOtherAppData(settings) {
119
+ // which app it is, and which version, are in app_version_info (serviceUrl, identifier and
120
+ // appversion): no keys of their own. 2.0.0-beta's appkey and appversion are read this once
121
+ var info = user_defaults.item('app_version_info') || {}; // no i18n
122
+ var stored = !isEmpty(info.serviceUrl) && !isEmpty(info.identifier)
123
+ ? appKey(info)
124
+ : user_defaults.item('appkey'); // no i18n
125
+ previousAppVersion = String((!isEmpty(info.appversion) ? info.appversion : user_defaults.item('appversion')) || ''); // no i18n
126
+ user_defaults.add('appkey', undefined); // no i18n
127
+ user_defaults.add('appversion', undefined); // no i18n
128
+ if (!isEmpty(stored) && stored !== appKey(settings)) {
129
+ Console.log('init: stored data belongs to another app, resetting'); // no i18n
130
+ clearStorage();
131
+ previousAppVersion = ''; // no i18n
132
+ }
133
+ }
134
+ /**
135
+ * Timing an app may tune in init(). Each has a range: a value outside it is ignored with a
136
+ * warning rather than applied, since a 10 ms flush interval would hammer the server.
137
+ */
138
+ const TUNABLE = Object.freeze([
139
+ { key: 'batch_flush_interval', min: 1000, max: 3600000 }, // no i18n
140
+ { key: 'getupdates_interval', min: 10000, max: 86400000 }, // no i18n
141
+ { key: 'batch_size', min: 1, max: 500 }, // no i18n
142
+ { key: 'batch_request_timeout', min: 1, max: 30 }, // no i18n
143
+ { key: 'min_session_duration', min: 0, max: 60000 }, // no i18n
144
+ { key: 'heatmap_max_per_session', min: 0, max: 10000 }, // no i18n
145
+ ]);
146
+ /** Reads the tunable timings out of the config. Anything missing goes back to its default. */
147
+ function applyIntervals(config) {
148
+ TUNABLE.forEach(function (rule) {
149
+ var value = config[rule.key];
150
+ // every init() decides these on its own, so a value from an earlier one never lingers
151
+ _ZAP._config[rule.key] = AP_CONFIG[rule.key];
152
+ if (isEmpty(value)) {
153
+ return;
154
+ }
155
+ var num = Number(value);
156
+ if (!isFinite(num) || num < rule.min || num > rule.max) {
157
+ warnAlways('Apptics.init: ' + rule.key + ' must be between ' + rule.min + ' and ' + rule.max + ', keeping ' + _ZAP._config[rule.key]); // no i18n
158
+ return;
159
+ }
160
+ _ZAP._config[rule.key] = num;
161
+ Console.log('Apptics.init: ' + rule.key + ' set to ' + num); // no i18n
162
+ });
163
+ // inactiveduration lives on state, not in _config
164
+ _ZAP.inactiveduration = DEFAULT_INACTIVE_MINUTES;
165
+ if (!isEmpty(config.inactiveduration)) {
166
+ var minutes = Number(config.inactiveduration);
167
+ if (!isFinite(minutes) || minutes < 1 || minutes > 1440) {
168
+ warnAlways('Apptics.init: inactiveduration must be between 1 and 1440 minutes, keeping ' + _ZAP.inactiveduration); // no i18n
169
+ }
170
+ else {
171
+ _ZAP.inactiveduration = minutes;
172
+ Console.log('Apptics.init: inactiveduration set to ' + minutes); // no i18n
173
+ }
174
+ }
175
+ }
176
+ function clearStorage() {
177
+ clearAttempts();
178
+ user_defaults.clear();
179
+ engagement_transactions.clear();
180
+ error_transactions.clear();
181
+ }
182
+ /**
183
+ * Starts the SDK. The config object is required: pass it directly, or let the console snippet
184
+ * supply it (auto-init reads window.appticssettings._defaultoptions and calls init with it).
185
+ * Returns true when the config has base_url, auth_key, app_domain and appversion and start-up has
186
+ * begun (see ready()), false when it was already running, the config is missing or incomplete, or
187
+ * there is no browser. Start-up calls app/addversion with those four, which answers with aaid, the
188
+ * portal and project ids and the rest; then device/add registers the browser, as in 1.x.
189
+ */
190
+ function init(config) {
191
+ if (!config || typeof config !== 'object') { // no i18n
192
+ warnAlways('Apptics.init: a config object is required, e.g. Apptics.init({ base_url, auth_key, app_domain, appversion })'); // no i18n
193
+ return false;
194
+ }
195
+ if (_ZAP._initialised) {
196
+ Console.warn('Apptics.init: already initialised; call Apptics.reset() to start again'); // no i18n
197
+ return false;
198
+ }
199
+ if (!isBrowser()) {
200
+ warnAlways('Apptics.init: skipped, no browser with storage and Promise support'); // no i18n
201
+ return false;
202
+ }
203
+ var settings = normaliseConfig(config);
204
+ var missing = REQUIRED_CONFIG.filter(function (key) {
205
+ return isEmpty(settings[CONFIG_KEYS[key] || key]);
206
+ });
207
+ if (missing.length > 0) {
208
+ warnAlways('Apptics.init: missing required config: ' + missing.join(', ')); // no i18n
209
+ return false;
210
+ }
211
+ if (isAppVersionPlaceholder(settings.appversion)) {
212
+ warnAlways('Apptics.init: appversion is still the placeholder "' + settings.appversion // no i18n
213
+ + '"; replace it with your app\'s version or build number, e.g. \'2.4.0\''); // no i18n
214
+ return false;
215
+ }
216
+ _ZAP._defaultoptions = settings;
217
+ // every request goes to serviceUrl; there is no other host to learn about
218
+ _ZAP._defaultoptions.base_domain = settings.serviceUrl;
219
+ // decided per init(), so a reset() or a page on another host never keeps the last one
220
+ _ZAP._frameworkID = frameworkIdFor(settings.serviceUrl);
221
+ // marks the SDK as started for the checks that need it; app/addversion replaces it with aaid
222
+ _ZAP._token = settings.identifier;
223
+ // console_log: the SDK's own activity in the browser console
224
+ if (!isEmpty(config.console_log)) {
225
+ _ZAP._config.debug = !!config.console_log;
226
+ }
227
+ if (typeof config.ignore_do_not_track === 'boolean') { // no i18n
228
+ _ZAP._config.ignore_do_not_track = config.ignore_do_not_track;
229
+ }
230
+ // debug: debug mode, the debug endpoints. Same payloads, but the answer says where to trace the
231
+ // request. debug_api is its earlier name and still works; debug wins when both are given
232
+ _ZAP._config.debug_api = typeof config.debug === 'boolean' ? config.debug // no i18n
233
+ : typeof config.debug_api === 'boolean' ? config.debug_api : AP_CONFIG.debug_api; // no i18n
234
+ // starts (or clears) the idle hour that closes debug mode on its own
235
+ // an enableDebug() or disableDebug() call the app already made wins over the config
236
+ applyDebugConfig(_ZAP._config.debug_api);
237
+ // what to call this device in the debug stream; see devicename in core/transport.ts
238
+ _ZAP._config.device_name = typeof config.device_name === 'string' ? config.device_name : AP_CONFIG.device_name; // no i18n
239
+ // the SDK no longer reports its own failures to the Remote Logger page: only the lines an app
240
+ // logs with AppticsLogger go there
241
+ if (config.remote_log !== undefined) {
242
+ warnAlways('Apptics.init: remote_log is no longer read; the Remote Logger page shows the lines your app logs with AppticsLogger'); // no i18n
243
+ }
244
+ // AppticsLogger lines go to the Remote Logger page only, never to the browser console
245
+ if (config.show_logs !== undefined) {
246
+ warnAlways('Apptics.init: show_logs is no longer read; AppticsLogger lines are not printed to the browser console'); // no i18n
247
+ }
248
+ // automatic api tracking: the app's own requests, wrapped. Which hosts it records is
249
+ // configureApiTracking's to say; the two keys that once did it are refused out loud rather
250
+ // than quietly ignored, since an app relying on them would otherwise record hosts it meant not to
251
+ _ZAP._config.track_api = AP_CONFIG.track_api;
252
+ ['track_api_hosts', 'track_api_exclude_hosts'].forEach(function (key) {
253
+ if (config[key] !== undefined) {
254
+ warnAlways('Apptics.init: ' + key + ' is no longer supported; use AppticsApi.configure(new AppticsApi.ApiTrackingBuilder().' // no i18n
255
+ + (key === 'track_api_hosts' ? 'allowOnlyDomains' : 'ignoreDomains') + '(...).build())'); // no i18n
256
+ }
257
+ });
258
+ // screen recording is set up in the console now, and arrives with getsdkconfig
259
+ ['DC', 'quartz_workspace_key', 'quartz_department_key'].forEach(function (key) {
260
+ if (config[key] !== undefined) {
261
+ warnAlways('Apptics.init: ' + key + ' is no longer read; screen recording in the feedback form is set up from the Apptics console'); // no i18n
262
+ }
263
+ });
264
+ // sessions are what everything else is recorded in; an app that wants nothing tracked uses
265
+ // AppticsSettings.setTrackingStatus instead
266
+ if (config.track_session !== undefined) {
267
+ warnAlways('Apptics.init: track_session is no longer read; sessions are always recorded. To stop tracking, use AppticsSettings.setTrackingStatus(AppticsSettings.AP_TRACKING_STATUS.NO_TRACKING)'); // no i18n
268
+ }
269
+ if (typeof config.track_api === 'boolean') { // no i18n
270
+ _ZAP._config.track_api = config.track_api;
271
+ }
272
+ enableApiTracking(_ZAP._config.track_api);
273
+ // heatmap capture: switched through the hook heatmap/track.ts sets
274
+ _ZAP._config.track_heatmap = typeof config.track_heatmap === 'boolean' // no i18n
275
+ ? config.track_heatmap
276
+ : AP_CONFIG.track_heatmap;
277
+ hooks.trackHeatmap(_ZAP._config.track_heatmap);
278
+ // automatic screen tracking, on unless the config says false: switched on by start(), once a
279
+ // screen view can be stored
280
+ _ZAP._config.track_screen = typeof config.track_screen === 'boolean' ? config.track_screen : AP_CONFIG.track_screen; // no i18n
281
+ _ZAP._config.screen_routes = screenRouteRules(config.screen_routes);
282
+ // a theme in the config wins; without one, what AppticsFeedback.setFeedbackTheme set stays
283
+ if (config.feedback_theme === 'light' || config.feedback_theme === 'dark' || config.feedback_theme === 'auto') { // no i18n
284
+ _ZAP._config.feedback_theme = config.feedback_theme;
285
+ }
286
+ applyIntervals(config);
287
+ lastConfig = config;
288
+ _ZAP._initialised = true;
289
+ _ZAP._ready = false;
290
+ _ZAP._pending = [];
291
+ var myGeneration = ++generation;
292
+ _ZAP._readyPromise = storageReady().then(function (backend) {
293
+ if (myGeneration !== generation) {
294
+ return false;
295
+ }
296
+ if (!backend) {
297
+ warnAlways('Apptics.init: no usable storage (IndexedDB or localStorage), not starting'); // no i18n
298
+ _ZAP._initialised = false;
299
+ _ZAP._token = ''; // no i18n
300
+ _ZAP._pending = [];
301
+ return false;
302
+ }
303
+ discardOtherAppData(_ZAP._defaultoptions);
304
+ // app/addversion is the first call and everything waits on it: it is what turns the four
305
+ // values init() was given into aaid, the portal and project ids every url carries, and
306
+ // appreleaseversionid, which metaWebSDKV2 refuses a payload without
307
+ return registerAppVersion().then(function (registered) {
308
+ if (myGeneration !== generation) {
309
+ return false;
310
+ }
311
+ if (!registered && appVersionFailedForNetwork()) {
312
+ // a first visit with no network: start once it is back, keeping what the app
313
+ // tracks until then queued, rather than giving up for the rest of the page
314
+ warnAlways('Apptics.init: offline, so app/addversion is tried again when the browser is back online; calls made until then are kept'); // no i18n
315
+ return registerWhenOnline(myGeneration).then(function (ok) {
316
+ if (myGeneration !== generation) {
317
+ return false;
318
+ }
319
+ if (!ok) {
320
+ _ZAP._initialised = false;
321
+ _ZAP._token = ''; // no i18n
322
+ _ZAP._pending = [];
323
+ return false;
324
+ }
325
+ return start(config, myGeneration);
326
+ });
327
+ }
328
+ if (!registered) {
329
+ warnAlways('Apptics.init: app/addversion did not return the app ids, not starting'); // no i18n
330
+ _ZAP._initialised = false;
331
+ _ZAP._token = ''; // no i18n
332
+ _ZAP._pending = [];
333
+ return false;
334
+ }
335
+ return start(config, myGeneration);
336
+ });
337
+ }).catch(function (err) {
338
+ Console.error('Apptics.init: start-up failed', err); // no i18n
339
+ return false;
340
+ });
341
+ return true;
342
+ }
343
+ /** How often a start-up waiting on the network tries app/addversion again, besides on `online`. */
344
+ const OFFLINE_RETRY_MS = 60 * 1000;
345
+ /**
346
+ * app/addversion again once the network is back: on the `online` event, and every minute for a
347
+ * network that came back without one. Resolves true once registered, false when the server
348
+ * refuses it or a reset()/new init() took over.
349
+ */
350
+ function registerWhenOnline(myGeneration) {
351
+ return new Promise(function (resolve) {
352
+ var timer = null;
353
+ var trying = false;
354
+ function done(ok) {
355
+ window.removeEventListener('online', attempt); // no i18n
356
+ if (timer !== null)
357
+ clearInterval(timer);
358
+ resolve(ok);
359
+ }
360
+ function attempt() {
361
+ if (myGeneration !== generation) {
362
+ done(false);
363
+ return;
364
+ }
365
+ if (trying || navigator.onLine === false) {
366
+ return;
367
+ }
368
+ trying = true;
369
+ registerAppVersion().then(function (registered) {
370
+ trying = false;
371
+ if (registered) {
372
+ done(true);
373
+ }
374
+ else if (!appVersionFailedForNetwork()) {
375
+ warnAlways('Apptics.init: app/addversion did not return the app ids, not starting'); // no i18n
376
+ done(false);
377
+ }
378
+ });
379
+ }
380
+ window.addEventListener('online', attempt); // no i18n
381
+ timer = setInterval(attempt, OFFLINE_RETRY_MS);
382
+ });
383
+ }
384
+ /**
385
+ * screen_routes as init() keeps it: each entry checked, an exact path cleaned up, a regex given as
386
+ * a string compiled. An entry that cannot be used is left out, and said, rather than matching
387
+ * something its author did not mean.
388
+ */
389
+ function screenRouteRules(routes) {
390
+ if (!Array.isArray(routes)) {
391
+ return [];
392
+ }
393
+ var out = [];
394
+ routes.forEach(function (route) {
395
+ if (typeof route === 'string') { // no i18n
396
+ if (route.trim() !== '') { // no i18n
397
+ out.push({ kind: 'pattern', pattern: route.trim() }); // no i18n
398
+ }
399
+ return;
400
+ }
401
+ var rule = route && typeof route === 'object' ? route : null; // no i18n
402
+ var name = rule && typeof rule.name === 'string' ? rule.name.trim() : ''; // no i18n
403
+ if (rule && name !== '' && typeof rule.equals === 'string' && rule.equals.trim() !== '') { // no i18n
404
+ out.push({ kind: 'equals', path: routePath(rule.equals.trim()), name: name }); // no i18n
405
+ return;
406
+ }
407
+ if (rule && name !== '' && rule.regex !== undefined) {
408
+ var regex = null;
409
+ if (rule.regex instanceof RegExp) {
410
+ regex = rule.regex;
411
+ }
412
+ else if (typeof rule.regex === 'string' && rule.regex !== '') { // no i18n
413
+ try {
414
+ regex = new RegExp(rule.regex);
415
+ }
416
+ catch (err) {
417
+ regex = null;
418
+ }
419
+ }
420
+ if (regex) {
421
+ out.push({ kind: 'regex', regex: regex, name: name }); // no i18n
422
+ return;
423
+ }
424
+ }
425
+ warnAlways('Apptics.init: screen_routes entry ' + safeJson(route) + ' is left out: give a route pattern, { equals, name } or { regex, name }'); // no i18n
426
+ });
427
+ return out;
428
+ }
429
+ /** An entry as the warning shows it: a RegExp as its source, which JSON.stringify would hide. */
430
+ function safeJson(value) {
431
+ try {
432
+ return JSON.stringify(value, function (_key, one) { return one instanceof RegExp ? String(one) : one; }) || String(value);
433
+ }
434
+ catch (err) {
435
+ return String(value);
436
+ }
437
+ }
438
+ /** Resolves true once start-up has finished, false if init() refused or storage is unusable. */
439
+ function ready() {
440
+ return _ZAP._readyPromise || Promise.resolve(false);
441
+ }
442
+ function start(config, myGeneration) {
443
+ // this tab's lock, before any screen view: it is how other tabs tell this one is still open
444
+ holdTabLock();
445
+ // app/addversion named the app; data stored for another one was discarded before it ran
446
+ _ZAP._token = String(_ZAP._defaultoptions.aaid);
447
+ // last known server settings (getupdates) apply before anything is tracked
448
+ restoreServerSettings();
449
+ // a new release of the app, against the version the stored data was for (see
450
+ // discardOtherAppData): a first visit has none, and is no change
451
+ var appVersionChanged = previousAppVersion !== '' && previousAppVersion != _ZAP._defaultoptions.appversion; // no i18n
452
+ _ZAP._ignoreDnt = _ZAP._config.ignore_do_not_track;
453
+ // the visitor's own stored choice, not getTrackingStatus(): that answers NO_TRACKING while Do
454
+ // Not Track is on, and storing it made one such visit switch tracking off for good
455
+ tracking_preference.update_status(tracking_preference.opt_in_status());
456
+ // the uuid and device info, and a registration on a first visit, under a lock shared with the
457
+ // site's other tabs (see prepareDevice)
458
+ return prepareDevice().then(function () {
459
+ if (myGeneration !== generation) {
460
+ return false;
461
+ }
462
+ return startTracking(appVersionChanged, myGeneration);
463
+ });
464
+ }
465
+ /** The rest of start-up, once the device is set up. */
466
+ function startTracking(appVersionChanged, myGeneration) {
467
+ // no getsdkconfig here, straight after app/addversion: it is asked for once device/add has
468
+ // succeeded (registerDeviceWithApptics), then every getupdates_interval. A returning visit
469
+ // starts from the settings saved by the last one (restoreServerSettings, in start())
470
+ if (appVersionChanged) {
471
+ _ZAP._device_info.appversionid = ''; // no i18n
472
+ updateDeviceWithApptics(_ZAP._device_info).then(function (result) {
473
+ if (isSuccess(result)) {
474
+ Console.log('init: appversion updated to ' + _ZAP._defaultoptions.appversion); // no i18n
475
+ }
476
+ }).catch(function (err) {
477
+ Console.log('init: error updating appversion: ' + err); // no i18n
478
+ });
479
+ }
480
+ // attempt to resolve connection type
481
+ _ZAP._device_info.connectionType = getConnectionType();
482
+ attachListeners();
483
+ _ZAP._properties.orientation = getOrientation();
484
+ getUserInfo();
485
+ return checkAndUpdateSession().then(function () {
486
+ if (myGeneration !== generation) {
487
+ return false;
488
+ }
489
+ startTimers();
490
+ sendStoredLogs();
491
+ _ZAP._ready = true;
492
+ // replay calls made while storage was loading, in order
493
+ var pending = _ZAP._pending;
494
+ _ZAP._pending = [];
495
+ pending.forEach(function (call) {
496
+ try {
497
+ call();
498
+ }
499
+ catch (err) {
500
+ Console.error('apptics: buffered call failed', err); // no i18n
501
+ }
502
+ });
503
+ // after the replay, so a inScreen() the app made during start-up keeps its place, and
504
+ // the first automatic view is the page as it is now
505
+ enableScreenTracking(_ZAP._config.track_screen);
506
+ // a no-op unless the remote-config entry was imported, which sets the hook
507
+ hooks.remoteConfigStarted();
508
+ window.appticsReadyStatus = true;
509
+ if (typeof window.appticsReady == 'function') { // no i18n
510
+ window.appticsReady();
511
+ }
512
+ return true;
513
+ });
514
+ }
515
+ /** Clears stored identity and queues, then starts again from the snippet. */
516
+ function reset() {
517
+ generation++;
518
+ stopTimers();
519
+ // the wrappers come off with everything else; the init() below puts them back if the config
520
+ // asked for them, so a reset that has no config to restore leaves XHR and fetch untouched
521
+ enableApiTracking(false);
522
+ enableScreenTracking(false);
523
+ clearAppVersion();
524
+ hooks.trackHeatmap(false);
525
+ hooks.resetHeatmap();
526
+ hooks.resetRemoteConfig();
527
+ clearStorage();
528
+ _ZAP._initialised = false;
529
+ _ZAP._ready = false;
530
+ _ZAP._pending = [];
531
+ _ZAP._readyPromise = null;
532
+ _ZAP._device_info = {};
533
+ _ZAP._user_info = {};
534
+ _ZAP._current_screen = {};
535
+ _ZAP._current_session = {};
536
+ _ZAP._uuid = ''; // no i18n
537
+ _ZAP._apid = ''; // no i18n
538
+ _ZAP._mapid = ''; // no i18n
539
+ _ZAP._sending = false;
540
+ Console.log('Apptics.reset()'); // no i18n
541
+ // start again with the config init() was called with
542
+ if (lastConfig) {
543
+ init(lastConfig);
544
+ }
545
+ }
546
+ function isActive() {
547
+ return _ZAP._ready;
548
+ }
549
+ /**
550
+ * A click-tracking attribute, in either spelling: `apeventaction`, or `data-apeventaction`, which
551
+ * is valid HTML and what React and TypeScript accept without declaring the attribute.
552
+ */
553
+ function trackingAttribute(el, name) {
554
+ var value = el.getAttribute(name);
555
+ return value !== null && value !== '' ? value : el.getAttribute('data-' + name); // no i18n
556
+ }
557
+ /** `[name]` and `[data-name]`, empty values left out, for closest(). */
558
+ function trackingSelector(name) {
559
+ return '[' + name + ']:not([' + name + '=""]),[data-' + name + ']:not([data-' + name + '=""])'; // no i18n
560
+ }
561
+ // Declarative click tracking: <el apeventaction="name" apeventprops='{"k":"v"}'> inside <el apgroupaction="group">,
562
+ // or the same attributes with a data- prefix
563
+ function onDocumentClick(event) {
564
+ if (!window.appticsReadyStatus || !isActive()) {
565
+ return;
566
+ }
567
+ var start = event.target;
568
+ if (start && typeof start.closest !== 'function') { // no i18n
569
+ start = start.parentElement;
570
+ }
571
+ if (!start) {
572
+ return;
573
+ }
574
+ var targetElem = start.closest(trackingSelector('apeventaction')); // no i18n
575
+ if (!targetElem) {
576
+ return;
577
+ }
578
+ var eventName = trackingAttribute(targetElem, 'apeventaction') || ''; // no i18n
579
+ var groupElem = targetElem.closest(trackingSelector('apgroupaction')); // no i18n
580
+ var groupName = (groupElem && trackingAttribute(groupElem, 'apgroupaction')) || AP_CONFIG.default_group_name; // no i18n
581
+ var eventProps = {};
582
+ var rawProps = trackingAttribute(targetElem, 'apeventprops'); // no i18n
583
+ if (!isEmpty(rawProps)) {
584
+ try {
585
+ eventProps = JSON.parse(rawProps);
586
+ }
587
+ catch (err) {
588
+ Console.warn('apptics: invalid JSON in apeventprops for "' + eventName + '", sending no properties'); // no i18n
589
+ eventProps = {};
590
+ }
591
+ }
592
+ if (!isEmpty(eventName)) {
593
+ trackEvent(eventName, groupName, eventProps);
594
+ }
595
+ }
596
+ /**
597
+ * Page is in the background but still there: close the open screen and send what's queued.
598
+ * By keepalive, because hidden is often the last moment before the tab closes, and a send still
599
+ * waiting on its answer would hold the queue as pagehide tries to send it.
600
+ */
601
+ function onPageHidden() {
602
+ if (!isActive())
603
+ return;
604
+ updateScreenWithEndtime();
605
+ flush(true);
606
+ Console.log('page hidden: closing the open screen and flushing'); // no i18n
607
+ }
608
+ /**
609
+ * The tab is closing, or the page is being replaced or frozen into the back/forward cache.
610
+ * The session ends here, and everything queued goes out by keepalive, since a normal
611
+ * request would be cancelled with the page.
612
+ */
613
+ function onPageClosing() {
614
+ if (!isActive())
615
+ return;
616
+ Console.log('page closing: ending the session and sending what is queued'); // no i18n
617
+ updateScreenWithEndtime();
618
+ forgetStoredLogs();
619
+ endCurrentSession().then(function () {
620
+ return flush(true);
621
+ });
622
+ }
623
+ function attachListeners() {
624
+ if (listenersAttached) {
625
+ return;
626
+ }
627
+ listenersAttached = true;
628
+ // listen for connection change events (only available in w3c implementation)
629
+ var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
630
+ if (connection && connection.addEventListener) {
631
+ connection.addEventListener('change', function () {
632
+ _ZAP._device_info.connectionType = getConnectionType();
633
+ });
634
+ }
635
+ // Track when the window loses focus (user switches to another window or application)
636
+ window.addEventListener('blur', function () {
637
+ if (!isActive())
638
+ return;
639
+ Console.log('Window lost focus, user switched to another window or application'); // no i18n
640
+ updateLastActiveTimeOfSession();
641
+ });
642
+ // Track when the window gains focus (user switches back to the window)
643
+ window.addEventListener('focus', function () {
644
+ if (!isActive())
645
+ return;
646
+ Console.log('Window regained focus, user switched back to the window'); // no i18n
647
+ checkAndUpdateSession();
648
+ startTimers();
649
+ });
650
+ // IndexedDB writes are async, so unload work starts on pagehide rather than beforeunload
651
+ window.addEventListener('pagehide', onPageClosing); // no i18n
652
+ // back/forward cache: pagehide ended the session, so coming back starts a new one
653
+ window.addEventListener('pageshow', function (event) {
654
+ if (!isActive() || !event.persisted)
655
+ return;
656
+ Console.log('restored from the back/forward cache: starting a new session'); // no i18n
657
+ // the screen the page was left on starts a new view, in the new session
658
+ checkAndUpdateSession().then(resumeScreen);
659
+ startTimers();
660
+ });
661
+ document.addEventListener('visibilitychange', function () {
662
+ if (!isActive())
663
+ return;
664
+ if (document.visibilityState === 'hidden') { // no i18n
665
+ onPageHidden();
666
+ return;
667
+ }
668
+ // back in view: the server's tracking flags may have changed while we were away
669
+ Console.log('page visible: refreshing the server settings'); // no i18n
670
+ // hiding ended the screen view; the screen the user is back on starts a new one, after the
671
+ // session is settled so the view belongs to the right one
672
+ checkAndUpdateSession().then(resumeScreen);
673
+ refreshServerSettings();
674
+ });
675
+ // if we are running in cordova use ondeviceready otherwise onload
676
+ window.addEventListener(window.cordova ? 'deviceready' : 'load', function () {
677
+ if (isActive())
678
+ checkAndUpdateSession();
679
+ }, { passive: true });
680
+ // Always send pending requests when the connection comes back online
681
+ window.addEventListener('online', function () {
682
+ if (!isActive())
683
+ return;
684
+ // a first visit that started offline has no device ids yet, and nothing can be sent
685
+ // until it has them: register before flushing, and flush once that has landed
686
+ if (needsDevice()) {
687
+ Console.log('back online: registering this device before sending'); // no i18n
688
+ // the same locked path as start-up, so two tabs coming back online register it once
689
+ prepareDevice().then(deviceReady).then(function () {
690
+ if (!isActive())
691
+ return;
692
+ flush();
693
+ // the lines logged while offline are waiting too, and log/add needs the same ids
694
+ sendStoredLogs();
695
+ });
696
+ return;
697
+ }
698
+ flush();
699
+ sendStoredLogs();
700
+ }, { passive: true });
701
+ if (window.screen && window.screen.orientation && typeof window.screen.orientation.addEventListener === 'function') { // no i18n
702
+ window.screen.orientation.addEventListener('change', function () {
703
+ _ZAP._properties.orientation = getOrientation();
704
+ });
705
+ }
706
+ window.addEventListener('unhandledrejection', function (event) {
707
+ if (isActive() && _ZAP._isGlobalErrorTracking) {
708
+ trackError(event);
709
+ }
710
+ });
711
+ // in the capture phase: a <script>, <img> or <link> that fails to load fires `error` on the
712
+ // element, and it does not bubble, so a bubbling listener never hears of it. One listener
713
+ // hears both kinds, the window's own errors included, so none is counted twice
714
+ window.addEventListener('error', function (event) {
715
+ if (!isActive() || !_ZAP._isGlobalErrorTracking) {
716
+ return;
717
+ }
718
+ var target = event.target;
719
+ if (target && target !== window && typeof target.tagName === 'string') { // no i18n
720
+ // named by describeTarget: Event "error" on <script src="...">
721
+ trackError({ type: 'error', reason: event }); // no i18n
722
+ return;
723
+ }
724
+ trackError(event);
725
+ }, true);
726
+ window.addEventListener('click', onDocumentClick, true); // no i18n
727
+ }
728
+
729
+ export { init, ready, reset, screenRouteRules };